static char sccsid
[] = "@(#)ld.c 4.7 1/31/83";
* ld - string table version for VAX
* 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
* 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
* 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 40 /* Number of segments, each data structure */
#define NSYM 1103 /* Number of symbols per segment */
#define NROUT 250 /* Number of library references per segment */
#define NSYMPR 100 /* 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.
* Csymseg points to the current symbol table segment;
* csymseg->sy_first[csymseg->sy_used] is the next symbol slot to be allocated,
* (unless csymseg->sy_used == NSYM in which case we will allocate another
* symbol table segment first.)
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
], *csymseg
;
* 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
* 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(x) (symseg[(x)/NSYM].sy_first+((x)%NSYM))
/* symx() is a function, defined below */
struct nlist cursym
; /* current symbol */
struct nlist
*lastsym
; /* last symbol entered */
struct nlist
*nextsym
; /* next available symbol table entry */
struct nlist
*addsym
; /* first sym defined during incr load */
int nsym
; /* pass2: number of local symbols in a.out */
/* nsym + symx(nextsym) 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.
* 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.
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
];
* 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
* work in hardware page sizes. The associated constants are defined
* as BLKSIZE, BLKSHIFT, and BLKMASK.
#define BLKMASK (BLKSIZE - 1)
* Header from the a.out and the archive it is from (if any).
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 zflag
; /* demand paged */
long hsize
; /* size of hole at beginning of data to be squashed */
int Aflag
; /* doing incremental load */
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 */
* 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, 0 unless given by -T.
* Database is the base of all data, computed before and used during pass2.
* 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
, 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.
* 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.
short b_nleft
; /* Number free spaces left in b_buf */
/* Initialize to be less than BUFSIZ initially, to boundary align in file */
char *b_ptr
; /* Next place to stuff characters */
char b_buf
[BUFSIZ
]; /* The buffer itself */
off_t b_off
; /* Current file offset */
struct biobuf
*b_link
; /* Link in chain for bflush() */
#define bputc(c,b) ((b)->b_nleft ? (--(b)->b_nleft, *(b)->b_ptr++ = (c)) \
struct biobuf
*tout
, *dout
, *trout
, *drout
, *sout
, *strout
;
* 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
);
int ofilfnd
; /* -o given; otherwise move l.out to a.out */
char *ofilename
= "l.out";
int ofilemode
; /* respect umask even for unsucessful ld's */
int infil
; /* current input file descriptor */
char *filname
; /* and its name */
* Base of the string table of the current module (pass1 and pass2).
if (signal(SIGINT
, SIG_IGN
) != SIG_IGN
) {
signal(SIGTERM
, delexit
);
* Scan files once to find where symbols are defined.
for (i
=1; ap
[i
]; i
++) switch (ap
[i
]) {
error(1, "-u or -c: arg missing");
error(1, "-H: arg missing");
error(1, "-H: too late, some text already loaded");
error(1, "-A: arg missing");
error(1, "-A: only one base file allowed");
trsize
= drsize
= tsize
= dsize
= bsize
= 0;
ctrel
= cdrel
= cbrel
= 0;
error(1, "-D: arg missing");
error(1, "-D: too small");
error(1, "-T: arg missing");
error(1, "-T: too late, some text already loaded");
printf("ld: -i ignored\n");
error(1, "-y: symbol name missing");
ytab
= (char **)calloc(argc
, sizeof (char **));
error(1, "ran out of memory (-y)");
ytab
[yflag
++] = &ap
[i
+1];
filname
= savestr("-x"); /* kludge */
filname
[1] = ap
[i
]; /* kludge */
archdr
.ar_name
[0] = 0; /* kludge */
if (rflag
== 0 && Nflag
== 0 && nflag
== 0)
* Convert a ascii string which is a hex number.
* Used by -T and -D options.
else if (c
>= 'a' && c
<= 'f')
else if (c
>= 'A' && c
<= 'F')
error(1, "badly formed hex number");
if (delarg
==0 && Aflag
==0)
chmod(ofilename
, ofilemode
);
* We have to insure that the last block of the data segment
* is allocated a full BLKSIZE block. If the underlying
* file system allocates frags that are smaller than BLKSIZE,
* a full zero filled BLKSIZE block needs to be allocated so
* that when it is demand paged, the paged in block will be
* appropriately filled with zeros.
size
= round(stbuf
.st_size
, BLKSIZE
);
if (!rflag
&& size
> stbuf
.st_size
) {
lseek(biofd
, size
- 1, 0);
for (i
=1; ap
[i
]; i
++) switch (ap
[i
]) {
bputc(0, dout
), dorigin
++;
* Scan file to find defined symbols.
register struct ranlib
*tp
;
* Archive without table of contents.
* (Slowly) process each member.
"warning: archive has no table of contents; add one using ranlib(1)");
round(atol(archdr
.ar_size
), sizeof (short));
* 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!)
nloc
= SARMAG
+ sizeof (archdr
);
dseek(&text
, nloc
, sizeof (tnum
));
mget((char *)&tnum
, sizeof (tnum
), &text
);
tab
= (struct ranlib
*)malloc(tnum
);
error(1, "ran out of memory (toc)");
dseek(&text
, nloc
, tnum
);
mget((char *)tab
, tnum
, &text
);
tnum
/= sizeof (struct ranlib
);
dseek(&text
, nloc
, sizeof (ssiz
));
mget((char *)&ssiz
, sizeof (ssiz
), &text
);
tabstr
= (char *)malloc(ssiz
);
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
;
* Table of contents is out of date, so search
* as a normal library (but skip the __.SYMDEF file).
"warning: table of contents for archive is out of date; rerun ranlib(1)");
round(atol(archdr
.ar_size
), sizeof(short));
* 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.
dseek(&text
, nloc
, (long) sizeof archdr
);
if (load1(1, nloc
+ (sizeof archdr
)))
* 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.
if (clibseg
->li_used
== NROUT
) {
if (++clibseg
== &libseg
[NSEG
])
error(1, "too many files loaded from libraries");
clibseg
->li_first
= (off_t
*)malloc(NROUT
* sizeof (off_t
));
if (clibseg
->li_first
== 0)
error(1, "ran out of memory (nextlibp)");
clibseg
->li_first
[clibseg
->li_used
++] = val
;
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.
register struct nlist
*sp
, **hp
;
register struct ranlib
*tp
, *tplast
;
int nsymt
= symx(nextsym
);
for (tp
= tab
; tp
<= tplast
; tp
++) {
if ((hp
= slookup(tp
->ran_un
.ran_name
)) == 0)
if (sp
->n_type
!= N_EXT
+N_UNDF
)
while (tp
< tplast
&& (tp
+1)->ran_off
== loc
)
return (symx(nextsym
) != nsymt
);
* Examine a single file or archive member on pass 1.
register struct nlist
*sp
;
int ndef
, nlocal
, type
, size
, nsymt
;
if (filhdr
.a_syms
== 0) {
if (filhdr
.a_text
+filhdr
.a_data
== 0)
maxoff
= atol(archdr
.ar_size
);
if (N_STROFF(filhdr
) + sizeof (off_t
) >= maxoff
)
error(1, "too small (old format .o?)");
ctrel
= tsize
; cdrel
+= dsize
; cbrel
+= bsize
;
dseek(&text
, loc
, filhdr
.a_syms
);
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 *)malloc(size
);
error(1, "no space for string table");
mget(curstr
+sizeof(off_t
), size
-sizeof(off_t
), &reloc
);
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
;
if (Xflag
==0 || cursym
.n_un
.n_name
[0]!='L' ||
if ((sp
= lastsym
)->n_type
!= N_EXT
+N_UNDF
)
if (cursym
.n_type
== N_EXT
+N_UNDF
) {
if (cursym
.n_value
> sp
->n_value
)
sp
->n_value
= cursym
.n_value
;
if (sp
->n_value
!= 0 && cursym
.n_type
== N_EXT
+N_TEXT
)
sp
->n_type
= cursym
.n_type
;
sp
->n_value
= cursym
.n_value
;
dsize
+= round(filhdr
.a_data
, sizeof (long));
bsize
+= round(filhdr
.a_bss
, sizeof (long));
trsize
+= filhdr
.a_trsize
;
drsize
+= filhdr
.a_drsize
;
textbase
= (*slookup("_end"))->n_value
;
for (i
= symx(savnext
); i
< nsymt
; i
++) {
sp
->n_un
.n_name
= savestr(sp
->n_un
.n_name
);
* No symbols defined by this library member.
* Rip out the hash table entries and reset the symbol table.
register struct nlist
*sp
;
long csize
, t
, corigin
, ocsize
;
p_etext
= *slookup("_etext");
p_edata
= *slookup("_edata");
p_end
= *slookup("_end");
* If there are any undefined symbols, save the relocation bits.
for (i
= 0; i
< nsymt
; i
++) {
if (sp
->n_type
==N_EXT
+N_UNDF
&& sp
->n_value
==0 &&
sp
!=p_end
&& sp
!=p_edata
&& sp
!=p_etext
) {
* Assign common locations.
addsym
= symseg
[0].sy_first
;
database
= round(tsize
+textbase
,
(nflag
||zflag
? PAGSIZ
: sizeof (long)));
ldrsym(p_etext
, tsize
, N_EXT
+N_TEXT
);
ldrsym(p_edata
, dsize
, N_EXT
+N_DATA
);
ldrsym(p_end
, bsize
, N_EXT
+N_BSS
);
for (i
= symx(addsym
); i
< nsymt
; i
++) {
if ((s
=sp
->n_type
)==N_EXT
+N_UNDF
&&
if (t
>= sizeof (double))
else if (t
>= sizeof (long))
csize
= round(csize
, rnd
);
sp
->n_type
= N_EXT
+N_COMM
;
if (s
&N_EXT
&& (s
&N_TYPE
)==N_UNDF
&& s
&N_STAB
) {
sp
->n_type
= (s
&N_STAB
) | (N_EXT
+N_COMM
);
* Now set symbols to their final value
csize
= round(csize
, sizeof (long));
corigin
= dorigin
+ dsize
;
borigin
= corigin
+ csize
;
for (i
= symx(addsym
); i
<nsymt
; i
++) {
switch (sp
->n_type
& (N_TYPE
+N_EXT
)) {
if ((arflag
==0 || dflag
) && sp
->n_value
==0) {
if (sp
==p_end
|| sp
==p_etext
|| sp
==p_edata
)
printf("%s\n", sp
->n_un
.n_name
);
sp
->n_type
= (sp
->n_type
& N_STAB
) | (N_EXT
+N_BSS
);
nsym
= ssize
/ (sizeof cursym
);
fixspec(p_etext
,torigin
);
fixspec(p_edata
,dorigin
);
if(symx(sym
) < symx(addsym
) && sym
!=0)
register struct nlist
*sp
;
if ((sp
->n_type
!= N_EXT
+N_UNDF
|| sp
->n_value
) && !Aflag
) {
printf("%s: ", sp
->n_un
.n_name
);
error(0, "user attempt to redfine loader-defined symbol");
extern char *sys_errlist
[];
ofilemode
= 0777 & ~umask(0);
biofd
= creat(ofilename
, 0666 & ofilemode
);
filname
= ofilename
; /* kludge */
archdr
.ar_name
[0] = 0; /* kludge */
error(1, sys_errlist
[errno
]); /* kludge */
struct stat mybuf
; /* kls kludge */
fstat(biofd
, &mybuf
); /* suppose file exists, wrong*/
if(mybuf
.st_mode
& 0111) { /* mode, ld fails? */
chmod(ofilename
, mybuf
.st_mode
& 0666);
ofilemode
= mybuf
.st_mode
;
filhdr
.a_magic
= nflag
? NMAGIC
: (zflag
? ZMAGIC
: OMAGIC
);
filhdr
.a_text
= nflag
? tsize
:
round(tsize
, zflag
? PAGSIZ
: sizeof (long));
filhdr
.a_data
= zflag
? round(dsize
, PAGSIZ
) : dsize
;
bss
= bsize
- (filhdr
.a_data
- dsize
);
filhdr
.a_trsize
= trsize
;
filhdr
.a_drsize
= drsize
;
filhdr
.a_syms
= sflag
? 0: (ssize
+ (sizeof cursym
)*symx(nextsym
));
if (entrypt
->n_type
!=N_EXT
+N_TEXT
)
error(0, "entry point not in text");
filhdr
.a_entry
= entrypt
->n_value
;
filhdr
.a_trsize
= (rflag
? trsize
:0);
filhdr
.a_drsize
= (rflag
? drsize
:0);
bwrite((char *)&filhdr
, sizeof (filhdr
), tout
);
wroff
= N_TXTOFF(filhdr
) + filhdr
.a_text
;
outb(&dout
, filhdr
.a_data
);
outb(&trout
, filhdr
.a_trsize
);
outb(&drout
, filhdr
.a_drsize
);
if (sflag
==0 || xflag
==0) {
outb(&sout
, filhdr
.a_syms
);
wroff
+= sizeof (offset
);
register struct biobuf
**bp
;
*bp
= (struct biobuf
*)malloc(sizeof (struct biobuf
));
error(1, "ran out of memory (outb)");
while (cp
>= acp
&& *--cp
!= '/');
} else { /* scan archive members referenced */
if (clibseg
->li_used2
== clibseg
->li_used
) {
if (clibseg
->li_used
< NROUT
)
error(1, "libseg botch");
loc
= clibseg
->li_first
[clibseg
->li_used2
++];
dseek(&text
, loc
, (long)sizeof(archdr
));
load2(loc
+ (long)sizeof(archdr
));
register struct nlist
*sp
;
register struct local
*lp
;
* Reread the symbol table, recording the numbering
* of symbols for fixing external references.
for (i
= 0; i
< LHSIZ
; i
++)
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
),
curstr
= (char *)malloc(size
);
error(1, "out of space reading string table (pass 2)");
mget(curstr
+sizeof(off_t
), size
-sizeof(off_t
), &text
);
dseek(&text
, loc
+filhdr
.a_text
+filhdr
.a_data
+
filhdr
.a_trsize
+filhdr
.a_drsize
, filhdr
.a_syms
);
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
;
/* inline expansion of symreloc() */
switch (cursym
.n_type
& 017) {
cursym
.n_type
= N_EXT
+N_ABS
;
/* end inline expansion of symreloc() */
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
)) {
(!Xflag
||cursym
.n_un
.n_name
[0]!='L'||type
&N_STAB
))
if ((sp
= *lookup()) == 0)
error(1, "internal error: symbol not found");
if (cursym
.n_type
== N_EXT
+N_UNDF
) {
if (clocseg
->lo_used
== NSYMPR
) {
if (++clocseg
== &locseg
[NSEG
])
error(1, "local symbol overflow");
if (clocseg
->lo_first
== 0) {
clocseg
->lo_first
= (struct local
*)
malloc(NSYMPR
* sizeof (struct local
));
if (clocseg
->lo_first
== 0)
error(1, "out of memory (clocseg)");
lp
= &clocseg
->lo_first
[clocseg
->lo_used
++];
lp
->l_link
= lochash
[symno
% LHSIZ
];
lochash
[symno
% LHSIZ
] = lp
;
if (cursym
.n_type
& N_STAB
)
if (cursym
.n_type
!=sp
->n_type
|| cursym
.n_value
!=sp
->n_value
) {
printf("%s: ", cursym
.n_un
.n_name
);
error(0, "multiply defined");
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
,
load2td(cdrel
, dorigin
- database
, dout
, drout
);
while (filhdr
.a_data
& (sizeof(long)-1)) {
torigin
+= filhdr
.a_text
;
dorigin
+= round(filhdr
.a_data
, sizeof (long));
borigin
+= round(filhdr
.a_bss
, sizeof (long));
register struct tynames
*tp
;
if (cursym
.n_type
& N_STAB
)
printf("(%s)", archdr
.ar_name
);
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
);
for (tp
= tynames
; tp
->ty_name
; tp
++)
if (tp
->ty_value
== (cursym
.n_type
&N_TYPE
))
printf((cursym
.n_type
&N_TYPE
) ? "definition of" : "reference to");
printf(" %s", tp
->ty_name
);
printf(" %s\n", cursym
.n_un
.n_name
);
* 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
)
register struct nlist
*sp
;
register struct local
*lp
;
register struct relocation_info
*rp
, *rpend
;
struct relocation_info
*relp
;
relp
= (struct relocation_info
*)malloc(relsz
);
codep
= (char *)malloc(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
++) {
cp
= codep
+ rp
->r_address
;
* Pick up previous value at location to be relocated.
error(1, "load2td botch: bad length");
* 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.
* Search the hash table which maps local
* symbol numbers to symbol tables entries
lp
= lochash
[rp
->r_symbolnum
% LHSIZ
];
while (lp
->l_index
!= rp
->r_symbolnum
) {
error(1, "local symbol botch");
if (sp
->n_type
== N_EXT
+N_UNDF
)
rp
->r_symbolnum
= nsym
+symx(sp
);
rp
->r_symbolnum
= sp
->n_type
& N_TYPE
;
} else switch (rp
->r_symbolnum
& N_TYPE
) {
* Relocation is relative to the loaded position
* of another segment. Update by the change in position
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.)
* Put the value back in the segment,
* while checking for overflow.
if (tw
< -128 || tw
> 127)
error(0, "byte displacement overflow");
if (tw
< -32768 || tw
> 32767)
error(0, "word displacement overflow");
* 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.
rp
->r_address
+= position
;
bwrite(codep
, codesz
, b1
);
for (i
= 0; i
< nsymt
; i
++)
bwrite(&offset
, sizeof offset
, sout
);
if (link("l.out", "a.out") < 0)
error(1, "cannot move l.out to a.out");
cursym
.n_value
= torigin
;
mget((char *)&archdr
, sizeof archdr
, &text
);
for (cp
=archdr
.ar_name
; cp
<&archdr
.ar_name
[sizeof(archdr
.ar_name
)];)
if (sp
->size
&& sp
->nibuf
) {
lseek(infil
, (sp
->bno
+1)*BLKSIZE
, 0);
if (take
> sp
->size
|| read(infil
, loc
, take
) != take
)
error(1, "premature EOF");
dseek(sp
, (sp
->bno
+1+take
/BLKSIZE
)*BLKSIZE
, -1);
sp
->n_un
.n_strx
= offset
;
bwrite(str
, len
, strout
);
bwrite(sp
, sizeof (*sp
), bp
);
error(1, "loader error; odd offset");
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
)
lseek(infil
, loc
& ~(long)BLKMASK
, 0);
if ((n
= read(infil
, p
->buff
, sizeof(p
->buff
))) < 0)
error(1, "botch: no pages");
if (s
!= -1) {sp
->size
= s
; sp
->pos
= 0;}
sp
->ptr
= (char *)(p
->buff
+ o
);
if ((sp
->nibuf
= p
->nibuf
-o
) <= 0)
if ((sp
->nibuf
-= sizeof(char)) < 0) {
dseek(sp
, ((long)(sp
->bno
+1)<<BLKSHIFT
), (long)-1);
sp
->nibuf
-= sizeof(char);
if ((sp
->size
-= sizeof(char)) <= 0) {
error(1, "premature EOF");
sp
->pno
= (PAGE
*) &fpage
;
archdr
.ar_name
[0] = '\0';
if (cp
[0]=='-' && cp
[1]=='l') {
char *locfilname
= "/usr/local/lib/libxxxxxxxxxxxxxxx";
filname
= "/usr/lib/libxxxxxxxxxxxxxxx";
locfilname
[c
+18] = cp
[c
+2];
filname
[c
+12] = locfilname
[c
+18] = '.';
filname
[c
+13] = locfilname
[c
+19] = 'a';
filname
[c
+14] = locfilname
[c
+20] = '\0';
if ((infil
= open(filname
+4, 0)) >= 0) {
} else if ((infil
= open(filname
, 0)) < 0) {
if (infil
== -1 && (infil
= open(filname
, 0)) < 0)
page
[0].bno
= page
[1].bno
= -1;
page
[0].nuser
= page
[1].nuser
= 0;
text
.pno
= reloc
.pno
= (PAGE
*) &fpage
;
dseek(&text
, 0L, SARMAG
);
error(1, "premature EOF");
mget((char *)arcmag
, SARMAG
, &text
);
if (strcmp(arcmag
, ARMAG
))
dseek(&text
, SARMAG
, sizeof archdr
);
if (strncmp(archdr
.ar_name
, "__.SYMDEF", sizeof(archdr
.ar_name
)) != 0)
return (stb
.st_mtime
> atol(archdr
.ar_date
) ? 3 : 2);
register struct nlist
**hp
;
register struct symseg
*gp
;
for (cp
= cursym
.n_un
.n_name
; *cp
;)
sh
= (sh
& 0x7fffffff) % HSIZE
;
for (gp
= symseg
; gp
< &symseg
[NSEG
]; gp
++) {
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
;
cp1
= (*hp
)->n_un
.n_name
;
for (cp
= cursym
.n_un
.n_name
; *cp
== *cp1
++;)
error(1, "hash table botch");
error(1, "symbol table overflow");
register struct symseg
*gp
;
register struct nlist
*sp
;
for (gp
= csymseg
; gp
>= symseg
; gp
--, csymseg
--) {
sp
= gp
->sy_first
+ gp
->sy_used
;
for (sp
--; sp
>= gp
->sy_first
; sp
--) {
gp
->sy_hfirst
[sp
->n_hash
] = 0;
error(1, "symfree botch");
cursym
.n_type
= N_EXT
+N_UNDF
;
register struct nlist
**hp
;
register struct nlist
*sp
;
if (hp
< csymseg
->sy_hfirst
|| hp
>= csymseg
->sy_hlast
)
*hp
= lastsym
= sp
= csymseg
->sy_first
+ csymseg
->sy_used
;
sp
->n_un
.n_name
= cursym
.n_un
.n_name
;
sp
->n_type
= cursym
.n_type
;
sp
->n_hash
= hp
- csymseg
->sy_hfirst
;
sp
->n_value
= cursym
.n_value
;
register struct symseg
*gp
;
for (gp
= csymseg
; gp
>= symseg
; gp
--)
/* <= is sloppy so nextsym will always work */
if (sp
>= gp
->sy_first
&& sp
<= gp
->sy_last
)
return ((gp
- symseg
) * NSYM
+ sp
- gp
->sy_first
);
switch (cursym
.n_type
& 017) {
cursym
.n_type
= N_EXT
+N_ABS
;
if (n
!= -1 && archdr
.ar_name
[0])
printf("(%s)", archdr
.ar_name
);
dseek(&text
, loc
, (long)sizeof(filhdr
));
mget((short *)&filhdr
, sizeof(filhdr
), &text
);
if (filhdr
.a_magic
== OARMAG
)
error(1, "bad magic number");
if (filhdr
.a_text
&01 || filhdr
.a_data
&01)
error(1, "text/data size odd");
if (filhdr
.a_magic
== NMAGIC
|| filhdr
.a_magic
== ZMAGIC
) {
cdrel
= -round(filhdr
.a_text
, PAGSIZ
);
cbrel
= cdrel
- filhdr
.a_data
;
} else if (filhdr
.a_magic
== OMAGIC
) {
cbrel
= cdrel
- filhdr
.a_data
;
savetab
= (char *)malloc(saveleft
);
error(1, "ran out of memory (savestr)");
strncpy(savetab
, cp
, len
);
bp
->b_nleft
= BUFSIZ
- off
% BUFSIZ
;
register struct biobuf
*bp
;
asm("movc3 r8,(r11),(r7)");
if (bp
->b_ptr
!= bp
->b_buf
)
put
= cnt
- cnt
% BUFSIZ
;
if (boffset
!= bp
->b_off
)
lseek(biofd
, bp
->b_off
, 0);
if (write(biofd
, p
, put
) != put
) {
error(1, "output write error");
register struct biobuf
*bp
;
for (bp
= biobufs
; bp
; bp
= bp
->b_link
)
register struct biobuf
*bp
;
register int cnt
= bp
->b_ptr
- bp
->b_buf
;
if (boffset
!= bp
->b_off
)
lseek(biofd
, bp
->b_off
, 0);
if (write(biofd
, bp
->b_buf
, cnt
) != cnt
) {
error(1, "output write error");
register struct biobuf
*bp
;