Fix for bug #78: Thanks to ggn for reporting and supplying the patch.
[rmac] / sect.c
1 //
2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // SECT.C - Code Generation, Fixups and Section Management
4 // Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source utilised with the kind permission of Landon Dyer
7 //
8
9 #include "sect.h"
10 #include "direct.h"
11 #include "error.h"
12 #include "expr.h"
13 #include "listing.h"
14 #include "mach.h"
15 #include "mark.h"
16 #include "riscasm.h"
17 #include "symbol.h"
18 #include "token.h"
19
20
21 // Function prototypes
22 void MakeSection(int, WORD);
23 void SwitchSection(int);
24
25 // Section descriptors
26 SECT sect[NSECTS];              // All sections... 
27 int cursect;                    // Current section number
28
29 // These are copied from the section descriptor, the current code chunk
30 // descriptor and the current fixup chunk descriptor when a switch is made into
31 // a section.  They are copied back to the descriptors when the section is left.
32 WORD scattr;                    // Section attributes 
33 LONG sloc;                              // Current loc in section 
34
35 CHUNK * scode;                  // Current (last) code chunk 
36 LONG challoc;                   // # bytes alloc'd to code chunk 
37 LONG ch_size;                   // # bytes used in code chunk 
38 char * chptr;                   // Deposit point in code chunk buffer 
39 char * chptr_opcode;    // Backup of chptr, updated before entering code generators
40
41 CHUNK * sfix;                   // Current (last) fixup chunk
42 LONG fchalloc;                  // # bytes alloc'd to fixup chunk
43 LONG fchsize;                   // # bytes used in fixup chunk
44 PTR fchptr;                             // Deposit point in fixup chunk buffer
45
46 // Return a size (SIZB, SIZW, SIZL) or 0, depending on what kind of fixup is
47 // associated with a location.
48 static char fusiztab[] = {
49    0,   // FU_QUICK
50    1,   // FU_BYTE
51    2,   // FU_WORD
52    2,   // FU_WBYTE
53    4,   // FU_LONG
54    1,   // FU_BBRA
55    0,   // (unused)
56    1,   // FU_6BRA
57 };
58
59 // Offset to REAL fixup location
60 static char fusizoffs[] = {
61    0,   // FU_QUICK
62    0,   // FU_BYTE
63    0,   // FU_WORD
64    1,   // FU_WBYTE
65    0,   // FU_LONG
66    1,   // FU_BBRA
67    0,   // (unused)
68    0,   // FU_6BRA
69 };
70
71
72 //
73 // Initialize sections; setup initial ABS, TEXT, DATA and BSS sections
74 //
75 void InitSection(void)
76 {
77         int i;
78
79         // Cleanup all sections
80         for(i=0; i<NSECTS; i++)
81                 MakeSection(i, 0);
82
83         // Construct default sections, make TEXT the current section
84         MakeSection(ABS,  SUSED | SABS | SBSS);         // ABS
85         MakeSection(TEXT, SUSED | TEXT       );         // TEXT
86         MakeSection(DATA, SUSED | DATA       );         // DATA
87         MakeSection(BSS,  SUSED | BSS  | SBSS);         // BSS
88 //      MakeSection(M6502, SUSED | TEXT       );                // 6502 code section
89
90         // Switch to TEXT for starters
91         SwitchSection(TEXT);
92 }
93
94
95 //
96 // Make a new (clean) section
97 //
98 void MakeSection(int sno, WORD attr)
99 {
100         SECT * p = &sect[sno];
101         p->scattr = attr;
102         p->sloc = 0;
103         p->scode = p->sfcode = NULL;
104         p->sfix = p->sffix = NULL;
105 }
106
107
108 //
109 // Switch to another section (copy section & chunk descriptors to global vars
110 // for fast access)
111 //
112 void SwitchSection(int sno)
113 {
114         CHUNK * cp;
115         cursect = sno;
116         SECT * p = &sect[sno];
117
118         // Copy section vars
119         scattr = p->scattr;
120         sloc = p->sloc;
121         scode = p->scode;
122         sfix = p->sfix;
123
124         // Copy code chunk vars
125         if ((cp = scode) != NULL)
126         {
127                 challoc = cp->challoc;
128                 ch_size = cp->ch_size;
129                 chptr = cp->chptr + ch_size;
130         }
131         else
132                 challoc = ch_size = 0;
133
134         // Copy fixup chunk vars 
135         if ((cp = sfix) != NULL)
136         {
137                 fchalloc = cp->challoc;
138                 fchsize = cp->ch_size;
139                 fchptr.cp = cp->chptr + fchsize;
140         }
141         else
142                 fchalloc = fchsize = 0;
143 }
144
145
146 //
147 // Save current section
148 //
149 void SaveSection(void)
150 {
151         SECT * p = &sect[cursect];
152
153         p->scattr = scattr;                                             // Bailout section vars
154         p->sloc = sloc;
155
156         if (scode != NULL)                                              // Bailout code chunk
157                 scode->ch_size = ch_size;
158
159         if (sfix != NULL)                                               // Bailout fixup chunk
160                 sfix->ch_size = fchsize;
161 }
162
163
164 //
165 // Test to see if a location has a fixup sic'd on it.  This is used by the
166 // listing generator to print 'xx's instead of '00's for forward references
167 //
168 int fixtest(int sno, LONG loc)
169 {
170         CHUNK * ch;
171         PTR fup;
172         char * fuend;
173         WORD w;
174         LONG xloc;
175
176         // Force update to sect[] variables
177         StopMark();
178
179         // Hairy, ugly linear search for a mark on our location; the speed doesn't
180         // matter, since this is only done when generating a listing, which is
181         // SLOW.
182         for(ch=sect[sno].sffix; ch!=NULL; ch=ch->chnext)
183         {
184                 fup.cp = (char *)ch->chptr;
185                 fuend = fup.cp + ch->ch_size;
186
187                 while (fup.cp < fuend)
188                 {
189                         w = *fup.wp++;
190                         xloc = *fup.lp++ + (int)fusizoffs[w & FUMASK];
191                         fup.wp += 2;
192
193                         if (xloc == loc)
194                                 return (int)fusiztab[w & FUMASK];
195
196                         if (w & FU_EXPR)
197                         {
198                                 w = *fup.wp++;
199                                 fup.lp += w;
200                         }
201                         else
202                                 fup.lp++;
203                 }
204         }
205
206         return 0;
207 }
208
209
210 // 
211 // Check that there are at least 'amt' bytes left in the current chunk. If
212 // there are not, allocate another chunk of at least 'amt' bytes (and probably
213 // more).
214 // 
215 // If 'amt' is zero, ensure there are at least CH_THRESHOLD bytes, likewise.
216 //
217 int chcheck(LONG amt)
218 {
219         DEBUG { printf("chcheck(%u)\n", amt); }
220         // If in BSS section, no allocation required
221         if (scattr & SBSS)
222                 return 0;
223
224         if (!amt)
225                 amt = CH_THRESHOLD;
226
227         DEBUG { printf("    challoc=%i, ch_size=%i, diff=%i\n", challoc, ch_size, challoc-ch_size); }
228         if ((int)(challoc - ch_size) >= (int)amt) 
229                 return 0;
230
231         if (amt < CH_CODE_SIZE)
232                 amt = CH_CODE_SIZE;
233
234         DEBUG { printf("    amt (adjusted)=%u\n", amt); }
235         SECT * p = &sect[cursect];
236         CHUNK * cp = malloc(sizeof(CHUNK) + amt);
237
238         // First chunk in section
239         if (scode == NULL)
240         {
241                 cp->chprev = NULL;
242                 p->sfcode = cp;
243         }
244         // Add chunk to other chunks
245         else
246         {
247                 cp->chprev = scode;
248                 scode->chnext = cp;
249                 scode->ch_size = ch_size;                       // Save old chunk's globals 
250         }
251
252         // Setup chunk and global vars
253         cp->chloc = sloc;
254         cp->chnext = NULL;
255         challoc = cp->challoc = amt;
256         ch_size = cp->ch_size = 0;
257         chptr = cp->chptr = ((char *)cp) + sizeof(CHUNK);
258         scode = p->scode = cp;
259
260         return 0;
261 }
262
263
264 // This is really wrong. We need to make some proper structures here so we
265 // don't have to count sizes of objects, that's what the compiler's for! :-P
266 #define FIXUP_BASE_SIZE (sizeof(WORD) + sizeof(LONG) + sizeof(WORD) + sizeof(WORD))
267 //
268 // Arrange for a fixup on a location
269 //
270 int AddFixup(WORD attr, LONG loc, TOKEN * fexpr)
271 {
272         LONG i;
273         LONG len = 0;
274         CHUNK * cp;
275         SECT * p;
276         // Shamus: Expression lengths are voodoo ATM (variable "i"). Need to fix
277         //         this.
278 WARNING(!!! AddFixup() is filled with VOODOO !!!)
279         DEBUG printf("FIXUP@$%X: $%X\n", loc, attr);
280
281         // Compute length of expression (could be faster); determine if it's the
282         // single-symbol case; no expression if it's just a mark. This code assumes
283         // 16 bit WORDs and 32 bit LONGs
284         if (*fexpr == SYMBOL && fexpr[2] == ENDEXPR)
285         {
286                 // Just a single symbol
287                 // SCPCD : correct bit mask for attr (else other FU_xxx will match) 
288                 // NYAN !
289                 if ((attr & FUMASKRISC) == FU_JR)
290                 {
291 //printf("AddFixup: ((attr & FUMASKRISC) == FU_JR)\n");
292 //                      i = 18;
293 //                      i = FIXUP_BASE_SIZE + (sizeof(LONG) * 2);
294                         i = FIXUP_BASE_SIZE + sizeof(SYM *) + sizeof(LONG);
295                 }
296                 else
297                 {
298 //printf("AddFixup: ((attr & FUMASKRISC) == FU_JR) ELSE\n");
299 //                      i = 14;
300                         i = FIXUP_BASE_SIZE + sizeof(SYM *);
301                 }
302         }
303         else
304         {
305 //printf("AddFixup: !SYMBOL\n");
306                 attr |= FU_EXPR;
307
308                 for(len=0; fexpr[len]!=ENDEXPR; len++)
309                 {
310                         if (fexpr[len] == CONST || fexpr[len] == SYMBOL)
311                                 len++;
312                 }
313
314                 len++;                                                          // Add 1 for ENDEXPR 
315 //              i = (len << 2) + 12;
316                 i = FIXUP_BASE_SIZE + sizeof(WORD) + (len * sizeof(TOKEN));
317         }
318
319         // Alloc another fixup chunk for this one to fit in if necessary
320         if ((fchalloc - fchsize) < i)
321         {
322                 p = &sect[cursect];
323                 cp = (CHUNK *)malloc(sizeof(CHUNK) + CH_FIXUP_SIZE);
324
325                 // First fixup chunk in section
326                 if (sfix == NULL)
327                 {
328                         cp->chprev = NULL;
329                         p->sffix = cp;
330                 }
331                 // Add to other chunks
332                 else
333                 {
334                         cp->chprev = sfix;
335                         sfix->chnext = cp;
336                         sfix->ch_size = fchsize;
337                 }
338
339                 // Setup fixup chunk and its global vars
340                 cp->chnext = NULL;
341                 fchalloc = cp->challoc = CH_FIXUP_SIZE;
342                 fchsize = cp->ch_size = 0;
343                 fchptr.cp = cp->chptr = ((char *)cp) + sizeof(CHUNK);
344                 sfix = p->sfix = cp;
345         }
346
347         // Record fixup type, fixup location, and the file number and line number
348         // the fixup is located at.
349         *fchptr.wp++ = attr;
350         *fchptr.lp++ = loc;
351         *fchptr.wp++ = cfileno;
352         *fchptr.wp++ = (WORD)curlineno;
353
354         // Store postfix expression or pointer to a single symbol, or nothing for a
355         // mark.
356         if (attr & FU_EXPR)
357         {
358                 *fchptr.wp++ = (WORD)len;
359
360                 while (len--)
361                         *fchptr.lp++ = (LONG)*fexpr++;
362         }
363         else
364         {
365 //              *fchptr.lp++ = (LONG)fexpr[1];
366                 *fchptr.sy++ = symbolPtr[fexpr[1]];
367 //printf("AddFixup: adding symbol (%s) [%08X]\n", symbolPtr[fexpr[1]]->sname, symbolPtr[fexpr[1]]->sattr);
368         }
369
370         // SCPCD : correct bit mask for attr (else other FU_xxx will match) NYAN !
371         if ((attr & FUMASKRISC) == FU_JR)
372         {
373                 if (orgactive)
374                         *fchptr.lp++ = orgaddr;
375                 else
376                         *fchptr.lp++ = 0x00000000;
377         }
378
379         fchsize += i;
380         return 0;
381 }
382
383
384 //
385 // Resolve fixups in a section
386 //
387 int ResolveFixups(int sno)
388 {
389         PTR fup;                                // Current fixup
390         WORD * fuend;                   // End of last fixup (in this chunk)
391         WORD w;                                 // Fixup word (type+modes+flags)
392         char * locp;                    // Location to fix (in cached chunk) 
393         LONG loc;                               // Location to fixup
394         VALUE eval;                             // Expression value 
395         WORD eattr;                             // Expression attrib
396         SYM * esym;                             // External symbol involved in expr
397         SYM * sy;                               // (Temp) pointer to a symbol
398         WORD i;                                 // (Temp) word
399         WORD tdb;                               // eattr & TDB
400         LONG oaddr;
401         int reg2;
402         WORD flags;
403         unsigned page_jump = 0;
404         unsigned address = 0;
405         //unsigned j;
406         //char buf[EBUFSIZ];
407         
408         SECT * sc = &sect[sno];
409         CHUNK * ch = sc->sffix;
410
411         if (ch == NULL)
412                 return 0;
413
414         // "Cache" first chunk
415         CHUNK * cch = sc->sfcode;
416
417         // Can't fixup a section with nothing in it
418         if (cch == NULL)
419                 return 0;
420
421         do
422         {
423                 fup.cp = ch->chptr;                                     // fup -> start of chunk
424                 fuend = (WORD *)(fup.cp + ch->ch_size); // fuend -> end of chunk
425
426                 while (fup.wp < fuend)
427                 {
428                         w = *fup.wp++;
429                         loc = *fup.lp++;
430                         cfileno = *fup.wp++;
431                         curlineno = (int)*fup.wp++;
432 DEBUG { printf("ResolveFixups: cfileno=%u\n", cfileno); }
433                         // This is based on global vars cfileno, curfname :-P
434                         // This approach is kinda meh as well. I think we can do better than this.
435                         SetFilenameForErrorReporting();
436
437                         esym = NULL;
438
439                         // Search for chunk containing location to fix up; compute a
440                         // pointer to the location (in the chunk). Often we will find the
441                         // fixup is in the "cached" chunk, so the linear-search is seldom
442                         // executed.
443                         if (loc < cch->chloc || loc >= (cch->chloc + cch->ch_size))
444                         {
445                                 for(cch=sc->sfcode; cch!=NULL; cch=cch->chnext)
446                                 {
447                                         if (loc >= cch->chloc && loc < (cch->chloc + cch->ch_size))
448                                                 break;
449                                 }
450
451                                 if (cch == NULL)
452                                 {
453                                         // Fixup (loc) out of range 
454                                         interror(7);
455                                         // NOTREACHED
456                                 }
457                         }
458
459                         locp = cch->chptr + (loc - cch->chloc);
460                         eattr = 0;
461
462                         // Compute expression/symbol value and attribs
463                         // Complex expression
464                         if (w & FU_EXPR)
465                         {
466                                 i = *fup.wp++;
467
468                                 if (evexpr(fup.tk, &eval, &eattr, &esym) != OK)
469                                 {
470                                         fup.lp += i;
471                                         continue;
472                                 }
473
474                                 fup.lp += i;
475                         }
476                         // Simple symbol
477                         else
478                         {
479                                 sy = *fup.sy++;
480                                 eattr = sy->sattr;
481
482                                 if (eattr & DEFINED)
483                                         eval = sy->svalue;
484                                 else
485                                         eval = 0;
486
487                                 if ((eattr & (GLOBAL | DEFINED)) == GLOBAL)
488                                         esym = sy;
489                         }
490
491                         tdb = (WORD)(eattr & TDB);
492
493                         // If the expression is undefined and no external symbol is
494                         // involved, then it's an error.
495                         if (!(eattr & DEFINED) && (esym == NULL))
496                         {
497                                 error(undef_error);
498                                 continue;
499                         }
500
501 // It seems that this is completely unnecessary!
502 #if 0
503                         if (((w & FUMASKRISC) == FU_MOVEI) && esym)
504 //{
505 //printf("DoFixups: Setting symbol attre to RISCSYM...\n");
506                                 esym->sattre |= RISCSYM;
507 //}
508 #endif
509
510                         // Do the fixup
511                         // 
512                         // If a PC-relative fixup is undefined, its value is *not*
513                         // subtracted from the location (that will happen in the linker
514                         // when the external reference is resolved).
515                         // 
516                         // MWC expects PC-relative things to have the LOC subtracted from
517                         // the value, if the value is external (that is, undefined at this
518                         // point).
519                         // 
520                         // PC-relative fixups must be DEFINED and either in the same
521                         // section (whereupon the subtraction takes place) or ABS (with no
522                         // subtract).
523                         if (w & FU_PCREL)
524                         {
525                                 if (eattr & DEFINED)
526                                 {
527                                         if (tdb == sno)
528                                                 eval -= (VALUE)loc;
529                                         else if (tdb)
530                                         {
531                                                 error("PC-relative expr across sections");
532                                                 continue;
533                                         }
534
535                                         if (sbra_flag && (w & FU_LBRA) && (eval + 0x80 < 0x100))
536                                                 warn("unoptimized short branch");
537                                 }
538                                 else if (obj_format == MWC)
539                                         eval -= (VALUE)loc;
540
541                                 tdb = 0;
542                                 eattr &= ~TDB;
543                         }
544
545                         // Do fixup classes
546                         switch ((int)(w & FUMASK))
547                         {
548                         // FU_BBRA fixes up a one-byte branch offset.
549                         case FU_BBRA:
550                                 if (!(eattr & DEFINED))
551                                 {
552                                         error("external short branch");
553                                         continue;
554                                 }
555
556                                 eval -= 2;
557
558                                 if (eval + 0x80 >= 0x100)
559                                         goto range;
560
561                                 if (eval == 0)
562                                 {
563                                         error("illegal bra.s with zero offset");
564                                         continue;
565                                 }
566
567                                 *++locp = (char)eval;
568                                 break;
569                         // Fixup one-byte value at locp + 1.
570                         case FU_WBYTE:
571                                 locp++;
572                                 // FALLTHROUGH
573                         // Fixup one-byte forward references
574                         case FU_BYTE:
575                                 if (!(eattr & DEFINED))
576                                 {
577                                         error("external byte reference");
578                                         continue;
579                                 }
580
581                                 if (tdb)
582                                 {
583                                         error("non-absolute byte reference");
584                                         continue;
585                                 }
586
587                                 if ((w & FU_PCREL) && eval + 0x80 >= 0x100)
588                                         goto range;
589
590                                 if (w & FU_SEXT)
591                                 {
592                                         if (eval + 0x100 >= 0x200)
593                                                 goto range;
594                                 }
595                                 else if (eval >= 0x100)
596                                         goto range;
597
598                                 *locp = (char)eval;
599                                 break;
600                         // Fixup WORD forward references; 
601                         // the word could be unaligned in the section buffer, so we have to
602                         // be careful.
603                         case FU_WORD:
604                                 if ((w & FUMASKRISC) == FU_JR)// || ((w & 0x0F00) == FU_MJR))
605                                 {
606                                         oaddr = *fup.lp++;
607
608                                         if (oaddr)
609                                                 reg2 = (signed)((eval - (oaddr + 2)) / 2);// & 0x1F;
610                                         else
611                                                 reg2 = (signed)((eval - (loc + 2)) / 2);// & 0x1F;
612
613                                         if ((reg2 < -16) || (reg2 > 15))
614                                         {
615                                                 error("relative jump out of range");
616                                                 break;
617                                         }
618
619                                         *locp = (char)(*locp | ((reg2 >> 3) & 0x03));
620                                         locp++;
621                                         *locp = (char)(*locp | ((reg2 & 0x07) << 5));
622                                         break;
623                                 }
624
625                                 if ((w & FUMASKRISC) == FU_NUM15)
626                                 {
627                                         if (eval < -16 || eval > 15)
628                                         {
629                                                 error("constant out of range");
630                                                 break;
631                                         }
632
633                                         *locp = (char)(*locp | ((eval >> 3) & 0x03));
634                                         locp++;
635                                         *locp = (char)(*locp | ((eval & 0x07) << 5));
636                                         break;
637                                 }
638
639                                 if ((w & FUMASKRISC) == FU_NUM31)
640                                 {
641                                         if (eval < 0 || eval > 31)
642                                         {
643                                                 error("constant out of range");
644                                                 break;
645                                         }
646
647                                         *locp = (char)(*locp | ((eval >> 3) & 0x03));
648                                         locp++;
649                                         *locp = (char)(*locp | ((eval & 0x07) << 5));
650                                         break;
651                                 }
652
653                                 if ((w & FUMASKRISC) == FU_NUM32)
654                                 {
655                                         if (eval < 1 || eval > 32)
656                                         {
657                                                 error("constant out of range");
658                                                 break;
659                                         }
660
661                                         if (w & FU_SUB32)
662                                                 eval = (32 - eval);
663
664                                         eval = (eval == 32) ? 0 : eval;
665                                         *locp = (char)(*locp | ((eval >> 3) & 0x03));
666                                         locp++;
667                                         *locp = (char)(*locp | ((eval & 0x07) << 5));
668                                         break;
669                                 }
670
671                                 if ((w & FUMASKRISC) == FU_REGONE)
672                                 {
673                                         if (eval < 0 || eval > 31)
674                                         {
675                                                 error("register value out of range");
676                                                 break;
677                                         }
678
679                                         *locp = (char)(*locp | ((eval >> 3) & 0x03));
680                                         locp++;
681                                         *locp = (char)(*locp | ((eval & 0x07) << 5));
682                                         break;
683                                 }
684
685                                 if ((w & FUMASKRISC) == FU_REGTWO)
686                                 {
687                                         if (eval < 0 || eval > 31)
688                                         {
689                                                 error("register value out of range");
690                                                 break;
691                                         }
692
693                                         locp++;
694                                         *locp = (char)(*locp | (eval & 0x1F));
695                                         break;
696                                 }
697
698                                 if (!(eattr & DEFINED))
699                                 {
700                                         if (w & FU_PCREL)
701                                                 w = MPCREL | MWORD;
702                                         else
703                                                 w = MWORD;
704
705                                         rmark(sno, loc, 0, w, esym);
706                                 }
707                                 else
708                                 {
709                                         if (tdb)
710                                                 rmark(sno, loc, tdb, MWORD, NULL);
711
712                                         if (w & FU_SEXT)
713                                         {
714                                                 if (eval + 0x10000 >= 0x20000)
715                                                         goto range;
716                                         }
717                                         else
718                                         {
719                                                 // Range-check BRA and DBRA
720                                                 if (w & FU_ISBRA)
721                                                 {
722                                                         if (eval + 0x8000 >= 0x10000)
723                                                         goto range;
724                                                 }
725                                                 else if (eval >= 0x10000)
726                                                         goto range;
727                                         }
728                                 }
729
730                                 *locp++ = (char)(eval >> 8);
731                                 *locp = (char)eval;
732                                 break;
733                         // Fixup LONG forward references;
734                         // the long could be unaligned in the section buffer, so be careful
735                         // (again).
736                         case FU_LONG:
737                                 if ((w & FUMASKRISC) == FU_MOVEI)
738                                 {
739                                         // Long constant in MOVEI # is word-swapped, so fix it here
740                                         eval = ((eval >> 16) & 0x0000FFFF) | ((eval << 16) & 0xFFFF0000);
741                                         flags = (MLONG | MMOVEI);
742                                 }
743                                 else
744                                         flags = MLONG;
745
746                                 if (!(eattr & DEFINED))
747                                 {
748 //printf("Fixup (long): Symbol undefined. loc = $%X, long = $%X, flags = $%x\n", loc, eval, flags);
749                                         rmark(sno, loc, 0, flags, esym);
750                                 }
751                                 else if (tdb)
752                                 {
753 //printf("Fixup (long): TDB = $%X. loc =$%X, long = $%X, flags = $%x\n", tdb, loc, eval, flags);
754                                         rmark(sno, loc, tdb, flags, NULL);
755                                 }
756 //else
757 //printf("Fixup (long): TDB = $%X. loc =$%X, long = $%X, flags = $%x\n", tdb, loc, eval, flags);
758
759                                 *locp++ = (char)(eval >> 24);
760                                 *locp++ = (char)(eval >> 16);
761                                 *locp++ = (char)(eval >> 8);
762                                 *locp = (char)eval;
763                                 break;
764
765                         // Fixup a 3-bit "QUICK" reference in bits 9..1
766                         // (range of 1..8) in a word.  Really bits 1..3 in a byte.
767                         case FU_QUICK:
768                                 if (!(eattr & DEFINED))
769                                 {
770                                         error("External quick reference");
771                                         continue;
772                                 }
773
774                                 if (eval < 1 || eval > 8)
775                                         goto range;
776
777                                 *locp |= (eval & 7) << 1;
778                                 break;
779
780                         // Fix up 6502 funny branch
781                         case FU_6BRA:
782                                 eval -= (loc + 1);
783
784                                 if (eval + 0x80 >= 0x100)
785                                         goto range;
786
787                                 *locp = (char)eval;
788                                 break;
789
790                         default:
791                                 // Bad fixup type--this should *never* happen!
792                                 interror(4);
793                                 // NOTREACHED
794                         }
795                         continue;
796 range:
797                         error("expression out of range");
798                 }
799
800                 ch = ch->chnext;
801         }
802         while (ch != NULL);
803
804         return 0;
805 }
806
807 //
808 // Resolve all fixups
809 //
810 int ResolveAllFixups(void)
811 {
812         //unsigned i;
813         //char buf[EBUFSIZ];
814
815         // Make undefined symbols GLOBL
816         if (glob_flag)
817                 ForceUndefinedSymbolsGlobal();
818
819         DEBUG printf("Resolving TEXT sections...\n");
820         ResolveFixups(TEXT);
821         DEBUG printf("Resolving DATA sections...\n");
822         ResolveFixups(DATA);
823
824         return 0;
825 }
826
827