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
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]" Def's are supposed to be defined in
26 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 xx xx bb bb ..." where xx xx is the address within the current segment
31 "R xx <how> <symbol>" the relocation info. xx is the offset within the
32 previous "T .." line. <how> could be something like REL_FF, REL_FFFF,
33 ABS_F0FF. symbol is the (previous) defined symbol it refers to
35 So, this is not a standalone linker. It will only link files generated
36 by xa_asm, which will only process files generated by the xa51 sdcc
45 #include "xa_version.h"
48 // these are all concatenated into the code image
52 //GSFINAL, // do we need this?
54 // these are only for storage
62 #define CODESIZE 0x10000
64 char codeImage[CODESIZE];
65 char gsinitImage[CODESIZE];
66 char xinitImage[CODESIZE];
76 } segments[MAX_SEGMENTS]={
77 {0, "????", 0, 0, 0, 0, NULL},
79 {GSINIT, "GSINIT", 0, 0, 0, 0, gsinitImage},
80 {CSEG, "CSEG", 0, 0, 0, 0, codeImage},
81 {XINIT, "XINIT", 0, 0, 0, 0, xinitImage},
82 //{GSFINAL, "GSFINAL", 0, 0, 0, 0, NULL},
84 {BSEG, "BSEG", 0, 0, 0, 0, NULL},
85 {DSEG, "DSEG", 0, 0, 0, 0, NULL},
86 {XSEG, "XSEG", 0, 0, 0, 0, NULL},
87 {XISEG, "XISEG", 0, 0, 0, 0, NULL},
92 int offset[MAX_SEGMENTS];
93 int size[MAX_SEGMENTS];
101 struct MODULE *module;
102 struct SEGMENT *segment;
113 static char outFileName[PATH_MAX];
115 struct SEGMENT *currentSegment;
116 struct MODULE *currentModule;
118 struct SEGMENT *findSegment(char *segment) {
120 for (i=1; i<MAX_SEGMENTS; i++) {
121 if (strcmp(segments[i].name, segment)==0) {
128 void addToModules (char *name) {
129 struct MODULE *module;
132 //fprintf (stderr, "addToModules: %s\n", name);
134 module=calloc(1, sizeof(struct MODULE));
135 module->name=strdup(name);
136 for (s=0; s<MAX_SEGMENTS; s++) {
137 module->offset[s]=segments[s].current;
142 modules->last->next=module;
144 currentModule=modules->last=module;
147 void addToRefs(char *ref) {
148 //fprintf (stderr, "addToRefs: %s\n", ref);
151 void addToDefs(char *def, int address) {
152 struct SYMBOL *symbol;
153 /* fprintf (stderr, "addToDefs: %s %s 0x%04x + 0x%04x\n",
154 currentSegment->name, def,
155 currentModule->offset[currentSegment->id],
157 symbol=calloc(1, sizeof(struct SYMBOL));
158 symbol->name=strdup(def);
159 symbol->module=currentModule;
160 symbol->segment=currentSegment;
161 symbol->address=currentModule->offset[currentSegment->id]+address;
165 symbols->last->next=symbol;
167 symbols->last=symbol;
168 currentSegment->hasSymbols++;
171 void syntaxError (char *err) {
172 fprintf (stderr, "error while parsing '%s'\n", err);
176 void baseName(char *name, char*base) {
179 // find the last path seperator in name
180 for (first=strlen(name)-1;
181 (name[first]!='/' && name[first]!='\\') && first;
183 if (name[first]=='/' || name[first]=='\\') {
187 // find the last ext seperator in name
188 for (last=strlen(name)-1;
189 (name[last]!='.' && last);
195 fprintf (stderr, "baseName: %s %d %d\n", name, first, last);
196 // fill the base with the baseName
197 for (i=first; i<last; i++) {
198 base[i-first]=name[i];
203 void readModule(char *module) {
207 char moduleName[PATH_MAX];
208 int segments, globals;
211 if ((relModule=fopen(module, "r"))==NULL) {
216 //fprintf (stderr, "ReadModule: %s\n", module);
218 // first we need to check if this is a valid file
219 if (sscanf(fgets(line, 132, relModule),
220 "SDCCXA rel, version %lf", &hisVersion)!=1) {
221 fprintf (stderr, "%s is not a valid input file\n", module);
224 if (hisVersion!=version) {
225 fprintf (stderr, "WARNING: version conflict; "
226 "we(%1.1f) != %s(%1.1f)\n",
227 version, module, hisVersion);
231 // H 7 areas 168 global symbols
232 if (sscanf(fgets(line, 132, relModule),
233 "H %d areas %d global symbols",
234 &segments, &globals)!=2) {
240 if (sscanf(fgets(line, 132, relModule),
241 "M %s", moduleName)!=1) {
245 // add this to the known modules with current offsets
246 addToModules(module);
248 fprintf (stderr, "module %s has %d segment%s and %d globals\n",
249 moduleName, segments, segments==1?"":"s", globals);
252 // now for the ASTR tags
253 while (fgets(line, 132, relModule)) {
259 if (sscanf(line, "A %[^ ] size %d flags %d",
260 segment, &size, &flags)!=3) {
261 fprintf (stderr, "%s:%d error in A record line\n",
262 module, currentLine);
265 // do we know this segment?
266 if (!(currentSegment=findSegment(segment))) {
267 fprintf (stderr, "%s:%d unknown area: %s\n", module,
268 currentLine, segment);
271 if (currentModule->size[currentSegment->id]) {
272 if (currentModule->size[currentSegment->id] != size) {
273 fprintf (stderr, "%s:%d error %s %d %d\n",
275 currentSegment->name,
276 currentModule->size[currentSegment->id],
280 currentModule->size[currentSegment->id]=size;
281 currentModule->offset[currentSegment->id]+=currentSegment->_size;
282 currentSegment->_size += size;
284 //fprintf (stderr, "Area: %s size: %d\n", segment, size);
285 // never mind about the flags for now
291 unsigned int address;
292 if (sscanf(line, "S %[^ ] %s", symbol, refdef)!=2) {
293 fprintf (stderr, "%s:%d syntax error near \"%s\"\n",
294 module, currentLine, line);
297 if (strncmp(refdef, "Ref", 3)==0) {
299 } else if (strncmp(refdef, "Def", 3)==0) {
300 sscanf (refdef, "Def%04x", &address);
301 addToDefs(symbol, address);
303 fprintf (stderr, "%s:%d found invalid symbol definition \"%s\"\n",
304 module, currentLine, line);
310 unsigned int address;
313 if (currentSegment->id!=CSEG &&
314 currentSegment->id!=GSINIT &&
315 //currentSegment->id!=GSFINAL &&
316 currentSegment->id!=XINIT) {
317 fprintf (stderr, "%s:%d cannot emit bytes in %s\n",
318 module, currentLine, currentSegment->name);
321 if (sscanf(strtok(&line[2], " "), "%04x", &address)!=1) {
322 fprintf (stderr, "%s:%d error in T record\n", module, currentLine);
325 //fprintf (stderr, "%04x:", address);
326 address+=currentSegment->current;
328 (tline=strtok(NULL, " \t\n")) &&
329 (sscanf(tline, "%02x", &byte)==1);
331 //fprintf (stderr, " %02x", byte);
332 currentSegment->image[address++]=byte;
333 currentSegment->current++;
335 //fprintf (stderr, "\n");
339 //fprintf (stderr, "%s", line);
342 /* fprintf (stderr, "%s:%d unknown record \"%s\"\n",
343 module, currentLine, line); */
348 // that's all for now, thanks for watching */
353 fprintf (stderr, "WriteModule: %s\n", outFileName);
354 // oops, forgot something :) */
358 struct SYMBOL *symbol;
359 int length=segments[GSINIT].current +
360 segments[CSEG].current +
361 segments[XINIT].current;
363 // first check if it will fit
364 if (length > 0xffff) {
365 fprintf (stderr, "error: code segment exceeds 0xffff\n");
368 fprintf (stderr, "relocate: total code size: 0x%04x\n", length);
370 // GSINIT gets the --code-loc
371 segments[GSINIT].start=segments[CSEG].start;
372 segments[CSEG].start=segments[GSINIT].start+segments[GSINIT]._size;
373 segments[XINIT].start=segments[CSEG].start+segments[CSEG]._size;
374 segments[XISEG].start=segments[XSEG].start+segments[XINIT]._size;
375 // now relocate the defined symbols
376 for (symbol=symbols; symbol; symbol=symbol->next) {
377 symbol->address += symbol->segment->start;
381 void usage (char * progName, int errNo) {
382 fprintf (stderr, "usage: %s lnkCmdFile\n", progName);
388 int main(int argc, char **argv) {
389 FILE *linkCommandsFile;
390 char linkCommandsPath[PATH_MAX];
391 char linkCommand[PATH_MAX];
392 struct MODULE *module;
393 struct SYMBOL *symbol;
400 memset(codeImage, 0xff, CODESIZE);
402 // read in the commands
403 sprintf (linkCommandsPath, "%s.lnk", argv[1]);
404 if (!(linkCommandsFile=fopen(linkCommandsPath, "r"))) {
405 perror(linkCommandsPath);
408 while (fgets(linkCommand, PATH_MAX, linkCommandsFile)) {
409 linkCommand[strlen(linkCommand)-1]='\0';
416 //puts (linkCommand);
417 if (*linkCommand=='-') {
418 switch (linkCommand[1])
421 // probably -muxi, ignore for now
424 // -e, always in the last line, ignore for now
428 // a segment start address like: "-b XSEG = 0x4000"
430 char *seg=strtok(&linkCommand[3], " \t");
431 for (s=0; s<MAX_SEGMENTS; s++) {
432 if (strcmp(segments[s].name, seg)==0) {
433 strtok(NULL, " \t"); // skip the '='
434 if (sscanf(strtok(NULL, " \t"), "%x",
435 &segments[s].start)!=1) {
436 syntaxError(linkCommand);
438 /* fprintf (stderr, "%s starts at 0x%04x\n", segments[s].name,
439 segments[s].start); */
443 if (s==MAX_SEGMENTS) {
444 syntaxError(linkCommand);
449 // a lib path like: "-k /usr/local/share/sdcc/lib/xa51"; one/line
450 libPaths[nlibPaths++]=strdup(&linkCommand[3]);
453 // a lib file like: "-l libsdcc"; one/line
454 libFiles[nlibFiles++]=strdup(&linkCommand[3]);
457 syntaxError(linkCommand);
460 // not a switch, must be an inputfile; one/line
461 readModule(linkCommand);
468 for (module=modules; module; module=module->next) {
469 fprintf (stderr, "%s: ", module->name);
470 for (s=0; s<MAX_SEGMENTS; s++) {
471 if (module->size[s]) {
472 fprintf (stderr, "%s:0x%04x-0x%04x ", segments[s].name,
473 module->offset[s], module->offset[s]+module->size[s]);
476 fprintf (stderr, "\n");
480 for (symbol=symbols; symbol; symbol=symbol->next) {
481 fprintf (stderr, "%s %s 0x%04x %s\n", symbol->name, symbol->segment->name,
482 symbol->address, symbol->module->name);
486 for (s=1; s<MAX_SEGMENTS; s++) {
487 if (segments[s]._size) {
488 fprintf (stderr, "%s start 0x%04x size 0x%04x %d symbols\n",
489 segments[s].name, segments[s].start,
491 segments[s].hasSymbols);