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