f6d708eb0361448266cb3fadd7071fff97b9794d
[fw/sdcc] / as / xa51 / xa_link.c
1 /* WORK IN PROGRESS: do not watch this if you don't have the legal
2    age in your country to watch this.
3 */
4
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.
9
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
13  */
14
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.
18
19    The relocatable format looks like the known one, BUT ISN'T.
20
21    The only things that are handled now are:
22
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_70FF. 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).
35
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
38    port.
39 */
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <limits.h>
44 #include <string.h>
45
46 #include "xa_version.h"
47
48 enum {
49   // these are all concatenated into the code image
50   GSINIT=1,
51   CSEG,
52   XINIT,
53   GSFINAL, // here goes the final output
54
55   // these are only for storage
56   BSEG,
57   DSEG,
58   XSEG,
59   XISEG,
60   MAX_SEGMENTS
61 };
62
63 enum {
64   REL_FF=1,
65   REL_FFFF,
66   BIT_03FF,
67   DIR_07FF,
68   DIR_70FF,
69   DIR_0700FF,
70   ABS_0F,
71   ABS_FF,
72   ABS_FFFF,
73   ABS_PC,
74   MAX_REFS
75 };
76
77 char *refModes[]={
78   "???",
79   "REL_FF",
80   "REL_FFFF",
81   "BIT_03FF",
82   "DIR_07FF",
83   "DIR_70FF",
84   "DIR_0700FF",
85   "ABS_0F",
86   "ABS_FF",
87   "ABS_FFFF",
88   "ABS_PC"
89 };
90
91 #define CODESIZE 0x10000
92
93 int fatalErrors=0;
94
95 unsigned char gsinitImage[CODESIZE];
96 unsigned char csegImage[CODESIZE];
97 unsigned char xinitImage[CODESIZE];
98 unsigned char gsfinalImage[CODESIZE];
99
100 struct SEGMENT {
101   short id;
102   char *name;
103   int hasSymbols;
104   int _size;
105   int start;
106   int current;
107   unsigned char *image;
108 } segments[MAX_SEGMENTS]={
109   {0,       "???",    0, 0, 0, 0, NULL},
110
111   {GSINIT,  "GSINIT",  0, 0, 0, 0, gsinitImage},
112   {CSEG,    "CSEG",    0, 0, 0, 0, csegImage},
113   {XINIT,   "XINIT",   0, 0, 0, 0, xinitImage},
114   {GSFINAL, "GSFINAL", 0, 0, 0, 0, gsfinalImage},
115
116   {BSEG,    "BSEG",    0, 0, 0, 0, NULL},
117   {DSEG,    "DSEG",    0, 0, 0, 0, NULL},
118   {XSEG,    "XSEG",    0, 0, 0, 0, NULL},
119   {XISEG,   "XISEG",   0, 0, 0, 0, NULL},
120 };
121
122 struct MODULE {
123   char *name;
124   int offset[MAX_SEGMENTS];
125   int size[MAX_SEGMENTS];
126   int isLib;
127   struct MODULE *next;
128   struct MODULE *last;
129 } *modules=NULL;
130
131
132 struct SYMBOL {
133   char *name;
134   struct MODULE *module;
135   int lineno;
136   struct SEGMENT *segment;
137   char absolute;
138   int address;
139   struct SYMBOL *next;
140   struct SYMBOL *last;
141 } *symbols=NULL;
142
143 struct REFERENCE {
144   char *name;
145   struct MODULE *module;
146   struct SEGMENT *segment;
147   int lineno;
148   unsigned address, pc;
149   short how;
150   short resolved;
151   struct REFERENCE *next;
152   struct REFERENCE *last;
153 } *references=NULL;
154
155 char *libraryPaths[128];
156 int nlibPaths=0;
157 char *libraryFiles[128];
158 int nlibFiles=0;
159
160 static char outFileName[PATH_MAX]={'\0'};
161 static char mapFileName[PATH_MAX]={'\0'};
162 FILE *mapOut;
163
164 struct SEGMENT *currentSegment;
165 struct MODULE *currentModule;
166 int currentLine;
167
168 int howToReference(char *how) {
169   int r;
170   for (r=1; r<MAX_REFS; r++) {
171     if (strcmp(refModes[r], how)==0) {
172       return r;
173     }
174   }
175   return 0;
176 }
177
178 struct SEGMENT *findSegmentByName(char *segment) {
179   int s;
180   for (s=0; s<MAX_SEGMENTS; s++) {
181     if (strcmp(segments[s].name, segment)==0) {
182       return &segments[s];
183     }
184   }
185   return 0;
186 }
187
188 struct SYMBOL *findSymbolByName(char *symName) {
189   struct SYMBOL *symbol;
190   for (symbol=symbols; symbol; symbol=symbol->next) {
191     if (strcmp(symbol->name, symName)==0) {
192       return symbol;
193     }
194   }
195   return 0;
196 }
197
198 struct MODULE *findModuleByName(char *modName) {
199   struct MODULE *module;
200   for (module=modules; module; module=module->next) {
201     if (strcmp(module->name, modName)==0) {
202       return module;
203     }
204   }
205   return NULL;
206 }
207
208 void addToModules (char *name, int isLib) {
209   struct MODULE *module;
210   int s;
211
212   module=calloc(1, sizeof(struct MODULE));
213   module->name=strdup(name);
214   for (s=0; s<MAX_SEGMENTS; s++) {
215     module->offset[s]=(segments[s]._size+1)&0xfffffe;
216   }
217   module->isLib=isLib;
218   if (!modules) {
219     modules=module;
220    } else {
221     modules->last->next=module;
222   }
223   currentModule=modules->last=module;
224 }
225
226 void addToRefs(char *ref, int address, char *how, int pc) {
227   struct REFERENCE *reference;
228
229   reference=calloc(1, sizeof(struct REFERENCE));
230   reference->name=strdup(ref);
231   reference->module=currentModule;
232   reference->segment=currentSegment;
233   reference->lineno=currentLine;
234   reference->address=address;
235   reference->how=howToReference(how);
236   if (reference->how==ABS_PC) {
237     reference->resolved=1;
238   }
239   reference->pc=pc;
240   if (!references) {
241     references=reference;
242   } else {
243     references->last->next=reference;
244   }
245   references->last=reference;
246 }
247
248 void resolve() {
249   struct REFERENCE *reference;
250   for (reference=references; reference; reference=reference->next) {
251     if ((reference->how==ABS_PC) || findSymbolByName(reference->name)) {
252       reference->resolved=1;
253     }
254   }
255 }
256
257 int isUnresolved(char *ref, int resolved) {
258   struct REFERENCE *reference;
259
260   for (reference=references; reference; reference=reference->next) {
261     if (strcmp(reference->name, ref)==0) {
262       // found 
263       if (reference->resolved) {
264         // already resolved
265         return 0;
266       }
267       if (resolved) {
268         reference->resolved=1;
269         return 1;
270       }
271     }
272   }
273   return 0;
274 }
275
276 void addToDefs(char *def, int address, char absolute) {
277   struct SYMBOL *symbol;
278
279   // no duplicates allowed
280   if ((symbol=findSymbolByName(def))) {
281     fprintf (stderr, "*** %s:%d duplicate symbol %s first defined in "
282              "module %s:%d\n",
283              currentModule->name, currentLine, def, 
284              symbol->module->name, symbol->lineno);
285     fatalErrors++;
286   }
287
288   symbol=calloc(1, sizeof(struct SYMBOL));
289   symbol->name=strdup(def);
290   symbol->module=currentModule;
291   symbol->lineno=currentLine;
292   symbol->segment=currentSegment;
293   symbol->absolute=absolute;
294   symbol->address=currentModule->offset[currentSegment->id]+address;
295   if (!symbols) {
296     symbols=symbol;
297   } else {
298     symbols->last->next=symbol;
299   }
300   symbols->last=symbol;
301   currentSegment->hasSymbols++;
302 }
303
304 void syntaxError (char *err) {
305   fprintf (stderr, "*** %s:%d error while parsing '%s'\n", 
306            currentModule->name, currentLine, err);
307   fatalErrors++;
308 }
309
310 void readModule(char *module, int isLib) {
311   double hisVersion;
312   char line[132];
313   FILE *relModule;
314   char moduleName[PATH_MAX];
315   int segments, globals;
316
317   currentLine=1;
318
319   if ((relModule=fopen(module, "r"))==NULL) {
320     perror (module);
321     exit (1);
322   }
323
324   // first we need to check if this is a valid file
325   if (sscanf(fgets(line, 132, relModule), 
326              "SDCCXA rel, version %lf", &hisVersion)!=1) {
327     fprintf (stderr, "*** %s is not a valid input file\n", module);
328     exit (1);
329   }
330   if (hisVersion!=version) {
331     fprintf (stderr, "*** WARNING: version conflict; "
332              "we(%1.1f) != %s(%1.1f)\n", 
333              version, module, hisVersion);
334   }
335   currentLine++;
336   
337   // H 7 areas 168 global symbols
338   if (sscanf(fgets(line, 132, relModule),
339              "H %d areas %d global symbols",
340              &segments, &globals)!=2) {
341     syntaxError(line);
342   }
343   currentLine++;
344
345   // M module
346   if (sscanf(fgets(line, 132, relModule),
347              "M %s", moduleName)!=1) {
348     syntaxError(line);
349   }
350
351   // add this to the known modules with current offsets
352   addToModules(module, isLib);
353
354   currentLine++;
355
356   // now for the ASTR tags
357   while (fgets(line, 132, relModule)) {
358     switch (line[0]) 
359       {
360       case 'A': {
361         char segment[32];
362         int size, flags;
363         if (sscanf(line, "A %[^ ] size %d flags %d",
364                    segment, &size, &flags)!=3) {
365           syntaxError(line);
366         }
367         // do we know this segment?
368         if (!(currentSegment=findSegmentByName(segment))) {
369           fprintf (stderr, "*** %s:%d unknown area: %s\n", module,
370                    currentLine, segment);
371           exit (1);
372         }
373         // double check repeated 'A' records
374         if (currentModule->size[currentSegment->id]) {
375           // pleased to meet you again, I hope ...
376           if (currentModule->size[currentSegment->id] != size) {
377             fprintf (stderr, "*** %s:%d error %s size %d != %d\n",
378                      module, currentLine,
379                      currentSegment->name,
380                      currentModule->size[currentSegment->id], 
381                      size);
382             fatalErrors++;
383           }
384         } else {
385           currentSegment->_size += size;
386           currentModule->size[currentSegment->id] = size;
387         }
388         // never mind about the flags for now
389         break;
390       }
391       case 'S': {
392         char symbol[132];
393         char refdef[132];
394         unsigned int address;
395         if (sscanf(line, "S %[^ ] %s", symbol, refdef)!=2) {
396           fprintf (stderr, "*** %s:%d syntax error near \"%s\"\n",
397                    module, currentLine, line);
398           exit (1);
399         }
400         if (strncmp(refdef, "Ref", 3)==0) {
401           // we don't need them
402         } else if (strncmp(refdef, "Def", 3)==0) {
403           sscanf (refdef, "Def%04x", &address);
404           addToDefs(symbol, address, 0);
405         } else if (strncmp(refdef, "Abs", 3)==0) {
406           sscanf (refdef, "Abs%04x", &address);
407           addToDefs(symbol, address, 1);
408         } else {
409           fprintf (stderr, "%s:%d found invalid symbol definition \"%s\"\n", 
410                    module, currentLine, line);
411           exit (1);
412         }
413         break;
414       }
415       case 'T': {
416         unsigned int address;
417         unsigned int byte;
418         char *tline=NULL;
419         if (currentSegment->id!=CSEG && 
420             currentSegment->id!=GSINIT &&
421             currentSegment->id!=XINIT) {
422           fprintf (stderr, "%s:%d cannot emit bytes in %s\n",
423                    module, currentLine, currentSegment->name);
424           exit (1);
425         }
426         if (sscanf(strtok(&line[2], " "), "%04x", &address)!=1) {
427           fprintf (stderr, "%s:%d error in T record\n", module, currentLine);
428           fatalErrors++;
429         }
430
431         address+=currentModule->offset[currentSegment->id];
432         //address+=currentSegment->current;
433         for ( ;
434               (tline=strtok(NULL, " \t\n")) && 
435                 (sscanf(tline, "%02x", &byte)==1);
436               ) {
437           currentSegment->image[address++]=byte;
438           currentSegment->current++;
439         }
440         break;
441       }
442       case 'R': {
443         unsigned address, pc;
444         char symbol[132];
445         char how[32];
446         sscanf (line, "R %x %[^ ] %[^ ] %x", &address, how, symbol, &pc);
447         addToRefs (symbol, address, how, pc);
448         break;
449       }
450       default:
451         fprintf (stderr, "%s:%d unknown record \"%s\"\n",
452                  module, currentLine, line);
453         fatalErrors++;
454         break;
455       }
456     currentLine++;
457   }
458   // that's all for now, thanks for watching */
459   fclose (relModule);
460 }
461
462 void writeModule(char *outFileName) {
463   FILE *fOut;
464   unsigned int address=segments[GSFINAL].start;
465   unsigned int size=segments[GSFINAL]._size;
466   unsigned int len;
467   unsigned int checksum;
468
469   if ((fOut=fopen(outFileName, "w"))==NULL) {
470     perror (outFileName);
471   }
472
473   while (size) {
474     len = size>16 ? 16 : size;
475     size-=len;
476     fprintf (fOut, ":%02X%04X%02X", len, address, 0);
477     checksum = len + (address>>8) + (address&0xff);
478     while (len--) {
479       checksum += gsfinalImage[address];
480       fprintf (fOut, "%02X", gsfinalImage[address++]);
481     }
482     checksum &= 0xff;
483     if (checksum) {
484       checksum = 0x100 - checksum;
485     }
486     fprintf (fOut, "%02X\n", checksum);
487   }
488   fprintf (fOut, ":00000001FF\n");
489
490   fclose (fOut);
491 }
492
493 int relocate() {
494   struct SYMBOL *symbol;
495   struct REFERENCE *reference;
496   char *from, *to;
497   int length=segments[GSINIT]._size +
498     segments[CSEG]._size +
499     segments[XINIT]._size;
500   int unresolved=0;
501
502   // first check if it will fit
503   if (length > 0xffff) {
504     fprintf (stderr, "error: code segment exceeds 0xffff\n");
505     fatalErrors++;
506   }
507
508   // resolve reverences
509   for (reference=references; reference; reference=reference->next) {
510     if (!reference->resolved && !findSymbolByName(reference->name)) {
511       unresolved++;
512     }
513   }
514   if (unresolved) {
515     // first scan the libraries
516     return unresolved;
517   }
518
519   // GSFINAL starts at --code-loc ( -b CSEG = 0x1234 )
520   if (segments[CSEG].start & 1) {
521     fprintf (stderr, "*** error: code doesn't start at "
522              "an even address: %04x\n", segments[CSEG].start);
523     exit (1);
524   }
525   segments[GSFINAL].start=segments[CSEG].start;
526   memset(gsfinalImage, 0xff, CODESIZE);
527
528   // copy gsinit to gsfinal
529   from = gsinitImage;
530   to = gsfinalImage + segments[GSFINAL].start + segments[GSFINAL]._size;
531   memcpy(to, from, segments[GSINIT]._size);
532   segments[GSINIT].start=segments[GSFINAL].start;
533   segments[GSFINAL]._size += segments[GSINIT]._size;
534   if (segments[GSFINAL]._size & 1) {
535     segments[GSFINAL]._size++;
536   }
537     
538   // append cseg to gsfinal
539   from=csegImage;
540   to = gsfinalImage + segments[GSFINAL].start + segments[GSFINAL]._size;
541   memcpy(to, from, segments[CSEG]._size);
542   segments[CSEG].start=segments[GSFINAL].start+segments[GSFINAL]._size;
543   segments[GSFINAL]._size += segments[CSEG]._size;
544   if (segments[GSFINAL]._size & 1) {
545     segments[GSFINAL]._size++;
546   }
547
548   // append xinit to gsfinal
549   from=xinitImage;
550   to = gsfinalImage + segments[GSFINAL].start + segments[GSFINAL]._size;
551   memcpy(to, from, segments[XINIT]._size);
552   segments[XINIT].start=segments[GSFINAL].start+segments[GSFINAL]._size;
553   segments[GSFINAL]._size += segments[XINIT]._size;
554   if (segments[GSFINAL]._size & 1) {
555     segments[GSFINAL]._size++;
556   }
557
558   // XISEG is located after XSEG
559   if (segments[XSEG].start & 1) {
560     fprintf (stderr, "*** warning: xdata doesn't start at "
561              "an even address: %04x\n", segments[XSEG].start);
562   }
563   if (segments[XSEG]._size & 1) {
564     segments[XSEG]._size++;
565   }
566   
567   segments[XISEG].start=segments[XSEG].start + 
568     segments[XSEG]._size;  
569
570   // now relocate the defined symbols
571   for (symbol=symbols; symbol; symbol=symbol->next) {
572     if (!symbol->absolute) {
573       symbol->address += symbol->segment->start;
574     }
575   }
576   // and the references
577   for (reference=references; reference; reference=reference->next) {
578     symbol=findSymbolByName(reference->name);
579     if (!reference->resolved && !symbol && reference->how!=ABS_PC) {
580       // this reference isn't resolved after all
581       fprintf (stderr, "*** %s:%d undefined symbol %s\n",
582                reference->module->name, reference->lineno,
583                reference->name);
584       fatalErrors++;
585     } else {
586       reference->address += 
587         reference->module->offset[reference->segment->id]+
588         reference->segment->start;
589       reference->pc += 
590         reference->module->offset[reference->segment->id]+
591         reference->segment->start;
592       switch (reference->how) 
593         {
594         case REL_FF: {
595           int rel8 = symbol->address-(reference->pc & ~1);
596           if (rel8<-256 || rel8>256) {
597             fprintf (stderr,
598                      "rel8 target for %s is out of range in module %s\n",
599                      reference->name, reference->module->name);
600             fatalErrors++;
601           }
602           gsfinalImage[reference->address]=rel8/2;
603           break;
604         }
605         case REL_FFFF: {
606           int rel16 = symbol->address-(reference->pc & ~1);
607           if (rel16<-65536 || rel16>65534) {
608             fprintf (stderr, 
609                      "rel16 target for %s is out of range in module %s\n",
610                      reference->name, reference->module->name);
611             fatalErrors++;
612           }
613           gsfinalImage[reference->address]=(rel16/2)>>8;
614           gsfinalImage[reference->address+1]=rel16/2;
615           break;
616         }
617         case DIR_70FF:
618           gsfinalImage[reference->address] = 
619             (gsfinalImage[reference->address]&~0x70) + 
620             ((symbol->address>>4)&0x70);
621           gsfinalImage[reference->address+1] = symbol->address;
622           break;
623         case ABS_FFFF:
624           gsfinalImage[reference->address] = symbol->address>>8;
625           gsfinalImage[reference->address+1] = symbol->address;
626           break;
627         case ABS_FF:
628           gsfinalImage[reference->address] = symbol->address;
629           break;
630         case ABS_PC: 
631           {
632             unsigned int address=
633               (gsfinalImage[reference->address]<<8) +
634               gsfinalImage[reference->address+1];
635             address += reference->module->offset[reference->segment->id];
636             address += segments[reference->segment->id].start;
637             gsfinalImage[reference->address] = address>>8;
638             gsfinalImage[reference->address+1] = address;
639           };
640           break;
641         default:
642           fprintf (stderr, "unsupported reference mode %d.\n",
643                    reference->how);
644           fatalErrors++;
645         }
646     }
647   }
648   return 0;
649 }
650
651 void usage (char * progName, int errNo) {
652   fprintf (stderr, "usage: %s lnkCmdFile\n", progName);
653   if (errNo) {
654     exit (errNo);
655   }
656 }
657
658 int scanLibraries(int unresolved) {
659   int resolved=0;
660   int nlp, nlf;
661   char libFiles[PATH_MAX];
662   char libFile[PATH_MAX];
663   char line[132];
664   char symName[132];
665   FILE *lf, *lfs;
666   
667   for (nlp=0; nlp<nlibPaths; nlp++) {
668     for (nlf=0; nlf<nlibFiles; nlf++) {
669       sprintf (libFiles, "%s/%s.lib", libraryPaths[nlp], libraryFiles[nlf]);
670       //fprintf (stderr, "  %s\n", libFiles);
671       if ((lfs=fopen(libFiles,"r"))==NULL) {
672         continue;
673       }
674       while (fgets(line, 132, lfs)) {
675         // remove trailing \n
676         line[strlen(line)-1]='\0';
677         sprintf (libFile, "%s/%s", libraryPaths[nlp], line);
678         //fprintf (stderr, "    %s\n", libFile);
679         if ((lf=fopen(libFile,"r"))==0) {
680           continue;
681         }
682         while (fgets(line, 132, lf)) {
683           int dummy; // we need this to get the right count of the next sscanf
684           if (sscanf(line, "S %[^ ] Def%04x", symName, &dummy)==2) {
685             if (isUnresolved(symName, 1)) {
686               //fprintf (stderr, "%s:%s\n", libFile, symName);
687               readModule(libFile,1);
688               if (resolved++ == unresolved) {
689                 // we are done
690                 return resolved;
691               }
692               // skip to next lib module
693               break;
694             }
695           }
696         }
697       }
698     }
699   }
700   return resolved;
701 }
702
703 int main(int argc, char **argv) {
704   FILE *linkCommandsFile;
705   char linkCommandsPath[PATH_MAX];
706   char linkCommand[PATH_MAX];
707   struct MODULE *module;
708   struct SYMBOL *symbol;
709   int s;
710   int unresolved;
711
712   if (argc!=2) {
713     usage(argv[0], 1);
714   }
715
716   // read in the commands
717   sprintf (linkCommandsPath, "%s.lnk", argv[1]);
718   if (!(linkCommandsFile=fopen(linkCommandsPath, "r"))) {
719     perror(linkCommandsPath);
720     exit(1);
721   }
722   while (fgets(linkCommand, PATH_MAX, linkCommandsFile)) {
723     linkCommand[strlen(linkCommand)-1]='\0';
724
725     // skip empty lines
726     if (!*linkCommand) {
727       continue;
728     }
729
730     //puts (linkCommand);
731     if (*linkCommand=='-') {
732       switch (linkCommand[1]) 
733         {
734         case 'm':
735           // probably -muxi, ignore for now
736           break;
737         case 'e':
738           // -e, always in the last line, ignore for now
739           break;
740         case 'b': 
741           {
742             // a segment start address like: "-b XSEG = 0x4000"
743             int s;
744             char *seg=strtok(&linkCommand[3], " \t");
745             for (s=0; s<MAX_SEGMENTS; s++) {
746               if (strcmp(segments[s].name, seg)==0) {
747                 strtok(NULL, " \t"); // skip the '='
748                 if (sscanf(strtok(NULL, " \t"), "%x", 
749                            &segments[s].start)!=1) {
750                   syntaxError(linkCommand);
751                 }
752                 break;
753               }
754             }
755             if (s==MAX_SEGMENTS) {
756               syntaxError(linkCommand);
757             }
758           }
759           break;
760         case 'k':
761           // a lib path like: "-k /usr/local/share/sdcc/lib/xa51"; one/line
762           libraryPaths[nlibPaths++]=strdup(&linkCommand[3]);
763           break;
764         case 'l':
765           // a lib file like: "-l libsdcc"; one/line
766           libraryFiles[nlibFiles++]=strdup(&linkCommand[3]);
767           break;
768         default:
769           syntaxError(linkCommand);
770         }
771     } else {
772       // not a switch, must be an inputfile; one/line
773       readModule(linkCommand, 0);
774       // the first one defines the output name
775       if (!outFileName[0]) {
776         strncpy(outFileName, linkCommand,
777                 strlen(linkCommand)-4);
778         sprintf(mapFileName, "%s.map", outFileName);
779         strcat(outFileName, ".hex");
780         if ((mapOut=fopen(mapFileName, "w"))==NULL) {
781           perror(mapFileName);
782         }
783       }
784     }
785   }
786
787   // add the segment symbols
788   currentSegment=findSegmentByName("XINIT");
789   addToDefs("s_XINIT", 0, 0);
790   addToDefs("l_XINIT", segments[XINIT]._size, 1);
791   currentSegment=findSegmentByName("XISEG");
792   addToDefs("s_XISEG", 0, 0);
793   addToDefs("l_XISEG", segments[XISEG]._size, 1);
794
795 #if 1
796   // mark the resolved references
797   resolve();
798
799   // now do something EXTREMELY SLOW AND INEFFICIENT :)
800   while ((unresolved=relocate())) {
801     if (!scanLibraries(unresolved)) {
802       struct REFERENCE *reference;
803       resolve();
804       for (reference=references; reference; reference=reference->next) {
805         if (!reference->resolved) {
806           fprintf (stderr, "*** unresolved symbol %s in %s:%d\n",
807                    reference->name, reference->module->name,
808                    reference->lineno);
809           fatalErrors++;
810         }
811       }
812       break;
813     }
814   }
815
816   if (unresolved==0) {
817     writeModule(outFileName);
818   }
819 #endif
820
821   // the modules
822   fprintf (mapOut, "Modules:\n");
823   for (module=modules; module; module=module->next) {
824     fprintf (mapOut, "\t%s\n", module->name);
825     for (s=0; s<MAX_SEGMENTS; s++) {
826       if (module->size[s]) {
827         fprintf (mapOut, "\t\t%s:0x%04x-0x%04x\n", segments[s].name,
828                  module->offset[s]+segments[s].start,
829                  module->offset[s]+segments[s].start+module->size[s]);
830       }
831     }
832   }
833
834   // the segments
835   fprintf (mapOut, "\nSegments:\n");
836   for (s=1; s<MAX_SEGMENTS; s++) {
837     if (segments[s]._size) {
838       fprintf (mapOut, "\t%s start 0x%04x size 0x%04x %d symbols\n",
839                segments[s].name, segments[s].start,
840                segments[s]._size, 
841                segments[s].hasSymbols);
842     }
843   }
844
845   // the symbols
846   fprintf (mapOut, "\nSymbols:\n");
847   for (symbol=symbols; symbol; symbol=symbol->next) {
848     fprintf (mapOut, "%s\t%s %s0x%04x %s\n", symbol->name, 
849              symbol->segment->name,
850              symbol->absolute ? "= " : "",
851              symbol->address, symbol->module->name);
852   }
853
854   fclose(mapOut);
855   return fatalErrors? 1 : 0;
856 }
857