X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?p=rmac;a=blobdiff_plain;f=mark.c;h=088263b2c0271d795f33b043046fda331f01bd97;hp=3b3bd3ada80dd969415089218b95f5b0b59e6e5d;hb=03dd34951a331e0b8971195ccef1600fffaea2e6;hpb=062214e62031c26d372edc2e68473ebb64f6a506 diff --git a/mark.c b/mark.c index 3b3bd3a..088263b 100644 --- a/mark.c +++ b/mark.c @@ -1,83 +1,120 @@ // -// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System +// RMAC - Reboot's Macro Assembler for all Atari computers // MARK.C - A record of things that are defined relative to any of the sections -// Copyright (C) 199x Landon Dyer, 2011-2012 Reboot and Friends +// Copyright (C) 199x Landon Dyer, 2011-2017 Reboot and Friends // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986 -// Source Utilised with the Kind Permission of Landon Dyer +// Source utilised with the kind permission of Landon Dyer // #include "mark.h" #include "error.h" #include "object.h" #include "riscasm.h" +#include "sect.h" +#define MARK_ALLOC_INCR 1024 // # bytes to alloc for more mark space +#define MIN_MARK_MEM (3 * sizeof(uint16_t) + 1 * sizeof(uint32_t) + sizeof(SYM *)) + MCHUNK * firstmch; // First mark chunk MCHUNK * curmch; // Current mark chunk PTR markptr; // Deposit point in current mark chunk -LONG mcalloc; // #bytes alloc'd to current mark chunk -LONG mcused; // #bytes used in current mark chunk -uint16_t curfrom; // Current "from" section - +uint32_t mcalloc; // # bytes alloc'd to current mark chunk +uint32_t mcused; // # bytes used in current mark chunk +uint16_t curfrom; // Current "from" section + +// Table to convert from TDB to fixup triad +static uint8_t mark_tr[] = { + 0, // (N/A) + 2, // TEXT relocatable + 1, 0, // DATA relocatable + 3 // BSS relocatable +}; //#define DEBUG_IMAGE_MARKING // -// Initialize Marker +// Initialize marker // void InitMark(void) { firstmch = curmch = NULL; mcalloc = mcused = 0; curfrom = 0; + sect[TEXT].relocs = sect[DATA].relocs = sect[BSS].relocs = 0; } // // Wrap up marker (called after final mark is made) // -void stopmark(void) +void StopMark(void) { if (curmch) { *markptr.wp = MCHEND; // Mark end of block - curmch->mcused = mcused; // Update #used in mark block + curmch->mcused = mcused; // Update # used in mark block } } // -// Mark a word or longword relocatable +// Mark a word or longword as relocatable +// +// Record is either 2, 3, or 4 pieces of data long. A mark is of the form: +// .W section mark is relative to, and flags in upper byte +// .L location of mark in "from" section +// .W [from] new from section (if different from current) +// .L [symbol] symbol involved in external reference (if any) // -int rmark(uint16_t from, uint32_t loc, uint16_t to, uint16_t size, SYM * symbol) +uint32_t MarkRelocatable(uint16_t section, uint32_t loc, uint16_t to, uint16_t flags, SYM * symbol) { #ifdef DEBUG_IMAGE_MARKING -printf("rmark: from=%i, loc=$%X, to=$%X, size=$%x, symbol=$%X\n", from, loc, to, size, symbol); +printf("MarkRelocatable: section=%i, loc=$%X, to=$%X, flags=$%x, symbol=$%X\n", section, loc, to, flags, symbol); if (symbol) printf(" symbol->stype=$%02X, sattr=$%04X, sattre=$%08X, svalue=%i, sname=%s\n", symbol->stype, symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname); #endif if ((mcalloc - mcused) < MIN_MARK_MEM) - amark(); + AllocateMark(); - uint16_t flags = (size | to); + // Set up flags + flags |= to; - if (from != curfrom) + if (section != curfrom) flags |= MCHFROM; if (symbol != NULL) flags |= MSYMBOL; - mcused += sizeof(WORD) + sizeof(LONG); + // + // Complain about some things are not allowed in '-p' (PRG) mode: + // o Marks that aren't to LONGs + // o External references + // + if (prg_flag) + { +#if 0 + if ((flags & MLONG) == 0) + error("illegal word relocatable (in .PRG mode)"); +#endif + + if (symbol != NULL) + errors("illegal external reference (in .PRG mode) to '%s'", + symbol->sname); + } + + // Dump crap into the mark *markptr.wp++ = flags; *markptr.lp++ = loc; + mcused += sizeof(uint16_t) + sizeof(uint32_t); if (flags & MCHFROM) { - curfrom = from; - *markptr.wp++ = from; - mcused += sizeof(WORD); + curfrom = section; + *markptr.wp++ = section; + mcused += sizeof(uint16_t); } if (flags & MSYMBOL) @@ -86,6 +123,11 @@ if (symbol) mcused += sizeof(SYM *); } + // Increment # of relocs in this section + sect[section].relocs++; + + // Not sure what this is about (making sure the next mark is clear until + // it's marked as the end--I think)... *markptr.wp = 0x0000; return 0; @@ -95,29 +137,28 @@ if (symbol) // // Allocate another chunk of mark space // -int amark(void) +uint32_t AllocateMark(void) { -// MCHUNK * p; - // Alloc mark block header (and data) and set it up. -// p = (MCHUNK *)amem((long)(sizeof(MCHUNK)) + MARK_ALLOC_INCR); - MCHUNK * p = (MCHUNK *)malloc(sizeof(MCHUNK) + MARK_ALLOC_INCR); + MCHUNK * p = malloc(sizeof(MCHUNK) + MARK_ALLOC_INCR); p->mcnext = NULL; p->mcalloc = MARK_ALLOC_INCR; - p->mcptr.cp = (char *)(((char *)p) + sizeof(MCHUNK)); + p->mcptr.cp = (uint8_t *)p + sizeof(MCHUNK); + p->mcused = 0; + + if (firstmch == NULL) + firstmch = p; if (curmch) { - // Link onto previous chunk - *markptr.wp++ = MCHEND; // Mark end of block + // Link onto previous chunk + *markptr.wp++ = MCHEND; // Mark end of block curmch->mcused = mcused; curmch->mcnext = p; } - if (!firstmch) - firstmch = p; - - curmch = p; // Setup global vars + // Setup global vars + curmch = p; markptr = p->mcptr; mcalloc = MARK_ALLOC_INCR; mcused = 0; @@ -127,212 +168,378 @@ int amark(void) // -// Make mark image for BSD .o file +// Make mark image for Alcyon .o file +// okflag: 1, ok to deposit reloc information // -uint32_t bsdmarkimg(char * mp, LONG siz, LONG tsize, int reqseg) +uint32_t MarkImage(register uint8_t * mp, uint32_t siz, uint32_t tsize, int okflag) { - MCHUNK * mch; // Mark chunk - PTR p; // Source point from within mark chunk - uint16_t from; // Section fixups are currently FROM - uint16_t w; // A word (temp) - uint32_t loc; // Location (temp) - SYM * symbol; // Symbols (temp) - uint8_t * wp; // Pointer into raw relocation info - uint8_t * dp; // Deposit point for RELMOD info - uint32_t diff; // Difference to relocate (RELMOD) - uint32_t raddr, rflag = 0; // BSD relocation address and flags - uint32_t rsize; // Relocation size - int validsegment = 0; // Valid segment being processed + uint16_t from = 0; // Section fixups are currently FROM + uint32_t loc; // Location (temp) + uint32_t lastloc; // Last location fixed up (RELMOD) + uint8_t * wp; // Pointer into raw relocation information + register uint8_t * dp; // Deposit point for RELMOD information -#ifdef DEBUG_IMAGE_MARKING -printf("bsdmarkimg():\n"); -#endif - // Initialise relocation size - rsize = 0; - chptr = mp; - from = 0; + if (okflag) + memset(mp, 0, siz); // zero relocation buffer - for(mch=firstmch; mch!=NULL; mch=mch->mcnext) + for(MCHUNK * mch=firstmch; mch!=NULL; mch=mch->mcnext) { - for(p=mch->mcptr;;) + for(PTR p=mch->mcptr;;) { - w = *p.wp++; // Next mark entry + uint16_t w = *p.wp++;// w = next mark entry - if (w & MCHEND) - break; // End of mark chunk + if (w & MCHEND) // (end of mark chunk) + break; // Get mark record - symbol = NULL; - loc = *p.lp++; // Mark location + SYM * symbol = NULL; + loc = *p.lp++; // mark location - if (w & MCHFROM) - { - // Maybe change "from" section + if (w & MCHFROM) // maybe change "from" section from = *p.wp++; - if (obj_format == BSD) + if (w & MSYMBOL) // maybe includes a symbol + symbol = *p.sy++; + + // Compute mark position in relocation information; in RELMOD mode, + // get address of data to fix up. + if (from == DATA) + loc += tsize; + + wp = (uint8_t *)(mp + loc); + + if (okflag && (w & MLONG)) // indicate first word of long + { + wp[1] = 5; + wp += 2; + } + + if (symbol) + { + // Deposit external reference + if (okflag) { - if (reqseg == TEXT) - { - // Requested segment is TEXT - if (from == TEXT) - validsegment = 1; - else - validsegment = 0; - } + if (w & MPCREL) + w = 6; // PC-relative fixup else - { - // Requested segment is DATA - if (from == DATA) - validsegment = 1; - else - validsegment = 0; - } + w = 4; // Absolute fixup + + w |= symbol->senv << 3; + *wp++ = w >> 8; + *wp = w; } } + else + { + // Deposit section-relative mark; in RELMOD mode, fix it up in + // the chunk, kind of like a sleazoid linker. + // + // In RELMOD mode, marks to words (MWORDs) "cannot happen," + // checks are made when mark() is called, so we don't have to + // check again here. + w &= TDB; + + if (okflag) + wp[1] = mark_tr[w]; + else if (prg_flag && (w & (DATA | BSS))) + { + uint32_t diff = GETBE32(wp, 0); +#ifdef DO_DEBUG + DEBUG printf("diff=%lx ==> ", diff); +#endif + diff += sect[TEXT].sloc; - if (w & MSYMBOL) // Maybe includes a symbol - symbol = *p.sy++; + if (w == BSS) + diff += sect[DATA].sloc; + + SETBE32(wp, 0, diff) +#ifdef DO_DEBUG + DEBUG printf("%lx\n", diff); +#endif + } + } + } + } + + // Generate ".PRG" relocation information in place in the relocation words + // (the "RELMOD" operation). + if (okflag && prg_flag) + { + int firstp = 1; + wp = dp = mp; - if (obj_format == BSD) + for(loc=0; loc254; diff-=254) + *dp++ = 1; + + *dp++ = (uint8_t)diff; + } + + lastloc = loc; + loc += 4; + wp += 4; + } + else + { + loc += 2; + wp += 2; + } + } + + // Terminate relocation list with 0L (if there was no relocation) or + // 0.B (if relocation information was written). + if (!firstp) + *dp++ = 0; + else + for(firstp=0; firstp<4; firstp++) + *dp++ = 0; + + // Return size of relocation information + loc = dp - mp; + return loc; + } + + return siz; +} + + +// +// Make mark image for BSD .o file +// +// Assumptions about mark records (for BSD): if there is a symbol, the mark is +// for an undefined symbol, otherwise it's just a normal TDB relocation. +// N.B.: tsize is only used if reqseg is DATA +// +uint32_t MarkBSDImage(uint8_t * mp, uint32_t siz, uint32_t tsize, int reqseg) { -printf(" validsegment: raddr = $%08X\n", raddr); -#endif - D_long(raddr); // Write relocation address + uint16_t from = 0; // Section fixups are currently FROM + uint32_t rsize = 0; // Relocation table size (written to mp) + int validsegment = 0; // We are not yet in a valid segment... + #ifdef DEBUG_IMAGE_MARKING -} +printf("MarkBSDImage():\n"); #endif + // Initialize relocation table point (for D_foo macros) + chptr = mp; - if (w & MPCREL) - rflag = 0x000000A0; // PC-relative fixup + // Run through all the relocation mark chunks + for(MCHUNK * mch=firstmch; mch!=NULL; mch=mch->mcnext) + { + for(PTR p=mch->mcptr;;) + { + SYM * symbol = NULL; + uint16_t w = *p.wp++; // Next mark entry + + // If we hit the end of a chunk, go get the next one + if (w & MCHEND) + break; + + // Get the rest of the mark record + uint32_t loc = *p.lp++; // Mark location + + // Maybe change "from" section + if (w & MCHFROM) + { + from = *p.wp++; + + if (((reqseg == TEXT) && (from == TEXT)) + || ((reqseg == DATA) && (from == DATA))) + validsegment = 1; else - rflag = 0x00000040; // Absolute fixup - -// This flag tells the linker to WORD swap the LONG when doing the fixup. - if (w & MMOVEI) -//{ -//printf("bsdmarkimg: ORing $01 to rflag (MMOVEI) [symbol=%s]...\n", symbol->sname); - rflag |= 0x00000001; -//} + validsegment = 0; } - // Compute mark position in relocation information; - // in RELMOD mode, get address of data to fix up. - if (from == DATA) - loc += tsize; + // Maybe includes a symbol + if (w & MSYMBOL) + symbol = *p.sy++; - wp = (uint8_t *)(mp + loc); + if (!validsegment) + continue; - if (symbol) +#ifdef DEBUG_IMAGE_MARKING +printf(" validsegment: raddr = $%08X\n", loc); +#endif + uint32_t rflag = 0x00000040; // Absolute relocation + + if (w & MPCREL) + rflag = 0x000000A0; // PC-relative relocation + + // This flag tells the linker to WORD swap the LONG when doing the + // relocation. + if (w & MMOVEI) + rflag |= 0x00000001; + + if (symbol != NULL) { // Deposit external reference - if (obj_format == BSD) - { - rflag |= 0x00000010; // Set external reloc flag bit - rflag |= (symbol->senv << 8); // Put symbol index in flags - -// Looks like this is completely unnecessary (considering it does the wrong thing!) -#if 0 - if (symbol->sattre & RISCSYM) -{ -printf("bsdmarkimg: ORing $01 to rflag (RISCSYM) [symbol=%s]...\n", symbol->sname); - rflag |= 0x00000001; -} -#endif + rflag |= 0x00000010; // Set external reloc flag bit + rflag |= (symbol->senv << 8); // Put symbol index in flags - if (validsegment) - { #ifdef DEBUG_IMAGE_MARKING printf(" validsegment(2): rflag = $%08X\n", rflag); #endif - D_long(rflag); // Write relocation flags - rsize += 8; // Increment relocation size - } - } } else { - if (obj_format == BSD) - { #ifdef DEBUG_IMAGE_MARKING printf(" w = $%04X\n", w); #endif - w &= TDB; // Set reloc flags to segment + w &= TDB; // Set reloc flags to segment - switch (w) - { - case TEXT: rflag |= 0x00000400; break; - case DATA: rflag |= 0x00000600; break; - case BSS: rflag |= 0x00000800; break; - } + switch (w) + { + case TEXT: rflag |= 0x00000400; break; + case DATA: rflag |= 0x00000600; break; + case BSS: rflag |= 0x00000800; break; + } - if (validsegment) - { #ifdef DEBUG_IMAGE_MARKING printf(" validsegment(3): rflag = $%08X\n", rflag); #endif - D_long(rflag); // Write relocation flags - rsize += 8; // Increment relocation size - } - - w &= TDB; - - if (validsegment) - { - if (w & (DATA|BSS)) - { - dp = objimage + BSDHDRSIZE + loc; - diff = ((LONG)(*dp++ & 0xFF)) << 24; - diff |= ((LONG)(*dp++ & 0xFF)) << 16; - diff |= ((LONG)(*dp++ & 0xFF)) << 8; - diff |= (LONG)(*dp & 0xFF); - DEBUG printf("diff=%ux ==> ", diff); + // Fix relocation by adding in start of TEXT segment, since it's + // currently relative to the start of the DATA (or BSS) segment + if (w & (DATA | BSS)) + { + uint8_t * dp = objImage + BSDHDRSIZE + loc; + + // Bump the start of the section if it's DATA (& not TEXT) + if (from == DATA) + dp += tsize; + + uint32_t diff = GETBE32(dp, 0); + DEBUG printf("diff=%uX ==> ", diff); #ifdef DEBUG_IMAGE_MARKING printf(" validsegment(4): diff = $%08X --> ", diff); #endif - - if (rflag & 0x01) - diff = ((diff >> 16) & 0x0000FFFF) | ((diff << 16) & 0xFFFF0000); + if (rflag & 0x01) + diff = WORDSWAP32(diff); - diff += sect[TEXT].sloc; + diff += sect[TEXT].sloc; - if (w == BSS) - diff += sect[DATA].sloc; + if (w == BSS) + diff += sect[DATA].sloc; - if (rflag & 0x01) - diff = ((diff >> 16) & 0x0000FFFF) | ((diff << 16) & 0xFFFF0000); + if (rflag & 0x01) + diff = WORDSWAP32(diff); - dp = objimage + BSDHDRSIZE + loc; - *dp++ = (char)(diff >> 24); - *dp++ = (char)(diff >> 16); - *dp++ = (char)(diff >> 8); - *dp = (char)diff; - DEBUG printf("%ux\n", diff); + SETBE32(dp, 0, diff); + DEBUG printf("%uX\n", diff); #ifdef DEBUG_IMAGE_MARKING printf("$%08X\n", diff); #endif - } - } } } + + D_long(loc); // Write relocation address + D_long(rflag); // Write relocation flags + rsize += 0x08; // Increment relocation size } } - // Return relocation size - if (obj_format == BSD) + // Return relocation table's size #ifdef DEBUG_IMAGE_MARKING -{ printf(" rsize = $%X\n", rsize); #endif - return rsize; -#ifdef DEBUG_IMAGE_MARKING + return rsize; } -#endif - return siz; + +// +// Make relocation record for ELF .o file. +// Returns the size of the relocation record. +// +uint32_t CreateELFRelocationRecord(uint8_t * buf, uint8_t * secBuf, uint16_t section) +{ + uint16_t from = 0; // Section fixups are currently FROM + uint32_t rsize = 0; // Size of the relocation table + + // Setup pointer for D_long/word/byte macros + chptr = buf; + + for(MCHUNK * mch=firstmch; mch!=NULL; mch=mch->mcnext) + { + for(register PTR p=mch->mcptr;;) + { + register uint16_t w = *p.wp++; // w = next mark entry + + if (w & MCHEND) // (end of mark chunk) + break; + + // Get mark record + SYM * symbol = NULL; + uint16_t symFlags = 0; + uint32_t r_offset = *p.lp++; // Mark's location + + if (w & MCHFROM) // Maybe change "from" section + from = *p.wp++; + + if (w & MSYMBOL) // Maybe includes a symbol + { + symbol = *p.sy++; + + if (symbol) + symFlags = symbol->sattr; + } + + // Create relocation record for ELF object, if the mark is in the + // current section. + if (from & section) + { + uint32_t r_sym = 0; + uint32_t r_type = 0; + uint32_t r_addend = 0; + + // Since we're chucking all symbols here for ELF objects by + // default (cf. sect.c), we discriminate here (normally, if + // there is a symbol in the mark record, it means an undefined + // symbol) :-P + if (symbol && !(symFlags & DEFINED) && (symFlags & GLOBAL)) + r_sym = symbol->senv + extraSyms; + else if (w & TEXT) + r_sym = elfHdrNum[ES_TEXT]; // Mark TEXT segment + else if (w & DATA) + r_sym = elfHdrNum[ES_DATA]; // Mark DATA segment + else if (w & BSS) + r_sym = elfHdrNum[ES_BSS]; // Mark BSS segment + + // Set the relocation type next + if (w & MPCREL) + r_type = 5; // R_68K_PC16 + // N.B.: Since we've established that (from & section) is non- + // zero, this condition will *never* be satisfied... :-P + // It might be better to check the symbol's senv; that is, + // if this is a real problem that needs addressing... + else if ((from & section) == 0) + // In the case of a section referring to a label in another + // section (for example text->data) use a R_68K_PC32 mark. + r_type = 4; // R_68K_PC32 + else + r_type = 1; // R_68K_32 + + r_addend = GETBE32(secBuf + r_offset, 0); + + // Deposit the relocation record + D_long(r_offset); + D_long((r_sym << 8) | r_type); + D_long(r_addend); + rsize += 0x0C; + } + } + } + + return rsize; } +