This commit was generated by cvs2svn to compensate for changes in r2,

which included commits to RCS files with non-trunk default branches.


git-svn-id: svn://svn.cc65.org/cc65/trunk@3 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
uz
2000-05-28 13:40:48 +00:00
parent 579491e8a4
commit 53dd513176
847 changed files with 91345 additions and 0 deletions

5
src/ld65/.cvsignore Normal file
View File

@@ -0,0 +1,5 @@
.depend
ld65
*.map
*.s

258
src/ld65/bin.c Normal file
View File

@@ -0,0 +1,258 @@
/*****************************************************************************/
/* */
/* bin.c */
/* */
/* Module to handle the raw binary format */
/* */
/* */
/* */
/* (C) 1999-2000 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "global.h"
#include "error.h"
#include "mem.h"
#include "fileio.h"
#include "segments.h"
#include "exports.h"
#include "config.h"
#include "expr.h"
#include "bin.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
struct BinDesc_ {
unsigned Undef; /* Count of undefined externals */
FILE* F; /* Output file */
const char* Filename; /* Name of output file */
};
/*****************************************************************************/
/* Code */
/*****************************************************************************/
BinDesc* NewBinDesc (void)
/* Create a new binary format descriptor */
{
/* Allocate memory for a new BinDesc struct */
BinDesc* D = Xmalloc (sizeof (BinDesc));
/* Initialize the fields */
D->Undef = 0;
D->F = 0;
D->Filename = 0;
/* Return the created struct */
return D;
}
void FreeBinDesc (BinDesc* D)
/* Free a binary format descriptor */
{
Xfree (D);
}
static unsigned BinWriteExpr (ExprNode* E, int Signed, unsigned Size,
unsigned long Offs, void* Data)
/* Called from SegWrite for an expression. Evaluate the expression, check the
* range and write the expression value to the file.
*/
{
/* There's a predefined function to handle constant expressions */
return SegWriteConstExpr (((BinDesc*)Data)->F, E, Signed, Size);
}
static void BinWriteMem (BinDesc* D, Memory* M)
/* Write the segments of one memory area to a file */
{
/* Get the start address of this memory area */
unsigned long Addr = M->Start;
/* Get a pointer to the first segment node */
MemListNode* N = M->SegList;
while (N) {
int DoWrite;
/* Get the segment from the list node */
SegDesc* S = N->Seg;
/* Keep the user happy */
if (Verbose) {
printf (" Writing `%s'\n", S->Name);
}
/* Writes do only occur in the load area and not for BSS segments */
DoWrite = (S->Flags & SF_BSS) == 0 && /* No BSS segment */
S->Load == M && /* LOAD segment */
S->Seg->Dumped == 0; /* Not already written */
/* Check if we would need an alignment */
if (S->Seg->Align > S->Align) {
/* Segment itself requires larger alignment than configured
* in the linker.
*/
Warning ("Segment `%s' in module `%s' requires larger alignment",
S->Name, S->Seg->AlignObj->Name);
}
/* Handle ALIGN and OFFSET/START */
if (S->Flags & SF_ALIGN) {
/* Align the address */
unsigned long Val, NewAddr;
Val = (0x01UL << S->Align) - 1;
NewAddr = (Addr + Val) & ~Val;
if (DoWrite) {
WriteMult (D->F, M->FillVal, NewAddr-Addr);
}
Addr = NewAddr;
/* Remember the fill value for the segment */
S->Seg->FillVal = M->FillVal;
} else if (S->Flags & (SF_OFFSET | SF_START)) {
unsigned long NewAddr = S->Addr;
if (S->Flags & SF_OFFSET) {
/* It's an offset, not a fixed address, make an address */
NewAddr += M->Start;
}
if (DoWrite) {
WriteMult (D->F, M->FillVal, NewAddr-Addr);
}
Addr = NewAddr;
}
/* Now write the segment to disk if it is not a BSS type segment and
* if the memory area is the load area.
*/
if (DoWrite) {
SegWrite (D->F, S->Seg, BinWriteExpr, D);
} else if (M->Flags & MF_FILL) {
WriteMult (D->F, M->FillVal, S->Seg->Size);
}
S->Seg->Dumped = 1;
/* Calculate the new address */
Addr += S->Seg->Size;
/* Next segment node */
N = N->Next;
}
/* If a fill was requested, fill the remaining space */
if (M->Flags & MF_FILL) {
while (M->FillLevel < M->Size) {
Write8 (D->F, M->FillVal);
++M->FillLevel;
}
}
}
static int BinUnresolved (const char* Name, void* D)
/* Called if an unresolved symbol is encountered */
{
/* Unresolved symbols are an error in binary format. Bump the counter
* and return zero telling the caller that the symbol is indeed
* unresolved.
*/
((BinDesc*) D)->Undef++;
return 0;
}
void BinWriteTarget (BinDesc* D, struct File_* F)
/* Write a binary output file */
{
Memory* M;
/* Place the filename in the control structure */
D->Filename = F->Name;
/* Check for unresolved symbols. The function BinUnresolved is called
* if we get an unresolved symbol.
*/
D->Undef = 0; /* Reset the counter */
CheckExports (BinUnresolved, D);
if (D->Undef > 0) {
/* We had unresolved symbols, cannot create output file */
Error ("%u unresolved external(s) found - cannot create output file", D->Undef);
}
/* Open the file */
D->F = fopen (F->Name, "wb");
if (D->F == 0) {
Error ("Cannot open `%s': %s", F->Name, strerror (errno));
}
/* Keep the user happy */
if (Verbose) {
printf ("Opened `%s'...\n", F->Name);
}
/* Dump all memory areas */
M = F->MemList;
while (M) {
if (Verbose) {
printf (" Dumping `%s'\n", M->Name);
}
BinWriteMem (D, M);
M = M->FNext;
}
/* Close the file */
if (fclose (D->F) != 0) {
Error ("Cannot write to `%s': %s", F->Name, strerror (errno));
}
/* Reset the file and filename */
D->F = 0;
D->Filename = 0;
}

78
src/ld65/bin.h Normal file
View File

@@ -0,0 +1,78 @@
/*****************************************************************************/
/* */
/* bin.h */
/* */
/* Module to handle the raw binary format */
/* */
/* */
/* */
/* (C) 1999 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef BIN_H
#define BIN_H
#include "config.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Structure describing the format */
typedef struct BinDesc_ BinDesc;
/*****************************************************************************/
/* Code */
/*****************************************************************************/
BinDesc* NewBinDesc (void);
/* Create a new binary format descriptor */
void FreeBinDesc (BinDesc* D);
/* Free a binary format descriptor */
void BinWriteTarget (BinDesc* D, File* F);
/* Write a binary output file */
/* End of bin.h */
#endif

89
src/ld65/binfmt.c Normal file
View File

@@ -0,0 +1,89 @@
/*****************************************************************************/
/* */
/* binfmt.c */
/* */
/* Binary format definitions for the ld65 linker */
/* */
/* */
/* */
/* (C) 1999 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include "error.h"
#include "binfmt.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Default format (depends on target system) */
unsigned char DefaultBinFmt = BINFMT_BINARY;
/*****************************************************************************/
/* Code */
/*****************************************************************************/
int RelocatableBinFmt (unsigned Format)
/* Return true if this is a relocatable format, return false otherwise */
{
int Reloc = 0;
/* Resolve the default format */
if (Format == BINFMT_DEFAULT) {
Format = DefaultBinFmt;
}
/* Check the type */
switch (Format) {
case BINFMT_BINARY:
Reloc = 0;
break;
case BINFMT_O65:
Reloc = 1;
break;
default:
Internal ("Invalid format specifier: %u", Format);
}
/* Return the flag */
return Reloc;
}

73
src/ld65/binfmt.h Normal file
View File

@@ -0,0 +1,73 @@
/*****************************************************************************/
/* */
/* binfmt.h */
/* */
/* Binary format definitions for the ld65 linker */
/* */
/* */
/* */
/* (C) 1999 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef BINFMT_H
#define BINFMT_H
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Types of available output formats */
#define BINFMT_DEFAULT 0 /* Default (binary) */
#define BINFMT_BINARY 1 /* Straight binary format */
#define BINFMT_O65 2 /* Andre Fachats o65 format */
/* Default format (depends on target system) */
extern unsigned char DefaultBinFmt;
/*****************************************************************************/
/* Code */
/*****************************************************************************/
int RelocatableBinFmt (unsigned Format);
/* Return true if this is a relocatable format, return false otherwise */
/* End of binfmt.h */
#endif

1202
src/ld65/config.c Normal file

File diff suppressed because it is too large Load Diff

147
src/ld65/config.h Normal file
View File

@@ -0,0 +1,147 @@
/*****************************************************************************/
/* */
/* config.h */
/* */
/* Target configuration file for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998-2000 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef CONFIG_H
#define CONFIG_H
#include "segments.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* File list entry */
typedef struct File_ File;
struct File_ {
File* Next; /* Pointer to next entry in list */
unsigned Flags;
unsigned Format; /* Output format */
struct Memory_* MemList; /* List of memory areas in this file */
struct Memory_* MemLast; /* Last memory area in this file */
char Name [1]; /* Name of file */
};
/* Segment list node. Needed because there are two lists (RUN & LOAD) */
typedef struct MemListNode_ MemListNode;
struct MemListNode_ {
MemListNode* Next; /* Next entry */
struct SegDesc_* Seg; /* Segment */
};
/* Memory list entry */
typedef struct Memory_ Memory;
struct Memory_ {
Memory* Next; /* Pointer to next entry in list */
Memory* FNext; /* Next in file list */
unsigned Attr; /* Which values are valid? */
unsigned Flags; /* Set of bitmapped flags */
unsigned long Start; /* Start address */
unsigned long Size; /* Length of memory section */
unsigned long FillLevel; /* Actual fill level of segment */
unsigned char FillVal; /* Value used to fill rest of seg */
MemListNode* SegList; /* List of segments for this section */
MemListNode* SegLast; /* Last segment in this section */
File* F; /* File that contains the entry */
char Name [1]; /* Name of the memory section */
};
/* Segment descriptor entry */
typedef struct SegDesc_ SegDesc;
struct SegDesc_ {
SegDesc* Next; /* Pointer to next entry in list */
Segment* Seg; /* Pointer to segment structure */
unsigned Attr; /* Attributes for segment */
unsigned Flags; /* Set of bitmapped flags */
Memory* Load; /* Load memory section */
Memory* Run; /* Run memory section */
unsigned long Addr; /* Start address or offset into segment */
unsigned char Align; /* Alignment if given */
char Name [1]; /* Copy of name */
};
/* Segment list */
extern SegDesc* SegDescList; /* Single linked list */
extern unsigned SegDescCount; /* Number of entries in list */
/* Memory flags */
#define MF_DEFINE 0x0001 /* Define start and size */
#define MF_FILL 0x0002 /* Fill segment */
#define MF_RO 0x0004 /* Read only memory area */
/* Segment flags */
#define SF_RO 0x0001 /* Read only segment */
#define SF_BSS 0x0002 /* Segment is BSS style segment */
#define SF_ZP 0x0004 /* Zeropage segment (o65 only) */
#define SF_WPROT 0x0008 /* Write protected segment */
#define SF_DEFINE 0x0010 /* Define start and size */
#define SF_ALIGN 0x0020 /* Align the segment */
#define SF_OFFSET 0x0040 /* Segment has offset in memory */
#define SF_START 0x0080 /* Segment has fixed start address */
#define SF_LOAD_AND_RUN 0x1000 /* LOAD and RUN given */
#define SF_RUN_DEF 0x2000 /* RUN symbols already defined */
#define SF_LOAD_DEF 0x4000 /* LOAD symbols already defined */
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void CfgRead (void);
/* Read the configuration */
void CfgAssignSegments (void);
/* Assign segments, define linker symbols where requested */
void CfgWriteTarget (void);
/* Write the target file(s) */
/* End of config.h */
#endif

210
src/ld65/dbgsyms.c Normal file
View File

@@ -0,0 +1,210 @@
/*****************************************************************************/
/* */
/* dbgsyms.c */
/* */
/* Debug symbol handing for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include <string.h>
#include "../common/symdefs.h"
#include "global.h"
#include "mem.h"
#include "error.h"
#include "fileio.h"
#include "objdata.h"
#include "expr.h"
#include "dbgsyms.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* We will collect all debug symbols in the following array and remove
* duplicates before outputing them.
*/
static DbgSym* DbgSymPool [256];
/*****************************************************************************/
/* Code */
/*****************************************************************************/
static DbgSym* NewDbgSym (unsigned char Type, const char* Name, ObjData* O)
/* Create a new DbgSym and return it */
{
/* Get the length of the symbol name */
unsigned Len = strlen (Name);
/* Allocate memory */
DbgSym* D = Xmalloc (sizeof (DbgSym) + Len);
/* Initialize the fields */
D->Next = 0;
D->Flags = 0;
D->Obj = O;
D->Expr = 0;
D->Type = Type;
memcpy (D->Name, Name, Len);
D->Name [Len] = '\0';
/* Return the new entry */
return D;
}
static DbgSym* GetDbgSym (DbgSym* D, long Val)
/* Check if we find the same debug symbol in the table. If we find it, return
* a pointer to the other occurrence, if we didn't find it, return NULL.
*/
{
/* Create the hash. We hash over the symbol value */
unsigned Hash = ((Val >> 24) & 0xFF) ^
((Val >> 16) & 0xFF) ^
((Val >> 8) & 0xFF) ^
((Val >> 0) & 0xFF);
/* Check for this symbol */
DbgSym* Sym = DbgSymPool [Hash];
while (Sym) {
/* Is this symbol identical? */
if (strcmp (Sym->Name, D->Name) == 0 && EqualExpr (Sym->Expr, D->Expr)) {
/* Found */
return Sym;
}
/* Next symbol */
Sym = Sym->Next;
}
/* This is the first symbol of it's kind */
return 0;
}
static void InsertDbgSym (DbgSym* D, long Val)
/* Insert the symbol into the hashed symbol pool */
{
/* Create the hash. We hash over the symbol value */
unsigned Hash = ((Val >> 24) & 0xFF) ^
((Val >> 16) & 0xFF) ^
((Val >> 8) & 0xFF) ^
((Val >> 0) & 0xFF);
/* Insert the symbol */
D->Next = DbgSymPool [Hash];
DbgSymPool [Hash] = D;
}
DbgSym* ReadDbgSym (FILE* F, ObjData* O)
/* Read a debug symbol from a file, insert and return it */
{
unsigned char Type;
char Name [256];
DbgSym* D;
/* Read the type */
Type = Read8 (F);
/* Read the name */
ReadStr (F, Name);
/* Create a new export */
D = NewDbgSym (Type, Name, O);
/* Read the value */
if (Type & EXP_EXPR) {
D->Expr = ReadExpr (F, O);
} else {
D->Expr = LiteralExpr (Read32 (F), O);
}
/* Last is the file position where the definition was done */
ReadFilePos (F, &D->Pos);
/* Return the new DbgSym */
return D;
}
long GetDbgSymVal (DbgSym* D)
/* Get the value of this symbol */
{
CHECK (D->Expr != 0);
return GetExprVal (D->Expr);
}
void PrintDbgSymLabels (ObjData* O, FILE* F)
/* Print the debug symbols in a VICE label file */
{
unsigned I;
/* Walk through all debug symbols in this module */
for (I = 0; I < O->DbgSymCount; ++I) {
/* Get the next debug symbol */
DbgSym* D = O->DbgSyms [I];
/* Get the symbol value */
long Val = GetDbgSymVal (D);
/* Lookup this symbol in the table. If it is found in the table, it was
* already written to the file, so don't emit it twice. If it is not in
* the table, insert and output it.
*/
if (GetDbgSym (D, Val) == 0) {
/* Emit the VICE label line */
fprintf (F, "al %06lX .%s\n", Val, D->Name);
/* Insert the symbol into the table */
InsertDbgSym (D, Val);
}
}
}

92
src/ld65/dbgsyms.h Normal file
View File

@@ -0,0 +1,92 @@
/*****************************************************************************/
/* */
/* dbgsyms.h */
/* */
/* Debug symbol handing for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef DBGSYMS_H
#define DBGSYMS_H
#include <stdio.h>
#include "../common/exprdefs.h"
#include "../common/filepos.h"
#include "objdata.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Debug symbol structure */
typedef struct DbgSym_ DbgSym;
struct DbgSym_ {
DbgSym* Next; /* Pool linear list link */
unsigned Flags; /* Generic flags */
ObjData* Obj; /* Object file that exports the name */
FilePos Pos; /* File position of definition */
ExprNode* Expr; /* Expression (0 if not def'd) */
unsigned char Type; /* Type of symbol */
char Name [1]; /* Name - dynamically allocated */
};
/*****************************************************************************/
/* Code */
/*****************************************************************************/
DbgSym* ReadDbgSym (FILE* F, ObjData* Obj);
/* Read a debug symbol from a file, insert and return it */
long GetDbgSymVal (DbgSym* D);
/* Get the value of this symbol */
void PrintDbgSymLabels (ObjData* O, FILE* F);
/* Print the debug symbols in a VICE label file */
/* End of dbgsyms.h */
#endif

106
src/ld65/error.c Normal file
View File

