V9/jerq/sgs/ld/ld2.c
static char ID[] = "@(#) ld2.c: 1.16 12/1/83";
#include "system.h"
#include <stdio.h>
#include "reloc.h"
#include "linenum.h"
#include "structs.h"
#include "y.tab.h"
#if TRVEC
#include "tv.h"
#include "ldtv.h"
#endif
#include "extrns.h"
#include "list.h"
#include "params.h"
#include "sgsmacros.h"
#include "patch.h"
#define BASIC_TYPES (STYP_TEXT | STYP_DATA | STYP_BSS)
#define K8 0x2000L
static ITEMID dotacid;
static OUTSECT *dotosptr;
/*eject*/
pboslist()
{
/*
* Process the BLDOUTSC List
*/
register OUTSECT *osptr;
register INSECT *insptr;
register INFILE *inflptr;
#if !ONEPROC
ACTITEM a;
#endif
OUTSECT *dfn_scn_grp();
long check_sect();
/*
* Process the list of output sections. Output sections can be
* defined in two places:
*
* 1. PASS 1: user-supplied; bldcnt will be > 0, and the bldoutsc
* list head will be NULL
* 2. PASS 2: default-generation; bldcnt will be 0, and the
* bldoutsc list will describe the output
* sections
*
* These two uses are mutually exclusive
*/
#if DEBUG
if( dflag > 2 )
fprintf( stderr, "\nBLDOSCN data structures:" );
#endif
#if !ONEPROC
while( bldcnt-- ) {
fread( &a, 1, sizeof(ACTITEM), trnfdes );
a.dfnscn.aiinflnm = (char *) ((int) a.dfnscn.aiinflnm + (int) strbase);
osptr = dfn_scn_grp(&a, 0);
copy(osptr->oshdr.s_name, a.dfnscn.ainame, 8);
#if TRVEC
/*
* User can define attributes of TV in two ways:
* (1) using TV { } directive
* (2) using SECTIONS { .tv : {} } directive
* so force them to agree
*/
if ( equal(a.dfnscn.ainame, _TV, 8) ) { /* defining .tv */
if ( tvspec.tvbndadr == -1L )
tvspec.tvbndadr = a.dfnscn.aibndadr;
else
a.dfnscn.aibndadr = tvspec.tvbndadr;
}
#endif
if( a.dfnscn.aitype == AIDFNSCN )
numoutsc++;
osptr->oshdr.s_paddr = -1L;
listadd(l_OS, &outsclst, osptr);
}
#endif
/*
* We now know everything there is to know about the
* transfer vector:
* At the end of ploadfil(), we knew how big it
* had to be.
* Here we know whether it was defined by ld or
* whether it is defined by .tv input sections
* together with a .tv SECTION directive
* Go check everything and complete tvspec definition.
*/
#if TRVEC
if ( tvflag )
tvupdat(); /* update definition of tv */
#endif
if( bldoutsc.head ) {
register ACTITEM *aptr, *a2ptr;
aptr = (ACTITEM *) bldoutsc.head;
while( aptr ) {
osptr = dfn_scn_grp(aptr, 1);
copy(osptr->oshdr.s_name, aptr->dfnscn.ainame, 8);
if( aptr->dfnscn.aitype == AIDFNSCN )
numoutsc++;
osptr->oshdr.s_paddr = -1L;
listadd(l_OS, &outsclst, osptr);
a2ptr = aptr;
aptr = aptr->dfnscn.ainext;
free( (char *) a2ptr);
}
}
/*
* Make sure all input sections are allocated
* into some output section.
*/
for( inflptr = (INFILE *) infilist.head; inflptr; inflptr = inflptr->flnext ) {
for( insptr = inflptr->flishead; insptr; insptr=insptr->isnext ) {
if (insptr->isoutsec <= 0) {
if ((osptr = fndoutsec(insptr->ishdr.s_name)) != NULL)
inscadd(insptr,osptr);
else {
osptr = (OUTSECT *) myalloc(sizeof(OUTSECT));
numoutsc++;
copy(osptr->oshdr.s_name, insptr->ishdr.s_name, 8);
osptr->osfill = globfill;
osptr->oshdr.s_paddr = -1l;
listadd(l_OS,&outsclst,osptr);
inscadd(insptr,osptr);
}
}
}
}
/*
* for each output section, check the flags, and for a group,
* check the size.
*/
for( osptr = (OUTSECT *) outsclst.head; osptr; osptr = osptr->osnext )
{
#if PAGING
ACTITEM *aptr;
ADDRESS textbegin, textsize;
textbegin = hflag + FILHSZ + SCNHSZ * numoutsc + memorg;
#endif
if (osptr->oshdr.s_flags & STYP_GROUP) {
OUTSECT *op;
for( op = ((OUTSECT *) osptr->osinclhd); op; op = op->osnext ) {
#if PAGING
if (bond_t_d && !Nflag && equal(op->oshdr.s_name,_DATA,8)) {
osptr->osalign = 0L;
aptr = (ACTITEM *) myalloc(sizeof(ACTITEM));
aptr->bond.aitype = AIBOND;
aptr->bond.aiinflnm = "*default.bond.file*";
aptr->bond.aiinlnno = 3;
aptr->bond.aioutsec = osptr;
aptr->bond.aiadrbnd = ((textsize + textbegin) / BOUNDARY + 1)
* BOUNDARY + (textsize + textbegin) % K8;
listadd(l_AI,&bondlist,aptr);
}
#endif
osptr->oshdr.s_size += check_sect( op );
}
if (osptr->oshdr.s_size > MAXSCNSIZE)
lderror(1,0,NULL, "GROUP containing section %.8s is too big",
osptr->osinclhd->ishdr.s_name);
} else {
#if PAGING
if (bond_t_d && !Nflag && equal(osptr->oshdr.s_name,_TEXT,8)) {
textsize = osptr->oshdr.s_size;
aptr = (ACTITEM *) myalloc(sizeof(ACTITEM));
aptr->bond.aitype = AIBOND;
aptr->bond.aiinflnm = "*default.bond.file*";
aptr->bond.aiinlnno = 2;
aptr->bond.aioutsec = osptr;
aptr->bond.aiadrbnd = textbegin;
listadd(l_AI,&bondlist,aptr);
}
#endif
check_sect( osptr );
}
}
/*
* If .tv is user-defined, we now know the true size of
* the section ( the sum of the sizes of the input
* sections) which we didn't know before. Now call the
* the final update routine to insure .tv symtab entry
* is correct
*/
#if TRVEC
if ( tvflag )
tvupdt2(); /* final update of tvrange and tvlength */
#endif
#if DEBUG
if (dflag)
dmp_outsects();
#endif
}
/*eject*/
OUTSECT *
dfn_scn_grp(aptr, dflt)
ACTITEM *aptr; /* DFNSCN or DFNGRP entry */
int dflt; /* user-supplied or ld-default entry */
{
/*
* Process one AIDFNSCN or AIDFNGRP data structure from
* the list of output sections
*/
OUTSECT *osptr, *op;
INFILE *inflptr;
INSECT *insptr;
ENODE *ep;
long val;
int fill, fillflag;
ACTITEM *a2ptr;
#if !ONEPROC
ACTITEM b;
#endif
#if DEBUG
if( dflag > 2 )
fprintf( stderr, "\n\t%04x %s (%s) %d (%s) %04x (%s)\n\t\t%08lx %d %08lx %08lx %d %d (%04x,%04x)",
aptr->dfnscn.ainext,
(aptr->dfnscn.aitype == AIDFNSCN) ? "AIDFNSCN" : "AIDFNGRP",
aptr->dfnscn.aiinflnm,
aptr->dfnscn.aiinlnno, aptr->dfnscn.ainame, aptr->dfnscn.aifill,
aptr->dfnscn.aiowname, aptr->dfnscn.aibndadr, aptr->dfnscn.aiattown,
aptr->dfnscn.aialign, aptr->dfnscn.aiblock, (unsigned) aptr->dfnscn.aifillfg,
(unsigned) aptr->dfnscn.aisctype, aptr->dfnscn.sectspec.head, aptr->dfnscn.sectspec.tail );
#endif
osptr = (OUTSECT *) myalloc(sizeof(OUTSECT));
if (aptr->dfnscn.aibndadr != -1L) { /* section bonded */
a2ptr = (ACTITEM *) myalloc(sizeof(ACTITEM));
a2ptr->bond.aitype = AIBOND;
a2ptr->bond.aiinflnm = aptr->dfnscn.aiinflnm;
a2ptr->bond.aiinlnno = aptr->dfnscn.aiinlnno;
a2ptr->bond.aioutsec = osptr;
a2ptr->bond.aiadrbnd = aptr->dfnscn.aibndadr;
listadd(l_AI,&bondlist,a2ptr);
}
else if (aptr->dfnscn.aiowname[0] != '\0') { /*owner specified */
a2ptr = (ACTITEM *) myalloc(sizeof(ACTITEM));
a2ptr->dfownr.aitype = AIDFOWNR;
a2ptr->dfownr.aiinflnm = aptr->dfnscn.aiinflnm;
a2ptr->dfownr.aiinlnno = aptr->dfnscn.aiinlnno;
a2ptr->dfownr.aioutsec = osptr;
copy(a2ptr->dfownr.ainamown, aptr->dfnscn.aiowname, 8);
listadd(l_AI,&ownlist,a2ptr);
}
else if (aptr->dfnscn.aiattown != 0) { /* attr of owner */
a2ptr = (ACTITEM *) myalloc(sizeof(ACTITEM));
a2ptr->ownatr.aitype = AIOWNATR;
a2ptr->ownatr.aiinflnm = aptr->dfnscn.aiinflnm;
a2ptr->ownatr.aiinlnno = aptr->dfnscn.aiinlnno;
a2ptr->ownatr.aioutsec = osptr;
a2ptr->ownatr.aiownatt = aptr->dfnscn.aiattown;
listadd(l_AI,&atownlst,a2ptr);
}
if (aptr->dfnscn.aitype == AIDFNGRP)
osptr->oshdr.s_flags = STYP_GROUP;
else
osptr->oshdr.s_flags = aptr->dfnscn.aisctype;
osptr->osalign = aptr->dfnscn.aialign;
osptr->osblock = aptr->dfnscn.aiblock;
osptr->osfill = aptr->dfnscn.aifill;
osptr->osflags |= aptr->dfnscn.aifillfg;
/*
* A DFNSCN need have no subordinate entries, since the following is
* legal:
* .text : {}
*/
if( aptr->dfnscn.sectspec.head == NULL )
return( osptr );
/*
* A DFNGRP is a sequence of one or more DFNSCN entries
*/
if( aptr->dfnscn.aitype == AIDFNGRP ) {
a2ptr = (ACTITEM *) aptr->dfnscn.sectspec.head;
do {
if( ! dflt ) {
#if !ONEPROC
fread( &b, 1, sizeof(ACTITEM), trnfdes );
b.dfnscn.aiinflnm = (char *) ((int) b.dfnscn.aiinflnm + (int) strbase);
a2ptr = &b;
#endif
}
op = dfn_scn_grp(a2ptr, dflt);
op->oshdr.s_paddr = -1L;
listadd(l_GRP, osptr, op);
numoutsc++;
copy(op->oshdr.s_name, a2ptr->dfnscn.ainame, 8);
if( (a2ptr = a2ptr->dfnscn.ainext) == NULL )
return( osptr );
}
while( 1 );
}
/*
* Process a DFNSCN with one or more subordinate entries, of type
* AIADFILE, AIADDSCN, or AIEVEXPR
*/
a2ptr = (ACTITEM *) aptr->dfnscn.sectspec.head;
do {
if( ! dflt ) {
#if !ONEPROC
fread( &b, 1, sizeof(ACTITEM), trnfdes );
b.adfile.aiinflnm = (char *) ((int) b.adfile.aiinflnm + (int) strbase);
a2ptr = &b;
#endif
}
switch( a2ptr->adfile.aitype ) {
case AIADFILE:
if( ! dflt )
a2ptr->adfile.aifilnam = (char *) ((int) a2ptr->adfile.aifilnam + (int) strbase);
#if DEBUG
if( dflag > 2 )
fprintf( stderr, "\n\t%04x AIADFILE (%s) %d (%s) %d %d %d",
a2ptr->adfile.ainext, a2ptr->adfile.aiinflnm,
a2ptr->adfile.aiinlnno, a2ptr->adfile.aifilnam, a2ptr->adfile.ainadscs,
a2ptr->adfile.aifill2, (unsigned) a2ptr->adfile.aifilflg );
#endif
if( (inflptr = fndinfil(a2ptr->adfile.aifilnam)) == NULL )
break;
if( a2ptr->adfile.ainadscs == 0 ) {
insptr = inflptr->flishead;
while( insptr ) {
if( insptr->isoutsec == NULL ) {
inscadd(insptr, osptr);
insptr->isfill = a2ptr->adfile.aifill2;
insptr->isfillfg = a2ptr->adfile.aifilflg;
}
insptr = insptr->isnext;
/*
* In case inflptr is library,
* get next one
*/
if( (insptr == NULL) && (inflptr->flfiloff > 0L) )
while( (inflptr = inflptr->flnext) )
if (strcmp(a2ptr->adfile.aifilnam,inflptr->flname) == 0) {
insptr = inflptr->flishead;
break;
}
}
}
else {
fill = a2ptr->adfile.aifill2;
fillflag = a2ptr->adfile.aifilflg;
}
break;
case AIADDSCN:
if( ! dflt )
a2ptr->addscn.aiscfile = (char *) ((int) a2ptr->addscn.aiscfile + (int) strbase);
#if DEBUG
if( dflag > 2 )
fprintf( stderr, "\n\t%04x AIADDSCN (%s) %d (%s) %04x (%s)",
a2ptr->addscn.ainext, a2ptr->addscn.aiinflnm,
a2ptr->addscn.aiinlnno, a2ptr->addscn.ainame, a2ptr->addscn.aifill,
a2ptr->addscn.aiscfile );
#endif
if( (inflptr = fndinfil(a2ptr->addscn.aiscfile)) == NULL )
break;
insptr = inflptr->flishead;
while(insptr) {
if (equal(a2ptr->addscn.ainame,insptr->ishdr.s_name,8)) {
if (insptr->isoutsec) {
lderror(1, a2ptr->addscn.aiinlnno, a2ptr->addscn.aiinflnm,
"adding %s(%.8s) to multiple output sections",
inflptr->flname,
insptr->ishdr.s_name);
goto contin1;
}
inscadd(insptr,osptr);
insptr->isfill = fill;
insptr->isfillfg = fillflag;
insptr = NULL;
if (inflptr->flfiloff > 0L)
/*
* In case inflptr is library,
* get next one
*/
while( (inflptr = inflptr->flnext) )
if (strcmp(a2ptr->addscn.aiscfile,inflptr->flname) == 0) {
insptr = inflptr->flishead;
break;
}
if ( insptr != NULL )
continue;
else
goto contin1;
}
insptr = insptr->isnext;
}
lderror(1, a2ptr->addscn.aiinlnno, a2ptr->addscn.aiinflnm,
"%s(%.8s) not found",
a2ptr->addscn.aiscfile,a2ptr->addscn.ainame);
break;
case AIEVEXPR:
#if DEBUG
if( dflag > 2 )
fprintf( stderr, "\n\t%04x AIEVEXPR (%s) %d %04x\n\t\tROOT:",
a2ptr->evexpr.ainext, a2ptr->evexpr.aiinflnm,
a2ptr->evexpr.aiinlnno, a2ptr->evexpr.aiexptr );
#endif
#if ONEPROC
aptr = a2ptr;
#else
aptr = ldexp( &b );
#endif
a2ptr = a2ptr->adfile.ainext;
ep = aptr->evexpr.aiexptr;
cur_dot = osptr->oshdr.s_size;
if (ep->gnode.exleft->gnode.exop != DOT) {
/*
* LHS of assnment is regular symbol
*/
dotacid = 0;
dotosptr = osptr;
chgdot(ep->gnode.exright);
listadd(l_AI, &explist, aptr);
}
else {
/*
* LHS is DOT symbol
*/
curexp = aptr;
val = eval(ep->gnode.exright);
if (val < cur_dot)
lderror(1, aptr->evexpr.aiinlnno, aptr->evexpr.aiinflnm,
"attempt to decrement DOT");
else
osptr->oshdr.s_size = val;
clrexp( aptr );
}
goto contin2;
}
contin1:
a2ptr = a2ptr->adfile.ainext;
contin2:
if (a2ptr == NULL)
return( osptr );
}
while( 1 );
}
/*eject*/
inscadd(pin,pout)
INSECT *pin;
OUTSECT *pout;
{
/*
* Add an input section to an output section.
*
* The text, relocation, and lineno info of the input section
* are allocated at the end of the output section.
*/
long btype;
pin->isoutsec = pout;
pin->isdispl = pout->oshdr.s_size;
pin->islndisp = ((long) pout->oshdr.s_nlnno * (long) LINESZ);
pout->oshdr.s_size += pin->ishdr.s_size;
pout->oshdr.s_nlnno += pin->ishdr.s_nlnno;
if (rflag) {
pin->isrldisp = ((long) pout->oshdr.s_nreloc * (long) RELSZ);
pout->oshdr.s_nreloc += pin->ishdr.s_nreloc;
}
btype = pin->ishdr.s_flags & BASIC_TYPES;
if (btype)
pout->oshdr.s_flags |= btype;
else if ( equal( _TEXT, pin->ishdr.s_name, 8 ))
pout->oshdr.s_flags |= STYP_TEXT;
else if ( equal( _DATA, pin->ishdr.s_name, 8 ))
pout->oshdr.s_flags |= STYP_DATA;
else if ( equal( _BSS, pin->ishdr.s_name, 8 ))
pout->oshdr.s_flags |= STYP_BSS;
pout->osflags |= (pin->ishdr.s_flags & STYP_DSECT) ? OSDSECT : OSREG;
if (pin->ishdr.s_flags & STYP_INFO)
pout->osflags |= OSINFO;
if (pin->ishdr.s_flags & STYP_COPY)
pout->osflags |= OSCOPY;
listadd(l_INC,pout,pin);
}
/*eject*/
INFILE *
fndinfil(fnam)
char *fnam;
{
/*
* Locate the input file structure by a given name, and
* return a pointer to the structure.
*
* Note: fnam must be a null terminated string.
*/
register INFILE *p;
p = (INFILE *) infilist.head;
while (p) {
if (strcmp(fnam,p->flname) == 0)
return(p);
p = p->flnext;
}
return(NULL);
}
/*eject*/
chgdot(p)
ENODE *p;
{
register SYMTAB *sym;
ITEMID add_dot();
/*
* This function is called when an assignment is encountered
* within an output section specification, and the LHS of the
* assnment is to a symbol other than DOT. Any occurances of
* DOT within the RHS expression must be replaced by a reference
* to a dummy symbol table entry, which will have the correct
* value after the output section is relocated.
*/
switch(p->gnode.exop) {
case DOT:
if( dotacid == 0 )
dotacid = add_dot(cur_dot, dotosptr);
p->nnode.exsymptr = dotacid;
break;
case NAME:
case INT:
break;
default:
if (p->gnode.exleft)
chgdot(p->gnode.exleft);
if (p->gnode.exright)
chgdot(p->gnode.exright);
}
}
/*eject*/
add_pad()
{
/*
* If the "-B" flag was specified, add any necessary "padding sections"
* to the outpt file
*/
register ANODE *ap; /* ptr into avlist */
ANODE *newap; /* ptr to padding section node */
register OUTSECT *osp;
register INSECT *isp;
int no_need_pad, /* = 1 iff don't need padding */
counter; /* used to make unique names */
char padname[8]; /* padding section name */
/*
* Look for an output section which meets one of two conditions:
*
* 1. The section is comprised entirely of uninitialized .bss
* sections
* 2. The section is of zero length
*
* For every output section of these types, add an additional output
* section immediatly after it. This "padding section" has only two
* non-zero/non-NULL/non-trivial characteristics:
* 1. It is composed of Bflag bytes of zero
* 2. It is written under control of BLOCK(Bflag)
*
* Note that padding sections have a virtual/physical address
* of -1 (to generate errors from any user program or utility
* attempting to use these values), and flags indicating that
* it is a padding section
*/
counter = 0;
for( ap = (ANODE *) avlist.head; ap; ap = ap->adnext ) {
if( ap->adtype != ADSECT )
continue;
osp = ap->adscnptr;
no_need_pad = (osp->osflags & FILL);
for( isp = osp->osinclhd; isp; isp = isp->isincnxt )
if( (isp->ishdr.s_scnptr > 0) || (isp->isfillfg) )
no_need_pad = 1;
if( ap->adsize == 0L )
no_need_pad = 0;
if( no_need_pad )
continue;
osp = (OUTSECT *) myalloc(sizeof(OUTSECT));
numoutsc++;
sprintf( padname, "-pad%2d-", counter++ );
copy( osp->oshdr.s_name, padname, 8 );
osp->oshdr.s_paddr = -1L;
osp->oshdr.s_vaddr = -1L;
osp->oshdr.s_size = Bflag;
osp->oshdr.s_flags = STYP_PAD;
osp->osblock = Bflag;
newap = (ANODE *) myalloc(sizeof(ANODE));
newap->adtype = ADPAD;
newap->adsize = Bflag;
newap->adscnptr = osp;
listins( l_ADR, &avlist, ap, newap );
}
#if DEBUG
if( dflag > 1 ) {
fprintf( stderr, "\nadd_pad" );
dump_mem();
}
#endif
}
/*eject*/
updatsms()
{
/*
* After allocation, this function sets
* 1. The section number of all output sections
* 2. The virtual addresses of all input sections (isnewvad)
* 3. The file offset of output sections
*
* In addition, the relocated value for all global symbols is
* computed and stored in the symbol table, along with the new
* section number.
*
* The virtual addresses of output sections are set by
* audit_regions in allocation.
*/
register SYMTAB *symp;
register OUTSECT *osp;
register INSECT *isp;
int snum, init;
long vaddr, indx;
long filoffst, lnnoptr, nrelocs;
ANODE *ap;
INFILE *fp;
/*
* Compute the starting file offset of the first output section
*
* ********** NOTE NOTE NOTE NOTE **********
*
* Increase the size of the optional header by the amount of
* space needed to generate a patch list
*
* ********** NOTE NOTE NOTE NOTE **********
*/
hflag += psize();
filoffst = (long) FILHSZ + hflag + SCNHSZ * numoutsc;
nrelocs = 0L;
snum = 0;
for( ap = (ANODE *) avlist.head; ap; ap = ap->adnext ) {
if (ap->adtype == ADSECT) {
osp = ap->adscnptr;
/*
***** Special processing *****
*
* The description of the _TV output section is
* changed, so as to make it equivalent to that
* section of the transfer vector actually used
* in this ld run
*
* Note that in the default case - no ASSIGN or
* RANGE commands, the entire transfer vector
* is used, and hence this code produces no
* change.
*
* When ASSIGN and RANGE commands are present,
* the actual section of the transfer vector
* used is typically a subset of the entire
* vector. Output only the piece used
*/
#if TRVEC
if( tvflag && equal(osp->oshdr.s_name,_TV,8) ) {
osp->oshdr.s_paddr +=
(tvspec.tvrange[0] * TVENTSZ);
osp->oshdr.s_vaddr +=
(tvspec.tvrange[0] * TVENTSZ);
osp->oshdr.s_size =
((tvspec.tvrange[1]-tvspec.tvrange[0]+1)*TVENTSZ);
}
#endif
init = (osp->osflags & FILL); /* section is initialized*/
osp->ossecnum = ++snum;
vaddr = osp->oshdr.s_vaddr;
for( isp = osp->osinclhd; isp; isp = isp->isincnxt ) {
isp->isnewvad = vaddr + isp->isdispl;
isp->isnewpad = osp->oshdr.s_paddr + isp->isdispl;
if (isp->ishdr.s_scnptr > 0 || isp->isfillfg)
init = 1;
}
if ((osp->oshdr.s_flags & STYP_NOLOAD) || (osp->oshdr.s_flags & STYP_DSECT))
init = 0;
if (init) {
filoffst += alignment(osp->osblock,filoffst);
osp->oshdr.s_scnptr = filoffst;
filoffst += osp->oshdr.s_size;
if (rflag)
nrelocs += (long) osp->oshdr.s_nreloc;
if (filoffst % 2)
++filoffst;
}
else
osp->oshdr.s_scnptr = 0L;
}
else if( ap->adtype == ADPAD ) {
osp = ap->adscnptr;
osp->ossecnum = ++snum;
filoffst += alignment(osp->osblock,filoffst);
osp->oshdr.s_scnptr = filoffst;
filoffst += osp->oshdr.s_size;
if( filoffst % 2 )
++filoffst;
}
}
/*
* Do the same for the "dummy" sections (DSECTS)
*/
for( osp = (OUTSECT *) dsectlst.head; osp; osp = osp->osdsnext ) {
osp->ossecnum = ++snum;
for( isp = osp->osinclhd; isp; isp = isp->isincnxt ) {
isp->isnewvad = osp->oshdr.s_vaddr + isp->isdispl;
isp->isnewpad = osp->oshdr.s_paddr + isp->isdispl;
}
if ( osp->oshdr.s_flags & (STYP_COPY | STYP_INFO)) {
filoffst += alignment(osp->osblock,filoffst);
osp->oshdr.s_scnptr = filoffst;
filoffst += osp->oshdr.s_size;
if ( rflag )
nrelocs += (long) osp->oshdr.s_nreloc;
if ( filoffst % 2)
++filoffst;
} else {
osp->oshdr.s_nreloc = 0;
osp->oshdr.s_nlnno = 0;
}
}
/*
* Loop through sections a 2nd time to set the
* file pointer to relocation and line numbers for each section
*/
lnnoptr = filoffst + nrelocs * (long) RELSZ;
for( ap = (ANODE *) avlist.head; ap; ap = ap->adnext ) {
if (ap->adtype == ADSECT) {
osp = ap->adscnptr;
if (osp->oshdr.s_flags & STYP_NOLOAD) {
osp->oshdr.s_nreloc = 0;
osp->oshdr.s_nlnno = 0;
continue;
}
if( rflag && (osp->oshdr.s_nreloc != 0) ) {
osp->oshdr.s_relptr = filoffst;
filoffst += ((long)osp->oshdr.s_nreloc *
(long) RELSZ);
}
#if UNIX || XL
if( (!sflag && !xflag) && (osp->oshdr.s_nlnno != 0) ) {
#else
if( (!sflag ) && (osp->oshdr.s_nlnno != 0) ) {
#endif
osp->oshdr.s_lnnoptr = lnnoptr;
lnnoptr += ((long)osp->oshdr.s_nlnno *
(long) LINESZ);
}
}
}
/*
* Do the same for the "copy" sections (COPY)
*/
for( osp = (OUTSECT *) dsectlst.head; osp; osp = osp->osdsnext ) {
if ( osp->oshdr.s_flags & (STYP_COPY | STYP_INFO)) {
if ( rflag && (osp->oshdr.s_nreloc != 0) ) {
osp->oshdr.s_relptr = filoffst;
filoffst += ((long) osp->oshdr.s_nreloc
* (long) RELSZ);
}
if ( (! sflag) && (osp->oshdr.s_nlnno != 0) ) {
osp->oshdr.s_lnnoptr = lnnoptr;
lnnoptr += ((long) osp->oshdr.s_nlnno *
(long) LINESZ);
}
}
}
symtborg = filoffst = lnnoptr;
fp = (INFILE *) infilist.head;
indx = 0;
while (fp) {
fp->flsymndx = indx;
indx += fp->flnlsyms;
fp = fp->flnext;
}
symp = NULL;
while( (symp = loopsym(symp, 1)) != NULL ) {
if( symp->sment.n_scnum > 0 ) {
isp = symp->smscnptr;
symp->sment.n_scnum = isp->isoutsec->ossecnum;
symp->smnewval = symp->sment.n_value
+ isp->isnewpad - isp->ishdr.s_paddr;
symp->smnewvirt = symp->smnewval
- isp->isnewpad + isp->isnewvad;
if( symp->smlocflg ) {
symp->smoutndx += isp->isfilptr->flsymndx;
}
else {
symp->smoutndx = indx++;
indx += symp->sment.n_numaux;
}
}
else {
if ((symp->sment.n_zeroes == 0) ||
(strncmp( symp->sment.n_name, ".dot", 4 ) != 0))
symp->smoutndx = indx++;
symp->smnewval = symp->sment.n_value;
symp->smnewvirt = symp->sment.n_value;
indx += symp->sment.n_numaux;
}
}
#if FLEXNAMES
tnumsyms = indx;
#endif
}
/*eject*/
OUTSECT *
findoscn(number)
int number; /* number of desired section */
{
/*
* Look through the output section list, outsclst,
* for a section with the specified number. Return
* a pointer to that element of the list. If no
* section exists with that number, return NULL.
*/
register OUTSECT *osptr;
osptr = (OUTSECT *) outsclst.head;
while ( osptr != NULL ) {
if ( osptr->ossecnum == number )
return (osptr);
osptr = osptr->osnext;
}
return (NULL);
}
/*eject*/
split_scns()
{
/*
* Run though the output section list. If the size of any output
* section is greater then MAXSCNSZ, split the output section into
* two (or more) output sections
*
* The name of a new section is the first char of the old name,
* followed by a number, followed by the rest of the old
* name. Only eight characters are kept.
*/
OUTSECT *osp, *newosp, *nxtosp;
INSECT *isp, *nxtisp;
char *oldname, newname[20]; /* 8 + 4 + extra */
int scnnumber;
long newdisp, startdisp; /* OUTSECT displacements */
/*
* "osp" scans down the outsclst, and "nxtosp" will
* always point to the next section on the original
* list. If we have to split osp, the new node
* will be newosp, and nxtosp will not change.
*/
for( osp = (OUTSECT *) outsclst.head; osp; osp = nxtosp ) {
nxtosp = osp->osnext;
/* begin KLUDGE */
adjsize(osp);
/* end KLUDGE */
if (osp->oshdr.s_flags & STYP_DSECT)
continue;
if( (osp->osinclhd == osp->osincltl) || (osp->oshdr.s_size <= MAXSCNSZ) ) {
/* Either there is only one input section in the
* output section, or the output section is
* within the permissible size
*/
if( (isp = osp->osinclhd) == NULL )
continue;
if( isp->ishdr.s_size > MAXSCNSIZE ) {
lderror(1,0,NULL, "section %.8s in file %s too big",
isp->ishdr.s_name, isp->isfilptr->flname);
osp->osinclhd = osp->osincltl = NULL;
}
continue;
}
/*
* An output section is too large, and must be split.
*
* Walk through the list of input sections, to build
* two (or more) output sections which are all within
* the permissible size range
*/
osp->oshdr.s_nreloc = 0;
osp->oshdr.s_nlnno = 0;
isp = osp->osinclhd;
osp->osinclhd = osp->osincltl = NULL;
scnnumber = 0;
oldname = osp->oshdr.s_name;
newdisp = 0L;
if( isp != NULL )
startdisp = osp->oshdr.s_size = isp->isdispl;
else
startdisp = osp->oshdr.s_size = 0L;
/*
* "isp" points to the current input section which we
* are trying to add to the output section given by
* "osp"
*/
for(; isp; isp = nxtisp ) {
nxtisp = isp->isincnxt;
if( osp->oshdr.s_size + isp->ishdr.s_size <= MAXSCNSZ ) {
newdisp = isp->isdispl - startdisp;
if( osp->oshdr.s_size > newdisp )
lderror(1,0, NULL,
"internal error: split_scns, size of %.8s exceeds its new displacement",
osp->oshdr.s_name);
osp->oshdr.s_size = newdisp;
isp->isincnxt = NULL;
inscadd(isp, osp);
}
else if ( osp->oshdr.s_size != 0 ) {
nxtisp = isp; /* back up to reprocess */
newosp = (OUTSECT *) myalloc(sizeof(OUTSECT));
numoutsc++;
sprintf(newname, "%c%x%.6s", *oldname,
scnnumber++, oldname + 1);
copy(newosp->oshdr.s_name, newname, 8);
newosp->oshdr.s_paddr = -1L;
newosp->osnext = osp->osnext;
osp->osnext = newosp;
if( (OUTSECT *) outsclst.tail == osp )
outsclst.tail = (char *) newosp;
osp = newosp;
newdisp = 0L;
startdisp = isp->isdispl;
}
else if ( isp->ishdr.s_size <= MAXSCNSIZE ) {
isp->isincnxt = NULL;
inscadd(isp, osp);
}
else
lderror(1,0,NULL, "section %.8s in file %s is too big",
isp->ishdr.s_name, isp->isfilptr->flname);
}
}
}
/*eject*/
psize()
{
/*
* Determine the size of the patch list. This is done by looking for
* all output sections having the name of ".patchnn", where nn is a
* two-digit number
*
* This routine returns, as an int value, the size of the patch list
*/
register int index, space;
char pname[10];
OUTSECT *fndoutsec();
if( ! pflag )
return( 0 );
else
space = sizeof(long);
/*
* Patch sections, if they exist, must be named consecutively, starting
* at ".patch00"
*/
for( index = 0; index < 100; index++ ) {
if (index < 10)
sprintf(pname, ".patch0%d", index);
else
sprintf( pname, ".patch%d", index );
if( fndoutsec(pname) == NULL )
break;
space += PESIZE;
}
return( space );
}
/*eject*/
OUTSECT *
fndoutsec(nam)
char *nam;
{
register OUTSECT *p, *q;
for( p = (OUTSECT *) outsclst.head; p; p=p->osnext ) {
if (p->oshdr.s_flags & STYP_GROUP)
for( q = (OUTSECT *) p->osinclhd; q; q=q->osnext ) {
if (equal(nam,q->oshdr.s_name,8))
return(q);
}
else
if (equal(nam,p->oshdr.s_name,8))
return(p);
}
return(NULL);
}
#if ILDOPT
add_extra()
{
/* If the "-ild" flag was specified, add sections to the output file to
* cover any remaining configured memory.
*/
register ANODE *ap, *newap; /* ptr into avlist */
OUTSECT *osp1, *osp2; /* ptrs to the new output section headers */
int counter; /* used to make unique names */
char sectname[9]; /* new section name */
/* For each remaining area of available memory, create a fake output section
* that fits in that area. The purpose of this is to cover all of configured
* memory so that the incremental ld will be able to determine the memory
* configuration. Increase numoutsc to leave room for the .history section
* header.
*/
numoutsc++;
counter = 0;
for (ap = (ANODE *) avlist.head; ap; ap = ap->adnext) {
if (counter > 99)
break;
if (ap->adtype != ADAVAIL)
continue;
if ( ap != (ANODE *) avlist.head && ap->adprev->adtype != ADAVAIL &&
ap->adprev->adscnptr != NULL &&
(ap->adprev->adscnptr->oshdr.s_flags & STYP_NOLOAD) &&
ap != (ANODE *) avlist.tail && ap->adnext->adtype != ADAVAIL &&
ap->adnext->adscnptr != NULL &&
(ap->adnext->adscnptr->oshdr.s_flags & STYP_NOLOAD) )
continue;
ap->adtype = ADSECT;
newap = (ANODE *) myalloc( sizeof(ANODE) + 2 * sizeof(OUTSECT));
osp1 = (OUTSECT *) (newap + 1);
osp2 = osp1 + 1;
numoutsc += 2;
if (counter < 10)
sprintf(sectname, ".i_l_d0%d", counter++);
else
sprintf( sectname, ".i_l_d%d", counter++);
copy( osp1->oshdr.s_name, sectname, 8 );
osp1->oshdr.s_flags = STYP_DSECT;
ap->adscnptr = osp1;
if (counter < 10)
sprintf( sectname, ".i_l_d0%d", counter++);
else
sprintf( sectname, ".i_l_d%d", counter++ );
copy( osp2->oshdr.s_name, sectname, 8 );
osp2->oshdr.s_paddr = ap->adpaddr;
osp2->oshdr.s_vaddr = ap->adpaddr;
osp2->oshdr.s_size = ap->adsize;
osp2->oshdr.s_flags = STYP_DSECT;
osp2->osflags = 0;
newap->adtype = ADSECT;
newap->adpaddr = ap->adpaddr;
newap->adsize = ap->adsize;
newap->adscnptr = osp2;
newap->admemp = ap->admemp;
newap->adregp = ap->adregp;
listins( l_ADR, &avlist, ap, newap );
}
}
#endif
long
check_sect( osptr )
OUTSECT *osptr;
{
/*
* check the flags in the output section. if all the input sections are dummy
* sections, the output section should be a dummy section.
* If no input section was a regular section and one was a copy section
* the output will be a copy section. If any input section was an info
* section, the output section will have the info flag on. (Most flags
* are not mutually exclusive.)
* if a bss section is combined with data or text, the bss section is
* initialized, and becomes data.
* return the size of the section if the output section is not a dummy
* (the size is used in allocating space for a group).
*/
if ((osptr->osflags & OSDSECT) && !(osptr->osflags & OSREG)) {
osptr->oshdr.s_flags |= STYP_DSECT;
/* remember COPY section also has OSDSECT on */
if (osptr->osflags & OSCOPY)
osptr->oshdr.s_flags |= STYP_COPY;
}
if (osptr->osflags & OSINFO)
osptr->oshdr.s_flags |= STYP_INFO;
if ((osptr->oshdr.s_flags & STYP_BSS) &&
((osptr->oshdr.s_flags & (STYP_TEXT | STYP_DATA)) ||
(osptr->osflags & FILL))) {
osptr->oshdr.s_flags ^= STYP_BSS;
osptr->oshdr.s_flags |= STYP_DATA;
}
if ( !(osptr->oshdr.s_flags & BASIC_TYPES))
if (equal( _TEXT, osptr->oshdr.s_name, 8 ))
osptr->oshdr.s_flags |= STYP_TEXT;
else if (equal( _DATA, osptr->oshdr.s_name, 8 ))
osptr->oshdr.s_flags |= STYP_DATA;
else if (equal( _BSS, osptr->oshdr.s_name, 8 ))
osptr->oshdr.s_flags |= STYP_BSS;
return ((osptr->oshdr.s_flags & STYP_DSECT) ? 0L : osptr->oshdr.s_size);
}