diff --git a/libexec/rtld-elf/Makefile b/libexec/rtld-elf/Makefile index bc23f7c..45318b9 100644 --- a/libexec/rtld-elf/Makefile +++ b/libexec/rtld-elf/Makefile @@ -34,7 +34,7 @@ CFLAGS+= -fPIC .else CFLAGS+= -fpic .endif -CFLAGS+= -DPIC +CFLAGS+= -DPIC $(DEBUG) LDFLAGS+= -shared -Wl,-Bsymbolic DPADD= ${LIBC_PIC} LDADD= -lc_pic -lssp_nonshared diff --git a/libexec/rtld-elf/amd64/reloc.c b/libexec/rtld-elf/amd64/reloc.c index 9e8c694..0bfc4fe 100644 --- a/libexec/rtld-elf/amd64/reloc.c +++ b/libexec/rtld-elf/amd64/reloc.c @@ -69,23 +69,28 @@ do_copy_relocations(Obj_Entry *dstobj) void *dstaddr; const Elf_Sym *dstsym; const char *name; - unsigned long hash; size_t size; const void *srcaddr; const Elf_Sym *srcsym; - Obj_Entry *srcobj; - const Ver_Entry *ve; + const Obj_Entry *srcobj, *defobj; + SymLook req; + int res; dstaddr = (void *) (dstobj->relocbase + rela->r_offset); dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info); name = dstobj->strtab + dstsym->st_name; - hash = elf_hash(name); size = dstsym->st_size; - ve = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); - - for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next) - if ((srcsym = symlook_obj(name, hash, srcobj, ve, 0)) != NULL) + symlook_init(&req, name); + req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); + + for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next) { + res = symlook_obj(&req, srcobj); + if (res == 0) { + srcsym = req.sym_out; + defobj = req.defobj_out; break; + } + } if (srcobj == NULL) { _rtld_error("Undefined symbol \"%s\" referenced from COPY" @@ -93,7 +98,7 @@ do_copy_relocations(Obj_Entry *dstobj) return -1; } - srcaddr = (const void *) (srcobj->relocbase + srcsym->st_value); + srcaddr = (const void *) (defobj->relocbase + srcsym->st_value); memcpy(dstaddr, srcaddr, size); } } @@ -113,7 +118,7 @@ init_pltgot(Obj_Entry *obj) /* Process the non-PLT relocations. */ int -reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) +reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate) { const Elf_Rela *relalim; const Elf_Rela *rela; @@ -146,7 +151,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) const Obj_Entry *defobj; def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) goto done; @@ -165,7 +170,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) const Obj_Entry *defobj; def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) goto done; @@ -195,7 +200,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) const Obj_Entry *defobj; def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) goto done; @@ -209,7 +214,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) const Obj_Entry *defobj; def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) goto done; @@ -240,7 +245,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) const Obj_Entry *defobj; def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) goto done; @@ -272,7 +277,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) const Obj_Entry *defobj; def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) goto done; @@ -286,7 +291,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) const Obj_Entry *defobj; def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) goto done; @@ -300,7 +305,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) const Obj_Entry *defobj; def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) goto done; @@ -350,7 +355,7 @@ reloc_plt(Obj_Entry *obj) /* Relocate the jump slots in an object. */ int -reloc_jmpslots(Obj_Entry *obj) +reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate) { const Elf_Rela *relalim; const Elf_Rela *rela; @@ -365,7 +370,8 @@ reloc_jmpslots(Obj_Entry *obj) assert(ELF_R_TYPE(rela->r_info) == R_X86_64_JMP_SLOT); where = (Elf_Addr *)(obj->relocbase + rela->r_offset); - def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, true, NULL); + def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, true, NULL, + lockstate); if (def == NULL) return -1; target = (Elf_Addr)(defobj->relocbase + def->st_value + rela->r_addend); diff --git a/libexec/rtld-elf/arm/reloc.c b/libexec/rtld-elf/arm/reloc.c index 6ad80fd..8f83a8e 100644 --- a/libexec/rtld-elf/arm/reloc.c +++ b/libexec/rtld-elf/arm/reloc.c @@ -36,31 +36,39 @@ do_copy_relocations(Obj_Entry *dstobj) void *dstaddr; const Elf_Sym *dstsym; const char *name; - unsigned long hash; size_t size; const void *srcaddr; const Elf_Sym *srcsym; - Obj_Entry *srcobj; - const Ver_Entry *ve; + const Obj_Entry *srcobj, *defobj; + SymLook req; + int res; dstaddr = (void *) (dstobj->relocbase + rel->r_offset); dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info); name = dstobj->strtab + dstsym->st_name; - hash = elf_hash(name); size = dstsym->st_size; - ve = fetch_ventry(dstobj, ELF_R_SYM(rel->r_info)); - - for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next) - if ((srcsym = symlook_obj(name, hash, srcobj, ve, 0)) != NULL) + + symlook_init(&req, name); + req.ventry = fetch_ventry(dstobj, + ELF_R_SYM(rel->r_info)); + for (srcobj = dstobj->next; srcobj != NULL; + srcobj = srcobj->next) { + res = symlook_obj(&req, srcobj); + if (res == 0) { + srcsym = req.sym_out; + defobj = req.defobj_out; break; - + } + } if (srcobj == NULL) { - _rtld_error("Undefined symbol \"%s\" referenced from COPY" - " relocation in %s", name, dstobj->path); - return -1; + _rtld_error( +"Undefined symbol \"%s\" referenced from COPY relocation in %s", + name, dstobj->path); + return (-1); } - srcaddr = (const void *) (srcobj->relocbase + srcsym->st_value); + srcaddr = (const void *)(defobj->relocbase + + srcsym->st_value); memcpy(dstaddr, srcaddr, size); } } @@ -123,7 +131,8 @@ store_ptr(void *where, Elf_Addr val) } static int -reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache) +reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache, + RtldLockState *lockstate) { Elf_Addr *where; const Elf_Sym *def; @@ -149,7 +158,8 @@ reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache) if (addend & 0x00800000) addend |= 0xff000000; - def = find_symdef(symnum, obj, &defobj, false, cache); + def = find_symdef(symnum, obj, &defobj, false, cache, + lockstate); if (def == NULL) return -1; tmp = (Elf_Addr)obj->relocbase + def->st_value @@ -175,7 +185,8 @@ reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache) case R_ARM_ABS32: /* word32 B + S + A */ case R_ARM_GLOB_DAT: /* word32 B + S */ - def = find_symdef(symnum, obj, &defobj, false, cache); + def = find_symdef(symnum, obj, &defobj, false, cache, + lockstate); if (def == NULL) return -1; if (__predict_true(RELOC_ALIGNED_P(where))) { @@ -240,7 +251,7 @@ reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache) * * Process non-PLT relocations * */ int -reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) +reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate) { const Elf_Rel *rellim; const Elf_Rel *rel; @@ -259,7 +270,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize); for (rel = obj->rel; rel < rellim; rel++) { - if (reloc_nonplt_object(obj, rel, cache) < 0) + if (reloc_nonplt_object(obj, rel, cache, lockstate) < 0) goto done; } r = 0; @@ -296,7 +307,7 @@ reloc_plt(Obj_Entry *obj) * * LD_BIND_NOW was set - force relocation for all jump slots * */ int -reloc_jmpslots(Obj_Entry *obj) +reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate) { const Obj_Entry *defobj; const Elf_Rel *rellim; @@ -310,7 +321,7 @@ reloc_jmpslots(Obj_Entry *obj) assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT); where = (Elf_Addr *)(obj->relocbase + rel->r_offset); def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, - true, NULL); + true, NULL, lockstate); if (def == NULL) { dbg("reloc_jmpslots: sym not found"); return (-1); diff --git a/libexec/rtld-elf/i386/reloc.c b/libexec/rtld-elf/i386/reloc.c index 818d2eb..9efebb3 100644 --- a/libexec/rtld-elf/i386/reloc.c +++ b/libexec/rtld-elf/i386/reloc.c @@ -70,23 +70,28 @@ do_copy_relocations(Obj_Entry *dstobj) void *dstaddr; const Elf_Sym *dstsym; const char *name; - unsigned long hash; size_t size; const void *srcaddr; const Elf_Sym *srcsym; - const Ver_Entry *ve; - Obj_Entry *srcobj; + const Obj_Entry *srcobj, *defobj; + SymLook req; + int res; dstaddr = (void *) (dstobj->relocbase + rel->r_offset); dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info); name = dstobj->strtab + dstsym->st_name; - hash = elf_hash(name); size = dstsym->st_size; - ve = fetch_ventry(dstobj, ELF_R_SYM(rel->r_info)); - - for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next) - if ((srcsym = symlook_obj(name, hash, srcobj, ve, 0)) != NULL) + symlook_init(&req, name); + req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rel->r_info)); + + for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next) { + res = symlook_obj(&req, srcobj); + if (res == 0) { + srcsym = req.sym_out; + defobj = req.defobj_out; break; + } + } if (srcobj == NULL) { _rtld_error("Undefined symbol \"%s\" referenced from COPY" @@ -94,7 +99,7 @@ do_copy_relocations(Obj_Entry *dstobj) return -1; } - srcaddr = (const void *) (srcobj->relocbase + srcsym->st_value); + srcaddr = (const void *) (defobj->relocbase + srcsym->st_value); memcpy(dstaddr, srcaddr, size); } } @@ -114,7 +119,7 @@ init_pltgot(Obj_Entry *obj) /* Process the non-PLT relocations. */ int -reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) +reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate) { const Elf_Rel *rellim; const Elf_Rel *rel; @@ -146,7 +151,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) const Obj_Entry *defobj; def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) goto done; @@ -165,7 +170,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) const Obj_Entry *defobj; def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) goto done; @@ -195,7 +200,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) const Obj_Entry *defobj; def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) goto done; @@ -213,7 +218,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) const Obj_Entry *defobj; def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) goto done; @@ -243,7 +248,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) const Obj_Entry *defobj; def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) goto done; @@ -257,7 +262,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) const Obj_Entry *defobj; def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) goto done; @@ -301,7 +306,7 @@ reloc_plt(Obj_Entry *obj) /* Relocate the jump slots in an object. */ int -reloc_jmpslots(Obj_Entry *obj) +reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate) { const Elf_Rel *rellim; const Elf_Rel *rel; @@ -316,7 +321,8 @@ reloc_jmpslots(Obj_Entry *obj) assert(ELF_R_TYPE(rel->r_info) == R_386_JMP_SLOT); where = (Elf_Addr *)(obj->relocbase + rel->r_offset); - def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true, NULL); + def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true, NULL, + lockstate); if (def == NULL) return -1; target = (Elf_Addr)(defobj->relocbase + def->st_value); diff --git a/libexec/rtld-elf/ia64/reloc.c b/libexec/rtld-elf/ia64/reloc.c index 728fe30..6ee0947 100644 --- a/libexec/rtld-elf/ia64/reloc.c +++ b/libexec/rtld-elf/ia64/reloc.c @@ -151,7 +151,7 @@ free_fptrs(Obj_Entry *obj, bool mapped) /* Relocate a non-PLT object with addend. */ static int reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, - SymCache *cache) + SymCache *cache, RtldLockState *lockstate) { struct fptr **fptrs; Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rela->r_offset); @@ -172,7 +172,7 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr target; def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) return -1; @@ -195,7 +195,7 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, int sym_index; def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - true, cache); + true, cache, lockstate); if (def == NULL) { /* * XXX r_debug_state is problematic and find_symdef() @@ -254,7 +254,7 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr target, gp; def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) return -1; @@ -277,7 +277,7 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, const Obj_Entry *defobj; def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) return -1; @@ -290,7 +290,7 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, const Obj_Entry *defobj; def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) return -1; @@ -303,7 +303,7 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, const Obj_Entry *defobj; def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) return -1; @@ -342,7 +342,7 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, /* Process the non-PLT relocations. */ int -reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) +reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate) { const Elf_Rel *rellim; const Elf_Rel *rel; @@ -368,14 +368,15 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) locrela.r_info = rel->r_info; locrela.r_offset = rel->r_offset; locrela.r_addend = 0; - if (reloc_non_plt_obj(obj_rtld, obj, &locrela, cache)) + if (reloc_non_plt_obj(obj_rtld, obj, &locrela, cache, + lockstate)) goto done; } /* Perform relocations with addend if there are any: */ relalim = (const Elf_Rela *) ((caddr_t) obj->rela + obj->relasize); for (rela = obj->rela; obj->rela != NULL && rela < relalim; rela++) { - if (reloc_non_plt_obj(obj_rtld, obj, rela, cache)) + if (reloc_non_plt_obj(obj_rtld, obj, rela, cache, lockstate)) goto done; } @@ -436,7 +437,7 @@ reloc_plt(Obj_Entry *obj) /* Relocate the jump slots in an object. */ int -reloc_jmpslots(Obj_Entry *obj) +reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate) { if (obj->jmpslots_done) return 0; @@ -455,7 +456,7 @@ reloc_jmpslots(Obj_Entry *obj) assert(ELF_R_TYPE(rel->r_info) == R_IA_64_IPLTLSB); where = (Elf_Addr *)(obj->relocbase + rel->r_offset); def = find_symdef(ELF_R_SYM(rel->r_info), obj, - &defobj, true, NULL); + &defobj, true, NULL, lockstate); if (def == NULL) return -1; reloc_jmpslot(where, @@ -476,7 +477,7 @@ reloc_jmpslots(Obj_Entry *obj) where = (Elf_Addr *)(obj->relocbase + rela->r_offset); def = find_symdef(ELF_R_SYM(rela->r_info), obj, - &defobj, true, NULL); + &defobj, true, NULL, lockstate); if (def == NULL) return -1; reloc_jmpslot(where, diff --git a/libexec/rtld-elf/mips/reloc.c b/libexec/rtld-elf/mips/reloc.c index 0195df6..682adcd 100644 --- a/libexec/rtld-elf/mips/reloc.c +++ b/libexec/rtld-elf/mips/reloc.c @@ -238,7 +238,8 @@ _mips_rtld_bind(Obj_Entry *obj, Elf_Size reloff) const Obj_Entry *defobj; Elf_Addr target; - def = find_symdef(reloff, obj, &defobj, SYMLOOK_IN_PLT, NULL); + def = find_symdef(reloff, obj, &defobj, SYMLOOK_IN_PLT, NULL, + NULL); if (def == NULL) _rtld_error("bind failed no symbol"); @@ -253,7 +254,7 @@ _mips_rtld_bind(Obj_Entry *obj, Elf_Size reloff) } int -reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) +reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate) { const Elf_Rel *rel; const Elf_Rel *rellim; @@ -312,7 +313,8 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) * to 0 if there are non-PLT references, but older * versions of GNU ld do not do this. */ - def = find_symdef(i, obj, &defobj, false, NULL); + def = find_symdef(i, obj, &defobj, false, NULL, + lockstate); if (def == NULL) return -1; *got = def->st_value + (Elf_Addr)defobj->relocbase; @@ -353,7 +355,8 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) } } else { /* TODO: add cache here */ - def = find_symdef(i, obj, &defobj, false, NULL); + def = find_symdef(i, obj, &defobj, false, NULL, + lockstate); if (def == NULL) { dbg("Warning4, cant find symbole %d", i); return -1; @@ -487,7 +490,7 @@ reloc_plt(Obj_Entry *obj) * LD_BIND_NOW was set - force relocation for all jump slots */ int -reloc_jmpslots(Obj_Entry *obj) +reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate) { /* Do nothing */ obj->jmpslots_done = true; diff --git a/libexec/rtld-elf/powerpc/reloc.c b/libexec/rtld-elf/powerpc/reloc.c index 84feff3..4aca86e 100644 --- a/libexec/rtld-elf/powerpc/reloc.c +++ b/libexec/rtld-elf/powerpc/reloc.c @@ -75,12 +75,12 @@ do_copy_relocations(Obj_Entry *dstobj) void *dstaddr; const Elf_Sym *dstsym; const char *name; - unsigned long hash; size_t size; const void *srcaddr; const Elf_Sym *srcsym = NULL; - Obj_Entry *srcobj; - const Ver_Entry *ve; + const Obj_Entry *srcobj, *defobj; + SymLook req; + int res; if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) { continue; @@ -89,14 +89,16 @@ do_copy_relocations(Obj_Entry *dstobj) dstaddr = (void *) (dstobj->relocbase + rela->r_offset); dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info); name = dstobj->strtab + dstsym->st_name; - hash = elf_hash(name); size = dstsym->st_size; - ve = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); + symlook_init(&req, name); + req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next) { - if ((srcsym = symlook_obj(name, hash, srcobj, ve, 0)) - != NULL) { + res = symlook_obj(&req, srcobj); + if (res == 0) { + srcsym = req.sym_out; + defobj = req.defobj_out; break; } } @@ -108,7 +110,7 @@ do_copy_relocations(Obj_Entry *dstobj) return (-1); } - srcaddr = (const void *) (srcobj->relocbase+srcsym->st_value); + srcaddr = (const void *) (defobj->relocbase+srcsym->st_value); memcpy(dstaddr, srcaddr, size); dbg("copy_reloc: src=%p,dst=%p,size=%d\n",srcaddr,dstaddr,size); } @@ -157,7 +159,7 @@ reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase) */ static int reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, - SymCache *cache) + SymCache *cache, RtldLockState *lockstate) { Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); const Elf_Sym *def; @@ -172,7 +174,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, case R_PPC_ADDR32: /* word32 S + A */ case R_PPC_GLOB_DAT: /* word32 S + A */ def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) { return (-1); } @@ -219,7 +221,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, case R_PPC_DTPMOD32: def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) return (-1); @@ -230,7 +232,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, case R_PPC_TPREL32: def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) return (-1); @@ -259,7 +261,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, case R_PPC_DTPREL32: def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) return (-1); @@ -283,7 +285,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, * Process non-PLT relocations */ int -reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) +reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate) { const Elf_Rela *relalim; const Elf_Rela *rela; @@ -307,7 +309,8 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) */ relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize); for (rela = obj->rela; rela < relalim; rela++) { - if (reloc_nonplt_object(obj_rtld, obj, rela, cache) < 0) + if (reloc_nonplt_object(obj_rtld, obj, rela, cache, lockstate) + < 0) goto done; } r = 0; @@ -401,7 +404,7 @@ reloc_plt(Obj_Entry *obj) * LD_BIND_NOW was set - force relocation for all jump slots */ int -reloc_jmpslots(Obj_Entry *obj) +reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate) { const Obj_Entry *defobj; const Elf_Rela *relalim; @@ -415,7 +418,7 @@ reloc_jmpslots(Obj_Entry *obj) assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); where = (Elf_Addr *)(obj->relocbase + rela->r_offset); def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - true, NULL); + true, NULL, lockstate); if (def == NULL) { dbg("reloc_jmpslots: sym not found"); return (-1); diff --git a/libexec/rtld-elf/powerpc64/reloc.c b/libexec/rtld-elf/powerpc64/reloc.c index d2430e7..b2236f2 100644 --- a/libexec/rtld-elf/powerpc64/reloc.c +++ b/libexec/rtld-elf/powerpc64/reloc.c @@ -69,12 +69,12 @@ do_copy_relocations(Obj_Entry *dstobj) void *dstaddr; const Elf_Sym *dstsym; const char *name; - unsigned long hash; size_t size; const void *srcaddr; const Elf_Sym *srcsym = NULL; - Obj_Entry *srcobj; - const Ver_Entry *ve; + const Obj_Entry *srcobj, *defobj; + SymLook req; + int res; if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) { continue; @@ -83,14 +83,16 @@ do_copy_relocations(Obj_Entry *dstobj) dstaddr = (void *) (dstobj->relocbase + rela->r_offset); dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info); name = dstobj->strtab + dstsym->st_name; - hash = elf_hash(name); size = dstsym->st_size; - ve = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); + symlook_init(&req, name); + req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next) { - if ((srcsym = symlook_obj(name, hash, srcobj, ve, 0)) - != NULL) { + res = symlook_obj(&req, srcobj); + if (res == 0) { + srcsym = req.sym_out; + defobj = req.defobj_out; break; } } @@ -102,7 +104,7 @@ do_copy_relocations(Obj_Entry *dstobj) return (-1); } - srcaddr = (const void *) (srcobj->relocbase+srcsym->st_value); + srcaddr = (const void *) (defobj->relocbase+srcsym->st_value); memcpy(dstaddr, srcaddr, size); dbg("copy_reloc: src=%p,dst=%p,size=%zd\n",srcaddr,dstaddr,size); } @@ -151,7 +153,7 @@ reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase) */ static int reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, - SymCache *cache) + SymCache *cache, RtldLockState *lockstate) { Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); const Elf_Sym *def; @@ -166,7 +168,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, case R_PPC64_ADDR64: /* doubleword64 S + A */ case R_PPC_GLOB_DAT: def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) { return (-1); } @@ -213,7 +215,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, case R_PPC64_DTPMOD64: def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) return (-1); @@ -224,7 +226,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, case R_PPC64_TPREL64: def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) return (-1); @@ -253,7 +255,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, case R_PPC64_DTPREL64: def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) return (-1); @@ -277,7 +279,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, * Process non-PLT relocations */ int -reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) +reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate) { const Elf_Rela *relalim; const Elf_Rela *rela; @@ -304,7 +306,8 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) */ relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize); for (rela = obj->rela; rela < relalim; rela++) { - if (reloc_nonplt_object(obj_rtld, obj, rela, cache) < 0) + if (reloc_nonplt_object(obj_rtld, obj, rela, cache, lockstate) + < 0) goto done; } r = 0; @@ -376,7 +379,7 @@ reloc_plt(Obj_Entry *obj) * LD_BIND_NOW was set - force relocation for all jump slots */ int -reloc_jmpslots(Obj_Entry *obj) +reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate) { const Obj_Entry *defobj; const Elf_Rela *relalim; @@ -390,7 +393,7 @@ reloc_jmpslots(Obj_Entry *obj) assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); where = (Elf_Addr *)(obj->relocbase + rela->r_offset); def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - true, NULL); + true, NULL, lockstate); if (def == NULL) { dbg("reloc_jmpslots: sym not found"); return (-1); diff --git a/libexec/rtld-elf/rtld.1 b/libexec/rtld-elf/rtld.1 index 592cb95..f77b150 100644 --- a/libexec/rtld-elf/rtld.1 +++ b/libexec/rtld-elf/rtld.1 @@ -221,6 +221,14 @@ If set, .Nm will log events such as the loading and unloading of shared objects via .Xr utrace 2 . +.Pp +.It Ev LD_LOADFLTR +If set, +.Nm +will process the filtee dependencies of the loaded objects immediately, +instead of postponing it until required. +Normally, the filtees are opened at the time of the first symbol resolution +from the filter object. .El .Sh FILES .Bl -tag -width ".Pa /var/run/ld-elf32.so.hints" -compact diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index a53a25a..802773b 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -71,16 +71,6 @@ typedef void (*func_ptr_type)(); typedef void * (*path_enum_proc) (const char *path, size_t len, void *arg); /* - * This structure provides a reentrant way to keep a list of objects and - * check which ones have already been processed in some way. - */ -typedef struct Struct_DoneList { - const Obj_Entry **objs; /* Array of object pointers */ - unsigned int num_alloc; /* Allocated size of the array */ - unsigned int num_used; /* Number of array slots used */ -} DoneList; - -/* * Function declarations. */ static const char *basename(const char *); @@ -91,6 +81,8 @@ static void digest_dynamic2(Obj_Entry *, const Elf_Dyn *, const Elf_Dyn *); static void digest_dynamic(Obj_Entry *, int); static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *); static Obj_Entry *dlcheck(void *); +static Obj_Entry *dlopen_object(const char *name, Obj_Entry *refobj, + int lo_flags, int mode); static Obj_Entry *do_load_object(int, const char *, char *, struct stat *, int); static int do_search_info(const Obj_Entry *obj, int, struct dl_serinfo *); static bool donelist_check(DoneList *, const Obj_Entry *); @@ -106,12 +98,14 @@ static void initlist_add_neededs(Needed_Entry *, Objlist *); static void initlist_add_objects(Obj_Entry *, Obj_Entry **, Objlist *); static void linkmap_add(Obj_Entry *); static void linkmap_delete(Obj_Entry *); +static void load_filtees(Obj_Entry *, int flags, RtldLockState *); +static void unload_filtees(Obj_Entry *); static int load_needed_objects(Obj_Entry *, int); static int load_preload_objects(void); static Obj_Entry *load_object(const char *, const Obj_Entry *, int); static Obj_Entry *obj_from_addr(const void *); -static void objlist_call_fini(Objlist *, Obj_Entry *, int *); -static void objlist_call_init(Objlist *, int *); +static void objlist_call_fini(Objlist *, Obj_Entry *, RtldLockState *); +static void objlist_call_init(Objlist *, RtldLockState *); static void objlist_clear(Objlist *); static Objlist_Entry *objlist_find(Objlist *, const Obj_Entry *); static void objlist_init(Objlist *); @@ -119,20 +113,18 @@ static void objlist_push_head(Objlist *, Obj_Entry *); static void objlist_push_tail(Objlist *, Obj_Entry *); static void objlist_remove(Objlist *, Obj_Entry *); static void *path_enumerate(const char *, path_enum_proc, void *); -static int relocate_objects(Obj_Entry *, bool, Obj_Entry *); +static int relocate_objects(Obj_Entry *, bool, Obj_Entry *, RtldLockState *); static int rtld_dirname(const char *, char *); static int rtld_dirname_abs(const char *, char *); static void rtld_exit(void); static char *search_library_path(const char *, const char *); static const void **get_program_var_addr(const char *); static void set_program_var(const char *, const void *); -static const Elf_Sym *symlook_default(const char *, unsigned long, - const Obj_Entry *, const Obj_Entry **, const Ver_Entry *, int); -static const Elf_Sym *symlook_list(const char *, unsigned long, const Objlist *, - const Obj_Entry **, const Ver_Entry *, int, DoneList *); -static const Elf_Sym *symlook_needed(const char *, unsigned long, - const Needed_Entry *, const Obj_Entry **, const Ver_Entry *, - int, DoneList *); +static int symlook_default(SymLook *, const Obj_Entry *refobj); +static void symlook_init_from_req(SymLook *, const SymLook *); +static int symlook_list(SymLook *, const Objlist *, DoneList *); +static int symlook_needed(SymLook *, const Needed_Entry *, DoneList *); +static int symlook_obj1(SymLook *, const Obj_Entry *); static void trace_loaded_objects(Obj_Entry *); static void unlink_object(Obj_Entry *); static void unload_object(Obj_Entry *); @@ -157,6 +149,7 @@ void r_debug_state(struct r_debug *, struct link_map *); static char *error_message; /* Message for dlerror(), or NULL */ struct r_debug r_debug; /* for GDB; */ static bool libmap_disable; /* Disable libmap */ +static bool ld_loadfltr; /* Immediate filters processing */ static char *libmap_override; /* Maps to use in addition to libmap.conf */ static bool trust; /* False for setuid and setgid programs */ static bool dangerous_ld_env; /* True if environment variables have been @@ -300,7 +293,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) Obj_Entry *obj; Obj_Entry **preload_tail; Objlist initlist; - int lockstate; + RtldLockState lockstate; /* * On entry, the dynamic linker itself has not been relocated yet. @@ -346,7 +339,8 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) if (!trust) { if (unsetenv(LD_ "PRELOAD") || unsetenv(LD_ "LIBMAP") || unsetenv(LD_ "LIBRARY_PATH") || unsetenv(LD_ "LIBMAP_DISABLE") || - unsetenv(LD_ "DEBUG") || unsetenv(LD_ "ELF_HINTS_PATH")) { + unsetenv(LD_ "DEBUG") || unsetenv(LD_ "ELF_HINTS_PATH") || + unsetenv(LD_ "LOADFLTR")) { _rtld_error("environment corrupt; aborting"); die(); } @@ -357,9 +351,10 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) ld_library_path = getenv(LD_ "LIBRARY_PATH"); ld_preload = getenv(LD_ "PRELOAD"); ld_elf_hints_path = getenv(LD_ "ELF_HINTS_PATH"); + ld_loadfltr = getenv(LD_ "LOADFLTR") != NULL; dangerous_ld_env = libmap_disable || (libmap_override != NULL) || (ld_library_path != NULL) || (ld_preload != NULL) || - (ld_elf_hints_path != NULL); + (ld_elf_hints_path != NULL) || ld_loadfltr; ld_tracing = getenv(LD_ "TRACE_LOADED_OBJECTS"); ld_utrace = getenv(LD_ "UTRACE"); @@ -373,6 +368,9 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) dbg("RTLD dynamic = %p", obj_rtld.dynamic); dbg("RTLD pltgot = %p", obj_rtld.pltgot); + dbg("initializing thread locks"); + lockdflt_init(); + /* * Load the main program, or process its program header if it is * already loaded. @@ -498,7 +496,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) allocate_initial_tls(obj_list); if (relocate_objects(obj_main, - ld_bind_now != NULL && *ld_bind_now != '\0', &obj_rtld) == -1) + ld_bind_now != NULL && *ld_bind_now != '\0', &obj_rtld, NULL) == -1) die(); dbg("doing copy relocations"); @@ -515,19 +513,21 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) set_program_var("environ", env); set_program_var("__elf_aux_vector", aux); - dbg("initializing thread locks"); - lockdflt_init(); - /* Make a list of init functions to call. */ objlist_init(&initlist); initlist_add_objects(obj_list, preload_tail, &initlist); r_debug_state(NULL, &obj_main->linkmap); /* say hello to gdb! */ - lockstate = wlock_acquire(rtld_bind_lock); + wlock_acquire(rtld_bind_lock, &lockstate); objlist_call_init(&initlist, &lockstate); objlist_clear(&initlist); - wlock_release(rtld_bind_lock, lockstate); + dbg("loading filtees"); + for (obj = obj_list->next; obj != NULL; obj = obj->next) { + if (ld_loadfltr || obj->z_loadfltr) + load_filtees(obj, 0, &lockstate); + } + lock_release(rtld_bind_lock, &lockstate); dbg("transferring control to program entry point = %p", obj_main->entry); @@ -545,16 +545,19 @@ _rtld_bind(Obj_Entry *obj, Elf_Size reloff) const Obj_Entry *defobj; Elf_Addr *where; Elf_Addr target; - int lockstate; + RtldLockState lockstate; - lockstate = rlock_acquire(rtld_bind_lock); + rlock_acquire(rtld_bind_lock, &lockstate); + if (setjmp(lockstate.env) != 0) + lock_upgrade(rtld_bind_lock, &lockstate); if (obj->pltrel) rel = (const Elf_Rel *) ((caddr_t) obj->pltrel + reloff); else rel = (const Elf_Rel *) ((caddr_t) obj->pltrela + reloff); where = (Elf_Addr *) (obj->relocbase + rel->r_offset); - def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true, NULL); + def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true, NULL, + &lockstate); if (def == NULL) die(); @@ -572,7 +575,7 @@ _rtld_bind(Obj_Entry *obj, Elf_Size reloff) * that the trampoline needs. */ target = reloc_jmpslot(where, target, defobj, obj, rel); - rlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return target; } @@ -721,6 +724,8 @@ digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath, { const Elf_Dyn *dynp; Needed_Entry **needed_tail = &obj->needed; + Needed_Entry **needed_filtees_tail = &obj->needed_filtees; + Needed_Entry **needed_aux_filtees_tail = &obj->needed_aux_filtees; int plttype = DT_REL; *dyn_rpath = NULL; @@ -831,6 +836,30 @@ digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath, } break; + case DT_FILTER: + if (!obj->rtld) { + Needed_Entry *nep = NEW(Needed_Entry); + nep->name = dynp->d_un.d_val; + nep->obj = NULL; + nep->next = NULL; + + *needed_filtees_tail = nep; + needed_filtees_tail = &nep->next; + } + break; + + case DT_AUXILIARY: + if (!obj->rtld) { + Needed_Entry *nep = NEW(Needed_Entry); + nep->name = dynp->d_un.d_val; + nep->obj = NULL; + nep->next = NULL; + + *needed_aux_filtees_tail = nep; + needed_aux_filtees_tail = &nep->next; + } + break; + case DT_PLTGOT: obj->pltgot = (Elf_Addr *) (obj->relocbase + dynp->d_un.d_ptr); break; @@ -923,6 +952,8 @@ digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath, obj->bind_now = true; if (dynp->d_un.d_val & DF_1_NODELETE) obj->z_nodelete = true; + if (dynp->d_un.d_val & DF_1_LOADFLTR) + obj->z_loadfltr = true; break; default: @@ -1163,14 +1194,15 @@ find_library(const char *xname, const Obj_Entry *refobj) */ const Elf_Sym * find_symdef(unsigned long symnum, const Obj_Entry *refobj, - const Obj_Entry **defobj_out, int flags, SymCache *cache) + const Obj_Entry **defobj_out, int flags, SymCache *cache, + RtldLockState *lockstate) { const Elf_Sym *ref; const Elf_Sym *def; const Obj_Entry *defobj; - const Ver_Entry *ventry; + SymLook req; const char *name; - unsigned long hash; + int res; /* * If we have already found this symbol, get the information from @@ -1185,6 +1217,7 @@ find_symdef(unsigned long symnum, const Obj_Entry *refobj, ref = refobj->symtab + symnum; name = refobj->strtab + ref->st_name; + def = NULL; defobj = NULL; /* @@ -1200,9 +1233,15 @@ find_symdef(unsigned long symnum, const Obj_Entry *refobj, _rtld_error("%s: Bogus symbol table entry %lu", refobj->path, symnum); } - ventry = fetch_ventry(refobj, symnum); - hash = elf_hash(name); - def = symlook_default(name, hash, refobj, &defobj, ventry, flags); + symlook_init(&req, name); + req.flags = flags; + req.ventry = fetch_ventry(refobj, symnum); + req.lockstate = lockstate; + res = symlook_default(&req, refobj); + if (res == 0) { + def = req.sym_out; + defobj = req.defobj_out; + } } else { def = ref; defobj = refobj; @@ -1336,7 +1375,7 @@ init_rtld(caddr_t mapbase, Elf_Auxinfo **aux_info) * that symbols can be found. */ - relocate_objects(&objtmp, true, &objtmp); + relocate_objects(&objtmp, true, &objtmp, NULL); } /* Initialize the object list. */ @@ -1416,6 +1455,77 @@ initlist_add_objects(Obj_Entry *obj, Obj_Entry **tail, Objlist *list) #define FPTR_TARGET(f) ((Elf_Addr) (f)) #endif +static void +free_needed_filtees(Needed_Entry *n) +{ + Needed_Entry *needed, *needed1; + + for (needed = n; needed != NULL; needed = needed->next) { + if (needed->obj != NULL) { + dlclose(needed->obj); + needed->obj = NULL; + } + } + for (needed = n; needed != NULL; needed = needed1) { + needed1 = needed->next; + free(needed); + } +} + +static void +unload_filtees(Obj_Entry *obj) +{ + + free_needed_filtees(obj->needed_filtees); + obj->needed_filtees = NULL; + free_needed_filtees(obj->needed_aux_filtees); + obj->needed_aux_filtees = NULL; + obj->filtees_loaded = false; +} + +static void +load_filtee1(Obj_Entry *obj, Needed_Entry *needed, int flags) +{ + + for (; needed != NULL; needed = needed->next) { + needed->obj = dlopen_object(obj->strtab + needed->name, obj, + flags, ((ld_loadfltr || obj->z_loadfltr) ? RTLD_NOW : RTLD_LAZY) | + RTLD_LOCAL); + } +} + +static void +load_filtees(Obj_Entry *obj, int flags, RtldLockState *lockstate) +{ + + lock_restart_for_upgrade(lockstate); + if (!obj->filtees_loaded) { + load_filtee1(obj, obj->needed_filtees, flags); + load_filtee1(obj, obj->needed_aux_filtees, flags); + obj->filtees_loaded = true; + } +} + +static int +process_needed(Obj_Entry *obj, Needed_Entry *needed, int flags) +{ + Obj_Entry *obj1; + + for (; needed != NULL; needed = needed->next) { + obj1 = needed->obj = load_object(obj->strtab + needed->name, obj, + flags & ~RTLD_LO_NOLOAD); + if (obj1 == NULL && !ld_tracing && (flags & RTLD_LO_FILTEES) == 0) + return (-1); + if (obj1 != NULL && obj1->z_nodelete && !obj1->ref_nodel) { + dbg("obj %s nodelete", obj1->path); + init_dag(obj1); + ref_dag(obj1); + obj1->ref_nodel = true; + } + } + return (0); +} + /* * Given a shared object, traverse its list of needed objects, and load * each of them. Returns 0 on success. Generates an error message and @@ -1424,26 +1534,13 @@ initlist_add_objects(Obj_Entry *obj, Obj_Entry **tail, Objlist *list) static int load_needed_objects(Obj_Entry *first, int flags) { - Obj_Entry *obj, *obj1; + Obj_Entry *obj; for (obj = first; obj != NULL; obj = obj->next) { - Needed_Entry *needed; - - for (needed = obj->needed; needed != NULL; needed = needed->next) { - obj1 = needed->obj = load_object(obj->strtab + needed->name, obj, - flags & ~RTLD_LO_NOLOAD); - if (obj1 == NULL && !ld_tracing) - return -1; - if (obj1 != NULL && obj1->z_nodelete && !obj1->ref_nodel) { - dbg("obj %s nodelete", obj1->path); - init_dag(obj1); - ref_dag(obj1); - obj1->ref_nodel = true; - } - } + if (process_needed(obj, obj->needed, flags) == -1) + return (-1); } - - return 0; + return (0); } static int @@ -1615,7 +1712,7 @@ obj_from_addr(const void *addr) * the objects are expected to have non-NULL fini functions. */ static void -objlist_call_fini(Objlist *list, Obj_Entry *root, int *lockstate) +objlist_call_fini(Objlist *list, Obj_Entry *root, RtldLockState *lockstate) { Objlist_Entry *elm; char *saved_msg; @@ -1645,9 +1742,9 @@ objlist_call_fini(Objlist *list, Obj_Entry *root, int *lockstate) * won't be unloaded although its fini function has been * called. */ - wlock_release(rtld_bind_lock, *lockstate); + lock_release(rtld_bind_lock, lockstate); call_initfini_pointer(elm->obj, elm->obj->fini); - *lockstate = wlock_acquire(rtld_bind_lock); + wlock_acquire(rtld_bind_lock, lockstate); /* No need to free anything if process is going down. */ if (root != NULL) free(elm); @@ -1668,7 +1765,7 @@ objlist_call_fini(Objlist *list, Obj_Entry *root, int *lockstate) * functions. */ static void -objlist_call_init(Objlist *list, int *lockstate) +objlist_call_init(Objlist *list, RtldLockState *lockstate) { Objlist_Entry *elm; Obj_Entry *obj; @@ -1700,9 +1797,9 @@ objlist_call_init(Objlist *list, int *lockstate) * without better locking. */ elm->obj->init_done = true; - wlock_release(rtld_bind_lock, *lockstate); + lock_release(rtld_bind_lock, lockstate); call_initfini_pointer(elm->obj, elm->obj->init); - *lockstate = wlock_acquire(rtld_bind_lock); + wlock_acquire(rtld_bind_lock, lockstate); } errmsg_restore(saved_msg); } @@ -1774,7 +1871,8 @@ objlist_remove(Objlist *list, Obj_Entry *obj) * or -1 on failure. */ static int -relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj) +relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj, + RtldLockState *lockstate) { Obj_Entry *obj; @@ -1799,7 +1897,7 @@ relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj) } /* Process the non-PLT relocations. */ - if (reloc_non_plt(obj, rtldobj)) + if (reloc_non_plt(obj, rtldobj, lockstate)) return -1; if (obj->textrel) { /* Re-protected the text segment. */ @@ -1816,7 +1914,7 @@ relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj) return -1; /* Relocate the jump slots if we are doing immediate binding. */ if (obj->bind_now || bind_now) - if (reloc_jmpslots(obj) == -1) + if (reloc_jmpslots(obj, lockstate) == -1) return -1; @@ -1842,15 +1940,15 @@ relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj) static void rtld_exit(void) { - int lockstate; + RtldLockState lockstate; - lockstate = wlock_acquire(rtld_bind_lock); + wlock_acquire(rtld_bind_lock, &lockstate); dbg("rtld_exit()"); objlist_call_fini(&list_fini, NULL, &lockstate); /* No need to remove the items from the list, since we are exiting. */ if (!libmap_disable) lm_fini(); - wlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); } static void * @@ -1945,12 +2043,12 @@ int dlclose(void *handle) { Obj_Entry *root; - int lockstate; + RtldLockState lockstate; - lockstate = wlock_acquire(rtld_bind_lock); + wlock_acquire(rtld_bind_lock, &lockstate); root = dlcheck(handle); if (root == NULL) { - wlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return -1; } LD_UTRACE(UTRACE_DLCLOSE_START, handle, NULL, 0, root->dl_refcount, @@ -1976,7 +2074,7 @@ dlclose(void *handle) unref_dag(root); LD_UTRACE(UTRACE_DLCLOSE_STOP, handle, NULL, 0, 0, NULL); - wlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return 0; } @@ -2013,25 +2111,36 @@ dllockinit(void *context, void * dlopen(const char *name, int mode) { - Obj_Entry **old_obj_tail; - Obj_Entry *obj; - Objlist initlist; - int result, lockstate, nodelete, lo_flags; + int lo_flags; LD_UTRACE(UTRACE_DLOPEN_START, NULL, NULL, 0, mode, name); ld_tracing = (mode & RTLD_TRACE) == 0 ? NULL : "1"; if (ld_tracing != NULL) environ = (char **)*get_program_var_addr("environ"); - nodelete = mode & RTLD_NODELETE; lo_flags = RTLD_LO_DLOPEN; + if (mode & RTLD_NODELETE) + lo_flags |= RTLD_LO_NODELETE; if (mode & RTLD_NOLOAD) lo_flags |= RTLD_LO_NOLOAD; if (ld_tracing != NULL) lo_flags |= RTLD_LO_TRACE; + return (dlopen_object(name, obj_main, lo_flags, + mode & (RTLD_MODEMASK | RTLD_GLOBAL))); +} + +static Obj_Entry * +dlopen_object(const char *name, Obj_Entry *refobj, int lo_flags, int mode) +{ + Obj_Entry **old_obj_tail; + Obj_Entry *obj; + Objlist initlist; + RtldLockState lockstate; + int result; + objlist_init(&initlist); - lockstate = wlock_acquire(rtld_bind_lock); + wlock_acquire(rtld_bind_lock, &lockstate); GDB_STATE(RT_ADD,NULL); old_obj_tail = obj_tail; @@ -2040,25 +2149,24 @@ dlopen(const char *name, int mode) obj = obj_main; obj->refcount++; } else { - obj = load_object(name, obj_main, lo_flags); + obj = load_object(name, refobj, lo_flags); } if (obj) { obj->dl_refcount++; if (mode & RTLD_GLOBAL && objlist_find(&list_global, obj) == NULL) objlist_push_tail(&list_global, obj); - mode &= RTLD_MODEMASK; if (*old_obj_tail != NULL) { /* We loaded something new. */ assert(*old_obj_tail == obj); - result = load_needed_objects(obj, RTLD_LO_DLOPEN); + result = load_needed_objects(obj, lo_flags & RTLD_LO_DLOPEN); init_dag(obj); ref_dag(obj); if (result != -1) result = rtld_verify_versions(&obj->dagmembers); if (result != -1 && ld_tracing) goto trace; - if (result == -1 || - (relocate_objects(obj, mode == RTLD_NOW, &obj_rtld)) == -1) { + if (result == -1 || (relocate_objects(obj, (mode & RTLD_MODEMASK) + == RTLD_NOW, &obj_rtld, &lockstate)) == -1) { obj->dl_refcount--; unref_dag(obj); if (obj->refcount == 0) @@ -2079,10 +2187,11 @@ dlopen(const char *name, int mode) init_dag(obj); ref_dag(obj); - if (ld_tracing) + if ((lo_flags & RTLD_LO_TRACE) != 0) goto trace; } - if (obj != NULL && (nodelete || obj->z_nodelete) && !obj->ref_nodel) { + if (obj != NULL && ((lo_flags & RTLD_LO_NODELETE) != 0 || + obj->z_nodelete) && !obj->ref_nodel) { dbg("obj %s nodelete", obj->path); ref_dag(obj); obj->z_nodelete = obj->ref_nodel = true; @@ -2096,11 +2205,11 @@ dlopen(const char *name, int mode) /* Call the init functions. */ objlist_call_init(&initlist, &lockstate); objlist_clear(&initlist); - wlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return obj; trace: trace_loaded_objects(obj); - wlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); exit(0); } @@ -2110,36 +2219,46 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve, { DoneList donelist; const Obj_Entry *obj, *defobj; - const Elf_Sym *def, *symp; - unsigned long hash; - int lockstate; + const Elf_Sym *def; + SymLook req; + RtldLockState lockstate; + int res; - hash = elf_hash(name); def = NULL; defobj = NULL; - flags |= SYMLOOK_IN_PLT; - - lockstate = rlock_acquire(rtld_bind_lock); + symlook_init(&req, name); + req.ventry = ve; + req.flags = flags | SYMLOOK_IN_PLT; + req.lockstate = &lockstate; + + rlock_acquire(rtld_bind_lock, &lockstate); + if (setjmp(lockstate.env) != 0) + lock_upgrade(rtld_bind_lock, &lockstate); if (handle == NULL || handle == RTLD_NEXT || handle == RTLD_DEFAULT || handle == RTLD_SELF) { if ((obj = obj_from_addr(retaddr)) == NULL) { _rtld_error("Cannot determine caller's shared object"); - rlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return NULL; } if (handle == NULL) { /* Just the caller's shared object. */ - def = symlook_obj(name, hash, obj, ve, flags); - defobj = obj; + res = symlook_obj(&req, obj); + if (res == 0) { + def = req.sym_out; + defobj = req.defobj_out; + } } else if (handle == RTLD_NEXT || /* Objects after caller's */ handle == RTLD_SELF) { /* ... caller included */ if (handle == RTLD_NEXT) obj = obj->next; for (; obj != NULL; obj = obj->next) { - if ((symp = symlook_obj(name, hash, obj, ve, flags)) != NULL) { - if (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK) { - def = symp; - defobj = obj; + res = symlook_obj(&req, obj); + if (res == 0) { + if (def == NULL || + ELF_ST_BIND(req.sym_out->st_info) != STB_WEAK) { + def = req.sym_out; + defobj = req.defobj_out; if (ELF_ST_BIND(def->st_info) != STB_WEAK) break; } @@ -2151,37 +2270,46 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve, * dynamic linker services such as dlopen. */ if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) { - symp = symlook_obj(name, hash, &obj_rtld, ve, flags); - if (symp != NULL) { - def = symp; - defobj = &obj_rtld; + res = symlook_obj(&req, &obj_rtld); + if (res == 0) { + def = req.sym_out; + defobj = req.defobj_out; } } } else { assert(handle == RTLD_DEFAULT); - def = symlook_default(name, hash, obj, &defobj, ve, flags); + res = symlook_obj(&req, obj); + if (res == 0) { + defobj = req.defobj_out; + def = req.sym_out; + } } } else { if ((obj = dlcheck(handle)) == NULL) { - rlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return NULL; } donelist_init(&donelist); if (obj->mainprog) { /* Search main program and all libraries loaded by it. */ - def = symlook_list(name, hash, &list_main, &defobj, ve, flags, - &donelist); - - /* - * We do not distinguish between 'main' object and global scope. - * If symbol is not defined by objects loaded at startup, continue - * search among dynamically loaded objects with RTLD_GLOBAL - * scope. - */ - if (def == NULL) - def = symlook_list(name, hash, &list_global, &defobj, ve, - flags, &donelist); + res = symlook_list(&req, &list_main, &donelist); + if (res == 0) { + def = req.sym_out; + defobj = req.defobj_out; + } else { + /* + * We do not distinguish between 'main' object and + * global scope. If symbol is not defined by objects + * loaded at startup, continue search among + * dynamically loaded objects with RTLD_GLOBAL scope. + */ + res = symlook_list(&req, &list_global, &donelist); + if (res == 0) { + def = req.sym_out; + defobj = req.defobj_out; + } + } } else { Needed_Entry fake; @@ -2189,13 +2317,16 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve, fake.next = NULL; fake.obj = (Obj_Entry *)obj; fake.name = 0; - def = symlook_needed(name, hash, &fake, &defobj, ve, flags, - &donelist); + res = symlook_needed(&req, &fake, &donelist); + if (res == 0) { + def = req.sym_out; + defobj = req.defobj_out; + } } } if (def != NULL) { - rlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); /* * The value required by the caller is derived from the value @@ -2212,7 +2343,7 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve, } _rtld_error("Undefined symbol \"%s\"", name); - rlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return NULL; } @@ -2253,17 +2384,17 @@ int _rtld_addr_phdr(const void *addr, struct dl_phdr_info *phdr_info) { const Obj_Entry *obj; - int lockstate; + RtldLockState lockstate; - lockstate = rlock_acquire(rtld_bind_lock); + rlock_acquire(rtld_bind_lock, &lockstate); obj = obj_from_addr(addr); if (obj == NULL) { _rtld_error("No shared object contains address"); - rlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return (0); } rtld_fill_dl_phdr_info(obj, phdr_info); - rlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return (1); } @@ -2274,13 +2405,13 @@ dladdr(const void *addr, Dl_info *info) const Elf_Sym *def; void *symbol_addr; unsigned long symoffset; - int lockstate; + RtldLockState lockstate; - lockstate = rlock_acquire(rtld_bind_lock); + rlock_acquire(rtld_bind_lock, &lockstate); obj = obj_from_addr(addr); if (obj == NULL) { _rtld_error("No shared object contains address"); - rlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return 0; } info->dli_fname = obj->path; @@ -2319,7 +2450,7 @@ dladdr(const void *addr, Dl_info *info) if (info->dli_saddr == addr) break; } - rlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return 1; } @@ -2327,9 +2458,10 @@ int dlinfo(void *handle, int request, void *p) { const Obj_Entry *obj; - int error, lockstate; + RtldLockState lockstate; + int error; - lockstate = rlock_acquire(rtld_bind_lock); + rlock_acquire(rtld_bind_lock, &lockstate); if (handle == NULL || handle == RTLD_SELF) { void *retaddr; @@ -2341,7 +2473,7 @@ dlinfo(void *handle, int request, void *p) obj = dlcheck(handle); if (obj == NULL) { - rlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return (-1); } @@ -2364,7 +2496,7 @@ dlinfo(void *handle, int request, void *p) error = -1; } - rlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return (error); } @@ -2389,10 +2521,11 @@ dl_iterate_phdr(__dl_iterate_hdr_callback callback, void *param) { struct dl_phdr_info phdr_info; const Obj_Entry *obj; - int error, bind_lockstate, phdr_lockstate; + RtldLockState bind_lockstate, phdr_lockstate; + int error; - phdr_lockstate = wlock_acquire(rtld_phdr_lock); - bind_lockstate = rlock_acquire(rtld_bind_lock); + wlock_acquire(rtld_phdr_lock, &phdr_lockstate); + rlock_acquire(rtld_bind_lock, &bind_lockstate); error = 0; @@ -2402,8 +2535,8 @@ dl_iterate_phdr(__dl_iterate_hdr_callback callback, void *param) break; } - rlock_release(rtld_bind_lock, bind_lockstate); - wlock_release(rtld_phdr_lock, phdr_lockstate); + lock_release(rtld_bind_lock, &bind_lockstate); + lock_release(rtld_phdr_lock, &phdr_lockstate); return (error); } @@ -2631,20 +2764,16 @@ static const void ** get_program_var_addr(const char *name) { const Obj_Entry *obj; - unsigned long hash; + SymLook req; - hash = elf_hash(name); + symlook_init(&req, name); for (obj = obj_main; obj != NULL; obj = obj->next) { - const Elf_Sym *def; - - if ((def = symlook_obj(name, hash, obj, NULL, 0)) != NULL) { - const void **addr; - - addr = (const void **)(obj->relocbase + def->st_value); - return addr; + if (symlook_obj(&req, obj) == 0) { + return ((const void **)(req.defobj_out->relocbase + + req.sym_out->st_value)); } } - return NULL; + return (NULL); } /* @@ -2669,37 +2798,38 @@ set_program_var(const char *name, const void *value) * no definition was found. Returns a pointer to the Obj_Entry of the * defining object via the reference parameter DEFOBJ_OUT. */ -static const Elf_Sym * -symlook_default(const char *name, unsigned long hash, const Obj_Entry *refobj, - const Obj_Entry **defobj_out, const Ver_Entry *ventry, int flags) +static int +symlook_default(SymLook *req, const Obj_Entry *refobj) { DoneList donelist; const Elf_Sym *def; - const Elf_Sym *symp; - const Obj_Entry *obj; const Obj_Entry *defobj; const Objlist_Entry *elm; + SymLook req1; + int res; def = NULL; defobj = NULL; donelist_init(&donelist); + symlook_init_from_req(&req1, req); /* Look first in the referencing object if linked symbolically. */ if (refobj->symbolic && !donelist_check(&donelist, refobj)) { - symp = symlook_obj(name, hash, refobj, ventry, flags); - if (symp != NULL) { - def = symp; - defobj = refobj; + res = symlook_obj(&req1, refobj); + if (res == 0) { + def = req1.sym_out; + defobj = req1.defobj_out; + assert(defobj != NULL); } } /* Search all objects loaded at program start up. */ if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) { - symp = symlook_list(name, hash, &list_main, &obj, ventry, flags, - &donelist); - if (symp != NULL && - (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { - def = symp; - defobj = obj; + res = symlook_list(&req1, &list_main, &donelist); + if (res == 0 && + (def == NULL || ELF_ST_BIND(req1.sym_out->st_info) != STB_WEAK)) { + def = req1.sym_out; + defobj = req1.defobj_out; + assert(defobj != NULL); } } @@ -2707,12 +2837,12 @@ symlook_default(const char *name, unsigned long hash, const Obj_Entry *refobj, STAILQ_FOREACH(elm, &list_global, link) { if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK) break; - symp = symlook_list(name, hash, &elm->obj->dagmembers, &obj, ventry, - flags, &donelist); - if (symp != NULL && - (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { - def = symp; - defobj = obj; + res = symlook_list(&req1, &elm->obj->dagmembers, &donelist); + if (res == 0 && + (def == NULL || ELF_ST_BIND(req1.sym_out->st_info) != STB_WEAK)) { + def = req1.sym_out; + defobj = req1.defobj_out; + assert(defobj != NULL); } } @@ -2720,12 +2850,12 @@ symlook_default(const char *name, unsigned long hash, const Obj_Entry *refobj, STAILQ_FOREACH(elm, &refobj->dldags, link) { if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK) break; - symp = symlook_list(name, hash, &elm->obj->dagmembers, &obj, ventry, - flags, &donelist); - if (symp != NULL && - (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { - def = symp; - defobj = obj; + res = symlook_list(&req1, &elm->obj->dagmembers, &donelist); + if (res == 0 && + (def == NULL || ELF_ST_BIND(req1.sym_out->st_info) != STB_WEAK)) { + def = req1.sym_out; + defobj = req1.defobj_out; + assert(defobj != NULL); } } @@ -2735,45 +2865,53 @@ symlook_default(const char *name, unsigned long hash, const Obj_Entry *refobj, * dynamic linker services such as dlopen. */ if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) { - symp = symlook_obj(name, hash, &obj_rtld, ventry, flags); - if (symp != NULL) { - def = symp; - defobj = &obj_rtld; + res = symlook_obj(&req1, &obj_rtld); + if (res == 0) { + def = req1.sym_out; + defobj = req1.defobj_out; + assert(defobj != NULL); } } - if (def != NULL) - *defobj_out = defobj; - return def; + if (def != NULL) { + assert(defobj != NULL); + req->defobj_out = defobj; + req->sym_out = def; + return (0); + } + return (ESRCH); } -static const Elf_Sym * -symlook_list(const char *name, unsigned long hash, const Objlist *objlist, - const Obj_Entry **defobj_out, const Ver_Entry *ventry, int flags, - DoneList *dlp) +static int +symlook_list(SymLook *req, const Objlist *objlist, DoneList *dlp) { - const Elf_Sym *symp; const Elf_Sym *def; const Obj_Entry *defobj; const Objlist_Entry *elm; + SymLook req1; + int res; def = NULL; defobj = NULL; STAILQ_FOREACH(elm, objlist, link) { if (donelist_check(dlp, elm->obj)) continue; - if ((symp = symlook_obj(name, hash, elm->obj, ventry, flags)) != NULL) { - if (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK) { - def = symp; - defobj = elm->obj; + symlook_init_from_req(&req1, req); + if ((res = symlook_obj(&req1, elm->obj)) == 0) { + if (def == NULL || ELF_ST_BIND(req1.sym_out->st_info) != STB_WEAK) { + def = req1.sym_out; + defobj = req1.defobj_out; if (ELF_ST_BIND(def->st_info) != STB_WEAK) break; } } } - if (def != NULL) - *defobj_out = defobj; - return def; + if (def != NULL) { + req->sym_out = def; + req->defobj_out = defobj; + return (0); + } + return (ESRCH); } /* @@ -2782,26 +2920,28 @@ symlook_list(const char *name, unsigned long hash, const Objlist *objlist, * breadth-first. Returns a pointer to the symbol, or NULL if no * definition was found. */ -static const Elf_Sym * -symlook_needed(const char *name, unsigned long hash, const Needed_Entry *needed, - const Obj_Entry **defobj_out, const Ver_Entry *ventry, int flags, - DoneList *dlp) +static int +symlook_needed(SymLook *req, const Needed_Entry *needed, DoneList *dlp) { const Elf_Sym *def, *def_w; const Needed_Entry *n; - const Obj_Entry *obj, *defobj, *defobj1; + const Obj_Entry *defobj, *defobj1; + SymLook req1; + int res; def = def_w = NULL; defobj = NULL; + symlook_init_from_req(&req1, req); for (n = needed; n != NULL; n = n->next) { - if ((obj = n->obj) == NULL || - donelist_check(dlp, obj) || - (def = symlook_obj(name, hash, obj, ventry, flags)) == NULL) + if (n->obj == NULL || donelist_check(dlp, n->obj) || + (res = symlook_obj(&req1, n->obj)) != 0) continue; - defobj = obj; + def = req1.sym_out; + defobj = req1.defobj_out; if (ELF_ST_BIND(def->st_info) != STB_WEAK) { - *defobj_out = defobj; - return (def); + req->defobj_out = defobj; + req->sym_out = def; + return (0); } } /* @@ -2809,12 +2949,13 @@ symlook_needed(const char *name, unsigned long hash, const Needed_Entry *needed, * directly needed objects, or found symbol is weak. */ for (n = needed; n != NULL; n = n->next) { - if ((obj = n->obj) == NULL) + if (n->obj == NULL) continue; - def_w = symlook_needed(name, hash, obj->needed, &defobj1, - ventry, flags, dlp); - if (def_w == NULL) + res = symlook_needed(&req1, n->obj->needed, dlp); + if (res != 0) continue; + def_w = req1.sym_out; + defobj1 = req1.defobj_out; if (def == NULL || ELF_ST_BIND(def_w->st_info) != STB_WEAK) { def = def_w; defobj = defobj1; @@ -2822,22 +2963,60 @@ symlook_needed(const char *name, unsigned long hash, const Needed_Entry *needed, if (ELF_ST_BIND(def_w->st_info) != STB_WEAK) break; } - if (def != NULL) - *defobj_out = defobj; - return (def); + if (def != NULL) { + req->sym_out = def; + req->defobj_out = defobj; + return (0); + } + return (ESRCH); } /* * Search the symbol table of a single shared object for a symbol of * the given name and version, if requested. Returns a pointer to the - * symbol, or NULL if no definition was found. + * symbol, or NULL if no definition was found. If the object is + * filter, return filtered symbol from filtee. * * The symbol's hash value is passed in for efficiency reasons; that * eliminates many recomputations of the hash value. */ -const Elf_Sym * -symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj, - const Ver_Entry *ventry, int flags) +int +symlook_obj(SymLook *req, const Obj_Entry *obj) +{ + DoneList donelist; + SymLook req1; + int res, mres; + + mres = symlook_obj1(req, obj); + if (mres == 0) { + if (obj->needed_filtees != NULL) { + load_filtees(__DECONST(Obj_Entry *, obj), 0, req->lockstate); + donelist_init(&donelist); + symlook_init_from_req(&req1, req); + res = symlook_needed(&req1, obj->needed_filtees, &donelist); + if (res == 0) { + req->sym_out = req1.sym_out; + req->defobj_out = req1.defobj_out; + } + return (res); + } + if (obj->needed_aux_filtees != NULL) { + load_filtees(__DECONST(Obj_Entry *, obj), 0, req->lockstate); + donelist_init(&donelist); + symlook_init_from_req(&req1, req); + res = symlook_needed(&req1, obj->needed_aux_filtees, &donelist); + if (res == 0) { + req->sym_out = req1.sym_out; + req->defobj_out = req1.defobj_out; + return (res); + } + } + } + return (mres); +} + +static int +symlook_obj1(SymLook *req, const Obj_Entry *obj) { unsigned long symnum; const Elf_Sym *vsymp; @@ -2845,18 +3024,18 @@ symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj, int vcount; if (obj->buckets == NULL) - return NULL; + return (ESRCH); vsymp = NULL; vcount = 0; - symnum = obj->buckets[hash % obj->nbuckets]; + symnum = obj->buckets[req->hash % obj->nbuckets]; for (; symnum != STN_UNDEF; symnum = obj->chains[symnum]) { const Elf_Sym *symp; const char *strp; if (symnum >= obj->nchains) - return NULL; /* Bad object */ + return (ESRCH); /* Bad object */ symp = obj->symtab + symnum; strp = obj->strtab + symp->st_name; @@ -2872,7 +3051,7 @@ symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj, if (symp->st_shndx != SHN_UNDEF) break; #ifndef __mips__ - else if (((flags & SYMLOOK_IN_PLT) == 0) && + else if (((req->flags & SYMLOOK_IN_PLT) == 0) && (ELF_ST_TYPE(symp->st_info) == STT_FUNC)) break; /* fallthrough */ @@ -2880,10 +3059,10 @@ symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj, default: continue; } - if (name[0] != strp[0] || strcmp(name, strp) != 0) + if (req->name[0] != strp[0] || strcmp(req->name, strp) != 0) continue; - if (ventry == NULL) { + if (req->ventry == NULL) { if (obj->versyms != NULL) { verndx = VER_NDX(obj->versyms[symnum]); if (verndx > obj->vernum) { @@ -2893,7 +3072,7 @@ symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj, } /* * If we are not called from dlsym (i.e. this is a normal - * relocation from unversioned binary, accept the symbol + * relocation from unversioned binary), accept the symbol * immediately if it happens to have first version after * this shared object became versioned. Otherwise, if * symbol is versioned and not hidden, remember it. If it @@ -2902,9 +3081,13 @@ symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj, * end of the function. If symbol is global (verndx < 2) * accept it unconditionally. */ - if ((flags & SYMLOOK_DLSYM) == 0 && verndx == VER_NDX_GIVEN) - return symp; - else if (verndx >= VER_NDX_GIVEN) { + if ((req->flags & SYMLOOK_DLSYM) == 0 && + verndx == VER_NDX_GIVEN) { + req->sym_out = symp; + req->defobj_out = obj; + return (0); + } + else if (verndx >= VER_NDX_GIVEN) { if ((obj->versyms[symnum] & VER_NDX_HIDDEN) == 0) { if (vsymp == NULL) vsymp = symp; @@ -2913,13 +3096,15 @@ symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj, continue; } } - return symp; + req->sym_out = symp; + req->defobj_out = obj; + return (0); } else { if (obj->versyms == NULL) { - if (object_match_name(obj, ventry->name)) { + if (object_match_name(obj, req->ventry->name)) { _rtld_error("%s: object %s should provide version %s for " - "symbol %s", obj_rtld.path, obj->path, ventry->name, - obj->strtab + symnum); + "symbol %s", obj_rtld.path, obj->path, + req->ventry->name, obj->strtab + symnum); continue; } } else { @@ -2929,8 +3114,8 @@ symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj, obj->path, obj->strtab + symnum, verndx); continue; } - if (obj->vertab[verndx].hash != ventry->hash || - strcmp(obj->vertab[verndx].name, ventry->name)) { + if (obj->vertab[verndx].hash != req->ventry->hash || + strcmp(obj->vertab[verndx].name, req->ventry->name)) { /* * Version does not match. Look if this is a global symbol * and if it is not hidden. If global symbol (verndx < 2) @@ -2938,16 +3123,23 @@ symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj, * called by dlvsym, because dlvsym looks for a specific * version and default one is not what dlvsym wants. */ - if ((flags & SYMLOOK_DLSYM) || + if ((req->flags & SYMLOOK_DLSYM) || (obj->versyms[symnum] & VER_NDX_HIDDEN) || (verndx >= VER_NDX_GIVEN)) continue; } } - return symp; + req->sym_out = symp; + req->defobj_out = obj; + return (0); } } - return (vcount == 1) ? vsymp : NULL; + if (vcount == 1) { + req->sym_out = vsymp; + req->defobj_out = obj; + return (0); + } + return (ESRCH); } static void @@ -3071,6 +3263,7 @@ unload_object(Obj_Entry *root) LD_UTRACE(UTRACE_UNLOAD_OBJECT, obj, obj->mapbase, obj->mapsize, 0, obj->path); dbg("unloading \"%s\"", obj->path); + unload_filtees(root); munmap(obj->mapbase, obj->mapsize); linkmap_delete(obj); *linkp = obj->next; @@ -3127,14 +3320,14 @@ void * tls_get_addr_common(Elf_Addr** dtvp, int index, size_t offset) { Elf_Addr* dtv = *dtvp; - int lockstate; + RtldLockState lockstate; /* Check dtv generation in case new modules have arrived */ if (dtv[0] != tls_dtv_generation) { Elf_Addr* newdtv; int to_copy; - lockstate = wlock_acquire(rtld_bind_lock); + wlock_acquire(rtld_bind_lock, &lockstate); newdtv = calloc(1, (tls_max_index + 2) * sizeof(Elf_Addr)); to_copy = dtv[1]; if (to_copy > tls_max_index) @@ -3143,17 +3336,17 @@ tls_get_addr_common(Elf_Addr** dtvp, int index, size_t offset) newdtv[0] = tls_dtv_generation; newdtv[1] = tls_max_index; free(dtv); - wlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); *dtvp = newdtv; } /* Dynamically allocate module TLS if necessary */ if (!dtv[index + 1]) { /* Signal safe, wlock will block out signals. */ - lockstate = wlock_acquire(rtld_bind_lock); + wlock_acquire(rtld_bind_lock, &lockstate); if (!dtv[index + 1]) dtv[index + 1] = (Elf_Addr)allocate_module_tls(index); - wlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); } return (void*) (dtv[index + 1] + offset); } @@ -3429,22 +3622,22 @@ void * _rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign) { void *ret; - int lockstate; + RtldLockState lockstate; - lockstate = wlock_acquire(rtld_bind_lock); + wlock_acquire(rtld_bind_lock, &lockstate); ret = allocate_tls(obj_list, oldtls, tcbsize, tcbalign); - wlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return (ret); } void _rtld_free_tls(void *tcb, size_t tcbsize, size_t tcbalign) { - int lockstate; + RtldLockState lockstate; - lockstate = wlock_acquire(rtld_bind_lock); + wlock_acquire(rtld_bind_lock, &lockstate); free_tls(tcb, tcbsize, tcbalign); - wlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); } static void @@ -3679,6 +3872,28 @@ fetch_ventry(const Obj_Entry *obj, unsigned long symnum) return NULL; } +void +symlook_init(SymLook *dst, const char *name) +{ + + bzero(dst, sizeof(*dst)); + dst->name = name; + dst->hash = elf_hash(name); +} + +static void +symlook_init_from_req(SymLook *dst, const SymLook *src) +{ + + dst->name = src->name; + dst->hash = src->hash; + dst->ventry = src->ventry; + dst->flags = src->flags; + dst->defobj_out = NULL; + dst->sym_out = NULL; + dst->lockstate = src->lockstate; +} + /* * Overrides for libc_pic-provided functions. */ diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h index faa84e2..b70e8b6 100644 --- a/libexec/rtld-elf/rtld.h +++ b/libexec/rtld-elf/rtld.h @@ -34,6 +34,7 @@ #include #include +#include #include #include "rtld_lock.h" @@ -197,6 +198,8 @@ typedef struct Struct_Obj_Entry { char *rpath; /* Search path specified in object */ Needed_Entry *needed; /* Shared objects needed by this one (%) */ + Needed_Entry *needed_filtees; + Needed_Entry *needed_aux_filtees; STAILQ_HEAD(, Struct_Name_Entry) names; /* List of names for this object we know about. */ @@ -219,10 +222,12 @@ typedef struct Struct_Obj_Entry { bool z_origin : 1; /* Process rpath and soname tokens */ bool z_nodelete : 1; /* Do not unload the object and dependencies */ bool z_noopen : 1; /* Do not load on dlopen */ + bool z_loadfltr : 1; /* Immediately load filtees */ bool ref_nodel : 1; /* Refcount increased to prevent dlclose */ bool init_scanned: 1; /* Object is already on init list. */ bool on_fini_list: 1; /* Object is already on fini list. */ bool dag_inited : 1; /* Object has its DAG initialized. */ + bool filtees_loaded : 1; /* Filtees loaded */ struct link_map linkmap; /* For GDB and dlinfo() */ Objlist dldags; /* Object belongs to these dlopened DAGs (%) */ @@ -246,6 +251,8 @@ typedef struct Struct_Obj_Entry { #define RTLD_LO_NOLOAD 0x01 /* dlopen() specified RTLD_NOLOAD. */ #define RTLD_LO_DLOPEN 0x02 /* Load_object() called from dlopen(). */ #define RTLD_LO_TRACE 0x04 /* Only tracing. */ +#define RTLD_LO_NODELETE 0x08 /* Loaded object cannot be closed. */ +#define RTLD_LO_FILTEES 0x10 /* Loading filtee. */ /* * Symbol cache entry used during relocation to avoid multiple lookups @@ -256,6 +263,34 @@ typedef struct Struct_SymCache { const Obj_Entry *obj; /* Shared object which defines it */ } SymCache; +/* + * This structure provides a reentrant way to keep a list of objects and + * check which ones have already been processed in some way. + */ +typedef struct Struct_DoneList { + const Obj_Entry **objs; /* Array of object pointers */ + unsigned int num_alloc; /* Allocated size of the array */ + unsigned int num_used; /* Number of array slots used */ +} DoneList; + +struct Struct_RtldLockState { + int lockstate; + jmp_buf env; +}; + +/* + * The pack of arguments and results for the symbol lookup functions. + */ +typedef struct Struct_SymLook { + const char *name; + unsigned long hash; + const Ver_Entry *ventry; + int flags; + const Obj_Entry *defobj_out; + const Elf_Sym *sym_out; + struct Struct_RtldLockState *lockstate; +} SymLook; + extern void _rtld_error(const char *, ...) __printflike(1, 2); extern Obj_Entry *map_object(int, const char *, const struct stat *); extern void *xcalloc(size_t); @@ -274,14 +309,14 @@ extern void dump_Elf_Rela (Obj_Entry *, const Elf_Rela *, u_long); */ unsigned long elf_hash(const char *); const Elf_Sym *find_symdef(unsigned long, const Obj_Entry *, - const Obj_Entry **, int, SymCache *); + const Obj_Entry **, int, SymCache *, struct Struct_RtldLockState *); void init_pltgot(Obj_Entry *); void lockdflt_init(void); void obj_free(Obj_Entry *); Obj_Entry *obj_new(void); void _rtld_bind_start(void); -const Elf_Sym *symlook_obj(const char *, unsigned long, const Obj_Entry *, - const Ver_Entry *, int); +void symlook_init(SymLook *, const char *); +int symlook_obj(SymLook *, const Obj_Entry *); void *tls_get_addr_common(Elf_Addr** dtvp, int index, size_t offset); void *allocate_tls(Obj_Entry *, void *, size_t, size_t); void free_tls(void *, size_t, size_t); @@ -294,9 +329,9 @@ const Ver_Entry *fetch_ventry(const Obj_Entry *obj, unsigned long); * MD function declarations. */ int do_copy_relocations(Obj_Entry *); -int reloc_non_plt(Obj_Entry *, Obj_Entry *); +int reloc_non_plt(Obj_Entry *, Obj_Entry *, struct Struct_RtldLockState *); int reloc_plt(Obj_Entry *); -int reloc_jmpslots(Obj_Entry *); +int reloc_jmpslots(Obj_Entry *, struct Struct_RtldLockState *); void allocate_initial_tls(Obj_Entry *); #endif /* } */ diff --git a/libexec/rtld-elf/rtld_lock.c b/libexec/rtld-elf/rtld_lock.c index c5e582e..e76a4da 100644 --- a/libexec/rtld-elf/rtld_lock.c +++ b/libexec/rtld-elf/rtld_lock.c @@ -43,7 +43,6 @@ */ #include - #include #include #include @@ -183,44 +182,88 @@ rtld_lock_t rtld_bind_lock = &rtld_locks[0]; rtld_lock_t rtld_libc_lock = &rtld_locks[1]; rtld_lock_t rtld_phdr_lock = &rtld_locks[2]; -int -rlock_acquire(rtld_lock_t lock) +#define print_ebp(str) do {register long ebp asm("ebp"); printf("%s 0x%0lx\n", str, ebp);} while (0) + +void +rlock_acquire(rtld_lock_t lock, RtldLockState *lockstate) { + + if (lockstate == NULL) + return; + if (thread_mask_set(lock->mask) & lock->mask) { - dbg("rlock_acquire: recursed"); - return (0); + dbg("rlock_acquire: recursed"); + lockstate->lockstate = RTLD_LOCK_UNLOCKED; + return; } lockinfo.rlock_acquire(lock->handle); - return (1); + lockstate->lockstate = RTLD_LOCK_RLOCKED; } -int -wlock_acquire(rtld_lock_t lock) +void +wlock_acquire(rtld_lock_t lock, RtldLockState *lockstate) { + + if (lockstate == NULL) + return; + if (thread_mask_set(lock->mask) & lock->mask) { - dbg("wlock_acquire: recursed"); - return (0); + dbg("wlock_acquire: recursed"); + lockstate->lockstate = RTLD_LOCK_UNLOCKED; + return; } lockinfo.wlock_acquire(lock->handle); - return (1); + lockstate->lockstate = RTLD_LOCK_WLOCKED; } void -rlock_release(rtld_lock_t lock, int locked) +lock_release(rtld_lock_t lock, RtldLockState *lockstate) { - if (locked == 0) - return; - thread_mask_clear(lock->mask); - lockinfo.lock_release(lock->handle); + + if (lockstate == NULL) + return; + + switch (lockstate->lockstate) { + case RTLD_LOCK_UNLOCKED: + break; + case RTLD_LOCK_RLOCKED: + case RTLD_LOCK_WLOCKED: + thread_mask_clear(lock->mask); + lockinfo.lock_release(lock->handle); + break; + default: + assert(0); + } } void -wlock_release(rtld_lock_t lock, int locked) +lock_upgrade(rtld_lock_t lock, RtldLockState *lockstate) { - if (locked == 0) - return; - thread_mask_clear(lock->mask); - lockinfo.lock_release(lock->handle); + + if (lockstate == NULL) + return; + + lock_release(lock, lockstate); + wlock_acquire(lock, lockstate); +} + +void +lock_restart_for_upgrade(RtldLockState *lockstate) +{ + + if (lockstate == NULL) + return; + + switch (lockstate->lockstate) { + case RTLD_LOCK_UNLOCKED: + case RTLD_LOCK_WLOCKED: + break; + case RTLD_LOCK_RLOCKED: + longjmp(lockstate->env, 1); + break; + default: + assert(0); + } } void @@ -322,15 +365,24 @@ _rtld_thread_init(struct RtldLockInfo *pli) void _rtld_atfork_pre(int *locks) { + RtldLockState ls[2]; + + wlock_acquire(rtld_phdr_lock, &ls[0]); + rlock_acquire(rtld_bind_lock, &ls[1]); - locks[2] = wlock_acquire(rtld_phdr_lock); - locks[0] = rlock_acquire(rtld_bind_lock); + /* XXXKIB: I am really sorry for this. */ + locks[0] = ls[1].lockstate; + locks[2] = ls[0].lockstate; } void _rtld_atfork_post(int *locks) { + RtldLockState ls[2]; - rlock_release(rtld_bind_lock, locks[0]); - wlock_release(rtld_phdr_lock, locks[2]); + bzero(ls, sizeof(ls)); + ls[0].lockstate = locks[2]; + ls[1].lockstate = locks[0]; + lock_release(rtld_bind_lock, &ls[1]); + lock_release(rtld_phdr_lock, &ls[0]); } diff --git a/libexec/rtld-elf/rtld_lock.h b/libexec/rtld-elf/rtld_lock.h index 6c04e3b..fa63787 100644 --- a/libexec/rtld-elf/rtld_lock.h +++ b/libexec/rtld-elf/rtld_lock.h @@ -57,10 +57,18 @@ extern rtld_lock_t rtld_bind_lock; extern rtld_lock_t rtld_libc_lock; extern rtld_lock_t rtld_phdr_lock; -int rlock_acquire(rtld_lock_t); -int wlock_acquire(rtld_lock_t); -void rlock_release(rtld_lock_t, int); -void wlock_release(rtld_lock_t, int); +#define RTLD_LOCK_UNLOCKED 0 +#define RTLD_LOCK_RLOCKED 1 +#define RTLD_LOCK_WLOCKED 2 + +struct Struct_RtldLockState; +typedef struct Struct_RtldLockState RtldLockState; + +void rlock_acquire(rtld_lock_t, RtldLockState *); +void wlock_acquire(rtld_lock_t, RtldLockState *); +void lock_release(rtld_lock_t, RtldLockState *); +void lock_upgrade(rtld_lock_t, RtldLockState *); +void lock_restart_for_upgrade(RtldLockState *); #endif /* IN_RTLD */ diff --git a/libexec/rtld-elf/sparc64/reloc.c b/libexec/rtld-elf/sparc64/reloc.c index 1b8f1fd..c8d657c 100644 --- a/libexec/rtld-elf/sparc64/reloc.c +++ b/libexec/rtld-elf/sparc64/reloc.c @@ -193,7 +193,7 @@ static const long reloc_target_bitmask[] = { __asm __volatile("flush %0 + %1" : : "r" (va), "I" (offs)); static int reloc_nonplt_object(Obj_Entry *obj, const Elf_Rela *rela, - SymCache *cache); + SymCache *cache, RtldLockState *lockstate); static void install_plt(Elf_Word *pltgot, Elf_Addr proc); extern char _rtld_bind_start_0[]; @@ -206,13 +206,13 @@ do_copy_relocations(Obj_Entry *dstobj) const Elf_Rela *rela; const Elf_Sym *dstsym; const Elf_Sym *srcsym; - const Ver_Entry *ve; void *dstaddr; const void *srcaddr; - Obj_Entry *srcobj; - unsigned long hash; + const Obj_Entry *srcobj, *defobj; + SymLook req; const char *name; size_t size; + int res; assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */ @@ -222,16 +222,20 @@ do_copy_relocations(Obj_Entry *dstobj) dstaddr = (void *)(dstobj->relocbase + rela->r_offset); dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info); name = dstobj->strtab + dstsym->st_name; - hash = elf_hash(name); size = dstsym->st_size; - ve = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); + symlook_init(&req, name); + req.ventry = fetch_ventry(dstobj, + ELF_R_SYM(rela->r_info)); for (srcobj = dstobj->next; srcobj != NULL; - srcobj = srcobj->next) - if ((srcsym = symlook_obj(name, hash, srcobj, - ve, 0)) != NULL) + srcobj = srcobj->next) { + res = symlook_obj(&req, srcobj); + if (res == 0) { + srcsym = req.sym_out; + defobj = req.defobj_out; break; - + } + } if (srcobj == NULL) { _rtld_error("Undefined symbol \"%s\"" "referenced from COPY relocation" @@ -239,7 +243,7 @@ do_copy_relocations(Obj_Entry *dstobj) return (-1); } - srcaddr = (const void *)(srcobj->relocbase + + srcaddr = (const void *)(defobj->relocbase + srcsym->st_value); memcpy(dstaddr, srcaddr, size); } @@ -249,7 +253,7 @@ do_copy_relocations(Obj_Entry *dstobj) } int -reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) +reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate) { const Elf_Rela *relalim; const Elf_Rela *rela; @@ -268,7 +272,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize); for (rela = obj->rela; rela < relalim; rela++) { - if (reloc_nonplt_object(obj, rela, cache) < 0) + if (reloc_nonplt_object(obj, rela, cache, lockstate) < 0) goto done; } r = 0; @@ -279,7 +283,8 @@ done: } static int -reloc_nonplt_object(Obj_Entry *obj, const Elf_Rela *rela, SymCache *cache) +reloc_nonplt_object(Obj_Entry *obj, const Elf_Rela *rela, SymCache *cache, + RtldLockState *lockstate) { const Obj_Entry *defobj; const Elf_Sym *def; @@ -333,7 +338,7 @@ reloc_nonplt_object(Obj_Entry *obj, const Elf_Rela *rela, SymCache *cache) /* Find the symbol */ def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - false, cache); + false, cache, lockstate); if (def == NULL) return (-1); @@ -416,7 +421,7 @@ reloc_plt(Obj_Entry *obj) assert(ELF64_R_TYPE_ID(rela->r_info) == R_SPARC_JMP_SLOT); where = (Elf_Addr *)(obj->relocbase + rela->r_offset); def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - true, NULL); + true, NULL, lockstate); value = (Elf_Addr)(defobj->relocbase + def->st_value); *where = value; } @@ -446,7 +451,7 @@ reloc_plt(Obj_Entry *obj) #define LOVAL(v) ((v) & 0x000003ff) int -reloc_jmpslots(Obj_Entry *obj) +reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate) { const Obj_Entry *defobj; const Elf_Rela *relalim; @@ -460,7 +465,7 @@ reloc_jmpslots(Obj_Entry *obj) assert(ELF64_R_TYPE_ID(rela->r_info) == R_SPARC_JMP_SLOT); where = (Elf_Addr *)(obj->relocbase + rela->r_offset); def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - true, NULL); + true, NULL, lockstate); if (def == NULL) return -1; target = (Elf_Addr)(defobj->relocbase + def->st_value);