|
@@ -0,0 +1,524 @@
|
|
|
+#ifndef lint
|
|
|
+static char rcsid[] = "$Header$";
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef SYMDBUG
|
|
|
+#include <sys/types.h>
|
|
|
+#include <sys/stat.h>
|
|
|
+#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);
|
|
|
+}
|