@@ -0,0 +1,106 @@
/*****************************************************************************/
/* */
/* global.c */
/* */
/* Error handling for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "error.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Messages for internal compiler errors */
const char _MsgCheckFailed [] =
"Check failed: `%s' (= %d), file `%s', line %u\n";
const char _MsgPrecondition [] =
"Precondition violated: `%s' (= %d), file `%s', line %u\n";
const char _MsgFail [] =
"%s, file `%s', line %u\n";
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void Warning (const char* Format, ...)
/* Print a warning message */
{
va_list ap;
va_start (ap, Format);
fprintf (stderr, "Warning: ");
vfprintf (stderr, Format, ap);
putc ('\n', stderr);
va_end (ap);
}
void Error (const char* Format, ...)
/* Print an error message and die */
{
va_list ap;
va_start (ap, Format);
fprintf (stderr, "Error: ");
vfprintf (stderr, Format, ap);
putc ('\n', stderr);
va_end (ap);
exit (EXIT_FAILURE);
}
void Internal (const char* Format, ...)
/* Print an internal error message and die */
{
va_list ap;
va_start (ap, Format);
fprintf (stderr, "Internal error: ");
vfprintf (stderr, Format, ap);
putc ('\n', stderr);
va_end (ap);
exit (EXIT_FAILURE);
}

87
src/ld65/error.h Normal file
View File

