+ if (fwrite(padarray, padsize, 1, fd) != 1) // Write padding bytes
+ return 1;
+ }
+
+ return 0; // All done
+}
+
+
+//
+// Write the Output File
+//
+int write_ofile(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
+
+ // 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)
+ }
+
+ fd = fopen(ofile, "wb"); // Attempt to open output file
+
+ if (!fd)
+ {
+ printf("Can't open output file %s\n", ofile); // Error opening output file
+ return 1;
+ }
+
+ // Build the output file header
+ // Absolute (COF) header
+ if (cflag)
+ {
+ 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++)
+ {
+ dsoff += obj_segsize[i][0]; // Adding TEXT segment sizes
+ bsoff += obj_segsize[i][0] + obj_segsize[i][1]; // Adding TEXT and DATA segment sizes
+ }
+
+ // 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)
+
+ // 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
+
+ // 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
+
+ // 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
+
+ // 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
+ }
+ // 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
+ }
+
+ // Write the header, but not if noheaderflag
+ // Absolute (ABS) header
+ if (!cflag)
+ {
+ if (!noheaderflag)
+ if (fwrite(himage, 36, 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
+ for(otemp=olist; otemp!=NULL; otemp=otemp->o_next)
+ {
+ osize = otemp->o_header.tsize;
+
+ // Write only if segment has size
+ if (osize)
+ {
+ if (vflag > 1)
+ printf("Writing TEXT Segment of %s\n", otemp->o_name);
+
+ if (fwrite(otemp->o_image + 32, osize, 1, fd) != 1)
+ goto werror;
+
+ // Pad to required alignment boundary
+ if (segmentpad(fd, osize, 0x0000))
+ goto werror;
+
+ symoffset += osize;
+ }
+ }
+
+ // Write the DATA segment of each object file
+ for(otemp = olist; otemp != NULL; otemp = otemp->o_next)
+ {
+ osize = otemp->o_header.dsize;
+
+ // Write only if the segment has size
+ if (osize)
+ {
+ if (vflag > 1)
+ printf("Writing DATA Segment of %s\n", otemp->o_name);
+
+ if (fwrite((otemp->o_image + 32 + otemp->o_header.tsize), osize, 1, fd) != 1)
+ goto werror;
+
+ // Pad to required alignment boundary
+ if (segmentpad(fd, osize, 0))
+ goto werror;
+
+ symoffset += osize;
+ }
+ }
+
+ if (!noheaderflag)
+ {
+ // Write the symbols table and string table
+ // Absolute (COF) symbol/string table
+ if (cflag)
+ {
+ 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;
+ }
+ }
+ // 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
+
+ for(i=0; i<ost_index; i++)
+ {
+ memset(symbol, 0, 14); // Initialise symbol record
+ abstype = 0; // Initialise ABS symbol type
+ slen = 0; // Initialise symbol string length
+ index = getlong(ost + (i * 12)); // Get symbol index
+ type = getlong((ost + (i * 12)) + 4); // Get symbol type
+
+ if (type & 0xF0000000)
+ continue; // Not doing debug symbols
+
+ value = getlong((ost + (i * 12)) + 8); // Get symbol value
+ slen = strlen(oststr + index);
+
+ // Get symbol string (maximum 8 chars)
+ if (slen > 8)
+ {
+ for(j=0; j<8; j++)
+ *(symbol + j) = *(oststr + index + j);
+ }
+ else
+ {
+ for(j=0; j<slen; j++)
+ *(symbol + j) = *(oststr + index + j);
+ }
+
+ // Modify to ABS symbol type
+ switch (type)
+ {
+ case 0x02000000: abstype = (short)ABST_DEFINED; break;
+ case 0x04000000: abstype = (short)ABST_DEFINED | ABST_TEXT; break;
+ case 0x05000000: abstype = (short)ABST_DEFINED | ABST_GLOBAL | ABST_TEXT; break;
+ case 0x06000000: abstype = (short)ABST_DEFINED | ABST_DATA; break;
+ case 0x07000000: abstype = (short)ABST_DEFINED | ABST_GLOBAL | ABST_DATA; break;
+ case 0x08000000: abstype = (short)ABST_DEFINED | ABST_BSS; break;
+ case 0x09000000: abstype = (short)ABST_DEFINED | ABST_GLOBAL | ABST_BSS; break;
+ default:
+ printf("write_ofile: abs, cannot determine symbol type\n");
+ type = 0;
+ break;
+ }
+
+ putword(symbol + 8, abstype); // Write back new ABS type
+ putlong(symbol + 10, value); // Write back value
+
+ if (fwrite(symbol, 14, 1, fd) != 1) goto werror; // Write symbol record
+ }
+ }
+ }
+
+ // Close the file
+ if (fclose(fd))
+ {
+ printf("Close error on output file %s\n",ofile);
+ return 1;
+ }
+ else
+ return 0;
+
+werror: // OMG! Why did Atari use these :)
+ printf("Write error on output file %s\n", ofile);
+ fclose(fd); // Try to close output file anyway
+ return 1;
+}
+
+
+//
+// Display the Symbol Load Map
+//
+int write_map(struct OHEADER * header)
+{
+ unsigned i, o; // Inner and outer loop iterators
+ unsigned c; // Column number
+ unsigned index; // Symbol string index
+ unsigned type; // Symbol type
+ unsigned value; // Symbol value
+ char * symbol; // Symbol string value
+
+ if (ost_index == 0)
+ return 0; // Return if no symbols to map
+
+ printf("LOAD MAP\n\n");
+
+ // Outer loop for each of the symbol areas to map out;
+ // 0 = NON-RELOCATABLE SYMBOLS
+ // 1 = TEXT-SEGMENT RELOCATABLE SYMBOLS
+ // 2 = DATA-SEGMENT RELOCATABLE SYMBOLS
+ // 3 = BSS-SEGMENT RELOCATABLE SYMBOLS
+ for(o=0; o<4; o++)
+ {
+ // Display the correct map header for the symbols being processed
+ switch (o)
+ {
+ case 0: printf("NON-RELOCATABLE SYMBOLS\n\n"); break;
+ case 1: printf("TEXT-SEGMENT RELOCATABLE SYMBOLS\n\n"); break;
+ case 2: printf("DATA-SEGMENT RELOCATABLE SYMBOLS\n\n"); break;
+ case 3: printf("BSS-SEGMENT RELOCATABLE SYMBOLS\n\n"); break;
+ }
+
+ c = 0; // Initialise column number
+
+ // Inner loop to process each record in the symbol table
+ for(i=0; i<(unsigned)ost_index; i++)
+ {
+ index = getlong(ost + (i * 12)); // Get symbol string index
+ type = getlong(ost + (i * 12) + 4); // Get symbol type
+ value = getlong(ost + (i * 12) + 8); // Get symbol value
+ symbol = oststr + index; // Get symbol string
+
+ // Display only three columns
+ if (c == 3)
+ {
+ printf("\n");
+ c = 0;
+ }
+
+ // If local symbols not included and the type is local then go to next symbol record
+ if (!lflag & !(type & 0x01000000))
+ continue;
+
+ // Output each symbol to the display, dependant on type
+ switch (o)
+ {
+ case 0: // Non-relocatable symbols
+ if (type == 0x02000000 || type == 0x03000000)
+ {
+ printf("%-8s %c %08X ", symbol, (type & 0x01000000) ? 'G' : 'L', value);
+ c++;
+ }
+
+ break;
+ case 1: // TEXT segment relocatable symbols
+ if (type == 0x04000000 || type == 0x05000000)
+ {
+ printf("%-8s %c %08X ", symbol, (type & 0x01000000) ? 'G' : 'L', value);
+ c++;
+ }
+
+ break;
+ case 2: // DATA segment relocatble symbols
+ if (type == 0x06000000 || type == 0x07000000)
+ {
+ printf("%-8s %c %08X ", symbol, (type & 0x01000000) ? 'G' : 'L', value);
+ c++;
+ }
+
+ break;
+ case 3: // BSS segment relocatable symbols
+ if (type == 0x08000000 || type == 0x09000000)
+ {
+ printf("%-8s %c %08X ", symbol, (type & 0x01000000) ? 'G' : 'L', value);
+ c++;
+ }
+
+ break;
+ }
+ }
+
+ printf("\n\n");
+ }
+
+ return 0; // All done
+}
+
+
+//
+// Convert ASCII to Hexadecimal
+//
+//int atolx(char * string, long * value)
+int atolx(char * string, int * value)
+{
+ *value = 0;
+
+ while (isxdigit(*string))
+ {
+ if (isdigit(*string))
+ {
+ *value = (*value << 4) + (*string++ - '0');
+ }
+ else
+ {
+ if (isupper(*string))
+ *string = tolower(*string);
+
+ *value = (*value << 4) + ((*string++ - 'a') + 10);
+ }
+ }
+
+ if (*string != '\0')
+ {
+ printf("Invalid hexadecimal value");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+//
+// Stuff the (long) value of a string into the value argument. RETURNS TRUE if
+// the string doesn't parse. Parses only as a hex string.
+//
+//int getval(char * string, long * value)
+int getval(char * string, int * value)
+{
+ return atolx(string, value);
+}
+
+
+//
+// Create one big .o file from the images already in memory, returning a
+// pointer to an OHEADER. Note that the oheader is just the header for the
+// output (plus some other information). The text, data, and fixups are all
+// still in the ofile images hanging off the global `olist'.
+//
+struct OHEADER * make_ofile()
+{
+ unsigned tptr, dptr, bptr; // Bases in runtime model
+ int ret = 0; // Return value
+ struct OFILE * otemp, * oprev, * ohold; // Object file list pointers
+ struct OHEADER * header; // Output header pointer
+
+ textsize = datasize = bsssize = 0; // Initialise cumulative segment sizes
+
+ // For each object file, accumulate the sizes of the segments but remove those
+ // object files which are unused
+ oprev = NULL; // Init previous obj file list ptr
+ otemp = olist; // Set temp pointer to object file list
+
+ while (otemp != NULL)
+ {
+ // UNUSED !!!!!
+ if (!(otemp->o_flags & O_ARCHIVE))
+ {
+ if ((otemp->o_flags & O_USED) == 0)
+ {
+ 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);
+ }
+ 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;
+ }
+ }
+
+ otemp = otemp->o_next; // Go to next object file list pointer
+ }
+
+ // Update base addresses and create symbols _TEXT_E, _DATA_E and _BSS_E
+ 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
+ bbase = bval;
+ ost_add("_BSS_E", 0x09000000, bval + bsssize);
+ }
+ }
+ else
+ {
+ // DATA is independant 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);
+ }
+ else
+ {
+ // BSS is independant of DATA
+ bbase = bval;
+ ost_add("_BSS_E", 0x09000000, bval + bsssize);
+ }
+ }
+
+ // Place each unresolved symbol in the output symbol table
+ if (dounresolved())
+ return NULL;
+
+ tptr = 0; // Initialise base addresses
+ dptr = 0;
+ bptr = 0;
+
+ // 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))
+ 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;
+ }
+
+ otemp = otemp->o_next;
+ }
+
+ // Places all the externs, globals etc into the output symbol table
+ if (docommon() == -1)
+ return NULL;
+
+ // Create a new output file header
+ if ((header = new_oheader()) == NULL)
+ {
+ printf("make_ofile: 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
+ 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
+ }
+ }
+
+ hash_free(); // Done with global symbol hash tables
+
+ return (ret ? (unsigned)NULL : header);
+}
+
+
+//
+// Add Symbol to Hash List
+//
+int add_to_hlist(struct HREC ** hptr, char * sym, struct OFILE * ofile, long value, int type)
+{
+ struct HREC * htemp; // Temporary hash record pointer
+ int i;
+
+ // Attempt to allocate new hash record
+ if ((htemp = new_hrec()) == NULL)
+ {
+ printf("Out of memory\n");
+ return 1;
+ }
+
+ // Shamus: Moar testing...
+ if (vflag > 1)
+ {
+ printf("add_to_hlist(): hptr=$%08X, sym=\"%s\", ofile=$%08X, value=%li, type=%i", (unsigned int)hptr, sym, (unsigned int)ofile, value, type);
+ }
+
+ for(i=0; i<SYMLEN; i++)
+ htemp->h_sym[i] = '\0';
+
+ strcpy(htemp->h_sym, sym); // Populate hash record
+ htemp->h_ofile = ofile;
+ htemp->h_value = value;
+ htemp->h_type = type;
+
+ htemp->h_next = *hptr; // Update hash record pointers
+ *hptr = htemp;
+
+ return 0;
+}
+
+
+//
+// Add Symbol to the Unresolved Symbols Hash Table
+//
+add_unresolved(char * sym, struct OFILE * ofile)
+{
+ if (vflag > 1)
+ printf("add_unresolved(%s,%s)\n", sym, ofile->o_name);
+
+ return add_to_hlist(&unresolved, sym, ofile, 0L, 0);
+}
+
+
+//
+// Generate and Return Hash Value
+//
+int dohash(char * s)
+{
+ 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;
+}
+
+
+//
+// Lookup a Symbol in the Hash Table
+//
+struct HREC * lookup(char * sym)
+{
+ struct HREC * hptr = htable[dohash(sym)]; // Hash index to record based on sym
+ char symbol[SYMLEN]; // Temporary symbol storage
+
+ memset(symbol, 0, SYMLEN); // Clean string for comparison
+ strcpy(symbol, sym);
+
+ while (hptr != NULL)
+ {
+//This is utter failure...
+// if (symcmp(symbol, hptr->h_sym)) <-- left here for giggles :D - LinkoVitch
+ if (strcmp(symbol, hptr->h_sym) == 0)
+ return hptr;
+
+ hptr = hptr->h_next; // Return hash pointer if found
+ }
+
+ return NULL; // Not found in hash table
+}
+
+
+//
+// Add Symbol to the Hash Table
+//
+int hash_add(char * sym, long type, long value, struct OFILE * ofile)
+{
+ struct HREC * hptr;
+ int flag = !iscommon(type);
+
+ if (vflag > 1)
+ {
+ printf("hash_add(%s,%s,%lx,", sym, ofile->o_name,value);
+ printf("%x,%s)\n", (unsigned int)type, (flag ? "GLOBAL" : "COMMON"));
+ }
+
+ if ((hptr = lookup(sym)) == NULL)
+ {
+ return add_to_hlist(&htable[dohash(sym)], sym, ofile, value, type);
+ }
+
+
+ // Already there!
+ if (iscommon(type) && !iscommon(hptr->h_type))
+ {
+ // 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");
+ }
+
+ 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)
+ {
+ printf("Warning: %s: global from ", sym);
+ put_name(ofile);
+ printf(" used, common from ");
+ put_name(hptr->h_ofile);
+ printf(" discarded.\n");
+ }
+
+ 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)
+ {
+ printf("Duplicate symbol %s: ", sym);
+ put_name(hptr->h_ofile);
+ printf(" used, ");
+ put_name(ofile);
+ printf(" discarded\n");
+ }
+
+ putword(sym + 8, ABST_EXTERN);
+ }
+ else
+ { // They're both common
+ if (hptr->h_value < value)
+ {
+ hptr->h_value = value;
+ hptr->h_ofile = ofile;
+ }
+ }
+
+ 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 this is a global/external
+ if (type & T_EXT)
+ {
+ if ((type - T_EXT))
+ {
+ // Then add to hash table
+ if (hash_add(symbol, type, value, Ofile))
+ {
+ return 1; // Error if addition failed
+ }
+ }
+ else
+ {
+ // If value is zero and in hash table
+ if ((hptr = lookup(symbol)) != NULL)
+ {
+ hptr->h_ofile->o_flags |= O_USED; // Mark symbol as used
+ }
+ // Otherwise add to unresolved list
+ else if (add_unresolved(symbol, Ofile))
+ {
+ 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
+
+ // Allocate memory for object record ptr
+ if ((Ofile = new_ofile()) == NULL)
+ {
+ 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);
+
+ // Check filename length
+ if (strlen(temp) > FNLEN - 1)
+ {
+ printf("File name too long: %s\n", temp);
+ return 1;
+ }
+
+ // Check archive name length
+ if (strlen(aname) > FNLEN - 1)
+ {
+ 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;
+
+ olast = Ofile;
+ return 0;
+}
+
+
+//
+// Remove Elements from Unresolved List which are Resolvable
+//
+int dolist(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