* asranlib/asranlib.c, link/lkar.h, link/lkar.c:
[fw/sdcc] / as / xa51 / xa_link.c
1 /* xa_link.c
2
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
6 later version.
7
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.
12
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/>. */
15
16 /* WORK IN PROGRESS: do not watch this if you don't have the legal
17    age in your country to watch this.
18 */
19
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. 
23
24    No hash or qsort yet.
25
26    The relocatable format looks like the known one, BUT ISN'T.
27
28    The only things that are handled now are:
29
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).
42
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
45    port.
46 */
47
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <limits.h>
51 #include <string.h>
52
53 #include "xa_version.h"
54
55 enum {
56   // these are all concatenated into the code image
57   GSINIT=1,
58   CSEG,
59   XINIT,
60
61   // here goes the final output and should be used by the assembler
62   GSFINAL,
63
64   // these are only for storage
65   BSEG,
66   DSEG,
67   XSEG,
68   XISEG,
69
70   // that's all
71   MAX_SEGMENTS
72 };
73
74 enum {
75   REL_FF=1,
76   REL_FFFF,
77   BIT_03FF,
78   DIR_07FF,
79   DIR_70FF,
80   DIR_0700FF,
81   ABS_0F,
82   ABS_FF,
83   ABS_FFFF,
84   ABS_PC,
85   MAX_REFS
86 };
87
88 char *refModes[]={
89   "???",
90   "REL_FF",
91   "REL_FFFF",
92   "BIT_03FF",
93   "DIR_07FF",
94   "DIR_70FF",
95   "DIR_0700FF",
96   "ABS_0F",
97   "ABS_FF",
98   "ABS_FFFF",
99   "ABS_PC"
100 };
101
102 #define CODESIZE 0x10000
103
104 int fatalErrors=0;
105
106 unsigned char gsinitImage[CODESIZE];
107 unsigned char csegImage[CODESIZE];
108 unsigned char xinitImage[CODESIZE];
109 unsigned char gsfinalImage[CODESIZE];
110
111 struct SEGMENT {
112   short id;
113   char *name;
114   int hasSymbols;
115   int _size;
116   int start;
117   int current;
118   unsigned char *image;
119 } segments[MAX_SEGMENTS]={
120   {0,       "???",    0, 0, 0, 0, NULL},
121
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},
126
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},
131 };
132
133 struct MODULE {
134   char *name;
135   int offset[MAX_SEGMENTS];
136   int size[MAX_SEGMENTS];
137   int isLib;
138   struct MODULE *next;
139   struct MODULE *last;
140 } *modules=NULL;
141
142
143 struct SYMBOL {
144   char *name;
145   struct MODULE *module;
146   int lineno;
147   struct SEGMENT *segment;
148   char absolute;
149   int address;
150   struct SYMBOL *next;
151   struct SYMBOL *last;
152 } *symbols=NULL;
153
154 struct REFERENCE {
155   char *name;
156   struct MODULE *module;
157   struct SEGMENT *segment;
158   int lineno;
159   unsigned address, pc;
160   short how;
161   short resolved;
162   struct REFERENCE *next;
163   struct REFERENCE *last;
164 } *references=NULL;
165
166 char *libraryPaths[128];
167 int nlibPaths=0;
168 char *libraryFiles[128];
169 int nlibFiles=0;
170
171 static char outFileName[PATH_MAX]={'\0'};
172 static char mapFileName[PATH_MAX]={'\0'};
173 FILE *mapOut;
174
175 struct SEGMENT *currentSegment;
176 struct MODULE *currentModule;
177 int currentLine;
178
179 int howToReference(char *how) {
180   int r;
181   for (r=1; r<MAX_REFS; r++) {
182     if (strcmp(refModes[r], how)==0) {
183       return r;
184     }
185   }
186   return 0;
187 }
188
189 struct SEGMENT *findSegmentByName(char *segment) {
190   int s;
191   for (s=0; s<MAX_SEGMENTS; s++) {
192     if (strcmp(segments[s].name, segment)==0) {
193       return &segments[s];
194     }
195   }
196   return 0;
197 }
198
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) {
203       return symbol;
204     }
205   }
206   return 0;
207 }
208
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) {
213       return module;
214     }
215   }
216   return NULL;
217 }
218
219 void addToModules (char *name, int isLib) {
220   struct MODULE *module;
221   int s;
222
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;
227   }
228   module->isLib=isLib;
229   if (!modules) {
230     modules=module;
231    } else {
232     modules->last->next=module;
233   }
234   currentModule=modules->last=module;
235 }
236
237 void addToRefs(char *ref, int address, char *how, int pc) {
238   struct REFERENCE *reference;
239
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;
249   }
250   reference->pc=pc;
251   if (!references) {
252     references=reference;
253   } else {
254     references->last->next=reference;
255   }
256   references->last=reference;
257 }
258
259 void resolve() {
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;
264     }
265   }
266 }
267
268 int isUnresolved(char *ref, int resolved) {
269   struct REFERENCE *reference;
270
271   for (reference=references; reference; reference=reference->next) {
272     if (strcmp(reference->name, ref)==0) {
273       // found 
274       if (reference->resolved) {
275         // already resolved
276         return 0;
277       }
278       if (resolved) {
279         reference->resolved=1;
280         return 1;
281       }
282     }
283   }
284   return 0;
285 }
286
287 void addToDefs(char *def, int address, char absolute) {
288   struct SYMBOL *symbol;
289
290   // no duplicates allowed
291   if ((symbol=findSymbolByName(def))) {
292     fprintf (stderr, "*** %s:%d duplicate symbol %s first defined in "
293              "module %s:%d\n",
294              currentModule->name, currentLine, def, 
295              symbol->module->name, symbol->lineno);
296     fatalErrors++;
297   }
298
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;
306   if (!symbols) {
307     symbols=symbol;
308   } else {
309     symbols->last->next=symbol;
310   }
311   symbols->last=symbol;
312   currentSegment->hasSymbols++;
313 }
314
315 void syntaxError (char *err) {
316   fprintf (stderr, "*** %s:%d error while parsing '%s'\n", 
317            currentModule->name, currentLine, err);
318   fatalErrors++;
319 }
320
321 void readModule(char *module, int isLib) {
322   double hisVersion;
323   char line[132];
324   FILE *relModule;
325   char moduleName[PATH_MAX];
326   int segments, globals;
327
328   currentLine=1;
329
330   if ((relModule=fopen(module, "r"))==NULL) {
331     perror (module);
332     exit (1);
333   }
334
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);
339     exit (1);
340   }
341   if (hisVersion!=version) {
342     fprintf (stderr, "*** WARNING: version conflict; "
343              "we(%1.1f) != %s(%1.1f)\n", 
344              version, module, hisVersion);
345   }
346   currentLine++;
347   
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) {
352     syntaxError(line);
353   }
354   currentLine++;
355
356   // M module
357   if (sscanf(fgets(line, 132, relModule),
358              "M %s", moduleName)!=1) {
359     syntaxError(line);
360   }
361
362   // add this to the known modules with current offsets
363   addToModules(module, isLib);
364
365   currentLine++;
366
367   // now for the ASTR tags
368   while (fgets(line, 132, relModule)) {
369     switch (line[0]) 
370       {
371       case 'A': {
372         char segment[32];
373         int size, flags;
374         if (sscanf(line, "A %[^ ] size %d flags %d",
375                    segment, &size, &flags)!=3) {
376           syntaxError(line);
377         }
378         // do we know this segment?
379         if (!(currentSegment=findSegmentByName(segment))) {
380           fprintf (stderr, "*** %s:%d unknown area: %s\n", module,
381                    currentLine, segment);
382           exit (1);
383         }
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",
389                      module, currentLine,
390                      currentSegment->name,
391                      currentModule->size[currentSegment->id], 
392                      size);
393             fatalErrors++;
394           }
395         } else {
396           currentSegment->_size += size;
397           currentModule->size[currentSegment->id] = size;
398         }
399         // never mind about the flags for now
400         break;
401       }
402       case 'S': {
403         char symbol[132];
404         char refdef[132];
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);
409           exit (1);
410         }
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);
419         } else {
420           fprintf (stderr, "%s:%d found invalid symbol definition \"%s\"\n", 
421                    module, currentLine, line);
422           exit (1);
423         }
424         break;
425       }
426       case 'T': {
427         unsigned int address;
428         unsigned int byte;
429         char *tline=NULL;
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);
435           exit (1);
436         }
437         if (sscanf(strtok(&line[2], " "), "%04x", &address)!=1) {
438           fprintf (stderr, "%s:%d error in T record\n", module, currentLine);
439           fatalErrors++;
440         }
441
442         address+=currentModule->offset[currentSegment->id];
443         //address+=currentSegment->current;
444         for ( ;
445               (tline=strtok(NULL, " \t\n")) && 
446                 (sscanf(tline, "%02x", &byte)==1);
447               ) {
448           currentSegment->image[address++]=byte;
449           currentSegment->current++;
450         }
451         break;
452       }
453       case 'R': {
454         unsigned address, pc;
455         char symbol[132];
456         char how[32];
457         sscanf (line, "R %x %[^ ] %[^ ] %x", &address, how, symbol, &pc);
458         addToRefs (symbol, address, how, pc);
459         break;
460       }
461       default:
462         fprintf (stderr, "%s:%d unknown record \"%s\"\n",
463                  module, currentLine, line);
464         fatalErrors++;
465         break;
466       }
467     currentLine++;
468   }
469   fclose (relModule);
470 }
471
472 void writeModule(char *outFileName) {
473   FILE *fOut;
474   unsigned int address=segments[GSFINAL].start;
475   unsigned int size=segments[GSFINAL]._size;
476   unsigned int len;
477   unsigned int checksum;
478
479   if ((fOut=fopen(outFileName, "w"))==NULL) {
480     perror (outFileName);
481   }
482
483   while (size) {
484     len = size>16 ? 16 : size;
485     size-=len;
486     fprintf (fOut, ":%02X%04X%02X", len, address, 0);
487     checksum = len + (address>>8) + (address&0xff);
488     while (len--) {
489       checksum += gsfinalImage[address];
490       fprintf (fOut, "%02X", gsfinalImage[address++]);
491     }
492     checksum &= 0xff;
493     if (checksum) {
494       checksum = 0x100 - checksum;
495     }
496     fprintf (fOut, "%02X\n", checksum);
497   }
498   fprintf (fOut, ":00000001FF\n");
499
500   fclose (fOut);
501 }
502
503 int relocate() {
504   struct SYMBOL *symbol;
505   struct REFERENCE *reference;
506   char *from, *to;
507   int length=segments[GSINIT]._size +
508     segments[CSEG]._size +
509     segments[XINIT]._size;
510   int unresolved=0;
511
512   // first check if it will fit
513   if (length > 0xffff) {
514     fprintf (stderr, "error: code segment exceeds 0xffff\n");
515     fatalErrors++;
516   }
517
518   // resolve reverences
519   for (reference=references; reference; reference=reference->next) {
520     if (!reference->resolved && !findSymbolByName(reference->name)) {
521       unresolved++;
522     }
523   }
524   if (unresolved) {
525     // first scan the libraries
526     return unresolved;
527   }
528
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);
533     exit (1);
534   }
535   segments[GSFINAL].start=segments[CSEG].start;
536   memset(gsfinalImage, 0xff, CODESIZE);
537
538   // copy gsinit to gsfinal
539   from = gsinitImage;
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++;
546   }
547     
548   // append cseg to gsfinal
549   from=csegImage;
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++;
556   }
557
558   // append xinit to gsfinal
559   from=xinitImage;
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++;
566   }
567
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);
572   }
573   if (segments[XSEG]._size & 1) {
574     segments[XSEG]._size++;
575   }
576   
577   segments[XISEG].start=segments[XSEG].start + 
578     segments[XSEG]._size;  
579
580   // now relocate the defined symbols
581   for (symbol=symbols; symbol; symbol=symbol->next) {
582     if (!symbol->absolute) {
583       symbol->address += symbol->segment->start;
584     }
585   }
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,
593                reference->name);
594       fatalErrors++;
595     } else {
596       reference->address += 
597         reference->module->offset[reference->segment->id]+
598         reference->segment->start;
599       reference->pc += 
600         reference->module->offset[reference->segment->id]+
601         reference->segment->start;
602       switch (reference->how) 
603         {
604         case REL_FF: {
605           int rel8 = symbol->address-(reference->pc & ~1);
606           if (rel8<-256 || rel8>256) {
607             fprintf (stderr,
608                      "rel8 target for %s is out of range in module %s:%d\n",
609                      reference->name, reference->module->name, 
610                      reference->lineno);
611             fatalErrors++;
612           }
613           gsfinalImage[reference->address]=rel8/2;
614           break;
615         }
616         case REL_FFFF: {
617           int rel16 = symbol->address-(reference->pc & ~1);
618           if (rel16<-65536 || rel16>65534) {
619             fprintf (stderr, 
620                      "rel16 target for %s is out of range in module %s:%d\n",
621                      reference->name, reference->module->name,
622                      reference->lineno);
623             fatalErrors++;
624           }
625           gsfinalImage[reference->address]=(rel16/2)>>8;
626           gsfinalImage[reference->address+1]=rel16/2;
627           break;
628         }
629         case DIR_70FF:
630           gsfinalImage[reference->address] = 
631             (gsfinalImage[reference->address]&~0x70) + 
632             ((symbol->address>>4)&0x70);
633           gsfinalImage[reference->address+1] = symbol->address;
634           break;
635         case ABS_FFFF:
636           gsfinalImage[reference->address] = symbol->address>>8;
637           gsfinalImage[reference->address+1] = symbol->address;
638           break;
639         case ABS_FF:
640           gsfinalImage[reference->address] = symbol->address;
641           break;
642         case ABS_PC: 
643           {
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;
651           };
652           break;
653         default:
654           fprintf (stderr, "unsupported reference mode %d.\n",
655                    reference->how);
656           fatalErrors++;
657         }
658     }
659   }
660   return 0;
661 }
662
663 void usage (char * progName, int errNo) {
664   fprintf (stderr, "usage: %s lnkCmdFile\n", progName);
665   if (errNo) {
666     exit (errNo);
667   }
668 }
669
670 int scanLibraries(int unresolved) {
671   int resolved=0;
672   int nlp, nlf;
673   char libFiles[PATH_MAX];
674   char libFile[PATH_MAX];
675   char line[132];
676   char symName[132];
677   FILE *lf, *lfs;
678   
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) {
683         continue;
684       }
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) {
690           continue;
691         }
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) {
698                 // we are done
699                 return resolved;
700               }
701               // skip to next lib module
702               break;
703             }
704           }
705         }
706       }
707     }
708   }
709   return resolved;
710 }
711
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;
718   int s;
719   int unresolved;
720
721   if (argc!=2) {
722     usage(argv[0], 1);
723   }
724
725   // read in the commands
726   sprintf (linkCommandsPath, "%s.lnk", argv[1]);
727   if (!(linkCommandsFile=fopen(linkCommandsPath, "r"))) {
728     perror(linkCommandsPath);
729     exit(1);
730   }
731   while (fgets(linkCommand, PATH_MAX, linkCommandsFile)) {
732     linkCommand[strlen(linkCommand)-1]='\0';
733
734     // skip empty lines
735     if (!*linkCommand) {
736       continue;
737     }
738
739     //puts (linkCommand);
740     if (*linkCommand=='-') {
741       switch (linkCommand[1]) 
742         {
743         case 'm':
744           // probably -muxi, ignore for now
745           break;
746         case 'e':
747           // -e, always in the last line, ignore for now
748           break;
749         case 'b': 
750           {
751             // a segment start address like: "-b XSEG = 0x4000"
752             int s;
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);
760                 }
761                 break;
762               }
763             }
764             if (s==MAX_SEGMENTS) {
765               syntaxError(linkCommand);
766             }
767           }
768           break;
769         case 'k':
770           // a lib path like: "-k /usr/local/share/sdcc/lib/xa51"; one/line
771           libraryPaths[nlibPaths++]=strdup(&linkCommand[3]);
772           break;
773         case 'l':
774           // a lib file like: "-l libsdcc"; one/line
775           libraryFiles[nlibFiles++]=strdup(&linkCommand[3]);
776           break;
777         default:
778           syntaxError(linkCommand);
779         }
780     } else {
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) {
790           perror(mapFileName);
791         }
792       }
793     }
794   }
795
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);
803
804   // mark the resolved references
805   resolve();
806
807   // now do something EXTREMELY SLOW AND INEFFICIENT :)
808   while ((unresolved=relocate())) {
809     if (!scanLibraries(unresolved)) {
810       struct REFERENCE *reference;
811       resolve();
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,
816                    reference->lineno);
817           fatalErrors++;
818         }
819       }
820       break;
821     }
822   }
823
824   if (unresolved==0) {
825     writeModule(outFileName);
826   }
827
828   // the modules
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]);
837       }
838     }
839   }
840
841   // the segments
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,
847                segments[s]._size, 
848                segments[s].hasSymbols);
849     }
850   }
851
852   // the symbols
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);
859   }
860
861   fclose(mapOut);
862   return fatalErrors? 1 : 0;
863 }
864