@@ -0,0 +1,87 @@
/*****************************************************************************/
/* */
/* global.h */
/* */
/* Error handling for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef ERROR_H
#define ERROR_H
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Messages for internal compiler errors */
extern const char _MsgCheckFailed [];
extern const char _MsgPrecondition [];
extern const char _MsgFail [];
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void Warning (const char* Format, ...);
/* Print a warning message */
void Error (const char* Format, ...);
/* Print an error message and die */
void Internal (const char* Format, ...);
/* Print an internal error message and die */
#define CHECK(c) \
if (!(c)) \
Internal (_MsgCheckFailed, #c, c, __FILE__, __LINE__)
#define PRECONDITION(c) \
if (!(c)) \
Internal (_MsgPrecondition, #c, c, __FILE__, __LINE__)
#define FAIL(s) \
Internal (_MsgFail, s, __FILE__, __LINE__)
/* End of error.h */
#endif

662
src/ld65/exports.c Normal file
View File

@@ -0,0 +1,662 @@
/*****************************************************************************/
/* */
/* exports.c */
/* */
/* Exports handing for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../common/symdefs.h"
#include "../common/hashstr.h"
#include "global.h"
#include "mem.h"
#include "error.h"
#include "fileio.h"
#include "objdata.h"
#include "expr.h"
#include "exports.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Hash table */
#define HASHTAB_SIZE 4081
static Export* HashTab [HASHTAB_SIZE];
/* Import management variables */
static unsigned ImpCount = 0; /* Import count */
static unsigned ImpOpen = 0; /* Count of open imports */
/* Export management variables */
static unsigned ExpCount = 0; /* Export count */
static Export** ExpPool = 0; /* Exports array */
/* Defines for the flags in Export */
#define EXP_USERMARK 0x0001
/*****************************************************************************/
/* Import handling */
/*****************************************************************************/
static Export* NewExport (unsigned char Type, const char* Name, ObjData* Obj);
/* Create a new export and initialize it */
static Import* NewImport (unsigned char Type, ObjData* Obj)
/* Create a new import and initialize it */
{
/* Allocate memory */
Import* I = Xmalloc (sizeof (Import));
/* Initialize the fields */
I->Next = 0;
I->Obj = Obj;
I->V.Name = 0;
I->Type = Type;
/* Return the new structure */
return I;
}
void InsertImport (Import* I)
/* Insert an import into the table */
{
Export* E;
unsigned HashVal;
/* As long as the import is not inserted, V.Name is valid */
const char* Name = I->V.Name;
/* Create a hash value for the given name */
HashVal = HashStr (Name) % HASHTAB_SIZE;
/* Search through the list in that slot and print matching duplicates */
if (HashTab [HashVal] == 0) {
/* The slot is empty, we need to insert a dummy export */
E = HashTab [HashVal] = NewExport (0, Name, 0);
++ExpCount;
} else {
E = HashTab [HashVal];
while (1) {
if (strcmp (E->Name, Name) == 0) {
/* We have an entry, L points to it */
break;
}
if (E->Next == 0) {
/* End of list an entry not found, insert a dummy */
E->Next = NewExport (0, Name, 0);
E = E->Next; /* Point to dummy */
++ExpCount; /* One export more */
break;
} else {
E = E->Next;
}
}
}
/* Ok, E now points to a valid exports entry for the given import. Insert
* the import into the imports list and update the counters.
*/
I->V.Exp = E;
I->Next = E->ImpList;
E->ImpList = I;
E->ImpCount++;
++ImpCount; /* Total import count */
if (E->Expr == 0) {
/* This is a dummy export */
++ImpOpen;
}
/* Now free the name since it's no longer needed */
Xfree (Name);
}
Import* ReadImport (FILE* F, ObjData* Obj)
/* Read an import from a file and return it */
{
Import* I;
/* Read the import type and check it */
unsigned char Type = Read8 (F);
if (Type != IMP_ZP && Type != IMP_ABS) {
Error ("Unknown import type in module `%s': %02X", Obj->Name, Type);
}
/* Create a new import */
I = NewImport (Type, Obj);
/* Read the name */
I->V.Name = ReadMallocedStr (F);
/* Read the file position */
ReadFilePos (F, &I->Pos);
/* Return the new import */
return I;
}
/*****************************************************************************/
/* Code */
/*****************************************************************************/
static Export* NewExport (unsigned char Type, const char* Name, ObjData* Obj)
/* Create a new export and initialize it */
{
/* Get the length of the symbol name */
unsigned Len = strlen (Name);
/* Allocate memory */
Export* E = Xmalloc (sizeof (Export) + Len);
/* Initialize the fields */
E->Next = 0;
E->Flags = 0;
E->Obj = Obj;
E->ImpCount = 0;
E->ImpList = 0;
E->Expr = 0;
E->Type = Type;
memcpy (E->Name, Name, Len);
E->Name [Len] = '\0';
/* Return the new entry */
return E;
}
void InsertExport (Export* E)
/* Insert an exported identifier and check if it's already in the list */
{
Export* L;
Export* Last;
Import* Imp;
unsigned HashVal;
/* Create a hash value for the given name */
HashVal = HashStr (E->Name) % HASHTAB_SIZE;
/* Search through the list in that slot */
if (HashTab [HashVal] == 0) {
/* The slot is empty */
HashTab [HashVal] = E;
++ExpCount;
} else {
Last = 0;
L = HashTab [HashVal];
do {
if (strcmp (L->Name, E->Name) == 0) {
/* This may be an unresolved external */
if (L->Expr == 0) {
/* This *is* an unresolved external */
E->Next = L->Next;
E->ImpCount = L->ImpCount;
E->ImpList = L->ImpList;
if (Last) {
Last->Next = E;
} else {
HashTab [HashVal] = E;
}
ImpOpen -= E->ImpCount; /* Decrease open imports now */
Xfree (L);
/* We must run through the import list and change the
* export pointer now.
*/
Imp = E->ImpList;
while (Imp) {
Imp->V.Exp = E;
Imp = Imp->Next;
}
} else {
/* Duplicate entry, ignore it */
Warning ("Duplicate external identifier: `%s'", L->Name);
}
return;
}
Last = L;
L = L->Next;
} while (L);
/* Insert export at end of queue */
Last->Next = E;
++ExpCount;
}
}
Export* ReadExport (FILE* F, ObjData* O)
/* Read an export from a file */
{
unsigned char Type;
char Name [256];
Export* E;
/* Read the type */
Type = Read8 (F);
/* Read the name */
ReadStr (F, Name);
/* Create a new export */
E = NewExport (Type, Name, O);
/* Read the value */
if (Type & EXP_EXPR) {
E->Expr = ReadExpr (F, O);
} else {
E->Expr = LiteralExpr (Read32 (F), O);
}
/* Last is the file position where the definition was done */
ReadFilePos (F, &E->Pos);
/* Return the new export */
return E;
}
Export* CreateConstExport (const char* Name, long Value)
/* Create an export for a literal date */
{
/* Create a new export */
Export* E = NewExport (EXP_ABS, Name, 0);
/* Assign the value */
E->Expr = LiteralExpr (Value, 0);
/* Insert the export */
InsertExport (E);
/* Return the new export */
return E;
}
Export* CreateMemExport (const char* Name, Memory* Mem, unsigned long Offs)
/* Create an relative export for a memory area offset */
{
/* Create a new export */
Export* E = NewExport (EXP_ABS, Name, 0);
/* Assign the value */
E->Expr = MemExpr (Mem, Offs, 0);
/* Insert the export */
InsertExport (E);
/* Return the new export */
return E;
}
static Export* FindExport (const char* Name)
/* Check for an identifier in the list. Return 0 if not found, otherwise
* return a pointer to the export.
*/
{
/* Get a pointer to the list with the symbols hash value */
Export* L = HashTab [HashStr (Name) % HASHTAB_SIZE];
while (L) {
/* Search through the list in that slot */
if (strcmp (L->Name, Name) == 0) {
/* Entry found */
return L;
}
L = L->Next;
}
/* Not found */
return 0;
}
int IsUnresolved (const char* Name)
/* Check if this symbol is an unresolved export */
{
/* Find the export */
Export* E = FindExport (Name);
/* Check if it's unresolved */
return E != 0 && E->Expr == 0;
}
int IsConstExport (const Export* E)
/* Return true if the expression associated with this export is const */
{
if (E->Expr == 0) {
/* External symbols cannot be const */
return 0;
} else {
return IsConstExpr (E->Expr);
}
}
long GetExportVal (const Export* E)
/* Get the value of this export */
{
if (E->Expr == 0) {
/* OOPS */
Internal ("`%s' is an undefined external", E->Name);
}
return GetExprVal (E->Expr);
}
static void CheckSymType (Export* E)
/* Check the types for one export */
{
/* External with matching imports */
Import* Imp = E->ImpList;
int ZP = (E->Type & EXP_ZP) != 0;
while (Imp) {
if (ZP != ((Imp->Type & IMP_ZP) != 0)) {
/* Export is ZP, import is abs or the other way round */
if (E->Obj) {
/* User defined export */
Warning ("Type mismatch for `%s', export in "
"%s(%lu), import in %s(%lu)",
E->Name, E->Obj->Files [Imp->Pos.Name],
E->Pos.Line, Imp->Obj->Files [Imp->Pos.Name],
Imp->Pos.Line);
} else {
/* Export created by the linker */
Warning ("Type mismatch for `%s', imported from %s(%lu)",
E->Name, Imp->Obj->Files [Imp->Pos.Name],
Imp->Pos.Line);
}
}
Imp = Imp->Next;
}
}
static void CheckSymTypes (void)
/* Check for symbol tape mismatches */
{
unsigned I;
/* Print all open imports */
for (I = 0; I < ExpCount; ++I) {
Export* E = ExpPool [I];
if (E->Expr != 0 && E->ImpCount > 0) {
/* External with matching imports */
CheckSymType (E);
}
}
}
static void PrintUnresolved (ExpCheckFunc F, void* Data)
/* Print a list of unresolved symbols. On unresolved symbols, F is
* called (see the comments on ExpCheckFunc in the data section).
*/
{
unsigned I;
/* Print all open imports */
for (I = 0; I < ExpCount; ++I) {
Export* E = ExpPool [I];
if (E->Expr == 0 && E->ImpCount > 0 && F (E->Name, Data) == 0) {
/* Unresolved external */
Import* Imp = E->ImpList;
fprintf (stderr,
"Unresolved external `%s' referenced in:\n",
E->Name);
while (Imp) {
const char* Name = Imp->Obj->Files [Imp->Pos.Name];
fprintf (stderr, " %s(%lu)\n", Name, Imp->Pos.Line);
Imp = Imp->Next;
}
}
}
}
static int CmpExpName (const void* K1, const void* K2)
/* Compare function for qsort */
{
return strcmp ((*(Export**)K1)->Name, (*(Export**)K2)->Name);
}
static void CreateExportPool (void)
/* Create an array with pointer to all exports */
{
unsigned I, J;
/* Allocate memory */
if (ExpPool) {
Xfree (ExpPool);
}
ExpPool = Xmalloc (ExpCount * sizeof (Export*));
/* Walk through the list and insert the exports */
for (I = 0, J = 0; I < sizeof (HashTab) / sizeof (HashTab [0]); ++I) {
Export* E = HashTab [I];
while (E) {
CHECK (J < ExpCount);
ExpPool [J++] = E;
E = E->Next;
}
}
/* Sort them by name */
qsort (ExpPool, ExpCount, sizeof (Export*), CmpExpName);
}
void CheckExports (ExpCheckFunc F, void* Data)
/* Check if there are any unresolved symbols. On unresolved symbols, F is
* called (see the comments on ExpCheckFunc in the data section).
*/
{
/* Create an export pool */
CreateExportPool ();
/* Check for symbol type mismatches */
CheckSymTypes ();
/* Check for unresolved externals (check here for special bin formats) */
if (ImpOpen != 0) {
/* Print all open imports */
PrintUnresolved (F, Data);
}
}
void PrintExportMap (FILE* F)
/* Print an export map to the given file */
{
unsigned I;
unsigned Count;
/* Print all exports */
Count = 0;
for (I = 0; I < ExpCount; ++I) {
Export* E = ExpPool [I];
/* Print unreferenced symbols only if explictly requested */
if (VerboseMap || E->ImpCount > 0) {
fprintf (F,
"%-25s %06lX %c%c ",
E->Name,
GetExportVal (E),
E->ImpCount? 'R' : ' ',
(E->Type & EXP_ZP)? 'Z' : ' ');
if (++Count == 2) {
Count = 0;
fprintf (F, "\n");
}
}
}
fprintf (F, "\n");
}
void PrintImportMap (FILE* F)
/* Print an import map to the given file */
{
unsigned I;
Import* Imp;
/* Loop over all exports */
for (I = 0; I < ExpCount; ++I) {
/* Get the export */
Export* Exp = ExpPool [I];
/* Print the symbol only if there are imports, or if a verbose map
* file is requested.
*/
if (VerboseMap || Exp->ImpCount > 0) {
/* Get the name of the object file that exports the symbol.
* Beware: There may be no object file if the symbol is a linker
* generated symbol.
*/
const char* ObjName = (Exp->Obj != 0)? Exp->Obj->Name : "linker generated";
/* Print the export */
fprintf (F,
"%s (%s):\n",
Exp->Name,
ObjName);
/* Print all imports for this symbol */
Imp = Exp->ImpList;
while (Imp) {
/* Print the import */
fprintf (F,
" %-25s %s(%lu)\n",
Imp->Obj->Name,
Imp->Obj->Files [Imp->Pos.Name],
Imp->Pos.Line);
/* Next import */
Imp = Imp->Next;
}
}
}
fprintf (F, "\n");
}
void PrintExportLabels (FILE* F)
/* Print the exports in a VICE label file */
{
unsigned I;
/* Print all exports */
for (I = 0; I < ExpCount; ++I) {
Export* E = ExpPool [I];
fprintf (F, "al %06lX .%s\n", GetExportVal (E), E->Name);
}
}
void MarkExport (Export* E)
/* Mark the export */
{
E->Flags |= EXP_USERMARK;
}
void UnmarkExport (Export* E)
/* Remove the mark from the export */
{
E->Flags &= ~EXP_USERMARK;
}
int ExportHasMark (Export* E)
/* Return true if the export has a mark */
{
return (E->Flags & EXP_USERMARK) != 0;
}
void CircularRefError (const Export* E)
/* Print an error about a circular reference using to define the given export */
{
Error ("Circular reference for symbol `%s', %s(%lu)",
E->Name, E->Obj->Files [E->Pos.Name], E->Pos.Line);
}

164
src/ld65/exports.h Normal file
View File

@@ -0,0 +1,164 @@
/*****************************************************************************/
/* */
/* exports.h */
/* */
/* Exports handing for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef EXPORTS_H
#define EXPORTS_H
#include <stdio.h>
#include "../common/exprdefs.h"
#include "../common/filepos.h"
#include "objdata.h"
#include "config.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Import symbol structure */
typedef struct Import_ Import;
struct Import_ {
Import* Next; /* Single linked list */
ObjData* Obj; /* Object file that imports the name */
FilePos Pos; /* File position of reference */
union {
struct Export_* Exp; /* Matching export for this import */
const char* Name; /* Name if not in table */
} V;
unsigned char Type; /* Type of import */
};
/* Export symbol structure */
typedef struct Export_ Export;
struct Export_ {
Export* Next; /* Hash table link */
unsigned Flags; /* Generic flags */
ObjData* Obj; /* Object file that exports the name */
unsigned ImpCount; /* How many imports for this symbol? */
Import* ImpList; /* List of imports for this symbol */
FilePos Pos; /* File position of definition */
ExprNode* Expr; /* Expression (0 if not def'd) */
unsigned char Type; /* Type of export */
char Name [1]; /* Name - dynamically allocated */
};
/* Prototype of a function that is called if an undefined symbol is found. It
* may check if the symbol is an external symbol (for binary formats that
* support externals) and will return zero if the symbol could not be
* resolved, or a value != zero if the symbol could be resolved. The
* CheckExports routine will print out the missing symbol in the first case.
*/
typedef int (*ExpCheckFunc) (const char* Name, void* Data);
/*****************************************************************************/
/* Code */
/*****************************************************************************/
Import* ReadImport (FILE* F, ObjData* Obj);
/* Read an import from a file and insert it into the table */
void InsertImport (Import* I);
/* Insert an import into the table */
Export* ReadExport (FILE* F, ObjData* Obj);
/* Read an export from a file */
void InsertExport (Export* E);
/* Insert an exported identifier and check if it's already in the list */
Export* CreateConstExport (const char* Name, long Value);
/* Create an export for a literal date */
Export* CreateMemExport (const char* Name, Memory* Mem, unsigned long Offs);
/* Create an relative export for a memory area offset */
int IsUnresolved (const char* Name);
/* Check if this symbol is an unresolved export */
int IsConstExport (const Export* E);
/* Return true if the expression associated with this export is const */
long GetExportVal (const Export* E);
/* Get the value of this export */
void CheckExports (ExpCheckFunc F, void* Data);
/* Check if there are any unresolved symbols. On unresolved symbols, F is
* called (see the comments on ExpCheckFunc in the data section).
*/
void PrintExportMap (FILE* F);
/* Print an export map to the given file */
void PrintImportMap (FILE* F);
/* Print an import map to the given file */
void PrintExportLabels (FILE* F);
/* Print the exports in a VICE label file */
void MarkExport (Export* E);
/* Mark the export */
void UnmarkExport (Export* E);
/* Remove the mark from the export */
int ExportHasMark (Export* E);
/* Return true if the export has a mark */
void CircularRefError (const Export* E);
/* Print an error about a circular reference using to define the given export */
/* End of exports.h */
#endif

622
src/ld65/expr.c Normal file
View File

@@ -0,0 +1,622 @@
/*****************************************************************************/
/* */
/* expr.c */
/* */
/* Expression evaluation for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998-2000 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include "../common/exprdefs.h"
#include "global.h"
#include "error.h"
#include "mem.h"
#include "fileio.h"
#include "segments.h"
#include "expr.h"
/*****************************************************************************/
/* Helpers */
/*****************************************************************************/
static ExprNode* NewExprNode (ObjData* O)
/* Create a new expression node */
{
/* Allocate fresh memory */
ExprNode* N = Xmalloc (sizeof (ExprNode));
N->Op = EXPR_NULL;
N->Left = 0;
N->Right = 0;
N->Obj = O;
N->V.Val = 0;
return N;
}
static void FreeExprNode (ExprNode* E)
/* Free a node */
{
/* Free the memory */
Xfree (E);
}
/*****************************************************************************/
/* Dump an expression tree on stdout for debugging */
/*****************************************************************************/
static void InternalDumpExpr (const ExprNode* Expr)
/* Dump an expression in UPN */
{
if (Expr == 0) {
return;
}
InternalDumpExpr (Expr->Left);
InternalDumpExpr (Expr->Right);
switch (Expr->Op) {
case EXPR_LITERAL:
printf (" $%04lX", Expr->V.Val & 0xFFFF);
break;
case EXPR_SYMBOL:
printf (" SYM");
break;
case EXPR_SEGMENT:
printf (" SEG");
break;
case EXPR_PLUS:
printf (" +");
break;
case EXPR_MINUS:
printf (" -");
break;
case EXPR_MUL:
printf (" *");
break;
case EXPR_DIV:
printf (" /");
break;
case EXPR_MOD:
printf (" %%");
break;
case EXPR_OR:
printf (" OR");
break;
case EXPR_XOR:
printf (" XOR");
break;
case EXPR_AND:
printf (" AND");
break;
case EXPR_SHL:
printf (" SHL");
break;
case EXPR_SHR:
printf (" SHR");
break;
case EXPR_EQ:
printf (" =");
break;
case EXPR_NE:
printf ("<>");
break;
case EXPR_LT:
printf (" <");
break;
case EXPR_GT:
printf (" >");
break;
case EXPR_UNARY_MINUS:
printf (" NEG");
break;
case EXPR_NOT:
printf (" ~");
break;
case EXPR_LOBYTE:
printf (" LO");
break;
case EXPR_HIBYTE:
printf (" HI");
break;
case EXPR_SWAP:
printf (" SWAP");
break;
case EXPR_BAND:
printf (" BOOL_AND");
break;
case EXPR_BOR:
printf (" BOOL_OR");
break;
case EXPR_BXOR:
printf (" BOOL_XOR");
break;
case EXPR_BNOT:
printf (" BOOL_NOT");
break;
default:
Internal ("Unknown Op type: %u", Expr->Op);
}
}
void DumpExpr (const ExprNode* Expr)
/* Dump an expression tree to stdout */
{
InternalDumpExpr (Expr);
printf ("\n");
}
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void FreeExpr (ExprNode* Root)
/* Free the expression, Root is pointing to. */
{
if (Root) {
FreeExpr (Root->Left);
FreeExpr (Root->Right);
FreeExprNode (Root);
}
}
int IsConstExpr (ExprNode* Root)
/* Return true if the given expression is a constant expression, that is, one
* with no references to external symbols.
*/
{
int Const;
Export* E;
if (EXPR_IS_LEAF (Root->Op)) {
switch (Root->Op) {
case EXPR_LITERAL:
return 1;
case EXPR_SYMBOL:
/* Get the referenced export */
E = GetExprExport (Root);
/* If this export has a mark set, we've already encountered it.
* This means that the export is used to define it's own value,
* which in turn means, that we have a circular reference.
*/
if (ExportHasMark (E)) {
Error ("Circular reference for symbol `%s', %s(%u)",
E->Name, E->Obj->Files [E->Pos.Name], E->Pos.Line);
Const = 0;
} else {
MarkExport (E);
Const = IsConstExport (E);
UnmarkExport (E);
}
return Const;
default:
return 0;
}
} else if (EXPR_IS_UNARY (Root->Op)) {
return IsConstExpr (Root->Left);
} else {
/* We must handle shortcut boolean expressions here */
switch (Root->Op) {
case EXPR_BAND:
if (IsConstExpr (Root->Left)) {
/* lhs is const, if it is zero, don't eval right */
if (GetExprVal (Root->Left) == 0) {
return 1;
} else {
return IsConstExpr (Root->Right);
}
} else {
/* lhs not const --> tree not const */
return 0;
}
break;
case EXPR_BOR:
if (IsConstExpr (Root->Left)) {
/* lhs is const, if it is not zero, don't eval right */
if (GetExprVal (Root->Left) != 0) {
return 1;
} else {
return IsConstExpr (Root->Right);
}
} else {
/* lhs not const --> tree not const */
return 0;
}
break;
default:
/* All others are handled normal */
return IsConstExpr (Root->Left) && IsConstExpr (Root->Right);
}
}
}
Import* GetExprImport (ExprNode* Expr)
/* Get the import data structure for a symbol expression node */
{
/* Check that this is really a symbol */
PRECONDITION (Expr->Op == EXPR_SYMBOL);
/* Return the import */
return Expr->Obj->Imports [Expr->V.ImpNum];
}
Export* GetExprExport (ExprNode* Expr)
/* Get the exported symbol for a symbol expression node */
{
/* Check that this is really a symbol */
PRECONDITION (Expr->Op == EXPR_SYMBOL);
/* Return the export */
return Expr->Obj->Imports [Expr->V.ImpNum]->V.Exp;
}
Section* GetExprSection (ExprNode* Expr)
/* Get the segment for a segment expression node */
{
/* Check that this is really a segment node */
PRECONDITION (Expr->Op == EXPR_SEGMENT);
/* Return the export */
return Expr->Obj->Sections [Expr->V.SegNum];
}
long GetExprVal (ExprNode* Expr)
/* Get the value of a constant expression */
{
long Right, Left, Val;
Section* S;
Export* E;
switch (Expr->Op) {
case EXPR_LITERAL:
return Expr->V.Val;
case EXPR_SYMBOL:
/* Get the referenced export */
E = GetExprExport (Expr);
/* If this export has a mark set, we've already encountered it.
* This means that the export is used to define it's own value,
* which in turn means, that we have a circular reference.
*/
if (ExportHasMark (E)) {
CircularRefError (E);
Val = 0;
} else {
MarkExport (E);
Val = GetExportVal (E);
UnmarkExport (E);
}
return Val;
case EXPR_SEGMENT:
S = GetExprSection (Expr);
return S->Offs + S->Seg->PC;
case EXPR_MEMAREA:
return Expr->V.MemArea->Start;
case EXPR_PLUS:
return GetExprVal (Expr->Left) + GetExprVal (Expr->Right);
case EXPR_MINUS:
return GetExprVal (Expr->Left) - GetExprVal (Expr->Right);
case EXPR_MUL:
return GetExprVal (Expr->Left) * GetExprVal (Expr->Right);
case EXPR_DIV:
Left = GetExprVal (Expr->Left);
Right = GetExprVal (Expr->Right);
if (Right == 0) {
Error ("Division by zero");
}
return Left / Right;
case EXPR_MOD:
Left = GetExprVal (Expr->Left);
Right = GetExprVal (Expr->Right);
if (Right == 0) {
Error ("Modulo operation with zero");
}
return Left % Right;
case EXPR_OR:
return GetExprVal (Expr->Left) | GetExprVal (Expr->Right);
case EXPR_XOR:
return GetExprVal (Expr->Left) ^ GetExprVal (Expr->Right);
case EXPR_AND:
return GetExprVal (Expr->Left) & GetExprVal (Expr->Right);
case EXPR_SHL:
return GetExprVal (Expr->Left) << GetExprVal (Expr->Right);
case EXPR_SHR:
return GetExprVal (Expr->Left) >> GetExprVal (Expr->Right);
case EXPR_EQ:
return (GetExprVal (Expr->Left) == GetExprVal (Expr->Right));
case EXPR_NE:
return (GetExprVal (Expr->Left) != GetExprVal (Expr->Right));
case EXPR_LT:
return (GetExprVal (Expr->Left) < GetExprVal (Expr->Right));
case EXPR_GT:
return (GetExprVal (Expr->Left) > GetExprVal (Expr->Right));
case EXPR_LE:
return (GetExprVal (Expr->Left) <= GetExprVal (Expr->Right));
case EXPR_GE:
return (GetExprVal (Expr->Left) >= GetExprVal (Expr->Right));
case EXPR_UNARY_MINUS:
return -GetExprVal (Expr->Left);
case EXPR_NOT:
return ~GetExprVal (Expr->Left);
case EXPR_LOBYTE:
return GetExprVal (Expr->Left) & 0xFF;
case EXPR_HIBYTE:
return (GetExprVal (Expr->Left) >> 8) & 0xFF;
case EXPR_SWAP:
Left = GetExprVal (Expr->Left);
return ((Left >> 8) & 0x00FF) | ((Left << 8) & 0xFF00);
case EXPR_BAND:
return GetExprVal (Expr->Left) && GetExprVal (Expr->Right);
case EXPR_BOR:
return GetExprVal (Expr->Left) || GetExprVal (Expr->Right);
case EXPR_BXOR:
return (GetExprVal (Expr->Left) != 0) ^ (GetExprVal (Expr->Right) != 0);
case EXPR_BNOT:
return !GetExprVal (Expr->Left);
default:
Internal ("Unknown expression Op type: %u", Expr->Op);
/* NOTREACHED */
return 0;
}
}
ExprNode* LiteralExpr (long Val, ObjData* O)
/* Return an expression tree that encodes the given literal value */
{
ExprNode* Expr = NewExprNode (O);
Expr->Op = EXPR_LITERAL;
Expr->V.Val = Val;
return Expr;
}
ExprNode* MemExpr (Memory* Mem, long Offs, ObjData* O)
/* Return an expression tree that encodes an offset into the memory area */
{
ExprNode* Root;
ExprNode* Expr = NewExprNode (O);
Expr->Op = EXPR_MEMAREA;
Expr->V.MemArea = Mem;
Root = NewExprNode (O);
Root->Op = EXPR_PLUS;
Root->Left = Expr;
Root->Right = LiteralExpr (Offs, O);
return Root;
}
ExprNode* ReadExpr (FILE* F, ObjData* O)
/* Read an expression from the given file */
{
ExprNode* Expr;
/* Read the node tag and handle NULL nodes */
unsigned char Op = Read8 (F);
if (Op == EXPR_NULL) {
return 0;
}
/* Create a new node */
Expr = NewExprNode (O);
Expr->Op = Op;
/* Check the tag and handle the different expression types */
if (EXPR_IS_LEAF (Op)) {
switch (Op) {
case EXPR_LITERAL:
Expr->V.Val = Read32Signed (F);
break;
case EXPR_SYMBOL:
/* Read the import number */
Expr->V.ImpNum = Read16 (F);
break;
case EXPR_SEGMENT:
/* Read the segment number */
Expr->V.SegNum = Read8 (F);
break;
default:
Error ("Invalid expression op: %02X", Op);
}
} else {
/* Not a leaf node */
Expr->Left = ReadExpr (F, O);
Expr->Right = ReadExpr (F, O);
}
/* Return the tree */
return Expr;
}
int EqualExpr (ExprNode* E1, ExprNode* E2)
/* Check if two expressions are identical. */
{
/* If one pointer is NULL, both must be NULL */
if ((E1 == 0) ^ (E2 == 0)) {
return 0;
}
if (E1 == 0) {
return 1;
}
/* Both pointers not NULL, check OP */
if (E1->Op != E2->Op) {
return 0;
}
/* OPs are identical, check data for leafs, or subtrees */
switch (E1->Op) {
case EXPR_LITERAL:
/* Value must be identical */
return (E1->V.Val == E2->V.Val);
case EXPR_SYMBOL:
/* Import number must be identical */
return (E1->V.ImpNum == E2->V.ImpNum);
case EXPR_SEGMENT:
/* Segment number must be identical */
return (E1->V.SegNum == E2->V.SegNum);
case EXPR_MEMAREA:
/* Memory area must be identical */
return (E1->V.MemArea == E2->V.MemArea);
default:
/* Not a leaf node */
return EqualExpr (E1->Left, E2->Left) && EqualExpr (E1->Right, E2->Right);
}
}

97
src/ld65/expr.h Normal file
View File

@@ -0,0 +1,97 @@
/*****************************************************************************/
/* */
/* expr.h */
/* */
/* Expression evaluation for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998-2000 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef EXPR_H
#define EXPR_H
#include "../common/exprdefs.h"
#include "objdata.h"
#include "exports.h"
#include "config.h"
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void FreeExpr (ExprNode* Root);
/* Free the expression tree, Root is pointing to. */
int IsConstExpr (ExprNode* Root);
/* Return true if the given expression is a constant expression, that is, one
* with no references to external symbols.
*/
Import* GetExprImport (ExprNode* Expr);
/* Get the import data structure for a symbol expression node */
Export* GetExprExport (ExprNode* Expr);
/* Get the exported symbol for a symbol expression node */
Section* GetExprSection (ExprNode* Expr);
/* Get the segment for a segment expression node */
long GetExprVal (ExprNode* Expr);
/* Get the value of a constant expression */
ExprNode* LiteralExpr (long Val, ObjData* O);
/* Return an expression tree that encodes the given literal value */
ExprNode* MemExpr (Memory* Mem, long Offs, ObjData* O);
/* Return an expression tree that encodes an offset into the memory area */
void DumpExpr (const ExprNode* Expr);
/* Dump an expression tree to stdout */
ExprNode* ReadExpr (FILE* F, ObjData* O);
/* Read an expression from the given file */
int EqualExpr (ExprNode* E1, ExprNode* E2);
/* Check if two expressions are identical. */
/* End of expr.h */
#endif

237
src/ld65/extsyms.c Normal file
View File

@@ -0,0 +1,237 @@
/*****************************************************************************/
/* */
/* extsyms.c */
/* */
/* Handle program external symbols for relocatable output formats */
/* */
/* */
/* */
/* (C) 1999 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include <string.h>
#include "../common/hashstr.h"
#include "mem.h"
#include "error.h"
#include "extsyms.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Structure holding an external symbol */
struct ExtSym_ {
ExtSym* List; /* Next entry in list of all symbols */
ExtSym* Next; /* Next entry in hash list */
unsigned Flags; /* Generic flags */
unsigned Num; /* Number of external symbol */
char Name [1]; /* Name - dynamically allocated */
};
/* External symbol table structure */
#define HASHTAB_SIZE 53
struct ExtSymTab_ {
ExtSym* Root; /* List of symbols */
ExtSym* Last; /* Pointer to last symbol */
unsigned Count; /* Number of symbols */
ExtSym* HashTab [HASHTAB_SIZE];
};
/*****************************************************************************/
/* Code */
/*****************************************************************************/
ExtSym* NewExtSym (ExtSymTab* Tab, const char* Name)
/* Create a new external symbol and insert it into the table */
{
/* Get the hash value of the string */
unsigned Hash = HashStr (Name) % HASHTAB_SIZE;
/* Get the length of the name */
unsigned Len = strlen (Name);
/* Check for duplicates */
ExtSym* E = GetExtSym (Tab, Name); /* Don't care about duplicate hash here... */
if (E != 0) {
/* We do already have a symbol with this name */
Error ("Duplicate external symbol `%s'", Name);
}
/* Allocate memory for the structure */
E = Xmalloc (sizeof (ExtSym) + Len);
/* Initialize the structure */
E->List = 0;
E->Flags = 0;
E->Num = Tab->Count;
memcpy (E->Name, Name, Len+1);
/* Insert the entry into the list of all symbols */
if (Tab->Last == 0) {
/* List is empty */
Tab->Root = E;
} else {
/* List not empty */
Tab->Last->List = E;
}
Tab->Last = E;
Tab->Count++;
/* Insert the symbol into the hash table */
E->Next = Tab->HashTab [Hash];
Tab->HashTab [Hash] = E;
/* Done, return the created entry */
return E;
}
static void FreeExtSym (ExtSym* E)
/* Free an external symbol structure. Will not unlink the entry, so internal
* use only.
*/
{
Xfree (E);
}
ExtSymTab* NewExtSymTab (void)
/* Create a new external symbol table */
{
unsigned I;
/* Allocate memory */
ExtSymTab* Tab = Xmalloc (sizeof (ExtSymTab));
/* Initialize the fields */
Tab->Root = 0;
Tab->Last = 0;
Tab->Count = 0;
for (I = 0; I < HASHTAB_SIZE; ++I) {
Tab->HashTab [I] = 0;
}
/* Done, return the hash table */
return Tab;
}
void FreeExtSymTab (ExtSymTab* Tab)
/* Free an external symbol structure */
{
/* Free all entries */
while (Tab->Root) {
ExtSym* E = Tab->Root;
Tab->Root = E->Next;
FreeExtSym (E);
}
/* Free the struct itself */
Xfree (Tab);
}
ExtSym* GetExtSym (const ExtSymTab* Tab, const char* Name)
/* Return the entry for the external symbol with the given name. Return NULL
* if there is no such symbol.
*/
{
/* Hash the name */
unsigned Hash = HashStr (Name) % HASHTAB_SIZE;
/* Check the linked list */
ExtSym* E = Tab->HashTab [Hash];
while (E) {
if (strcmp (E->Name, Name) == 0) {
/* Found it */
break;
}
E = E->Next;
}
/* Return the symbol we found */
return E;
}
unsigned ExtSymCount (const ExtSymTab* Tab)
/* Return the number of symbols in the table */
{
return Tab->Count;
}
const ExtSym* ExtSymList (const ExtSymTab* Tab)
/* Return the start of the symbol list sorted by symbol number. Call
* ExtSymNext for the next symbol.
*/
{
return Tab->Root;
}
unsigned ExtSymNum (const ExtSym* E)
/* Return the number of an external symbol */
{
return E->Num;
}
const char* ExtSymName (const ExtSym* E)
/* Return the symbol name */
{
return E->Name;
}
const ExtSym* ExtSymNext (const ExtSym* E)
/* Return the next symbol in the list */
{
return E->Next;
}

99
src/ld65/extsyms.h Normal file
View File

@@ -0,0 +1,99 @@
/*****************************************************************************/
/* */
/* extsyms.h */
/* */
/* Handle program external symbols for relocatable output formats */
/* */
/* */
/* */
/* (C) 1999 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef EXTSYMS_H
#define EXTSYMS_H
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Forward decl for structure holding an external symbol */
typedef struct ExtSym_ ExtSym;
/* External symbol table structure */
typedef struct ExtSymTab_ ExtSymTab;
/*****************************************************************************/
/* Code */
/*****************************************************************************/
ExtSym* NewExtSym (ExtSymTab* Tab, const char* Name);
/* Create a new external symbol and insert it into the list */
ExtSymTab* NewExtSymTab (void);
/* Create a new external symbol table */
void FreeExtSymTab (ExtSymTab* Tab);
/* Free an external symbol structure */
ExtSym* GetExtSym (const ExtSymTab* Tab, const char* Name);
/* Return the entry for the external symbol with the given name. Return NULL
* if there is no such symbol.
*/
unsigned ExtSymCount (const ExtSymTab* Tab);
/* Return the number of symbols in the table */
const ExtSym* ExtSymList (const ExtSymTab* Tab);
/* Return the start of the symbol list sorted by symbol number. Call
* ExtSymNext for the next symbol.
*/
unsigned ExtSymNum (const ExtSym* E);
/* Return the number of an external symbol */
const char* ExtSymName (const ExtSym* E);
/* Return the symbol name */
const ExtSym* ExtSymNext (const ExtSym* E);
/* Return the next symbol in the list */
/* End of extsyms.h */
#endif

269
src/ld65/fileio.c Normal file
View File

@@ -0,0 +1,269 @@
/*****************************************************************************/
/* */
/* fileio.c */
/* */
/* File I/O for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998-2000 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include <string.h>
#include "error.h"
#include "mem.h"
#include "fileio.h"
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void Write8 (FILE* F, unsigned char Val)
/* Write an 8 bit value to the file */
{
if (putc (Val, F) == EOF) {
Error ("Write error (disk full?)");
}
}
void Write16 (FILE* F, unsigned Val)
/* Write a 16 bit value to the file */
{
Write8 (F, (unsigned char) Val);
Write8 (F, (unsigned char) (Val >> 8));
}
void Write24 (FILE* F, unsigned long Val)
/* Write a 24 bit value to the file */
{
Write8 (F, (unsigned char) Val);
Write8 (F, (unsigned char) (Val >> 8));
Write8 (F, (unsigned char) (Val >> 16));
}
void Write32 (FILE* F, unsigned long Val)
/* Write a 32 bit value to the file */
{
Write8 (F, (unsigned char) Val);
Write8 (F, (unsigned char) (Val >> 8));
Write8 (F, (unsigned char) (Val >> 16));
Write8 (F, (unsigned char) (Val >> 24));
}
void WriteVal (FILE* F, unsigned long Val, unsigned Size)
/* Write a value of the given size to the output file */
{
switch (Size) {
case 1:
Write8 (F, Val);
break;
case 2:
Write16 (F, Val);
break;
case 3:
Write24 (F, Val);
break;
case 4:
Write32 (F, Val);
break;
default:
Internal ("WriteVal: Invalid size: %u", Size);
}
}
void WriteStr (FILE* F, const char* S)
/* Write a string to the file */
{
unsigned Len = strlen (S);
if (Len > 255) {
Internal ("String too long");
}
Write8 (F, (unsigned char) Len);
WriteData (F, S, Len);
}
void WriteData (FILE* F, const void* Data, unsigned Size)
/* Write data to the file */
{
if (fwrite (Data, 1, Size, F) != Size) {
Error ("Write error (disk full?)");
}
}
void WriteMult (FILE* F, unsigned char Val, unsigned long Count)
/* Write one byte several times to the file */
{
while (Count--) {
Write8 (F, Val);
}
}
unsigned Read8 (FILE* F)
/* Read an 8 bit value from the file */
{
int C = getc (F);
if (C == EOF) {
Error ("Read error (file corrupt?)");
}
return C;
}
unsigned Read16 (FILE* F)
/* Read a 16 bit value from the file */
{
unsigned Lo = Read8 (F);
unsigned Hi = Read8 (F);
return (Hi << 8) | Lo;
}
unsigned long Read24 (FILE* F)
/* Read a 24 bit value from the file */
{
unsigned long Lo = Read16 (F);
unsigned long Hi = Read8 (F);
return (Hi << 16) | Lo;
}
unsigned long Read32 (FILE* F)
/* Read a 32 bit value from the file */
{
unsigned long Lo = Read16 (F);
unsigned long Hi = Read16 (F);
return (Hi << 16) | Lo;
}
long Read32Signed (FILE* F)
/* Read a 32 bit value from the file. Sign extend the value. */
{
/* Read a 32 bit value */
unsigned long V = Read32 (F);
/* Sign extend the value */
if (V & 0x80000000UL) {
/* Signed value */
V |= ~0xFFFFFFFFUL;
}
/* Return it as a long */
return (long) V;
}
char* ReadStr (FILE* F, char* Str)
/* Read a string from the file. Str must hold 256 chars at max */
{
/* Read the length byte */
unsigned Len = Read8 (F);
/* Read the string itself */
ReadData (F, Str, Len);
/* Terminate the string and return it */
Str [Len] = '\0';
return Str;
}
char* ReadMallocedStr (FILE* F)
/* Read a string from the file into a malloced area */
{
/* Read the length byte */
unsigned Len = Read8 (F);
/* Allocate memory */
char* Str = Xmalloc (Len + 1);
/* Read the string itself */
ReadData (F, Str, Len);
/* Terminate the string and return it */
Str [Len] = '\0';
return Str;
}
FilePos* ReadFilePos (FILE* F, FilePos* Pos)
/* Read a file position from the file */
{
/* The line number is encoded as 24 bit value to save some space */
Pos->Line = Read24 (F);
Pos->Col = Read8 (F);
Pos->Name = Read8 (F);
return Pos;
}
void* ReadData (FILE* F, void* Data, unsigned Size)
/* Read data from the file */
{
if (fread (Data, 1, Size, F) != Size) {
Error ("Read error (file corrupt?)");
}
return Data;
}

111
src/ld65/fileio.h Normal file
View File

@@ -0,0 +1,111 @@
/*****************************************************************************/
/* */
/* fileio.h */
/* */
/* File I/O for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998-2000 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef FILEIO_H
#define FILEIO_H
#include <stdio.h>
#include "../common/filepos.h"
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void Write8 (FILE* F, unsigned char Val);
/* Write an 8 bit value to the file */
void Write16 (FILE* F, unsigned Val);
/* Write a 16 bit value to the file */
void Write24 (FILE* F, unsigned long Val);
/* Write a 24 bit value to the file */
void Write32 (FILE* F, unsigned long Val);
/* Write a 32 bit value to the file */
void WriteVal (FILE* F, unsigned long Val, unsigned Size);
/* Write a value of the given size to the output file */
void WriteStr (FILE* F, const char* S);
/* Write a string to the file */
void WriteData (FILE* F, const void* Data, unsigned Size);
/* Write data to the file */
void WriteMult (FILE* F, unsigned char Val, unsigned long Count);
/* Write one byte several times to the file */
unsigned Read8 (FILE* F);
/* Read an 8 bit value from the file */
unsigned Read16 (FILE* F);
/* Read a 16 bit value from the file */
unsigned long Read24 (FILE* F);
/* Read a 24 bit value from the file */
unsigned long Read32 (FILE* F);
/* Read a 32 bit value from the file */
long Read32Signed (FILE* F);
/* Read a 32 bit value from the file. Sign extend the value. */
char* ReadStr (FILE* F, char* Str);
/* Read a string from the file. Str must hold 256 chars at max */
char* ReadMallocedStr (FILE* F);
/* Read a string from the file into a malloced area */
FilePos* ReadFilePos (FILE* F, FilePos* Pos);
/* Read a file position from the file */
void* ReadData (FILE* F, void* Data, unsigned Size);
/* Read data from the file */
/* End of fileio.h */
#endif

59
src/ld65/global.c Normal file
View File

@@ -0,0 +1,59 @@
/*****************************************************************************/
/* */
/* global.c */
/* */
/* Global variables for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include "global.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
const char* ProgName = "ld65"; /* Program name */
const char* OutputName = "a.out"; /* Name of output file */
unsigned long StartAddr = 0x200; /* Start address */
unsigned char Verbose = 0; /* Verbose operation flag */
unsigned char VerboseMap = 0; /* Verbose map file */
const char* MapFileName = 0; /* Name of the map file */
const char* LabelFileName = 0; /* Name of the label file */
unsigned char WProtSegs = 0; /* Mark write protected segments */

66
src/ld65/global.h Normal file
View File

@@ -0,0 +1,66 @@
/*****************************************************************************/
/* */
/* global.h */
/* */
/* Global variables for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef GLOBAL_H
#define GLOBAL_H
/*****************************************************************************/
/* Data */
/*****************************************************************************/
extern const char* ProgName; /* Program name */
extern const char* OutputName; /* Name of output file */
extern unsigned long StartAddr; /* Start address */
extern unsigned char Verbose; /* Verbose operation flag */
extern unsigned char VerboseMap; /* Verbose map file */
extern const char* MapFileName; /* Name of the map file */
extern const char* LabelFileName; /* Name of the label file */
extern unsigned char WProtSegs; /* Mark write protected segments */
/* End of global.h */
#endif

285
src/ld65/library.c Normal file
View File

@@ -0,0 +1,285 @@
/*****************************************************************************/
/* */
/* library.c */
/* */
/* Library data structures and helpers for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "../common/objdefs.h"
#include "../common/libdefs.h"
#include "../common/symdefs.h"
#include "../common/exprdefs.h"
#include "../common/filepos.h"
#include "mem.h"
#include "error.h"
#include "fileio.h"
#include "objdata.h"
#include "objfile.h"
#include "exports.h"
#include "library.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Library data */
static FILE* Lib = 0;
static char* LibName = 0;
static unsigned ModuleCount = 0;
static ObjData** Index = 0;
/*****************************************************************************/
/* Reading file data structures */
/*****************************************************************************/
static void LibReadObjHeader (ObjData* O)
/* Read the header of the object file checking the signature */
{
O->Header.Magic = Read32 (Lib);
if (O->Header.Magic != OBJ_MAGIC) {
Error ("Object file `%s' in library `%s' is invalid", O->Name, LibName);
}
O->Header.Version = Read16 (Lib);
if (O->Header.Version != OBJ_VERSION) {
Error ("Object file `%s' in library `%s' has wrong version",
O->Name, LibName);
}
O->Header.Flags = Read16 (Lib);
O->Header.OptionOffs = Read32 (Lib);
O->Header.OptionSize = Read32 (Lib);
O->Header.FileOffs = Read32 (Lib);
O->Header.FileSize = Read32 (Lib);
O->Header.SegOffs = Read32 (Lib);
O->Header.SegSize = Read32 (Lib);
O->Header.ImportOffs = Read32 (Lib);
O->Header.ImportSize = Read32 (Lib);
O->Header.ExportOffs = Read32 (Lib);
O->Header.ExportSize = Read32 (Lib);
O->Header.DbgSymOffs = Read32 (Lib);
O->Header.DbgSymSize = Read32 (Lib);
}
static ObjData* ReadIndexEntry (void)
/* Read one entry in the index */
{
unsigned I;
/* Create a new entry and insert it into the list */
ObjData* O = NewObjData ();
/* Module name/flags/MTime/Start/Size */
O->Name = ReadMallocedStr (Lib);
O->Flags = Read16 (Lib);
Read32 (Lib); /* Skip MTime */
O->Start = Read32 (Lib);
Read32 (Lib); /* Skip Size */
/* Skip the export size, then read the exports */
Read16 (Lib);
O->ExportCount = Read16 (Lib);
O->Exports = Xmalloc (O->ExportCount * sizeof (Export*));
for (I = 0; I < O->ExportCount; ++I) {
O->Exports [I] = ReadExport (Lib, O);
}
/* Skip the import size, then read the imports */
Read16 (Lib);
O->ImportCount = Read16 (Lib);
O->Imports = Xmalloc (O->ImportCount * sizeof (Import*));
for (I = 0; I < O->ImportCount; ++I) {
O->Imports [I] = ReadImport (Lib, O);
}
/* Done */
return O;
}
static void ReadIndex (void)
/* Read the index of a library file */
{
unsigned I;
/* Read the object file count and allocate memory */
ModuleCount = Read16 (Lib);
Index = Xmalloc (ModuleCount * sizeof (ObjData*));
/* Read all entries in the index */
for (I = 0; I < ModuleCount; ++I) {
Index [I] = ReadIndexEntry ();
}
}
/*****************************************************************************/
/* High level stuff */
/*****************************************************************************/
static void LibCheckExports (ObjData* O)
/* Check if the exports from this file can satisfy any import requests. If so,
* insert the imports and exports from this file and mark the file as added.
*/
{
unsigned I;
/* Check all exports */
for (I = 0; I < O->ExportCount; ++I) {
if (IsUnresolved (O->Exports [I]->Name)) {
/* We need this module */
O->Flags |= OBJ_REF;
break;
}
}
/* If we need this module, insert the imports and exports */
if (O->Flags & OBJ_REF) {
/* Insert the exports */
for (I = 0; I < O->ExportCount; ++I) {
InsertExport (O->Exports [I]);
}
/* Insert the imports */
for (I = 0; I < O->ImportCount; ++I) {
InsertImport (O->Imports [I]);
}
}
}
void LibAdd (FILE* F, const char* Name)
/* Add files from the library to the list if there are references that could
* be satisfied.
*/
{
int Add;
unsigned I;
LibHeader Header;
/* Store the parameters, so they're visible for other routines */
Lib = F;
LibName = StrDup (Name);
/* Read the remaining header fields (magic is already read) */
Header.Magic = LIB_MAGIC;
Header.Version = Read16 (Lib);
if (Header.Version != LIB_VERSION) {
Error ("Wrong data version in `%s'", Name);
}
Header.Flags = Read16 (Lib);
Header.IndexOffs = Read32 (Lib);
/* Seek to the index position and read the index */
fseek (Lib, Header.IndexOffs, SEEK_SET);
ReadIndex ();
/* Walk through all library modules and check for each module if there
* are unresolved externals in existing modules that may be resolved
* by adding the module. Repeat this step until no more object files
* were added.
*/
do {
Add = 0;
for (I = 0; I < ModuleCount; ++I) {
ObjData* O = Index [I];
if ((O->Flags & OBJ_REF) == 0) {
LibCheckExports (O);
if (O->Flags & OBJ_REF) {
/* The routine added the file */
Add = 1;
}
}
}
} while (Add);
/* Add the files list and sections for all requested modules */
for (I = 0; I < ModuleCount; ++I) {
ObjData* O = Index [I];
if (O->Flags & OBJ_REF) {
/* Seek to the start of the object file and read the header */
fseek (Lib, O->Start, SEEK_SET);
LibReadObjHeader (O);
/* Seek to the start of the files list and read the files list */
fseek (Lib, O->Start + O->Header.FileOffs, SEEK_SET);
ObjReadFiles (Lib, O);
/* Seek to the start of the segment list and read the segments */
fseek (Lib, O->Start + O->Header.SegOffs, SEEK_SET);
ObjReadSections (Lib, O);
/* Seek to the start of the debug info and read the debug info */
fseek (Lib, O->Start + O->Header.DbgSymOffs, SEEK_SET);
ObjReadDbgSyms (Lib, O);
/* We have the data now */
O->Flags |= OBJ_HAVEDATA;
}
/* Add a pointer to the library name */
O->LibName = LibName;
}
/* Done. Close the file, release allocated memory */
fclose (F);
Xfree (Index);
Lib = 0;
LibName = 0;
ModuleCount = 0;
Index = 0;
}

59
src/ld65/library.h Normal file
View File

@@ -0,0 +1,59 @@
/*****************************************************************************/
/* */
/* library.h */
/* */
/* Library data structures and helpers for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef LIBRARY_H
#define LIBRARY_H
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void LibAdd (FILE* F, const char* Name);
/* Add files from the library to the list if there are references that could
* be satisfied.
*/
/* End of library.h */
#endif

391
src/ld65/main.c Normal file
View File

@@ -0,0 +1,391 @@
/*****************************************************************************/
/* */
/* main.c */
/* */
/* Main program for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "../common/libdefs.h"
#include "../common/objdefs.h"
#include "../common/version.h"
#include "global.h"
#include "error.h"
#include "mem.h"
#include "target.h"
#include "fileio.h"
#include "scanner.h"
#include "config.h"
#include "objfile.h"
#include "library.h"
#include "exports.h"
#include "segments.h"
#include "mapfile.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
static unsigned ObjFiles = 0; /* Count of object files linked */
static unsigned LibFiles = 0; /* Count of library files linked */
static const char* LibPath = 0; /* Search path for modules */
static unsigned LibPathLen = 0; /* Length of LibPath */
/*****************************************************************************/
/* Code */
/*****************************************************************************/
static void Usage (void)
/* Print usage information and exit */
{
fprintf (stderr,
"Usage: %s [options] module ...\n"
"Options are:\n"
"\t-m name\t\tCreate a map file\n"
"\t-o name\t\tName the default output file\n"
"\t-t type\t\tType of target system\n"
"\t-v\t\tVerbose mode\n"
"\t-vm\t\tVerbose map file\n"
"\t-C name\t\tUse linker config file\n"
"\t-Ln name\tCreate a VICE label file\n"
"\t-Lp\t\tMark write protected segments as such (VICE)\n"
"\t-S addr\t\tSet the default start address\n"
"\t-V\t\tPrint linker version\n",
ProgName);
exit (EXIT_FAILURE);
}
static void UnknownOption (const char* Arg)
/* Print an error about an unknown option. Print usage information and exit */
{
fprintf (stderr, "Unknown option: %s\n", Arg);
Usage ();
}
static void InvNumber (const char* Arg)
/* Print an error about an unknown option. Print usage information and exit */
{
fprintf (stderr, "Invalid number given in argument: %s\n", Arg);
Usage ();
}
static unsigned long CvtNumber (const char* Arg, const char* Number)
/* Convert a number from a string. Allow '$' and '0x' prefixes for hex
* numbers.
*/
{
unsigned long Val;
/* Convert */
if (*Number == '$') {
++Number;
if (sscanf (Number, "%lx", &Val) != 1) {
InvNumber (Arg);
}
} else {
if (sscanf (Number, "%li", (long*)&Val) != 1) {
InvNumber (Arg);
}
}
/* Return the result */
return Val;
}
static const char* GetArg (int* ArgNum, char* argv [], unsigned Len)
/* Get an option argument */
{
const char* Arg = argv [*ArgNum];
if (Arg [Len] != '\0') {
/* Argument appended */
return Arg + Len;
} else {
/* Separate argument */
Arg = argv [*ArgNum + 1];
if (Arg == 0) {
/* End of arguments */
fprintf (stderr, "Option requires an argument: %s\n", argv [*ArgNum]);
exit (EXIT_FAILURE);
}
++(*ArgNum);
return Arg;
}
}
static void LongOption (int* Arg, char* argv [])
/* Handle a long command line option */
{
/* For now ... */
UnknownOption (argv [*Arg]);
}
static int HasPath (const char* Name)
/* Check if the given Name has a path component */
{
return strchr (Name, '/') != 0 || strchr (Name, '\\') != 0;
}
static void LinkFile (const char* Name)
/* Handle one file */
{
unsigned long Magic;
unsigned Len;
char* NewName = 0;
/* Try to open the file */
FILE* F = fopen (Name, "rb");
if (F == 0) {
/* We couldn't open the file. If the name doesn't have a path, and we
* have a search path given, try the name with the search path
* prepended.
*/
if (LibPathLen > 0 && !HasPath (Name)) {
/* Allocate memory. Account for the trailing zero, and for a
* path separator character eventually needed.
*/
Len = LibPathLen;
NewName = Xmalloc (strlen (Name) + Len + 2);
/* Build the new name */
memcpy (NewName, LibPath, Len);
if (NewName [Len-1] != '/' && NewName [Len-1] != '\\') {
/* We need an additional path separator */
NewName [Len++] = '/';
}
strcpy (NewName + Len, Name);
/* Now try to open the new file */
F = fopen (NewName, "rb");
}
if (F == 0) {
Error ("Cannot open `%s': %s", Name, strerror (errno));
}
}
/* Read the magic word */
Magic = Read32 (F);
/* Do we know this type of file? */
switch (Magic) {
case OBJ_MAGIC:
ObjAdd (F, Name);
++ObjFiles;
break;
case LIB_MAGIC:
LibAdd (F, Name);
++LibFiles;
break;
default:
fclose (F);
Error ("File `%s' has unknown type", Name);
}
/* If we have allocated memory, free it here. Note: Memory will not always
* be freed if we run into an error, but that's no problem. Adding more
* code to work around it will use more memory than the chunk that's lost.
*/
Xfree (NewName);
}
int main (int argc, char* argv [])
/* Assembler main program */
{
int I;
/* Evaluate the CC65_LIB environment variable */
LibPath = getenv ("CC65_LIB");
if (LibPath == 0) {
/* Use some default path */
#ifdef CC65_LIB
LibPath = CC65_LIB;
#else
LibPath = "/usr/lib/cc65/lib/";
#endif
}
LibPathLen = strlen (LibPath);
/* Check the parameters */
I = 1;
while (I < argc) {
/* Get the argument */
const char* Arg = argv [I];
/* Check for an option */
if (Arg [0] == '-') {
/* An option */
switch (Arg [1]) {
case '-':
LongOption (&I, argv);
break;
case 'm':
MapFileName = GetArg (&I, argv, 2);
break;
case 'o':
OutputName = GetArg (&I, argv, 2);
break;
case 't':
if (CfgAvail ()) {
Error ("Cannot use -C/-t twice");
}
TgtSet (GetArg (&I, argv, 2));
break;
case 'v':
switch (Arg [2]) {
case 'm': VerboseMap = 1; break;
case '\0': ++Verbose; break;
default: UnknownOption (Arg);
}
break;
case 'C':
if (CfgAvail ()) {
Error ("Cannot use -C/-t twice");
}
CfgSetName (GetArg (&I, argv, 2));
break;
case 'L':
switch (Arg [2]) {
case 'n': LabelFileName = GetArg (&I, argv, 3); break;
case 'p': WProtSegs = 1; break;
default: UnknownOption (Arg);
}
break;
case 'S':
StartAddr = CvtNumber (Arg, GetArg (&I, argv, 2));
break;
case 'V':
fprintf (stderr,
"ld65 V%u.%u.%u - (C) Copyright 1998-2000 Ullrich von Bassewitz\n",
VER_MAJOR, VER_MINOR, VER_PATCH);
break;
default:
UnknownOption (Arg);
break;
}
} else {
/* A filename */
LinkFile (Arg);
}
/* Next argument */
++I;
}
/* Check if we had any object files */
if (ObjFiles == 0) {
fprintf (stderr, "No object files to link\n");
Usage ();
}
/* Check if we have a valid configuration */
if (!CfgAvail ()) {
fprintf (stderr, "Memory configuration missing\n");
Usage ();
}
/* Read the config file */
CfgRead ();
/* Assign start addresses for the segments, define linker symbols */
CfgAssignSegments ();
/* Create the output file */
CfgWriteTarget ();
/* Check for segments not written to the output file */
CheckSegments ();
/* If requested, create a map file and a label file for VICE */
if (MapFileName) {
CreateMapFile ();
}
if (LabelFileName) {
CreateLabelFile ();
}
/* Dump the data for debugging */
if (Verbose > 1) {
SegDump ();
}
/* Return an apropriate exit code */
return EXIT_SUCCESS;
}

66
src/ld65/make/gcc.mak Normal file
View File

@@ -0,0 +1,66 @@
#
# gcc Makefile for ld65
#
# Default for the compiler lib search path as compiler define
CDEFS=-DCC65_LIB=\"/usr/lib/cc65/lib/\"
CFLAGS = -g -O2 -Wall $(CDEFS)
CC=gcc
LDFLAGS=
OBJS = bin.o \
binfmt.o \
config.o \
dbgsyms.o \
error.o \
exports.o \
expr.o \
extsyms.o \
fileio.o \
global.o \
library.o \
main.o \
mapfile.o \
mem.o \
o65.o \
objdata.o \
objfile.o \
scanner.o \
segments.o \
target.o
LIBS = ../common/common.a
EXECS = ld65
.PHONY: all
ifeq (.depend,$(wildcard .depend))
all : $(EXECS)
include .depend
else
all: depend
@$(MAKE) -f make/gcc.mak all
endif
ld65: $(OBJS) $(LIBS)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS)
clean:
rm -f *~ core *.map
zap: clean
rm -f *.o $(EXECS) .depend
# ------------------------------------------------------------------------------
# Make the dependencies
.PHONY: depend dep
depend dep: $(OBJS:.o=.c)
@echo "Creating dependency information"
$(CC) -MM $^ > .depend

136
src/ld65/make/watcom.mak Normal file
View File

@@ -0,0 +1,136 @@
#
# ld65 Makefile for the Watcom compiler
#
# ------------------------------------------------------------------------------
# Generic stuff
.AUTODEPEND
.SUFFIXES .ASM .C .CC .CPP
.SWAP
AR = WLIB
LD = WLINK
!if !$d(TARGET)
!if $d(__OS2__)
TARGET = OS2
!else
TARGET = NT
!endif
!endif
# target specific macros.
!if $(TARGET)==OS2
# --------------------- OS2 ---------------------
SYSTEM = os2v2
CC = WCC386
CCCFG = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
!elif $(TARGET)==DOS32
# -------------------- DOS4G --------------------
SYSTEM = dos4g
CC = WCC386
CCCFG = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
!elif $(TARGET)==DOS
# --------------------- DOS ---------------------
SYSTEM = dos
CC = WCC
CCCFG = -bt=$(TARGET) -d1 -onatx -zp2 -2 -ml -zq -w2
!elif $(TARGET)==NT
# --------------------- NT ----------------------
SYSTEM = nt
CC = WCC386
CCCFG = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
!else
!error
!endif
# ------------------------------------------------------------------------------
# Implicit rules
.c.obj:
$(CC) $(CCCFG) $<
# ------------------------------------------------------------------------------
# All OBJ files
OBJS = bin.obj \
binfmt.obj \
config.obj \
dbgsyms.obj \
error.obj \
exports.obj \
expr.obj \
extsyms.obj \
fileio.obj \
global.obj \
library.obj \
main.obj \
mapfile.obj \
mem.obj \
o65.obj \
objdata.obj \
objfile.obj \
scanner.obj \
segments.obj \
target.obj
LIBS = ..\common\common.lib
# ------------------------------------------------------------------------------
# Main targets
all: ld65
ld65: ld65.exe
# ------------------------------------------------------------------------------
# Other targets
ld65.exe: $(OBJS) $(LIBS)
$(LD) system $(SYSTEM) @&&|
DEBUG ALL
OPTION QUIET
NAME $<
FILE bin.obj
FILE binfmt.obj
FILE config.obj
FILE dbgsyms.obj
FILE error.obj
FILE exports.obj
FILE expr.obj
FILE extsyms.obj
FILE fileio.obj
FILE global.obj
FILE library.obj
FILE main.obj
FILE mapfile.obj
FILE mem.obj
FILE o65.obj
FILE objdata.obj
FILE objfile.obj
FILE scanner.obj
FILE segments.obj
FILE target.obj
LIBRARY ..\common\common.lib
|
clean:
@if exist *.obj del *.obj
@if exist *.obj del ld65.exe
strip:
@-wstrip ld65.exe

170
src/ld65/mapfile.c Normal file
View File

@@ -0,0 +1,170 @@
/*****************************************************************************/
/* */
/* mapfile.c */
/* */
/* Map file creation for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "global.h"
#include "error.h"
#include "objdata.h"
#include "segments.h"
#include "dbgsyms.h"
#include "exports.h"
#include "config.h"
#include "mapfile.h"
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void CreateMapFile (void)
/* Create a map file */
{
ObjData* O;
unsigned I;
/* Open the map file */
FILE* F = fopen (MapFileName, "w");
if (F == 0) {
Error ("Cannot create map file `%s': %s", MapFileName, strerror (errno));
}
/* Write a modules list */
fprintf (F, "Modules list:\n"
"-------------\n");
O = ObjRoot;
while (O) {
if (O->Flags & OBJ_HAVEDATA) {
/* We've linked this module */
if (O->LibName) {
/* The file is from a library */
fprintf (F, "%s(%s):\n", O->LibName, O->Name);
} else {
fprintf (F, "%s:\n", O->Name);
}
for (I = 0; I < O->SectionCount; ++I) {
const Section* S = O->Sections [I];
/* Don't include zero sized sections if not explicitly
* requested
*/
if (VerboseMap || S->Size > 0) {
fprintf (F, " %-15s Offs = %06lX Size = %06lX\n",
S->Seg->Name, S->Offs, S->Size);
}
}
}
O = O->Next;
}
/* Write the segment list */
fprintf (F, "\n\n"
"Segment list:\n"
"-------------\n");
PrintSegmentMap (F);
/* Write the exports list */
fprintf (F, "\n\n"
"Exports list:\n"
"-------------\n");
PrintExportMap (F);
/* Write the imports list */
fprintf (F, "\n\n"
"Imports list:\n"
"-------------\n");
PrintImportMap (F);
/* Close the file */
if (fclose (F) != 0) {
Error ("Error closing map file `%s': %s", MapFileName, strerror (errno));
}
}
void CreateLabelFile (void)
/* Create a label file */
{
ObjData* O;
/* Open the map file */
FILE* F = fopen (LabelFileName, "w");
if (F == 0) {
Error ("Cannot create label file `%s': %s", LabelFileName, strerror (errno));
}
/* Print the labels for the export symbols */
PrintExportLabels (F);
/* Print debug symbols from all modules we have linked into the output file */
O = ObjRoot;
while (O) {
if (O->Flags & OBJ_HAVEDATA) {
/* We've linked this module */
PrintDbgSymLabels (O, F);
}
O = O->Next;
}
/* If we should mark write protected areas as such, do it */
if (WProtSegs) {
SegDesc* S = SegDescList;
while (S) {
/* Is this segment write protected and contains data? */
if (S->Flags & SF_WPROT && S->Seg->Size > 0) {
/* Write protect the memory area in VICE */
fprintf (F, "wp %04lX %04lX\n",
S->Seg->PC,
S->Seg->PC + S->Seg->Size - 1);
}
/* Next segment */
S = S->Next;
}
}
/* Close the file */
if (fclose (F) != 0) {
Error ("Error closing map file `%s': %s", LabelFileName, strerror (errno));
}
}

64
src/ld65/mapfile.h Normal file
View File

@@ -0,0 +1,64 @@
/*****************************************************************************/
/* */
/* mapfile.h */
/* */
/* Map file creation for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef MAPFILE_H
#define MAPFILE_H
#include <stdio.h>
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void CreateMapFile (void);
/* Create a map file */
void CreateLabelFile (void);
/* Create a label file */
/* End of mapfile.h */
#endif

84
src/ld65/mem.c Normal file
View File

@@ -0,0 +1,84 @@
/*****************************************************************************/
/* */
/* mem.c */
/* */
/* Memory allocation for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include "error.h"
#include "mem.h"
/*****************************************************************************/
/* code */
/*****************************************************************************/
void* Xmalloc (size_t size)
/* Allocate memory, check for out of memory condition. Do some debugging */
{
void* p;
p = malloc (size);
if (p == 0 && size != 0) {
Error ("Out of memory");
}
/* Return a pointer to the block */
return p;
}
void Xfree (const void* block)
/* Free the block, do some debugging */
{
free ((void*) block);
}
char* StrDup (const char* s)
/* Duplicate a string on the heap. The function checks for out of memory */
{
unsigned len;
len = strlen (s) + 1;
return memcpy (Xmalloc (len), s, len);
}

67
src/ld65/mem.h Normal file
View File

@@ -0,0 +1,67 @@
/*****************************************************************************/
/* */
/* mem.h */
/* */
/* Memory allocation for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef MEM_H
#define MEM_H
#include <stddef.h>
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void* Xmalloc (size_t size);
/* Allocate memory, check for out of memory condition. Do some debugging */
void Xfree (const void* block);
/* Free the block, do some debugging */
char* StrDup (const char* s);
/* Duplicate a string on the heap. The function checks for out of memory */
/* End of mem.h */
#endif

1067
src/ld65/o65.c Normal file

File diff suppressed because it is too large Load Diff

119
src/ld65/o65.h Normal file
View File

@@ -0,0 +1,119 @@
/*****************************************************************************/
/* */
/* o65.h */
/* */
/* Module to handle the o65 binary format */
/* */
/* */
/* */
/* (C) 1999 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef O65_H
#define O65_H
#include <stdio.h>
#include "extsyms.h"
#include "config.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Structure describing the format */
typedef struct O65Desc_ O65Desc;
/* Option tags */
#define O65OPT_FILENAME 0
#define O65OPT_OS 1
#define O65OPT_ASM 2
#define O65OPT_AUTHOR 3
#define O65OPT_TIMESTAMP 4
/* Operating system codes for O65OPT_OS */
#define O65OS_OSA65 1
#define O65OS_LUNIX 2
/*****************************************************************************/
/* Code */
/*****************************************************************************/
O65Desc* NewO65Desc (void);
/* Create, initialize and return a new O65 descriptor struct */
void FreeO65Desc (O65Desc* D);
/* Delete the descriptor struct with cleanup */
void O65Set816 (O65Desc* D);
/* Enable 816 mode */
void O65SetLargeModel (O65Desc* D);
/* Enable a large memory model executable */
void O65SetAlignment (O65Desc* D, unsigned Align);
/* Set the executable alignment */
void O65SetOption (O65Desc* D, unsigned Type, const void* Data, unsigned DataLen);
/* Set an o65 header option */
void O65SetOS (O65Desc* D, unsigned OS);
/* Set an option describing the target operating system */
ExtSym* O65GetImport (O65Desc* D, const char* Ident);
/* Return the imported symbol or NULL if not found */
void O65SetImport (O65Desc* D, const char* Ident);
/* Set an imported identifier */
ExtSym* O65GetExport (O65Desc* D, const char* Ident);
/* Return the exported symbol or NULL if not found */
void O65SetExport (O65Desc* D, const char* Ident);
/* Set an exported identifier */
void O65WriteTarget (O65Desc* D, File* F);
/* Write an o65 output file */
/* End of o65.h */
#endif

112
src/ld65/objdata.c Normal file
View File

@@ -0,0 +1,112 @@
/*****************************************************************************/
/* */
/* objdata.c */
/* */
/* Handling object file data for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include <string.h>
#include "mem.h"
#include "error.h"
#include "objdata.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Object data list management */
unsigned ObjCount = 0; /* Count of object files in the list */
ObjData* ObjRoot = 0; /* List of object files */
ObjData* ObjLast = 0; /* Last entry in list */
ObjData** ObjPool = 0; /* Object files as array */
/*****************************************************************************/
/* Code */
/*****************************************************************************/
ObjData* NewObjData (void)
/* Allocate a new structure on the heap, insert it into the list, return it */
{
/* Allocate memory */
ObjData* O = Xmalloc (sizeof (ObjData));
/* Initialize the data */
O->Next = 0;
O->Name = 0;
O->LibName = 0;
O->Flags = 0;
O->Start = 0;
O->ExportCount = 0;
O->Exports = 0;
O->ImportCount = 0;
O->Imports = 0;
O->DbgSymCount = 0;
O->DbgSyms = 0;
/* Link it into the list */
if (ObjLast) {
ObjLast->Next = O;
ObjLast = O;
} else {
/* First entry */
ObjRoot = ObjLast = O;
}
/* One object file more now */
++ObjCount;
/* Return the new entry */
return O;
}
void FreeObjData (ObjData* O)
/* Free a complete struct */
{
Xfree (O->Name);
Xfree (O->Imports);
Xfree (O->Exports);
Xfree (O->DbgSyms);
Xfree (O);
}

106
src/ld65/objdata.h Normal file
View File

@@ -0,0 +1,106 @@
/*****************************************************************************/
/* */
/* objdata.h */
/* */
/* Handling object file data for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef OBJDATA_H
#define OBJDATA_H
#include "../common/objdefs.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Values for the Flags field */
#define OBJ_REF 0x0001 /* We have a reference to this file */
#define OBJ_HAVEDATA 0x0002 /* We have this object file already */
#define OBJ_MARKED 0x0004 /* Generic marker bit */
/* Internal structure holding object file data */
typedef struct ObjData_ ObjData;
struct ObjData_ {
ObjData* Next; /* Linked list of all objects */
char* Name; /* Module name */
char* LibName; /* Name of library */
ObjHeader Header; /* Header of file */
unsigned long Start; /* Start offset of data in library */
unsigned Flags;
unsigned FileCount; /* Input file count */
char** Files; /* List of input files */
unsigned SectionCount; /* Count of sections in this object */
struct Section_** Sections; /* List of all sections */
unsigned ExportCount; /* Count of exports */
struct Export_** Exports; /* List of all exports */
unsigned ImportCount; /* Count of imports */
struct Import_** Imports; /* List of all imports */
unsigned DbgSymCount; /* Count of debug symbols */
struct DbgSym_** DbgSyms; /* List of debug symbols */
};
/* Object data list management */
extern unsigned ObjCount; /* Count of files in the list */
extern ObjData* ObjRoot; /* List of object files */
extern ObjData* ObjLast; /* Last entry in list */
/*****************************************************************************/
/* Code */
/*****************************************************************************/
ObjData* NewObjData (void);
/* Allocate a new structure on the heap, insert it into the list, return it */
void FreeObjData (ObjData* O);
/* Free a complete struct */
/* End of objdata.h */
#endif

225
src/ld65/objfile.c Normal file
View File

@@ -0,0 +1,225 @@
/*****************************************************************************/
/* */
/* objfile.c */
/* */
/* Object file handling for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/stat.h>
#include "error.h"
#include "mem.h"
#include "objdata.h"
#include "fileio.h"
#include "segments.h"
#include "exports.h"
#include "dbgsyms.h"
#include "objfile.h"
/*****************************************************************************/
/* Code */
/*****************************************************************************/
static const char* GetModule (const char* Name)
/* Get a module name from the file name */
{
/* Make a module name from the file name */
const char* Module = Name + strlen (Name);
while (Module > Name) {
--Module;
if (*Module == '/' || *Module == '\\') {
++Module;
break;
}
}
if (*Module == 0) {
Error ("Cannot make module name from `%s'", Name);
}
return Module;
}
static void ObjReadHeader (FILE* Obj, ObjHeader* H, const char* Name)
/* Read the header of the object file checking the signature */
{
H->Version = Read16 (Obj);
if (H->Version != OBJ_VERSION) {
Error ("Object file `%s' has wrong version", Name);
}
H->Flags = Read16 (Obj);
H->OptionOffs = Read32 (Obj);
H->OptionSize = Read32 (Obj);
H->FileOffs = Read32 (Obj);
H->FileSize = Read32 (Obj);
H->SegOffs = Read32 (Obj);
H->SegSize = Read32 (Obj);
H->ImportOffs = Read32 (Obj);
H->ImportSize = Read32 (Obj);
H->ExportOffs = Read32 (Obj);
H->ExportSize = Read32 (Obj);
H->DbgSymOffs = Read32 (Obj);
H->DbgSymSize = Read32 (Obj);
}
void ObjReadFiles (FILE* F, ObjData* O)
/* Read the files list from a file at the current position */
{
unsigned I;
O->FileCount = Read8 (F);
O->Files = Xmalloc (O->FileCount * sizeof (char*));
for (I = 0; I < O->FileCount; ++I) {
/* Skip MTime and size */
Read32 (F);
Read32 (F);
/* Read the filename */
O->Files [I] = ReadMallocedStr (F);
}
}
void ObjReadImports (FILE* F, ObjData* O)
/* Read the imports from a file at the current position */
{
unsigned I;
O->ImportCount = Read16 (F);
O->Imports = Xmalloc (O->ImportCount * sizeof (Import*));
for (I = 0; I < O->ImportCount; ++I) {
O->Imports [I] = ReadImport (F, O);
InsertImport (O->Imports [I]);
}
}
void ObjReadExports (FILE* F, ObjData* O)
/* Read the exports from a file at the current position */
{
unsigned I;
O->ExportCount = Read16 (F);
O->Exports = Xmalloc (O->ExportCount * sizeof (Export*));
for (I = 0; I < O->ExportCount; ++I) {
O->Exports [I] = ReadExport (F, O);
InsertExport (O->Exports [I]);
}
}
void ObjReadDbgSyms (FILE* F, ObjData* O)
/* Read the debug symbols from a file at the current position */
{
unsigned I;
O->DbgSymCount = Read16 (F);
O->DbgSyms = Xmalloc (O->DbgSymCount * sizeof (DbgSym*));
for (I = 0; I < O->DbgSymCount; ++I) {
O->DbgSyms [I] = ReadDbgSym (F, O);
}
}
void ObjReadSections (FILE* F, ObjData* O)
/* Read the section data from a file at the current position */
{
unsigned I;
O->SectionCount = Read8 (F);
O->Sections = Xmalloc (O->SectionCount * sizeof (Section*));
for (I = 0; I < O->SectionCount; ++I) {
O->Sections [I] = ReadSection (F, O);
}
}
void ObjAdd (FILE* Obj, const char* Name)
/* Add an object file to the module list */
{
/* Create a new structure for the object file data */
ObjData* O = NewObjData ();
/* The magic was already read and checked, so set it in the header */
O->Header.Magic = OBJ_MAGIC;
/* Read and check the header */
ObjReadHeader (Obj, &O->Header, Name);
/* Initialize the object module data structure */
O->Name = StrDup (GetModule (Name));
O->Flags = OBJ_HAVEDATA;
/* Read the files list from the object file */
fseek (Obj, O->Header.FileOffs, SEEK_SET);
ObjReadFiles (Obj, O);
/* Read the imports list from the object file */
fseek (Obj, O->Header.ImportOffs, SEEK_SET);
ObjReadImports (Obj, O);
/* Read the object file exports and insert them into the exports list */
fseek (Obj, O->Header.ExportOffs, SEEK_SET);
ObjReadExports (Obj, O);
/* Read the object debug symbols from the object file */
fseek (Obj, O->Header.DbgSymOffs, SEEK_SET);
ObjReadDbgSyms (Obj, O);
/* Read the segment list from the object file. This must be last, since
* the expressions stored in the code may reference segments or imported
* symbols.
*/
fseek (Obj, O->Header.SegOffs, SEEK_SET);
ObjReadSections (Obj, O);
/* Mark this object file as needed */
O->Flags |= OBJ_REF | OBJ_HAVEDATA;
/* Done, close the file (we read it only, so no error check) */
fclose (Obj);
}

80
src/ld65/objfile.h Normal file
View File

@@ -0,0 +1,80 @@
/*****************************************************************************/
/* */
/* objfile.h */
/* */
/* Object file handling for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef OBJFILE_H
#define OBJFILE_H
#include <stdio.h>
#include "../common/objdefs.h"
#include "objdata.h"
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void ObjReadFiles (FILE* F, ObjData* O);
/* Read the files list from a file at the current position */
void ObjReadImports (FILE* F, ObjData* O);
/* Read the imports from a file at the current position */
void ObjReadExports (FILE* F, ObjData* O);
/* Read the exports from a file at the current position */
void ObjReadDbgSyms (FILE* F, ObjData* O);
/* Read the debug symbols from a file at the current position */
void ObjReadSections (FILE* F, ObjData* O);
/* Read the section data from a file at the current position */
void ObjAdd (FILE* F, const char* Name);
/* Add an object file to the module list */
/* End of objfile.h */
#endif

535
src/ld65/scanner.c Normal file
View File

@@ -0,0 +1,535 @@
/*****************************************************************************/
/* */
/* scanner.c */
/* */
/* Configuration file scanner for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998-2000 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include "global.h"
#include "error.h"
#include "scanner.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Current token and attributes */
unsigned CfgTok;
char CfgSVal [CFG_MAX_IDENT_LEN+1];
unsigned long CfgIVal;
/* Error location */
unsigned CfgErrorLine;
unsigned CfgErrorCol;
/* Input sources for the configuration */
static const char* CfgName = 0;
static const char* CfgBuf = 0;
/* Other input stuff */
static int C = ' ';
static unsigned InputLine = 1;
static unsigned InputCol = 0;
static FILE* InputFile = 0;
/*****************************************************************************/
/* Error handling */
/*****************************************************************************/
void CfgWarning (const char* Format, ...)
/* Print a warning message adding file name and line number of the config file */
{
char Buf [512];
va_list ap;
va_start (ap, Format);
#ifdef __WATCOMC__
_vbprintf (Buf, sizeof (Buf), Format, ap);
#else
vsnprintf (Buf, sizeof (Buf), Format, ap);
#endif
Warning ("%s(%u): %s", CfgName, CfgErrorLine, Buf);
}
void CfgError (const char* Format, ...)
/* Print an error message adding file name and line number of the config file */
{
char Buf [512];
va_list ap;
va_start (ap, Format);
#ifdef __WATCOMC__
_vbprintf (Buf, sizeof (Buf), Format, ap);
#else
vsnprintf (Buf, sizeof (Buf), Format, ap);
#endif
Error ("%s(%u): %s", CfgName, CfgErrorLine, Buf);
}
/*****************************************************************************/
/* Code */
/*****************************************************************************/
static void NextChar (void)
/* Read the next character from the input file */
{
if (CfgBuf) {
/* Read from buffer */
C = (unsigned char)(*CfgBuf);
if (C == 0) {
C = EOF;
} else {
++CfgBuf;
}
} else {
/* Read from the file */
C = getc (InputFile);
}
/* Count columns */
if (C != EOF) {
++InputCol;
}
/* Count lines */
if (C == '\n') {
++InputLine;
InputCol = 0;
}
}
static unsigned DigitVal (int C)
/* Return the value for a numeric digit */
{
if (isdigit (C)) {
return C - '0';
} else {
return toupper (C) - 'A' + 10;
}
}
void CfgNextTok (void)
/* Read the next token from the input stream */
{
unsigned I;
Again:
/* Skip whitespace */
while (isspace (C)) {
NextChar ();
}
/* Remember the current position */
CfgErrorLine = InputLine;
CfgErrorCol = InputCol;
/* Identifier? */
if (C == '_' || isalpha (C)) {
/* Read the identifier */
I = 0;
while (C == '_' || isalnum (C)) {
if (I < CFG_MAX_IDENT_LEN) {
CfgSVal [I++] = C;
}
NextChar ();
}
CfgSVal [I] = '\0';
CfgTok = CFGTOK_IDENT;
return;
}
/* Hex number? */
if (C == '$') {
NextChar ();
if (!isxdigit (C)) {
Error ("%s(%u): Hex digit expected", CfgName, InputLine);
}
CfgIVal = 0;
while (isxdigit (C)) {
CfgIVal = CfgIVal * 16 + DigitVal (C);
NextChar ();
}
CfgTok = CFGTOK_INTCON;
return;
}
/* Decimal number? */
if (isdigit (C)) {
CfgIVal = 0;
while (isdigit (C)) {
CfgIVal = CfgIVal * 10 + DigitVal (C);
NextChar ();
}
CfgTok = CFGTOK_INTCON;
return;
}
/* Other characters */
switch (C) {
case '{':
NextChar ();
CfgTok = CFGTOK_LCURLY;
break;
case '}':
NextChar ();
CfgTok = CFGTOK_RCURLY;
break;
case ';':
NextChar ();
CfgTok = CFGTOK_SEMI;
break;
case '.':
NextChar ();
CfgTok = CFGTOK_DOT;
break;
case ',':
NextChar ();
CfgTok = CFGTOK_COMMA;
break;
case '=':
NextChar ();
CfgTok = CFGTOK_EQ;
break;
case ':':
NextChar ();
CfgTok = CFGTOK_COLON;
break;
case '\"':
NextChar ();
I = 0;
while (C != '\"') {
if (C == EOF || C == '\n') {
Error ("%s(%u): Unterminated string", CfgName, InputLine);
}
if (I < CFG_MAX_IDENT_LEN) {
CfgSVal [I++] = C;
}
NextChar ();
}
NextChar ();
CfgSVal [I] = '\0';
CfgTok = CFGTOK_STRCON;
break;
case '#':
/* Comment */
while (C != '\n' && C != EOF) {
NextChar ();
}
if (C != EOF) {
goto Again;
}
CfgTok = CFGTOK_EOF;
break;
case '%':
NextChar ();
switch (C) {
case 'O':
NextChar ();
if (OutputName) {
strncpy (CfgSVal, OutputName, CFG_MAX_IDENT_LEN);
CfgSVal [CFG_MAX_IDENT_LEN] = '\0';
} else {
CfgSVal [0] = '\0';
}
CfgTok = CFGTOK_STRCON;
break;
case 'S':
NextChar ();
CfgIVal = StartAddr;
CfgTok = CFGTOK_INTCON;
break;
default:
CfgError ("Invalid format specification");
}
break;
case EOF:
CfgTok = CFGTOK_EOF;
break;
default:
Error ("%s(%u): Invalid character `%c'", CfgName, InputLine, C);
}
}
void CfgConsume (unsigned T, const char* Msg)
/* Skip a token, print an error message if not found */
{
if (CfgTok != T) {
CfgError (Msg);
}
CfgNextTok ();
}
void CfgConsumeSemi (void)
/* Consume a semicolon */
{
CfgConsume (CFGTOK_SEMI, "`;' expected");
}
void CfgConsumeColon (void)
/* Consume a colon */
{
CfgConsume (CFGTOK_COLON, "`:' expected");
}
void CfgOptionalComma (void)
/* Consume a comma if there is one */
{
if (CfgTok == CFGTOK_COMMA) {
CfgNextTok ();
}
}
void CfgOptionalAssign (void)
/* Consume an equal sign if there is one */
{
if (CfgTok == CFGTOK_EQ) {
CfgNextTok ();
}
}
void CfgAssureInt (void)
/* Make sure the next token is an integer */
{
if (CfgTok != CFGTOK_INTCON) {
CfgError ("Integer constant expected");
}
}
void CfgAssureStr (void)
/* Make sure the next token is a string constant */
{
if (CfgTok != CFGTOK_STRCON) {
CfgError ("String constant expected");
}
}
void CfgAssureIdent (void)
/* Make sure the next token is an identifier */
{
if (CfgTok != CFGTOK_IDENT) {
CfgError ("Identifier expected");
}
}
void CfgRangeCheck (unsigned long Lo, unsigned long Hi)
/* Check the range of CfgIVal */
{
if (CfgIVal < Lo || CfgIVal > Hi) {
CfgError ("Range error");
}
}
void CfgSpecialToken (const IdentTok* Table, unsigned Size, const char* Name)
/* Map an identifier to one of the special tokens in the table */
{
unsigned I;
/* We need an identifier */
if (CfgTok == CFGTOK_IDENT) {
/* Make it upper case */
I = 0;
while (CfgSVal [I]) {
CfgSVal [I] = toupper (CfgSVal [I]);
++I;
}
/* Linear search */
for (I = 0; I < Size; ++I) {
if (strcmp (CfgSVal, Table [I].Ident) == 0) {
CfgTok = Table [I].Tok;
return;
}
}
}
/* Not found or no identifier */
Error ("%s(%u): %s expected", CfgName, InputLine, Name);
}
void CfgBoolToken (void)
/* Map an identifier or integer to a boolean token */
{
static const IdentTok Booleans [] = {
{ "YES", CFGTOK_TRUE },
{ "NO", CFGTOK_FALSE },
{ "TRUE", CFGTOK_TRUE },
{ "FALSE", CFGTOK_FALSE },
};
/* If we have an identifier, map it to a boolean token */
if (CfgTok == CFGTOK_IDENT) {
CfgSpecialToken (Booleans, ENTRY_COUNT (Booleans), "Boolean");
} else {
/* We expected an integer here */
if (CfgTok != CFGTOK_INTCON) {
CfgError ("Boolean value expected");
}
CfgTok = (CfgIVal == 0)? CFGTOK_FALSE : CFGTOK_TRUE;
}
}
void CfgSetName (const char* Name)
/* Set a name for a config file */
{
CfgName = Name;
}
const char* CfgGetName (void)
/* Get the name of the config file */
{
return CfgName? CfgName : "";
}
void CfgSetBuf (const char* Buf)
/* Set a memory buffer for the config */
{
CfgBuf = Buf;
}
int CfgAvail (void)
/* Return true if we have a configuration available */
{
return CfgName != 0 || CfgBuf != 0;
}
void CfgOpenInput (void)
/* Open the input file if we have one */
{
/* If we have a config name given, open the file, otherwise we will read
* from a buffer.
*/
if (!CfgBuf) {
/* Open the file */
InputFile = fopen (CfgName, "r");
if (InputFile == 0) {
Error ("Cannot open `%s': %s", CfgName, strerror (errno));
}
}
/* Initialize variables */
C = ' ';
InputLine = 1;
InputCol = 0;
/* Start the ball rolling ... */
CfgNextTok ();
}
void CfgCloseInput (void)
/* Close the input file if we have one */
{
/* Close the input file if we had one */
if (InputFile) {
(void) fclose (InputFile);
InputFile = 0;
}
}

198
src/ld65/scanner.h Normal file
View File

@@ -0,0 +1,198 @@
/*****************************************************************************/
/* */
/* scanner.h */
/* */
/* Configuration file scanner for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef SCANNER_H
#define SCANNER_H
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Config file tokens */
#define CFGTOK_NONE 0
#define CFGTOK_INTCON 1
#define CFGTOK_STRCON 2
#define CFGTOK_IDENT 3
#define CFGTOK_LCURLY 4
#define CFGTOK_RCURLY 5
#define CFGTOK_SEMI 6
#define CFGTOK_COMMA 7
#define CFGTOK_EQ 8
#define CFGTOK_COLON 9
#define CFGTOK_DOT 10
#define CFGTOK_EOF 11
/* Special identifiers */
#define CFGTOK_MEMORY 20
#define CFGTOK_FILES 21
#define CFGTOK_SEGMENTS 22
#define CFGTOK_FORMATS 23
#define CFGTOK_START 30
#define CFGTOK_SIZE 31
#define CFGTOK_TYPE 32
#define CFGTOK_FILE 33
#define CFGTOK_DEFINE 34
#define CFGTOK_FILL 35
#define CFGTOK_FILLVAL 36
#define CFGTOK_EXPORT 37
#define CFGTOK_IMPORT 38
#define CFGTOK_OS 39
#define CFGTOK_FORMAT 40
#define CFGTOK_LOAD 50
#define CFGTOK_RUN 51
#define CFGTOK_ALIGN 52
#define CFGTOK_OFFSET 53
#define CFGTOK_RO 60
#define CFGTOK_RW 61
#define CFGTOK_BSS 62
#define CFGTOK_ZP 63
#define CFGTOK_WPROT 64
#define CFGTOK_O65 70
#define CFGTOK_BIN 71
#define CFGTOK_SMALL 80
#define CFGTOK_LARGE 81
#define CFGTOK_TRUE 90
#define CFGTOK_FALSE 91
#define CFGTOK_LUNIX 100
#define CFGTOK_OSA65 101
/* Mapping table entry, special identifier --> token */
typedef struct IdentTok_ IdentTok;
struct IdentTok_ {
const char* Ident; /* Identifier */
unsigned Tok; /* Token for identifier */
};
#define ENTRY_COUNT(s) (sizeof (s) / sizeof (s [0]))
/* Current token and attributes */
#define CFG_MAX_IDENT_LEN 255
extern unsigned CfgTok;
extern char CfgSVal [CFG_MAX_IDENT_LEN+1];
extern unsigned long CfgIVal;
/* Error location */
extern unsigned CfgErrorLine;
extern unsigned CfgErrorCol;
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void CfgWarning (const char* Format, ...);
/* Print a warning message adding file name and line number of the config file */
void CfgError (const char* Format, ...);
/* Print an error message adding file name and line number of the config file */
void CfgNextTok (void);
/* Read the next token from the input stream */
void CfgConsume (unsigned T, const char* Msg);
/* Skip a token, print an error message if not found */
void CfgConsumeSemi (void);
/* Consume a semicolon */
void CfgConsumeColon (void);
/* Consume a colon */
void CfgOptionalComma (void);
/* Consume a comma if there is one */
void CfgOptionalAssign (void);
/* Consume an equal sign if there is one */
void CfgAssureInt (void);
/* Make sure the next token is an integer */
void CfgAssureStr (void);
/* Make sure the next token is a string constant */
void CfgAssureIdent (void);
/* Make sure the next token is an identifier */
void CfgRangeCheck (unsigned long Lo, unsigned long Hi);
/* Check the range of CfgIVal */
void CfgSpecialToken (const IdentTok* Table, unsigned Size, const char* Name);
/* Map an identifier to one of the special tokens in the table */
void CfgBoolToken (void);
/* Map an identifier or integer to a boolean token */
void CfgSetName (const char* Name);
/* Set a name for a config file */
const char* CfgGetName (void);
/* Get the name of the config file */
void CfgSetBuf (const char* Buf);
/* Set a memory buffer for the config */
int CfgAvail (void);
/* Return true if we have a configuration available */
void CfgOpenInput (void);
/* Open the input file if we have one */
void CfgCloseInput (void);
/* Close the input file if we have one */
/* End of scanner.h */
#endif

666
src/ld65/segments.c Normal file
View File

@@ -0,0 +1,666 @@
/*****************************************************************************/
/* */
/* segments.c */
/* */
/* Segment handling for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998-2000 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include "../common/exprdefs.h"
#include "../common/symdefs.h"
#include "../common/segdefs.h"
#include "../common/hashstr.h"
#include "mem.h"
#include "global.h"
#include "error.h"
#include "fileio.h"
#include "expr.h"
#include "segments.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Fragment structure */
typedef struct Fragment_ Fragment;
struct Fragment_ {
Fragment* Next; /* Next fragment in list */
ObjData* Obj; /* Source of fragment */
unsigned long Size; /* Size of data/expression */
ExprNode* Expr; /* Expression if FRAG_EXPR */
FilePos Pos; /* File position in source */
unsigned char Type; /* Type of fragment */
unsigned char LitBuf [1]; /* Dynamically alloc'ed literal buffer */
};
/* Hash table */
#define HASHTAB_SIZE 253
static Segment* HashTab [HASHTAB_SIZE];
static unsigned SegCount = 0; /* Segment count */
static Segment* SegRoot = 0; /* List of all segments */
/*****************************************************************************/
/* Code */
/*****************************************************************************/
static Fragment* NewFragment (unsigned char Type, unsigned long Size, Section* S)
/* Create a new fragment and insert it into the segment S */
{
/* Allocate memory */
Fragment* F = Xmalloc (sizeof (Fragment) - 1 + Size); /* Portable? */
/* Initialize the data */
F->Next = 0;
F->Obj = 0;
F->Size = Size;
F->Expr = 0;
F->Type = Type;
/* Insert the code fragment into the segment */
if (S->FragRoot == 0) {
/* First fragment */
S->FragRoot = F;
} else {
S->FragLast->Next = F;
}
S->FragLast = F;
S->Size += Size;
/* Return the new fragment */
return F;
}
static Segment* NewSegment (const char* Name, unsigned char Type)
/* Create a new segment and initialize it */
{
/* Get the length of the symbol name */
unsigned Len = strlen (Name);
/* Allocate memory */
Segment* S = Xmalloc (sizeof (Segment) + Len);
/* Initialize the fields */
S->Next = 0;
S->SecRoot = 0;
S->SecLast = 0;
S->PC = 0;
S->Size = 0;
S->AlignObj = 0;
S->Align = 0;
S->FillVal = 0;
S->Type = Type;
S->Dumped = 0;
memcpy (S->Name, Name, Len);
S->Name [Len] = '\0';
/* Insert the segment into the segment list */
S->List = SegRoot;
SegRoot = S;
++SegCount;
/* Return the new entry */
return S;
}
static Section* NewSection (Segment* Seg, unsigned char Align, unsigned char Type)
/* Create a new section for the given segment */
{
unsigned long V;
/* Allocate memory */
Section* S = Xmalloc (sizeof (Segment));
/* Initialize the data */
S->Next = 0;
S->Seg = Seg;
S->FragRoot = 0;
S->FragLast = 0;
S->Size = 0;
S->Align = Align;
S->Type = Type;
/* Calculate the alignment bytes needed for the section */
V = (0x01UL << S->Align) - 1;
S->Fill = ((Seg->Size + V) & ~V) - Seg->Size;
/* Adjust the segment size and set the section offset */
Seg->Size += S->Fill;
S->Offs = Seg->Size; /* Current size is offset */
/* Insert the section into the segment */
if (Seg->SecRoot == 0) {
/* First section in this segment */
Seg->SecRoot = S;
} else {
Seg->SecLast->Next = S;
}
Seg->SecLast = S;
/* Return the struct */
return S;
}
static Segment* SegFindInternal (const char* Name, unsigned HashVal)
/* Try to find the segment with the given name, return a pointer to the
* segment structure, or 0 if not found.
*/
{
Segment* S = HashTab [HashVal];
while (S) {
if (strcmp (Name, S->Name) == 0) {
/* Found */
break;
}
S = S->Next;
}
/* Not found */
return S;
}
Section* ReadSection (FILE* F, ObjData* O)
/* Read a section from a file */
{
unsigned HashVal;
char Name [256];
unsigned long Size;
unsigned char Align;
unsigned char Type;
Segment* S;
Section* Sec;
/* Read the name */
ReadStr (F, Name);
/* Read the size */
Size = Read32 (F);
/* Read the alignment */
Align = Read8 (F);
/* Read the segment type */
Type = Read8 (F);
/* Print some data */
if (Verbose > 1) {
printf ("Module `%s': Found segment `%s', size = %lu, align = %u, type = %u\n",
O->Name, Name, Size, Align, Type);
}
/* Create a hash over the name and try to locate the segment in the table */
HashVal = HashStr (Name) % HASHTAB_SIZE;
S = SegFindInternal (Name, HashVal);
/* If we don't have that segment already, allocate it using the type of
* the first section.
*/
if (S == 0) {
/* Create a new segment and insert it */
S = NewSegment (Name, Type);
S->Next = HashTab [HashVal];
HashTab [HashVal] = S;
}
/* Allocate the section we will return later */
Sec = NewSection (S, Align, Type);
/* Check if the section has the same type as the segment */
if (Sec->Type != S->Type) {
/* OOPS */
Error ("Module `%s': Type mismatch for segment `%s'", O->Name, S->Name);
}
/* Set up the minimum segment alignment */
if (Sec->Align > S->Align) {
/* Section needs larger alignment, use this one */
S->Align = Sec->Align;
S->AlignObj = O;
}
/* Start reading fragments from the file and insert them into the section . */
while (Size) {
Fragment* Frag;
/* Read the fragment type */
unsigned char Type = Read8 (F);
/* Handle the different fragment types */
switch (Type) {
case FRAG_LITERAL8:
Frag = NewFragment (FRAG_LITERAL, Read8 (F), Sec);
break;
case FRAG_LITERAL16:
Frag = NewFragment (FRAG_LITERAL, Read16 (F), Sec);
break;
case FRAG_LITERAL24:
Frag = NewFragment (FRAG_LITERAL, Read24 (F), Sec);
break;
case FRAG_LITERAL32:
Frag = NewFragment (FRAG_LITERAL, Read32 (F), Sec);
break;
case FRAG_EXPR8:
case FRAG_EXPR16:
case FRAG_EXPR24:
case FRAG_EXPR32:
case FRAG_SEXPR8:
case FRAG_SEXPR16:
case FRAG_SEXPR24:
case FRAG_SEXPR32:
Frag = NewFragment (Type & FRAG_TYPEMASK, Type & FRAG_BYTEMASK, Sec);
break;
case FRAG_FILL:
/* Will allocate memory, but we don't care... */
Frag = NewFragment (FRAG_FILL, Read16 (F), Sec);
break;
default:
Error ("Unknown fragment type in module `%s', segment `%s': %02X",
O->Name, S->Name, Type);
/* NOTREACHED */
return 0;
}
/* Now read the fragment data */
switch (Frag->Type) {
case FRAG_LITERAL:
/* Literal data */
ReadData (F, Frag->LitBuf, Frag->Size);
break;
case FRAG_EXPR:
case FRAG_SEXPR:
/* An expression */
Frag->Expr = ReadExpr (F, O);
break;
}
/* Read the file position of the fragment */
ReadFilePos (F, &Frag->Pos);
/* Remember the module we had this fragment from */
Frag->Obj = O;
/* Next one */
CHECK (Size >= Frag->Size);
Size -= Frag->Size;
}
/* Increment the segment size by the section size */
S->Size += Sec->Size;
/* Return the section */
return Sec;
}
Segment* SegFind (const char* Name)
/* Return the given segment or NULL if not found. */
{
return SegFindInternal (Name, HashStr (Name) % HASHTAB_SIZE);
}
int IsBSSType (Segment* S)
/* Check if the given segment is a BSS style segment, that is, it does not
* contain non-zero data.
*/
{
/* Loop over all sections */
Section* Sec = S->SecRoot;
while (Sec) {
/* Loop over all fragments */
Fragment* F = Sec->FragRoot;
while (F) {
if (F->Type == FRAG_LITERAL) {
unsigned char* Data = F->LitBuf;
unsigned long Count = F->Size;
while (Count--) {
if (*Data++ != 0) {
return 0;
}
}
} else if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
if (GetExprVal (F->Expr) != 0) {
return 0;
}
}
F = F->Next;
}
Sec = Sec->Next;
}
return 1;
}
void SegDump (void)
/* Dump the segments and it's contents */
{
unsigned I;
unsigned long Count;
unsigned char* Data;
Segment* Seg = SegRoot;
while (Seg) {
Section* S = Seg->SecRoot;
printf ("Segment: %s (%lu)\n", Seg->Name, Seg->Size);
while (S) {
Fragment* F = S->FragRoot;
printf (" Section:\n");
while (F) {
switch (F->Type) {
case FRAG_LITERAL:
printf (" Literal (%lu bytes):", F->Size);
Count = F->Size;
Data = F->LitBuf;
I = 100;
while (Count--) {
if (I > 75) {
printf ("\n ");
I = 3;
}
printf (" %02X", *Data++);
I += 3;
}
printf ("\n");
break;
case FRAG_EXPR:
printf (" Expression (%lu bytes):\n", F->Size);
printf (" ");
DumpExpr (F->Expr);
break;
case FRAG_SEXPR:
printf (" Signed expression (%lu bytes):\n", F->Size);
printf (" ");
DumpExpr (F->Expr);
break;
case FRAG_FILL:
printf (" Empty space (%lu bytes)\n", F->Size);
break;
default:
Internal ("Invalid fragment type: %02X", F->Type);
}
F = F->Next;
}
S = S->Next;
}
Seg = Seg->List;
}
}
unsigned SegWriteConstExpr (FILE* F, ExprNode* E, int Signed, unsigned Size)
/* Write a supposedly constant expression to the target file. Do a range
* check and return one of the SEG_EXPR_xxx codes.
*/
{
static const unsigned long U_HighRange [4] = {
0x000000FF, 0x0000FFFF, 0x00FFFFFF, 0xFFFFFFFF
};
static const long S_HighRange [4] = {
0x0000007F, 0x00007FFF, 0x007FFFFF, 0x7FFFFFFF
};
static const long S_LowRange [4] = {
0xFFFFFF80, 0xFFFF8000, 0xFF800000, 0x80000000
};
/* Get the expression value */
long Val = GetExprVal (E);
/* Check the size */
CHECK (Size >= 1 && Size <= 4);
/* Check for a range error */
if (Signed) {
if (Val > S_HighRange [Size-1] || Val < S_LowRange [Size-1]) {
/* Range error */
return SEG_EXPR_RANGE_ERROR;
}
} else {
if (((unsigned long)Val) > U_HighRange [Size-1]) {
/* Range error */
return SEG_EXPR_RANGE_ERROR;
}
}
/* Write the value to the file */
WriteVal (F, Val, Size);
/* Success */
return SEG_EXPR_OK;
}
void SegWrite (FILE* Tgt, Segment* S, SegWriteFunc F, void* Data)
/* Write the data from the given segment to a file. For expressions, F is
* called (see description of SegWriteFunc above).
*/
{
int Sign;
unsigned long Offs = 0;
/* Loop over all sections in this segment */
Section* Sec = S->SecRoot;
while (Sec) {
Fragment* Frag;
/* If we have fill bytes, write them now */
WriteMult (Tgt, S->FillVal, Sec->Fill);
/* Loop over all fragments in this section */
Frag = Sec->FragRoot;
while (Frag) {
switch (Frag->Type) {
case FRAG_LITERAL:
WriteData (Tgt, Frag->LitBuf, Frag->Size);
break;
case FRAG_EXPR:
case FRAG_SEXPR:
Sign = (Frag->Type == FRAG_SEXPR);
/* Call the users function and evaluate the result */
switch (F (Frag->Expr, Sign, Frag->Size, Offs, Data)) {
case SEG_EXPR_OK:
break;
case SEG_EXPR_RANGE_ERROR:
Error ("Range error in module `%s', line %lu",
Frag->Obj->Files [Frag->Pos.Name], Frag->Pos.Line);
break;
case SEG_EXPR_TOO_COMPLEX:
Error ("Expression too complex in module `%s', line %lu",
Frag->Obj->Files [Frag->Pos.Name], Frag->Pos.Line);
break;
default:
Internal ("Invalid return code from SegWriteFunc");
}
break;
case FRAG_FILL:
WriteMult (Tgt, S->FillVal, Frag->Size);
break;
default:
Internal ("Invalid fragment type: %02X", Frag->Type);
}
/* Update the offset */
Offs += Frag->Size;
/* Next fragment */
Frag = Frag->Next;
}
/* Next section */
Sec = Sec->Next;
}
}
static int CmpSegStart (const void* K1, const void* K2)
/* Compare function for qsort */
{
/* Get the real segment pointers */
const Segment* S1 = *(const Segment**)K1;
const Segment* S2 = *(const Segment**)K2;
/* Compare the start addresses */
if (S1->PC > S2->PC) {
return 1;
} else if (S1->PC < S2->PC) {
return -1;
} else {
/* Sort segments with equal starts by name */
return strcmp (S1->Name, S2->Name);
}
}
void PrintSegmentMap (FILE* F)
/* Print a segment map to the given file */
{
unsigned I;
Segment* S;
Segment** SegPool;
/* Allocate memory for the segment pool */
SegPool = Xmalloc (SegCount * sizeof (Segment*));
/* Collect pointers to the segments */
I = 0;
S = SegRoot;
while (S) {
/* Check the count for safety */
CHECK (I < SegCount);
/* Remember the pointer */
SegPool [I] = S;
/* Follow the linked list */
S = S->List;
/* Next array index */
++I;
}
CHECK (I == SegCount);
/* Sort the array by increasing start addresses */
qsort (SegPool, SegCount, sizeof (Segment*), CmpSegStart);
/* Print a header */
fprintf (F, "Name Start End Size\n"
"--------------------------------------------\n");
/* Print the segments */
for (I = 0; I < SegCount; ++I) {
/* Get a pointer to the segment */
S = SegPool [I];
/* Print empty segments only if explicitly requested */
if (VerboseMap || S->Size > 0) {
/* Print the segment data */
fprintf (F, "%-20s %06lX %06lX %06lX\n",
S->Name, S->PC, S->PC + S->Size, S->Size);
}
}
/* Free the segment pool */
Xfree (SegPool);
}
void CheckSegments (void)
/* Walk through the segment list and check if there are segments that were
* not written to the output file. Output an error if this is the case.
*/
{
Segment* S = SegRoot;
while (S) {
if (S->Size > 0 && S->Dumped == 0) {
Error ("Missing memory area assignment for segment `%s'", S->Name);
}
S = S->List;
}
}

