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, // do we need this?
55 // these are only for storage
89 #define CODESIZE 0x10000
93 char gsinitImage[CODESIZE];
94 char csegImage[CODESIZE];
95 char xinitImage[CODESIZE];
96 //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, NULL},
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 void addToModules (char *name, int isLib) {
196 struct MODULE *module;
199 module=calloc(1, sizeof(struct MODULE));
200 module->name=strdup(name);
201 for (s=0; s<MAX_SEGMENTS; s++) {
202 module->offset[s]=segments[s].current;
208 modules->last->next=module;
210 currentModule=modules->last=module;
213 void addToRefs(char *ref, int address, char *how, int pc) {
214 struct REFERENCE *reference;
216 reference=calloc(1, sizeof(struct REFERENCE));
217 reference->name=strdup(ref);
218 reference->module=currentModule;
219 reference->lineno=currentLine;
220 reference->address=address;
221 reference->how=howToReference(how);
224 references=reference;
226 references->last->next=reference;
228 references->last=reference;
232 struct REFERENCE *reference;
233 for (reference=references; reference; reference=reference->next) {
234 if (findSymbolByName(reference->name)) {
235 reference->resolved=1;
240 int isUnresolved(char *ref, int resolved) {
241 struct REFERENCE *reference;
243 for (reference=references; reference; reference=reference->next) {
244 if (strcmp(reference->name, ref)==0) {
246 if (reference->resolved) {
251 reference->resolved=1;
259 void addToDefs(char *def, int address, char absolute) {
260 struct SYMBOL *symbol;
262 // no duplicates allowed
263 if ((symbol=findSymbolByName(def))) {
264 fprintf (stderr, "*** %s:%d duplicate symbol %s first defined in "
266 currentModule->name, currentLine, def,
267 symbol->module->name, symbol->lineno);
271 symbol=calloc(1, sizeof(struct SYMBOL));
272 symbol->name=strdup(def);
273 symbol->module=currentModule;
274 symbol->lineno=currentLine;
275 symbol->segment=currentSegment;
276 symbol->absolute=absolute;
277 symbol->address=currentModule->offset[currentSegment->id]+address;
281 symbols->last->next=symbol;
283 symbols->last=symbol;
284 currentSegment->hasSymbols++;
287 void syntaxError (char *err) {
288 fprintf (stderr, "*** %s:%d error while parsing '%s'\n",
289 currentModule->name, currentLine, err);
293 void readModule(char *module, int isLib) {
297 char moduleName[PATH_MAX];
298 int segments, globals;
302 if ((relModule=fopen(module, "r"))==NULL) {
307 // first we need to check if this is a valid file
308 if (sscanf(fgets(line, 132, relModule),
309 "SDCCXA rel, version %lf", &hisVersion)!=1) {
310 fprintf (stderr, "*** %s is not a valid input file\n", module);
313 if (hisVersion!=version) {
314 fprintf (stderr, "*** WARNING: version conflict; "
315 "we(%1.1f) != %s(%1.1f)\n",
316 version, module, hisVersion);
320 // H 7 areas 168 global symbols
321 if (sscanf(fgets(line, 132, relModule),
322 "H %d areas %d global symbols",
323 &segments, &globals)!=2) {
329 if (sscanf(fgets(line, 132, relModule),
330 "M %s", moduleName)!=1) {
334 // add this to the known modules with current offsets
335 addToModules(module, isLib);
339 // now for the ASTR tags
340 while (fgets(line, 132, relModule)) {
346 if (sscanf(line, "A %[^ ] size %d flags %d",
347 segment, &size, &flags)!=3) {
350 // do we know this segment?
351 if (!(currentSegment=findSegmentByName(segment))) {
352 fprintf (stderr, "*** %s:%d unknown area: %s\n", module,
353 currentLine, segment);
356 // double check repeated 'A' records
357 if (currentModule->size[currentSegment->id]) {
358 if (currentModule->size[currentSegment->id] != size) {
359 fprintf (stderr, "*** %s:%d error %s size %d != %d\n",
361 currentSegment->name,
362 currentModule->size[currentSegment->id],
366 // pleased to meet you again
369 currentModule->size[currentSegment->id]=size;
370 currentModule->offset[currentSegment->id]+=currentSegment->_size;
371 currentSegment->_size += size;
373 // never mind about the flags for now
379 unsigned int address;
380 if (sscanf(line, "S %[^ ] %s", symbol, refdef)!=2) {
381 fprintf (stderr, "*** %s:%d syntax error near \"%s\"\n",
382 module, currentLine, line);
385 if (strncmp(refdef, "Ref", 3)==0) {
386 // we don't need them
387 } else if (strncmp(refdef, "Def", 3)==0) {
388 sscanf (refdef, "Def%04x", &address);
389 addToDefs(symbol, address, 0);
390 } else if (strncmp(refdef, "Abs", 3)==0) {
391 sscanf (refdef, "Abs%04x", &address);
392 addToDefs(symbol, address, 1);
394 fprintf (stderr, "%s:%d found invalid symbol definition \"%s\"\n",
395 module, currentLine, line);
401 unsigned int address;
404 if (currentSegment->id!=CSEG &&
405 currentSegment->id!=GSINIT &&
406 //currentSegment->id!=GSFINAL &&
407 currentSegment->id!=XINIT) {
408 fprintf (stderr, "%s:%d cannot emit bytes in %s\n",
409 module, currentLine, currentSegment->name);
412 if (sscanf(strtok(&line[2], " "), "%04x", &address)!=1) {
413 fprintf (stderr, "%s:%d error in T record\n", module, currentLine);
416 address+=currentSegment->current;
418 (tline=strtok(NULL, " \t\n")) &&
419 (sscanf(tline, "%02x", &byte)==1);
421 currentSegment->image[address++]=byte;
422 currentSegment->current++;
427 unsigned address, from;
430 sscanf (line, "R %x %[^ ] %[^ ] %x", &address, how, symbol, &from);
431 addToRefs (symbol, address, how, from);
435 fprintf (stderr, "%s:%d unknown record \"%s\"\n",
436 module, currentLine, line);
442 // that's all for now, thanks for watching */
446 void writeModule(char *outFileName) {
449 if ((fOut=fopen(outFileName, "w"))==NULL) {
450 perror (outFileName);
452 // oops, forgot something :) */
457 struct SYMBOL *symbol;
458 struct REFERENCE *reference;
460 int length=segments[GSINIT].current +
461 segments[CSEG].current +
462 segments[XINIT].current;
465 // first check if it will fit
466 if (length > 0xffff) {
467 fprintf (stderr, "error: code segment exceeds 0xffff\n");
471 // resolve reverences
472 for (reference=references; reference; reference=reference->next) {
473 if (!reference->resolved && !findSymbolByName(reference->name)) {
478 // first scan the libraries
482 // GSINIT gets the --code-loc
483 segments[GSINIT].start=segments[CSEG].start;
484 segments[CSEG].start=segments[GSINIT].start+segments[GSINIT]._size;
485 // concat cseg and gsinit
487 to=&gsinitImage[segments[GSINIT].start+segments[GSINIT]._size];
488 memcpy(to, from, segments[CSEG]._size);
489 segments[XINIT].start=segments[CSEG].start+segments[CSEG]._size;
491 to+=segments[CSEG]._size;
492 memcpy(to, from, segments[XINIT]._size);
495 to+=segments[XINIT]._size;
496 memcpy(to, from, segments[GSFINAL]._size);
498 segments[XISEG].start=segments[XSEG].start+segments[XINIT]._size;
499 // now relocate the defined symbols
500 for (symbol=symbols; symbol; symbol=symbol->next) {
501 if (!symbol->absolute) {
502 symbol->address += symbol->segment->start;
505 // and the references
506 for (reference=references; reference; reference=reference->next) {
507 if (!(symbol=findSymbolByName(reference->name))) {
508 // this reference isn't defined after all
509 fprintf (stderr, "*** %s:%d undefined symbol %s\n",
510 reference->module->name, reference->lineno,
514 reference->address += symbol->segment->start;
515 switch (reference->how)
518 int rel16 = symbol->address-reference->pc;
519 if (rel16<-65536 || rel16>65534) {
521 "rel16 target for %s is out of range in module %s\n",
522 reference->name, reference->module->name);
525 gsinitImage[reference->address+1]=(rel16/2)>>8;
526 gsinitImage[reference->address]=rel16/2;
530 int rel8 = symbol->address-reference->pc;
531 if (rel8<-256 || rel8>256) {
533 "rel8 target for %s is out of range in module %s\n",
534 reference->name, reference->module->name);
537 gsinitImage[reference->address]=rel8/2;
541 gsinitImage[reference->address+1] = symbol->address>>8;
544 gsinitImage[reference->address] = symbol->address;
547 fprintf (stderr, "unsupported reference mode %d.\n",
556 void usage (char * progName, int errNo) {
557 fprintf (stderr, "usage: %s lnkCmdFile\n", progName);
563 int scanLibraries(int unresolved) {
566 char libFiles[PATH_MAX];
567 char libFile[PATH_MAX];
572 for (nlp=0; nlp<nlibPaths; nlp++) {
573 for (nlf=0; nlf<nlibFiles; nlf++) {
574 sprintf (libFiles, "%s/%s.lib", libraryPaths[nlp], libraryFiles[nlf]);
575 //fprintf (stderr, " %s\n", libFiles);
576 if ((lfs=fopen(libFiles,"r"))==NULL) {
579 while (fgets(line, 132, lfs)) {
580 // remove trailing \n
581 line[strlen(line)-1]='\0';
582 sprintf (libFile, "%s/%s", libraryPaths[nlp], line);
583 //fprintf (stderr, " %s\n", libFile);
584 if ((lf=fopen(libFile,"r"))==0) {
587 while (fgets(line, 132, lf)) {
588 if (sscanf(line, "S %[^ ] Def", symName)==1) {
589 if (isUnresolved(symName, 1)) {
590 fprintf (stderr, "%s:%s\n", libFile, symName);
591 readModule(libFile,1);
592 if (resolved++ == unresolved) {
605 int main(int argc, char **argv) {
606 FILE *linkCommandsFile;
607 char linkCommandsPath[PATH_MAX];
608 char linkCommand[PATH_MAX];
609 struct MODULE *module;
610 struct SYMBOL *symbol;
618 // read in the commands
619 sprintf (linkCommandsPath, "%s.lnk", argv[1]);
620 if (!(linkCommandsFile=fopen(linkCommandsPath, "r"))) {
621 perror(linkCommandsPath);
624 while (fgets(linkCommand, PATH_MAX, linkCommandsFile)) {
625 linkCommand[strlen(linkCommand)-1]='\0';
632 //puts (linkCommand);
633 if (*linkCommand=='-') {
634 switch (linkCommand[1])
637 // probably -muxi, ignore for now
640 // -e, always in the last line, ignore for now
644 // a segment start address like: "-b XSEG = 0x4000"
646 char *seg=strtok(&linkCommand[3], " \t");
647 for (s=0; s<MAX_SEGMENTS; s++) {
648 if (strcmp(segments[s].name, seg)==0) {
649 strtok(NULL, " \t"); // skip the '='
650 if (sscanf(strtok(NULL, " \t"), "%x",
651 &segments[s].start)!=1) {
652 syntaxError(linkCommand);
657 if (s==MAX_SEGMENTS) {
658 syntaxError(linkCommand);
663 // a lib path like: "-k /usr/local/share/sdcc/lib/xa51"; one/line
664 libraryPaths[nlibPaths++]=strdup(&linkCommand[3]);
667 // a lib file like: "-l libsdcc"; one/line
668 libraryFiles[nlibFiles++]=strdup(&linkCommand[3]);
671 syntaxError(linkCommand);
674 // not a switch, must be an inputfile; one/line
675 readModule(linkCommand, 0);
676 // the first one defines the output name
677 if (!outFileName[0]) {
678 strncpy(outFileName, linkCommand,
679 strlen(linkCommand)-4);
680 sprintf(mapFileName, "%s.map", outFileName);
681 strcat(outFileName, ".hex");
682 if ((mapOut=fopen(mapFileName, "w"))==NULL) {
689 // add the segment symbols
690 currentSegment=findSegmentByName("XINIT");
691 addToDefs("s_XINIT", segments[XINIT].start, 0);
692 addToDefs("l_XINIT", segments[XINIT]._size, 0);
693 currentSegment=findSegmentByName("XISEG");
694 addToDefs("s_XISEG", segments[XISEG].start, 0);
695 addToDefs("l_XISEG", segments[XISEG]._size, 0);
697 // mark the resolved references
700 // now do something :) EXTREMELY SLOW AND INEFFICIENT
701 while ((unresolved=relocate())) {
702 if (!scanLibraries(unresolved)) {
703 struct REFERENCE *reference;
704 for (reference=references; reference; reference=reference->next) {
705 if (!reference->resolved) {
706 fprintf (stderr, "*** unresolved symbol %s in %s:%d\n",
707 reference->name, reference->module->name,
717 writeModule(outFileName);
721 fprintf (mapOut, "Modules:\n");
722 for (module=modules; module; module=module->next) {
723 fprintf (mapOut, "\t%s\n", module->name);
724 for (s=0; s<MAX_SEGMENTS; s++) {
725 if (module->size[s]) {
726 fprintf (mapOut, "\t\t%s:0x%04x-0x%04x\n", segments[s].name,
727 module->offset[s], module->offset[s]+module->size[s]);
733 fprintf (mapOut, "\nSegments:\n");
734 for (s=1; s<MAX_SEGMENTS; s++) {
735 if (segments[s]._size) {
736 fprintf (mapOut, "\t%s start 0x%04x size 0x%04x %d symbols\n",
737 segments[s].name, segments[s].start,
739 segments[s].hasSymbols);
744 fprintf (mapOut, "\nSymbols:\n");
745 for (symbol=symbols; symbol; symbol=symbol->next) {
746 fprintf (mapOut, "%s\t%s %s0x%04x %s\n", symbol->name,
747 symbol->segment->name,
748 symbol->absolute ? "= " : "",
749 symbol->address, symbol->module->name);
752 writeModule(outFileName);
754 return fatalErrors? 1 : 0;