ack/util/led/scan.c
2017-08-06 11:58:36 +02:00

609 lines
15 KiB
C

/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
#ifndef lint
static char rcsid[] = "$Id$";
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#ifdef SYMDBUG
#endif /* SYMDBUG */
#include "arch.h"
#include "out.h"
#include "ranlib.h"
#include "object.h"
#include "const.h"
#include "assert.h"
#include "memory.h"
#include "scan.h"
#include "debug.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 char *core_alloc();
extern bool incore;
extern int infile;
extern int passnumber;
char *archname; /* Name of archive, if reading from archive. */
char *modulname; /* Name of object module. */
#ifdef SYMDBUG
long objectsize;
#endif /* SYMDBUG */
static long align(long size);
static char *modulbase;
static long modulsize(struct outhead* head);
static void can_modul(void);
static bool all_alloc(void);
static bool direct_alloc(struct outhead* head);
static bool indirect_alloc(struct outhead* head);
static bool putemitindex(ind_t sectindex, ind_t emitoff, int allopiece);
static bool putreloindex(ind_t relooff, long nrelobytes);
#ifdef SYMDBUG
static bool putdbugindex(ind_t dbugoff, long ndbugbytes);
#endif /* SYMDBUG */
static void get_indirect(struct outhead* head, struct outsect* sect);
static void read_modul(void);
static void scan_modul(void);
/*
* 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;
{
unsigned int rd_unsigned2();
struct ar_hdr archive_header;
unsigned short magic_number;
#ifdef SYMDBUG
struct stat statbuf;
extern int fstat();
#endif /* SYMDBUG */
archname = (char *)0;
modulname = (char *)0;
if (passnumber == FIRST || !incore) {
if ((infile = open(filename, READ)) < 0)
fatal("can't read %s", filename);
magic_number = rd_unsigned2(infile);
} else {
modulbase = modulptr((ind_t)0);
magic_number = *(unsigned short *)modulbase;
}
switch (magic_number) {
case O_MAGIC:
#ifdef SYMDBUG
if (passnumber == FIRST || !incore) {
if (fstat(infile, &statbuf) < 0)
fatal("cannot stat %s", filename);
objectsize = statbuf.st_size;
}
#endif /* SYMDBUG */
seek((long)0);
modulname = filename;
return PLAIN;
case ARMAG:
case AALMAG:
archname = filename;
if (passnumber == FIRST) {
rd_arhdr(infile, &archive_header);
if (strcmp(archive_header.ar_name, SYMDEF))
fatal("%s: no table of contents", filename);
} else if (incore) {
modulbase += sizeof(int);
core_position += sizeof(int);
}
return ARCHIVE;
default:
fatal("%s: wrong magic number", filename);
}
/* NOTREACHED */
}
void closefile(char* filename)
{
if (passnumber == FIRST || !incore)
close(infile);
}
void get_archive_header(struct ar_hdr* archive_header)
{
if (passnumber == FIRST || !incore) {
rd_arhdr(infile, archive_header);
} else {
/* Copy structs. */
*archive_header = *(struct ar_hdr *)modulbase;
modulbase += int_align(sizeof(struct ar_hdr));
core_position += int_align(sizeof(struct ar_hdr));
}
#ifdef SYMDBUG
objectsize = archive_header.ar_size;
#endif /* SYMDBUG */
}
void get_modul(void)
{
if (passnumber == FIRST) {
rd_fdopen(infile);
scan_modul();
} else if (!incore) {
rd_fdopen(infile);
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 void
scan_modul(void)
{
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);
}
rd_name((struct outname *)modulptr(IND_NAME(*head)), head->oh_nname);
rd_string((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(void)
{
struct outhead head;
extern ind_t hard_alloc();
if (hard_alloc(ALLOMODL, (long)sizeof(struct outhead)) == BADOFF)
fatal("no space for module header");
rd_ohead((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);
register struct outsect *sects;
unsigned short 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");
rd_sect(sects = ((struct outsect *)modulptr(sectindex)), nsect);
while (nsect--) {
if (sects->os_lign > 1) {
sects->os_size += sects->os_lign - 1;
sects->os_size -= sects->os_size % sects->os_lign;
}
sects++;
}
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;
unsigned short nsect = head->oh_nsect;
unsigned short 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(ind_t sectindex, ind_t emitoff, int allopiece)
{
long flen;
ind_t emitindex;
extern ind_t alloc();
static long zeros[MAXSECT];
register long zero = zeros[allopiece - ALLOEMIT];
/*
* Notice that "sectindex" is not a section number!
* It contains the offset of the section from the beginning
* of the module. Thus, it cannot be used to index "zeros".
* AIAIAIAIA
*/
flen = ((struct outsect *)modulptr(sectindex))->os_flen;
if (flen && zero) {
if ((emitindex = alloc(allopiece, zero)) != BADOFF){
register char *p = address(allopiece, emitindex);
debug("Zeros %ld\n", zero, 0,0,0);
while (zero--) *p++ = 0;
}
else return FALSE;
zero = 0;
}
zeros[allopiece - ALLOEMIT] =
zero + ((struct outsect *) modulptr(sectindex))->os_size - 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(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(ind_t dbugoff, long ndbugbytes)
{
ind_t dbugindex;
extern ind_t alloc();
if ((dbugindex = alloc(ALLODBUG, 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 void
get_indirect(struct outhead* head, struct outsect* sect)
{
register ind_t *emitindex;
register int nsect;
register int piece;
ind_t *reloindex;
emitindex = (ind_t *)modulptr(IND_EMIT(*head));
piece = ALLOEMIT;
for (nsect = 0; nsect < head->oh_nsect; nsect++) {
rd_outsect(nsect);
rd_emit(address(piece, *emitindex), sect->os_flen);
piece++; emitindex++; sect++;
}
reloindex = (ind_t *)modulptr(IND_RELO(*head));
rd_relo((struct outrelo *)address(ALLORELO, *reloindex),
head->oh_nrelo
);
}
/*
* Set the file pointer at `pos'.
*/
void seek(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.
*/
void skip_modul(struct outhead* head)
{
register ind_t skip = modulsize(head);
if (incore) {
core_position += int_align(skip);
if (passnumber == SECOND)
modulbase += int_align(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 void
read_modul(void)
{
struct outhead *head;
register struct outsect *sects;
struct outname *names;
char *chars;
ind_t sectindex, nameindex, charindex;
unsigned short nsect, nname;
long size;
long nchar;
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);
rd_ohead(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);
#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);
rd_sect(sects, nsect);
while (nsect--) {
if (sects->os_lign > 1) {
sects->os_size += sects->os_lign - 1;
sects->os_size -= sects->os_size % sects->os_lign;
}
sects++;
}
rd_name(names, nname);
rd_string(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;
{
return (size + (sizeof(double) - 1)) & ~(int)(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
*/
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;
static unsigned short cnt_relos;
static unsigned short relind;
#define _RELSIZ 64
void startrelo(struct outhead* head)
{
ind_t reloindex;
if (incore) {
reloindex = *(ind_t *)(modulbase + IND_RELO(*head));
walkrelo = (struct outrelo *)address(ALLORELO, reloindex);
}
else {
relind = _RELSIZ;
rd_rew_relos(head);
cnt_relos = head->oh_nrelo;
}
}
struct outrelo* nextrelo(void)
{
static struct outrelo relobuf[_RELSIZ];
if (incore)
return walkrelo++;
if (relind == _RELSIZ) {
unsigned int i = cnt_relos >= _RELSIZ ? _RELSIZ : cnt_relos;
cnt_relos -= i;
rd_relo(relobuf, i);
relind = 0;
}
return &relobuf[relind++];
}
/* ------------------------------------------------------------------------- */
/*
* 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)
return 0;
rd_outsect(sectindex);
rd_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);
}
char *
getblk(totalsz, pblksz, sectindex)
long totalsz;
long *pblksz;
int sectindex;
{
char *ret;
long sz = (1L << 30);
assert(!incore);
while (sz >= totalsz) sz >>= 1;
while (sz) {
ret = core_alloc(ALLOMODL, sz);
if (ret != (char *) 0) {
rd_outsect(sectindex);
*pblksz = sz;
return ret;
}
sz >>= 1;
}
fatal("no space for section contents");
return (char *) 0;
}
void endemit(char* emit)
{
core_free(ALLOMODL, emit);
}