2 // RMAC - Renamed Macro Assembler for all Atari computers
3 // MARK.C - A record of things that are defined relative to any of the sections
4 // Copyright (C) 199x Landon Dyer, 2011-2021 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
16 #define MARK_ALLOC_INCR 1024 // # bytes to alloc for more mark space
17 #define MIN_MARK_MEM (3 * sizeof(uint16_t) + 1 * sizeof(uint32_t) + sizeof(SYM *))
19 MCHUNK * firstmch; // First mark chunk
20 MCHUNK * curmch; // Current mark chunk
21 PTR markptr; // Deposit point in current mark chunk
22 uint32_t mcalloc; // # bytes alloc'd to current mark chunk
23 uint32_t mcused; // # bytes used in current mark chunk
24 uint16_t curfrom; // Current "from" section
26 // Table to convert from TDB to fixup triad
27 static uint8_t mark_tr[] = {
29 2, // TEXT relocatable
30 1, 0, // DATA relocatable
34 //#define DEBUG_IMAGE_MARKING
42 firstmch = curmch = NULL;
45 sect[TEXT].relocs = sect[DATA].relocs = sect[BSS].relocs = 0;
50 // Wrap up marker (called after final mark is made)
56 *markptr.wp = MCHEND; // Mark end of block
57 curmch->mcused = mcused; // Update # used in mark block
63 // Mark a word or longword as relocatable
65 // Record is either 2, 3, or 4 pieces of data long. A mark is of the form:
66 // .W <to+flags> section mark is relative to, and flags in upper byte
67 // .L <loc> location of mark in "from" section
68 // .W [from] new from section (if different from current)
69 // .L [symbol] symbol involved in external reference (if any)
71 uint32_t MarkRelocatable(uint16_t section, uint32_t loc, uint16_t to, uint16_t flags, SYM * symbol)
73 #ifdef DEBUG_IMAGE_MARKING
74 printf("MarkRelocatable: section=%i, loc=$%X, to=$%X, flags=$%x, symbol=%p\n", section, loc, to, flags, symbol);
76 printf(" symbol->stype=$%02X, sattr=$%04X, sattre=$%08X, svalue=%li, sname=%s\n", symbol->stype, symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
79 if ((mcalloc - mcused) < MIN_MARK_MEM)
85 if (section != curfrom)
92 // Complain about some things are not allowed in '-p' (PRG) mode:
93 // o Marks that aren't to LONGs
94 // o External references
99 error("illegal external reference (in .PRG mode) to '%s'",
103 // Dump crap into the mark
104 *markptr.wp++ = flags;
106 mcused += sizeof(uint16_t) + sizeof(uint32_t);
111 *markptr.wp++ = section;
112 mcused += sizeof(uint16_t);
117 *markptr.sy++ = symbol;
118 mcused += sizeof(SYM *);
121 // Increment # of relocs in this section
122 sect[section].relocs++;
124 // Not sure what this is about (making sure the next mark is clear until
125 // it's marked as the end--I think)...
126 *markptr.wp = 0x0000;
133 // Allocate another chunk of mark space
135 uint32_t AllocateMark(void)
137 // Alloc mark block header (and data) and set it up.
138 MCHUNK * p = malloc(sizeof(MCHUNK) + MARK_ALLOC_INCR);
140 p->mcalloc = MARK_ALLOC_INCR;
141 p->mcptr.cp = (uint8_t *)p + sizeof(MCHUNK);
144 if (firstmch == NULL)
149 // Link onto previous chunk
150 *markptr.wp++ = MCHEND; // Mark end of block
151 curmch->mcused = mcused;
158 mcalloc = MARK_ALLOC_INCR;
166 // Make mark image for Alcyon .o file
167 // okflag: 1, ok to deposit reloc information
169 uint32_t MarkImage(register uint8_t * mp, uint32_t siz, uint32_t tsize, int okflag)
171 uint16_t from = 0; // Section fixups are currently FROM
172 uint32_t loc; // Location (temp)
173 uint32_t lastloc; // Last location fixed up (RELMOD)
174 uint8_t * wp; // Pointer into raw relocation information
175 register uint8_t * dp; // Deposit point for RELMOD information
178 memset(mp, 0, siz); // zero relocation buffer
180 for(MCHUNK * mch=firstmch; mch!=NULL; mch=mch->mcnext)
182 for(PTR p=mch->mcptr;;)
184 uint16_t w = *p.wp++;// w = next mark entry
186 if (w & MCHEND) // (end of mark chunk)
191 loc = *p.lp++; // mark location
193 if (w & MCHFROM) // maybe change "from" section
196 if (w & MSYMBOL) // maybe includes a symbol
199 // Compute mark position in relocation information; in RELMOD mode,
200 // get address of data to fix up.
204 wp = (uint8_t *)(mp + loc);
206 if (okflag && (w & MLONG)) // indicate first word of long
214 // Deposit external reference
218 w = 6; // PC-relative fixup
220 w = 4; // Absolute fixup
222 w |= symbol->senv << 3;
229 // Deposit section-relative mark; in RELMOD mode, fix it up in
230 // the chunk, kind of like a sleazoid linker.
232 // In RELMOD mode, marks to words (MWORDs) "cannot happen,"
233 // checks are made when mark() is called, so we don't have to
239 else if (prg_flag && (w & (DATA | BSS)))
241 uint32_t diff = GETBE32(wp, 0);
243 DEBUG printf("diff=%lx ==> ", diff);
245 diff += sect[TEXT].sloc;
248 diff += sect[DATA].sloc;
252 DEBUG printf("%lx\n", diff);
259 // Generate ".PRG" relocation information in place in the relocation words
260 // (the "RELMOD" operation).
261 if (okflag && prg_flag)
268 if ((wp[1] & 7) == 5)
280 for(diff=loc-lastloc; diff>254; diff-=254)
283 *dp++ = (uint8_t)diff;
297 // Terminate relocation list with 0L (if there was no relocation) or
298 // 0.B (if relocation information was written).
302 for(firstp=0; firstp<4; firstp++)
305 // Return size of relocation information
315 // Make mark image for BSD .o file
317 // Assumptions about mark records (for BSD): if there is a symbol, the mark is
318 // for an undefined symbol, otherwise it's just a normal TDB relocation.
319 // N.B.: tsize is only used if reqseg is DATA
321 uint32_t MarkBSDImage(uint8_t * mp, uint32_t siz, uint32_t tsize, int reqseg)
323 uint16_t from = 0; // Section fixups are currently FROM
324 uint32_t rsize = 0; // Relocation table size (written to mp)
325 int validsegment = 0; // We are not yet in a valid segment...
327 #ifdef DEBUG_IMAGE_MARKING
328 printf("MarkBSDImage():\n");
330 // Initialize relocation table point (for D_foo macros)
333 // Run through all the relocation mark chunks
334 for(MCHUNK * mch=firstmch; mch!=NULL; mch=mch->mcnext)
336 for(PTR p=mch->mcptr;;)
339 uint16_t w = *p.wp++; // Next mark entry
341 // If we hit the end of a chunk, go get the next one
345 // Get the rest of the mark record
346 uint32_t loc = *p.lp++; // Mark location
348 // Maybe change "from" section
353 if (((reqseg == TEXT) && (from == TEXT))
354 || ((reqseg == DATA) && (from == DATA)))
360 // Maybe includes a symbol
367 #ifdef DEBUG_IMAGE_MARKING
368 printf(" validsegment: raddr = $%08X\n", loc);
370 uint32_t rflag = 0x00000040; // Absolute relocation
373 rflag = 0x000000A0; // PC-relative relocation
375 // This flag tells the linker to WORD swap the LONG when doing the
380 // This tells the linker to do a WORD relocation (otherwise it
381 // defaults to doing a LONG, throwing things off for WORD sized
383 if (!(w & (MLONG | MQUAD)))
386 // Tell the linker that the fixup is an OL QUAD data address
392 // Deposit external reference
393 rflag |= 0x00000010; // Set external reloc flag bit
394 rflag |= (symbol->senv << 8); // Put symbol index in flags
396 #ifdef DEBUG_IMAGE_MARKING
397 printf(" validsegment(2): rflag = $%08X\n", rflag);
402 #ifdef DEBUG_IMAGE_MARKING
403 printf(" w = $%04X\n", w);
405 w &= TDB; // Set reloc flags to segment
409 case TEXT: rflag |= 0x00000400; break;
410 case DATA: rflag |= 0x00000600; break;
411 case BSS: rflag |= 0x00000800; break;
414 #ifdef DEBUG_IMAGE_MARKING
415 printf(" validsegment(3): rflag = $%08X\n", rflag);
417 // Fix relocation by adding in start of TEXT segment, since it's
418 // currently relative to the start of the DATA (or BSS) segment
419 if (w & (DATA | BSS))
421 uint8_t * dp = objImage + BSDHDRSIZE + loc;
422 uint32_t olBitsSave = 0;
424 // Bump the start of the section if it's DATA (& not TEXT)
428 uint32_t diff = (rflag & 0x02 ? GETBE16(dp, 0) : GETBE32(dp, 0));
430 // Special handling for OP (data addr) relocation...
433 olBitsSave = diff & 0x7FF;
434 diff = (diff & 0xFFFFF800) >> 8;
437 DEBUG printf("diff=%uX ==> ", diff);
438 #ifdef DEBUG_IMAGE_MARKING
439 printf(" validsegment(4): diff = $%08X ", diff);
442 diff = WORDSWAP32(diff);
444 #ifdef DEBUG_IMAGE_MARKING
445 printf("(sect[TEXT].sloc=$%X) --> ", sect[TEXT].sloc);
447 diff += sect[TEXT].sloc;
450 diff += sect[DATA].sloc;
453 diff = WORDSWAP32(diff);
455 // Make sure to deposit the correct size payload
456 // N.B.: The braces around the SETBExx macros are needed
457 // because the macro supplies its own set of braces,
458 // thus leaving a naked semicolon afterwards to
459 // screw up the if/else structure. This is the price
460 // you pay when using macros pretending to be code.
461 if (rflag & 0x02) // WORD relocation
463 SETBE16(dp, 0, diff);
465 else if (rflag & 0x04) // OP data address relocation
467 // We do it this way because we might have an offset
468 // that is not a multiple of 8 and thus we need this in
469 // place to prevent a bad address at link time. :-P As
470 // a consequence of this, the highest address we can
471 // have here is $1FFFF8.
472 uint32_t diffsave = diff;
473 diff = ((diff & 0x001FFFFF) << 11) | olBitsSave;
474 SETBE32(dp, 0, diff);
475 // But we need those 3 bits, otherwise we can get in
476 // trouble with things like OL data that is in the cart
477 // space, and BOOM! So the 2nd phrase of the fixup (it
478 // will *always* have a 2nd phrase) has a few spare
479 // bits, we chuck them in there.
480 uint32_t p2 = GETBE32(dp, 8);
482 p2 |= (diffsave & 0x00E00000) << 8;
485 else // LONG relocation
487 SETBE32(dp, 0, diff);
490 DEBUG printf("%uX\n", diff);
491 #ifdef DEBUG_IMAGE_MARKING
492 printf("$%08X\n", diff);
497 D_long(loc); // Write relocation address
498 D_long(rflag); // Write relocation flags
499 rsize += 0x08; // Increment relocation size
503 // Return relocation table's size
504 #ifdef DEBUG_IMAGE_MARKING
505 printf(" rsize = $%X\n", rsize);
512 // Make mark image for RAW file
514 uint32_t MarkABSImage(uint8_t * mp, uint32_t siz, uint32_t tsize, int reqseg)
516 uint16_t from = 0; // Section fixups are currently FROM
517 uint32_t rsize = 0; // Relocation table size (written to mp)
518 int validsegment = 0; // We are not yet in a valid segment...
520 // Initialize relocation table point (for D_foo macros)
523 // Run through all the relocation mark chunks
524 for(MCHUNK * mch=firstmch; mch!=NULL; mch=mch->mcnext)
526 for (PTR p = mch->mcptr;;)
529 uint16_t w = *p.wp++; // Next mark entry
531 // If we hit the end of a chunk, go get the next one
535 // Get the rest of the mark record
536 uint32_t loc = *p.lp++; // Mark location
538 // Maybe change "from" section
543 if (((reqseg == TEXT) && (from == TEXT))
544 || ((reqseg == DATA) && (from == DATA)))
550 // Maybe includes a symbol
557 uint32_t rflag = 0x00000040; // Absolute relocation
560 rflag = 0x000000A0; // PC-relative relocation
562 // This flag tells the linker to WORD swap the LONG when doing the
567 // This tells the linker to do a WORD relocation (otherwise it
568 // defaults to doing a LONG, throwing things off for WORD sized
570 if (!(w & (MLONG | MQUAD)))
573 // Tell the linker that the fixup is an OL QUAD data address
579 return error("Unresolved symbol when outputting raw image");
583 w &= TDB; // Set reloc flags to segment
587 case TEXT: rflag |= 0x00000400; break;
588 case DATA: rflag |= 0x00000600; break;
589 case BSS: rflag |= 0x00000800; break;
592 // Fix relocation by adding in start of TEXT segment, since it's
593 // currently relative to the start of the DATA (or BSS) segment
594 uint8_t * dp = objImage + loc;
595 uint32_t olBitsSave = 0;
597 // Bump the start of the section if it's DATA (& not TEXT)
601 uint32_t diff = (rflag & 0x02 ? GETBE16(dp, 0) : GETBE32(dp, 0));
603 if (w & (DATA | BSS))
605 // Special handling for OP (data addr) relocation...
608 olBitsSave = diff & 0x7FF;
609 diff = (diff & 0xFFFFF800) >> 8;
613 diff = WORDSWAP32(diff);
615 diff += sect[TEXT].sloc;
618 diff += sect[DATA].sloc;
620 if ((rflag & 0x02) == 0)
622 diff += org68k_address;
626 diff = WORDSWAP32(diff);
628 // Make sure to deposit the correct size payload
629 // Check comments in MarkBSDImage for more candid moments
630 if (rflag & 0x02) // WORD relocation
632 SETBE16(dp, 0, diff);
634 else if (rflag & 0x04) // OP data address relocation
636 // We do it this way because we might have an offset
637 // that is not a multiple of 8 and thus we need this in
638 // place to prevent a bad address at link time. :-P As
639 // a consequence of this, the highest address we can
640 // have here is $1FFFF8.
641 uint32_t diffsave = diff;
642 diff = ((diff & 0x001FFFFF) << 11) | olBitsSave;
643 SETBE32(dp, 0, diff);
644 // But we need those 3 bits, otherwise we can get in
645 // trouble with things like OL data that is in the cart
646 // space, and BOOM! So the 2nd phrase of the fixup (it
647 // will *always* have a 2nd phrase) has a few spare
648 // bits, we chuck them in there.
649 uint32_t p2 = GETBE32(dp, 8);
651 p2 |= (diffsave & 0x00E00000) << 8;
654 else // LONG relocation
656 SETBE32(dp, 0, diff);
667 // Make relocation record for ELF .o file.
668 // Returns the size of the relocation record.
670 uint32_t CreateELFRelocationRecord(uint8_t * buf, uint8_t * secBuf, uint16_t section)
672 uint16_t from = 0; // Section fixups are currently FROM
673 uint32_t rsize = 0; // Size of the relocation table
675 // Setup pointer for D_long/word/byte macros
679 for(MCHUNK * mch=firstmch; mch!=NULL; mch=mch->mcnext)
681 for(register PTR p=mch->mcptr;;)
683 register uint16_t w = *p.wp++; // w = next mark entry
685 if (w & MCHEND) // (end of mark chunk)
690 uint16_t symFlags = 0;
691 uint32_t r_offset = *p.lp++; // Mark's location
693 if (w & MCHFROM) // Maybe change "from" section
696 if (w & MSYMBOL) // Maybe includes a symbol
701 symFlags = symbol->sattr;
704 // Create relocation record for ELF object, if the mark is in the
710 uint32_t r_addend = 0;
712 // Since we're chucking all symbols here for ELF objects by
713 // default (cf. sect.c), we discriminate here (normally, if
714 // there is a symbol in the mark record, it means an undefined
716 if (symbol && !(symFlags & DEFINED) && (symFlags & GLOBAL))
717 r_sym = symbol->senv + extraSyms;
719 r_sym = elfHdrNum[ES_TEXT]; // Mark TEXT segment
721 r_sym = elfHdrNum[ES_DATA]; // Mark DATA segment
723 r_sym = elfHdrNum[ES_BSS]; // Mark BSS segment
725 // Set the relocation type next
727 r_type = 5; // R_68K_PC16
728 // N.B.: Since we've established that (from & section) is non-
729 // zero, this condition will *never* be satisfied... :-P
730 // It might be better to check the symbol's senv; that is,
731 // if this is a real problem that needs addressing...
732 else if ((from & section) == 0)
733 // In the case of a section referring to a label in another
734 // section (for example text->data) use a R_68K_PC32 mark.
735 r_type = 4; // R_68K_PC32
737 r_type = 1; // R_68K_32
739 r_addend = GETBE32(secBuf + r_offset, 0);
741 // Deposit the relocation record
743 D_long(((r_sym << 8) | r_type));