summaryrefslogtreecommitdiffstats
path: root/libexec/rtld-elf
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2010-12-25 08:51:20 +0000
committerkib <kib@FreeBSD.org>2010-12-25 08:51:20 +0000
commitcefd8b2a41e4b4bf7a16e2dea1e0c719a30d56a3 (patch)
tree487c080e0cb090d960945a4f112301253d4a6e9f /libexec/rtld-elf
parent377233e6cca2d48c8ecba755aa46304a8ae7731b (diff)
downloadFreeBSD-src-cefd8b2a41e4b4bf7a16e2dea1e0c719a30d56a3.zip
FreeBSD-src-cefd8b2a41e4b4bf7a16e2dea1e0c719a30d56a3.tar.gz
Implement support for ELF filters in rtld. Both normal and auxillary
filters are implemented. Filtees are loaded on demand, unless LD_LOADFLTR environment variable is set or -z loadfltr was specified during the linking. This forces rtld to upgrade read-locked rtld_bind_lock to write lock when it encounters an object with filter during symbol lookup. Consolidate common arguments of the symbol lookup functions in the SymLook structure. Track the state of the rtld locks in the RtldLockState structure. Pass local RtldLockState through the rtld symbol lookup calls to allow lock upgrades. Reviewed by: kan Tested by: Mykola Dzham <i levsha me>, nwhitehorn (powerpc)
Diffstat (limited to 'libexec/rtld-elf')
-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