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. No hash or qsort yet.
19 The relocatable format looks like the known one, BUT ISN'T.
21 The only things that are handled now are:
23 "SDCCXA rel, version %f" must be the first line, sort of MAGIC word
24 "H %d areas %d global symbols" defines the # of areas and globals
25 "S <symbol> [Ref0000 | DefXXXX | AbsXXXX]" Def's are supposed to be
26 defined in their own area/segment
27 "A <seg> size %d flags %d" switch to another segment. this can happen
28 multiple times and should be equal. flags is ignored for now
29 "T xxxx <how> <symbol> 0"
30 "R xxxx <how> <symbol> <pc+>" the relocation info. xxxx is the address
31 within relative code space. How is something like REL_FF, REL_FFFF,
32 ABS_70FF. Symbol is the referenced symbol and pc+ is the program
33 counter that will be used to calculate the relative address (that is
34 the address of the following instruction).
36 So, this is not a standalone linker. It will only link files generated
37 by xa_rasm, which will only process files generated by the xa51 sdcc
46 #include "xa_version.h"
49 // these are all concatenated into the code image
53 GSFINAL, // here goes the final output
55 // these are only for storage
91 #define CODESIZE 0x10000
95 unsigned char gsinitImage[CODESIZE];
96 unsigned char csegImage[CODESIZE];
97 unsigned char xinitImage[CODESIZE];
98 unsigned char gsfinalImage[CODESIZE];
107 unsigned char *image;
108 } segments[MAX_SEGMENTS]={
109 {0, "???", 0, 0, 0, 0, NULL},
111 {GSINIT, "GSINIT", 0, 0, 0, 0, gsinitImage},
112 {CSEG, "CSEG", 0, 0, 0, 0, csegImage},
113 {XINIT, "XINIT", 0, 0, 0, 0, xinitImage},
114 {GSFINAL, "GSFINAL", 0, 0, 0, 0, gsfinalImage},
116 {BSEG, "BSEG", 0, 0, 0, 0, NULL},
117 {DSEG, "DSEG", 0, 0, 0, 0, NULL},
118 {XSEG, "XSEG", 0, 0, 0, 0, NULL},
119 {XISEG, "XISEG", 0, 0, 0, 0, NULL},
124 int offset[MAX_SEGMENTS];
125 int size[MAX_SEGMENTS];
134 struct MODULE *module;
136 struct SEGMENT *segment;
145 struct MODULE *module;
146 struct SEGMENT *segment;
148 unsigned address, pc;
151 struct REFERENCE *next;
152 struct REFERENCE *last;
155 char *libraryPaths[128];
157 char *libraryFiles[128];
160 static char outFileName[PATH_MAX]={'\0'};
161 static char mapFileName[PATH_MAX]={'\0'};
164 struct SEGMENT *currentSegment;
165 struct MODULE *currentModule;
168 int howToReference(char *how) {
170 for (r=1; r<MAX_REFS; r++) {
171 if (strcmp(refModes[r], how)==0) {
178 struct SEGMENT *findSegmentByName(char *segment) {
180 for (s=0; s<MAX_SEGMENTS; s++) {
181 if (strcmp(segments[s].name, segment)==0) {
188 struct SYMBOL *findSymbolByName(char *symName) {
189 struct SYMBOL *symbol;
190 for (symbol=symbols; symbol; symbol=symbol->next) {
191 if (strcmp(symbol->name, symName)==0) {
198 struct MODULE *findModuleByName(char *modName) {
199 struct MODULE *module;
200 for (module=modules; module; module=module->next) {
201 if (strcmp(module->name, modName)==0) {
208 void addToModules (char *name, int isLib) {
209 struct MODULE *module;
212 module=calloc(1, sizeof(struct MODULE));
213 module->name=strdup(name);
214 for (s=0; s<MAX_SEGMENTS; s++) {
215 module->offset[s]=segments[s]._size;
221 modules->last->next=module;
223 currentModule=modules->last=module;
226 void addToRefs(char *ref, int address, char *how, int pc) {
227 struct REFERENCE *reference;
229 reference=calloc(1, sizeof(struct REFERENCE));
230 reference->name=strdup(ref);
231 reference->module=currentModule;
232 reference->segment=currentSegment;
233 reference->lineno=currentLine;
234 reference->address=address;
235 reference->how=howToReference(how);
236 if (reference->how==ABS_PC) {
237 reference->resolved=1;
241 references=reference;
243 references->last->next=reference;
245 references->last=reference;
249 struct REFERENCE *reference;
250 for (reference=references; reference; reference=reference->next) {
251 if ((reference->how==ABS_PC) || findSymbolByName(reference->name)) {
252 reference->resolved=1;
257 int isUnresolved(char *ref, int resolved) {
258 struct REFERENCE *reference;
260 for (reference=references; reference; reference=reference->next) {
261 if (strcmp(reference->name, ref)==0) {
263 if (reference->resolved) {
268 reference->resolved=1;
276 void addToDefs(char *def, int address, char absolute) {
277 struct SYMBOL *symbol;
279 // no duplicates allowed
280 if ((symbol=findSymbolByName(def))) {
281 fprintf (stderr, "*** %s:%d duplicate symbol %s first defined in "
283 currentModule->name, currentLine, def,
284 symbol->module->name, symbol->lineno);
288 symbol=calloc(1, sizeof(struct SYMBOL));
289 symbol->name=strdup(def);
290 symbol->module=currentModule;
291 symbol->lineno=currentLine;
292 symbol->segment=currentSegment;
293 symbol->absolute=absolute;
294 symbol->address=currentModule->offset[currentSegment->id]+address;
298 symbols->last->next=symbol;
300 symbols->last=symbol;
301 currentSegment->hasSymbols++;
304 void syntaxError (char *err) {
305 fprintf (stderr, "*** %s:%d error while parsing '%s'\n",
306 currentModule->name, currentLine, err);
310 void readModule(char *module, int isLib) {
314 char moduleName[PATH_MAX];
315 int segments, globals;
319 if ((relModule=fopen(module, "r"))==NULL) {
324 // first we need to check if this is a valid file
325 if (sscanf(fgets(line, 132, relModule),
326 "SDCCXA rel, version %lf", &hisVersion)!=1) {
327 fprintf (stderr, "*** %s is not a valid input file\n", module);
330 if (hisVersion!=version) {
331 fprintf (stderr, "*** WARNING: version conflict; "
332 "we(%1.1f) != %s(%1.1f)\n",
333 version, module, hisVersion);
337 // H 7 areas 168 global symbols
338 if (sscanf(fgets(line, 132, relModule),
339 "H %d areas %d global symbols",
340 &segments, &globals)!=2) {
346 if (sscanf(fgets(line, 132, relModule),
347 "M %s", moduleName)!=1) {
351 // add this to the known modules with current offsets
352 addToModules(module, isLib);
356 // now for the ASTR tags
357 while (fgets(line, 132, relModule)) {
363 if (sscanf(line, "A %[^ ] size %d flags %d",
364 segment, &size, &flags)!=3) {
367 // do we know this segment?
368 if (!(currentSegment=findSegmentByName(segment))) {
369 fprintf (stderr, "*** %s:%d unknown area: %s\n", module,
370 currentLine, segment);
373 // double check repeated 'A' records
374 if (currentModule->size[currentSegment->id]) {
375 // pleased to meet you again, I hope ...
376 if (currentModule->size[currentSegment->id] != size) {
377 fprintf (stderr, "*** %s:%d error %s size %d != %d\n",
379 currentSegment->name,
380 currentModule->size[currentSegment->id],
385 currentSegment->_size += size;
386 currentModule->size[currentSegment->id] = size;
388 // never mind about the flags for now
394 unsigned int address;
395 if (sscanf(line, "S %[^ ] %s", symbol, refdef)!=2) {
396 fprintf (stderr, "*** %s:%d syntax error near \"%s\"\n",
397 module, currentLine, line);
400 if (strncmp(refdef, "Ref", 3)==0) {
401 // we don't need them
402 } else if (strncmp(refdef, "Def", 3)==0) {
403 sscanf (refdef, "Def%04x", &address);
404 addToDefs(symbol, address, 0);
405 } else if (strncmp(refdef, "Abs", 3)==0) {
406 sscanf (refdef, "Abs%04x", &address);
407 addToDefs(symbol, address, 1);
409 fprintf (stderr, "%s:%d found invalid symbol definition \"%s\"\n",
410 module, currentLine, line);
416 unsigned int address;
419 if (currentSegment->id!=CSEG &&
420 currentSegment->id!=GSINIT &&
421 currentSegment->id!=XINIT) {
422 fprintf (stderr, "%s:%d cannot emit bytes in %s\n",
423 module, currentLine, currentSegment->name);
426 if (sscanf(strtok(&line[2], " "), "%04x", &address)!=1) {
427 fprintf (stderr, "%s:%d error in T record\n", module, currentLine);
431 address+=currentModule->offset[currentSegment->id];
432 //address+=currentSegment->current;
434 (tline=strtok(NULL, " \t\n")) &&
435 (sscanf(tline, "%02x", &byte)==1);
437 currentSegment->image[address++]=byte;
438 currentSegment->current++;
443 unsigned address, pc;
446 sscanf (line, "R %x %[^ ] %[^ ] %x", &address, how, symbol, &pc);
447 addToRefs (symbol, address, how, pc);
451 fprintf (stderr, "%s:%d unknown record \"%s\"\n",
452 module, currentLine, line);
458 // that's all for now, thanks for watching */
462 void writeModule(char *outFileName) {
464 unsigned int address=segments[GSFINAL].start;
465 unsigned int size=segments[GSFINAL]._size;
467 unsigned int checksum;
469 fprintf (stderr, "writeModule: %s from 0x%04x to 0x%04x\n",
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 segments[GSFINAL].start=segments[CSEG].start;
526 memset(gsfinalImage, 0xff, CODESIZE);
528 // copy gsinit to gsfinal
530 to = gsfinalImage + segments[GSFINAL].start + segments[GSFINAL]._size;
531 memcpy(to, from, segments[GSINIT]._size);
532 segments[GSINIT].start=segments[GSFINAL].start;
533 segments[GSFINAL]._size += segments[GSINIT]._size;
535 // append cseg to gsfinal
537 to = gsfinalImage + segments[GSFINAL].start + segments[GSFINAL]._size;
538 memcpy(to, from, segments[CSEG]._size);
539 segments[CSEG].start=segments[GSFINAL].start+segments[GSFINAL]._size;
540 segments[GSFINAL]._size += segments[CSEG]._size;
542 // append xinit to gsfinal
544 to = gsfinalImage + segments[GSFINAL].start + segments[GSFINAL]._size;
545 memcpy(to, from, segments[XINIT]._size);
546 segments[XINIT].start=segments[GSFINAL].start+segments[GSFINAL]._size;
547 segments[GSFINAL]._size += segments[XINIT]._size;
549 // XISEG is located after XSEG
550 segments[XISEG].start=segments[XSEG].start +
551 segments[XSEG]._size;
553 // now relocate the defined symbols
554 for (symbol=symbols; symbol; symbol=symbol->next) {
555 if (!symbol->absolute) {
556 symbol->address += symbol->segment->start;
559 // and the references
560 for (reference=references; reference; reference=reference->next) {
561 symbol=findSymbolByName(reference->name);
562 if (!reference->resolved && !symbol && reference->how!=ABS_PC) {
563 // this reference isn't resolved after all
564 fprintf (stderr, "*** %s:%d undefined symbol %s\n",
565 reference->module->name, reference->lineno,
569 reference->address +=
570 reference->module->offset[reference->segment->id]+
571 reference->segment->start;
573 reference->module->offset[reference->segment->id]+
574 reference->segment->start;
575 switch (reference->how)
578 int rel8 = symbol->address-(reference->pc & ~1);
579 if (rel8<-256 || rel8>256) {
581 "rel8 target for %s is out of range in module %s\n",
582 reference->name, reference->module->name);
585 gsfinalImage[reference->address]=rel8/2;
589 int rel16 = symbol->address-(reference->pc & ~1);
590 if (rel16<-65536 || rel16>65534) {
592 "rel16 target for %s is out of range in module %s\n",
593 reference->name, reference->module->name);
596 gsfinalImage[reference->address]=(rel16/2)>>8;
597 gsfinalImage[reference->address+1]=rel16/2;
601 gsfinalImage[reference->address] = (symbol->address<<4)&0x70;
602 gsfinalImage[reference->address+1] = symbol->address;
605 gsfinalImage[reference->address] = symbol->address>>8;
606 gsfinalImage[reference->address+1] = symbol->address;
609 gsfinalImage[reference->address] = symbol->address;
613 unsigned int address=
614 (gsfinalImage[reference->address]<<8) +
615 gsfinalImage[reference->address+1];
616 address += reference->module->offset[reference->segment->id];
617 address += segments[reference->segment->id].start;
618 gsfinalImage[reference->address] = address>>8;
619 gsfinalImage[reference->address+1] = address;
623 fprintf (stderr, "unsupported reference mode %d.\n",
632 void usage (char * progName, int errNo) {
633 fprintf (stderr, "usage: %s lnkCmdFile\n", progName);
639 int scanLibraries(int unresolved) {
642 char libFiles[PATH_MAX];
643 char libFile[PATH_MAX];
648 for (nlp=0; nlp<nlibPaths; nlp++) {
649 for (nlf=0; nlf<nlibFiles; nlf++) {
650 sprintf (libFiles, "%s/%s.lib", libraryPaths[nlp], libraryFiles[nlf]);
651 //fprintf (stderr, " %s\n", libFiles);
652 if ((lfs=fopen(libFiles,"r"))==NULL) {
655 while (fgets(line, 132, lfs)) {
656 // remove trailing \n
657 line[strlen(line)-1]='\0';
658 sprintf (libFile, "%s/%s", libraryPaths[nlp], line);
659 //fprintf (stderr, " %s\n", libFile);
660 if ((lf=fopen(libFile,"r"))==0) {
663 while (fgets(line, 132, lf)) {
664 int dummy; // we need this to get the right count of the next sscanf
665 if (sscanf(line, "S %[^ ] Def%04x", symName, &dummy)==2) {
666 if (isUnresolved(symName, 1)) {
667 //fprintf (stderr, "%s:%s\n", libFile, symName);
668 readModule(libFile,1);
669 if (resolved++ == unresolved) {
673 // skip to next lib module
684 int main(int argc, char **argv) {
685 FILE *linkCommandsFile;
686 char linkCommandsPath[PATH_MAX];
687 char linkCommand[PATH_MAX];
688 struct MODULE *module;
689 struct SYMBOL *symbol;
697 // read in the commands
698 sprintf (linkCommandsPath, "%s.lnk", argv[1]);
699 if (!(linkCommandsFile=fopen(linkCommandsPath, "r"))) {
700 perror(linkCommandsPath);
703 while (fgets(linkCommand, PATH_MAX, linkCommandsFile)) {
704 linkCommand[strlen(linkCommand)-1]='\0';
711 //puts (linkCommand);
712 if (*linkCommand=='-') {
713 switch (linkCommand[1])
716 // probably -muxi, ignore for now
719 // -e, always in the last line, ignore for now
723 // a segment start address like: "-b XSEG = 0x4000"
725 char *seg=strtok(&linkCommand[3], " \t");
726 for (s=0; s<MAX_SEGMENTS; s++) {
727 if (strcmp(segments[s].name, seg)==0) {
728 strtok(NULL, " \t"); // skip the '='
729 if (sscanf(strtok(NULL, " \t"), "%x",
730 &segments[s].start)!=1) {
731 syntaxError(linkCommand);
736 if (s==MAX_SEGMENTS) {
737 syntaxError(linkCommand);
742 // a lib path like: "-k /usr/local/share/sdcc/lib/xa51"; one/line
743 libraryPaths[nlibPaths++]=strdup(&linkCommand[3]);
746 // a lib file like: "-l libsdcc"; one/line
747 libraryFiles[nlibFiles++]=strdup(&linkCommand[3]);
750 syntaxError(linkCommand);
753 // not a switch, must be an inputfile; one/line
754 readModule(linkCommand, 0);
755 // the first one defines the output name
756 if (!outFileName[0]) {
757 strncpy(outFileName, linkCommand,
758 strlen(linkCommand)-4);
759 sprintf(mapFileName, "%s.map", outFileName);
760 strcat(outFileName, ".hex");
761 if ((mapOut=fopen(mapFileName, "w"))==NULL) {
768 // add the segment symbols
769 currentSegment=findSegmentByName("XINIT");
770 addToDefs("s_XINIT", 0, 0);
771 addToDefs("l_XINIT", segments[XINIT]._size, 1);
772 currentSegment=findSegmentByName("XISEG");
773 addToDefs("s_XISEG", 0, 0);
774 addToDefs("l_XISEG", segments[XISEG]._size, 1);
777 // mark the resolved references
780 // now do something EXTREMELY SLOW AND INEFFICIENT :)
781 while ((unresolved=relocate())) {
782 if (!scanLibraries(unresolved)) {
783 struct REFERENCE *reference;
785 for (reference=references; reference; reference=reference->next) {
786 if (!reference->resolved) {
787 fprintf (stderr, "*** unresolved symbol %s in %s:%d\n",
788 reference->name, reference->module->name,
798 writeModule(outFileName);
803 fprintf (mapOut, "Modules:\n");
804 for (module=modules; module; module=module->next) {
805 fprintf (mapOut, "\t%s\n", module->name);
806 for (s=0; s<MAX_SEGMENTS; s++) {
807 if (module->size[s]) {
808 fprintf (mapOut, "\t\t%s:0x%04x-0x%04x\n", segments[s].name,
809 module->offset[s]+segments[s].start,
810 module->offset[s]+segments[s].start+module->size[s]);
816 fprintf (mapOut, "\nSegments:\n");
817 for (s=1; s<MAX_SEGMENTS; s++) {
818 if (segments[s]._size) {
819 fprintf (mapOut, "\t%s start 0x%04x size 0x%04x %d symbols\n",
820 segments[s].name, segments[s].start,
822 segments[s].hasSymbols);
827 fprintf (mapOut, "\nSymbols:\n");
828 for (symbol=symbols; symbol; symbol=symbol->next) {
829 fprintf (mapOut, "%s\t%s %s0x%04x %s\n", symbol->name,
830 symbol->segment->name,
831 symbol->absolute ? "= " : "",
832 symbol->address, symbol->module->name);
836 return fatalErrors? 1 : 0;