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