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