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