1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-07 07:29:33 +00:00

Reworked and improved the SYMBOLS section. The old syntax (using symbol =

value) is now gone, attributes are used instead. The SYMBOLS section does now
support imports, so the linker config can be used to force symbols (and
therefore module) imports. Evaluation of start address and size for memory
areas has been delayed even further, so it is now possible to use the values
from one memory area in the definition of the next one.


git-svn-id: svn://svn.cc65.org/cc65/trunk@4851 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
uz 2010-11-12 14:17:35 +00:00
parent a0a0347ecc
commit 5e8252fa36
38 changed files with 460 additions and 334 deletions

View File

@ -832,8 +832,8 @@ The necessary o65 attributes are defined in a special section labeled
The <tt/FORMAT/ section is used to describe file formats. The default (binary)
format has currently no attributes, so, while it may be listed in this
section, the attribute list is empty. The second supported format,
<htmlurl url="http://www.6502.org/users/andre/o65/fileformat.html" name="o65">,
section, the attribute list is empty. The second supported format,
<htmlurl url="http://www.6502.org/users/andre/o65/fileformat.html" name="o65">,
has several attributes that may be defined here.
<tscreen><verb>
@ -942,12 +942,41 @@ mean, that the <tt/FEATURES/ section has to go to the top of the config file.
<sect1>The SYMBOLS section<label id="SYMBOLS"><p>
The configuration file may also be used to define symbols used in the link
stage. The mandatory attribute for a symbol is its value. A second, boolean
attribute named <tt/weak/ is available. If a symbol is marked as weak, it may
be overridden by defining a symbol of the same name from the command line. The
default for symbols is that they're strong, which means that an attempt to
define a symbol with the same name from the command line will lead to an
error.
stage or to force symbols imports. This is done in the SYMBOLS section. The
symbol name is followed by a colon and symbol attributes.
The following symbol attributes are supported:
<descrip>
<tag><tt>addrsize</tt></tag>
The <tt/addrsize/ attribute specifies the address size of the symbol and
may be one of
<itemize>
<item><tt/zp/, <tt/zeropage/ or <tt/direct/
<item><tt/abs/, <tt/absolute/ or <tt/near/
<item><tt/far/
<item><tt/long/ or <tt/dword/.
</itemize>
Without this attribute, the default address size is <tt/abs/.
<tag><tt>type</tt></tag>
This attribute is mandatory. Its value is one of <tt/export/, <tt/import/ or
<tt/weak/. <tt/export/ means that the symbol is defined and exported from
the linker config. <tt/import/ means that an import is generated for this
symbol, eventually forcing a module that exports this symbol to be included
in the output. <tt/weak/ is similar as <tt/export/. However, the symbol is
only defined if it is not defined elsewhere.
<tag><tt>value</tt></tag>
This must only be given for symbols of type <tt/export/ or <tt/weak/. It
defines the value of the symbol and may be an expression.
</descrip>
The following example defines the stack size for an application, but allows
the programmer to override the value by specifying <tt/--define
@ -956,7 +985,7 @@ __STACKSIZE__=xxx/ on the command line.
<tscreen><verb>
SYMBOLS {
# Define the stack size for the application
__STACKSIZE__: value = $800, weak = yes;
__STACKSIZE__: type = weak, value = $800;
}
</verb></tscreen>

View File

