mirror of
https://github.com/cc65/cc65.git
synced 2024-12-25 17:29:50 +00:00
Separate processing the linker config file into two phases: The config file is
read when the -t or -C switch is encountered and parts of it are processed. The remaining parts are processed when all object files and libraries have been read. To make this work, the expression evaluation in cfgexpr has been rewritten to generate true expression trees. This means that expressions in the linker config may use exports from the object files. Separation of config file processing is the base for several enhancements, for example forced imports by linker config. This code needs more work and is only very, very, very roughly tested. git-svn-id: svn://svn.cc65.org/cc65/trunk@4840 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
6c0a9c0438
commit
da792b3fd0
@ -126,15 +126,15 @@ static void ReadIndexEntry (void)
|
||||
O->Strings[I] = ReadStr (Lib);
|
||||
}
|
||||
|
||||
/* Exports */
|
||||
O->ExportSize = ReadVar (Lib);
|
||||
O->Exports = xmalloc (O->ExportSize);
|
||||
ReadData (Lib, O->Exports, O->ExportSize);
|
||||
|
||||
/* Imports */
|
||||
O->ImportSize = ReadVar (Lib);
|
||||
O->Imports = xmalloc (O->ImportSize);
|
||||
ReadData (Lib, O->Imports, O->ImportSize);
|
||||
|
||||
/* Exports */
|
||||
O->ExportSize = ReadVar (Lib);
|
||||
O->Exports = xmalloc (O->ExportSize);
|
||||
ReadData (Lib, O->Exports, O->ExportSize);
|
||||
}
|
||||
|
||||
|
||||
@ -197,13 +197,13 @@ static void WriteIndexEntry (ObjData* O)
|
||||
WriteStr (NewLib, O->Strings[I]);
|
||||
}
|
||||
|
||||
/* Exports */
|
||||
WriteVar (NewLib, O->ExportSize);
|
||||
WriteData (NewLib, O->Exports, O->ExportSize);
|
||||
|
||||
/* Imports */
|
||||
WriteVar (NewLib, O->ImportSize);
|
||||
WriteData (NewLib, O->Imports, O->ImportSize);
|
||||
|
||||
/* Exports */
|
||||
WriteVar (NewLib, O->ExportSize);
|
||||
WriteData (NewLib, O->Exports, O->ExportSize);
|
||||
}
|
||||
|
||||
|
||||
|
@ -110,8 +110,8 @@ struct ExprNode {
|
||||
long IVal; /* If this is a int value */
|
||||
struct SymEntry* Sym; /* If this is a symbol */
|
||||
unsigned SegNum; /* If this is a segment */
|
||||
unsigned ImpNum; /* If this is an import */
|
||||
struct Memory* Mem; /* If this is a memory area */
|
||||
struct Import* Imp; /* If this is an import */
|
||||
struct MemoryArea* Mem; /* If this is a memory area */
|
||||
struct Segment* Seg; /* If this is a segment */
|
||||
struct Section* Sec; /* If section and Obj is NULL */
|
||||
} V;
|
||||
|
@ -6,8 +6,8 @@
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998-2003 Ullrich von Bassewitz */
|
||||
/* Römerstrasse 52 */
|
||||
/* (C) 1998-2010, Ullrich von Bassewitz */
|
||||
/* Roemerstrasse 52 */
|
||||
/* D-70794 Filderstadt */
|
||||
/* EMail: uz@cc65.org */
|
||||
/* */
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
/* Defines for magic and version */
|
||||
#define LIB_MAGIC 0x7A55616E
|
||||
#define LIB_VERSION 0x000B
|
||||
#define LIB_VERSION 0x000C
|
||||
|
||||
/* Size of an library file header */
|
||||
#define LIB_HDR_SIZE 12
|
||||
|
@ -6,7 +6,7 @@
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1999-2008 Ullrich von Bassewitz */
|
||||
/* (C) 1999-2010, Ullrich von Bassewitz */
|
||||
/* Roemerstrasse 52 */
|
||||
/* D-70794 Filderstadt */
|
||||
/* EMail: uz@cc65.org */
|
||||
@ -50,6 +50,7 @@
|
||||
#include "global.h"
|
||||
#include "fileio.h"
|
||||
#include "lineinfo.h"
|
||||
#include "memarea.h"
|
||||
#include "segments.h"
|
||||
#include "spool.h"
|
||||
|
||||
@ -129,7 +130,7 @@ static void PrintNumVal (const char* Name, unsigned long V)
|
||||
|
||||
|
||||
|
||||
static void BinWriteMem (BinDesc* D, Memory* M)
|
||||
static void BinWriteMem (BinDesc* D, MemoryArea* M)
|
||||
/* Write the segments of one memory area to a file */
|
||||
{
|
||||
/* Get the start address of this memory area */
|
||||
@ -294,9 +295,9 @@ void BinWriteTarget (BinDesc* D, struct File* F)
|
||||
Print (stdout, 1, "Opened `%s'...\n", D->Filename);
|
||||
|
||||
/* Dump all memory areas */
|
||||
for (I = 0; I < CollCount (&F->MemList); ++I) {
|
||||
for (I = 0; I < CollCount (&F->MemoryAreas); ++I) {
|
||||
/* Get this entry */
|
||||
Memory* M = CollAtUnchecked (&F->MemList, I);
|
||||
MemoryArea* M = CollAtUnchecked (&F->MemoryAreas, I);
|
||||
Print (stdout, 1, " Dumping `%s'\n", GetString (M->Name));
|
||||
BinWriteMem (D, M);
|
||||
}
|
||||
|
@ -34,109 +34,47 @@
|
||||
|
||||
|
||||
/* common */
|
||||
#include "addrsize.h"
|
||||
#include "strbuf.h"
|
||||
|
||||
/* ld65 */
|
||||
#include "cfgexpr.h"
|
||||
#include "error.h"
|
||||
#include "exports.h"
|
||||
#include "expr.h"
|
||||
#include "scanner.h"
|
||||
#include "spool.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Type of a CfgExpr */
|
||||
enum {
|
||||
ceEmpty,
|
||||
ceInt,
|
||||
ceString
|
||||
};
|
||||
|
||||
typedef struct CfgExpr CfgExpr;
|
||||
struct CfgExpr {
|
||||
unsigned Type; /* Type of the expression */
|
||||
long IVal; /* Integer value if it's a string */
|
||||
StrBuf SVal; /* String value if it's a string */
|
||||
};
|
||||
|
||||
#define CFGEXPR_INITIALIZER { ceEmpty, 0, STATIC_STRBUF_INITIALIZER }
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Forwards */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void Expr (CfgExpr* E);
|
||||
/* Full expression */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* struct CfgExpr */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void CE_Done (CfgExpr* E)
|
||||
/* Cleanup a CfgExpr struct */
|
||||
{
|
||||
/* If the type is a string, we must delete the string buffer */
|
||||
if (E->Type == ceString) {
|
||||
SB_Done (&E->SVal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void CE_AssureInt (const CfgExpr* E)
|
||||
/* Make sure, E contains an integer */
|
||||
{
|
||||
if (E->Type != ceInt) {
|
||||
CfgError ("Integer type expected");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void Factor (CfgExpr* E)
|
||||
/* Read and return a factor in E */
|
||||
static ExprNode* Factor (void)
|
||||
/* Read and return a factor */
|
||||
{
|
||||
Export* Sym;
|
||||
ExprNode* N = 0; /* Initialize to avoid compiler warnings */
|
||||
Export* E;
|
||||
unsigned Name;
|
||||
|
||||
|
||||
switch (CfgTok) {
|
||||
|
||||
case CFGTOK_IDENT:
|
||||
/* An identifier - search an export with the given name */
|
||||
Sym = FindExport (GetStrBufId (&CfgSVal));
|
||||
if (Sym == 0) {
|
||||
CfgError ("Unknown symbol in expression: `%s'",
|
||||
SB_GetConstBuf (&CfgSVal));
|
||||
}
|
||||
/* We can only handle constants */
|
||||
if (!IsConstExport (Sym)) {
|
||||
CfgError ("Value for symbol `%s' is not constant",
|
||||
SB_GetConstBuf (&CfgSVal));
|
||||
}
|
||||
/* Get the name as an id */
|
||||
Name = GetStrBufId (&CfgSVal);
|
||||
|
||||
/* Use the symbol value */
|
||||
E->IVal = GetExportVal (Sym);
|
||||
E->Type = ceInt;
|
||||
/* Check if we know the symbol already */
|
||||
E = FindExport (Name);
|
||||
if (E != 0 && IsConstExport (E)) {
|
||||
N = LiteralExpr (GetExportVal (E), 0);
|
||||
} else {
|
||||
N = NewExprNode (0, EXPR_SYMBOL);
|
||||
N->V.Imp = InsertImport (GenImport (Name, ADDR_SIZE_ABS));
|
||||
}
|
||||
|
||||
/* Skip the symbol name */
|
||||
CfgNextTok ();
|
||||
@ -144,37 +82,27 @@ static void Factor (CfgExpr* E)
|
||||
|
||||
case CFGTOK_INTCON:
|
||||
/* An integer constant */
|
||||
E->IVal = CfgIVal;
|
||||
E->Type = ceInt;
|
||||
CfgNextTok ();
|
||||
break;
|
||||
|
||||
case CFGTOK_STRCON:
|
||||
/* A string constant */
|
||||
SB_Copy (&E->SVal, &CfgSVal);
|
||||
E->Type = ceString;
|
||||
N = LiteralExpr (CfgIVal, 0);
|
||||
CfgNextTok ();
|
||||
break;
|
||||
|
||||
case CFGTOK_PLUS:
|
||||
/* Unary plus */
|
||||
CfgNextTok ();
|
||||
Factor (E);
|
||||
CE_AssureInt (E);
|
||||
N = Factor ();
|
||||
break;
|
||||
|
||||
case CFGTOK_MINUS:
|
||||
/* Unary minus */
|
||||
CfgNextTok ();
|
||||
Factor (E);
|
||||
CE_AssureInt (E);
|
||||
E->IVal = -E->IVal;
|
||||
N = NewExprNode (0, EXPR_UNARY_MINUS);
|
||||
N->Left = Factor ();
|
||||
break;
|
||||
|
||||
case CFGTOK_LPAR:
|
||||
/* Left parenthesis */
|
||||
CfgNextTok ();
|
||||
Expr (E);
|
||||
N = CfgExpr ();
|
||||
CfgConsume (CFGTOK_RPAR, "')' expected");
|
||||
break;
|
||||
|
||||
@ -182,139 +110,115 @@ static void Factor (CfgExpr* E)
|
||||
CfgError ("Invalid expression: %d", CfgTok);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Return the new expression node */
|
||||
return N;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void Term (CfgExpr* E)
|
||||
static ExprNode* Term (void)
|
||||
/* Multiplicative operators: * and / */
|
||||
{
|
||||
/* Left operand */
|
||||
Factor (E);
|
||||
/* Read left hand side */
|
||||
ExprNode* Root = Factor ();
|
||||
|
||||
/* Handle multiplicative operators */
|
||||
while (CfgTok == CFGTOK_MUL || CfgTok == CFGTOK_DIV) {
|
||||
|
||||
CfgExpr RightSide = CFGEXPR_INITIALIZER;
|
||||
ExprNode* Left;
|
||||
ExprNode* Right;
|
||||
unsigned char Op;
|
||||
|
||||
/* Remember the token, then skip it */
|
||||
cfgtok_t Tok = CfgTok;
|
||||
CfgNextTok ();
|
||||
|
||||
/* Left side must be an int */
|
||||
CE_AssureInt (E);
|
||||
|
||||
/* Get the right operand and make sure it's an int */
|
||||
Factor (&RightSide);
|
||||
CE_AssureInt (&RightSide);
|
||||
/* Move root to left side, then read right side */
|
||||
Left = Root;
|
||||
Right = Factor ();
|
||||
|
||||
/* Handle the operation */
|
||||
switch (Tok) {
|
||||
|
||||
case CFGTOK_MUL:
|
||||
E->IVal *= RightSide.IVal;
|
||||
break;
|
||||
|
||||
case CFGTOK_DIV:
|
||||
if (RightSide.IVal == 0) {
|
||||
CfgError ("Division by zero");
|
||||
case CFGTOK_MUL: Op = EXPR_MUL; break;
|
||||
case CFGTOK_DIV: Op = EXPR_DIV; break;
|
||||
default: Internal ("Unhandled token in Term: %d", Tok);
|
||||
}
|
||||
E->IVal /= RightSide.IVal;
|
||||
break;
|
||||
|
||||
default:
|
||||
Internal ("Unhandled token in Term: %d", Tok);
|
||||
Root = NewExprNode (0, Op);
|
||||
Root->Left = Left;
|
||||
Root->Right = Right;
|
||||
}
|
||||
|
||||
/* Cleanup RightSide (this is not really needed since it may not
|
||||
* contain strings at this point, but call it anyway for clarity.
|
||||
*/
|
||||
CE_Done (&RightSide);
|
||||
}
|
||||
/* Return the expression tree we've created */
|
||||
return Root;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void SimpleExpr (CfgExpr* E)
|
||||
static ExprNode* SimpleExpr (void)
|
||||
/* Additive operators: + and - */
|
||||
{
|
||||
/* Left operand */
|
||||
Term (E);
|
||||
/* Read left hand side */
|
||||
ExprNode* Root = Term ();
|
||||
|
||||
/* Handle additive operators */
|
||||
while (CfgTok == CFGTOK_PLUS || CfgTok == CFGTOK_MINUS) {
|
||||
|
||||
CfgExpr RightSide = CFGEXPR_INITIALIZER;
|
||||
ExprNode* Left;
|
||||
ExprNode* Right;
|
||||
unsigned char Op;
|
||||
|
||||
/* Remember the token, then skip it */
|
||||
cfgtok_t Tok = CfgTok;
|
||||
CfgNextTok ();
|
||||
|
||||
/* Get the right operand */
|
||||
Term (&RightSide);
|
||||
|
||||
/* Make sure, left and right side are of the same type */
|
||||
if (E->Type != RightSide.Type) {
|
||||
CfgError ("Incompatible types in expression");
|
||||
}
|
||||
/* Move root to left side, then read right side */
|
||||
Left = Root;
|
||||
Right = Term ();
|
||||
|
||||
/* Handle the operation */
|
||||
switch (Tok) {
|
||||
|
||||
case CFGTOK_PLUS:
|
||||
/* Plus is defined for strings and ints */
|
||||
if (E->Type == ceInt) {
|
||||
E->IVal += RightSide.IVal;
|
||||
} else if (E->Type == ceString) {
|
||||
SB_Append (&E->SVal, &RightSide.SVal);
|
||||
} else {
|
||||
Internal ("Unhandled type in '+' operator: %u", E->Type);
|
||||
case CFGTOK_PLUS: Op = EXPR_PLUS; break;
|
||||
case CFGTOK_MINUS: Op = EXPR_MINUS; break;
|
||||
default: Internal ("Unhandled token in SimpleExpr: %d", Tok);
|
||||
}
|
||||
break;
|
||||
|
||||
case CFGTOK_MINUS:
|
||||
/* Operands must be ints */
|
||||
CE_AssureInt (E);
|
||||
E->IVal -= RightSide.IVal;
|
||||
break;
|
||||
|
||||
default:
|
||||
Internal ("Unhandled token in SimpleExpr: %d", Tok);
|
||||
Root = NewExprNode (0, Op);
|
||||
Root->Left = Left;
|
||||
Root->Right = Right;
|
||||
}
|
||||
|
||||
/* Cleanup RightSide */
|
||||
CE_Done (&RightSide);
|
||||
}
|
||||
/* Return the expression tree we've created */
|
||||
return Root;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void Expr (CfgExpr* E)
|
||||
ExprNode* CfgExpr (void)
|
||||
/* Full expression */
|
||||
{
|
||||
SimpleExpr (E);
|
||||
return SimpleExpr ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
long CfgIntExpr (void)
|
||||
/* Read an expression, make sure it's an int, and return its value */
|
||||
long CfgConstExpr (void)
|
||||
/* Read an integer expression, make sure its constant and return its value */
|
||||
{
|
||||
long Val;
|
||||
|
||||
CfgExpr E = CFGEXPR_INITIALIZER;
|
||||
|
||||
/* Parse the expression */
|
||||
Expr (&E);
|
||||
ExprNode* Expr = CfgExpr ();
|
||||
|
||||
/* Make sure it's an integer */
|
||||
CE_AssureInt (&E);
|
||||
/* Check that it's const */
|
||||
if (!IsConstExpr (Expr)) {
|
||||
CfgError ("Constant expression expected");
|
||||
}
|
||||
|
||||
/* Get the value */
|
||||
Val = E.IVal;
|
||||
Val = GetExprVal (Expr);
|
||||
|
||||
/* Cleaup E */
|
||||
CE_Done (&E);
|
||||
/* Cleanup E */
|
||||
FreeExpr (Expr);
|
||||
|
||||
/* Return the value */
|
||||
return Val;
|
||||
@ -322,13 +226,13 @@ long CfgIntExpr (void)
|
||||
|
||||
|
||||
|
||||
long CfgCheckedIntExpr (long Min, long Max)
|
||||
long CfgCheckedConstExpr (long Min, long Max)
|
||||
/* Read an expression, make sure it's an int and in range, then return its
|
||||
* value.
|
||||
*/
|
||||
{
|
||||
/* Get the value */
|
||||
long Val = CfgIntExpr ();
|
||||
long Val = CfgConstExpr ();
|
||||
|
||||
/* Check the range */
|
||||
if (Val < Min || Val > Max) {
|
||||
|
@ -6,8 +6,8 @@
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2005, Ullrich von Bassewitz */
|
||||
/* Römerstrasse 52 */
|
||||
/* (C) 2005-2010, Ullrich von Bassewitz */
|
||||
/* Roemerstrasse 52 */
|
||||
/* D-70794 Filderstadt */
|
||||
/* EMail: uz@cc65.org */
|
||||
/* */
|
||||
@ -38,16 +38,24 @@
|
||||
|
||||
|
||||
|
||||
/* common */
|
||||
#include "exprdefs.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
long CfgIntExpr (void);
|
||||
/* Read an expression, make sure it's an int, and return its value */
|
||||
ExprNode* CfgExpr (void);
|
||||
/* Read an integer expression and return its value */
|
||||
|
||||
long CfgCheckedIntExpr (long Min, long Max);
|
||||
long CfgConstExpr (void);
|
||||
/* Read an integer expression, make sure its constant and return its value */
|
||||
|
||||
long CfgCheckedConstExpr (long Min, long Max);
|
||||
/* Read an expression, make sure it's an int and in range, then return its
|
||||
* value.
|
||||
*/
|
||||
|
@ -53,7 +53,9 @@
|
||||
#include "config.h"
|
||||
#include "error.h"
|
||||
#include "exports.h"
|
||||
#include "expr.h"
|
||||
#include "global.h"
|
||||
#include "memarea.h"
|
||||
#include "o65.h"
|
||||
#include "objdata.h"
|
||||
#include "scanner.h"
|
||||
@ -84,7 +86,7 @@ static enum {
|
||||
static Collection FileList = STATIC_COLLECTION_INITIALIZER;
|
||||
|
||||
/* Memory list */
|
||||
static Collection MemoryList = STATIC_COLLECTION_INITIALIZER;
|
||||
static Collection MemoryAreas = STATIC_COLLECTION_INITIALIZER;
|
||||
|
||||
/* Memory attributes */
|
||||
#define MA_START 0x0001
|
||||
@ -95,8 +97,6 @@ static Collection MemoryList = STATIC_COLLECTION_INITIALIZER;
|
||||
#define MA_FILL 0x0020
|
||||
#define MA_FILLVAL 0x0040
|
||||
|
||||
|
||||
|
||||
/* Segment list */
|
||||
static Collection SegDescList = STATIC_COLLECTION_INITIALIZER;
|
||||
|
||||
@ -111,7 +111,30 @@ static Collection SegDescList = STATIC_COLLECTION_INITIALIZER;
|
||||
#define SA_START 0x0080
|
||||
#define SA_OPTIONAL 0x0100
|
||||
|
||||
/* 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 {
|
||||
const char* CfgName; /* Config file name */
|
||||
unsigned CfgLine; /* Config file position */
|
||||
unsigned CfgCol;
|
||||
unsigned Name; /* Symbol name */
|
||||
unsigned Flags; /* Symbol flags */
|
||||
long Val; /* Symbol value if any */
|
||||
};
|
||||
|
||||
/* 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 */
|
||||
|
||||
/* Descriptor holding information about the binary formats */
|
||||
static BinDesc* BinFmtDesc = 0;
|
||||
@ -164,21 +187,21 @@ static File* GetFile (unsigned Name)
|
||||
|
||||
|
||||
|
||||
static void FileInsert (File* F, Memory* M)
|
||||
static void FileInsert (File* F, MemoryArea* M)
|
||||
/* Insert the memory area into the files list */
|
||||
{
|
||||
M->F = F;
|
||||
CollAppend (&F->MemList, M);
|
||||
CollAppend (&F->MemoryAreas, M);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static Memory* CfgFindMemory (unsigned Name)
|
||||
static MemoryArea* CfgFindMemory (unsigned Name)
|
||||
/* Find the memory are with the given name. Return NULL if not found */
|
||||
{
|
||||
unsigned I;
|
||||
for (I = 0; I < CollCount (&MemoryList); ++I) {
|
||||
Memory* M = CollAtUnchecked (&MemoryList, I);
|
||||
for (I = 0; I < CollCount (&MemoryAreas); ++I) {
|
||||
MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
|
||||
if (M->Name == Name) {
|
||||
return M;
|
||||
}
|
||||
@ -188,10 +211,10 @@ static Memory* CfgFindMemory (unsigned Name)
|
||||
|
||||
|
||||
|
||||
static Memory* CfgGetMemory (unsigned Name)
|
||||
static MemoryArea* CfgGetMemory (unsigned Name)
|
||||
/* Find the memory are with the given name. Print an error on an invalid name */
|
||||
{
|
||||
Memory* M = CfgFindMemory (Name);
|
||||
MemoryArea* M = CfgFindMemory (Name);
|
||||
if (M == 0) {
|
||||
CfgError ("Invalid memory area `%s'", GetString (Name));
|
||||
}
|
||||
@ -218,16 +241,7 @@ static SegDesc* CfgFindSegDesc (unsigned Name)
|
||||
|
||||
|
||||
|
||||
static void SegDescInsert (SegDesc* S)
|
||||
/* Insert a segment descriptor into the list of segment descriptors */
|
||||
{
|
||||
/* Insert the struct into the list */
|
||||
CollAppend (&SegDescList, S);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void MemoryInsert (Memory* M, SegDesc* S)
|
||||
static void MemoryInsert (MemoryArea* M, SegDesc* S)
|
||||
/* Insert the segment descriptor into the memory area list */
|
||||
{
|
||||
/* Insert the segment into the segment list of the memory area */
|
||||
@ -242,6 +256,39 @@ static void MemoryInsert (Memory* 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.
|
||||
*/
|
||||
{
|
||||
/* Allocate memory */
|
||||
Symbol* Sym = xmalloc (sizeof (Symbol));
|
||||
|
||||
/* Initialize the fields */
|
||||
Sym->CfgName = CfgGetName ();
|
||||
Sym->CfgLine = CfgErrorLine;
|
||||
Sym->CfgCol = CfgErrorCol;
|
||||
Sym->Name = Name;
|
||||
Sym->Flags = Flags;
|
||||
Sym->Val = Val;
|
||||
|
||||
/* Return the initialized struct */
|
||||
return Sym;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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 */
|
||||
{
|
||||
@ -252,7 +299,7 @@ static File* NewFile (unsigned Name)
|
||||
F->Name = Name;
|
||||
F->Flags = 0;
|
||||
F->Format = BINFMT_DEFAULT;
|
||||
InitCollection (&F->MemList);
|
||||
InitCollection (&F->MemoryAreas);
|
||||
|
||||
/* Insert the struct into the list */
|
||||
CollAppend (&FileList, F);
|
||||
@ -263,32 +310,20 @@ static File* NewFile (unsigned Name)
|
||||
|
||||
|
||||
|
||||
static Memory* NewMemory (unsigned Name)
|
||||
/* Create a new memory section and insert it into the list */
|
||||
static MemoryArea* CreateMemoryArea (unsigned Name)
|
||||
/* Create a new memory area and insert it into the list */
|
||||
{
|
||||
/* Check for duplicate names */
|
||||
Memory* M = CfgFindMemory (Name);
|
||||
MemoryArea* M = CfgFindMemory (Name);
|
||||
if (M) {
|
||||
CfgError ("Memory area `%s' defined twice", GetString (Name));
|
||||
}
|
||||
|
||||
/* Allocate memory */
|
||||
M = xmalloc (sizeof (Memory));
|
||||
/* Create a new memory area */
|
||||
M = NewMemoryArea (Name);
|
||||
|
||||
/* Initialize the fields */
|
||||
M->Name = Name;
|
||||
M->Attr = 0;
|
||||
M->Flags = 0;
|
||||
M->Start = 0;
|
||||
M->Size = 0;
|
||||
M->FillLevel = 0;
|
||||
M->FillVal = 0;
|
||||
M->Relocatable = 0;
|
||||
InitCollection (&M->SegList);
|
||||
M->F = 0;
|
||||
|
||||
/* Insert the struct into the list */
|
||||
CollAppend (&MemoryList, M);
|
||||
/* Insert the struct into the list ... */
|
||||
CollAppend (&MemoryAreas, M);
|
||||
|
||||
/* ...and return it */
|
||||
return M;
|
||||
@ -297,9 +332,8 @@ static Memory* NewMemory (unsigned Name)
|
||||
|
||||
|
||||
static SegDesc* NewSegDesc (unsigned Name)
|
||||
/* Create a segment descriptor */
|
||||
/* Create a segment descriptor and insert it into the list */
|
||||
{
|
||||
Segment* Seg;
|
||||
|
||||
/* Check for duplicate names */
|
||||
SegDesc* S = CfgFindSegDesc (Name);
|
||||
@ -307,21 +341,19 @@ static SegDesc* NewSegDesc (unsigned Name)
|
||||
CfgError ("Segment `%s' defined twice", GetString (Name));
|
||||
}
|
||||
|
||||
/* Search for the actual segment in the input files. The function may
|
||||
* return NULL (no such segment), this is checked later.
|
||||
*/
|
||||
Seg = SegFind (Name);
|
||||
|
||||
/* Allocate memory */
|
||||
S = xmalloc (sizeof (SegDesc));
|
||||
|
||||
/* Initialize the fields */
|
||||
S->Name = Name;
|
||||
S->Seg = Seg;
|
||||
S->Seg = 0;
|
||||
S->Attr = 0;
|
||||
S->Flags = 0;
|
||||
S->Align = 0;
|
||||
|
||||
/* Insert the struct into the list ... */
|
||||
CollAppend (&SegDescList, S);
|
||||
|
||||
/* ...and return it */
|
||||
return S;
|
||||
}
|
||||
@ -337,7 +369,7 @@ static void FreeSegDesc (SegDesc* S)
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/* Config file parsing */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
@ -385,7 +417,7 @@ static void ParseMemory (void)
|
||||
while (CfgTok == CFGTOK_IDENT) {
|
||||
|
||||
/* Create a new entry on the heap */
|
||||
Memory* M = NewMemory (GetStrBufId (&CfgSVal));
|
||||
MemoryArea* M = CreateMemoryArea (GetStrBufId (&CfgSVal));
|
||||
|
||||
/* Skip the name and the following colon */
|
||||
CfgNextTok ();
|
||||
@ -408,12 +440,12 @@ static void ParseMemory (void)
|
||||
|
||||
case CFGTOK_START:
|
||||
FlagAttr (&M->Attr, MA_START, "START");
|
||||
M->Start = CfgIntExpr ();
|
||||
M->StartExpr = CfgExpr ();
|
||||
break;
|
||||
|
||||
case CFGTOK_SIZE:
|
||||
FlagAttr (&M->Attr, MA_SIZE, "SIZE");
|
||||
M->Size = CfgIntExpr ();
|
||||
M->SizeExpr = CfgExpr ();
|
||||
break;
|
||||
|
||||
case CFGTOK_TYPE:
|
||||
@ -455,7 +487,7 @@ static void ParseMemory (void)
|
||||
|
||||
case CFGTOK_FILLVAL:
|
||||
FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
|
||||
M->FillVal = (unsigned char) CfgCheckedIntExpr (0, 0xFF);
|
||||
M->FillVal = (unsigned char) CfgCheckedConstExpr (0, 0xFF);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -640,7 +672,7 @@ static void ParseSegments (void)
|
||||
|
||||
case CFGTOK_ALIGN:
|
||||
FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
|
||||
Val = CfgCheckedIntExpr (1, 0x10000);
|
||||
Val = CfgCheckedConstExpr (1, 0x10000);
|
||||
S->Align = BitFind (Val);
|
||||
if ((0x01L << S->Align) != Val) {
|
||||
CfgError ("Alignment must be a power of 2");
|
||||
@ -650,7 +682,7 @@ static void ParseSegments (void)
|
||||
|
||||
case CFGTOK_ALIGN_LOAD:
|
||||
FlagAttr (&S->Attr, SA_ALIGN_LOAD, "ALIGN_LOAD");
|
||||
Val = CfgCheckedIntExpr (1, 0x10000);
|
||||
Val = CfgCheckedConstExpr (1, 0x10000);
|
||||
S->AlignLoad = BitFind (Val);
|
||||
if ((0x01L << S->AlignLoad) != Val) {
|
||||
CfgError ("Alignment must be a power of 2");
|
||||
@ -676,7 +708,7 @@ static void ParseSegments (void)
|
||||
|
||||
case CFGTOK_OFFSET:
|
||||
FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
|
||||
S->Addr = CfgCheckedIntExpr (1, 0x1000000);
|
||||
S->Addr = CfgCheckedConstExpr (1, 0x1000000);
|
||||
S->Flags |= SF_OFFSET;
|
||||
break;
|
||||
|
||||
@ -697,7 +729,7 @@ static void ParseSegments (void)
|
||||
|
||||
case CFGTOK_START:
|
||||
FlagAttr (&S->Attr, SA_START, "START");
|
||||
S->Addr = CfgCheckedIntExpr (1, 0x1000000);
|
||||
S->Addr = CfgCheckedConstExpr (1, 0x1000000);
|
||||
S->Flags |= SF_START;
|
||||
break;
|
||||
|
||||
@ -732,15 +764,6 @@ static void ParseSegments (void)
|
||||
S->Run = S->Load;
|
||||
}
|
||||
|
||||
/* If the segment is marked as BSS style, and if the segment exists
|
||||
* in any of the object file, check that there's no initialized data
|
||||
* in the segment.
|
||||
*/
|
||||
if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
|
||||
Warning ("%s(%u): Segment with type `bss' contains initialized data",
|
||||
CfgGetName (), CfgErrorLine);
|
||||
}
|
||||
|
||||
/* An attribute of ALIGN_LOAD doesn't make sense if there are no
|
||||
* separate run and load memory areas.
|
||||
*/
|
||||
@ -776,29 +799,6 @@ static void ParseSegments (void)
|
||||
CfgError ("Only one of ALIGN, START, OFFSET may be used");
|
||||
}
|
||||
|
||||
/* If this segment does exist in any of the object files, insert the
|
||||
* descriptor into the list of segment descriptors. Otherwise print a
|
||||
* warning and discard it, because the segment pointer in the
|
||||
* descriptor is invalid.
|
||||
*/
|
||||
if (S->Seg != 0) {
|
||||
/* Insert the descriptor into the list of all descriptors */
|
||||
SegDescInsert (S);
|
||||
/* Insert the segment into the memory area list */
|
||||
MemoryInsert (S->Run, S);
|
||||
if (S->Load != S->Run) {
|
||||
/* We have separate RUN and LOAD areas */
|
||||
MemoryInsert (S->Load, S);
|
||||
}
|
||||
} else {
|
||||
/* Print a warning if the segment is not optional */
|
||||
if ((S->Flags & SF_OPTIONAL) == 0) {
|
||||
CfgWarning ("Segment `%s' does not exist", GetString (S->Name));
|
||||
}
|
||||
/* Discard the descriptor */
|
||||
FreeSegDesc (S);
|
||||
}
|
||||
|
||||
/* Skip the semicolon */
|
||||
CfgConsumeSemi ();
|
||||
}
|
||||
@ -845,7 +845,6 @@ static void ParseO65 (void)
|
||||
unsigned AttrFlags = atNone;
|
||||
|
||||
/* Remember the attributes read */
|
||||
unsigned CfgSValId;
|
||||
unsigned OS = 0; /* Initialize to keep gcc happy */
|
||||
unsigned Version = 0;
|
||||
|
||||
@ -869,23 +868,8 @@ static void ParseO65 (void)
|
||||
AttrFlags |= atExport;
|
||||
/* We expect an identifier */
|
||||
CfgAssureIdent ();
|
||||
/* Convert the string into a string index */
|
||||
CfgSValId = GetStrBufId (&CfgSVal);
|
||||
/* Check if the export symbol is also defined as an import. */
|
||||
if (O65GetImport (O65FmtDesc, CfgSValId) != 0) {
|
||||
CfgError ("Exported symbol `%s' cannot be an import",
|
||||
SB_GetConstBuf (&CfgSVal));
|
||||
}
|
||||
/* 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, CfgSValId) != 0) {
|
||||
CfgError ("Duplicate exported symbol: `%s'",
|
||||
SB_GetConstBuf (&CfgSVal));
|
||||
}
|
||||
/* Insert the symbol into the table */
|
||||
O65SetExport (O65FmtDesc, CfgSValId);
|
||||
/* Remember it as an export for later */
|
||||
CollAppend (&O65Exports, NewO65Symbol ());
|
||||
/* Eat the identifier token */
|
||||
CfgNextTok ();
|
||||
break;
|
||||
@ -895,23 +879,8 @@ static void ParseO65 (void)
|
||||
AttrFlags |= atImport;
|
||||
/* We expect an identifier */
|
||||
CfgAssureIdent ();
|
||||
/* Convert the string into a string index */
|
||||
CfgSValId = GetStrBufId (&CfgSVal);
|
||||
/* Check if the imported symbol is also defined as an export. */
|
||||
if (O65GetExport (O65FmtDesc, CfgSValId) != 0) {
|
||||
CfgError ("Imported symbol `%s' cannot be an export",
|
||||
SB_GetConstBuf (&CfgSVal));
|
||||
}
|
||||
/* 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, CfgSValId) != 0) {
|
||||
CfgError ("Duplicate imported symbol: `%s'",
|
||||
SB_GetConstBuf (&CfgSVal));
|
||||
}
|
||||
/* Insert the symbol into the table */
|
||||
O65SetImport (O65FmtDesc, CfgSValId);
|
||||
/* Remember it as an import for later */
|
||||
CollAppend (&O65Imports, NewO65Symbol ());
|
||||
/* Eat the identifier token */
|
||||
CfgNextTok ();
|
||||
break;
|
||||
@ -964,14 +933,14 @@ static void ParseO65 (void)
|
||||
/* Cannot have this attribute twice */
|
||||
FlagAttr (&AttrFlags, atID, "ID");
|
||||
/* We're expecting a number in the 0..$FFFF range*/
|
||||
ModuleId = (unsigned) CfgCheckedIntExpr (0, 0xFFFF);
|
||||
ModuleId = (unsigned) CfgCheckedConstExpr (0, 0xFFFF);
|
||||
break;
|
||||
|
||||
case CFGTOK_VERSION:
|
||||
/* Cannot have this attribute twice */
|
||||
FlagAttr (&AttrFlags, atVersion, "VERSION");
|
||||
/* We're expecting a number in byte range */
|
||||
Version = (unsigned) CfgCheckedIntExpr (0, 0xFF);
|
||||
Version = (unsigned) CfgCheckedConstExpr (0, 0xFF);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1237,7 +1206,7 @@ static void ParseStartAddress (void)
|
||||
/* Don't allow this twice */
|
||||
FlagAttr (&AttrFlags, atDefault, "DEFAULT");
|
||||
/* We expect a numeric expression */
|
||||
DefStartAddr = CfgCheckedIntExpr (0, 0xFFFFFF);
|
||||
DefStartAddr = CfgCheckedConstExpr (0, 0xFFFFFF);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1322,8 +1291,7 @@ static void ParseSymbols (void)
|
||||
while (CfgTok == CFGTOK_IDENT) {
|
||||
|
||||
long Val = 0L;
|
||||
int Weak = 0;
|
||||
Export* E;
|
||||
unsigned Flags = SYM_NONE;
|
||||
|
||||
/* Remember the name */
|
||||
unsigned Name = GetStrBufId (&CfgSVal);
|
||||
@ -1343,7 +1311,10 @@ static void ParseSymbols (void)
|
||||
/* Make sure the next token is an integer expression, read and
|
||||
* skip it.
|
||||
*/
|
||||
Val = CfgIntExpr ();
|
||||
Val = CfgConstExpr ();
|
||||
|
||||
/* This is a defined symbol */
|
||||
Flags = SYM_DEF;
|
||||
|
||||
} else {
|
||||
|
||||
@ -1380,14 +1351,18 @@ static void ParseSymbols (void)
|
||||
/* Don't allow this twice */
|
||||
FlagAttr (&AttrFlags, atValue, "VALUE");
|
||||
/* We expect a numeric expression */
|
||||
Val = CfgIntExpr ();
|
||||
Val = CfgConstExpr ();
|
||||
/* Symbol is defined */
|
||||
Flags |= SYM_DEF;
|
||||
break;
|
||||
|
||||
case CFGTOK_WEAK:
|
||||
/* Don't allow this twice */
|
||||
FlagAttr (&AttrFlags, atWeak, "WEAK");
|
||||
CfgBoolToken ();
|
||||
Weak = (CfgTok == CFGTOK_TRUE);
|
||||
if (CfgTok == CFGTOK_TRUE) {
|
||||
Flags |= SYM_WEAK;
|
||||
}
|
||||
CfgNextTok ();
|
||||
break;
|
||||
|
||||
@ -1406,26 +1381,10 @@ static void ParseSymbols (void)
|
||||
|
||||
/* Check if we have all mandatory attributes */
|
||||
AttrCheck (AttrFlags, atValue, "VALUE");
|
||||
|
||||
/* Weak is optional, the default are non weak symbols */
|
||||
if ((AttrFlags & atWeak) == 0) {
|
||||
Weak = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Check if the symbol is already defined */
|
||||
if ((E = FindExport (Name)) != 0 && !IsUnresolvedExport (E)) {
|
||||
/* If the symbol is not marked as weak, this is an error.
|
||||
* Otherwise ignore the symbol from the config.
|
||||
*/
|
||||
if (!Weak) {
|
||||
CfgError ("Symbol `%s' is already defined", GetString (Name));
|
||||
}
|
||||
} else {
|
||||
/* The symbol is undefined, generate an export */
|
||||
CreateConstExport (Name, Val);
|
||||
}
|
||||
/* Remember the symbol for later */
|
||||
CollAppend (&Symbols, NewSymbol (Name, Flags, Val));
|
||||
|
||||
/* Skip the semicolon */
|
||||
CfgConsumeSemi ();
|
||||
@ -1521,6 +1480,220 @@ void CfgRead (void)
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Config file processing */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
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)) {
|
||||
Error ("Start address of memory area `%s' is not constant",
|
||||
GetString (M->Name));
|
||||
}
|
||||
M->Start = GetExprVal (M->StartExpr);
|
||||
|
||||
if (!IsConstExpr (M->SizeExpr)) {
|
||||
Error ("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 */
|
||||
{
|
||||
unsigned I;
|
||||
|
||||
/* Walk over the list of segment descriptors */
|
||||
I = 0;
|
||||
while (I < CollCount (&SegDescList)) {
|
||||
|
||||
/* Get the next segment descriptor */
|
||||
SegDesc* S = CollAtUnchecked (&SegDescList, I);
|
||||
|
||||
/* Search for the actual segment in the input files. The function may
|
||||
* return NULL (no such segment), this is checked later.
|
||||
*/
|
||||
S->Seg = SegFind (S->Name);
|
||||
|
||||
/* If the segment is marked as BSS style, and if the segment exists
|
||||
* in any of the object file, check that there's no initialized data
|
||||
* in the segment.
|
||||
*/
|
||||
if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
|
||||
Warning ("Segment `%s' with type `bss' contains initialized data",
|
||||
GetString (S->Name));
|
||||
}
|
||||
|
||||
/* If this segment does exist in any of the object files, insert the
|
||||
* segment into the load/run memory areas. Otherwise print a warning
|
||||
* and discard it, because the segment pointer in the descriptor is
|
||||
* invalid.
|
||||
*/
|
||||
if (S->Seg != 0) {
|
||||
|
||||
/* Insert the segment into the memory area list */
|
||||
MemoryInsert (S->Run, S);
|
||||
if (S->Load != S->Run) {
|
||||
/* We have separate RUN and LOAD areas */
|
||||
MemoryInsert (S->Load, S);
|
||||
}
|
||||
|
||||
/* Process the next segment descriptor in the next run */
|
||||
++I;
|
||||
|
||||
} else {
|
||||
|
||||
/* Print a warning if the segment is not optional */
|
||||
if ((S->Flags & SF_OPTIONAL) == 0) {
|
||||
CfgWarning ("Segment `%s' does not exist", GetString (S->Name));
|
||||
}
|
||||
|
||||
/* Discard the descriptor and remove it from the collection */
|
||||
FreeSegDesc (S);
|
||||
CollDelete (&SegDescList, I);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
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) {
|
||||
Error ("%s(%u): Duplicate imported o65 symbol: `%s'",
|
||||
Sym->CfgName, Sym->CfgLine, 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) {
|
||||
Error ("%s(%u): Exported o65 symbol `%s' cannot also be an o65 import",
|
||||
Sym->CfgName, Sym->CfgLine, 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) {
|
||||
Error ("%s(%u): Duplicate exported o65 symbol: `%s'",
|
||||
Sym->CfgName, Sym->CfgLine, 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 */
|
||||
{
|
||||
Export* E;
|
||||
|
||||
/* Walk over all symbols */
|
||||
unsigned I;
|
||||
for (I = 0; I < CollCount (&Symbols); ++I) {
|
||||
|
||||
/* Get the next symbol */
|
||||
Symbol* Sym = CollAtUnchecked (&Symbols, 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 ("Symbol `%s' is already defined",
|
||||
GetString (Sym->Name));
|
||||
}
|
||||
} else {
|
||||
/* The symbol is undefined, generate an export */
|
||||
CreateConstExport (Sym->Name, Sym->Val);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CfgProcess (void)
|
||||
/* Process the config file after reading in object files and libraries */
|
||||
{
|
||||
ProcessSymbols (); /* ######## */
|
||||
ProcessMemory ();
|
||||
ProcessSegments ();
|
||||
ProcessFormats ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void CreateRunDefines (SegDesc* S, unsigned long SegAddr)
|
||||
/* Create the defines for a RUN segment */
|
||||
{
|
||||
@ -1563,19 +1736,16 @@ unsigned CfgAssignSegments (void)
|
||||
* segments while doing this.
|
||||
*/
|
||||
unsigned I;
|
||||
for (I = 0; I < CollCount (&MemoryList); ++I) {
|
||||
for (I = 0; I < CollCount (&MemoryAreas); ++I) {
|
||||
|
||||
unsigned J;
|
||||
|
||||
/* Get this entry */
|
||||
Memory* M = CollAtUnchecked (&MemoryList, I);
|
||||
MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
|
||||
|
||||
/* Get the start address of this memory area */
|
||||
unsigned long Addr = M->Start;
|
||||
|
||||
/* Remember if this is a relocatable memory area */
|
||||
M->Relocatable = RelocatableBinFmt (M->F->Format);
|
||||
|
||||
/* Walk through the segments in this memory area */
|
||||
for (J = 0; J < CollCount (&M->SegList); ++J) {
|
||||
|
||||
@ -1622,6 +1792,9 @@ unsigned CfgAssignSegments (void)
|
||||
S->Seg->ReadOnly = (S->Flags & SF_RO) != 0;
|
||||
S->Seg->Relocatable = M->Relocatable;
|
||||
|
||||
/* Remember that this segment is placed */
|
||||
S->Seg->Placed = 1;
|
||||
|
||||
} else if (S->Load == M) {
|
||||
|
||||
/* This is the load memory area, *and* run and load are
|
||||
@ -1696,7 +1869,7 @@ void CfgWriteTarget (void)
|
||||
File* F = CollAtUnchecked (&FileList, I);
|
||||
|
||||
/* We don't need to look at files with no memory areas */
|
||||
if (CollCount (&F->MemList) > 0) {
|
||||
if (CollCount (&F->MemoryAreas) > 0) {
|
||||
|
||||
/* Is there an output file? */
|
||||
if (SB_GetLen (GetStrBuf (F->Name)) > 0) {
|
||||
@ -1728,12 +1901,12 @@ void CfgWriteTarget (void)
|
||||
* loading into these memory areas in this file as dumped.
|
||||
*/
|
||||
unsigned J;
|
||||
for (J = 0; J < CollCount (&F->MemList); ++J) {
|
||||
for (J = 0; J < CollCount (&F->MemoryAreas); ++J) {
|
||||
|
||||
unsigned K;
|
||||
|
||||
/* Get this entry */
|
||||
Memory* M = CollAtUnchecked (&F->MemList, J);
|
||||
MemoryArea* M = CollAtUnchecked (&F->MemoryAreas, J);
|
||||
|
||||
/* Debugging */
|
||||
Print (stdout, 2, "Skipping `%s'...\n", GetString (M->Name));
|
||||
|
@ -52,28 +52,16 @@
|
||||
|
||||
|
||||
|
||||
/* Forward for struct MemoryArea */
|
||||
struct MemoryArea;
|
||||
|
||||
/* File list entry */
|
||||
typedef struct File File;
|
||||
struct File {
|
||||
unsigned Name; /* Name index of the file */
|
||||
unsigned Flags;
|
||||
unsigned Format; /* Output format */
|
||||
Collection MemList; /* List of memory areas in this file */
|
||||
};
|
||||
|
||||
/* Memory list entry */
|
||||
typedef struct Memory Memory;
|
||||
struct Memory {
|
||||
unsigned Name; /* Name index of the memory section */
|
||||
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 */
|
||||
unsigned char Relocatable; /* Memory area is relocatable */
|
||||
Collection SegList; /* List of segments for this section */
|
||||
File* F; /* File that contains the entry */
|
||||
Collection MemoryAreas; /* List of memory areas in this file */
|
||||
};
|
||||
|
||||
/* Segment descriptor entry */
|
||||
@ -83,19 +71,13 @@ struct SegDesc {
|
||||
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 */
|
||||
struct MemoryArea* Load; /* Load memory section */
|
||||
struct MemoryArea* Run; /* Run memory section */
|
||||
unsigned long Addr; /* Start address or offset into segment */
|
||||
unsigned char Align; /* Run area alignment if given */
|
||||
unsigned char AlignLoad; /* Load area alignment if given */
|
||||
};
|
||||
|
||||
/* Memory flags */
|
||||
#define MF_DEFINE 0x0001 /* Define start and size */
|
||||
#define MF_FILL 0x0002 /* Fill segment */
|
||||
#define MF_RO 0x0004 /* Read only memory area */
|
||||
#define MF_OVERFLOW 0x0008 /* Memory area overflow */
|
||||
|
||||
/* Segment flags */
|
||||
#define SF_RO 0x0001 /* Read only segment */
|
||||
#define SF_BSS 0x0002 /* Segment is BSS style segment */
|
||||
@ -120,6 +102,9 @@ struct SegDesc {
|
||||
void CfgRead (void);
|
||||
/* Read the configuration */
|
||||
|
||||
void CfgProcess (void);
|
||||
/* Process the config file after reading in object files and libraries */
|
||||
|
||||
unsigned CfgAssignSegments (void);
|
||||
/* Assign segments, define linker symbols where requested. The function will
|
||||
* return the number of memory area overflows (so zero means anything went ok).
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include "expr.h"
|
||||
#include "fileio.h"
|
||||
#include "global.h"
|
||||
#include "memarea.h"
|
||||
#include "objdata.h"
|
||||
#include "spool.h"
|
||||
|
||||
@ -176,14 +177,14 @@ Import* ReadImport (FILE* F, ObjData* Obj)
|
||||
|
||||
|
||||
|
||||
Import* GenImport (const char* Name, unsigned char AddrSize)
|
||||
Import* GenImport (unsigned Name, unsigned char AddrSize)
|
||||
/* Generate a new import with the given name and address size and return it */
|
||||
{
|
||||
/* Create a new import */
|
||||
Import* I = NewImport (AddrSize, 0);
|
||||
|
||||
/* Read the name */
|
||||
I->Name = GetStringId (Name);
|
||||
I->Name = Name;
|
||||
|
||||
/* Check the address size */
|
||||
if (I->AddrSize == ADDR_SIZE_DEFAULT || I->AddrSize > ADDR_SIZE_LONG) {
|
||||
@ -211,8 +212,8 @@ Import* GenImport (const char* Name, unsigned char AddrSize)
|
||||
|
||||
|
||||
|
||||
void InsertImport (Import* I)
|
||||
/* Insert an import into the table */
|
||||
Import* InsertImport (Import* I)
|
||||
/* Insert an import into the table, return I */
|
||||
{
|
||||
Export* E;
|
||||
|
||||
@ -261,6 +262,9 @@ void InsertImport (Import* I)
|
||||
|
||||
/* Mark the import so we know it's in the list */
|
||||
I->Flags |= IMP_INLIST;
|
||||
|
||||
/* Return the import to allow shorter code */
|
||||
return I;
|
||||
}
|
||||
|
||||
|
||||
@ -463,7 +467,7 @@ Export* CreateConstExport (unsigned Name, long Value)
|
||||
|
||||
|
||||
|
||||
Export* CreateMemoryExport (unsigned Name, Memory* Mem, unsigned long Offs)
|
||||
Export* CreateMemoryExport (unsigned Name, MemoryArea* Mem, unsigned long Offs)
|
||||
/* Create an relative export for a memory area offset */
|
||||
{
|
||||
/* Create a new export */
|
||||
|
@ -6,7 +6,7 @@
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998-2009, Ullrich von Bassewitz */
|
||||
/* (C) 1998-2010, Ullrich von Bassewitz */
|
||||
/* Roemerstrasse 52 */
|
||||
/* D-70794 Filderstadt */
|
||||
/* EMail: uz@cc65.org */
|
||||
@ -46,8 +46,9 @@
|
||||
#include "filepos.h"
|
||||
|
||||
/* ld65 */
|
||||
#include "objdata.h"
|
||||
#include "config.h"
|
||||
#include "memarea.h"
|
||||
#include "objdata.h"
|
||||
|
||||
|
||||
|
||||
@ -114,11 +115,11 @@ void FreeImport (Import* I);
|
||||
Import* ReadImport (FILE* F, ObjData* Obj);
|
||||
/* Read an import from a file and insert it into the table */
|
||||
|
||||
Import* GenImport (const char* Name, unsigned char AddrSize);
|
||||
Import* GenImport (unsigned Name, unsigned char AddrSize);
|
||||
/* Generate a new import with the given name and address size and return it */
|
||||
|
||||
void InsertImport (Import* I);
|
||||
/* Insert an import into the table */
|
||||
Import* InsertImport (Import* I);
|
||||
/* Insert an import into the table, return I */
|
||||
|
||||
void FreeExport (Export* E);
|
||||
/* Free an export. NOTE: This won't remove the export from the exports table,
|
||||
@ -135,7 +136,7 @@ void InsertExport (Export* E);
|
||||
Export* CreateConstExport (unsigned Name, long Value);
|
||||
/* Create an export for a literal date */
|
||||
|
||||
Export* CreateMemoryExport (unsigned Name, Memory* Mem, unsigned long Offs);
|
||||
Export* CreateMemoryExport (unsigned Name, MemoryArea* Mem, unsigned long Offs);
|
||||
/* Create an relative export for a memory area offset */
|
||||
|
||||
Export* CreateSegmentExport (unsigned Name, Segment* Seg, unsigned long Offs);
|
||||
|
@ -42,23 +42,24 @@
|
||||
#include "global.h"
|
||||
#include "error.h"
|
||||
#include "fileio.h"
|
||||
#include "memarea.h"
|
||||
#include "segments.h"
|
||||
#include "expr.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Helpers */
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static ExprNode* NewExprNode (ObjData* O)
|
||||
ExprNode* NewExprNode (ObjData* O, unsigned char Op)
|
||||
/* Create a new expression node */
|
||||
{
|
||||
/* Allocate fresh memory */
|
||||
ExprNode* N = xmalloc (sizeof (ExprNode));
|
||||
N->Op = EXPR_NULL;
|
||||
N->Op = Op;
|
||||
N->Left = 0;
|
||||
N->Right = 0;
|
||||
N->Obj = O;
|
||||
@ -78,12 +79,6 @@ static void FreeExprNode (ExprNode* E)
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void FreeExpr (ExprNode* Root)
|
||||
/* Free the expression, Root is pointing to. */
|
||||
{
|
||||
@ -130,18 +125,19 @@ int IsConstExpr (ExprNode* Root)
|
||||
|
||||
case EXPR_SECTION:
|
||||
/* A section expression is const if the segment it is in is
|
||||
* not relocatable.
|
||||
* not relocatable and already placed.
|
||||
*/
|
||||
S = GetExprSection (Root);
|
||||
return !S->Seg->Relocatable;
|
||||
return !S->Seg->Relocatable && S->Seg->Placed;
|
||||
|
||||
case EXPR_SEGMENT:
|
||||
/* A segment is const if it is not relocatable */
|
||||
return !Root->V.Seg->Relocatable;
|
||||
/* A segment is const if it is not relocatable and placed */
|
||||
return !Root->V.Seg->Relocatable && Root->V.Seg->Placed;
|
||||
|
||||
case EXPR_MEMAREA:
|
||||
/* A memory area is const if it is not relocatable */
|
||||
return !Root->V.Mem->Relocatable;
|
||||
/* A memory area is const if it is not relocatable and placed */
|
||||
return !Root->V.Mem->Relocatable &&
|
||||
(Root->V.Mem->Flags & MF_PLACED);
|
||||
|
||||
default:
|
||||
/* Anything else is not const */
|
||||
@ -201,7 +197,7 @@ Import* GetExprImport (ExprNode* Expr)
|
||||
PRECONDITION (Expr->Op == EXPR_SYMBOL);
|
||||
|
||||
/* Return the import */
|
||||
return CollAt (&Expr->Obj->Imports, Expr->V.ImpNum);
|
||||
return Expr->V.Imp;
|
||||
}
|
||||
|
||||
|
||||
@ -397,26 +393,23 @@ long GetExprVal (ExprNode* Expr)
|
||||
ExprNode* LiteralExpr (long Val, ObjData* O)
|
||||
/* Return an expression tree that encodes the given literal value */
|
||||
{
|
||||
ExprNode* Expr = NewExprNode (O);
|
||||
Expr->Op = EXPR_LITERAL;
|
||||
ExprNode* Expr = NewExprNode (O, EXPR_LITERAL);
|
||||
Expr->V.IVal = Val;
|
||||
return Expr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ExprNode* MemoryExpr (Memory* Mem, long Offs, ObjData* O)
|
||||
ExprNode* MemoryExpr (MemoryArea* Mem, long Offs, ObjData* O)
|
||||
/* Return an expression tree that encodes an offset into a memory area */
|
||||
{
|
||||
ExprNode* Root;
|
||||
|
||||
ExprNode* Expr = NewExprNode (O);
|
||||
Expr->Op = EXPR_MEMAREA;
|
||||
ExprNode* Expr = NewExprNode (O, EXPR_MEMAREA);
|
||||
Expr->V.Mem = Mem;
|
||||
|
||||
if (Offs != 0) {
|
||||
Root = NewExprNode (O);
|
||||
Root->Op = EXPR_PLUS;
|
||||
Root = NewExprNode (O, EXPR_PLUS);
|
||||
Root->Left = Expr;
|
||||
Root->Right = LiteralExpr (Offs, O);
|
||||
} else {
|
||||
@ -433,13 +426,11 @@ ExprNode* SegmentExpr (Segment* Seg, long Offs, ObjData* O)
|
||||
{
|
||||
ExprNode* Root;
|
||||
|
||||
ExprNode* Expr = NewExprNode (O);
|
||||
Expr->Op = EXPR_SEGMENT;
|
||||
ExprNode* Expr = NewExprNode (O, EXPR_SEGMENT);
|
||||
Expr->V.Seg = Seg;
|
||||
|
||||
if (Offs != 0) {
|
||||
Root = NewExprNode (O);
|
||||
Root->Op = EXPR_PLUS;
|
||||
Root = NewExprNode (O, EXPR_PLUS);
|
||||
Root->Left = Expr;
|
||||
Root->Right = LiteralExpr (Offs, O);
|
||||
} else {
|
||||
@ -456,13 +447,11 @@ ExprNode* SectionExpr (Section* Sec, long Offs, ObjData* O)
|
||||
{
|
||||
ExprNode* Root;
|
||||
|
||||
ExprNode* Expr = NewExprNode (O);
|
||||
Expr->Op = EXPR_SECTION;
|
||||
ExprNode* Expr = NewExprNode (O, EXPR_SECTION);
|
||||
Expr->V.Sec = Sec;
|
||||
|
||||
if (Offs != 0) {
|
||||
Root = NewExprNode (O);
|
||||
Root->Op = EXPR_PLUS;
|
||||
Root = NewExprNode (O, EXPR_PLUS);
|
||||
Root->Left = Expr;
|
||||
Root->Right = LiteralExpr (Offs, O);
|
||||
} else {
|
||||
@ -478,6 +467,7 @@ ExprNode* ReadExpr (FILE* F, ObjData* O)
|
||||
/* Read an expression from the given file */
|
||||
{
|
||||
ExprNode* Expr;
|
||||
unsigned ImpNum;
|
||||
|
||||
/* Read the node tag and handle NULL nodes */
|
||||
unsigned char Op = Read8 (F);
|
||||
@ -486,8 +476,7 @@ ExprNode* ReadExpr (FILE* F, ObjData* O)
|
||||
}
|
||||
|
||||
/* Create a new node */
|
||||
Expr = NewExprNode (O);
|
||||
Expr->Op = Op;
|
||||
Expr = NewExprNode (O, Op);
|
||||
|
||||
/* Check the tag and handle the different expression types */
|
||||
if (EXPR_IS_LEAF (Op)) {
|
||||
@ -499,7 +488,8 @@ ExprNode* ReadExpr (FILE* F, ObjData* O)
|
||||
|
||||
case EXPR_SYMBOL:
|
||||
/* Read the import number */
|
||||
Expr->V.ImpNum = ReadVar (F);
|
||||
ImpNum = ReadVar (F);
|
||||
Expr->V.Imp = CollAt (&O->Imports, ImpNum);
|
||||
break;
|
||||
|
||||
case EXPR_SECTION:
|
||||
@ -550,8 +540,8 @@ int EqualExpr (ExprNode* E1, ExprNode* E2)
|
||||
return (E1->V.IVal == E2->V.IVal);
|
||||
|
||||
case EXPR_SYMBOL:
|
||||
/* Import number must be identical */
|
||||
return (E1->V.ImpNum == E2->V.ImpNum);
|
||||
/* Import must be identical */
|
||||
return (E1->V.Imp == E2->V.Imp);
|
||||
|
||||
case EXPR_SECTION:
|
||||
/* Section must be identical */
|
||||
@ -563,7 +553,7 @@ int EqualExpr (ExprNode* E1, ExprNode* E2)
|
||||
|
||||
case EXPR_MEMAREA:
|
||||
/* Memory area must be identical */
|
||||
return (E1->V.Mem == E2->V.Mem );
|
||||
return (E1->V.Mem == E2->V.Mem);
|
||||
|
||||
default:
|
||||
/* Not a leaf node */
|
||||
|
@ -54,6 +54,9 @@
|
||||
|
||||
|
||||
|
||||
ExprNode* NewExprNode (ObjData* O, unsigned char Op);
|
||||
/* Create a new expression node */
|
||||
|
||||
void FreeExpr (ExprNode* Root);
|
||||
/* Free the expression tree, Root is pointing to. */
|
||||
|
||||
@ -77,7 +80,7 @@ long GetExprVal (ExprNode* Expr);
|
||||
ExprNode* LiteralExpr (long Val, ObjData* O);
|
||||
/* Return an expression tree that encodes the given literal value */
|
||||
|
||||
ExprNode* MemoryExpr (Memory* Mem, long Offs, ObjData* O);
|
||||
ExprNode* MemoryExpr (MemoryArea* Mem, long Offs, ObjData* O);
|
||||
/* Return an expression tree that encodes an offset into the memory area */
|
||||
|
||||
ExprNode* SegmentExpr (Segment* Seg, long Offs, ObjData* O);
|
||||
|
@ -211,14 +211,14 @@ static ObjData* ReadIndexEntry (Library* L)
|
||||
/* Read the string pool */
|
||||
ObjReadStrPool (L->F, FileGetPos (L->F), O);
|
||||
|
||||
/* Skip the export size, then read the exports */
|
||||
(void) ReadVar (L->F);
|
||||
ObjReadExports (L->F, FileGetPos (L->F), O);
|
||||
|
||||
/* Skip the import size, then read the imports */
|
||||
(void) ReadVar (L->F);
|
||||
ObjReadImports (L->F, FileGetPos (L->F), O);
|
||||
|
||||
/* Skip the export size, then read the exports */
|
||||
(void) ReadVar (L->F);
|
||||
ObjReadExports (L->F, FileGetPos (L->F), O);
|
||||
|
||||
/* Done */
|
||||
return O;
|
||||
}
|
||||
|
@ -302,6 +302,9 @@ static void OptConfig (const char* Opt attribute ((unused)), const char* Arg)
|
||||
} else {
|
||||
CfgSetName (PathName);
|
||||
}
|
||||
|
||||
/* Read the config */
|
||||
CfgRead ();
|
||||
}
|
||||
|
||||
|
||||
@ -356,7 +359,7 @@ static void OptForceImport (const char* Opt attribute ((unused)), const char* Ar
|
||||
/* Use default address size (which for now is always absolute
|
||||
* addressing)
|
||||
*/
|
||||
InsertImport (GenImport (Arg, ADDR_SIZE_ABS));
|
||||
InsertImport (GenImport (GetStringId (Arg), ADDR_SIZE_ABS));
|
||||
|
||||
} else {
|
||||
|
||||
@ -375,7 +378,7 @@ static void OptForceImport (const char* Opt attribute ((unused)), const char* Ar
|
||||
A[ColPos - Arg] = '\0';
|
||||
|
||||
/* Generate the import */
|
||||
InsertImport (GenImport (A, AddrSize));
|
||||
InsertImport (GenImport (GetStringId (A), AddrSize));
|
||||
|
||||
/* Delete the copy of the argument */
|
||||
xfree (A);
|
||||
@ -481,6 +484,9 @@ static void OptTarget (const char* Opt attribute ((unused)), const char* Arg)
|
||||
/* Set the target data */
|
||||
DefaultBinFmt = D->BinFmt;
|
||||
CfgSetBuf (D->Cfg);
|
||||
|
||||
/* Read the target config */
|
||||
CfgRead ();
|
||||
}
|
||||
|
||||
|
||||
@ -643,12 +649,12 @@ int main (int argc, char* argv [])
|
||||
/* Check if we have open library groups */
|
||||
LibCheckGroup ();
|
||||
|
||||
/* Read the config file */
|
||||
CfgRead ();
|
||||
|
||||
/* Create the condes tables if requested */
|
||||
ConDesCreate ();
|
||||
|
||||
/* Process data from the config file */
|
||||
CfgProcess ();
|
||||
|
||||
/* Assign start addresses for the segments, define linker symbols. The
|
||||
* function will return the number of memory area overflows (zero on
|
||||
* success).
|
||||
|
@ -51,6 +51,7 @@ OBJS = asserts.o \
|
||||
lineinfo.o \
|
||||
main.o \
|
||||
mapfile.o \
|
||||
memarea.o \
|
||||
o65.o \
|
||||
objdata.o \
|
||||
objfile.o \
|
||||
|
@ -82,6 +82,7 @@ OBJS = asserts.obj \
|
||||
lineinfo.obj \
|
||||
main.obj \
|
||||
mapfile.obj \
|
||||
memarea.obj \
|
||||
o65.obj \
|
||||
objdata.obj \
|
||||
objfile.obj \
|
||||
|
76
src/ld65/memarea.c
Normal file
76
src/ld65/memarea.c
Normal file
@ -0,0 +1,76 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* memarea.c */
|
||||
/* */
|
||||
/* Memory area definition for the ld65 linker */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2010, Ullrich von Bassewitz */
|
||||
/* Roemerstrasse 52 */
|
||||
/* D-70794 Filderstadt */
|
||||
/* EMail: uz@cc65.org */
|
||||
/* */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* common */
|
||||
#include "xmalloc.h"
|
||||
|
||||
/* ld65 */
|
||||
#include "memarea.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
MemoryArea* NewMemoryArea (unsigned Name)
|
||||
/* Create a new memory area and insert it into the list */
|
||||
{
|
||||
/* Allocate memory */
|
||||
MemoryArea* M = xmalloc (sizeof (MemoryArea));
|
||||
|
||||
/* Initialize the fields ... */
|
||||
M->Name = Name;
|
||||
M->Attr = 0;
|
||||
M->Flags = 0;
|
||||
M->StartExpr = 0;
|
||||
M->Start = 0;
|
||||
M->SizeExpr = 0;
|
||||
M->Size = 0;
|
||||
M->FillLevel = 0;
|
||||
M->FillVal = 0;
|
||||
M->Relocatable = 0;
|
||||
InitCollection (&M->SegList);
|
||||
M->F = 0;
|
||||
|
||||
/* ...and return it */
|
||||
return M;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
100
src/ld65/memarea.h
Normal file
100
src/ld65/memarea.h
Normal file
@ -0,0 +1,100 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* memarea.h */
|
||||
/* */
|
||||
/* Memory area definition for the ld65 linker */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2010, Ullrich von Bassewitz */
|
||||
/* Roemerstrasse 52 */
|
||||
/* D-70794 Filderstadt */
|
||||
/* EMail: uz@cc65.org */
|
||||
/* */
|
||||
/* */
|
||||
/* 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 MEMAREA_H
|
||||
#define MEMAREA_H
|
||||
|
||||
|
||||
|
||||
/* common */
|
||||
#include "coll.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Forwards for structures */
|
||||
struct ExprNode;
|
||||
struct File;
|
||||
|
||||
/* Memory area entry */
|
||||
typedef struct MemoryArea MemoryArea;
|
||||
struct MemoryArea {
|
||||
unsigned Name; /* Name index of the memory section */
|
||||
unsigned Attr; /* Which values are valid? */
|
||||
unsigned Flags; /* Set of bitmapped flags */
|
||||
struct ExprNode* StartExpr; /* Expression for start address */
|
||||
unsigned long Start; /* Start address */
|
||||
struct ExprNode* SizeExpr; /* Expression for size */
|
||||
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 */
|
||||
unsigned char Relocatable; /* Memory area is relocatable */
|
||||
Collection SegList; /* List of segments for this area */
|
||||
struct File* F; /* Output file for this area */
|
||||
};
|
||||
|
||||
/* Memory flags */
|
||||
#define MF_DEFINE 0x0001 /* Define start and size */
|
||||
#define MF_FILL 0x0002 /* Fill segment */
|
||||
#define MF_RO 0x0004 /* Read only memory area */
|
||||
#define MF_OVERFLOW 0x0008 /* Memory area overflow */
|
||||
#define MF_PLACED 0x0010 /* Memory area was placed */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
MemoryArea* NewMemoryArea (unsigned Name);
|
||||
/* Create a new memory area and insert it into the list */
|
||||
|
||||
|
||||
|
||||
/* End of memarea.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include "fileio.h"
|
||||
#include "global.h"
|
||||
#include "lineinfo.h"
|
||||
#include "memarea.h"
|
||||
#include "o65.h"
|
||||
#include "spool.h"
|
||||
|
||||
@ -175,7 +176,7 @@ struct ExprDesc {
|
||||
O65Desc* D; /* File format descriptor */
|
||||
long Val; /* The offset value */
|
||||
int TooComplex; /* Expression too complex */
|
||||
Memory* MemRef; /* Memory reference if any */
|
||||
MemoryArea* MemRef; /* Memory reference if any */
|
||||
Segment* SegRef; /* Segment reference if any */
|
||||
Section* SecRef; /* Section reference if any */
|
||||
ExtSym* ExtRef; /* External reference if any */
|
||||
@ -244,7 +245,7 @@ static void CvtMemoryToSegment (ExprDesc* ED)
|
||||
*/
|
||||
{
|
||||
/* Get the memory area from the expression */
|
||||
Memory* M = ED->MemRef;
|
||||
MemoryArea* M = ED->MemRef;
|
||||
|
||||
/* Remember the "nearest" segment and its offset */
|
||||
Segment* Nearest = 0;
|
||||
@ -1227,9 +1228,9 @@ static void O65SetupSegments (O65Desc* D, File* F)
|
||||
D->ZPCount = 0;
|
||||
|
||||
/* Walk over the memory list */
|
||||
for (I = 0; I < CollCount (&F->MemList); ++I) {
|
||||
for (I = 0; I < CollCount (&F->MemoryAreas); ++I) {
|
||||
/* Get this entry */
|
||||
Memory* M = CollAtUnchecked (&F->MemList, I);
|
||||
MemoryArea* M = CollAtUnchecked (&F->MemoryAreas, I);
|
||||
|
||||
/* Walk through the segment list and count the segment types */
|
||||
unsigned J;
|
||||
@ -1257,9 +1258,9 @@ static void O65SetupSegments (O65Desc* D, File* F)
|
||||
|
||||
/* Walk again through the list and setup the segment arrays */
|
||||
TextIdx = DataIdx = BssIdx = ZPIdx = 0;
|
||||
for (I = 0; I < CollCount (&F->MemList); ++I) {
|
||||
for (I = 0; I < CollCount (&F->MemoryAreas); ++I) {
|
||||
/* Get this entry */
|
||||
Memory* M = CollAtUnchecked (&F->MemList, I);
|
||||
MemoryArea* M = CollAtUnchecked (&F->MemoryAreas, I);
|
||||
|
||||
/* Walk over the segment list and check the segment types */
|
||||
unsigned J;
|
||||
|
@ -103,6 +103,7 @@ static Segment* NewSegment (unsigned Name, unsigned char AddrSize)
|
||||
S->AddrSize = AddrSize;
|
||||
S->ReadOnly = 0;
|
||||
S->Relocatable = 0;
|
||||
S->Placed = 0;
|
||||
S->Dumped = 0;
|
||||
|
||||
/* Insert the segment into the segment list and assign the segment id */
|
||||
|
@ -70,6 +70,7 @@ struct Segment {
|
||||
unsigned char AddrSize; /* Address size of segment */
|
||||
unsigned char ReadOnly; /* True for readonly segments (config) */
|
||||
unsigned char Relocatable; /* True if the segment is relocatable */
|
||||
unsigned char Placed; /* Did we place this segment already? */
|
||||
unsigned char Dumped; /* Did we dump this segment? */
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user