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