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