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:
5
src/ld65/.cvsignore
Normal file
5
src/ld65/.cvsignore
Normal file
@@ -0,0 +1,5 @@
|
||||
.depend
|
||||
ld65
|
||||
*.map
|
||||
*.s
|
||||
|
||||
258
src/ld65/bin.c
Normal file
258
src/ld65/bin.c
Normal 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
78
src/ld65/bin.h
Normal 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
89
src/ld65/binfmt.c
Normal 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
73
src/ld65/binfmt.h
Normal 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
1202
src/ld65/config.c
Normal file
File diff suppressed because it is too large
Load Diff
147
src/ld65/config.h
Normal file
147
src/ld65/config.h
Normal 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
210
src/ld65/dbgsyms.c
Normal 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
92
src/ld65/dbgsyms.h
Normal 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
106
src/ld65/error.c
Normal 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
87
src/ld65/error.h
Normal 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
662
src/ld65/exports.c
Normal 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
164
src/ld65/exports.h
Normal 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
622
src/ld65/expr.c
Normal 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
97
src/ld65/expr.h
Normal 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
237
src/ld65/extsyms.c
Normal 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
99
src/ld65/extsyms.h
Normal 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
269
src/ld65/fileio.c
Normal 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
111
src/ld65/fileio.h
Normal 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
59
src/ld65/global.c
Normal 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
66
src/ld65/global.h
Normal 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
285
src/ld65/library.c
Normal 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
59
src/ld65/library.h
Normal 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
391
src/ld65/main.c
Normal 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
66
src/ld65/make/gcc.mak
Normal 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
136
src/ld65/make/watcom.mak
Normal 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
170
src/ld65/mapfile.c
Normal 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
64
src/ld65/mapfile.h
Normal 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
84
src/ld65/mem.c
Normal 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
67
src/ld65/mem.h
Normal 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
1067
src/ld65/o65.c
Normal file
File diff suppressed because it is too large
Load Diff
119
src/ld65/o65.h
Normal file
119
src/ld65/o65.h
Normal 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
112
src/ld65/objdata.c
Normal 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
106
src/ld65/objdata.h
Normal 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
225
src/ld65/objfile.c
Normal 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
80
src/ld65/objfile.h
Normal 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
535
src/ld65/scanner.c
Normal 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
198
src/ld65/scanner.h
Normal 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
666
src/ld65/segments.c
Normal 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
152
src/ld65/segments.h
Normal 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
351
src/ld65/target.c
Normal 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
64
src/ld65/target.h
Normal 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
58
src/ld65/version.h
Normal 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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user