"SDCCXA rel, version %f" must be the first line, sort of MAGIC word
"H %d areas %d global symbols" defines the # of areas and globals
- "S <symbol> [Ref0000 | DefXXXX]" Def's are supposed to be defined in
- their own area/segment
+ "S <symbol> [Ref0000 | DefXXXX | AbsXXXX]" Def's are supposed to be
+ defined in their own area/segment
"A <seg> size %d flags %d" switch to another segment. this can happen
multiple times and should be equal. flags is ignored for now
- "T xx xx bb bb ..." where xx xx is the address within the current segment
- and bb are the bytes
- "R xx <how> <symbol>" the relocation info. xx is the offset within the
- previous "T .." line. <how> could be something like REL_FF, REL_FFFF,
- ABS_F0FF. symbol is the (previous) defined symbol it refers to
+ "T xxxx <how> <symbol> 0"
+ "R xxxx <how> <symbol> <pc+>" the relocation info. xxxx is the address
+ within relative code space. How is something like REL_FF, REL_FFFF,
+ ABS_F0FF. Symbol is the referenced symbol and pc+ is the program
+ counter that will be used to calculate the relative address (that is
+ the address of the following instruction).
So, this is not a standalone linker. It will only link files generated
by xa_asm, which will only process files generated by the xa51 sdcc
MAX_SEGMENTS
};
+enum {
+ REL_FF=1,
+ REL_FFFF,
+ ABS_0F,
+ ABS_FF,
+ ABS_03FF,
+ ABS_07FF,
+ ABS_F0FF,
+ ABS_FFFF,
+ ABS_0F00FF,
+ MAX_REFS
+};
+
+char *refModes[]={
+ "???",
+ "REL_FF",
+ "REL_FFFF",
+ "ABS_0F",
+ "ABS_FF",
+ "ABS_03FF",
+ "ABS_07FF",
+ "ABS_F0FF",
+ "ABS_FFFF",
+ "ABS_0F00FF",
+};
+
#define CODESIZE 0x10000
-char codeImage[CODESIZE];
+int fatalErrors=0;
+
char gsinitImage[CODESIZE];
+char csegImage[CODESIZE];
char xinitImage[CODESIZE];
+//char gsfinalImage[CODESIZE];
struct SEGMENT {
short id;
int current;
unsigned char *image;
} segments[MAX_SEGMENTS]={
- {0, "????", 0, 0, 0, 0, NULL},
+ {0, "???", 0, 0, 0, 0, NULL},
{GSINIT, "GSINIT", 0, 0, 0, 0, gsinitImage},
- {CSEG, "CSEG", 0, 0, 0, 0, codeImage},
+ {CSEG, "CSEG", 0, 0, 0, 0, csegImage},
{XINIT, "XINIT", 0, 0, 0, 0, xinitImage},
//{GSFINAL, "GSFINAL", 0, 0, 0, 0, NULL},
struct SYMBOL {
char *name;
struct MODULE *module;
+ int lineno;
struct SEGMENT *segment;
+ char absolute;
int address;
struct SYMBOL *next;
struct SYMBOL *last;
} *symbols=NULL;
+struct REFERENCE {
+ char *name;
+ struct MODULE *module;
+ int lineno;
+ unsigned address, pc;
+ short how;
+ struct REFERENCE *next;
+ struct REFERENCE *last;
+} *references=NULL;
+
char *libPaths[128];
int nlibPaths=0;
char *libFiles[128];
int nlibFiles=0;
-static char outFileName[PATH_MAX];
+static char outFileName[PATH_MAX]={'\0'};
struct SEGMENT *currentSegment;
struct MODULE *currentModule;
+int currentLine;
+
+int howToReference(char *how) {
+ int r;
+ for (r=1; r<MAX_REFS; r++) {
+ if (strcmp(refModes[r], how)==0) {
+ return r;
+ }
+ }
+ return 0;
+}
-struct SEGMENT *findSegment(char *segment) {
- int i;
- for (i=1; i<MAX_SEGMENTS; i++) {
- if (strcmp(segments[i].name, segment)==0) {
- return &segments[i];
+struct SEGMENT *findSegmentByName(char *segment) {
+ int s;
+ for (s=0; s<MAX_SEGMENTS; s++) {
+ if (strcmp(segments[s].name, segment)==0) {
+ return &segments[s];
+ }
+ }
+ return 0;
+}
+
+struct SYMBOL *findSymbolByName(char *symName) {
+ struct SYMBOL *symbol;
+ for (symbol=symbols; symbol; symbol=symbol->next) {
+ if (strcmp(symbol->name, symName)==0) {
+ return symbol;
}
}
return 0;
currentModule=modules->last=module;
}
-void addToRefs(char *ref) {
+void addToRefs(char *ref, int address, char *how, int pc) {
+ struct REFERENCE *reference;
+
//fprintf (stderr, "addToRefs: %s\n", ref);
+
+ reference=calloc(1, sizeof(struct REFERENCE));
+ reference->name=strdup(ref);
+ reference->module=currentModule;
+ reference->lineno=currentLine;
+ reference->address=address;
+ reference->how=howToReference(how);
+ reference->pc=pc;
+ if (!references) {
+ references=reference;
+ } else {
+ references->last->next=reference;
+ }
+ references->last=reference;
}
-void addToDefs(char *def, int address) {
+void addToDefs(char *def, int address, char absolute) {
struct SYMBOL *symbol;
+
/* fprintf (stderr, "addToDefs: %s %s 0x%04x + 0x%04x\n",
currentSegment->name, def,
currentModule->offset[currentSegment->id],
address); */
+
+ // no duplicates allowed
+ if ((symbol=findSymbolByName(def))) {
+ fprintf (stderr, "*** %s:%d duplicate symbol %s first defined in "
+ "module %s:%d\n",
+ currentModule->name, currentLine, def,
+ symbol->module->name, symbol->lineno);
+ fatalErrors++;
+ }
+
symbol=calloc(1, sizeof(struct SYMBOL));
symbol->name=strdup(def);
symbol->module=currentModule;
+ symbol->lineno=currentLine;
symbol->segment=currentSegment;
+ symbol->absolute=absolute;
symbol->address=currentModule->offset[currentSegment->id]+address;
if (!symbols) {
symbols=symbol;
}
void syntaxError (char *err) {
- fprintf (stderr, "error while parsing '%s'\n", err);
+ fprintf (stderr, "*** %s:%d error while parsing '%s'\n",
+ currentModule->name, currentLine, err);
exit(1);
}
FILE *relModule;
char moduleName[PATH_MAX];
int segments, globals;
- int currentLine=1;
+
+ currentLine=1;
if ((relModule=fopen(module, "r"))==NULL) {
perror (module);
// first we need to check if this is a valid file
if (sscanf(fgets(line, 132, relModule),
"SDCCXA rel, version %lf", &hisVersion)!=1) {
- fprintf (stderr, "%s is not a valid input file\n", module);
+ fprintf (stderr, "*** %s is not a valid input file\n", module);
exit (1);
}
if (hisVersion!=version) {
- fprintf (stderr, "WARNING: version conflict; "
+ fprintf (stderr, "*** WARNING: version conflict; "
"we(%1.1f) != %s(%1.1f)\n",
version, module, hisVersion);
}
int size, flags;
if (sscanf(line, "A %[^ ] size %d flags %d",
segment, &size, &flags)!=3) {
- fprintf (stderr, "%s:%d error in A record line\n",
- module, currentLine);
- exit (1);
+ syntaxError(line);
}
// do we know this segment?
- if (!(currentSegment=findSegment(segment))) {
- fprintf (stderr, "%s:%d unknown area: %s\n", module,
+ if (!(currentSegment=findSegmentByName(segment))) {
+ fprintf (stderr, "*** %s:%d unknown area: %s\n", module,
currentLine, segment);
exit (1);
}
if (currentModule->size[currentSegment->id]) {
if (currentModule->size[currentSegment->id] != size) {
- fprintf (stderr, "%s:%d error %s %d %d\n",
+ fprintf (stderr, "*** %s:%d error %s size %d != %d\n",
module, currentLine,
currentSegment->name,
currentModule->size[currentSegment->id],
size);
+ } else {
+ // pleased to meet you again
}
} else {
currentModule->size[currentSegment->id]=size;
char refdef[132];
unsigned int address;
if (sscanf(line, "S %[^ ] %s", symbol, refdef)!=2) {
- fprintf (stderr, "%s:%d syntax error near \"%s\"\n",
+ fprintf (stderr, "*** %s:%d syntax error near \"%s\"\n",
module, currentLine, line);
exit (1);
}
if (strncmp(refdef, "Ref", 3)==0) {
- addToRefs(symbol);
+ // we don't need them
} else if (strncmp(refdef, "Def", 3)==0) {
sscanf (refdef, "Def%04x", &address);
- addToDefs(symbol, address);
+ addToDefs(symbol, address, 0);
+ } else if (strncmp(refdef, "Abs", 3)==0) {
+ sscanf (refdef, "Abs%04x", &address);
+ addToDefs(symbol, address, 1);
} else {
fprintf (stderr, "%s:%d found invalid symbol definition \"%s\"\n",
module, currentLine, line);
//fprintf (stderr, "\n");
break;
}
- case 'R':
+ case 'R': {
+ unsigned address, from;
+ char symbol[132];
+ char how[32];
//fprintf (stderr, "%s", line);
+ sscanf (line, "R %x %[^ ] %[^ ] %x", &address, how, symbol, &from);
+ addToRefs (symbol, address, how, from);
break;
+ }
default:
- /* fprintf (stderr, "%s:%d unknown record \"%s\"\n",
- module, currentLine, line); */
+ fprintf (stderr, "%s:%d unknown record \"%s\"\n",
+ module, currentLine, line);
+ fatalErrors++;
break;
}
currentLine++;
fclose (relModule);
}
-void writeModule() {
+void writeModule(char *outFileName) {
+ FILE *fOut;
+
fprintf (stderr, "WriteModule: %s\n", outFileName);
+ if ((fOut=fopen(outFileName, "w"))==NULL) {
+ perror (outFileName);
+ }
// oops, forgot something :) */
+ fclose (fOut);
}
void relocate() {
struct SYMBOL *symbol;
+ struct REFERENCE *reference;
+ char *from, *to;
int length=segments[GSINIT].current +
segments[CSEG].current +
segments[XINIT].current;
+ //fprintf (stderr, "relocate: total code size: 0x%04x\n", length);
+
// first check if it will fit
if (length > 0xffff) {
fprintf (stderr, "error: code segment exceeds 0xffff\n");
- exit(1);
+ fatalErrors++;
}
- fprintf (stderr, "relocate: total code size: 0x%04x\n", length);
// GSINIT gets the --code-loc
segments[GSINIT].start=segments[CSEG].start;
segments[CSEG].start=segments[GSINIT].start+segments[GSINIT]._size;
+ // concat cseg to gsinit
+ from=csegImage;
+ to=&gsinitImage[segments[GSINIT].start+segments[GSINIT]._size];
+ memcpy(to, from, segments[CSEG]._size);
segments[XINIT].start=segments[CSEG].start+segments[CSEG]._size;
+ from=xinitImage;
+ to+=segments[CSEG]._size;
+ memcpy(to, from, segments[XINIT]._size);
+#if 0
+ from=gsfinalImage;
+ to+=segments[XINIT]._size;
+ memcpy(to, from, segments[GSFINAL]._size);
+#endif
segments[XISEG].start=segments[XSEG].start+segments[XINIT]._size;
// now relocate the defined symbols
for (symbol=symbols; symbol; symbol=symbol->next) {
- symbol->address += symbol->segment->start;
+ if (!symbol->absolute) {
+ symbol->address += symbol->segment->start;
+ }
+ }
+ // add the segment symbols
+ currentSegment=findSegmentByName("XINIT");
+ addToDefs("s_XINIT", segments[XINIT].start, 0);
+ addToDefs("l_XINIT", segments[XINIT]._size, 0);
+ currentSegment=findSegmentByName("XISEG");
+ addToDefs("s_XISEG", segments[XISEG].start, 0);
+ addToDefs("l_XISEG", segments[XISEG]._size, 0);
+ // and the references
+ for (reference=references; reference; reference=reference->next) {
+ if (!(symbol=findSymbolByName(reference->name))) {
+ fprintf (stderr, "*** %s:%d undefined symbol %s\n",
+ reference->module->name, reference->lineno,
+ reference->name);
+ } else {
+ reference->address += symbol->segment->start;
+ switch (reference->how)
+ {
+ case REL_FFFF: {
+ int rel16 = symbol->address-reference->pc;
+ if (rel16<-65536 || rel16>65534) {
+ fprintf (stderr,
+ "rel16 target for %s is out of range in module %s\n",
+ reference->name, reference->module->name);
+ fatalErrors++;
+ }
+ gsinitImage[reference->address+1]=(rel16/2)>>8;
+ gsinitImage[reference->address]=rel16/2;
+ break;
+ }
+ case REL_FF: {
+ int rel8 = symbol->address-reference->pc;
+ if (rel8<-256 || rel8>256) {
+ fprintf (stderr,
+ "rel8 target for %s is out of range in module %s\n",
+ reference->name, reference->module->name);
+ fatalErrors++;
+ }
+ gsinitImage[reference->address]=rel8/2;
+ break;
+ }
+ case ABS_FFFF:
+ gsinitImage[reference->address+1] = symbol->address>>8;
+ // fall through
+ case ABS_FF:
+ gsinitImage[reference->address] = symbol->address;
+ break;
+ default:
+ fprintf (stderr, "unsupported reference mode %d.\n",
+ reference->how);
+ fatalErrors++;
+ }
+ }
}
}
usage(argv[0], 1);
}
- memset(codeImage, 0xff, CODESIZE);
-
// read in the commands
sprintf (linkCommandsPath, "%s.lnk", argv[1]);
if (!(linkCommandsFile=fopen(linkCommandsPath, "r"))) {
} else {
// not a switch, must be an inputfile; one/line
readModule(linkCommand);
+ // the first one defines the output name
+ if (!outFileName[0]) {
+ strncpy(outFileName, linkCommand,
+ strlen(linkCommand)-4);
+ strcat(outFileName, ".hex");
+ }
}
}
// the symbols
for (symbol=symbols; symbol; symbol=symbol->next) {
- fprintf (stderr, "%s %s 0x%04x %s\n", symbol->name, symbol->segment->name,
+ fprintf (stderr, "%s %s %s0x%04x %s\n", symbol->name,
+ symbol->segment->name,
+ symbol->absolute ? "= " : "",
symbol->address, symbol->module->name);
}
}
}
- writeModule();
- return 0;
+ writeModule(outFileName);
+ return fatalErrors? 1 : 0;
}