5396 lines
130 KiB
C
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
|