diff options
-rw-r--r-- | libexec/rtld-elf/ia64/reloc.c | 19 |
1 files changed, 16 insertions, 3 deletions
diff --git a/libexec/rtld-elf/ia64/reloc.c b/libexec/rtld-elf/ia64/reloc.c index 8ec6860..a38d1b0 100644 --- a/libexec/rtld-elf/ia64/reloc.c +++ b/libexec/rtld-elf/ia64/reloc.c @@ -136,7 +136,7 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, * to ensure this within a single object. If the * caller's alloca failed, we don't even ensure that. */ - const Elf_Sym *def; + const Elf_Sym *def, *ref; const Obj_Entry *defobj; struct fptr *fptr = 0; Elf_Addr target, gp; @@ -153,8 +153,21 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, def = &obj->symtab[ELF_R_SYM(rela->r_info)]; defobj = obj; } - target = (Elf_Addr) (defobj->relocbase + def->st_value); - gp = (Elf_Addr) defobj->pltgot; + /* + * If this is an undefined weak reference, we need to + * have a zero target,gp fptr, not pointing to relocbase. + * This isn't quite right. Maybe we should check + * explicitly for def == &sym_zero. + */ + if (def->st_value == 0 && + (ref = obj->symtab + ELF_R_SYM(rela->r_info)) && + ELF_ST_BIND(ref->st_info) == STB_WEAK) { + target = 0; + gp = 0; + } else { + target = (Elf_Addr) (defobj->relocbase + def->st_value); + gp = (Elf_Addr) defobj->pltgot; + } /* * Find the @fptr, using fptrs as a helper. |