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_F0FF. 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
89 #define CODESIZE 0x10000
93 unsigned char gsinitImage[CODESIZE];
94 unsigned char csegImage[CODESIZE];
95 unsigned char xinitImage[CODESIZE];
96 unsigned char gsfinalImage[CODESIZE];
105 unsigned char *image;
106 } segments[MAX_SEGMENTS]={
107 {0, "???", 0, 0, 0, 0, NULL},
109 {GSINIT, "GSINIT", 0, 0, 0, 0, gsinitImage},
110 {CSEG, "CSEG", 0, 0, 0, 0, csegImage},
111 {XINIT, "XINIT", 0, 0, 0, 0, xinitImage},
112 {GSFINAL, "GSFINAL", 0, 0, 0, 0, gsfinalImage},
114 {BSEG, "BSEG", 0, 0, 0, 0, NULL},
115 {DSEG, "DSEG", 0, 0, 0, 0, NULL},
116 {XSEG, "XSEG", 0, 0, 0, 0, NULL},
117 {XISEG, "XISEG", 0, 0, 0, 0, NULL},
122 int offset[MAX_SEGMENTS];
123 int size[MAX_SEGMENTS];
132 struct MODULE *module;
134 struct SEGMENT *segment;
143 struct MODULE *module;
145 unsigned address, pc;
148 struct REFERENCE *next;
149 struct REFERENCE *last;
152 char *libraryPaths[128];
154 char *libraryFiles[128];
157 static char outFileName[PATH_MAX]={'\0'};
158 static char mapFileName[PATH_MAX]={'\0'};
161 struct SEGMENT *currentSegment;
162 struct MODULE *currentModule;
165 int howToReference(char *how) {
167 for (r=1; r<MAX_REFS; r++) {
168 if (strcmp(refModes[r], how)==0) {
175 struct SEGMENT *findSegmentByName(char *segment) {
177 for (s=0; s<MAX_SEGMENTS; s++) {
178 if (strcmp(segments[s].name, segment)==0) {
185 struct SYMBOL *findSymbolByName(char *symName) {
186 struct SYMBOL *symbol;
187 for (symbol=symbols; symbol; symbol=symbol->next) {
188 if (strcmp(symbol->name, symName)==0) {
195 struct MODULE *findModuleByName(char *modName) {
196 struct MODULE *module;
197 for (module=modules; module; module=module->next) {
198 if (strcmp(module->name, modName)==0) {
205 void addToModules (char *name, int isLib) {
206 struct MODULE *module;
209 module=calloc(1, sizeof(struct MODULE));
210 module->name=strdup(name);
211 for (s=0; s<MAX_SEGMENTS; s++) {
212 module->offset[s]=segments[s]._size;
218 modules->last->next=module;
220 currentModule=modules->last=module;
223 void addToRefs(char *ref, int address, char *how, int pc) {
224 struct REFERENCE *reference;
226 reference=calloc(1, sizeof(struct REFERENCE));
227 reference->name=strdup(ref);
228 reference->module=currentModule;
229 reference->lineno=currentLine;
230 reference->address=address;
231 reference->how=howToReference(how);
234 references=reference;
236 references->last->next=reference;
238 references->last=reference;
242 struct REFERENCE *reference;
243 for (reference=references; reference; reference=reference->next) {
244 if (findSymbolByName(reference->name)) {
245 reference->resolved=1;
250 int isUnresolved(char *ref, int resolved) {
251 struct REFERENCE *reference;
253 for (reference=references; reference; reference=reference->next) {
254 if (strcmp(reference->name, ref)==0) {
256 if (reference->resolved) {
261 reference->resolved=1;
269 void addToDefs(char *def, int address, char absolute) {
270 struct SYMBOL *symbol;
272 // no duplicates allowed
273 if ((symbol=findSymbolByName(def))) {
274 fprintf (stderr, "*** %s:%d duplicate symbol %s first defined in "
276 currentModule->name, currentLine, def,
277 symbol->module->name, symbol->lineno);
281 symbol=calloc(1, sizeof(struct SYMBOL));
282 symbol->name=strdup(def);
283 symbol->module=currentModule;
284 symbol->lineno=currentLine;
285 symbol->segment=currentSegment;
286 symbol->absolute=absolute;
287 symbol->address=currentModule->offset[currentSegment->id]+address;
291 symbols->last->next=symbol;
293 symbols->last=symbol;
294 currentSegment->hasSymbols++;
297 void syntaxError (char *err) {
298 fprintf (stderr, "*** %s:%d error while parsing '%s'\n",
299 currentModule->name, currentLine, err);
303 void readModule(char *module, int isLib) {
307 char moduleName[PATH_MAX];
308 int segments, globals;
312 if ((relModule=fopen(module, "r"))==NULL) {
317 // first we need to check if this is a valid file
318 if (sscanf(fgets(line, 132, relModule),
319 "SDCCXA rel, version %lf", &hisVersion)!=1) {
320 fprintf (stderr, "*** %s is not a valid input file\n", module);
323 if (hisVersion!=version) {
324 fprintf (stderr, "*** WARNING: version conflict; "
325 "we(%1.1f) != %s(%1.1f)\n",
326 version, module, hisVersion);
330 // H 7 areas 168 global symbols
331 if (sscanf(fgets(line, 132, relModule),
332 "H %d areas %d global symbols",
333 &segments, &globals)!=2) {
339 if (sscanf(fgets(line, 132, relModule),
340 "M %s", moduleName)!=1) {
344 // add this to the known modules with current offsets
345 addToModules(module, isLib);
349 // now for the ASTR tags
350 while (fgets(line, 132, relModule)) {
356 if (sscanf(line, "A %[^ ] size %d flags %d",
357 segment, &size, &flags)!=3) {
360 // do we know this segment?
361 if (!(currentSegment=findSegmentByName(segment))) {
362 fprintf (stderr, "*** %s:%d unknown area: %s\n", module,
363 currentLine, segment);
366 // double check repeated 'A' records
367 if (currentModule->size[currentSegment->id]) {
368 // pleased to meet you again, I hope ...
369 if (currentModule->size[currentSegment->id] != size) {
370 fprintf (stderr, "*** %s:%d error %s size %d != %d\n",
372 currentSegment->name,
373 currentModule->size[currentSegment->id],
378 currentSegment->_size += size;
379 currentModule->size[currentSegment->id] = size;
381 // never mind about the flags for now
387 unsigned int address;
388 if (sscanf(line, "S %[^ ] %s", symbol, refdef)!=2) {
389 fprintf (stderr, "*** %s:%d syntax error near \"%s\"\n",
390 module, currentLine, line);
393 if (strncmp(refdef, "Ref", 3)==0) {
394 // we don't need them
395 } else if (strncmp(refdef, "Def", 3)==0) {
396 sscanf (refdef, "Def%04x", &address);
397 addToDefs(symbol, address, 0);
398 } else if (strncmp(refdef, "Abs", 3)==0) {
399 sscanf (refdef, "Abs%04x", &address);
400 addToDefs(symbol, address, 1);
402 fprintf (stderr, "%s:%d found invalid symbol definition \"%s\"\n",
403 module, currentLine, line);
409 unsigned int address;
412 if (currentSegment->id!=CSEG &&
413 currentSegment->id!=GSINIT &&
414 currentSegment->id!=XINIT) {
415 fprintf (stderr, "%s:%d cannot emit bytes in %s\n",
416 module, currentLine, currentSegment->name);
419 if (sscanf(strtok(&line[2], " "), "%04x", &address)!=1) {
420 fprintf (stderr, "%s:%d error in T record\n", module, currentLine);
424 address+=currentModule->offset[currentSegment->id];
425 //address+=currentSegment->current;
427 (tline=strtok(NULL, " \t\n")) &&
428 (sscanf(tline, "%02x", &byte)==1);
430 currentSegment->image[address++]=byte;
431 currentSegment->current++;
436 unsigned address, pc;
439 sscanf (line, "R %x %[^ ] %[^ ] %x", &address, how, symbol, &pc);
440 addToRefs (symbol, address, how, pc);
444 fprintf (stderr, "%s:%d unknown record \"%s\"\n",
445 module, currentLine, line);
451 // that's all for now, thanks for watching */
455 void writeModule(char *outFileName) {
457 unsigned int address=segments[GSFINAL].start;
458 unsigned int size=segments[GSFINAL]._size;
460 unsigned int checksum;
462 fprintf (stderr, "writeModule: %s from 0x%04x to 0x%04x\n",
467 if ((fOut=fopen(outFileName, "w"))==NULL) {
468 perror (outFileName);
470 fprintf (fOut, "Just for now, make it a little bit more readable\n");
473 len = size>16 ? 16 : size;
475 fprintf (fOut, ":%02X.%04X.%02X >", len, address, 0);
476 checksum = len + (address>>8) + (address&0xff);
478 checksum += gsfinalImage[address];
479 fprintf (fOut, " %02X", gsfinalImage[address++]);
483 checksum = 0x100 - checksum;
485 fprintf (fOut, " < %02X\n", checksum);
487 fprintf (fOut, ":00000001FF\n");
493 struct SYMBOL *symbol;
494 struct REFERENCE *reference;
496 int length=segments[GSINIT]._size +
497 segments[CSEG]._size +
498 segments[XINIT]._size;
501 // first check if it will fit
502 if (length > 0xffff) {
503 fprintf (stderr, "error: code segment exceeds 0xffff\n");
507 // resolve reverences
508 for (reference=references; reference; reference=reference->next) {
509 if (!reference->resolved && !findSymbolByName(reference->name)) {
514 // first scan the libraries
518 // GSFINAL starts at --code-loc ( -b CSEG = 0x1234 )
519 segments[GSFINAL].start=segments[CSEG].start;
520 memset(gsfinalImage, 0xff, CODESIZE);
522 // copy gsinit to gsfinal
524 to = gsfinalImage + segments[GSFINAL].start + segments[GSFINAL]._size;
525 memcpy(to, from, segments[GSINIT]._size);
526 segments[GSINIT].start=segments[GSFINAL].start;
527 segments[GSFINAL]._size += segments[GSINIT]._size;
529 // append cseg to gsfinal
531 to = gsfinalImage + segments[GSFINAL].start + segments[GSFINAL]._size;
532 memcpy(to, from, segments[CSEG]._size);
533 segments[CSEG].start=segments[GSFINAL].start+segments[GSFINAL]._size;
534 segments[GSFINAL]._size += segments[CSEG]._size;
536 // append xinit to gsfinal
538 to = gsfinalImage + segments[GSFINAL].start + segments[GSFINAL]._size;
539 memcpy(to, from, segments[XINIT]._size);
540 segments[XINIT].start=segments[GSFINAL].start+segments[GSFINAL]._size;
541 segments[GSFINAL]._size += segments[XINIT]._size;
543 // XISEG is located after XSEG
544 segments[XISEG].start=segments[XSEG].start +
545 segments[XSEG]._size;
547 // now relocate the defined symbols
548 for (symbol=symbols; symbol; symbol=symbol->next) {
549 if (!symbol->absolute) {
550 symbol->address += symbol->segment->start;
553 // and the references
554 for (reference=references; reference; reference=reference->next) {
555 if (!(symbol=findSymbolByName(reference->name))) {
556 // this reference isn't defined after all
557 fprintf (stderr, "*** %s:%d undefined symbol %s\n",
558 reference->module->name, reference->lineno,
562 reference->address += symbol->segment->start;
563 reference->pc += symbol->segment->start;
564 switch (reference->how)
567 int rel16 = symbol->address-reference->pc;
568 if (rel16<-65536 || rel16>65534) {
570 "rel16 target for %s is out of range in module %s\n",
571 reference->name, reference->module->name);
574 gsinitImage[reference->address+1]=(rel16/2)>>8;
575 gsinitImage[reference->address]=rel16/2;
579 int rel8 = symbol->address-reference->pc;
580 if (rel8<-256 || rel8>256) {
582 "rel8 target for %s is out of range in module %s\n",
583 reference->name, reference->module->name);
586 gsinitImage[reference->address]=rel8/2;
590 gsinitImage[reference->address+1] = symbol->address>>8;
593 gsinitImage[reference->address] = symbol->address;
596 fprintf (stderr, "unsupported reference mode %d.\n",
605 void usage (char * progName, int errNo) {
606 fprintf (stderr, "usage: %s lnkCmdFile\n", progName);
612 int scanLibraries(int unresolved) {
615 char libFiles[PATH_MAX];
616 char libFile[PATH_MAX];
621 for (nlp=0; nlp<nlibPaths; nlp++) {
622 for (nlf=0; nlf<nlibFiles; nlf++) {
623 sprintf (libFiles, "%s/%s.lib", libraryPaths[nlp], libraryFiles[nlf]);
624 //fprintf (stderr, " %s\n", libFiles);
625 if ((lfs=fopen(libFiles,"r"))==NULL) {
628 while (fgets(line, 132, lfs)) {
629 // remove trailing \n
630 line[strlen(line)-1]='\0';
631 sprintf (libFile, "%s/%s", libraryPaths[nlp], line);
632 //fprintf (stderr, " %s\n", libFile);
633 if ((lf=fopen(libFile,"r"))==0) {
636 while (fgets(line, 132, lf)) {
637 int dummy; // we need this to get the right count of the next sscanf
638 if (sscanf(line, "S %[^ ] Def%04x", symName, &dummy)==2) {
639 if (isUnresolved(symName, 1)) {
640 //fprintf (stderr, "%s:%s\n", libFile, symName);
641 readModule(libFile,1);
642 if (resolved++ == unresolved) {
646 // skip to next lib module
657 int main(int argc, char **argv) {
658 FILE *linkCommandsFile;
659 char linkCommandsPath[PATH_MAX];
660 char linkCommand[PATH_MAX];
661 struct MODULE *module;
662 struct SYMBOL *symbol;
670 // read in the commands
671 sprintf (linkCommandsPath, "%s.lnk", argv[1]);
672 if (!(linkCommandsFile=fopen(linkCommandsPath, "r"))) {
673 perror(linkCommandsPath);
676 while (fgets(linkCommand, PATH_MAX, linkCommandsFile)) {
677 linkCommand[strlen(linkCommand)-1]='\0';
684 //puts (linkCommand);
685 if (*linkCommand=='-') {
686 switch (linkCommand[1])
689 // probably -muxi, ignore for now
692 // -e, always in the last line, ignore for now
696 // a segment start address like: "-b XSEG = 0x4000"
698 char *seg=strtok(&linkCommand[3], " \t");
699 for (s=0; s<MAX_SEGMENTS; s++) {
700 if (strcmp(segments[s].name, seg)==0) {
701 strtok(NULL, " \t"); // skip the '='
702 if (sscanf(strtok(NULL, " \t"), "%x",
703 &segments[s].start)!=1) {
704 syntaxError(linkCommand);
709 if (s==MAX_SEGMENTS) {
710 syntaxError(linkCommand);
715 // a lib path like: "-k /usr/local/share/sdcc/lib/xa51"; one/line
716 libraryPaths[nlibPaths++]=strdup(&linkCommand[3]);
719 // a lib file like: "-l libsdcc"; one/line
720 libraryFiles[nlibFiles++]=strdup(&linkCommand[3]);
723 syntaxError(linkCommand);
726 // not a switch, must be an inputfile; one/line
727 readModule(linkCommand, 0);
728 // the first one defines the output name
729 if (!outFileName[0]) {
730 strncpy(outFileName, linkCommand,
731 strlen(linkCommand)-4);
732 sprintf(mapFileName, "%s.map", outFileName);
733 strcat(outFileName, ".hex");
734 if ((mapOut=fopen(mapFileName, "w"))==NULL) {
741 // add the segment symbols
742 currentSegment=findSegmentByName("XINIT");
743 addToDefs("s_XINIT", 0, 0);
744 addToDefs("l_XINIT", segments[XINIT]._size, 1);
745 currentSegment=findSegmentByName("XISEG");
746 addToDefs("s_XISEG", 0, 0);
747 addToDefs("l_XISEG", segments[XISEG]._size, 1);
750 // mark the resolved references
753 // now do something EXTREMELY SLOW AND INEFFICIENT :)
754 while ((unresolved=relocate())) {
755 if (!scanLibraries(unresolved)) {
756 struct REFERENCE *reference;
758 for (reference=references; reference; reference=reference->next) {
759 if (!reference->resolved) {
760 fprintf (stderr, "*** unresolved symbol %s in %s:%d\n",
761 reference->name, reference->module->name,
771 writeModule(outFileName);
776 fprintf (mapOut, "Modules:\n");
777 for (module=modules; module; module=module->next) {
778 fprintf (mapOut, "\t%s\n", module->name);
779 for (s=0; s<MAX_SEGMENTS; s++) {
780 if (module->size[s]) {
781 fprintf (mapOut, "\t\t%s:0x%04x-0x%04x\n", segments[s].name,
782 module->offset[s]+segments[s].start,
783 module->offset[s]+segments[s].start+module->size[s]);
789 fprintf (mapOut, "\nSegments:\n");
790 for (s=1; s<MAX_SEGMENTS; s++) {
791 if (segments[s]._size) {
792 fprintf (mapOut, "\t%s start 0x%04x size 0x%04x %d symbols\n",
793 segments[s].name, segments[s].start,
795 segments[s].hasSymbols);
800 fprintf (mapOut, "\nSymbols:\n");
801 for (symbol=symbols; symbol; symbol=symbol->next) {
802 fprintf (mapOut, "%s\t%s %s0x%04x %s\n", symbol->name,
803 symbol->segment->name,
804 symbol->absolute ? "= " : "",
805 symbol->address, symbol->module->name);
809 return fatalErrors? 1 : 0;