* $Id: lib.c,v 1.4 1993/11/05 12:43:11 pk Exp $ - library routines
/* Length of the vector `search_dirs'. */
struct file_entry
*decode_library_subfile();
void linear_library(), symdef_library();
* Search the library ENTRY, already open on descriptor DESC. This means
* deciding which library members to load, making a chain of `struct
* file_entry' for those members, and entering their global symbols in the
search_library(desc
, entry
)
struct file_entry
*entry
;
register struct file_entry
*subentry
;
if (!(link_mode
& FORCEARCHIVE
) && !undefined_global_sym_count
)
/* Examine its first member, which starts SARMAG bytes in. */
subentry
= decode_library_subfile(desc
, entry
, SARMAG
, &member_length
);
name
= subentry
->filename
;
/* Search via __.SYMDEF if that exists, else linearly. */
if (!strcmp(name
, "__.SYMDEF"))
symdef_library(desc
, entry
, member_length
);
linear_library(desc
, entry
);
* Construct and return a file_entry for a library member. The library's
* file_entry is library_entry, and the library is open on DESC.
* SUBFILE_OFFSET is the byte index in the library of this member's header.
* We store the length of the member into *LENGTH_LOC.
decode_library_subfile(desc
, library_entry
, subfile_offset
, length_loc
)
struct file_entry
*library_entry
;
register struct file_entry
*subentry
;
lseek(desc
, subfile_offset
, 0);
bytes_read
= read(desc
, &hdr1
, sizeof hdr1
);
return 0; /* end of archive */
if (sizeof hdr1
!= bytes_read
)
fatal_with_file("malformed library archive ", library_entry
);
if (sscanf(hdr1
.ar_size
, "%d", &member_length
) != 1)
fatal_with_file("malformatted header of archive member in ", library_entry
);
subentry
= (struct file_entry
*) xmalloc(sizeof(struct file_entry
));
bzero(subentry
, sizeof(struct file_entry
));
namelen
< sizeof hdr1
.ar_name
&& hdr1
.ar_name
[namelen
] != 0 && hdr1
.ar_name
[namelen
] != ' '
&& hdr1
.ar_name
[namelen
] != '/';
name
= (char *) xmalloc(namelen
+ 1);
strncpy(name
, hdr1
.ar_name
, namelen
);
subentry
->filename
= name
;
subentry
->local_sym_name
= name
;
subentry
->starting_offset
= subfile_offset
+ sizeof hdr1
;
subentry
->superfile
= library_entry
;
subentry
->library_flag
= 0;
subentry
->header_read_flag
= 0;
subentry
->just_syms_flag
= 0;
subentry
->total_size
= member_length
;
(*length_loc
) = member_length
;
* Search a library that has a __.SYMDEF member. DESC is a descriptor on
* which the library is open. The file pointer is assumed to point at the
* __.SYMDEF data. ENTRY is the library's file_entry. MEMBER_LENGTH is the
* length of the __.SYMDEF data.
symdef_library(desc
, entry
, member_length
)
struct file_entry
*entry
;
int *symdef_data
= (int *) xmalloc(member_length
);
register struct ranlib
*symdef_base
;
struct file_entry
*prev
= 0;
bytes_read
= read(desc
, symdef_data
, member_length
);
if (bytes_read
!= member_length
)
fatal_with_file("malformatted __.SYMDEF in ", entry
);
number_of_symdefs
= md_swap_long(*symdef_data
) / sizeof(struct ranlib
);
if (number_of_symdefs
< 0 ||
number_of_symdefs
* sizeof(struct ranlib
) + 2 * sizeof(int) > member_length
)
fatal_with_file("malformatted __.SYMDEF in ", entry
);
symdef_base
= (struct ranlib
*) (symdef_data
+ 1);
length_of_strings
= md_swap_long(*(int *) (symdef_base
+ number_of_symdefs
));
if (length_of_strings
< 0
|| number_of_symdefs
* sizeof(struct ranlib
) + length_of_strings
+ 2 * sizeof(int) > member_length
)
fatal_with_file("malformatted __.SYMDEF in ", entry
);
sym_name_base
= sizeof(int) + (char *) (symdef_base
+ number_of_symdefs
);
/* Check all the string indexes for validity. */
md_swapin_ranlib_hdr(symdef_base
, number_of_symdefs
);
for (i
= 0; i
< number_of_symdefs
; i
++) {
register int index
= symdef_base
[i
].ran_un
.ran_strx
;
if (index
< 0 || index
>= length_of_strings
|| (index
&& *(sym_name_base
+ index
- 1)))
fatal_with_file("malformatted __.SYMDEF in ", entry
);
* Search the symdef data for members to load. Do this until one
* whole pass finds nothing to load.
* Scan all the symbols mentioned in the symdef for ones that
* we need. Load the library members that contain such
for (i
= 0; (i
< number_of_symdefs
&&
((link_mode
& FORCEARCHIVE
) ||
undefined_global_sym_count
||
common_defined_global_count
)); i
++) {
register int offset
= symdef_base
[i
].ran_off
;
struct file_entry
*subentry
;
if (symdef_base
[i
].ran_un
.ran_strx
< 0)
sp
= getsym_soft(sym_name_base
+ symdef_base
[i
].ran_un
.ran_strx
);
* If we find a symbol that appears to be needed,
* think carefully about the archive member that the
* Per Mike Karels' recommendation, we no longer load
* library files if the only reference(s) that would
* be satisfied are 'common' references. This
* prevents some problems with name pollution (e.g. a
* global common 'utime' linked to a function).
if (!(link_mode
& FORCEARCHIVE
) &&
(!sp
->referenced
&& !sp
->sorefs
)) )
* Don't think carefully about any archive member
* more than once in a given pass.
if (prev_offset
== offset
)
* Read the symbol table of the archive member.
subentry
= decode_library_subfile(desc
,
"invalid offset for %s in symbol table of %s",
+ symdef_base
[i
].ran_un
.ran_strx
,
read_entry_symbols(desc
, subentry
);
subentry
->strings
= (char *)
malloc(subentry
->string_size
);
read_entry_strings(desc
, subentry
);
* Now scan the symbol table and decide whether to
if (!(link_mode
& FORCEARCHIVE
) &&
!subfile_wanted_p(subentry
)) {
* This member is needed; load it. Since we
* are loading something on this pass, we
* must make another pass through the symdef
read_entry_relocation(desc
, subentry
);
enter_file_symbols(subentry
);
entry
->subfiles
= subentry
;
* Clear out this member's symbols from the
* symdef data so that following passes won't
for (j
= 0; j
< number_of_symdefs
; j
++) {
if (symdef_base
[j
].ran_off
== offset
)
symdef_base
[j
].ran_un
.ran_strx
= -1;
* We'll read the strings again if we need them
* Search a library that has no __.SYMDEF. ENTRY is the library's file_entry.
* DESC is the descriptor it is open on.
linear_library(desc
, entry
)
struct file_entry
*entry
;
register struct file_entry
*prev
= 0;
register int this_subfile_offset
= SARMAG
;
while ((link_mode
& FORCEARCHIVE
) ||
undefined_global_sym_count
|| common_defined_global_count
) {
register struct file_entry
*subentry
;
subentry
= decode_library_subfile(desc
, entry
, this_subfile_offset
,
read_entry_symbols(desc
, subentry
);
subentry
->strings
= (char *) alloca(subentry
->string_size
);
read_entry_strings(desc
, subentry
);
if (!(link_mode
& FORCEARCHIVE
) &&
!subfile_wanted_p(subentry
)) {
read_entry_relocation(desc
, subentry
);
enter_file_symbols(subentry
);
entry
->subfiles
= subentry
;
subentry
->strings
= 0; /* Since space will dissapear
this_subfile_offset
+= member_length
+ sizeof(struct ar_hdr
);
if (this_subfile_offset
& 1)
* ENTRY is an entry for a library member. Its symbols have been read into
* core, but not entered. Return nonzero if we ought to load this member.
struct file_entry
*entry
;
struct localsymbol
*lsp
, *lspend
;
register int dollar_cond
= 0;
lspend
= entry
->symbols
+ entry
->nsymbols
;
for (lsp
= entry
->symbols
; lsp
< lspend
; lsp
++) {
register struct nlist
*p
= &lsp
->nzlist
.nlist
;
register int type
= p
->n_type
;
register char *name
= p
->n_un
.n_strx
+ entry
->strings
;
register symbol
*sp
= getsym_soft(name
);
* If the symbol has an interesting definition, we could
|| (type
== (N_UNDF
| N_EXT
) && p
->n_value
== 0
|| set_element_prefixed_p(name
)
sp
= getsym_soft(&name
[2]);
print_file_name(entry
, stdout
);
fprintf(stdout
, " needed due to $-conditional %s\n", name
);
* If this symbol has not been hashed, we can't be
* We don't load a file if it merely satisfies a
* common reference (see explanation above in
if (sp
->referenced
&& !sp
->defined
) {
* This is a symbol we are looking for. It
* is either not yet defined or defined as a
if (type
== (N_UNDF
| N_EXT
)) {
* Symbol being defined as common.
* Remember this, but don't load
* If it didn't used to be common, up
* the count of common symbols.
if (!sp
->max_common_size
)
common_defined_global_count
++;
if (sp
->max_common_size
< p
->n_value
)
sp
->max_common_size
= p
->n_value
;
undefined_global_sym_count
--;
print_file_name(entry
, stdout
);
fprintf(stdout
, " needed due to %s\n", sp
->name
);
/* Check for undefined symbols in shared objects */
for (lsp
= sp
->sorefs
; lsp
; lsp
= lsp
->next
) {
type
= lsp
->nzlist
.nlist
.n_type
;
type
!= (N_UNDF
| N_EXT
))
continue; /* We don't need it */
print_file_name(entry
, stdout
);
fprintf(stdout
, " needed due to shared lib ref %s\n", sp
->name
);
* Read the symbols of dynamic entity ENTRY into core. Assume it is already
* open, on descriptor DESC.
read_shared_object (desc
, entry
)
struct file_entry
*entry
;
struct link_dynamic_2 dyn2
;
if (!entry
->header_read_flag
)
read_header (desc
, entry
);
/* Read DYNAMIC structure (first in data segment) */
text_offset (entry
) + entry
->header
.a_text
,
if (read(desc
, &dyn
, sizeof dyn
) != sizeof dyn
) {
"premature eof in data segment of ", entry
);
md_swapin_link_dynamic(&dyn
);
switch (dyn
.ld_version
) {
fatal_with_file( "unsupported _DYNAMIC version ", entry
);
/* Read link_dynamic_2 struct (from data segment) */
text_offset(entry
) + dyn
.ld_un
.ld_2
,
if (read(desc
, &dyn2
, sizeof dyn2
) != sizeof dyn2
) {
fatal_with_file( "premature eof in data segment of ", entry
);
md_swapin_link_dynamic_2(&dyn2
);
/* Read symbols (text segment) */
n
= dyn2
.ld_strings
- dyn2
.ld_symbols
;
(has_nz
? sizeof(struct nzlist
) : sizeof(struct nlist
));
nzp
= (struct nzlist
*)(np
= (struct nlist
*) alloca (n
));
entry
->symbols
= (struct localsymbol
*)
xmalloc(entry
->nsymbols
* sizeof(struct localsymbol
));
lseek(desc
, text_offset (entry
) + dyn2
.ld_symbols
, L_SET
);
if (read(desc
, (char *)nzp
, n
) != n
) {
"premature eof while reading dyn syms ", entry
);
md_swapin_zsymbols(nzp
, entry
->nsymbols
);
md_swapin_symbols(np
, entry
->nsymbols
);
/* Convert to structs localsymbol */
for (i
= 0; i
< entry
->nsymbols
; i
++) {
entry
->symbols
[i
].nzlist
= *nzp
++;
entry
->symbols
[i
].nzlist
.nlist
= *np
++;
entry
->symbols
[i
].nzlist
.nz_size
= 0;
entry
->symbols
[i
].symbol
= NULL
;
entry
->symbols
[i
].next
= NULL
;
entry
->symbols
[i
].gotslot_offset
= -1;
/* Read strings (text segment) */
n
= entry
->string_size
= dyn2
.ld_str_sz
;
entry
->strings
= (char *) alloca(n
);
entry
->strings_offset
= text_offset (entry
) + dyn2
.ld_strings
;
lseek(desc
, entry
->strings_offset
, L_SET
);
if (read(desc
, entry
->strings
, n
) != n
) {
"premature eof while reading dyn strings ", entry
);
enter_file_symbols (entry
);
/* TODO: examine needed shared objects */
int major
= -1, minor
= -1;
if (p
->search_dynamic_flag
== 0)
fname
= findshlib(p
->filename
, &major
, &minor
);
if (fname
&& (desc
= open (fname
, O_RDONLY
, 0)) > 0) {
p
->search_dynamic_flag
= 0;
if (cp
= strrchr(p
->filename
, '/')) {
fname
= concat(concat(p
->filename
, "/lib", cp
), ".a", "");
fname
= concat("lib", p
->filename
, ".a");
for (i
= 0; i
< n_search_dirs
; i
++) {
= concat (search_dirs
[i
], "/", fname
);
desc
= open (string
, O_RDONLY
, 0);