152
src/ld65/segments.h Normal file
View File

@@ -0,0 +1,152 @@
/*****************************************************************************/
/* */
/* segments.h */
/* */
/* Segment handling for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998-2000 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef SEGMENTS_H
#define SEGMENTS_H
#include <stdio.h>
#include "../common/exprdefs.h"
#include "objdata.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Forward for the section structure (a section is a part of a segment) */
typedef struct Section_ Section;
/* Segment structure */
typedef struct Segment_ Segment;
struct Segment_ {
Segment* Next; /* Hash list */
Segment* List; /* List of all segments */
Section* SecRoot; /* Section list */
Section* SecLast; /* Pointer to last section */
unsigned long PC; /* PC were this segment is located */
unsigned long Size; /* Size of data so far */
ObjData* AlignObj; /* Module that requested the alignment */
unsigned char Align; /* Alignment needed */
unsigned char FillVal; /* Value to use for fill bytes */
unsigned char Type; /* Type of segment */
char Dumped; /* Did we dump this segment? */
char Name [1]; /* Name, dynamically allocated */
};
/* Section structure (a section is a part of a segment) */
struct Section_ {
Section* Next; /* List of sections in a segment */
Segment* Seg; /* Segment that contains the section */
struct Fragment_* FragRoot; /* Fragment list */
struct Fragment_* FragLast; /* Pointer to last fragment */
unsigned long Offs; /* Offset into the segment */
unsigned long Size; /* Size of the section */
unsigned char Align; /* Alignment */
unsigned char Fill; /* Fill bytes for alignment */
unsigned char Type; /* Type of segment */
};
/* Prototype for a function that is used to write expressions to the target
* file (used in SegWrite). It returns one of the following values:
*/
#define SEG_EXPR_OK 0 /* Ok */
#define SEG_EXPR_RANGE_ERROR 1 /* Range error */
#define SEG_EXPR_TOO_COMPLEX 2 /* Expression too complex */
typedef unsigned (*SegWriteFunc) (ExprNode* E, /* The expression to write */
int Signed, /* Signed expression? */
unsigned Size, /* Size (=range) */
unsigned long Offs, /* File offset */
void* Data); /* Callers data */
/*****************************************************************************/
/* Code */
/*****************************************************************************/
Section* ReadSection (FILE* F, ObjData* O);
/* Read a section from a file */
Segment* SegFind (const char* Name);
/* Return the given segment or NULL if not found. */
int IsBSSType (Segment* S);
/* Check if the given segment is a BSS style segment, that is, it does not
* contain non-zero data.
*/
void SegDump (void);
/* Dump the segments and it's contents */
unsigned SegWriteConstExpr (FILE* F, ExprNode* E, int Signed, unsigned Size);
/* Write a supposedly constant expression to the target file. Do a range
* check and return one of the SEG_EXPR_xxx codes.
*/
void SegWrite (FILE* Tgt, Segment* S, SegWriteFunc F, void* Data);
/* Write the data from the given segment to a file. For expressions, F is
* called (see description of SegWriteFunc above).
*/
void PrintSegmentMap (FILE* F);
/* Print a segment map to the given file */
void CheckSegments (void);
/* Walk through the segment list and check if there are segments that were
* not written to the output file. Output an error if this is the case.
*/
/* End of segments.h */
#endif

