250 lines
6.3 KiB
C
250 lines
6.3 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[] = "$Header$";
|
|
#endif
|
|
|
|
#include <out.h>
|
|
#include "const.h"
|
|
#include "debug.h"
|
|
#include "defs.h"
|
|
#include "memory.h"
|
|
#include "orig.h"
|
|
#include "scan.h"
|
|
|
|
static get_names();
|
|
static process();
|
|
static getexternal();
|
|
static redefine();
|
|
static transfer();
|
|
|
|
/*
|
|
* Get section sizes and symboltable information from present module.
|
|
*/
|
|
extract()
|
|
{
|
|
struct outhead head;
|
|
|
|
get_modul();
|
|
/*
|
|
* Copy head because we need it so often but it can change place,
|
|
* so we can't trust a pointer to it.
|
|
*/
|
|
head = *(struct outhead *)modulptr(IND_HEAD);
|
|
get_names(&head);
|
|
process(&head);
|
|
skip_modul(&head);
|
|
}
|
|
|
|
ushort NLocals = 0; /* Number of local names to be saved. */
|
|
ushort NGlobals = 0; /* Number of global names. */
|
|
|
|
/*
|
|
* Walk through the nametable of this module, counting the locals that must
|
|
* appear in the final output file if this module is linked.
|
|
* That number will be returned.
|
|
*/
|
|
static
|
|
get_names(head)
|
|
register struct outhead *head;
|
|
{
|
|
register int nnames;
|
|
register ind_t nameindex, charindex;
|
|
register ind_t charoff;
|
|
extern int flagword;
|
|
|
|
nnames = head->oh_nname;
|
|
nameindex = IND_NAME(*head);
|
|
charindex = IND_CHAR(*head);
|
|
charoff = OFF_CHAR(*head);
|
|
while (nnames--) {
|
|
struct outname name; /* A local copy. */
|
|
/*
|
|
* Because savelocal/getexternal might relocate the modules
|
|
* we have to compute the core addresses again.
|
|
*/
|
|
name = *(struct outname *)modulptr(nameindex);
|
|
/*
|
|
* Change the offset in file into an offset in the memory area.
|
|
* There will always be at least a header before the string
|
|
* area, so we don't have to be afraid to confuse "no name"
|
|
* with "the first name".
|
|
*/
|
|
if (name.on_foff) {
|
|
if (name.on_foff < charoff ||
|
|
name.on_foff >= charoff+head->oh_nchar) {
|
|
fatal("illegal offset in name");
|
|
}
|
|
name.on_foff += charindex - charoff;
|
|
}
|
|
namerelocate(&name);
|
|
if ((name.on_type & S_TYP) == S_CRS) {
|
|
name.on_valu += charindex - charoff;
|
|
name.on_valu = savechar(ALLOGCHR, (ind_t)name.on_valu);
|
|
}
|
|
if (name.on_type & S_EXT) {
|
|
getexternal(&name);
|
|
} else {
|
|
/*
|
|
* The only thing we want to know about locals is
|
|
* whether they must appear in the output file.
|
|
*/
|
|
if (!(flagword & SFLAG) && mustsavelocal(&name)) {
|
|
NLocals++;
|
|
savelocal(&name);
|
|
}
|
|
}
|
|
nameindex += sizeof(struct outname);
|
|
}
|
|
}
|
|
|
|
extern struct orig relorig[];
|
|
|
|
static
|
|
process(head)
|
|
register struct outhead *head;
|
|
{
|
|
register struct outsect *sects;
|
|
register struct outsect *outsp;
|
|
register int nsect;
|
|
register struct orig *orig = relorig;
|
|
extern struct outhead outhead;
|
|
extern struct outsect outsect[];
|
|
|
|
outhead.oh_nrelo += head->oh_nrelo;
|
|
outhead.oh_nemit += head->oh_nemit;
|
|
if (head->oh_nsect > outhead.oh_nsect)
|
|
outhead.oh_nsect = head->oh_nsect;
|
|
sects = (struct outsect *)modulptr(IND_SECT(*head));
|
|
nsect = head->oh_nsect;
|
|
outsp = outsect;
|
|
while (nsect--) {
|
|
if (sects->os_flen) {
|
|
/* contains non-zero stuff */
|
|
outhead.oh_nemit += outsp->os_size - outsp->os_flen;
|
|
outsp->os_flen = outsp->os_size + sects->os_flen;
|
|
}
|
|
else {
|
|
outsp->os_flen += sects->os_flen;
|
|
}
|
|
outsp->os_size += sects->os_size;
|
|
/*
|
|
* Add all flen's and all (size - flen == zero)'s of
|
|
* preceding sections with the same number.
|
|
*/
|
|
orig->org_size = outsp->os_size;
|
|
orig++; outsp++; sects++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Add relocation constant for names in user defined sections.
|
|
* The value of a common name indicates a size instead of an offset,
|
|
* and hence shouldn't be relocated.
|
|
* Otherwise we just add the accumulated size of all normal parts in preceding
|
|
* sections with the same size.
|
|
*/
|
|
namerelocate(name)
|
|
register struct outname *name;
|
|
{
|
|
register int type = name->on_type;
|
|
register int sct = type & S_TYP;
|
|
|
|
if (sct == S_UND || sct == S_ABS || sct == S_CRS)
|
|
return;
|
|
if (type & S_COM) {
|
|
if ( ! (type&S_EXT) ) fatal("local commons should be handled by the assembler") ;
|
|
return;
|
|
}
|
|
|
|
name->on_valu += relorig[(type & S_TYP) - S_MIN].org_size;
|
|
}
|
|
|
|
/*
|
|
* If we see this name for the first time, we must remember it for
|
|
* we might need it later on. Otherwise it must confirm to what we already
|
|
* know about it, and eventually add to that knowledge.
|
|
*/
|
|
static
|
|
getexternal(name)
|
|
register struct outname *name;
|
|
{
|
|
register char *string;
|
|
register int h;
|
|
register struct outname *old;
|
|
extern int hash();
|
|
extern struct outname *searchname();
|
|
|
|
string = modulptr((ind_t)name->on_foff);
|
|
h = hash(string);
|
|
old = searchname(string, h);
|
|
if (old == (struct outname *)0) {
|
|
NGlobals++;
|
|
entername(name, h);
|
|
if (ISUNDEFINED(name)) {
|
|
verbose("requires %s", string, 0, 0, 0);
|
|
}
|
|
} else if (!ISUNDEFINED(name)) {
|
|
if (ISUNDEFINED(old)) {
|
|
name->on_mptr = string; /* Just for convenience. */
|
|
transfer(name, old);
|
|
} else {
|
|
name->on_mptr = string; /* Just for convenience. */
|
|
redefine(name, old);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Handle the redefinition of `new' in the current module.
|
|
* A name can be defined in three ways, in increasing priority:
|
|
* undefined,
|
|
* common,
|
|
* defined in a section.
|
|
* A name may become "higher" when defined, but not "lower".
|
|
* A redefinition as common is allowed. It is ignored, but a warning is given
|
|
* when the desired section of `new' doesn't correspond with the section of
|
|
* `old'. If a common definition is given again for a name, we take the
|
|
* greatest value so that the common declared name always has enough space.
|
|
* If a common is defined as a not-common, the old definition is ignored.
|
|
*/
|
|
static
|
|
redefine(new, old)
|
|
register struct outname *new, *old;
|
|
{
|
|
if (!ISCOMMON(old)) {
|
|
if (!ISCOMMON(new))
|
|
error("%s: multiply defined", new->on_mptr);
|
|
/*
|
|
else if ((new->on_type & S_TYP) != (old->on_type & S_TYP))
|
|
warning("%s: sections differ", new->on_mptr);
|
|
*/
|
|
} else {
|
|
/* `Old' is common. */
|
|
if (ISCOMMON(new)) {
|
|
if ((new->on_type & S_TYP) != (old->on_type & S_TYP))
|
|
warning("%s: sections differ", new->on_mptr);
|
|
|
|
if (new->on_valu > old->on_valu)
|
|
old->on_valu = new->on_valu;
|
|
} else {
|
|
transfer(new, old);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Transfer things we want to know from `src' to `dst'.
|
|
*/
|
|
static
|
|
transfer(src, dst)
|
|
register struct outname *src, *dst;
|
|
{
|
|
debug("%s defined here\n", src->on_mptr, 0, 0, 0);
|
|
dst->on_valu = src->on_valu;
|
|
dst->on_type = src->on_type;
|
|
dst->on_desc = src->on_desc;
|
|
}
|