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