/* This is a cheap hack. The xa51 has a couple of ways to scramble
relocation info into it's opcode that the standard linker can't
- handle.
+ handle. No hash or qsort yet.
The relocatable format looks like the known one, BUT ISN'T.
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
+ by xa_rasm, which will only process files generated by the xa51 sdcc
port.
*/
char *name;
int offset[MAX_SEGMENTS];
int size[MAX_SEGMENTS];
+ int isLib;
struct MODULE *next;
struct MODULE *last;
} *modules=NULL;
int lineno;
unsigned address, pc;
short how;
+ short resolved;
struct REFERENCE *next;
struct REFERENCE *last;
} *references=NULL;
-char *libPaths[128];
+char *libraryPaths[128];
int nlibPaths=0;
-char *libFiles[128];
+char *libraryFiles[128];
int nlibFiles=0;
static char outFileName[PATH_MAX]={'\0'};
+static char mapFileName[PATH_MAX]={'\0'};
+FILE *mapOut;
struct SEGMENT *currentSegment;
struct MODULE *currentModule;
return 0;
}
-void addToModules (char *name) {
+void addToModules (char *name, int isLib) {
struct MODULE *module;
int s;
- //fprintf (stderr, "addToModules: %s\n", name);
-
module=calloc(1, sizeof(struct MODULE));
module->name=strdup(name);
for (s=0; s<MAX_SEGMENTS; s++) {
module->offset[s]=segments[s].current;
}
+ module->isLib=isLib;
if (!modules) {
modules=module;
- } else {
+ } else {
modules->last->next=module;
}
currentModule=modules->last=module;
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;
references->last=reference;
}
+void resolve() {
+ struct REFERENCE *reference;
+ for (reference=references; reference; reference=reference->next) {
+ if (findSymbolByName(reference->name)) {
+ reference->resolved=1;
+ }
+ }
+}
+
+int isUnresolved(char *ref, int resolved) {
+ struct REFERENCE *reference;
+
+ for (reference=references; reference; reference=reference->next) {
+ if (strcmp(reference->name, ref)==0) {
+ // found
+ if (reference->resolved) {
+ // already resolved
+ return 0;
+ }
+ if (resolved) {
+ reference->resolved=1;
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
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 "
void syntaxError (char *err) {
fprintf (stderr, "*** %s:%d error while parsing '%s'\n",
currentModule->name, currentLine, err);
- exit(1);
+ fatalErrors++;
}
-void baseName(char *name, char*base) {
- int i, first, last;
-
- // find the last path seperator in name
- for (first=strlen(name)-1;
- (name[first]!='/' && name[first]!='\\') && first;
- first--);
- if (name[first]=='/' || name[first]=='\\') {
- first++;
- }
-
- // find the last ext seperator in name
- for (last=strlen(name)-1;
- (name[last]!='.' && last);
- last--);
- if (!last) {
- last=strlen(name);
- }
-
- fprintf (stderr, "baseName: %s %d %d\n", name, first, last);
- // fill the base with the baseName
- for (i=first; i<last; i++) {
- base[i-first]=name[i];
- }
- base[i]='\0';
-}
-
-void readModule(char *module) {
+void readModule(char *module, int isLib) {
double hisVersion;
char line[132];
FILE *relModule;
exit (1);
}
- //fprintf (stderr, "ReadModule: %s\n", module);
-
// first we need to check if this is a valid file
if (sscanf(fgets(line, 132, relModule),
"SDCCXA rel, version %lf", &hisVersion)!=1) {
}
// add this to the known modules with current offsets
- addToModules(module);
+ addToModules(module, isLib);
- fprintf (stderr, "module %s has %d segment%s and %d globals\n",
- moduleName, segments, segments==1?"":"s", globals);
currentLine++;
// now for the ASTR tags
currentLine, segment);
exit (1);
}
+ // double check repeated 'A' records
if (currentModule->size[currentSegment->id]) {
if (currentModule->size[currentSegment->id] != size) {
fprintf (stderr, "*** %s:%d error %s size %d != %d\n",
currentSegment->name,
currentModule->size[currentSegment->id],
size);
+ fatalErrors++;
} else {
// pleased to meet you again
}
currentModule->offset[currentSegment->id]+=currentSegment->_size;
currentSegment->_size += size;
}
- //fprintf (stderr, "Area: %s size: %d\n", segment, size);
// never mind about the flags for now
break;
}
}
if (sscanf(strtok(&line[2], " "), "%04x", &address)!=1) {
fprintf (stderr, "%s:%d error in T record\n", module, currentLine);
- exit (1);
+ fatalErrors++;
}
- //fprintf (stderr, "%04x:", address);
address+=currentSegment->current;
for ( ;
(tline=strtok(NULL, " \t\n")) &&
(sscanf(tline, "%02x", &byte)==1);
) {
- //fprintf (stderr, " %02x", byte);
currentSegment->image[address++]=byte;
currentSegment->current++;
}
- //fprintf (stderr, "\n");
break;
}
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;
void writeModule(char *outFileName) {
FILE *fOut;
- fprintf (stderr, "WriteModule: %s\n", outFileName);
if ((fOut=fopen(outFileName, "w"))==NULL) {
perror (outFileName);
}
fclose (fOut);
}
-void relocate() {
+int 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);
+ int unresolved=0;
// first check if it will fit
if (length > 0xffff) {
fatalErrors++;
}
+ // resolve reverences
+ for (reference=references; reference; reference=reference->next) {
+ if (!reference->resolved && !findSymbolByName(reference->name)) {
+ unresolved++;
+ }
+ }
+ if (unresolved) {
+ // first scan the libraries
+ return unresolved;
+ }
+
// GSINIT gets the --code-loc
segments[GSINIT].start=segments[CSEG].start;
segments[CSEG].start=segments[GSINIT].start+segments[GSINIT]._size;
- // concat cseg to gsinit
+ // concat cseg and gsinit
from=csegImage;
to=&gsinitImage[segments[GSINIT].start+segments[GSINIT]._size];
memcpy(to, from, segments[CSEG]._size);
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))) {
+ // this reference isn't defined after all
fprintf (stderr, "*** %s:%d undefined symbol %s\n",
reference->module->name, reference->lineno,
reference->name);
+ fatalErrors++;
} else {
reference->address += symbol->segment->start;
switch (reference->how)
}
}
}
+ return 0;
}
void usage (char * progName, int errNo) {
}
}
+int scanLibraries(int unresolved) {
+ int resolved=0;
+ int nlp, nlf;
+ char libFiles[PATH_MAX];
+ char libFile[PATH_MAX];
+ char line[132];
+ char symName[132];
+ FILE *lf, *lfs;
+
+ for (nlp=0; nlp<nlibPaths; nlp++) {
+ for (nlf=0; nlf<nlibFiles; nlf++) {
+ sprintf (libFiles, "%s/%s.lib", libraryPaths[nlp], libraryFiles[nlf]);
+ //fprintf (stderr, " %s\n", libFiles);
+ if ((lfs=fopen(libFiles,"r"))==NULL) {
+ continue;
+ }
+ while (fgets(line, 132, lfs)) {
+ // remove trailing \n
+ line[strlen(line)-1]='\0';
+ sprintf (libFile, "%s/%s", libraryPaths[nlp], line);
+ //fprintf (stderr, " %s\n", libFile);
+ if ((lf=fopen(libFile,"r"))==0) {
+ continue;
+ }
+ while (fgets(line, 132, lf)) {
+ if (sscanf(line, "S %[^ ] Def", symName)==1) {
+ if (isUnresolved(symName, 1)) {
+ fprintf (stderr, "%s:%s\n", libFile, symName);
+ readModule(libFile,1);
+ if (resolved++ == unresolved) {
+ // we are done
+ return resolved;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return resolved;
+}
+
int main(int argc, char **argv) {
FILE *linkCommandsFile;
char linkCommandsPath[PATH_MAX];
struct MODULE *module;
struct SYMBOL *symbol;
int s;
+ int unresolved;
if (argc!=2) {
usage(argv[0], 1);
&segments[s].start)!=1) {
syntaxError(linkCommand);
}
- /* fprintf (stderr, "%s starts at 0x%04x\n", segments[s].name,
- segments[s].start); */
break;
}
}
break;
case 'k':
// a lib path like: "-k /usr/local/share/sdcc/lib/xa51"; one/line
- libPaths[nlibPaths++]=strdup(&linkCommand[3]);
+ libraryPaths[nlibPaths++]=strdup(&linkCommand[3]);
break;
case 'l':
// a lib file like: "-l libsdcc"; one/line
- libFiles[nlibFiles++]=strdup(&linkCommand[3]);
+ libraryFiles[nlibFiles++]=strdup(&linkCommand[3]);
break;
default:
syntaxError(linkCommand);
}
} else {
// not a switch, must be an inputfile; one/line
- readModule(linkCommand);
+ readModule(linkCommand, 0);
// the first one defines the output name
if (!outFileName[0]) {
strncpy(outFileName, linkCommand,
strlen(linkCommand)-4);
+ sprintf(mapFileName, "%s.map", outFileName);
strcat(outFileName, ".hex");
+ if ((mapOut=fopen(mapFileName, "w"))==NULL) {
+ perror(mapFileName);
+ }
+ }
+ }
+ }
+
+ // 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);
+
+ // mark the resolved references
+ resolve();
+
+ // now do something :) EXTREMELY SLOW AND INEFFICIENT
+ while ((unresolved=relocate())) {
+ if (!scanLibraries(unresolved)) {
+ struct REFERENCE *reference;
+ for (reference=references; reference; reference=reference->next) {
+ if (!reference->resolved) {
+ fprintf (stderr, "*** unresolved symbol %s in %s:%d\n",
+ reference->name, reference->module->name,
+ reference->lineno);
+ fatalErrors++;
+ }
}
+ break;
}
}
- relocate();
+ if (unresolved==0) {
+ writeModule(outFileName);
+ }
// the modules
+ fprintf (mapOut, "Modules:\n");
for (module=modules; module; module=module->next) {
- fprintf (stderr, "%s: ", module->name);
+ fprintf (mapOut, "\t%s\n", module->name);
for (s=0; s<MAX_SEGMENTS; s++) {
if (module->size[s]) {
- fprintf (stderr, "%s:0x%04x-0x%04x ", segments[s].name,
+ fprintf (mapOut, "\t\t%s:0x%04x-0x%04x\n", segments[s].name,
module->offset[s], module->offset[s]+module->size[s]);
}
}
- fprintf (stderr, "\n");
- }
-
- // the symbols
- for (symbol=symbols; symbol; symbol=symbol->next) {
- fprintf (stderr, "%s %s %s0x%04x %s\n", symbol->name,
- symbol->segment->name,
- symbol->absolute ? "= " : "",
- symbol->address, symbol->module->name);
}
// the segments
+ fprintf (mapOut, "\nSegments:\n");
for (s=1; s<MAX_SEGMENTS; s++) {
if (segments[s]._size) {
- fprintf (stderr, "%s start 0x%04x size 0x%04x %d symbols\n",
+ fprintf (mapOut, "\t%s start 0x%04x size 0x%04x %d symbols\n",
segments[s].name, segments[s].start,
segments[s]._size,
segments[s].hasSymbols);
}
}
+ // the symbols
+ fprintf (mapOut, "\nSymbols:\n");
+ for (symbol=symbols; symbol; symbol=symbol->next) {
+ fprintf (mapOut, "%s\t%s %s0x%04x %s\n", symbol->name,
+ symbol->segment->name,
+ symbol->absolute ? "= " : "",
+ symbol->address, symbol->module->name);
+ }
+
writeModule(outFileName);
+ fclose(mapOut);
return fatalErrors? 1 : 0;
}