3 This program is free software; you can redistribute it and/or modify it
4 under the terms of the GNU General Public License as published by the
5 Free Software Foundation; either version 3, or (at your option) any
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>. */
16 /* WORK IN PROGRESS: do not watch this if you don't have the legal
17 age in your country to watch this.
20 /* This is a cheap hack. The xa51 has a couple of ways to scramble
21 relocation info into it's opcode that the standard linker can't
22 handle, not to mention word allignment.
26 The relocatable format looks like the known one, BUT ISN'T.
28 The only things that are handled now are:
30 "SDCCXA rel, version %f" must be the first line, sort of MAGIC word
31 "H %d areas %d global symbols" defines the # of areas and globals
32 "S <symbol> [Ref0000 | DefXXXX | AbsXXXX]" Def's are supposed to be
33 defined in their own area/segment
34 "A <seg> size %d flags %d" switch to another segment. this can happen
35 multiple times and should be equal. flags is ignored for now
36 "T xxxx <how> <symbol> 0"
37 "R xxxx <how> <symbol> <pc+>" the relocation info. xxxx is the address
38 within relative code space. How is something like REL_FF, REL_FFFF,
39 ABS_70FF. Symbol is the referenced symbol and pc+ is the program
40 counter that will be used to calculate the relative address (that is
41 the address of the following instruction).
43 So, this is not a standalone linker. It will only link files generated
44 by xa_rasm, which will only process files generated by the xa51 sdcc
53 #include "xa_version.h"
56 // these are all concatenated into the code image
61 // here goes the final output and should be used by the assembler
64 // these are only for storage
102 #define CODESIZE 0x10000
106 unsigned char gsinitImage
[CODESIZE
];
107 unsigned char csegImage
[CODESIZE
];
108 unsigned char xinitImage
[CODESIZE
];
109 unsigned char gsfinalImage
[CODESIZE
];
118 unsigned char *image
;
119 } segments
[MAX_SEGMENTS
]={
120 {0, "???", 0, 0, 0, 0, NULL
},
122 {GSINIT
, "GSINIT", 0, 0, 0, 0, gsinitImage
},
123 {CSEG
, "CSEG", 0, 0, 0, 0, csegImage
},
124 {XINIT
, "XINIT", 0, 0, 0, 0, xinitImage
},
125 {GSFINAL
, "GSFINAL", 0, 0, 0, 0, gsfinalImage
},
127 {BSEG
, "BSEG", 0, 0, 0, 0, NULL
},
128 {DSEG
, "DSEG", 0, 0, 0, 0, NULL
},
129 {XSEG
, "XSEG", 0, 0, 0, 0, NULL
},
130 {XISEG
, "XISEG", 0, 0, 0, 0, NULL
},
135 int offset
[MAX_SEGMENTS
];
136 int size
[MAX_SEGMENTS
];
145 struct MODULE
*module
;
147 struct SEGMENT
*segment
;
156 struct MODULE
*module
;
157 struct SEGMENT
*segment
;
159 unsigned address
, pc
;
162 struct REFERENCE
*next
;
163 struct REFERENCE
*last
;
166 char *libraryPaths
[128];
168 char *libraryFiles
[128];
171 static char outFileName
[PATH_MAX
]={'\0'};
172 static char mapFileName
[PATH_MAX
]={'\0'};
175 struct SEGMENT
*currentSegment
;
176 struct MODULE
*currentModule
;
179 int howToReference(char *how
) {
181 for (r
=1; r
<MAX_REFS
; r
++) {
182 if (strcmp(refModes
[r
], how
)==0) {
189 struct SEGMENT
*findSegmentByName(char *segment
) {
191 for (s
=0; s
<MAX_SEGMENTS
; s
++) {
192 if (strcmp(segments
[s
].name
, segment
)==0) {
199 struct SYMBOL
*findSymbolByName(char *symName
) {
200 struct SYMBOL
*symbol
;
201 for (symbol
=symbols
; symbol
; symbol
=symbol
->next
) {
202 if (strcmp(symbol
->name
, symName
)==0) {
209 struct MODULE
*findModuleByName(char *modName
) {
210 struct MODULE
*module
;
211 for (module
=modules
; module
; module
=module
->next
) {
212 if (strcmp(module
->name
, modName
)==0) {
219 void addToModules (char *name
, int isLib
) {
220 struct MODULE
*module
;
223 module
=calloc(1, sizeof(struct MODULE
));
224 module
->name
=strdup(name
);
225 for (s
=0; s
<MAX_SEGMENTS
; s
++) {
226 module
->offset
[s
]=(segments
[s
]._size
+1)&0xfffffe;
232 modules
->last
->next
=module
;
234 currentModule
=modules
->last
=module
;
237 void addToRefs(char *ref
, int address
, char *how
, int pc
) {
238 struct REFERENCE
*reference
;
240 reference
=calloc(1, sizeof(struct REFERENCE
));
241 reference
->name
=strdup(ref
);
242 reference
->module
=currentModule
;
243 reference
->segment
=currentSegment
;
244 reference
->lineno
=currentLine
;
245 reference
->address
=address
;
246 reference
->how
=howToReference(how
);
247 if (reference
->how
==ABS_PC
) {
248 reference
->resolved
=1;
252 references
=reference
;
254 references
->last
->next
=reference
;
256 references
->last
=reference
;
260 struct REFERENCE
*reference
;
261 for (reference
=references
; reference
; reference
=reference
->next
) {
262 if ((reference
->how
==ABS_PC
) || findSymbolByName(reference
->name
)) {
263 reference
->resolved
=1;
268 int isUnresolved(char *ref
, int resolved
) {
269 struct REFERENCE
*reference
;
271 for (reference
=references
; reference
; reference
=reference
->next
) {
272 if (strcmp(reference
->name
, ref
)==0) {
274 if (reference
->resolved
) {
279 reference
->resolved
=1;
287 void addToDefs(char *def
, int address
, char absolute
) {
288 struct SYMBOL
*symbol
;
290 // no duplicates allowed
291 if ((symbol
=findSymbolByName(def
))) {
292 fprintf (stderr
, "*** %s:%d duplicate symbol %s first defined in "
294 currentModule
->name
, currentLine
, def
,
295 symbol
->module
->name
, symbol
->lineno
);
299 symbol
=calloc(1, sizeof(struct SYMBOL
));
300 symbol
->name
=strdup(def
);
301 symbol
->module
=currentModule
;
302 symbol
->lineno
=currentLine
;
303 symbol
->segment
=currentSegment
;
304 symbol
->absolute
=absolute
;
305 symbol
->address
=currentModule
->offset
[currentSegment
->id
]+address
;
309 symbols
->last
->next
=symbol
;
311 symbols
->last
=symbol
;
312 currentSegment
->hasSymbols
++;
315 void syntaxError (char *err
) {
316 fprintf (stderr
, "*** %s:%d error while parsing '%s'\n",
317 currentModule
->name
, currentLine
, err
);
321 void readModule(char *module
, int isLib
) {
325 char moduleName
[PATH_MAX
];
326 int segments
, globals
;
330 if ((relModule
=fopen(module
, "r"))==NULL
) {
335 // first we need to check if this is a valid file
336 if (sscanf(fgets(line
, 132, relModule
),
337 "SDCCXA rel, version %lf", &hisVersion
)!=1) {
338 fprintf (stderr
, "*** %s is not a valid input file\n", module
);
341 if (hisVersion
!=version
) {
342 fprintf (stderr
, "*** WARNING: version conflict; "
343 "we(%1.1f) != %s(%1.1f)\n",
344 version
, module
, hisVersion
);
348 // H 7 areas 168 global symbols
349 if (sscanf(fgets(line
, 132, relModule
),
350 "H %d areas %d global symbols",
351 &segments
, &globals
)!=2) {
357 if (sscanf(fgets(line
, 132, relModule
),
358 "M %s", moduleName
)!=1) {
362 // add this to the known modules with current offsets
363 addToModules(module
, isLib
);
367 // now for the ASTR tags
368 while (fgets(line
, 132, relModule
)) {
374 if (sscanf(line
, "A %[^ ] size %d flags %d",
375 segment
, &size
, &flags
)!=3) {
378 // do we know this segment?
379 if (!(currentSegment
=findSegmentByName(segment
))) {
380 fprintf (stderr
, "*** %s:%d unknown area: %s\n", module
,
381 currentLine
, segment
);
384 // double check repeated 'A' records
385 if (currentModule
->size
[currentSegment
->id
]) {
386 // pleased to meet you again, I hope ...
387 if (currentModule
->size
[currentSegment
->id
] != size
) {
388 fprintf (stderr
, "*** %s:%d error %s size %d != %d\n",
390 currentSegment
->name
,
391 currentModule
->size
[currentSegment
->id
],
396 currentSegment
->_size
+= size
;
397 currentModule
->size
[currentSegment
->id
] = size
;
399 // never mind about the flags for now
405 unsigned int address
;
406 if (sscanf(line
, "S %[^ ] %s", symbol
, refdef
)!=2) {
407 fprintf (stderr
, "*** %s:%d syntax error near \"%s\"\n",
408 module
, currentLine
, line
);
411 if (strncmp(refdef
, "Ref", 3)==0) {
412 // we don't need them
413 } else if (strncmp(refdef
, "Def", 3)==0) {
414 sscanf (refdef
, "Def%04x", &address
);
415 addToDefs(symbol
, address
, 0);
416 } else if (strncmp(refdef
, "Abs", 3)==0) {
417 sscanf (refdef
, "Abs%04x", &address
);
418 addToDefs(symbol
, address
, 1);
420 fprintf (stderr
, "%s:%d found invalid symbol definition \"%s\"\n",
421 module
, currentLine
, line
);
427 unsigned int address
;
430 if (currentSegment
->id
!=CSEG
&&
431 currentSegment
->id
!=GSINIT
&&
432 currentSegment
->id
!=XINIT
) {
433 fprintf (stderr
, "%s:%d cannot emit bytes in %s\n",
434 module
, currentLine
, currentSegment
->name
);
437 if (sscanf(strtok(&line
[2], " "), "%04x", &address
)!=1) {
438 fprintf (stderr
, "%s:%d error in T record\n", module
, currentLine
);
442 address
+=currentModule
->offset
[currentSegment
->id
];
443 //address+=currentSegment->current;
445 (tline
=strtok(NULL
, " \t\n")) &&
446 (sscanf(tline
, "%02x", &byte
)==1);
448 currentSegment
->image
[address
++]=byte
;
449 currentSegment
->current
++;
454 unsigned address
, pc
;
457 sscanf (line
, "R %x %[^ ] %[^ ] %x", &address
, how
, symbol
, &pc
);
458 addToRefs (symbol
, address
, how
, pc
);
462 fprintf (stderr
, "%s:%d unknown record \"%s\"\n",
463 module
, currentLine
, line
);
472 void writeModule(char *outFileName
) {
474 unsigned int address
=segments
[GSFINAL
].start
;
475 unsigned int size
=segments
[GSFINAL
]._size
;
477 unsigned int checksum
;
479 if ((fOut
=fopen(outFileName
, "w"))==NULL
) {
480 perror (outFileName
);
484 len
= size
>16 ? 16 : size
;
486 fprintf (fOut
, ":%02X%04X%02X", len
, address
, 0);
487 checksum
= len
+ (address
>>8) + (address
&0xff);
489 checksum
+= gsfinalImage
[address
];
490 fprintf (fOut
, "%02X", gsfinalImage
[address
++]);
494 checksum
= 0x100 - checksum
;
496 fprintf (fOut
, "%02X\n", checksum
);
498 fprintf (fOut
, ":00000001FF\n");
504 struct SYMBOL
*symbol
;
505 struct REFERENCE
*reference
;
507 int length
=segments
[GSINIT
]._size
+
508 segments
[CSEG
]._size
+
509 segments
[XINIT
]._size
;
512 // first check if it will fit
513 if (length
> 0xffff) {
514 fprintf (stderr
, "error: code segment exceeds 0xffff\n");
518 // resolve reverences
519 for (reference
=references
; reference
; reference
=reference
->next
) {
520 if (!reference
->resolved
&& !findSymbolByName(reference
->name
)) {
525 // first scan the libraries
529 // GSFINAL starts at --code-loc ( -b CSEG = 0x1234 )
530 if (segments
[CSEG
].start
& 1) {
531 fprintf (stderr
, "*** error: code doesn't start at "
532 "an even address: %04x\n", segments
[CSEG
].start
);
535 segments
[GSFINAL
].start
=segments
[CSEG
].start
;
536 memset(gsfinalImage
, 0xff, CODESIZE
);
538 // copy gsinit to gsfinal
540 to
= gsfinalImage
+ segments
[GSFINAL
].start
+ segments
[GSFINAL
]._size
;
541 memcpy(to
, from
, segments
[GSINIT
]._size
);
542 segments
[GSINIT
].start
=segments
[GSFINAL
].start
;
543 segments
[GSFINAL
]._size
+= segments
[GSINIT
]._size
;
544 if (segments
[GSFINAL
]._size
& 1) {
545 segments
[GSFINAL
]._size
++;
548 // append cseg to gsfinal
550 to
= gsfinalImage
+ segments
[GSFINAL
].start
+ segments
[GSFINAL
]._size
;
551 memcpy(to
, from
, segments
[CSEG
]._size
);
552 segments
[CSEG
].start
=segments
[GSFINAL
].start
+segments
[GSFINAL
]._size
;
553 segments
[GSFINAL
]._size
+= segments
[CSEG
]._size
;
554 if (segments
[GSFINAL
]._size
& 1) {
555 segments
[GSFINAL
]._size
++;
558 // append xinit to gsfinal
560 to
= gsfinalImage
+ segments
[GSFINAL
].start
+ segments
[GSFINAL
]._size
;
561 memcpy(to
, from
, segments
[XINIT
]._size
);
562 segments
[XINIT
].start
=segments
[GSFINAL
].start
+segments
[GSFINAL
]._size
;
563 segments
[GSFINAL
]._size
+= segments
[XINIT
]._size
;
564 if (segments
[GSFINAL
]._size
& 1) {
565 segments
[GSFINAL
]._size
++;
568 // XISEG is located after XSEG
569 if (segments
[XSEG
].start
& 1) {
570 fprintf (stderr
, "*** warning: xdata doesn't start at "
571 "an even address: %04x\n", segments
[XSEG
].start
);
573 if (segments
[XSEG
]._size
& 1) {
574 segments
[XSEG
]._size
++;
577 segments
[XISEG
].start
=segments
[XSEG
].start
+
578 segments
[XSEG
]._size
;
580 // now relocate the defined symbols
581 for (symbol
=symbols
; symbol
; symbol
=symbol
->next
) {
582 if (!symbol
->absolute
) {
583 symbol
->address
+= symbol
->segment
->start
;
586 // and the references
587 for (reference
=references
; reference
; reference
=reference
->next
) {
588 symbol
=findSymbolByName(reference
->name
);
589 if (!reference
->resolved
&& !symbol
&& reference
->how
!=ABS_PC
) {
590 // this reference isn't resolved after all
591 fprintf (stderr
, "*** %s:%d undefined symbol %s\n",
592 reference
->module
->name
, reference
->lineno
,
596 reference
->address
+=
597 reference
->module
->offset
[reference
->segment
->id
]+
598 reference
->segment
->start
;
600 reference
->module
->offset
[reference
->segment
->id
]+
601 reference
->segment
->start
;
602 switch (reference
->how
)
605 int rel8
= symbol
->address
-(reference
->pc
& ~1);
606 if (rel8
<-256 || rel8
>256) {
608 "rel8 target for %s is out of range in module %s:%d\n",
609 reference
->name
, reference
->module
->name
,
613 gsfinalImage
[reference
->address
]=rel8
/2;
617 int rel16
= symbol
->address
-(reference
->pc
& ~1);
618 if (rel16
<-65536 || rel16
>65534) {
620 "rel16 target for %s is out of range in module %s:%d\n",
621 reference
->name
, reference
->module
->name
,
625 gsfinalImage
[reference
->address
]=(rel16
/2)>>8;
626 gsfinalImage
[reference
->address
+1]=rel16
/2;
630 gsfinalImage
[reference
->address
] =
631 (gsfinalImage
[reference
->address
]&~0x70) +
632 ((symbol
->address
>>4)&0x70);
633 gsfinalImage
[reference
->address
+1] = symbol
->address
;
636 gsfinalImage
[reference
->address
] = symbol
->address
>>8;
637 gsfinalImage
[reference
->address
+1] = symbol
->address
;
640 gsfinalImage
[reference
->address
] = symbol
->address
;
644 unsigned int address
=
645 (gsfinalImage
[reference
->address
]<<8) +
646 gsfinalImage
[reference
->address
+1];
647 address
+= reference
->module
->offset
[reference
->segment
->id
];
648 address
+= segments
[reference
->segment
->id
].start
;
649 gsfinalImage
[reference
->address
] = address
>>8;
650 gsfinalImage
[reference
->address
+1] = address
;
654 fprintf (stderr
, "unsupported reference mode %d.\n",
663 void usage (char * progName
, int errNo
) {
664 fprintf (stderr
, "usage: %s lnkCmdFile\n", progName
);
670 int scanLibraries(int unresolved
) {
673 char libFiles
[PATH_MAX
];
674 char libFile
[PATH_MAX
];
679 for (nlp
=0; nlp
<nlibPaths
; nlp
++) {
680 for (nlf
=0; nlf
<nlibFiles
; nlf
++) {
681 sprintf (libFiles
, "%s/%s.lib", libraryPaths
[nlp
], libraryFiles
[nlf
]);
682 if ((lfs
=fopen(libFiles
,"r"))==NULL
) {
685 while (fgets(line
, 132, lfs
)) {
686 // remove trailing \n
687 line
[strlen(line
)-1]='\0';
688 sprintf (libFile
, "%s/%s", libraryPaths
[nlp
], line
);
689 if ((lf
=fopen(libFile
,"r"))==NULL
) {
692 while (fgets(line
, 132, lf
)) {
693 int dummy
; // we need this to get the right count of the next sscanf
694 if (sscanf(line
, "S %[^ ] Def%04x", symName
, &dummy
)==2) {
695 if (isUnresolved(symName
, 1)) {
696 readModule(libFile
,1);
697 if (resolved
++ == unresolved
) {
701 // skip to next lib module
712 int main(int argc
, char **argv
) {
713 FILE *linkCommandsFile
;
714 char linkCommandsPath
[PATH_MAX
];
715 char linkCommand
[PATH_MAX
];
716 struct MODULE
*module
;
717 struct SYMBOL
*symbol
;
725 // read in the commands
726 sprintf (linkCommandsPath
, "%s.lnk", argv
[1]);
727 if (!(linkCommandsFile
=fopen(linkCommandsPath
, "r"))) {
728 perror(linkCommandsPath
);
731 while (fgets(linkCommand
, PATH_MAX
, linkCommandsFile
)) {
732 linkCommand
[strlen(linkCommand
)-1]='\0';
739 //puts (linkCommand);
740 if (*linkCommand
=='-') {
741 switch (linkCommand
[1])
744 // probably -muxi, ignore for now
747 // -e, always in the last line, ignore for now
751 // a segment start address like: "-b XSEG = 0x4000"
753 char *seg
=strtok(&linkCommand
[3], " \t");
754 for (s
=0; s
<MAX_SEGMENTS
; s
++) {
755 if (strcmp(segments
[s
].name
, seg
)==0) {
756 strtok(NULL
, " \t"); // skip the '='
757 if (sscanf(strtok(NULL
, " \t"), "%x",
758 &segments
[s
].start
)!=1) {
759 syntaxError(linkCommand
);
764 if (s
==MAX_SEGMENTS
) {
765 syntaxError(linkCommand
);
770 // a lib path like: "-k /usr/local/share/sdcc/lib/xa51"; one/line
771 libraryPaths
[nlibPaths
++]=strdup(&linkCommand
[3]);
774 // a lib file like: "-l libsdcc"; one/line
775 libraryFiles
[nlibFiles
++]=strdup(&linkCommand
[3]);
778 syntaxError(linkCommand
);
781 // not a switch, must be an inputfile; one/line
782 readModule(linkCommand
, 0);
783 // the first one defines the output name
784 if (!outFileName
[0]) {
785 strncpy(outFileName
, linkCommand
,
786 strlen(linkCommand
)-4);
787 sprintf(mapFileName
, "%s.map", outFileName
);
788 strcat(outFileName
, ".hex");
789 if ((mapOut
=fopen(mapFileName
, "w"))==NULL
) {
796 // add the segment symbols
797 currentSegment
=findSegmentByName("XINIT");
798 addToDefs("s_XINIT", 0, 0);
799 addToDefs("l_XINIT", segments
[XINIT
]._size
, 1);
800 currentSegment
=findSegmentByName("XISEG");
801 addToDefs("s_XISEG", 0, 0);
802 addToDefs("l_XISEG", segments
[XISEG
]._size
, 1);
804 // mark the resolved references
807 // now do something EXTREMELY SLOW AND INEFFICIENT :)
808 while ((unresolved
=relocate())) {
809 if (!scanLibraries(unresolved
)) {
810 struct REFERENCE
*reference
;
812 for (reference
=references
; reference
; reference
=reference
->next
) {
813 if (!reference
->resolved
) {
814 fprintf (stderr
, "*** unresolved symbol %s in %s:%d\n",
815 reference
->name
, reference
->module
->name
,
825 writeModule(outFileName
);
829 fprintf (mapOut
, "Modules:\n");
830 for (module
=modules
; module
; module
=module
->next
) {
831 fprintf (mapOut
, "\t%s\n", module
->name
);
832 for (s
=0; s
<MAX_SEGMENTS
; s
++) {
833 if (module
->size
[s
]) {
834 fprintf (mapOut
, "\t\t%s:0x%04x-0x%04x\n", segments
[s
].name
,
835 module
->offset
[s
]+segments
[s
].start
,
836 module
->offset
[s
]+segments
[s
].start
+module
->size
[s
]);
842 fprintf (mapOut
, "\nSegments:\n");
843 for (s
=1; s
<MAX_SEGMENTS
; s
++) {
844 if (segments
[s
]._size
) {
845 fprintf (mapOut
, "\t%s start 0x%04x size 0x%04x %d symbols\n",
846 segments
[s
].name
, segments
[s
].start
,
848 segments
[s
].hasSymbols
);
853 fprintf (mapOut
, "\nSymbols:\n");
854 for (symbol
=symbols
; symbol
; symbol
=symbol
->next
) {
855 fprintf (mapOut
, "%s\t%s %s0x%04x %s\n", symbol
->name
,
856 symbol
->segment
->name
,
857 symbol
->absolute
? "= " : "",
858 symbol
->address
, symbol
->module
->name
);
862 return fatalErrors
? 1 : 0;