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