From b9aa930e449daf128eaaacfe2814dbb378708094 Mon Sep 17 00:00:00 2001 From: nate Date: Sat, 4 Mar 1995 17:49:20 +0000 Subject: Weak symbol support from NetBSD. This should bring us in sync with the NetBSD ld code except for local changes for dlopen() and friends and the hashing on the minor value of the shlibs. We should be binary compatible now with all their libraries. Obtained from: NetBSD --- gnu/usr.bin/ld/i386/md.c | 47 ++--- gnu/usr.bin/ld/i386/md.h | 89 +++------ gnu/usr.bin/ld/i386/mdprologue.S | 64 ++---- gnu/usr.bin/ld/ld.c | 380 +++++++++++++++++++++++------------- gnu/usr.bin/ld/ld.h | 40 ++-- gnu/usr.bin/ld/lib.c | 27 ++- gnu/usr.bin/ld/rrs.c | 395 ++++++++++++++++++++------------------ gnu/usr.bin/ld/rtld/Makefile | 14 +- gnu/usr.bin/ld/rtld/malloc.c | 5 +- gnu/usr.bin/ld/rtld/rtld.c | 110 +++++------ gnu/usr.bin/ld/shlib.c | 4 +- gnu/usr.bin/ld/sparc/md.h | 12 +- gnu/usr.bin/ld/sparc/mdprologue.S | 6 +- gnu/usr.bin/ld/warnings.c | 68 +++++-- 14 files changed, 706 insertions(+), 555 deletions(-) (limited to 'gnu/usr.bin/ld') diff --git a/gnu/usr.bin/ld/i386/md.c b/gnu/usr.bin/ld/i386/md.c index 40d9916..07271fc 100644 --- a/gnu/usr.bin/ld/i386/md.c +++ b/gnu/usr.bin/ld/i386/md.c @@ -27,7 +27,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: md.c,v 1.10 1994/06/15 22:40:44 rich Exp $ + * $Id: md.c,v 1.11 1994/12/23 22:31:12 nate Exp $ */ #include @@ -58,9 +58,10 @@ unsigned char *addr; return get_short(addr); case 2: return get_long(addr); + default: + errx(1, "Unsupported relocation size: %x", + RELOC_TARGET_SIZE(rp)); } - errx(1, "Unsupported relocation size: %x", RELOC_TARGET_SIZE(rp)); - return 0; } /* @@ -76,15 +77,17 @@ int relocatable_output; switch (RELOC_TARGET_SIZE(rp)) { case 0: put_byte(addr, relocation); - return; + break; case 1: put_short(addr, relocation); - return; + break; case 2: put_long(addr, relocation); - return; + break; + default: + errx(1, "Unsupported relocation size: %x", + RELOC_TARGET_SIZE(rp)); } - errx(1, "Unsupported relocation size: %x", RELOC_TARGET_SIZE(rp)); } /* @@ -257,7 +260,7 @@ int magic, flags; #endif /* TEXT_START depends on the value of outheader.a_entry. */ - if (!(link_mode & SHAREABLE)) /*WAS: if (entry_symbol) */ + if (!(link_mode & SHAREABLE)) hp->a_entry = PAGSIZ; } #endif /* RTLD */ @@ -305,15 +308,15 @@ int n; for (; n; n--, r++) { r->r_address = md_swap_long(r->r_address); bits = ((int *)r)[1]; - r->r_symbolnum = md_swap_long(bits & 0xffffff00); + r->r_symbolnum = md_swap_long(bits) & 0x00ffffff; r->r_pcrel = (bits & 1); - r->r_length = ((bits >> 1) & 3); - r->r_extern = ((bits >> 3) & 1); - r->r_baserel = ((bits >> 4) & 1); - r->r_jmptable = ((bits >> 5) & 1); - r->r_relative = ((bits >> 6) & 1); + r->r_length = (bits >> 1) & 3; + r->r_extern = (bits >> 3) & 1; + r->r_baserel = (bits >> 4) & 1; + r->r_jmptable = (bits >> 5) & 1; + r->r_relative = (bits >> 6) & 1; #ifdef N_SIZE - r->r_copy = ((bits >> 7) & 1); + r->r_copy = (bits >> 7) & 1; #endif } } @@ -327,15 +330,15 @@ int n; for (; n; n--, r++) { r->r_address = md_swap_long(r->r_address); - bits = (md_swap_long(r->r_symbolnum) & 0xffffff00); + bits = md_swap_long(r->r_symbolnum) & 0xffffff00; bits |= (r->r_pcrel & 1); - bits |= ((r->r_length << 1) & 6); - bits |= ((r->r_extern << 3) & 8); - bits |= ((r->r_baserel << 4) & 0x10); - bits |= ((r->r_jmptable << 5) & 0x20); - bits |= ((r->r_relative << 6) & 0x40); + bits |= (r->r_length & 3) << 1; + bits |= (r->r_extern & 1) << 3; + bits |= (r->r_baserel & 1) << 4; + bits |= (r->r_jmptable & 1) << 5; + bits |= (r->r_relative & 1) << 6; #ifdef N_SIZE - bits |= ((r->r_copy << 7) & 0x80); + bits |= (r->r_copy & 1) << 7; #endif ((int *)r)[1] = bits; } diff --git a/gnu/usr.bin/ld/i386/md.h b/gnu/usr.bin/ld/i386/md.h index 89c1213..da5283d 100644 --- a/gnu/usr.bin/ld/i386/md.h +++ b/gnu/usr.bin/ld/i386/md.h @@ -27,14 +27,12 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: md.h,v 1.10 1994/06/15 22:40:46 rich Exp $ + * $Id: md.h,v 1.11 1994/12/23 22:31:14 nate Exp $ */ #if defined(CROSS_LINKER) && defined(XHOST) && XHOST==sparc - #define NEED_SWAP - #endif #define MAX_ALIGNMENT (sizeof (long)) @@ -144,6 +142,34 @@ typedef struct jmpslot { #ifdef CROSS_LINKER +#define get_byte(p) ( ((unsigned char *)(p))[0] ) + +#define get_short(p) ( ( ((unsigned char *)(p))[0] << 8) | \ + ( ((unsigned char *)(p))[1] ) \ + ) + +#define get_long(p) ( ( ((unsigned char *)(p))[0] << 24) | \ + ( ((unsigned char *)(p))[1] << 16) | \ + ( ((unsigned char *)(p))[2] << 8 ) | \ + ( ((unsigned char *)(p))[3] ) \ + ) + +#define put_byte(p, v) { ((unsigned char *)(p))[0] = ((unsigned long)(v)); } + +#define put_short(p, v) { ((unsigned char *)(p))[0] = \ + ((((unsigned long)(v)) >> 8) & 0xff); \ + ((unsigned char *)(p))[1] = \ + ((((unsigned long)(v)) ) & 0xff); } + +#define put_long(p, v) { ((unsigned char *)(p))[0] = \ + ((((unsigned long)(v)) >> 24) & 0xff); \ + ((unsigned char *)(p))[1] = \ + ((((unsigned long)(v)) >> 16) & 0xff); \ + ((unsigned char *)(p))[2] = \ + ((((unsigned long)(v)) >> 8) & 0xff); \ + ((unsigned char *)(p))[3] = \ + ((((unsigned long)(v)) ) & 0xff); } + #ifdef NEED_SWAP /* Define IO byte swapping routines */ @@ -177,67 +203,11 @@ void md_swapout_jmpslot __P((jmpslot_t *, int)); #define md_swap_long(x) ( (((x) >> 24) & 0xff ) | (((x) >> 8 ) & 0xff00 ) | \ (((x) << 8 ) & 0xff0000) | (((x) << 24) & 0xff000000)) -#define get_byte(p) ( ((unsigned char *)(p))[0] ) - -#define get_short(p) ( ( ((unsigned char *)(p))[1] << 8) | \ - ( ((unsigned char *)(p))[0] ) \ - ) -#define get_long(p) ( ( ((unsigned char *)(p))[3] << 24) | \ - ( ((unsigned char *)(p))[2] << 16) | \ - ( ((unsigned char *)(p))[1] << 8 ) | \ - ( ((unsigned char *)(p))[0] ) \ - ) - -#define put_byte(p, v) { ((unsigned char *)(p))[0] = ((unsigned long)(v)); } - -#define put_short(p, v) { ((unsigned char *)(p))[1] = \ - ((((unsigned long)(v)) >> 8) & 0xff); \ - ((unsigned char *)(p))[0] = \ - ((((unsigned long)(v)) ) & 0xff); } - -#define put_long(p, v) { ((unsigned char *)(p))[3] = \ - ((((unsigned long)(v)) >> 24) & 0xff); \ - ((unsigned char *)(p))[2] = \ - ((((unsigned long)(v)) >> 16) & 0xff); \ - ((unsigned char *)(p))[1] = \ - ((((unsigned long)(v)) >> 8) & 0xff); \ - ((unsigned char *)(p))[0] = \ - ((((unsigned long)(v)) ) & 0xff); } - #else /* We need not swap, but must pay attention to alignment: */ #define md_swap_short(x) (x) #define md_swap_long(x) (x) -#define get_byte(p) ( ((unsigned char *)(p))[0] ) - -#define get_short(p) ( ( ((unsigned char *)(p))[0] << 8) | \ - ( ((unsigned char *)(p))[1] ) \ - ) - -#define get_long(p) ( ( ((unsigned char *)(p))[0] << 24) | \ - ( ((unsigned char *)(p))[1] << 16) | \ - ( ((unsigned char *)(p))[2] << 8 ) | \ - ( ((unsigned char *)(p))[3] ) \ - ) - - -#define put_byte(p, v) { ((unsigned char *)(p))[0] = ((unsigned long)(v)); } - -#define put_short(p, v) { ((unsigned char *)(p))[0] = \ - ((((unsigned long)(v)) >> 8) & 0xff); \ - ((unsigned char *)(p))[1] = \ - ((((unsigned long)(v)) ) & 0xff); } - -#define put_long(p, v) { ((unsigned char *)(p))[0] = \ - ((((unsigned long)(v)) >> 24) & 0xff); \ - ((unsigned char *)(p))[1] = \ - ((((unsigned long)(v)) >> 16) & 0xff); \ - ((unsigned char *)(p))[2] = \ - ((((unsigned long)(v)) >> 8) & 0xff); \ - ((unsigned char *)(p))[3] = \ - ((((unsigned long)(v)) ) & 0xff); } - #endif /* NEED_SWAP */ #else /* Not a cross linker: use native */ @@ -254,4 +224,3 @@ void md_swapout_jmpslot __P((jmpslot_t *, int)); #define put_long(where,what) (*(long *)(where) = (what)) #endif /* CROSS_LINKER */ - diff --git a/gnu/usr.bin/ld/i386/mdprologue.S b/gnu/usr.bin/ld/i386/mdprologue.S index 43640c6..1de0f72 100644 --- a/gnu/usr.bin/ld/i386/mdprologue.S +++ b/gnu/usr.bin/ld/i386/mdprologue.S @@ -27,7 +27,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: mdprologue.S,v 1.4 1994/06/15 22:40:49 rich Exp $ + * $Id: mdprologue.S,v 1.7 1994/12/04 07:42:44 mycroft Exp $ */ /* @@ -35,7 +35,6 @@ */ #include -#define LCALL(x,y) .byte 0x9a ; .long y; .word x .text .globl _binder, _binder_entry @@ -46,76 +45,49 @@ _rtl: # crt0 calls us here pushl %ebp # Allocate stack frame - movl %esp, %ebp + movl %esp,%ebp pushl %ebx + call 1f # PIC function prologue 1: popl %ebx - addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx + addl $_GLOBAL_OFFSET_TABLE_+[.-1b],%ebx - movl 12(%ebp), %eax # Extract data from interface structure + movl 12(%ebp),%eax # Extract data from interface structure movl (%eax),%eax # base address of ld.so (first field) # setup arguments for rtld() - movl (%ebx), %ecx # 1st entry in GOT is our __DYNAMIC - addl %eax, %ecx # add load address + movl (%ebx),%ecx # 1st entry in GOT is our __DYNAMIC + addl %eax,%ecx # add load address pushl %ecx # 3rd arg pushl 12(%ebp) # 2nd arg == &crt. pushl 8(%ebp) # 1st arg == version - addl _rtld@GOT(%ebx), %eax # relocate address of function + addl _rtld@GOT(%ebx),%eax # relocate address of function call %eax # _rtld(version, crtp, DYNAMIC) addl $12,%esp # pop arguments - movl -4(%ebp), %ebx # restore %ebx - leave # remove stack frame, - ret # let's rock + popl %ebx + leave # remove stack frame + ret # First call to a procedure generally comes through here for # binding. _binder_entry: pushl %ebp # setup a stack frame - movl %esp, %ebp + movl %esp,%ebp pusha # save all regs - movl $0, %eax # clear - movl 4(%ebp), %esi # return address in PLT - movw (%esi), %ax # get hold of relocation number - subl $6, %esi # make it point to the jmpslot + xorl %eax,%eax # clear + movl 4(%ebp),%esi # return address in PLT + movw (%esi),%ax # get hold of relocation number + subl $6,%esi # make it point to the jmpslot pushl %eax # pushd arguments pushl %esi # call _binder@PLT # _binder(rpc, index) - addl $8, %esp # pop arguments - movl %eax, 4(%ebp) # return value from _binder() == actual + addl $8,%esp # pop arguments + movl %eax,4(%ebp) # return value from _binder() == actual # address of function popa # restore regs leave # remove our stack frame ret - - # Special system call stubs which return real and effective user and group - # id's. Saves overhead of making separate calls for each. - # !! Relies on compatability option in BSD 4.three-and-a-half - - .globl _getreuid, _getregid -_getreuid: - lea SYS_getuid, %eax - LCALL(7,0) - jc out - movl 4(%esp), %ecx # get 1st arg - movl %eax, (%ecx) # put value in it - movl 8(%esp), %ecx # same for 2nd arg - movl %edx, (%ecx) # - ret # done - -_getregid: - lea SYS_getgid, %eax - LCALL(7,0) - jc out - movl 4(%esp), %ecx # get 1st arg - movl %eax, (%ecx) # put value in it - movl 8(%esp), %ecx # same for 2nd arg - movl %edx, (%ecx) # - ret # done - -out: jmp cerror@PLT # Call common error routine - diff --git a/gnu/usr.bin/ld/ld.c b/gnu/usr.bin/ld/ld.c index 5d713a0..14f7cd0 100644 --- a/gnu/usr.bin/ld/ld.c +++ b/gnu/usr.bin/ld/ld.c @@ -32,7 +32,7 @@ static char sccsid[] = "@(#)ld.c 6.10 (Berkeley) 5/22/91"; Set, indirect, and warning symbol features added by Randy Smith. */ /* - * $Id: ld.c,v 1.22 1994/06/15 22:39:40 rich Exp $ + * $Id: ld.c,v 1.23 1994/12/23 22:30:37 nate Exp $ */ /* Define how to initialize system-dependent header fields. */ @@ -135,7 +135,7 @@ int input_desc; /* The name of the file to write; "a.out" by default. */ char *output_filename; /* Output file name. */ -int outdesc; /* Output file descriptor. */ +FILE *outstream; /* Output file descriptor. */ struct exec outheader; /* Output file header. */ int magic; /* Output file magic. */ int oldmagic; @@ -183,11 +183,15 @@ int undefined_shobj_sym_count; /* # of undefined symbols referenced int multiple_def_count; /* # of multiply defined symbols. */ int defined_global_sym_count; /* # of defined global symbols. */ int common_defined_global_count; /* # of common symbols. */ +int undefined_weak_sym_count; /* # of weak symbols referenced and + not defined. */ +#if notused int special_sym_count; /* # of linker defined symbols. */ /* XXX - Currently, only __DYNAMIC and _G_O_T_ go here if required, * perhaps _etext, _edata and _end should go here too. */ +#endif int global_alias_count; /* # of aliased symbols */ int set_symbol_count; /* # of N_SET* symbols. */ int set_vector_count; /* # of set vectors in output. */ @@ -346,9 +350,6 @@ main(argc, argv) /* Create the symbols `etext', `edata' and `end'. */ symtab_init(relocatable_output); - /* Prepare for the run-time linking support. */ - init_rrs(); - /* * Determine whether to count the header as part of the text size, * and initialize the text size accordingly. This depends on the kind @@ -386,7 +387,7 @@ main(argc, argv) * Print error messages for any missing symbols, for any warning * symbols, and possibly multiple definitions */ - make_executable = do_warnings(stderr); + make_executable &= do_warnings(stderr); /* Print a map, if requested. */ if (write_map) @@ -1344,7 +1345,7 @@ enter_global_ref(lsp, name, entry) int olddef = sp->defined; int com = sp->defined && sp->common_size; - if (type == (N_INDR | N_EXT)) { + if (type == (N_INDR | N_EXT) && !olddef) { sp->alias = getsym(entry->strings + (lsp + 1)->nzlist.nz_strx); if (sp == sp->alias) { warnx("%s: %s is alias for itself", @@ -1356,6 +1357,10 @@ enter_global_ref(lsp, name, entry) } else { global_alias_count++; } +#if 0 + if (sp->flags & GS_REFERENCED) + sp->alias->flags |= GS_REFERENCED; +#endif } if (entry->flags & E_DYNAMIC) { @@ -1383,6 +1388,8 @@ enter_global_ref(lsp, name, entry) /* * This is an ex common... */ + if (com) + common_defined_global_count--; sp->common_size = 0; sp->defined = 0; } @@ -1428,32 +1435,72 @@ enter_global_ref(lsp, name, entry) return; } -#ifdef N_SIZE + if (olddef && N_ISWEAK(&nzp->nlist) && !(sp->flags & GS_WEAK)) { +#ifdef DEBUG + printf("%s: not overridden by weak symbol from %s\n", + sp->name, get_file_name(entry)); +#endif + return; + } + if (type == (N_SIZE | N_EXT)) { + if (relocatable_output && nzp->nz_value != 0 && sp->size == 0) size_sym_count++; if (sp->size < nzp->nz_value) sp->size = nzp->nz_value; - } else -#endif - if (type != (N_UNDF | N_EXT) || nzp->nz_value) { + + } else if (type != (N_UNDF | N_EXT) || nzp->nz_value) { /* * Set `->defined' here, so commons and undefined globals * can be counted correctly. */ - if (!sp->defined || sp->defined == (N_UNDF | N_EXT)) + if (!sp->defined || sp->defined == (N_UNDF | N_EXT)) { sp->defined = type; + } - if (oldref && !olddef) + if ((sp->flags & GS_WEAK) && !N_ISWEAK(&nzp->nlist)) { + /* + * Upgrade an existing weak definition. + * We fake it by pretending the symbol is undefined; + * must undo any common fiddling, however. + */ + if (!oldref) + errx(1, "internal error: enter_glob_ref: " + "weak symbol not referenced"); + if (!olddef && !com) + undefined_weak_sym_count--; + undefined_global_sym_count++; + sp->defined = type; + sp->flags &= ~GS_WEAK; + olddef = 0; + if (com) + common_defined_global_count--; + com = 0; + sp->common_size = 0; + } + if (oldref && !olddef) { /* * It used to be undefined and we're defining it. */ undefined_global_sym_count--; - if (undefined_global_sym_count < 0) - errx(1, - "internal error: enter_glob_ref: undefined_global_sym_count = %d", - undefined_global_sym_count); + if (sp->flags & GS_WEAK) + /* Used to be a weak reference */ + undefined_weak_sym_count--; + if (undefined_global_sym_count < 0 || + undefined_weak_sym_count < 0) + errx(1, "internal error: enter_glob_ref: " + "undefined_global_sym_count = %d, " + "undefined_weak_sym_count = %d", + undefined_global_sym_count, + undefined_weak_sym_count); + + } + + if (N_ISWEAK(&nzp->nlist)) + /* The definition is weak */ + sp->flags |= GS_WEAK; if (!olddef && type == (N_UNDF | N_EXT) && nzp->nz_value) { /* @@ -1479,13 +1526,18 @@ enter_global_ref(lsp, name, entry) if (SET_ELEMENT_P(type) && (!olddef || com)) set_vector_count++; - } else if (!oldref && !com) + } else if (!oldref && !com) { /* * An unreferenced symbol can already be defined * as common by shared objects. */ undefined_global_sym_count++; - + if (N_ISWEAK(&nzp->nlist)) { + /* The reference is weak */ + sp->flags |= GS_WEAK; + undefined_weak_sym_count++; + } + } if (sp == end_symbol && (entry->flags & E_JUST_SYMS) && !T_flag_specified) @@ -1495,8 +1547,8 @@ enter_global_ref(lsp, name, entry) register char *reftype; switch (type & N_TYPE) { case N_UNDF: - reftype = nzp->nz_value? - "defined as common":"referenced"; + reftype = nzp->nz_value + ? "defined as common" : "referenced"; break; case N_ABS: @@ -1515,12 +1567,21 @@ enter_global_ref(lsp, name, entry) reftype = "defined in BSS section"; break; + case N_INDR: + reftype = "alias"; + break; + + case N_SIZE: + reftype = "size spec"; + break; + default: reftype = "I don't know this type"; break; } - fprintf(stderr, "symbol %s %s in ", sp->name, reftype); + fprintf(stderr, "symbol %s %s%s in ", sp->name, + (N_ISWEAK(&nzp->nlist))?"weakly ":"", reftype); print_file_name (entry, stderr); fprintf(stderr, "\n"); } @@ -1707,17 +1768,20 @@ printf("set_sect_start = %#x, set_sect_size = %#x\n", } if (relocatable_output) - /* We write out the original N_SET* symbols */ + /* We write out the original N_SIZE symbols */ global_sym_count += size_sym_count; #ifdef DEBUG printf( -"global symbols %d (defined %d, undefined %d, aliases %d, warnings 2 * %d), \ -locals: %d, debug symbols: %d, set_symbols %d\n", +"global symbols %d " +"(defined %d, undefined %d, weak %d, aliases %d, warnings 2 * %d, " +"size symbols %d)\ncommons %d, locals: %d, debug symbols: %d, set_symbols %d\n", global_sym_count, defined_global_sym_count, undefined_global_sym_count, - global_alias_count, warn_sym_count, - local_sym_count, debugger_sym_count, set_symbol_count); + undefined_weak_sym_count, + global_alias_count, warn_sym_count, size_sym_count, + common_defined_global_count, local_sym_count, + debugger_sym_count, set_symbol_count); #endif } @@ -1738,6 +1802,7 @@ digest_pass1() * definition find this way. */ FOR_EACH_SYMBOL(i, sp) { + symbol *spsave; struct localsymbol *lsp; int defs = 0; @@ -1792,6 +1857,7 @@ digest_pass1() * of this set vector. */ bzero(&reloc, sizeof(reloc)); + RELOC_INIT_SEGMENT_RELOC(&reloc); RELOC_ADDRESS(&reloc) = setv_fill_count * sizeof(long); alloc_rrs_segment_reloc(NULL, &reloc); @@ -1801,15 +1867,18 @@ digest_pass1() && (type & N_TYPE) != N_FN && (type & N_TYPE) != N_SIZE) { /* non-common definition */ - if (defs++ && sp->value != p->n_value - && entry_symbol/*XXX*/) { + if (!N_ISWEAK(p)) + ++defs; + if (defs > 1) { sp->mult_defs = 1; multiple_def_count++; + } else if (!N_ISWEAK(p) || + (!sp->def_lsp && !sp->common_size)) { + sp->def_lsp = lsp; + lsp->entry->flags |= E_SYMBOLS_USED; + sp->defined = type; + sp->aux = N_AUX(p); } - sp->def_lsp = lsp; - lsp->entry->flags |= E_SYMBOLS_USED; - sp->defined = type; - sp->aux = N_AUX(p); } } @@ -1846,6 +1915,7 @@ digest_pass1() continue; } + spsave=sp; again: for (lsp = sp->sorefs; lsp; lsp = lsp->next) { register struct nlist *p = &lsp->nzlist.nlist; @@ -1858,31 +1928,41 @@ digest_pass1() sp->so_defined = type; sp->aux = N_AUX(p); if (lsp->entry->flags & E_SECONDCLASS) + /* Keep looking for something better */ continue; - lsp->entry->flags |= E_SYMBOLS_USED; - if (sp->flags & GS_REFERENCED) - undefined_global_sym_count--; - else - sp->flags |= GS_REFERENCED; + if (N_ISWEAK(p)) + /* Keep looking for something better */ + continue; + break; + } + } + if (sp->def_lsp) { #ifdef DEBUG -printf("shr: %s gets defined to %x with value %x\n", sp->name, type, sp->value); +printf("pass1: SO definition for %s, type %x in %s at %#x\n", + sp->name, sp->so_defined, get_file_name(sp->def_lsp->entry), + sp->def_lsp->nzlist.nz_value); #endif - if (undefined_global_sym_count < 0) - errx(1, - "internal error: digest_pass1,2: %s: undefined_global_sym_count = %d", + sp->def_lsp->entry->flags |= E_SYMBOLS_USED; + if (sp->flags & GS_REFERENCED) + undefined_global_sym_count--; + else + sp->flags |= GS_REFERENCED; + if (undefined_global_sym_count < 0) + errx(1, "internal error: digest_pass1,2: " + "%s: undefined_global_sym_count = %d", sp->name, undefined_global_sym_count); - if (sp->alias && !(sp->alias->flags & GS_REFERENCED)) { - sp = sp->alias; - goto again; - } - break; + if (sp->alias && + !(sp->alias->flags & GS_REFERENCED)) { + sp = sp->alias; + goto again; } } + sp=spsave; } END_EACH_SYMBOL; if (setv_fill_count != set_sect_size/sizeof(long)) - errx(1, "internal error: allocated set symbol space (%d) \ -doesn't match actual (%d)", + errx(1, "internal error: allocated set symbol space (%d) " + "doesn't match actual (%d)", set_sect_size/sizeof(long), setv_fill_count); } @@ -1987,7 +2067,7 @@ consider_relocation(entry, dataseg) lsp = &entry->symbols[reloc->r_symbolnum]; sp = lsp->symbol; if (sp == NULL) - errx(1, "%s: internal error, sp==NULL", + errx(1, "%s: bogus relocation record", get_file_name(entry)); if (sp->alias) @@ -2031,7 +2111,8 @@ consider_relocation(entry, dataseg) alloc_rrs_cpy_reloc(entry, sp); sp->defined = N_SIZE; - } else if (!sp->defined && sp->common_size == 0) + } else if (!sp->defined && sp->common_size == 0 && + sp->so_defined) alloc_rrs_reloc(entry, sp); } else { @@ -2217,14 +2298,27 @@ digest_pass2() continue; if (sp->alias && - (relocatable_output || building_shared_object || - (sp->alias->defined && !sp->alias->so_defined))) + (relocatable_output || building_shared_object || + (sp->alias->defined && !sp->alias->so_defined))) { /* * The alias points at a defined symbol, so it * must itself be counted as one too, in order to * compute the correct number of symbol table entries. */ + if (!sp->defined) { + /* + * Change aliased symbol's definition too. + * These things happen if shared object commons + * or data is going into our symbol table. + */ + if (sp->so_defined != (N_INDR+N_EXT)) + warnx( "pass2: %s: alias isn't", + sp->name); + sp->defined = sp->so_defined; + sp->so_defined = 0; + } defined_global_sym_count++; + } if ((sp->defined & N_TYPE) == N_SETV) { /* @@ -2253,6 +2347,7 @@ digest_pass2() struct relocation_info reloc; bzero(&reloc, sizeof(reloc)); + RELOC_INIT_SEGMENT_RELOC(&reloc); RELOC_ADDRESS(&reloc) = (1 + i + length_word_index) * sizeof(long) @@ -2284,7 +2379,11 @@ digest_pass2() sp->value = sp->def_lsp->nzlist.nz_value; if (sp->so_defined && (sp->def_lsp->entry->flags & E_SECONDCLASS)) + /* Flag second-hand definitions */ undefined_global_sym_count++; + if (sp->flags & GS_TRACE) + printf("symbol %s assigned to location %#x\n", + sp->name, sp->value); } /* @@ -2333,11 +2432,9 @@ digest_pass2() size = PALIGN(size, sizeof(int)); - while (!(size & align)) + while (align < MAX_ALIGNMENT && !(size & align)) align <<= 1; - align = align > MAX_ALIGNMENT ? MAX_ALIGNMENT : align; - bss_size = PALIGN(bss_size + data_size + rrs_data_start, align) - (data_size + rrs_data_start); @@ -2372,19 +2469,21 @@ write_output() (void)unlink(output_filename); } - outdesc = open(output_filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); - if (outdesc < 0) + outstream = fopen(output_filename, "w"); + if (outstream == NULL) err(1, "open: %s", output_filename); if (atexit(cleanup)) err(1, "atexit"); - if (fstat (outdesc, &statbuf) < 0) + if (fstat(fileno(outstream), &statbuf) < 0) err(1, "fstat: %s", output_filename); filemode = statbuf.st_mode; - chmod (output_filename, filemode & ~0111); + if (S_ISREG(statbuf.st_mode) && + chmod(output_filename, filemode & ~0111) == -1) + err(1, "chmod: %s", output_filename); /* Output the a.out header. */ write_header(); @@ -2406,8 +2505,11 @@ write_output() if (chmod (output_filename, filemode | 0111) == -1) err(1, "chmod: %s", output_filename); - close(outdesc); - outdesc = 0; + fflush(outstream); + /* Report I/O error such as disk full. */ + if (ferror(outstream) || fclose(outstream) != 0) + err(1, "write_output: %s", output_filename); + outstream = 0; } /* Total number of symbols to be written in the output file. */ @@ -2419,12 +2521,19 @@ write_header() int flags; if (link_mode & SHAREABLE) + /* Output is shared object */ flags = EX_DYNAMIC | EX_PIC; - else if (pic_code_seen) + else if (relocatable_output && pic_code_seen) + /* Output is relocatable and contains PIC code */ flags = EX_PIC; else if (rrs_section_type == RRS_FULL) + /* Output is a dynamic executable */ flags = EX_DYNAMIC; else + /* + * Output is a static executable + * or a non-PIC relocatable object + */ flags = 0; if (oldmagic && (flags & EX_DPMASK)) @@ -2457,7 +2566,7 @@ write_header() } md_swapout_exec_hdr(&outheader); - mywrite(&outheader, sizeof (struct exec), 1, outdesc); + mywrite(&outheader, sizeof (struct exec), 1, outstream); md_swapin_exec_hdr(&outheader); /* @@ -2466,7 +2575,7 @@ write_header() */ #ifndef COFF_ENCAPSULATE - padfile(N_TXTOFF(outheader) - sizeof outheader, outdesc); + padfile(N_TXTOFF(outheader) - sizeof outheader, outstream); #endif } @@ -2487,7 +2596,7 @@ write_text() if (trace_files) fprintf(stderr, "\n"); - padfile(text_pad, outdesc); + padfile(text_pad, outstream); } /* @@ -2525,7 +2634,7 @@ copy_text(entry) entry->textrel, entry->ntextrel, entry, 0); /* Write the relocated text to the output file. */ - mywrite(bytes, 1, entry->header.a_text, outdesc); + mywrite(bytes, 1, entry->header.a_text, outstream); } /* @@ -2542,8 +2651,8 @@ write_data() fprintf(stderr, "Copying and relocating data:\n\n"); pos = N_DATOFF(outheader) + data_start - rrs_data_start; - if (lseek(outdesc, pos, L_SET) != pos) - errx(1, "write_data: lseek"); + if (fseek(outstream, pos, SEEK_SET) != 0) + errx(1, "write_data: fseek"); each_full_file(copy_data, 0); file_close(); @@ -2556,13 +2665,13 @@ write_data() if (set_vector_count) { swap_longs(set_vectors, set_symbol_count + 2*set_vector_count); mywrite(set_vectors, set_symbol_count + 2*set_vector_count, - sizeof (unsigned long), outdesc); + sizeof (unsigned long), outstream); } if (trace_files) fprintf(stderr, "\n"); - padfile(data_pad, outdesc); + padfile(data_pad, outstream); } /* @@ -2596,7 +2705,7 @@ copy_data(entry) perform_relocation(bytes, entry->header.a_data, entry->datarel, entry->ndatarel, entry, 1); - mywrite(bytes, 1, entry->header.a_data, outdesc); + mywrite(bytes, 1, entry->header.a_data, outstream); } /* @@ -2657,6 +2766,9 @@ perform_relocation(data, data_size, reloc, nreloc, entry, dataseg) get_file_name(entry)); sp = lsp->symbol; + if (sp == NULL) + errx(1, "%s: bogus relocation record", + get_file_name(entry)); if (sp->alias) sp = sp->alias; @@ -2697,6 +2809,9 @@ perform_relocation(data, data_size, reloc, nreloc, entry, dataseg) get_file_name(entry)); sp = entry->symbols[symindex].symbol; + if (sp == NULL) + errx(1, "%s: bogus relocation record", + get_file_name(entry)); if (sp->alias) sp = sp->alias; @@ -2761,11 +2876,11 @@ perform_relocation(data, data_size, reloc, nreloc, entry, dataseg) "symbol %s claims RRS in %s%s\n", sp->name, get_file_name(entry), (sp->so_defined == (N_TEXT+N_EXT) && - sp->jmpslot_offset != -1)? + sp->flags & GS_HASJMPSLOT)? " (JMPSLOT)":""); } if (sp->so_defined == (N_TEXT+N_EXT) && - sp->jmpslot_offset != -1) { + sp->flags & GS_HASJMPSLOT) { /* * Claim a jmpslot if one was allocated. * @@ -2781,8 +2896,10 @@ perform_relocation(data, data_size, reloc, nreloc, entry, dataseg) entry->data_start_address: entry->text_start_address; relocation = addend; - if (claim_rrs_reloc( - entry, r, sp, &relocation)) + if ((building_shared_object || + sp->so_defined) && + claim_rrs_reloc(entry, r, sp, + &relocation)) continue; } } @@ -3005,7 +3122,7 @@ coptxtrel(entry) } md_swapout_reloc(entry->textrel, entry->ntextrel); mywrite(entry->textrel, entry->ntextrel, - sizeof(struct relocation_info), outdesc); + sizeof(struct relocation_info), outstream); } static void @@ -3070,7 +3187,7 @@ copdatrel(entry) } md_swapout_reloc(entry->datarel, entry->ndatarel); mywrite(entry->datarel, entry->ndatarel, - sizeof(struct relocation_info), outdesc); + sizeof(struct relocation_info), outstream); } void write_file_syms __P((struct file_entry *, int *)); @@ -3078,15 +3195,15 @@ void write_string_table __P((void)); /* Offsets and current lengths of symbol and string tables in output file. */ -static int symbol_table_offset; -static int symbol_table_len; +static int symtab_offset; +static int symtab_len; /* Address in output file where string table starts. */ -static int string_table_offset; +static int strtab_offset; /* Offset within string table where the strings in `strtab_vector' should be written. */ -static int string_table_len; +static int strtab_len; /* Total size of string table strings allocated so far, including strings in `strtab_vector'. */ @@ -3121,8 +3238,6 @@ assign_string_table_index(name) return index; } -FILE *outstream = (FILE *)0; - /* * Write the contents of `strtab_vector' into the string table. This is done * once for each file's local&debugger symbols and once for the global @@ -3133,23 +3248,13 @@ write_string_table() { register int i; - if (lseek(outdesc, string_table_offset + string_table_len, 0) == - (off_t)-1) - err(1, "write_string_table: %s: lseek", output_filename); - - if (!outstream) - outstream = fdopen(outdesc, "w"); + if (fseek(outstream, strtab_offset + strtab_len, SEEK_SET) != 0) + err(1, "write_string_table: %s: fseek", output_filename); for (i = 0; i < strtab_index; i++) { - fwrite (strtab_vector[i], 1, strtab_lens[i], outstream); - string_table_len += strtab_lens[i]; + mywrite(strtab_vector[i], 1, strtab_lens[i], outstream); + strtab_len += strtab_lens[i]; } - - fflush(outstream); - - /* Report I/O error such as disk full. */ - if (ferror(outstream)) - err(1, "write_string_table: %s", output_filename); } /* Write the symbol table and string table of the output file. */ @@ -3173,10 +3278,10 @@ write_syms() /* Size of string table includes the bytes that store the size. */ strtab_size = sizeof strtab_size; - symbol_table_offset = N_SYMOFF(outheader); - symbol_table_len = 0; - string_table_offset = N_STROFF(outheader); - string_table_len = strtab_size; + symtab_offset = N_SYMOFF(outheader); + symtab_len = 0; + strtab_offset = N_STROFF(outheader); + strtab_len = strtab_size; if (strip_symbols == STRIP_ALL) return; @@ -3264,9 +3369,10 @@ write_syms() * these, symbol was discounted in digest_pass1() * (they are in the RRS symbol table). */ - if (!building_shared_object) + if (building_shared_object) + continue; + if (!(sp->flags & GS_WEAK)) warnx("symbol %s remains undefined", sp->name); - continue; } if (syms_written >= global_sym_count) @@ -3296,6 +3402,8 @@ write_syms() nl.n_value = sp->alias->value; nl.n_other = N_OTHER(0, sp->alias->aux); } else { + int bind = 0; + if (sp->defined == N_SIZE) nl.n_type = N_DATA | N_EXT; else @@ -3305,7 +3413,9 @@ write_syms() errx(1, "%s: N_INDR has value %#x", sp->name, sp->value); nl.n_value = sp->value; - nl.n_other = N_OTHER(0, sp->aux); + if (sp->def_lsp) + bind = N_BIND(&sp->def_lsp->nzlist.nlist); + nl.n_other = N_OTHER(bind, sp->aux); } } else if (sp->common_size) { @@ -3375,18 +3485,17 @@ printf("writesym(#%d): %s, type %x\n", syms_written, sp->name, sp->defined); } END_EACH_SYMBOL; if (syms_written != strtab_index || strtab_index != global_sym_count) - errx(1, "internal error:\ -wrong number (%d) of global symbols written into output file, should be %d", - syms_written, global_sym_count); + errx(1, "internal error: wrong number (%d) of global symbols " + "written into output file, should be %d", + syms_written, global_sym_count); /* Output the buffer full of `struct nlist's. */ - if (lseek(outdesc, symbol_table_offset + symbol_table_len, 0) == - (off_t)-1) - err(1, "write_syms: lseek"); + if (fseek(outstream, symtab_offset + symtab_len, SEEK_SET) != 0) + err(1, "write_syms: fseek"); md_swapout_symbols(buf, bufp - buf); - mywrite(buf, bufp - buf, sizeof(struct nlist), outdesc); - symbol_table_len += sizeof(struct nlist) * (bufp - buf); + mywrite(buf, bufp - buf, sizeof(struct nlist), outstream); + symtab_len += sizeof(struct nlist) * (bufp - buf); /* Write the strings for the global symbols. */ write_string_table(); @@ -3396,18 +3505,19 @@ wrong number (%d) of global symbols written into output file, should be %d", file_close(); if (syms_written != nsyms) - errx(1, "internal error:\ -wrong number of symbols (%d) written into output file, should be %d", - syms_written, nsyms); + errx(1, "internal error: wrong number of symbols (%d) " + "written into output file, should be %d", + syms_written, nsyms); - if (symbol_table_offset + symbol_table_len != string_table_offset) + if (symtab_offset + symtab_len != strtab_offset) errx(1, "internal error: inconsistent symbol table length: %d vs %s", - symbol_table_offset + symbol_table_len, string_table_offset); + symtab_offset + symtab_len, strtab_offset); - lseek(outdesc, string_table_offset, 0); + if (fseek(outstream, strtab_offset, SEEK_SET) != 0) + err(1, "write_syms: fseek"); strtab_size = md_swap_long(strtab_size); - mywrite(&strtab_size, sizeof(int), 1, outdesc); + mywrite(&strtab_size, sizeof(int), 1, outstream); } @@ -3507,10 +3617,11 @@ write_file_syms(entry, syms_written_addr) /* All the symbols are now in BUF; write them. */ - lseek(outdesc, symbol_table_offset + symbol_table_len, 0); + if (fseek(outstream, symtab_offset + symtab_len, SEEK_SET) != 0) + err(1, "write local symbols: fseek"); md_swapout_symbols(buf, bufp - buf); - mywrite(buf, bufp - buf, sizeof(struct nlist), outdesc); - symbol_table_len += sizeof(struct nlist) * (bufp - buf); + mywrite(buf, bufp - buf, sizeof(struct nlist), outstream); + symtab_len += sizeof(struct nlist) * (bufp - buf); /* * Write the string-table data for the symbols just written, using @@ -3546,18 +3657,11 @@ mywrite(buf, count, eltsize, fd) void *buf; int count; int eltsize; - int fd; + FILE *fd; { - register int val; - register int bytes = count * eltsize; - - while (bytes > 0) { - val = write(fd, buf, bytes); - if (val <= 0) - err(1, "write: %s", output_filename); - buf += val; - bytes -= val; - } + + if (fwrite(buf, eltsize, count, fd) != count) + err(1, "write"); } static void @@ -3565,10 +3669,10 @@ cleanup() { struct stat statbuf; - if (outdesc <= 0) + if (outstream == 0) return; - if (fstat(outdesc, &statbuf) == 0) { + if (fstat(fileno(outstream), &statbuf) == 0) { if (S_ISREG(statbuf.st_mode)) (void)unlink(output_filename); } @@ -3580,8 +3684,8 @@ cleanup() */ void padfile(padding, fd) - int padding; - int fd; + int padding; + FILE *fd; { register char *buf; if (padding <= 0) diff --git a/gnu/usr.bin/ld/ld.h b/gnu/usr.bin/ld/ld.h index 58e5c1e..6b4b7f5 100644 --- a/gnu/usr.bin/ld/ld.h +++ b/gnu/usr.bin/ld/ld.h @@ -1,5 +1,5 @@ /* - * $Id: ld.h,v 1.11 1994/06/15 22:39:46 rich Exp $ + * $Id: ld.h,v 1.12 1994/12/23 22:30:42 nate Exp $ */ /*- * This code is derived from software copyrighted by the Free Software @@ -151,6 +151,16 @@ extern int netzmagic; #define CHECK_GOT_RELOC(r) ((r)->r_pcrel) +#define RELOC_INIT_SEGMENT_RELOC(r) + +#endif + +#ifndef MAX_GOTOFF +#define MAX_GOTOFF (LONG_MAX) +#endif + +#ifndef MIN_GOTOFF +#define MIN_GOTOFF (LONG_MIN) #endif /* @@ -309,7 +319,6 @@ extern int netzmagic; #ifndef __GNU_STAB__ - /* Line number for the data section. This is to be used to describe the source location of a variable declaration. */ #ifndef N_DSLINE @@ -321,9 +330,10 @@ extern int netzmagic; #ifndef N_BSLINE #define N_BSLINE (N_SLINE+N_BSS-N_TEXT) #endif - #endif /* not __GNU_STAB__ */ - + +#define N_ISWEAK(p) (N_BIND(p) & BIND_WEAK) + typedef struct localsymbol { struct nzlist nzlist; /* n[z]list from file */ @@ -337,7 +347,7 @@ typedef struct localsymbol { #define LS_L_SYMBOL 1 /* Local symbol starts with an `L' */ #define LS_WRITE 2 /* Symbol goes in output symtable */ #define LS_RENAME 4 /* xlat name to `.' */ -#define LS_GOTSLOTCLAIMED 8 /* This symbol has a GOT entry */ +#define LS_HASGOTSLOT 8 /* This symbol has a GOT entry */ #define LS_WARNING 16 /* Second part of a N_WARNING duo */ } localsymbol_t; @@ -388,14 +398,15 @@ typedef struct glosym { long flags; -#define GS_DEFINED 1 /* Symbol has definition (notyetused)*/ -#define GS_REFERENCED 2 /* Symbol is referred to by something +#define GS_DEFINED 0x1 /* Symbol has definition (notyetused)*/ +#define GS_REFERENCED 0x2 /* Symbol is referred to by something interesting */ -#define GS_TRACE 4 /* Symbol will be traced */ -#define GS_JMPSLOTCLAIMED 8 /* */ -#define GS_GOTSLOTCLAIMED 0x10 /* Some state bits concerning */ +#define GS_TRACE 0x4 /* Symbol will be traced */ +#define GS_HASJMPSLOT 0x8 /* */ +#define GS_HASGOTSLOT 0x10 /* Some state bits concerning */ #define GS_CPYRELOCRESERVED 0x20 /* entries in GOT and PLT tables */ #define GS_CPYRELOCCLAIMED 0x40 /* */ +#define GS_WEAK 0x80 /* Symbol is weakly defined */ } symbol; @@ -415,6 +426,9 @@ extern symbol *symtab[]; /* # of global symbols referenced and not defined. */ extern int undefined_global_sym_count; +/* # of weak symbols referenced and not defined. */ +extern int undefined_weak_sym_count; + /* # of undefined symbols referenced by shared objects */ extern int undefined_shobj_sym_count; @@ -575,7 +589,7 @@ extern int link_mode; #define SHAREABLE 8 /* Build a shared object */ #define SILLYARCHIVE 16 /* Process .sa companions, if any */ -extern int outdesc; /* Output file descriptor. */ +extern FILE *outstream; /* Output file. */ extern struct exec outheader; /* Output file header. */ extern int magic; /* Output file magic. */ extern int oldmagic; @@ -601,8 +615,8 @@ int file_open __P((struct file_entry *)); void each_file __P((void (*)(), void *)); void each_full_file __P((void (*)(), void *)); unsigned long check_each_file __P((unsigned long (*)(), void *)); -void mywrite __P((void *, int, int, int)); -void padfile __P((int,int)); +void mywrite __P((void *, int, int, FILE *)); +void padfile __P((int, FILE *)); /* In warnings.c: */ void perror_name __P((char *)); diff --git a/gnu/usr.bin/ld/lib.c b/gnu/usr.bin/ld/lib.c index 737b526..25512bb 100644 --- a/gnu/usr.bin/ld/lib.c +++ b/gnu/usr.bin/ld/lib.c @@ -1,5 +1,5 @@ /* - * $Id: lib.c,v 1.10 1994/06/15 22:39:49 rich Exp $ - library routines + * $Id: lib.c,v 1.11 1994/12/23 22:30:45 nate Exp $ - library routines */ #include @@ -260,6 +260,12 @@ symdef_library(fd, entry, member_length) * be satisfied are 'common' references. This * prevents some problems with name pollution (e.g. a * global common 'utime' linked to a function). + * + * If we're not forcing the archive in then we don't + * need to bother if: we've never heard of the symbol, + * or if it is already defined. The last clause causes + * archive members to be searched for definitions + * satisfying undefined shared object symbols. */ if (!(link_mode & FORCEARCHIVE) && (!sp || sp->defined || @@ -501,6 +507,9 @@ subfile_wanted_p(entry) sp->defined = type; continue; } + if (sp->flags & GS_WEAK) + /* Weak symbols don't pull archive members */ + continue; if (write_map) { print_file_name(entry, stdout); fprintf(stdout, " needed due to %s\n", sp->name); @@ -542,8 +551,19 @@ subfile_wanted_p(entry) * a common; ignore it. */ continue; + + if (N_ISWEAK(&lsp->nzlist.nlist)) + /* Weak symbols don't pull archive members */ + continue; } + /* + * At this point, either the new symbol is a common + * and the shared object reference is undefined -- + * in which case we note the common -- or the shared + * object reference has a definition -- in which case + * the library member takes precedence. + */ if (iscommon) { /* * New symbol is common, just takes its @@ -565,8 +585,9 @@ subfile_wanted_p(entry) if (write_map) { print_file_name(entry, stdout); fprintf(stdout, - " needed due to shared lib ref %s\n", - sp->name); + " needed due to shared lib ref %s (%d)\n", + sp->name, + lsp ? lsp->nzlist.nlist.n_type : -1); } return 1; } diff --git a/gnu/usr.bin/ld/rrs.c b/gnu/usr.bin/ld/rrs.c index 93ad89b..2d1b3bc 100644 --- a/gnu/usr.bin/ld/rrs.c +++ b/gnu/usr.bin/ld/rrs.c @@ -27,7 +27,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: rrs.c,v 1.12 1994/06/15 22:39:52 rich Exp $ + * $Id: rrs.c,v 1.13 1994/12/23 22:30:48 nate Exp $ */ #include @@ -64,8 +64,8 @@ static int reserved_rrs_relocs; static int claimed_rrs_relocs; static int discarded_rrs_relocs; -static int number_of_gotslots; -static int number_of_jmpslots; +static int number_of_gotslots = 1; +static int number_of_jmpslots = 1; static int number_of_rrs_hash_entries; static int number_of_rrs_symbols; static int rrs_strtab_size; @@ -73,10 +73,14 @@ static int rrs_symbol_size; static int current_jmpslot_offset; static int current_got_offset; +static int got_origin; static int current_reloc_offset; static int current_hash_index; int number_of_shobjs; +/* Convert a GOT offset into a table entry */ +#define GOTP(off) ((got_t *)((long)rrs_got + got_origin + (off))) + struct shobj { struct shobj *next; struct file_entry *entry; @@ -125,9 +129,10 @@ RRS data segment: | | | sdt | | | - +-------------------+ <-- _GLOBAL_OFFSET_TABLE_ (sdt_got) + +-------------------+ <-- sdt_got | | - | _GOT_ | + | _GOT_ | <-- _GLOBAL_OFFSET_TABLE_ + | | ( == sdt_got + got_origin) | | +-------------------+ <-- sdt_plt | | @@ -137,37 +142,12 @@ RRS data segment: */ /* - * Initialize RRS - */ - -void -init_rrs() -{ - reserved_rrs_relocs = 0; - claimed_rrs_relocs = 0; - discarded_rrs_relocs = 0; - - number_of_rrs_symbols = 0; - rrs_strtab_size = 0; - - /* First jmpslot reserved for run-time binder */ - current_jmpslot_offset = sizeof(jmpslot_t); - number_of_jmpslots = 1; - - /* First gotslot reserved for __DYNAMIC */ - current_got_offset = sizeof(got_t); - number_of_gotslots = 1; - - current_reloc_offset = 0; -} - -/* * Add NAME to the list of needed run-time objects. * Return 1 if ENTRY was added to the list. */ int rrs_add_shobj(entry) -struct file_entry *entry; + struct file_entry *entry; { struct shobj **p; @@ -184,8 +164,8 @@ struct file_entry *entry; void alloc_rrs_reloc(entry, sp) -struct file_entry *entry; -symbol *sp; + struct file_entry *entry; + symbol *sp; { #ifdef DEBUG printf("alloc_rrs_reloc: %s in %s\n", sp->name, get_file_name(entry)); @@ -195,8 +175,8 @@ printf("alloc_rrs_reloc: %s in %s\n", sp->name, get_file_name(entry)); void alloc_rrs_segment_reloc(entry, r) -struct file_entry *entry; -struct relocation_info *r; + struct file_entry *entry; + struct relocation_info *r; { #ifdef DEBUG printf("alloc_rrs_segment_reloc at %#x in %s\n", @@ -207,30 +187,31 @@ printf("alloc_rrs_segment_reloc at %#x in %s\n", void alloc_rrs_jmpslot(entry, sp) -struct file_entry *entry; -symbol *sp; + struct file_entry *entry; + symbol *sp; { - if (sp->jmpslot_offset == -1) { - sp->jmpslot_offset = current_jmpslot_offset; - current_jmpslot_offset += sizeof(jmpslot_t); - number_of_jmpslots++; - reserved_rrs_relocs++; - } + if (sp->flags & GS_HASJMPSLOT) + return; + + sp->flags |= GS_HASJMPSLOT; + number_of_jmpslots++; + reserved_rrs_relocs++; } void alloc_rrs_gotslot(entry, r, lsp) -struct file_entry *entry; -struct relocation_info *r; -struct localsymbol *lsp; + struct file_entry *entry; + struct relocation_info *r; + struct localsymbol *lsp; { symbol *sp = lsp->symbol; if (!RELOC_EXTERN_P(r)) { if (sp != NULL) { - warnx("%s: relocation for internal symbol expected at %#x", - get_file_name(entry), RELOC_ADDRESS(r)); + warnx("%s: relocation for internal symbol " + "expected at %#x", + get_file_name(entry), RELOC_ADDRESS(r)); return; } @@ -238,38 +219,37 @@ struct localsymbol *lsp; /* No need for a GOT slot */ return; - if (lsp->gotslot_offset == -1) { - lsp->gotslot_offset = current_got_offset; - current_got_offset += sizeof(got_t); - number_of_gotslots++; - reserved_rrs_relocs++; - } + if (lsp->flags & LS_HASGOTSLOT) + return; + + lsp->flags |= LS_HASGOTSLOT; } else { if (sp == NULL) { - warnx("%s: relocation must refer to global symbol at %#x", - get_file_name(entry), RELOC_ADDRESS(r)); + warnx("%s: relocation must refer " + "to global symbol at %#x", + get_file_name(entry), RELOC_ADDRESS(r)); return; } if (sp->alias) sp = sp->alias; - if (sp->gotslot_offset == -1) { - sp->gotslot_offset = current_got_offset; - current_got_offset += sizeof(got_t); - number_of_gotslots++; - reserved_rrs_relocs++; - } + if (sp->flags & GS_HASGOTSLOT) + return; + + sp->flags |= GS_HASGOTSLOT; } + number_of_gotslots++; + reserved_rrs_relocs++; } void alloc_rrs_cpy_reloc(entry, sp) -struct file_entry *entry; -symbol *sp; + struct file_entry *entry; + symbol *sp; { if (sp->flags & GS_CPYRELOCRESERVED) return; @@ -302,10 +282,10 @@ rrs_next_reloc() */ int claim_rrs_reloc(entry, rp, sp, relocation) -struct file_entry *entry; -struct relocation_info *rp; -symbol *sp; -long *relocation; + struct file_entry *entry; + struct relocation_info *rp; + symbol *sp; + long *relocation; { struct relocation_info *r = rrs_next_reloc(); @@ -322,7 +302,7 @@ printf("claim_rrs_reloc: %s in %s\n", sp->name, get_file_name(entry)); if (link_mode & SYMBOLIC) { if (!sp->defined) warnx("Cannot reduce symbol \"%s\" in %s", - sp->name, get_file_name(entry)); + sp->name, get_file_name(entry)); RELOC_EXTERN_P(r) = 0; *relocation += sp->value; (void) md_make_reloc(rp, r, RELTYPE_RELATIVE); @@ -338,28 +318,31 @@ printf("claim_rrs_reloc: %s in %s\n", sp->name, get_file_name(entry)); */ long claim_rrs_jmpslot(entry, rp, sp, addend) -struct file_entry *entry; -struct relocation_info *rp; -symbol *sp; -long addend; + struct file_entry *entry; + struct relocation_info *rp; + symbol *sp; + long addend; { struct relocation_info *r; - if (sp->flags & GS_JMPSLOTCLAIMED) + if (!(sp->flags & GS_HASJMPSLOT)) + errx(1, "internal error: " + "%s: claim_rrs_jmpslot: %s: no reservation", + get_file_name(entry), + sp->name); + + if (sp->jmpslot_offset != -1) return rrs_sdt.sdt_plt + sp->jmpslot_offset; + sp->jmpslot_offset = current_jmpslot_offset; + current_jmpslot_offset += sizeof(jmpslot_t); + #ifdef DEBUG printf("claim_rrs_jmpslot: %s: %s(%d) -> offset %x\n", get_file_name(entry), sp->name, sp->rrs_symbolnum, sp->jmpslot_offset); #endif - if (sp->jmpslot_offset == -1) - errx(1, - "internal error: %s: claim_rrs_jmpslot: %s: jmpslot_offset == -1\n", - get_file_name(entry), - sp->name); - if ((link_mode & SYMBOLIC) || rrs_section_type == RRS_PARTIAL) { if (!sp->defined) warnx("Cannot reduce symbol \"%s\" in %s", @@ -370,7 +353,6 @@ printf("claim_rrs_jmpslot: %s: %s(%d) -> offset %x\n", sp->value); if (rrs_section_type == RRS_PARTIAL || !JMPSLOT_NEEDS_RELOC) { /* PLT is self-contained */ - sp->flags |= GS_JMPSLOTCLAIMED; discarded_rrs_relocs++; return rrs_sdt.sdt_plt + sp->jmpslot_offset; } @@ -384,7 +366,6 @@ printf("claim_rrs_jmpslot: %s: %s(%d) -> offset %x\n", * Install a run-time relocation for this PLT entry. */ r = rrs_next_reloc(); - sp->flags |= GS_JMPSLOTCLAIMED; RELOC_SYMBOL(r) = sp->rrs_symbolnum; @@ -408,10 +389,10 @@ printf("claim_rrs_jmpslot: %s: %s(%d) -> offset %x\n", */ long claim_rrs_gotslot(entry, rp, lsp, addend) -struct file_entry *entry; -struct relocation_info *rp; -struct localsymbol *lsp; -long addend; + struct file_entry *entry; + struct relocation_info *rp; + struct localsymbol *lsp; + long addend; { struct relocation_info *r; symbol *sp = lsp->symbol; @@ -424,28 +405,42 @@ long addend; if (sp->alias) sp = sp->alias; -#ifdef DEBUG -printf("claim_rrs_gotslot: %s(%d,%#x) slot offset %#x, addend %#x\n", - sp->name, sp->rrs_symbolnum, sp->value, sp->gotslot_offset, addend); -#endif - if (sp->gotslot_offset == -1) - errx(1, - "internal error: %s: claim_rrs_gotslot: %s: gotslot_offset == -1\n", + if (!(sp->flags & GS_HASGOTSLOT)) + errx(1, "internal error: " + "%s: claim_rrs_gotslot: %s: no reservation", get_file_name(entry), sp->name); - if (sp->flags & GS_GOTSLOTCLAIMED) { -#ifdef DEBUG - if (*(long *)((long)rrs_got + sp->gotslot_offset) != addend + - (!(link_mode & SHAREABLE) || (link_mode & SYMBOLIC)) - ?sp->value:0) - errx(1, "%s: %s: gotslot at %#x is multiple valued\n", + if (sp->gotslot_offset != -1) { +#ifdef DIAGNOSTIC + if (*GOTP(sp->gotslot_offset) != addend + + ((!(link_mode & SHAREABLE) || (link_mode & SYMBOLIC)) + ? sp->value : 0)) + errx(1, "%s: %s: gotslot at %#x is multiple valued, " + "*got = %#x, addend = %#x, sp->value = %#x", get_file_name(entry), sp->name, - sp->gotslot_offset); + sp->gotslot_offset, + *GOTP(sp->gotslot_offset), addend, sp->value); #endif /* This symbol already passed here before. */ return sp->gotslot_offset; } + if (current_got_offset == 0) + /* GOT offset 0 is reserved */ + current_got_offset += sizeof(got_t); + + if (current_got_offset > MAX_GOTOFF) + errx(1, "%s: GOT overflow on symbol `%s' at %#x", + get_file_name(entry), sp->name, RELOC_ADDRESS(rp)); + + sp->gotslot_offset = current_got_offset; + current_got_offset += sizeof(got_t); + +#ifdef DEBUG +printf("claim_rrs_gotslot: %s(%d,%#x) slot offset %#x, addend %#x\n", + sp->name, sp->rrs_symbolnum, sp->value, sp->gotslot_offset, addend); +#endif + if (sp->defined && (!(link_mode & SHAREABLE) || (link_mode & SYMBOLIC))) { @@ -453,8 +448,7 @@ printf("claim_rrs_gotslot: %s(%d,%#x) slot offset %#x, addend %#x\n", * Reduce to just a base-relative translation. */ - *(got_t *)((long)rrs_got + sp->gotslot_offset) = - sp->value + addend; + *GOTP(sp->gotslot_offset) = sp->value + addend; reloc_type = RELTYPE_RELATIVE; } else if ((link_mode & SYMBOLIC) || rrs_section_type == RRS_PARTIAL) { @@ -464,7 +458,7 @@ printf("claim_rrs_gotslot: %s(%d,%#x) slot offset %#x, addend %#x\n", * so again all symbols must be known. */ warnx("Cannot reduce symbol \"%s\" in %s", - sp->name, get_file_name(entry)); + sp->name, get_file_name(entry)); } else { @@ -472,7 +466,7 @@ printf("claim_rrs_gotslot: %s(%d,%#x) slot offset %#x, addend %#x\n", * This gotslot will be updated with symbol value at run-time. */ - *(got_t *)((long)rrs_got + sp->gotslot_offset) = addend; + *GOTP(sp->gotslot_offset) = addend; } if (rrs_section_type == RRS_PARTIAL) { @@ -483,9 +477,8 @@ printf("claim_rrs_gotslot: %s(%d,%#x) slot offset %#x, addend %#x\n", */ if (!sp->defined) warnx("Cannot reduce symbol \"%s\" in %s", - sp->name, get_file_name(entry)); + sp->name, get_file_name(entry)); discarded_rrs_relocs++; - sp->flags |= GS_GOTSLOTCLAIMED; return sp->gotslot_offset; } @@ -498,8 +491,7 @@ printf("claim_rrs_gotslot: %s(%d,%#x) slot offset %#x, addend %#x\n", * as no symbol need be looked up at run-time. */ r = rrs_next_reloc(); - sp->flags |= GS_GOTSLOTCLAIMED; - r->r_address = rrs_sdt.sdt_got + sp->gotslot_offset; + r->r_address = got_symbol->value + sp->gotslot_offset; RELOC_SYMBOL(r) = sp->rrs_symbolnum; RELOC_EXTERN_P(r) = !(reloc_type == RELTYPE_RELATIVE); md_make_gotreloc(rp, r, reloc_type); @@ -515,40 +507,50 @@ printf("claim_rrs_gotslot: %s(%d,%#x) slot offset %#x, addend %#x\n", */ long claim_rrs_internal_gotslot(entry, rp, lsp, addend) -struct file_entry *entry; -struct relocation_info *rp; -struct localsymbol *lsp; -long addend; + struct file_entry *entry; + struct relocation_info *rp; + struct localsymbol *lsp; + long addend; { struct relocation_info *r; addend += lsp->nzlist.nz_value; if (!RELOC_STATICS_THROUGH_GOT_P(r)) - return addend - rrs_sdt.sdt_got; - -#ifdef DEBUG -printf("claim_rrs_internal_gotslot: %s: slot offset %#x, addend = %#x\n", - get_file_name(entry), lsp->gotslot_offset, addend); -#endif + return addend - got_symbol->value; - if (lsp->gotslot_offset == -1) - errx(1, - "internal error: %s: claim_rrs_internal_gotslot at %#x: slot_offset == -1\n", + if (!(lsp->flags & LS_HASGOTSLOT)) + errx(1, "internal error: " + "%s: claim_rrs_internal_gotslot at %#x: no reservation", get_file_name(entry), RELOC_ADDRESS(rp)); - if (lsp->flags & LS_GOTSLOTCLAIMED) { - /* Already done */ - if (addend != *(long *)((long)rrs_got + lsp->gotslot_offset)) - errx(1, "%s: gotslot at %#x is multiple valued\n", + if (lsp->gotslot_offset != -1) { + /* Already claimed */ + if (*GOTP(lsp->gotslot_offset) != addend) + errx(1, "%s: gotslot at %#x is multiple valued", get_file_name(entry), lsp->gotslot_offset); return lsp->gotslot_offset; } - *(long *)((long)rrs_got + lsp->gotslot_offset) = addend; + if (current_got_offset == 0) + /* GOT offset 0 is reserved */ + current_got_offset += sizeof(got_t); + + if (current_got_offset > MAX_GOTOFF) + errx(1, "%s: GOT overflow for relocation at %#x", + get_file_name(entry), RELOC_ADDRESS(rp)); + + lsp->gotslot_offset = current_got_offset; + current_got_offset += sizeof(got_t); + + *GOTP(lsp->gotslot_offset) = addend; + +#ifdef DEBUG +printf("claim_rrs_internal_gotslot: %s: slot offset %#x, addend = %#x\n", + get_file_name(entry), lsp->gotslot_offset, addend); +#endif if (rrs_section_type == RRS_PARTIAL) { - lsp->flags |= LS_GOTSLOTCLAIMED; discarded_rrs_relocs++; return lsp->gotslot_offset; } @@ -557,8 +559,7 @@ printf("claim_rrs_internal_gotslot: %s: slot offset %#x, addend = %#x\n", * Relocation entry needed for this static GOT entry. */ r = rrs_next_reloc(); - lsp->flags |= LS_GOTSLOTCLAIMED; - r->r_address = rrs_sdt.sdt_got + lsp->gotslot_offset; + r->r_address = got_symbol->value + lsp->gotslot_offset; RELOC_EXTERN_P(r) = 0; md_make_gotreloc(rp, r, RELTYPE_RELATIVE); return lsp->gotslot_offset; @@ -566,9 +567,9 @@ printf("claim_rrs_internal_gotslot: %s: slot offset %#x, addend = %#x\n", void claim_rrs_cpy_reloc(entry, rp, sp) -struct file_entry *entry; -struct relocation_info *rp; -symbol *sp; + struct file_entry *entry; + struct relocation_info *rp; + symbol *sp; { struct relocation_info *r; @@ -576,8 +577,8 @@ symbol *sp; return; if (!(sp->flags & GS_CPYRELOCRESERVED)) - errx(1, - "internal error: %s: claim_cpy_reloc: %s: no reservation\n", + errx(1, "internal error: " + "%s: claim_cpy_reloc: %s: no reservation", get_file_name(entry), sp->name); #ifdef DEBUG @@ -595,8 +596,8 @@ printf("claim_rrs_copy: %s: %s -> %x\n", void claim_rrs_segment_reloc(entry, rp) -struct file_entry *entry; -struct relocation_info *rp; + struct file_entry *entry; + struct relocation_info *rp; { struct relocation_info *r = rrs_next_reloc(); @@ -618,8 +619,8 @@ printf("claim_rrs_segment_reloc: %s at %#x\n", */ void rrs_insert_hash(cp, index) -char *cp; -int index; + char *cp; + int index; { int hashval = 0; struct rrs_hash *hp; @@ -699,6 +700,8 @@ consider_rrs_section_lengths() if (rrs_section_type == RRS_NONE) { got_symbol->defined = 0; + if (reserved_rrs_relocs > 0) + errx(1, "internal error: empty RRS has reservations"); return; } @@ -781,7 +784,8 @@ consider_rrs_section_lengths() if (rrs_sdt.sdt_buckets < 4) rrs_sdt.sdt_buckets = 4; - number_of_rrs_hash_entries = rrs_sdt.sdt_buckets + number_of_rrs_symbols; + number_of_rrs_hash_entries = rrs_sdt.sdt_buckets + + number_of_rrs_symbols; rrs_hashtab = (struct rrs_hash *)xmalloc( number_of_rrs_hash_entries * sizeof(struct rrs_hash)); for (n = 0; n < rrs_sdt.sdt_buckets; n++) @@ -838,11 +842,32 @@ relocate_rrs_addresses() dynamic_symbol->value = 0; + /* + * Get ready to allocate linkage table offsets. + * First jmpslot is reserved for the run-time binder + * GOT entry at offset 0 is reserved for `__DYNAMIC'. + */ + current_jmpslot_offset = sizeof(jmpslot_t); + current_got_offset = 0; + + if (1 /* Not "-fPIC" seen */) { + int gotsize = number_of_gotslots * sizeof(got_t); + + if (gotsize + MIN_GOTOFF - (int)sizeof(got_t) > MAX_GOTOFF) + warnx("Global Offset Table overflow"); + if (gotsize > MAX_GOTOFF) + /* Position at "two-complements" origin */ + current_got_offset += MIN_GOTOFF; + } + + got_origin = -current_got_offset; + if (rrs_section_type == RRS_NONE) return; if (rrs_section_type == RRS_PARTIAL) { - got_symbol->value = rrs_sdt.sdt_got = rrs_data_start; + rrs_sdt.sdt_got = rrs_data_start; + got_symbol->value = rrs_sdt.sdt_got + got_origin; rrs_sdt.sdt_plt = rrs_sdt.sdt_got + number_of_gotslots * sizeof(got_t); return; @@ -889,12 +914,11 @@ relocate_rrs_addresses() rrs_sdt.sdt_filler2 = 0; /* - * Assign addresses to _GLOBAL_OFFSET_TABLE_ and __DYNAMIC - * &__DYNAMIC is also in the first GOT entry. + * Assign addresses to _GLOBAL_OFFSET_TABLE_ and __DYNAMIC. + * The value `&__DYNAMIC' is in the GOT table at offset 0. */ - got_symbol->value = rrs_sdt.sdt_got; - - *rrs_got = dynamic_symbol->value = rrs_data_start; + got_symbol->value = rrs_sdt.sdt_got + got_origin; + *GOTP(0) = dynamic_symbol->value = rrs_data_start; } @@ -907,36 +931,37 @@ write_rrs_data() return; pos = rrs_data_start + (N_DATOFF(outheader) - DATA_START(outheader)); - if (lseek(outdesc, pos, L_SET) != pos) - err(1, "write_rrs_data: lseek"); + if (fseek(outstream, pos, SEEK_SET) != 0) + err(1, "write_rrs_data: fseek"); if (rrs_section_type == RRS_PARTIAL) { /* * Only a GOT and PLT are needed. */ md_swapout_got(rrs_got, number_of_gotslots); - mywrite(rrs_got, number_of_gotslots, sizeof(got_t), outdesc); + mywrite(rrs_got, number_of_gotslots, sizeof(got_t), outstream); md_swapout_jmpslot(rrs_plt, number_of_jmpslots); - mywrite(rrs_plt, number_of_jmpslots, sizeof(jmpslot_t), outdesc); + mywrite(rrs_plt, number_of_jmpslots, + sizeof(jmpslot_t), outstream); return; } md_swapout__dynamic(&rrs_dyn); - mywrite(&rrs_dyn, 1, sizeof(struct _dynamic), outdesc); + mywrite(&rrs_dyn, 1, sizeof(struct _dynamic), outstream); md_swapout_so_debug(&rrs_so_debug); - mywrite(&rrs_so_debug, 1, sizeof(struct so_debug), outdesc); + mywrite(&rrs_so_debug, 1, sizeof(struct so_debug), outstream); md_swapout_section_dispatch_table(&rrs_sdt); - mywrite(&rrs_sdt, 1, sizeof(struct section_dispatch_table), outdesc); + mywrite(&rrs_sdt, 1, sizeof(struct section_dispatch_table), outstream); md_swapout_got(rrs_got, number_of_gotslots); - mywrite(rrs_got, number_of_gotslots, sizeof(got_t), outdesc); + mywrite(rrs_got, number_of_gotslots, sizeof(got_t), outstream); md_swapout_jmpslot(rrs_plt, number_of_jmpslots); - mywrite(rrs_plt, number_of_jmpslots, sizeof(jmpslot_t), outdesc); + mywrite(rrs_plt, number_of_jmpslots, sizeof(jmpslot_t), outstream); } void @@ -949,23 +974,24 @@ write_rrs_text() int offset = 0; struct shobj *shp; struct sod *sodp; + int bind; if (rrs_section_type == RRS_PARTIAL) return; pos = rrs_text_start + (N_TXTOFF(outheader) - TEXT_START(outheader)); - if (lseek(outdesc, pos, L_SET) != pos) - err(1, "write_rrs_text: lseek"); + if (fseek(outstream, pos, SEEK_SET) != 0) + err(1, "write_rrs_text: fseek"); /* Write relocation records */ md_swapout_reloc(rrs_reloc, reserved_rrs_relocs); mywrite(rrs_reloc, reserved_rrs_relocs, - sizeof(struct relocation_info), outdesc); + sizeof(struct relocation_info), outstream); /* Write the RRS symbol hash tables */ md_swapout_rrs_hash(rrs_hashtab, number_of_rrs_hash_entries); mywrite(rrs_hashtab, number_of_rrs_hash_entries, - sizeof(struct rrs_hash), outdesc); + sizeof(struct rrs_hash), outstream); /* * Determine size of an RRS symbol entry, allocate space @@ -1028,8 +1054,8 @@ write_rrs_text() if ((long)nlp - (long)rrs_symbols >= number_of_rrs_symbols * rrs_symbol_size) - errx(1, - "internal error: rrs symbols exceed allocation %d ", + errx(1, "internal error: " + "rrs symbols exceed allocation %d", number_of_rrs_symbols); nlp->nz_desc = 0; @@ -1037,6 +1063,8 @@ write_rrs_text() if (LD_VERSION_NZLIST_P(soversion)) nlp->nz_size = 0; + bind = (sp->flags & GS_WEAK) ? BIND_WEAK : 0; + if (sp->defined > 1) { /* defined with known type */ if (!(link_mode & SHAREABLE) && @@ -1049,7 +1077,7 @@ write_rrs_text() */ nlp->nz_type = sp->alias->defined; nlp->nz_value = sp->alias->value; - nlp->nz_other = N_OTHER(0, sp->alias->aux); + nlp->nz_other = N_OTHER(bind, sp->alias->aux); } else if (sp->defined == N_SIZE) { /* * Make sure this symbol isn't going @@ -1060,35 +1088,38 @@ write_rrs_text() } else { nlp->nz_type = sp->defined; nlp->nz_value = sp->value; - nlp->nz_other = N_OTHER(0, sp->aux); + nlp->nz_other = N_OTHER(bind, sp->aux); } if (LD_VERSION_NZLIST_P(soversion)) nlp->nz_size = sp->size; } else if (sp->common_size) { /* - * a common definition + * A common definition. */ nlp->nz_type = N_UNDF | N_EXT; nlp->nz_value = sp->common_size; + nlp->nz_other = N_OTHER(bind, 0); } else if (!sp->defined) { /* undefined */ nlp->nz_type = N_UNDF | N_EXT; nlp->nz_value = 0; if (sp->so_defined && sp->jmpslot_offset != -1) { /* - * Define a "weak" function symbol. + * A PLT entry. The auxiliary type -- which + * must be AUX_FUNC -- is used by the run-time + * linker to unambiguously resolve function + * address references. */ if (sp->aux != AUX_FUNC) errx(1, "%s: non-function jmpslot", - sp->name); - nlp->nz_other = N_OTHER(0, sp->aux); + sp->name); + nlp->nz_other = N_OTHER(bind, sp->aux); nlp->nz_value = rrs_sdt.sdt_plt + sp->jmpslot_offset; } } else - errx(1, - "internal error: %s defined in mysterious way", - sp->name); + errx(1, "internal error: %s defined in mysterious way", + sp->name); /* Set symbol's name */ nlp->nz_strx = offset; @@ -1103,7 +1134,7 @@ write_rrs_text() int t = (nlp->nz_type == N_INDR + N_EXT); INCR_NLP(nlp); - nlp->nz_type = N_UNDF + t?N_EXT:0; + nlp->nz_type = N_UNDF + (t ? N_EXT : 0); nlp->nz_un.n_strx = offset; nlp->nz_value = 0; nlp->nz_other = 0; @@ -1118,8 +1149,8 @@ write_rrs_text() } END_EACH_SYMBOL; if (MALIGN(offset) != rrs_strtab_size) - errx(1, - "internal error: inconsistent RRS string table length: %d, expected %d", + errx(1, "internal error: " + "inconsistent RRS string table length: %d, expected %d", offset, rrs_strtab_size); /* Write the symbol table */ @@ -1127,10 +1158,10 @@ write_rrs_text() md_swapout_symbols(rrs_symbols, number_of_rrs_symbols); else md_swapout_zsymbols(rrs_symbols, number_of_rrs_symbols); - mywrite(rrs_symbols, symsize, 1, outdesc); + mywrite(rrs_symbols, symsize, 1, outstream); /* Write the strings */ - mywrite(rrs_strtab, rrs_strtab_size, 1, outdesc); + mywrite(rrs_strtab, rrs_strtab_size, 1, outstream); /* * Write the names of the shared objects needed at run-time @@ -1161,12 +1192,12 @@ write_rrs_text() } if (i < number_of_shobjs) - errx(1, - "internal error: # of link objects less then expected %d", + errx(1, "internal error: " + "# of link objects less then expected %d", number_of_shobjs); md_swapout_sod(sodp, number_of_shobjs); - mywrite(sodp, number_of_shobjs, sizeof(struct sod), outdesc); + mywrite(sodp, number_of_shobjs, sizeof(struct sod), outstream); for (i = 0, shp = rrs_shobjs; shp; i++, shp = shp->next) { char *name = shp->entry->local_sym_name; @@ -1175,7 +1206,7 @@ write_rrs_text() name += 2; } - mywrite(name, strlen(name) + 1, 1, outdesc); + mywrite(name, strlen(name) + 1, 1, outstream); } } @@ -1188,8 +1219,8 @@ write_rrs() */ if (rrs_section_type == RRS_NONE) { if (reserved_rrs_relocs > 1) - errx(1, - "internal error: RRS relocs in static program: %d", + errx(1, "internal error: " + "RRS relocs in static program: %d", reserved_rrs_relocs-1); return; } @@ -1202,8 +1233,8 @@ printf("rrs_relocs: reserved %d claimed %d discarded %d, gotslots %d jmpslots %d /* Final consistency check */ if (claimed_rrs_relocs + discarded_rrs_relocs != reserved_rrs_relocs) { - errx(1, - "internal error: reserved relocs(%d) != claimed(%d) + discarded(%d)", + errx(1, "internal error: " + "reserved relocs(%d) != claimed(%d) + discarded(%d)", reserved_rrs_relocs, claimed_rrs_relocs, discarded_rrs_relocs); diff --git a/gnu/usr.bin/ld/rtld/Makefile b/gnu/usr.bin/ld/rtld/Makefile index d8c9165..7c81145 100644 --- a/gnu/usr.bin/ld/rtld/Makefile +++ b/gnu/usr.bin/ld/rtld/Makefile @@ -1,10 +1,9 @@ -# $Id: Makefile,v 1.12 1994/08/28 18:48:32 bde Exp $ +# $Id: Makefile,v 1.13 1994/09/18 19:41:38 swallace Exp $ PROG= ld.so SRCS= mdprologue.S rtld.c malloc.c shlib.c etc.c md.c NOMAN= noman LDDIR?= $(.CURDIR)/.. -#PICFLAG=-pic PICFLAG=-fpic CFLAGS+=-I$(LDDIR) -I$(.CURDIR) -I$(LDDIR)/$(MACHINE) $(PICFLAG) -DRTLD LDFLAGS+=-Bshareable -Bsymbolic -assert nosymbolic @@ -14,18 +13,9 @@ LDADD+= -lc_pic -lgcc_pic BINDIR= /usr/libexec INSTALLFLAGS+= -fschg -.SUFFIXES: .S - .PATH: $(LDDIR) $(LDDIR)/$(MACHINE) $(PROG): ${OBJS} ${DPADD} - $(LD) -o $(PROG) $(LDFLAGS) $(OBJS) $(LDDESTDIR) $(LDADD) - -.S.o: -.if defined(DESTDIR) - ${CPP} -I${DESTDIR}/usr/include ${.IMPSRC} | ${AS} ${ASFLAGS} -o ${.TARGET} - -.else - ${CPP} ${.IMPSRC} | ${AS} ${ASFLAGS} -o ${.TARGET} - -.endif + $(LD) -o $(PROG) $(LDFLAGS) $(OBJS) $(LDADD) .include diff --git a/gnu/usr.bin/ld/rtld/malloc.c b/gnu/usr.bin/ld/rtld/malloc.c index b5c54f8..0d94200 100644 --- a/gnu/usr.bin/ld/rtld/malloc.c +++ b/gnu/usr.bin/ld/rtld/malloc.c @@ -33,7 +33,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)malloc.c 5.11 (Berkeley) 2/23/91";*/ -static char *rcsid = "$Id: malloc.c,v 1.1 1994/02/13 20:44:09 jkh Exp $"; +static char *rcsid = "$Id: malloc.c,v 1.2 1994/06/15 22:41:13 rich Exp $"; #endif /* LIBC_SCCS and not lint */ /* @@ -72,8 +72,7 @@ static int findbucket(); /* * Pre-allocate mmap'ed pages */ -#define getpagesize() NBPG -#define NPOOLPAGES (32*1024/NBPG) +#define NPOOLPAGES (32*1024/pagesz) static caddr_t pagepool_start, pagepool_end; static int morepages(); diff --git a/gnu/usr.bin/ld/rtld/rtld.c b/gnu/usr.bin/ld/rtld/rtld.c index 6332911..c2e6021 100644 --- a/gnu/usr.bin/ld/rtld/rtld.c +++ b/gnu/usr.bin/ld/rtld/rtld.c @@ -27,7 +27,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: rtld.c,v 1.20 1995/01/12 19:12:29 joerg Exp $ + * $Id: rtld.c,v 1.21 1995/02/07 13:33:42 jkh Exp $ */ #include @@ -38,9 +38,8 @@ #include #include #include -#ifndef BSD +#ifndef MAP_COPY #define MAP_COPY MAP_PRIVATE -#define MAP_ANON 0 #endif #include #include @@ -58,8 +57,19 @@ #include "ld.h" -#ifndef BSD /* Need do better than this */ -#define NEED_DEV_ZERO 1 +#ifndef MAP_ANON +#define MAP_ANON 0 +#define anon_open() do { \ + if ((anon_fd = open("/dev/zero", O_RDWR, 0)) == -1) \ + err("open: %s", "/dev/zero"); \ +} while (0) +#define anon_close() do { \ + (void)close(anon_fd); \ + anon_fd = -1; \ +} while (0) +#else +#define anon_open() +#define anon_close() #endif /* @@ -135,6 +145,7 @@ static int careful; static char __main_progname[] = "main"; static char *main_progname = __main_progname; static char us[] = "/usr/libexec/ld.so"; +static int anon_fd = -1; struct so_map *link_map_head, *main_map; struct so_map **link_map_tail = &link_map_head; @@ -166,14 +177,15 @@ static void init_map __P((struct so_map *, char *)); static char *rtfindlib __P((char *, int, int, int *)); void binder_entry __P((void)); long binder __P((jmpslot_t *)); -static void maphints __P((void)); -static void unmaphints __P((void)); static struct nzlist *lookup __P((char *, struct so_map **, int)); static inline struct rt_symbol *lookup_rts __P((char *)); static struct rt_symbol *enter_rts __P((char *, long, int, caddr_t, long, struct so_map *)); static void generror __P((char *, ...)); +static void maphints __P((void)); +static void unmaphints __P((void)); + static inline int strcmp (register const char *s1, register const char *s2) { @@ -251,6 +263,7 @@ struct _dynamic *dp; if (getenv("LD_NOSTD_PATH") == NULL) std_search_path(); + anon_open(); /* Load required objects into the process address space */ load_objects(crtp, dp); @@ -301,11 +314,12 @@ struct _dynamic *dp; ddp->dd_sym_loaded = 1; } - /* Forget hints so that hints file can go away if it is unlinked */ + /* Close the hints file */ unmaphints(); /* Close our file descriptor */ (void)close(crtp->crt_ldfd); + anon_close(); return 0; } @@ -511,9 +525,9 @@ again: return NULL; } - if ((addr = mmap(0, hdr.a_text + hdr.a_data, - PROT_READ|PROT_EXEC, - MAP_COPY, fd, 0)) == (caddr_t)-1) { + if ((addr = mmap(0, hdr.a_text + hdr.a_data + hdr.a_bss, + PROT_READ|PROT_EXEC, + MAP_COPY, fd, 0)) == (caddr_t)-1) { generror ("mmap failed for \"%s\" : %s", path, strerror (errno)); (void)close(fd); @@ -528,29 +542,17 @@ again: return NULL; } - (void)close(fd); - - fd = -1; -#ifdef NEED_DEV_ZERO - if ((fd = open("/dev/zero", O_RDWR, 0)) == -1) { - generror ("open failed for \"/dev/zero\" : %s", - strerror (errno)); - return NULL; - } -#endif - if (hdr.a_bss && mmap(addr + hdr.a_text + hdr.a_data, hdr.a_bss, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_ANON|MAP_FIXED|MAP_COPY, - fd, hdr.a_text + hdr.a_data) == (caddr_t)-1) { + if (mmap(addr + hdr.a_text + hdr.a_data, hdr.a_bss, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_ANON|MAP_COPY|MAP_FIXED, + anon_fd, 0) == (caddr_t)-1) { generror ("mmap failed for \"%s\" : %s", path, strerror (errno)); (void)close(fd); return NULL; - } + } -#ifdef NEED_DEV_ZERO - close(fd); -#endif + (void)close(fd); /* Assume _DYNAMIC is the first data item */ dp = (struct _dynamic *)(addr+hdr.a_text); @@ -634,7 +636,7 @@ caddr_t addr; if (getenv("LD_SUPPRESS_WARNINGS") == NULL && getenv("LD_WARN_NON_PURE_CODE") != NULL) - warnx("ld.so: warning: non pure code in %s at %x (%s)\n", + warnx("warning: non pure code in %s at %x (%s)", smp->som_path, r->r_address, sym); if (smp->som_write == 0 && @@ -884,7 +886,7 @@ lookup(name, src_map, strong) * Search all maps for a definition of NAME */ for (smp = link_map_head; smp; smp = smp->som_next) { - int buckets = LD_BUCKETS(smp->som_dynamic); + int buckets; long hashval; struct rrs_hash *hp; char *cp; @@ -896,10 +898,13 @@ lookup(name, src_map, strong) char *stringbase; int symsize; - if (LM_PRIVATE(smp)->spd_flags & RTLD_RTLD) + if (*src_map && smp != *src_map) continue; - if (*src_map && smp != *src_map) + if ((buckets = LD_BUCKETS(smp->som_dynamic)) == 0) + continue; + + if (LM_PRIVATE(smp)->spd_flags & RTLD_RTLD) continue; restart: @@ -1042,8 +1047,9 @@ binder(jsp) } +static int hfd; +static long hsize; static struct hints_header *hheader; -static long hmsize; static struct hints_bucket *hbuckets; static char *hstrtab; @@ -1053,52 +1059,47 @@ static char *hstrtab; maphints __P((void)) { caddr_t addr; - long msize; - int fd; - if ((fd = open(_PATH_LD_HINTS, O_RDONLY, 0)) == -1) { + if ((hfd = open(_PATH_LD_HINTS, O_RDONLY, 0)) == -1) { hheader = (struct hints_header *)-1; return; } - msize = PAGSIZ; - addr = mmap(0, msize, PROT_READ, MAP_COPY, fd, 0); + hsize = PAGSIZ; + addr = mmap(0, hsize, PROT_READ, MAP_COPY, hfd, 0); if (addr == (caddr_t)-1) { - close(fd); + close(hfd); hheader = (struct hints_header *)-1; return; } hheader = (struct hints_header *)addr; if (HH_BADMAG(*hheader)) { - munmap(addr, msize); - close(fd); + munmap(addr, hsize); + close(hfd); hheader = (struct hints_header *)-1; return; } if (hheader->hh_version != LD_HINTS_VERSION_1) { - munmap(addr, msize); - close(fd); + munmap(addr, hsize); + close(hfd); hheader = (struct hints_header *)-1; return; } - hmsize = msize; - if (hheader->hh_ehints > msize) { - hmsize = hheader->hh_ehints; - if (mmap(addr+msize, hheader->hh_ehints - msize, + if (hheader->hh_ehints > hsize) { + if (mmap(addr+hsize, hheader->hh_ehints - hsize, PROT_READ, MAP_COPY|MAP_FIXED, - fd, msize) != (caddr_t)(addr+msize)) { + hfd, hsize) != (caddr_t)(addr+hsize)) { - munmap((caddr_t)hheader, msize); - close(fd); + munmap((caddr_t)hheader, hsize); + close(hfd); hheader = (struct hints_header *)-1; return; } } - close(fd); hbuckets = (struct hints_bucket *)(addr + hheader->hh_hashtab); hstrtab = (char *)(addr + hheader->hh_strtab); @@ -1107,8 +1108,10 @@ maphints __P((void)) static void unmaphints() { + if (HINTS_VALID) { - munmap((caddr_t)hheader, hmsize); + munmap((caddr_t)hheader, hsize); + close(hfd); hheader = NULL; } } @@ -1404,4 +1407,3 @@ char *fmt; (void)write(1, buf, strlen(buf)); va_end(ap); } - diff --git a/gnu/usr.bin/ld/shlib.c b/gnu/usr.bin/ld/shlib.c index 058689a..38cb2d1 100644 --- a/gnu/usr.bin/ld/shlib.c +++ b/gnu/usr.bin/ld/shlib.c @@ -27,7 +27,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: shlib.c,v 1.10 1994/12/23 22:30:51 nate Exp $ + * $Id: shlib.c,v 1.11 1995/01/05 02:36:29 swallace Exp $ */ #include @@ -54,7 +54,7 @@ char *strsep(); * Standard directories to search for files specified by -l. */ #ifndef STANDARD_SEARCH_DIRS -#define STANDARD_SEARCH_DIRS "/usr/lib", "/usr/X11R6/lib", "/usr/local/lib" +#define STANDARD_SEARCH_DIRS "/usr/lib", "/usr/local/lib" #endif /* diff --git a/gnu/usr.bin/ld/sparc/md.h b/gnu/usr.bin/ld/sparc/md.h index 3545d97..f83c1ff 100644 --- a/gnu/usr.bin/ld/sparc/md.h +++ b/gnu/usr.bin/ld/sparc/md.h @@ -27,7 +27,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: md.h,v 1.5 1993/12/02 01:03:47 jkh Exp $ + * $Id: md.h,v 1.6 1994/02/13 20:43:07 jkh Exp $ */ /* @@ -106,11 +106,21 @@ #define RELOC_STATICS_THROUGH_GOT_P(r) (1) #define JMPSLOT_NEEDS_RELOC (1) +/* + * Define the range of usable Global Offset Table offsets + * when using sparc 13 bit relocation types (-4096 - 4092). + */ +#define MAX_GOTSIZE (8192) +#define MAX_GOTOFF (4092) +#define MIN_GOTOFF (-4096) + #define CHECK_GOT_RELOC(r) \ ((r)->r_type == RELOC_PC10 || (r)->r_type == RELOC_PC22) #define md_got_reloc(r) (-(r)->r_address) +#define RELOC_INIT_SEGMENT_RELOC(r) ((r)->r_type = RELOC_32) + #ifdef SUN_COMPAT /* * Sun plays games with `r_addend' diff --git a/gnu/usr.bin/ld/sparc/mdprologue.S b/gnu/usr.bin/ld/sparc/mdprologue.S index 0d006d0..d3236a3 100644 --- a/gnu/usr.bin/ld/sparc/mdprologue.S +++ b/gnu/usr.bin/ld/sparc/mdprologue.S @@ -27,7 +27,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: mdprologue.S,v 1.2 1993/11/09 04:19:36 paul Exp $ + * $Id: mdprologue.S,v 1.3 1994/02/13 20:43:13 jkh Exp $ */ /* @@ -56,7 +56,7 @@ L.2B: add %i1, %fp, %i1 ! if so, adjust to absolute address 1: ld [%i1], %o3 ! load base address (crtp->crt_ba) - ld [%l7], %o2 ! get rtld's __DYNAMIC address + ld [%l7], %o2 ! get __DYNAMIC address ! from 1st GOT entry add %o2, %o3, %o2 ! relocate and make it 3rd arg. @@ -94,7 +94,7 @@ _binder_entry: restore ! get rid of our context jmp %g1 ! and go. - restore ! and the jmpslot's + restore ! and the jmpslot context nop .seg "data" ! [internal] diff --git a/gnu/usr.bin/ld/warnings.c b/gnu/usr.bin/ld/warnings.c index 0479344..3c65a22 100644 --- a/gnu/usr.bin/ld/warnings.c +++ b/gnu/usr.bin/ld/warnings.c @@ -1,5 +1,5 @@ /* - * $Id: warnings.c,v 1.8 1994/06/15 22:40:00 rich Exp $ + * $Id: warnings.c,v 1.9 1994/12/23 22:30:57 nate Exp $ */ #include @@ -25,6 +25,8 @@ #include "ld.h" +static int reported_undefineds; + /* * Print the filename of ENTRY on OUTFILE (a stdio stream), * and then a newline. @@ -101,18 +103,21 @@ print_symbols(outfile) fprintf(outfile, "\nGlobal symbols:\n\n"); FOR_EACH_SYMBOL(i, sp) { - if (sp->defined == (N_UNDF|N_EXT)) - fprintf(outfile, " %s: common, length %#x\n", - sp->name, sp->common_size); + fprintf(outfile, " %s: ", sp->name); if (!(sp->flags & GS_REFERENCED)) - fprintf(outfile, " %s: unreferenced\n", sp->name); + fprintf(outfile, "unreferenced"); else if (sp->so_defined) - fprintf(outfile, " %s: sodefined\n", sp->name); + fprintf(outfile, "sodefined"); else if (!sp->defined) - fprintf(outfile, " %s: undefined\n", sp->name); + fprintf(outfile, "undefined"); + else if (sp->defined == (N_UNDF|N_EXT)) + fprintf(outfile, "common: size %#x", sp->common_size); else - fprintf(outfile, " %s: %#x, size %#x\n", - sp->name, sp->value, sp->size); + fprintf(outfile, "type %d, value %#x, size %#x", + sp->defined, sp->value, sp->size); + if (sp->alias) + fprintf(outfile, ", aliased to %s", sp->alias->name); + fprintf(outfile, "\n"); } END_EACH_SYMBOL; each_file(list_file_locals, (void *)outfile); @@ -463,10 +468,11 @@ do_relocation_warnings(entry, data_segment, outfile, nlist_bitvector) /* Mark as being noted by relocation warning pass. */ SET_BIT(nlist_bitvector, lsp - start_of_syms); + if (g->undef_refs == 0) + reported_undefineds++; if (g->undef_refs >= MAX_UREFS_PRINTED) /* Listed too many */ continue; - /* Undefined symbol which we should mention */ if (++(g->undef_refs) == MAX_UREFS_PRINTED) { @@ -632,10 +638,28 @@ do_file_warnings (entry, outfile) line_number = -1; break; - default: -warnx("Unexpected multiple definitions of symbol `%s', type %#x\n", g->name, np->n_type); + case N_SIZE | N_EXT: + errfmt = + "Size element definition of symbol `%s' (multiply defined)"; + line_number = -1; + break; + + case N_INDR | N_EXT: + errfmt = + "Alias definition of symbol `%s' (multiply defined)"; + line_number = -1; + break; + + case N_UNDF | N_EXT: /* Don't print out multiple defs at references.*/ continue; + + default: + warnx("%s: unexpected multiple definitions " + "of symbol `%s', type %#x", + get_file_name(entry), + g->name, np->n_type); + break; } } else if (BIT_SET_P(nlist_bitvector, i)) { @@ -643,9 +667,10 @@ warnx("Unexpected multiple definitions of symbol `%s', type %#x\n", g->name, np- } else if (list_unresolved_refs && !g->defined && !g->so_defined) { + if (g->undef_refs == 0) + reported_undefineds++; if (g->undef_refs >= MAX_UREFS_PRINTED) continue; - if (++(g->undef_refs) == MAX_UREFS_PRINTED) errfmt = "More undefined `%s' refs follow"; else @@ -656,7 +681,7 @@ warnx("Unexpected multiple definitions of symbol `%s', type %#x\n", g->name, np- g->def_lsp->entry->flags & E_SECONDCLASS) { fprintf(outfile, "%s: Undefined symbol `%s' referenced (use %s ?)\n", - entry->filename, + get_file_name(entry), g->name, g->def_lsp->entry->local_sym_name); continue; @@ -678,7 +703,7 @@ warnx("Unexpected multiple definitions of symbol `%s', type %#x\n", g->name, np- continue; if (line_number == -1) - fprintf(outfile, "%s: ", entry->filename); + fprintf(outfile, "%s: ", get_file_name(entry)); else fprintf(outfile, "%s:%d: ", file_name, line_number); @@ -698,8 +723,11 @@ int do_warnings(outfile) FILE *outfile; { + list_unresolved_refs = !relocatable_output && - (undefined_global_sym_count || undefined_shobj_sym_count); + ( (undefined_global_sym_count - undefined_weak_sym_count) > 0 + || undefined_shobj_sym_count + ); list_multiple_defs = multiple_def_count != 0; if (!(list_unresolved_refs || @@ -714,6 +742,14 @@ do_warnings(outfile) each_file(do_file_warnings, (void *)outfile); + if (list_unresolved_refs && + reported_undefineds != + (undefined_global_sym_count - undefined_weak_sym_count)) + warnx("Spurious undefined symbols: " + "# undefined symbols %d, reported %d", + (undefined_global_sym_count - undefined_weak_sym_count), + reported_undefineds); + if (list_unresolved_refs || list_multiple_defs) return 0; -- cgit v1.1