1 /* WORK IN PROGRESS: do not watch this if you don't have the legal
2 age in your country to watch this.
5 /* This program is distributed in the hope that it will be useful,
6 * but WITHOUT ANY WARRANTY; without even the implied warranty of
7 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8 * GNU General Public License for more details.
10 * You should have received a copy of the GNU General Public License
11 * along with this program; if not, write to the Free Software
12 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 /* This is a cheap hack. The xa51 has a couple of ways to scramble
16 relocation info into it's opcode that the standard linker can't
17 handle, not to mention word allignment.
21 The relocatable format looks like the known one, BUT ISN'T.
23 The only things that are handled now are:
25 "SDCCXA rel, version %f" must be the first line, sort of MAGIC word
26 "H %d areas %d global symbols" defines the # of areas and globals
27 "S <symbol> [Ref0000 | DefXXXX | AbsXXXX]" Def's are supposed to be
28 defined in their own area/segment
29 "A <seg> size %d flags %d" switch to another segment. this can happen
30 multiple times and should be equal. flags is ignored for now
31 "T xxxx <how> <symbol> 0"
32 "R xxxx <how> <symbol> <pc+>" the relocation info. xxxx is the address
33 within relative code space. How is something like REL_FF, REL_FFFF,
34 ABS_70FF. Symbol is the referenced symbol and pc+ is the program
35 counter that will be used to calculate the relative address (that is
36 the address of the following instruction).
38 So, this is not a standalone linker. It will only link files generated
39 by xa_rasm, which will only process files generated by the xa51 sdcc
48 #include "xa_version.h"
51 // these are all concatenated into the code image
56 // here goes the final output and should be used by the assembler
59 // these are only for storage
97 #define CODESIZE 0x10000
101 unsigned char gsinitImage[CODESIZE];
102 unsigned char csegImage[CODESIZE];
103 unsigned char xinitImage[CODESIZE];
104 unsigned char gsfinalImage[CODESIZE];
113 unsigned char *image;
114 } segments[MAX_SEGMENTS]={
115 {0, "???", 0, 0, 0, 0, NULL},
117 {GSINIT, "GSINIT", 0, 0, 0, 0, gsinitImage},
118 {CSEG, "CSEG", 0, 0, 0, 0, csegImage},
119 {XINIT, "XINIT", 0, 0, 0, 0, xinitImage},
120 {GSFINAL, "GSFINAL", 0, 0, 0, 0, gsfinalImage},
122 {BSEG, "BSEG", 0, 0, 0, 0, NULL},
123 {DSEG, "DSEG", 0, 0, 0, 0, NULL},
124 {XSEG, "XSEG", 0, 0, 0, 0, NULL},
125 {XISEG, "XISEG", 0, 0, 0, 0, NULL},
130 int offset[MAX_SEGMENTS];
131 int size[MAX_SEGMENTS];
140 struct MODULE *module;
142 struct SEGMENT *segment;
151 struct MODULE *module;
152 struct SEGMENT *segment;
154 unsigned address, pc;
157 struct REFERENCE *next;
158 struct REFERENCE *last;
161 char *libraryPaths[128];
163 char *libraryFiles[128];
166 static char outFileName[PATH_MAX]={'\0'};
167 static char mapFileName[PATH_MAX]={'\0'};
170 struct SEGMENT *currentSegment;
171 struct MODULE *currentModule;
174 int howToReference(char *how) {
176 for (r=1; r<MAX_REFS; r++) {
177 if (strcmp(refModes[r], how)==0) {
184 struct SEGMENT *findSegmentByName(char *segment) {
186 for (s=0; s<MAX_SEGMENTS; s++) {
187 if (strcmp(segments[s].name, segment)==0) {
194 struct SYMBOL *findSymbolByName(char *symName) {
195 struct SYMBOL *symbol;
196 for (symbol=symbols; symbol; symbol=symbol->next) {
197 if (strcmp(symbol->name, symName)==0) {
204 struct MODULE *findModuleByName(char *modName) {
205 struct MODULE *module;
206 for (module=modules; module; module=module->next) {
207 if (strcmp(module->name, modName)==0) {
214 void addToModules (char *name, int isLib) {
215 struct MODULE *module;
218 module=calloc(1, sizeof(struct MODULE));
219 module->name=strdup(name);
220 for (s=0; s<MAX_SEGMENTS; s++) {
221 module->offset[s]=(segments[s]._size+1)&0xfffffe;
227 modules->last->next=module;
229 currentModule=modules->last=module;
232 void addToRefs(char *ref, int address, char *how, int pc) {
233 struct REFERENCE *reference;
235 reference=calloc(1, sizeof(struct REFERENCE));
236 reference->name=strdup(ref);
237 reference->module=currentModule;
238 reference->segment=currentSegment;
239 reference->lineno=currentLine;
240 reference->address=address;
241 reference->how=howToReference(how);
242 if (reference->how==ABS_PC) {
243 reference->resolved=1;
247 references=reference;
249 references->last->next=reference;
251 references->last=reference;
255 struct REFERENCE *reference;
256 for (reference=references; reference; reference=reference->next) {
257 if ((reference->how==ABS_PC) || findSymbolByName(reference->name)) {
258 reference->resolved=1;
263 int isUnresolved(char *ref, int resolved) {
264 struct REFERENCE *reference;
266 for (reference=references; reference; reference=reference->next) {
267 if (strcmp(reference->name, ref)==0) {
269 if (reference->resolved) {
274 reference->resolved=1;
282 void addToDefs(char *def, int address, char absolute) {
283 struct SYMBOL *symbol;
285 // no duplicates allowed
286 if ((symbol=findSymbolByName(def))) {
287 fprintf (stderr, "*** %s:%d duplicate symbol %s first defined in "
289 currentModule->name, currentLine, def,
290 symbol->module->name, symbol->lineno);
294 symbol=calloc(1, sizeof(struct SYMBOL));
295 symbol->name=strdup(def);
296 symbol->module=currentModule;
297 symbol->lineno=currentLine;
298 symbol->segment=currentSegment;
299 symbol->absolute=absolute;
300 symbol->address=currentModule->offset[currentSegment->id]+address;
304 symbols->last->next=symbol;
306 symbols->last=symbol;
307 currentSegment->hasSymbols++;
310 void syntaxError (char *err) {
311 fprintf (stderr, "*** %s:%d error while parsing '%s'\n",
312 currentModule->name, currentLine, err);
316 void readModule(char *module, int isLib) {
320 char moduleName[PATH_MAX];
321 int segments, globals;
325 if ((relModule=fopen(module, "r"))==NULL) {
330 // first we need to check if this is a valid file
331 if (sscanf(fgets(line, 132, relModule),
332 "SDCCXA rel, version %lf", &hisVersion)!=1) {
333 fprintf (stderr, "*** %s is not a valid input file\n", module);
336 if (hisVersion!=version) {
337 fprintf (stderr, "*** WARNING: version conflict; "
338 "we(%1.1f) != %s(%1.1f)\n",
339 version, module, hisVersion);
343 // H 7 areas 168 global symbols
344 if (sscanf(fgets(line, 132, relModule),
345 "H %d areas %d global symbols",
346 &segments, &globals)!=2) {
352 if (sscanf(fgets(line, 132, relModule),
353 "M %s", moduleName)!=1) {
357 // add this to the known modules with current offsets
358 addToModules(module, isLib);
362 // now for the ASTR tags
363 while (fgets(line, 132, relModule)) {
369 if (sscanf(line, "A %[^ ] size %d flags %d",
370 segment, &size, &flags)!=3) {
373 // do we know this segment?
374 if (!(currentSegment=findSegmentByName(segment))) {
375 fprintf (stderr, "*** %s:%d unknown area: %s\n", module,
376 currentLine, segment);
379 // double check repeated 'A' records
380 if (currentModule->size[currentSegment->id]) {
381 // pleased to meet you again, I hope ...
382 if (currentModule->size[currentSegment->id] != size) {
383 fprintf (stderr, "*** %s:%d error %s size %d != %d\n",
385 currentSegment->name,
386 currentModule->size[currentSegment->id],
391 currentSegment->_size += size;
392 currentModule->size[currentSegment->id] = size;
394 // never mind about the flags for now
400 unsigned int address;
401 if (sscanf(line, "S %[^ ] %s", symbol, refdef)!=2) {
402 fprintf (stderr, "*** %s:%d syntax error near \"%s\"\n",
403 module, currentLine, line);
406 if (strncmp(refdef, "Ref", 3)==0) {
407 // we don't need them
408 } else if (strncmp(refdef, "Def", 3)==0) {
409 sscanf (refdef, "Def%04x", &address);
410 addToDefs(symbol, address, 0);
411 } else if (strncmp(refdef, "Abs", 3)==0) {
412 sscanf (refdef, "Abs%04x", &address);
413 addToDefs(symbol, address, 1);
415 fprintf (stderr, "%s:%d found invalid symbol definition \"%s\"\n",
416 module, currentLine, line);
422 unsigned int address;
425 if (currentSegment->id!=CSEG &&
426 currentSegment->id!=GSINIT &&
427 currentSegment->id!=XINIT) {
428 fprintf (stderr, "%s:%d cannot emit bytes in %s\n",
429 module, currentLine, currentSegment->name);
432 if (sscanf(strtok(&line[2], " "), "%04x", &address)!=1) {
433 fprintf (stderr, "%s:%d error in T record\n", module, currentLine);
437 address+=currentModule->offset[currentSegment->id];
438 //address+=currentSegment->current;
440 (tline=strtok(NULL, " \t\n")) &&
441 (sscanf(tline, "%02x", &byte)==1);
443 currentSegment->image[address++]=byte;
444 currentSegment->current++;
449 unsigned address, pc;
452 sscanf (line, "R %x %[^ ] %[^ ] %x", &address, how, symbol, &pc);
453 addToRefs (symbol, address, how, pc);
457 fprintf (stderr, "%s:%d unknown record \"%s\"\n",
458 module, currentLine, line);
467 void writeModule(char *outFileName) {
469 unsigned int address=segments[GSFINAL].start;
470 unsigned int size=segments[GSFINAL]._size;
472 unsigned int checksum;
474 if ((fOut=fopen(outFileName, "w"))==NULL) {
475 perror (outFileName);
479 len = size>16 ? 16 : size;
481 fprintf (fOut, ":%02X%04X%02X", len, address, 0);
482 checksum = len + (address>>8) + (address&0xff);
484 checksum += gsfinalImage[address];
485 fprintf (fOut, "%02X", gsfinalImage[address++]);
489 checksum = 0x100 - checksum;
491 fprintf (fOut, "%02X\n", checksum);
493 fprintf (fOut, ":00000001FF\n");
499 struct SYMBOL *symbol;
500 struct REFERENCE *reference;
502 int length=segments[GSINIT]._size +
503 segments[CSEG]._size +
504 segments[XINIT]._size;
507 // first check if it will fit
508 if (length > 0xffff) {
509 fprintf (stderr, "error: code segment exceeds 0xffff\n");
513 // resolve reverences
514 for (reference=references; reference; reference=reference->next) {
515 if (!reference->resolved && !findSymbolByName(reference->name)) {
520 // first scan the libraries
524 // GSFINAL starts at --code-loc ( -b CSEG = 0x1234 )
525 if (segments[CSEG].start & 1) {
526 fprintf (stderr, "*** error: code doesn't start at "
527 "an even address: %04x\n", segments[CSEG].start);
530 segments[GSFINAL].start=segments[CSEG].start;
531 memset(gsfinalImage, 0xff, CODESIZE);
533 // copy gsinit to gsfinal
535 to = gsfinalImage + segments[GSFINAL].start + segments[GSFINAL]._size;
536 memcpy(to, from, segments[GSINIT]._size);
537 segments[GSINIT].start=segments[GSFINAL].start;
538 segments[GSFINAL]._size += segments[GSINIT]._size;
539 if (segments[GSFINAL]._size & 1) {
540 segments[GSFINAL]._size++;
543 // append cseg to gsfinal
545 to = gsfinalImage + segments[GSFINAL].start + segments[GSFINAL]._size;
546 memcpy(to, from, segments[CSEG]._size);
547 segments[CSEG].start=segments[GSFINAL].start+segments[GSFINAL]._size;
548 segments[GSFINAL]._size += segments[CSEG]._size;
549 if (segments[GSFINAL]._size & 1) {
550 segments[GSFINAL]._size++;
553 // append xinit to gsfinal
555 to = gsfinalImage + segments[GSFINAL].start + segments[GSFINAL]._size;
556 memcpy(to, from, segments[XINIT]._size);
557 segments[XINIT].start=segments[GSFINAL].start+segments[GSFINAL]._size;
558 segments[GSFINAL]._size += segments[XINIT]._size;
559 if (segments[GSFINAL]._size & 1) {
560 segments[GSFINAL]._size++;
563 // XISEG is located after XSEG
564 if (segments[XSEG].start & 1) {
565 fprintf (stderr, "*** warning: xdata doesn't start at "
566 "an even address: %04x\n", segments[XSEG].start);
568 if (segments[XSEG]._size & 1) {
569 segments[XSEG]._size++;
572 segments[XISEG].start=segments[XSEG].start +
573 segments[XSEG]._size;
575 // now relocate the defined symbols
576 for (symbol=symbols; symbol; symbol=symbol->next) {
577 if (!symbol->absolute) {
578 symbol->address += symbol->segment->start;
581 // and the references
582 for (reference=references; reference; reference=reference->next) {
583 symbol=findSymbolByName(reference->name);
584 if (!reference->resolved && !symbol && reference->how!=ABS_PC) {
585 // this reference isn't resolved after all
586 fprintf (stderr, "*** %s:%d undefined symbol %s\n",
587 reference->module->name, reference->lineno,
591 reference->address +=
592 reference->module->offset[reference->segment->id]+
593 reference->segment->start;
595 reference->module->offset[reference->segment->id]+
596 reference->segment->start;
597 switch (reference->how)
600 int rel8 = symbol->address-(reference->pc & ~1);
601 if (rel8<-256 || rel8>256) {
603 "rel8 target for %s is out of range in module %s:%d\n",
604 reference->name, reference->module->name,
608 gsfinalImage[reference->address]=rel8/2;
612 int rel16 = symbol->address-(reference->pc & ~1);
613 if (rel16<-65536 || rel16>65534) {
615 "rel16 target for %s is out of range in module %s:%d\n",
616 reference->name, reference->module->name,
620 gsfinalImage[reference->address]=(rel16/2)>>8;
621 gsfinalImage[reference->address+1]=rel16/2;
625 gsfinalImage[reference->address] =
626 (gsfinalImage[reference->address]&~0x70) +
627 ((symbol->address>>4)&0x70);
628 gsfinalImage[reference->address+1] = symbol->address;
631 gsfinalImage[reference->address] = symbol->address>>8;
632 gsfinalImage[reference->address+1] = symbol->address;
635 gsfinalImage[reference->address] = symbol->address;
639 unsigned int address=
640 (gsfinalImage[reference->address]<<8) +
641 gsfinalImage[reference->address+1];
642 address += reference->module->offset[reference->segment->id];
643 address += segments[reference->segment->id].start;
644 gsfinalImage[reference->address] = address>>8;
645 gsfinalImage[reference->address+1] = address;
649 fprintf (stderr, "unsupported reference mode %d.\n",
658 void usage (char * progName, int errNo) {
659 fprintf (stderr, "usage: %s lnkCmdFile\n", progName);
665 int scanLibraries(int unresolved) {
668 char libFiles[PATH_MAX];
669 char libFile[PATH_MAX];
674 for (nlp=0; nlp<nlibPaths; nlp++) {
675 for (nlf=0; nlf<nlibFiles; nlf++) {
676 sprintf (libFiles, "%s/%s.lib", libraryPaths[nlp], libraryFiles[nlf]);
677 if ((lfs=fopen(libFiles,"r"))==NULL) {
680 while (fgets(line, 132, lfs)) {
681 // remove trailing \n
682 line[strlen(line)-1]='\0';
683 sprintf (libFile, "%s/%s", libraryPaths[nlp], line);
684 if ((lf=fopen(libFile,"r"))==NULL) {
687 while (fgets(line, 132, lf)) {
688 int dummy; // we need this to get the right count of the next sscanf
689 if (sscanf(line, "S %[^ ] Def%04x", symName, &dummy)==2) {
690 if (isUnresolved(symName, 1)) {
691 readModule(libFile,1);
692 if (resolved++ == unresolved) {
696 // skip to next lib module
707 int main(int argc, char **argv) {
708 FILE *linkCommandsFile;
709 char linkCommandsPath[PATH_MAX];
710 char linkCommand[PATH_MAX];
711 struct MODULE *module;
712 struct SYMBOL *symbol;
720 // read in the commands
721 sprintf (linkCommandsPath, "%s.lnk", argv[1]);
722 if (!(linkCommandsFile=fopen(linkCommandsPath, "r"))) {
723 perror(linkCommandsPath);
726 while (fgets(linkCommand, PATH_MAX, linkCommandsFile)) {
727 linkCommand[strlen(linkCommand)-1]='\0';
734 //puts (linkCommand);
735 if (*linkCommand=='-') {
736 switch (linkCommand[1])
739 // probably -muxi, ignore for now
742 // -e, always in the last line, ignore for now
746 // a segment start address like: "-b XSEG = 0x4000"
748 char *seg=strtok(&linkCommand[3], " \t");
749 for (s=0; s<MAX_SEGMENTS; s++) {
750 if (strcmp(segments[s].name, seg)==0) {
751 strtok(NULL, " \t"); // skip the '='
752 if (sscanf(strtok(NULL, " \t"), "%x",
753 &segments[s].start)!=1) {
754 syntaxError(linkCommand);
759 if (s==MAX_SEGMENTS) {
760 syntaxError(linkCommand);
765 // a lib path like: "-k /usr/local/share/sdcc/lib/xa51"; one/line
766 libraryPaths[nlibPaths++]=strdup(&linkCommand[3]);
769 // a lib file like: "-l libsdcc"; one/line
770 libraryFiles[nlibFiles++]=strdup(&linkCommand[3]);
773 syntaxError(linkCommand);
776 // not a switch, must be an inputfile; one/line
777 readModule(linkCommand, 0);
778 // the first one defines the output name
779 if (!outFileName[0]) {
780 strncpy(outFileName, linkCommand,
781 strlen(linkCommand)-4);
782 sprintf(mapFileName, "%s.map", outFileName);
783 strcat(outFileName, ".hex");
784 if ((mapOut=fopen(mapFileName, "w"))==NULL) {
791 // add the segment symbols
792 currentSegment=findSegmentByName("XINIT");
793 addToDefs("s_XINIT", 0, 0);
794 addToDefs("l_XINIT", segments[XINIT]._size, 1);
795 currentSegment=findSegmentByName("XISEG");
796 addToDefs("s_XISEG", 0, 0);
797 addToDefs("l_XISEG", segments[XISEG]._size, 1);
799 // mark the resolved references
802 // now do something EXTREMELY SLOW AND INEFFICIENT :)
803 while ((unresolved=relocate())) {
804 if (!scanLibraries(unresolved)) {
805 struct REFERENCE *reference;
807 for (reference=references; reference; reference=reference->next) {
808 if (!reference->resolved) {
809 fprintf (stderr, "*** unresolved symbol %s in %s:%d\n",
810 reference->name, reference->module->name,
820 writeModule(outFileName);
824 fprintf (mapOut, "Modules:\n");
825 for (module=modules; module; module=module->next) {
826 fprintf (mapOut, "\t%s\n", module->name);
827 for (s=0; s<MAX_SEGMENTS; s++) {
828 if (module->size[s]) {
829 fprintf (mapOut, "\t\t%s:0x%04x-0x%04x\n", segments[s].name,
830 module->offset[s]+segments[s].start,
831 module->offset[s]+segments[s].start+module->size[s]);
837 fprintf (mapOut, "\nSegments:\n");
838 for (s=1; s<MAX_SEGMENTS; s++) {
839 if (segments[s]._size) {
840 fprintf (mapOut, "\t%s start 0x%04x size 0x%04x %d symbols\n",
841 segments[s].name, segments[s].start,
843 segments[s].hasSymbols);
848 fprintf (mapOut, "\nSymbols:\n");
849 for (symbol=symbols; symbol; symbol=symbol->next) {
850 fprintf (mapOut, "%s\t%s %s0x%04x %s\n", symbol->name,
851 symbol->segment->name,
852 symbol->absolute ? "= " : "",
853 symbol->address, symbol->module->name);
857 return fatalErrors? 1 : 0;