home *** CD-ROM | disk | FTP | other *** search
- /*
- * SCCS: @(#)robj.c 1.2 11/2/84 14:19:59
- * Read object files.
- *
- ***********************************************************************
- * This software is copyright of
- *
- * John M Collins
- * 47 Cedarwood Drive
- * St Albans
- * Herts, AL4 0DN
- * England +44 727 57267
- *
- * and is released into the public domain on the following conditions:
- *
- * 1. No free maintenance will be guaranteed.
- * 2. Nothing may be based on this software without
- * acknowledgement, including incorporation of this
- * notice.
- *
- * Notwithstanding the above, the author welcomes correspondence and bug
- * fixes.
- ***********************************************************************
- *
- * This particular module will obviously have to be munged beyond
- * recognition for another object format.
- */
-
- #include <stdio.h>
- #include <a.out.h>
- #include "unc.h"
-
- void gette(), getde(), setde(), putte(), putde();
- long gettw(), getdw();
- void reallst(), lclash(), nomem(), unimpl();
- void addit();
- char *malloc();
- long lseek();
-
- int par_entry, par_round, nmods, donedrel, donebrel;
- struct commit abstab, comtab, dreltab;
- long trelpos, drelpos, brelpos;
-
- ef_fids mainfile;
-
- symbol lookup(), inventsymb(), getnsymb();
-
- #define DBSIZE 100
- #define STINIT 20
-
- /*
- * Read text segment. Return 0 if not ok.
- */
-
- int rtext(inf, offset, outf)
- int inf; /* a.out file (possibly in library) */
- long offset; /* Offset from start of inf of a.out file */
- ef_fid outf; /* Output file descriptor */
- {
- t_entry tstr;
- struct bhdr filhdr;
- register long size;
- register int i, l;
- unsigned short inbuf[DBSIZE/2];
-
- /*
- * Initialise fields in structure.
- */
-
- tstr.t_type = T_UNKNOWN;
- tstr.t_vins = 1; /* For the moment */
- tstr.t_bdest = 0;
- tstr.t_gbdest = 0;
- tstr.t_lng = 1;
- tstr.t_reloc = R_NONE;
- tstr.t_rdisp = 0;
- tstr.t_isrel = 0;
- tstr.t_amap = 0;
- tstr.t_dref = 0;
- tstr.t_relsymb = NULL;
- tstr.t_reldisp = 0;
- tstr.t_lab = NULL;
- tstr.t_lsymb = 0;
- tstr.t_refhi = 0;
- tstr.t_reflo = 0x7fffffff;
- tstr.t_match = 0;
-
- /*
- * Read a.out header.
- */
-
- (void) lseek(inf, offset, 0);
-
- if (read(inf, (char *)&filhdr, sizeof(filhdr)) != sizeof(filhdr))
- return 0;
-
- if (filhdr.fmagic != FMAGIC && filhdr.fmagic != NMAGIC)
- return 0;
-
- /*
- * Warn user if entry point does not tie up.
- */
-
- if (filhdr.entry != par_entry)
- (void) fprintf(stderr, "Warning: File has -R%X\n", filhdr.entry);
-
- outf->ef_entry = filhdr.entry;
- outf->ef_tbase = filhdr.entry;
- outf->ef_dbase = filhdr.tsize + filhdr.entry;
-
- if (filhdr.fmagic == NMAGIC)
- outf->ef_dbase = (outf->ef_dbase + par_round) & (~par_round);
-
- outf->ef_bbase = outf->ef_dbase + filhdr.dsize;
- outf->ef_end = outf->ef_bbase + filhdr.bsize;
-
- outf->ef_tsize = filhdr.tsize;
- outf->ef_dsize = filhdr.dsize;
- outf->ef_bsize = filhdr.bsize;
-
- (void) lseek(inf, offset + TEXTPOS, 0);
-
- size = outf->ef_tsize;
-
- while (size > 1) {
- l = size > DBSIZE? DBSIZE: size;
- if (read(inf, (char *)inbuf, l) != l)
- return 0;
- l /= 2;
- for (i = 0; i < l; i++) {
- tstr.t_contents = inbuf[i];
- (void) write(outf->ef_t, (char *)&tstr, sizeof(tstr));
- }
- size -= l + l;
- }
-
- /*
- * Extra one to cope with "etext".
- */
-
- (void) write(outf->ef_t, (char *)&tstr, sizeof(tstr));
- return 1;
- }
-
- /*
- * Same sort of thing for the data segment.
- */
-
- int rdata(inf, offset, outf)
- int inf; /* a.out file (possibly in library) */
- long offset; /* Offset from start of inf of a.out file */
- ef_fid outf; /* Output file descriptor */
- {
- d_entry dstr;
- struct bhdr filhdr;
- register long size;
- register int i, l;
- unsigned char inbuf[DBSIZE];
-
- /*
- * Initialise fields in structure.
- */
-
- dstr.d_type = D_BYTE;
- dstr.d_reloc = R_NONE;
- dstr.d_lng = 1;
- dstr.d_relsymb = NULL;
- dstr.d_reldisp = 0;
- dstr.d_lab = NULL;
-
- /*
- * Read a.out header.
- */
-
- (void) lseek(inf, offset, 0);
-
- if (read(inf, (char *)&filhdr, sizeof(filhdr)) != sizeof(filhdr))
- return 0;
-
- (void) lseek(inf, offset + DATAPOS, 0);
-
- size = outf->ef_dsize;
-
- while (size > 0) {
- l = size > DBSIZE? DBSIZE: size;
- if (read(inf, (char *)inbuf, l) != l)
- return 0;
- for (i = 0; i < l; i++) {
- dstr.d_contents = inbuf[i];
- (void) write(outf->ef_d, (char *)&dstr, sizeof(dstr));
- }
- size -= l;
- }
-
- /*
- * Repeat for BSS segment.
- */
-
- dstr.d_contents = 0;
- for (size = outf->ef_bsize; size > 0; size--)
- (void) write(outf->ef_d, (char *)&dstr, sizeof(dstr));
-
- /*
- * Extra one to cope with "end".
- */
-
- (void) write(outf->ef_d, (char *)&dstr, sizeof(dstr));
- return 1;
- }
-
- /*
- * Process symbol table segment.
- */
-
- int rsymb(inf, offset, dproc, outf)
- int inf; /* a.out file (possibly in library) */
- long offset; /* Offset from start of inf of a.out file */
- symbol (*dproc)();
- register ef_fid outf; /* Output file descriptor */
- {
- register symbol csym;
- struct bhdr filhdr;
- struct sym isym;
- register long size;
- register int i, l;
- char inbuf[SYMLENGTH+1];
-
- /*
- * Read a.out header.
- */
-
- (void) lseek(inf, offset, 0);
-
- if (read(inf, (char *)&filhdr, sizeof(filhdr)) != sizeof(filhdr))
- return 0;
-
- offset += SYMPOS;
- size = filhdr.ssize;
- if (size <= 0)
- return 1;
-
- /*
- * Guesstimate symbol table vector size.
- */
-
- l = size / (sizeof(struct sym) + 4);
- if (l <= 0)
- l = STINIT;
-
- outf->ef_stvec = (symbol *) malloc(l * sizeof(symbol));
- if (outf->ef_stvec == NULL)
- nomem();
-
- outf->ef_stcnt = 0;
- outf->ef_stmax = l;
-
- while (size > sizeof(struct sym)) {
- (void) lseek(inf, offset, 0);
- if (read(inf, (char *)&isym, sizeof(isym)) != sizeof(isym))
- return 0;
- size -= sizeof(isym);
- l = SYMLENGTH;
- if (l > size)
- l = size;
- if (read(inf, inbuf, l) != l)
- return 0;
- inbuf[l] = '\0';
- for (i = 0; inbuf[i] != '\0'; i++)
- ;
- size -= i + 1;
- offset += sizeof(isym) + i + 1;
- csym = (*dproc)(lookup(inbuf), isym.stype, isym.svalue, outf);
- if (outf->ef_stcnt >= outf->ef_stmax)
- reallst(outf);
- outf->ef_stvec[outf->ef_stcnt++] = csym;
- }
- return 1;
- }
-
- /*
- * Process relocation stuff. -1 error, 0 no relocation, 1 relocation.
- */
-
- int rrel(inf, offset, outf)
- int inf; /* a.out file (possibly in library) */
- long offset; /* Offset from start of inf of a.out file */
- ef_fid outf; /* Output file descriptor */
- {
- struct bhdr filhdr;
- struct reloc crel;
- t_entry tstr;
- d_entry dstr;
- register long size;
- long cont, pos;
-
- /*
- * Read a.out header.
- */
-
- (void) lseek(inf, offset, 0);
-
- if (read(inf, (char *)&filhdr, sizeof(filhdr)) != sizeof(filhdr))
- return -1;
- if (filhdr.rtsize <= 0 && filhdr.rdsize <= 0)
- return 0;
-
- size = filhdr.rtsize;
-
- (void) lseek(inf, RTEXTPOS + offset, 0);
- while (size >= sizeof(struct reloc)) {
- if (read(inf, (char *)&crel, sizeof(crel)) != sizeof(crel))
- return -1;
-
- pos = crel.rpos + outf->ef_tbase;
- gette(outf, pos, &tstr);
- tstr.t_reloc = crel.rsize + 1; /* Fiddle! YUK!!! */
- tstr.t_rdisp = crel.rdisp;
- tstr.t_rptr = crel.rsegment;
- if (crel.rsegment == REXT) {
- if (crel.rsymbol >= outf->ef_stcnt)
- return -1;
- tstr.t_relsymb = outf->ef_stvec[crel.rsymbol];
- tstr.t_reldisp = gettw(outf, pos, (int)crel.rsize+1);
- }
- else {
- cont = gettw(outf, pos, (int)crel.rsize+1);
- tstr.t_relsymb = getnsymb(outf, crel.rsegment, cont);
- }
- tstr.t_relsymb->s_used++;
- putte(outf, pos, &tstr);
- size -= sizeof(crel);
- }
-
- /*
- * And now repeat all that for data relocations.
- */
-
- size = filhdr.rdsize;
-
- (void) lseek(inf, RDATAPOS + offset, 0);
- while (size >= sizeof(struct reloc)) {
- if (read(inf, (char *)&crel, sizeof(crel)) != sizeof(crel))
- return -1;
-
- pos = crel.rpos + outf->ef_dbase;
- getde(outf, pos, &dstr);
- dstr.d_reloc = crel.rsize + 1; /* Fiddle! YUK!!! */
- dstr.d_rptr = crel.rsegment;
-
- if (crel.rsegment == REXT) {
- if (crel.rsymbol >= outf->ef_stcnt)
- return -1;
- dstr.d_relsymb = outf->ef_stvec[crel.rsymbol];
- dstr.d_reldisp = getdw(outf, pos, (int)crel.rsize+1);
- }
- else {
- cont = getdw(outf, pos, (int)crel.rsize+1);
- dstr.d_relsymb = getnsymb(outf, crel.rsegment, cont);
- if (dstr.d_relsymb->s_type == TEXT) {
- gette(outf, cont, &tstr);
- tstr.t_dref = 1;
- putte(outf, cont, &tstr);
- }
- }
- switch (crel.rsize) {
- default:
- unimpl("Data byte relocation");
- break;
- case RWORD:
- unimpl("data word reloc");
- dstr.d_type = D_WORD;
- dstr.d_lng = 2;
- setde(outf, pos+1, D_CONT, 1);
- break;
- case RLONG:
- dstr.d_type = D_ADDR;
- dstr.d_lng = 4;
- setde(outf, pos+1, D_CONT, 1);
- setde(outf, pos+2, D_CONT, 1);
- setde(outf, pos+3, D_CONT, 1);
- break;
- }
- dstr.d_relsymb->s_used++;
- putde(outf, pos, &dstr);
- size -= sizeof(crel);
- }
- return 1;
- }
-
- /*
- * Process a symbol.
- */
-
- symbol dosymb(sy, type, val, fid)
- register symbol sy;
- int type;
- long val;
- ef_fid fid;
- {
- t_entry tstr;
- d_entry dstr;
-
- if (!sy->s_newsym) {
- if (type & EXTERN) {
- (void) fprintf(stderr, "Duplicate symbol %s\n", sy->s_name);
- exit(10);
- }
- if (++sy->s_defs > nmods)
- nmods = sy->s_defs;
- sy = inventsymb("DUP");
- }
-
- sy->s_value = val;
-
- switch (type) {
- default:
- return NULL;
-
- case EXTERN|UNDEF:
- if (val != 0) {
- sy->s_type = COMM;
- addit(&comtab, sy);
- }
- else
- sy->s_type = N_UNDF;
- sy->s_glob = 1;
- break;
-
- case EXTERN|ABS:
- sy->s_type = N_ABS;
- sy->s_glob = 1;
- addit(&abstab, sy);
- break;
-
- case ABS:
- sy->s_type = N_ABS;
- addit(&abstab, sy);
- break;
-
- case EXTERN|TEXT:
- case TEXT:
- sy->s_type = N_TEXT;
- gette(fid, val, &tstr);
- tstr.t_bdest = 1;
- if (type & EXTERN) {
- tstr.t_gbdest = 1;
- sy->s_glob = 1;
- }
- sy->s_link = tstr.t_lab;
- tstr.t_lab = sy;
- putte(fid, val, &tstr);
- break;
-
- case BSS:
- case EXTERN|BSS:
- sy->s_type = N_BSS;
- goto datrest;
- case DATA:
- case EXTERN|DATA:
- sy->s_type = N_DATA;
- datrest:
- getde(fid, val, &dstr);
- if (type & EXTERN)
- sy->s_glob = 1;
- sy->s_link = dstr.d_lab;
- dstr.d_lab = sy;
- putde(fid, val, &dstr);
- break;
- }
-
- sy->s_newsym = 0;
- return sy;
- }
-
- /*
- * Process relocation stuff in putative library modules.
- * The main function of all this is to mark which bits of the text
- * not to look at as I compare the stuff.
- *
- * As with "rrel", return -1 error, 0 no relocation, 1 relocation.
- */
-
- int rrell1(inf, offset, outf)
- int inf; /* a.out file (possibly in library) */
- long offset; /* Offset from start of inf of a.out file */
- ef_fid outf; /* Output file descriptor */
- {
- struct bhdr filhdr;
- struct reloc crel;
- t_entry tstr;
- register long size;
- long pos;
-
- /*
- * Read a.out header.
- */
-
- (void) lseek(inf, offset, 0);
-
- if (read(inf, (char *)&filhdr, sizeof(filhdr)) != sizeof(filhdr))
- return -1;
- if (filhdr.rtsize <= 0 && filhdr.rdsize <= 0)
- return 0;
-
- size = filhdr.rtsize;
-
- (void) lseek(inf, RTEXTPOS + offset, 0);
- while (size >= sizeof(struct reloc)) {
- if (read(inf, (char *)&crel, sizeof(crel)) != sizeof(crel))
- return -1;
-
- pos = crel.rpos + outf->ef_tbase;
- gette(outf, pos, &tstr);
- tstr.t_reloc = crel.rsize + 1; /* Fiddle! YUK!!! */
- tstr.t_rdisp = crel.rdisp;
- tstr.t_rptr = crel.rsegment;
- tstr.t_isrel = 1;
- putte(outf, pos, &tstr);
- if (crel.rsize == RLONG) {
- gette(outf, pos+2, &tstr);
- tstr.t_isrel = 1;
- putte(outf, pos+2, &tstr);
- }
- size -= sizeof(crel);
- }
-
- /*
- * Dont bother with data relocation at this stage. We'll
- * tie that up later.
- */
-
- return 1;
- }
-
- /*
- * Process a symbol in library file. The extern variable trelpos gives
- * the place in the main file where the library module is relocated.
- * We don't know the data position until we do the final merge, perhaps
- * not even then.
- */
-
- symbol dolsymb(sy, type, val, fid)
- register symbol sy;
- int type;
- long val;
- ef_fid fid;
- {
- t_entry tstr;
-
- switch (type) {
- default:
- return NULL;
-
- case EXTERN|UNDEF:
- if (!sy->s_newsym)
- return sy;
- sy->s_value = val;
- if (val != 0) {
- sy->s_type = COMM;
- addit(&dreltab, sy);
- }
- else
- sy->s_type = N_UNDF;
- sy->s_glob = 1;
- break;
-
- case EXTERN|ABS:
- if (!sy->s_newsym) {
- if (sy->s_type != N_ABS || sy->s_value != val)
- lclash("abs");
- }
- sy->s_type = N_ABS;
- sy->s_value = val;
- sy->s_glob = 1;
- addit(&abstab, sy);
- break;
-
- case EXTERN|TEXT:
- sy->s_type = N_TEXT;
- val += trelpos - fid->ef_tbase;
- if (!sy->s_newsym) {
- if (val != sy->s_value)
- lclash("tsym");
- return sy;
- }
- sy->s_value = val;
- gette(&mainfile, val, &tstr);
- tstr.t_bdest = 1;
- tstr.t_gbdest = 1;
- sy->s_glob = 1;
- sy->s_link = tstr.t_lab;
- tstr.t_lab = sy;
- putte(&mainfile, val, &tstr);
- break;
-
- case EXTERN|BSS:
- if (!sy->s_newsym)
- return sy;
- sy->s_type = N_BSS;
- sy->s_value = val - fid->ef_bbase;
- goto datrest;
-
- case EXTERN|DATA:
- if (!sy->s_newsym)
- return sy;
- sy->s_type = N_DATA;
- sy->s_value = val - fid->ef_dbase;
- datrest:
- sy->s_glob = 1;
- addit(&dreltab, sy);
- break;
- }
-
- sy->s_newsym = 0;
- return sy;
- }
-
- /*
- * Change definition of undefined symbol as we define it.
- */
-
- void reassign(sy, val)
- register symbol sy;
- long val;
- {
- sy->s_value = val;
-
- if (val < mainfile.ef_tbase) {
- sy->s_type = N_ABS;
- addit(&abstab, sy);
- }
- else if (val < mainfile.ef_dbase) {
- t_entry tstr;
-
- sy->s_type = N_TEXT;
- gette(&mainfile, val, &tstr);
- tstr.t_bdest = 1;
- tstr.t_gbdest = 1;
- sy->s_glob = 1;
- sy->s_link = tstr.t_lab;
- tstr.t_lab = sy;
- putte(&mainfile, val, &tstr);
- }
- else {
- d_entry dstr;
-
- sy->s_type = val < mainfile.ef_bbase? N_DATA: N_BSS;
- getde(&mainfile, val, &dstr);
- sy->s_link = dstr.d_lab;
- dstr.d_lab = sy;
- putde(&mainfile, val, &dstr);
- }
- }
-
- /*
- * When we discover where bss or data come, reallocate the table.
- */
-
- void zapdat(seg, inc)
- int seg;
- long inc;
- {
- register int i;
- register symbol csymb;
- d_entry dent;
-
- for (i = 0; i < dreltab.c_int; i++) {
- csymb = dreltab.c_symb[i];
- if (csymb->s_type != seg)
- continue;
- csymb->s_value += inc;
- getde(&mainfile, csymb->s_value, &dent);
- csymb->s_link = dent.d_lab;
- dent.d_lab = csymb;
- putde(&mainfile, csymb->s_value, &dent);
- }
- }
-
- /*
- * Process relocation stuff in library module which we are inserting.
- * Horrors if something goes wrong.
- */
-
- void rrell2(inf, offset, outf)
- int inf; /* a.out file (possibly in library) */
- long offset; /* Offset from start of inf of a.out file */
- ef_fid outf; /* Output file descriptor */
- {
- struct bhdr filhdr;
- struct reloc crel;
- t_entry mtstr;
- d_entry mdstr;
- register long size;
- register symbol csymb;
- long pos, mpos, mval, lval;
- int dhere = 0; /* Mark whether bss done */
-
- /*
- * Read a.out header.
- */
-
- (void) lseek(inf, offset, 0);
-
- if (read(inf, (char *)&filhdr, sizeof(filhdr)) != sizeof(filhdr))
- return;
- if (filhdr.rtsize <= 0 && filhdr.rdsize <= 0)
- return;
-
- size = filhdr.rtsize;
-
- (void) lseek(inf, RTEXTPOS + offset, 0);
- for (; size >= sizeof(struct reloc); size -= sizeof(crel)) {
- if (read(inf, (char *)&crel, sizeof(crel)) != sizeof(crel))
- lclash("rd trel");
-
- pos = crel.rpos + outf->ef_tbase;
- mpos = crel.rpos + trelpos;
- gette(&mainfile, mpos, &mtstr);
- lval = gettw(outf, pos, (int)crel.rsize+1);
- mval = gettw(&mainfile, mpos, (int)crel.rsize+1);
-
- switch (crel.rsegment) {
- case RTEXT:
- if (lval + trelpos - outf->ef_tbase != mval)
- lclash("Trel");
- continue;
- case RDATA:
- if (donedrel) {
- if (lval + drelpos - outf->ef_dbase != mval)
- lclash("Drel");
- }
- else {
- donedrel++;
- drelpos = mval - lval + outf->ef_dbase;
- }
- continue;
- case RBSS:
- if (donebrel) {
- if (lval + brelpos - outf->ef_bbase != mval)
- lclash("brel");
- }
- else {
- donebrel++;
- brelpos = mval - lval + outf->ef_bbase;
- }
- continue;
- case REXT:
- if (crel.rsymbol >= outf->ef_stcnt)
- lclash("Bad sy no");
- csymb = outf->ef_stvec[crel.rsymbol];
- if (csymb == NULL)
- continue;
- switch (csymb->s_type) {
- case N_UNDF:
- reassign(csymb, mval - lval);
- break;
- case N_ABS:
- if (lval + csymb->s_value != mval)
- lclash("abs rel");
- break;
- case N_TEXT:
- if (lval + csymb->s_value != mval)
- lclash("text rel");
- break;
- case N_DATA:
- if (lval + csymb->s_value != mval)
- lclash("data rel");
- break;
- case N_BSS:
- if (lval + csymb->s_value != mval)
- lclash("bss rel");
- break;
- case COMM:
- reassign(csymb, mval - lval);
- break;
- }
- mtstr.t_relsymb = csymb;
- mtstr.t_reldisp = lval;
- break;
- }
- }
-
- /*
- * Relocate data and bss if possible.
- */
-
- if (donebrel) {
- zapdat(N_BSS, brelpos);
- dhere++;
- }
-
- if (!donedrel)
- return;
-
-
- zapdat(N_DATA, drelpos);
-
- /*
- * And now repeat all that for data relocations if possible
- */
-
- size = filhdr.rdsize;
-
- (void) lseek(inf, RDATAPOS + offset, 0);
- for (; size >= sizeof(struct reloc); size -= sizeof(crel)) {
- if (read(inf, (char *)&crel, sizeof(crel)) != sizeof(crel))
- lclash("Rd drel");
-
- if (crel.rsize != RLONG)
- continue;
-
- pos = crel.rpos + outf->ef_dbase;
- mpos = crel.rpos + drelpos;
- getde(&mainfile, mpos, &mdstr);
- lval = getdw(outf, pos, (int)crel.rsize+1);
- mval = getdw(&mainfile, mpos, (int)crel.rsize+1);
- switch (crel.rsegment) {
- case RTEXT:
- if (lval + trelpos - outf->ef_tbase != mval)
- lclash("Trel-d");
- continue;
- case RDATA:
- if (lval + drelpos - outf->ef_dbase != mval)
- lclash("Drel-d");
- continue;
- case RBSS:
- if (donebrel) {
- if (lval + brelpos - outf->ef_bbase != mval)
- lclash("brel");
- }
- else {
- donebrel++;
- brelpos = mval - lval + outf->ef_bbase;
- }
- continue;
- case REXT:
- if (crel.rsymbol >= outf->ef_stcnt)
- lclash("Bad sy no");
- csymb = outf->ef_stvec[crel.rsymbol];
- if (csymb == NULL)
- continue;
- switch (csymb->s_type) {
- case N_UNDF:
- reassign(csymb, mval - lval);
- break;
- case N_ABS:
- if (lval + csymb->s_value != mval)
- lclash("abs rel");
- break;
- case N_TEXT:
- if (lval + csymb->s_value != mval)
- lclash("text rel");
- break;
- case N_DATA:
- if (lval + csymb->s_value != mval)
- lclash("data rel");
- break;
- case N_BSS:
- if (lval + csymb->s_value != mval)
- lclash("bss rel");
- break;
- case COMM:
- reassign(csymb, mval - lval);
- break;
- }
- mtstr.t_relsymb = csymb;
- mtstr.t_reldisp = lval;
- break;
- }
- }
-
- if (dhere || !donebrel)
- return;
-
- zapdat(N_BSS, brelpos);
- }
-