351
src/ld65/target.c Normal file
View File

@@ -0,0 +1,351 @@
/*****************************************************************************/
/* */
/* target.c */
/* */
/* Target system support for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998-2000 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include "error.h"
#include "global.h"
#include "binfmt.h"
#include "scanner.h"
#include "config.h"
#include "target.h"
/*****************************************************************************/
/* Target configurations */
/*****************************************************************************/
static const char CfgNone [] =
"MEMORY {"
"RAM: start = %S, size = $10000, file = %O;"
"}"
"SEGMENTS {"
"CODE: load = RAM, type = rw;"
"RODATA: load = RAM, type = rw;"
"DATA: load = RAM, type = rw;"
"BSS: load = RAM, type = bss, define = yes;"
"}";
static const char CfgAtari [] =
"MEMORY {"
"HEADER: start = $0000, size = $6, file = %O;"
"RAM: start = $1F00, size = $6100, file = %O;"
"}"
"SEGMENTS {"
"EXEHDR: load = HEADER, type = wprot;"
"CODE: load = RAM, type = wprot, define = yes;"
"RODATA: load = RAM, type = wprot;"
"DATA: load = RAM, type = rw;"
"BSS: load = RAM, type = bss, define = yes;"
"AUTOSTRT: load = RAM, type = wprot;"
"}";
static const char CfgC64 [] =
"MEMORY {"
"RAM: start = $7FF, size = $c801, file = %O;"
"}"
"SEGMENTS {"
"CODE: load = RAM, type = wprot;"
"RODATA: load = RAM, type = wprot;"
"DATA: load = RAM, type = rw;"
"BSS: load = RAM, type = bss, define = yes;"
"}";
static const char CfgC128 [] =
"MEMORY {"
"RAM: start = $1bff, size = $a401, file = %O;"
"}"
"SEGMENTS {"
"CODE: load = RAM, type = wprot;"
"RODATA: load = RAM, type = wprot;"
"DATA: load = RAM, type = rw;"
"BSS: load = RAM, type = bss, define = yes;"
"}";
static const char CfgAce [] =
"";
static const char CfgPlus4 [] =
"MEMORY {"
"RAM: start = $0fff, size = $7001, file = %O;"
"}"
"SEGMENTS {"
"CODE: load = RAM, type = wprot;"
"RODATA: load = RAM, type = wprot;"
"DATA: load = RAM, type = rw;"
"BSS: load = RAM, type = bss, define = yes;"
"}";
static const char CfgCBM610 [] =
"MEMORY {"
"RAM: start = $0001, size = $FFF0, file = %O;"
"}"
"SEGMENTS {"
"CODE: load = RAM, type = wprot;"
"RODATA: load = RAM, type = wprot;"
"DATA: load = RAM, type = rw;"
"BSS: load = RAM, type = bss, define = yes;"
"}";
static const char CfgPET [] =
"MEMORY {"
"RAM: start = $03FF, size = $7BFF, file = %O;"
"}"
"SEGMENTS {"
"CODE: load = RAM, type = wprot;"
"RODATA: load = RAM, type = wprot;"
"DATA: load = RAM, type = rw;"
"BSS: load = RAM, type = bss, define = yes;"
"}";
static const char CfgNES [] =
"MEMORY {"
"RAM: start = $0200, size = $0600, file = \"\";"
"ROM: start = $8000, size = $8000, file = %O;"
"}"
"SEGMENTS {"
"CODE: load = ROM, type = ro;"
"RODATA: load = ROM, type = ro;"
"DATA: load = ROM, run = RAM, type = rw, define = yes;"
"BSS: load = RAM, type = bss, define = yes;"
"VECTORS: load = ROM, type = ro, start = $FFFA;"
"}";
static const char CfgLunix [] =
"MEMORY {"
"COMBINED: start = $0000, size = $FFFF, file = %O;"
"ZEROPAGE: start = $0000, size = $0100, file = %O;"
"}"
"SEGMENTS {"
"CODE: load = COMBINED, type = wprot;"
"RODATA: load = COMBINED, type = wprot;"
"DATA: load = COMBINED, type = rw, define = yes;"
"BSS: load = COMBINED, type = bss, define = yes;"
"ZEROPAGE: load = ZEROPAGE, type = zp;"
"}"
"FILES {"
"%O: format = o65;"
"}"
"FORMATS {"
"o65: os = lunix, type = small,"
"extsym = \"LUNIXKERNAL\", extsym = \"LIB6502\";"
"}";
static const char CfgOSA65 [] =
"MEMORY {"
"COMBINED: start = $0000, size = $FFFF, file = %O;"
"ZEROPAGE: start = $0000, size = $0100, file = %O;"
"}"
"SEGMENTS {"
"CODE: load = COMBINED, type = wprot;"
"RODATA: load = COMBINED, type = wprot;"
"DATA: load = COMBINED, type = rw, define = yes;"
"BSS: load = COMBINED, type = bss, define = yes;"
"ZEROPAGE: load = ZEROPAGE, type = zp;"
"}"
"FILES {"
"%O: format = o65;"
"}"
"FORMATS {"
"o65: os = osa65, type = small,"
"extsym = \"OSA2KERNAL\", extsym = \"LIB6502\";"
"}";
static const char CfgApple2 [] =
"MEMORY {"
"RAM: start = $800, size = $8E00, file = %O;"
"}"
"SEGMENTS { "
"CODE: load = RAM, type = ro;"
"RODATA: load = RAM, type = ro;"
"DATA: load = RAM, type = rw;"
"BSS: load = RAM, type = bss, define = yes;"
"}";
static const char CfgGeos [] =
"MEMORY {"
"HEADER: start = $204, size = 508, file = %O;"
"RAM: start = $400, size = $7C00, file = %O;"
"}"
"SEGMENTS { "
"HEADER: load = HEADER, type = ro;"
"CODE: load = RAM, type = ro;"
"RODATA: load = RAM, type = ro;"
"DATA: load = RAM, type = rw;"
"BSS: load = RAM, type = bss, define = yes;"
"}";
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Supported systems */
#define TGT_NONE 0
#define TGT_ATARI 1 /* Atari 8 bit machines */
#define TGT_C64 2
#define TGT_C128 3
#define TGT_ACE 4
#define TGT_PLUS4 5
#define TGT_CBM610 6 /* CBM 600/700 family */
#define TGT_PET 7 /* CBM PET family */
#define TGT_NES 8 /* Nintendo Entertainment System */
#define TGT_LUNIX 9
#define TGT_OSA65 10
#define TGT_APPLE2 11
#define TGT_GEOS 12
#define TGT_COUNT 13 /* Count of supported systems */
/* Structure describing a target */
typedef struct TargetCfg_ TargetCfg;
struct TargetCfg_ {
const char* Name; /* Name of the system */
unsigned char BinFmt; /* Default binary format for the target */
const char* Cfg; /* Pointer to configuration */
};
static const TargetCfg Targets [TGT_COUNT] = {
{ "none", BINFMT_BINARY, CfgNone },
{ "atari", BINFMT_BINARY, CfgAtari },
{ "c64", BINFMT_BINARY, CfgC64 },
{ "c128", BINFMT_BINARY, CfgC128 },
{ "ace", BINFMT_BINARY, CfgAce },
{ "plus4", BINFMT_BINARY, CfgPlus4 },
{ "cbm610", BINFMT_BINARY, CfgCBM610 },
{ "pet", BINFMT_BINARY, CfgPET },
{ "nes", BINFMT_BINARY, CfgNES },
{ "lunix", BINFMT_O65, CfgLunix },
{ "osa65", BINFMT_O65, CfgOSA65 },
{ "apple2", BINFMT_BINARY, CfgApple2 },
{ "geos", BINFMT_BINARY, CfgGeos },
};
/* Selected target system type */
static const TargetCfg* Target;
/*****************************************************************************/
/* Code */
/*****************************************************************************/
static int StrICmp (const char* S1, const char* S2)
/* Compare two strings case insensitive */
{
int Diff = 0;
while (1) {
Diff = tolower (*S1) - tolower (*S2);
if (Diff != 0 || *S1 == '\0') {
return Diff;
}
++S1;
++S2;
}
}
static int TgtMap (const char* Name)
/* Map a target name to a system code. Return -1 in case of an error */
{
unsigned I;
/* Check for a numeric target */
if (isdigit (*Name)) {
int Target = atoi (Name);
if (Target >= 0 && Target < TGT_COUNT) {
return Target;
}
}
/* Check for a target string */
for (I = 0; I < TGT_COUNT; ++I) {
if (StrICmp (Targets [I].Name, Name) == 0) {
return I;
}
}
/* Not found */
return -1;
}
void TgtSet (const char* T)
/* Set the target system, initialize internal stuff for this target */
{
/* Map the target to a number */
int TgtNum = TgtMap (T);
if (TgtNum == -1) {
Error ("Invalid target system: %s", T);
}
Target = &Targets [TgtNum];
/* Set the target data */
DefaultBinFmt = Target->BinFmt;
CfgSetBuf (Target->Cfg);
}
void TgtPrintList (FILE* F)
/* Print a list of the available target systems */
{
unsigned I;
/* Print a header */
fprintf (F, "Available targets:\n");
/* Print a list of the target systems */
for (I = 0; I < TGT_COUNT; ++I) {
fprintf (F, " %s\n", Targets [I].Name);
}
}

64
src/ld65/target.h Normal file
View File

@@ -0,0 +1,64 @@
/*****************************************************************************/
/* */
/* target.h */
/* */
/* Target system support for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998-2000 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef TARGET_H
#define TARGET_H
#include <stdio.h>
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void TgtSet (const char* T);
/* Set the target system, initialize internal stuff for this target */
void TgtPrintList (FILE* F);
/* Print a list of the available target systems */
/* End of target.h */
#endif

58
src/ld65/version.h Normal file
View File

@@ -0,0 +1,58 @@
/*****************************************************************************/
/* */
/* version.h */
/* */
/* Version information for the ld65 linker */
/* */
/* */
/* */
/* (C) 1998 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef VERSION_H
#define VERSION_H
/*****************************************************************************/
/* Data */
/*****************************************************************************/
#define VER_MAJOR 2U
#define VER_MINOR 4U
#define VER_PATCH 0U
/* End of version.h */
#endif