X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?p=rmac;a=blobdiff_plain;f=object.c;h=0b7df7ed8ecc77b1d7bb2eb1ad9ad26b6319821b;hp=9f9de01b8071b0a984268d051e9e4d41b801065a;hb=HEAD;hpb=9153334781cd2e23750f4dc002e847606c07a1f0 diff --git a/object.c b/object.c index 9f9de01..6dbf9c5 100644 --- a/object.c +++ b/object.c @@ -1,7 +1,7 @@ // -// RMAC - Reboot's Macro Assembler for all Atari computers +// RMAC - Renamed Macro Assembler for all Atari computers // OBJECT.C - Writing Object Files -// Copyright (C) 199x Landon Dyer, 2011-2018 Reboot and Friends +// Copyright (C) 199x Landon Dyer, 2011-2022 Reboot and Friends // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986 // Source utilised with the kind permission of Landon Dyer // @@ -9,11 +9,13 @@ #include "object.h" #include "6502.h" #include "direct.h" +#include "dsp56k.h" #include "error.h" #include "mark.h" #include "riscasm.h" #include "sect.h" #include "symbol.h" +#include "version.h" //#define DEBUG_ELF @@ -56,6 +58,9 @@ See left. 4 & 5 If these bits are set to 0 (PF_PRIVATE), the processes' - 6-15 Currently unused */ +// Internal function prototypes +static void WriteLOD(void); +static void WriteP56(void); // // Add entry to symbol table (in ALCYON mode) @@ -118,7 +123,8 @@ uint8_t * AddSymEntry(register uint8_t * buf, SYM * sym, int globflag) w |= AL_EXTERN | AL_GLOBAL; // Common symbol w &= ~AL_BSS; // They're not BSS in Alcyon object files } - else if (w1 & DEFINED) + + if (w1 & DEFINED) { if (globflag) // Export the symbol w |= AL_GLOBAL; @@ -150,34 +156,73 @@ uint8_t * AddSymEntry(register uint8_t * buf, SYM * sym, int globflag) return buf; } - // // Add an entry to the BSD symbol table // +// From stab.def (https://sites.uclouvain.be/SystInfo/usr/include/bits/stab.def.html): +/* +_________________________________________________ +| 00 - 1F are not dbx stab symbols | +| In most cases, the low bit is the EXTernal bit| + +| 00 UNDEF | 02 ABS | 04 TEXT | 06 DATA | +| 01 |EXT | 03 |EXT | 05 |EXT | 07 |EXT | + +| 08 BSS | 0A INDR | 0C FN_SEQ | 0E WEAKA | +| 09 |EXT | 0B | 0D WEAKU | 0F WEAKT | + +| 10 WEAKD | 12 COMM | 14 SETA | 16 SETT | +| 11 WEAKB | 13 | 15 | 17 | + +| 18 SETD | 1A SETB | 1C SETV | 1E WARNING| +| 19 | 1B | 1D | 1F FN | +*/ uint8_t * AddBSDSymEntry(uint8_t * buf, SYM * sym, int globflag) { chptr = buf; // Point to buffer for depositing longs - D_long(strindx); // Deposit the symbol string index + if (sym->sname) + { + D_long(strindx); // Deposit the symbol string index + } + else + { + D_long(0); // Deposit special NULL string index + } uint16_t w1 = sym->sattr; // Obtain symbol attributes uint32_t z = 0; // Initialize resulting symbol flags - if (w1 & EQUATED) + if (sym->stype == DBGSYM) { - z = 0x02000000; // Set equated flag + // Debug symbols hard-code the a.out symbol type in the st_type field + // and can include additional type-specific data in the a.out symbol + // "other" and "description" fields, both packed into this same dword. + z = sym->st_type << 24; + z |= sym->st_other << 16; + z |= sym->st_desc; } else { + // Translate rmac symbol attributes to an a.out symbol type. + if (w1 & EQUATED) + { + z = 0x02000000; // Set equated flag + } + + // If a symbol is both EQUd and flagged as TBD then we let the latter + // take precedence. Otherwise the linker will not even bother trying to + // relocate the address during link time. + switch (w1 & TDB) { case TEXT: z = 0x04000000; break; // Set TEXT segment flag case DATA: z = 0x06000000; break; // Set DATA segment flag case BSS : z = 0x08000000; break; // Set BSS segment flag } - } - if (globflag) - z |= 0x01000000; // Set global flag if requested + if (globflag) + z |= 0x01000000; // Set global flag if requested + } D_long(z); // Deposit symbol attribute z = sym->svalue; // Obtain symbol value @@ -189,15 +234,17 @@ uint8_t * AddBSDSymEntry(uint8_t * buf, SYM * sym, int globflag) z += sect[DATA].sloc; // If BSS add DATA segment size D_long(z); // Deposit symbol value - strcpy(strtable + strindx, sym->sname); - strindx += strlen(sym->sname) + 1; // Incr string index incl null terminate + if (sym->sname) + { + strcpy(strtable + strindx, sym->sname); + strindx += strlen(sym->sname) + 1; // Incr string index incl null terminate + } buf += 12; // Increment buffer to next record symsize += 12; // Increment symbol table size return buf; } - // // Add entry to ELF symbol table; if `globflag' is 1, make the symbol global // @@ -212,15 +259,10 @@ uint8_t * AddELFSymEntry(uint8_t * buf, SYM * sym, int globflag) register WORD w1 = sym->sattr; - if (w1 & COMMON) - { - //w |= AL_EXTERN | AL_GLOBAL; // common symbol - //w &= ~AL_BSS; // they're not BSS in Alcyon object files - } - else if (w1 & DEFINED) + if (w1 & DEFINED) { if (globflag) // Export the symbol - st_info |= 16; //STB_GLOBAL (1<<4) + st_info |= 16; // STB_GLOBAL (1<<4) } else if (w1 & (GLOBAL | REFERENCED)) st_info |= 16; @@ -228,7 +270,7 @@ uint8_t * AddELFSymEntry(uint8_t * buf, SYM * sym, int globflag) D_byte(st_info); D_byte(0); // st_other - uint16_t st_shndx = 0xFFF1; // Assume absolute (equated) number + uint16_t st_shndx = SHN_ABS; // Assume absolute (equated) number if (w1 & TEXT) st_shndx = elfHdrNum[ES_TEXT]; @@ -236,8 +278,13 @@ uint8_t * AddELFSymEntry(uint8_t * buf, SYM * sym, int globflag) st_shndx = elfHdrNum[ES_DATA]; else if (w1 & BSS) st_shndx = elfHdrNum[ES_BSS]; - else if (globflag) - st_shndx = 0; // Global, not absolute + else if (globflag && !(w1 & DEFINED) && (w1 & REFERENCED)) + { + st_shndx = SHN_UNDEF; + } // If the symbol is global then probably we + // don't need to do anything (probably) + // since we set STB_GLOBAL in st_info above. + // Unless we need to set it to SHN_COMMON? D_word(st_shndx); @@ -248,7 +295,6 @@ uint8_t * AddELFSymEntry(uint8_t * buf, SYM * sym, int globflag) return buf + 0x10; } - // // Helper function for ELF output // @@ -269,7 +315,6 @@ int DepositELFSectionHeader(uint8_t * ptr, uint32_t name, uint32_t type, uint32_ return 40; } - // // Deposit an entry in the Section Header string table // @@ -284,7 +329,6 @@ printf("DepositELFSHSTEntry: s = \"%s\"\n", s); return strSize + 1; } - // // Deposit a symbol table entry in the ELF Symbol Table // @@ -301,21 +345,19 @@ uint32_t DepositELFSymbol(uint8_t * ptr, uint32_t name, uint32_t addr, uint32_t return 16; } - // // Write an object file to the passed in file descriptor // N.B.: Return value is ignored... // int WriteObject(int fd) { - LONG t; // Scratch long LONG tds; // TEXT & DATA segment size int i; // Temporary int CHUNK * cp; // Chunk (for gather) uint8_t * buf; // Scratch area uint8_t * p; // Temporary ptr LONG trsize, drsize; // Size of relocations - long unused; // For supressing 'write' warnings + uint32_t unused; // For supressing 'write' warnings if (verb_flag) { @@ -326,7 +368,9 @@ int WriteObject(int fd) // Write requested object file... if ((obj_format == BSD) || ((obj_format == ALCYON) && (prg_flag == 0))) - { + { + ch_size = 0; + // Force BSD format (if it was ALCYON format) obj_format = BSD; @@ -335,9 +379,9 @@ int WriteObject(int fd) printf("Total : %d bytes\n", sect[TEXT].sloc + sect[DATA].sloc + sect[BSS].sloc); } - sy_assign(NULL, NULL); // Assign index numbers to the symbols + AssignSymbolNos(NULL, NULL); // Assign index numbers to the symbols tds = sect[TEXT].sloc + sect[DATA].sloc; // Get size of TEXT and DATA segment - buf = malloc(0x800000); // Allocate 8MB object file image memory + buf = malloc(0x800000); // Allocate 8MB object file image memory if (buf == NULL) { @@ -351,6 +395,7 @@ int WriteObject(int fd) if (strtable == NULL) { + free(buf); error("cannot allocate string table memory (in BSD mode)"); return ERROR; } @@ -359,6 +404,8 @@ int WriteObject(int fd) // Build object file header chptr = buf; // Base of header (for D_foo macros) + ch_size = 0; + challoc = 0x800000; D_long(0x00000107); // Magic number D_long(sect[TEXT].sloc); // TEXT size D_long(sect[DATA].sloc); // DATA size @@ -394,7 +441,7 @@ int WriteObject(int fd) // Point to start of symbol table p = buf + BSDHDRSIZE + tds + trsize + drsize; - sy_assign(p, AddBSDSymEntry); // Build symbol and string tables + AssignSymbolNos(p, AddBSDSymEntry); // Build symbol and string tables chptr = buf + 0x10; // Point to sym table size hdr entry D_long(symsize); // Write the symbol table size @@ -421,6 +468,8 @@ int WriteObject(int fd) } else if (obj_format == ALCYON) { + ch_size = 0; + if (verb_flag) { if (prg_flag) @@ -431,7 +480,8 @@ int WriteObject(int fd) // Assign index numbers to the symbols, get # of symbols (we assume // that all symbols can potentially be extended, hence the x28) - uint32_t symbolMaxSize = sy_assign(NULL, NULL) * 28; + // (To clarify: 28 bytes is the size of an extended symbol) + uint32_t symbolMaxSize = AssignSymbolNos(NULL, NULL) * 28; // Alloc memory for header + text + data, symbol and relocation // information construction. @@ -440,6 +490,8 @@ int WriteObject(int fd) // Build object file header just before the text+data image chptr = buf; // -> base of header + ch_size = 0; + challoc = HDRSIZE + tds + symbolMaxSize; D_word(0x601A); // 00 - magic number D_long(sect[TEXT].sloc); // 02 - TEXT size D_long(sect[DATA].sloc); // 06 - DATA size @@ -469,10 +521,13 @@ int WriteObject(int fd) // Construct symbol table and update the header entry, if necessary if (prg_flag > 1) { - // sy_assign with AddSymEntry updates symsize (stays 0 otherwise) - sy_assign(buf + HDRSIZE + tds, AddSymEntry); + // AssignSymbolNos with AddSymEntry updates symsize (stays 0 otherwise) + AssignSymbolNos(buf + HDRSIZE + tds, AddSymEntry); chptr = buf + 0x0E; // Point to symbol table size entry D_long(symsize); + + if (verb_flag) + printf("Symbol table: %d bytes\n", symsize); } // Write out the header + text & data + symbol table (if any) @@ -592,6 +647,8 @@ for(int j=0; jELF" Magic Number D_byte(0x01); // 04 - 32 vs 64 (1 = 32, 2 = 64) D_byte(0x02); // 05 - Endianness (1 = LE, 2 = BE) @@ -721,7 +778,7 @@ for(int j=0; j base of header + ch_size = 0; + challoc = 0x600000; + + if (obj_format == LOD) + WriteLOD(); + else + WriteP56(); + + // Write all the things \o/ + unused = write(fd, buf, chptr - buf); + + if (buf) + free(buf); + } + else if (obj_format == RAW) + { + if (!org68k_active && used_architectures & (!(M6502 | M56001P | M56001X | M56001Y | M56001L))) + return error("cannot output absolute binary without a starting address (.org or command line)"); + + if (used_architectures & M6502) + { + // Okay, this is not the best. But it'll have to do until we revamp things a bit with sections. + // Basically we assume that if raw output is requested and 6502 mode was switched on, nobody + // switched to other architectures. The combination doesn't make much sense anyway for now. + m6502raw(fd); + return 0; + } + + // Alloc memory for text + data construction. + tds = sect[TEXT].sloc + sect[DATA].sloc; + buf = malloc(tds); + chptr = buf; + + // Construct text and data segments; fixup relocatable longs; + // finally write the text + data + + p = buf; + objImage = buf; // Set global object image pointer + for(i=TEXT; i<=DATA; i++) + { + for(cp=sect[i].sfcode; cp!=NULL; cp=cp->chnext) + { + memcpy(p, cp->chptr, cp->ch_size); + p += cp->ch_size; + } + } + + if (MarkABSImage(buf, tds, sect[TEXT].sloc, TEXT) != OK) // Do TEXT relocation table + { + return ERROR; + } + if (MarkABSImage(buf, tds, sect[TEXT].sloc, DATA) != OK) // Do DATA relocation table + { + return ERROR; + } + + // Write out the header + text & data + symbol table (if any) + unused = write(fd, buf, tds); + + } return 0; } +static void WriteLOD(void) +{ + D_printf("_START %s 0000 0000 0000 RMAC %01i.%01i.%01i\n\n", firstfname, MAJOR, MINOR, PATCH); + + for(DSP_ORG * l=&dsp_orgmap[0]; lend != l->start) + { + switch (l->memtype) + { + case ORG_P: D_printf("_DATA P %.4X\n", l->orgadr); break; + case ORG_X: D_printf("_DATA X %.4X\n", l->orgadr); break; + case ORG_Y: D_printf("_DATA Y %.4X\n", l->orgadr); break; + case ORG_L: D_printf("_DATA L %.4X\n", l->orgadr); break; + default: + error("Internal error: unknown DSP56001 org'd section"); + return; + } + + CHUNK * cp = l->chunk; + uint8_t * p_chunk = l->start; + uint8_t * p_chunk_end = p_chunk; + uint32_t j = 0; + + while (p_chunk_end != l->end) + { + if (l->end < (cp->chptr + cp->ch_size) && l->end > cp->chptr) + { + // If the end of the section is inside the current chunk, just dump everything and stop + p_chunk_end = l->end; + } + else + { + // If the end of the section is not inside the current chunk, just dump everything from the current chunk and move on to the next + p_chunk_end = cp->chptr + cp->ch_size; + } + + uint32_t count = (uint32_t)(p_chunk_end - p_chunk); + + for(uint32_t i=0; ichnext; // Advance chunk + + if (cp != NULL) + p_chunk = cp->chptr; // Set dump pointer to start of this chunk + } + + if ((j & 7) != 0) + D_printf("\n"); + } + } + + // Dump the symbol table into the buf + DumpLODSymbols(); + + D_printf("\n_END %.4X\n", dsp_orgmap[0].orgadr); +} + +static void WriteP56(void) +{ + for(DSP_ORG * l=&dsp_orgmap[0]; lend == l->start) + continue; + + if ((l->memtype < ORG_P) || (l->memtype > ORG_L)) + { + error("Internal error: unknown DSP56001 org'd section"); + return; + } + + CHUNK * cp = l->chunk; + uint8_t * p_chunk = l->start; + uint8_t * p_chunk_end = p_chunk; + + // Memory type (P, X, Y or L) + D_dsp(l->memtype); + + // Chunk start address (in DSP words) + D_dsp(l->orgadr); + + // Chunk length (in DSP words) + // We'll fill this field after we write the chunk so we can calculate + // how long it is (so if the chunk is split into different CHUNKs we + // can deal with this during copy) + uint8_t * p_buf_len = chptr; + chptr += 3; + + // The chunk itself + uint32_t chunk_size = 0; + + while (p_chunk_end != l->end) + { + if (l->end < (cp->chptr + cp->ch_size) && l->end > cp->chptr) + { + // If the end of the section is inside the current chunk, just + // dump everything and stop + p_chunk_end = l->end; + } + else + { + // If the end of the section is not inside the current chunk, + // just dump everything from the current chunk and move on to + // the next + p_chunk_end = cp->chptr + cp->ch_size; + } + + uint32_t current_chunk_size = p_chunk_end - p_chunk; + chunk_size += current_chunk_size; + memcpy(chptr, p_chunk, current_chunk_size); + chptr += current_chunk_size; + + cp = cp->chnext; // Advance chunk + + if (cp != NULL) + p_chunk = cp->chptr; // Set dump pointer to start of this chunk + } + + // Now we can mark the chunk's length (DSP word size is 24-bits, so + // the byte count needs to be divided by 3) + SETBE24(p_buf_len, chunk_size / 3); + } +}