X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?p=rln;a=blobdiff_plain;f=rln.c;h=a0b5ab02aa040e7e4c071822b100bba2956addba;hp=e41042fb6b7079da3c32e6fd347b8a64d7224c46;hb=HEAD;hpb=ff28769b66909bc028d0b99ee8918305bc649348 diff --git a/rln.c b/rln.c index e41042f..212a05c 100644 --- a/rln.c +++ b/rln.c @@ -1,376 +1,341 @@ // -// RLN - Reboot's Linker for the Atari Jaguar Console System -// RLN.C - Application Code -// Copyright (C) 199x, Allan K. Pratt, 2011 Reboot & Friends +// RLN - Renamed Linker for the Atari Jaguar console system +// Copyright (C) 199x, Allan K. Pratt, 2014-2021 Reboot & Friends // #include "rln.h" - -unsigned errflag = 0; // Error flag, goes TRUE on error -unsigned waitflag = 0; // Wait for any keypress flag -unsigned versflag = 0; // Version banner has been shown flag -unsigned aflag = 0; // Absolute linking flag -unsigned bflag = 0; // Don't remove mulitply def locals flag -unsigned cflag = 0; // COF executable -unsigned dflag = 0; // Wait for key after link flag -unsigned gflag = 0; // Source level debug include flag -unsigned lflag = 0; // Add local symbols to output flag -unsigned mflag = 0; // Produce symbol load map flag -unsigned oflag = 0; // Output filename specified -unsigned rflag = 0; // Segment alignment size flag -unsigned sflag = 0; // Output only global symbols -unsigned vflag = 0; // Verbose flag -unsigned zflag = 0; // Suppress banner flag -unsigned pflag, uflag, wflag; // Unimplemented flags -unsigned hd = 0; // Index of next file handle to fill -unsigned secalign = 7; // Section Alignment (8=phrase) -unsigned tbase = 0; // TEXT base address -unsigned dbase = 0; // DATA base address -unsigned bbase = 0; // BSS base address -unsigned textoffset = 0; // COF TEXT segment offset -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 -int tval, dval, bval; // Values of these abs bases -int hflag[NHANDLES]; // True for include files -int handle[NHANDLES]; // Open file handles -int textsize, datasize, bsssize; // Cumulative segment sizes -char libdir[FARGSIZE * 3]; // Library directory to search -char ofile[FARGSIZE]; // Output file name (.o) -char * name[NHANDLES]; // Associated file names -char * cmdlnexec = NULL; // Executable name - pointer to ARGV[0] -char * hsym1[SYMLEN]; // First symbol for include files -char * hsym2[SYMLEN]; // Second symbol for include files -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[512][FNLEN]; // Object file names -unsigned obj_segsize[512][3]; // Object file seg sizes; TEXT,DATA,BSS -unsigned obj_index = 0; // Object file index/count -struct HREC * htable[NBUCKETS]; // Hash table -struct HREC * unresolved = NULL; // Pointer to unresolved hash list -struct HREC * lookup(char *); // Hash lookup -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 - - -// -// Get a Long Word from Memory -// -unsigned getlong(char * src) +//#include + +unsigned errflag = 0; // Error flag, goes TRUE on error +unsigned waitflag = 0; // Wait for any keypress flag +unsigned versflag = 0; // Version banner has been shown flag +unsigned aflag = 0; // Absolute linking flag +unsigned bflag = 0; // Don't remove mulitply def locals flag +unsigned cflag = 0; // COF executable +unsigned dflag = 0; // Wait for key after link flag +unsigned gflag = 0; // Source level debug include flag +unsigned lflag = 0; // Add local symbols to output flag +unsigned mflag = 0; // Produce symbol load map flag +unsigned oflag = 0; // Output filename specified +unsigned rflag = 0; // Segment alignment size flag +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 (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 +unsigned dbase = 0; // DATA base address +unsigned bbase = 0; // BSS base address +unsigned textoffset = 0; // COF TEXT segment offset +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 +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 +int tval, dval, bval; // Values of these abs bases +int hflag[NHANDLES]; // True for include files +int handle[NHANDLES]; // Open file handles +int textsize, datasize, bsssize; // Cumulative segment sizes +char libdir[FARGSIZE * 3]; // Library directory to search +char ofile[FARGSIZE]; // Output file name (.o) +char * name[NHANDLES]; // Associated file names +char * cmdlnexec = NULL; // Executable name - pointer to ARGV[0] +char * hsym1[SYMLEN]; // First symbol for include files +char * hsym2[SYMLEN]; // Second symbol for include files +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 * arPtr[512]; +uint32_t arIndex = 0; +struct HREC * htable[NBUCKETS]; // Hash table +struct HREC * unresolved = NULL; // Pointer to unresolved hash list +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 + + +// Function prototypes +struct HREC * LookupHREC(char *); +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 +// +static inline uint32_t GetLong(uint8_t * src) { - unsigned temp; - char * out; - - out = (char *)&temp; - - if (endian == 1) - { - *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 +// Put a long word into memory // -void putlong(char * dest, unsigned val) +static inline void PutLong(uint8_t * dest, uint32_t val) { - *dest++ = (char)(val >> 24); - *dest++ = (char)(val >> 16); - *dest++ = (char)(val >> 8); - *dest = (char)val; + *dest++ = (uint8_t)(val >> 24); + *dest++ = (uint8_t)(val >> 16); + *dest++ = (uint8_t)(val >> 8); + *dest = (uint8_t)val; } // -// Get a Word from Memory +// Get a word from memory // -int getword(char * src) +static inline uint16_t GetWord(uint8_t * src) { - unsigned temp; - char * out; - - out = (char *)&temp; - *out++ = src[1]; - *out++ = src[0]; - *out++ = 0; - *out = 0; - - return temp; + return (src[0] << 8) | src[1]; } // -// Put a Word into Memory +// Put a word into memory // -void putword(char * dest, int val) +static inline void PutWord(uint8_t * dest, uint16_t val) { - *dest++ = (char)(val >> 8); - *dest = (char)val; + *dest++ = (uint8_t)(val >> 8); + *dest = (uint8_t)val; } // -// Obtain a File's Size +// Find passed in file's length in bytes +// N.B.: This also resets the file's pointer to the start of the file // -long FSIZE(int fd) +long FileSize(int fd) { - unsigned temp, hold; + long size = lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_SET); - temp = lseek(fd, 0L, SEEK_CUR); - hold = lseek(fd, 0L, SEEK_END); - lseek(fd, 0L, SEEK_SET); - - return hold; + return size; } // // For this object file, add symbols to the output symbol table after -// relocating them. Returns TRUE if ost_lookup returns an error (-1). +// relocating them. Returns TRUE if OSTLookup returns an error (-1). // -int dosym(struct OFILE * ofile) +int DoSymbols(struct OFILE * ofile) { - char * symptr; // Symbol pointer - char * symend; // Symbol end pointer - int type; // Symbol type - long value; // Symbol value - int index; // Symbol index - int j; // Iterator - int ssidx; // Segment size table index - unsigned tsegoffset; // Cumulative TEXT segment offset - unsigned dsegoffset; // Cumulative DATA segment offset - unsigned bsegoffset; // Cumulative BSS segment offset - struct HREC * hptr; // Hash table pointer for globl/extrn - char sym[SYMLEN]; // String for symbol name/hash search - - // Point to first symbol record in the object file - symptr = (ofile->o_image + 32 + - ofile->o_header.tsize + - ofile->o_header.dsize + - ofile->o_header.absrel.reloc.tsize + - ofile->o_header.absrel.reloc.dsize); - - // Point to end of symbol record in the object file - 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. - ssidx = -1; // Initialise segment index - tsegoffset = dsegoffset = bsegoffset = 0; // Initialise segment offsets - - for(j=0; j<(int)obj_index; j++) - { // Search for object file name - if (!strcmp(ofile->o_name, obj_fname[j])) - { - ssidx = j; // Object file name found - break; - } - - tsegoffset += obj_segsize[j][0]; // Accumulate segment sizes - dsegoffset += obj_segsize[j][1]; - bsegoffset += obj_segsize[j][2]; - } - - if (ssidx == -1) - { - printf("dosym() : Cannot get object file segment size : %s\n", ofile->o_name); - return 1; - } - - // Process each record in the 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 - - // Global/External symbols have a pre-processing stage - if (type & 0x01000000) - { - // Obtain the string table index for the relocation symbol, look 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. - memset(sym, 0, SYMLEN); - strcpy(sym, symend + index); - hptr = lookup(sym); - - if (hptr == NULL) - { - printf("dosym() : Cannot determine symbol : %s\n", sym); - return 1; - } - - // 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; // Initialise segment index - tsegoffset = dsegoffset = bsegoffset = 0; // Initialise segment offsets - - for(j=0; j<(int)obj_index; j++) - { // Search for object filename - if (!strcmp((const char *)hptr->h_ofile, obj_fname[j])) + int type; + long value; + int index; + char *string; + int j; + struct HREC * hptr; + uint32_t tsoSave, dsoSave, bsoSave; + + // Point to first symbol record in the object file + char * symptr = (ofile->o_image + 32 + + ofile->o_header.tsize + + ofile->o_header.dsize + + ofile->o_header.absrel.reloc.tsize + + ofile->o_header.absrel.reloc.dsize); + + // Point to end of symbol record in the object file + char * symend = symptr + ofile->o_header.ssize; + + 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; + + // 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 + 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 + // local symbol follows a global/exported one, it gets wrong + // info! [Should be FIXED now] + if (type & 0x01000000) + { + // 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(string); + + if (hptr == NULL) + { + // Try to find it in the OST + int ostIndex = OSTLookup(string); + + if (ostIndex == -1) + { + 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 [or maybe not? In verbose mode, we see nothing...!] + continue; + } + + 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 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 + // accordance with the segment sizes of the object file it + // originates from + if (hptr->h_value) { - ssidx = j; // Symbol object filename - break; - } - - tsegoffset += obj_segsize[j][0]; // Accumulate segment sizes - dsegoffset += obj_segsize[j][1]; - bsegoffset += obj_segsize[j][2]; - } - - if (ssidx == -1) - { - printf("dosym() : Cannot get object file segment size : %s\n", - ofile->o_name); - return 1; - } - - type = hptr->h_type; // Update type with global type - - if (type == 0x03000000) - type = 0x02000000; // Reset external flag if absolute - - // If the global/external has a value then update that vaule in accordance with the - // segment sizes of the object file it originates from - if (hptr->h_value) - { - switch (hptr->h_type & 0x0E000000) + switch (hptr->h_type & 0x0E000000) + { + case T_ABS: + case T_TEXT: + value = hptr->h_value; + break; + case T_DATA: + value = hptr->h_value - hptr->h_ofile->o_header.tsize; + break; + case T_BSS: + value = hptr->h_value + - (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); + } + } + } + // If *not* a global/external, use the info from passed in object + else + tsegoffset = tsoSave, dsegoffset = dsoSave, bsegoffset = bsoSave; + + // Process and update the value dependent on whether the symbol is a + // debug symbol or not + // N.B.: Debug symbols are currently not supported + if (type & 0xF0000000) + { + // DEBUG SYMBOL + switch (type & 0xFF000000) + { + case 0x64000000: // Primary source file path and/or name + case 0x84000000: // Included source file path and/or name + case 0x44000000: // Text line number + value = tbase + tsegoffset + value; + break; + case 0x46000000: // Data line number (Not used by GCC/rmac) + value = dbase + dsegoffset + value; + break; + case 0x48000000: // BSS line number (Not used by GCC/rmac) + value = bbase + bsegoffset + value; + default: + // All other debug symbols don't need to be relocated + // XXX Not true, but matches ALN behavior. + break; + } + + PutLong(symptr + 8, value); + } + else + { + // NON-DEBUG SYMBOL + // Now make modifications to the symbol value, local or global, + // based on the segment sizes of the object file currently being + // processed. + switch (type & T_SEG) + { + case T_ABS: + break; + case T_TEXT: + value = tbase + tsegoffset + value; + PutLong(symptr + 8, value); + break; + case T_DATA: + if (type & T_GLBL) + value = dbase + dsegoffset + value; + else + value = dbase + dsegoffset + (value + - ofile->o_header.tsize); + + PutLong(symptr + 8, value); + break; + case T_BSS: + 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); + break; + default: + break; + } + } + + // Add to output symbol table if global/extern, or local flag is set + if (isglobal(type) || lflag) + { + 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) { - case 0x02000000: // Absolute value - case 0x04000000: // TEXT segment - value = hptr->h_value; - break; - case 0x06000000: // DATA segment - value = hptr->h_value - (hptr->h_ofile->o_header.tsize); - break; - case 0x08000000: // BSS segment - value = hptr->h_value - - (hptr->h_ofile->o_header.tsize + hptr->h_ofile->o_header.dsize); - break; - } - } - } - - // Process and update the value dependant on whether the symbol is a debug symbol or not - 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); - break; - case T_BSS: // BSS segment - if (type & 0x01000000) value = bbase + bsegoffset + value; - else value = bbase + bsegoffset + - (value - (ofile->o_header.tsize + ofile->o_header.dsize)); - putlong(symptr + 8, value); - break; - default: - break; - } - } - - // Add to output symbol table - if (lflag || !islocal(type)) - { - if (islocal(type) || isglobal(type)) - { - if ((index = ost_add(symend + index, type, value)) == -1) - return 1; - } - else - { - // Belongs in OST, but don't look it up yet - index = -1; - } - } - } - - dosymi++; // Increment dosym() processsing - return 0; + printf("DoSymbols(): Failed to add symbol '%s' to OST!\n", string); + return 1; + } + } + } + + return 0; } // -// Free Up Hash Records +// Free up hash memory // -void hash_free(void) +void FreeHashes(void) { int i; - struct HREC * htemp, * hptr; for(i=0; ih_next; + struct HREC * htemp = hptr->h_next; free(hptr); hptr = htemp; } @@ -378,26 +343,39 @@ void hash_free(void) } -// -// Add all Global and External Symbols to the Output Symbol Table -// -long docommon(void) +// +// Add all global and external symbols to the output symbol table +// [This is confusing--is it adding globals or locals? common == local! +// 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; // Hash record pointer - int i; // Iterator + struct HREC * hptr; + int i; for(i=0; ih_next) { - if (iscommon(hptr->h_type)) +//NO! if (iscommon(hptr->h_type)) + if (isglobal(hptr->h_type))// || isextern(hptr->h_type)) { - if (hptr->h_type == 0x03000000) - hptr->h_type = 0x02000000; // Absolutes can't be externals +// Skip if in *.a file... (does nothing) +//if (hptr->h_ofile->isArchiveFile) +// continue; - if (ost_add(hptr->h_sym, hptr->h_type, hptr->h_value) == -1) +//Is this true? Couldn't an absolute be exported??? + 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) return -1; - } + } } } @@ -406,392 +384,546 @@ long docommon(void) // -// Add a Symbol's Name, Type, and Value to the OST. -// Return the Index of the Symbol in OST, or -1 for Error. +// Add a symbol's name, type, and value to the OST. +// Returns the index of the symbol in OST, or -1 for error. // -int ost_add(char *name, int type, long value) +int OSTAdd(char * name, int type, long value) { - int ost_offset_p, ost_offset_e = 0; // OST table offsets for position calcs - int slen = 0; // Symbol string length - int ostresult; // OST index result - - slen = strlen(name); - - // If the OST or OST String Table has not been initialised then do so - if (ost_index == 0) { - if ((ost = malloc(OST_BLOCK)) == NULL) { - printf("OST memory allocation error (stringtable).\n"); - return(-1); - } - ost_ptr = ost; // Set OST start pointer - ost_end = ost + OST_BLOCK; // Set OST end pointer - if ((oststr = malloc(OST_BLOCK)) == NULL) { - printf("OST memory allocation error (string).\n"); - return(-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; - } else { - // If next symbol record exceeds current allocation then expand symbol table. - ost_offset_p = (ost_ptr - ost); - ost_offset_e = (ost_end - ost); - if ((ost_ptr + 12) > ost_end) { // 3 x int (12) - if ((ost = realloc(ost, (unsigned)(ost_end + OST_BLOCK))) == NULL) { - printf("OST memory reallocation error.\n"); - return(-1); - } - ost_ptr = ost + ost_offset_p; - ost_end = (ost + ost_offset_e) + OST_BLOCK; - } - ost_offset_p = (oststr_ptr - oststr); - ost_offset_e = (oststr_end - oststr); - if ((oststr_ptr + (slen+1+4)) > oststr_end) { - if ((oststr = realloc(oststr, (unsigned)(oststr_end + OST_BLOCK))) == NULL) { - printf("OSTSTR memory reallocation error.\n"); - return(-1); - } - 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 - } else { - ostresult = ost_lookup(name); // Get symbol index in OST - // 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 - putlong(ost_ptr + 4, type ); - putlong(ost_ptr + 8, value); - ost_ptr += 12; - // 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 - } - return(ost_index++); // Return OST index - } - } - - return 0; // not sure about this as it could affect return indices. needed to stop return error. + int ost_offset_p = 0, ost_offset_e; // OST table offsets for position calcs + int ostresult; // OST index result + int slen; // String length, including terminator + + // 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 (!name || !name[0]) + slen = 0; + else + slen = strlen(name) + 1; + + // Get symbol index in OST, if any (-1 if not found) + ostresult = slen ? OSTLookup(name) : -1; + + // 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; + } + + // If the OST has not been initialised, or more space is needed, then + // allocate it. + if ((ost_index + 1) > ost_size) + { + if (ost_size == 0) + ost_size = OST_SIZE_INIT; + + ost_size *= 2; + + ost = realloc(ost, ost_size * sizeof(ost[0])); + + 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); + + // If the OST data has been exhausted, allocate another chunk. + if (((oststr_ptr + slen + 4) > oststr_end)) + { + // string length + terminating NULL + uint32_t (terminal long) + if ((oststr_ptr + (slen + 1 + 4)) > oststr_end) + { + oststr = realloc(oststr, ost_offset_e + OST_BLOCK); + + if (oststr == NULL) + { + printf("OSTSTR memory reallocation error.\n"); + return -1; + } + + oststr_ptr = oststr + ost_offset_p; + oststr_end = (oststr + ost_offset_e) + OST_BLOCK; + + // On the first alloc, reserve space for the string table + // size field. + if (ost_offset_e == 0) + oststr_ptr += 4; + } + } + + 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 + } + + ostresult = ost_index++; + + ost[ostresult].s_idx = ost_offset_p; + ost[ostresult].s_type = type; + ost[ostresult].s_value = value; + + if (vflag > 1) + printf("OSTAdd: (%s), type=$%08X, val=$%08lX\n", + slen ? name : "", type, value); + + return ost_index; } + // -// Return the Index of a Symbol in the Output Symbol Table ------------------------------------- +// Return the index of a symbol in the output symbol table +// N.B.: This is a 1-based index! (though there's no real reason for it to be) // +int OSTLookup(char * sym) +{ + int i; -int ost_lookup(char *sym) { - int i; // Iterator - int stro = 4; // Offset in string table - - for(i = 0; i < ost_index; i++) { - if (!strcmp(oststr+stro, sym)) { - return(i+1); - } else { - stro += strlen(oststr+stro) + 1; - } - } + for(i=0; ih_sym, T_GLBL, 0L) == -1) + return 1; + + if (vflag > 1) + printf("DoUnresolved(): '%s' (%s:$%08X) in OST\n", hptr->h_sym, hptr->h_ofile->o_name, hptr->h_type); -int dounresolved(void) { - struct HREC *hptr, *htemp; // Hash record pointers + struct HREC * htemp = hptr->h_next; + free(hptr); + hptr = htemp; + } - hptr = unresolved; // Point to unresolved symbols list - - while (hptr != NULL) { // While unresolved list is valid - if (ost_add(hptr->h_sym, T_EXT, 0L) == -1) return 1; - htemp = hptr->h_next; // Temporarily get ptr to next record - free(hptr); // Free current record - hptr = htemp; // Make next record ptr, current - } - - unresolved = NULL; // Zero unresolved record list - - return 0; + unresolved = NULL; + return 0; } - -// ------------------------------------------------------------------------------------------------- -// Update Object File TEXT and DATA Segments Based on Relocation Records. Take in an OFILE header -// and flag (T_TEXT, T_DATA) to process. Return (0) is successful or non-zero (1) if failed. -// ------------------------------------------------------------------------------------------------- - -int reloc_segment(struct OFILE *ofile, int flag) { - char *symtab; // Start of symbol table - char *symbols; // Start of symbols - char *sptr; // Start of segment data - char *rptr; // Start of segment relocation records - unsigned symidx; // Offset to symbol - unsigned addr; // Relocation address - unsigned rflg; // Relocation flags - unsigned olddata; // Old segment data at reloc address - unsigned newdata = 0; // New segment data at reloc address - unsigned pad; // Temporary to calculate phrase padding - int i; // Iterator - char sym[SYMLEN]; // String for symbol name/hash search - int ssidx; // Segment size table index - unsigned glblreloc; // Global relocation flag - unsigned absreloc; // Absolute relocation flag - unsigned relreloc; // Relative relocation flag - unsigned swcond; // Switch statement condition - unsigned relocsize; // Relocation record size - - // 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 - if ((flag == T_TEXT) && !ofile->o_header.absrel.reloc.tsize) { - pad = ((ofile->o_header.tsize+secalign) & ~secalign); // TEXT segment size plus padding - textoffset += (ofile->o_header.tsize + (pad - ofile->o_header.tsize)); - if (vflag > 1) { // Verbose mode information - printf("reloc_segment(%s, TEXT) : No Relocation Data\n", ofile->o_name); - } - return 0; - } - - // If there is no DATA relocation data for the selected object file segment then update the COF - // DATA and BSS segment offsets allowing for the phrase padding - if ((flag == T_DATA) && !ofile->o_header.absrel.reloc.dsize) { - pad = ((ofile->o_header.dsize+secalign) & ~secalign); // DATA segment size plus padding - dataoffset += (ofile->o_header.dsize + (pad - ofile->o_header.dsize)); - pad = ((ofile->o_header.bsize+secalign) & ~secalign); // BSS segment size plus padding - bssoffset += (ofile->o_header.bsize + (pad - ofile->o_header.bsize)); - if (vflag > 1) { // Verbose mode information - printf("reloc_segment(%s, DATA) : No Relocation Data\n", ofile->o_name); - } - return 0; - } - - // Verbose mode information - if (vflag > 1) { - printf("reloc_segment(%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 + ofile->o_header.dsize + - ofile->o_header.absrel.reloc.tsize + ofile->o_header.absrel.reloc.dsize); - - // Obtain pointer to start of symbols - symbols = symtab + ofile->o_header.ssize; - - // Obtain pointer to start of TEXT segment - sptr = ofile->o_image + 32; - - // Obtain pointer to start of TEXT relocation records - rptr = sptr + (ofile->o_header.tsize + ofile->o_header.dsize); - - relocsize = ofile->o_header.absrel.reloc.tsize; - - // Update pointers if DATA relocation records are being processed - if (flag == T_DATA) { - sptr += ofile->o_header.tsize; // Start of DATA segment - rptr += ofile->o_header.absrel.reloc.tsize; // Start of DATA relocation records - relocsize = ofile->o_header.absrel.reloc.dsize; - } - - // Process each relocation record for the TEXT segment - for(i = 0; i < (int)relocsize; i += 8) { - // 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 - - // Additional processing required for global relocations - if (glblreloc) { - // Obtain the string table index for the relocation symbol, look 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)); - memset(sym, 0, SYMLEN); - strcpy(sym, symbols + symidx); - olddata = newdata = 0; // Initialise old and new segment data - ssidx = ost_lookup(sym); - newdata = getlong(ost + ((ssidx-1) * 12) + 8); - } - - // 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); - if (rflg & 0x01) 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 = glblreloc ? ((hptr->h_type & 0x0E000000) >> 16) : (rflg & 0xFFFFFF00); - swcond = (rflg & 0xFFFFFF00); - if (!glblreloc) { - switch (swcond) { - case 0x00000200: // Absolute Value - break; - case 0x00000400: // TEXT segment relocation record - if (!glblreloc) - if (flag == T_TEXT) newdata = tbase + textoffset + olddata; - else newdata = tbase + dataoffset + olddata; - break; - case 0x00000600: // DATA segment relocation record - if (!glblreloc) newdata = dbase + dataoffset + (olddata - ofile->o_header.tsize); - break; - case 0x00000800: // BSS segment relocation record - if (!glblreloc) newdata = bbase + bssoffset + - (olddata - (ofile->o_header.tsize + ofile->o_header.dsize)); - break; - } - } else { - if (!relreloc) newdata += olddata; - } - // Set absolute (long) or relative (word) address of symbol - if (absreloc) { - // 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) newdata = _SWAPWORD(newdata); - - putlong(sptr + addr, newdata); - - } - else if (relreloc) { - putword(sptr + addr, newdata - tbase - addr - ofile->o_tbase); - } - - rptr += 8; // Point to the next relocation record - } - - // Update the COF segment offset allowing for the phrase padding. - if (flag == T_TEXT) { - pad = ((ofile->o_header.tsize+secalign) & ~secalign); // TEXT segment plus padding - textoffset += (ofile->o_header.tsize + (pad - ofile->o_header.tsize)); - } else { - pad = ((ofile->o_header.dsize+secalign) & ~secalign); // DATA segment plus padding - dataoffset += (ofile->o_header.dsize + (pad - ofile->o_header.dsize)); - pad = ((ofile->o_header.bsize+secalign) & ~secalign); // BSS segment plus padding - bssoffset += (ofile->o_header.bsize + (pad - ofile->o_header.bsize)); - } - - return 0; // Return value, should always be zero + + +// +// Update object file TEXT and DATA segments based on relocation records. Take +// in an OFILE header and flag (T_TEXT, T_DATA) to process. Return (0) is +// successful or non-zero (1) if failed. +// +int RelocateSegment(struct OFILE * ofile, int flag) +{ + char * symtab; // Start of symbol table + char * symbols; // Start of symbols + char * sptr; // Start of segment data + char * rptr; // Start of segment relocation records + unsigned symidx; // Offset to symbol + unsigned addr; // Relocation address + unsigned rflg; // Relocation flags + unsigned olddata; // Old segment data at reloc address + unsigned newdata = 0; // New segment data at reloc address + unsigned pad; // Temporary to calculate phrase padding + int i; // Iterator + char sym[SYMLEN]; // String for symbol name/hash search + int ssidx; // Segment size table index + 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 + if ((flag == T_TEXT) && !ofile->o_header.absrel.reloc.tsize) + { + // SCPCD : we should not increment the textoffset before the end of processing the object file, else data section will point to wrong textoffset + return 0; + } + + // If there is no DATA relocation data for the selected object file segment + // then update the COF DATA and BSS segment offsets allowing for the phrase + // padding + if ((flag == T_DATA) && !ofile->o_header.absrel.reloc.dsize) + { + // SCPCD : the T_DATA is the last section of the file, we can now increment the textoffset, dataoffset and bssoffset + + // TEXT segment size plus padding + pad = ((ofile->o_header.tsize + secalign) & ~secalign); + textoffset += (ofile->o_header.tsize + (pad - ofile->o_header.tsize)); + + if (vflag > 1) + 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); + + return 0; + } + + 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 + + ofile->o_header.dsize + + ofile->o_header.absrel.reloc.tsize + + ofile->o_header.absrel.reloc.dsize); + + // Obtain pointer to start of symbols + symbols = symtab + ofile->o_header.ssize; + + // Obtain pointer to start of TEXT segment + sptr = ofile->o_image + 32; + + // Obtain pointer to start of TEXT relocation records + rptr = sptr + (ofile->o_header.tsize + ofile->o_header.dsize); + + relocsize = ofile->o_header.absrel.reloc.tsize; + + if (vflag) + printf("RELOCSIZE :: %d Records = %d\n", relocsize, relocsize / 8); + + // Update pointers if DATA relocation records are being processed + if (flag == T_DATA) + { + sptr += ofile->o_header.tsize; // Start of DATA segment + rptr += ofile->o_header.absrel.reloc.tsize; // Start of DATA relocation records + relocsize = ofile->o_header.absrel.reloc.dsize; + } + + // Process each relocation record for the TEXT segment + for(i=0; i<(int)relocsize; i+=8) + { + // Obtain both the relocation address and the relocation flags from the + // object file image + 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) + { + // Obtain the string table index for the relocation symbol, look + // 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 + (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 = ost[ssidx - 1].s_value; + } + + // 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 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 & BSDREL_SEGMASK); + + if (!glblreloc) + { + switch (swcond) + { + case BSDREL_SEG_ABS: + break; + case BSDREL_SEG_TEXT: + // SCPCD : the symbol point to a text segment, we should use the textoffset + newdata = tbase + textoffset + olddata; + + break; + case BSDREL_SEG_DATA: + newdata = dbase + dataoffset + + (olddata - ofile->o_header.tsize); + + break; + case BSDREL_SEG_BSS: + newdata = bbase + bssoffset + + (olddata - (ofile->o_header.tsize + + ofile->o_header.dsize)); + + break; + } + } + else + { + if (!relreloc) + newdata += olddata; + } + + // Set absolute (long) or relative (word) address of symbol + if (absreloc) + { + // 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 & BSDREL_MOVEI) + newdata = _SWAPWORD(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); + } + + // Shamus: Let's output some info to aid in debugging this crap + if (vflag > 1) + { + char ssiString[128]; + ssiString[0] = 0; + + 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); + } + + rptr += 8; // Point to the next relocation record + } + + // Update the COF segment offset allowing for the phrase padding. + // SCPCD : we should not increment the textoffset before the end of processing the object file, else data section will point to wrong textoffset + if (flag == T_DATA) + { + // TEXT segment plus padding + pad = ((ofile->o_header.tsize + secalign) & ~secalign); + textoffset += (ofile->o_header.tsize + (pad - ofile->o_header.tsize)); + + // 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)); + } + + // Return value, should always be zero + return 0; } + // -// ------------------------------------------------------------------------------------------------- -// Add a path character to the end of string 's' if it doesn't already end with one. -// The last occurrance of '/' or '\\' in the string is assumed to be the path character. -// ------------------------------------------------------------------------------------------------- +// Add a path character to the end of string 's' if it doesn't already end with +// one. The last occurrance of '/' or '\' in the string is assumed to be the +// path character. // +// This is fucking shit. We know what the path delimiter is, its FUCKING +// DEFINED IN THE FUCKING HEADER. FOR FUCKS SAKE. AND YES, HOPE TO GOD THERE'S +// ENOUGH SPACE IN THE PASSED IN BUFFER TO HOLD THE EXTRA CHARACTER! +// +void AppendPathDelimiter(char * s) +{ +#if 0 + // And hope to God that there's enough space in the buffer... + char pathchar = 0; -void pathadd(char *s) { - char pathchar = 0; + while (*s) + { + if (*s == '/' || *s == '\\') + pathchar = *s; + + s++; + } + + s--; - while (*s) { - if (*s == '/' || *s == '\\') pathchar = *s; - s++; - } - s--; - if (*s == pathchar) return; + if (*s == pathchar) + return; - *++s = pathchar; - *++s = 0; + *++s = pathchar; + *++s = 0; +#else + int length = strlen(s); + + if (s[length - 1] != PATH_DELIMITER) + { + s[length] = PATH_DELIMITER; + s[length + 1] = 0; // BUFFER OVERFLOW!!!! FFFFFFFFUUUUUUUUUUUU + } +#endif } + // -// ------------------------------------------------------------------------------------------------- -// Try to open "name", "name.o", "${libdir}name", "${libdir}name.o". Return the handle of the file -// successfully opened. p_name is updated to point to a malloc()'ed string which is the name which -// actually got opened. p_name will return unchanged if the file can't be found. -// ------------------------------------------------------------------------------------------------- -// - -int tryopen(char **p_name) { - char *name = *p_name; // Filename - char *tmpbuf, *lastdot; // Buffer and 'dot' pointers - int fd, hasdot; // File descriptor and 'has dot' flag - - // Note that libdir will be an empty string if there is none specified - if ((tmpbuf = malloc((long)strlen(name) + strlen(libdir) + 3)) == NULL) { - printf("tryopen() : out of memory\n"); - return(-1); - } - strcpy(tmpbuf, name); - - hasdot = ((lastdot = strrchr(tmpbuf, '.')) > strrchr(tmpbuf, '/')) && - (lastdot > strrchr(tmpbuf, '\\')); - - if ((fd = open(tmpbuf, _OPEN_FLAGS)) >= 0) goto ok; // Try to open file as passed first - if (!hasdot) { - strcat(tmpbuf, ".o"); // Try to open file with '.o' added - if ((fd = open(tmpbuf, _OPEN_FLAGS)) >= 0) goto ok; - } - - // Try the libdir only if the name isn't already anchored - if (*name != '/' && *name != '\\' && !strchr(name, ':')) { - strcpy(tmpbuf,libdir); - // Add a trailing path char if there isn't one already - pathadd(tmpbuf); - strcat(tmpbuf, name); - if ((fd = open(tmpbuf, _OPEN_FLAGS)) >= 0) goto ok; - if (!hasdot) { - strcat(tmpbuf, ".o"); - if ((fd = open(tmpbuf, _OPEN_FLAGS)) >= 0) goto ok; - } - } - - return(-1); // Couldn't open file at all - - ok: // What more Atari label use - sigh!!! - - if ((tmpbuf = realloc(tmpbuf, (long)strlen(tmpbuf) + 1)) == NULL) { - printf("tryopen() : out of memory\n"); - return(-1); - } - *p_name = tmpbuf; - - return(fd); // Return file descriptor +// Try to open "name", "name.o", "${libdir}name", "${libdir}name.o". Return the +// handle of the file successfully opened. p_name is updated to point to a +// malloc()'ed string which is the name which actually got opened. p_name will +// return unchanged if the file can't be found. +// +int TryOpenFile(char ** p_name) +{ + char * name = *p_name; + + // Note that libdir will be an empty string if there is none specified + char * tmpbuf = malloc(strlen(name) + strlen(libdir) + 3); + + if (tmpbuf == NULL) + { + printf("TryOpenFile() : out of memory\n"); + return -1; + } + + strcpy(tmpbuf, name); + int hasdot = (strrchr(tmpbuf, '.') > strrchr(tmpbuf, PATH_DELIMITER)); + // Try to open file as passed first + int fd = open(tmpbuf, _OPEN_FLAGS); + + if (fd >= 0) + goto ok; + + if (!hasdot) + { + // Try to open file with '.o' added + strcat(tmpbuf, ".o"); + fd = open(tmpbuf, _OPEN_FLAGS); + + if (fd >= 0) + goto ok; + } + + // Try the libdir only if the name isn't already anchored + // Shamus: WTH, this makes no sense... Why the ':'? Is this a Macintosh?? +// if (*name != '/' && *name != '\\' && !strchr(name, ':')) + if ((*name != PATH_DELIMITER) && (strchr(name, ':') == NULL)) + { + strcpy(tmpbuf, libdir); + // Add a trailing path char if there isn't one already + AppendPathDelimiter(tmpbuf); + strcat(tmpbuf, name); + + if ((fd = open(tmpbuf, _OPEN_FLAGS)) >= 0) + goto ok; + + if (!hasdot) + { + strcat(tmpbuf, ".o"); + + if ((fd = open(tmpbuf, _OPEN_FLAGS)) >= 0) + goto ok; + } + } + + // Couldn't open file at all + return -1; + +// There are worse things... :-P +ok: + tmpbuf = realloc(tmpbuf, strlen(tmpbuf) + 1); + + if (tmpbuf == NULL) + { + printf("TryOpenFile() : out of memory\n"); + return -1; + } + + *p_name = tmpbuf; + return fd; } // -// Archive File Use, Needs to be Removed +// 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 ? p->o_arname : "", flag ? ":" : "", p->o_name); + printf("%s%s%s", (flag ? (char *)(p->o_arname) : ""), (flag ? ":" : ""), p->o_name); } // // Collect file names and handles in a buffer so there is less disk activity. -// Call dofile with flag FALSE for normal object files and archives. +// Call DoFile with flag FALSE for normal object files and archives. // Call it with flag TRUE and a symbol name for include files (-i). // -int dofile(char * fname, int flag, char * sym) +int DoFile(char * fname, int incFlag, char * sym) { - int fd; // File descriptor - int temp; // Temporary storage - // Verbose information if (vflag) { - printf("dofile() : `%s' %s", fname, flag ? "INCLUDE" : "NORMAL"); + printf("DoFile() : `%s' %s", fname, incFlag ? "INCLUDE" : "NORMAL"); - if (flag) + if (incFlag) printf(" symbol %s", sym); printf("\n"); @@ -800,39 +932,42 @@ int dofile(char * fname, int flag, char * sym) // Reached maximum file handles if (hd == NHANDLES) { - if (flush_handles()) return 1; + if (ProcessFiles()) + return 1; } // Attempt to open input file - if ((fd = tryopen(&fname)) < 0) + int fd = TryOpenFile(&fname); + + if (fd < 0) { printf("Cannot find input module %s\n", fname); return 1; } - // The file is open; save its info in the handle and name arrays + // The file is open; save its info in the handle and name arrays handle[hd] = fd; - name[hd] = fname; // This is the name from tryopen() - hflag[hd] = flag; + name[hd] = fname; // This is the name from TryOpenFile() + hflag[hd] = incFlag; // Include files - if (flag) + if (incFlag) { - temp = strlen(sym); // Get symbol length + int temp = strlen(sym); // Get symbol length - // 100 chars is max length of a symbol + // 100 chars is max length of a symbol if (temp > 99) { sym[99] = '\0'; temp = 99; } - // Malloc enough space for two symbols, then build the second one. Second one may be one - // character longer than first + // Malloc enough space for two symbols, then build the second one. + // Second one may be one character longer than first if ((hsym1[hd] = malloc((long)temp + 1)) == NULL || (hsym2[hd] = malloc((long)temp + 2)) == NULL) { - printf("dofile() : out of memory for include-file symbols\n"); + printf("DoFile() : out of memory for include-file symbols\n"); return 1; } @@ -856,23 +991,24 @@ int dofile(char * fname, int flag, char * sym) } } - hd++; // Increment next handle index - return 0; // No problems + // Increment next handle index + hd++; + // No problems + return 0; } // -// Pad TEXT or DATA Segment to the Requested Boundary +// 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) { - long padsize; // Number of pad bytes needed - int i; // Good 'ol iterator - char padarray[32]; // Array of padding bytes - char * padptr; // Pointer to array + int i; + char padarray[32]; + char * padptr; // Determine the number of padding bytes that are needed - padsize = (segsize + secalign) & ~secalign; + long padsize = (segsize + secalign) & ~secalign; padsize = padsize - segsize; // Fill pad array if padding is required @@ -882,51 +1018,52 @@ int segmentpad(FILE * fd, long segsize, int value) for(i=0; i<16; i++) { - putword(padptr, value); + PutWord(padptr, value); padptr += 2; } symoffset += padsize; - if (fwrite(padarray, padsize, 1, fd) != 1) // Write padding bytes + // Write padding bytes + if (fwrite(padarray, padsize, 1, fd) != 1) return 1; } - return 0; // All done + return 0; } // -// Write the Output File +// Write the output file // -int write_ofile(struct OHEADER * header) +int WriteOutputFile(struct OHEADER * header) { - FILE * fd; // File descriptor - 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 - short abstype; // ABS symbol type - char symbol[14]; // Symbol record for ABS files - int slen; // Symbol string length - - symoffset = 0; // Initialise symbol offset + unsigned osize; // Object segment size + struct OFILE * otemp; // Object file pointer + int i, j; // Iterators + char himage[0x168]; // Header image (COF = 0xA8) + uint32_t tsoff, dsoff, bsoff; // Segment offset values + short abstype; // ABS symbol type + char symbol[14]; // raw symbol record + + symoffset = 0; // Initialise symbol offset // Add correct output extension if none if (strchr(ofile, '.') == NULL) { - if (aflag && cflag) strcat(ofile, ".cof"); // COF files - else if (aflag && !cflag) strcat(ofile, ".abs"); // ABS files - else strcat(ofile, ".o"); // Object files (partial linking etc) + if (aflag && cflag) + 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) } - fd = fopen(ofile, "wb"); // Attempt to open output file + FILE * fd = fopen(ofile, "wb"); // Attempt to open output file if (!fd) - { - printf("Can't open output file %s\n", ofile); // Error opening output file + { + printf("Can't open output file %s\n", ofile); return 1; } @@ -934,106 +1071,108 @@ int write_ofile(struct OHEADER * header) // Absolute (COF) header if (cflag) { - tsoff = dsoff = bsoff = 0xA8; // Initialises segment offsets + tsoff = dsoff = bsoff = 0xA8; // Initialises segment offsets - // 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++) + // Process each object file segment size to obtain a cumulative segment + // size for both the TEXT and DATA segments + 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. + // 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 - - symoffset = 168; // Update symbol offset + 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 } // Absolute (ABS) 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 - - symoffset = 36; // Update symbol offset + 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) - if (fwrite(himage, 36, 1, fd) != 1) + // 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 @@ -1047,11 +1186,11 @@ int write_ofile(struct OHEADER * header) if (vflag > 1) printf("Writing TEXT Segment of %s\n", otemp->o_name); - if (fwrite(otemp->o_image + 32, osize, 1, fd) != 1) + if (fwrite(otemp->o_image + 32, osize, 1, fd) != 1) goto werror; // Pad to required alignment boundary - if (segmentpad(fd, osize, 0x0000)) + if (PadSegment(fd, osize, 0x0000)) goto werror; symoffset += osize; @@ -1059,7 +1198,7 @@ int write_ofile(struct OHEADER * header) } // Write the DATA segment of each object file - for(otemp = olist; otemp != NULL; otemp = otemp->o_next) + for(otemp=olist; otemp!=NULL; otemp=otemp->o_next) { osize = otemp->o_header.dsize; @@ -1073,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 @@ -1088,46 +1232,44 @@ int write_ofile(struct OHEADER * header) { if (header->ssize) { - if (fwrite(ost, (ost_ptr - ost), 1, fd) != 1) goto werror; - if (fwrite(oststr, (oststr_ptr - oststr), 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; } } // Absolute (ABS) symbol/string table else { - // The symbol and string table have been created as part of the dosym() function and the - // output symbol and string tables are in COF format. For an ABS file we need to process - // through this to create the 14 character long combined symbol and string table. - // Format of symbol table in ABS: AAAAAAAATTVVVV, where (A)=STRING, (T)=TYPE & (V)=VALUE + // The symbol and string table have been created as part of the + // DoSymbols() function and the output symbol and string tables are + // in COF format. For an ABS file we need to process through this + // to create the 14 character long combined symbol and string + // table. Format of symbol table in ABS: AAAAAAAATTVVVV, where + // (A)=STRING, (T)=TYPE & (V)=VALUE for(i=0; i 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; - } - - ohold = otemp; - free(ohold->o_image); - free(ohold); + printf("Unused object file "); + WriteARName(otemp); + printf(" discarded.\n"); } + + // Drop the entry from the linked list + if (oprev == NULL) + olist = otemp->o_next; 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; - } + oprev->o_next = otemp->o_next; + + // Free the object entry if it's not an archive file + if (!otemp->isArchiveFile) + free(otemp->o_image); + } + else + { + // Save accumulated addresses in the object + otemp->segBase[TEXT] = textsize; + otemp->segBase[DATA] = datasize; + otemp->segBase[BSS] = bsssize; + + // 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; } - otemp = otemp->o_next; // Go to next object file list pointer + // Go to next object file list pointer + otemp = otemp->o_next; } - // 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; - ost_add("_TEXT_E", 0x05000000, tval + textsize); if (!dval) { // DATA follows TEXT dbase = tval + textsize; - ost_add("_DATA_E", 0x07000000, tval + textsize + datasize); if (!bval) - { // BSS follows DATA bbase = tval + textsize + datasize; - ost_add("_BSS_E", 0x09000000, tval + textsize + datasize + bsssize); - } else - { - // BSS is independant of DATA + // BSS is independent of DATA bbase = bval; - ost_add("_BSS_E", 0x09000000, bval + bsssize); - } } else { - // DATA is independant of TEXT + // DATA is independent of TEXT dbase = dval; - ost_add("_DATA_E", 0x07000000, dval + datasize); if (!bval) { - // BSS follows DATA - bbase = dval + datasize; - ost_add("_BSS_E", 0x09000000, dval + datasize + bsssize); + if (btype == -2) + // BSS follows TEXT + bbase = tval + textsize; + else + // BSS follows DATA + bbase = dval + datasize; } else { - // BSS is independant of DATA + // BSS is independent of DATA bbase = bval; - ost_add("_BSS_E", 0x09000000, bval + bsssize); } } - // Place each unresolved symbol in the output symbol table - if (dounresolved()) - return NULL; + // 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); + + // Place each unresolved symbol in the output symbol table + // N.B.: It only gets here to do this if user passes in -u flag + // [Only used here, once] + if (DoUnresolved()) + return NULL; - tptr = 0; // Initialise base addresses - dptr = 0; - bptr = 0; + // Initialise base addresses + tptr = dptr = bptr = 0; - // For each file, relocate its symbols and add them to the output symbol table + // For each file, relocate its symbols and add them to the output symbol + // table otemp = olist; oprev = NULL; 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; - } - // For each symbol, (conditionally) add it to the ost - // For ARCHIVE markers, this adds the symbol for the file & returns - if (dosym(otemp)) + 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 + // (Shamus: N.B. it does no such thing ATM) + // [Only used here, once] + 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; - } - - ohold = otemp; - - if (ohold->o_image) free(ohold->o_image); - free(ohold); - } - else - { - oprev = otemp; - } - + oprev = otemp; otemp = otemp->o_next; } // Places all the externs, globals etc into the output symbol table - if (docommon() == -1) + if (DoCommon() == -1) return NULL; // Create a new output file header - if ((header = new_oheader()) == NULL) + header = new_oheader(); + + if (header == NULL) { - printf("make_ofile: out of memory!\n"); + printf("MakeOutputObject: out of memory!\n"); return NULL; } - // Fill in the output header. Does not match the actual output but values used as reference - header->magic = 0x0150; // COF magic number - 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 - - // 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 + // Fill in the output header. Does not match the actual output but values + // used as reference + header->magic = 0x0150; // COF magic number + header->tsize = textsize; // TEXT segment size + header->dsize = datasize; // DATA segment size + header->bsize = bsssize; // BSS segment size + 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 |= reloc_segment(otemp, T_TEXT); // TEXT segment relocations - ret |= reloc_segment(otemp, T_DATA); // DATA segment relocations - } + ret |= RelocateSegment(otemp, T_TEXT); // TEXT segment relocations + ret |= RelocateSegment(otemp, T_DATA); // DATA segment relocations } - hash_free(); // Done with global symbol hash tables + // Done with global symbol hash tables + FreeHashes(); - return (ret ? (unsigned)NULL : header); + return (ret ? (struct OHEADER *)NULL : header); } // -// Add Symbol to Hash List +// Add symbol to hash list // -int add_to_hlist(struct HREC **hptr, char *sym, struct OFILE *ofile, long value, int type) +int AddSymbolToHashList(struct HREC ** hptr, char * sym, struct OFILE * ofile, + long value, int type) { - struct HREC *htemp; // Temporary hash record pointer - int i; + struct HREC * htemp = new_hrec(); - // Attempt to allocate new hash record - if ((htemp = new_hrec()) == NULL) + if (htemp == NULL) { printf("Out of memory\n"); return 1; } - for(i=0; ih_sym[i] = '\0'; + // Shamus: Moar testing... + if (vflag > 1) + { + printf("AddSymbolToHashList(): hptr=$%08X, sym=\"%s\", ofile=$%08X, value=$%X, type=$%X\n", hptr, sym, ofile, value, type); + } - strcpy(htemp->h_sym, sym); // Populate hash record + // Populate hash record + memset(htemp->h_sym, 0, SYMLEN); + strcpy(htemp->h_sym, sym); htemp->h_ofile = ofile; htemp->h_value = value; htemp->h_type = type; - htemp->h_next = *hptr; // Update hash record pointers + // Add new hash to the front of the list (hence the ** for hptr) + htemp->h_next = *hptr; *hptr = htemp; return 0; @@ -1534,1032 +1656,1699 @@ int add_to_hlist(struct HREC **hptr, char *sym, struct OFILE *ofile, long value, // -// Add Symbol to the Unresolved Symbols Hash Table +// Add symbol to the unresolved symbols hash table (really, it's a linked list) // -add_unresolved(char * sym, struct OFILE * ofile) +int AddUnresolvedSymbol(char * sym, struct OFILE * ofile) { if (vflag > 1) - printf("add_unresolved(%s,%s)\n", sym, ofile->o_name); + printf("AddUnresolvedSymbol(%s, %s)\n", sym, ofile->o_name); - return add_to_hlist(&unresolved, sym, ofile, 0L, 0); + return AddSymbolToHashList(&unresolved, sym, ofile, 0L, 0); } // -// Generate and Return Hash Value +// Remove the HREC from the unresolved symbol list, and pass back a pointer +// to the spot where the HREC was. // -int dohash(char * s) +struct HREC * RemoveUnresolvedSymbol(struct HREC * hrec) { - int i = (s[0]+s[1]+s[2]+s[3]+s[4]+s[5]+s[6]+s[7] +s[8]+s[9]+s[10]+s[11]+s[12]+s[13]+s[14]) % NBUCKETS; - return i; + struct HREC * ptr = unresolved; + struct HREC * previous = NULL; + + while ((ptr != hrec) && (ptr != NULL)) + { + previous = ptr; + ptr = ptr->h_next; + } + + // Not found...! + if (ptr == NULL) + return NULL; + + struct HREC * next = ptr->h_next; + + // Remove the head if nothing previous, otherwise, remove what we found + if (previous == NULL) + unresolved = next; + else + previous->h_next = next; + + free(ptr); + return next; +} + + +// +// Add symbol to the unresolved symbols hash table +// +int AddARSymbol(char * sym, struct OFILE * ofile) +{ + if (vflag > 1) + printf("AddARSymbol(%s, %s)\n", sym, ofile->o_name); + + return AddSymbolToHashList(&arSymbol, sym, ofile, 0L, 0); } // -// Lookup a Symbol in the Hash Table +// Generate hash value from the 1st 15 characters of the symbol modulo the +// number of buckets in the hash. // -struct HREC * lookup(char * sym) +int GetHash(char * s) { - struct HREC * hptr = htable[dohash(sym)]; // Hash index to record based on sym - char symbol[SYMLEN]; // Temporary symbol storage + // For this to be consistent, the symbol MUST be zeroed out beforehand! + // N.B.: strncpy() pads zeroes for us, if the symbol is less than 15 chars. + char c[15]; + strncpy(c, s, 15); + + int i = (c[0] + c[1] + c[2] + c[3] + c[4] + c[5] + c[6] + c[7] + c[8] + + c[9] + c[10] + c[11] + c[12] + c[13] + c[14]) % NBUCKETS; + return i; +} + - memset(symbol, 0, SYMLEN); // Clean string for comparison - strcpy(symbol, sym); +// +// Lookup a symbol in the hash table. +// Returns either a pointer to the HREC or NULL if not found. +// +struct HREC * LookupHREC(char * symbol) +{ + struct HREC * hptr = htable[GetHash(symbol)]; while (hptr != NULL) { - if (symcmp(symbol, hptr->h_sym)) +//This is utter failure... +// if (symcmp(symbol, hptr->h_sym)) <-- left here for giggles :D - LinkoVitch + // Return hash record pointer if found + if (strcmp(symbol, hptr->h_sym) == 0) return hptr; - hptr = hptr->h_next; // Return hash pointer if found + hptr = hptr->h_next; } - return NULL; // Not found in hash table + return NULL; } // -// Add Symbol to the Hash Table +// Lookup a symbol in the AR symbol table. +// Returns either a pointer to the HREC or NULL if not found. // -int hash_add(char * sym, long type, long value, struct OFILE * ofile) +struct HREC * LookupARHREC(char * symbol) { - struct HREC * hptr; - int flag = !iscommon(type); + struct HREC * hptr = arSymbol; - if (vflag > 1) + while (hptr != NULL) { - printf("hash_add(%s,%s,%lx,", sym, ofile->o_name,value); - printf("%x,%s)\n", (unsigned int)type, (flag ? "GLOBAL" : "COMMON")); + // Return hash record pointer if found + if (strcmp(symbol, hptr->h_sym) == 0) + return hptr; + + hptr = hptr->h_next; } - if ((hptr = lookup(sym)) == NULL) + return NULL; +} + + +// +// Add the imported symbols from this file to unresolved, and the global and +// common (???) symbols to the exported hash table. +// +// 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) { - return add_to_hlist(&htable[dohash(sym)], sym, ofile, value, type); + 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); } - // Already there! - if (iscommon(type) && !iscommon(hptr->h_type)) + // Get base pointer, start of sym fixups + char * ptr = Ofile->o_image + 32 + + Ofile->o_header.tsize + + Ofile->o_header.dsize + + Ofile->o_header.absrel.reloc.tsize + + Ofile->o_header.absrel.reloc.dsize; + char * sfix = ptr; // Set symbol fixup pointer + char * sstr = sfix + Ofile->o_header.ssize; // Set symbol table pointer + long nsymbols = Ofile->o_header.ssize / 12; // Obtain number of symbols + + while (nsymbols) { - // Mismatch: global came first; warn and keep the global one - if (wflag) - { - printf("Warning: %s: global from ",sym); - put_name(hptr->h_ofile); - printf(" used, common from "); - put_name(ofile); - printf(" discarded.\n"); - } + long index = GetLong(sfix); // Get symbol string index + long type = GetLong(sfix + 4); // Get symbol type + long value = GetLong(sfix + 8); // Get symbol value - putword(sym + 8, ABST_EXTERN); - putlong(sym + 10, 0L); - } - else if (iscommon(hptr->h_type) && !iscommon(type)) - { - // Mismatch: common came first; warn and keep the global one - if (wflag) + if ((Ofile->isArchiveFile) && !(Ofile->o_flags & O_USED)) { - printf("Warning: %s: global from ", sym); - put_name(ofile); - printf(" used, common from "); - put_name(hptr->h_ofile); - printf(" discarded.\n"); + if ((type & T_GLBL) && (type & (T_SEG | T_ABS))) + if (AddARSymbol(sstr + index, Ofile)) + return 1; } - - hptr->h_type = type; - hptr->h_ofile = ofile; - hptr->h_value = value; - } - else if (flag) - { // They're both global - // Global exported by another ofile; warn and make this one extern - if (wflag) + else if (type == T_GLBL) { - printf("Duplicate symbol %s: ", sym); - put_name(hptr->h_ofile); - printf(" used, "); - put_name(ofile); - printf(" discarded\n"); - } + // Global symbol that may or may not be in the current unit + hptr = LookupHREC(sstr + index); - putword(sym + 8, ABST_EXTERN); - } - else - { // They're both common - if (hptr->h_value < value) + if (hptr != NULL) + hptr->h_ofile->o_flags |= O_USED; // Mark .o file as used + // Otherwise, *maybe* add to unresolved list + else + { + // 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)) + { + if (AddUnresolvedSymbol(sstr + index, Ofile)) + return 1; // Error if addition failed + } + } + } + else if ((type & T_GLBL) && (type & (T_SEG | T_ABS))) { - hptr->h_value = value; - hptr->h_ofile = ofile; + hptr = LookupHREC(sstr + index); + + // Symbol isn't in the table, so try to add it: + if (hptr == NULL) + { + if (AddSymbolToHashList(&htable[GetHash(sstr + index)], + sstr + index, Ofile, value, type)) + return 1; + } + 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); + WriteARName(Ofile); + printf(" used, common from "); + WriteARName(hptr->h_ofile); + printf(" discarded.\n"); + } + + hptr->h_ofile = Ofile; + hptr->h_type = type; + hptr->h_value = value; + } + else + { + // Global exported by another ofile; warn and make this one + // extern + if (wflag) + { + printf("Duplicate symbol %s: ", sstr + index); + WriteARName(hptr->h_ofile); + printf(" used, "); + 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_GLBL); + } + } } + + sfix += 12; // Increment symbol fixup pointer + nsymbols--; // Decrement num of symbols to process } + // Success loading symbols return 0; } -// -// ------------------------------------------------------------------------------------------------- -// Add the imported symbols from this file to unresolved, and the global and common symbols to the -// exported hash table. -// -// Change old-style commons (type == T_EXTERN, value != 0) to new-style ones -// (type == (T_GLOBAL | T_EXTERN)). -// ------------------------------------------------------------------------------------------------- -// - -int add_symbols(struct OFILE *Ofile) { - long nsymbols; // Number of symbols in object file - char *ptr; // Object data base pointer - char *sfix; // Symbol fixup table pointer - char *sstr; // Symbol string table pointer - long index; // String index - long type; // Symbol type - long value; // Symbol value - struct HREC *hptr; // Hash record pointer - char symbol[SYMLEN]; - - if (vflag > 1) - printf("Add symbols for file %s\n", Ofile->o_name); - - ptr = Ofile->o_image + 32 + // Get base pointer, start of sym fixups - Ofile->o_header.tsize + - Ofile->o_header.dsize + - Ofile->o_header.absrel.reloc.tsize + - Ofile->o_header.absrel.reloc.dsize; - sfix = ptr; // Set symbol fixup pointer - sstr = sfix + Ofile->o_header.ssize; // Set symbol table pointer - nsymbols = Ofile->o_header.ssize / 12; // Obtain number of symbols - - while (nsymbols) { - index = getlong(sfix); // Get symbol string index - type = getlong(sfix+4); // Get symbol type - value = getlong(sfix+8); // Get symbol value - memset(symbol, 0, SYMLEN); - strcpy(symbol, sstr+index); - - if (type & T_EXT) { // If this is a global/external - if ((type - T_EXT)) { - if (hash_add(symbol, type, value, Ofile)) { // Then add to hash table - return 1; // Error if addition failed - } - } else { - if ((hptr = lookup(symbol)) != NULL) { // If value is zero and in hash table - hptr->h_ofile->o_flags |= O_USED; // Mark symbol as used - } else if (add_unresolved(symbol, Ofile)) { // Otherwise add to unresolved list - return 1; // Error if addition failed - } - } - } - - sfix += 12; // Increment symbol fixup pointer - nsymbols--; // Decrement num of symbols to process - } - - return 0; // Success loading symbols -} // -// Process Object File for Symbols ------------------------------------------------------------- -// - -int doobj(char *fname, char *ptr, char *aname, int flags) { - struct OFILE *Ofile; // Object record pointer - char *temp; // Temporary data pointer - - if ((Ofile = new_ofile()) == NULL) { // Allocate memory for object record ptr - printf("Out of memory processing %s\n",fname); - return 1; - } - - // Starting after all pathnames, etc., copy .o file name to Ofile - temp = path_tail(fname); - if (strlen(temp) > FNLEN - 1) { // Check filename length - printf("File name too long: %s\n", temp); - return 1; - } - if (strlen(aname) > FNLEN - 1) { // Check archive name length - printf("Archive name too long: %s\n", aname); - return 1; - } - strcpy(Ofile->o_name, temp); // Store filename - strcpy(Ofile->o_arname, aname); // Store archive name - - Ofile->o_next = NULL; // Initialise object record information - Ofile->o_tbase = 0; - Ofile->o_dbase = 0; - Ofile->o_bbase = 0; - Ofile->o_flags = flags; - Ofile->o_image = ptr; - - // Don't do anything if this is just an ARCHIVE marker, just add the file to the olist - if (!(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); - - // Round BSS off to alignment boundary - Ofile->o_header.bsize = (Ofile->o_header.bsize + secalign) & ~secalign; - if (Ofile->o_header.dsize & 7) { - 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 (add_symbols(Ofile)) return 1; - } - - // Add this file to the olist - if (olist == NULL) - olist = Ofile; - else - olast->o_next = Ofile; +// Process object file for symbols +// +int DoItem(struct OFILE * obj) +{ + // Allocate memory for object record ptr + struct OFILE * Ofile = new_ofile(); + + if (Ofile == NULL) + { + printf("Out of memory while processing %s\n", obj->o_name); + return 1; + } + + // Starting after all pathnames, etc., copy .o file name to Ofile + char * temp = PathTail(obj->o_name); + + // Check filename length + if (strlen(temp) > FNLEN - 1) + { + printf("File name too long: %s\n", temp); + return 1; + } + + // Check archive name length + if (strlen(obj->o_arname) > (FNLEN - 1)) + { + printf("Archive name too long: %s\n", obj->o_arname); + return 1; + } + + strcpy(Ofile->o_name, temp); // Store filename + strcpy(Ofile->o_arname, obj->o_arname); // Store archive name + + // Initialise object record information + Ofile->o_next = NULL; + Ofile->o_tbase = 0; + Ofile->o_dbase = 0; + Ofile->o_bbase = 0; + 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; + + 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 (??? 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 "); + WriteARName(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 "); + WriteARName(Ofile); + printf("; link aborted.\n"); + return 1; + } + + if (AddSymbols(Ofile)) + return 1; + + // Add this file to the olist + if (olist == NULL) + olist = Ofile; + else + olast->o_next = Ofile; + olast = Ofile; return 0; } // -// Remove Elements from Unresolved List which are Resolvable +// Handle items in processing list. // -int dolist(void) +// After loading all objects, archives & include files, we now go and process +// each item on the processing list (plist). Once this is done, we go through +// any unresolved symbols left and see if they have shown up. +// +int ProcessLists(void) { - struct HREC * uptr; // Unresolved hash record pointer - struct HREC * prev = NULL; // Previous hash record pointer - struct HREC * htemp; // Temporary hash record pointer - struct OFILE * ptemp; // Temporary object file record pointer - - // Process object file list + // Process object file list first (adds symbols from each unit & creates + // the olist) while (plist != NULL) { - if (doobj(plist->o_name, plist->o_image, plist->o_arname, plist->o_flags)) + if (DoItem(plist)) return 1; - ptemp = plist; + struct OFILE * ptemp = plist; plist = plist->o_next; free(ptemp); } - // Process unresolved list - for(uptr=unresolved; uptr!=NULL; ) + struct HREC * uptr; + + // Process the unresolved symbols list. This may involve pulling in symbols + // from any included .a units. Such units are lazy linked by default; we + // generally don't want everything they provide, just what's referenced. + for(uptr=unresolved; uptr!=NULL; ) + { + if (vflag > 1) + printf("LookupHREC(%s) => ", uptr->h_sym); + + struct HREC * htemp = LookupHREC(uptr->h_sym); + + if (htemp != NULL) + { + // Found it in the symbol table! + if (vflag > 1) + printf("%s in %s (=$%06X)\n", (isglobal(htemp->h_type) ? "global" : "common"), htemp->h_ofile->o_name, htemp->h_value); + + // Mark the .o unit that the symbol is in as seen & remove from the + // unresolved list + htemp->h_ofile->o_flags |= O_USED; + uptr = RemoveUnresolvedSymbol(uptr); + } + else + { + if (vflag > 1) + printf("NULL\n"); + + // Check to see if the unresolved symbol is on the AR symbol list. + htemp = LookupARHREC(uptr->h_sym); + + // If the unresolved symbol is in a .o unit that is unused, we can + // drop it; same if the unresolved symbol is in the exported AR + // symbol list. Otherwise, go to the next unresolved symbol. + if (!(uptr->h_ofile->o_flags & O_USED) || (htemp != NULL)) + uptr = RemoveUnresolvedSymbol(uptr); + else + uptr = uptr->h_next; + + // Now that we've possibly deleted the symbol from unresolved list + // that was also in the AR list, we add the symbols from this .o + // unit to the symbol table, mark the .o unit as used, and restart + // scanning the unresolved list as there is a good possibility that + // the symbols in the unit we're adding has unresolved symbols as + // well. + if (htemp != NULL) + { + htemp->h_ofile->o_flags |= O_USED; + AddSymbols(htemp->h_ofile); + uptr = unresolved; + } + } + } + + // Show files used if the user requests it. + if (vflag > 1) + { + printf("Files used:\n"); + struct OFILE * filePtr = olist; + + while (filePtr != NULL) + { + if (filePtr->o_flags & O_USED) + { + printf(" %s%s%s\n", filePtr->o_name, (filePtr->isArchiveFile ? ":" : ""), (filePtr->isArchiveFile ? filePtr->o_arname : nullStr)); + } + + filePtr = filePtr->o_next; + } + } + + return 0; +} + + +// +// Extract filename from path +// +char * PathTail(char * name) +{ + // Find last occurance of PATH_DELIMETER + char * temp = strrchr(name, PATH_DELIMITER); + + // Return what was passed in if path delimiter was not found + if (temp == NULL) + return name; + + return temp + 1; +} + + +// +// Add input file to processing list +// +int AddToProcessingList(char * ptr, char * fname, char * arname, uint8_t arFile, uint32_t tSize, uint32_t dSize, uint32_t bSize) +{ + if (plist == NULL) + { + // First time object record allocation + plist = new_ofile(); + plast = plist; + } + else + { + // Next object record allocation + plast->o_next = new_ofile(); + plast = plast->o_next; + } + + if (plast == NULL) + { + printf("Out of memory.\n"); // Error if memory allocation fails + return 1; + } + + // Discard paths from filenames... + fname = PathTail(fname); + arname = PathTail(arname); + + // Check for filename length errors... + if (strlen(fname) > (FNLEN - 1)) + { + printf("File name too long: %s (sorry!)\n", fname); + return 1; + } + + if (strlen(arname) > (FNLEN - 1)) + { + printf("AR file name too long: %s (sorry!)\n", arname); + return 1; + } + + strcpy(plast->o_name, fname); // Store filename sans path + strcpy(plast->o_arname, arname); // Store archive name sans path + plast->o_image = ptr; // Store data pointer + 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 +} + + +// +// Process in binary include files and add them to the processing list. This +// routine takes in the binary file and creates an 'object' file in memory. +// Sym1/Sym2 point to the start and end of data. +// +// 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) +// Symbols ...... (strlen(sym1) + 1) + (strlen(sym2) + 1) +// Terminate .... 4 bytes (0x00000000) +// +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 + int sym1len = strlen(sym1) + 1; // Get sym1 length + null termination + int sym2len = strlen(sym2) + 1; // Get sym2 length + null termination + long size = 32 + dsize + 24 + 4 + sym1len + sym2len + 4; + + // Use calloc so the header & fixups initialize to zero + // Allocate object image memory + if ((ptr = calloc(size, 1)) == NULL) + { + printf("Out of memory while including %s\n", fname); + close(handle); + return 1; + } + + // Read in binary data + if (read(handle, ptr + 32, fsize) != fsize) + { + printf("File read error on %s\n", fname); + close(handle); + free(ptr); + return 1; + } + + close(handle); + + // Build this image's dummy header + PutLong(ptr, 0x00000107); // Magic number + + if (segment) + { + PutLong(ptr+4, dsize); // Text size + PutLong(ptr+8, 0L); // Data size + symtype = 0x05000000; + tSize = dsize; + } + else + { + PutLong(ptr+4, 0L); // Text size + PutLong(ptr+8, dsize); // Data size + symtype = 0x07000000; + dSize = dsize; + } + + 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) + + sptr = ptr + 32 + dsize + 24; // Set sptr to symbol table size loc + + PutLong(sptr, sym1len + 4L); // Size of symbol table + + sptr = ptr + 32 + dsize + 24 + 4; // Set sptr to symbol table location + + for(i=0; i<(sym1len-1); i++) // Write symbol1 to string table + sptr[i] = *sym1++; + + sptr += (sym1len - 1); // Step past symbol string + *sptr = '\0'; // Terminate symbol string + sptr += 1; // Step past termination + + for(i=0; i<(sym2len-1); i++) // Write symbol2 to string table + sptr[i] = *sym2++; + + sptr += (sym2len - 1); // Step past symbol string + *sptr = '\0'; // Terminate symbol string + sptr += 1; // Step past termination + + PutLong(sptr, 0L); // Terminating long for object file + + return AddToProcessingList(ptr, fname, nullStr, 0, tSize, dSize, bSize); +} + + +// +// Takes a file name, gets in its image, puts it on plist. The image may +// already be in memory: If so, the ptr arg is non-null. If so, the file is +// already closed. Note that the file is already open (from DoFile()). RETURNS +// a pointer to the OFILE structure for this file, so you can diddle its flags +// (DoFile sets O_USED for files on the command line). +// +int LoadObject(char * fname, int fd, char * ptr) +{ + uint32_t tSize = 0, dSize = 0, bSize = 0; + + if (ptr == NULL) + { + long size = FileSize(fd); + + // 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; + } + + 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) + 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 +// +uint8_t HasDotOSuffix(char * s) +{ + char * temp = strrchr(s, '.'); + + if ((temp == NULL) || (strncmp(temp, ".o", 2) != 0)) + return 0; + + return 1; +} + + +// +// Process an ar archive file (*.a) +// +int LoadArchive(char * fname, int fd) +{ + // Read in the archive file to memory and process + long size = FileSize(fd); + char * ptr = malloc(size); + char * endPtr = ptr + size; + char * longFilenames = NULL; + + if (ptr == NULL) + { + printf("Out of memory while processing %s\n", fname); + close(fd); + return 1; + } + + if (read(fd, ptr, size) != size) + { + printf("File read error on %s\n", fname); + close(fd); + free(ptr); + return 1; + } + + close(fd); + + // Save the pointer for later... + arPtr[arIndex++] = ptr; + char objName[FNLEN]; + char objSize[11]; + int i; +//printf("\nProcessing AR file \"%s\"...\n", fname); + ptr += 8; + + // Loop through all objects in the archive and process them + do + { + memset(objName, 0, 17); + objSize[10] = 0; + + for(i=0; i<16; i++) + { +// if ((ptr[i] == '/') || (ptr[i] == ' ')) + if ((ptr[i] == ' ') && (i != 0)) + { + objName[i] = 0; + break; + } + + objName[i] = ptr[i]; + } + + for(i=0; i<10; i++) + { + if (ptr[48 + i] == ' ') + { + objSize[i] = 0; + break; + } + + objSize[i] = ptr[48 + i]; + } + + // Check to see if a long filename was requested + // N.B.: " " is for GNU archives, and "/" is for BSD archives + if ((objName[0] == 0x20) || (objName[0] == '/')) + { + uint32_t fnSize = atoi(objName + 1); + + if (longFilenames != NULL) + { + i = 0; + char * currentFilename = longFilenames + fnSize; + + while (*currentFilename != 0x0A) + objName[i++] = *currentFilename++; + + objName[i] = 0; + } + } + + if ((strncmp(objName, "ARFILENAMES/", 12) == 0) || (strncmp(objName, "//", 2) == 0)) + { + longFilenames = ptr + 60; + } + else if (HasDotOSuffix(objName)) + { + + // Strip off any trailing forward slash at end of object name + int lastChar = strlen(objName) - 1; + + if (objName[lastChar] == '/') + objName[lastChar] = 0; + +//printf("Processing object \"%s\" (size == %i, obj_index == %i)...\n", objName, atoi(objSize), 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, tSize, dSize, bSize)) + return 1; + } + + uint32_t size = atoi(objSize); + size += (size & 0x01 ? 1 : 0); + ptr += 60 + size; + } + while (ptr < endPtr); + + return 0; +} + + +// +// Process files (*.o, *.a) passed in on the command line +// +int ProcessFiles(void) +{ + int i; + char magic[8]; // Magic header number (4 bytes for *.o, 8 for *.a) + + // Process all file handles + for(i=0; i<(int)hd; i++) + { + // Verbose mode information + if (vflag == 1) + printf("Read file %s%s\n", name[i], (hflag[i] ? " (include)" : "")); + + if (!hflag[i]) + { + // Attempt to read file magic number (OBJECT/ARCHIVE FILES) + if (read(handle[i], magic, 8) != 8) + { + printf("Error reading file %s\n", name[i]); + close(handle[i]); + return 1; + } + + 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) + { + // 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) + { + if (LoadArchive(name[i], handle[i])) + return 1; + } + else + { + // Close file and error + printf("%s is not a supported object or archive file\n", name[i]); + printf("Magic == [%02X][%02X][%02X][%02X]\n", magic[0], magic[1], magic[2], magic[3]); + close(handle[i]); + return 1; + } + } + else + { + // INCLUDE FILES + // If hflag[i] is 1, include this in the data segment; if 2, put it + // in text segment + if (LoadInclude(name[i], handle[i], hsym1[i], hsym2[i], hflag[i] - 1)) + return 1; + } + } + + // Free include, symbol & object handles + for(i=0; i<(int)hd; i++) + { + free(name[i]); + + if (hflag[i]) + { + free(hsym1[i]); + free(hsym2[i]); + } + } + + // Reset next handle indicator + hd = 0; + return 0; +} + + +// +// Load newargv with pointers to arguments found in the buffer +// +int parse(char * buf, char * newargv[]) +{ + int i = 1; + + if (vflag) + printf("begin parsing\n"); + + while (1) { - if (vflag > 1) - printf("lookup(%s) => ",uptr->h_sym); + while (*buf && strchr(",\t\n\r\14 ", *buf)) + buf++; - if ((htemp = lookup(uptr->h_sym)) != NULL) + /* test for eof */ + if (*buf == '\0' || *buf == 26) { - if (vflag > 1) - printf(" %s in %s\n", isglobal(htemp->h_type) ? "global" : "common", htemp->h_ofile->o_name); - - htemp->h_ofile->o_flags |= O_USED; - - if (prev == NULL) + if (i == 0) { - unresolved = uptr->h_next; - free(uptr); - uptr = unresolved; + printf("No commands in command file\n"); + return -1; } else { - prev->h_next = uptr->h_next; - free(uptr); - uptr = prev->h_next; + return i; } } - else + + /* test for comment */ + if (*buf == '#') { - printf("NULL\n"); - prev = uptr; - uptr = uptr->h_next; + /* found a comment; skip to next \n and start over */ + while (*buf && *buf != '\n') + buf++; + + continue; } - } - return 0; -} + if (i == MAXARGS) + { + printf("Too many arguments in command file\n"); + return -1; + } + newargv[i] = buf; -// -// Extract Filename from Path -// -char * path_tail(char * name) -{ - char * temp = max(strrchr(name,'/'), max(strrchr(name,':'), strrchr(name, 92))); + while (!strchr(",\t\n\r\14 ", *buf)) + { + if (*buf == '\0' || *buf == 26) + { + printf("Finished parsing %d args\n", i); + return i; + } - if (temp == NULL) - temp = (name - 1); + buf++; + } - return temp + 1; + *buf++ = '\0'; + + if (vflag) + printf("argv[%d] = \"%s\"\n", i, newargv[i]); + + i++; + } } // -// Add Input File to Processing List +// Process in a link command file // -int pladd(char * ptr, char * fname) +int docmdfile(char * fname) { - if (plist == NULL) - { - plist = new_ofile(); // First time object record allocation - plast = plist; // Update last object record pointer + int fd; // File descriptor + unsigned size; // Command file size + char * ptr; // Pointer + int newargc; // New argument count + char * (*newargv)[]; // New argument value array + + // Verbose information + if (vflag > 1) + printf("docmdfile(%s)\n", fname); + + // Allocate memory for new argument values + newargv = malloc((long)(sizeof(char *) * MAXARGS)); + + if (!newargv) + { + printf("Out of memory.\n"); + return 1; + } + + // Attempt to open and read in the command file + if (fname) + { + if ((fd = open(fname, _OPEN_FLAGS)) < 0) + { + printf("Cannot open command file %s.\n", fname); + return 1; + } + + size = FileSize(fd); + + if ((ptr = malloc(size + 1)) == NULL) + { + printf("Out of memory.\n"); + close(fd); + return 1; + } + + if (read(fd, ptr, size) != (int)size) + { + printf("Read error on command file %s.\n", fname); + close(fd); + return 1; + } + + *(ptr + size) = 0; // Null terminate the buffer + close(fd); } else { - plast->o_next = new_ofile(); // Next object record allocation - plast = plast->o_next; // Update last object record pointer + printf("No command filename specified\n"); + return 1; } - if (plast == NULL) - { - printf("Out of memory.\n"); // Error if memory allocation fails + // Parse the command file + if ((newargc = parse(ptr, *newargv)) == -1) + { return 1; } - if (strlen(path_tail(fname)) > FNLEN-1) - { // Error on excessive filename length - printf("File name too long: %s (sorry!)\n",fname); + // Process the inputted flags + if (doargs(newargc, *newargv)) + { + printf("docmdfile: doargs returns TRUE\n"); return 1; } - strcpy(plast->o_name, path_tail(fname)); // Store filename, not path - *plast->o_arname = 0; // No archive name for this file - plast->o_image = ptr; // Store data pointer - plast->o_flags = O_USED; // File is used - plast->o_next = NULL; // Initialise next record pointer + free(ptr); + free(newargv); - return 0; // Return without errors + return 0; } // -// Process in Binary Include Files and Add them to the Processing List. This -// routine takes in the binary file and creates an 'object' file in memory. -// Sym1/Sym2 point to the start and end of data. -// -// 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) -// Symbols ...... (strlen(sym1) + 1) + (strlen(sym2) + 1) -// Terminate .... 4 bytes (0x00000000) +// Take an argument list and parse the command line // -int doinclude(char * fname, int handle, char * sym1, char * sym2, int segment) +int doargs(int argc, char * argv[]) { - long fsize, dsize, size; // File, DATA segment and image sizes - char * ptr, * sptr; // Data pointers - int i; // Iterators - int sym1len = 0; // Symbol 1 length - int sym2len = 0; // Symbol 2 length - unsigned symtype = 0; + int i = 1; // Iterator + int c; // Command line character + char * ifile, * isym; // File name and symbol name for -i - fsize = FSIZE(handle); // Get size of include file - dsize = (fsize+secalign) & ~secalign; // Round up to a alignment boundary + // Parse through option switches & files + while (i < argc) + { + // Process command line switches + if (argv[i][0] == '-') + { + if (!argv[i][1]) + { + printf("Illegal option argument: %s\n\n", argv[i]); + ShowHelp(); + return 1; + } - sym1len = strlen(sym1) + 1; // Get sym1 length + null termination - sym2len = strlen(sym2) + 1; // Get sym2 length + null termination + c = argv[i++][1]; // Get next character in command line - size = 32 + dsize + 24 + 4 + sym1len + sym2len + 4; + // Process command line switch + switch (c) + { + case '?': // Display usage information + case 'h': + case 'H': + ShowVersion(); + ShowHelp(); + return 1; + case 'a': + case 'A': // Set absolute linking on + if (aflag) + warn('a', 1); - // Use calloc so the header & fixups initialize to zero - // Allocate object image memory - if ((ptr = calloc(size, 1L)) == NULL) - { - printf("Out of memory while including %s\n", fname); - close(handle); - return 1; - } + if (i + 2 >= argc) + { + printf("Not enough arguments to -a\n"); + return 1; + } - // Read in binary data - if (read(handle, ptr+32, fsize) != fsize) - { - printf("File read error on %s\n", fname); - close(handle); - free(ptr); - return 1; - } + aflag = 1; // Set abs link flag + + // Segment order is TEXT, DATA, BSS + // Text segment can be 'r' or a value + if ((*argv[i] == 'r' || *argv[i] == 'R') && !argv[i][1]) + { + ttype = -1; // TEXT segment is relocatable + } + else if ((*argv[i] == 'x' || *argv[i] == 'X')) + { + printf("Error in text-segment address: cannot be contiguous\n"); + return 1; + } + else if (GetHexValue(argv[i], &tval)) + { + printf("Error in text-segment address: %s is not 'r' or an address.", argv[i]); + return 1; + } - close(handle); // Close file + i++; - strcpy(obj_fname[obj_index], path_tail(fname)); + // Data segment can be 'r', 'x' or a value + if ((*argv[i] == 'r' || *argv[i] == 'R') && !argv[i][1]) + { + dtype = -1; // DATA segment is relocatable + } + else if ((*argv[i] == 'x' || *argv[i] == 'X')) + { + dtype = -2; // DATA follows TEXT + } + else if (GetHexValue(argv[i], &dval)) + { + printf("Error in data-segment address: %s is not 'r', 'x' or an address.", argv[i]); + return 1; + } - // Build this image's dummy header - putlong(ptr, 0x00000107); // Magic number + i++; - if (segment) - { - 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; - } - else - { - 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; - } + // BSS segment can be 'r', 'x' or a value + if ((*argv[i] == 'r' || *argv[i] == 'R') && !argv[i][1]) + { + btype = -1; // BSS segment is relocatable + } + else if ((*argv[i] == 'x' || *argv[i] == 'X')) + { + 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; + } + + i++; + break; + case 'b': + case 'B': // Don't remove muliply defined locals + if (bflag) + warn('b', 1); + + bflag = 1; + break; + case 'c': + case 'C': // Process a command file + if (i == argc) + { + printf("Not enough arguments to -c\n"); + return 1; + } - obj_index++; // Increment object count + if (docmdfile(argv[i++])) + { + return 1; + } - 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 + break; + case 'd': + case 'D': // Wait for "return" before exiting + if (dflag) + warn('d', 0); - sptr = ptr + 32 + dsize; // Set sptr to symbol table location + dflag = 1; + waitflag = 1; + break; + case 'e': + case 'E': // Output COFF (absolute only) + cflag = 1; - 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) + if (noheaderflag) + printf("Warning: -e overridden by -n, output will be headerless\n"); - sptr = ptr + 32 + dsize + 24; // Set sptr to symbol table size loc + break; + case 'g': + case 'G': // Output source level debugging + if (gflag) warn('g', 1); + gflag = 1; + break; + case 'i': + case 'I': // Include binary file + if (i + 2 > argc) + { + printf("Not enough arguments to -i\n"); + return 1; + } - putlong(sptr, sym1len + 4L); // Size of symbol table + ifile = argv[i++]; + isym = argv[i++]; - sptr = ptr + 32 + dsize + 24 + 4; // Set sptr to symbol table location + // handle -ii (No truncation) + if ((argv[i-3][2] == 'i') || (argv[i-3][2] == 'I')) + { + if (!cflag) + printf("warning: (-ii) COFF format output not specified\n"); + } + // handle -i (Truncation) + else + { + if (strlen(isym) > 8) + isym[8] = '\0'; + } - for(i=0; i<(sym1len-1); i++) // Write symbol1 to string table - sptr[i] = *sym1++; + // Place include files in the DATA segment only + if (DoFile(ifile, DSTSEG_D, isym)) + return 1; - sptr += (sym1len-1); // Step past symbol string - *sptr = '\0'; // Terminate symbol string - sptr += 1; // Step past termination + break; + case 'l': + case 'L': // Add local symbols + if (lflag) + warn('l', 1); - for(i=0; i<(sym2len-1); i++) // Write symbol2 to string table - sptr[i] = *sym2++; + lflag = 1; + break; + case 'm': + case 'M': // Produce load symbol map + if (mflag) + warn('m', 1); - sptr += (sym2len-1); // Step past symbol string - *sptr = '\0'; // Terminate symbol string - sptr += 1; // Step past termination + mflag = 1; + break; + case 'n': + case 'N': // Output no header to .abs file + if (noheaderflag) + warn('n', 1); - putlong(sptr, 0L); // Terminating long for object file + if (cflag) + printf("Warning: -e overridden by -n, output will be headerless\n"); - return pladd(ptr, fname); -} + noheaderflag = 1; + break; + case 'o': + case 'O': // Specify an output file + if (oflag) + warn('o', 1); + oflag = 1; -// -// Takes a file name, gets in its image, puts it on plist. The image may -// already be in memory: If so, the ptr arg is non-null. If so, the file is -// already closed. Note that the file is already open (from dofile()). RETURNS -// a pointer to the OFILE structure for this file, so you can diddle its flags -// (dofile sets O_USED for files on the command line). -// -int doobject(char * fname, int fd, char * ptr) -{ - long size; // File size + if (i >= argc) + { + printf("No output filename following -o switch\n"); + return 1; + } - if (ptr == NULL) - { - size = FSIZE(fd); // Get size of input object file + if (strlen(argv[i]) > FARGSIZE - 5) + { + printf("Output file name too long (sorry!)\n"); + return 1; + } - // Allocate memory for file data - if ((ptr = malloc(size)) == NULL) - { - printf("Out of memory while processing %s\n", fname); - close(fd); // Close and error - return 1; - } + strcpy(ofile, argv[i++]); + break; + case 'r': + case 'R': // Section alignment size + if (rflag) + warn('r', 1); - // Read in file data - if (read(fd, ptr, size) != size) - { - printf("File read error on %s\n", fname); - close(fd); // Close, free memory and error - free(ptr); - return 1; - } + rflag = 1; - strcpy(obj_fname[obj_index], path_tail(fname)); // SCPCD : get the name of the file instead of all pathname - 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++; + switch (argv[i-1][2]) + { + case 'w': case 'W': secalign = 1; break; // Word alignment + case 'l': case 'L': secalign = 3; break; // Long alignment + case 'p': case 'P': secalign = 7; break; // Phrase alignment + case 'd': case 'D': secalign = 15; break; // Double phrase alignment + case 'q': case 'Q': secalign = 31; break; // Quad phrase alignment + default: secalign = 7; break; // Default phrase alignment + } - close(fd); // Close file - } + break; + case 's': + case 'S': // Output only global symbols + if (sflag) + warn('s', 1); - // Now add this image to the list of pending ofiles (plist) - // This routine is shared by doinclude after it builds the image - return pladd(ptr, fname); -} + sflag = 1; + break; + case 'u': + case 'U': // Undefined symbols + uflag++; + break; + case 'v': + case 'V': // Verbose information + if (!vflag && !versflag) + { + ShowVersion(); + } + vflag++; + break; + case 'w': + case 'W': // Show warnings flag + if (wflag) + warn('w', 1); -// -// Process In Outstanding Object Files -// -int flush_handles(void) -{ - int i; // Iterator - char magic[4]; // Magic header number - // unsigned test; - - for(i = 0; i < (int)hd; i++) { // Process all handles - if (vflag == 1) { // Verbose mode information - printf("Read file %s%s\n", name[i], hflag[i] ? " (include)" : ""); - } - if (!hflag[i]) { // Attempt to read file magic number - // OBJECT FILES - if (read(handle[i],magic,4) != 4) { - printf("Error reading file %s\n", name[i]); - close(handle[i]); // Close file and error - return 1; - } - - lseek(handle[i], 0L, 0); // Reset to start of input file -// test = getlong(magic); printf("Magic Number is 0x%08X\n", test); - if (getlong(magic) == 0x00000107) { // Look for SMAC/MAC object files - if (doobject(name[i], handle[i], 0L)) // Process input object file - return 1; - } else { - printf("%s is not a supported object file\n", name[i]); - close(handle[i]); // Close file and error - return 1; - } - } else { - // INCLUDE FILES - // If hflag[i] is 1, include this in the data segment; if 2, put in in text segment - if (doinclude(name[i], handle[i], hsym1[i], hsym2[i], hflag[i]-1)) - return 1; - } - } - - for(i = 0; i < (int)hd; i++) { // Free include, symbol & object handles - free(name[i]); - if (hflag[i]) { - free(hsym1[i]); - free(hsym2[i]); - } - } - - hd = 0; // Reset next handle indicator - - return 0; // Return -} + wflag = 1; + break; + case 'y': + case 'Y': + if (i >= argc) + { + printf("No directory filename following -y switch\n"); + return 1; + } -// -// Load newargv with Pointers to Arguments Found in the Buffer --------------------------------- -// - -int parse(char *buf, char *newargv[]) { - int i = 1; - - if (vflag) { - printf("begin parsing\n"); - } - while (1) { - while (*buf && strchr(",\t\n\r\14 ", *buf)) buf++; - - /* test for eof */ - if (*buf == '\0' || *buf == 26) { - if (i == 0) { - printf("No commands in command file\n"); - return(-1); - } else { - return(i); - } - } - - /* test for comment */ - if (*buf == '#') { - /* found a comment; skip to next \n and start over */ - while (*buf && *buf != '\n') buf++; - continue; - } - - if (i == MAXARGS) { - printf("Too many arguments in command file\n"); - return(-1); - } - newargv[i] = buf; - while (!strchr(",\t\n\r\14 ", *buf)) { - if (*buf == '\0' || *buf == 26) { - printf("Finished parsing %d args\n", i); - return(i); - } - buf++; - } - *buf++ = '\0'; - if (vflag) { - printf("argv[%d] = \"%s\"\n",i,newargv[i]); - } - i++; - } -} + if (strlen(argv[i]) > FARGSIZE * 3) + { + printf("Directory file name too long (sorry!)\n"); + return 1; + } -// -// Process in a Link Command File ----------------------------------------- -// + strcpy(libdir, argv[i++]); + break; + case 'z': + case 'Z': // Suppress banner flag + if (zflag) + warn('z', 1); -int docmdfile(char * fname) -{ - int fd; // File descriptor - unsigned size; // Command file size - char * ptr; // Pointer - int newargc; // New argument count - char * (*newargv)[]; // New argument value array - - if (vflag > 1) - printf("docmdfile(%s)\n", fname); // Verbose information - - // Allocate memory for new argument values - newargv = malloc((long)(sizeof(char *) * MAXARGS)); - - if (!newargv) - { - printf("Out of memory.\n"); - return 1; - } - - // Attempt to open and read in the command file - if (fname) - { - if ((fd = open(fname, _OPEN_FLAGS)) < 0) - { - printf("Cannot open command file %s.\n", fname); - return 1; - } - - size = FSIZE(fd); - - if ((ptr = malloc(size + 1)) == NULL) - { - printf("Out of memory.\n"); - close(fd); - return 1; - } - - if (read(fd, ptr, size) != (int)size) - { - printf("Read error on command file %s.\n", fname); - close(fd); - return 1; - } - - *(ptr + size) = 0; // Null terminate the buffer - close(fd); - } - else - { - printf("No command filename specified\n"); - return 1; - } - - // Parse the command file - if ((newargc = parse(ptr, *newargv)) == -1) - { - return 1; - } - - // Process the inputted flags - if (doargs(newargc, *newargv)) - { - printf("docmdfile: doargs returns TRUE\n"); - return 1; - } - - free(ptr); - free(newargv); - - return 0; -} + zflag = 1; + break; + default: + printf("unknown option argument `%c'\n", c); + return 1; + } + } + else + { + // Not a switch, then process as a file + if (DoFile(argv[i++], 0, NULL)) + return 1; + } + } -// -// Take an Argument List and Parse the Command Line ----------------------- -// + if (!oflag && vflag) + { + strcpy(ofile, "output"); + printf("Output file is %s[.ext]\n", ofile); + } -int doargs(int argc, char * argv[]) -{ - int i = 1; // Iterator - int c; // Command line character - char * ifile, * isym; // File name and symbol name for -i - - while (i < argc) - { // Parse through option switches & files - if (argv[i][0] == '-') - { // Process command line switches - if (!argv[i][1]) - { - printf("Illegal option argument: %s\n\n", argv[i]); - display_help(); - return 1; - } - - c = argv[i++][1]; // Get next character in command line - - switch (c) - { // Process command line switch - case '?': // Display usage information - case 'h': - case 'H': - display_version(); - display_help(); - return 1; - case 'a': - case 'A': // Set absolute linking on - if (aflag) - warn('a', 1); - - if (i + 2 >= argc) - { - printf("Not enough arguments to -a\n"); - return 1; - } - - aflag = 1; // Set abs link flag - // Segment order is TEXT, DATA, BSS - // Text segment can be 'r', 'x' or a value - ttype = 0; - - if ((*argv[i] == 'r' || *argv[i] == 'R') && !argv[i][1]) - { - ttype = -1; // TEXT segment is relocatable - } - else if ((*argv[i] == 'x' || *argv[i] == 'X')) - { - printf("Error in text-segment address: cannot be contiguous\n"); - return 1; - } - else if ((ttype = 0), getval(argv[i], &tval)) - { - printf("Error in text-segment address: %s is not 'r', 'x' or an address.", argv[i]); - return 1; - } - - i++; - // Data segment can be 'r', 'x' or a value - dtype = 0; - - if ((*argv[i] == 'r' || *argv[i] == 'R') && !argv[i][1]) - { - dtype = -1; // DATA segment is relocatable - } - else if ((*argv[i] == 'x' || *argv[i] == 'X')) - { - dtype = -2; // DATA follows TEXT - } - else if ((dtype = 0), getval(argv[i],&dval)) - { - printf("Error in data-segment address: %s is not 'r', 'x' or an address.", argv[i]); - return 1; - } - - i++; - btype = 0; - - // BSS segment can be 'r', 'x' or a value - if ((*argv[i] == 'r' || *argv[i] == 'R') && !argv[i][1]) - { - btype = -1; // BSS segment is relocatable - } - else if ((*argv[i] == 'x' || *argv[i] == 'X')) - { - btype = -3; // BSS follows DATA - } - else if ((btype = 0), getval(argv[i],&bval)) - { - printf("Error in bss-segment address: %s is not 'r', 'x[td]', or an address.", argv[i]); - return 1; - } - - i++; - break; - case 'b': - case 'B': // Don't remove muliply defined locals - if (bflag) - warn('b', 1); - - bflag = 1; - break; - case 'c': - case 'C': // Process a command file - if (i == argc) - { - printf("Not enough arguments to -c\n"); - return 1; - } - - if (docmdfile(argv[i++])) - { - return 1; - } - - break; - case 'd': - case 'D': // Wait for "return" before exiting - if (dflag) - warn('d', 0); - - dflag = 1; - waitflag = 1; - break; - case 'e': - case 'E': // Output COFF (absolute only) - cflag = 1; - 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 - if (i + 2 > argc) - { - printf("Not enough arguments to -i\n"); - return 1; - } - - ifile = argv[i++]; - isym = argv[i++]; - - if ((argv[i-3][2] == 'i') || (argv[i-3][2] == 'I')) - { // handle -ii (No truncation) - if (!cflag) - printf("warning: (-ii) COFF format output not specified\n"); - } - else - { // handle -i (Truncation) - if (strlen(isym) > 7) - isym[7] = '\0'; - } - - // Place include files in the DATA segment only - if (dofile(ifile, DSTSEG_D, isym)) - return 1; - - break; - case 'l': - case 'L': // Add local symbols - if (lflag) - warn('l', 1); - - lflag = 1; - break; - case 'm': - case 'M': // Produce load symbol map - if (mflag) - warn('m', 1); - - mflag = 1; - break; - case 'n': - case 'N': // Output no header to .abs file - if (noheaderflag) - warn('n', 1); - - noheaderflag = 1; - break; - case 'o': - case 'O': // Specify an output file - if (oflag) - warn('o', 1); - - oflag = 1; - - if (i >= argc) - { - printf("No output filename following -o switch\n"); - return 1; - } - - if (strlen(argv[i]) > FARGSIZE - 5) - { - printf("Output file name too long (sorry!)\n"); - return 1; - } - - strcpy(ofile, argv[i++]); - break; - case 'r': - case 'R': // Section alignment size - if (rflag) - warn('r', 1); - - rflag = 1; - - switch (argv[i-1][2]) - { - case 'w': case 'W': secalign = 1; break; // Word alignment - case 'l': case 'L': secalign = 3; break; // Long alignment - case 'p': case 'P': secalign = 7; break; // Phrase alignment - case 'd': case 'D': secalign = 15; break; // Double phrase alignment - case 'q': case 'Q': secalign = 31; break; // Quad phrase alignment - default: secalign = 7; break; // Default phrase alignment - } - - break; - case 's': - case 'S': // Output only global symbols - if (sflag) - warn('s', 1); - - sflag = 1; - break; - case 'v': - case 'V': // Verbose information - if (!vflag && !versflag) - { - display_version(); - } - - vflag++; - break; - case 'z': - case 'Z': // Suppress banner flag - if (zflag) - warn('z', 1); - - zflag = 1; - break; - default: - printf("unknown option argument `%c'\n", c); - return 1; - } - } - else - { // Not a switch, then process as a file - if (dofile(argv[i++], 0, NULL)) - return 1; - } - - } - - if (!oflag && vflag) - { - strcpy(ofile, "output"); - printf("Output file is %s[.ext]\n", ofile); - } - - if (oflag && vflag) - printf("Output file is %s\n", ofile); - - if (sflag) - lflag = 0; - - return 0; // No problems encountered + if (oflag && vflag) + printf("Output file is %s\n", ofile); + + if (sflag) + lflag = 0; + + // No problems encountered + return 0; } // -// 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, 2011 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