2.9BSD/usr/src/ucb/l11/link.c
# include "link.h"
char *sprintf(),*strcpy(), *ctime(), *strsub(), *tack(), *lalloc();
WORD getword();
#include <signal.h>
/******************** variables with global scope ************************/
struct psect *Tex_root = NULL; /* root of ins psects */
struct psect *Tex_end = NULL; /* last structure of ins list */
struct psect *Dat_root = NULL; /* root of data psects */
struct psect *Dat_end = NULL; /* last structure of data list */
struct psect *Bss_root = NULL; /* root of bss psects */
struct psect *Bss_end = NULL; /* last structure of bss list */
struct objfile *File_root = NULL; /* root of object file link-list */
struct symbol *Sym_root = NULL; /* root of symbol table */
struct g_sect *Gsect_root = NULL; /* root of tree of global psects */
WORD Maxabs = 0; /* maximum size of absolute files,
** also low limit of relocatable code */
WORD R_counter; /* relocation counter, used in
** assigning relocation constants,
** also high limit of relocatable
** code after relocation */
long Seekoff; /* offset for seeking in out file */
char Do_410 = 0; /* boolean for out file format */
int Verbose =0; /* Boolean for verbose commentary */
char Do_411 = 0; /* boolean for out file format */
char Do_map = 0; /* boolean for printing load map */
char Do_lpr_map = 0; /* boolean for line printing map */
char Do_bits = 0; /* boolean for including relocation
** bits in .out file */
char C_rel = 0; /* boolean for having out file end
** with '.o' */
char Do_kludge = 0; /* boolean for writing global sybmbols
** in the out file with a preceding
** underscore character */
char Do_silent = 0; /* boolean for not printing zero
** errors message */
char Do_table = 1; /* boolean for including symbol table
** in out file */
char No_locals = 0; /* boolean for not including local
** symbols in the out table */
char Do_odt = 0; /* boolean for including odt module */
WORD Transadd = 1; /* transfer address */
struct objfile *Transfile; /* object file of transfer address */
char Transsect[7]; /* program section of trans address */
WORD Tex_size; /* for out file */
WORD Dat_size; /* for out file */
WORD Bss_size; /* for out file */
char *Outbase; /* out file name without '.out' */
char *Outname = NULL; /* name of out file */
char *Mapname; /* name of map file */
FILE *Mapp = NULL; /* pointer for map file */
char Erstring[80]; /* buffer for error messages */
int Nerrors = 0; /* the number of user errors */
char No_out = 0; /* boolean for no out file */
char Scanerr = 0; /* boolean for error in arguments */
/********************** main ********************************************/
main(argc, argv)
int argc;
char *argv[];
{
scanargs(argc, argv);
pass1();
relocate();
relsyms(Sym_root);
post_bail();
if (Do_map)
printmap();
if (No_out)
exit(0);
warmup();
pass2();
loose_ends();
}
/********************* scanargs ******************************************/
scanargs(argc, argv)
int argc;
char *argv[];
{
register char *s;
char *r;
register struct objfile *end; /* last file in link-list */
struct objfile *newfile(); /* allocaters */
while (--argc)
{
s = *++argv;
if (*s == '-')
{
s++;
if ((r = strsub(s, "na:")) != NULL)
Outname = tack(r, ".out");
else if (!strcmp(s, "ls") || !strcmp(s, "mp"))
Do_map = 1;
else if (!strcmp(s, "lp"))
Do_map = Do_lpr_map = 1;
else if (!strcmp(s, "od"))
Do_odt = 1;
else if (!strcmp(s, "r"))
Do_bits = 1;
else if (!strcmp(s, "c"))
Do_bits = C_rel = 1;
else if (!strcmp(s, "K"))
Do_bits = C_rel = Do_kludge = 1;
else if (!strcmp(s, ""))
Do_silent = 1;
else if (!strcmp(s, "ns"))
Do_table = 0;
else if (!strcmp(s, "go"))
No_locals = 1;
else if (!strcmp(s, "no"))
No_out = 1;
else if (!strcmp(s, "n"))
Do_410 = 1;
else if (!strcmp(s, "i"))
Do_411 = 1;
else if(!strcmp(s, "v"))
Verbose = 1;
else
{
fprintf(stderr, "Unrecognizable argument: -%s\n", s);
Scanerr = 1;
}
}
else
{
if (File_root == NULL)
end = File_root = newfile();
else
{
end->nextfile = newfile();
end = end->nextfile;
}
s = tack(s, ".obj");
end->fname = s;
}
}
if (File_root == NULL)
{
fprintf(stderr, "Error: no object files given\n");
exit(1);
}
if (Do_odt)
{
end->nextfile = newfile();
end->nextfile->fname = "/usr/lib/odt.obj";
}
if (Scanerr)
exit(1);
outnames();
}
/*************************** strsub ***************************************/
char *strsub(s, t) /* if t is the initial part of s then return a pointer
** to the rest of s, else return NULL */
register char *s;
register char *t;
{
register char *q;
q = t;
while (*t)
if (*s++ != *t++)
return (NULL);
if (*s == '\0') /* check for no filename */
{
fprintf(stderr, "Argument error: a filename should be contiguous with -%s\n", q);
Scanerr = 1;
return(NULL);
}
else
return (s);
}
/**************************** outnames ************************************/
outnames() /* determine names of output files */
{
if (Outname == NULL)
{
Outbase = lalloc(strlen(File_root->fname) + 1);
strcpy(Outbase, File_root->fname);
strip(Outbase, ".obj");
}
else
{
Outbase = lalloc(strlen(Outname) + 5);
strcpy(Outbase, Outname);
strip(Outbase, ".out");
strip(Outbase, ".o");
}
if (C_rel)
Outname = tack(Outbase, ".o");
else
Outname = tack(Outbase, ".out");
if (Do_map)
Mapname = tack(Outbase, ".map");
}
/*************************** newpsect ************************************/
struct psect *newpsect() /* allocate and initialize a new psect
** structure */
{
register struct psect *p;
p = (struct psect *) lalloc(sizeof (struct psect));
p->next = p->pssame = p->obsame = NULL;
p->slist = NULL;
return (p);
}
/*********************** newsymbol ***************************************/
struct symbol *newsymbol() /* allocate and initialize new symbol
** structure */
{
register struct symbol *p;
p = (struct symbol *) lalloc(sizeof (struct symbol));
p->prsect = (struct psect *)NULL;
p->right = p->left = (struct symbol *)NULL;
return (p);
}
/********************** newfile ******************************************/
struct objfile *newfile() /* allocate and initialize new psect
** structure */
{
register struct objfile *p;
p = (struct objfile *) lalloc(sizeof (struct objfile));
p->nextfile = NULL;
p->psect_list = NULL;
p->ver_id = NULL;
return (p);
}
/**************************** new_gsect ***********************************/
struct g_sect *new_gsect()
{
register struct g_sect *p;
p = (struct g_sect *) lalloc(sizeof(struct g_sect));
p->leftt = p->rightt = NULL;
return (p);
}
/********************* pass1 *********************************************/
pass1()
{
char name[7]; /* string from M11 */
char attr; /* attribute from M11 */
register int type; /* type of string */
int value; /* from M11 */
register struct objfile *of; /* current object file */
register struct psect *ps; /* current psect */
struct symbol *sym; /* current and last symbol
** in symbol list */
struct symbol **nextsym; /* pointer to pointer which
** should point to next symbol
** in the psect list */
struct psect *newpsect();
struct symbol *newsymbol();
of = File_root;
while (of != NULL)
{
ch_input(of->fname, HEADER); /* change input */
while(morebytes())
{
dc_symbol(name);
attr = getbyte();
type = getbyte();
value = getword();
switch(type)
{
case 0: /* program name */
strcpy(of->pname, name);
break;
case 1: /* program section */
case 5: /* program section */
if(Verbose)
fprintf(stderr,"gsd%d <%6s> %o\n",
type, name, attr);
/* increment size if odd */
value += (value % 2) ? 1 : 0;
/* place psect at end of link-list for objfile */
if (of->psect_list == NULL)
ps = of->psect_list = newpsect();
else
{
ps->obsame = newpsect();
ps = ps->obsame;
}
strcpy(ps->name, name);
if (Do_410)
/* if the psect is sharable and data
** make it instruction, this is an old
** L11 kludge. */
{
if ((attr & SHR) && !(attr & (INS | BSS)))
ps->type = attr | INS;
else
ps->type = attr;
}
else
ps->type = attr;
ps->nbytes = value;
nextsym = &(ps->slist);
if (!(attr & REL)) /* if psect is absolute */
{
ps->rc = 0;
Maxabs = (value > Maxabs) ? value : Maxabs;
}
/* else put psect in proper ins-dat-bss
** link-list */
else
place_global(ps);
break;
case 2: /* this case has not been observed
** and is assumed to be un-used */
lerror("internal symbol table");
break;
case 3: /* transfer address */
if (value == 1) /* if 1 bogus */
break;
if (Transadd != 1) /* transfer address
** already specified */
fprintf(stderr, "Warning: more than \
one transfer address specified\n");
Transadd = value;
Transfile = of;
strcpy(Transsect, name);
break;
case 4: /* global symbol */
/* make structure and place in obj file list */
sym = newsymbol();
sym->prsect = ps;
strcpy(sym->name, name);
sym->type = attr;
sym->value = value;
if (attr & DEF) /* if the symbol is defined,
** place in link-list of
** symbols */
{
*nextsym = sym;
nextsym = &(sym->symlist);
}
/* place in symbol table */
table(&Sym_root, sym);
break;
case 6: /* version identification */
of->ver_id = lalloc(7);
strcpy(of->ver_id, name);
break;
default:
lerror("header type out of range");
}
}
of = of->nextfile;
}
}
/***************************** place_global ******************************/
place_global(ps) /* try to place the given program section
** in proper ins - dat - bss link-list by
** finding it in the global psect tree. if
** it is not there then add to tree and place
** it through place_local */
register struct psect *ps;
{
register struct g_sect **ptr;
register int cond;
ptr = &Gsect_root;
while (*ptr != NULL)
{
if ( !(cond = strcmp(ps->name, (*ptr)->name)))
{
if (ps->type != (*ptr)->type)
{
fprintf(stderr, "psect <%6s> attribute clash: ", ps->name);
fprintf(stderr, " already has %3o, now declared %3o. Using %3o\n", 0377 & (*ptr)->type, 0377 & ps->type, 0377 & (*ptr)->type);
ps->type = (*ptr)->type;
}
/* place psect in list of sames */
(*ptr)->last_sect->pssame = ps;
(*ptr)->last_sect = ps;
return;
}
else if (cond < 0)
ptr = &((*ptr)->leftt);
else
ptr = &((*ptr)->rightt);
}
/* global section cannot be found in tree so make a new node for
** it and place it as a local */
*ptr = new_gsect();
strcpy((*ptr)->name, ps->name);
(*ptr)->type = ps->type;
(*ptr)->last_sect = ps;
place_local(ps);
}
/************************* place_local *******************************/
place_local(ps) /* place psect at end of its UNIX section
** type link-list */
register struct psect *ps;
{
register type = ps->type;
if( !(type & REL)) /* asect */
{
fprintf(stderr, "Don't know what to do with .asect yet\n");
}
if (type & INS) /* instruction psect */
{
if (Tex_root == NULL)
Tex_root = Tex_end = ps;
else
{
Tex_end->next = ps;
Tex_end = ps;
}
}
else if (type & BSS) /* bss psect */
{
if (Bss_root == NULL)
Bss_root = Bss_end = ps;
else
{
Bss_end->next = ps;
Bss_end = ps;
}
}
else /* data psect */
{
if (Dat_root == NULL)
Dat_root = Dat_end = ps;
else
{
Dat_end->next = ps;
Dat_end = ps;
}
}
}
/************************* table **************************************/
table(root, new) /* place new symbol structure in symbol table tree */
register struct symbol *root[]; /* pointer to root pointer of tree */
register struct symbol *new; /* pointer to symbol (structure) to
** be added */
{
register int cond;
for (;;) /* repeat until break */
{
if (*root == NULL) /* empty tree */
{
/* set root, return */
*root = new;
return;
}
/* check for same name */
else if ((cond = strcmp(new->name, (*root)->name)) == 0)
{
/* new symbol and one in table have same name */
if (new->type & DEF) /* ignore new if undefined */
{
if (isdef(*root)) /* both defined */
{
if(isabs(*root) && (new->value ==
(*root)->value))
fprintf(stderr, "Warning: abs sym %s defined as %06o twice\n", new->name, new->value);
else {
sprintf(Erstring, "%s defined twice", new->name);
uerror(Erstring);
}
}
/* else /* get rid of old undefined symbol */
{
new->left = (*root)->left;
new->right = (*root)->right;
*root = new;
}
}
return;
}
/* else branch */
else if (cond < 0)
root = &((*root)->left);
else
root = &((*root)->right);
}
}
/***************************** relocate ********************************/
# define _8K 020000
relocate() /* assign relocation constants for all relocatable psects */
{
register unsigned temp;
struct outword trans_rc;
R_counter = Maxabs; /* set relocation counter to follow
** absolute sections */
asgn_rcs(Tex_root);
/* text size = absolute and ins psects */
Tex_size = R_counter;
if (Do_410)
{
temp = Tex_size + _8K;
temp &= ~(_8K - 1);
R_counter = temp;
Seekoff = (long) Tex_size - (long )R_counter;
}
else if (Do_411)
{
R_counter = temp = 0;
Seekoff = Tex_size;
}
else
{
temp = Tex_size;
Seekoff = 0;
}
asgn_rcs(Dat_root);
Dat_size = (int)R_counter - (int)temp;
temp = R_counter;
asgn_rcs(Bss_root);
Bss_size = (int)R_counter - (int)temp;
/* relocate transfer address if defined */
if (Transadd != 1) /* if defined */
{
get_rc(&trans_rc, Transfile, Transsect);
Transadd += trans_rc.val;
}
if (Do_bits && Maxabs)
{
uerror("absolute section present - relocation bits suppressed");
Do_bits = 0;
}
}
/*************************** asgn_rcs ************************************/
asgn_rcs(p) /* assign relocation constants to
** the psects pointed to. this routine uses the
** variable R_counter which contains the address of the
** next available space in memory */
register struct psect *p; /* called with ins-dat-bss root */
{
register int size; /* addendum to R_counter */
register struct psect *d; /* temporary pointer used to access
** same psects */
for (;;) /* repeat until break */
{
if (p == NULL) /* end of list, break */
break;
/* set relocation constant to R_counter */
p->rc = R_counter;
/* set size initially to size of psect. size is not added
** to R_counter at this point because of the possibility
** that the psect is part of a group of overlaid psects */
size = p->nbytes;
/* check for same psect(s) */
if (p->pssame != NULL)
{
/* set d to same psect */
d = p;
if (p->type & OVR) /* if the sames are overlaid */
/* travel through sames.
** set the rc's of all sames to R_counter.
** size equals maximum psect size */
do
{
d = d->pssame;
d->rc = R_counter;
size = (size > d->nbytes) ? size : d->nbytes;
} while (d->pssame != NULL);
else /* sames are concatenated */
/* travel through sames
** add size to R_counter before assigning
** to rc for each psect.
** redefine size as number of bytes in psect */
do
{
d = d->pssame;
d->rc = (R_counter += size);
size = d->nbytes;
} while (d->pssame != NULL);
R_counter += size;
/* insert a psect structure at bottom of sames list to
** to facilitate '^p' M11 directives */
d->pssame = newpsect();
d = d->pssame;
d->rc = p->rc;
d->type = p->type;
d->nbytes = R_counter - p->rc;
}
else
R_counter += size;
p = p->next;
}
}
/************************* relsyms **************************************/
relsyms(sym) /* relocate global symbols */
register struct symbol *sym;
{
if (sym == NULL)
return;
sym->value += sym->prsect->rc;
relsyms(sym->left);
relsyms(sym->right);
}
/************************* printmap ***********************************/
printmap()
{
register struct objfile *op;
register struct psect *pp;
int tvec[2]; /* time vector */
static char dashes[] = "----------------";
Mapp = fopen(Mapname, "w");
if (Mapp == NULL)
fprintf(stderr, "%s not accessible\n", Mapname);
else
{
long datstart = Tex_size;
if(Do_411) datstart = 0L;
/* print map header */
time(tvec);
fprintf(Mapp, "%s Linker-11 version 22may79 %s\n", Outname, ctime(tvec));
fprintf(Mapp, "Magic number: %o\t",
Do_410 ? 0410 : ( Do_411 ? 0411 : 0407) );
if(Do_410) fprintf(Mapp, "(Shared text)\n");
else if (Do_411) fprintf(Mapp,"(Separate I & D)\n");
else fprintf(Mapp, "(Executable)\n");
fprintf(Mapp, "\tStart\tLimit\tLength\n");
brag("Text", 0L, (long)Tex_size, (Do_410 || Do_411)?"Shareable" : "");
brag("Data", datstart, (long)Dat_size, "");
brag("Bss", (long)(datstart+Dat_size), (long)Bss_size, "");
fprintf(Mapp, "transfer address: %06o\n", Transadd);
for (op = File_root; op != NULL; op = op->nextfile)
{
fprintf(Mapp, "%s\n", dashes);
fprintf(Mapp, "module: %s", op->pname);
if (op->ver_id != NULL)
fprintf(Mapp, " %s", op->ver_id);
fprintf(Mapp, "\nsection orgin size\n");
pp = op->psect_list;
while (pp != NULL)
{
fprintf(Mapp, "<%s> ", pp->name);
fprintf(Mapp, "%06o %06o", pp->rc, pp->nbytes);
prattr(pp->type);
dump_symlist(pp->slist);
pp = pp->obsame;
}
}
fprintf(Mapp, "%s", dashes);
if (dump_undefs(Sym_root, 0))
fprintf(Mapp, "\n%s\n", dashes);
else
fprintf(Mapp, "\n");
}
}
brag(s, start, size, tag)
char *s;
long start, size;
char *tag;
{
long stop = 0177777 & (size + start);
fprintf(Mapp, "%s:\t%06O\t%06O\t%06O\t%s\n", s, start, stop, size, tag);
}
prattr(x)
{
fprintf(Mapp, "\t");
attr(x&SHR, "shr, ", "prv, ");
attr(x&INS, "ins, ", "");
attr(x&BSS, "bss, ", "");
attr( !((x&BSS) || (x&INS)), "dat,", "");
attr(x&REL, "rel, ", "abs, ");
attr(x&OVR,"ovr, ", "con, ");
attr(x&GBL,"gbl", "loc");
}
attr(x, s, t)
register x;
register char *s, *t;
{
if(x) fprintf(Mapp, s);
else fprintf(Mapp, t);
}
/***************************** dump_symlist *******************************/
dump_symlist(sym) /* write to the map file the symbol list for a psect */
register struct symbol *sym;
{
register int i;
for (i = 0; sym != NULL; sym = sym->symlist)
{
fprintf(Mapp, "%s ", (i++ % 3) ? "" : "\n ");
fprintf(Mapp, "%s %06o", sym->name, sym->value);
fprintf(Mapp, " %c", (sym->type & REL) ? 'r' :'a');
}
fprintf(Mapp, "\n");
}
/***************************** dump_undefs *******************************/
dump_undefs(sym, n) /* dump into map file all undefined global symbols */
struct symbol *sym;
int n;
{
if (sym == NULL)
return (n);
n = dump_undefs(sym->left, n);
if ( !(sym->type & DEF))
{
fprintf(Mapp, "%s ", (n++ % 3) ? "" : "\n ");
fprintf(Mapp, "%s ****** u", sym->name);
}
n = dump_undefs(sym->right, n);
return (n);
}
/************************** post_bail *************************************/
post_bail() /* set interrupt routine to bail_out */
{
extern bail_out();
sigx(1);
sigx(2);
sigx(3);
sigx(15);
}
sigx(n)
{
if(signal(n, SIG_IGN) != SIG_IGN)
signal(n, bail_out);
}