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+1)&0xfffffe;
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 if ((fOut=fopen(outFileName, "w"))==NULL) {
470 perror (outFileName);
474 len = size>16 ? 16 : size;
476 fprintf (fOut, ":%02X%04X%02X", len, address, 0);
477 checksum = len + (address>>8) + (address&0xff);
479 checksum += gsfinalImage[address];
480 fprintf (fOut, "%02X", gsfinalImage[address++]);
484 checksum = 0x100 - checksum;
486 fprintf (fOut, "%02X\n", checksum);
488 fprintf (fOut, ":00000001FF\n");
494 struct SYMBOL *symbol;
495 struct REFERENCE *reference;
497 int length=segments[GSINIT]._size +
498 segments[CSEG]._size +
499 segments[XINIT]._size;
502 // first check if it will fit
503 if (length > 0xffff) {
504 fprintf (stderr, "error: code segment exceeds 0xffff\n");
508 // resolve reverences
509 for (reference=references; reference; reference=reference->next) {
510 if (!reference->resolved && !findSymbolByName(reference->name)) {
515 // first scan the libraries
519 // GSFINAL starts at --code-loc ( -b CSEG = 0x1234 )
520 if (segments[CSEG].start & 1) {
521 fprintf (stderr, "*** error: code doesn't start at "
522 "an even address: %04x\n", segments[CSEG].start);
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;
534 if (segments[GSFINAL]._size & 1) {
535 segments[GSFINAL]._size++;
538 // append cseg to gsfinal
540 to = gsfinalImage + segments[GSFINAL].start + segments[GSFINAL]._size;
541 memcpy(to, from, segments[CSEG]._size);
542 segments[CSEG].start=segments[GSFINAL].start+segments[GSFINAL]._size;
543 segments[GSFINAL]._size += segments[CSEG]._size;
544 if (segments[GSFINAL]._size & 1) {
545 segments[GSFINAL]._size++;
548 // append xinit to gsfinal
550 to = gsfinalImage + segments[GSFINAL].start + segments[GSFINAL]._size;
551 memcpy(to, from, segments[XINIT]._size);
552 segments[XINIT].start=segments[GSFINAL].start+segments[GSFINAL]._size;
553 segments[GSFINAL]._size += segments[XINIT]._size;
554 if (segments[GSFINAL]._size & 1) {
555 segments[GSFINAL]._size++;
558 // XISEG is located after XSEG
559 if (segments[XSEG].start & 1) {
560 fprintf (stderr, "*** warning: xdata doesn't start at "
561 "an even address: %04x\n", segments[XSEG].start);
563 if (segments[XSEG]._size & 1) {
564 segments[XSEG]._size++;
567 segments[XISEG].start=segments[XSEG].start +
568 segments[XSEG]._size;
570 // now relocate the defined symbols
571 for (symbol=symbols; symbol; symbol=symbol->next) {
572 if (!symbol->absolute) {
573 symbol->address += symbol->segment->start;
576 // and the references
577 for (reference=references; reference; reference=reference->next) {
578 symbol=findSymbolByName(reference->name);
579 if (!reference->resolved && !symbol && reference->how!=ABS_PC) {
580 // this reference isn't resolved after all
581 fprintf (stderr, "*** %s:%d undefined symbol %s\n",
582 reference->module->name, reference->lineno,
586 reference->address +=
587 reference->module->offset[reference->segment->id]+
588 reference->segment->start;
590 reference->module->offset[reference->segment->id]+
591 reference->segment->start;
592 switch (reference->how)
595 int rel8 = symbol->address-(reference->pc & ~1);
596 if (rel8<-256 || rel8>256) {
598 "rel8 target for %s is out of range in module %s\n",
599 reference->name, reference->module->name);
602 gsfinalImage[reference->address]=rel8/2;
606 int rel16 = symbol->address-(reference->pc & ~1);
607 if (rel16<-65536 || rel16>65534) {
609 "rel16 target for %s is out of range in module %s\n",
610 reference->name, reference->module->name);
613 gsfinalImage[reference->address]=(rel16/2)>>8;
614 gsfinalImage[reference->address+1]=rel16/2;
618 gsfinalImage[reference->address] =
619 (gsfinalImage[reference->address]&~0x70) +
620 ((symbol->address>>4)&0x70);
621 gsfinalImage[reference->address+1] = symbol->address;
624 gsfinalImage[reference->address] = symbol->address>>8;
625 gsfinalImage[reference->address+1] = symbol->address;
628 gsfinalImage[reference->address] = symbol->address;
632 unsigned int address=
633 (gsfinalImage[reference->address]<<8) +
634 gsfinalImage[reference->address+1];
635 address += reference->module->offset[reference->segment->id];
636 address += segments[reference->segment->id].start;
637 gsfinalImage[reference->address] = address>>8;
638 gsfinalImage[reference->address+1] = address;
642 fprintf (stderr, "unsupported reference mode %d.\n",
651 void usage (char * progName, int errNo) {
652 fprintf (stderr, "usage: %s lnkCmdFile\n", progName);
658 int scanLibraries(int unresolved) {
661 char libFiles[PATH_MAX];
662 char libFile[PATH_MAX];
667 for (nlp=0; nlp<nlibPaths; nlp++) {
668 for (nlf=0; nlf<nlibFiles; nlf++) {
669 sprintf (libFiles, "%s/%s.lib", libraryPaths[nlp], libraryFiles[nlf]);
670 //fprintf (stderr, " %s\n", libFiles);
671 if ((lfs=fopen(libFiles,"r"))==NULL) {
674 while (fgets(line, 132, lfs)) {
675 // remove trailing \n
676 line[strlen(line)-1]='\0';
677 sprintf (libFile, "%s/%s", libraryPaths[nlp], line);
678 //fprintf (stderr, " %s\n", libFile);
679 if ((lf=fopen(libFile,"r"))==0) {
682 while (fgets(line, 132, lf)) {
683 int dummy; // we need this to get the right count of the next sscanf
684 if (sscanf(line, "S %[^ ] Def%04x", symName, &dummy)==2) {
685 if (isUnresolved(symName, 1)) {
686 //fprintf (stderr, "%s:%s\n", libFile, symName);
687 readModule(libFile,1);
688 if (resolved++ == unresolved) {
692 // skip to next lib module
703 int main(int argc, char **argv) {
704 FILE *linkCommandsFile;
705 char linkCommandsPath[PATH_MAX];
706 char linkCommand[PATH_MAX];
707 struct MODULE *module;
708 struct SYMBOL *symbol;
716 // read in the commands
717 sprintf (linkCommandsPath, "%s.lnk", argv[1]);
718 if (!(linkCommandsFile=fopen(linkCommandsPath, "r"))) {
719 perror(linkCommandsPath);
722 while (fgets(linkCommand, PATH_MAX, linkCommandsFile)) {
723 linkCommand[strlen(linkCommand)-1]='\0';
730 //puts (linkCommand);
731 if (*linkCommand=='-') {
732 switch (linkCommand[1])
735 // probably -muxi, ignore for now
738 // -e, always in the last line, ignore for now
742 // a segment start address like: "-b XSEG = 0x4000"
744 char *seg=strtok(&linkCommand[3], " \t");
745 for (s=0; s<MAX_SEGMENTS; s++) {
746 if (strcmp(segments[s].name, seg)==0) {
747 strtok(NULL, " \t"); // skip the '='
748 if (sscanf(strtok(NULL, " \t"), "%x",
749 &segments[s].start)!=1) {
750 syntaxError(linkCommand);
755 if (s==MAX_SEGMENTS) {
756 syntaxError(linkCommand);
761 // a lib path like: "-k /usr/local/share/sdcc/lib/xa51"; one/line
762 libraryPaths[nlibPaths++]=strdup(&linkCommand[3]);
765 // a lib file like: "-l libsdcc"; one/line
766 libraryFiles[nlibFiles++]=strdup(&linkCommand[3]);
769 syntaxError(linkCommand);
772 // not a switch, must be an inputfile; one/line
773 readModule(linkCommand, 0);
774 // the first one defines the output name
775 if (!outFileName[0]) {
776 strncpy(outFileName, linkCommand,
777 strlen(linkCommand)-4);
778 sprintf(mapFileName, "%s.map", outFileName);
779 strcat(outFileName, ".hex");
780 if ((mapOut=fopen(mapFileName, "w"))==NULL) {
787 // add the segment symbols
788 currentSegment=findSegmentByName("XINIT");
789 addToDefs("s_XINIT", 0, 0);
790 addToDefs("l_XINIT", segments[XINIT]._size, 1);
791 currentSegment=findSegmentByName("XISEG");
792 addToDefs("s_XISEG", 0, 0);
793 addToDefs("l_XISEG", segments[XISEG]._size, 1);
796 // mark the resolved references
799 // now do something EXTREMELY SLOW AND INEFFICIENT :)
800 while ((unresolved=relocate())) {
801 if (!scanLibraries(unresolved)) {
802 struct REFERENCE *reference;
804 for (reference=references; reference; reference=reference->next) {
805 if (!reference->resolved) {
806 fprintf (stderr, "*** unresolved symbol %s in %s:%d\n",
807 reference->name, reference->module->name,
817 writeModule(outFileName);
822 fprintf (mapOut, "Modules:\n");
823 for (module=modules; module; module=module->next) {
824 fprintf (mapOut, "\t%s\n", module->name);
825 for (s=0; s<MAX_SEGMENTS; s++) {
826 if (module->size[s]) {
827 fprintf (mapOut, "\t\t%s:0x%04x-0x%04x\n", segments[s].name,
828 module->offset[s]+segments[s].start,
829 module->offset[s]+segments[s].start+module->size[s]);
835 fprintf (mapOut, "\nSegments:\n");
836 for (s=1; s<MAX_SEGMENTS; s++) {
837 if (segments[s]._size) {
838 fprintf (mapOut, "\t%s start 0x%04x size 0x%04x %d symbols\n",
839 segments[s].name, segments[s].start,
841 segments[s].hasSymbols);
846 fprintf (mapOut, "\nSymbols:\n");
847 for (symbol=symbols; symbol; symbol=symbol->next) {
848 fprintf (mapOut, "%s\t%s %s0x%04x %s\n", symbol->name,
849 symbol->segment->name,
850 symbol->absolute ? "= " : "",
851 symbol->address, symbol->module->name);
855 return fatalErrors? 1 : 0;