diff --git a/h/out.h b/h/out.h new file mode 100644 index 000000000..6bcceaa15 --- /dev/null +++ b/h/out.h @@ -0,0 +1,120 @@ +/* $Header$ */ +/* + * output format for ACK assemblers + */ +#ifndef ushort +#define ushort unsigned short +#endif ushort + +struct outhead { + ushort oh_magic; /* magic number */ + ushort oh_stamp; /* version stamp */ + ushort oh_flags; /* several format flags */ + ushort oh_nsect; /* number of outsect structures */ + ushort oh_nrelo; /* number of outrelo structures */ + ushort oh_nname; /* number of outname structures */ + long oh_nemit; /* sum of all os_flen */ + long oh_nchar; /* size of string area */ +}; + +#define O_MAGIC 0x0201 /* magic number of output file */ +#define O_STAMP 0 /* version stamp */ + +#ifdef JOHAN +#define HF_BREV 0x0001 /* high order byte lowest address */ +#define HF_WREV 0x0002 /* high order word lowest address */ +#endif JOHAN +#define HF_LINK 0x0004 /* unresolved references left */ +#define HF_8086 0x0008 /* os_base specially encoded */ + +struct outsect { + long os_base; /* startaddress in machine */ + long os_size; /* section size in machine */ + long os_foff; /* startaddress in file */ + long os_flen; /* section size in file */ + long os_lign; /* section alignment */ +}; + +struct outrelo { + char or_type; /* type of reference */ + char or_sect; /* referencing section */ + ushort or_nami; /* referenced symbol index */ + long or_addr; /* referencing address */ +}; + +struct outname { + union { + char *on_ptr; /* symbol name (in core) */ + long on_off; /* symbol name (in file) */ + } on_u; +#define on_mptr on_u.on_ptr +#define on_foff on_u.on_off + ushort on_type; /* symbol type */ + ushort on_desc; /* debug info */ + long on_valu; /* symbol value */ +}; + +/* + * relocation type bits + */ +#define RELSZ 0x07 /* relocation length */ +#define RELO1 1 /* 1 byte */ +#define RELO2 2 /* 2 bytes */ +#define RELO4 4 /* 4 bytes */ +#define RELPC 0x08 /* pc relative */ +#ifndef JOHAN +#define RELBR 0x10 /* High order byte lowest address. */ +#define RELWR 0x20 /* High order word lowest address. */ +#endif JOHAN + +/* + * section type bits and fields + */ +#define S_TYP 0x007F /* undefined, absolute or relative */ +#define S_EXT 0x0080 /* external flag */ +#define S_ETC 0x7F00 /* for symbolic debug, bypassing 'as' */ + +/* + * S_TYP field values + */ +#define S_UND 0x0000 /* undefined item */ +#define S_ABS 0x0001 /* absolute item */ +#define S_MIN 0x0002 /* first user section */ +#define S_MAX S_TYP /* last user section */ + +/* + * S_ETC field values + */ +#define S_SCT 0x0100 /* section names */ +#define S_LIN 0x0200 /* hll source line item */ +#define S_FIL 0x0300 /* hll source file item */ +#define S_MOD 0x0400 /* ass source file item */ +#ifndef JOHAN +#define S_COM 0x1000 /* Common name. */ +#endif JOHAN + +/* + * structure format strings + */ +#define SF_HEAD "22222244" +#define SF_SECT "44444" +#define SF_RELO "1124" +#define SF_NAME "4224" + +/* + * structure sizes (bytes in file; add digits in SF_*) + */ +#define SZ_HEAD 20 +#define SZ_SECT 20 +#define SZ_RELO 8 +#define SZ_NAME 12 + +/* + * file access macros + */ +#define BADMAGIC(x) ((x).oh_magic!=O_MAGIC) +#define OFF_SECT(x) SZ_HEAD +#define OFF_EMIT(x) (OFF_SECT(x) + ((long)(x).oh_nsect * SZ_SECT)) +#define OFF_RELO(x) (OFF_EMIT(x) + (x).oh_nemit) +#define OFF_NAME(x) (OFF_RELO(x) + ((long)(x).oh_nrelo * SZ_RELO)) +#define OFF_CHAR(x) (OFF_NAME(x) + ((long)(x).oh_nname * SZ_NAME)) diff --git a/h/ranlib.h b/h/ranlib.h new file mode 100644 index 000000000..cf76a86e5 --- /dev/null +++ b/h/ranlib.h @@ -0,0 +1,25 @@ +/* $Header$ */ + +#ifndef SYMDEF +# define SYMDEF "__.SYMDEF" +#endif SYMDEF + +/* + * Structure of the SYMDEF table of contents for an archive. + * SYMDEF begins with a long giving the number of ranlib + * structures that immediately follow, and then continues with a string + * table consisting of a long giving the number of bytes of + * strings that follow and then the strings themselves. + */ +struct ranlib { + union { + char *ran__ptr; /* symbol name (in core) */ + long ran__off; /* symbol name (in file) */ + } ran_u; +#define ran_ptr ran_u.ran__ptr +#define ran_off ran_u.ran__off + long ran_pos; /* library member is at this position */ +}; + +#define SZ_RAN 8 +#define SF_RAN "44" diff --git a/util/led/archive.c b/util/led/archive.c new file mode 100644 index 000000000..f453256e6 --- /dev/null +++ b/util/led/archive.c @@ -0,0 +1,178 @@ +#ifndef lint +static char rcsid[] = "$Header$"; +#endif + +#include "arch.h" +#include "out.h" +#include "ranlib.h" +#include "const.h" +#include "debug.h" +#include "defs.h" +#include "memory.h" + +#define ENDLIB ((long)0) + +extern ind_t hard_alloc(); + +static struct ar_hdr arhdr; + +/* + * First read a long telling how many ranlib structs there are, then + * the structs themselves. Second read a long telling how many chars there are + * in the string table, then the string table itself. + * We keep only one ranlib table in core, so this table always starts at offset + * (ind_t)0 from its base. + */ +static long +getsymdeftable() +{ + register ind_t off; + register struct ranlib *ran; + register long count; + register long nran, nchar; + extern long getlong(); + + count = nran = getlong(); + debug("%ld ranlib structs, ", nran, 0, 0, 0); + off = hard_alloc(ALLORANL, nran * sizeof(struct ranlib)); + if (off == BADOFF) + fatal("no space for ranlib structs"); + ran = (struct ranlib *)address(ALLORANL, off); + read_table(ran, count); + nchar = getlong(); + debug("%ld ranlib chars\n", nchar, 0, 0, 0); + if ((off = hard_alloc(ALLORANL, nchar)) == BADOFF) + fatal("no space for ranlib strings"); + read_char(address(ALLORANL, off), nchar); + ran = (struct ranlib *)address(ALLORANL, (ind_t)0); + while (count--) { + /* + * Adjust because names are now in core, not on file. + * Note that `ran_off' is measured from the beginning of the + * string area, NOT from the beginning of the file. + */ + if (ran->ran_off >= nchar) + fatal("bad ranlib string offset"); + ran->ran_off += off; + ran++; + } + return nran; +} + +extern char *modulname; +extern long position; + +/* + * Process archive with table of contents. The table of contents tells + * of symbols in which module they are defined. We scan the table for + * symbols that are known but not yet defined. Then we extract all necessary + * information from the corresponding module. This module may need symbols that + * were defined in modules located before this one in the archive, so we + * scan the table again. We perform these actions as long as new symbols + * are defined. + */ +arch() +{ + long nran; + bool resolved; + + nran = getsymdeftable(); + + savemagic(); + do { + register ind_t ranindex; + register long count; + + debug("(re)scan ranlib table\n", 0, 0, 0, 0); + ranindex = (ind_t)0; + count = nran; + resolved = FALSE; + while (count > 0) { + register struct ranlib *ran; + register char *string; + register struct outname *name; + register long pos; + extern int hash(); + extern struct outname *searchname(); + + ran = (struct ranlib *)address(ALLORANL, ranindex); + string = address(ALLORANL, (ind_t)ran->ran_off); + name = searchname(string, hash(string)); + if (name == (struct outname *)0 || !ISUNDEFINED(name)) { + ranindex += sizeof(struct ranlib); + count--; + continue; + } + seek(ran->ran_pos); + get_archive_header(&arhdr); + modulname = arhdr.ar_name; + debug("%s defines %s\n", modulname, string, 0, 0); + position = ran->ran_pos + SZ_ARCH; + resolved = TRUE; + /* + * This archive member is going to be linked, + * so we don't need to know what else it defines. + * Note that we assume that all ranlib information of + * one archive member is contiguous. + */ + pos = ran->ran_pos; + do { + count--; ran++; + ranindex += sizeof(struct ranlib); + } while (count > 0 && ran->ran_pos == pos); + notelib(pos); + savehdr(&arhdr); + extract(); + } + } while (resolved); + + dealloc(ALLORANL); + notelib(ENDLIB); +} + +/* + * An archive member that will be loaded is remembered by storing its position + * in the archive into the table of positions. + */ +notelib(pos) + long pos; +{ + register ind_t off; + + if ((off = hard_alloc(ALLOARCH, (long)sizeof(long))) == BADOFF) + fatal("no space for archive position"); + *(long *)address(ALLOARCH, off) = pos; +} + +/* + * Index of position of first archive member of next archive. + */ +static ind_t posindex = (ind_t)0; + +/* + * Process the archive in pass 2. + * We walk through the table of positions telling at what byte offset the + * archive header + module is located, until this position is ENDLIB, meaning + * that we've processed all needed modules in this archive. Each group of + * positions of an archive is terminated with ENDLIB. + */ +arch2() +{ + register long *pos; + register ind_t localpos; + + localpos = posindex; + for ( pos = (long *)address(ALLOARCH, localpos); + *pos != ENDLIB; + pos++, localpos += sizeof(long) + ) { + seek(*pos); + get_archive_header(&arhdr); + modulname = arhdr.ar_name; + debug("%s: archive member\n", modulname, 0, 0, 0); + position = *pos + SZ_ARCH; + finish(); + } + localpos += sizeof(long); /* Skip ENDLIB. */ + posindex = localpos; /* Remember for next call. */ +} diff --git a/util/led/assert.h b/util/led/assert.h new file mode 100644 index 000000000..9ff3ae982 --- /dev/null +++ b/util/led/assert.h @@ -0,0 +1,18 @@ +/* $Header$ */ + +#ifndef lint +#ifdef NASSERT + +#define assert(ex) + +#else NASSERT + +#define assert(ex) \ +{if (!(ex)) fatal("Assertion failed: file %s, line %d", __FILE__, __LINE__);} + +#endif NASSERT +#else lint + +#define assert(ex) + +#endif lint diff --git a/util/led/byte_order.c b/util/led/byte_order.c new file mode 100644 index 000000000..0172ec3de --- /dev/null +++ b/util/led/byte_order.c @@ -0,0 +1,90 @@ +#ifndef lint +static char rcsid[] = "$Header$"; +#endif lint + +#include "const.h" +#include "assert.h" + +bool bytes_reversed = FALSE; +bool words_reversed = FALSE; + +/* + * Determine the byte/word order in shorts/longs, assuming the size of a short + * is 2 chars, and the size of a long is 4 chars. Not all theoretical + * possibilities are tested; only bytes reversed and/or words reversed. + */ +determine_ordering() +{ + short s; + long l; + register char *cp; + register short *sp; + + cp = (char *)&s; + cp[0] = 0x01; cp[1] = 0x02; + if (s != 0x01 + (0x02 << 8)) + bytes_reversed = TRUE; + sp = (short *)&l; + sp[0] = 0x0001; sp[1] = 0x0002; + if (l != 0x0001 + (0x0002 << 16)) + words_reversed = TRUE; +} + +/* + * `Format' is a string of digits indicating how many bytes must be taken + * from `buf' to form an integer of some type. E.g. if the digit is '2', two + * bytes are taken to form a short. + */ +swap(buf, format) + register char *buf; + register char *format; +{ + register char savebyte; + + while (*format) { + switch (*format++) { + case '1': + buf += 1; + break; + case '2': + if (bytes_reversed) { + savebyte = buf[0]; + buf[0] = buf[1]; + buf[1] = savebyte; + } + buf += 2; + break; + case '4': + /* + * Written out to save recursive calls. + */ + if (bytes_reversed && words_reversed) { + savebyte = buf[0]; + buf[0] = buf[3]; + buf[3] = savebyte; + savebyte = buf[1]; + buf[1] = buf[2]; + buf[2] = savebyte; + } else if (bytes_reversed) { + savebyte = buf[0]; + buf[0] = buf[1]; + buf[1] = savebyte; + savebyte = buf[2]; + buf[2] = buf[3]; + buf[3] = savebyte; + } else if (words_reversed) { + savebyte = buf[0]; + buf[0] = buf[2]; + buf[2] = savebyte; + savebyte = buf[1]; + buf[1] = buf[3]; + buf[3] = savebyte; + } + buf += 4; + break; + default: + assert(FALSE); + break; + } + } +} diff --git a/util/led/const.h b/util/led/const.h new file mode 100644 index 000000000..6c70358d2 --- /dev/null +++ b/util/led/const.h @@ -0,0 +1,26 @@ +/* $Header$ */ + +typedef int bool; + +#define FALSE 0 +#define TRUE 1 + +#define S_ZER 0x2000 /* Internal use only. */ + +#define WIDTH 8 /* Number of bits in a byte. */ +#define BYTEMASK 0xFF /* Mask to get low order byte. */ +#define MININT (1 << (sizeof(int) * WIDTH - 1)) +#define MAXCHUNK (-(MININT + 1)) /* Highest count we write(2). */ + +#define RFLAG 0x01 /* -r flag given. */ +#define SFLAG 0x02 /* -s flag given. */ + +#define MAXSECT 64 /* Maximum number of sections. */ + +#define PLAIN 0 /* Input file is a normal file. */ +#define ARCHIVE 1 /* Input file is an archive. */ + +#define FIRST 1 /* Pass number. */ +#define SECOND 2 /* Idem. */ + +#define BADOFF ((ind_t)-1) diff --git a/util/led/debug.h b/util/led/debug.h new file mode 100644 index 000000000..16fff039a --- /dev/null +++ b/util/led/debug.h @@ -0,0 +1,11 @@ +/* $Header$ */ + +#ifdef NDEBUG + +#define debug(s, a1, a2, a3, a4) + +#else + +#define debug(s, a1, a2, a3, a4) printf(s, a1, a2, a3, a4) + +#endif diff --git a/util/led/defs.h b/util/led/defs.h new file mode 100644 index 000000000..721986a04 --- /dev/null +++ b/util/led/defs.h @@ -0,0 +1,10 @@ +/* $Header$ */ + +/* + * We need the S_EXT because we leave locals alone. + */ +#define ISUNDEFINED(n) (((n)->on_type & (S_TYP | S_EXT)) == (S_UND | S_EXT)) +#define ISABSOLUTE(n) (((n)->on_type & (S_TYP | S_EXT)) == (S_ABS | S_EXT)) +#define ISCOMMON(n) (((n)->on_type & (S_COM | S_EXT)) == (S_COM | S_EXT)) + +#define mustsavelocal(name) (!((name)->on_type & S_SCT)) diff --git a/util/led/finish.c b/util/led/finish.c new file mode 100644 index 000000000..00125f679 --- /dev/null +++ b/util/led/finish.c @@ -0,0 +1,182 @@ +#ifndef lint +static char rcsid[] = "$Header$"; +#endif + +#include "out.h" +#include "const.h" +#include "defs.h" +#include "memory.h" +#include "orig.h" +#include "scan.h" + +extern bool incore; +extern int flagword; + +/* + * We know all there is to know about the current module. + * Now we relocate the values in the emitted bytes and write + * those to the final output file. Then we compute the relative origins + * for the next module. + */ +finish() +{ + struct outhead *head; + struct outsect *sects; + struct outname *names; + char *chars; + + get_modul(); + head = (struct outhead *)modulptr(IND_HEAD); + sects = (struct outsect *)modulptr(IND_SECT(*head)); + names = (struct outname *)modulptr(IND_NAME(*head)); + chars = (char *)modulptr(IND_CHAR(*head)); + adjust_names(names, head, chars); + handle_relos(head, sects, names); + if (!incore && !(flagword & SFLAG)) { + put_locals(names, head->oh_nname, sects); +#ifdef SYMDBUG + put_dbug(OFF_DBUG(*head)); +#endif SYMDBUG + } + compute_origins(sects, head->oh_nsect); + skip_modul(head); +} + +/* + * Adjust all local names for the move into core. + */ +static +adjust_names(name, head, chars) + register struct outname *name; + struct outhead *head; + register char *chars; +{ + register int cnt; + register ind_t charoff; + + cnt = head->oh_nname; + charoff = OFF_CHAR(*head); + while (cnt--) { + if (name->on_foff != (long)0) + name->on_mptr = chars + name->on_foff - charoff; + name++; + } +} + +/* + * If all sections are in core, we can access them randomly, so we need only + * scan the relocation table once. Otherwise we must for each section scan + * the relocation table again, because the relocation entries of one section + * need not be consecutive. + */ +static +handle_relos(head, sects, names) + struct outhead *head; + struct outsect *sects; + struct outname *names; +{ + register struct outrelo *relo; + register int sectindex; + register int nrelo; + register char *emit; + extern char *getemit(); + extern struct outrelo *nextrelo(); + + if (incore) { + nrelo = head->oh_nrelo; sectindex = -1; + startrelo(head); relo = nextrelo(); + while (nrelo--) { + if (sectindex != relo->or_sect - S_MIN) { + sectindex = relo->or_sect - S_MIN; + emit = getemit(head, sects, sectindex); + } + relocate(head, emit, names, relo, sects); + relo++; + } + } else { + for (sectindex = 0; sectindex < head->oh_nsect; sectindex++) { + emit = getemit(head, sects, sectindex); + nrelo = head->oh_nrelo; startrelo(head); + while (nrelo--) { + relo = nextrelo(); + if (relo->or_sect - S_MIN == sectindex) { + relocate(head,emit,names,relo,sects); + /* + * Write out the (probably changed) + * relocation information. + */ + if (flagword & RFLAG) + wrt_relo(relo); + } + } + wrt_emit(emit, sectindex, sects[sectindex].os_flen); + /* + * XXX We should be able to free the emitted bytes. + */ + } + } +} + +/* + * Write out the local names that must be saved. + */ +static +put_locals(name, nnames, sects) + register struct outname *name; + register ushort nnames; + register struct outsect *sects; +{ + while (nnames--) { + if ((name->on_type & S_EXT) == 0 && mustsavelocal(name)) { + namerelocate(name, sects); + addbase(name); + wrt_name(name); + } + name++; + } +} + +/* + * Add all flen's and all (size - flen == zero)'s of preceding sections + * with the same number. + */ +static +compute_origins(sect, nsect) + register struct outsect *sect; + register ushort nsect; +{ + extern struct orig relorig[]; + register struct orig *orig = relorig; + + while (nsect--) { + orig->org_flen += sect->os_flen; + orig->org_zero += sect->os_size - sect->os_flen; + orig++; sect++; + } +} +#ifdef SYMDBUG + +/* + * Write out what is after the string area. This is likely to be + * debugging information. + */ +static +put_dbug(offdbug) + long offdbug; +{ + char buf[512]; + register int nbytes; + register long dbugsize; + extern long objectsize; + extern long position; + + dbugsize = objectsize - offdbug; + seek(position + offdbug); + while (dbugsize) { + nbytes = dbugsize > 512 ? 512 : dbugsize; + read_char(buf, (long)nbytes); + wrt_dbug(buf, nbytes); + dbugsize -= nbytes; + } +} +#endif SYMDBUG diff --git a/util/led/mach.c b/util/led/mach.c new file mode 100644 index 000000000..e17bf1217 --- /dev/null +++ b/util/led/mach.c @@ -0,0 +1,24 @@ +/* + * $Header$ + */ +/* + * Values depend on the machine on which this program should run. + * Now for Vax 11/750. + */ + +#define K 1024 + + mems[ALLOEMIT + 0].mem_left = 64 * K; + mems[ALLOEMIT + 1].mem_left = 64 * K; + mems[ALLORELO].mem_left = 64 * K; + mems[ALLOLOCL].mem_left = 64 * K; + mems[ALLOGLOB].mem_left = 64 * K; + mems[ALLOLCHR].mem_left = 64 * K; + mems[ALLOGCHR].mem_left = 64 * K; +#ifdef SYMDBUG + mems[ALLODBUG].mem_left = 64 * K; +#endif SYMDBUG + mems[ALLOSYMB].mem_left = 4 * K; + mems[ALLOARCH].mem_left = 1 * K; + mems[ALLOMODL].mem_left = 3 * 64 * K; + mems[ALLORANL].mem_left = 4 * K; diff --git a/util/led/memory.c b/util/led/memory.c index 7cb22f14a..8069af18c 100644 --- a/util/led/memory.c +++ b/util/led/memory.c @@ -9,7 +9,6 @@ static char rcsid[] = "$Header$"; * is done and pieces after the one that requested the growth are moved up. */ -#include #include "out.h" #include "const.h" #include "assert.h" @@ -19,7 +18,7 @@ static char rcsid[] = "$Header$"; struct memory mems[NMEMS]; bool incore = TRUE; /* TRUE while everything can be kept in core. */ -off_t core_position = (off_t)0; /* Index of current module. */ +ind_t core_position = (ind_t)0; /* Index of current module. */ #define AT_LEAST 2 /* See comment about string areas. */ @@ -29,51 +28,18 @@ off_t core_position = (off_t)0; /* Index of current module. */ */ init_core() { - FILE *ledrc; - int piece; - off_t left; register char *base; - register off_t total_size; + register ind_t total_size; register struct memory *mem; extern char *sbrk(); -#ifndef TJALK - /* - * Read in what should be allocated for each piece initially. - * This facilitates testing, but is slower and should not - * be done in the final version. XXX - */ - incore = (ledrc = fopen(".ledrc", "r")) != (FILE *)0; +#include "mach.c" - if (incore) { - while (fscanf(ledrc, "%d %d", &piece, &left) == 2) - mems[piece].mem_left = left; - fclose(ledrc); - } -#else TJALK - mems[ALLOHEAD].mem_left = 20; /*XXX*/ - mems[ALLOSECT].mem_left = 60; /*XXX*/ - mems[ALLOEMIT + 0].mem_left = 65536; - mems[ALLOEMIT + 1].mem_left = 65536; - mems[ALLORELO].mem_left = 65536; - mems[ALLOLOCL].mem_left = 65536; - mems[ALLOGLOB].mem_left = 65536; - mems[ALLOLCHR].mem_left = 65536; - mems[ALLOGCHR].mem_left = 65536; -#ifdef SYMDBUG - mems[ALLODBUG].mem_left = 65536; -#endif SYMDBUG - mems[ALLOSYMB].mem_left = 4096; - mems[ALLOARCH].mem_left = 512; - mems[ALLOMODL].mem_left = 196608; - mems[ALLORANL].mem_left = 4096; -#endif TJALK - - total_size = (off_t)0;/* Will accumulate the sizes. */ + total_size = (ind_t)0; /* Will accumulate the sizes. */ base = sbrk(0); /* First free. */ for (mem = mems; mem < &mems[NMEMS]; mem++) { mem->mem_base = base; - mem->mem_full = (off_t)0; + mem->mem_full = (ind_t)0; base += mem->mem_left; /* Each piece will start after prev. */ total_size += mem->mem_left; } @@ -93,12 +59,11 @@ init_core() mems[ALLOLCHR].mem_full = 1; mems[ALLOGCHR].mem_full = 1; - if ((int)sbrk(total_size) == -1) { + if (total_size != (int)total_size || (int)sbrk((int)total_size) == -1) { incore = FALSE; /* In core strategy failed. */ if ((int)sbrk(AT_LEAST) == -1) fatal("no core at all"); } - } /* @@ -109,13 +74,13 @@ init_core() static bool move_up(piece, incr) register int piece; - register off_t incr; + register ind_t incr; { register struct memory *mem; extern char *sbrk(); debug("move_up(%d, %d)\n", piece, (int)incr, 0, 0); - if ((int)sbrk(incr) == -1) + if (incr != (int)incr || (int)sbrk((int)incr) == -1) return FALSE; for (mem = &mems[NMEMS - 1]; mem > &mems[piece]; mem--) @@ -137,33 +102,33 @@ extern int passnumber; static bool compact(piece, incr) register int piece; - register off_t incr; + register ind_t incr; { - register off_t gain; + register ind_t gain; register struct memory *mem; debug("compact(%d, %d)\n", piece, (int)incr, 0, 0); gain = mems[0].mem_left; - mems[0].mem_left = (off_t)0; + mems[0].mem_left = (ind_t)0; for (mem = &mems[1]; mem <= &mems[piece]; mem++) { /* Here memory is inserted before a piece. */ - assert(passnumber == FIRST || gain == (off_t)0); + assert(passnumber == FIRST || gain == (ind_t)0); copy_down(mem, gain); gain += mem->mem_left; - mem->mem_left = (off_t)0; + mem->mem_left = (ind_t)0; } /* * Note that we already added the left bytes of the piece we want to * enlarge to `gain'. */ if (gain < incr) { - register off_t up = (off_t)0; + register ind_t up = (ind_t)0; for (mem = &mems[NMEMS - 1]; mem > &mems[piece]; mem--) { /* Here memory is appended after a piece. */ up += mem->mem_left; copy_up(mem, up); - mem->mem_left = (off_t)0; + mem->mem_left = (ind_t)0; } gain += up; } @@ -180,11 +145,11 @@ compact(piece, incr) static copy_down(mem, dist) register struct memory *mem; - off_t dist; + ind_t dist; { register char *old; register char *new; - register off_t size; + register ind_t size; size = mem->mem_full; old = mem->mem_base; @@ -203,11 +168,11 @@ copy_down(mem, dist) static copy_up(mem, dist) register struct memory *mem; - off_t dist; + ind_t dist; { register char *old; register char *new; - register off_t size; + register ind_t size; size = mem->mem_full; old = mem->mem_base + size; @@ -224,18 +189,20 @@ copy_up(mem, dist) * how many times the area is moved, because of another allocate, this offset * remains valid. */ -off_t +ind_t alloc(piece, size) register int piece; - register off_t size; + register long size; { - register off_t incr = 0; - register off_t left = mems[piece].mem_left; - register off_t full = mems[piece].mem_full; + register ind_t incr = 0; + register ind_t left = mems[piece].mem_left; + register ind_t full = mems[piece].mem_full; assert(passnumber == FIRST || (!incore && piece == ALLOMODL)); - if (size == (off_t)0) + if (size == (long)0) return full; + if (size != (ind_t)size) + return BADOFF; while (left + incr < size) incr += INCRSIZE; @@ -254,14 +221,16 @@ alloc(piece, size) * Same as alloc() but for a piece which really needs it. If the first * attempt fails, release the space occupied by other pieces and try again. */ -off_t +ind_t hard_alloc(piece, size) - int piece; - off_t size; + register int piece; + register long size; { - off_t ret; + register ind_t ret; register int i; + if (size != (ind_t)size) + return BADOFF; if ((ret = alloc(piece, size)) != BADOFF) return ret; @@ -270,8 +239,6 @@ hard_alloc(piece, size) */ for (i = 0; i < NMEMS; i++) { switch (i) { - case ALLOHEAD: - case ALLOSECT: case ALLOGLOB: case ALLOGCHR: case ALLOSYMB: @@ -296,7 +263,7 @@ hard_alloc(piece, size) static free_saved_moduls() { - register off_t size; + register ind_t size; register char *old, *new; register struct memory *mem = &mems[ALLOMODL]; @@ -307,7 +274,7 @@ free_saved_moduls() *new++ = *old++; mem->mem_full -= core_position; mem->mem_left += core_position; - core_position = (off_t)0; + core_position = (ind_t)0; } /* @@ -320,22 +287,20 @@ dealloc(piece) /* * Some pieces need their memory throughout the program. */ - assert(piece != ALLOHEAD); - assert(piece != ALLOSECT); assert(piece != ALLOGLOB); assert(piece != ALLOGCHR); assert(piece != ALLOSYMB); assert(piece != ALLOARCH); mems[piece].mem_left += mems[piece].mem_full; - mems[piece].mem_full = (off_t)0; + mems[piece].mem_full = (ind_t)0; } char * core_alloc(piece, size) register int piece; - register off_t size; + register long size; { - register off_t off; + register ind_t off; if ((off = alloc(piece, size)) == BADOFF) return (char *)0; @@ -350,15 +315,13 @@ freeze_core() { register int i; - core_position = (off_t)0; + core_position = (ind_t)0; if (incore) return; for (i = 0; i < NMEMS; i++) { switch (i) { - case ALLOHEAD: - case ALLOSECT: case ALLOGLOB: case ALLOGCHR: case ALLOSYMB: @@ -369,7 +332,7 @@ freeze_core() break; } } - compact(NMEMS - 1, (off_t)0); + compact(NMEMS - 1, (ind_t)0); } /* ------------------------------------------------------------------------- */ @@ -383,24 +346,24 @@ extern bool words_reversed; */ write_bytes() { - register struct outhead *head; - ushort nsect, nrelo; - long offchar; - int fd; - register int piece; - extern ushort NLocals, NGlobals; - extern long NLChars, NGChars; - extern int flagword; - extern char *outputname; + ushort nsect, nrelo; + long offchar; + int fd; + register struct memory *mem; + extern ushort NLocals, NGlobals; + extern long NLChars, NGChars; + extern int flagword; + extern struct outhead outhead; + extern struct outsect outsect[]; + extern char *outputname; - head = (struct outhead *)mems[ALLOHEAD].mem_base; - nsect = head->oh_nsect; - nrelo = head->oh_nrelo; - offchar = OFF_CHAR(*head); + nsect = outhead.oh_nsect; + nrelo = outhead.oh_nrelo; + offchar = OFF_CHAR(outhead); if (bytes_reversed || words_reversed) { - headswap(); - sectswap(nsect); + swap((char *)&outhead, SF_HEAD); + sectswap(outsect, nsect); reloswap(nrelo); } /* @@ -423,8 +386,10 @@ write_bytes() /* * These pieces must always be written. */ - for (piece = ALLOHEAD; piece < ALLORELO; piece++) - writelong(fd, mems[piece].mem_base, mems[piece].mem_full); + writelong(fd, (char *)&outhead, (ind_t)SZ_HEAD); + writelong(fd, (char *)outsect, (ind_t)nsect * SZ_SECT); + for (mem = &mems[ALLOEMIT]; mem < &mems[ALLORELO]; mem++) + writelong(fd, mem->mem_base, mem->mem_full); /* * The rest depends on the flags. */ @@ -433,10 +398,10 @@ write_bytes() if (!(flagword & SFLAG)) { writelong(fd, mems[ALLOLOCL].mem_base, mems[ALLOLOCL].mem_full); writelong(fd, mems[ALLOGLOB].mem_base, mems[ALLOGLOB].mem_full); - writelong(fd, mems[ALLOLCHR].mem_base + 1, NLChars); - writelong(fd, mems[ALLOGCHR].mem_base + 1, NGChars); + writelong(fd, mems[ALLOLCHR].mem_base + 1, (ind_t)NLChars); + writelong(fd, mems[ALLOGCHR].mem_base + 1, (ind_t)NGChars); #ifdef SYMDBUG - writelong(fd, mems[ALLODBUG].mem_base, mems[ALLODBUG].mem_size); + writelong(fd, mems[ALLODBUG].mem_base, mems[ALLODBUG].mem_full); #endif SYMDBUG } close(fd); @@ -446,12 +411,12 @@ static writelong(fd, base, size) register int fd; register char *base; - register off_t size; + register ind_t size; { register int chunk; while (size) { - chunk = size > (off_t)MAXCHUNK ? MAXCHUNK : size; + chunk = size > (ind_t)MAXCHUNK ? MAXCHUNK : size; write(fd, base, chunk); size -= chunk; base += chunk; @@ -459,21 +424,10 @@ writelong(fd, base, size) } static -headswap() -{ - register struct outhead *head; - - head = (struct outhead *)mems[ALLOHEAD].mem_base; - swap((char *)head, SF_HEAD); -} - -static -sectswap(nsect) +sectswap(sect, nsect) + register struct outsect *sect; register ushort nsect; { - register struct outsect *sect; - - sect = (struct outsect *)mems[ALLOSECT].mem_base; while (nsect--) swap((char *)sect++, SF_SECT); } diff --git a/util/led/memory.h b/util/led/memory.h new file mode 100644 index 000000000..e78b065d3 --- /dev/null +++ b/util/led/memory.h @@ -0,0 +1,35 @@ +/* $Header$ */ + +#define ALLOEMIT 0 /* Section contents. */ +#define ALLORELO (ALLOEMIT + MAXSECT) /* Relocation table. */ +#define ALLOLOCL (ALLORELO + 1) /* Saved local names. */ +#define ALLOGLOB (ALLOLOCL + 1) /* Saved global names. */ +#define ALLOLCHR (ALLOGLOB + 1) /* Strings of local names. */ +#define ALLOGCHR (ALLOLCHR + 1) /* Strings of global names. */ +#ifdef SYMDEBUG +#define ALLODBUG (ALLOGCHR + 1) /* Symbolic debugging info. */ +#else SYMDEBUG +#define ALLODBUG ALLOGCHR +#endif SYMDEBUG +#define ALLOSYMB (ALLODBUG + 1) /* Symbol table. */ +#define ALLOARCH (ALLOSYMB + 1) /* Archive positions. */ +#define ALLOMODL (ALLOARCH + 1) /* Modules. */ +#define ALLORANL (ALLOMODL + 1) /* Ranlib information. */ +#define NMEMS (ALLORANL + 1) + +#define INCRSIZE 1024 + +typedef unsigned int ind_t; +#define BADOFF ((ind_t)-1) + +struct memory { + char *mem_base; + ind_t mem_full; + ind_t mem_left; +}; +extern struct memory mems[]; + +#define address(piece,offset) (mems[(piece)].mem_base+(offset)) +#define modulptr(offset) (mems[ALLOMODL].mem_base+core_position+(offset)) + +extern ind_t core_position; diff --git a/util/led/orig.h b/util/led/orig.h new file mode 100644 index 000000000..0fed9e974 --- /dev/null +++ b/util/led/orig.h @@ -0,0 +1,6 @@ +/* $Header$ */ + +struct orig { + long org_flen; /* Accumulated length of preceding sections. */ + long org_zero; /* " " " zeroparts. */ +}; diff --git a/util/led/read.c b/util/led/read.c new file mode 100644 index 000000000..f888a71a1 --- /dev/null +++ b/util/led/read.c @@ -0,0 +1,134 @@ +#ifndef lint +static char rcsid[] = "$Header$"; +#endif + +/* + * Routines to read in the various parts of the object file. + */ + +#include "arch.h" +#include "out.h" +#include "ranlib.h" +#include "const.h" +#include "assert.h" + +int infile; /* The current input file. */ + +extern bool bytes_reversed; +extern bool words_reversed; + +ushort +getushort() +{ + ushort ubuf; + + if (read(infile, (char *)&ubuf, 2) != 2) + fatal("premature EOF"); + if (bytes_reversed) + swap((char *)&ubuf, "2"); + return ubuf; +} + +long +getlong() +{ + long lbuf; + + if (read(infile, (char *)&lbuf, 4) != 4) + fatal("premature EOF"); + if (bytes_reversed || words_reversed) + swap((char *)&lbuf, "4"); + return lbuf; +} + +read_head(head) + register struct outhead *head; +{ + if (read(infile, (char *)head, SZ_HEAD) != SZ_HEAD) + fatal("premature EOF"); + if (bytes_reversed || words_reversed) + swap((char *)head, SF_HEAD); + if (BADMAGIC(*head)) + fatal("bad magic number"); +} + +/* + * Someone inadvertently misaligned a long, thereby creating a hole. + * Therefore we can't read the header in one chunk. + */ +read_arhdr(arhdr) + register struct ar_hdr *arhdr; +{ + if (read(infile, (char *)arhdr, 14) != 14) + fatal("premature EOF"); + if (read(infile, (char *)&arhdr->ar_date, SZ_ARCH - 14) != SZ_ARCH - 14) + fatal("premature EOF"); + if (bytes_reversed || words_reversed) + swap((char *)&arhdr->ar_date, SF_ARCH); +} + +read_table(ran, cnt) + register struct ranlib *ran; + register long cnt; +{ + read_char((char *)ran, cnt * SZ_RAN); + if (bytes_reversed || words_reversed) + while (cnt--) + swap((char *)ran++, SF_RAN); +} + +read_sect(sect, cnt) + register struct outsect *sect; + register ushort cnt; +{ + if (read(infile, (char *)sect, cnt * SZ_SECT) != cnt * SZ_SECT) + fatal("premature EOF"); + if (bytes_reversed || words_reversed) + while (cnt--) + swap((char *)sect++, SF_SECT); +} + +read_emit(emit, cnt) + register char *emit; + register long cnt; +{ + read_char(emit, cnt); +} + +read_relo(relo, cnt) + register struct outrelo *relo; + register ushort cnt; +{ + read_char((char *)relo, (long)cnt * SZ_RELO); + if (bytes_reversed || words_reversed) + while (cnt--) + swap((char *)relo++, SF_RELO); +} + +read_name(name, cnt) + register struct outname *name; + register ushort cnt; +{ + read_char((char *)name, (long)cnt * SZ_NAME); + if (bytes_reversed || words_reversed) + while (cnt--) + swap((char *)name++, SF_NAME); +} + +/* + * We don't have to worry about byte order here. + */ +read_char(string, cnt) + register char *string; + register long cnt; +{ + register int n; + + while (cnt) { + n = cnt >= MAXCHUNK ? MAXCHUNK : cnt; + if (read(infile, string, n) != n) + fatal("premature EOF"); + string += n; + cnt -= n; + } +} diff --git a/util/led/relocate.c b/util/led/relocate.c new file mode 100644 index 000000000..05d604822 --- /dev/null +++ b/util/led/relocate.c @@ -0,0 +1,256 @@ +#ifndef lint +static char rcsid[] = "$Header$"; +#endif + +#include "out.h" +#include "const.h" +#include "debug.h" +#include "defs.h" +#include "orig.h" + +#define UBYTE(x) ((x) & BYTEMASK) + +/* + * The bits in type indicate how many bytes the value occupies and what + * significance should be attributed to each byte. + */ +static long +getvalu(addr, type) + char addr[]; + char type; +{ + ushort word0, word1; + + switch (type & RELSZ) { + case RELO1: + return UBYTE(addr[0]); + case RELO2: + if (type & RELBR) + return (UBYTE(addr[0]) << WIDTH) + UBYTE(addr[1]); + else + return (UBYTE(addr[1]) << WIDTH) + UBYTE(addr[0]); + case RELO4: + if (type & RELBR) { + word0 = (UBYTE(addr[0]) << WIDTH) + UBYTE(addr[1]); + word1 = (UBYTE(addr[2]) << WIDTH) + UBYTE(addr[3]); + } else { + word0 = (UBYTE(addr[1]) << WIDTH) + UBYTE(addr[0]); + word1 = (UBYTE(addr[3]) << WIDTH) + UBYTE(addr[2]); + } + if (type & RELWR) + return ((long)word0 << (2 * WIDTH)) + word1; + else + return ((long)word1 << (2 * WIDTH)) + word0; + default: + fatal("bad relocation size"); + } + /* NOTREACHED */ +} + +/* + * The bits in type indicate how many bytes the value occupies and what + * significance should be attributed to each byte. + * We do not check for overflow. + */ +static +putvalu(valu, addr, type) + long valu; + char addr[]; + char type; +{ + ushort word0, word1; + + switch (type & RELSZ) { + case RELO1: + addr[0] = valu; + break; + case RELO2: + if (type & RELBR) { + addr[0] = valu >> WIDTH; + addr[1] = valu; + } else { + addr[0] = valu; + addr[1] = valu >> WIDTH; + } + break; + case RELO4: + if (type & RELWR) { + word0 = valu >> (2 * WIDTH); + word1 = valu; + } else { + word0 = valu; + word1 = valu >> (2 * WIDTH); + } + if (type & RELBR) { + addr[0] = word0 >> WIDTH; + addr[1] = word0; + addr[2] = word1 >> WIDTH; + addr[3] = word1; + } else { + addr[0] = word0; + addr[1] = word0 >> WIDTH; + addr[2] = word1; + addr[3] = word1 >> WIDTH; + } + break; + default: + fatal("bad relocation size"); + } +} + +/* + * Returns whether `valu' refers to the zero part of its section. + * The address of its zero part (relative to the beginning of the section) + * is in `zero_addr'. If `valu' is used in a pc-relative address computation, + * we have to do that computation ourselves. A pc-relative address is the + * difference between the address of the byte after the value and the "real" + * address: + * referencing address + its size + pc-relative address == "real" address. + */ +static bool +refers_zero(valu, relo, zero_addr) + register long valu; + struct outrelo *relo; + long zero_addr; +{ + if (relo->or_type & RELPC) { + valu += relo->or_addr; + /* + * Below is a dirty switch-statement. But an even dirtier + * statement would be: valu += (relo->or_type & RELSZ), + * because in that case you would have to know the values + * of the RELO[124] symbols. + */ + switch (relo->or_type & RELSZ) { + case RELO4: valu += 1; + valu += 1; + case RELO2: valu += 1; + case RELO1: valu += 1; + } + } + return valu >= zero_addr; +} + +extern ushort NLocals, NGlobals; +extern struct outsect outsect[]; +extern struct orig relorig[]; + +/* + * There are two cases: `local' is an undefined external or common name, + * or `local' is a section name. + * First case: if the name has been defined in another module, + * its value is known and can be added. Or_nami will be the + * index of the name of the section in which this name was + * defined. Otherwise we must change or_nami to the index of + * this name in the name table of the output file and leave + * its value unchanged. + * Second case: we must update the value by the change + * in position of the section of local. + */ +static ushort +addrelo(relo, names, sects, valu_out) + struct outrelo *relo; + struct outname *names; + struct outsect *sects; + long *valu_out; /* Out variable. */ +{ + register struct outname *local = &names[relo->or_nami]; + register ushort index = NLocals; + register long valu = *valu_out; + + if (ISUNDEFINED(local) || ISCOMMON(local)) { + register struct outname *name; + extern int hash(); + extern struct outname *searchname(); + extern ushort indexof(); + + name = searchname(local->on_mptr, hash(local->on_mptr)); + if (name == (struct outname *)0) + fatal("name %s not found in pass 2", local->on_mptr); + if (ISCOMMON(name) || ISUNDEFINED(name)) { + debug("can't relocate from %s\n",local->on_mptr,0,0,0); + index += indexof(name); + } else { + valu += name->on_valu; + index += NGlobals + (name->on_type & S_TYP) - S_MIN; + } + } else { + register int sectindex = (local->on_type & S_TYP) - S_MIN; + + if (!(local->on_type & S_SCT)) + fatal("bad relocation index"); + if (refers_zero(valu, relo, sects[sectindex].os_flen)) { + valu -= sects[sectindex].os_flen; + valu += outsect[sectindex].os_flen; + valu += relorig[sectindex].org_zero; + } else { + valu += relorig[sectindex].org_flen; + } + valu += outsect[sectindex].os_base; + index += NGlobals + sectindex; + } + *valu_out = valu; + return index; +} + +/* + * This routine relocates a value in a section pointed to by `emit', of + * which the header is pointed to by `head'. Relocation is relative to the + * names in `names'; `relo' tells how to relocate. + */ +relocate(head, emit, names, relo, sects) + struct outhead *head; + char *emit; + struct outname names[]; + struct outrelo *relo; + struct outsect *sects; +{ + long valu; + int sectindex = relo->or_sect - S_MIN; + extern struct outhead outhead; + + /* + * Pick up previous value at location to be relocated. + */ + valu = getvalu(emit + relo->or_addr, relo->or_type); + /* + * Or_nami is an index in the name table of the considered module. + * The name of which it is an index can be: + * - an undefined external or a common name + * - a section name + * - the first name outside! the name table (argh) + */ + if (relo->or_nami < head->oh_nname) { + /* First two cases. */ + relo->or_nami = addrelo(relo, names, sects, &valu); + } else { + /* + * Third case: it is absolute. The relocation of absolute + * names is always 0. We only need to change the index. + */ + relo->or_nami = NLocals + NGlobals + outhead.oh_nsect; + } + + /* + * If relocation is pc-relative, we had to update the value by + * the change in distance between the referencING and referencED + * section. We already added the origin of the referencED section; + * now we subtract the origin of the referencING section. + * Note that the the value to be relocated cannot lie within the + * zero part. + */ + if (relo->or_type & RELPC) + valu -= relorig[sectindex].org_flen+outsect[sectindex].os_base; + + /* + * Now put the value back. + */ + putvalu(valu, emit + relo->or_addr, relo->or_type); + + /* + * We must change the offset within the section of the value to be + * relocated to its offset in the new section. `Or_addr' must again be + * in the normal part, of course. + */ + relo->or_addr += relorig[sectindex].org_flen; +} diff --git a/util/led/save.c b/util/led/save.c new file mode 100644 index 000000000..807c79e69 --- /dev/null +++ b/util/led/save.c @@ -0,0 +1,104 @@ +#ifndef lint +static char rcsid[] = "$Header$"; +#endif + +/* + * If everything is kept in core, we must save some things for the second pass. + */ + +#include "arch.h" +#include "out.h" +#include "const.h" +#include "assert.h" +#include "memory.h" + +extern bool incore; +extern char *core_alloc(); + +savemagic() +{ + register char *p; + + if (!incore) + return; + + if ((p = core_alloc(ALLOMODL, (long)sizeof(ushort))) != (char *)0) { + *(ushort *)p = ARMAG; + core_position += sizeof(ushort); + } +} + +savehdr(hdr) + struct ar_hdr *hdr; +{ + register char *p; + + if (!incore) + return; + + if ((p=core_alloc(ALLOMODL,(long)sizeof(struct ar_hdr)))!=(char *)0) { + *(struct ar_hdr *)p = *hdr; + core_position += sizeof(struct ar_hdr); + } +} + +long NLChars = 0; /* Size of string area for local names. */ +long NGChars = 0; /* Idem for global names. */ + +/* + * Put the string in cp into the block allocated for the string area. + * Return its offset in this area. We don't use the first char of the string + * area, so that empty strings can be distinguished from the first string. + */ +ind_t +savechar(piece, off) + register int piece; + register ind_t off; +{ + register long len; + register ind_t newoff; + extern int strlen(); + extern ind_t alloc(); + extern ind_t hard_alloc(); + extern char *strcpy(); + + if (off == (ind_t)0) + return 0; + + len = strlen(modulptr(off)) + 1; + if (piece == ALLOLCHR) { + NLChars += len; + if (!incore || (newoff = alloc(piece, len)) == BADOFF) + return BADOFF; + } else { + assert(piece == ALLOGCHR); + NGChars += len; + if ((newoff = hard_alloc(piece, len)) == BADOFF) + return BADOFF; + } + strcpy(address(piece, newoff), modulptr(off)); + return newoff; +} + +/* + * Put the local in `name' in the piece allocated for local names that must + * be saved. `Name' points to a private copy, so will not become invalid after + * allocation, but the string of which name->on_foff is the offset may be + * destroyed, so we save that first. + */ +savelocal(name) + struct outname *name; +{ + ind_t savindex; + struct outname *new; + + if ((savindex = savechar(ALLOLCHR, (ind_t)name->on_foff)) == BADOFF) + return; + + new = (struct outname *) + core_alloc(ALLOLOCL, (long)sizeof(struct outname)); + if (new != (struct outname *)0) { + *new = *name; + new->on_foff = savindex; + } +} diff --git a/util/led/scan.c b/util/led/scan.c new file mode 100644 index 000000000..32ed1efde --- /dev/null +++ b/util/led/scan.c @@ -0,0 +1,524 @@ +#ifndef lint +static char rcsid[] = "$Header$"; +#endif + +#ifdef SYMDBUG +#include +#include +#endif SYMDBUG +#include "arch.h" +#include "out.h" +#include "ranlib.h" +#include "const.h" +#include "assert.h" +#include "memory.h" +#include "scan.h" + +#define READ 0 + +#define IND_EMIT(x) (IND_CHAR(x) + (ind_t)align((x).oh_nchar)) +#define IND_RELO(x) (IND_EMIT(x) + (x).oh_nsect * sizeof(ind_t)) +#ifdef SYMDBUG +#define IND_DBUG(x) (IND_RELO(x) + sizeof(ind_t)) +#endif SYMDBUG + +extern long lseek(); +extern bool incore; +extern int infile; +extern int passnumber; + +char *archname; /* Name of archive, if reading from archive. */ +char *modulname; /* Name of object module. */ +long position; /* Byte offset within cuurent input file. */ +#ifdef SYMDBUG +long objectsize; +#endif SYMDBUG + +static long align(); +static char *modulbase; +static long modulsize(); + +/* + * Open the file with name `filename' (if necessary) and examine the first + * few bytes to see if it's a plain file or an archive. + * In case of a plain file, the file pointer is repositioned after the + * examination. Otherwise it is at the beginning of the table of contents. + */ +int +getfile(filename) + char *filename; +{ + struct ar_hdr archive_header; + ushort magic_number; +#ifdef SYMDBUG + struct stat statbuf; + extern int fstat(); +#endif SYMDBUG + extern ushort getushort(); + + archname = (char *)0; + modulname = (char *)0; + + if (passnumber == FIRST || !incore) { + if ((infile = open(filename, READ)) < 0) + fatal("can't read %s", filename); + magic_number = getushort(); + } else { + modulbase = modulptr((ind_t)0); + magic_number = *(ushort *)modulbase; + } + + switch (magic_number) { + case O_MAGIC: +#ifdef SYMDBUG + if (passnumber == FIRST || !incore) { + if (fstat(infile, &statbuf) < 0) + fatal("cannot stat"); + objectsize = statbuf.st_size; + } +#endif SYMDBUG + position = (long)0; + seek((long)0); + modulname = filename; + return PLAIN; + case ARMAG: + archname = filename; + if (passnumber == FIRST) { + read_arhdr(&archive_header); + if (strcmp(archive_header.ar_name, SYMDEF)) + fatal("no table of contents"); + } else if (incore) { + modulbase += sizeof(ushort); + core_position += sizeof(ushort); + } + return ARCHIVE; + default: + fatal("wrong magic number"); + } + /* NOTREACHED */ +} + +/* ARGSUSED */ +closefile(filename) + char *filename; +{ + if (passnumber == FIRST || !incore) + close(infile); +} + +get_archive_header(archive_header) + register struct ar_hdr *archive_header; +{ + if (passnumber == FIRST || !incore) { + read_arhdr(archive_header); + } else { + /* Copy structs. */ + *archive_header = *(struct ar_hdr *)modulbase; + modulbase += sizeof(struct ar_hdr); + core_position += sizeof(struct ar_hdr); + } +#ifdef SYMDBUG + objectsize = archive_header.ar_size; +#endif SYMDBUG +} + +get_modul() +{ + if (passnumber == FIRST) { + scan_modul(); + } else if (!incore) { + read_modul(); + } +} + +/* + * Read module from the current file. If it doesn't fit into core, the strategy + * to keep everything in core is abandoned, but we will always put the header, + * the section table, and the name and string table into core. + */ +static +scan_modul() +{ + bool space; + struct outhead *head; + struct outsect *sect; + + space = all_alloc(); + head = (struct outhead *)modulptr(IND_HEAD); + if (space) { + sect = (struct outsect *)modulptr(IND_SECT(*head)); + get_indirect(head, sect); + } else { + lseek(infile, OFF_NAME(*head) - OFF_EMIT(*head), 1); + } + read_name((struct outname *)modulptr(IND_NAME(*head)), head->oh_nname); + read_char((char *)modulptr(IND_CHAR(*head)), head->oh_nchar); +#ifdef SYMDBUG + if (space) { + get_dbug(*(ind_t *)modulptr(IND_DBUG(*head)), + ojectsize - OFF_DBUG(*head) + ); + } +#endif SYMDBUG +} + +/* + * Allocate space for and read in the header and section table. + * First get the header. With this we can determine what to allocate + * for the rest of the module, and with the rest we can determine what + * to allocate for the section contents. + * If possible, allocate space for the rest of the module. Return whether + * this was possible. + */ +static bool +all_alloc() +{ + struct outhead head; + extern ind_t hard_alloc(); + + if (hard_alloc(ALLOMODL, (long)sizeof(struct outhead)) == BADOFF) + fatal("no space for module header"); + read_head((struct outhead *)modulptr(IND_HEAD)); + /* + * Copy the header because we need it so often. + */ + head = *(struct outhead *)modulptr(IND_HEAD); + return direct_alloc(&head) && indirect_alloc(&head); +} + +/* + * Allocate space for the rest of the direct bytes. + * First allocate the section table and read it in, then allocate the rest + * and return whether this succeeded. + */ +static bool +direct_alloc(head) + struct outhead *head; +{ + ind_t sectindex = IND_SECT(*head); + ushort nsect = head->oh_nsect; + long size, rest; + extern ind_t hard_alloc(); + extern ind_t alloc(); + +#ifdef SYMDBUG + rest = nsect * sizeof(ind_t) + sizeof(ind_t) + sizeof(ind_t); +#else SYMDBUG + rest = nsect * sizeof(ind_t) + sizeof(ind_t); +#endif SYMDBUG + /* + * We already allocated space for the header, we now need + * the section, name an string table. + */ + size = modulsize(head) - sizeof(struct outhead) - rest; + if (hard_alloc(ALLOMODL, size) == BADOFF) + fatal("no space for module"); + read_sect((struct outsect *)modulptr(sectindex), nsect); + + return incore && alloc(ALLOMODL, rest) != BADOFF; +} + +/* + * Allocate space for the indirectly accessed pieces: the section contents and + * the relocation table, and put their indices in the right place. + */ +static bool +indirect_alloc(head) + struct outhead *head; +{ + register int allopiece; + ushort nsect = head->oh_nsect; + ushort nrelo = head->oh_nrelo; + ind_t sectindex = IND_SECT(*head); + ind_t emitoff = IND_EMIT(*head); + ind_t relooff = IND_RELO(*head); +#ifdef SYMDBUG + ind_t dbugoff = IND_DBUG(*head); + extern long objectsize; + long dbugsize = objectsize - OFF_DBUG(*head); +#endif SYMDBUG + + assert(incore); + for (allopiece = ALLOEMIT; allopiece < ALLOEMIT + nsect; allopiece++) { + if (!putemitindex(sectindex, emitoff, allopiece)) + return FALSE; + sectindex += sizeof(struct outsect); + emitoff += sizeof(ind_t); + } +#ifdef SYMDBUG + return putreloindex(relooff, (long)nrelo * sizeof(struct outrelo)) + && + putdbugindex(dbugoff, dbugsize); +#else SYMDBUG + return putreloindex(relooff, (long)nrelo * sizeof(struct outrelo)); +#endif SYMDBUG +} + +/* + * Allocate space for the contents of the section of which the table entry is + * at offset `sectindex'. Put the offset of the allocated piece at offset + * `emitoff'. + */ +static bool +putemitindex(sectindex, emitoff, allopiece) + ind_t sectindex; + ind_t emitoff; + int allopiece; +{ + long flen; + ind_t emitindex; + extern ind_t alloc(); + + flen = ((struct outsect *)modulptr(sectindex))->os_flen; + if ((emitindex = alloc(allopiece, flen)) != BADOFF) { + *(ind_t *)modulptr(emitoff) = emitindex; + return TRUE; + } + return FALSE; +} + +/* + * Allocate space for a relocation table with `nrelobytes' bytes, and put the + * offset at `relooff'. + */ +static bool +putreloindex(relooff, nrelobytes) + ind_t relooff; + long nrelobytes; +{ + ind_t reloindex; + extern ind_t alloc(); + + if ((reloindex = alloc(ALLORELO, nrelobytes)) != BADOFF) { + *(ind_t *)modulptr(relooff) = reloindex; + return TRUE; + } + return FALSE; +} +#ifdef SYMDBUG +/* + * Allocate space for debugging information and put the offset at `dbugoff'. + */ +static bool +putdbugindex(dbugoff, ndbugbytes) + ind_t relooff; + long ndbugbytes; +{ + ind_t dbugindex; + extern ind_t alloc(); + + if ((dbugindex = alloc(ALLORELO, ndbugbytes)) != BADOFF) { + *(ind_t *)modulptr(dbugoff) = dbugindex; + return TRUE; + } + return FALSE; +} +#endif SYMDBUG + +/* + * Compute addresses and read in. Remember that the contents of the sections + * and also the relocation table are accessed indirectly. + */ +static +get_indirect(head, sect) + register struct outhead *head; + register struct outsect *sect; +{ + register ind_t *emitindex; + register int nsect; + register int piece; + ind_t *reloindex; + + emitindex = (ind_t *)modulptr(IND_EMIT(*head)); + nsect = head->oh_nsect; piece = ALLOEMIT; + while (nsect--) { + read_emit(address(piece, *emitindex), sect->os_flen); + piece++; emitindex++; sect++; + } + reloindex = (ind_t *)modulptr(IND_RELO(*head)); + read_relo((struct outrelo *)address(ALLORELO, *reloindex), + head->oh_nrelo + ); +} + +/* + * Set the file pointer at `pos'. + */ +seek(pos) + long pos; +{ + if (passnumber == FIRST || !incore) + lseek(infile, pos, 0); +} + +/* + * A file pointer is advanced automatically when reading, a char pointer + * is not. That's why we do it here. If we don't keep everything in core, + * we give the space allocated for a module back. + */ +skip_modul(head) + struct outhead *head; +{ + register ind_t skip = modulsize(head); + + if (incore) { + core_position += skip; + if (passnumber == SECOND) + modulbase += skip; + } else { + dealloc(ALLOMODL); + core_position = (ind_t)0; + } +} + +/* + * Read in what we need in pass 2, because we couldn't keep it in core. + */ +static +read_modul() +{ + struct outhead *head; + struct outsect *sects; + struct outname *names; + char *chars; + ind_t sectindex, nameindex, charindex; + ushort nsect, nname; + long size; + long nchar; + long skip; + extern ind_t hard_alloc(); + + assert(passnumber == SECOND); + assert(!incore); + if (hard_alloc(ALLOMODL, (long)sizeof(struct outhead)) == BADOFF) + fatal("no space for module header"); + head = (struct outhead *)modulptr(IND_HEAD); + read_head(head); + nsect = head->oh_nsect; sectindex = IND_SECT(*head); + nname = head->oh_nname; nameindex = IND_NAME(*head); + nchar = head->oh_nchar; charindex = IND_CHAR(*head); + skip = OFF_NAME(*head) - OFF_EMIT(*head); +#ifdef SYMDBUG + size = modulsize(head) - (nsect * sizeof(ind_t) + 2 * sizeof(ind_t)); +#else SYMDBUG + size = modulsize(head) - (nsect * sizeof(ind_t) + sizeof(ind_t)); +#endif SYMDBUG + if (hard_alloc(ALLOMODL, size) == BADOFF) + fatal("no space for module"); + + sects = (struct outsect *)modulptr(sectindex); + names = (struct outname *)modulptr(nameindex); + chars = modulptr(charindex); + + read_sect(sects, nsect); + lseek(infile, skip, 1); + read_name(names, nname); + read_char(chars, nchar); +} + +/* + * Align `size' to a multiple of the size of a double. + * This is assumed to be a power of 2. + */ +static long +align(size) + register long size; +{ + size += sizeof(double) - 1; + return size - (size & (sizeof(double) - 1)); +} + +/* + * Compute how many DIRECT bytes must be allocated for a module of which the + * header is pointed to by `head': + * 0. the header, + * 1. the section table, + * 2. the name table, + * 3. the string table, + * 4. for each section the offset of its contents, + * 5. the offset of the relocation table. +#ifdef SYMDBUG + * 6. the offset of the debugging information. +#endif SYMDBUG + */ +static long +modulsize(head) + register struct outhead *head; +{ + return sizeof(struct outhead) + /* 0 */ + head->oh_nsect * sizeof(struct outsect) + /* 1 */ + head->oh_nname * sizeof(struct outname) + /* 2 */ + align(head->oh_nchar) + /* 3 */ + head->oh_nsect * sizeof(ind_t) + /* 4 */ +#ifdef SYMDBUG + sizeof(ind_t) + /* 5 */ + sizeof(ind_t); /* 6 */ +#else SYMDBUG + sizeof(ind_t); /* 5 */ +#endif SYMDBUG +} + +/* ------------------------------------------------------------------------- */ + +/* + * Walk through the relocation table of the current module. We must either walk + * through core or through file. Startrelo() should be called first. + */ + +static struct outrelo *walkrelo; + +startrelo(head) + struct outhead *head; +{ + ind_t reloindex; + + if (incore) { + reloindex = *(ind_t *)(modulbase + IND_RELO(*head)); + walkrelo = (struct outrelo *)address(ALLORELO, reloindex); + } else + lseek(infile, position + OFF_RELO(*head), 0); +} + +struct outrelo * +nextrelo() +{ + static struct outrelo relobuf; + + if (incore) + return walkrelo++; + + read_relo(&relobuf, (ushort)1); + return &relobuf; +} + +/* ------------------------------------------------------------------------- */ + +/* + * Get the section contents in core of which the describing struct has index + * `sectindex'. `Head' points to the header of the module. + */ +char * +getemit(head, sects, sectindex) + struct outhead *head; + struct outsect *sects; + int sectindex; +{ + char *ret; + ind_t off; + extern char *core_alloc(); + + if (!incore) { + ret = core_alloc(ALLOMODL, sects[sectindex].os_flen); + if (ret == (char *)0) + fatal("no space for section contents"); + lseek(infile, position + sects[sectindex].os_foff, 0); + read_emit(ret, sects[sectindex].os_flen); + return ret; + } + /* + * We have an offset in the contents of the final output + * "file" where normally the contents would be. + */ + off = *((ind_t *)(modulbase + IND_EMIT(*head)) + sectindex); + return address(ALLOEMIT + sectindex, off); +} diff --git a/util/led/scan.h b/util/led/scan.h new file mode 100644 index 000000000..a35b015b4 --- /dev/null +++ b/util/led/scan.h @@ -0,0 +1,13 @@ +/* $Header$ */ + +/* + * Offsets of the pieces of the input module in core. + */ + +#define IND_HEAD ((ind_t)0) +#define IND_SECT(x) (IND_HEAD + sizeof(struct outhead)) +#define IND_NAME(x) (IND_SECT(x) + (x).oh_nsect * sizeof(struct outsect)) +#define IND_CHAR(x) (IND_NAME(x) + (x).oh_nname * sizeof(struct outname)) +#ifdef SYMDBUG +#define OFF_DBUG(x) (OFF_CHAR(x) + (x).oh_nchar) +#endif SYMDBUG diff --git a/util/led/sym.c b/util/led/sym.c new file mode 100644 index 000000000..b257fba6b --- /dev/null +++ b/util/led/sym.c @@ -0,0 +1,132 @@ +#ifndef lint +static char rcsid[] = "$Header$"; +#endif + +/* + * Symbol table management. + */ + +#include "out.h" +#include "const.h" +#include "memory.h" + +/* + * Symbol table types. Each hash table entry contains the offset of a symbol + * struct. `Sy_name' contains the offset the name in the piece of global + * names. `Sy_next' contains the offset of the next symbol of which the + * corresponding name has the same hash value. + */ +struct symbol { + ind_t sy_name; + ind_t sy_next; +}; + +#define NHASH 256 /* Size of hash table. Should be even. */ + +static ind_t hashtable[NHASH]; + +/* + * Initialize the symbol table. All indices should be noticeably invalid. + */ +init_symboltable() +{ + register ind_t *rap; + + for (rap = hashtable; rap < &hashtable[NHASH]; rap++) + *rap = BADOFF; +} + +/* + * Search for `string' in the symboltable. The hash value of `string' is in + * `hashval'. The linked list belonging to the entry of hashval + * in the hash table is followed. If the names match, a pointer to the outname + * in this element of the list is returned. When a match cannot be found, + * NIL is returned. + */ +struct outname * +searchname(string, hashval) + char *string; + int hashval; +{ + register char *rcp; + register char *namestring; + register ind_t symindex; + register struct outname *name; + register struct symbol *sym; + + symindex = hashtable[hashval]; + while (symindex != BADOFF) { + sym = (struct symbol *)address(ALLOSYMB, symindex); + name = (struct outname *)address(ALLOGLOB, sym->sy_name); + namestring = address(ALLOGCHR, (ind_t)name->on_foff); + rcp = string; + while (*rcp == *namestring++) + if (*rcp++ == '\0') + return name; + symindex = sym->sy_next; + } + /* Not found. */ + return (struct outname *)0; +} + +/* + * Enter a new name in the symbol table. We must copy everything to a + * new entry. `Name' is a private copy, i.e. the pointer to it will not be + * destroyed by allocation. However, the string of which name->on_foff is the + * offset can be destroyed, so we save it first. + */ +entername(name, hashval) + struct outname *name; + int hashval; +{ + ind_t savindex; + ind_t symindex; + ind_t namindex; + struct symbol *sym; + struct outname *newname; + extern ind_t savechar(); + extern ind_t hard_alloc(); + + savindex = savechar(ALLOGCHR, (ind_t)name->on_foff); + symindex = hard_alloc(ALLOSYMB, (long)sizeof(struct symbol)); + namindex = hard_alloc(ALLOGLOB, (long)sizeof(struct outname)); + if (savindex == BADOFF || symindex == BADOFF || namindex == BADOFF) + fatal("symbol table overflow"); + sym = (struct symbol *)address(ALLOSYMB, symindex); + sym->sy_name = namindex; + newname = (struct outname *)address(ALLOGLOB, namindex); + *newname = *name; + newname->on_foff = savindex; + sym->sy_next = hashtable[hashval]; + hashtable[hashval] = symindex; +} + +/* + * Return the index of `name' in the symbol table in the order in which + * it was entered. We need a REAL index, not a byte offset. + */ +ushort +indexof(name) + struct outname *name; +{ + return name - (struct outname *)address(ALLOGLOB, (ind_t)0); +} + +/* + * Assign an integer to the string in p. + * 0 <= hash(p) < NHASH, so it can - and will - be used + * as index in a hash table. + */ +int +hash(p) + register char *p; +{ + register unsigned int h = 0; + register int c; + + while (c = *p++) { + h <<= 2; + h += c; + } + return h & (NHASH - 1); +} diff --git a/util/led/write.c b/util/led/write.c new file mode 100644 index 000000000..bb4014dcc --- /dev/null +++ b/util/led/write.c @@ -0,0 +1,297 @@ +#ifndef lint +static char rcsid[] = "$Header$"; +#endif + +/* + * You can choose between two strategies: + * - Open the output file several times, once for each logical part, and + * write to it in multiple places. + * - Open the output file once and seek back and forth to each logical + * part. In this case #define OUTSEEK. + */ + +#include +#include "out.h" +#include "const.h" +#include "assert.h" +#include "memory.h" +#include "orig.h" + +extern long lseek(); + +#define WRITE 1 /* Argument to open(). */ + +/* + * Parts of the output file. + */ +#define PARTEMIT 0 +#define PARTRELO 1 +#define PARTNAME 2 +#define PARTCHAR 3 +#ifdef SYMDBUG +#define PARTDBUG 4 +#else SYMDBUG +#define PARTDBUG PARTCHAR +#endif SYMDBUG +#define NPARTS (PARTDBUG + 1) + +/* + * Call OUTPART() with the part you want to write on as argument, before + * you call OUTWRITE(). + */ +static int outpart = NPARTS; + +#ifdef OUTSEEK + +static int outfile; +static long outseek[NPARTS]; + +#define OUTPART(p) \ + { if (outpart != (p)) {\ + outpart = (p);\ + lseek(outfile, outseek[(p)], 0);\ + }\ + } +#define OUTSECT(i) \ + { outpart = NPARTS;\ + outseek[PARTEMIT] =\ + outsect[(i)].os_foff + relorig[(i)].org_flen;\ + } +#define OUTWRITE(b, n) \ + { if (write(outfile, (b), (n)) != (n))\ + fatal("write error");\ + outseek[outpart] += (n);\ + } +#define BEGINSEEK(p, o) \ + { outseek[(p)] = (o);\ + } + +#else OUTSEEK + +static int outfile[NPARTS]; + +#define OUTPART(p) \ + { outpart = (p);\ + } +#define OUTSECT(i) \ + { lseek( outfile[PARTEMIT],\ + outsect[(i)].os_foff + relorig[(i)].org_flen,\ + 0\ + );\ + } +#define OUTWRITE(b, n) \ + { if (write(outfile[outpart], (b), (n)) != (n))\ + fatal("write error");\ + } +#define BEGINSEEK(p, o) \ + { lseek(outfile[(p)], (o), 0);\ + } + +#endif OUTSEEK + +extern struct outhead outhead; +extern struct outsect outsect[]; +extern int flagword; +extern struct orig relorig[]; +extern bool bytes_reversed, words_reversed; +extern bool incore; + + +static long offchar; + +/* + * Open the output file according to the chosen strategy. + * Write away the header and section table: they will not change anymore. + */ +begin_write() +{ + register long off; + + openoutput(); + BEGINSEEK(PARTEMIT, (long)0); + wrt_head(&outhead); + wrt_sect(outsect, outhead.oh_nsect); + + off = SZ_HEAD + (long)outhead.oh_nsect * SZ_SECT + outhead.oh_nemit; + + if (flagword & RFLAG) { + /* A relocation table will be produced. */ + BEGINSEEK(PARTRELO, off); + off += (long)outhead.oh_nrelo * SZ_RELO; + } + + if (flagword & SFLAG) + return; + + /* A name table will be produced. */ + BEGINSEEK(PARTNAME, off); + off += (long)outhead.oh_nname * SZ_NAME; + BEGINSEEK(PARTCHAR, off); + offchar = off; /* See wrt_name(). */ +#ifdef SYMDBUG + off += outhead.oh_nchar; + BEGINSEEK(PARTDBUG, off); +#endif SYMDBUG +} + +static +openoutput() +{ +#ifndef OUTSEEK + register int *fdp; +#endif OUTSEEK + extern char *outputname; + + close(creat(outputname, 0666)); +#ifdef OUTSEEK + if ((outfile = open(outputname, WRITE)) < 0) + fatal("can't write %s", outputname); +#else OUTSEEK + for (fdp = &outfile[PARTEMIT]; fdp < &outfile[NPARTS]; fdp++) + if ((*fdp = open(outputname, WRITE)) < 0) + fatal("can't write %s", outputname); +#endif OUTSEEK +} + +static struct outname * +sectname(sectindex) + int sectindex; +{ + static struct outname namebuf; + + namebuf.on_foff = (long)0; /* No string name. */ + namebuf.on_type = (S_MIN + sectindex) | S_SCT; + namebuf.on_desc = 0; + namebuf.on_valu = outsect[sectindex].os_base; + + return &namebuf; +} + +/* + * Write out the symbol table and the section names. + */ +end_write() +{ + register ushort cnt; + register struct outname *name; + register int sectindex; + extern ushort NGlobals; + + assert(!incore); + assert(!(flagword & SFLAG)); + cnt = NGlobals; + name = (struct outname *)address(ALLOGLOB, (ind_t)0); + while (cnt--) { + if (name->on_foff != (long)0) { + name->on_mptr = address(ALLOGCHR, (ind_t)name->on_foff); + } else { + name->on_mptr = (char *)0; + } + wrt_name(name); + name++; + } + + for (sectindex = 0; sectindex < outhead.oh_nsect; sectindex++) + wrt_name(sectname(sectindex)); +} + +static +wrt_head(head) + register struct outhead *head; +{ + assert(!incore); + OUTPART(PARTEMIT); + if (bytes_reversed || words_reversed) + swap((char *)head, SF_HEAD); + OUTWRITE((char *)head, SZ_HEAD); + /* + * Swap back because we will need it again. + */ + if (bytes_reversed || words_reversed) + swap((char *)head, SF_HEAD); +} + +static +wrt_sect(sect, cnt) + register struct outsect *sect; + register ushort cnt; +{ + assert(!incore); + OUTPART(PARTEMIT); + while (cnt--) { + if (bytes_reversed || words_reversed) + swap((char *)sect, SF_SECT); + OUTWRITE((char *)sect, SZ_SECT); + /* + * Swap back because we will need it again. + */ + if (bytes_reversed || words_reversed) + swap((char *)sect, SF_SECT); + sect++; + } +} + +/* + * We don't have to worry about byte order here. + */ +wrt_emit(emit, sectindex, cnt) + register char *emit; + int sectindex; + register long cnt; +{ + register int n; + + assert(!incore); + OUTPART(PARTEMIT); + OUTSECT(sectindex); + while (cnt) { + n = cnt >= BUFSIZ ? BUFSIZ : cnt; + OUTWRITE(emit, n); + emit += n; + cnt -= n; + } +} + +wrt_relo(relo) + register struct outrelo *relo; +{ + assert(!incore); + assert(flagword & RFLAG); + OUTPART(PARTRELO); + if (bytes_reversed || words_reversed) + swap((char *)relo, SF_RELO); + OUTWRITE((char *)relo, SZ_RELO); +} + +wrt_name(name) + register struct outname *name; +{ + assert(!incore); + assert(!(flagword & SFLAG)); + if (name->on_mptr != (char *)0) { + register int len = strlen(name->on_mptr) + 1; + + OUTPART(PARTCHAR); + OUTWRITE(name->on_mptr, len); + name->on_foff = offchar; + offchar += len; + } else { + name->on_foff = (long)0; + } + OUTPART(PARTNAME); + if (bytes_reversed || words_reversed) + swap((char *)name, SF_NAME); + OUTWRITE((char *)name, SZ_NAME); +} +#ifdef SYMDBUG + +wrt_dbug(buf, size) + char *buf; + int size; +{ + assert(!incore); + assert(!(flagword & SFLAG)); + OUTPART(PARTDBUG); + OUTWRITE((char *)buf, size); +} +#endif SYMDBUG