summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libexec/rtld-elf/amd64/reloc.c46
-rw-r--r--libexec/rtld-elf/arm/reloc.c51
-rw-r--r--libexec/rtld-elf/i386/reloc.c42
-rw-r--r--libexec/rtld-elf/ia64/reloc.c27
-rw-r--r--libexec/rtld-elf/mips/reloc.c13
-rw-r--r--libexec/rtld-elf/powerpc/reloc.c37
-rw-r--r--libexec/rtld-elf/powerpc64/reloc.c37
-rw-r--r--libexec/rtld-elf/rtld.18
-rw-r--r--libexec/rtld-elf/rtld.c713
-rw-r--r--libexec/rtld-elf/rtld.h45
-rw-r--r--libexec/rtld-elf/rtld_lock.c102
-rw-r--r--libexec/rtld-elf/rtld_lock.h16
-rw-r--r--libexec/rtld-elf/sparc64/reloc.c41
13 files changed, 767 insertions, 411 deletions
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 <elf-hints.h>
#include <link.h>
+#include <setjmp.h>
#include <stddef.h>
#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 <sys/param.h>
-
#include <signal.h>
#include <stdlib.h>
#include <time.h>
@@ -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);
OpenPOWER on IntegriCloud