ack/util/led/scan.c

587 lines
15 KiB
C
Raw Permalink Normal View History

1987-03-09 19:15:41 +00:00
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
1985-01-10 13:35:39 +00:00
#ifndef lint
1994-06-24 11:31:16 +00:00
static char rcsid[] = "$Id$";
1985-01-10 13:35:39 +00:00
#endif
#include <assert.h>
#include <stdio.h>
2017-01-18 18:55:56 +00:00
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
2017-08-06 09:58:36 +00:00
#include <string.h>
1985-01-10 13:35:39 +00:00
#include <sys/types.h>
#ifdef SYMDBUG
1985-01-10 13:35:39 +00:00
#include <sys/stat.h>
#endif /* SYMDBUG */
2017-08-06 09:58:36 +00:00
#include <fcntl.h>
#include <unistd.h>
#include "arch.h"
#include "out.h"
#include "ranlib.h"
2017-08-06 09:58:36 +00:00
#include "object.h"
1985-01-10 13:35:39 +00:00
#include "const.h"
#include "memory.h"
#include "scan.h"
#include "debug.h"
1985-01-10 13:35:39 +00:00
#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 */
1985-01-10 13:35:39 +00:00
extern FILE* infile;
1985-01-10 13:35:39 +00:00
extern int passnumber;
char *archname; /* Name of archive, if reading from archive. */
char *modulname; /* Name of object module. */
#ifdef SYMDBUG
long objectsize;
#endif /* SYMDBUG */
1985-01-10 13:35:39 +00:00
static size_t align(size_t size);
1985-01-10 13:35:39 +00:00
static char *modulbase;
static size_t modulsize(struct outhead* head);
2017-08-06 09:58:36 +00:00
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, size_t nrelobytes);
#ifdef SYMDBUG
static bool putdbugindex(ind_t dbugoff, size_t ndbugbytes);
#endif /* SYMDBUG */
2017-08-06 09:58:36 +00:00
static void get_indirect(struct outhead* head, struct outsect* sect);
static void read_modul(void);
static void scan_modul(void);
1985-01-10 13:35:39 +00:00
/*
* 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(char* filename)
1985-01-10 13:35:39 +00:00
{
unsigned int rd_unsigned2();
1985-01-10 13:35:39 +00:00
struct ar_hdr archive_header;
unsigned short magic_number;
1985-01-10 13:35:39 +00:00
#ifdef SYMDBUG
struct stat statbuf;
#endif /* SYMDBUG */
1985-01-10 13:35:39 +00:00
archname = (char *)0;
modulname = (char *)0;
if (passnumber == FIRST || !incore) {
if ((infile = fopen(filename, "rb")) == NULL)
1985-01-10 13:35:39 +00:00
fatal("can't read %s", filename);
magic_number = rd_unsigned2(infile);
1985-01-10 13:35:39 +00:00
} else {
modulbase = modulptr((ind_t)0);
magic_number = *(unsigned short *)modulbase;
1985-01-10 13:35:39 +00:00
}
switch (magic_number) {
case O_MAGIC:
#ifdef SYMDBUG
if (passnumber == FIRST || !incore) {
if (fstat(infile, &statbuf) < 0)
fatal("cannot stat %s", filename);
1985-01-10 13:35:39 +00:00
objectsize = statbuf.st_size;
}
#endif /* SYMDBUG */
1985-01-10 13:35:39 +00:00
seek((long)0);
modulname = filename;
return PLAIN;
case ARMAG:
case AALMAG:
1985-01-10 13:35:39 +00:00
archname = filename;
if (passnumber == FIRST) {
rd_arhdr(infile, &archive_header);
1985-01-10 13:35:39 +00:00
if (strcmp(archive_header.ar_name, SYMDEF))
fatal("%s: no table of contents", filename);
1985-01-10 13:35:39 +00:00
} else if (incore) {
1988-04-21 18:53:31 +00:00
modulbase += sizeof(int);
core_position += sizeof(int);
1985-01-10 13:35:39 +00:00
}
return ARCHIVE;
default:
fatal("%s: wrong magic number", filename);
1985-01-10 13:35:39 +00:00
}
/* NOTREACHED */
}
2017-08-06 09:58:36 +00:00
void closefile(char* filename)
1985-01-10 13:35:39 +00:00
{
if (passnumber == FIRST || !incore)
fclose(infile);
1985-01-10 13:35:39 +00:00
}
2017-08-06 09:58:36 +00:00
void get_archive_header(struct ar_hdr* archive_header)
1985-01-10 13:35:39 +00:00
{
if (passnumber == FIRST || !incore) {
rd_arhdr(infile, archive_header);
1985-01-10 13:35:39 +00:00
} else {
/* Copy structs. */
*archive_header = *(struct ar_hdr *)modulbase;
1988-04-21 18:53:31 +00:00
modulbase += int_align(sizeof(struct ar_hdr));
core_position += int_align(sizeof(struct ar_hdr));
1985-01-10 13:35:39 +00:00
}
#ifdef SYMDBUG
objectsize = archive_header.ar_size;
#endif /* SYMDBUG */
1985-01-10 13:35:39 +00:00
}
2017-08-06 09:58:36 +00:00
void get_modul(void)
1985-01-10 13:35:39 +00:00
{
if (passnumber == FIRST) {
rd_fdopen(infile);
1985-01-10 13:35:39 +00:00
scan_modul();
} else if (!incore) {
rd_fdopen(infile);
1985-01-10 13:35:39 +00:00
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)
1985-01-10 13:35:39 +00:00
{
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);
1985-01-10 13:35:39 +00:00
#ifdef SYMDBUG
if (space) {
get_dbug(*(ind_t *)modulptr(IND_DBUG(*head)),
ojectsize - OFF_DBUG(*head)
);
}
#endif /* SYMDBUG */
1985-01-10 13:35:39 +00:00
}
/*
* 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)
1985-01-10 13:35:39 +00:00
{
struct outhead head;
if (hard_alloc(ALLOMODL, sizeof(struct outhead)) == BADOFF)
1985-01-10 13:35:39 +00:00
fatal("no space for module header");
rd_ohead((struct outhead *)modulptr(IND_HEAD));
1985-01-10 13:35:39 +00:00
/*
* 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(struct outhead *head)
1985-01-10 13:35:39 +00:00
{
ind_t sectindex = IND_SECT(*head);
1987-08-06 18:40:02 +00:00
register struct outsect *sects;
unsigned short nsect = head->oh_nsect;
size_t size, rest;
1985-01-10 13:35:39 +00:00
#ifdef SYMDBUG
rest = nsect * sizeof(ind_t) + sizeof(ind_t) + sizeof(ind_t);
#else /* SYMDBUG */
1985-01-10 13:35:39 +00:00
rest = nsect * sizeof(ind_t) + sizeof(ind_t);
#endif /* SYMDBUG */
1985-01-10 13:35:39 +00:00
/*
* 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");
1987-08-06 18:40:02 +00:00
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++;
}
1985-01-10 13:35:39 +00:00
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(struct outhead *head)
1985-01-10 13:35:39 +00:00
{
register int allopiece;
unsigned short nsect = head->oh_nsect;
unsigned short nrelo = head->oh_nrelo;
1985-01-10 13:35:39 +00:00
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);
size_t dbugsize = objectsize - OFF_DBUG(*head);
#endif /* SYMDBUG */
1985-01-10 13:35:39 +00:00
assert(incore);
for (allopiece = ALLOEMIT; allopiece < ALLOEMIT + nsect; allopiece++) {
if (!putemitindex(sectindex, emitoff, allopiece))
return FALSE;
sectindex += sizeof(struct outsect);
emitoff += sizeof(ind_t);
}
if (nrelo > SIZE_MAX / sizeof(struct outrelo))
return FALSE; /* nrelo * size would overflow */
1985-01-10 13:35:39 +00:00
#ifdef SYMDBUG
return putreloindex(relooff, nrelo * sizeof(struct outrelo))
1985-01-10 13:35:39 +00:00
&&
putdbugindex(dbugoff, dbugsize);
#else /* SYMDBUG */
return putreloindex(relooff, nrelo * sizeof(struct outrelo));
#endif /* SYMDBUG */
1985-01-10 13:35:39 +00:00
}
/*
* 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)
1985-01-10 13:35:39 +00:00
{
long flen;
ind_t emitindex;
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
*/
1985-01-10 13:35:39 +00:00
flen = ((struct outsect *)modulptr(sectindex))->os_flen;
if (flen && zero) {
if (zero != (size_t)zero)
return FALSE;
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;
1987-03-12 19:18:59 +00:00
zero = 0;
}
zeros[allopiece - ALLOEMIT] =
1987-03-12 19:18:59 +00:00
zero + ((struct outsect *) modulptr(sectindex))->os_size - flen;
if (flen != (size_t)flen)
return FALSE;
1985-01-10 13:35:39 +00:00
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, size_t nrelobytes)
1985-01-10 13:35:39 +00:00
{
ind_t reloindex;
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, size_t ndbugbytes)
1985-01-10 13:35:39 +00:00
{
ind_t dbugindex;
1987-04-08 17:15:30 +00:00
if ((dbugindex = alloc(ALLODBUG, ndbugbytes)) != BADOFF) {
1985-01-10 13:35:39 +00:00
*(ind_t *)modulptr(dbugoff) = dbugindex;
return TRUE;
}
return FALSE;
}
#endif /* SYMDBUG */
1985-01-10 13:35:39 +00:00
/*
* 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)
1985-01-10 13:35:39 +00:00
{
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);
1985-01-10 13:35:39 +00:00
piece++; emitindex++; sect++;
}
reloindex = (ind_t *)modulptr(IND_RELO(*head));
rd_relo((struct outrelo *)address(ALLORELO, *reloindex),
1985-01-10 13:35:39 +00:00
head->oh_nrelo
);
}
/*
* Set the file pointer at `pos'.
*/
2017-08-06 09:58:36 +00:00
void seek(long pos)
1985-01-10 13:35:39 +00:00
{
if (passnumber == FIRST || !incore)
fseek(infile, pos, SEEK_SET);
1985-01-10 13:35:39 +00:00
}
/*
* 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.
*/
2017-08-06 09:58:36 +00:00
void skip_modul(struct outhead* head)
1985-01-10 13:35:39 +00:00
{
register ind_t skip = modulsize(head);
if (incore) {
1988-04-21 18:53:31 +00:00
core_position += int_align(skip);
1985-01-10 13:35:39 +00:00
if (passnumber == SECOND)
1988-04-21 18:53:31 +00:00
modulbase += int_align(skip);
1985-01-10 13:35:39 +00:00
} 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)
1985-01-10 13:35:39 +00:00
{
struct outhead *head;
1987-08-06 18:40:02 +00:00
register struct outsect *sects;
1985-01-10 13:35:39 +00:00
struct outname *names;
char *chars;
ind_t sectindex, nameindex, charindex;
unsigned short nsect, nname;
size_t size;
1985-01-10 13:35:39 +00:00
long nchar;
assert(passnumber == SECOND);
assert(!incore);
if (hard_alloc(ALLOMODL, sizeof(struct outhead)) == BADOFF)
1985-01-10 13:35:39 +00:00
fatal("no space for module header");
head = (struct outhead *)modulptr(IND_HEAD);
rd_ohead(head);
1985-01-10 13:35:39 +00:00
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 */
1985-01-10 13:35:39 +00:00
size = modulsize(head) - (nsect * sizeof(ind_t) + sizeof(ind_t));
#endif /* SYMDBUG */
1985-01-10 13:35:39 +00:00
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);
1987-08-06 18:40:02 +00:00
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);
1985-01-10 13:35:39 +00:00
}
/*
* Align `size' to a multiple of the size of a double.
* This is assumed to be a power of 2.
*/
static size_t
align(size_t size)
1985-01-10 13:35:39 +00:00
{
return (size + (sizeof(double) - 1)) & ~(sizeof(double) - 1);
1985-01-10 13:35:39 +00:00
}
/*
* 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.
1991-12-18 09:14:25 +00:00
#endif
1985-01-10 13:35:39 +00:00
*/
static size_t
modulsize(struct outhead *head)
1985-01-10 13:35:39 +00:00
{
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 */
1985-01-10 13:35:39 +00:00
sizeof(ind_t); /* 5 */
#endif /* SYMDBUG */
1985-01-10 13:35:39 +00:00
}
/* ------------------------------------------------------------------------- */
/*
* 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;
1987-04-08 17:15:30 +00:00
#define _RELSIZ 64
1985-01-10 13:35:39 +00:00
2017-08-06 09:58:36 +00:00
void startrelo(struct outhead* head)
1985-01-10 13:35:39 +00:00
{
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);
1987-01-29 09:43:40 +00:00
cnt_relos = head->oh_nrelo;
}
1985-01-10 13:35:39 +00:00
}
2017-08-06 09:58:36 +00:00
struct outrelo* nextrelo(void)
1985-01-10 13:35:39 +00:00
{
1987-04-08 17:15:30 +00:00
static struct outrelo relobuf[_RELSIZ];
1985-01-10 13:35:39 +00:00
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++];
1985-01-10 13:35:39 +00:00
}
/* ------------------------------------------------------------------------- */
/*
* Get the section contents in core of which the describing struct has index
* `sectindex'. `Head' points to the header of the module.
*/
char *getemit(struct outhead *head, struct outsect *sects, int sectindex)
1985-01-10 13:35:39 +00:00
{
char *ret;
ind_t off;
long flen;
1985-01-10 13:35:39 +00:00
if (!incore) {
flen = sects[sectindex].os_flen;
if (flen != (size_t)flen)
return 0;
ret = core_alloc(ALLOMODL, flen);
1985-01-10 13:35:39 +00:00
if (ret == (char *)0)
return 0;
rd_outsect(sectindex);
rd_emit(ret, sects[sectindex].os_flen);
1985-01-10 13:35:39 +00:00
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(long totalsz, long *pblksz, int sectindex)
{
char *ret;
long sz = (1L << 30);
assert(!incore);
while (sz != (size_t)sz) sz >>= 1;
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 *) NULL;
}
2017-08-06 09:58:36 +00:00
void endemit(char* emit)
{
core_free(ALLOMODL, emit);
}