X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?p=rln;a=blobdiff_plain;f=rln.c;h=a0b5ab02aa040e7e4c071822b100bba2956addba;hp=6f383bad5b687192a5d826dfbcc73b08c6a401e6;hb=HEAD;hpb=5c7a0db5a2628d9b30607ddeb0d22d543b400f2e diff --git a/rln.c b/rln.c index 6f383ba..212a05c 100644 --- a/rln.c +++ b/rln.c @@ -1,7 +1,6 @@ // -// RLN - Reboot's Linker for the Atari Jaguar Console System -// RLN.C - Application Code -// Copyright (C) 199x, Allan K. Pratt, 2014 Reboot & Friends +// RLN - Renamed Linker for the Atari Jaguar console system +// Copyright (C) 199x, Allan K. Pratt, 2014-2021 Reboot & Friends // #include "rln.h" @@ -23,7 +22,7 @@ unsigned sflag = 0; // Output only global symbols unsigned vflag = 0; // Verbose flag unsigned wflag = 0; // Show warnings flag unsigned zflag = 0; // Suppress banner flag -unsigned pflag = 0, uflag = 0; // Unimplemented flags +unsigned pflag = 0, uflag = 0; // Unimplemented flags (partial link, don't abort on unresolved symbols) unsigned hd = 0; // Index of next file handle to fill unsigned secalign = 7; // Section Alignment (8=phrase) unsigned tbase = 0; // TEXT base address @@ -34,9 +33,6 @@ unsigned dataoffset = 0; // COF DATA segment offset unsigned bssoffset = 0; // COF BSS segment offset unsigned displaybanner = 1; // Display version banner unsigned symoffset = 0; // Symbol table offset in output file -unsigned dosymi = 0; // Dosym() processing iterator -unsigned dbgsymbase = 0; // Debug symbol base address -//unsigned symtrunc = 0; // Symbol truncation -i and -ii int noheaderflag = 0; // No header flag for ABS files int hflags; // Value of the arg to -h option int ttype, dtype, btype; // Type flag: 0, -1, -2, -3, -4 @@ -54,66 +50,44 @@ struct OFILE * plist = NULL; // Object image list pointer struct OFILE * plast; // Last object image list pointer struct OFILE * olist = NULL; // Pointer to first object file in list struct OFILE * olast; // Pointer to last object file in list -char obj_fname[16384][FNLEN]; // Object file names -unsigned obj_segsize[16384][3]; // Object file seg sizes; TEXT,DATA,BSS -unsigned obj_index = 0; // Object file index/count char * arPtr[512]; uint32_t arIndex = 0; struct HREC * htable[NBUCKETS]; // Hash table struct HREC * unresolved = NULL; // Pointer to unresolved hash list -char * ost; // Output symbol table -char * ost_ptr; // Output symbol table; current pointer -char * ost_end; // Output symbol table; end pointer -char * oststr; // Output string table -char * oststr_ptr; // Output string table; current pointer -char * oststr_end; // Output string table; end pointer -int ost_index = 0; // Index of next ost addition -int endian; // Processor endianess +struct SYMREC * ost; // Output symbol table +char * oststr = NULL; // Output string table +char * oststr_ptr = NULL; // Output string table; current pointer +char * oststr_end = NULL; // Output string table; end pointer +int ost_index = 0; // Index of next free ost entry +int ost_size = 0; // Size of ost uint8_t nullStr[1] = "\x00"; // Empty string struct HREC * arSymbol = NULL; // Pointer to AR symbol table -// Some human readable defines for endianess -#define ENDIANNESS_BIG 1 -#define ENDIANNESS_LITTLE 0 // Function prototypes struct HREC * LookupHREC(char *); -char * path_tail(char *); -void display_help(void); -void display_version(void); +char * PathTail(char *); +void ShowHelp(void); +void ShowVersion(void); +int OSTLookup(char * sym); +int OSTAdd(char * name, int type, long value); +int ProcessFiles(void); +int doargs(int argc, char * argv[]); // // Get a long word from memory // -uint32_t getlong(uint8_t * src) +static inline uint32_t GetLong(uint8_t * src) { - uint32_t temp; - uint8_t * out = (uint8_t *)&temp; - - if (endian == ENDIANNESS_BIG) - { - *out++ = src[0]; - *out++ = src[1]; - *out++ = src[2]; - *out = src[3]; - } - else - { - *out++ = src[3]; - *out++ = src[2]; - *out++ = src[1]; - *out = src[0]; - } - - return temp; + return (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3]; } // // Put a long word into memory // -void putlong(uint8_t * dest, uint32_t val) +static inline void PutLong(uint8_t * dest, uint32_t val) { *dest++ = (uint8_t)(val >> 24); *dest++ = (uint8_t)(val >> 16); @@ -125,30 +99,16 @@ void putlong(uint8_t * dest, uint32_t val) // // Get a word from memory // -uint16_t getword(uint8_t * src) +static inline uint16_t GetWord(uint8_t * src) { - uint16_t temp; - uint8_t * out = (uint8_t *)&temp; - - if (endian == ENDIANNESS_BIG) - { - out[0] = src[0]; - out[1] = src[1]; - } - else - { - out[0] = src[1]; - out[1] = src[0]; - } - - return temp; + return (src[0] << 8) | src[1]; } // // Put a word into memory // -void putword(uint8_t * dest, uint16_t val) +static inline void PutWord(uint8_t * dest, uint16_t val) { *dest++ = (uint8_t)(val >> 8); *dest = (uint8_t)val; @@ -177,9 +137,10 @@ int DoSymbols(struct OFILE * ofile) int type; long value; int index; + char *string; int j; struct HREC * hptr; - unsigned tsoSave, dsoSave, bsoSave; + uint32_t tsoSave, dsoSave, bsoSave; // Point to first symbol record in the object file char * symptr = (ofile->o_image + 32 @@ -191,33 +152,9 @@ int DoSymbols(struct OFILE * ofile) // Point to end of symbol record in the object file char * symend = symptr + ofile->o_header.ssize; - // Search through object segment size table to accumulated segment sizes to - // ensure the correct offsets are used in the resulting COF file. - int ssidx = -1; - unsigned tsegoffset = 0, dsegoffset = 0, bsegoffset = 0; - - // Search for object file name - for(j=0; j<(int)obj_index; j++) - { - if (!strcmp(ofile->o_name, obj_fname[j])) - { - // Object file name found - ssidx = j; - break; - } - - // Accumulate segment sizes - tsegoffset += obj_segsize[j][0]; - dsegoffset += obj_segsize[j][1]; - bsegoffset += obj_segsize[j][2]; - } - - if (ssidx == -1) - { - printf("DoSymbols(): Object file missing from obj_fname: %s\n", - ofile->o_name); - return 1; - } + uint32_t tsegoffset = ofile->segBase[TEXT]; + uint32_t dsegoffset = ofile->segBase[DATA]; + uint32_t bsegoffset = ofile->segBase[BSS]; // Save segment vars, so we can restore them if needed tsoSave = tsegoffset, dsoSave = dsegoffset, bsoSave = bsegoffset; @@ -225,9 +162,10 @@ int DoSymbols(struct OFILE * ofile) // Process each record in the object's symbol table for(; symptr!=symend; symptr+=12) { - index = getlong(symptr + 0); // Obtain symbol string index - type = getlong(symptr + 4); // Obtain symbol type - value = getlong(symptr + 8); // Obtain symbol value + index = GetLong(symptr + 0); // Obtain symbol string index + type = GetLong(symptr + 4); // Obtain symbol type + value = GetLong(symptr + 8); // Obtain symbol value + string = index ? symend + index : ""; // Global/External symbols have a pre-processing stage // N.B.: This destroys the t/d/bsegoffset discovered above. So if a @@ -238,62 +176,37 @@ int DoSymbols(struct OFILE * ofile) // Obtain the string table index for the relocation symbol, look // for it in the globals hash table to obtain information on that // symbol. - hptr = LookupHREC(symend + index); + hptr = LookupHREC(string); if (hptr == NULL) { // Try to find it in the OST - int ostIndex = OSTLookup(symend + index); + int ostIndex = OSTLookup(string); if (ostIndex == -1) { - printf("DoSymbols(): Symbol not found in hash table: '%s' (%s)\n", symend + index, ofile->o_name); + printf("DoSymbols(): Symbol not found in hash table: '%s' (%s)\n", string, ofile->o_name); return 1; } + if (vflag > 1) + printf("DoSymbols(): Skipping symbol '%s' (%s) found in OST...\n", string, ofile->o_name); + // If the symbol is not in any .a or .o units, it must be one // of the injected ones (_TEXT_E, _DATA_E, or _BSS_E), so skip - // it + // it [or maybe not? In verbose mode, we see nothing...!] continue; } - // Search through object segment size table to obtain segment sizes - // for the object that has the required external/global as a local - // symbol. As each object is interrogated the segment sizes are - // accumulated to ensure the correct offsets are used in the - // resulting COF file. This is effectively 'done again' only as we - // are working with a different object file. - ssidx = -1; - tsegoffset = dsegoffset = bsegoffset = 0; - - // Search for object filename - for(j=0; j<(int)obj_index; j++) - { - if (!strcmp(hptr->h_ofile->o_name, obj_fname[j])) - { - ssidx = j; // Symbol object filename - break; - } - - // Accumulate segment sizes - tsegoffset += obj_segsize[j][0]; - dsegoffset += obj_segsize[j][1]; - bsegoffset += obj_segsize[j][2]; - } - - if (ssidx == -1) - { - printf("DoSymbols(): Object file missing from obj_fname: '%s:%s' symbol: '%s' (%s)\n", - hptr->h_ofile->o_name, hptr->h_ofile->o_arname, - symend + index, ofile->o_name); - return 1; - } + tsegoffset = hptr->h_ofile->segBase[TEXT]; + dsegoffset = hptr->h_ofile->segBase[DATA]; + bsegoffset = hptr->h_ofile->segBase[BSS]; // Update type with global type type = hptr->h_type; - // Remove external flag if absolute - if (type == (T_EXT | T_ABS)) + // Remove global flag if absolute + if (type == (T_GLBL | T_ABS)) type = T_ABS; // If the global/external has a value then update that value in @@ -315,6 +228,9 @@ int DoSymbols(struct OFILE * ofile) - (hptr->h_ofile->o_header.tsize + hptr->h_ofile->o_header.dsize); break; + default: + if (vflag > 1) + printf("DoSymbols: No adjustment made for symbol: %s (%s) = %X\n", string, ofile->o_name, hptr->h_value); } } } @@ -324,30 +240,29 @@ int DoSymbols(struct OFILE * ofile) // Process and update the value dependent on whether the symbol is a // debug symbol or not - // N.B.: These are currently not supported + // N.B.: Debug symbols are currently not supported if (type & 0xF0000000) { // DEBUG SYMBOL - // Set the correct debug symbol base address (TEXT segment) - dbgsymbase = 0; - - for(j=0; (unsigned)jo_header.tsize); - putlong(symptr + 8, value); + PutLong(symptr + 8, value); break; case T_BSS: - if (type & T_EXT) + if (type & T_GLBL) value = bbase + bsegoffset + value; else value = bbase + bsegoffset + (value - (ofile->o_header.tsize + ofile->o_header.dsize)); - putlong(symptr + 8, value); + PutLong(symptr + 8, value); break; default: break; @@ -390,19 +305,19 @@ int DoSymbols(struct OFILE * ofile) // Add to output symbol table if global/extern, or local flag is set if (isglobal(type) || lflag) { - index = OSTAdd(symend + index, type, value); + if (vflag > 1) + printf("DoSymbols: Adding symbol: %s (%s) to OST...\n", string, ofile->o_name); + + index = OSTAdd(index ? string : NULL, type, value); if (index == -1) { - printf("DoSymbols(): Failed to add symbol '%s' to OST!\n", symend + index); + printf("DoSymbols(): Failed to add symbol '%s' to OST!\n", string); return 1; } } } - // Increment dosymi processsing - dosymi++; - return 0; } @@ -434,6 +349,10 @@ void FreeHashes(void) // but then again, we see this in the header: // #define T_COMMON (T_GLOBAL | T_EXTERN) but that could be just bullshit.] // +// Common symbols have a different number in the "value" field of the symbol +// table (!0) than purely external symbols do (0). So you have to look at the +// type (T_GLBL) *and* the value to determine if it's a common symbol. +// long DoCommon(void) { struct HREC * hptr; @@ -451,7 +370,7 @@ long DoCommon(void) // continue; //Is this true? Couldn't an absolute be exported??? - if (hptr->h_type == (T_EXT | T_ABS)) + if (hptr->h_type == (T_GLBL | T_ABS)) hptr->h_type = T_ABS; // Absolutes *can't* be externals if (OSTAdd(hptr->h_sym, hptr->h_type, hptr->h_value) == -1) @@ -470,129 +389,102 @@ long DoCommon(void) // int OSTAdd(char * name, int type, long value) { - int ost_offset_p, ost_offset_e = 0; // OST table offsets for position calcs + int ost_offset_p = 0, ost_offset_e; // OST table offsets for position calcs int ostresult; // OST index result - int slen = strlen(name); + int slen; // String length, including terminator - // If the OST or OST string table has not been initialised then do so - if (ost_index == 0) + // If this is a debug symbol and the include debug symbol flag (-g) is not + // set then do nothing + if ((type & 0xF0000000) && !gflag) { - ost = malloc(OST_BLOCK); - oststr = malloc(OST_BLOCK); - - if (ost == NULL) - { - printf("OST memory allocation error.\n"); - return -1; - } + // Do nothing + return 0; + } - if (oststr == NULL) - { - printf("OSTSTR memory allocation error.\n"); - return -1; - } + if (!name || !name[0]) + slen = 0; + else + slen = strlen(name) + 1; - ost_ptr = ost; // Set OST start pointer - ost_end = ost + OST_BLOCK; // Set OST end pointer + // Get symbol index in OST, if any (-1 if not found) + ostresult = slen ? OSTLookup(name) : -1; - putlong(oststr, 0x00000004); // Just null long for now - oststr_ptr = oststr + 4; // Skip size of str table long (incl null long) - putlong(oststr_ptr, 0x00000000); // Null terminating long - oststr_end = oststr + OST_BLOCK; + // If the symbol is in the output symbol table and the bflag is set + // (don't remove multiply defined locals) and this is not an + // external/global symbol, or the gflag (output debug symbols) is + // set and this a debug symbol, *** OR *** the symbol is not in the + // output symbol table then add it. + if ((ostresult != -1) && !(bflag && !(type & 0x01000000)) + && !(gflag && (type & 0xF0000000))) + { + return ostresult; } - else + + // If the OST has not been initialised, or more space is needed, then + // allocate it. + if ((ost_index + 1) > ost_size) { - // If next symbol record exceeds current allocation then expand symbol - // table and/or symbol string table. - ost_offset_p = (ost_ptr - ost); - ost_offset_e = (ost_end - ost); + if (ost_size == 0) + ost_size = OST_SIZE_INIT; - // 3 x uint32_t (12 bytes) - if ((ost_ptr + 12) > ost_end) - { - // We want to allocate the current size of the OST + another block. - ost = realloc(ost, ost_offset_e + OST_BLOCK); + ost_size *= 2; - if (ost == NULL) - { - printf("OST memory reallocation error.\n"); - return -1; - } + ost = realloc(ost, ost_size * sizeof(ost[0])); - ost_ptr = ost + ost_offset_p; - ost_end = (ost + ost_offset_e) + OST_BLOCK; + if (ost == NULL) + { + printf("OST memory allocation error.\n"); + return -1; } + } + if (slen) + { ost_offset_p = (oststr_ptr - oststr); ost_offset_e = (oststr_end - oststr); - // string length + terminating NULL + uint32_t (terminal long) - if ((oststr_ptr + (slen + 1 + 4)) > oststr_end) + // If the OST data has been exhausted, allocate another chunk. + if (((oststr_ptr + slen + 4) > oststr_end)) { - oststr = realloc(oststr, ost_offset_e + OST_BLOCK); - - if (oststr == NULL) + // string length + terminating NULL + uint32_t (terminal long) + if ((oststr_ptr + (slen + 1 + 4)) > oststr_end) { - printf("OSTSTR memory reallocation error.\n"); - return -1; - } + oststr = realloc(oststr, ost_offset_e + OST_BLOCK); - oststr_ptr = oststr + ost_offset_p; - oststr_end = (oststr + ost_offset_e) + OST_BLOCK; - } - } - - // If this is a debug symbol and the include debug symbol flag (-g) is not - // set then do nothing - if ((type & 0xF0000000) && !gflag) - { - // Do nothing - return 0; - } + if (oststr == NULL) + { + printf("OSTSTR memory reallocation error.\n"); + return -1; + } - // Get symbol index in OST, if any (-1 if not found) - ostresult = OSTLookup(name); + oststr_ptr = oststr + ost_offset_p; + oststr_end = (oststr + ost_offset_e) + OST_BLOCK; - // If the symbol is in the output symbol table and the bflag is set - // (don't remove multiply defined locals) and this is not an - // external/global symbol *** OR *** the symbol is not in the output - // symbol table then add it. - if (((ostresult != -1) && bflag && !(type & 0x01000000)) - || ((ostresult != -1) && gflag && (type & 0xF0000000)) - || (ostresult == -1)) - { - if ((type & 0xF0000000) == 0x40000000) - putlong(ost_ptr, 0x00000000); // Zero string table offset for dbg line - else - putlong(ost_ptr, (oststr_ptr - oststr)); // String table offset of symbol string + // On the first alloc, reserve space for the string table + // size field. + if (ost_offset_e == 0) + oststr_ptr += 4; + } + } - putlong(ost_ptr + 4, type); - putlong(ost_ptr + 8, value); - ost_ptr += 12; + strcpy(oststr_ptr, name); // Put symbol name in string table + oststr_ptr += slen; + oststr_ptr[-1] = '\0'; // Add null terminating character + PutLong(oststr_ptr, 0x00000000); // Null terminating long + PutLong(oststr, (oststr_ptr - oststr)); // Update size of string table + } - // If the symbol type is anything but a debug line information - // symbol then write the symbol string to the string table - if ((type & 0xF0000000) != 0x40000000) - { - strcpy(oststr_ptr, name); // Put symbol name in string table - *(oststr_ptr + slen) = '\0'; // Add null terminating character - oststr_ptr += (slen + 1); - putlong(oststr_ptr, 0x00000000); // Null terminating long - putlong(oststr, (oststr_ptr - oststr)); // Update size of string table - } + ostresult = ost_index++; - if (vflag > 1) - { - printf("OSTAdd: (%s), type=$%08X, val=$%08lX\n", name, type, value); - } + ost[ostresult].s_idx = ost_offset_p; + ost[ostresult].s_type = type; + ost[ostresult].s_value = value; -// is ost_index pointing one past? -// does this return the same regardless of if its ++n or n++? -// no. it returns the value of ost_index *before* it's incremented. - return ++ost_index; - } + if (vflag > 1) + printf("OSTAdd: (%s), type=$%08X, val=$%08lX\n", + slen ? name : "", type, value); - return ostresult; + return ost_index; } @@ -603,14 +495,11 @@ int OSTAdd(char * name, int type, long value) int OSTLookup(char * sym) { int i; - int stro = 4; // Offset in string table for(i=0; ih_sym, T_EXT, 0L) == -1) + if (OSTAdd(hptr->h_sym, T_GLBL, 0L) == -1) return 1; if (vflag > 1) @@ -667,8 +556,12 @@ int RelocateSegment(struct OFILE * ofile, int flag) unsigned glblreloc; // Global relocation flag unsigned absreloc; // Absolute relocation flag unsigned relreloc; // Relative relocation flag + unsigned wordreloc; // Relocate word only flag + unsigned opreloc; // Relocate OP data address only flag unsigned swcond; // Switch statement condition unsigned relocsize; // Relocation record size + unsigned saveBits; // OP data leftover bits save + unsigned saveBits2; // If there is no TEXT relocation data for the selected object file segment // then update the COF TEXT segment offset allowing for the phrase padding @@ -690,27 +583,25 @@ int RelocateSegment(struct OFILE * ofile, int flag) textoffset += (ofile->o_header.tsize + (pad - ofile->o_header.tsize)); if (vflag > 1) - printf("RelocateSegment(%s, TEXT) : No Relocation Data\n", ofile->o_name); + printf("RelocateSegment(%s, TEXT) : No relocation data\n", ofile->o_name); // DATA segment size plus padding pad = ((ofile->o_header.dsize + secalign) & ~secalign); dataoffset += (ofile->o_header.dsize + (pad - ofile->o_header.dsize)); + // BSS segment size plus padding pad = ((ofile->o_header.bsize + secalign) & ~secalign); bssoffset += (ofile->o_header.bsize + (pad - ofile->o_header.bsize)); if (vflag > 1) - printf("RelocateSegment(%s, DATA) : No Relocation Data\n", ofile->o_name); + printf("RelocateSegment(%s, DATA) : No relocation data\n", ofile->o_name); return 0; } - // Verbose mode information if (vflag > 1) - { printf("RelocateSegment(%s, %s) : Processing Relocation Data\n", ofile->o_name, flag == T_DATA ? "DATA" : "TEXT"); - } // Obtain pointer to start of symbol table symtab = (ofile->o_image + 32 + ofile->o_header.tsize @@ -745,11 +636,13 @@ int RelocateSegment(struct OFILE * ofile, int flag) { // Obtain both the relocation address and the relocation flags from the // object file image - addr = getlong(rptr); - rflg = getlong(rptr + 4); - glblreloc = (rflg & 0x00000010 ? 1 : 0);// Set global relocation flag - absreloc = (rflg & 0x00000040 ? 1 : 0); // Set absolute relocation flag - relreloc = (rflg & 0x000000A0 ? 1 : 0); // Set relative relocation flag + addr = GetLong(rptr); + rflg = GetLong(rptr + 4); + glblreloc = (rflg & BSDREL_GLOBAL ? 1 : 0); + absreloc = (rflg & BSDREL_ABS ? 1 : 0); + relreloc = (rflg & BSDREL_PCREL ? 1 : 0); + wordreloc = (rflg & BSDREL_WORD ? 1 : 0); + opreloc = (rflg & BSDREL_OP ? 1 : 0); // Additional processing required for global relocations if (glblreloc) @@ -758,44 +651,57 @@ int RelocateSegment(struct OFILE * ofile, int flag) // for it in the globals hash table to obtain information on that // symbol. For the hash calculation to work correctly it must be // placed in a 'clean' string before looking it up. - symidx = getlong(symtab + ((rflg >> 8) * 12)); + symidx = GetLong(symtab + (BSDREL_SYMIDX(rflg) * 12)); memset(sym, 0, SYMLEN); strcpy(sym, symbols + symidx); olddata = newdata = 0; // Initialise old and new segment data ssidx = OSTLookup(sym); - newdata = getlong(ost + ((ssidx - 1) * 12) + 8); + newdata = ost[ssidx - 1].s_value; } - // Obtain the existing long word segment data and flip words if the - // relocation flags indicate it relates to a RISC MOVEI instruction - olddata = getlong(sptr + addr); + // Obtain the existing long word (or word) segment data and flip words + // if the relocation flags indicate it relates to a RISC MOVEI + // instruction + olddata = (wordreloc ? GetWord(sptr + addr) : GetLong(sptr + addr)); - if (rflg & 0x01) + // If it's a OP QUAD relocation, get the data out of the DATA bits. + // Note that because we can't afford to lose the bottom 3 bits of the + // relocation record, we lose 3 off the top--which means the maximum + // this can store is $1FFFF8 (vs. $FFFFF8). + if (opreloc) + { + saveBits2 = (GetLong(sptr + addr + 8) & 0xE0000000) >> 8; // Upper 3 of data addr + saveBits = olddata & 0x7FF; + olddata = (olddata & 0xFFFFF800) >> 11; + olddata |= saveBits2; // Restore upper 3 bits of data addr + } + + if (rflg & BSDREL_MOVEI) olddata = _SWAPWORD(olddata); // Process record dependant on segment it relates to; TEXT, DATA or // BSS. Construct a new relocated segment long word based on the // required segment base address, the segment data offset in the // resulting COF file and the offsets from the incoming object file. - swcond = (rflg & 0xFFFFFF00); + swcond = (rflg & BSDREL_SEGMASK); if (!glblreloc) { switch (swcond) { - case 0x00000200: // Absolute Value + case BSDREL_SEG_ABS: break; - case 0x00000400: // TEXT segment relocation record + case BSDREL_SEG_TEXT: // SCPCD : the symbol point to a text segment, we should use the textoffset - newdata = tbase + textoffset + olddata; + newdata = tbase + textoffset + olddata; break; - case 0x00000600: // DATA segment relocation record + case BSDREL_SEG_DATA: newdata = dbase + dataoffset + (olddata - ofile->o_header.tsize); break; - case 0x00000800: // BSS segment relocation record + case BSDREL_SEG_BSS: newdata = bbase + bssoffset + (olddata - (ofile->o_header.tsize + ofile->o_header.dsize)); @@ -815,14 +721,28 @@ int RelocateSegment(struct OFILE * ofile, int flag) // Flip the new long word segment data if the relocation record // indicated a RISC MOVEI instruction and place the resulting data // back in the COF segment - if (rflg & 0x01) + if (rflg & BSDREL_MOVEI) newdata = _SWAPWORD(newdata); - putlong(sptr + addr, newdata); + if (wordreloc) + PutWord(sptr + addr, newdata); + else if (opreloc) + { + if (vflag > 1) + printf("OP reloc: oldata=$%X, newdata=$%X\n", olddata, newdata); + + newdata = ((newdata & 0x00FFFFF8) << 8) | saveBits; + PutLong(sptr + addr, newdata); + // Strip out extraneous data hitchhikers from 2nd phrase... + newdata = GetLong(sptr + addr + 8) & 0x007FFFFF; + PutLong(sptr + addr + 8, newdata); + } + else + PutLong(sptr + addr, newdata); } else if (relreloc) { - putword(sptr + addr, newdata - tbase - addr - ofile->o_tbase); + PutWord(sptr + addr, newdata - tbase - addr - ofile->o_tbase); } // Shamus: Let's output some info to aid in debugging this crap @@ -834,7 +754,7 @@ int RelocateSegment(struct OFILE * ofile, int flag) if (glblreloc) sprintf(ssiString, " [ssi:%i]", ssidx); - printf("RelocateSegment($%08X): %s, $%08X: $%08X => $%08X%s\n", rflg, (glblreloc ? sym : "(LOCAL)"), addr, olddata, getlong(sptr + addr), ssiString); + printf("RelocateSegment($%08X): %s, $%08X: $%08X => $%08X%s\n", rflg, (glblreloc ? sym : "(LOCAL)"), addr, olddata, GetLong(sptr + addr), ssiString); } rptr += 8; // Point to the next relocation record @@ -851,6 +771,7 @@ int RelocateSegment(struct OFILE * ofile, int flag) // DATA segment plus padding pad = ((ofile->o_header.dsize + secalign) & ~secalign); dataoffset += (ofile->o_header.dsize + (pad - ofile->o_header.dsize)); + // BSS segment plus padding pad = ((ofile->o_header.bsize + secalign) & ~secalign); bssoffset += (ofile->o_header.bsize + (pad - ofile->o_header.bsize)); @@ -981,9 +902,9 @@ ok: // -// Archive File Use, Needs to be Removed [Shamus: NON!] +// What it says on the tin // -void put_name(struct OFILE * p) +void WriteARName(struct OFILE * p) { int flag = *(p->o_arname); printf("%s%s%s", (flag ? (char *)(p->o_arname) : ""), (flag ? ":" : ""), p->o_name); @@ -1080,7 +1001,7 @@ int DoFile(char * fname, int incFlag, char * sym) // // Pad TEXT or DATA segment to the requested boundary // -int segmentpad(FILE * fd, long segsize, int value) +int PadSegment(FILE * fd, long segsize, int value) { int i; char padarray[32]; @@ -1097,7 +1018,7 @@ int segmentpad(FILE * fd, long segsize, int value) for(i=0; i<16; i++) { - putword(padptr, value); + PutWord(padptr, value); padptr += 2; } @@ -1115,17 +1036,15 @@ int segmentpad(FILE * fd, long segsize, int value) // // Write the output file // -int write_ofile(struct OHEADER * header) +int WriteOutputFile(struct OHEADER * header) { unsigned osize; // Object segment size struct OFILE * otemp; // Object file pointer int i, j; // Iterators char himage[0x168]; // Header image (COF = 0xA8) - unsigned tsoff, dsoff, bsoff; // Segment offset values - unsigned index, type, value; // Symbol table index, type and value + uint32_t tsoff, dsoff, bsoff; // Segment offset values short abstype; // ABS symbol type - char symbol[14]; // Symbol record for ABS files - int slen; // Symbol string length + char symbol[14]; // raw symbol record symoffset = 0; // Initialise symbol offset @@ -1133,11 +1052,11 @@ int write_ofile(struct OHEADER * header) if (strchr(ofile, '.') == NULL) { if (aflag && cflag) - strcat(ofile, ".cof"); // COF files + strcat(ofile, ".cof"); // COF files (a type of abs) else if (aflag && !cflag) strcat(ofile, ".abs"); // ABS files else - strcat(ofile, ".o"); // Object files (partial linking etc) + strcat(ofile, ".o"); // Object files (partial linking, etc) } FILE * fd = fopen(ofile, "wb"); // Attempt to open output file @@ -1156,68 +1075,68 @@ int write_ofile(struct OHEADER * header) // Process each object file segment size to obtain a cumulative segment // size for both the TEXT and DATA segments - for(i=0; i<(int)obj_index; i++) + for(otemp=olist; otemp!=NULL; otemp=otemp->o_next) { - dsoff += obj_segsize[i][0]; // Adding TEXT segment sizes - bsoff += obj_segsize[i][0] + obj_segsize[i][1]; // Adding TEXT and DATA segment sizes + dsoff += otemp->segSize[TEXT]; + bsoff += otemp->segSize[TEXT] + otemp->segSize[DATA]; } // Currently this only builds a COF absolute file. Conditionals and // additional code will need to be added for ABS and partial linking. // Build the COF_HDR - putword(himage + 0, 0x0150 ); // Magic Number (0x0150) - putword(himage + 2, 0x0003 ); // Sections Number (3) - putlong(himage + 4, 0x00000000 ); // Date (0L) - putlong(himage + 8, dsoff + header->dsize); // Offset to Symbols Section - putlong(himage + 12, ost_index); // Number of Symbols - putword(himage + 16, 0x001C ); // Size of RUN_HDR (0x1C) - putword(himage + 18, 0x0003 ); // Executable Flags (3) + PutWord(himage + 0, 0x0150 ); // Magic Number (0x0150) + PutWord(himage + 2, 0x0003 ); // Sections Number (3) + PutLong(himage + 4, 0x00000000 ); // Date (0L) + PutLong(himage + 8, dsoff + header->dsize); // Offset to Symbols Section + PutLong(himage + 12, ost_index); // Number of Symbols + PutWord(himage + 16, 0x001C ); // Size of RUN_HDR (0x1C) + PutWord(himage + 18, 0x0003 ); // Executable Flags (3) // Build the RUN_HDR - putlong(himage + 20, 0x00000107 ); // Magic/vstamp - putlong(himage + 24, header->tsize ); // TEXT size in bytes - putlong(himage + 28, header->dsize ); // DATA size in bytes - putlong(himage + 32, header->bsize ); // BSS size in bytes - putlong(himage + 36, tbase ); // Start of executable, normally @TEXT - putlong(himage + 40, tbase ); // @TEXT - putlong(himage + 44, dbase ); // @DATA + PutLong(himage + 20, 0x00000107 ); // Magic/vstamp + PutLong(himage + 24, header->tsize ); // TEXT size in bytes + PutLong(himage + 28, header->dsize ); // DATA size in bytes + PutLong(himage + 32, header->bsize ); // BSS size in bytes + PutLong(himage + 36, tbase ); // Start of executable, normally @TEXT + PutLong(himage + 40, tbase ); // @TEXT + PutLong(himage + 44, dbase ); // @DATA // Build the TEXT SEC_HDR - putlong(himage + 48, 0x2E746578 ); - putlong(himage + 52, 0x74000000 ); // ".text" - putlong(himage + 56, tbase ); // TEXT START - putlong(himage + 60, tbase ); // TEXT START - putlong(himage + 64, header->tsize ); // TEXT size in bytes - putlong(himage + 68, tsoff ); // Offset to section data in file - putlong(himage + 72, 0x00000000 ); // Offset to section reloc in file (0L) - putlong(himage + 76, 0x00000000 ); // Offset to debug lines structures (0L) - putlong(himage + 80, 0x00000000 ); // Nreloc/nlnno (0L) - putlong(himage + 84, 0x00000020 ); // SEC_FLAGS: STYP_TEXT + PutLong(himage + 48, 0x2E746578 ); + PutLong(himage + 52, 0x74000000 ); // ".text" + PutLong(himage + 56, tbase ); // TEXT START + PutLong(himage + 60, tbase ); // TEXT START + PutLong(himage + 64, header->tsize ); // TEXT size in bytes + PutLong(himage + 68, tsoff ); // Offset to section data in file + PutLong(himage + 72, 0x00000000 ); // Offset to section reloc in file (0L) + PutLong(himage + 76, 0x00000000 ); // Offset to debug lines structures (0L) + PutLong(himage + 80, 0x00000000 ); // Nreloc/nlnno (0L) + PutLong(himage + 84, 0x00000020 ); // SEC_FLAGS: STYP_TEXT // Build the DATA SEC_HDR - putlong(himage + 88, 0x2E646174 ); - putlong(himage + 92, 0x61000000 ); // ".data" - putlong(himage + 96, dbase ); // DATA START - putlong(himage + 100, dbase ); // DATA START - putlong(himage + 104, header->dsize ); // DATA size in bytes - putlong(himage + 108, dsoff ); // Offset to section data in file - putlong(himage + 112, 0x00000000 ); // Offset to section reloc in file (0L) - putlong(himage + 116, 0x00000000 ); // Offset to debugging lines structures (0L) - putlong(himage + 120, 0x00000000 ); // Nreloc/nlnno (0L) - putlong(himage + 124, 0x00000040 ); // SEC_FLAGS: STYP_DATA + PutLong(himage + 88, 0x2E646174 ); + PutLong(himage + 92, 0x61000000 ); // ".data" + PutLong(himage + 96, dbase ); // DATA START + PutLong(himage + 100, dbase ); // DATA START + PutLong(himage + 104, header->dsize ); // DATA size in bytes + PutLong(himage + 108, dsoff ); // Offset to section data in file + PutLong(himage + 112, 0x00000000 ); // Offset to section reloc in file (0L) + PutLong(himage + 116, 0x00000000 ); // Offset to debugging lines structures (0L) + PutLong(himage + 120, 0x00000000 ); // Nreloc/nlnno (0L) + PutLong(himage + 124, 0x00000040 ); // SEC_FLAGS: STYP_DATA // Build the BSS SEC_HDR - putlong(himage + 128, 0x2E627373 ); - putlong(himage + 132, 0x00000000 ); // ".bss" - putlong(himage + 136, bbase ); // BSS START - putlong(himage + 140, bbase ); // BSS START - putlong(himage + 144, header->bsize ); // BSS size in bytes - putlong(himage + 148, bsoff ); // Offset to section data in file - putlong(himage + 152, 0x00000000 ); // Offset to section reloc in file (0L) - putlong(himage + 156, 0x00000000 ); // Offset to debugging lines structures (0L) - putlong(himage + 160, 0x00000000 ); // Nreloc/nlnno (0L) - putlong(himage + 164, 0x00000080 ); // SEC_FLAGS: STYP_BSS + PutLong(himage + 128, 0x2E627373 ); + PutLong(himage + 132, 0x00000000 ); // ".bss" + PutLong(himage + 136, bbase ); // BSS START + PutLong(himage + 140, bbase ); // BSS START + PutLong(himage + 144, header->bsize ); // BSS size in bytes + PutLong(himage + 148, bsoff ); // Offset to section data in file + PutLong(himage + 152, 0x00000000 ); // Offset to section reloc in file (0L) + PutLong(himage + 156, 0x00000000 ); // Offset to debugging lines structures (0L) + PutLong(himage + 160, 0x00000000 ); // Nreloc/nlnno (0L) + PutLong(himage + 164, 0x00000080 ); // SEC_FLAGS: STYP_BSS symoffset = 168; // Update symbol offset } @@ -1225,33 +1144,35 @@ int write_ofile(struct OHEADER * header) else { // Build the ABS header - putword(himage + 0, 0x601B ); // Magic Number (0x601B) - putlong(himage + 2, header->tsize ); // TEXT segment size - putlong(himage + 6, header->dsize ); // DATA segment size - putlong(himage + 10, header->bsize ); // BSS segment size - putlong(himage + 14, ost_index * 14 ); // Symbol table size (?) - putlong(himage + 18, 0x00000000 ); // - putlong(himage + 22, tbase ); // TEXT base address - putword(himage + 26, 0xFFFF ); // Flags (?) - putlong(himage + 28, dbase ); // DATA base address - putlong(himage + 32, bbase ); // BSS base address + PutWord(himage + 0, 0x601B ); // Magic Number (0x601B) + PutLong(himage + 2, header->tsize ); // TEXT segment size + PutLong(himage + 6, header->dsize ); // DATA segment size + PutLong(himage + 10, header->bsize ); // BSS segment size + PutLong(himage + 14, ost_index * 14 ); // Symbol table size (?) + PutLong(himage + 18, 0x00000000 ); // + PutLong(himage + 22, tbase ); // TEXT base address + PutWord(himage + 26, 0xFFFF ); // Flags (?) + PutLong(himage + 28, dbase ); // DATA base address + PutLong(himage + 32, bbase ); // BSS base address symoffset = 36; // Update symbol offset } // Write the header, but not if noheaderflag - // Absolute (ABS) header - if (!cflag) + if (!noheaderflag) { - if (!noheaderflag) + // Absolute (ABS) header + if (!cflag) + { if (fwrite(himage, 36, 1, fd) != 1) goto werror; - } - // Absolute (COF) header - else - { - if (fwrite(himage, 168, 1, fd) != 1) - goto werror; + } + // Absolute (COF) header + else + { + if (fwrite(himage, 168, 1, fd) != 1) + goto werror; + } } // Write the TEXT segment of each object file @@ -1269,7 +1190,7 @@ int write_ofile(struct OHEADER * header) goto werror; // Pad to required alignment boundary - if (segmentpad(fd, osize, 0x0000)) + if (PadSegment(fd, osize, 0x0000)) goto werror; symoffset += osize; @@ -1291,14 +1212,19 @@ int write_ofile(struct OHEADER * header) goto werror; // Pad to required alignment boundary - if (segmentpad(fd, osize, 0)) + if (PadSegment(fd, osize, 0)) goto werror; symoffset += osize; } } - if (!noheaderflag) +//wha? if (!noheaderflag) + // This isn't quite right, but it's closer... + // (the l and s flags tell the linker to output local & global symbols + // in the symbol table, so it seems there's some other thing that's a + // default set somewhere. Not 100% sure. Setting -s kills -l, BTW...) + if (lflag || sflag) { // Write the symbols table and string table // Absolute (COF) symbol/string table @@ -1306,8 +1232,15 @@ int write_ofile(struct OHEADER * header) { if (header->ssize) { - if (fwrite(ost, (ost_ptr - ost), 1, fd) != 1) - goto werror; + for (i = 0; i < ost_index; i++) + { + PutLong(symbol, ost[i].s_idx); + PutLong(symbol + 4, ost[i].s_type); + PutLong(symbol + 8, ost[i].s_value); + + if (fwrite(symbol, 12, 1, fd) != 1) + goto werror; + } if (fwrite(oststr, (oststr_ptr - oststr), 1, fd) != 1) goto werror; @@ -1327,32 +1260,16 @@ int write_ofile(struct OHEADER * header) { memset(symbol, 0, 14); // Initialise symbol record abstype = 0; // Initialise ABS symbol type - slen = 0; // Initialise symbol string length - index = getlong(ost + (i * 12)); // Get symbol index - type = getlong((ost + (i * 12)) + 4); // Get symbol type // Skip debug symbols - if (type & 0xF0000000) + if (ost[i].s_type & 0xF0000000) continue; - // Get symbol value - value = getlong((ost + (i * 12)) + 8); - slen = strlen(oststr + index); - // Get symbol string (maximum 8 chars) - if (slen > 8) - { - for(j=0; j<8; j++) - *(symbol + j) = *(oststr + index + j); - } - else - { - for(j=0; jo_flags & O_ARCHIVE)) + // If the object is unused, discard it... + if ((otemp->o_flags & O_USED) == 0) { - if ((otemp->o_flags & O_USED) == 0) + if (wflag) { - if (wflag) - { - printf("Unused object file "); - put_name(otemp); - printf(" discarded.\n"); - } - - if (oprev == NULL) - olist = otemp->o_next; - else - oprev->o_next = otemp->o_next; - - struct OFILE * ohold = otemp; - - if (!ohold->isArchiveFile) - free(ohold->o_image); - - // Also need to remove them from the obj_* tables too :-P - // N.B.: Would probably be worthwhile to remove crap like this - // and stuff it into the OFILE structure... - if (wflag) - printf("»-> removing %s... (index == %i, len == %i)\n", obj_fname[i], i, obj_index - 1); + printf("Unused object file "); + WriteARName(otemp); + printf(" discarded.\n"); + } - int k; + // Drop the entry from the linked list + if (oprev == NULL) + olist = otemp->o_next; + else + oprev->o_next = otemp->o_next; - for(k=i; kisArchiveFile) + free(otemp->o_image); + } + else + { + // Save accumulated addresses in the object + otemp->segBase[TEXT] = textsize; + otemp->segBase[DATA] = datasize; + otemp->segBase[BSS] = bsssize; - obj_index--; - i--; - } - else - { - // Increment total of segment sizes ensuring requested - // alignment - textsize += (otemp->o_header.tsize + secalign) & ~secalign; - datasize += (otemp->o_header.dsize + secalign) & ~secalign; - bsssize += (otemp->o_header.bsize + secalign) & ~secalign; - oprev = otemp; - } + // Increment total of segment sizes ensuring requested alignment + textsize += (otemp->o_header.tsize + secalign) & ~secalign; + datasize += (otemp->o_header.dsize + secalign) & ~secalign; + bsssize += (otemp->o_header.bsize + secalign) & ~secalign; + oprev = otemp; } // Go to next object file list pointer otemp = otemp->o_next; - i++; } - // Update base addresses and create symbols _TEXT_E, _DATA_E and _BSS_E + // Update base addresses and inject the symbols _TEXT_E, _DATA_E and _BSS_E + // into the OST tbase = tval; if (!dval) @@ -1627,17 +1524,26 @@ struct OHEADER * make_ofile() } else { - // DATA is independant of TEXT + // DATA is independent of TEXT dbase = dval; if (!bval) - // BSS follows DATA - bbase = dval + datasize; + { + if (btype == -2) + // BSS follows TEXT + bbase = tval + textsize; + else + // BSS follows DATA + bbase = dval + datasize; + } else + { // BSS is independent of DATA bbase = bval; + } } + // Inject segment end labels, for C compilers that expect this shite OSTAdd("_TEXT_E", 0x05000000, tbase + textsize); OSTAdd("_DATA_E", 0x07000000, dbase + datasize); OSTAdd("_BSS_E", 0x09000000, bbase + bsssize); @@ -1659,16 +1565,11 @@ struct OHEADER * make_ofile() while (otemp != NULL) { otemp->o_tbase = tptr; - - // Do rest only for non-ARCHIVE markers - if (!(otemp->o_flags & O_ARCHIVE)) - { - otemp->o_dbase = dptr; - otemp->o_bbase = bptr; - tptr += (otemp->o_header.tsize + secalign) & ~secalign; - dptr += (otemp->o_header.dsize + secalign) & ~secalign; - bptr += (otemp->o_header.bsize + secalign) & ~secalign; - } + otemp->o_dbase = dptr; + otemp->o_bbase = bptr; + tptr += (otemp->o_header.tsize + secalign) & ~secalign; + dptr += (otemp->o_header.dsize + secalign) & ~secalign; + bptr += (otemp->o_header.bsize + secalign) & ~secalign; // For each symbol, (conditionally) add it to the ost // For ARCHIVE markers, this adds the symbol for the file & returns @@ -1677,27 +1578,7 @@ struct OHEADER * make_ofile() if (DoSymbols(otemp)) return NULL; - if (otemp->o_flags & O_ARCHIVE) - { - // Now that the archive is marked, remove it from list - if (oprev == NULL) - olist = otemp->o_next; - else - oprev->o_next = otemp->o_next; - - struct OFILE * ohold = otemp; - - if (ohold->o_image) - if (!ohold->isArchiveFile) - free(ohold->o_image); - - free(ohold); - } - else - { - oprev = otemp; - } - + oprev = otemp; otemp = otemp->o_next; } @@ -1710,7 +1591,7 @@ struct OHEADER * make_ofile() if (header == NULL) { - printf("make_ofile: out of memory!\n"); + printf("MakeOutputObject: out of memory!\n"); return NULL; } @@ -1720,19 +1601,16 @@ struct OHEADER * make_ofile() header->tsize = textsize; // TEXT segment size header->dsize = datasize; // DATA segment size header->bsize = bsssize; // BSS segment size - header->ssize = (ost_ptr - ost); // Symbol table size - header->ostbase = ost; // Output symbol table base address + header->ssize = ost_index * 12; // Symbol table size + header->ostbase = NULL; // Output symbol table base address // For each object file, relocate its TEXT and DATA segments. OR the result // into ret so all files get moved (and errors reported) before returning // with the error condition for(otemp=olist; otemp!=NULL; otemp=otemp->o_next) { - if (!(otemp->o_flags & O_ARCHIVE)) - { - ret |= RelocateSegment(otemp, T_TEXT); // TEXT segment relocations - ret |= RelocateSegment(otemp, T_DATA); // DATA segment relocations - } + ret |= RelocateSegment(otemp, T_TEXT); // TEXT segment relocations + ret |= RelocateSegment(otemp, T_DATA); // DATA segment relocations } // Done with global symbol hash tables @@ -1879,7 +1757,7 @@ struct HREC * LookupHREC(char * symbol) // struct HREC * LookupARHREC(char * symbol) { - struct HREC * hptr = arSymbol;//htable[GetHash(symbol)]; + struct HREC * hptr = arSymbol; while (hptr != NULL) { @@ -1900,13 +1778,27 @@ struct HREC * LookupARHREC(char * symbol) // // Change old-style commons (type == T_EXTERN, value != 0) to new-style ones // (type == (T_GLOBAL | T_EXTERN)). [??? O_o] +// [N.B.: Whoever wrote the above didn't know what the fuck they were talking +// about. Commons (globals) are exactly what they are calling 'old +// style'. Also note, that there is no "T_GLOBAL" or "T_EXTERN" symbols +// defined anywhere in the code.] // int AddSymbols(struct OFILE * Ofile) { struct HREC * hptr; // Hash record pointer if (vflag > 1) - printf("Add symbols for file %s\n", Ofile->o_name); + { + printf("AddSymbols: for file %s\n", Ofile->o_name); + printf(" t_bbase = $%X\n", Ofile->o_tbase); + printf(" d_bbase = $%X\n", Ofile->o_dbase); + printf(" o_bbase = $%X\n", Ofile->o_bbase); + printf(" tsize = $%X\n", Ofile->o_header.tsize); + printf(" dsize = $%X\n", Ofile->o_header.dsize); + printf(" bsize = $%X\n", Ofile->o_header.bsize); + printf(" reloc.tsize = $%X\n", Ofile->o_header.absrel.reloc.tsize); + printf(" reloc.dsize = $%X\n", Ofile->o_header.absrel.reloc.dsize); + } // Get base pointer, start of sym fixups char * ptr = Ofile->o_image + 32 @@ -1920,28 +1812,50 @@ int AddSymbols(struct OFILE * Ofile) while (nsymbols) { - long index = getlong(sfix); // Get symbol string index - long type = getlong(sfix + 4); // Get symbol type - long value = getlong(sfix + 8); // Get symbol value + long index = GetLong(sfix); // Get symbol string index + long type = GetLong(sfix + 4); // Get symbol type + long value = GetLong(sfix + 8); // Get symbol value if ((Ofile->isArchiveFile) && !(Ofile->o_flags & O_USED)) { - if ((type & T_EXT) && (type & (T_SEG | T_ABS))) + if ((type & T_GLBL) && (type & (T_SEG | T_ABS))) if (AddARSymbol(sstr + index, Ofile)) return 1; } - else if (type == T_EXT) + else if (type == T_GLBL) { - // External symbol that is *not* in the current unit + // Global symbol that may or may not be in the current unit hptr = LookupHREC(sstr + index); if (hptr != NULL) hptr->h_ofile->o_flags |= O_USED; // Mark .o file as used - // Otherwise add to unresolved list + // Otherwise, *maybe* add to unresolved list else { - // Check for built-in externals... - if ((strcmp(sstr + index, "_TEXT_E") != 0) + // Check to see if this is a common symbol; if so, add it to + // the hash list... + if (value != 0) + { + // Actually, we need to convert this to a BSS symbol, + // increase the size of the BSS segment for this object, & + // add it to the hash list + uint32_t bssLocation = Ofile->o_header.tsize + Ofile->o_header.dsize + Ofile->o_header.bsize; + Ofile->o_header.bsize += value; + Ofile->segSize[BSS] += value; + type |= T_BSS; + value = bssLocation; + PutLong(sfix + 4, type); + PutLong(sfix + 8, value); + + if (vflag > 1) + printf("AddSymbols: Resetting common label to BSS label\n"); + + if (AddSymbolToHashList(&htable[GetHash(sstr + index)], + sstr + index, Ofile, value, type)) + return 1; // Error if addition failed + } + // Make sure it's not a built-in external... + else if ((strcmp(sstr + index, "_TEXT_E") != 0) && (strcmp(sstr + index, "_DATA_E") != 0) && (strcmp(sstr + index, "_BSS_E") != 0)) { @@ -1950,13 +1864,8 @@ int AddSymbols(struct OFILE * Ofile) } } } - else if ((type & T_EXT) && (type & (T_SEG | T_ABS))) + else if ((type & T_GLBL) && (type & (T_SEG | T_ABS))) { -#if 0 - // Symbol in the current unit that is also EXPORTED - if (DealWithSymbol(sstr + index, type, value, Ofile)) - return 1; // Error if addition failed -#else hptr = LookupHREC(sstr + index); // Symbol isn't in the table, so try to add it: @@ -1969,15 +1878,17 @@ int AddSymbols(struct OFILE * Ofile) else { // Symbol already exists, decide what to do about it + // [N.B.: This isn't a check for a common symbol... + // BEWARE OF BAD INTERPRETATIONS!!] if (iscommon(hptr->h_type)) { // Mismatch: common came first; warn and keep the global if (wflag) { printf("Warning: %s: global from ", sstr + index); - put_name(Ofile); + WriteARName(Ofile); printf(" used, common from "); - put_name(hptr->h_ofile); + WriteARName(hptr->h_ofile); printf(" discarded.\n"); } @@ -1992,19 +1903,18 @@ int AddSymbols(struct OFILE * Ofile) if (wflag) { printf("Duplicate symbol %s: ", sstr + index); - put_name(hptr->h_ofile); + WriteARName(hptr->h_ofile); printf(" used, "); - put_name(Ofile); + WriteARName(Ofile); printf(" discarded\n"); } // Set the global in this unit to pure external // (is this a good idea? what if the other one is a ref to // this one???) - putlong(sfix + 4, T_EXT); + PutLong(sfix + 4, T_GLBL); } } -#endif } sfix += 12; // Increment symbol fixup pointer @@ -2031,7 +1941,7 @@ int DoItem(struct OFILE * obj) } // Starting after all pathnames, etc., copy .o file name to Ofile - char * temp = path_tail(obj->o_name); + char * temp = PathTail(obj->o_name); // Check filename length if (strlen(temp) > FNLEN - 1) @@ -2041,7 +1951,7 @@ int DoItem(struct OFILE * obj) } // Check archive name length - if (strlen(obj->o_arname) > FNLEN - 1) + if (strlen(obj->o_arname) > (FNLEN - 1)) { printf("Archive name too long: %s\n", obj->o_arname); return 1; @@ -2058,45 +1968,42 @@ int DoItem(struct OFILE * obj) Ofile->o_flags = obj->o_flags; Ofile->o_image = obj->o_image; Ofile->isArchiveFile = obj->isArchiveFile; + Ofile->segSize[TEXT] = obj->segSize[TEXT]; + Ofile->segSize[DATA] = obj->segSize[DATA]; + Ofile->segSize[BSS] = obj->segSize[BSS]; char * ptr = obj->o_image; - // Don't do anything if this is just an ARCHIVE marker, just add the file - // to the olist - // (Shamus: N.B.: it does no such ARCHIVE thing ATM) - if (!(obj->o_flags & O_ARCHIVE)) - { - Ofile->o_header.magic = getlong(ptr); - Ofile->o_header.tsize = getlong(ptr + 4); - Ofile->o_header.dsize = getlong(ptr + 8); - Ofile->o_header.bsize = getlong(ptr + 12); - Ofile->o_header.ssize = getlong(ptr + 16); - Ofile->o_header.absrel.reloc.tsize = getlong(ptr + 24); - Ofile->o_header.absrel.reloc.dsize = getlong(ptr + 28); + Ofile->o_header.magic = GetLong(ptr); + Ofile->o_header.tsize = GetLong(ptr + 4); + Ofile->o_header.dsize = GetLong(ptr + 8); + Ofile->o_header.bsize = GetLong(ptr + 12); + Ofile->o_header.ssize = GetLong(ptr + 16); + Ofile->o_header.absrel.reloc.tsize = GetLong(ptr + 24); + Ofile->o_header.absrel.reloc.dsize = GetLong(ptr + 28); - // Round BSS off to alignment boundary - Ofile->o_header.bsize = (Ofile->o_header.bsize + secalign) & ~secalign; + // Round BSS off to alignment boundary (??? isn't this already done ???) + Ofile->o_header.bsize = (Ofile->o_header.bsize + secalign) & ~secalign; - if ((Ofile->o_header.dsize & 7) && wflag) - { - printf("Warning: data segment size of "); - put_name(Ofile); - printf(" is not a phrase multiple\n"); - } - - // Check for odd segment sizes - if ((Ofile->o_header.tsize & 1) || (Ofile->o_header.dsize & 1) - || (Ofile->o_header.bsize & 1)) - { - printf("Error: odd-sized segment in "); - put_name(Ofile); - printf("; link aborted.\n"); - return 1; - } + if ((Ofile->o_header.dsize & 7) && wflag) + { + printf("Warning: data segment size of "); + WriteARName(Ofile); + printf(" is not a phrase multiple\n"); + } - if (AddSymbols(Ofile)) - return 1; + // Check for odd segment sizes + if ((Ofile->o_header.tsize & 1) || (Ofile->o_header.dsize & 1) + || (Ofile->o_header.bsize & 1)) + { + printf("Error: odd-sized segment in "); + WriteARName(Ofile); + printf("; link aborted.\n"); + return 1; } + if (AddSymbols(Ofile)) + return 1; + // Add this file to the olist if (olist == NULL) olist = Ofile; @@ -2207,7 +2114,7 @@ int ProcessLists(void) // // Extract filename from path // -char * path_tail(char * name) +char * PathTail(char * name) { // Find last occurance of PATH_DELIMETER char * temp = strrchr(name, PATH_DELIMITER); @@ -2223,7 +2130,7 @@ char * path_tail(char * name) // // Add input file to processing list // -int AddToProcessingList(char * ptr, char * fname, char * arname, uint8_t arFile) +int AddToProcessingList(char * ptr, char * fname, char * arname, uint8_t arFile, uint32_t tSize, uint32_t dSize, uint32_t bSize) { if (plist == NULL) { @@ -2244,19 +2151,19 @@ int AddToProcessingList(char * ptr, char * fname, char * arname, uint8_t arFile) return 1; } - fname = path_tail(fname); - arname = path_tail(arname); + // Discard paths from filenames... + fname = PathTail(fname); + arname = PathTail(arname); - if (strlen(fname) > FNLEN - 1) + // Check for filename length errors... + if (strlen(fname) > (FNLEN - 1)) { - // Error on excessive filename length printf("File name too long: %s (sorry!)\n", fname); return 1; } - if (strlen(arname) > FNLEN - 1) + if (strlen(arname) > (FNLEN - 1)) { - // Error on excessive filename length printf("AR file name too long: %s (sorry!)\n", arname); return 1; } @@ -2267,6 +2174,9 @@ int AddToProcessingList(char * ptr, char * fname, char * arname, uint8_t arFile) plast->o_flags = (arFile ? 0 : O_USED); // File is used if NOT in archive plast->o_next = NULL; // Initialise next record pointer plast->isArchiveFile = arFile; // Shamus: Temp until can sort it out + plast->segSize[TEXT] = tSize; + plast->segSize[DATA] = dSize; + plast->segSize[BSS] = bSize; return 0; // Return without errors } @@ -2280,8 +2190,8 @@ int AddToProcessingList(char * ptr, char * fname, char * arname, uint8_t arFile) // Image size for include files is: // Header ....... 32 bytes // Data ......... dsize -// Sym Fixups ... 2 * 12 bytes -// Symbol Size .. 4 bytes (Value to include symbols and terminating null) +// Sym fixups ... 2 * 12 bytes +// Symbol size .. 4 bytes (Value to include symbols and terminating null) // Symbols ...... (strlen(sym1) + 1) + (strlen(sym2) + 1) // Terminate .... 4 bytes (0x00000000) // @@ -2290,6 +2200,7 @@ int LoadInclude(char * fname, int handle, char * sym1, char * sym2, int segment) char * ptr, * sptr; int i; unsigned symtype = 0; + uint32_t tSize = 0, dSize = 0, bSize = 0; long fsize = FileSize(handle); // Get size of include file long dsize = (fsize + secalign) & ~secalign; // Align size to boundary @@ -2317,50 +2228,42 @@ int LoadInclude(char * fname, int handle, char * sym1, char * sym2, int segment) close(handle); - strcpy(obj_fname[obj_index], path_tail(fname)); - // Build this image's dummy header - putlong(ptr, 0x00000107); // Magic number + PutLong(ptr, 0x00000107); // Magic number if (segment) { - putlong(ptr+4, dsize); // Text size - putlong(ptr+8, 0L); // Data size + PutLong(ptr+4, dsize); // Text size + PutLong(ptr+8, 0L); // Data size symtype = 0x05000000; - obj_segsize[obj_index][0] = dsize; - obj_segsize[obj_index][1] = 0; - obj_segsize[obj_index][2] = 0; + tSize = dsize; } else { - putlong(ptr+4, 0L); // Text size - putlong(ptr+8, dsize); // Data size + PutLong(ptr+4, 0L); // Text size + PutLong(ptr+8, dsize); // Data size symtype = 0x07000000; - obj_segsize[obj_index][0] = 0; - obj_segsize[obj_index][1] = dsize; - obj_segsize[obj_index][2] = 0; + dSize = dsize; } - obj_index++; // Increment object count - - putlong(ptr+12, 0L); // BSS size - putlong(ptr+16, 24); // Symbol table size - putlong(ptr+20, 0L); // Entry point - putlong(ptr+24, 0L); // TEXT relocation size - putlong(ptr+28, 0L); // DATA relocation size + PutLong(ptr+12, 0L); // BSS size + PutLong(ptr+16, 24); // Symbol table size + PutLong(ptr+20, 0L); // Entry point + PutLong(ptr+24, 0L); // TEXT relocation size + PutLong(ptr+28, 0L); // DATA relocation size sptr = ptr + 32 + dsize; // Set sptr to symbol table location - putlong(sptr, 4L); // String offset of symbol1 - putlong(sptr+4, symtype); // Symbol type - putlong(sptr+8, 0x00000000); // Symbol has no value (START) - putlong(sptr+12, 4L + (sym2len - 1)); // String offset of symbol2 - putlong(sptr+16, symtype); // Symbol type - putlong(sptr+20, dsize); // Symbol is data size (END) + PutLong(sptr, 4L); // String offset of symbol1 + PutLong(sptr+4, symtype); // Symbol type + PutLong(sptr+8, 0x00000000); // Symbol has no value (START) + PutLong(sptr+12, 4L + (sym2len - 1)); // String offset of symbol2 + PutLong(sptr+16, symtype); // Symbol type + PutLong(sptr+20, dsize); // Symbol is data size (END) sptr = ptr + 32 + dsize + 24; // Set sptr to symbol table size loc - putlong(sptr, sym1len + 4L); // Size of symbol table + PutLong(sptr, sym1len + 4L); // Size of symbol table sptr = ptr + 32 + dsize + 24 + 4; // Set sptr to symbol table location @@ -2378,9 +2281,9 @@ int LoadInclude(char * fname, int handle, char * sym1, char * sym2, int segment) *sptr = '\0'; // Terminate symbol string sptr += 1; // Step past termination - putlong(sptr, 0L); // Terminating long for object file + PutLong(sptr, 0L); // Terminating long for object file - return AddToProcessingList(ptr, fname, nullStr, 0); + return AddToProcessingList(ptr, fname, nullStr, 0, tSize, dSize, bSize); } @@ -2393,6 +2296,8 @@ int LoadInclude(char * fname, int handle, char * sym1, char * sym2, int segment) // int LoadObject(char * fname, int fd, char * ptr) { + uint32_t tSize = 0, dSize = 0, bSize = 0; + if (ptr == NULL) { long size = FileSize(fd); @@ -2416,21 +2321,290 @@ int LoadObject(char * fname, int fd, char * ptr) return 1; } - // SCPCD: get the name of the file instead of all pathname - strcpy(obj_fname[obj_index], path_tail(fname)); - obj_segsize[obj_index][0] = (getlong(ptr + 4) + secalign) & ~secalign; - obj_segsize[obj_index][1] = (getlong(ptr + 8) + secalign) & ~secalign; - obj_segsize[obj_index][2] = (getlong(ptr + 12) + secalign) & ~secalign; - obj_index++; - - close(fd); // Close file + tSize = (GetLong(ptr + 4) + secalign) & ~secalign; + dSize = (GetLong(ptr + 8) + secalign) & ~secalign; + bSize = (GetLong(ptr + 12) + secalign) & ~secalign; + close(fd); } // Now add this image to the list of pending ofiles (plist) - // This routine is shared by LoadInclude after it builds the image - return AddToProcessingList(ptr, fname, nullStr, 0); + return AddToProcessingList(ptr, fname, nullStr, 0, tSize, dSize, bSize); } +uint32_t SymTypeAlcToAout(uint32_t alcType) +{ + uint32_t type = T_UNDF; + + // Symbol type mappings here are derived from comparing Alcyon and BSD + // object files generated by MADMAC using the "size" utility from jag_utils + // (https://github.com/cubanismo/jag_utils) and the old PC/DOS Atari SDK. + // + // In BSD/a.out: + // + // 1) text | global text == text relocatable symbol in this file + // 2) data | global data == data relocatable symbol in this file + // 3) BSS | global BSS == bss relocatable symbol in this file + // 4) ABS | global ABS == non-relocatable symbol in this file + // 4) | global == undefined global symbol (extern) + // + // In DRI/Alcyon: + // + // 1) Everything seems to be marked defined. + // 2) There is an explicit "external" bit. It appears to be mutually + // exclusive with the "global" bit, at least in MADMAC's output. + // 3) There are separate "equated" and "equated reg" type bits that + // both represent ABS/non-relocatable values. + if ((alcType & ALCSYM_EQUATED) || + (alcType & ALCSYM_EQUATED_REG)) + type |= T_ABS; + else if (alcType & ALCSYM_TEXT) + type |= T_TEXT; + else if (alcType & ALCSYM_DATA) + type |= T_DATA; + else if (alcType & ALCSYM_BSS) + type |= T_BSS; + + if ((alcType & ALCSYM_GLOBAL) || + (alcType & ALCSYM_EXTERN)) + type |= T_GLBL; + + return type; +} + +int LoadAlcyon(char * fname, int fd) +{ + char *ptr, *sptr, *aout, *saout, *traout, *strPtr; + char *trelptr, *drelptr, *relend; + struct ALCHEADER hdr; + struct ALCSYM *alcSyms; + long size = FileSize(fd); + size_t symStrLen; + size_t strOff; + uint32_t numSyms, numTRel, numDRel, i, j; + + // Validate the file is at least large enough to contain a valid header + if (size < 0x1c) + { + printf("Alcyon object file %s too small to contain header\n", fname); + return 1; + } + + // Allocate memory for file data + ptr = malloc(size); + + if (ptr == NULL) + { + printf("Out of memory while processing %s\n", fname); + close(fd); + return 1; + } + + // Read in file data + if (read(fd, ptr, size) != size) + { + printf("File read error on %s\n", fname); + close(fd); + free(ptr); + return 1; + } + + close(fd); + + hdr.magic = GetWord(ptr); + hdr.tsize = GetLong(ptr + 2); + hdr.dsize = GetLong(ptr + 6); + hdr.bsize = GetLong(ptr + 10); + hdr.ssize = GetLong(ptr + 14); + + // Construct a BSD-style/aout object file in memory from the Alcyon data + numSyms = hdr.ssize / 14; + + alcSyms = calloc(numSyms, sizeof(*alcSyms)); + if (alcSyms == NULL) + { + printf("Out of memory while processing %s\n", fname); + free(ptr); + return 1; + } + + sptr = ptr + 0x1c + hdr.tsize + hdr.dsize; + trelptr = sptr + hdr.ssize; + drelptr = trelptr + hdr.tsize; + relend = drelptr + hdr.dsize; + + if (relend - ptr > size) + { + printf("Alcyon object file %s truncated: Header wants %ldB, file is %ldB\n", + fname, relend - ptr, size); + return 1; + } + + for (i = 0, symStrLen = 0; i < numSyms; i++) + { + memcpy(alcSyms[i].name, sptr, 8); + alcSyms[i].type = GetWord(sptr + 8); + alcSyms[i].value = GetLong(sptr + 10); + symStrLen += strnlen((char *)alcSyms[i].name, 8) + 1; + sptr += 14; + } + + for (i = 0, numTRel = 0; trelptr + i < drelptr; i += 2) + { + uint16_t rel = GetWord(trelptr + i); + if ((rel != ALCREL_ABS) && + (rel != ALCREL_LONG)) + numTRel++; + } + + for (i = 0, numDRel = 0; drelptr + i < relend; i += 2) + { + uint16_t rel = GetWord(drelptr + i); + if ((rel != ALCREL_ABS) && + (rel != ALCREL_LONG)) + numDRel++; + } + + aout = malloc(32 + /* header */ + hdr.tsize + + hdr.dsize + + numTRel * 8 + /* Text section relocations */ + numDRel * 8 + /* Data section relocations */ + numSyms * 12 + /* symbol table */ + 4 + symStrLen + /* string table size + strings */ + 4 /* NULL-terminator for file */); + if (aout == NULL) + { + printf("Out of memory while processing %s\n", fname); + free(alcSyms); + free(ptr); + return 1; + } + + // Construct the BSD/a.out header. + PutLong(aout, 0x00000107); // Magic number + + PutLong(aout+4, hdr.tsize); // Text size + PutLong(aout+8, hdr.dsize); // Data size + PutLong(aout+12, hdr.bsize); // BSS size + PutLong(aout+16, numSyms * 12); // Symbol table size + PutLong(aout+20, 0L); // Entry point + + PutLong(aout+24, numTRel * 8); // TEXT relocation size + PutLong(aout+28, numDRel * 8); // DATA relocation size + + // Copy the raw text and data segments + memcpy(aout + 32, ptr + 0x1c, hdr.tsize); + memcpy(aout + 32 + hdr.tsize, ptr + 0x1c + hdr.tsize, hdr.dsize); + + // Set traout to the start of the relocation tables + traout = aout + 32 + hdr.tsize + hdr.dsize; + + // Set saout to symbol table location + saout = traout + numTRel * 8 + numDRel * 8 ; + + // Convert the text and data relocations to a.out format + for (i = 0; trelptr + i < relend; i += 2) + { + uint16_t rel = GetWord(trelptr + i); + uint16_t relFlags = rel & 7; + uint32_t aoutflags = BSDREL_ABS; + uint32_t valoffset = 0; + char *const valaddr = aout + 32 + i; + const uint32_t reladdr = (trelptr + i >= drelptr) ? i - hdr.tsize : i; + + if (relFlags == ALCREL_LONG) + { + i += 2; + rel = GetWord(trelptr + i); + relFlags = rel & 7; + } + else + { + aoutflags |= BSDREL_WORD; + } + + if (relFlags == ALCREL_ABS) + continue; + + switch (relFlags) { + case ALCREL_EXTPCREL: + aoutflags &= ~BSDREL_ABS; + aoutflags |= BSDREL_PCREL; + /* Fall through */ + case ALCREL_EXTABS: + aoutflags |= BSDREL_GLOBAL; + aoutflags |= (ALCREL_SYMIDX(rel) << BSDREL_SYMIDX_SHIFT); + break; + case ALCREL_TEXT: + aoutflags |= BSDREL_SEG_TEXT; + break; + case ALCREL_DATA: + aoutflags |= BSDREL_SEG_DATA; + valoffset = hdr.tsize; + break; + case ALCREL_BSS: + aoutflags |= BSDREL_SEG_BSS; + valoffset = hdr.tsize + hdr.dsize; + break; + + default: + printf("Invalid Alcyon relocation flags: 0x%02x\n", relFlags); + free(alcSyms); + free(ptr); + free(aout); + return 1; + } + + if (valoffset != 0) + { + if (aoutflags & BSDREL_WORD) + { + valoffset += GetWord(valaddr); + PutWord(valaddr, (uint16_t)valoffset); + } + else + { + valoffset += GetLong(valaddr); + PutLong(valaddr, valoffset); + } + } + + PutLong(traout, reladdr); + PutLong(traout+4, aoutflags); + traout += 8; + } + + // Done with the Alcyon data. + free(ptr); + ptr = NULL; + sptr = NULL; + + // Set strPtr to string table location and write string table size + strPtr = saout + numSyms * 12; + PutLong(strPtr, 4 + symStrLen); + + for (i = 0, strOff = 4; i < numSyms; i++) + { + PutLong(saout, strOff); // String offset of symbol + PutLong(saout+4, SymTypeAlcToAout(alcSyms[i].type)); // Symbol type + PutLong(saout+8, alcSyms[i].value); // Symbol value + saout += 12; + + for (j = 0; j < 8 && alcSyms[i].name[j] != '\0'; j++) + *(strPtr + strOff + j) = alcSyms[i].name[j]; + strOff += j; // Step past string + *(strPtr + strOff) = '\0'; // Terminate symbol string + strOff++; // Step past termination + } + + PutLong(strPtr + strOff, 0L); // Terminating long for object file + + // Done with the Alcyon symbol table. + free(alcSyms); + + // Now add this image to the list of pending ofiles (plist) + return AddToProcessingList(aout, fname, nullStr, 0, hdr.tsize, hdr.dsize, hdr.bsize); +} // // What it says on the tin: check for a .o suffix on the passed in string @@ -2512,7 +2686,8 @@ int LoadArchive(char * fname, int fd) } // Check to see if a long filename was requested - if (objName[0] == 0x20) + // N.B.: " " is for GNU archives, and "/" is for BSD archives + if ((objName[0] == 0x20) || (objName[0] == '/')) { uint32_t fnSize = atoi(objName + 1); @@ -2542,13 +2717,11 @@ int LoadArchive(char * fname, int fd) objName[lastChar] = 0; //printf("Processing object \"%s\" (size == %i, obj_index == %i)...\n", objName, atoi(objSize), obj_index); - strcpy(obj_fname[obj_index], objName); - obj_segsize[obj_index][0] = (getlong(ptr + 60 + 4) + secalign) & ~secalign; - obj_segsize[obj_index][1] = (getlong(ptr + 60 + 8) + secalign) & ~secalign; - obj_segsize[obj_index][2] = (getlong(ptr + 60 + 12) + secalign) & ~secalign; - obj_index++; + uint32_t tSize = (GetLong(ptr + 60 + 4) + secalign) & ~secalign; + uint32_t dSize = (GetLong(ptr + 60 + 8) + secalign) & ~secalign; + uint32_t bSize = (GetLong(ptr + 60 + 12) + secalign) & ~secalign; - if (AddToProcessingList(ptr + 60, objName, fname, 1)) + if (AddToProcessingList(ptr + 60, objName, fname, 1, tSize, dSize, bSize)) return 1; } @@ -2590,12 +2763,19 @@ int ProcessFiles(void) lseek(handle[i], 0L, 0); // Reset to start of input file // Look for RMAC/MAC/GCC (a.out) object files - if ((getlong(magic) & 0xFFFF) == 0x0107) + if ((GetLong(magic) & 0xFFFF) == 0x0107) { // Process input object file if (LoadObject(name[i], handle[i], 0L)) return 1; } + // Look for DRI Alcyon C (and old MAC) object files + else if (GetWord(magic) == 0x601A) + { + // Process Alcyon object file. + if (LoadAlcyon(name[i], handle[i])) + return 1; + } // Otherwise, look for an object archive file else if (strncmp(magic, "!\x0A", 8) == 0) { @@ -2708,7 +2888,7 @@ int parse(char * buf, char * newargv[]) // -// Process in a Link Command File +// Process in a link command file // int docmdfile(char * fname) { @@ -2786,7 +2966,7 @@ int docmdfile(char * fname) // -// Take an Argument List and Parse the Command Line +// Take an argument list and parse the command line // int doargs(int argc, char * argv[]) { @@ -2803,7 +2983,7 @@ int doargs(int argc, char * argv[]) if (!argv[i][1]) { printf("Illegal option argument: %s\n\n", argv[i]); - display_help(); + ShowHelp(); return 1; } @@ -2815,8 +2995,8 @@ int doargs(int argc, char * argv[]) case '?': // Display usage information case 'h': case 'H': - display_version(); - display_help(); + ShowVersion(); + ShowHelp(); return 1; case 'a': case 'A': // Set absolute linking on @@ -2874,9 +3054,33 @@ int doargs(int argc, char * argv[]) } else if ((*argv[i] == 'x' || *argv[i] == 'X')) { - btype = -3; // BSS follows DATA + switch (argv[i][1]) + { + case 'd': case 'D': case '\0': + btype = -3; // BSS follows DATA + break; + + case 't': case 'T': + btype = -2; // BSS follows TEXT + if (btype == dtype) + { + printf("Error in bss-segment address: data-segment also follows text\n"); + return 1; + } + break; + + default: + btype = -4; // Error + break; + } } else if (GetHexValue(argv[i], &bval)) + { + btype = -4; + return 1; + } + + if (btype == -4) { printf("Error in bss-segment address: %s is not 'r', 'x[td]', or an address.", argv[i]); return 1; @@ -2916,15 +3120,15 @@ int doargs(int argc, char * argv[]) case 'e': case 'E': // Output COFF (absolute only) cflag = 1; + + if (noheaderflag) + printf("Warning: -e overridden by -n, output will be headerless\n"); + break; case 'g': case 'G': // Output source level debugging - printf("\'g\' flag not currently implemented\n"); - gflag = 0; - /* if (gflag) warn('g', 1); gflag = 1; - */ break; case 'i': case 'I': // Include binary file @@ -2946,8 +3150,8 @@ int doargs(int argc, char * argv[]) // handle -i (Truncation) else { - if (strlen(isym) > 7) - isym[7] = '\0'; + if (strlen(isym) > 8) + isym[8] = '\0'; } // Place include files in the DATA segment only @@ -2974,6 +3178,9 @@ int doargs(int argc, char * argv[]) if (noheaderflag) warn('n', 1); + if (cflag) + printf("Warning: -e overridden by -n, output will be headerless\n"); + noheaderflag = 1; break; case 'o': @@ -3030,7 +3237,7 @@ int doargs(int argc, char * argv[]) case 'V': // Verbose information if (!vflag && !versflag) { - display_version(); + ShowVersion(); } vflag++; @@ -3042,6 +3249,22 @@ int doargs(int argc, char * argv[]) wflag = 1; break; + case 'y': + case 'Y': + if (i >= argc) + { + printf("No directory filename following -y switch\n"); + return 1; + } + + if (strlen(argv[i]) > FARGSIZE * 3) + { + printf("Directory file name too long (sorry!)\n"); + return 1; + } + + strcpy(libdir, argv[i++]); + break; case 'z': case 'Z': // Suppress banner flag if (zflag) @@ -3080,42 +3303,52 @@ int doargs(int argc, char * argv[]) // -// Display Version Information +// Display version information // -void display_version(void) +void ShowVersion(void) { if (displaybanner)// && vflag) { - printf("\nReboot's Linker for Atari Jaguar\n"); - printf("Copyright (c) 199x Allan K. Pratt, 2014 Reboot\n"); - printf("V%i.%i.%i %s (%s)\n\n", MAJOR, MINOR, PATCH, __DATE__, PLATFORM); + printf( + " _\n" + " _ __| |_ ___\n" + "| '__| | '_ \\\n" + "| | | | | | |\n" + "|_| |_|_| |_|\n" + "\nRenamed Linker for Atari Jaguar\n" + "Copyright (c) 199x Allan K. Pratt, 2014-2021 Reboot & Friends\n" + "V%i.%i.%i %s (%s)\n\n", MAJOR, MINOR, PATCH, __DATE__, PLATFORM); } } // -// Display Command Line Help +// Display command line help // -void display_help(void) +void ShowHelp(void) { printf("Usage:\n"); printf(" %s [-options] file(s)\n", cmdlnexec); printf("\n"); printf("Options:\n"); printf(" -? or -h display usage information\n"); - printf(" -a output absolute file\n"); + printf(" -a output absolute file (default: ABS)\n"); printf(" hex value: segment address\n"); printf(" r: relocatable segment\n"); - printf(" x: contiguous segment\n"); + printf(" x[dt]: contiguous segment\n"); + printf(" for contiguous bss:\n"); + printf(" d(default): follows data segment\n"); + printf(" t: follows text segment\n"); printf(" -b don't remove multiply defined local labels\n"); printf(" -c add contents of to command line\n"); printf(" -d wait for key after link\n"); printf(" -e output COF absolute file\n"); printf(" -g output source-level debugging\n"); - printf(" -i