X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?p=rmac;a=blobdiff_plain;f=mark.c;h=53eaf871854bb87bcd7e32f6a36e519ebcf8250f;hp=855d925b253e31b5021c9cb970af2b294f919f43;hb=9153334781cd2e23750f4dc002e847606c07a1f0;hpb=d28f432296e812643e236d1bfc9b556a7b11c461 diff --git a/mark.c b/mark.c index 855d925..53eaf87 100644 --- a/mark.c +++ b/mark.c @@ -1,228 +1,561 @@ -//////////////////////////////////////////////////////////////////////////////////////////////////// -// 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 Reboot and Friends +// Copyright (C) 199x Landon Dyer, 2011-2018 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 "risca.h" +#include "riscasm.h" +#include "sect.h" -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 -WORD curfrom; // Current "from" section -// -// --- Initialize Marker --------------------------------------------------------------------------- -// +#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 *)) -void init_mark(void) { - firstmch = curmch = NULL; - mcalloc = mcused = 0; - curfrom = 0; -} +MCHUNK * firstmch; // First mark chunk +MCHUNK * curmch; // Current mark chunk +PTR markptr; // Deposit point in current mark chunk +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 -// -// --- Wrap up marker (called after final mark is made) -------------------------------------------- -// +// 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 -void stopmark(void) { - if(curmch) { - *markptr.wp = MCHEND; // Mark end of block - curmch->mcused = mcused; // Update #used in mark block - } -} // -// --- Mark a word or longword relocatable --------------------------------------------------------- +// Initialize marker // +void InitMark(void) +{ + firstmch = curmch = NULL; + mcalloc = mcused = 0; + curfrom = 0; + sect[TEXT].relocs = sect[DATA].relocs = sect[BSS].relocs = 0; +} -int rmark(int from, LONG loc, int to, int size, SYM *symbol) { - WORD w; - - if((mcalloc - mcused) < MIN_MARK_MEM) - amark(); - - w = (WORD)(size | to); - if(from != curfrom) - w |= MCHFROM; - if(symbol != NULL) - w |= MSYMBOL; - - mcused += sizeof(WORD) + sizeof(LONG); - *markptr.wp++ = w; - *markptr.lp++ = loc; - - if(w & MCHFROM) { - *markptr.wp++ = (WORD)from; - curfrom = (WORD)from; - mcused += sizeof(WORD); - } - if(w & MSYMBOL) { - *markptr.sy++ = symbol; - mcused += sizeof(LONG); - } +// +// Wrap up marker (called after final mark is made) +// +void StopMark(void) +{ + if (curmch) + { + *markptr.wp = MCHEND; // Mark end of block + curmch->mcused = mcused; // Update # used in mark block + } +} - *markptr.wp = 0x0000; - return(0); +// +// 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) +// +uint32_t MarkRelocatable(uint16_t section, uint32_t loc, uint16_t to, uint16_t flags, SYM * symbol) +{ +#ifdef DEBUG_IMAGE_MARKING +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) + AllocateMark(); + + // Set up flags + flags |= to; + + if (section != curfrom) + flags |= MCHFROM; + + if (symbol != NULL) + flags |= MSYMBOL; + + // + // 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 (symbol != NULL) + error("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 = section; + *markptr.wp++ = section; + mcused += sizeof(uint16_t); + } + + if (flags & MSYMBOL) + { + *markptr.sy++ = 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; } + // -// --- Allocate another chunk of mark space -------------------------------------------------------- +// Allocate another chunk of mark space // +uint32_t AllocateMark(void) +{ + // Alloc mark block header (and data) and set it up. + MCHUNK * p = malloc(sizeof(MCHUNK) + MARK_ALLOC_INCR); + p->mcnext = NULL; + p->mcalloc = MARK_ALLOC_INCR; + 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 + curmch->mcused = mcused; + curmch->mcnext = p; + } + + // Setup global vars + curmch = p; + markptr = p->mcptr; + mcalloc = MARK_ALLOC_INCR; + mcused = 0; + + return 0; +} -int amark(void) { - MCHUNK *p; - - // Alloc mark block header (and data) and set it up. - p = (MCHUNK *)amem((long)(sizeof(MCHUNK)) + MARK_ALLOC_INCR); - p->mcnext = NULL; - p->mcalloc = MARK_ALLOC_INCR; - p->mcptr.cp = (char *)(((char *)p) + sizeof(MCHUNK)); - if(curmch) { // Link onto previous chunk - *markptr.wp++ = MCHEND; // Mark end of block - curmch->mcused = mcused; - curmch->mcnext = p; - } - if(!firstmch) - firstmch = p; +// +// Make mark image for Alcyon .o file +// okflag: 1, ok to deposit reloc information +// +uint32_t MarkImage(register uint8_t * mp, uint32_t siz, uint32_t tsize, int okflag) +{ + 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 + + if (okflag) + memset(mp, 0, siz); // zero relocation buffer + + for(MCHUNK * mch=firstmch; mch!=NULL; mch=mch->mcnext) + { + for(PTR p=mch->mcptr;;) + { + uint16_t w = *p.wp++;// w = next mark entry + + if (w & MCHEND) // (end of mark chunk) + break; + + // Get mark record + SYM * symbol = NULL; + loc = *p.lp++; // mark location + + if (w & MCHFROM) // maybe change "from" section + from = *p.wp++; + + 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 (w & MPCREL) + w = 6; // PC-relative fixup + else + w = 4; // Absolute fixup + + w |= symbol->senv << 3; + *wp++ = w >> 8; + *wp = (uint8_t)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 == 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; + + 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; +} - curmch = p; // Setup global vars - markptr = p->mcptr; - mcalloc = MARK_ALLOC_INCR; - mcused = 0; - return(0); +// +// 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) +{ + 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; + + // 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 + validsegment = 0; + } + + // Maybe includes a symbol + if (w & MSYMBOL) + symbol = *p.sy++; + + if (!validsegment) + continue; + +#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; + + // This tells the linker to do a WORD relocation (otherwise it + // defaults to doing a LONG, throwing things off for WORD sized + // fixups) + if (!(w & MLONG)) + rflag |= 0x00000002; + + if (symbol != NULL) + { + // Deposit external reference + rflag |= 0x00000010; // Set external reloc flag bit + rflag |= (symbol->senv << 8); // Put symbol index in flags + +#ifdef DEBUG_IMAGE_MARKING +printf(" validsegment(2): rflag = $%08X\n", rflag); +#endif + } + else + { +#ifdef DEBUG_IMAGE_MARKING +printf(" w = $%04X\n", w); +#endif + w &= TDB; // Set reloc flags to segment + + switch (w) + { + case TEXT: rflag |= 0x00000400; break; + case DATA: rflag |= 0x00000600; break; + case BSS: rflag |= 0x00000800; break; + } + +#ifdef DEBUG_IMAGE_MARKING +printf(" validsegment(3): rflag = $%08X\n", rflag); +#endif + // 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 = (rflag & 0x02 ? GETBE16(dp, 0) : GETBE32(dp, 0)); + DEBUG printf("diff=%uX ==> ", diff); +#ifdef DEBUG_IMAGE_MARKING +printf(" validsegment(4): diff = $%08X --> ", diff); +#endif + if (rflag & 0x01) + diff = WORDSWAP32(diff); + + diff += sect[TEXT].sloc; + + if (w == BSS) + diff += sect[DATA].sloc; + + if (rflag & 0x01) + diff = WORDSWAP32(diff); + + // Make sure to deposit the correct size payload + // N.B.: The braces around the SETBExx macros are needed + // because the macro supplies its own set of braces, + // thus leaving a naked semicolon afterwards to + // screw up the if/else structure. This is the price + // you pay when using macros pretending to be code. + if (rflag & 0x02) + { + SETBE16(dp, 0, diff); + } + else + { + 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 table's size +#ifdef DEBUG_IMAGE_MARKING +printf(" rsize = $%X\n", rsize); +#endif + return rsize; } + // -// --- Make mark image for BSD .o file ------------------------------------------------------------- -// - -LONG bsdmarkimg(char *mp, LONG siz, LONG tsize, int reqseg) { - MCHUNK *mch; // Mark chunk - PTR p; // Source point from within mark chunk - WORD from; // Section fixups are currently FROM - WORD w; // A word (temp) - LONG loc; // Location (temp) - SYM *symbol; // Symbols (temp) - char *wp; // Pointer into raw relocation info - char *dp; // Deposit point for RELMOD info - LONG diff; // Difference to relocate (RELMOD) - LONG raddr, rflag = 0; // BSD relocation address and flags - LONG rsize; // Relocation size - int validsegment = 0; // Valid segment being processed - - rsize = 0; // Initialise relocation size - chptr = mp; - - from = 0; - for(mch = firstmch; mch != NULL; mch = mch->mcnext) - for(p = mch->mcptr;;) { - w = *p.wp++; // Next mark entry - - if(w & MCHEND) break; // End of mark chunk - - // Get mark record - symbol = NULL; - loc = *p.lp++; // Mark location - if(w & MCHFROM) { // Maybe change "from" section - from = *p.wp++; - if(obj_format == BSD) { - if(reqseg == TEXT) { // Requested segment is TEXT - if(from == TEXT) validsegment = 1; - else validsegment = 0; - } else { // Requested segment is DATA - if(from == DATA) validsegment = 1; - else validsegment = 0; - } - } - } - - if(w & MSYMBOL) // Maybe includes a symbol - symbol = *p.sy++; - - if(obj_format == BSD) { - raddr = loc; // Set relocation address - if(validsegment) - D_long(raddr); // Write relocation address - if(w & MPCREL) - rflag = 0x000000A0; // PC-relative fixup - else - rflag = 0x00000040; // Absolute fixup - if(w & MMOVEI) - rflag |= 0x00000001; - } - - // Compute mark position in relocation information; - // in RELMOD mode, get address of data to fix up. - if(from == DATA) - loc += tsize; - wp = (char *)(mp + loc); - - if(symbol) { - // Deposit external reference - if(obj_format == BSD) { - rflag |= 0x00000010; // Set external reloc flag bit - rflag |= (symbol->senv << 8); // Put symbol index in flags - if(symbol->sattre & RISCSYM) rflag |= 0x00000001; - if(validsegment) { - D_long(rflag); // Write relocation flags - rsize += 8; // Increment relocation size - } - } - - } else { - - if(obj_format == BSD) { - w &= TDB; // Set reloc flags to segment - switch(w) { - case TEXT: rflag |= 0x00000400; break; - case DATA: rflag |= 0x00000600; break; - case BSS: rflag |= 0x00000800; break; - } - if(validsegment) { - 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=%lx ==> ", diff); - if(rflag & 0x01) - diff = ((diff >> 16) & 0x0000FFFF) | ((diff << 16) & 0xFFFF0000); - diff += sect[TEXT].sloc; - if(w == BSS) - diff += sect[DATA].sloc; - if(rflag & 0x01) - diff = ((diff >> 16) & 0x0000FFFF) | ((diff << 16) & 0xFFFF0000); - dp = objimage + BSDHDRSIZE + loc; - *dp++ = (char)(diff >> 24); - *dp++ = (char)(diff >> 16); - *dp++ = (char)(diff >> 8); - *dp = (char)diff; - DEBUG printf("%lx\n", diff); - } - } - } - } - } - - if(obj_format == BSD) // Return relocation size - return(rsize); - else - 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; + ch_size = 0; + + 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; } +