Pick three bugfixes from next branch to trunk for inclusion in 4.5.0 RC2, as discusse...
[sdcc.git] / sdcc / sdas / xa51 / xa_link.c
bloba6823d246765f8272f394fb5266747832df3bc99
1 /* xa_link.c
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.
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.
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/>. */
16 /* WORK IN PROGRESS: do not watch this if you don't have the legal
17 age in your country to watch this.
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.
24 No hash or qsort yet.
26 The relocatable format looks like the known one, BUT ISN'T.
28 The only things that are handled now are:
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).
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.
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <limits.h>
51 #include <string.h>
53 #include "xa_version.h"
55 enum {
56 // these are all concatenated into the code image
57 GSINIT=1,
58 CSEG,
59 XINIT,
61 // here goes the final output and should be used by the assembler
62 GSFINAL,
64 // these are only for storage
65 BSEG,
66 DSEG,
67 XSEG,
68 XISEG,
70 // that's all
71 MAX_SEGMENTS
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
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"
102 #define CODESIZE 0x10000
104 int fatalErrors=0;
106 unsigned char gsinitImage[CODESIZE];
107 unsigned char csegImage[CODESIZE];
108 unsigned char xinitImage[CODESIZE];
109 unsigned char gsfinalImage[CODESIZE];
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},
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},
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},
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;
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;
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;
166 char *libraryPaths[128];
167 int nlibPaths=0;
168 char *libraryFiles[128];
169 int nlibFiles=0;
171 static char outFileName[PATH_MAX]={'\0'};
172 static char mapFileName[PATH_MAX]={'\0'};
173 FILE *mapOut;
175 struct SEGMENT *currentSegment;
176 struct MODULE *currentModule;
177 int currentLine;
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;
186 return 0;
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];
196 return 0;
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;
206 return 0;
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;
216 return NULL;
219 void addToModules (char *name, int isLib) {
220 struct MODULE *module;
221 int s;
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;
228 module->isLib=isLib;
229 if (!modules) {
230 modules=module;
231 } else {
232 modules->last->next=module;
234 currentModule=modules->last=module;
237 void addToRefs(char *ref, int address, char *how, int pc) {
238 struct REFERENCE *reference;
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;
250 reference->pc=pc;
251 if (!references) {
252 references=reference;
253 } else {
254 references->last->next=reference;
256 references->last=reference;
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;
268 int isUnresolved(char *ref, int resolved) {
269 struct REFERENCE *reference;
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;
278 if (resolved) {
279 reference->resolved=1;
280 return 1;
284 return 0;
287 void addToDefs(char *def, int address, char absolute) {
288 struct SYMBOL *symbol;
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++;
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;
311 symbols->last=symbol;
312 currentSegment->hasSymbols++;
315 void syntaxError (char *err) {
316 fprintf (stderr, "*** %s:%d error while parsing '%s'\n",
317 currentModule->name, currentLine, err);
318 fatalErrors++;
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;
328 currentLine=1;
330 if ((relModule=fopen(module, "r"))==NULL) {
331 perror (module);
332 exit (1);
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);
341 if (hisVersion!=version) {
342 fprintf (stderr, "*** WARNING: version conflict; "
343 "we(%1.1f) != %s(%1.1f)\n",
344 version, module, hisVersion);
346 currentLine++;
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);
354 currentLine++;
356 // M module
357 if (sscanf(fgets(line, 132, relModule),
358 "M %s", moduleName)!=1) {
359 syntaxError(line);
362 // add this to the known modules with current offsets
363 addToModules(module, isLib);
365 currentLine++;
367 // now for the ASTR tags
368 while (fgets(line, 132, relModule)) {
369 switch (line[0])
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);
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);
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++;
395 } else {
396 currentSegment->_size += size;
397 currentModule->size[currentSegment->id] = size;
399 // never mind about the flags for now
400 break;
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);
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);
424 break;
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);
437 if (sscanf(strtok(&line[2], " "), "%04x", &address)!=1) {
438 fprintf (stderr, "%s:%d error in T record\n", module, currentLine);
439 fatalErrors++;
442 address+=currentModule->offset[currentSegment->id];
443 //address+=currentSegment->current;
444 for ( ;
445 (tline=strtok(NULL, " \t\n")) &&
446 (sscanf(tline, "%02x", &byte)==1);
448 currentSegment->image[address++]=byte;
449 currentSegment->current++;
451 break;
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;
461 default:
462 fprintf (stderr, "%s:%d unknown record \"%s\"\n",
463 module, currentLine, line);
464 fatalErrors++;
465 break;
467 currentLine++;
469 fclose (relModule);
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;
479 if ((fOut=fopen(outFileName, "w"))==NULL) {
480 perror (outFileName);
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++]);
492 checksum &= 0xff;
493 if (checksum) {
494 checksum = 0x100 - checksum;
496 fprintf (fOut, "%02X\n", checksum);
498 fprintf (fOut, ":00000001FF\n");
500 fclose (fOut);
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;
512 // first check if it will fit
513 if (length > 0xffff) {
514 fprintf (stderr, "error: code segment exceeds 0xffff\n");
515 fatalErrors++;
518 // resolve reverences
519 for (reference=references; reference; reference=reference->next) {
520 if (!reference->resolved && !findSymbolByName(reference->name)) {
521 unresolved++;
524 if (unresolved) {
525 // first scan the libraries
526 return unresolved;
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);
535 segments[GSFINAL].start=segments[CSEG].start;
536 memset(gsfinalImage, 0xff, CODESIZE);
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++;
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++;
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++;
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);
573 if (segments[XSEG]._size & 1) {
574 segments[XSEG]._size++;
577 segments[XISEG].start=segments[XSEG].start +
578 segments[XSEG]._size;
580 // now relocate the defined symbols
581 for (symbol=symbols; symbol; symbol=symbol->next) {
582 if (!symbol->absolute) {
583 symbol->address += symbol->segment->start;
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)
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++;
613 gsfinalImage[reference->address]=rel8/2;
614 break;
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++;
625 gsfinalImage[reference->address]=(rel16/2)>>8;
626 gsfinalImage[reference->address+1]=rel16/2;
627 break;
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:
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;
652 break;
653 default:
654 fprintf (stderr, "unsupported reference mode %d.\n",
655 reference->how);
656 fatalErrors++;
660 return 0;
663 void usage (char * progName, int errNo) {
664 fprintf (stderr, "usage: %s lnkCmdFile\n", progName);
665 if (errNo) {
666 exit (errNo);
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;
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;
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;
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;
701 // skip to next lib module
702 break;
709 return resolved;
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;
721 if (argc!=2) {
722 usage(argv[0], 1);
725 // read in the commands
726 sprintf (linkCommandsPath, "%s.lnk", argv[1]);
727 if (!(linkCommandsFile=fopen(linkCommandsPath, "r"))) {
728 perror(linkCommandsPath);
729 exit(1);
731 while (fgets(linkCommand, PATH_MAX, linkCommandsFile)) {
732 linkCommand[strlen(linkCommand)-1]='\0';
734 // skip empty lines
735 if (!*linkCommand) {
736 continue;
739 //puts (linkCommand);
740 if (*linkCommand=='-') {
741 switch (linkCommand[1])
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':
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);
761 break;
764 if (s==MAX_SEGMENTS) {
765 syntaxError(linkCommand);
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);
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);
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);
804 // mark the resolved references
805 resolve();
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++;
820 break;
824 if (unresolved==0) {
825 writeModule(outFileName);
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]);
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);
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);
861 fclose(mapOut);
862 return fatalErrors? 1 : 0;