6eb90101b0f801635980904d17bae7322d58c0d0
[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;
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   fprintf (stderr, "writeModule: %s from 0x%04x to 0x%04x\n",
470            outFileName, 
471            address,
472            address+size);
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   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     
535   // append cseg to gsfinal
536   from=csegImage;
537   to = gsfinalImage + segments[GSFINAL].start + segments[GSFINAL]._size;
538   memcpy(to, from, segments[CSEG]._size);
539   segments[CSEG].start=segments[GSFINAL].start+segments[GSFINAL]._size;
540   segments[GSFINAL]._size += segments[CSEG]._size;
541
542   // append xinit to gsfinal
543   from=xinitImage;
544   to = gsfinalImage + segments[GSFINAL].start + segments[GSFINAL]._size;
545   memcpy(to, from, segments[XINIT]._size);
546   segments[XINIT].start=segments[GSFINAL].start+segments[GSFINAL]._size;
547   segments[GSFINAL]._size += segments[XINIT]._size;
548
549   // XISEG is located after XSEG
550   segments[XISEG].start=segments[XSEG].start + 
551     segments[XSEG]._size;  
552
553   // now relocate the defined symbols
554   for (symbol=symbols; symbol; symbol=symbol->next) {
555     if (!symbol->absolute) {
556       symbol->address += symbol->segment->start;
557     }
558   }
559   // and the references
560   for (reference=references; reference; reference=reference->next) {
561     symbol=findSymbolByName(reference->name);
562     if (!reference->resolved && !symbol && reference->how!=ABS_PC) {
563       // this reference isn't resolved after all
564       fprintf (stderr, "*** %s:%d undefined symbol %s\n",
565                reference->module->name, reference->lineno,
566                reference->name);
567       fatalErrors++;
568     } else {
569       reference->address += 
570         reference->module->offset[reference->segment->id]+
571         reference->segment->start;
572       reference->pc += 
573         reference->module->offset[reference->segment->id]+
574         reference->segment->start;
575       switch (reference->how) 
576         {
577         case REL_FF: {
578           int rel8 = symbol->address-(reference->pc & ~1);
579           if (rel8<-256 || rel8>256) {
580             fprintf (stderr,
581                      "rel8 target for %s is out of range in module %s\n",
582                      reference->name, reference->module->name);
583             fatalErrors++;
584           }
585           gsfinalImage[reference->address]=rel8/2;
586           break;
587         }
588         case REL_FFFF: {
589           int rel16 = symbol->address-(reference->pc & ~1);
590           if (rel16<-65536 || rel16>65534) {
591             fprintf (stderr, 
592                      "rel16 target for %s is out of range in module %s\n",
593                      reference->name, reference->module->name);
594             fatalErrors++;
595           }
596           gsfinalImage[reference->address]=(rel16/2)>>8;
597           gsfinalImage[reference->address+1]=rel16/2;
598           break;
599         }
600         case DIR_70FF:
601           gsfinalImage[reference->address] = (symbol->address<<4)&0x70;
602           gsfinalImage[reference->address+1] = symbol->address;
603           break;
604         case ABS_FFFF:
605           gsfinalImage[reference->address] = symbol->address>>8;
606           gsfinalImage[reference->address+1] = symbol->address;
607           break;
608         case ABS_FF:
609           gsfinalImage[reference->address] = symbol->address;
610           break;
611         case ABS_PC: 
612           {
613             unsigned int address=
614               (gsfinalImage[reference->address]<<8) +
615               gsfinalImage[reference->address+1];
616             address += reference->module->offset[reference->segment->id];
617             address += segments[reference->segment->id].start;
618             gsfinalImage[reference->address] = address>>8;
619             gsfinalImage[reference->address+1] = address;
620           };
621           break;
622         default:
623           fprintf (stderr, "unsupported reference mode %d.\n",
624                    reference->how);
625           fatalErrors++;
626         }
627     }
628   }
629   return 0;
630 }
631
632 void usage (char * progName, int errNo) {
633   fprintf (stderr, "usage: %s lnkCmdFile\n", progName);
634   if (errNo) {
635     exit (errNo);
636   }
637 }
638
639 int scanLibraries(int unresolved) {
640   int resolved=0;
641   int nlp, nlf;
642   char libFiles[PATH_MAX];
643   char libFile[PATH_MAX];
644   char line[132];
645   char symName[132];
646   FILE *lf, *lfs;
647   
648   for (nlp=0; nlp<nlibPaths; nlp++) {
649     for (nlf=0; nlf<nlibFiles; nlf++) {
650       sprintf (libFiles, "%s/%s.lib", libraryPaths[nlp], libraryFiles[nlf]);
651       //fprintf (stderr, "  %s\n", libFiles);
652       if ((lfs=fopen(libFiles,"r"))==NULL) {
653         continue;
654       }
655       while (fgets(line, 132, lfs)) {
656         // remove trailing \n
657         line[strlen(line)-1]='\0';
658         sprintf (libFile, "%s/%s", libraryPaths[nlp], line);
659         //fprintf (stderr, "    %s\n", libFile);
660         if ((lf=fopen(libFile,"r"))==0) {
661           continue;
662         }
663         while (fgets(line, 132, lf)) {
664           int dummy; // we need this to get the right count of the next sscanf
665           if (sscanf(line, "S %[^ ] Def%04x", symName, &dummy)==2) {
666             if (isUnresolved(symName, 1)) {
667               //fprintf (stderr, "%s:%s\n", libFile, symName);
668               readModule(libFile,1);
669               if (resolved++ == unresolved) {
670                 // we are done
671                 return resolved;
672               }
673               // skip to next lib module
674               break;
675             }
676           }
677         }
678       }
679     }
680   }
681   return resolved;
682 }
683
684 int main(int argc, char **argv) {
685   FILE *linkCommandsFile;
686   char linkCommandsPath[PATH_MAX];
687   char linkCommand[PATH_MAX];
688   struct MODULE *module;
689   struct SYMBOL *symbol;
690   int s;
691   int unresolved;
692
693   if (argc!=2) {
694     usage(argv[0], 1);
695   }
696
697   // read in the commands
698   sprintf (linkCommandsPath, "%s.lnk", argv[1]);
699   if (!(linkCommandsFile=fopen(linkCommandsPath, "r"))) {
700     perror(linkCommandsPath);
701     exit(1);
702   }
703   while (fgets(linkCommand, PATH_MAX, linkCommandsFile)) {
704     linkCommand[strlen(linkCommand)-1]='\0';
705
706     // skip empty lines
707     if (!*linkCommand) {
708       continue;
709     }
710
711     //puts (linkCommand);
712     if (*linkCommand=='-') {
713       switch (linkCommand[1]) 
714         {
715         case 'm':
716           // probably -muxi, ignore for now
717           break;
718         case 'e':
719           // -e, always in the last line, ignore for now
720           break;
721         case 'b': 
722           {
723             // a segment start address like: "-b XSEG = 0x4000"
724             int s;
725             char *seg=strtok(&linkCommand[3], " \t");
726             for (s=0; s<MAX_SEGMENTS; s++) {
727               if (strcmp(segments[s].name, seg)==0) {
728                 strtok(NULL, " \t"); // skip the '='
729                 if (sscanf(strtok(NULL, " \t"), "%x", 
730                            &segments[s].start)!=1) {
731                   syntaxError(linkCommand);
732                 }
733                 break;
734               }
735             }
736             if (s==MAX_SEGMENTS) {
737               syntaxError(linkCommand);
738             }
739           }
740           break;
741         case 'k':
742           // a lib path like: "-k /usr/local/share/sdcc/lib/xa51"; one/line
743           libraryPaths[nlibPaths++]=strdup(&linkCommand[3]);
744           break;
745         case 'l':
746           // a lib file like: "-l libsdcc"; one/line
747           libraryFiles[nlibFiles++]=strdup(&linkCommand[3]);
748           break;
749         default:
750           syntaxError(linkCommand);
751         }
752     } else {
753       // not a switch, must be an inputfile; one/line
754       readModule(linkCommand, 0);
755       // the first one defines the output name
756       if (!outFileName[0]) {
757         strncpy(outFileName, linkCommand,
758                 strlen(linkCommand)-4);
759         sprintf(mapFileName, "%s.map", outFileName);
760         strcat(outFileName, ".hex");
761         if ((mapOut=fopen(mapFileName, "w"))==NULL) {
762           perror(mapFileName);
763         }
764       }
765     }
766   }
767
768   // add the segment symbols
769   currentSegment=findSegmentByName("XINIT");
770   addToDefs("s_XINIT", 0, 0);
771   addToDefs("l_XINIT", segments[XINIT]._size, 1);
772   currentSegment=findSegmentByName("XISEG");
773   addToDefs("s_XISEG", 0, 0);
774   addToDefs("l_XISEG", segments[XISEG]._size, 1);
775
776 #if 1
777   // mark the resolved references
778   resolve();
779
780   // now do something EXTREMELY SLOW AND INEFFICIENT :)
781   while ((unresolved=relocate())) {
782     if (!scanLibraries(unresolved)) {
783       struct REFERENCE *reference;
784       resolve();
785       for (reference=references; reference; reference=reference->next) {
786         if (!reference->resolved) {
787           fprintf (stderr, "*** unresolved symbol %s in %s:%d\n",
788                    reference->name, reference->module->name,
789                    reference->lineno);
790           fatalErrors++;
791         }
792       }
793       break;
794     }
795   }
796
797   if (unresolved==0) {
798     writeModule(outFileName);
799   }
800 #endif
801
802   // the modules
803   fprintf (mapOut, "Modules:\n");
804   for (module=modules; module; module=module->next) {
805     fprintf (mapOut, "\t%s\n", module->name);
806     for (s=0; s<MAX_SEGMENTS; s++) {
807       if (module->size[s]) {
808         fprintf (mapOut, "\t\t%s:0x%04x-0x%04x\n", segments[s].name,
809                  module->offset[s]+segments[s].start,
810                  module->offset[s]+segments[s].start+module->size[s]);
811       }
812     }
813   }
814
815   // the segments
816   fprintf (mapOut, "\nSegments:\n");
817   for (s=1; s<MAX_SEGMENTS; s++) {
818     if (segments[s]._size) {
819       fprintf (mapOut, "\t%s start 0x%04x size 0x%04x %d symbols\n",
820                segments[s].name, segments[s].start,
821                segments[s]._size, 
822                segments[s].hasSymbols);
823     }
824   }
825
826   // the symbols
827   fprintf (mapOut, "\nSymbols:\n");
828   for (symbol=symbols; symbol; symbol=symbol->next) {
829     fprintf (mapOut, "%s\t%s %s0x%04x %s\n", symbol->name, 
830              symbol->segment->name,
831              symbol->absolute ? "= " : "",
832              symbol->address, symbol->module->name);
833   }
834
835   fclose(mapOut);
836   return fatalErrors? 1 : 0;
837 }
838