+ // 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;
+ }
+
+ 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)
+ {
+ if (symcmp(symbol, hptr->h_sym))
+ 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;
+ }