Files
Arquivotheca.SunOS-4.1.4/lang/ld/ld.c
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

5396 lines
130 KiB
C

/*
* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*
* Copyright (c) 1990,1992 by Sun Microsystems, Inc.
*/
#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1980 Regents of the University of California.\n\
All rights reserved.\n\
Copyright (c) 1992 by Sun Microsystems, Inc.\n";
#endif not lint
#ifndef lint
static char sccsid[] = "@(#)ld.c 1.1 94/10/31"; /* from UCB 5.4 85/11/26 */
#endif not lint
/*
* ld - string table version
*/
#include <sys/param.h>
#include <signal.h>
#include <stdio.h>
#include <ctype.h>
#include <ar.h>
#include <a.out.h>
#include <ranlib.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <stab.h>
#include <sys/dir.h>
#include <link.h>
#include "dynamic.h"
#include "reloc_info.h"
#ifdef SUNPRO
#include <vroot.h>
#include <report.h>
#endif
int nsymwrite;
char *rindex();
extern int errno;
char *errmsg();
/*
* Basic strategy:
*
* The loader takes a number of files and libraries as arguments.
* A first pass examines each file in turn. Normal files are
* unconditionally loaded, and the (external) symbols they define and require
* are noted in the symbol table. Libraries are searched, and the
* library members which define needed symbols are remembered
* in a special data structure so they can be selected on the second
* pass. Symbols defined and required by library members are also
* recorded.
*
* After the first pass, the loader knows the size of the basic text
* data, and bss segments from the sum of the sizes of the modules which
* were required. It has computed, for each ``common'' symbol, the
* maximum size of any reference to it, and these symbols are then assigned
* storage locations after their sizes are appropriately rounded.
* The loader now knows all sizes for the eventual output file, and
* can determine the final locations of external symbols before it
* begins a second pass.
*
* On the second pass each normal file and required library member
* is processed again. The symbol table for each such file is
* reread and relevant parts of it are placed in the output. The offsets
* in the local symbol table for externally defined symbols are recorded
* since relocation information refers to symbols in this way.
* Armed with all necessary information, the text and data segments
* are relocated and the result is placed in the output file, which
* is pasted together, ``in place'', by writing to it in several
* different places concurrently.
*/
/*
* Internal data structures
*
* All internal data structures are segmented and dynamically extended.
* The basic structures hold 1103 (NSYM) symbols, ~~200 (NROUT)
* referenced library members, and 100 (NSYMPR) private (local) symbols
* per object module. For large programs and/or modules, these structures
* expand to be up to 40 (NSEG) times as large as this as necessary.
*/
#define NSEG 3000 /* Number of segments, each data structure */
#define NSYM 13103 /* Number of symbols per segment */
#define NROUT 2000 /* Number of library references per segment */
#define NSYMPR 600 /* Number of private symbols per segment */
/*
* Structure describing each symbol table segment.
* Each segment has its own hash table. We record the first
* address in and first address beyond both the symbol and hash
* tables, for use in the routine symx and the lookup routine respectively.
* The symfree routine also understands this structure well as it used
* to back out symbols from modules we decide that we don't need in pass 1.
*
* cs points to the current symbol table segment;
* cs->sy_first[cs->sy_used] is the next symbol slot to be allocated,
* (unless cs->sy_used == NSYM in which case we will allocate another
* symbol table segment first.)
*/
struct symseg {
struct nlist *sy_first; /* base of this alloc'ed segment */
struct nlist *sy_last; /* end of this segment, for n_strx */
int sy_used; /* symbols used in this seg */
struct nlist **sy_hfirst; /* base of hash table, this seg */
struct nlist **sy_hlast; /* end of hash table, this seg */
} symseg[NSEG], nsymseg[NSEG];
struct syminfo {
struct symseg *fs; /* address of first segment */
struct symseg *cs; /* address of current segment */
struct nlist *ls; /* last symbol entered */
struct nlist *ns; /* next symbol entered */
} ldsym = { symseg, symseg, 0, 0 }, /* symbol table for a.out */
shsym = { nsymseg, nsymseg, 0, 0 }; /* symbols from dynamic objects */
/*
* The lookup routine uses quadratic rehash. Since a quadratic rehash
* only probes 1/2 of the buckets in the table, and since the hash
* table is segmented the same way the symbol table is, we make the
* hash table have twice as many buckets as there are symbol table slots
* in the segment. This guarantees that the quadratic rehash will never
* fail to find an empty bucket if the segment is not full and the
* symbol is not there.
*/
#define HSIZE (NSYM*2)
#ifndef n_hash
#define n_hash n_desc
#endif n_hash
/*
* Xsym converts symbol table indices (ala x) into symbol table pointers.
* Symx (harder, but never used in loops) inverts pointers into the symbol
* table into indices using the symseg[] structure.
*/
#define xsym(s, x) (s[(x)/NSYM].sy_first+((x)%NSYM))
/* symx() is a function, defined below */
struct nlist cursym; /* current symbol */
struct nlist *addsym; /* first sym defined during incr load */
int nsym; /* pass2: number of local symbols in a.out */
/* nsym + symx(s, ldsym.ns) is the symbol table size during pass2 */
struct nlist **lookup(), **slookup();
struct nlist *p_etext, *p_edata, *p_end, *entrypt;
/*
* Definitions of segmentation for library member table.
* For each library we encounter on pass 1 we record pointers to all
* members which we will load on pass 2. These are recorded as offsets
* into the archive in the library member table. Libraries are
* separated in the table by the special offset value -1.
*/
off_t li_init[NROUT];
struct libseg {
off_t *li_first;
int li_used;
int li_used2;
} libseg[NSEG] = {
li_init, 0, 0,
}, *clibseg = libseg;
/*
* In processing each module on pass 2 we must relocate references
* relative to external symbols. These references are recorded
* in the relocation information as relative to local symbol numbers
* assigned to the external symbols when the module was created.
* Thus before relocating the module in pass 2 we create a table
* which maps these internal numbers to symbol table entries.
* A hash table is constructed, based on the local symbol table indices,
* for quick lookup of these symbols.
*/
struct local {
int l_index; /* index to symbol in file */
struct nlist *l_symbol; /* ptr to symbol table */
struct local *l_link; /* hash link */
} *lochash[LHSIZ], lhinit[NSYMPR];
struct locseg {
struct local *lo_first;
int lo_used;
} locseg[NSEG] = {
lhinit, 0
}, *clocseg;
/*
* These data structures keep track of symbols of the following type
* stpic for static pic, dpic for data pic, tpic for text pic (or jump)
* npic for relocation in non pic modules.
*/
struct nlist *loc_symb;
struct slsymb {
int sl_offset;
int sl_lo; /* offset into the data/jump linkage */
struct nlist sl_symbol;
struct slsymb *sl_link;
u_char sl_new;
int sl_rc; /* reference count */
} *stpichash[LHSIZ], *dpichash[LHSIZ], *tpichash[LHSIZ],
*npichash[LHSIZ],
stpicinit[NSYMPR], dpicinit[NSYMPR], tpicinit[NSYMPR],
npicinit[NSYMPR];
struct slsseg {
struct slsymb *sls_first;
int sls_used;
};
struct slsseg stpicseg[NSEG] = { stpicinit, 0 }, *stpic;
struct slsseg dpicseg[NSEG] = { dpicinit, 0 }, *dpic;
struct slsseg tpicseg[NSEG] = { tpicinit, 0 }, *tpic;
struct slsseg npicseg[NSEG] = { npicinit, 0 }, *npic;
#define NSAVETAB 8192
char *savetab; /* for symbols build by load1 */
int saveleft;
struct dynamic dynamic;
struct link_dynamic lkd;
struct link_dynamic_2 lkd2;
struct ld_debug ldd;
int doff;
int pad;
#define GT "__GLOBAL_OFFSET_TABLE_"
#define ISGT(x) (!strcmp(GT,x))
#define DYNAMIC 1
#define SYMBOLIC 2
int forceflag = DYNAMIC;
int entryflag;
int referonly; /* load1 use this flag to decide when to bring in any
modules from the .sa archive */
int sa_load; /* ldrand used this flag to skip lookin at the shsym
symbol table when checking out the .sa file */
#define ST_BIND 0x1
#define DN_BIND 0x2
#define DEFINITIONS 0x1
#define NOSYMBOLIC 0x2
#define PURE_TEXT 0x4
int bindingflag;
int assertflag;
struct runtime rt, *rtp = &rt;
#define ISDYNAMIC ((entryflag == 0 && ((bindingflag & DN_BIND) || !(bindingflag & ST_BIND))) || dynamic.lib != 0)
#define SHLIBSTR 1000
char shlibstr[SHLIBSTR];
char *shlibtab = shlibstr;
int shlibleft = SHLIBSTR;
struct slsymb *sllookup();
/*
* Libraries are typically built with a table of contents,
* which is the first member of a library with special file
* name __.SYMDEF and contains a list of symbol names
* and with each symbol the offset of the library member which defines
* it. The loader uses this table to quickly tell which library members
* are (potentially) useful. The alternative, examining the symbol
* table of each library member, is painfully slow for large archives.
*
* See <ranlib.h> for the definition of the ranlib structure and an
* explanation of the __.SYMDEF file format.
*/
int tnum; /* number of symbols in table of contents */
int ssiz; /* size of string table for table of contents */
struct ranlib *tab; /* the table of contents (dynamically allocated) */
char *tabstr; /* string table for table of contents */
/*
* We open each input file or library only once, but in pass2 we
* (historically) read from such a file at 2 different places at the
* same time. These structures are remnants from those days,
* and now serve only to catch ``Premature EOF''.
* In order to make I/O more efficient, we provide routines which
* use the optimal block size returned by stat().
*/
#define BLKSIZE 1024
typedef struct {
short *fakeptr;
int bno;
int nibuf;
int nuser;
char *buff;
int bufsize;
} PAGE;
PAGE page[2];
int p_blksize;
int p_blkshift;
int p_blkmask;
struct {
short *fakeptr;
int bno;
int nibuf;
int nuser;
} fpage;
typedef struct {
char *ptr;
int bno;
int nibuf;
long size;
long pos;
PAGE *pno;
} STREAM;
STREAM text;
STREAM reloc;
/*
* Header from the a.out and the archive it is from (if any).
*/
struct exec filhdr;
struct exec outfilhdr;
struct ar_hdr archdr;
#define OARMAG 0177545
/*
* Options.
*/
int trace;
int xflag; /* discard local symbols */
int Xflag; /* discard locals starting with 'L' */
int Sflag; /* discard all except locals and globals*/
int rflag; /* preserve relocation bits, don't define common */
int arflag; /* original copy of rflag */
int sflag; /* discard all symbols */
int Mflag; /* print rudimentary load map */
int nflag; /* pure procedure */
int dflag; /* define common even with rflag */
int pflag; /* force definition of procedures */
int pdflag; /* pad text to the next page boundary for 410 file */
int zflag; /* demand paged */
long hsize; /* size of hole at beginning of data to be squashed */
int Aflag; /* doing incremental load */
int Tflag = 0;
int Nflag; /* want impure a.out */
int funding; /* reading fundamental file for incremental load */
int yflag; /* number of symbols to be traced */
char **ytab; /* the symbols */
/* Alastair's changes to support Sky Warrior */
int Pflag; /* number of commons to be aligned */
char **Ptab; /* the commons */
#if TARGET==SUN3 || TARGET==SUN2
int use68020; /* 68020-specific instructions used */
#endif /* 680x0 */
/*
* These are the cumulative sizes, set in pass 1, which
* appear in the a.out header when the loader is finished.
*/
off_t tsize, dsize, bsize, trsize, drsize, ssize;
/*
* Symbol relocation: c?rel is a scale factor which is
* added to an old relocation to convert it to new units;
* i.e. it is the difference between segment origins.
* (Thus if we are loading from a data segment which began at location
* 4 in a .o file into an a.out where it will be loaded starting at
* 1024, cdrel will be 1020.)
*/
long ctrel, cdrel, cbrel;
/*
* Textbase is the start address of all text, given by textreloc()
* unless specified by -T, or unless we are still relocating (-r), in
* which case it is 0. Database is the base of all data, computed
* before and used during pass2.
*/
long textbase = -1, database = -1;
#ifdef vax
#define textreloc() 0
#define pagesize() sys_pagesize
#define segsize() sys_pagesize
#endif vax
#ifdef sun
# define textreloc() (zflag ? PAGSIZ+sizeof (struct exec): PAGSIZ)
# define pagesize() PAGSIZ
# define segsize() SEGSIZ
# define seground() sizeof (double)
#endif sun
/*
* Origins of the text and data segments can be regulated by command-
* line flags -Ttext & -Tdata (just -T will be interpreted as -Ttext).
*/
struct origopts{
char *optname;
char *whatbase;
long *flagptr;
long *whatsize;
} origopts[] = {
"T", "text", &textbase, &tsize,
"Ttext", "text", &textbase, &tsize,
"Tdata", "data", &database, &dsize,
(char *)0 ,
};
/*
* changes for Sun-3 and subsequent architectures:
*
* 1. (magic numbers) Magic numbers are 16 bits and are preceded by
* a 16-bit machine type field, which is 0 for Sun-2 and earlier
* architectures. Sun-3 has a machine type of 1.
*
* 2. (segment relocation bases) Changed from Sun-2:
*
* text(old): 0x8000
* text(new): 0x2000 + sizeof(struct exec)
* data(old): begins at a multiple of 0x8000
* data(new): begins at a multiple of 0x20000
*
* 3. (location of a.out header) In all Sun-3 object file formats,
* the exec structure is at the beginning of the text segment.
* In demand-paged (0413) files, this saves about a page of
* disk space.
*/
/*
* The base addresses for the loaded text, data and bss from the
* current module during pass2 are given by torigin, dorigin and borigin.
*/
long torigin, dorigin, ndorigin, borigin;
/*
* Errlev is nonzero when errors have occured.
* Delarg is an implicit argument to the routine delexit
* which is called on error. We do ``delarg = errlev'' before normal
* exits, and only if delarg is 0 (i.e. errlev was 0) do we make the
* result file executable.
*/
int errlev;
int delarg = 4;
/*
* The biobuf structure and associated routines are used to write
* into one file at several places concurrently. Calling bopen
* with a biobuf structure sets it up to write ``biofd'' starting
* at the specified offset. You can then use ``bwrite'' and/or ``bputc''
* to stuff characters in the stream, much like ``fwrite'' and ``fputc''.
* Calling bflush drains all the buffers and MUST be done before exit.
*/
struct biobuf {
int b_nleft; /* Number free spaces left in b_buf */
/* Initialize to be less than b_bufsize initially, to boundary align in file */
char *b_ptr; /* Next place to stuff characters */
char *b_buf; /* Pointer to the buffer */
int b_bufsize; /* Size of the buffer */
off_t b_off; /* Current file offset */
struct biobuf *b_link; /* Link in chain for bflush() */
} *biobufs;
#define bputc(c,b) ((b)->b_nleft ? (--(b)->b_nleft, *(b)->b_ptr++ = (c)) \
: bflushc(b, c))
int biofd;
off_t boffset;
struct biobuf *tout, *dout, *trout, *drout, *sout, *strout, *dynout;
/*
* Offset is the current offset in the string file.
* Its initial value reflects the fact that we will
* eventually stuff the size of the string table at the
* beginning of the string table (i.e. offset itself!).
*/
off_t offset = sizeof (off_t);
char *aoutname = "a.out"; /* name of resultant file: -o argument or a.out */
char ofilename[MAXNAMLEN+1];
int ofilemode; /* respect umask even for unsucessful ld's */
int infil; /* current input file descriptor */
char *filname; /* and its name */
int header_num; /* ordinal # of header file (for dbx) */
#define NDIRS 100 /* programs are getting bigger */
#define NDEFDIRS 3 /* number of default directories in dirs[] */
char *dirs[NDIRS]; /* directories for library search */
int ndir; /* number of directories */
char *ldpath1; /* place to hold make's copy of additionals */
char *ldpath2; /* place to hold ld's copy of additionals */
char *defaults_dir[NDEFDIRS] = {
"/lib",
"/usr/lib",
"/usr/local/lib"
};
#ifdef SUNPRO
pathcellpt sp_dirs[NDIRS]; /* search path containing one directory */
#endif
/*
* Base of the string table of the current module (pass1 and pass2).
*/
char *curstr;
/*
* System software page size
*/
int sys_pagesize;
char get();
int delexit();
char *savestr();
char *malloc();
char *calloc();
char *mymalloc();
/*
* list of all libraries both dynamic and static one.
*/
#define PLAIN 0
#define ARCH1 1 /* archive without table of contents */
#define ARCH2 2 /* archive with table of contents */
#define ARCH3 3 /* archive with out of date table of contents */
#define SHLIB 4 /* shared library */
/*
* definition of flag value
*/
#define DOREADME 1 /* when set do read in my symbol table */
#define DOLOADME 2 /* in load2arg when set do load in needed .o */
struct ldlib {
char *ll_name;
int ll_flag;
int ll_type;
struct ldlib *ll_next;
} *hldlp, **ldlpp;
/*
* Debugging logic
*/
extern printf();
null(){};
int (*dp)();
int is_null = 0;
#ifdef BROWSER
char *cb_program_name = "ld";
int cb_ranlib_saw_library_name = 0;
#include <stab.h>
#define N_BROWS 0x48 /* Zap when 4.1 <stab.h> is installed */
#ifndef cb_executable_tags_h_INCLUDED
#include "cb_executable_tags.h"
#endif
#endif
main(argc, argv)
int argc;
char **argv;
{
register int c, i;
int num;
register char *ap, **p;
char *cp;
char save;
char *ln;
char *getenv();
char *ld_opts;
char **prepend_argv();
struct nlist **spp;
int doneflag = 1;
dp = is_null ? printf : null;
if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
signal(SIGINT, delexit);
signal(SIGTERM, delexit);
}
if (argc == 1)
exit(4);
alloc_inclstack();
sys_pagesize = getpagesize();
/*
* some initializations for doing dynamic linking
*/
dpic = dpicseg;
tpic = tpicseg;
npic = npicseg;
rtp->dp = &dynamic;
rtp->libname = shlibstr;
assertflag |= DEFINITIONS;
dovroot();
ld_opts = getenv("LD_OPTIONS");
if (ld_opts != NULL)
argv = prepend_argv(ld_opts, argv, &argc);
/*
* Scan arguments to determine the correct setting of
* zflag. The text relocation base depends on it, and
* cannot change after the first file is processed.
* We also scan to pick up any "-L" flags, so we can set the
* list of directories to search for libraries in before
* we actually process the libraries.
*/
zflag = 1; /* default: on */
for (c = 1; c < argc; c++) {
ap = argv[c];
if (ap[0] != '-') {
/* not an option string */
doneflag = 0;
continue;
}
for (i=1; ap[i]; i++) {
switch (ap[i]) {
case 'e':
entryflag++;
#ifdef BROWSER
c++;
goto nextarg;
#endif
case 'o':
#ifdef BROWSER
if (!cb_ranlib_saw_library_name) {
cb_ranlib_start_library(argv[c+1],
CB_CURRENT_LANGUAGE,
CB_CURRENT_MAJOR_VERSION,
CB_CURRENT_MINOR_VERSION,
CB_EX_FOCUS_UNIT_PROGRAM_FORMAT);
cb_ranlib_saw_library_name = 1;
}
/* Fall thru */
#endif
case 'u':
doneflag = 0;
case 'H':
case 'D':
case 'A':
case 'T':
case 'a':
/*
* skip the next argument string --
* but look at the rest of the flags
* in the current one (bletch)
*/
c++;
goto nextarg;
case 'l':
case 'y':
case 'B':
/*
* discard the rest of the current argument
* string
*/
goto nextarg;
case 'r':
case 'n':
case 'N':
continue;
case 'L':
/*
* add a directory to the list of directories
* to look for libraries in
*/
if (ap[i+1] == '\0')
error(1, "-L: pathname missing");
if (ndir >= NDIRS - NDEFDIRS)
error(1, "-L: too many directories");
#ifdef SUNPRO
add_dir_to_path(&ap[i+1], &sp_dirs[ndir], 0);
#endif
dirs[ndir++] = &ap[i+1];
goto nextarg;
default:
continue;
}
}
nextarg:
continue;
}
if (doneflag)
exit(0);
for (i = 0; i < ndir; i++)
rtp->spthlen += strlen(dirs[i]) + 1;
if (rtp->spthlen) {
rtp->searchpath = calloc(lalign(rtp->spthlen), 1);
cp = rtp->searchpath;
for (i = 0; i < ndir; i++) {
strcat(cp, dirs[i]);
strcat(cp, ":");
}
cp = rindex(cp, ':');
*cp = '\0';
}
#ifdef SUNPRO
ln = getenv(LDPATH);
i = ndir;
if (ln != NULL) {
ldpath1 = malloc(strlen(ln) + 1);
strcpy(ldpath1, ln);
ln = ldpath1;
for (;;) {
char *cp = ln;
while (*cp != '\0' && *cp != ':')
cp++;
if (*cp == ':') {
*cp = '\0';
add_dir_to_path(ln, &sp_dirs[i++], 0);
ln = cp + 1;
} else {
add_dir_to_path(ln, &sp_dirs[i++], 0);
break;
}
}
}
#endif
ln = getenv(LDPATH);
/* add default search directories */
if (ln != NULL) {
ldpath2 = malloc(strlen(ln) + 1);
strcpy(ldpath2, ln);
ln = ldpath2;
for (;;) {
char *cp = ln;
while (*cp != '\0' && *cp != ':')
cp++;
if (*cp == ':') {
*cp = '\0';
dirs[ndir++] = ln;
ln = cp + 1;
} else {
dirs[ndir++] = ln;
break;
}
}
}
#ifdef SUNPRO
i = ndir;
add_dir_to_path("/lib", &sp_dirs[i++], 0);
add_dir_to_path("/usr/lib", &sp_dirs[i++], 0);
add_dir_to_path("/usr/local/lib", &sp_dirs[i++], 0);
#endif
for (i = 0; i < NDEFDIRS; i++)
dirs[ndir++] = defaults_dir[i];
for (c = 1; c < argc; c++) {
ap = argv[c];
if (ap[0] != '-') {
getlibname(ap);
continue;
}
for (i=1; ap[i]; i++) {
switch (ap[i]) {
case 'o':
case 'u':
case 'H':
case 'D':
case 'e':
case 'T':
case 'a':
/*
* skip the next argument string --
* but look at the rest of the flags
* in the current one (bletch)
*/
c++;
goto nextt;
case 'l':
getlibname(&ap[--i]);
case 'y':
goto nextt;
case 'B':
if (ap[i+1] == '\0')
error(1, "-B: force option missing");
if (!strcmp(&ap[i+1],"static"))
forceflag &= ~DYNAMIC;
else if (!strncmp(&ap[i+1],"symbolic",8)) {
char *c = &ap[i+1];
if (*(c+8) == '=')
getsymb(c+9);
bindingflag |= DN_BIND;
forceflag |= SYMBOLIC;
} else if (!strcmp(&ap[i+1],"dynamic")) {
bindingflag |= DN_BIND;
forceflag |= DYNAMIC;
} else
error(1, "-B: unknown force option");
goto nextt;
case 'n':
case 'N':
case 'A':
bindingflag |= ST_BIND;
forceflag &= ~DYNAMIC;
continue;
case 'r':
rflag++;
continue;
case 'L':
goto nextt;
default:
continue;
}
}
nextt:
continue;
}
if (!rflag)
initss(rtp);
else
if (entryflag)
error(1, "do not mix -e and -r flags.");
if (!entryflag && bindingflag != ST_BIND && !rflag)
textbase = sizeof(struct exec);
p = argv+1;
/*
* Scan files once to find where symbols are defined.
*/
forceflag = DYNAMIC; /* reset to default value */
for (c=1; c<argc; c++) {
if (trace)
printf("%s:\n", *p);
filname = 0;
ap = *p++;
if (*ap != '-') {
load1arg(ap);
continue;
}
for (i=1; ap[i]; i++) switch (ap[i]) {
case 'a': /* align to page size option */
if (strcmp( &ap[i] ,"align")) {
if (strcmp( &ap[i] ,"assert"))
error(1, "-a??? option not recognized");
else {
char *tmp = *p++;
if (++c >= argc)
error(1, "-assert argument missing");
if (!strcmp(tmp, "definitions"))
assertflag |= DEFINITIONS;
else if (!strcmp(tmp, "nodefinitions"))
assertflag &= ~DEFINITIONS;
else if (!strcmp(tmp, "nosymbolic"))
assertflag |= NOSYMBOLIC;
else if (!strcmp(tmp, "pure-text"))
assertflag |= PURE_TEXT;
else
error(1, "[no]definitions, nosymbolic, pure-text are the only valid assert options");
goto next;
}
} else {
if (++c >= argc)
error(1, "-align argument missing");
if (Pflag == 0) {
Ptab = (char **)calloc(argc, sizeof (char **));
if (Ptab == 0)
error(1, "ran out of memory (-align)");
}
Ptab[Pflag++] = *p++;
goto next ;
}
case 'B':
if (ap[i+1] == '\0')
error(1, "-B: force option missing");
if (!strcmp(&ap[i+1],"static"))
forceflag &= ~DYNAMIC;
else if (!strncmp(&ap[i+1],"symbolic", 8)) {
forceflag |= SYMBOLIC;
} else if (!strcmp(&ap[i+1],"dynamic")) {
forceflag |= DYNAMIC;
} else
error(1, "-B: unknown force option");
goto next;
case 'o':
if (++c >= argc)
error(1, "-o: arg missing");
aoutname = *p++;
continue;
case 'u':
case 'e':
if (++c >= argc)
error(1, "-u or -c: arg missing");
spp = slookup(*p, &ldsym);
if (*spp == 0)
rtp->fsalloc += strlen(*p) + 1;
enter(&ldsym, spp, &cursym);
p++;
if (ap[i]=='e')
entrypt = ldsym.ls;
continue;
case 'H':
if (++c >= argc)
error(1, "-H: arg missing");
if (tsize!=0)
error(1, "-H: too late, some text already loaded");
hsize = atoi(*p++);
continue;
case 'A':
if (++c >= argc)
error(1, "-A: arg missing");
if (Aflag)
error(1, "-A: only one base file allowed");
Aflag = 1;
nflag = zflag = 0;
funding = 1;
load1arg(*p++);
trsize = drsize = tsize = dsize = bsize = 0;
ctrel = cdrel = cbrel = 0;
funding = 0;
addsym = ldsym.ns;
continue;
case 'D':
if (++c >= argc)
error(1, "-D: arg missing");
num = htoi(*p++);
if (dsize > num)
error(1, "-D: too small");
dsize = num;
continue;
case 'T':
{
struct origopts *t;
for (t = origopts; t->optname; t++){
if (!strcmp( &ap[i] ,t->optname))
break;
}
if (t->optname==NULL)
error(1, "-%s option unrecognized", &ap[i] );
if (++c >= argc)
error(1, "-%s: arg missing", t->optname);
if (*(t->whatsize)!=0)
error(1, "-%s: too late,some %s already loaded",
t->optname, t->whatbase);
if (*(t->flagptr)>=0 && !Aflag)
error(-1, "-%s: %s base already given: old value overridden",
t->optname, t->whatbase);
*(t->flagptr) = htoi(*p++);
}
goto next;
case 'l':
save = ap[--i];
ap[i]='-';
load1arg(&ap[i]);
ap[i]=save;
goto next;
case 'M':
Mflag++;
continue;
case 'x':
xflag++;
continue;
case 'X':
Xflag++;
continue;
case 'S':
Sflag++;
continue;
case 'r':
rflag++;
arflag++;
/* We don't want to relocate the text. */
if (textbase != 0 && textbase != -1){
if (tsize!=0)
error(1, "-r: too late, some text already loaded");
else
error(0, "-T & -r are mutually exclusive");
}
textbase = 0;
continue;
case 's':
sflag++;
xflag++;
continue;
case 'd':
if (ap[i+1] == 'c' || ap[i+1] == '\0')
dflag++;
else if (ap[i+1] == 'p')
pflag++;
else
error(1, "bad -d flag");
goto next;
case 't':
trace++;
continue;
case 'y':
if (ap[i+1] == 0)
error(1, "-y: symbol name missing");
if (yflag == 0) {
ytab = (char **)calloc(argc, sizeof (char **));
if (ytab == 0)
error(1, "ran out of memory (-y)");
}
ytab[yflag++] = &ap[i+1];
goto next;
case 'N':
Nflag++;
nflag = zflag = 0;
forceflag &= ~DYNAMIC;
continue;
case 'n':
nflag++;
Nflag = zflag = 0;
forceflag &= ~DYNAMIC;
continue;
case 'p':
pdflag++;
continue;
case 'z':
zflag++;
Nflag = nflag = 0;
continue;
case 'L':
goto next; /* we already did this one */
default:
filname = savestr("-x", &savetab, &saveleft); /* kludge */
filname[1] = ap[i]; /* kludge */
archdr.ar_name[0] = 0; /* kludge */
error(1, "bad flag");
}
next:
;
}
ap = rindex( aoutname, '/' );
if ( ap != 0 ){
strncpy( ofilename, aoutname, ap-aoutname+1 );
}
strcat( ofilename, "l.outXXXXXX");
mktemp( ofilename );
header_num = 0;
merge_headers();
endload(argc, argv);
#ifdef BROWSER
cb_ranlib_exit();
#endif
exit(0);
}
/*
* This routine set up theses special symbols for the runtime symbol table.
* It also set up the values here so calcreloc doesn't account any
* reference to these symbols
*/
initss(rt)
register struct runtime *rt;
{
register struct nlist *sp;
struct nlist **slookup();
enter(&ldsym, slookup("_etext", &ldsym), &cursym);
enter(&ldsym, slookup("_edata", &ldsym), &cursym);
enter(&ldsym, slookup("_end", &ldsym), &cursym);
rt->fsalloc += 19; /* lenght of _etext _edata _end plus 3 null */
sp = *slookup("_etext", &ldsym);
ldrsym(sp, -1, N_EXT+N_UNDF);
sp = *slookup("_edata", &ldsym);
ldrsym(sp, -1, N_EXT+N_UNDF);
sp = *slookup("_end", &ldsym);
ldrsym(sp, -1, N_EXT+N_UNDF);
}
getlibname(cp)
char *cp;
{
int kind;
int i;
int dummy;
struct ldlib *llp;
struct ldlib *tllp;
kind = getfile(cp, &dummy, &dummy, NULL);
close(infil);
if (kind == PLAIN)
return (0);
/*
* first time
*/
if (!hldlp)
ldlpp = &hldlp;
else {
for (tllp = hldlp; tllp != NULL; tllp = tllp->ll_next)
if (!strcmp(tllp->ll_name, cp))
return (-1);
}
*ldlpp = llp = (struct ldlib *) mymalloc(sizeof(struct ldlib));
if (!llp)
error(1, "getlibname: out of memory\n");
ldlpp = &llp->ll_next;
llp->ll_flag = llp->ll_type = 0;
llp->ll_next = NULL;
if ((llp->ll_name = mymalloc(strlen(filname)+1)) == NULL)
error(1, "getlibname: out of memory\n");
else
strcpy(llp->ll_name, filname);
switch (kind) {
case ARCH1:
case ARCH2:
case ARCH3:
for (tllp = hldlp; tllp != llp; tllp = tllp->ll_next)
if (tllp->ll_type == SHLIB)
tllp->ll_flag |= DOREADME;
break;
case SHLIB:
bindingflag |= DN_BIND;
llp->ll_type = kind;
break;
default:
error(1, "getlibname: unexpected type of file\n");
}
return (0);
}
/*
* Convert a ascii string which is a hex number.
* Used by -T and -D options.
*/
htoi(p)
register char *p;
{
register int c, n;
n = 0;
while (c = *p++) {
n <<= 4;
if (isdigit(c))
n += c - '0';
else if (c >= 'a' && c <= 'f')
n += 10 + (c - 'a');
else if (c >= 'A' && c <= 'F')
n += 10 + (c - 'A');
else
error(1, "badly formed hex number");
}
return (n);
}
delexit()
{
struct stat stbuf;
long size;
char c = 0;
register int nwritten;
bflush();
unlink(ofilename);
delete_section_temps(); /* for management of extra sections */
/*
* We have to insure that the last block of the data segment
* is allocated a full pagesize block. If the underlying
* file system allocates frags that are smaller than pagesize,
* a full zero filled pagesize block needs to be allocated so
* that when it is demand paged, the paged in block will be
* appropriately filled with zeros.
*/
fstat(biofd, &stbuf);
size = round(stbuf.st_size, pagesize());
if (!rflag && zflag && size > stbuf.st_size) {
lseek(biofd, size - 1, 0);
nwritten = write(biofd, &c, 1);
if (nwritten != 1) {
filname = ofilename; /* kludge */
archdr.ar_name[0] = 0; /* kludge */
if (nwritten < 0)
error(-1, "output write error: %s",
errmsg(errno));
else
error(-1, "output write error: premature EOF");
delarg = 2;
}
}
if (Aflag==0)
(void) chmod(aoutname, ofilemode);
#ifdef BROWSER
cb_ranlib_exit();
#endif
exit (delarg);
}
#define DISCARDIT 0xff
endload(argc, argv)
int argc;
char **argv;
{
register int c, i;
long dnum;
register char *ap, **p;
struct nlist *sp;
clibseg = libseg;
filname = 0;
middle();
setupout();
/*
* In the case of static linking then symbol __DYNAMIC
* has a value of zero to tell crt0 that there is no need
* for any futher relocation.
* Also we dont need to increment ssize to account for
* this mkfsym since we are not going to write the __DYNAMIC
* that is already in the symbol table.
*/
if (!rflag) {
int savexflag;
cursym.n_un.n_name = D_NAME;
savexflag = xflag;
xflag = 0;
if ((sp = *lookup(&ldsym)) == 0) {
if (entryflag) {
if (rtp->dp->lib != 0)
error(1, "_DYNAMIC bootstrapping not available: use -Bstatic.");
else
mkfsym(cursym.n_un.n_name, 0, N_DATA);
} else {
/*
* when we are building a shared library here
* ++++ is this a reasonable assumption???
*/
mkfsym(cursym.n_un.n_name, dorigin, N_DATA);
if (forceflag & SYMBOLIC)
*(rtp->dt + abs(rtp->dp->got_off)) =
dorigin;
}
} else {
mkfsym(sp->n_un.n_name, sp->n_value, N_DATA);
/*
* we are setting the first location of the glob
* table to contain the location of the dynamic
* structure to assist the runtime loader in
* locating it.
*/
if (sp->n_value != 0)
*(rtp->dt + abs(rtp->dp->got_off)) = dorigin;
sp->n_type = DISCARDIT;
}
xflag = savexflag;
nsym++;
forceflag |= DYNAMIC; /* reset it to default value */
}
p = argv+1;
for (c=1; c<argc; c++) {
ap = *p++;
if (trace)
printf("%s:\n", ap);
if (*ap != '-') {
load2arg(ap);
continue;
}
for (i=1; ap[i]; i++) switch (ap[i]) {
case 'D':
dnum = htoi(*p);
if (dorigin < dnum)
while (dorigin < dnum)
bputc(0, dout), dorigin++;
/* fall into ... */
case 'u':
case 'e':
case 'o':
case 'H':
++c;
++p;
/* fall into ... */
default:
continue;
case 'A':
funding = 1;
load2arg(*p++);
funding = 0;
c++;
continue;
case 'a': /* Page align */
case 'T':
++c;
++p;
/* fall into ... */
case 'y':
case 'L':
goto next;
case 'B':
if (!strcmp(&ap[i+1],"static"))
forceflag &= ~DYNAMIC;
else if (!strncmp(&ap[i+1],"symbolic", 8))
forceflag |= SYMBOLIC;
else if (!strcmp(&ap[i+1],"dynamic"))
forceflag |= DYNAMIC;
goto next;
case 'l':
ap[--i]='-';
load2arg(&ap[i]);
goto next;
case 'n':
case 'N':
forceflag &= ~DYNAMIC;
continue;
}
next:
;
}
finishout();
}
struct lslib {
char *libname;
struct lslib *lib_next;
};
struct lslib *rd_shsb();
/*
* Scan file to find defined symbols.
*/
load1arg(cp)
register char *cp;
{
register struct ranlib *tp;
off_t nloc;
int kind;
int i;
char *p, *pp, *tpp;
int maj = 0;
int min = 0;
struct ldlib *tllp;
struct lslib *lp = 0;
static int nosa = 0;
/*
* If the user hasn't somehow specified a textbase (by -T or -r)
* take the default.
*/
if (textbase == -1 && !Aflag)
textbase = textreloc();
kind = getfile(cp, &maj, &min, NULL);
if (Mflag)
printf("%s\n", filname);
switch (kind) {
/*
* Plain file.
*/
case PLAIN:
load1(0, 0L);
break;
/*
* Archive without table of contents.
* (Slowly) process each member.
*/
case ARCH1:
error(-1,
"warning: archive has no table of contents; add one using ranlib(1)");
nloc = SARMAG;
while (step(nloc))
nloc += sizeof(archdr) +
round(atol(archdr.ar_size), sizeof (short));
break;
/*
* Archive with table of contents.
* Read the table of contents and its associated string table.
* Pass through the library resolving symbols until nothing changes
* for an entire pass (i.e. you can get away with backward references
* when there is a table of contents!)
*/
case ARCH2:
nloc = SARMAG + sizeof (archdr);
dseek(&text, nloc, sizeof (tnum));
mget((char *)&tnum, sizeof (tnum), &text);
nloc += sizeof (tnum);
tab = (struct ranlib *)mymalloc(tnum);
if (tab == 0)
error(1, "ran out of memory (toc)");
dseek(&text, nloc, tnum);
mget((char *)tab, tnum, &text);
nloc += tnum;
tnum /= sizeof (struct ranlib);
dseek(&text, nloc, sizeof (ssiz));
mget((char *)&ssiz, sizeof (ssiz), &text);
nloc += sizeof (ssiz);
tabstr = (char *)mymalloc(ssiz);
if (tabstr == 0)
error(1, "ran out of memory (tocstr)");
dseek(&text, nloc, ssiz);
mget((char *)tabstr, ssiz, &text);
for (tp = &tab[tnum]; --tp >= tab;) {
if (tp->ran_un.ran_strx < 0 ||
tp->ran_un.ran_strx >= ssiz)
error(1, "mangled archive table of contents");
tp->ran_un.ran_name = tabstr + tp->ran_un.ran_strx;
}
while (ldrand())
continue;
free((char *)tab);
free(tabstr);
nextlibp(-1);
break;
/*
* Table of contents is out of date, so search
* as a normal library (but skip the __.SYMDEF file).
*/
case ARCH3:
error(-1,
"warning: table of contents for archive is out of date; rerun ranlib(1)");
nloc = SARMAG;
do
nloc += sizeof(archdr) +
round(atol(archdr.ar_size), sizeof(short));
while (step(nloc));
break;
/*
* shared library file.
*/
case SHLIB:
/*
* look up ldlib table to see if we need to read its symbol
* table.
*/
for (tllp = hldlp; tllp; tllp = tllp->ll_next) {
if (!strcmp(tllp->ll_name, filname)) {
if ((tllp->ll_flag & DOREADME)
|| dflag || pflag)
lp = rd_shsb(filname);
break;
}
}
p = cp;
if (p[0] == '-' && p[1] == 'l') {
/*
* remove version string if one was specified;
* save shlib name, then put version string back
*/
if ((tpp = rindex(p,'.')) != 0) {
while (*tpp == '.' || isdigit(*tpp)) {
if (*tpp == '.')
pp = tpp;
tpp--;
}
*pp = '\0';
savestr(p+2, &shlibtab, &shlibleft);
*pp = '.';
} else
savestr(p+2, &shlibtab, &shlibleft);
rtp->lko[rtp->lko_i].lo_library = 1;
rtp->lko[rtp->lko_i].lo_major = maj;
rtp->lko[rtp->lko_i].lo_minor = min;
rtp->dp->libstr += (strlen(p+2) + 1);
/*
* if we are forced to define common then we need
* to bring in the sister library (of the form libx.sa)
* which is of an archive form and has all the
* definitions of both initialized and uninitialized
* commons for the shared library libx.so.
* if it is only -dp then we simply wanted to get the
* size information from the sister library (libx.sa) in
* order to assist later on the calcution of jump slots
* for relocation in non pic code.
*/
if ((dflag || pflag) && !nosa) {
if ((p = rindex(filname, '/')) == 0)
p = filname;
while (*p != '.')
p++;
strncpy(++p, "sa", 2);
if (open(filname, O_RDONLY) >= 0) {
/*
* +++ need to check here whether
* or not it is of the archive type
* of a file.
*/
tllp->ll_flag |= DOLOADME;
sa_load = 1;
if (pflag && !dflag)
referonly = 1;
load1arg(filname);
referonly = 0;
sa_load = 0;
}
}
} else {
savestr(p, &shlibtab, &shlibleft);
rtp->lko[rtp->lko_i].lo_library = 0;
rtp->lko[rtp->lko_i].lo_major = 0;
rtp->lko[rtp->lko_i].lo_minor = 0;
rtp->dp->libstr += (strlen(p) + 1);
}
if (shlibtab > &shlibstr[SHLIBSTR])
error(1,"out of memory for shlib strings");
rtp->dp->lib++;
rtp->lko_i++;
nosa++; /* Don't process .sa files for cascaded refs */
while (lp != 0) {
getlibname(lp->libname);
load1arg(lp->libname);
lp = lp->lib_next;
}
nosa--;
break;
}
close(infil);
}
/*
* Read symbols from shared object *name.
*/
#define VERSION2 2
struct lslib *
rd_shsb(name)
char *name;
{
struct nlist *sp; /* Allocated symbol table */
struct nlist *csp; /* Current symbol entry */
char *str; /* Allocated string area */
int i; /* General temporary */
int fd; /* fd on *name */
struct exec exec; /* For examining header of *name */
struct link_dynamic dinfo; /* For examining dynamic structures */
struct link_dynamic_2 d2; /* More of the same */
int ssize; /* Calculated symbol table size */
char *buf; /* buffer for link objects */
struct lslib *lp = 0, **lpp = &lp;
/*
* Open and sanity check *name.
*/
if ((fd = open(name, O_RDONLY)) == -1)
error(1, "rd_shsb: can't open shared library %s", name);
if (read(fd, &exec, sizeof(struct exec)) != sizeof(struct exec))
error(1,
"rd_shsb: can't read struct exec for shared library %s",
name);
/*
* Object's __DYNAMIC is assumed to be first thing right after
* text. XXX
*/
lseek(fd, exec.a_text, L_SET);
if (read(fd, &dinfo, sizeof(struct link_dynamic)) !=
sizeof (struct link_dynamic))
error(1,
"rd_shsb: can't read struct dynamic for shared library %s",
name);
/*
* Version check the interface and get the appropriate instantiation
* of the __DYNAMIC structure.
*/
if (dinfo.ld_version < VERSION2)
error(1,
"rd_shsb: ld no longer supports this version of %s\n",
name);
lseek(fd, exec.a_text+sizeof(dinfo)+sizeof(struct ld_debug), L_SET);
if (read(fd, &d2, sizeof(struct link_dynamic_2)) != sizeof(d2))
error(1,
"rd_shsb: ld can't read link_dynamic_2 of file %s", name);
/*
* Get the symbol table. Note assumption of layout of dynamic
* information in object, namely that symbol strings immediately
* follow the symbol table.
*/
dinfo.v2 = &d2;
if (dinfo.v2->ld_need) {
struct link_object *lko;
char tmp[1024];
char *cp, *cp1;
/*
* get the object name. This is a bad hack... there should
* be a field denoting the space needed for this aera.
*/
#define LO_BUFSIZE 0x2000
buf = malloc(LO_BUFSIZE);
lseek(fd, dinfo.v2->ld_need, L_SET);
if (read(fd, buf, LO_BUFSIZE) == -1)
error(1, "rd_shsb: can't read link_object stuff\n");
lko = (struct link_object *) buf;
while (1) {
*lpp = (struct lslib *)malloc(sizeof(struct lslib));
(*lpp)->lib_next = (struct lslib *)0;
cp = buf + ((int)lko->lo_name - dinfo.v2->ld_need);
if (lko->lo_library) {
strcpy(tmp, "-l");
strcat(tmp, buf + ((int) lko->lo_name -
dinfo.v2->ld_need));
cp = malloc(strlen(tmp)+1);
strcpy(cp, tmp);
(*lpp)->libname = cp;
lpp = &((*lpp)->lib_next);
} else {
cp1 = malloc(strlen(cp) + 1);
strcpy(cp1, cp);
(*lpp)->libname = cp1;
lpp = &((*lpp)->lib_next);
}
if (lko->lo_next)
lko = (struct link_object *) (buf +
(int) lko->lo_next - dinfo.v2->ld_need);
else
break;
}
free(buf);
}
ssize = dinfo.v2->ld_symbols - dinfo.v2->ld_stab;
if ((sp = (struct nlist *) mymalloc(ssize)) == NULL)
error(1,
"rd_shsb: out of memory for object %s with symbol size %d",
name, ssize);
lseek(fd, dinfo.v2->ld_stab, L_SET);
if (read(fd, sp, ssize) != ssize)
error(1,
"rd_shsb: can't read symbol table for object %s",
name);
/*
* Get the strings.
*/
if ((str = mymalloc(dinfo.v2->ld_symb_size)) == NULL)
error(1,
"rd_shsb: out of memory for strings for object %s",
name);
lseek(fd, dinfo.v2->ld_symbols, L_SET);
if (read(fd, str, dinfo.v2->ld_symb_size) != dinfo.v2->ld_symb_size)
error(1, "rd_shsb: can't read strings for shared library %s",
name);
/*
* Process the symbols in this dynamic object.
*/
csp = sp;
for (i = 0; i < (ssize / sizeof (struct nlist)); i++, csp++) {
/*
* Chuck symbols that are not "extern".
*/
if (!(csp->n_type&N_EXT))
continue;
/*
* Fixup pointer to allocated string area, and then
* get the "current" symbol.
*/
csp->n_un.n_name = str + csp->n_un.n_strx;
cursym = *csp;
/*
* Add this symbol. If it is new, we're done.
*/
if (enter(&shsym, lookup(&shsym), &cursym))
continue;
(*dp)("shsb: collision with %s and %s\n", shsym.ls->n_un.n_name,
cursym.n_un.n_name);
/*
* Symbol collides. If what it collided with is already
* defined, skip over it.
*/
if (shsym.ls->n_type != N_EXT+N_UNDF)
continue;
(*dp)("shsb: collision was with N_EXT+N_UNDF %s\n", shsym.ls->n_un.n_name);
/*
* Collision with an undefined symbol. If the symbol we're
* examining is not a definition, and it has a value, then
* accumulate that value (e.g., common size) into the symbol
* we collided with. Is this an error? Shouldn't we check
* the type of the collided symbol first? I bet so...
*/
if (cursym.n_type == N_EXT+N_UNDF) {
if (cursym.n_value > shsym.ls->n_value)
shsym.ls->n_value = cursym.n_value;
continue;
}
(*dp)("shsb: collision because of new definition of %s, type %x, value %x\n",
cursym.n_un.n_name, cursym.n_type, cursym.n_value);
/*
* Symbol we're adding is a definition of some kind. If
* the symbol we collided with already has a value, and
* the addition is in text, then we're done.
* XXX Why?
*/
if (shsym.ls->n_value != 0 && cursym.n_type == N_EXT+N_TEXT)
continue;
(*dp)("shsb: collision adds a definition for a reference\n");
/*
* Symbol we're adding is a definition for a symbol we already
* have a reference for. Replace the reference with the
* definition and value we're supplying now.
*/
shsym.ls->n_type = cursym.n_type;
shsym.ls->n_value = cursym.n_value;
}
/*
* Leave the symbol strings intact, but free up the symbol table
* scratch space we've allocated and get rid of the descriptor on
* the library.
*/
free((char *) sp);
close(fd);
return(lp);
}
/*
* Advance to the next archive member, which
* is at offset nloc in the archive. If the member
* is useful, record its location in the liblist structure
* for use in pass2. Mark the end of the archive in libilst with a -1.
*/
step(nloc)
off_t nloc;
{
dseek(&text, nloc, (long) sizeof archdr);
if (text.size <= 0) {
nextlibp(-1);
return (0);
}
getarhdr();
(*dp)("step: %.16s\n", archdr.ar_name);
if (load1(1, nloc + (sizeof archdr)))
nextlibp(nloc);
return (1);
}
/*
* Record the location of a useful archive member.
* Recording -1 marks the end of files from an archive.
* The liblist data structure is dynamically extended here.
*/
nextlibp(val)
off_t val;
{
if (clibseg->li_used == NROUT) {
if (++clibseg == &libseg[NSEG])
error(1, "too many files loaded from libraries");
clibseg->li_first = (off_t *)mymalloc(NROUT * sizeof (off_t));
if (clibseg->li_first == 0)
error(1, "ran out of memory (nextlibp)");
}
clibseg->li_first[clibseg->li_used++] = val;
if (val != -1 && Mflag)
printf("\t%s\n", archdr.ar_name);
}
/*
* One pass over an archive with a table of contents.
* Remember the number of symbols currently defined,
* then call step on members which look promising (i.e.
* that define a symbol which is currently externally undefined).
* Indicate to our caller whether this process netted any more symbols.
*/
ldrand()
{
register struct nlist *sp, **hp;
register struct ranlib *tp, *tplast;
off_t loc;
int nsymt = symx(&ldsym, ldsym.ns);
tplast = &tab[tnum-1];
for (tp = tab; tp <= tplast; tp++) {
if ((hp = slookup(tp->ran_un.ran_name, &ldsym)) == 0)
goto next;
if ((sp = *hp) == NULL)
goto next;
if (sp->n_type != N_EXT+N_UNDF)
continue;
else
goto stepit;
next:
if (sa_load)
continue;
if ((hp = slookup(tp->ran_un.ran_name, &shsym)) == 0)
continue;
if ((sp = *hp) == NULL)
continue;
if (sp->n_type != N_EXT+N_UNDF)
continue;
stepit:
step(tp->ran_off);
loc = tp->ran_off;
while (tp < tplast && (tp+1)->ran_off == loc)
tp++;
}
return (symx(&ldsym, ldsym.ns) != nsymt);
}
/*
* Examine a single file or archive member on pass 1.
*/
load1(libflg, loc)
off_t loc;
{
register struct local *lp;
register struct nlist *sp;
struct nlist *savnext;
int ndef, nlocal, type, size, nsymt;
register int i;
off_t maxoff;
struct stat stb;
int symno;
register struct nlist *csp;
off_t saveloc = loc;
struct nlist **hp;
int lpicflag;
static int symsize = 0;
new_obj1();
readhdr(loc);
for (i = 0; i < LHSIZ; i++)
lochash[i] = 0;
clocseg = locseg;
clocseg->lo_used = 0;
symno = -1;
if (loc_symb == 0) {
symsize = filhdr.a_syms;
loc_symb = (struct nlist *) calloc(
filhdr.a_syms/sizeof(struct nlist), sizeof(struct local));
if (loc_symb == 0)
error(1, "out of memory for relocation symbols");
} else {
/*
* check if number of symbols of current file exceed
* the last one, if so free up the last one and allocate
* a new one.
*/
if (filhdr.a_syms > symsize) {
symsize = filhdr.a_syms;
free(loc_symb);
loc_symb = (struct nlist *) calloc(
symsize/sizeof(struct nlist),sizeof(struct local));
if (loc_symb == 0)
error(1,
"out of memory for relocation symbols");
}
}
csp = loc_symb;
if (filhdr.a_syms == 0) {
if (filhdr.a_text+filhdr.a_data == 0) {
if (libflg == 0) {
ssize += sizeof(cursym);
}
return(0);
}
error(1, "no namelist");
}
if (libflg)
maxoff = atol(archdr.ar_size);
else {
fstat(infil, &stb);
maxoff = stb.st_size;
}
if (N_STROFF(filhdr) + sizeof (off_t) >= maxoff)
error(1, "too small (old format .o?)");
ctrel = tsize; cdrel += dsize; cbrel += bsize;
ndef = 0;
nlocal = sizeof(cursym);
savnext = ldsym.ns;
loc += N_SYMOFF(filhdr);
dseek(&reloc, loc + filhdr.a_syms, sizeof(off_t));
mget(&size, sizeof (size), &reloc);
dseek(&reloc, loc + filhdr.a_syms+sizeof (off_t), size-sizeof (off_t));
curstr = (char *)mymalloc(size);
if (curstr == NULL)
error(1, "no space for string table");
mget(curstr+sizeof(off_t), size-sizeof(off_t), &reloc);
/*
* If we are -r'ing a -pic file, we need to "globalize" local
* symbols so they're around when the output gets passed through
* us again.
*/
lpicflag = 0;
if (rflag) {
dseek(&text, loc, filhdr.a_syms);
while (text.size > 0) {
mget((char *)&cursym, sizeof (struct nlist), &text);
if (cursym.n_un.n_strx == 0)
continue;
if (cursym.n_un.n_strx < sizeof (size) ||
cursym.n_un.n_strx >= size)
error(1, "bad string table index (pic pass 1)");
cursym.n_un.n_name = curstr + cursym.n_un.n_strx;
if (ISGT(cursym.n_un.n_name)) {
lpicflag = 1;
break;
}
}
}
/*
* Now process each symbol.
*/
dseek(&text, loc, filhdr.a_syms);
while (text.size > 0) {
symno++;
mget((char *)&cursym, sizeof(struct nlist), &text);
if (cursym.n_un.n_strx) {
if (cursym.n_un.n_strx<sizeof(size) ||
cursym.n_un.n_strx>=size)
error(1, "bad string table index (pass 1)");
cursym.n_un.n_name = curstr + cursym.n_un.n_strx;
#ifdef BROWSER
if (cursym.n_type == N_BROWS) {
if (!cb_ranlib_saw_library_name) {
cb_ranlib_saw_library_name = 1;
cb_ranlib_start_library(aoutname,
CB_CURRENT_LANGUAGE,
CB_CURRENT_MAJOR_VERSION,
CB_CURRENT_MINOR_VERSION,
CB_EX_FOCUS_UNIT_PROGRAM_FORMAT);
}
cb_ranlib_symbol(cursym.n_un.n_name,
cb_focus_program_unit);
}
#endif
(*dp)("load1: %s\t%x\t%x\n", cursym.n_un.n_name, cursym.n_type,
cursym.n_value);
}
type = cursym.n_type;
if (type & N_STAB) {
if (type == N_BINCL) {
start_incl1(&cursym, header_num);
header_num++;
} else if (type == N_EINCL) {
end_incl1();
} else {
stab1(&cursym);
}
}
/*
* do not keep track of any dbx symbols for load1reloc
* +++ is it safe?
*/
if (!(type & N_STAB)) {
if (csp > loc_symb + (symsize/sizeof(struct nlist)))
error(1,
"load1: ran out of local symbol space");
if (clocseg->lo_used == NSYMPR) {
if (++clocseg == &locseg[NSEG])
error(1, "local symbol overflow");
clocseg->lo_used = 0;
}
if (clocseg->lo_first == 0) {
clocseg->lo_first = (struct local *)
calloc(NSYMPR, sizeof (struct local));
if (clocseg->lo_first == 0)
error(1, "out of memory (clocseg)");
}
lp = &clocseg->lo_first[clocseg->lo_used++];
lp->l_index = symno;
*csp = cursym;
lp->l_symbol = csp++;
lp->l_link = lochash[symno % LHSIZ];
lochash[symno % LHSIZ] = lp;
}
if ((type&N_EXT)==0) {
/*
* compiling with pic flag generated local symbol
* and we dont wanted to write these back out.
*/
if (type & N_STAB || cursym.n_un.n_name[0]!='L' ||
(rflag && cursym.n_un.n_name[0]== 'L'
&& (lpicflag)))
nlocal += sizeof cursym;
continue;
}
symreloc();
/*
* Make an entry for this symbol. If it is new, then
* see if a dynamic object has referenced it. If it has,
* then calculate any common contributions or, if this
* symbol contributes a definition, increment count of
* definitions seen.
*
* If the symbol is not new, then see if other references
* have now been satisfied or calculate this symbol's
* common contribution (if appropriate). If this symbol
* satisfies a previously undefined reference, then bump count
* of definitions seen.
*/
if (enter(&ldsym, lookup(&ldsym), &cursym)) {
if ((hp = lookup(&shsym)) == 0)
continue;
if (*hp == NULL)
continue;
if ((*hp)->n_type != N_EXT+N_UNDF)
continue;
if (ldsym.ls->n_type == N_EXT+N_UNDF) {
if ((*hp)->n_value > ldsym.ls->n_value)
ldsym.ls->n_value = (*hp)->n_value;
} else
ndef++;
continue;
} else {
if ((sp = ldsym.ls)->n_type != N_EXT+N_UNDF)
continue;
if (cursym.n_type == N_EXT+N_UNDF) {
if (cursym.n_value > sp->n_value)
sp->n_value = cursym.n_value;
continue;
}
if (referonly)
continue;
if (sp->n_value != 0 && cursym.n_type == N_EXT+N_TEXT)
continue;
ndef++;
sp->n_type = cursym.n_type;
sp->n_value = cursym.n_value;
}
}
if (libflg==0 || ndef) {
tsize += filhdr.a_text;
dsize += round(filhdr.a_data, seground());
bsize += round(filhdr.a_bss, seground());
ssize += nlocal;
trsize += filhdr.a_trsize;
drsize += filhdr.a_drsize;
if (funding) {
if (textbase == -1 && Tflag == 0) {
if ((*slookup("_end", &ldsym)) == 0) {
error(1, "base address is not provided, use option \"-T\" or link the fundamental file with option \"-u _end\"");
}
textbase = (*slookup("_end", &ldsym))->n_value;
}
}
nsymt = symx(&ldsym, ldsym.ns);
for (i = symx(&ldsym, savnext); i < nsymt; i++) {
sp = xsym(ldsym.fs, i);
if (sp->n_un.n_name) {
rtp->fsalloc += strlen(sp->n_un.n_name) + 1;
sp->n_un.n_name = savestr(sp->n_un.n_name,
&savetab, &saveleft);
}
}
load1rel(saveloc);
free(curstr);
return (1);
}
/*
* No symbols defined by this library member.
* Rip out the hash table entries and reset the symbol table.
*/
incl_free();
symfree(&ldsym, savnext);
free(curstr);
return(0);
}
#define TEXTSEG 0
#define DATASEG 1
struct dslot sl;
struct rl rl;
int relocused;
/*
* This routine looked all the relocation datums to determine how
* much space is needed for pic data, pic static, pic and force allocation
* of a jump entry.
*/
load1rel(loc)
off_t loc;
{
int i;
/*
* reintialize static pic stuff after each module
*/
for (i = 0; i < LHSIZ; i++)
stpichash[i] = 0;
stpic = stpicseg;
stpicseg->sls_used = 0;
loc += N_TXTOFF(filhdr);
dseek(&text, loc, filhdr.a_text);
dseek(&reloc, loc+filhdr.a_text+filhdr.a_data, filhdr.a_trsize);
load1reltd(TEXTSEG);
dseek(&text, loc+filhdr.a_text, filhdr.a_data);
dseek(&reloc, loc+filhdr.a_text+filhdr.a_data+filhdr.a_trsize,
filhdr.a_drsize);
load1reltd(DATASEG);
}
#undef relocation_info
#if TARGET== SUN4
# define relocation_info reloc_info_sparc
# define r_symbolnum r_index
#endif
#if TARGET==SUN2 || TARGET==SUN3
# define relocation_info reloc_info_68k
#endif /* mc68000 */
/*
* Get symbol local to the object file being relocated.
*/
static
struct nlist *
getlocsymb(rp)
struct relocation_info *rp;
{
register struct local *lp;
lp = lochash[rp->r_symbolnum % LHSIZ];
for (;;) {
if (lp == 0)
error(1,
"object file inconsistency: nonexistent symbol");
if (lp->l_index == rp->r_symbolnum)
break;
lp = lp->l_link;
}
return(lp->l_symbol);
}
int picflag = 0;
load1reltd(seg)
int seg;
{
register struct nlist *sp;
register struct relocation_info *rp, *rpend;
register struct slsymb *ps;
struct relocation_info *relp;
char *codep;
register char *cp;
int relsz, codesz;
int offset;
relsz = reloc.size;
relp = (struct relocation_info *)mymalloc(relsz);
codesz = text.size;
codep = (char *)mymalloc(codesz);
if (relp == 0 || codep == 0)
error(1, "out of memory (load2td)");
mget((char *)relp, relsz, &reloc);
rpend = &relp[relsz / sizeof (struct relocation_info)];
mget(codep, codesz, &text);
for (rp = relp; rp < rpend; rp++) {
/*
* keep track of the global separeted from the local references
*/
#if TARGET==SUN4
switch (rp->r_type) {
/*
* skip relocation for __GLOBAL_OFFSET_TABLE_
*/
case RELOC_PC22:
case RELOC_PC10:
continue;
case RELOC_BASE13:
case RELOC_BASE10:
case RELOC_BASE22:
if (!picflag) {
if (rp->r_type == RELOC_BASE13)
picflag = 1;
else
picflag = 2;
} else {
if ((picflag == 1 && rp->r_type != RELOC_BASE13)
|| (picflag == 2 &&
!(rp->r_type == RELOC_BASE10 ||
rp->r_type == RELOC_BASE22)))
error(1, "can't mix pic and PIC .o");
}
sp = getlocsymb(rp);
if (rp->r_extern) {
ps = sllookup(&dpic, &dpicseg[NSEG], dpichash,
sp, rp->r_addend, 1, -1);
if (ps->sl_new)
sl.ds++;
} else {
ps = sllookup(&stpic, &stpicseg[NSEG],
stpichash, sp, rp->r_addend, 0, -1);
if (ps->sl_new)
sl.ss++;
}
continue;
case RELOC_JMP_TBL:
sp = getlocsymb(rp);
ps = sllookup(&tpic, &tpicseg[NSEG], tpichash, sp,
0, 1, -1);
if (ps->sl_new)
sl.js++;
continue;
default:
break;
}
#endif
#if TARGET==SUN2 || TARGET==SUN3
cp = codep + rp->r_address;
switch (rp->r_length) {
case 0: /* byte */
offset = *cp;
break;
case 1: /* word */
offset = *(short *)cp;
break;
case 2: /* long */
/* "cp" points to an least a 16-bit boundary, but
* not necessarily a 32-bit boundary.
*/
#ifdef mc68000 /* 68k host can do long accesses on 16-bit boundaries */
offset = *(long *)cp;
#else /*!mc68000*/ /* others can only do long accesses on 32-bit bdy's */
*((short*) (&offset) ) = *((short*) cp );
*((short*)(((char*)(&offset))+2)) = *((short*)(cp+2));
#endif /*mc68000*/
break;
default:
error(1, "load1reltd botch: bad length");
}
if (rp->r_baserel || rp->r_jmptable) {
if (rp->r_jmptable && !rp->r_extern)
continue;
sp = getlocsymb(rp);
if (rp->r_baserel) {
if (!picflag) {
if (rp->r_length == 1)
picflag = 1;
else
picflag = 2;
} else {
if ((picflag == 1 && rp->r_length == 2)
|| (picflag == 2 && rp->r_length == 1))
error(1, "can't mix pic and PIC .o");
}
}
if (rp->r_extern) {
if (rp->r_baserel) {
ps = sllookup(&dpic, &dpicseg[NSEG],
dpichash, sp, offset, 1, -1);
if (ps->sl_new)
sl.ds++;
} else if (rp->r_jmptable) {
ps = sllookup(&tpic, &tpicseg[NSEG],
tpichash, sp, 0, 1, -1);
if (ps->sl_new)
sl.js++;
}
} else {
if (rp->r_baserel) {
ps = sllookup(&stpic, &stpicseg[NSEG],
stpichash, sp, offset, 0, -1);
if (ps->sl_new)
sl.ss++;
}
}
continue;
}
#endif
if (seg == DATASEG) {
rl.rl_d++;
if (rp->r_extern) {
sp = getlocsymb(rp);
#if TARGET==SUN2 || TARGET==SUN3
if (rp->r_pcrel && ISGT(sp->n_un.n_name))
rl.rl_d--;
else {
rl.rl_de++;
(void) sllookup(&npic, &npicseg[NSEG],
npichash, sp, 0, 1, -1);
}
#endif
#if TARGET==SUN4
rl.rl_de++;
(void) sllookup(&npic, &npicseg[NSEG], npichash,
sp, 0, 1, -1);
#endif
}
} else {
/*
* dont count if symbol is "__GLOBAL_OFFSET_TABLE_"
*/
rl.rl_t++;
if (rp->r_extern) {
sp = getlocsymb(rp);
#if TARGET==SUN4
rl.rl_te++;
(void) sllookup(&npic, &npicseg[NSEG], npichash,
sp, 0, 1, -1);
#endif
#if TARGET==SUN2 || TARGET==SUN3
if (rp->r_pcrel && ISGT(sp->n_un.n_name))
rl.rl_t--;
else {
rl.rl_te++;
(void) sllookup(&npic, &npicseg[NSEG],
npichash, sp, 0, 1, -1);
}
#endif
}
}
}
free(relp);
free(codep);
}
/*
* this is a generalized routine to do look up on 3 sort of lists:
* the static, data and jump pic list. The static list is only good per
* module basis while the data and jump list span to all modules.
*/
char *psavetab; /* for symbols needed by load1rel */
int psaveleft;
struct slsymb *
sllookup(slsseg, endseg, slslot, sp, offset, save, lo)
struct slsseg **slsseg;
struct slsseg *endseg;
struct slsymb *slslot[];
struct nlist *sp;
int offset;
int save;
int lo;
{
register int i;
register struct slsymb *ps;
struct slsymb *slfindit();
i = hashit(sp);
ps = slfindit(slslot, sp, offset, i);
if (ps != 0) {
ps->sl_rc++;
return(ps);
}
if ((*slsseg)->sls_used == NSYMPR) {
if (++(*slsseg) == endseg)
error(1, "pic symbol overflow");
(*slsseg)->sls_used = 0;
}
if ((*slsseg)->sls_first == 0) {
(*slsseg)->sls_first = ps = (struct slsymb *)
calloc(NSYMPR, sizeof (struct slsymb));
if ((*slsseg)->sls_first == 0)
error(1, "out of memory(slsseg)");
}
ps = &(*slsseg)->sls_first[(*slsseg)->sls_used++];
ps->sl_offset = offset;
ps->sl_symbol = *sp;
if (save) {
ps->sl_symbol.n_un.n_name =
savestr(ps->sl_symbol.n_un.n_name, &psavetab, &psaveleft);
}
ps->sl_link = slslot[i];
/*
* a value of -1 for the linkoffset means that no slot is assigned
* for this symbol yet.
*/
ps->sl_lo = lo;
ps->sl_new = 1;
ps->sl_rc++;
slslot[i] = ps;
return(ps);
}
int
hashit(sp)
struct nlist *sp;
{
int i;
char *cp;
i = 0;
for (cp = sp->n_un.n_name; *cp;)
i = (i<<1) + *cp++;
return ((i & 0x7fffffff) % LHSIZ);
}
struct slsymb *
slfindit(slslot, sp, offset, slot)
struct slsymb *slslot[];
struct nlist *sp;
{
register struct slsymb *ps;
/* now compare name,offset pair */
ps = slslot[slot];
while (ps != 0) {
if (!strcmp(ps->sl_symbol.n_un.n_name, sp->n_un.n_name)) {
if (ps->sl_offset == offset) {
ps->sl_new = 0;
return(ps);
}
}
ps = ps->sl_link;
}
return(ps);
}
/*
* How the fast symbol hash table is build:
* - There can be at most (dataslot + jumpslot) number of hash slots
* of which the first RTHS slot are the initial buckets. Each
* bucket has 2 items: one denoting the ordinal symbol number
* the other one a pointer in the form of an index to the slots
* following the first RTHS slots.
* - Following right after the hash table for the symbols are the
* symbols themselves followed by the strings.
*/
/*
* This routine look up to the hash table for dynamic symbols.
* return the ordinal symbol number if symbol is found
* else add the symbol and return a -1
*/
int
fslookup(sp, rt)
register struct nlist *sp;
register struct runtime *rt;
{
register int i;
register char *cp;
register struct fshash *p;
struct nlist *sp1 = rt->sp;
static int fs = 0; /* ordinal number for next symbol */
i = 0;
for (cp = sp->n_un.n_name; *cp;)
i = (i<<1) + *cp++;
i = (i & 0x7fffffff) % rt->buckets;
p = rt->hp + i;
if (p->fssymbno == -1) {
p->fssymbno = fs++;
addfs(sp, rt);
} else {
do {
if (!strcmp(sp->n_un.n_name, rt->fsstr +
(sp1+p->fssymbno)->n_un.n_strx))
return(p->fssymbno);
else if (p->next == 0) {
p->next = rt->hp_ind;
p = rt->hp + rt->hp_ind;
rt->hp_ind++;
if (p > rt->hp_last)
error(1, "out of hash space");
p->fssymbno = fs++;
p->next = 0;
addfs(sp, rt);
break;
}
} while (p = rt->hp + p->next);
}
return -1;
}
addfs(sp, rt)
register struct nlist *sp;
register struct runtime *rt;
{
register char *s = sp->n_un.n_name;
register int len;
*(rt->spp) = *sp;
rt->spp->n_un.n_strx = rt->fsoff;
len = strlen(s) + 1;
strcpy(rt->fsstr + rt->fsoff, s);
rt->fsoff += len;
rt->spp++;
if (rt->spp > rt->sp_last)
error(1, "out of dynamic symbol space");
if (rt->fsoff > rtp->fsalloc)
error(1, "out of string space");
}
static int nund = 0;
static int undbanner = 0;
static struct nlist **
ck_shd(sp)
register struct nlist *sp;
{
register struct nlist **hp;
hp = lookup(&shsym);
if (*hp == NULL) {
if (assertflag & DEFINITIONS) {
if (undbanner == 0) {
error(0, "Undefined symbol ");
undbanner = 1;
}
error(-2, " %s ", sp->n_un.n_name);
}
}
return (hp);
}
static int
ck_shs(sp, ps, p)
register struct nlist *sp;
register struct slsymb *ps;
register struct slsymb *p;
{
int count = 0;
register struct nlist **hp;
hp = ck_shd(sp);
if (*hp != NULL) {
if ((*hp)->n_type == N_EXT+N_TEXT) {
count += p->sl_rc - 1;
ps = sllookup(&tpic,&tpicseg[NSEG],tpichash,
sp, 0, 1, -1);
if (ps->sl_new)
sl.js++;
}
}
return (count);
}
/*
* this routine check whether a symbol is in the procedure table or
* in the shared library symbol table.
* ++++ the handling of _end and company is ugly here. must search
* for a better way to do it.
*/
int
calcreloc()
{
register int i;
register int count;
register int tcount = 0;
register struct slsymb *p;
register struct slsymb *ps;
register struct nlist *sp;
register struct nlist **hp;
if (entryflag == 0) /* needed to do relative to absolute */
return (sl.ds + sl.ss + sl.js + rl.rl_d + rl.rl_t);
/*
* go through the dataslot, jumpslot symbols and dont count the
* symbols that are defined. Also go throught the nonpic
* referred symbols and discount symbols that are defined.
*/
count = sl.ds + sl.js;
for (i = 0; i < LHSIZ; i++) {
p = dpichash[i];
while (p != 0) {
cursym = p->sl_symbol;
if ((sp = *lookup(&ldsym)) == 0)
error(1, "calrelco symb lookup botch");
/*
* if we are not forced to define common and
* the symbol is a defined common (non zero
* size) then we still have to allocate
* relocation record for that symbol except
* the case where the symbol is one of these
* special ones _end, _etext, _edata.
*/
if (dflag == 0 && sp->n_type == N_EXT+N_UNDF &&
sp->n_value != 0) {
if (strcmp("_end", sp->n_un.n_name) &&
strcmp("_etext", sp->n_un.n_name) &&
strcmp("_edata", sp->n_un.n_name)) {
p = p->sl_link;
continue;
}
}
if (sp->n_type != N_EXT+N_UNDF ||
sp->n_value != 0)
count--;
else {
(void) ck_shd(sp);
}
p = p->sl_link;
}
}
/*
* should I allowed people to jump to _end, _edata, _etext
* here ++++++++++
*/
for (i = 0; i < LHSIZ; i++) {
p = tpichash[i];
while (p != 0) {
cursym = p->sl_symbol;
if ((sp = *lookup(&ldsym)) == 0)
error(1, "calrelco symb lookup botch");
if (sp->n_type != N_EXT+N_UNDF || sp->n_value != 0)
count--;
else {
(void) ck_shd(sp);
}
p = p->sl_link;
}
}
tcount += count;
count = rl.rl_de + rl.rl_te;
/*
* if we are not forced to allocate common and procedure
* then what we need to discount are the relocations to defined
* symbols that are not of the type N_EXT+N_UNDF with a non zero
* size.
*
* if we are forced to define both then what we needed
* are the relocations for the extra jump slots (at this
* time whatever symbols that are left in this table (npichash)
* of the type N_EXT+N_UNDF with a size of 0 should have a
* definition in the shsym symbol table of type N_EXT+N_TEXT)
*
* if we are forced to define only common, then we can only
* discount all relocation to N_EXT+N_UNDF with non zero size.
*
* if we are forced to define only procedure then we can
* discount a) relocation(s) to defined routine in user program,
* b) for relocation(s) to routine already in the jump table
* we can discount the reference count to that symbol,
* c) the last step here is to determine if the symbol is
* a common in which case we can't discount the references to it.
* the algorithm we used to determine whether it is a common is
* to check whether the type is N_UNDF+N_EXT with a non zero size.
* (we presume that the ".sa" file's symbols are used to update
* the size information for any match found in the static symbol
* table; however none of the modules are not brought in.)
* if the symbol is not a common then we need then to decide
* whether it is a routine by checking to see if it's type
* is N_EXT+N_TEXT in the shlib symbol table; we can discount
* reference count - 1 since we need a relocation datum for that
* entry in the jump table.
*/
for (i = 0; i < LHSIZ; i++) {
p = npichash[i];
while (p != 0) {
cursym = p->sl_symbol;
if ((sp = *lookup(&ldsym)) == 0)
error(1, "calrelco symb lookup botch");
/*
* case where we are not forced to define
* both commons and procedures
*/
if (dflag == 0 && pflag == 0) {
if (sp->n_type != N_EXT+N_UNDF)
count -= p->sl_rc;
else {
if (!strcmp("_end", sp->n_un.n_name) ||
!strcmp("_etext",sp->n_un.n_name) ||
!strcmp("_edata", sp->n_un.n_name))
count -= p->sl_rc;
}
} else if (dflag && pflag) {
/*
* case where we are forced to define
* both commons and procedures
*/
if (sp->n_type != N_EXT+N_UNDF ||
sp->n_value != 0)
count -= p->sl_rc;
else {
if ((ps = slfindit(tpichash, sp,
0, hashit(sp))))
count -= p->sl_rc;
else
count -= ck_shs(sp, ps, p);
}
} else if (dflag) {
/*
* common are forced to be defined (-dc).
*/
if (sp->n_type != N_EXT+N_UNDF ||
sp->n_value != 0)
count -= p->sl_rc;
} else {
/*
* only procedure are forced to be defined (-dp)
*/
if (sp->n_type != N_EXT+N_UNDF)
count -= p->sl_rc;
else if (!strcmp("_end", sp->n_un.n_name) ||
!strcmp("_etext", sp->n_un.n_name) ||
!strcmp("_edata", sp->n_un.n_name))
count -= p->sl_rc;
else if (sp->n_value == 0) {
if ((ps = slfindit(tpichash,
sp, 0, hashit(sp))))
count -= p->sl_rc;
else
count -= ck_shs (sp, ps, p);
}
}
p = p->sl_link;
}
}
tcount += count;
return(tcount);
}
middle()
{
register struct nlist *sp;
register struct nlist *sp1;
long csize, t, corigin, ocsize;
int rnd;
char s;
register int i;
register int j;
int nsymt;
int otsize;
torigin = 0;
dorigin = 0;
borigin = 0;
if (!rflag) {
/*
* needed to kludge this here so calcreloc to discount
* the reference to __DYNAMIC from crt0.s.
*/
if ((sp = *slookup(D_NAME, &ldsym)) != NULL)
ldrsym(sp, -1, N_EXT+N_DATA);
if ((ISDYNAMIC) || forceflag & SYMBOLIC) {
rt_init(rtp);
for (i = 0; i < NSEG; i++)
if (ldsym.fs[i].sy_first != 0) {
sp = ldsym.fs[i].sy_first;
for (j = 0; j<ldsym.fs[i].sy_used;j++) {
fslookup(sp, rtp);
sp++;
}
} else
break;
dj_init(rtp, &sl, 1);
dp_init(rtp);
} else {
/*
* case of pic code link statically
*/
dj_init(rtp, &sl, 0);
}
}
p_etext = *slookup("_etext", &ldsym);
p_edata = *slookup("_edata", &ldsym);
p_end = *slookup("_end", &ldsym);
nsymt = symx(&ldsym, ldsym.ns);
if (rflag)
sflag = zflag = 0;
/*
* Assign common locations.
*/
csize = 0;
if (!Aflag)
addsym = ldsym.fs[0].sy_first;
#ifdef sun
if (zflag) {
/*
* in Sun-x demand-paged programs,
* the exec structure is in text space
*/
tsize += sizeof(struct exec);
}
#endif sun
otsize = tsize; /* original tsize without shared lib stuff */
if (!rflag && (ISDYNAMIC))
tsize += dynamic.rs + dynamic.hs + dynamic.ss + dynamic.sts +
dynamic.libstr + (rtp->spthlen ? lalign(rtp->spthlen) : 0) +
(rtp->dp->lib*sizeof(struct link_object));
#if (TARGET==SUN2) || (TARGET==SUN3) /* i.e. mc68000 */
/*
* prevent programs from ending exactly on a page boundary;
* if they do, they will coredump as they prefetch the last
* "unlk a6; rts" instruction sequence (bug in unlk instruction)
*/
if (tsize > 0 && tsize % pagesize() == 0) {
tsize += sizeof(long);
}
#endif /* mc68000 */
if (database == -1 ){
/* compute normal, default data base */
database = textbase + tsize;
#ifdef sun
if (zflag) {
/*
* Don't count the header TWICE. If we do, and
* the data segment gets put at the next segment
* boundary as a result, we'll disagree with exec,
* and data references will end up in no man's land.
*/
database -= sizeof(struct exec);
}
#endif sun
if (!Aflag)
database = round(database, (nflag||zflag||pdflag ?
segsize() : seground()));
database += hsize;
}
/*
* +++ dont allocate common if dflag is not on
*/
if (!rflag || dflag) {
ldrsym(p_etext, tsize, N_EXT+N_TEXT);
ldrsym(p_edata, dsize, N_EXT+N_DATA);
ldrsym(p_end, bsize, N_EXT+N_BSS);
if (dflag || forceflag & SYMBOLIC || bindingflag == ST_BIND ||
(entryflag && rtp->dp->lib == 0)) {
for (i = symx(&ldsym, addsym); i < nsymt; i++) {
sp = xsym(ldsym.fs, i);
if ((s=sp->n_type)==N_EXT+N_UNDF &&
(t = sp->n_value)!=0) {
if (t >= sizeof (double))
rnd = sizeof (double);
else if (t >= sizeof (long))
rnd = sizeof (long);
else
rnd = sizeof (short);
/*
* check if this common is to
* be page aligned
*/
if (Pflag && sp->n_un.n_name) {
int ii;
for (ii = 0; ii < Pflag; ii++)
if(Ptab[ii][1] ==
sp->n_un.n_name[1] &&
!strcmp(Ptab[ii],
sp->n_un.n_name)) {
rnd = pagesize();
t = round(t,pagesize());
break;
}
}
csize = round(csize, rnd);
sp->n_value = csize;
sp->n_type = N_EXT+N_COMM;
ocsize = csize;
csize += t;
}
if (s&N_EXT && (s&N_TYPE)==N_UNDF && s&N_STAB) {
sp->n_value = ocsize;
sp->n_type =(s&N_STAB) | (N_EXT+N_COMM);
}
}
}
}
/*
* Now set symbols to their final value
*/
if (!rflag && ((ISDYNAMIC) || (dynamic.ds + dynamic.js))) {
lkd.v2 = &lkd2;
lkd.ldd = &ldd;
init_lkd(&lkd, rtp, otsize, database);
i = sizeof(struct link_dynamic) + sizeof(struct link_dynamic_2)
+ sizeof (struct ld_debug) + dynamic.ds + dynamic.js;
if (i % sizeof(double))
pad = sizeof(double) - (i % sizeof(double));
doff = i + pad;
}
csize = round(csize, seground());
torigin = textbase;
dorigin = database;
ndorigin = database + doff;
corigin = ndorigin + dsize;
if(Pflag) { /* make sure commons start on a page boundary */
corigin = round(corigin, pagesize());
} else
corigin = round(corigin, seground()); /* Commons must start on seg bdy. */
borigin = corigin + csize;
nsymt = symx(&ldsym, ldsym.ns);
for (i = symx(&ldsym, addsym); i<nsymt; i++) {
sp = xsym(ldsym.fs, i);
switch (sp->n_type & (N_TYPE+N_EXT)) {
case N_EXT+N_UNDF:
if (arflag == 0 && !(ISDYNAMIC) &&
!(dynamic.ds + dynamic.js) )
errlev |= 01;
if ((arflag==0 || dflag) && sp->n_value==0) {
if (sp==p_end || sp==p_etext || sp==p_edata)
continue;
if (undbanner == 0)
if (!(ISDYNAMIC) &&
!ISGT(sp->n_un.n_name)) {
error(0, "Undefined symbol");
undbanner = 1;
}
if (!rflag && !ISGT(sp->n_un.n_name))
nund++;
if (!(ISDYNAMIC) && !ISGT(sp->n_un.n_name))
error(-2, " %s", sp->n_un.n_name);
}
continue;
case N_EXT+N_ABS:
default:
continue;
case N_EXT+N_TEXT:
sp->n_value += torigin;
continue;
case N_EXT+N_DATA:
sp->n_value += ndorigin;
continue;
case N_EXT+N_BSS:
sp->n_value += borigin;
continue;
case N_EXT+N_COMM:
/*
* ++++ why this in sun4 ld
*/
if (dflag || rflag == 0) {
sp->n_type = (sp->n_type & N_STAB) | (N_EXT+N_BSS);
sp->n_value += corigin;
}
continue;
}
}
if (!rflag)
if ((sp = *slookup(GT, &ldsym)) != NULL)
ldrsym(sp, lkd.v2->ld_got, N_EXT+N_DATA);
rtp->us = nund;
if (sflag || xflag)
ssize = 0;
if ( (sp = *slookup(D_NAME, &ldsym)) != NULL) {
/*
* now load in the real value of __DYNAMIC.
* if there is a definition for __DYNAMIC and rflag is on
* just leave it alone (i.e ld -x -r crt0.o)
*/
if (!rflag) {
sp->n_type = N_EXT+N_DATA;
if (ISDYNAMIC || forceflag & SYMBOLIC)
sp->n_value = dorigin;
else
sp->n_value = 0;
}
} else {
/*
* if there is no reference to __DYNAMIC symbol
* then we need to account for it here since we will
* be writing this symbol in endload.
* In the case where it is already in the ldsym table
* then we dont need to account for it here since we
* wanted to avoid writing out the same symbol twice.
*/
if (!rflag)
ssize += sizeof cursym;
}
bsize += csize;
nsym = ssize / (sizeof cursym);
if (Aflag) {
fixspec(p_etext,torigin);
fixspec(p_edata,dorigin);
fixspec(p_end,borigin);
}
/*
* update value field for all the symbols used for dynamic linking.
*/
if (!rflag)
if ((ISDYNAMIC) || forceflag & SYMBOLIC) {
sp1 = rtp->sp;
for (i = 0; i < totalsymb(); i++) {
cursym.n_un.n_name = rtp->fsstr +
sp1->n_un.n_strx;
if ( (sp = *lookup(&ldsym)) == 0 )
error(1, "fast symbol not found");
sp1->n_value = sp->n_value;
sp1->n_type = sp->n_type;
sp1++;
}
}
/*
* Finally, verify that all .so symbols would be satisfied if we
* were to run now.
*/
if (!(assertflag & DEFINITIONS))
return;
nsymt = symx(&shsym, shsym.ns);
for (i = symx(&shsym, 0); i < nsymt; i++) {
sp = xsym(shsym.fs, i);
if ((sp->n_type == (N_EXT + N_UNDF)) && (sp->n_value == 0)) {
cursym = *sp;
sp1 = *lookup(&ldsym);
if (sp1 == NULL ||
((sp1->n_type == (N_EXT + N_UNDF)) &&
(sp1->n_value == 0))) {
if (undbanner == 0) {
error(0, "Undefined symbol");
undbanner = 1;
}
error(-2, " %s", sp->n_un.n_name);
}
}
}
}
fixspec(sym,offset)
struct nlist *sym;
long offset;
{
if (symx(&ldsym, sym) < symx(&ldsym, addsym) && sym!=0)
sym->n_value += offset;
}
ldrsym(sp, val, type)
register struct nlist *sp;
long val;
{
if (sp == 0)
return;
if ((sp->n_type != N_EXT+N_UNDF) && !Aflag) {
error(0, "%s: user attempt to redefine loader-defined symbol",
sp->n_un.n_name);
return;
}
sp->n_type = type;
sp->n_value = val;
}
off_t wroff;
struct biobuf toutb;
setupout()
{
int bss;
struct stat stbuf;
int ds;
int ntsize;
ofilemode = 0777 & ~umask(0);
biofd = creat(ofilename, 0666 & ofilemode);
if (biofd < 0) {
filname = ofilename; /* kludge */
archdr.ar_name[0] = 0; /* kludge */
error(1, errmsg(errno)); /* kludge */
}
fstat(biofd, &stbuf); /* suppose file exists, wrong*/
if (stbuf.st_mode & 0111) { /* mode, ld fails? */
chmod(ofilename, stbuf.st_mode & 0666);
ofilemode = stbuf.st_mode;
}
#if TARGET==SUN3 || TARGET==SUN2
outfilhdr.a_machtype = (use68020 ? M_68020 : M_68010);
#endif /* mc680x0 */
#if TARGET == SUN4
outfilhdr.a_toolversion = TV_SUN4;
outfilhdr.a_machtype = M_SPARC;
#endif /* sun4 */
outfilhdr.a_magic = nflag ? NMAGIC : (zflag ? ZMAGIC : OMAGIC);
outfilhdr.a_text = round(tsize,zflag||pdflag?pagesize():seground());
ds = dsize;
if (!rflag && ((ISDYNAMIC) || (dynamic.ds + dynamic.js))) {
if (ISDYNAMIC)
outfilhdr.a_dynamic = 1;
ds += doff;
lkd.v2->ld_text = outfilhdr.a_text;
}
outfilhdr.a_data = round(ds, zflag ? pagesize() : seground());
bss = bsize - (Pflag ? 0 : (outfilhdr.a_data - ds));
if (bss < 0)
bss = 0;
outfilhdr.a_bss = bss = round(bss, seground());
outfilhdr.a_trsize = trsize;
outfilhdr.a_drsize = drsize;
outfilhdr.a_syms = sflag? 0:
(ssize + (sizeof cursym)*(symx(&ldsym, ldsym.ns)-rtp->us));
if (entrypt) {
if (entrypt->n_type!=N_EXT+N_TEXT)
error(0, "entry point not in text");
else
outfilhdr.a_entry = entrypt->n_value;
} else
outfilhdr.a_entry = textbase;
outfilhdr.a_trsize = (rflag ? trsize:0);
outfilhdr.a_drsize = (rflag ? drsize:0);
tout = &toutb;
bopen(tout, 0, stbuf.st_blksize);
bwrite((char *)&outfilhdr, sizeof (outfilhdr), tout);
#ifndef sun
if (zflag)
bseek(tout, pagesize());
#endif sun
wroff = N_TXTOFF(outfilhdr) + outfilhdr.a_text;
/*
* in case of static linking only space for data and jump linkage
* is needed else the dynamic header, relocation datum and the fast
* symbol table will be added before the real data segment began.
*/
if (!rflag && ((ISDYNAMIC) || (dynamic.ds + dynamic.js))) {
struct link_dynamic lk;
outb(&dynout, doff, stbuf.st_blksize);
lk.ld_version = 3;
(int) (lk.ldd) = (int)database + sizeof(struct link_dynamic);
(int) (lk.v2) = (int)lk.ldd + sizeof(struct ld_debug);
lkd.v2->ld_buckets = rtp->buckets;
bwrite((char *)&lk, sizeof(struct link_dynamic), dynout);
bwrite((char *)(lkd.ldd), sizeof(struct ld_debug), dynout);
bwrite((char *)(lkd.v2), sizeof(struct link_dynamic_2), dynout);
}
outb(&dout, outfilhdr.a_data - doff, stbuf.st_blksize);
if (rflag) {
outb(&trout, outfilhdr.a_trsize, stbuf.st_blksize);
outb(&drout, outfilhdr.a_drsize, stbuf.st_blksize);
}
if (sflag==0 || xflag==0) {
outb(&sout, outfilhdr.a_syms, stbuf.st_blksize);
wroff += sizeof (offset);
outb(&strout, 0, stbuf.st_blksize);
}
}
outb(bp, inc, bufsize)
register struct biobuf **bp;
{
*bp = (struct biobuf *)mymalloc(sizeof (struct biobuf));
if (*bp == 0)
error(1, "ran out of memory (outb)");
bopen(*bp, wroff, bufsize);
wroff += inc;
}
int localsymbolno = 0;
load2arg(acp)
char *acp;
{
register char *cp;
register int i;
register int j;
register char *p;
off_t loc;
int dummy;
struct ldlib *tllp;
long maxoff;
cp = acp;
if ((i = getfile(cp, &dummy, &dummy, &maxoff)) == 0) {
while (*cp)
cp++;
while (cp >= acp && *--cp != '/');
mkfsym(++cp, torigin, N_TEXT);
localsymbolno++;
load2(0L, maxoff);
} else { /* scan archive members referenced */
if (i != SHLIB) {
for (;;) {
if (clibseg->li_used2 == clibseg->li_used) {
if (clibseg->li_used < NROUT)
error(1, "libseg botch");
clibseg++;
}
loc = clibseg->li_first[clibseg->li_used2++];
if (loc == -1)
break;
dseek(&text, loc, (long)sizeof(archdr));
getarhdr();
mkfsym(archdr.ar_name, torigin, N_TEXT);
if (rflag)
localsymbolno++;
load2(loc + (long)sizeof(archdr), atol(archdr.ar_size));
}
} else {
for (tllp = hldlp; tllp; tllp = tllp->ll_next) {
if (!strcmp(tllp->ll_name, filname)) {
if (tllp->ll_flag & DOLOADME) {
if (!(p = rindex(filname, '/')))
p = filname;
while (*p != '.')
p++;
strncpy(++p, "sa", 2);
load2arg(filname);
}
break;
}
}
}
}
close(infil);
}
load2(loc, maxoff)
int loc;
long maxoff;
{
int size;
register struct nlist *sp;
register struct local *lp;
register int symno, i;
int type;
int exclude;
register struct nlist *csp;
int lpicflag;
int lsymbno;
exclude = 0;
readhdr(loc);
if (!funding) {
ctrel = torigin;
cdrel += ndorigin;
cbrel += borigin;
}
/*
* Reread the symbol table, recording the numbering
* of symbols for fixing external references.
*/
for (i = 0; i < LHSIZ; i++)
lochash[i] = 0;
clocseg = locseg;
clocseg->lo_used = 0;
symno = -1;
csp = loc_symb;
/*
* reintialize static pic stuff after each module
*/
for (i = 0; i < LHSIZ; i++)
stpichash[i] = 0;
stpic = stpicseg;
stpicseg->sls_used = 0;
loc += N_TXTOFF(filhdr);
dseek(&text, loc+filhdr.a_text+filhdr.a_data+
filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms, sizeof(off_t));
mget(&size, sizeof(size), &text);
dseek(&text, loc+filhdr.a_text+filhdr.a_data+
filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms+sizeof(off_t),
size - sizeof(off_t));
curstr = (char *)mymalloc(size);
if (curstr == NULL)
error(1, "out of space reading string table (pass 2)");
mget(curstr+sizeof(off_t), size-sizeof(off_t), &text);
/*
* detect the existance of the extra sections.
* go blat them to temp files.
*/
if ( maxoff > N_STROFF(filhdr)+size ){
/* it should be out there. go get it */
collect_extra_sections( &text, loc,
filhdr.a_text+filhdr.a_data+
filhdr.a_trsize+filhdr.a_drsize+
filhdr.a_syms+size, maxoff );
}
/*
* If we are -r'ing a -pic file, we need to "globalize" local
* symbols so they're around when the output gets passed through
* us again.
*/
lpicflag = 0;
if (rflag) {
dseek(&text, loc+filhdr.a_text+filhdr.a_data+
filhdr.a_trsize+filhdr.a_drsize, filhdr.a_syms);
while (text.size > 0) {
mget((char *)&cursym, sizeof (struct nlist), &text);
if (cursym.n_un.n_strx == 0)
continue;
if (cursym.n_un.n_strx < sizeof (size) ||
cursym.n_un.n_strx >= size)
error(1, "bad string table index (pic pass 1)");
cursym.n_un.n_name = curstr + cursym.n_un.n_strx;
if (ISGT(cursym.n_un.n_name)) {
lpicflag = 1;
break;
}
}
}
/*
* Now process each symbol.
*/
dseek(&text, loc+filhdr.a_text+filhdr.a_data+
filhdr.a_trsize+filhdr.a_drsize, filhdr.a_syms);
lsymbno = 0;
while (text.size > 0) {
symno++;
mget((char *)&cursym, sizeof(struct nlist), &text);
if (cursym.n_un.n_strx) {
if (cursym.n_un.n_strx<sizeof(size) ||
cursym.n_un.n_strx>=size)
error(1, "bad string table index (pass 2)");
cursym.n_un.n_name = curstr + cursym.n_un.n_strx;
}
if (cursym.n_type & N_STAB) {
if (cursym.n_type == N_BINCL) {
exclude = start_incl2(&cursym, header_num);
header_num++;
} else if (cursym.n_type == N_EINCL) {
if (exclude) {
exclude = end_incl2();
continue;
} else {
exclude = end_incl2();
}
} else if (exclude) {
continue;
}
} else {
/*
* do not keep track of any dbx symbols for load2td
* +++ is it safe?
*/
if (clocseg->lo_used == NSYMPR) {
if (++clocseg == &locseg[NSEG])
error(1, "local symbol overflow");
clocseg->lo_used = 0;
}
if (clocseg->lo_first == 0) {
clocseg->lo_first = (struct local *)
calloc(NSYMPR, sizeof (struct local));
if (clocseg->lo_first == 0)
error(1, "out of memory (clocseg)");
}
lp = &clocseg->lo_first[clocseg->lo_used++];
lp->l_index = symno;
if (rflag && lpicflag && cursym.n_un.n_name[0]=='L') {
char *cp;
cp = malloc(strlen(filname) +
strlen(cursym.n_un.n_name) + 2);
strcpy(cp, filname);
strcat(cp, ".");
strcat(cp, cursym.n_un.n_name);
cursym.n_un.n_name = cp;
}
*csp = cursym;
lp->l_symbol = csp++;
lp->l_link = lochash[symno % LHSIZ];
lochash[symno % LHSIZ] = lp;
}
/* inline expansion of symreloc() */
if (!funding) {
/*
* Do not relocate symbols in fundamental file.
* This turns out only to matter for local
* static and debugging symbols, which
* are written out here.
*/
switch (cursym.n_type & (N_TYPE+N_EXT)) {
case N_TEXT:
case N_EXT+N_TEXT:
cursym.n_value += ctrel;
break;
case N_DATA:
case N_EXT+N_DATA:
cursym.n_value += cdrel;
break;
case N_BSS:
case N_EXT+N_BSS:
cursym.n_value += cbrel;
break;
case N_EXT+N_UNDF:
break;
default:
if (cursym.n_type&N_EXT)
cursym.n_type = N_EXT+N_ABS;
}
}
/* end inline expansion of symreloc() */
type = cursym.n_type;
if (yflag && cursym.n_un.n_name)
for (i = 0; i < yflag; i++)
/* fast check for 2d character! */
if (ytab[i][1] == cursym.n_un.n_name[1] &&
!strcmp(ytab[i], cursym.n_un.n_name)) {
tracesym();
break;
}
if ((type&N_EXT) == 0) {
if ((!sflag && !xflag && (type & N_STAB ||
cursym.n_un.n_name[0]!='L')) ||
(rflag && (lpicflag) &&
cursym.n_un.n_name[0] == 'L') ) {
if (!(type & N_STAB))
lp->l_symbol->n_desc = lsymbno;
lsymbno++;
symwrite(&cursym, sout);
}
continue;
}
if (funding)
continue;
if ((sp = *lookup(&ldsym)) == 0)
error(1, "internal error: symbol not found");
if (cursym.n_type & N_STAB || cursym.n_type == N_EXT+N_UNDF)
continue;
if (cursym.n_type!=sp->n_type || cursym.n_value!=sp->n_value) {
if (!ISGT(cursym.n_un.n_name)) {
error(0, "%s: multiply defined",
cursym.n_un.n_name);
}
}
}
if (funding)
return;
dseek(&text, loc, filhdr.a_text);
dseek(&reloc, loc+filhdr.a_text+filhdr.a_data, filhdr.a_trsize);
load2td(ctrel, torigin - textbase, tout, trout);
dseek(&text, loc+filhdr.a_text, filhdr.a_data);
dseek(&reloc, loc+filhdr.a_text+filhdr.a_data+filhdr.a_trsize,
filhdr.a_drsize);
load2td(cdrel, ndorigin - database, dout, drout);
while (filhdr.a_data & (seground()-1)) {
bputc(0, dout);
filhdr.a_data++;
}
localsymbolno += lsymbno;
torigin += filhdr.a_text;
ndorigin += round(filhdr.a_data, seground());
borigin += round(filhdr.a_bss, seground());
free(curstr);
}
struct tynames {
int ty_value;
char *ty_name;
} tynames[] = {
N_UNDF, "undefined",
N_ABS, "absolute",
N_TEXT, "text",
N_DATA, "data",
N_BSS, "bss",
N_COMM, "common",
0, 0,
};
tracesym()
{
register struct tynames *tp;
if (cursym.n_type & N_STAB)
return;
printf("%s", filname);
if (archdr.ar_name[0])
printf("(%s)", archdr.ar_name);
printf(": ");
if ((cursym.n_type&N_TYPE) == N_UNDF && cursym.n_value) {
printf("definition of common %s size %d\n",
cursym.n_un.n_name, cursym.n_value);
return;
}
for (tp = tynames; tp->ty_name; tp++)
if (tp->ty_value == (cursym.n_type&N_TYPE))
break;
printf((cursym.n_type&N_TYPE) ? "definition of" : "reference to");
if (cursym.n_type&N_EXT)
printf(" external");
if (tp->ty_name)
printf(" %s", tp->ty_name);
printf(" %s\n", cursym.n_un.n_name);
}
extern struct ssymbol *ssymbol_p;
static int
forcesymbolic(flag, sp)
int flag;
struct nlist *sp;
{
struct ssymbol *ssp = ssymbol_p;
if (!(flag & SYMBOLIC))
return(0);
if (!ssp)
return(1);
if (!sp->n_un.n_name)
return(0);
while (ssp)
if (!strcmp(sp->n_un.n_name, ssp->ssp))
return(1);
else
ssp = ssp->ss_next;
return(0);
}
/*
* these bits denote a relocation type for bldreloc routine
*/
#define REL_RP 1 /* relative */
#define EXT_RP 2 /* extern */
#define BSR_RP 4 /* base relative */
#define JMP_RP 8 /* jump */
#define PCREL_RP 0x10 /* pc relative */
#define DONE_RP 0x20 /* done */
#define dloff (lkd.v2->ld_got)
#define jloff (lkd.v2->ld_plt)
static
ext_pic_got(rp, sp, sp1, ps, where, b1)
register struct relocation_info *rp;
register struct nlist *sp;
register struct nlist *sp1;
struct slsymb *ps;
char *where;
struct biobuf *b1;
{
int rf = 0;
static char *errmsg = "can't reduce symbolic to relative:";
#if TARGET==SUN4
ps = sllookup(&dpic, &dpicseg[NSEG], dpichash, sp, rp->r_addend, 0, 0);
#endif
#if TARGET==SUN3 || TARGET==SUN2
ps = sllookup(&dpic, &dpicseg[NSEG], dpichash, sp, 0, 0, 0);
#endif
if (ps->sl_new)
error(1, "data linkage botch");
else {
if (ps->sl_lo == -1) {
ps->sl_lo = rtp->dto;
relocate(rp, where, rtp->dto, b1);
if (forcesymbolic(forceflag, sp1) || entryflag) {
/*
* case where ld is asked to do
* symbolic to relative.
*/
if ((sp1->n_type & (N_TYPE+N_EXT)) !=
N_EXT+N_UNDF) {
/*
* this ps->offset is bogus here since
* for now we are ignoring offset+++
*/
if (sp1->n_type == N_TEXT+N_EXT)
*(rtp->dtp)++ = sp1->n_value;
else
*(rtp->dtp)++ = sp1->n_value +
ps->sl_offset;
if (entryflag) {
rtp->dto += sizeof(int);
return;
}
rf |= REL_RP;
} else {
rtp->dtp++;
if (forcesymbolic(forceflag, sp1))
if (assertflag & NOSYMBOLIC) {
error(0,
"%s %s\n", errmsg,
sp1->n_un.n_name);
errlev |= 01;
}
}
} else
*(rtp->dtp)++ = ps->sl_offset;
/*
* cooking up new relocation datum
*/
rf |= EXT_RP + BSR_RP;
bldreloc(rtp, dloff+rtp->dto, rf, sp, rp);
rtp->dto += sizeof(int);
} else
relocate(rp, where, ps->sl_lo, b1);
}
}
static
jmp_slot(rp, sp, sp1, ps, where, b1, tw, creloc)
register struct relocation_info *rp;
register struct nlist *sp;
register struct nlist *sp1;
struct slsymb *ps;
char *where;
struct biobuf *b1;
long tw;
long creloc;
{
int rf = 0;
#if TARGET==SUN4
ps = sllookup(&tpic, &tpicseg[NSEG], tpichash, sp,
0, 0, 0);
#endif
#if TARGET==SUN2 || TARGET==SUN3
ps = sllookup(&tpic, &tpicseg[NSEG], tpichash, sp, 0, 0, 0);
#endif
if (ps->sl_new)
error(1, "jump linkage botch");
else {
if (ps->sl_lo == -1) {
tw += (jloff + rtp->jto) - creloc;
relocate (rp, where, tw, b1);
if (((sp1->n_type & (N_TYPE+N_EXT)) == N_EXT+N_UNDF) ||
!(forcesymbolic(forceflag, sp) || entryflag)) {
if (forcesymbolic(forceflag, sp)) {
if (assertflag & NOSYMBOLIC) {
error(0, "can't reduce symbolic to relative: %s", sp1->n_un.n_name);
errlev |= 01;
}
} else {
#if TARGET==SUN4
#define MASK(n) ((1<<(n))-1)
#define jmpoff ( (unsigned long)(-4 - rtp->jto) )
rtp->jtp->jb_inst[0] = SAVE;
rtp->jtp->jb_inst[1] =
CALL | ((jmpoff>>2) & MASK(30));
rtp->jtp->jb_inst[2] = SETHIG0 |
(rtp->rpp - rtp->rp);
#endif
#if TARGET==SUN2
#define jmpoff ( (unsigned long)(-4 - rtp->jto) )
rtp->jtp->code = NOP;
rtp->jtp->cl_hi = JBSR;
rtp->jtp->cl_low = jmpoff;
#endif
#if TARGET==SUN3
#define jmpoff ( (unsigned long)(-2 - rtp->jto) )
rtp->jtp->code = JBSR;
rtp->jtp->cl_hi = jmpoff >> 16;
rtp->jtp->cl_low = jmpoff & 0xffff;
#endif
}
} else {
/*
* case where ld is asked to do
* symbolic to relative.
*/
#if TARGET==SUN4
setupjs(rtp->jtp, sp1->n_value);
#endif
#if TARGET==SUN2 || TARGET==SUN3
rtp->jtp->code = JUMP;
rtp->jtp->cl_hi = sp1->n_value >> 16;
rtp->jtp->cl_low = sp1->n_value & 0xffff;
#endif
if (entryflag) {
ps->sl_lo = rtp->jto;
rtp->jto += sizeof(struct jbind);
rtp->jtp++;
return;
}
rf |= REL_RP;
}
/*
* cook up new relocation info
*/
#if TARGET==SUN2 || TARGET==SUN3
rtp->jtp->reloc_index = rtp->rpp - rtp->rp;
#endif
ps->sl_lo = rtp->jto;
rtp->jtp++;
rf |= EXT_RP + JMP_RP;
#if TARGET==SUN4
bldreloc(rtp, jloff + rtp->jto, rf, sp, rp);
#endif
#if TARGET==SUN2 || TARGET==SUN3
bldreloc(rtp, jloff + rtp->jto + 2, rf, sp, rp);
#endif
rtp->jto += sizeof(struct jbind);
} else {
tw += (jloff + ps->sl_lo) - creloc;
relocate(rp, where, tw, b1);
}
}
}
/*
* This routine relocates the single text or data segment argument.
* Offsets from external symbols are resolved by adding the value
* of the external symbols. Non-external reference are updated to account
* for the relative motion of the segments (ctrel, cdrel, ...). If
* a relocation was pc-relative, then we update it to reflect the
* change in the positioning of the segments by adding the displacement
* of the referenced segment and subtracting the displacement of the
* current segment (creloc).
*
* If we are saving the relocation information, then we increase
* each relocation datum address by our base position in the new segment.
*/
load2td(creloc, position, b1, b2)
long creloc, position;
struct biobuf *b1, *b2;
{
register struct nlist *sp;
register struct nlist *sp1;
register int rf;
long tw;
register struct relocation_info *rp, *rpend;
struct relocation_info *relp;
char *codep;
register char *cp;
int relsz, codesz;
struct slsymb *ps;
int piccode;
relsz = reloc.size;
relp = (struct relocation_info *)mymalloc(relsz);
codesz = text.size;
codep = (char *)mymalloc(codesz);
if (relp == 0 || codep == 0)
error(1, "out of memory (load2td)");
mget((char *)relp, relsz, &reloc);
rpend = &relp[relsz / sizeof (struct relocation_info)];
mget(codep, codesz, &text);
for (rp = relp, piccode = 0; rp < rpend; rp++) {
if (rp->r_extern == 0)
continue;
sp = getlocsymb(rp);
#if TARGET==SUN4
# define IN_RANGE(v,n) ((-(1<<((n)-1))) <=(v) && (v) < (1<<((n)-1)))
/*
* the peephole optimizer on sun4 figured out that
* sometimes the __GLOBAL_OFFSET_TABLE_ relocation is not
* needed (i.e only jmp_table reloc are in the routine)
* so we have to test here for both conditions.
*/
if (ISGT(sp->n_un.n_name) || rp->r_type == RELOC_JMP_TBL) {
#endif
#if TARGET==SUN3 || TARGET==SUN2
if (ISGT(sp->n_un.n_name) || rp->r_jmptable) {
#endif
piccode = 1;
break;
}
}
for (rp = relp; rp < rpend; rp++) {
rf = 0;
cp = codep + rp->r_address;
/*
* Search the hash table which maps local
* symbol numbers to symbol tables entries
* in the new a.out file.
*/
if (piccode || rp->r_extern)
sp = getlocsymb(rp);
/*
* Pick up previous value at location to be relocated.
*/
#if TARGET== SUN4
/*
* Pick up addend.
*/
tw = rp->r_addend;
#endif
#if TARGET==SUN3 || TARGET==SUN2
switch (rp->r_length) {
case 0: /* byte */
tw = *cp;
break;
case 1: /* word */
tw = *(short *)cp;
break;
case 2: /* long */
/* "cp" points to an least a 16-bit boundary, but
* not necessarily a 32-bit boundary.
*/
#ifdef mc68000 /* 68k host can do long accesses on 16-bit boundaries */
tw = *(long *)cp;
#else /*!mc68000*/ /* others can only do long accesses on 32-bit bdy's */
*((short*) (&tw) ) = *((short*) cp );
*((short*)(((char*)(&tw))+2)) = *((short*)(cp+2));
#endif /*mc68000*/
break;
default:
error(1, "load2td botch: bad length");
}
#endif
if (rp->r_extern) {
cursym.n_un.n_name = sp->n_un.n_name;
if ( (sp1 = *lookup(&ldsym)) == 0 )
error(1, "can't find symbol");
}
/*
* The 0'th entry of the GOT (which may not be its base
* address) is reserved to hold the location of __DYNAMIC.
*/
if (rtp->dto == 0) {
rtp->dto += sizeof (int);
rtp->dtp++;
}
#if TARGET==SUN4
if (rp->r_type == RELOC_BASE10 || rp->r_type == RELOC_BASE13 ||
rp->r_type == RELOC_BASE22) {
#endif
#if TARGET==SUN3 || TARGET==SUN2
if (rp->r_baserel) {
#endif
if (rflag) {
if (rp->r_extern)
rp->r_symbolnum = nsym+symx(&ldsym, sp1);
else
rp->r_symbolnum = sp->n_desc + localsymbolno;
goto dorflag;
}
if (rp->r_extern) {
ext_pic_got(rp, sp, sp1, ps, cp, b1);
} else {
#if TARGET==SUN4
ps = sllookup(&stpic, &stpicseg[NSEG], stpichash, sp,
rp->r_addend, 0, (rtp->dtp - rtp->dt));
#endif
#if TARGET==SUN3 || TARGET==SUN2
ps = sllookup(&stpic, &stpicseg[NSEG], stpichash, sp,
0, 0, (rtp->dtp - rtp->dt));
#endif
if (ps->sl_new) {
ps->sl_lo = rtp->dto;
relocate(rp, cp, rtp->dto, b1);
switch (sp->n_type) {
case N_TEXT:
/* tw += ctrel; */
tw += ctrel + sp->n_value;
break;
case N_DATA:
/* tw += cdrel; */
tw += cdrel + sp->n_value;
break;
case N_BSS:
/* tw += cbrel; */
tw += cbrel + sp->n_value;
break;
default:
error(1, "base relative static symbol(%s) botch",
sp->n_un.n_name);
}
if (!entryflag || forcesymbolic(forceflag, sp)) {
rf |= REL_RP+BSR_RP;
bldreloc(rtp, dloff+rtp->dto, rf, 0, rp);
}
rtp->dto += sizeof(int);
*(rtp->dtp)++ = tw;
} else
relocate(rp, cp, ps->sl_lo, b1);
}
continue;
}
#if TARGET==SUN4
if (rp->r_type == RELOC_JMP_TBL) {
#endif
#if TARGET==SUN2 || TARGET==SUN3
if (rp->r_jmptable) {
#endif
if (rflag) {
rp->r_symbolnum = nsym+symx(&ldsym, sp1);
goto dorflag;
}
/*
* pc relative call to a symbol in the data segment
*/
if (rp->r_extern == 0) {
u_int dsoff; /* offset into data segment */
dsoff = tw - (filhdr.a_text - rp->r_address);
tw = cdrel + filhdr.a_text - (ctrel + rp->r_address) +
dsoff;
relocate(rp, cp, tw, b1);
continue;
}
jmp_slot(rp, sp, sp1, ps, cp, b1, tw, creloc);
continue;
}
#if TARGET==SUN4
if (rp->r_type == RELOC_PC10 || rp->r_type == RELOC_PC22) {
if (!ISGT(sp1->n_un.n_name))
error(1, "load2td: expect __GLOBAL_OFFSET_TABLE_");
if (rflag) {
rp->r_symbolnum = nsym+symx(&ldsym, sp1);
goto dorflag;
}
/*
* pc relative reference that used 4 instructions since
* sparc doesn't have one pc relative instruction to
* access a symbol.
*/
tw = sp1->n_value - creloc - rp->r_address + rp->r_addend;
relocate(rp, cp, tw, b1);
continue;
}
#endif
/*
* If relative to an external which is defined,
* resolve to a simpler kind of reference in the
* result file. If the external is undefined, just
* convert the symbol number to the number of the
* symbol in the result file and leave it undefined.
*/
#define r_addr rp->r_address + position + (b1 == dout ? database : textbase)
#if TARGET==SUN4
#ifdef _SUN4_DEVELOPMENT
#define isitpcrel(rp) (rp->r_type == RELOC_DISP8 || rp->r_type == RELOC_DISP16\
|| rp->r_type == RELOC_DISP32 || rp->r_type == RELOC_WDISP30 \
|| rp->r_type == oRELOC_WDISP23 || rp->r_type == RELOC_WDISP22)
#else
#define isitpcrel(rp) (rp->r_type == RELOC_DISP8 || rp->r_type == RELOC_DISP16\
|| rp->r_type == RELOC_DISP32 || rp->r_type == RELOC_WDISP30 \
|| rp->r_type == RELOC_WDISP22)
#endif _SUN4_DEVELOPMENT
#endif
if (rp->r_extern) {
if (sp1->n_type == N_EXT+N_UNDF) {
rp->r_symbolnum = nsym+symx(&ldsym, sp1);
if ((ISDYNAMIC) && !rflag) {
/*
* if we are forced to allocate both common and
* procedure then all that are left here should
* be procedure (all the common should be turn
* into BSS type by now).
*
* if we are forced to declare only common then
* what is left here are normal relocation to
* undefined routines.
*
* if we are forced to allocate only procedure
* then what we are concerned here are the symbols
* with a value of 0.
*/
if (pflag) {
if ((ps = slfindit(tpichash, sp1, 0, hashit(sp1)))) {
if (ps->sl_lo == -1) {
#if TARGET==SUN4
if (isitpcrel(rp))
#endif
#if TARGET==SUN3 || TARGET==SUN2
if (rp->r_pcrel)
#endif
tw += (jloff+rtp->jto) - creloc;
else
tw += (jloff+rtp->jto);
relocate(rp, cp, tw, b1);
if (forceflag & SYMBOLIC)
error(1, "symbolic flag botch");
#if TARGET==SUN4
rtp->jtp->jb_inst[0] = SAVE;
rtp->jtp->jb_inst[1] = CALL | ((jmpoff>>2) & MASK(30));
rtp->jtp->jb_inst[2] = SETHIG0 |
(rtp->rpp - rtp->rp);
#endif
#if TARGET==SUN2
rtp->jtp->code = NOP;
rtp->jtp->cl_hi = JBSR;
rtp->jtp->cl_low = jmpoff;
#endif
#if TARGET==SUN3
rtp->jtp->code = JBSR;
rtp->jtp->cl_hi = jmpoff >> 16;
rtp->jtp->cl_low = jmpoff & 0xffff;
#endif
#if TARGET==SUN2 || TARGET==SUN3
rtp->jtp->reloc_index = rtp->rpp - rtp->rp;
#endif
ps->sl_lo = rtp->jto;
rtp->jtp++;
rf |= EXT_RP + JMP_RP;
#if TARGET==SUN4
bldreloc(rtp, jloff + rtp->jto, rf, sp, rp);
#endif
#if TARGET==SUN3 || TARGET==SUN2
bldreloc(rtp, jloff + rtp->jto + 2, rf, sp, rp);
#endif
rtp->jto += sizeof(struct jbind);
} else {
#if TARGET==SUN4
if (isitpcrel(rp))
#endif
#if TARGET==SUN3 || TARGET==SUN2
if (rp->r_pcrel)
#endif
tw += (jloff+ps->sl_lo) - creloc;
else
tw += (jloff+ps->sl_lo);
relocate(rp, cp, tw, b1);
}
continue;
}
}
#if TARGET==SUN4
if (isitpcrel(rp))
#endif
#if TARGET==SUN3 || TARGET==SUN2
if (rp->r_pcrel)
#endif
if (b1 != tout)
error(1, "no pc rel from data");
else {
rf |= PCREL_RP;
tw -= creloc;
#if TARGET==SUN4
rp->r_addend = tw;
#endif
#if TARGET==SUN3 || TARGET==SUN2
relocate(rp, cp, tw, b1);
#endif
}
rf |= EXT_RP;
bldreloc(rtp, r_addr, rf, sp, rp);
continue;
}
} else {
/* what a kludge here */
#if (TARGET==SUN3) || (TARGET==SUN2)
if (ISGT(sp1->n_un.n_name)) {
if (rflag)
goto dorflag;
rp->r_symbolnum = sp1->n_type & N_TYPE;
tw += sp1->n_value;
rp->r_extern = 0;
tw -= creloc; /* ++++ assumes that this is pcrel */
relocate(rp, cp, tw, b1, rp);
continue;
}
#endif
/*
* This is the case of a non pic module referencing
* a defined symbol.
*/
if (!rflag && !entryflag && (bindingflag != ST_BIND)
&& !(forcesymbolic(forceflag, sp1))) {
#if TARGET==SUN4
if (isitpcrel(rp))
#endif
#if TARGET==SUN3 || TARGET==SUN2
if (rp->r_pcrel)
#endif
if (b1 != tout)
error(1, "no pc rel from data");
else {
rf |= PCREL_RP;
tw -= creloc;
#if TARGET==SUN4
rp->r_addend = tw;
#endif
#if TARGET==SUN3 || TARGET==SUN2
relocate(rp, cp, tw, b1);
#endif
}
rf |= EXT_RP;
bldreloc(rtp, r_addr, rf, sp, rp);
continue;
}
rp->r_symbolnum = sp1->n_type & N_TYPE;
tw += sp1->n_value;
rp->r_extern = 0;
if ((ISDYNAMIC) && !rflag) {
if (forcesymbolic(forceflag, sp1)) {
#if TARGET==SUN4
if (isitpcrel(rp))
#endif
#if TARGET==SUN2 || TARGET==SUN3
if (rp->r_pcrel)
#endif
if (b1 != tout)
error(1, "no pc rel from data");
else {
tw -= creloc;
rf |= DONE_RP;
}
relocate(rp, cp, tw, b1);
rf |= REL_RP;
bldreloc(rtp, r_addr, rf, 0, rp);
continue;
}
}
}
} else switch (rp->r_symbolnum & N_TYPE) {
/*
* Relocation is relative to the loaded position
* of another segment. Update by the change in position
* of that segment.
*/
case N_TEXT:
tw += ctrel;
if (rflag)
break;
if (!entryflag && ((bindingflag & DN_BIND) ||
!(bindingflag & ST_BIND))) {
relocate(rp, cp, tw, b1);
rf |= REL_RP;
bldreloc(rtp, r_addr, rf, 0, rp);
continue;
}
break;
case N_DATA:
tw += cdrel;
if (rflag)
break;
if (!entryflag && ((bindingflag & DN_BIND) ||
!(bindingflag & ST_BIND))) {
relocate(rp, cp, tw, b1);
rf |= REL_RP;
bldreloc(rtp, r_addr, rf, 0, rp);
continue;
}
break;
case N_BSS:
tw += cbrel;
if (rflag)
break;
if (!entryflag && ((bindingflag & DN_BIND) ||
!(bindingflag & ST_BIND))) {
relocate(rp, cp, tw, b1);
rf |= REL_RP;
bldreloc(rtp, r_addr, rf, 0, rp);
continue;
}
break;
case N_ABS:
break;
default:
error(1,"relocation format botch (symbol type))");
}
/*
* Relocation is pc relative, so decrease the relocation
* by the amount the current segment is displaced.
* (E.g if we are a relative reference to a text location
* from data space, we added the increase in the text address
* above, and subtract the increase in our (data) address
* here, leaving the net change the relative change in the
* positioning of our text and data segments.)
*/
dorflag:
#if TARGET==SUN4
switch (rp->r_type) {
case RELOC_DISP8:
case RELOC_DISP16:
case RELOC_DISP32:
case RELOC_WDISP30:
#ifdef _SUN4_DEVELOPMENT
case oRELOC_WDISP23:
#endif _SUN4_DEVELOPMENT
case RELOC_WDISP22:
case RELOC_JMP_TBL:
tw -= creloc;
}
/*
* If we're saving the relocation record, just stuff the
* value back into it. Otherwise,
* Put the value back in the segment,
* while checking for overflow.
*/
if (rflag){
rp->r_addend = tw;
rp->r_address += position;
} else
relocate(rp, cp, tw, b1);
#endif
#if TARGET==SUN2 || TARGET==SUN3
if (rp->r_pcrel)
tw -= creloc;
relocate(rp, cp, tw, b1);
/*
* If we are saving relocation information,
* we must convert the address in the segment from
* the old .o file into an address in the segment in
* the new a.out, by adding the position of our
* segment in the new larger segment.
*/
if (rflag)
rp->r_address += position;
#endif
}
bwrite(codep, codesz, b1);
if (rflag)
bwrite(relp, relsz, b2);
free((char *)relp);
free(codep);
}
#if TARGET==SUN4
setupjs(jtp, val)
register struct jbind *jtp;
int val;
{
jtp->jb_inst[0] = SETHI | ((val >> (32-22)) & MASK(22));
jtp->jb_inst[1] = JMPI | (val & MASK(10));
jtp->jb_inst[2] = NOP;
}
#endif
/*
* This routine build a relocation record for runtime linking
*/
bldreloc(rt, addr, flag, sp, rp)
register struct runtime *rt;
register int addr;
register int flag;
register struct nlist *sp;
register struct relocation_info *rp;
{
/*
* If we are building a fully statically linked program, and we
* are doing a pic relocation against undefined symbols, it is
* possible for us to get asked to build a relocation entry
* for the undefined reference. Of course, because we aren't
* doing any dynamic linking, we won't have a table to build
* it against. Check for this here, and just pretend success
* in such a circumstance.
*/
if (rt->rpp == NULL) {
if (!rflag && ((ISDYNAMIC) || forceflag & SYMBOLIC))
error(1, "bldreloc: relocation table missing");
return;
}
/*
* Verify arguments and proceed to build a new relocation entry.
*/
if (flag == 0)
error(1, "Illegal flag");
rt->rpp->r_address = addr;
if ((assertflag & PURE_TEXT) && !(rflag || Nflag))
if (addr < database)
error(0, "assert pure-text failed: reference to %s at %x in %s\n",
(sp == 0 ? "[offset]" : sp->n_un.n_name),
addr, filname);
#if TARGET==SUN4
rt->rpp->r_addend = rp->r_addend;
if (flag & REL_RP) {
if (flag & JMP_RP)
rt->rpp->r_type = RELOC_RELATIVE;
else if (flag & BSR_RP)
rt->rpp->r_type = RELOC_32;
else
rt->rpp->r_type = rp->r_type;
} else if (flag & BSR_RP)
rt->rpp->r_type = RELOC_GLOB_DAT;
else if (flag & JMP_RP)
rt->rpp->r_type = RELOC_JMP_SLOT;
else
rt->rpp->r_type = rp->r_type;
#endif
#if TARGET==SUN2 || TARGET==SUN3
if (flag & REL_RP)
rt->rpp->r_relative = 1;
if (flag & JMP_RP)
rt->rpp->r_jmptable = 1;
if (flag & BSR_RP)
rt->rpp->r_baserel = 1;
if (flag & PCREL_RP)
rt->rpp->r_pcrel = 1;
#endif
if (flag & EXT_RP) {
if ((rt->rpp->r_symbolnum = fslookup(sp, rt)) == -1)
error(1, "fast symbol botch");
if (flag & REL_RP)
rt->rpp->r_extern = 0;
else
rt->rpp->r_extern = 1;
}
rt->rpp++;
relocused++;
}
relocate (rp, where, what, b1)
struct relocation_info *rp;
char *where;
long what;
struct biobuf *b1;
{
#if TARGET==SUN4
switch (rp->r_type) {
case RELOC_8:
case RELOC_DISP8:
if (!IN_RANGE(what,8))
error(0, "byte displacement overflow at %s+%#x",
b1==tout?"text":"data", rp->r_address);
*where = what;
break;
#ifdef _SUN4_DEVELOPMENT
case oRELOC_LO9:
*(long *)where = (*(long *)where & ~MASK(9)) | (what & MASK(9));
break;
#endif _SUN4_DEVELOPMENT
case RELOC_LO10:
case RELOC_PC10:
case RELOC_BASE10:
*(long *)where = (*(long *)where & ~MASK(10)) | (what & MASK(10));
break;
case RELOC_BASE13:
case RELOC_13:
*(long *)where = (*(long *)where & ~MASK(13)) | (what & MASK(13));
break;
case RELOC_16:
case RELOC_DISP16:
if (!IN_RANGE(what,16))
error(0, "word displacement overflow at %s+%#x",
b1==tout?"text":"data", rp->r_address);
*(short *)where = what;
break;
#ifdef _SUN4_DEVELOPMENT
case oRELOC_23:
if (!IN_RANGE(what,23))
error(0, "sethi displacement overflow at %s+%#x",
b1==tout?"text":"data", rp->r_address);
*(long *)where = (*(long *)where & ~MASK(23)) | (what & MASK(23));
break;
#endif _SUN4_DEVELOPMENT
case RELOC_22:
if (!IN_RANGE(what,22))
error(0, "sethi displacement overflow at %s+%#x",
b1==tout?"text":"data", rp->r_address);
*(long *)where = (*(long *)where & ~MASK(22)) | (what & MASK(22));
break;
#ifdef _SUN4_DEVELOPMENT
case oRELOC_HI23:
*(long *)where = (*(long *)where & ~MASK(23))
| ((what>>(32-23)) & MASK(23));
break;
#endif _SUN4_DEVELOPMENT
case RELOC_HI22:
case RELOC_BASE22:
case RELOC_PC22:
*(long *)where = (*(long *)where & ~MASK(22))
| ((what>>(32-22)) & MASK(22));
break;
#ifdef _SUN4_DEVELOPMENT
case oRELOC_WDISP23:
if (what & MASK(2) )
error(0, "odd word displacement at %s+%#x",
b1==tout?"text":"data", rp->r_address);
what >>= 2;
if (!IN_RANGE(what,23))
error(0, "branch displacement overflow at %s+%#x",
b1==tout?"text":"data", rp->r_address);
*(long *)where = (*(long *)where & ~MASK(23)) | (what & MASK(23));
break;
#endif _SUN4_DEVELOPMENT
case RELOC_WDISP22:
if (what & MASK(2) )
error(0, "odd word displacement at %s+%#x",
b1==tout?"text":"data", rp->r_address);
what >>= 2;
if (!IN_RANGE(what,22))
error(0, "branch displacement overflow at %s+%#x",
b1==tout?"text":"data", rp->r_address);
*(long *)where = (*(long *)where & ~MASK(22)) | (what & MASK(22));
break;
case RELOC_JMP_TBL:
case RELOC_WDISP30:
if (what & MASK(2) )
error(0, "odd word displacement at %s+%#x",
b1==tout?"text":"data", rp->r_address);
what >>= 2;
*(long *)where = (*(long *)where & ~MASK(30)) | (what&MASK(30));
break;
case RELOC_32:
case RELOC_DISP32:
*(long *)where = what;
break;
}
#endif
#if TARGET==SUN2 || TARGET==SUN3
/*
* Put the value back in the segment,
* while checking for overflow.
*/
switch (rp->r_length) {
case 0: /* byte */
if (what < -128 || what > 127)
error(0, "byte displacement overflow at %s+%#x",
b1==tout?"text":"data", rp->r_address);
*where = what;
break;
case 1: /* word */
if (what < -32768 || what > 32767)
error(0, "word displacement overflow at %s+%#x",
b1==tout?"text":"data", rp->r_address);
*(short *)where = what;
break;
case 2: /* long */
/* "where" points to an least a 16-bit boundary, but
* not necessarily a 32-bit boundary.
*/
#ifdef mc68000 /* 68k host can do long accesses on 16-bit boundaries */
*(long *)where = what;
#else /*!mc68000*/ /* others can only do long accesses on 32-bit bdy's */
*((short*) where ) = *((short*) (&what) );
*((short*)(where+2)) = *((short*)(((char*)(&what))+2));
#endif /*mc68000*/
break;
}
#endif
}
finishout()
{
register int i;
register struct nlist *sp;
int nsymt;
/*
* if dynamic linking then flush out the data, jump linkage table plus
* the relocation datum followed by the hash table for the fast symbols
* and the symbols themselves.
*/
if (!rflag) {
int *j = rtp->dt;
struct jbind *k = rtp->jt;
if (ISDYNAMIC) {
if ((i = lalign(rtp->fsoff)) != rtp->fsalloc) {
error(1, "allocated %d used %d for fast symb",
rtp->fsalloc, i);
}
if (relocused != rtp->rl) {
error(1, "no of reloc used %d != no alloc %d",
relocused, rtp->rl);
}
{
struct relocation_info *l = rtp->rp;
struct fshash *m = rtp->hp;
struct nlist *n = rtp->sp;
char *x = (char *) calloc(8,1);
for (i = 0; i < sl.ds+sl.ss; i++)
bwrite((char *)j++, sizeof(int),
dynout);
for (i = 0; i < sl.js; i++)
bwrite((char *)k++,
sizeof(struct jbind), dynout);
if (pad != 0)
bwrite((char *)x, pad, dynout);
for (i = 0; i < rtp->rl; i++)
bwrite((char *)l++,
sizeof(struct relocation_info),
tout);
for (i = 0; i < rtp->hp_ind; i++)
bwrite((char *)m++,
sizeof(struct fshash), tout);
for (i = 0; i < totalsymb(); i++)
bwrite((char *)n++,
sizeof(struct nlist), tout);
bwrite((char *)rtp->fsstr, rtp->fsalloc, tout);
if (rtp->searchpath)
bwrite(rtp->searchpath,
lalign(rtp->spthlen), tout);
bwrite((char *) rtp->lko, dynamic.lib *
sizeof(struct link_object), tout);
bwrite(shlibstr, dynamic.libstr, tout);
}
} else if (dynamic.ds + dynamic.js) {
for (i = 0; i < sl.ds+sl.ss; i++)
bwrite((char *)j++, sizeof(int), dynout);
for (i = 0; i < sl.js; i++)
bwrite((char *)k++, sizeof(struct jbind),
dynout);
}
}
if (sflag==0) {
nsymt = symx(&ldsym, ldsym.ns);
for (i = 0; i < nsymt; i++) {
sp = xsym(ldsym.fs, i);
if (sp->n_type == DISCARDIT)
continue;
/*
* ++++ -g option for the symbolic debugger
* generated symbol types N_UNDF and N_ABS
* that can have value 0. Is this correct
* to say here that if we see such symbol the
* we can write it out. Checking for external
* text symbol here to deal with flag -N -T 0.
*/
if (!rflag) {
if (sp->n_value != 0 || sp->n_type == N_UNDF ||
sp->n_type == N_EXT+N_TEXT ||
sp->n_type == N_ABS ||
sp->n_type == N_ABS+N_EXT)
symwrite(sp, sout);
} else
symwrite(sp, sout);
}
bwrite(&offset, sizeof offset, sout);
/*
* if appropriate, write out extra sections
* following the string table
*/
write_extra_sections( strout );
}
filname = aoutname;
archdr.ar_name[0] = '\0';
if (rename(ofilename, aoutname) < 0) {
filname = NULL; /* kludge */
error(1, "cannot move temp file %s to %s: %s", ofilename,
aoutname, errmsg(errno));
}
delarg = errlev;
delexit();
}
mkfsym(s, value, type)
char *s;
int value;
int type;
{
static struct nlist fsym;
if (sflag || xflag)
return;
fsym.n_un.n_name = s;
fsym.n_type = type;
fsym.n_value = value;
symwrite(&fsym, sout);
}
getarhdr()
{
register char *cp;
mget((char *)&archdr, sizeof archdr, &text);
for (cp=archdr.ar_name; cp<&archdr.ar_name[sizeof(archdr.ar_name)];)
if (*cp++ == ' ') {
cp[-1] = 0;
return;
}
}
mget(loc, n, sp)
register STREAM *sp;
register char *loc;
{
register char *p;
register int take;
register int nread;
top:
if (n == 0)
return;
if (sp->size && sp->nibuf) {
p = sp->ptr;
take = sp->size;
if (take > sp->nibuf)
take = sp->nibuf;
if (take > n)
take = n;
n -= take;
sp->size -= take;
sp->nibuf -= take;
sp->pos += take;
do
*loc++ = *p++;
while (--take > 0);
sp->ptr = p;
goto top;
}
if (n > p_blksize) {
take = n - n % p_blksize;
lseek(infil, (sp->bno+1)<<p_blkshift, 0);
if (take > sp->size)
error(1, "premature EOF");
if (nread = read(infil, loc, take) != take) {
if (nread < 0)
error(1, errmsg(errno));
else
error(1, "premature EOF");
}
loc += take;
n -= take;
sp->size -= take;
sp->pos += take;
dseek(sp, (sp->bno+1+(take>>p_blkshift))<<p_blkshift, -1);
goto top;
}
*loc++ = get(sp);
--n;
goto top;
}
symwrite(sp, bp)
struct nlist *sp;
struct biobuf *bp;
{
register int len;
register char *str;
str = sp->n_un.n_name;
if (str) {
sp->n_un.n_strx = offset;
len = strlen(str) + 1;
bwrite(str, len, strout);
offset += len;
}
bwrite(sp, sizeof (*sp), bp);
sp->n_un.n_name = str;
nsymwrite++;
}
dseek(sp, loc, s)
register STREAM *sp;
long loc, s;
{
register o;
o = loc&p_blkmask;
if (o&01)
error(1, "loader error; odd offset");
dseek1(sp, loc, s);
}
dseek1(sp, loc, s)
register STREAM *sp;
long loc, s;
{
register PAGE *p;
register b, o;
int n;
b = loc>>p_blkshift;
o = loc&p_blkmask;
--sp->pno->nuser;
if ((p = &page[0])->bno!=b && (p = &page[1])->bno!=b)
if (p->nuser==0 || (p = &page[0])->nuser==0) {
if (page[0].nuser==0 && page[1].nuser==0)
if (page[0].bno < page[1].bno)
p = &page[0];
p->bno = b;
lseek(infil, loc & ~(long)p_blkmask, 0);
if ((n = read(infil, p->buff, p_blksize)) < 0)
error(1, errmsg(errno));
p->nibuf = n;
} else
error(1, "botch: no pages");
++p->nuser;
sp->bno = b;
sp->pno = p;
if (s != -1) {sp->size = s; sp->pos = 0;}
sp->ptr = (char *)(p->buff + o);
if ((sp->nibuf = p->nibuf-o) <= 0)
sp->size = 0;
}
char
get(asp)
STREAM *asp;
{
register STREAM *sp;
sp = asp;
if ((sp->nibuf -= sizeof(char)) < 0) {
dseek(sp, ((long)(sp->bno+1)<<p_blkshift), (long)-1);
sp->nibuf -= sizeof(char);
}
if ((sp->size -= sizeof(char)) <= 0) {
if (sp->size < 0)
error(1, "premature EOF");
++fpage.nuser;
--sp->pno->nuser;
sp->pno = (PAGE *) &fpage;
}
sp->pos += sizeof(char);
return(*sp->ptr++);
}
getfile(acp, mj, mn, sizep)
char *acp;
int *mj;
int *mn;
long *sizep;
{
register char *cp;
register int c;
union {
char arcmag[SARMAG+1];
struct exec ex;
} u;
struct stat stb;
#ifdef SUNPRO
char *path;
#endif
cp = acp;
archdr.ar_name[0] = '\0';
filname = cp;
if (cp[0]=='-' && cp[1]=='l')
infil = libopen(filname + 2, O_RDONLY, mj, mn);
else {
#ifdef SUNPRO
infil = open_vroot(filname, O_RDONLY, 0, NULL, VROOT_DEFAULT);
if (trace) {
char *full_path;
get_vroot_path(&full_path, NULL, NULL);
(void)printf("\t%s\n", full_path);
}
#else
infil = open(filname, O_RDONLY);
#endif
}
if (infil < 0)
error(1, errmsg(errno));
fstat(infil, &stb);
page[0].bno = page[1].bno = -1;
page[0].nuser = page[1].nuser = 0;
c = stb.st_blksize;
if (c == 0 || (c & (c - 1)) != 0) {
/* use default size if not a power of two */
c = BLKSIZE;
}
if (p_blksize != c) {
p_blksize = c;
p_blkmask = c - 1;
for (p_blkshift = 0; c > 1 ; p_blkshift++)
c >>= 1;
if (page[0].buff != NULL)
free(page[0].buff);
page[0].buff = (char *)mymalloc(p_blksize);
if (page[0].buff == NULL)
error(1, "ran out of memory (getfile)");
if (page[1].buff != NULL)
free(page[1].buff);
page[1].buff = (char *)mymalloc(p_blksize);
if (page[1].buff == NULL)
error(1, "ran out of memory (getfile)");
}
text.pno = reloc.pno = (PAGE *) &fpage;
fpage.nuser = 2;
dseek(&text, 0L, SARMAG);
if (text.size <= 0)
error(1, "premature EOF");
mget((char *)u.arcmag, SARMAG, &text);
u.arcmag[SARMAG] = 0;
if (strcmp(u.arcmag, ARMAG)) {
if (u.ex.a_dynamic)
return(SHLIB);
else {
if (sizep != NULL)
if (u.ex.a_magic != ZMAGIC)
*sizep = stb.st_size;
else
*sizep = 0;
return(PLAIN);
}
}
dseek(&text, SARMAG, sizeof archdr);
if (text.size <= 0)
return (ARCH1);
getarhdr();
if (strncmp(archdr.ar_name, "__.SYMDEF", sizeof(archdr.ar_name)) != 0)
return (ARCH1);
/*
* +++++++ kludge. have to get rid of this stuff later
*/
return(stb.st_mtime > atol(archdr.ar_date) + 60 ? ARCH3 : ARCH2);
}
/*
* Search for a library with given name
* using the directory search array.
*/
libopen(name, oflags, mj, mn)
char *name;
int oflags;
int *mj;
int *mn;
{
register char *p, *cp, *q;
char *pp, *tpp;
register int i;
static char buf[MAXPATHLEN+1];
char lib[MAXPATHLEN+1];
int fd = -1;
#ifdef SUNPRO
char *path;
#endif
/*
* for shared library we are not reporting make dependency
* since it could be changed at runtime. ++++ will need
* to revisit this area at some future date
*/
if (*name == '\0') /* backwards compat */
name = "a";
for (i = 0; i < ndir && fd == -1; i++) {
(void) strcpy(buf, dirs[i]);
(void) strcpy(lib, "lib");
/*
* Fix up library name if verision number was specifed
*/
if ((tpp = rindex(name,'.')) != 0) {
while (*tpp == '.' || isdigit(*tpp)) {
if (*tpp == '.')
pp = tpp;
tpp--;
}
(void) strncat(lib,name,pp-name);
(void) strcat(lib, ".so");
(void) strcat(lib, pp);
} else
(void) strcat(lib, name);
if ((forceflag & DYNAMIC) && getshlib(buf, lib, mj, mn) != -1)
fd = open(buf, oflags);
else {
#ifdef SUNPRO
(void)strcpy(buf, "lib");
(void)strcat(buf, name);
(void)strcat(buf, ".a");
fd = open_vroot(buf, oflags, 0, sp_dirs[i],
VROOT_DEFAULT);
get_vroot_path(NULL, &path, NULL);
if (fd != -1) {
if (trace)
(void)printf("\t%s\n", path);
(void)strcpy(buf, path);
report_dependency(stripvroot(buf));
do_report_libdep(buf, "LD");
}
#else
(void)strcpy(buf, dirs[i]);
(void)strcat(buf, "/lib");
(void)strcat(buf, name);
(void)strcat(buf, ".a");
fd = open(buf, oflags);
#endif
}
}
if (fd != -1)
filname = buf;
return (fd);
}
struct nlist **
lookup(st)
struct syminfo *st;
{
register int sh;
register struct nlist **hp;
register char *cp, *cp1;
register struct symseg *gp;
register int i;
sh = 0;
if (!(cp = cursym.n_un.n_name))
error(1, "object file inconsistency: symbol has no string");
while (*cp)
sh = (sh<<1) + *cp++;
sh = (sh & 0x7fffffff) % HSIZE;
for (gp = st->fs; gp < &(st->fs[NSEG]); gp++) {
if (gp->sy_first == 0) {
gp->sy_first = (struct nlist *)
calloc(NSYM, sizeof (struct nlist));
gp->sy_hfirst = (struct nlist **)
calloc(HSIZE, sizeof (struct nlist *));
if (gp->sy_first == 0 || gp->sy_hfirst == 0)
error(1, "ran out of space for symbol table");
gp->sy_last = gp->sy_first + NSYM;
gp->sy_hlast = gp->sy_hfirst + HSIZE;
}
if (gp > st->cs)
st->cs = gp;
hp = gp->sy_hfirst + sh;
i = 1;
do {
if (*hp == 0) {
if (gp->sy_used == NSYM)
break;
return (hp);
}
cp1 = (*hp)->n_un.n_name;
for (cp = cursym.n_un.n_name; *cp == *cp1++;)
if (*cp++ == 0)
return (hp);
hp += i;
i += 2;
if (hp >= gp->sy_hlast)
hp -= HSIZE;
} while (i < HSIZE);
if (i > HSIZE)
error(1, "hash table botch");
}
error(1, "symbol table overflow");
/*NOTREACHED*/
}
symfree(st, saved)
struct syminfo *st;
struct nlist *saved;
{
register struct symseg *gp;
register struct nlist *sp;
for (gp = st->cs; gp >= st->fs; gp--, st->cs--) {
sp = gp->sy_first + gp->sy_used;
if (sp == saved) {
st->ns = sp;
return;
}
for (sp--; sp >= gp->sy_first; sp--) {
gp->sy_hfirst[sp->n_hash] = 0;
gp->sy_used--;
if (sp == saved) {
st->ns = sp;
return;
}
}
}
if (saved == 0)
return;
error(1, "symfree botch");
}
struct nlist **
slookup(s, st)
char *s;
struct syminfo *st;
{
cursym.n_un.n_name = s;
cursym.n_type = N_EXT+N_UNDF;
cursym.n_value = 0;
return (lookup(st));
}
enter(st, hp, nsp)
register struct syminfo *st;
register struct nlist **hp;
register struct nlist *nsp;
{
register struct nlist *sp;
if (*hp==0) {
if (hp < st->cs->sy_hfirst || hp >= st->cs->sy_hlast)
error(1, "enter botch");
*hp = st->ls = sp = st->cs->sy_first + st->cs->sy_used;
st->cs->sy_used++;
sp->n_un.n_name = nsp->n_un.n_name;
sp->n_type = nsp->n_type;
sp->n_hash = hp - st->cs->sy_hfirst;
sp->n_value = nsp->n_value;
st->ns = st->ls + 1;
(*dp)("enter: %s\t%s\t%x\t%x\n", st == &shsym ? "shsym" : "ldsym",
nsp->n_un.n_name, nsp->n_type, nsp->n_value);
return(1);
} else {
st->ls = *hp;
return(0);
}
}
symx(st, sp)
struct syminfo *st;
struct nlist *sp;
{
register struct symseg *gp;
if (sp == 0)
return (0);
for (gp = st->cs; gp >= st->fs; gp--)
/* <= is sloppy so ldsym.ns will always work */
if (sp >= gp->sy_first && sp <= gp->sy_last)
return ((gp - st->fs) * NSYM + sp - gp->sy_first);
error(1, "symx botch");
/*NOTREACHED*/
}
symreloc()
{
if (funding)
return;
switch (cursym.n_type & (N_TYPE+N_EXT)) {
case N_TEXT:
case N_EXT+N_TEXT:
cursym.n_value += ctrel;
return;
case N_DATA:
case N_EXT+N_DATA:
cursym.n_value += cdrel;
return;
case N_BSS:
case N_EXT+N_BSS:
cursym.n_value += cbrel;
return;
case N_EXT+N_UNDF:
return;
default:
if (cursym.n_type&N_EXT)
cursym.n_type = N_EXT+N_ABS;
return;
}
}
/*VARARGS 2*/
error(n, s, w, x, y, z)
char *s;
{
if (n == -2)
n = 0;
else
fprintf(stderr, "ld: ");
if (filname) {
fprintf(stderr, "%s", filname);
if (n != -1 && archdr.ar_name[0])
fprintf(stderr, "(%s)", archdr.ar_name);
fprintf(stderr, ": ");
}
fprintf(stderr, s, w, x, y, z);
fprintf(stderr, "\n");
if (n == -1)
return;
if (n)
delexit();
errlev = 2;
}
char *
errmsg(errnum)
int errnum;
{
extern int sys_nerr;
extern char *sys_errlist[];
static char buf[6+10+1]; /* "Error " + "int" + '\0' */
if (errnum < 0 || errnum > sys_nerr) {
(void) sprintf(buf, "Error %d", errnum);
return (buf);
} else
return (sys_errlist[errnum]);
}
readhdr(loc)
off_t loc;
{
dseek(&text, loc, (long)sizeof(filhdr));
mget((short *)&filhdr, sizeof(filhdr), &text);
if (N_BADMAG(filhdr)) {
if (filhdr.a_magic == OARMAG)
error(1, "old archive");
error(1, "bad magic number");
}
#if TARGET==SUN3 || TARGET==SUN2
if (filhdr.a_machtype == M_68020) {
use68020 = 1;
} else if ( !(filhdr.a_machtype == M_68010
|| filhdr.a_machtype == M_OLDSUN2))
error(1, "wrong machine type");
#endif /* sun3 */
if (filhdr.a_text&01 || filhdr.a_data&01)
error(1, "text/data size odd");
#if TARGET== SUN4
if (filhdr.a_machtype != M_SPARC)
error(1, "wrong machine type");
if (filhdr.a_toolversion != TV_SUN4){
error(1,"linker expected toolversion number 0x%x and got 0x%x",
TV_SUN4, filhdr.a_toolversion);
}
#endif /* sun4 */
if (filhdr.a_magic == NMAGIC || filhdr.a_magic == ZMAGIC) {
cdrel = -round(filhdr.a_text, segsize());
cbrel = cdrel - filhdr.a_data;
} else if (filhdr.a_magic == OMAGIC) {
cdrel = -filhdr.a_text;
cbrel = cdrel - filhdr.a_data;
} else
error(1, "bad format");
}
round(v, r)
int v;
u_long r;
{
r--;
v += r;
v &= ~(long)r;
return(v);
}
char *
savestr(cp, stab, sleft)
register char *cp;
char **stab;
int *sleft;
{
register int len;
len = strlen(cp) + 1;
if (len > *sleft) {
*sleft = NSAVETAB;
if (len > *sleft)
saveleft = *sleft;
*stab = mymalloc(*sleft);
if (*stab == 0)
error(1, "ran out of memory (savestr)");
}
strncpy(*stab, cp, len);
cp = *stab;
*stab += len;
*sleft -= len;
return (cp);
}
bopen(bp, off, bufsize)
register struct biobuf *bp;
{
bp->b_ptr = bp->b_buf = mymalloc(bufsize);
if (bp->b_ptr == (char *)0)
error(1, "ran out of memory (bopen)");
bp->b_bufsize = bufsize;
bp->b_nleft = bufsize - (off % bufsize);
bp->b_off = off;
bp->b_link = biobufs;
biobufs = bp;
}
int bwrerror;
bwrite(p, cnt, bp)
register char *p;
register int cnt;
register struct biobuf *bp;
{
register int put;
register char *to;
register int nwritten;
top:
if (cnt == 0)
return;
if (bp->b_nleft) {
put = bp->b_nleft;
if (put > cnt)
put = cnt;
bp->b_nleft -= put;
to = bp->b_ptr;
bcopy(p, to, put);
bp->b_ptr += put;
p += put;
cnt -= put;
goto top;
}
if (cnt >= bp->b_bufsize) {
if (bp->b_ptr != bp->b_buf)
bflush1(bp);
put = cnt - cnt % bp->b_bufsize;
if (boffset != bp->b_off)
lseek(biofd, bp->b_off, 0);
nwritten = write(biofd, p, put);
if (nwritten != put) {
bwrerror = 1;
filname = ofilename; /* kludge */
archdr.ar_name[0] = 0; /* kludge */
if (nwritten < 0)
error(1, "output write error: %s",
errmsg(errno));
else
error(1, "output write error: premature EOF");
}
bp->b_off += put;
boffset = bp->b_off;
p += put;
cnt -= put;
goto top;
}
bflush1(bp);
goto top;
}
bflush()
{
register struct biobuf *bp;
if (bwrerror)
return;
for (bp = biobufs; bp; bp = bp->b_link)
bflush1(bp);
}
bflush1(bp)
register struct biobuf *bp;
{
register int cnt = bp->b_ptr - bp->b_buf;
register int nwritten;
if (cnt == 0)
return;
if (boffset != bp->b_off)
lseek(biofd, bp->b_off, 0);
nwritten = write(biofd, bp->b_buf, cnt);
if (nwritten != cnt) {
bwrerror = 1;
filname = ofilename; /* kludge */
archdr.ar_name[0] = 0; /* kludge */
if (nwritten < 0)
error(1, "output write error: %s", errmsg(errno));
else
error(1, "output write error: premature EOF");
}
bp->b_off += cnt;
boffset = bp->b_off;
bp->b_ptr = bp->b_buf;
bp->b_nleft = bp->b_bufsize;
}
bflushc(bp, c)
register struct biobuf *bp;
{
bflush1(bp);
bputc(c, bp);
}
bseek(bp, off)
register struct biobuf *bp;
register off_t off;
{
bflush1(bp);
bp->b_nleft = bp->b_bufsize - (off % bp->b_bufsize);
bp->b_off = off;
}
/*
* total the symbols found
*/
int
totalsymb()
{
register int i;
register int j = 0;
for (i = 0; i < NSEG; i++)
if (ldsym.fs[i].sy_first != 0)
j += ldsym.fs[i].sy_used;
else
break;
return(j);
}
/*
* old malloc where if you wanted to allocated 0 byte it will returned
* you a address instead of null
*/
char *
mymalloc(cc)
int cc;
{
if (cc == 0)
return(malloc(1));
else
return(malloc(cc));
}
char *WhiteSp = " |\\\n";
char
**prepend_argv(ld_opts, argv, argc)
char *ld_opts;
char **argv;
int *argc;
{
char *new, *s;
char **tmp_argv = NULL;
int tmp_argc = 0;
int i, nochars = 0;
while(isspace(*ld_opts)) ld_opts++;
s = ld_opts;
nochars = strlen(ld_opts) + 1;
while(strlen(s) != 0) {
tmp_argc++;
if((new = (char *)strpbrk(s, WhiteSp)) == NULL)
break;
else {
*new++ = '\0';
while(isspace(*new)) new++;
s = new;
};
};
tmp_argv = (char **)calloc(tmp_argc + *argc, sizeof(char *));
*tmp_argv = *argv;
s = ld_opts;
for(i=1; (i < (tmp_argc + *argc)); i++){
if (i < (tmp_argc +1)){
if((strlen(s) <= nochars) && (s != NULL)){
while(isspace(*s)){ s++; nochars--;}
tmp_argv[i] = s;
if ((nochars -= (strlen(s)+1)) > 1)
s = s + strlen(s) + 1;
else s = s + strlen(s);
};
} else tmp_argv[i] = argv[i-tmp_argc];
};
*argc += tmp_argc;
return(tmp_argv);
}
#ifdef BROWSER
cb_callback_write_stab()
{
}
#endif
#ifdef SUNPRO
struct slc { /* SUNPRO libdep cell */
char *slc_name; /* name of dependent library */
struct slc *slc_next; /* next cell */
};
do_report_libdep(path)
char *path;
{
struct slc *p;
static struct slc *sp = 0;
static struct slc **spp = &sp;
for (p = sp; p; p = p->slc_next) {
if (strcmp(path, p->slc_name) == 0)
return;
}
*spp = (struct slc *)mymalloc(sizeof (struct slc));
(*spp)->slc_name = (char *)strcpy(mymalloc(strlen(path) + 1), path);
(*spp)->slc_next = (struct slc *)0;
spp = &(*spp)->slc_next;
report_libdep(path, "LD");
}
#endif NSE