age in your country to watch this.
*/
+/* This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
/* 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, not to mention word allignment.
+
+ No hash or qsort yet.
The relocatable format looks like the known one, BUT ISN'T.
"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> [Ref000 | 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_70FF. 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_rasm, which will only process files generated by the xa51 sdcc
+ port.
*/
#include <stdio.h>
#include "xa_version.h"
-static char outFileName[PATH_MAX];
+enum {
+ // these are all concatenated into the code image
+ GSINIT=1,
+ CSEG,
+ XINIT,
+
+ // here goes the final output and should be used by the assembler
+ GSFINAL,
+
+ // these are only for storage
+ BSEG,
+ DSEG,
+ XSEG,
+ XISEG,
+
+ // that's all
+ MAX_SEGMENTS
+};
+
+enum {
+ REL_FF=1,
+ REL_FFFF,
+ BIT_03FF,
+ DIR_07FF,
+ DIR_70FF,
+ DIR_0700FF,
+ ABS_0F,
+ ABS_FF,
+ ABS_FFFF,
+ ABS_PC,
+ MAX_REFS
+};
+
+char *refModes[]={
+ "???",
+ "REL_FF",
+ "REL_FFFF",
+ "BIT_03FF",
+ "DIR_07FF",
+ "DIR_70FF",
+ "DIR_0700FF",
+ "ABS_0F",
+ "ABS_FF",
+ "ABS_FFFF",
+ "ABS_PC"
+};
+
+#define CODESIZE 0x10000
+
+int fatalErrors=0;
+
+unsigned char gsinitImage[CODESIZE];
+unsigned char csegImage[CODESIZE];
+unsigned char xinitImage[CODESIZE];
+unsigned char gsfinalImage[CODESIZE];
+
+struct SEGMENT {
+ short id;
+ char *name;
+ int hasSymbols;
+ int _size;
+ int start;
+ int current;
+ unsigned char *image;
+} segments[MAX_SEGMENTS]={
+ {0, "???", 0, 0, 0, 0, NULL},
+
+ {GSINIT, "GSINIT", 0, 0, 0, 0, gsinitImage},
+ {CSEG, "CSEG", 0, 0, 0, 0, csegImage},
+ {XINIT, "XINIT", 0, 0, 0, 0, xinitImage},
+ {GSFINAL, "GSFINAL", 0, 0, 0, 0, gsfinalImage},
+
+ {BSEG, "BSEG", 0, 0, 0, 0, NULL},
+ {DSEG, "DSEG", 0, 0, 0, 0, NULL},
+ {XSEG, "XSEG", 0, 0, 0, 0, NULL},
+ {XISEG, "XISEG", 0, 0, 0, 0, NULL},
+};
-void baseName(char *name, char*base) {
- int i, first, last;
+struct MODULE {
+ char *name;
+ int offset[MAX_SEGMENTS];
+ int size[MAX_SEGMENTS];
+ int isLib;
+ struct MODULE *next;
+ struct MODULE *last;
+} *modules=NULL;
- // find the last path seperator in name
- for (first=strlen(name)-1;
- (name[first]!='/' && name[first]!='\\') && first;
- first--);
- if (name[first]=='/' || name[first]=='\\') {
- first++;
+
+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;
+ struct SEGMENT *segment;
+ int lineno;
+ unsigned address, pc;
+ short how;
+ short resolved;
+ struct REFERENCE *next;
+ struct REFERENCE *last;
+} *references=NULL;
+
+char *libraryPaths[128];
+int nlibPaths=0;
+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;
+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;
+}
- // find the last ext seperator in name
- for (last=strlen(name)-1;
- (name[last]!='.' && last);
- last--);
- if (!last) {
- last=strlen(name);
+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;
+}
- 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];
+struct SYMBOL *findSymbolByName(char *symName) {
+ struct SYMBOL *symbol;
+ for (symbol=symbols; symbol; symbol=symbol->next) {
+ if (strcmp(symbol->name, symName)==0) {
+ return symbol;
+ }
}
- base[i]='\0';
+ return 0;
}
-
-void readModule(char *module) {
+
+struct MODULE *findModuleByName(char *modName) {
+ struct MODULE *module;
+ for (module=modules; module; module=module->next) {
+ if (strcmp(module->name, modName)==0) {
+ return module;
+ }
+ }
+ return NULL;
+}
+
+void addToModules (char *name, int isLib) {
+ struct MODULE *module;
+ int s;
+
+ module=calloc(1, sizeof(struct MODULE));
+ module->name=strdup(name);
+ for (s=0; s<MAX_SEGMENTS; s++) {
+ module->offset[s]=(segments[s]._size+1)&0xfffffe;
+ }
+ module->isLib=isLib;
+ if (!modules) {
+ modules=module;
+ } else {
+ modules->last->next=module;
+ }
+ currentModule=modules->last=module;
+}
+
+void addToRefs(char *ref, int address, char *how, int pc) {
+ struct REFERENCE *reference;
+
+ reference=calloc(1, sizeof(struct REFERENCE));
+ reference->name=strdup(ref);
+ reference->module=currentModule;
+ reference->segment=currentSegment;
+ reference->lineno=currentLine;
+ reference->address=address;
+ reference->how=howToReference(how);
+ if (reference->how==ABS_PC) {
+ reference->resolved=1;
+ }
+ reference->pc=pc;
+ if (!references) {
+ references=reference;
+ } else {
+ references->last->next=reference;
+ }
+ references->last=reference;
+}
+
+void resolve() {
+ struct REFERENCE *reference;
+ for (reference=references; reference; reference=reference->next) {
+ if ((reference->how==ABS_PC) || 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;
+
+ // 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;
+ } else {
+ symbols->last->next=symbol;
+ }
+ symbols->last=symbol;
+ currentSegment->hasSymbols++;
+}
+
+void syntaxError (char *err) {
+ fprintf (stderr, "*** %s:%d error while parsing '%s'\n",
+ currentModule->name, currentLine, err);
+ fatalErrors++;
+}
+
+void readModule(char *module, int isLib) {
double hisVersion;
char line[132];
FILE *relModule;
+ char moduleName[PATH_MAX];
+ int segments, globals;
+
+ currentLine=1;
if ((relModule=fopen(module, "r"))==NULL) {
perror (module);
exit (1);
}
- printf ("ReadModule: %s\n", module);
+
// first we need to check if this is a valid file
- if (sscanf(line, "SDCCXA rel, version %lf", &hisVersion)!=1) {
- fprintf (stderr, "%s is not a valid input file\n", module);
+ if (sscanf(fgets(line, 132, relModule),
+ "SDCCXA rel, version %lf", &hisVersion)!=1) {
+ fprintf (stderr, "*** %s is not a valid input file\n", module);
exit (1);
}
if (hisVersion!=version) {
- fprintf (stderr, "version conflict; we: %f != module: %f\n",
- version, hisVersion);
+ fprintf (stderr, "*** WARNING: version conflict; "
+ "we(%1.1f) != %s(%1.1f)\n",
+ version, module, hisVersion);
+ }
+ currentLine++;
+
+ // H 7 areas 168 global symbols
+ if (sscanf(fgets(line, 132, relModule),
+ "H %d areas %d global symbols",
+ &segments, &globals)!=2) {
+ syntaxError(line);
+ }
+ currentLine++;
+
+ // M module
+ if (sscanf(fgets(line, 132, relModule),
+ "M %s", moduleName)!=1) {
+ syntaxError(line);
}
- fprintf (stderr, "Wow! This seems a nice module.\n");
- // that's all for now, thanks for watching */
+ // add this to the known modules with current offsets
+ addToModules(module, isLib);
+
+ currentLine++;
+
+ // now for the ASTR tags
+ while (fgets(line, 132, relModule)) {
+ switch (line[0])
+ {
+ case 'A': {
+ char segment[32];
+ int size, flags;
+ if (sscanf(line, "A %[^ ] size %d flags %d",
+ segment, &size, &flags)!=3) {
+ syntaxError(line);
+ }
+ // do we know this segment?
+ if (!(currentSegment=findSegmentByName(segment))) {
+ fprintf (stderr, "*** %s:%d unknown area: %s\n", module,
+ currentLine, segment);
+ exit (1);
+ }
+ // double check repeated 'A' records
+ if (currentModule->size[currentSegment->id]) {
+ // pleased to meet you again, I hope ...
+ if (currentModule->size[currentSegment->id] != size) {
+ fprintf (stderr, "*** %s:%d error %s size %d != %d\n",
+ module, currentLine,
+ currentSegment->name,
+ currentModule->size[currentSegment->id],
+ size);
+ fatalErrors++;
+ }
+ } else {
+ currentSegment->_size += size;
+ currentModule->size[currentSegment->id] = size;
+ }
+ // never mind about the flags for now
+ break;
+ }
+ case 'S': {
+ char symbol[132];
+ char refdef[132];
+ unsigned int address;
+ if (sscanf(line, "S %[^ ] %s", symbol, refdef)!=2) {
+ fprintf (stderr, "*** %s:%d syntax error near \"%s\"\n",
+ module, currentLine, line);
+ exit (1);
+ }
+ if (strncmp(refdef, "Ref", 3)==0) {
+ // we don't need them
+ } else if (strncmp(refdef, "Def", 3)==0) {
+ sscanf (refdef, "Def%04x", &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);
+ exit (1);
+ }
+ break;
+ }
+ case 'T': {
+ unsigned int address;
+ unsigned int byte;
+ char *tline=NULL;
+ if (currentSegment->id!=CSEG &&
+ currentSegment->id!=GSINIT &&
+ currentSegment->id!=XINIT) {
+ fprintf (stderr, "%s:%d cannot emit bytes in %s\n",
+ module, currentLine, currentSegment->name);
+ exit (1);
+ }
+ if (sscanf(strtok(&line[2], " "), "%04x", &address)!=1) {
+ fprintf (stderr, "%s:%d error in T record\n", module, currentLine);
+ fatalErrors++;
+ }
+
+ address+=currentModule->offset[currentSegment->id];
+ //address+=currentSegment->current;
+ for ( ;
+ (tline=strtok(NULL, " \t\n")) &&
+ (sscanf(tline, "%02x", &byte)==1);
+ ) {
+ currentSegment->image[address++]=byte;
+ currentSegment->current++;
+ }
+ break;
+ }
+ case 'R': {
+ unsigned address, pc;
+ char symbol[132];
+ char how[32];
+ sscanf (line, "R %x %[^ ] %[^ ] %x", &address, how, symbol, &pc);
+ addToRefs (symbol, address, how, pc);
+ break;
+ }
+ default:
+ fprintf (stderr, "%s:%d unknown record \"%s\"\n",
+ module, currentLine, line);
+ fatalErrors++;
+ break;
+ }
+ currentLine++;
+ }
fclose (relModule);
}
-void writeModule(char *module) {
- if (!outFileName[0]) {
- sprintf (outFileName, "%s.bin", module);
+void writeModule(char *outFileName) {
+ FILE *fOut;
+ unsigned int address=segments[GSFINAL].start;
+ unsigned int size=segments[GSFINAL]._size;
+ unsigned int len;
+ unsigned int checksum;
+
+ if ((fOut=fopen(outFileName, "w"))==NULL) {
+ perror (outFileName);
+ }
+
+ while (size) {
+ len = size>16 ? 16 : size;
+ size-=len;
+ fprintf (fOut, ":%02X%04X%02X", len, address, 0);
+ checksum = len + (address>>8) + (address&0xff);
+ while (len--) {
+ checksum += gsfinalImage[address];
+ fprintf (fOut, "%02X", gsfinalImage[address++]);
+ }
+ checksum &= 0xff;
+ if (checksum) {
+ checksum = 0x100 - checksum;
+ }
+ fprintf (fOut, "%02X\n", checksum);
}
- fprintf (stderr, "WriteModule: %s\n", outFileName);
- // oops, forgot something :) */
+ fprintf (fOut, ":00000001FF\n");
+
+ fclose (fOut);
+}
+
+int relocate() {
+ struct SYMBOL *symbol;
+ struct REFERENCE *reference;
+ char *from, *to;
+ int length=segments[GSINIT]._size +
+ segments[CSEG]._size +
+ segments[XINIT]._size;
+ int unresolved=0;
+
+ // first check if it will fit
+ if (length > 0xffff) {
+ fprintf (stderr, "error: code segment exceeds 0xffff\n");
+ 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;
+ }
+
+ // GSFINAL starts at --code-loc ( -b CSEG = 0x1234 )
+ if (segments[CSEG].start & 1) {
+ fprintf (stderr, "*** error: code doesn't start at "
+ "an even address: %04x\n", segments[CSEG].start);
+ exit (1);
+ }
+ segments[GSFINAL].start=segments[CSEG].start;
+ memset(gsfinalImage, 0xff, CODESIZE);
+
+ // copy gsinit to gsfinal
+ from = gsinitImage;
+ to = gsfinalImage + segments[GSFINAL].start + segments[GSFINAL]._size;
+ memcpy(to, from, segments[GSINIT]._size);
+ segments[GSINIT].start=segments[GSFINAL].start;
+ segments[GSFINAL]._size += segments[GSINIT]._size;
+ if (segments[GSFINAL]._size & 1) {
+ segments[GSFINAL]._size++;
+ }
+
+ // append cseg to gsfinal
+ from=csegImage;
+ to = gsfinalImage + segments[GSFINAL].start + segments[GSFINAL]._size;
+ memcpy(to, from, segments[CSEG]._size);
+ segments[CSEG].start=segments[GSFINAL].start+segments[GSFINAL]._size;
+ segments[GSFINAL]._size += segments[CSEG]._size;
+ if (segments[GSFINAL]._size & 1) {
+ segments[GSFINAL]._size++;
+ }
+
+ // append xinit to gsfinal
+ from=xinitImage;
+ to = gsfinalImage + segments[GSFINAL].start + segments[GSFINAL]._size;
+ memcpy(to, from, segments[XINIT]._size);
+ segments[XINIT].start=segments[GSFINAL].start+segments[GSFINAL]._size;
+ segments[GSFINAL]._size += segments[XINIT]._size;
+ if (segments[GSFINAL]._size & 1) {
+ segments[GSFINAL]._size++;
+ }
+
+ // XISEG is located after XSEG
+ if (segments[XSEG].start & 1) {
+ fprintf (stderr, "*** warning: xdata doesn't start at "
+ "an even address: %04x\n", segments[XSEG].start);
+ }
+ if (segments[XSEG]._size & 1) {
+ segments[XSEG]._size++;
+ }
+
+ segments[XISEG].start=segments[XSEG].start +
+ segments[XSEG]._size;
+
+ // now relocate the defined symbols
+ for (symbol=symbols; symbol; symbol=symbol->next) {
+ if (!symbol->absolute) {
+ symbol->address += symbol->segment->start;
+ }
+ }
+ // and the references
+ for (reference=references; reference; reference=reference->next) {
+ symbol=findSymbolByName(reference->name);
+ if (!reference->resolved && !symbol && reference->how!=ABS_PC) {
+ // this reference isn't resolved after all
+ fprintf (stderr, "*** %s:%d undefined symbol %s\n",
+ reference->module->name, reference->lineno,
+ reference->name);
+ fatalErrors++;
+ } else {
+ reference->address +=
+ reference->module->offset[reference->segment->id]+
+ reference->segment->start;
+ reference->pc +=
+ reference->module->offset[reference->segment->id]+
+ reference->segment->start;
+ switch (reference->how)
+ {
+ case REL_FF: {
+ int rel8 = symbol->address-(reference->pc & ~1);
+ if (rel8<-256 || rel8>256) {
+ fprintf (stderr,
+ "rel8 target for %s is out of range in module %s:%d\n",
+ reference->name, reference->module->name,
+ reference->lineno);
+ fatalErrors++;
+ }
+ gsfinalImage[reference->address]=rel8/2;
+ break;
+ }
+ case REL_FFFF: {
+ int rel16 = symbol->address-(reference->pc & ~1);
+ if (rel16<-65536 || rel16>65534) {
+ fprintf (stderr,
+ "rel16 target for %s is out of range in module %s:%d\n",
+ reference->name, reference->module->name,
+ reference->lineno);
+ fatalErrors++;
+ }
+ gsfinalImage[reference->address]=(rel16/2)>>8;
+ gsfinalImage[reference->address+1]=rel16/2;
+ break;
+ }
+ case DIR_70FF:
+ gsfinalImage[reference->address] =
+ (gsfinalImage[reference->address]&~0x70) +
+ ((symbol->address>>4)&0x70);
+ gsfinalImage[reference->address+1] = symbol->address;
+ break;
+ case ABS_FFFF:
+ gsfinalImage[reference->address] = symbol->address>>8;
+ gsfinalImage[reference->address+1] = symbol->address;
+ break;
+ case ABS_FF:
+ gsfinalImage[reference->address] = symbol->address;
+ break;
+ case ABS_PC:
+ {
+ unsigned int address=
+ (gsfinalImage[reference->address]<<8) +
+ gsfinalImage[reference->address+1];
+ address += reference->module->offset[reference->segment->id];
+ address += segments[reference->segment->id].start;
+ gsfinalImage[reference->address] = address>>8;
+ gsfinalImage[reference->address+1] = address;
+ };
+ break;
+ default:
+ fprintf (stderr, "unsupported reference mode %d.\n",
+ reference->how);
+ fatalErrors++;
+ }
+ }
+ }
+ return 0;
}
void usage (char * progName, int errNo) {
- fprintf (stderr, "usage: %s f.rel [f1.rel [f2.rel [...]]]\n", progName);
+ fprintf (stderr, "usage: %s lnkCmdFile\n", progName);
if (errNo) {
exit (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]);
+ 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);
+ if ((lf=fopen(libFile,"r"))==NULL) {
+ continue;
+ }
+ while (fgets(line, 132, lf)) {
+ int dummy; // we need this to get the right count of the next sscanf
+ if (sscanf(line, "S %[^ ] Def%04x", symName, &dummy)==2) {
+ if (isUnresolved(symName, 1)) {
+ readModule(libFile,1);
+ if (resolved++ == unresolved) {
+ // we are done
+ return resolved;
+ }
+ // skip to next lib module
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ return resolved;
+}
+
int main(int argc, char **argv) {
- char outputName[PATH_MAX];
- int i;
+ FILE *linkCommandsFile;
+ char linkCommandsPath[PATH_MAX];
+ char linkCommand[PATH_MAX];
+ struct MODULE *module;
+ struct SYMBOL *symbol;
+ int s;
+ int unresolved;
- // no options yet, assuming "--code-loc 0 --xram-loc 0 --stack-loc 0x100"
- if (argc<2) {
+ if (argc!=2) {
usage(argv[0], 1);
}
- baseName(argv[1], outputName);
- fprintf (stderr, "using baseName: %s\n", outputName);
- for (i=1; i<argc; i++) {
- readModule(argv[i]);
+
+ // read in the commands
+ sprintf (linkCommandsPath, "%s.lnk", argv[1]);
+ if (!(linkCommandsFile=fopen(linkCommandsPath, "r"))) {
+ perror(linkCommandsPath);
+ exit(1);
}
- strcat(outputName, ".bin");
- writeModule (outputName);
- return 0;
+ while (fgets(linkCommand, PATH_MAX, linkCommandsFile)) {
+ linkCommand[strlen(linkCommand)-1]='\0';
+
+ // skip empty lines
+ if (!*linkCommand) {
+ continue;
+ }
+
+ //puts (linkCommand);
+ if (*linkCommand=='-') {
+ switch (linkCommand[1])
+ {
+ case 'm':
+ // probably -muxi, ignore for now
+ break;
+ case 'e':
+ // -e, always in the last line, ignore for now
+ break;
+ case 'b':
+ {
+ // a segment start address like: "-b XSEG = 0x4000"
+ int s;
+ char *seg=strtok(&linkCommand[3], " \t");
+ for (s=0; s<MAX_SEGMENTS; s++) {
+ if (strcmp(segments[s].name, seg)==0) {
+ strtok(NULL, " \t"); // skip the '='
+ if (sscanf(strtok(NULL, " \t"), "%x",
+ &segments[s].start)!=1) {
+ syntaxError(linkCommand);
+ }
+ break;
+ }
+ }
+ if (s==MAX_SEGMENTS) {
+ syntaxError(linkCommand);
+ }
+ }
+ break;
+ case 'k':
+ // a lib path like: "-k /usr/local/share/sdcc/lib/xa51"; one/line
+ libraryPaths[nlibPaths++]=strdup(&linkCommand[3]);
+ break;
+ case 'l':
+ // a lib file like: "-l libsdcc"; one/line
+ libraryFiles[nlibFiles++]=strdup(&linkCommand[3]);
+ break;
+ default:
+ syntaxError(linkCommand);
+ }
+ } else {
+ // not a switch, must be an inputfile; one/line
+ 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", 0, 0);
+ addToDefs("l_XINIT", segments[XINIT]._size, 1);
+ currentSegment=findSegmentByName("XISEG");
+ addToDefs("s_XISEG", 0, 0);
+ addToDefs("l_XISEG", segments[XISEG]._size, 1);
+
+ // mark the resolved references
+ resolve();
+
+ // now do something EXTREMELY SLOW AND INEFFICIENT :)
+ while ((unresolved=relocate())) {
+ if (!scanLibraries(unresolved)) {
+ struct REFERENCE *reference;
+ resolve();
+ 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;
+ }
+ }
+
+ if (unresolved==0) {
+ writeModule(outFileName);
+ }
+
+ // the modules
+ fprintf (mapOut, "Modules:\n");
+ for (module=modules; module; module=module->next) {
+ fprintf (mapOut, "\t%s\n", module->name);
+ for (s=0; s<MAX_SEGMENTS; s++) {
+ if (module->size[s]) {
+ fprintf (mapOut, "\t\t%s:0x%04x-0x%04x\n", segments[s].name,
+ module->offset[s]+segments[s].start,
+ module->offset[s]+segments[s].start+module->size[s]);
+ }
+ }
+ }
+
+ // the segments
+ fprintf (mapOut, "\nSegments:\n");
+ for (s=1; s<MAX_SEGMENTS; s++) {
+ if (segments[s]._size) {
+ 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);
+ }
+
+ fclose(mapOut);
+ return fatalErrors? 1 : 0;
}
-
+