@ -1,10 +1,10 @@
# Configuration optimized for DOS 3.3 by allowing for 12KB of HIGHCODE
FEATURES {
STARTADDRESS: default = $0803;
}
SYMBOLS {
__STACKSIZE__: value = $0800, weak = yes; # 2k stack
__STACKSIZE__: type = weak, value = $0800; # 2k stack
}
MEMORY {
ZP: define = yes, start = $0080, size = $001A;

View File

@ -4,7 +4,7 @@ FEATURES {
STARTADDRESS: default = $0800;
}
SYMBOLS {
__STACKSIZE__: value = $0800, weak = yes; # 2k stack
__STACKSIZE__: type = weak, value = $0800; # 2k stack
}
MEMORY {
ZP: define = yes, start = $0080, size = $001A;

View File

@ -5,7 +5,7 @@ FEATURES {
STARTADDRESS: default = $0800;
}
SYMBOLS {
__STACKSIZE__: value = $0800, weak = yes; # 2k stack
__STACKSIZE__: type = weak, value = $0800; # 2k stack
}
MEMORY {
ZP: define = yes, start = $0080, size = $001A;

View File

@ -1,7 +1,7 @@
# Configuration for ProDOS 8 system programs (without the header)
SYMBOLS {
__STACKSIZE__: value = $0800, weak = yes; # 2k stack
__STACKSIZE__: type = weak, value = $0800; # 2k stack
}
MEMORY {
ZP: define = yes, start = $0080, size = $001A;

View File

@ -1,10 +1,10 @@
# Default configuration built into ld65 (allowing for 3KB of HIGHCODE)
FEATURES {
STARTADDRESS: default = $0803;
}
SYMBOLS {
__STACKSIZE__: value = $0800, weak = yes; # 2k stack
__STACKSIZE__: type = weak, value = $0800; # 2k stack
}
MEMORY {
ZP: define = yes, start = $0080, size = $001A;

View File

@ -1,10 +1,10 @@
# Configuration optimized for DOS 3.3 by allowing for 12KB of HIGHCODE
FEATURES {
STARTADDRESS: default = $0803;
}
SYMBOLS {
__STACKSIZE__: value = $0800, weak = yes; # 2k stack
__STACKSIZE__: type = weak, value = $0800; # 2k stack
}
MEMORY {
ZP: define = yes, start = $0080, size = $001A;

View File

@ -4,7 +4,7 @@ FEATURES {
STARTADDRESS: default = $0800;
}
SYMBOLS {
__STACKSIZE__: value = $0800, weak = yes; # 2k stack
__STACKSIZE__: type = weak, value = $0800; # 2k stack
}
MEMORY {
ZP: define = yes, start = $0080, size = $001A;

View File

@ -5,7 +5,7 @@ FEATURES {
STARTADDRESS: default = $0800;
}
SYMBOLS {
__STACKSIZE__: value = $0800, weak = yes; # 2k stack
__STACKSIZE__: type = weak, value = $0800; # 2k stack
}
MEMORY {
ZP: define = yes, start = $0080, size = $001A;

View File

@ -1,7 +1,7 @@
# Configuration for ProDOS 8 system programs (without the header)
SYMBOLS {
__STACKSIZE__: value = $0800, weak = yes; # 2k stack
__STACKSIZE__: type = weak, value = $0800; # 2k stack
}
MEMORY {
ZP: define = yes, start = $0080, size = $001A;

View File

@ -1,10 +1,10 @@
# Default configuration built into ld65 (allowing for 3KB of HIGHCODE)
FEATURES {
STARTADDRESS: default = $0803;
}
SYMBOLS {
__STACKSIZE__: value = $0800, weak = yes; # 2k stack
__STACKSIZE__: type = weak, value = $0800; # 2k stack
}
MEMORY {
ZP: define = yes, start = $0080, size = $001A;

View File

@ -2,8 +2,8 @@ FEATURES {
STARTADDRESS: default = $2E00;
}
SYMBOLS {
__STACKSIZE__: value = $0800, weak = yes; # 2k stack
__RESERVED_MEMORY__: value = $0000, weak = yes;
__STACKSIZE__: type = weak, value = $0800; # 2k stack
__RESERVED_MEMORY__: type = weak, value = $0000;
}
MEMORY {
ZP: define = yes, start = $0082, size = $007E;

View File

@ -1,5 +1,5 @@
SYMBOLS {
__STACKSIZE__: value = $0800, weak = yes; # 2k stack
__STACKSIZE__: type = weak, value = $0800; # 2k stack
}
MEMORY {
ZP: define = yes, start = $00E2, size = $001A;

View File

@ -1,5 +1,5 @@
SYMBOLS {
__STACKSIZE__: value = $0800, weak = yes; # 2k stack
__STACKSIZE__: type = weak, value = $0800; # 2k stack
}
MEMORY {
ZP: define = yes, start = $0070, size = $0020;

View File

@ -1,6 +1,6 @@
SYMBOLS {
__STACKSIZE__: value = $0800, weak = yes; # 2k stack
}
__STACKSIZE__: type = weak, value = $0800; # 2k stack
}
MEMORY {
ZP: define = yes, start = $0002, size = $001A;
HEADER: file = %O, start = $1BFF, size = $000E;

View File

@ -1,5 +1,5 @@
SYMBOLS {
__STACKSIZE__: value = $0800, weak = yes; # 2k stack
__STACKSIZE__: type = weak, value = $0800; # 2k stack
}
MEMORY {
ZP: define = yes, start = $0002, size = $001A;

View File

@ -1,5 +1,5 @@
SYMBOLS {
__STACKSIZE__: value = $0800, weak = yes; # 2k stack
__STACKSIZE__: type = weak, value = $0800; # 2k stack
}
MEMORY {
ZP: define = yes, start = $0002, size = $001A;

View File

@ -1,6 +1,6 @@
SYMBOLS {
# The stack starts from $FEC3 and grows towards the video ram
__STACKSIZE__: value = $06C3, weak = yes; # ~1.5k stack
__STACKSIZE__: type = weak, value = $06C3; # ~1.5k stack
}
MEMORY {
HEADER: file = %O, start = $0001, size = $0050, fill = yes;

View File

@ -1,5 +1,5 @@
SYMBOLS {
__STACKSIZE__: value = $0800, weak = yes; # 2k stack
__STACKSIZE__: type = weak, value = $0800; # 2k stack
}
MEMORY {
HEADER: file = %O, start = $0001, size = $0050, fill = yes;

View File

@ -1,5 +1,5 @@
SYMBOLS {
__STACKSIZE__: value = $0400, weak = yes; # 1k stack
__STACKSIZE__: type = weak, value = $0400; # 1k stack
}
MEMORY {
ZP: define = yes, start = $0058, size = $0028;

View File

@ -1,8 +1,8 @@
# ld65 Linker-configuration for LUnix, Next Generation.
SYMBOLS {
__HEAPSIZE__: value = $2000, weak = yes; # 8k heap [temporary, until LUnix malloc() exists]
__STACKSIZE__: value = $0400, weak = yes; # 1k stack (do typical LUnix apps. need 2k?)
__HEAPSIZE__: type = weak, value = $2000; # 8k heap [temporary, until LUnix malloc() exists]
__STACKSIZE__: type = weak, value = $0400; # 1k stack (do typical LUnix apps. need 2k?)
}
MEMORY {
ZP: start = $0080, size = $0040;
@ -28,7 +28,7 @@ FEATURES {
label = __DESTRUCTOR_TABLE__,
count = __DESTRUCTOR_COUNT__;
CONDES: segment = RODATA,
type = interruptor,
type = interruptor,
label = __INTERRUPTOR_TABLE__,
count = __INTERRUPTOR_COUNT__;
}

View File

@ -1,5 +1,5 @@
SYMBOLS {
__STACKSIZE__: value = $0800, weak = yes; # 2k stack
__STACKSIZE__: type = weak, value = $0800; # 2k stack
}
MEMORY {
ZP: define = yes, start = $0000, size = $0100;

View File

@ -1,5 +1,5 @@
SYMBOLS {
__STACKSIZE__: value = $0300, weak = yes; # 3 pages stack
__STACKSIZE__: type = weak, value = $0300; # 3 pages stack
}
MEMORY {
ZP: start = $0002, size = $001A, type = rw, define = yes;

View File

@ -1,5 +1,5 @@
SYMBOLS {
__STACKSIZE__: value = $0800, weak = yes; # 2k stack
__STACKSIZE__: type = weak, value = $0800; # 2k stack
}
MEMORY {
ZP: define = yes, start = $0000, size = $0001F;

View File

@ -1,5 +1,5 @@
SYMBOLS {
__STACKSIZE__: value = $0800, weak = yes; # 2k stack
__STACKSIZE__: type = weak, value = $0800; # 2k stack
}
MEMORY {
ZP: define = yes, start = $0055, size = $001A;

View File

@ -1,5 +1,5 @@
SYMBOLS {
__STACKSIZE__: value = $0800, weak = yes; # 2k stack
__STACKSIZE__: type = weak, value = $0800; # 2k stack
}
MEMORY {
ZP: define = yes, start = $0002, size = $001A;

View File

@ -5,7 +5,7 @@
# ld65 --config supervision.cfg -o <prog>.bin <prog>.o
SYMBOLS {
__STACKSIZE__: value = $0100, weak = yes; # 1 page stack
__STACKSIZE__: type = weak, value = $0100; # 1 page stack
}
MEMORY {
RAM: start = $0000, size = $2000 - __STACKSIZE__;

View File

@ -4,7 +4,7 @@
# ld65 --config supervision16.cfg -o <prog>.bin <prog>.o
SYMBOLS {
__STACKSIZE__: value = $0100, weak = yes; # 1 page stack
__STACKSIZE__: type = weak, value = $0100; # 1 page stack
}
MEMORY {
ZP: start = $0000, size = $0100;

View File

@ -5,7 +5,7 @@
# ld65 --config supervision.cfg -o <prog>.bin <prog>.o
SYMBOLS {
__STACKSIZE__: value = $0100, weak = yes; # 1 page stack
__STACKSIZE__: type = weak, value = $0100; # 1 page stack
}
MEMORY {
RAM: start = $0000, size = $2000 - __STACKSIZE__;

View File

@ -2,7 +2,7 @@
# Contributed by Stefan Haubenthal
SYMBOLS {
__STACKSIZE__: value = $0400, weak = yes; # 1k stack
__STACKSIZE__: type = weak, value = $0400; # 1k stack
}
MEMORY {
ZP: define = yes, start = $0002, size = $001A;

View File

@ -1,5 +1,5 @@
SYMBOLS {
__STACKSIZE__: value = $0400, weak = yes; # 1k stack
__STACKSIZE__: type = weak, value = $0400; # 1k stack
}
MEMORY {
ZP: define = yes, start = $0002, size = $001A;

View File

@ -74,6 +74,7 @@ static ExprNode* Factor (void)
} else {
N = NewExprNode (0, EXPR_SYMBOL);
N->V.Imp = InsertImport (GenImport (Name, ADDR_SIZE_ABS));
N->V.Imp->Pos = CfgErrorPos;
}
/* Skip the symbol name */

View File

@ -39,6 +39,7 @@
#include <errno.h>
/* common */
#include "addrsize.h"
#include "bitops.h"
#include "check.h"
#include "print.h"
@ -111,28 +112,30 @@ static Collection SegDescList = STATIC_COLLECTION_INITIALIZER;
#define SA_START 0x0080
#define SA_OPTIONAL 0x0100
/* Symbol types used in the CfgSymbol structure */
typedef enum {
CfgSymExport, /* Not really used in struct CfgSymbol */
CfgSymImport, /* Dito */
CfgSymWeak, /* Like export but weak */
CfgSymO65Export, /* An o65 export */
CfgSymO65Import, /* An o65 import */
} CfgSymType;
/* Symbol structure. It is used for o65 imports and exports, but also for
* symbols from the SYMBOLS sections (symbols defined in the config file or
* forced imports).
*/
typedef struct Symbol Symbol;
struct Symbol {
typedef struct CfgSymbol CfgSymbol;
struct CfgSymbol {
CfgSymType Type; /* Type of symbol */
FilePos Pos; /* Config file position */
unsigned Name; /* Symbol name */
unsigned Flags; /* Symbol flags */
long Val; /* Symbol value if any */
ExprNode* Value; /* Symbol value if any */
unsigned AddrSize; /* Address size of symbol */
};
/* Collections with symbols */
static Collection O65Imports = STATIC_COLLECTION_INITIALIZER;
static Collection O65Exports = STATIC_COLLECTION_INITIALIZER;
static Collection Symbols = STATIC_COLLECTION_INITIALIZER;
/* Symbol flags */
#define SYM_NONE 0x00 /* No special meaning */
#define SYM_DEF 0x01 /* Symbol defined in the config file */
#define SYM_WEAK 0x02 /* Defined symbol is weak */
#define SYM_IMPORT 0x04 /* A forced import */
static Collection CfgSymbols = STATIC_COLLECTION_INITIALIZER;
/* Descriptor holding information about the binary formats */
static BinDesc* BinFmtDesc = 0;
@ -254,19 +257,24 @@ static void MemoryInsert (MemoryArea* M, SegDesc* S)
static Symbol* NewSymbol (unsigned Name, unsigned Flags, long Val)
/* Create a new Symbol structure with the given name name and flags. The
* current config file position is recorded in the returned struct.
static CfgSymbol* NewCfgSymbol (CfgSymType Type, unsigned Name)
/* Create a new CfgSymbol structure with the given type and name. The
* current config file position is recorded in the returned struct. The
* created struct is inserted into the CfgSymbols collection and returned.
*/
{
/* Allocate memory */
Symbol* Sym = xmalloc (sizeof (Symbol));
CfgSymbol* Sym = xmalloc (sizeof (CfgSymbol));
/* Initialize the fields */
Sym->Pos = CfgErrorPos;
Sym->Name = Name;
Sym->Flags = Flags;
Sym->Val = Val;
Sym->Type = Type;
Sym->Pos = CfgErrorPos;
Sym->Name = Name;
Sym->Value = 0;
Sym->AddrSize = ADDR_SIZE_INVALID;
/* Insert the symbol into the collection */
CollAppend (&CfgSymbols, Sym);
/* Return the initialized struct */
return Sym;
@ -274,17 +282,6 @@ static Symbol* NewSymbol (unsigned Name, unsigned Flags, long Val)
static Symbol* NewO65Symbol (void)
/* Create a new Symbol structure with the name in the current CfgSVal variable
* ready for use as an o65 symbol. The current config file position is recorded
* in the returned struct.
*/
{
return NewSymbol (GetStrBufId (&CfgSVal), SYM_NONE, 0);
}
static File* NewFile (unsigned Name)
/* Create a new file descriptor and insert it into the list */
{
@ -344,6 +341,7 @@ static SegDesc* NewSegDesc (unsigned Name)
/* Initialize the fields */
S->Name = Name;
S->Pos = CfgErrorPos;
S->Seg = 0;
S->Attr = 0;
S->Flags = 0;
@ -872,7 +870,7 @@ static void ParseO65 (void)
/* We expect an identifier */
CfgAssureIdent ();
/* Remember it as an export for later */
CollAppend (&O65Exports, NewO65Symbol ());
NewCfgSymbol (CfgSymO65Export, GetStrBufId (&CfgSVal));
/* Eat the identifier token */
CfgNextTok ();
break;
@ -883,7 +881,7 @@ static void ParseO65 (void)
/* We expect an identifier */
CfgAssureIdent ();
/* Remember it as an import for later */
CollAppend (&O65Imports, NewO65Symbol ());
NewCfgSymbol (CfgSymO65Import, GetStrBufId (&CfgSVal));
/* Eat the identifier token */
CfgNextTok ();
break;
@ -1291,107 +1289,159 @@ static void ParseSymbols (void)
/* Parse a symbols section */
{
static const IdentTok Attributes[] = {
{ "ADDRSIZE", CFGTOK_ADDRSIZE },
{ "TYPE", CFGTOK_TYPE },
{ "VALUE", CFGTOK_VALUE },
{ "WEAK", CFGTOK_WEAK },
};
static const IdentTok AddrSizes [] = {
{ "ABS", CFGTOK_ABS },
{ "ABSOLUTE", CFGTOK_ABS },
{ "DIRECT", CFGTOK_ZP },
{ "DWORD", CFGTOK_LONG },
{ "FAR", CFGTOK_FAR },
{ "LONG", CFGTOK_LONG },
{ "NEAR", CFGTOK_ABS },
{ "ZEROPAGE", CFGTOK_ZP },
{ "ZP", CFGTOK_ZP },
};
static const IdentTok Types [] = {
{ "EXPORT", CFGTOK_EXPORT },
{ "IMPORT", CFGTOK_IMPORT },
{ "WEAK", CFGTOK_WEAK },
};
while (CfgTok == CFGTOK_IDENT) {
long Val = 0L;
unsigned Flags = SYM_NONE;
/* Bitmask to remember the attributes we got already */
enum {
atNone = 0x0000,
atAddrSize = 0x0001,
atType = 0x0002,
atValue = 0x0004,
};
unsigned AttrFlags = atNone;
ExprNode* Value = 0;
CfgSymType Type = CfgSymExport;
unsigned char AddrSize = ADDR_SIZE_ABS;
Import* Imp;
Export* Exp;
CfgSymbol* Sym;
/* Remember the name */
unsigned Name = GetStrBufId (&CfgSVal);
CfgNextTok ();
/* Support both, old and new syntax here. New syntax is a colon
* followed by an attribute list, old syntax is an optional equal
* sign plus a value.
*/
if (CfgTok != CFGTOK_COLON) {
/* New syntax - skip the colon */
CfgNextTok ();
/* Old syntax */
/* Parse the attributes */
while (1) {
/* Allow an optional assignment */
CfgOptionalAssign ();
/* Map the identifier to a token */
cfgtok_t AttrTok;
CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
AttrTok = CfgTok;
/* Make sure the next token is an integer expression, read and
* skip it.
*/
Val = CfgConstExpr ();
/* This is a defined symbol */
Flags = SYM_DEF;
} else {
/* Bitmask to remember the attributes we got already */
enum {
atNone = 0x0000,
atValue = 0x0001,
atWeak = 0x0002
};
unsigned AttrFlags = atNone;
/* New syntax - skip the colon */
/* Skip the attribute name */
CfgNextTok ();
/* Parse the attributes */
while (1) {
/* An optional assignment follows */
CfgOptionalAssign ();
/* Map the identifier to a token */
cfgtok_t AttrTok;
CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
AttrTok = CfgTok;
/* Check which attribute was given */
switch (AttrTok) {
/* Skip the attribute name */
CfgNextTok ();
/* An optional assignment follows */
CfgOptionalAssign ();
/* Check which attribute was given */
switch (AttrTok) {
case CFGTOK_VALUE:
/* Don't allow this twice */
FlagAttr (&AttrFlags, atValue, "VALUE");
/* We expect a numeric expression */
Val = CfgConstExpr ();
/* Symbol is defined */
Flags |= SYM_DEF;
break;
case CFGTOK_WEAK:
/* Don't allow this twice */
FlagAttr (&AttrFlags, atWeak, "WEAK");
CfgBoolToken ();
if (CfgTok == CFGTOK_TRUE) {
Flags |= SYM_WEAK;
}
CfgNextTok ();
break;
default:
FAIL ("Unexpected attribute token");
}
/* Semicolon ends the decl, otherwise accept an optional comma */
if (CfgTok == CFGTOK_SEMI) {
break;
} else if (CfgTok == CFGTOK_COMMA) {
case CFGTOK_ADDRSIZE:
/* Don't allow this twice */
FlagAttr (&AttrFlags, atAddrSize, "ADDRSIZE");
/* Map the type to a token */
CfgSpecialToken (AddrSizes, ENTRY_COUNT (AddrSizes), "AddrSize");
switch (CfgTok) {
case CFGTOK_ABS: AddrSize = ADDR_SIZE_ABS; break;
case CFGTOK_FAR: AddrSize = ADDR_SIZE_FAR; break;
case CFGTOK_LONG: AddrSize = ADDR_SIZE_LONG; break;
case CFGTOK_ZP: AddrSize = ADDR_SIZE_ZP; break;
default:
Internal ("Unexpected token: %d", CfgTok);
}
CfgNextTok ();
}
break;
case CFGTOK_TYPE:
/* Don't allow this twice */
FlagAttr (&AttrFlags, atType, "TYPE");
/* Map the type to a token */
CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
switch (CfgTok) {
case CFGTOK_EXPORT: Type = CfgSymExport; break;
case CFGTOK_IMPORT: Type = CfgSymImport; break;
case CFGTOK_WEAK: Type = CfgSymWeak; break;
default:
Internal ("Unexpected token: %d", CfgTok);
}
CfgNextTok ();
break;
case CFGTOK_VALUE:
/* Don't allow this twice */
FlagAttr (&AttrFlags, atValue, "VALUE");
/* Value is an expression */
Value = CfgExpr ();
break;
default:
FAIL ("Unexpected attribute token");
}
/* Check if we have all mandatory attributes */
AttrCheck (AttrFlags, atValue, "VALUE");
/* Semicolon ends the decl, otherwise accept an optional comma */
if (CfgTok == CFGTOK_SEMI) {
break;
} else if (CfgTok == CFGTOK_COMMA) {
CfgNextTok ();
}
}
/* Remember the symbol for later */
CollAppend (&Symbols, NewSymbol (Name, Flags, Val));
/* We must have a type */
AttrCheck (AttrFlags, atType, "TYPE");
/* Further actions depend on the type */
switch (Type) {
case CfgSymExport:
/* We must have a value */
AttrCheck (AttrFlags, atType, "TYPE");
/* Create the export */
Exp = CreateExprExport (Name, Value, AddrSize);
Exp->Pos = CfgErrorPos;
break;
case CfgSymImport:
/* An import must not have a value */
if (AttrFlags & atValue) {
CfgError (&CfgErrorPos, "Imports must not have a value");
}
/* Generate the import */
Imp = InsertImport (GenImport (Name, AddrSize));
/* Remember the file position */
Imp->Pos = CfgErrorPos;
break;
case CfgSymWeak:
/* We must have a value */
AttrCheck (AttrFlags, atType, "TYPE");
/* Remember the symbol for later */
Sym = NewCfgSymbol (CfgSymWeak, Name);
Sym->Value = Value;
Sym->AddrSize = AddrSize;
break;
default:
Internal ("Unexpected symbol type %d", Type);
}
/* Skip the semicolon */
CfgConsumeSemi ();
@ -1493,41 +1543,6 @@ void CfgRead (void)
static void ProcessMemory (void)
/* Process the MEMORY section */
{
/* Walk over the list with the memory areas */
unsigned I;
for (I = 0; I < CollCount (&MemoryAreas); ++I) {
/* Get the next memory area */
MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
/* Remember if this is a relocatable memory area */
M->Relocatable = RelocatableBinFmt (M->F->Format);
/* Resolve the expressions */
if (!IsConstExpr (M->StartExpr)) {
CfgError (&M->Pos,
"Start address of memory area `%s' is not constant",
GetString (M->Name));
}
M->Start = GetExprVal (M->StartExpr);
if (!IsConstExpr (M->SizeExpr)) {
CfgError (&M->Pos,
"Size of memory area `%s' is not constant",
GetString (M->Name));
}
M->Size = GetExprVal (M->SizeExpr);
/* Mark the memory area as placed */
M->Flags |= MF_PLACED;
}
}
static void ProcessSegments (void)
/* Process the SEGMENTS section */
{
@ -1589,77 +1604,6 @@ static void ProcessSegments (void)
static void ProcessO65 (void)
/* Process the o65 format section */
{
unsigned I;
/* Walk over the imports, check and add them to the o65 data */
for (I = 0; I < CollCount (&O65Imports); ++I) {
/* Get the import */
Symbol* Sym = CollAtUnchecked (&O65Imports, I);
/* Check if we have this symbol defined already. The entry
* routine will check this also, but we get a more verbose
* error message when checking it here.
*/
if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
CfgError (&Sym->Pos,
"Duplicate imported o65 symbol: `%s'",
GetString (Sym->Name));
}
/* Insert the symbol into the table */
O65SetImport (O65FmtDesc, Sym->Name);
}
/* Walk over the exports, check and add them to the o65 data */
for (I = 0; I < CollCount (&O65Exports); ++I) {
/* Get the export */
Symbol* Sym = CollAtUnchecked (&O65Exports, I);
/* Check if the export symbol is also defined as an import. */
if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
CfgError (&Sym->Pos,
"Exported o65 symbol `%s' cannot also be an o65 import",
GetString (Sym->Name));
}
/* Check if we have this symbol defined already. The entry
* routine will check this also, but we get a more verbose
* error message when checking it here.
*/
if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
CfgError (&Sym->Pos,
"Duplicate exported o65 symbol: `%s'",
GetString (Sym->Name));
}
/* Insert the symbol into the table */
O65SetExport (O65FmtDesc, Sym->Name);
}
}
static void ProcessBin (void)
/* Process the bin format section */
{
}
static void ProcessFormats (void)
/* Process the target format section */
{
ProcessO65 ();
ProcessBin ();
}
static void ProcessSymbols (void)
/* Process the SYMBOLS section */
{
@ -1667,33 +1611,81 @@ static void ProcessSymbols (void)
/* Walk over all symbols */
unsigned I;
for (I = 0; I < CollCount (&Symbols); ++I) {
for (I = 0; I < CollCount (&CfgSymbols); ++I) {
/* Get the next symbol */
Symbol* Sym = CollAtUnchecked (&Symbols, I);
CfgSymbol* Sym = CollAtUnchecked (&CfgSymbols, I);
/* Do we define this symbol? */
if ((Sym->Flags & SYM_DEF) != 0) {
/* Check if the symbol is already defined somewhere else */
if ((E = FindExport (Sym->Name)) != 0 && !IsUnresolvedExport (E)) {
/* If the symbol is not marked as weak, this is an error.
* Otherwise ignore the symbol from the config.
*/
if ((Sym->Flags & SYM_WEAK) == 0) {
CfgError (&CfgErrorPos,
"Symbol `%s' is already defined",
GetString (Sym->Name));
/* Check what it is. */
switch (Sym->Type) {
case CfgSymO65Export:
/* Check if the export symbol is also defined as an import. */
if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
CfgError (
&Sym->Pos,
"Exported o65 symbol `%s' cannot also be an o65 import",
GetString (Sym->Name)
);
}
} else {
/* The symbol is undefined, generate an export */
CreateConstExport (Sym->Name, Sym->Val);
}
} else {
/* Check if we have this symbol defined already. The entry
* routine will check this also, but we get a more verbose
* error message when checking it here.
*/
if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
CfgError (
&Sym->Pos,
"Duplicate exported o65 symbol: `%s'",
GetString (Sym->Name)
);
}
/* Insert the symbol into the table */
O65SetExport (O65FmtDesc, Sym->Name);
break;
case CfgSymO65Import:
/* Check if the import symbol is also defined as an export. */
if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
CfgError (
&Sym->Pos,
"Imported o65 symbol `%s' cannot also be an o65 export",
GetString (Sym->Name)
);
}
/* Check if we have this symbol defined already. The entry
* routine will check this also, but we get a more verbose
* error message when checking it here.
*/
if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
CfgError (
&Sym->Pos,
"Duplicate imported o65 symbol: `%s'",
GetString (Sym->Name)
);
}
/* Insert the symbol into the table */
O65SetImport (O65FmtDesc, Sym->Name);
break;
case CfgSymWeak:
/* If the symbol is not defined until now, define it */
if ((E = FindExport (Sym->Name)) == 0 || IsUnresolvedExport (E)) {
/* The symbol is undefined, generate an export */
E = CreateExprExport (Sym->Name, Sym->Value, Sym->AddrSize);
E->Pos = Sym->Pos;
}
break;
default:
Internal ("Unexpected symbol type %d", Sym->Type);
break;
}
}
}
@ -1701,12 +1693,19 @@ static void ProcessSymbols (void)
static void CreateRunDefines (SegDesc* S, unsigned long SegAddr)
/* Create the defines for a RUN segment */
{
Export* E;
StrBuf Buf = STATIC_STRBUF_INITIALIZER;
/* Define the run address of the segment */
SB_Printf (&Buf, "__%s_RUN__", GetString (S->Name));
CreateMemoryExport (GetStrBufId (&Buf), S->Run, SegAddr - S->Run->Start);
E = CreateMemoryExport (GetStrBufId (&Buf), S->Run, SegAddr - S->Run->Start);
E->Pos = S->Pos;
/* Define the size of the segment */
SB_Printf (&Buf, "__%s_SIZE__", GetString (S->Name));
CreateConstExport (GetStrBufId (&Buf), S->Seg->Size);
E = CreateConstExport (GetStrBufId (&Buf), S->Seg->Size);
E->Pos = S->Pos;
S->Flags |= SF_RUN_DEF;
SB_Done (&Buf);
}
@ -1716,10 +1715,14 @@ static void CreateRunDefines (SegDesc* S, unsigned long SegAddr)
static void CreateLoadDefines (SegDesc* S, unsigned long SegAddr)
/* Create the defines for a LOAD segment */
{
Export* E;
StrBuf Buf = STATIC_STRBUF_INITIALIZER;
/* Define the load address of the segment */
SB_Printf (&Buf, "__%s_LOAD__", GetString (S->Name));
CreateMemoryExport (GetStrBufId (&Buf), S->Load, SegAddr - S->Load->Start);
E = CreateMemoryExport (GetStrBufId (&Buf), S->Load, SegAddr - S->Load->Start);
E->Pos = S->Pos;
S->Flags |= SF_LOAD_DEF;
SB_Done (&Buf);
}
@ -1738,11 +1741,13 @@ unsigned CfgProcess (void)
unsigned Overflows = 0;
unsigned I;
/* Do postprocessing of the config file data */
ProcessSymbols (); /* ######## */
ProcessMemory ();
/* Postprocess symbols. We must do that first, since weak symbols are
* defined here, which may be needed later.
*/
ProcessSymbols ();
/* Postprocess segments */
ProcessSegments ();
ProcessFormats ();
/* Walk through each of the memory sections. Add up the sizes and check
* for an overflow of the section. Assign the start addresses of the
@ -1751,12 +1756,35 @@ unsigned CfgProcess (void)
for (I = 0; I < CollCount (&MemoryAreas); ++I) {
unsigned J;
unsigned long Addr;
/* Get this entry */
/* Get the next memory area */
MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
/* Remember if this is a relocatable memory area */
M->Relocatable = RelocatableBinFmt (M->F->Format);
/* Resolve the start address expression */
if (!IsConstExpr (M->StartExpr)) {
CfgError (&M->Pos,
"Start address of memory area `%s' is not constant",
GetString (M->Name));
}
M->Start = GetExprVal (M->StartExpr);
/* Resolve the size expression */
if (!IsConstExpr (M->SizeExpr)) {
CfgError (&M->Pos,
"Size of memory area `%s' is not constant",
GetString (M->Name));
}
M->Size = GetExprVal (M->SizeExpr);
/* Mark the memory area as placed */
M->Flags |= MF_PLACED;
/* Get the start address of this memory area */
unsigned long Addr = M->Start;
Addr = M->Start;
/* Walk through the segments in this memory area */
for (J = 0; J < CollCount (&M->SegList); ++J) {
@ -1855,13 +1883,24 @@ unsigned CfgProcess (void)
/* If requested, define symbols for start and size of the memory area */
if (M->Flags & MF_DEFINE) {
Export* E;
StrBuf Buf = STATIC_STRBUF_INITIALIZER;
/* Define the start of the memory area */
SB_Printf (&Buf, "__%s_START__", GetString (M->Name));
CreateMemoryExport (GetStrBufId (&Buf), M, 0);
E = CreateMemoryExport (GetStrBufId (&Buf), M, 0);
E->Pos = M->Pos;
/* Define the size of the memory area */
SB_Printf (&Buf, "__%s_SIZE__", GetString (M->Name));
CreateConstExport (GetStrBufId (&Buf), M->Size);
E = CreateConstExport (GetStrBufId (&Buf), M->Size);
E->Pos = M->Pos;
/* Define the fill level of the memory area */
SB_Printf (&Buf, "__%s_LAST__", GetString (M->Name));
CreateMemoryExport (GetStrBufId (&Buf), M, M->FillLevel);
E = CreateMemoryExport (GetStrBufId (&Buf), M, M->FillLevel);
E->Pos = M->Pos;
SB_Done (&Buf);
}

View File

@ -40,6 +40,7 @@
/* common */
#include "coll.h"
#include "filepos.h"
/* ld65 */
#include "segments.h"
@ -68,6 +69,7 @@ struct File {
typedef struct SegDesc SegDesc;
struct SegDesc {
unsigned Name; /* Index of the name */
FilePos Pos; /* Position of definition */
Segment* Seg; /* Pointer to segment structure */
unsigned Attr; /* Attributes for segment */
unsigned Flags; /* Set of bitmapped flags */

View File

@ -105,8 +105,8 @@ static Import* NewImport (unsigned char AddrSize, ObjData* Obj)
Import* I = xmalloc (sizeof (Import));
/* Initialize the fields */
I->Next = 0;
I->Obj = Obj;
I->Next = 0;
I->Obj = Obj;
InitFilePos (&I->Pos);
I->Exp = 0;
I->Name = INVALID_STRING_ID;
@ -290,6 +290,7 @@ static Export* NewExport (unsigned char Type, unsigned char AddrSize,
E->ImpCount = 0;
E->ImpList = 0;
E->Expr = 0;
InitFilePos (&E->Pos);
E->Type = Type;
E->AddrSize = AddrSize;
memset (E->ConDes, 0, sizeof (E->ConDes));
@ -467,6 +468,24 @@ Export* CreateConstExport (unsigned Name, long Value)
Export* CreateExprExport (unsigned Name, ExprNode* Expr, unsigned char AddrSize)
/* Create an export for an expression */
{
/* Create a new export */
Export* E = NewExport (SYM_EXPR | SYM_EQUATE, AddrSize, Name, 0);
/* Assign the value expression */
E->Expr = Expr;
/* Insert the export */
InsertExport (E);
/* Return the new export */
return E;
}
Export* CreateMemoryExport (unsigned Name, MemoryArea* Mem, unsigned long Offs)
/* Create an relative export for a memory area offset */
{
@ -590,40 +609,57 @@ static void CheckSymType (const Export* E)
/* Check the types for one export */
{
/* External with matching imports */
Import* Imp = E->ImpList;
while (Imp) {
if (E->AddrSize != Imp->AddrSize) {
/* Export is ZP, import is abs or the other way round */
Import* I = E->ImpList;
while (I) {
if (E->AddrSize != I->AddrSize) {
/* Export and import address sizes do not match */
StrBuf ExportLoc = STATIC_STRBUF_INITIALIZER;
StrBuf ImportLoc = STATIC_STRBUF_INITIALIZER;
const char* ExpAddrSize = AddrSizeToStr (E->AddrSize);
const char* ImpAddrSize = AddrSizeToStr (Imp->AddrSize);
const char* ExpObjName = GetObjFileName (E->Obj);
const char* ImpObjName = GetObjFileName (Imp->Obj);
if (E->Obj) {
/* User defined export */
Warning ("Address size mismatch for `%s': Exported from %s, "
"%s(%lu) as `%s', import in %s, %s(%lu) as `%s'",
GetString (E->Name),
ExpObjName,
GetSourceFileName (E->Obj, E->Pos.Name),
E->Pos.Line,
ExpAddrSize,
ImpObjName,
GetSourceFileName (Imp->Obj, Imp->Pos.Name),
Imp->Pos.Line,
ImpAddrSize);
} else {
/* Export created by the linker */
Warning ("Address size mismatch for `%s': Symbol is `%s'"
", but imported from %s, %s(%lu) as `%s'",
GetString (E->Name),
ExpAddrSize,
ImpObjName,
GetSourceFileName (Imp->Obj, Imp->Pos.Name),
Imp->Pos.Line,
ImpAddrSize);
}
const char* ImpAddrSize = AddrSizeToStr (I->AddrSize);
/* Generate strings that describe the location of the im- and
* exports. This depends on the place from where they come:
* Object file or linker config.
*/
if (E->Obj) {
/* The export comes from an object file */
SB_Printf (&ExportLoc, "%s, %s(%lu)",
GetString (E->Obj->Name),
GetSourceFileName (E->Obj, E->Pos.Name),
E->Pos.Line);
} else {
SB_Printf (&ExportLoc, "%s(%lu)",
GetSourceFileName (E->Obj, E->Pos.Name),
E->Pos.Line);
}
if (I->Obj) {
/* The import comes from an object file */
SB_Printf (&ImportLoc, "%s, %s(%lu)",
GetString (I->Obj->Name),
GetSourceFileName (I->Obj, I->Pos.Name),
I->Pos.Line);
} else {
SB_Printf (&ImportLoc, "%s(%lu)",
GetSourceFileName (I->Obj, I->Pos.Name),
I->Pos.Line);
}
/* Output the diagnostic */
Warning ("Address size mismatch for `%s': "
"Exported from %s as `%s', "
"import in %s as `%s'",
GetString (E->Name),
SB_GetConstBuf (&ExportLoc),
ExpAddrSize,
SB_GetConstBuf (&ImportLoc),
ImpAddrSize);
/* Free the temporary strings */
SB_Done (&ExportLoc);
SB_Done (&ImportLoc);
}
Imp = Imp->Next;
I = I->Next;
}
}

View File

@ -81,8 +81,8 @@ struct Export {
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) */
FilePos Pos; /* File position of definition */
unsigned char Type; /* Type of export */
unsigned char AddrSize; /* Address size of export */
unsigned char ConDes[CD_TYPE_COUNT]; /* Constructor/destructor decls */
@ -136,6 +136,9 @@ void InsertExport (Export* E);
Export* CreateConstExport (unsigned Name, long Value);
/* Create an export for a literal date */
Export* CreateExprExport (unsigned Name, ExprNode* Expr, unsigned char AddrSize);
/* Create an export for an expression */
Export* CreateMemoryExport (unsigned Name, MemoryArea* Mem, unsigned long Offs);
/* Create an relative export for a memory area offset */

View File

@ -81,7 +81,7 @@ ObjData* NewObjData (void)
O->FileCount = 0;
O->Files = EmptyCollection;
O->SectionCount = 0;
O->Sections = EmptyCollection;
O->Sections = EmptyCollection;
O->ExportCount = 0;
O->Exports = EmptyCollection;
O->ImportCount = 0;
@ -198,7 +198,11 @@ const char* GetSourceFileName (const ObjData* O, unsigned Index)
if (O == 0) {
/* No object file */
return "[linker generated]";
if (Index == INVALID_STRING_ID) {
return "[linker generated]";
} else {
return GetString (Index);
}
} else {

View File

@ -122,9 +122,15 @@ typedef enum {
CFGTOK_CONDES,
CFGTOK_STARTADDRESS,
CFGTOK_ADDRSIZE,
CFGTOK_VALUE,
CFGTOK_WEAK,
CFGTOK_ABS,
CFGTOK_FAR,
CFGTOK_LONG,
CFGTOK_SEGMENT,
CFGTOK_LABEL,
CFGTOK_COUNT,
@ -158,7 +164,13 @@ extern cfgtok_t CfgTok;
extern StrBuf CfgSVal;
extern unsigned long CfgIVal;
/* Error location */
/* Error location. PLEASE NOTE: I'm abusing the FilePos structure to some
* degree. It is used mostly to hold a file position, where the Name member
* is an index into the source file table of an object file. As used in config
* file processing, the Name member is a string pool index instead. This is
* distinguished by the object file pointer being NULL or not in the structs
* where this is relevant.
*/
extern FilePos CfgErrorPos;