Libraries updates and cleanup
* Updating common/lib * Updating lib/csu * Updating lib/libc * Updating libexec/ld.elf_so * Corrected test on __minix in featuretest to actually follow the meaning of the comment. * Cleaned up _REENTRANT-related defintions. * Disabled -D_REENTRANT for libfetch * Removing some unneeded __NBSD_LIBC defines and tests Change-Id: Ic1394baef74d11b9f86b312f5ff4bbc3cbf72ce2
This commit is contained in:
@@ -1,20 +1,14 @@
|
||||
# $NetBSD: Makefile,v 1.112 2012/08/04 15:17:16 matt Exp $
|
||||
# $NetBSD: Makefile,v 1.114 2012/08/23 21:21:15 joerg Exp $
|
||||
#
|
||||
# NOTE: when changing ld.so, ensure that ldd still compiles.
|
||||
#
|
||||
|
||||
WARNS?=4
|
||||
|
||||
#LSC MINIX until warnings get fixed...
|
||||
NOGCCERROR:=yes
|
||||
|
||||
# This executable needs to be linked dynamically
|
||||
LDSTATIC= -dynamic
|
||||
|
||||
# And the minix gcc currently references /libexec/ld-elf.so.1
|
||||
SYMLINKS+= ${SHLINKINSTALLDIR}/${PROG} /libexec/ld-elf.so.1
|
||||
# Minix Clang binaries references /libexec/ld.elf_so
|
||||
SYMLINKS+= ${SHLINKINSTALLDIR}/${PROG} /libexec/ld.elf_so
|
||||
# And the minix gcc currently references /libexec/ld-elf.so.1
|
||||
SYMLINKS+= ${SHLINKINSTALLDIR}/${PROG} /libexec/ld-elf.so.1
|
||||
|
||||
# This needs to be before bsd.init.mk
|
||||
.if defined(BSD_MK_COMPAT_FILE)
|
||||
@@ -73,7 +67,8 @@ PROG= ld.elf_so
|
||||
CLIBOBJ!= cd ${NETBSDSRCDIR}/lib/libc && ${PRINTOBJDIR}
|
||||
|
||||
SRCS+= rtld.c reloc.c symbol.c xmalloc.c xprintf.c debug.c \
|
||||
map_object.c load.c search.c headers.c paths.c expand.c
|
||||
map_object.c load.c search.c headers.c paths.c expand.c \
|
||||
tls.c symver.c diagassert.c
|
||||
|
||||
.if ${USE_FORT} == "yes"
|
||||
.PATH.c: ${NETBSDSRCDIR}/lib/libc/misc
|
||||
@@ -83,7 +78,7 @@ SRCS+= stack_protector.c
|
||||
.PATH.c: ${NETBSDSRCDIR}/lib/libc/stdlib
|
||||
SRCS+= exit.c
|
||||
|
||||
errlist_concat.h: ${NETBSDSRCDIR}/lib/libc/gen/errlist.awk ${NETBSDSRCDIR}/include/sys/errno.h
|
||||
errlist_concat.h: ${NETBSDSRCDIR}/lib/libc/gen/errlist.awk ${NETBSDSRCDIR}/sys/sys/errno.h
|
||||
${TOOL_AWK} -v concat=1 -f ${.ALLSRC} > ${.TARGET}.tmp && \
|
||||
mv -f ${.TARGET}.tmp ${.TARGET}
|
||||
|
||||
@@ -101,8 +96,8 @@ CPPFLAGS+= -DCOMBRELOC
|
||||
#CPPFLAGS+= -DDEBUG
|
||||
#CPPFLAGS+= -DRTLD_DEBUG
|
||||
#CPPFLAGS+= -DRTLD_DEBUG_RELOC
|
||||
DBG= -g
|
||||
#COPTS= -O3 -fomit-frame-pointer
|
||||
#DBG= -g
|
||||
COPTS= -O3 -fomit-frame-pointer
|
||||
|
||||
.if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "x86_64"
|
||||
COPTS+= -mno-3dnow -mno-mmx -mno-sse -mno-sse2 -mno-sse3
|
||||
|
||||
67
libexec/ld.elf_so/README.TLS
Normal file
67
libexec/ld.elf_so/README.TLS
Normal file
@@ -0,0 +1,67 @@
|
||||
Steps for adding TLS support for a new platform:
|
||||
|
||||
(1) Declare TLS variant in machine/types.h by defining either
|
||||
__HAVE_TLS_VARIANT_I or __HAVE_TLS_VARIANT_II.
|
||||
|
||||
(2) _lwp_makecontext has to set the reserved register or kernel transfer
|
||||
variable in uc_mcontext to the provided value of 'private'. See
|
||||
src/lib/libc/arch/$PLATFORM/gen/_lwp.c.
|
||||
|
||||
This is not possible on the VAX as there is no free space in ucontext_t.
|
||||
This requires either a special version of _lwp_create or versioning
|
||||
everything using ucontext_t. Debug support depends on getting the data from
|
||||
ucontext_t, so the second option is possibly required.
|
||||
|
||||
(3) _lwp_setprivate(2) has to update the same register as
|
||||
_lwp_makecontext uses for the private area pointer. Normally
|
||||
cpu_lwp_setprivate is provided by MD to reflect the kernel view and
|
||||
enabled by defining __HAVE_CPU_LWP_SETPRIVATE in machine/types.h.
|
||||
cpu_setmcontext is responsible for keeping the MI l_private field
|
||||
synchronised by calling lwp_setprivate as needed.
|
||||
|
||||
cpu_switchto has to update the mapping.
|
||||
|
||||
_lwp_setprivate is used for the initial thread, all other threads
|
||||
created by libpthread use _lwp_makecontext for this purpose.
|
||||
|
||||
(4) Provide __tls_get_addr and possible other MD functions for dynamic
|
||||
TLS offset computation. If such alternative entry points exist (currently
|
||||
only i386), also add a weak reference to 0 in src/lib/libc/tls/tls.c.
|
||||
|
||||
The generic implementation can be found in tls.c and is used with
|
||||
__HAVE_COMMON___TLS_GET_ADDR. It depends on ___lwp_getprivate_fast
|
||||
(see below).
|
||||
|
||||
(5) Implement the necessary relocation records in mdreloc.c. There are
|
||||
typically three relocation types found in dynamic binaries:
|
||||
|
||||
(a) R_TYPE(TLS_DTPOFF): Offset inside the module. The common TLS code
|
||||
ensures that the DTV vector points to offset 0 inside the module TLS block.
|
||||
This is normally def->st_value + rela->r_addend.
|
||||
|
||||
(b) R_TYPE(TLS_DTPMOD): Module index.
|
||||
|
||||
(c) R_TYPE(TLS_TPOFF): Static TLS offset. The code has to check whether
|
||||
the static TLS offset for this module has been allocated
|
||||
(defobj->tls_done) and otherwise call _rtld_tls_offset_allocate(). This
|
||||
may fail if no static space is available and the object has been pulled
|
||||
in via dlopen(3).
|
||||
|
||||
For TLS Variant I, this is typically:
|
||||
|
||||
def->st_value + rela->r_addend + defobj->tlsoffset + sizeof(struct tls_tcb)
|
||||
|
||||
e.g. the relocation doesn't include the fixed TCB.
|
||||
|
||||
For TLS Variant II, this is typically:
|
||||
|
||||
def->st_value - defobj->tlsoffset + rela->r_addend
|
||||
|
||||
e.g. starting offset is counting down from the TCB.
|
||||
|
||||
(6) Implement _lwp_getprivate_fast() in machine/mcontext.h and set
|
||||
__HAVE___LWP_GETPRIVATE_FAST in machine/types.h.
|
||||
|
||||
(7) Test using src/tests/lib/libc/tls. Make sure with "objdump -R" that
|
||||
t_tls_dynamic has two TPOFF relocations and h_tls_dlopen.so.1 and
|
||||
libh_tls_dynamic.so.1 have both two DTPMOD and DTPOFF relocations.
|
||||
@@ -1,6 +1,10 @@
|
||||
rtld:
|
||||
* resolve MIPS binding lossage
|
||||
|
||||
TLS:
|
||||
* implement proper allocator for static TLS and support for actively
|
||||
freeing DTV entries.
|
||||
|
||||
binutils/gcc:
|
||||
* alpha: why are there GLOB_DAT relocs in ld.elf_so?
|
||||
* alpha: bogus textrels in rtti info
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $NetBSD: alpha_reloc.c,v 1.38 2010/09/30 09:11:18 skrll Exp $ */
|
||||
/* $NetBSD: alpha_reloc.c,v 1.40 2011/03/31 15:30:31 skrll Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 Wasabi Systems, Inc.
|
||||
@@ -62,10 +62,11 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: alpha_reloc.c,v 1.38 2010/09/30 09:11:18 skrll Exp $");
|
||||
__RCSID("$NetBSD: alpha_reloc.c,v 1.40 2011/03/31 15:30:31 skrll Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/tls.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "rtld.h"
|
||||
@@ -261,6 +262,64 @@ _rtld_relocate_nonplt_objects(Obj_Entry *obj)
|
||||
rdbg(("COPY (avoid in main)"));
|
||||
break;
|
||||
|
||||
case R_TYPE(TPREL64):
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
if (!defobj->tls_done &&
|
||||
_rtld_tls_offset_allocate(obj))
|
||||
return -1;
|
||||
|
||||
tmp = (Elf64_Addr)(def->st_value +
|
||||
sizeof(struct tls_tcb) + defobj->tlsoffset +
|
||||
rela->r_addend);
|
||||
|
||||
if (__predict_true(RELOC_ALIGNED_P(where)))
|
||||
*where = tmp;
|
||||
else
|
||||
store_ptr(where, tmp);
|
||||
|
||||
rdbg(("TPREL64 %s in %s --> %p",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where));
|
||||
|
||||
break;
|
||||
|
||||
case R_TYPE(DTPMOD64):
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
tmp = (Elf64_Addr)defobj->tlsindex;
|
||||
if (__predict_true(RELOC_ALIGNED_P(where)))
|
||||
*where = tmp;
|
||||
else
|
||||
store_ptr(where, tmp);
|
||||
|
||||
rdbg(("DTPMOD64 %s in %s --> %p",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where));
|
||||
|
||||
break;
|
||||
|
||||
case R_TYPE(DTPREL64):
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
tmp = (Elf64_Addr)(def->st_value + rela->r_addend);
|
||||
if (__predict_true(RELOC_ALIGNED_P(where)))
|
||||
*where = tmp;
|
||||
else
|
||||
store_ptr(where, tmp);
|
||||
|
||||
rdbg(("DTPREL64 %s in %s --> %p",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where));
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
rdbg(("sym = %lu, type = %lu, offset = %p, "
|
||||
"addend = %p, contents = %p, symbol = %s",
|
||||
@@ -483,9 +542,11 @@ _rtld_bind(const Obj_Entry *obj, Elf_Addr reloff)
|
||||
Elf_Addr result = 0; /* XXX gcc */
|
||||
int err;
|
||||
|
||||
_rtld_shared_enter();
|
||||
err = _rtld_relocate_plt_object(obj, rela, &result);
|
||||
if (err)
|
||||
_rtld_die();
|
||||
_rtld_shared_exit();
|
||||
|
||||
return (caddr_t)result;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* $NetBSD: mdreloc.c,v 1.34 2010/08/06 16:33:17 joerg Exp $ */
|
||||
/* $NetBSD: mdreloc.c,v 1.37 2011/11/18 16:10:03 joerg Exp $ */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: mdreloc.c,v 1.34 2010/08/06 16:33:17 joerg Exp $");
|
||||
__RCSID("$NetBSD: mdreloc.c,v 1.37 2011/11/18 16:10:03 joerg Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
@@ -179,6 +179,59 @@ _rtld_relocate_nonplt_objects(Obj_Entry *obj)
|
||||
rdbg(("COPY (avoid in main)"));
|
||||
break;
|
||||
|
||||
case R_TYPE(TLS_DTPOFF32):
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
tmp = (Elf_Addr)(def->st_value);
|
||||
if (__predict_true(RELOC_ALIGNED_P(where)))
|
||||
*where = tmp;
|
||||
else
|
||||
store_ptr(where, tmp);
|
||||
|
||||
rdbg(("TLS_DTPOFF32 %s in %s --> %p",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)tmp));
|
||||
|
||||
break;
|
||||
case R_TYPE(TLS_DTPMOD32):
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
tmp = (Elf_Addr)(defobj->tlsindex);
|
||||
if (__predict_true(RELOC_ALIGNED_P(where)))
|
||||
*where = tmp;
|
||||
else
|
||||
store_ptr(where, tmp);
|
||||
|
||||
rdbg(("TLS_DTPMOD32 %s in %s --> %p",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)tmp));
|
||||
|
||||
break;
|
||||
|
||||
case R_TYPE(TLS_TPOFF32):
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
if (!defobj->tls_done &&
|
||||
_rtld_tls_offset_allocate(obj))
|
||||
return -1;
|
||||
|
||||
tmp = (Elf_Addr)def->st_value + defobj->tlsoffset +
|
||||
sizeof(struct tls_tcb);
|
||||
if (__predict_true(RELOC_ALIGNED_P(where)))
|
||||
*where = tmp;
|
||||
else
|
||||
store_ptr(where, tmp);
|
||||
rdbg(("TLS_TPOFF32 %s in %s --> %p",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)tmp));
|
||||
break;
|
||||
|
||||
default:
|
||||
rdbg(("sym = %lu, type = %lu, offset = %p, "
|
||||
"contents = %p, symbol = %s",
|
||||
@@ -254,9 +307,11 @@ _rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
|
||||
Elf_Addr new_value = 0; /* XXX gcc */
|
||||
int err;
|
||||
|
||||
_rtld_shared_enter();
|
||||
err = _rtld_relocate_plt_object(obj, rel, &new_value);
|
||||
if (err)
|
||||
_rtld_die();
|
||||
_rtld_shared_exit();
|
||||
|
||||
return (caddr_t)new_value;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $NetBSD: rtld_start.S,v 1.10 2009/11/11 14:15:41 skrll Exp $ */
|
||||
/* $NetBSD: rtld_start.S,v 1.11 2012/08/13 02:53:25 matt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1998, 2002 The NetBSD Foundation, Inc.
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
#include <machine/asm.h>
|
||||
|
||||
RCSID("$NetBSD: rtld_start.S,v 1.10 2009/11/11 14:15:41 skrll Exp $")
|
||||
RCSID("$NetBSD: rtld_start.S,v 1.11 2012/08/13 02:53:25 matt Exp $")
|
||||
|
||||
.text
|
||||
.align 0
|
||||
@@ -58,9 +58,8 @@ _rtld_start:
|
||||
bl _rtld /* call the shared loader */
|
||||
mov r3, r0 /* save entry point */
|
||||
|
||||
ldr r2, [sp, #0] /* r2 = cleanup */
|
||||
ldr r1, [sp, #4] /* r1 = obj_main */
|
||||
add sp, sp, #8 /* restore stack */
|
||||
ldr r2, [sp], #4 /* pop r2 = cleanup */
|
||||
ldr r1, [sp], #4 /* pop r1 = obj_main */
|
||||
mov r0, r4 /* restore ps_strings */
|
||||
#ifdef _ARM_ARCH_4T
|
||||
bx r3 /* jump to the entry point */
|
||||
@@ -81,7 +80,7 @@ _rtld_start:
|
||||
* lr = &GOT[2]
|
||||
*/
|
||||
_rtld_bind_start:
|
||||
stmdb sp!,{r0-r4,sl,fp}
|
||||
stmdb sp!,{r0-r4,sl,fp} /* 8 byte aligned (lr already saved) */
|
||||
|
||||
sub r1, ip, lr /* r1 = 4 * (n + 1) */
|
||||
sub r1, r1, #4 /* r1 = 4 * n */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $NetBSD: hppa_reloc.c,v 1.34 2010/09/24 11:41:46 skrll Exp $ */
|
||||
/* $NetBSD: hppa_reloc.c,v 1.42 2012/01/06 10:38:57 skrll Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2002, 2004 The NetBSD Foundation, Inc.
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: hppa_reloc.c,v 1.34 2010/09/24 11:41:46 skrll Exp $");
|
||||
__RCSID("$NetBSD: hppa_reloc.c,v 1.42 2012/01/06 10:38:57 skrll Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <stdlib.h>
|
||||
@@ -82,6 +82,30 @@ store_ptr(void *where, Elf_Addr val)
|
||||
(void)memcpy(where, &val, sizeof(val));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
fdc(void *addr)
|
||||
{
|
||||
__asm volatile("fdc %%r0(%%sr0, %0)" : : "r" (addr));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
fic(void *addr)
|
||||
{
|
||||
__asm volatile("fic %%r0(%%sr0,%0)" : : "r" (addr));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
sync(void)
|
||||
{
|
||||
__asm volatile("sync" : : : "memory");
|
||||
}
|
||||
|
||||
#define PLT_STUB_MAGIC1 0x00c0ffee
|
||||
#define PLT_STUB_MAGIC2 0xdeadbeef
|
||||
|
||||
#define PLT_STUB_INSN1 0x0e801081 /* ldw 0(%r20), %r1 */
|
||||
#define PLT_STUB_INSN2 0xe820c000 /* bv %r0(%r1) */
|
||||
|
||||
/*
|
||||
* In the runtime architecture (ABI), PLABEL function pointers are
|
||||
* distinguished from normal function pointers by having the next-least-
|
||||
@@ -114,7 +138,7 @@ static SLIST_HEAD(hppa_plabel_head, _hppa_plabel) hppa_plabel_list
|
||||
* Because I'm hesitant to use NEW while relocating self,
|
||||
* this is a small pool of preallocated PLABELs.
|
||||
*/
|
||||
#define HPPA_PLABEL_PRE (14)
|
||||
#define HPPA_PLABEL_PRE (32)
|
||||
static hppa_plabel hppa_plabel_pre[HPPA_PLABEL_PRE];
|
||||
static int hppa_plabel_pre_next = 0;
|
||||
|
||||
@@ -177,7 +201,7 @@ _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
|
||||
case DT_PLTGOT:
|
||||
pltgot = (Elf_Addr *)
|
||||
(relocbase + dynp->d_un.d_ptr);
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
relalim = (const Elf_Rela *)((const char *)relafirst + relasz);
|
||||
@@ -230,11 +254,11 @@ _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
|
||||
|
||||
plabel = &hppa_plabel_pre[hppa_plabel_pre_next++];
|
||||
|
||||
plabel->hppa_plabel_pc = (Elf_Addr)
|
||||
plabel->hppa_plabel_pc = (Elf_Addr)
|
||||
(relocbase + sym->st_value + rela->r_addend);
|
||||
plabel->hppa_plabel_sl = (Elf_Addr)pltgot;
|
||||
plabel->hppa_plabel_sl = (Elf_Addr)pltgot;
|
||||
|
||||
SLIST_INSERT_HEAD(&hppa_plabel_list, plabel, hppa_plabel_next);
|
||||
SLIST_INSERT_HEAD(&hppa_plabel_list, plabel, hppa_plabel_next);
|
||||
*((Elf_Addr *)where) = (Elf_Addr)(RTLD_MAKE_PLABEL(plabel));
|
||||
}
|
||||
|
||||
@@ -355,7 +379,34 @@ _rtld_function_descriptor_function(const void *addr)
|
||||
void
|
||||
_rtld_setup_pltgot(const Obj_Entry *obj)
|
||||
{
|
||||
__rtld_setup_hppa_pltgot(obj, obj->pltgot);
|
||||
Elf_Word *got = obj->pltgot;
|
||||
|
||||
assert(got[-2] == PLT_STUB_MAGIC1);
|
||||
assert(got[-1] == PLT_STUB_MAGIC2);
|
||||
|
||||
__rtld_setup_hppa_pltgot(obj, got);
|
||||
|
||||
fdc(&got[-2]);
|
||||
fdc(&got[-1]);
|
||||
fdc(&got[1]);
|
||||
sync();
|
||||
fic(&got[-2]);
|
||||
fic(&got[-1]);
|
||||
fic(&got[1]);
|
||||
sync();
|
||||
|
||||
/*
|
||||
* libc makes use of %t1 (%r22) to pass errno values to __cerror. Fixup
|
||||
* the PLT stub to not use %r22.
|
||||
*/
|
||||
got[-7] = PLT_STUB_INSN1;
|
||||
got[-6] = PLT_STUB_INSN2;
|
||||
fdc(&got[-7]);
|
||||
fdc(&got[-6]);
|
||||
sync();
|
||||
fic(&got[-7]);
|
||||
fic(&got[-6]);
|
||||
sync();
|
||||
}
|
||||
|
||||
int
|
||||
@@ -473,6 +524,48 @@ _rtld_relocate_nonplt_objects(Obj_Entry *obj)
|
||||
rdbg(("COPY (avoid in main)"));
|
||||
break;
|
||||
|
||||
case R_TYPE(TLS_TPREL32):
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
if (!defobj->tls_done && _rtld_tls_offset_allocate(obj))
|
||||
return -1;
|
||||
|
||||
*where = (Elf_Addr)(defobj->tlsoffset + def->st_value +
|
||||
rela->r_addend + sizeof(struct tls_tcb));
|
||||
|
||||
rdbg(("TPREL32 %s in %s --> %p in %s",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where, defobj->path));
|
||||
break;
|
||||
|
||||
case R_TYPE(TLS_DTPMOD32):
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
*where = (Elf_Addr)(defobj->tlsindex);
|
||||
|
||||
rdbg(("TLS_DTPMOD32 %s in %s --> %p",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where));
|
||||
|
||||
break;
|
||||
|
||||
case R_TYPE(TLS_DTPOFF32):
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
*where = (Elf_Addr)(def->st_value);
|
||||
|
||||
rdbg(("TLS_DTPOFF32 %s in %s --> %p",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where));
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
rdbg(("sym = %lu, type = %lu, offset = %p, "
|
||||
"addend = %p, contents = %p, symbol = %s",
|
||||
@@ -597,9 +690,11 @@ _rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
|
||||
|
||||
assert(ELF_R_SYM(rela->r_info) != 0);
|
||||
|
||||
_rtld_shared_enter();
|
||||
err = _rtld_relocate_plt_object(obj, rela, &new_value);
|
||||
if (err)
|
||||
_rtld_die();
|
||||
_rtld_shared_exit();
|
||||
|
||||
return (caddr_t)new_value;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $NetBSD: rtld_start.S,v 1.9 2010/09/30 19:32:40 skrll Exp $ */
|
||||
/* $NetBSD: rtld_start.S,v 1.12 2012/01/06 10:38:57 skrll Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2002 The NetBSD Foundation, Inc.
|
||||
@@ -46,7 +46,7 @@ ENTRY($rtld_start,HPPA_FRAME_SIZE)
|
||||
* twice later: once to call _rtld, and again to transfer to the
|
||||
* program's entry point.
|
||||
*/
|
||||
stw %arg0, HPPA_FRAME_ARG(0)(%r3)
|
||||
stw %arg0, HPPA_FRAME_ARG(0)(%r3)
|
||||
|
||||
/*
|
||||
* We can't move to C until we relocate at least the
|
||||
@@ -139,7 +139,7 @@ L$lpc2: addil L'_rtld_bind_start - ($PIC_pcrel$0 - 8), %arg0
|
||||
stw %arg0, -8(%arg1)
|
||||
bv %r0(%rp)
|
||||
stw %r19, -4(%arg1)
|
||||
EXIT(__rtld_hppa_setup_pltgot)
|
||||
EXIT(__rtld_setup_hppa_pltgot)
|
||||
|
||||
/*
|
||||
* In order to support lazy binding, this implementation of _rtld_bind_start is
|
||||
@@ -181,6 +181,7 @@ ENTRY(_rtld_bind_start,HPPA_FRAME_SIZE)
|
||||
/* 0(%r3) is filled with the saved %r3 above */
|
||||
stw %ret0, 4(%r3)
|
||||
stw %ret1, 8(%r3)
|
||||
stw %t1, 12(%r3) /* %r22 */
|
||||
|
||||
/*
|
||||
* The linker PLT stub loads %r20 with (GOT - 8) for the object that
|
||||
@@ -220,6 +221,7 @@ ENTRY(_rtld_bind_start,HPPA_FRAME_SIZE)
|
||||
ldw HPPA_FRAME_ARG(3)(%r3), %arg3
|
||||
ldw 4(%r3), %ret0
|
||||
ldw 8(%r3), %ret1
|
||||
ldw 12(%r3), %t1 /* %r22 */
|
||||
|
||||
/* End stack calling convention. */
|
||||
ldo HPPA_FRAME_SIZE(%r3), %sp
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
/* $NetBSD: mdreloc.c,v 1.32 2010/08/06 16:33:18 joerg Exp $ */
|
||||
/* $NetBSD: mdreloc.c,v 1.34 2011/03/25 18:07:05 joerg Exp $ */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: mdreloc.c,v 1.32 2010/08/06 16:33:18 joerg Exp $");
|
||||
__RCSID("$NetBSD: mdreloc.c,v 1.34 2011/03/25 18:07:05 joerg Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ucontext.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "rtld.h"
|
||||
@@ -119,6 +120,49 @@ _rtld_relocate_nonplt_objects(Obj_Entry *obj)
|
||||
rdbg(("COPY (avoid in main)"));
|
||||
break;
|
||||
|
||||
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
|
||||
case R_TYPE(TLS_TPOFF):
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
if (!defobj->tls_done &&
|
||||
_rtld_tls_offset_allocate(obj))
|
||||
return -1;
|
||||
|
||||
*where = (Elf_Addr)(def->st_value - defobj->tlsoffset);
|
||||
|
||||
rdbg(("TLS_TPOFF %s in %s --> %p",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where));
|
||||
break;
|
||||
|
||||
case R_TYPE(TLS_DTPMOD32):
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
*where = (Elf_Addr)(defobj->tlsindex);
|
||||
|
||||
rdbg(("TLS_DTPMOD32 %s in %s --> %p",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where));
|
||||
break;
|
||||
|
||||
case R_TYPE(TLS_DTPOFF32):
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
*where = (Elf_Addr)(def->st_value);
|
||||
|
||||
rdbg(("TLS_DTPOFF32 %s in %s --> %p",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where));
|
||||
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
rdbg(("sym = %lu, type = %lu, offset = %p, "
|
||||
"contents = %p, symbol = %s",
|
||||
@@ -194,9 +238,11 @@ _rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
|
||||
|
||||
new_value = 0; /* XXX gcc */
|
||||
|
||||
_rtld_shared_enter();
|
||||
err = _rtld_relocate_plt_object(obj, rel, &new_value);
|
||||
if (err)
|
||||
_rtld_die();
|
||||
_rtld_shared_exit();
|
||||
|
||||
return (caddr_t)new_value;
|
||||
}
|
||||
@@ -214,3 +260,27 @@ _rtld_relocate_plt_objects(const Obj_Entry *obj)
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
|
||||
/*
|
||||
* i386 specific GNU variant of __tls_get_addr using register based
|
||||
* argument passing.
|
||||
*/
|
||||
#define DTV_MAX_INDEX(dtv) ((size_t)((dtv)[-1]))
|
||||
|
||||
__dso_public __attribute__((__regparm__(1))) void *
|
||||
___tls_get_addr(void *arg_)
|
||||
{
|
||||
size_t *arg = (size_t *)arg_;
|
||||
void **dtv;
|
||||
struct tls_tcb *tcb = __lwp_getprivate_fast();
|
||||
size_t idx = arg[0], offset = arg[1];
|
||||
|
||||
dtv = tcb->tcb_dtv;
|
||||
|
||||
if (__predict_true(idx < DTV_MAX_INDEX(dtv) && dtv[idx] != NULL))
|
||||
return (uint8_t *)dtv[idx] + offset;
|
||||
|
||||
return _rtld_tls_get_addr(tcb, idx, offset);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/* $NetBSD: mdreloc.c,v 1.27 2010/08/06 16:33:18 joerg Exp $ */
|
||||
/* $NetBSD: mdreloc.c,v 1.29 2011/11/22 15:25:28 joerg Exp $ */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: mdreloc.c,v 1.27 2010/08/06 16:33:18 joerg Exp $");
|
||||
__RCSID("$NetBSD: mdreloc.c,v 1.29 2011/11/22 15:25:28 joerg Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: mdreloc.c,v 1.27 2010/08/06 16:33:18 joerg Exp $");
|
||||
__RCSID("$NetBSD: mdreloc.c,v 1.29 2011/11/22 15:25:28 joerg Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
@@ -126,6 +126,47 @@ _rtld_relocate_nonplt_objects(Obj_Entry *obj)
|
||||
rdbg(("COPY (avoid in main)"));
|
||||
break;
|
||||
|
||||
case R_TYPE(TLS_DTPMOD32):
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
*where = (Elf_Addr)defobj->tlsindex;
|
||||
rdbg(("DTPMOD32 %s in %s --> %p in %s",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where, defobj->path));
|
||||
break;
|
||||
|
||||
case R_TYPE(TLS_DTPREL32):
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
if (!defobj->tls_done && _rtld_tls_offset_allocate(obj))
|
||||
return -1;
|
||||
|
||||
*where = (Elf_Addr)(def->st_value + rela->r_addend
|
||||
- TLS_DTV_OFFSET);
|
||||
rdbg(("DTPREL32 %s in %s --> %p in %s",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where, defobj->path));
|
||||
break;
|
||||
|
||||
case R_TYPE(TLS_TPREL32):
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
if (!defobj->tls_done && _rtld_tls_offset_allocate(obj))
|
||||
return -1;
|
||||
|
||||
*where = (Elf_Addr)(def->st_value + rela->r_addend
|
||||
+ defobj->tlsoffset - TLS_TP_OFFSET);
|
||||
rdbg(("TPREL32 %s in %s --> %p in %s",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where, defobj->path));
|
||||
break;
|
||||
|
||||
default:
|
||||
rdbg(("sym = %lu, type = %lu, offset = %p, "
|
||||
"addend = %p, contents = %p, symbol = %s",
|
||||
@@ -204,9 +245,11 @@ _rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
|
||||
|
||||
result = 0; /* XXX gcc */
|
||||
|
||||
_rtld_shared_enter();
|
||||
err = _rtld_relocate_plt_object(obj, rela, &result);
|
||||
if (err)
|
||||
_rtld_die();
|
||||
_rtld_shared_exit();
|
||||
|
||||
return (caddr_t)result;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $NetBSD: mips_reloc.c,v 1.60 2010/09/24 15:20:52 matt Exp $ */
|
||||
/* $NetBSD: mips_reloc.c,v 1.62 2011/03/25 18:07:05 joerg Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright 1997 Michael L. Hitch <mhitch@montana.edu>
|
||||
@@ -30,11 +30,12 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: mips_reloc.c,v 1.60 2010/09/24 15:20:52 matt Exp $");
|
||||
__RCSID("$NetBSD: mips_reloc.c,v 1.62 2011/03/25 18:07:05 joerg Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/endian.h>
|
||||
#include <sys/tls.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -375,6 +376,79 @@ _rtld_relocate_nonplt_objects(Obj_Entry *obj)
|
||||
break;
|
||||
}
|
||||
|
||||
#if ELFSIZE == 64
|
||||
case R_TYPE(TLS_DTPMOD64):
|
||||
#else
|
||||
case R_TYPE(TLS_DTPMOD32):
|
||||
#endif
|
||||
{
|
||||
Elf_Addr old = load_ptr(where, ELFSIZE / 8);
|
||||
Elf_Addr val = old;
|
||||
|
||||
def = _rtld_find_symdef(r_symndx, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
val += (Elf_Addr)defobj->tlsindex;
|
||||
|
||||
store_ptr(where, val, ELFSIZE / 8);
|
||||
rdbg(("DTPMOD %s in %s --> %p in %s",
|
||||
obj->strtab + obj->symtab[r_symndx].st_name,
|
||||
obj->path, (void *)old, defobj->path));
|
||||
break;
|
||||
}
|
||||
|
||||
#if ELFSIZE == 64
|
||||
case R_TYPE(TLS_DTPREL64):
|
||||
#else
|
||||
case R_TYPE(TLS_DTPREL32):
|
||||
#endif
|
||||
{
|
||||
Elf_Addr old = load_ptr(where, ELFSIZE / 8);
|
||||
Elf_Addr val = old;
|
||||
|
||||
def = _rtld_find_symdef(r_symndx, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
if (!defobj->tls_done && _rtld_tls_offset_allocate(obj))
|
||||
return -1;
|
||||
|
||||
val += (Elf_Addr)def->st_value - TLS_DTV_OFFSET;
|
||||
store_ptr(where, val, ELFSIZE / 8);
|
||||
|
||||
rdbg(("DTPREL %s in %s --> %p in %s",
|
||||
obj->strtab + obj->symtab[r_symndx].st_name,
|
||||
obj->path, (void *)old, defobj->path));
|
||||
break;
|
||||
}
|
||||
|
||||
#if ELFSIZE == 64
|
||||
case R_TYPE(TLS_TPREL64):
|
||||
#else
|
||||
case R_TYPE(TLS_TPREL32):
|
||||
#endif
|
||||
{
|
||||
Elf_Addr old = load_ptr(where, ELFSIZE / 8);
|
||||
Elf_Addr val = old;
|
||||
|
||||
def = _rtld_find_symdef(r_symndx, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
if (!defobj->tls_done && _rtld_tls_offset_allocate(obj))
|
||||
return -1;
|
||||
|
||||
val += (Elf_Addr)(def->st_value + defobj->tlsoffset
|
||||
- TLS_TP_OFFSET);
|
||||
store_ptr(where, val, ELFSIZE / 8);
|
||||
|
||||
rdbg(("TPREL %s in %s --> %p in %s",
|
||||
obj->strtab + obj->symtab[r_symndx].st_name,
|
||||
obj->path, (void *)*where, defobj->path));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
rdbg(("sym = %lu, type = %lu, offset = %p, "
|
||||
"contents = %p, symbol = %s",
|
||||
@@ -431,9 +505,11 @@ _rtld_bind(Elf_Word a0, Elf_Addr a1, Elf_Addr a2, Elf_Addr a3)
|
||||
Elf_Addr new_value = 0; /* XXX gcc */
|
||||
int err;
|
||||
|
||||
_rtld_shared_enter();
|
||||
err = _rtld_relocate_plt_object(obj, a0, &new_value);
|
||||
if (err)
|
||||
_rtld_die();
|
||||
_rtld_shared_exit();
|
||||
|
||||
return (caddr_t)new_value;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $NetBSD: ppc_reloc.c,v 1.46 2011/01/16 01:22:29 matt Exp $ */
|
||||
/* $NetBSD: ppc_reloc.c,v 1.49 2011/03/25 18:07:06 joerg Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (C) 1998 Tsubai Masanari
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: ppc_reloc.c,v 1.46 2011/01/16 01:22:29 matt Exp $");
|
||||
__RCSID("$NetBSD: ppc_reloc.c,v 1.49 2011/03/25 18:07:06 joerg Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <stdarg.h>
|
||||
@@ -82,6 +82,9 @@ _rtld_setup_pltgot(const Obj_Entry *obj)
|
||||
if (obj->gotptr != NULL) {
|
||||
obj->gotptr[1] = (Elf_Addr) _rtld_bind_secureplt_start;
|
||||
obj->gotptr[2] = (Elf_Addr) obj;
|
||||
dbg(("obj %s secure-plt gotptr=%p start=%p obj=%p",
|
||||
obj->path, obj->gotptr,
|
||||
(void *) obj->gotptr[1], (void *) obj->gotptr[2]));
|
||||
} else {
|
||||
Elf_Word *pltcall, *pltresolve;
|
||||
Elf_Word *jmptab;
|
||||
@@ -91,6 +94,10 @@ _rtld_setup_pltgot(const Obj_Entry *obj)
|
||||
if (N > 8192)
|
||||
N += N-8192;
|
||||
|
||||
dbg(("obj %s bss-plt pltgot=%p jmptab=%u start=%p obj=%p",
|
||||
obj->path, obj->pltgot, 18 + N * 2,
|
||||
_rtld_bind_bssplt_start, obj));
|
||||
|
||||
pltcall = obj->pltgot;
|
||||
jmptab = pltcall + 18 + N * 2;
|
||||
|
||||
@@ -197,6 +204,47 @@ _rtld_relocate_nonplt_objects(Obj_Entry *obj)
|
||||
rdbg(("COPY (avoid in main)"));
|
||||
break;
|
||||
|
||||
case R_TYPE(DTPMOD32):
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
*where = (Elf_Addr)defobj->tlsindex;
|
||||
rdbg(("DTPMOD32 %s in %s --> %p in %s",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where, defobj->path));
|
||||
break;
|
||||
|
||||
case R_TYPE(DTPREL32):
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
if (!defobj->tls_done && _rtld_tls_offset_allocate(obj))
|
||||
return -1;
|
||||
|
||||
*where = (Elf_Addr)(def->st_value + rela->r_addend
|
||||
- TLS_DTV_OFFSET);
|
||||
rdbg(("DTPREL32 %s in %s --> %p in %s",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where, defobj->path));
|
||||
break;
|
||||
|
||||
case R_TYPE(TPREL32):
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
if (!defobj->tls_done && _rtld_tls_offset_allocate(obj))
|
||||
return -1;
|
||||
|
||||
*where = (Elf_Addr)(def->st_value + rela->r_addend
|
||||
+ defobj->tlsoffset - TLS_TP_OFFSET);
|
||||
rdbg(("TPREL32 %s in %s --> %p in %s",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where, defobj->path));
|
||||
break;
|
||||
|
||||
default:
|
||||
rdbg(("sym = %lu, type = %lu, offset = %p, "
|
||||
"addend = %p, contents = %p, symbol = %s",
|
||||
@@ -343,15 +391,17 @@ _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, int reloff
|
||||
caddr_t
|
||||
_rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
|
||||
{
|
||||
const Elf_Rela *rela = (const void *)((const char *)obj->pltrela + reloff);
|
||||
const Elf_Rela *rela = obj->pltrela + reloff;
|
||||
Elf_Addr new_value;
|
||||
int err;
|
||||
|
||||
new_value = 0; /* XXX gcc */
|
||||
|
||||
_rtld_shared_enter();
|
||||
err = _rtld_relocate_plt_object(obj, rela, reloff, &new_value);
|
||||
if (err)
|
||||
_rtld_die();
|
||||
_rtld_shared_exit();
|
||||
|
||||
return (caddr_t)new_value;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $NetBSD: rtld_start.S,v 1.14 2011/01/16 01:22:29 matt Exp $ */
|
||||
/* $NetBSD: rtld_start.S,v 1.17 2011/09/26 01:52:22 mrg Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (C) 1998 Tsubai Masanari
|
||||
@@ -84,14 +84,26 @@ END(_rtld_start)
|
||||
* bss-plt expects %r11 to be index of the rela entry.
|
||||
* So for bss-plt, we multiply the index by 12 to get the offset.
|
||||
*/
|
||||
ENTRY_NOPROFILE(_rtld_bind_bssplt_start)
|
||||
slwi %r11,%r11,2
|
||||
add %r0,%r11,%r11
|
||||
add %r11,%r11,%r0
|
||||
ENTRY_NOPROFILE(_rtld_bind_secureplt_start)
|
||||
stwu %r1,-160(%r1)
|
||||
stw %r0,20(%r1)
|
||||
|
||||
/*
|
||||
* Instead of division which is costly we will use multiplicative
|
||||
* inverse. a / n = ((a * inv(n)) >> 32)
|
||||
* where inv(n) = (0x100000000 + n - 1) / n
|
||||
*/
|
||||
mr %r0,%r11
|
||||
lis %r11,0x15555556@h # load multiplicative inverse of 12
|
||||
ori %r11,%r11,0x15555556@l
|
||||
mulhwu %r11,%r11,%r0 # get high half of multiplication
|
||||
|
||||
b 1f
|
||||
ENTRY_NOPROFILE(_rtld_bind_bssplt_start)
|
||||
stwu %r1,-160(%r1)
|
||||
|
||||
stw %r0,20(%r1)
|
||||
1:
|
||||
mflr %r0
|
||||
stw %r0,16(%r1) # save lr
|
||||
mfcr %r0
|
||||
@@ -112,7 +124,7 @@ ENTRY_NOPROFILE(_rtld_bind_secureplt_start)
|
||||
|
||||
addi %r1,%r1,160
|
||||
bctr
|
||||
END(_rtld_bind_start)
|
||||
END(_rtld_bind_secureplt_start)
|
||||
|
||||
.globl _rtld_powerpc_pltcall
|
||||
.globl _rtld_powerpc_pltresolve
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
/* $NetBSD: mdreloc.c,v 1.28 2010/08/06 16:33:18 joerg Exp $ */
|
||||
/* $NetBSD: mdreloc.c,v 1.30 2011/03/25 18:07:06 joerg Exp $ */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: mdreloc.c,v 1.28 2010/08/06 16:33:18 joerg Exp $");
|
||||
__RCSID("$NetBSD: mdreloc.c,v 1.30 2011/03/25 18:07:06 joerg Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: mdreloc.c,v 1.28 2010/08/06 16:33:18 joerg Exp $");
|
||||
__RCSID("$NetBSD: mdreloc.c,v 1.30 2011/03/25 18:07:06 joerg Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/tls.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "rtld.h"
|
||||
@@ -154,6 +155,49 @@ _rtld_relocate_nonplt_objects(Obj_Entry *obj)
|
||||
rdbg(("COPY (avoid in main)"));
|
||||
break;
|
||||
|
||||
case R_TYPE(TLS_DTPOFF32):
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
*where = (Elf_Addr)(def->st_value);
|
||||
|
||||
rdbg(("TLS_DTPOFF32 %s in %s --> %p",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where));
|
||||
|
||||
break;
|
||||
case R_TYPE(TLS_DTPMOD32):
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
*where = (Elf_Addr)(defobj->tlsindex);
|
||||
|
||||
rdbg(("TLS_DTPMOD32 %s in %s --> %p",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where));
|
||||
|
||||
break;
|
||||
|
||||
case R_TYPE(TLS_TPOFF32):
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
if (!defobj->tls_done &&
|
||||
_rtld_tls_offset_allocate(obj))
|
||||
return -1;
|
||||
|
||||
*where = (Elf_Addr)def->st_value +
|
||||
rela->r_addend + defobj->tlsoffset +
|
||||
sizeof(struct tls_tcb);
|
||||
|
||||
rdbg(("TLS_TPOFF32 %s in %s --> %p",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where));
|
||||
break;
|
||||
|
||||
default:
|
||||
rdbg(("sym = %lu, type = %lu, offset = %p, "
|
||||
"addend = %p, contents = %p, symbol = %s",
|
||||
@@ -200,9 +244,11 @@ _rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
|
||||
|
||||
new_value = 0; /* XXX gcc */
|
||||
|
||||
_rtld_shared_enter();
|
||||
err = _rtld_relocate_plt_object(obj, rela, &new_value);
|
||||
if (err)
|
||||
_rtld_die();
|
||||
_rtld_shared_exit();
|
||||
|
||||
return (caddr_t)new_value;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $NetBSD: mdreloc.c,v 1.44 2010/08/06 16:33:18 joerg Exp $ */
|
||||
/* $NetBSD: mdreloc.c,v 1.47 2011/03/31 12:47:01 nakayama Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: mdreloc.c,v 1.44 2010/08/06 16:33:18 joerg Exp $");
|
||||
__RCSID("$NetBSD: mdreloc.c,v 1.47 2011/03/31 12:47:01 nakayama Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <errno.h>
|
||||
@@ -66,7 +66,7 @@ __RCSID("$NetBSD: mdreloc.c,v 1.44 2010/08/06 16:33:18 joerg Exp $");
|
||||
#define _RF_U 0x04000000 /* Unaligned */
|
||||
#define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */
|
||||
#define _RF_RS(s) ( (s) & 0xff) /* right shift */
|
||||
static const int reloc_target_flags[] = {
|
||||
static const int reloc_target_flags[R_TYPE(TLS_TPOFF64)+1] = {
|
||||
0, /* NONE */
|
||||
_RF_S|_RF_A| _RF_SZ(8) | _RF_RS(0), /* RELOC_8 */
|
||||
_RF_S|_RF_A| _RF_SZ(16) | _RF_RS(0), /* RELOC_16 */
|
||||
@@ -91,6 +91,8 @@ static const int reloc_target_flags[] = {
|
||||
_RF_SZ(32) | _RF_RS(0), /* JMP_SLOT */
|
||||
_RF_A| _RF_B| _RF_SZ(32) | _RF_RS(0), /* RELATIVE */
|
||||
_RF_S|_RF_A| _RF_U| _RF_SZ(32) | _RF_RS(0), /* UA_32 */
|
||||
|
||||
/* TLS and 64 bit relocs not listed here... */
|
||||
};
|
||||
|
||||
#ifdef RTLD_DEBUG_RELOC
|
||||
@@ -99,7 +101,22 @@ static const char *reloc_names[] = {
|
||||
"DISP_16", "DISP_32", "WDISP_30", "WDISP_22", "HI22",
|
||||
"22", "13", "LO10", "GOT10", "GOT13",
|
||||
"GOT22", "PC10", "PC22", "WPLT30", "COPY",
|
||||
"GLOB_DAT", "JMP_SLOT", "RELATIVE", "UA_32"
|
||||
"GLOB_DAT", "JMP_SLOT", "RELATIVE", "UA_32",
|
||||
|
||||
/* not used with 32bit userland, besides a few of the TLS ones */
|
||||
"PLT32",
|
||||
"HIPLT22", "LOPLT10", "LOPLT10", "PCPLT22", "PCPLT32",
|
||||
"10", "11", "64", "OLO10", "HH22",
|
||||
"HM10", "LM22", "PC_HH22", "PC_HM10", "PC_LM22",
|
||||
"WDISP16", "WDISP19", "GLOB_JMP", "7", "5", "6",
|
||||
"DISP64", "PLT64", "HIX22", "LOX10", "H44", "M44",
|
||||
"L44", "REGISTER", "UA64", "UA16",
|
||||
"TLS_GD_HI22", "TLS_GD_LO10", "TLS_GD_ADD", "TLS_GD_CALL",
|
||||
"TLS_LDM_HI22", "TLS_LDM_LO10", "TLS_LDM_ADD", "TLS_LDM_CALL",
|
||||
"TLS_LDO_HIX22", "TLS_LDO_LOX10", "TLS_LDO_ADD", "TLS_IE_HI22",
|
||||
"TLS_IE_LO10", "TLS_IE_LD", "TLS_IE_LDX", "TLS_IE_ADD", "TLS_LE_HIX22",
|
||||
"TLS_LE_LOX10", "TLS_DTPMOD32", "TLS_DTPMOD64", "TLS_DTPOFF32",
|
||||
"TLS_DTPOFF64", "TLS_TPOFF32", "TLS_TPOFF64",
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -110,6 +127,7 @@ static const char *reloc_names[] = {
|
||||
#define RELOC_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0)
|
||||
#define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff)
|
||||
#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff)
|
||||
#define RELOC_TLS(t) (t >= R_TYPE(TLS_GD_HI22))
|
||||
|
||||
static const int reloc_target_bitmask[] = {
|
||||
#define _BM(x) (~(-(1ULL << (x))))
|
||||
@@ -208,13 +226,80 @@ _rtld_relocate_nonplt_objects(Obj_Entry *obj)
|
||||
|
||||
/*
|
||||
* We use the fact that relocation types are an `enum'
|
||||
* Note: R_SPARC_6 is currently numerically largest.
|
||||
* Note: R_SPARC_TLS_TPOFF64 is currently numerically largest.
|
||||
*/
|
||||
if (type > R_TYPE(6))
|
||||
if (type > R_TYPE(TLS_TPOFF64))
|
||||
return (-1);
|
||||
|
||||
value = rela->r_addend;
|
||||
|
||||
/*
|
||||
* Handle TLS relocations here, they are different.
|
||||
*/
|
||||
if (RELOC_TLS(type)) {
|
||||
switch (type) {
|
||||
case R_TYPE(TLS_DTPMOD32):
|
||||
def = _rtld_find_symdef(symnum, obj,
|
||||
&defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
*where = (Elf_Addr)defobj->tlsindex;
|
||||
|
||||
rdbg(("TLS_DTPMOD32 %s in %s --> %p",
|
||||
obj->strtab +
|
||||
obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where));
|
||||
|
||||
break;
|
||||
|
||||
case R_TYPE(TLS_DTPOFF32):
|
||||
def = _rtld_find_symdef(symnum, obj,
|
||||
&defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
*where = (Elf_Addr)(def->st_value
|
||||
+ rela->r_addend);
|
||||
|
||||
rdbg(("TLS_DTPOFF32 %s in %s --> %p",
|
||||
obj->strtab +
|
||||
obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where));
|
||||
|
||||
break;
|
||||
|
||||
case R_TYPE(TLS_TPOFF32):
|
||||
def = _rtld_find_symdef(symnum, obj,
|
||||
&defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
if (!defobj->tls_done &&
|
||||
_rtld_tls_offset_allocate(obj))
|
||||
return -1;
|
||||
|
||||
*where = (Elf_Addr)(def->st_value -
|
||||
defobj->tlsoffset +
|
||||
rela->r_addend);
|
||||
|
||||
rdbg(("TLS_TPOFF32 %s in %s --> %p",
|
||||
obj->strtab +
|
||||
obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where));
|
||||
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* If it is no TLS relocation (handled above), we can not
|
||||
* deal with it if it is beyound R_SPARC_6.
|
||||
*/
|
||||
if (type > R_TYPE(6))
|
||||
return (-1);
|
||||
|
||||
/*
|
||||
* Handle relative relocs here, as an optimization.
|
||||
*/
|
||||
@@ -325,9 +410,11 @@ _rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
|
||||
|
||||
value = 0; /* XXX gcc */
|
||||
|
||||
_rtld_shared_enter();
|
||||
err = _rtld_relocate_plt_object(obj, rela, &value);
|
||||
if (err)
|
||||
_rtld_die();
|
||||
_rtld_shared_exit();
|
||||
|
||||
return (caddr_t)value;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $NetBSD: mdreloc.c,v 1.50 2010/09/24 12:00:10 skrll Exp $ */
|
||||
/* $NetBSD: mdreloc.c,v 1.53 2012/07/22 09:21:03 martin Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2000 Eduardo Horvath.
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: mdreloc.c,v 1.50 2010/09/24 12:00:10 skrll Exp $");
|
||||
__RCSID("$NetBSD: mdreloc.c,v 1.53 2012/07/22 09:21:03 martin Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <errno.h>
|
||||
@@ -67,7 +67,7 @@ __RCSID("$NetBSD: mdreloc.c,v 1.50 2010/09/24 12:00:10 skrll Exp $");
|
||||
#define _RF_U 0x04000000 /* Unaligned */
|
||||
#define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */
|
||||
#define _RF_RS(s) ( (s) & 0xff) /* right shift */
|
||||
static const int reloc_target_flags[] = {
|
||||
static const int reloc_target_flags[R_TYPE(TLS_TPOFF64)+1] = {
|
||||
0, /* NONE */
|
||||
_RF_S|_RF_A| _RF_SZ(8) | _RF_RS(0), /* RELOC_8 */
|
||||
_RF_S|_RF_A| _RF_SZ(16) | _RF_RS(0), /* RELOC_16 */
|
||||
@@ -125,6 +125,7 @@ static const int reloc_target_flags[] = {
|
||||
_RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* REGISTER */
|
||||
_RF_S|_RF_A| _RF_U| _RF_SZ(64) | _RF_RS(0), /* UA64 */
|
||||
_RF_S|_RF_A| _RF_U| _RF_SZ(16) | _RF_RS(0), /* UA16 */
|
||||
/* TLS relocs not represented here! */
|
||||
};
|
||||
|
||||
#ifdef RTLD_DEBUG_RELOC
|
||||
@@ -139,7 +140,13 @@ static const char *reloc_names[] = {
|
||||
"HM10", "LM22", "PC_HH22", "PC_HM10", "PC_LM22",
|
||||
"WDISP16", "WDISP19", "GLOB_JMP", "7", "5", "6",
|
||||
"DISP64", "PLT64", "HIX22", "LOX10", "H44", "M44",
|
||||
"L44", "REGISTER", "UA64", "UA16"
|
||||
"L44", "REGISTER", "UA64", "UA16",
|
||||
"TLS_GD_HI22", "TLS_GD_LO10", "TLS_GD_ADD", "TLS_GD_CALL",
|
||||
"TLS_LDM_HI22", "TLS_LDM_LO10", "TLS_LDM_ADD", "TLS_LDM_CALL",
|
||||
"TLS_LDO_HIX22", "TLS_LDO_LOX10", "TLS_LDO_ADD", "TLS_IE_HI22",
|
||||
"TLS_IE_LO10", "TLS_IE_LD", "TLS_IE_LDX", "TLS_IE_ADD", "TLS_LE_HIX22",
|
||||
"TLS_LE_LOX10", "TLS_DTPMOD32", "TLS_DTPMOD64", "TLS_DTPOFF32",
|
||||
"TLS_DTPOFF64", "TLS_TPOFF32", "TLS_TPOFF64",
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -150,6 +157,7 @@ static const char *reloc_names[] = {
|
||||
#define RELOC_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0)
|
||||
#define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff)
|
||||
#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff)
|
||||
#define RELOC_TLS(t) (t >= R_TYPE(TLS_GD_HI22))
|
||||
|
||||
static const long reloc_target_bitmask[] = {
|
||||
#define _BM(x) (~(-(1ULL << (x))))
|
||||
@@ -315,6 +323,10 @@ _rtld_relocate_nonplt_objects(Obj_Entry *obj)
|
||||
if (type == R_TYPE(NONE))
|
||||
continue;
|
||||
|
||||
/* OLO10 relocations have extra info */
|
||||
if ((type & 0x00ff) == R_SPARC_OLO10)
|
||||
type = R_SPARC_OLO10;
|
||||
|
||||
/* We do JMP_SLOTs in _rtld_bind() below */
|
||||
if (type == R_TYPE(JMP_SLOT))
|
||||
continue;
|
||||
@@ -325,13 +337,75 @@ _rtld_relocate_nonplt_objects(Obj_Entry *obj)
|
||||
|
||||
/*
|
||||
* We use the fact that relocation types are an `enum'
|
||||
* Note: R_SPARC_UA16 is currently numerically largest.
|
||||
* Note: R_SPARC_TLS_TPOFF64 is currently numerically largest.
|
||||
*/
|
||||
if (type > R_TYPE(UA16))
|
||||
return (-1);
|
||||
if (type > R_TYPE(TLS_TPOFF64)) {
|
||||
dbg(("unknown relocation type %x at %p", type, rela));
|
||||
return -1;
|
||||
}
|
||||
|
||||
value = rela->r_addend;
|
||||
|
||||
/*
|
||||
* Handle TLS relocations here, they are different.
|
||||
*/
|
||||
if (RELOC_TLS(type)) {
|
||||
switch (type) {
|
||||
case R_TYPE(TLS_DTPMOD64):
|
||||
def = _rtld_find_symdef(symnum, obj,
|
||||
&defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
*where = (Elf64_Addr)defobj->tlsindex;
|
||||
|
||||
rdbg(("TLS_DTPMOD64 %s in %s --> %p",
|
||||
obj->strtab +
|
||||
obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where));
|
||||
|
||||
break;
|
||||
|
||||
case R_TYPE(TLS_DTPOFF64):
|
||||
def = _rtld_find_symdef(symnum, obj,
|
||||
&defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
*where = (Elf64_Addr)(def->st_value
|
||||
+ rela->r_addend);
|
||||
|
||||
rdbg(("DTPOFF64 %s in %s --> %p",
|
||||
obj->strtab +
|
||||
obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where));
|
||||
|
||||
break;
|
||||
|
||||
case R_TYPE(TLS_TPOFF64):
|
||||
def = _rtld_find_symdef(symnum, obj,
|
||||
&defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
if (!defobj->tls_done &&
|
||||
_rtld_tls_offset_allocate(obj))
|
||||
return -1;
|
||||
|
||||
*where = (Elf64_Addr)(def->st_value -
|
||||
defobj->tlsoffset +
|
||||
rela->r_addend);
|
||||
|
||||
rdbg(("TLS_TPOFF64 %s in %s --> %p",
|
||||
obj->strtab +
|
||||
obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where));
|
||||
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle relative relocs here, as an optimization.
|
||||
*/
|
||||
@@ -354,6 +428,11 @@ _rtld_relocate_nonplt_objects(Obj_Entry *obj)
|
||||
value += (Elf_Addr)(defobj->relocbase + def->st_value);
|
||||
}
|
||||
|
||||
if (type == R_SPARC_OLO10) {
|
||||
value = (value & 0x3ff)
|
||||
+ (((Elf64_Xword)rela->r_info<<32)>>40);
|
||||
}
|
||||
|
||||
if (RELOC_PC_RELATIVE(type)) {
|
||||
value -= (Elf_Addr)where;
|
||||
}
|
||||
@@ -471,9 +550,11 @@ _rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
|
||||
rela -= 4;
|
||||
}
|
||||
|
||||
_rtld_shared_enter();
|
||||
err = _rtld_relocate_plt_object(obj, rela, &result);
|
||||
if (err)
|
||||
_rtld_die();
|
||||
_rtld_shared_exit();
|
||||
|
||||
return (caddr_t)result;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/* $NetBSD: mdreloc.c,v 1.27 2010/08/06 16:33:19 joerg Exp $ */
|
||||
/* $NetBSD: mdreloc.c,v 1.28 2011/03/25 18:07:07 joerg Exp $ */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: mdreloc.c,v 1.27 2010/08/06 16:33:19 joerg Exp $");
|
||||
__RCSID("$NetBSD: mdreloc.c,v 1.28 2011/03/25 18:07:07 joerg Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: mdreloc.c,v 1.27 2010/08/06 16:33:19 joerg Exp $");
|
||||
__RCSID("$NetBSD: mdreloc.c,v 1.28 2011/03/25 18:07:07 joerg Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
@@ -187,9 +187,11 @@ _rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
|
||||
|
||||
result = 0; /* XXX gcc */
|
||||
|
||||
_rtld_shared_enter();
|
||||
err = _rtld_relocate_plt_object(obj, rela, &result);
|
||||
if (err)
|
||||
_rtld_die();
|
||||
_rtld_shared_exit();
|
||||
|
||||
return (caddr_t)result;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $NetBSD: mdreloc.c,v 1.38 2010/08/06 16:33:19 joerg Exp $ */
|
||||
/* $NetBSD: mdreloc.c,v 1.40 2011/03/25 18:07:07 joerg Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 Wasabi Systems, Inc.
|
||||
@@ -68,7 +68,7 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: mdreloc.c,v 1.38 2010/08/06 16:33:19 joerg Exp $");
|
||||
__RCSID("$NetBSD: mdreloc.c,v 1.40 2011/03/25 18:07:07 joerg Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
@@ -161,7 +161,7 @@ _rtld_relocate_nonplt_objects(Obj_Entry *obj)
|
||||
*where32 = tmp32;
|
||||
rdbg(("32/32S %s in %s --> %p in %s",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)(unsigned long)*where32,
|
||||
obj->path, (void *)(uintptr_t)*where32,
|
||||
defobj->path));
|
||||
break;
|
||||
case R_TYPE(64): /* word64 S + A */
|
||||
@@ -211,6 +211,50 @@ _rtld_relocate_nonplt_objects(Obj_Entry *obj)
|
||||
(void *)*where64));
|
||||
break;
|
||||
|
||||
case R_TYPE(TPOFF64):
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
if (!defobj->tls_done &&
|
||||
_rtld_tls_offset_allocate(obj))
|
||||
return -1;
|
||||
|
||||
*where64 = (Elf64_Addr)(def->st_value -
|
||||
defobj->tlsoffset + rela->r_addend);
|
||||
|
||||
rdbg(("TPOFF64 %s in %s --> %p",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where64));
|
||||
|
||||
break;
|
||||
|
||||
case R_TYPE(DTPMOD64):
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
*where64 = (Elf64_Addr)defobj->tlsindex;
|
||||
|
||||
rdbg(("DTPMOD64 %s in %s --> %p",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where64));
|
||||
|
||||
break;
|
||||
|
||||
case R_TYPE(DTPOFF64):
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
*where64 = (Elf64_Addr)(def->st_value + rela->r_addend);
|
||||
|
||||
rdbg(("DTPOFF64 %s in %s --> %p",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where64));
|
||||
|
||||
break;
|
||||
|
||||
case R_TYPE(COPY):
|
||||
rdbg(("COPY"));
|
||||
break;
|
||||
@@ -291,9 +335,11 @@ _rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
|
||||
|
||||
new_value = 0; /* XXX GCC4 */
|
||||
|
||||
_rtld_shared_enter();
|
||||
error = _rtld_relocate_plt_object(obj, rela, &new_value);
|
||||
if (error)
|
||||
_rtld_die();
|
||||
_rtld_shared_exit();
|
||||
|
||||
return (caddr_t)new_value;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $NetBSD: rtld_start.S,v 1.8 2010/12/05 00:56:07 joerg Exp $ */
|
||||
/* $NetBSD: rtld_start.S,v 1.9 2011/12/11 22:07:26 joerg Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 Wasabi Systems, Inc.
|
||||
@@ -47,6 +47,8 @@
|
||||
movq %rsp,%r12 # stack pointer arg to _rtld
|
||||
pushq %rbx # save ps_strings
|
||||
|
||||
andq $~15,%rsp # align rsp, to be restored from r12
|
||||
|
||||
leaq _GLOBAL_OFFSET_TABLE_(%rip),%rax
|
||||
leaq _DYNAMIC(%rip),%rdi # &_DYNAMIC
|
||||
movq %rdi,%rbx
|
||||
@@ -59,6 +61,7 @@
|
||||
movq %rbx,%rsi
|
||||
call _rtld # _rtld(sp, relocbase)
|
||||
|
||||
leaq -8(%r12),%rsp # restore saved rsp, including %rbx
|
||||
popq %rbx # %rbx = ps_strings
|
||||
popq %rdx # %rdx = cleanup
|
||||
popq %rcx # %rcx = obj_main
|
||||
|
||||
9
libexec/ld.elf_so/diagassert.c
Normal file
9
libexec/ld.elf_so/diagassert.c
Normal file
@@ -0,0 +1,9 @@
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
__dead void
|
||||
/*ARGSUSED*/
|
||||
__diagassert13(const char *fn, int fl, const char *fu, const char *m)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
@@ -75,8 +75,10 @@ expand(char *buf, const char *execname, int what, size_t bl)
|
||||
{
|
||||
const char *p, *ep;
|
||||
char *bp = buf;
|
||||
#if !defined(__minix)
|
||||
size_t len;
|
||||
char name[32];
|
||||
#endif /* !defined(__minix) */
|
||||
|
||||
switch (what) {
|
||||
case 0: /* HWCAP XXX: Not yet */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $NetBSD: headers.c,v 1.39 2011/01/16 01:22:29 matt Exp $ */
|
||||
/* $NetBSD: headers.c,v 1.43 2012/08/15 03:46:06 matt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright 1996 John D. Polstra.
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: headers.c,v 1.39 2011/01/16 01:22:29 matt Exp $");
|
||||
__RCSID("$NetBSD: headers.c,v 1.43 2012/08/15 03:46:06 matt Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <err.h>
|
||||
@@ -136,6 +136,29 @@ _rtld_digest_dynamic(const char *execname, Obj_Entry *obj)
|
||||
obj->strsize = dynp->d_un.d_val;
|
||||
break;
|
||||
|
||||
case DT_VERNEED:
|
||||
obj->verneed = (const Elf_Verneed *)
|
||||
(obj->relocbase + dynp->d_un.d_ptr);
|
||||
break;
|
||||
|
||||
case DT_VERNEEDNUM:
|
||||
obj->verneednum = dynp->d_un.d_val;
|
||||
break;
|
||||
|
||||
case DT_VERDEF:
|
||||
obj->verdef = (const Elf_Verdef *)
|
||||
(obj->relocbase + dynp->d_un.d_ptr);
|
||||
break;
|
||||
|
||||
case DT_VERDEFNUM:
|
||||
obj->verdefnum = dynp->d_un.d_val;
|
||||
break;
|
||||
|
||||
case DT_VERSYM:
|
||||
obj->versyms = (const Elf_Versym *)
|
||||
(obj->relocbase + dynp->d_un.d_ptr);
|
||||
break;
|
||||
|
||||
case DT_HASH:
|
||||
{
|
||||
const Elf_Symindx *hashtab = (const Elf_Symindx *)
|
||||
@@ -204,10 +227,32 @@ _rtld_digest_dynamic(const char *execname, Obj_Entry *obj)
|
||||
init = dynp->d_un.d_ptr;
|
||||
break;
|
||||
|
||||
#ifdef HAVE_INITFINI_ARRAY
|
||||
case DT_INIT_ARRAY:
|
||||
obj->init_array =
|
||||
(fptr_t *)(obj->relocbase + dynp->d_un.d_ptr);
|
||||
break;
|
||||
|
||||
case DT_INIT_ARRAYSZ:
|
||||
obj->init_arraysz = dynp->d_un.d_val / sizeof(fptr_t);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case DT_FINI:
|
||||
fini = dynp->d_un.d_ptr;
|
||||
break;
|
||||
|
||||
#ifdef HAVE_INITFINI_ARRAY
|
||||
case DT_FINI_ARRAY:
|
||||
obj->fini_array =
|
||||
(fptr_t *)(obj->relocbase + dynp->d_un.d_ptr);
|
||||
break;
|
||||
|
||||
case DT_FINI_ARRAYSZ:
|
||||
obj->fini_arraysz = dynp->d_un.d_val / sizeof(fptr_t);
|
||||
break;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Don't process DT_DEBUG on MIPS as the dynamic section
|
||||
* is mapped read-only. DT_MIPS_RLD_MAP is used instead.
|
||||
@@ -333,7 +378,6 @@ _rtld_digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry)
|
||||
obj->phsize, (long)obj->relocbase));
|
||||
break;
|
||||
}
|
||||
assert(obj->phdr == phdr);
|
||||
|
||||
for (ph = phdr; ph < phlimit; ++ph) {
|
||||
vaddr = (Elf_Addr)(uintptr_t)(obj->relocbase + ph->p_vaddr);
|
||||
@@ -360,6 +404,16 @@ _rtld_digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry)
|
||||
case PT_DYNAMIC:
|
||||
obj->dynamic = (Elf_Dyn *)(uintptr_t)vaddr;
|
||||
break;
|
||||
|
||||
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
|
||||
case PT_TLS:
|
||||
obj->tlsindex = 1;
|
||||
obj->tlssize = ph->p_memsz;
|
||||
obj->tlsalign = ph->p_align;
|
||||
obj->tlsinitsize = ph->p_filesz;
|
||||
obj->tlsinit = (void *)(uintptr_t)ph->p_vaddr;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
assert(nsegs == 2);
|
||||
|
||||
@@ -202,22 +202,24 @@ static bool
|
||||
_rtld_load_by_name(const char *name, Obj_Entry *obj, Needed_Entry **needed,
|
||||
int flags)
|
||||
{
|
||||
#if !defined(__minix)
|
||||
Library_Xform *x = _rtld_xforms;
|
||||
Obj_Entry *o = NULL;
|
||||
size_t j;
|
||||
ssize_t i;
|
||||
#endif /* !defined(__minix) */
|
||||
bool got = false;
|
||||
#if !defined(__minix)
|
||||
union {
|
||||
int i;
|
||||
u_quad_t q;
|
||||
char s[16];
|
||||
} val;
|
||||
#endif /* !defined(__minix) */
|
||||
|
||||
#if !defined(__minix)
|
||||
dbg(("load by name %s %p", name, x));
|
||||
for (; x; x = x->next) {
|
||||
#ifdef __minix
|
||||
continue;
|
||||
#else
|
||||
if (strcmp(x->name, name) != 0)
|
||||
continue;
|
||||
|
||||
@@ -281,8 +283,8 @@ _rtld_load_by_name(const char *name, Obj_Entry *obj, Needed_Entry **needed,
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
#endif /* !defined(__minix) */
|
||||
|
||||
if (got)
|
||||
return true;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $NetBSD: map_object.c,v 1.41 2010/10/16 10:27:07 skrll Exp $ */
|
||||
/* $NetBSD: map_object.c,v 1.45 2012/10/13 21:13:07 dholland Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright 1996 John D. Polstra.
|
||||
@@ -34,11 +34,10 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: map_object.c,v 1.41 2010/10/16 10:27:07 skrll Exp $");
|
||||
__RCSID("$NetBSD: map_object.c,v 1.45 2012/10/13 21:13:07 dholland Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -56,6 +55,10 @@ __RCSID("$NetBSD: map_object.c,v 1.41 2010/10/16 10:27:07 skrll Exp $");
|
||||
|
||||
#define MINIXVERBOSE 0
|
||||
|
||||
#if MINIXVERBOSE
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
static int protflags(int); /* Elf flags -> mmap protection */
|
||||
|
||||
#define EA_UNDEF (~(Elf_Addr)0)
|
||||
@@ -86,13 +89,15 @@ _rtld_map_object(const char *path, int fd, const struct stat *sb)
|
||||
Obj_Entry *obj;
|
||||
Elf_Ehdr *ehdr;
|
||||
Elf_Phdr *phdr;
|
||||
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
|
||||
Elf_Phdr *phtls;
|
||||
#endif
|
||||
size_t phsize;
|
||||
Elf_Phdr *phlimit;
|
||||
Elf_Phdr *segs[2];
|
||||
int nsegs;
|
||||
caddr_t mapbase = MAP_FAILED;
|
||||
size_t mapsize = 0;
|
||||
size_t bsssize = 0;
|
||||
int mapflags;
|
||||
Elf_Off base_offset;
|
||||
#ifdef MAP_ALIGNED
|
||||
@@ -108,10 +113,15 @@ _rtld_map_object(const char *path, int fd, const struct stat *sb)
|
||||
Elf_Addr data_vlimit;
|
||||
int data_flags;
|
||||
caddr_t data_addr;
|
||||
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
|
||||
Elf_Addr tls_vaddr = 0; /* Noise GCC */
|
||||
#endif
|
||||
Elf_Addr phdr_vaddr;
|
||||
size_t phdr_memsz;
|
||||
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
|
||||
caddr_t gap_addr;
|
||||
size_t gap_size;
|
||||
#endif
|
||||
int i;
|
||||
#ifdef RTLD_LOADER
|
||||
Elf_Addr clear_vaddr;
|
||||
@@ -120,7 +130,7 @@ _rtld_map_object(const char *path, int fd, const struct stat *sb)
|
||||
#endif
|
||||
|
||||
if (sb != NULL && sb->st_size < (off_t)sizeof (Elf_Ehdr)) {
|
||||
_rtld_error("%s: unrecognized file format1", path);
|
||||
_rtld_error("%s: not ELF file (too short)", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -149,9 +159,12 @@ _rtld_map_object(const char *path, int fd, const struct stat *sb)
|
||||
goto bad;
|
||||
}
|
||||
/* Make sure the file is valid */
|
||||
if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 ||
|
||||
ehdr->e_ident[EI_CLASS] != ELFCLASS) {
|
||||
_rtld_error("%s: unrecognized file format2 [%x != %x]", path,
|
||||
if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0) {
|
||||
_rtld_error("%s: not ELF file (magic number bad)", path);
|
||||
goto bad;
|
||||
}
|
||||
if (ehdr->e_ident[EI_CLASS] != ELFCLASS) {
|
||||
_rtld_error("%s: invalid ELF class %x; expected %x", path,
|
||||
ehdr->e_ident[EI_CLASS], ELFCLASS);
|
||||
goto bad;
|
||||
}
|
||||
@@ -189,6 +202,9 @@ _rtld_map_object(const char *path, int fd, const struct stat *sb)
|
||||
* in that order.
|
||||
*/
|
||||
phdr = (Elf_Phdr *) ((caddr_t)ehdr + ehdr->e_phoff);
|
||||
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
|
||||
phtls = NULL;
|
||||
#endif
|
||||
phsize = ehdr->e_phnum * sizeof(phdr[0]);
|
||||
obj->phdr = NULL;
|
||||
phdr_vaddr = EA_UNDEF;
|
||||
@@ -206,20 +222,36 @@ _rtld_map_object(const char *path, int fd, const struct stat *sb)
|
||||
if (nsegs < 2)
|
||||
segs[nsegs] = phdr;
|
||||
++nsegs;
|
||||
dbg(("%s: PT_LOAD %p", obj->path, phdr));
|
||||
|
||||
#if ELFSIZE == 64
|
||||
#define PRImemsz PRIu64
|
||||
#else
|
||||
#define PRImemsz PRIu32
|
||||
#endif
|
||||
dbg(("%s: %s %p phsize %" PRImemsz, obj->path, "PT_LOAD",
|
||||
(void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
|
||||
break;
|
||||
|
||||
case PT_PHDR:
|
||||
phdr_vaddr = phdr->p_vaddr;
|
||||
phdr_memsz = phdr->p_memsz;
|
||||
dbg(("%s: PT_PHDR %p phsize %zu", obj->path,
|
||||
(void *)(uintptr_t)phdr_vaddr, phdr_memsz));
|
||||
dbg(("%s: %s %p phsize %" PRImemsz, obj->path, "PT_PHDR",
|
||||
(void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
|
||||
break;
|
||||
|
||||
case PT_DYNAMIC:
|
||||
obj->dynamic = (void *)(uintptr_t)phdr->p_vaddr;
|
||||
dbg(("%s: PT_DYNAMIC %p", obj->path, obj->dynamic));
|
||||
dbg(("%s: %s %p phsize %" PRImemsz, obj->path, "PT_DYNAMIC",
|
||||
(void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
|
||||
break;
|
||||
|
||||
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
|
||||
case PT_TLS:
|
||||
phtls = phdr;
|
||||
dbg(("%s: %s %p phsize %" PRImemsz, obj->path, "PT_TLS",
|
||||
(void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
++phdr;
|
||||
@@ -268,6 +300,17 @@ _rtld_map_object(const char *path, int fd, const struct stat *sb)
|
||||
obj->vaddrbase = base_vaddr;
|
||||
obj->isdynamic = ehdr->e_type == ET_DYN;
|
||||
|
||||
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
|
||||
if (phtls != NULL) {
|
||||
++_rtld_tls_dtv_generation;
|
||||
obj->tlsindex = ++_rtld_tls_max_index;
|
||||
obj->tlssize = phtls->p_memsz;
|
||||
obj->tlsalign = phtls->p_align;
|
||||
obj->tlsinitsize = phtls->p_filesz;
|
||||
tls_vaddr = phtls->p_vaddr;
|
||||
}
|
||||
#endif
|
||||
|
||||
obj->phdr_loaded = false;
|
||||
for (i = 0; i < nsegs; i++) {
|
||||
if (phdr_vaddr != EA_UNDEF &&
|
||||
@@ -355,25 +398,18 @@ _rtld_map_object(const char *path, int fd, const struct stat *sb)
|
||||
_rtld_error("mmap of data failed: %s", xstrerror(errno));
|
||||
goto bad;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __minix
|
||||
bsssize= base_vlimit - data_vlimit;
|
||||
if(bsssize > 0) {
|
||||
/* Overlay the bss segment onto the proper region. */
|
||||
if (mmap(mapbase + data_vlimit - base_vaddr, bsssize,
|
||||
if (mmap(mapbase + data_vlimit - base_vaddr, base_vlimit - data_vlimit,
|
||||
data_flags, MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0) ==
|
||||
MAP_FAILED) {
|
||||
_rtld_error("mmap of bss (at 0x%lx, 0x%lx bytes) failed: %s",
|
||||
mapbase + data_vlimit - base_vaddr, bsssize, xstrerror(errno));
|
||||
_rtld_error("mmap of bss failed: %s", xstrerror(errno));
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
/* Unmap the gap between the text and data. */
|
||||
gap_addr = mapbase + round_up(text_vlimit - base_vaddr);
|
||||
gap_size = data_addr - gap_addr;
|
||||
|
||||
if (gap_size != 0 && mprotect(gap_addr, gap_size, PROT_NONE) == -1) {
|
||||
_rtld_error("mprotect of text -> data gap failed: %s",
|
||||
xstrerror(errno));
|
||||
@@ -390,6 +426,11 @@ _rtld_map_object(const char *path, int fd, const struct stat *sb)
|
||||
/* Non-file portion of BSS mapped above. */
|
||||
#endif
|
||||
|
||||
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
|
||||
if (phtls != NULL)
|
||||
obj->tlsinit = mapbase + tls_vaddr;
|
||||
#endif
|
||||
|
||||
obj->mapbase = mapbase;
|
||||
obj->mapsize = mapsize;
|
||||
obj->relocbase = mapbase - base_vaddr;
|
||||
@@ -419,6 +460,10 @@ _rtld_obj_free(Obj_Entry *obj)
|
||||
{
|
||||
Objlist_Entry *elm;
|
||||
|
||||
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
|
||||
if (obj->tls_done)
|
||||
_rtld_tls_offset_free(obj);
|
||||
#endif
|
||||
xfree(obj->path);
|
||||
while (obj->needed != NULL) {
|
||||
Needed_Entry *needed = obj->needed;
|
||||
|
||||
@@ -61,13 +61,17 @@ __RCSID("$NetBSD: paths.c,v 1.40 2009/05/19 20:44:52 christos Exp $");
|
||||
static Search_Path *_rtld_find_path(Search_Path *, const char *, size_t);
|
||||
static Search_Path **_rtld_append_path(Search_Path **, Search_Path **,
|
||||
const char *, const char *, const char *);
|
||||
#if !defined(__minix)
|
||||
static void _rtld_process_mapping(Library_Xform **, const char *,
|
||||
const char *);
|
||||
#endif /* !defined(__minix) */
|
||||
static char *exstrdup(const char *, const char *);
|
||||
#if !defined(__minix)
|
||||
static const char *getstr(const char **, const char *, const char *);
|
||||
static const char *getcstr(const char **, const char *, const char *);
|
||||
static const char *getword(const char **, const char *, const char *);
|
||||
static int matchstr(const char *, const char *, const char *);
|
||||
#endif /* !defined(__minix) */
|
||||
|
||||
static const char WS[] = " \t\n";
|
||||
|
||||
@@ -86,6 +90,7 @@ exstrdup(const char *bp, const char *ep)
|
||||
return (cp);
|
||||
}
|
||||
|
||||
#if !defined(__minix)
|
||||
/*
|
||||
* Like strsep(), but takes end of string and doesn't put any NUL. To
|
||||
* detect empty string, compare `*p' and return value.
|
||||
@@ -158,6 +163,7 @@ matchstr(const char *p, const char *bp, const char *ep)
|
||||
|
||||
return (*p == 0);
|
||||
}
|
||||
#endif /* !defined(__minix) */
|
||||
|
||||
static Search_Path *
|
||||
_rtld_find_path(Search_Path *path, const char *pathstr, size_t pathlen)
|
||||
@@ -228,6 +234,7 @@ _rtld_add_paths(const char *execname, Search_Path **path_p, const char *pathstr)
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(__minix)
|
||||
/*
|
||||
* Process library mappings of the form:
|
||||
* <library_name> <machdep_variable> <value,...:library_name,...> ...
|
||||
@@ -333,6 +340,7 @@ cleanup:
|
||||
xfree(hwptr->name);
|
||||
xfree(hwptr);
|
||||
}
|
||||
#endif /* !defined(__minix) */
|
||||
|
||||
void
|
||||
_rtld_process_hints(const char *execname, Search_Path **path_p,
|
||||
@@ -349,6 +357,7 @@ _rtld_process_hints(const char *execname, Search_Path **path_p,
|
||||
struct stat st;
|
||||
ssize_t sz;
|
||||
Search_Path **head_p = path_p;
|
||||
|
||||
if ((fd = open(fname, O_RDONLY)) == -1) {
|
||||
/* Don't complain */
|
||||
return;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $NetBSD: reloc.c,v 1.103 2010/12/24 12:41:43 skrll Exp $ */
|
||||
/* $NetBSD: reloc.c,v 1.106 2012/01/06 10:38:56 skrll Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright 1996 John D. Polstra.
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: reloc.c,v 1.103 2010/12/24 12:41:43 skrll Exp $");
|
||||
__RCSID("$NetBSD: reloc.c,v 1.106 2012/01/06 10:38:56 skrll Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <err.h>
|
||||
@@ -73,9 +73,12 @@ _rtld_do_copy_relocation(const Obj_Entry *dstobj, const Elf_Rela *rela)
|
||||
const Elf_Sym *srcsym = NULL;
|
||||
Obj_Entry *srcobj;
|
||||
|
||||
for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next)
|
||||
if ((srcsym = _rtld_symlook_obj(name, hash, srcobj, false)) != NULL)
|
||||
for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next) {
|
||||
srcsym = _rtld_symlook_obj(name, hash, srcobj, 0,
|
||||
_rtld_fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)));
|
||||
if (srcsym != NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
if (srcobj == NULL) {
|
||||
_rtld_error("Undefined symbol \"%s\" referenced from COPY"
|
||||
@@ -199,9 +202,6 @@ _rtld_relocate_objects(Obj_Entry *first, bool bind_now)
|
||||
dbg(("doing lazy PLT binding"));
|
||||
if (_rtld_relocate_plt_lazy(obj) < 0)
|
||||
ok = 0;
|
||||
#if defined(__hppa__)
|
||||
bind_now = 1;
|
||||
#endif
|
||||
if (obj->z_now || bind_now) {
|
||||
dbg(("doing immediate PLT binding"));
|
||||
if (_rtld_relocate_plt_objects(obj) < 0)
|
||||
@@ -214,7 +214,11 @@ _rtld_relocate_objects(Obj_Entry *first, bool bind_now)
|
||||
obj->magic = RTLD_MAGIC;
|
||||
obj->version = RTLD_VERSION;
|
||||
|
||||
/* Fill in the dynamic linker entry points. */
|
||||
/*
|
||||
* Fill in the backwards compatibility dynamic linker entry points.
|
||||
*
|
||||
* DO NOT ADD TO THIS LIST
|
||||
*/
|
||||
obj->dlopen = dlopen;
|
||||
obj->dlsym = dlsym;
|
||||
obj->dlerror = dlerror;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $NetBSD: rtld.c,v 1.137 2010/12/24 12:41:43 skrll Exp $ */
|
||||
/* $NetBSD: rtld.c,v 1.159 2012/10/01 03:03:46 riastradh Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright 1996 John D. Polstra.
|
||||
@@ -44,19 +44,23 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: rtld.c,v 1.137 2010/12/24 12:41:43 skrll Exp $");
|
||||
__RCSID("$NetBSD: rtld.c,v 1.159 2012/10/01 03:03:46 riastradh Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/atomic.h>
|
||||
#include <sys/mman.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#if !defined(__minix)
|
||||
#include <lwp.h>
|
||||
#endif /* !defined(__minix) */
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/mman.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include <ctype.h>
|
||||
@@ -91,6 +95,7 @@ Obj_Entry *_rtld_objmain; /* The main program shared object */
|
||||
Obj_Entry _rtld_objself; /* The dynamic linker shared object */
|
||||
u_int _rtld_objcount; /* Number of objects in _rtld_objlist */
|
||||
u_int _rtld_objloads; /* Number of objects loaded in _rtld_objlist */
|
||||
u_int _rtld_objgen; /* Generation count for _rtld_objlist */
|
||||
const char _rtld_path[] = _PATH_RTLD;
|
||||
|
||||
/* Initialize a fake symbol for resolving undefined weak references. */
|
||||
@@ -104,6 +109,7 @@ Search_Path *_rtld_default_paths;
|
||||
Search_Path *_rtld_paths;
|
||||
|
||||
Library_Xform *_rtld_xforms;
|
||||
static void *auxinfo;
|
||||
|
||||
/*
|
||||
* Global declarations normally provided by crt0.
|
||||
@@ -111,6 +117,10 @@ Library_Xform *_rtld_xforms;
|
||||
char *__progname;
|
||||
char **environ;
|
||||
|
||||
#if !defined(__minix)
|
||||
static volatile bool _rtld_mutex_may_recurse;
|
||||
#endif /* !defined(__minix) */
|
||||
|
||||
#if defined(RTLD_DEBUG)
|
||||
#ifndef __sh__
|
||||
extern Elf_Addr _GLOBAL_OFFSET_TABLE_[];
|
||||
@@ -120,8 +130,8 @@ register Elf_Addr *_GLOBAL_OFFSET_TABLE_ asm("r12");
|
||||
#endif /* RTLD_DEBUG */
|
||||
extern Elf_Dyn _DYNAMIC;
|
||||
|
||||
static void _rtld_call_fini_functions(int);
|
||||
static void _rtld_call_init_functions(void);
|
||||
static void _rtld_call_fini_functions(sigset_t *, int);
|
||||
static void _rtld_call_init_functions(sigset_t *);
|
||||
static void _rtld_initlist_visit(Objlist *, Obj_Entry *, int);
|
||||
static void _rtld_initlist_tsort(Objlist *, int);
|
||||
static Obj_Entry *_rtld_dlcheck(void *);
|
||||
@@ -129,88 +139,169 @@ static void _rtld_init_dag(Obj_Entry *);
|
||||
static void _rtld_init_dag1(Obj_Entry *, Obj_Entry *);
|
||||
static void _rtld_objlist_remove(Objlist *, Obj_Entry *);
|
||||
static void _rtld_objlist_clear(Objlist *);
|
||||
static void _rtld_unload_object(Obj_Entry *, bool);
|
||||
static void _rtld_unload_object(sigset_t *, Obj_Entry *, bool);
|
||||
static void _rtld_unref_dag(Obj_Entry *);
|
||||
static Obj_Entry *_rtld_obj_from_addr(const void *);
|
||||
|
||||
static inline void
|
||||
_rtld_call_initfini_function(fptr_t func, sigset_t *mask)
|
||||
{
|
||||
_rtld_exclusive_exit(mask);
|
||||
(*func)();
|
||||
_rtld_exclusive_enter(mask);
|
||||
}
|
||||
|
||||
static void
|
||||
_rtld_call_fini_functions(int force)
|
||||
_rtld_call_fini_function(Obj_Entry *obj, sigset_t *mask, u_int cur_objgen)
|
||||
{
|
||||
if (obj->fini_arraysz == 0 && (obj->fini == NULL || obj->fini_called)) {
|
||||
return;
|
||||
}
|
||||
if (obj->fini != NULL && !obj->fini_called) {
|
||||
dbg (("calling fini function %s at %p%s", obj->path,
|
||||
(void *)obj->fini,
|
||||
obj->z_initfirst ? " (DF_1_INITFIRST)" : ""));
|
||||
obj->fini_called = 1;
|
||||
_rtld_call_initfini_function(obj->fini, mask);
|
||||
}
|
||||
#ifdef HAVE_INITFINI_ARRAY
|
||||
/*
|
||||
* Now process the fini_array if it exists. Simply go from
|
||||
* start to end. We need to make restartable so just advance
|
||||
* the array pointer and decrement the size each time through
|
||||
* the loop.
|
||||
*/
|
||||
while (obj->fini_arraysz > 0 && _rtld_objgen == cur_objgen) {
|
||||
fptr_t fini = *obj->fini_array++;
|
||||
obj->fini_arraysz--;
|
||||
dbg (("calling fini array function %s at %p%s", obj->path,
|
||||
(void *)fini,
|
||||
obj->z_initfirst ? " (DF_1_INITFIRST)" : ""));
|
||||
_rtld_call_initfini_function(fini, mask);
|
||||
}
|
||||
#endif /* HAVE_INITFINI_ARRAY */
|
||||
}
|
||||
|
||||
static void
|
||||
_rtld_call_fini_functions(sigset_t *mask, int force)
|
||||
{
|
||||
Objlist_Entry *elm;
|
||||
Objlist finilist;
|
||||
Obj_Entry *obj;
|
||||
u_int cur_objgen;
|
||||
|
||||
dbg(("_rtld_call_fini_functions(%d)", force));
|
||||
|
||||
restart:
|
||||
cur_objgen = ++_rtld_objgen;
|
||||
SIMPLEQ_INIT(&finilist);
|
||||
_rtld_initlist_tsort(&finilist, 1);
|
||||
|
||||
/* First pass: objects _not_ marked with DF_1_INITFIRST. */
|
||||
SIMPLEQ_FOREACH(elm, &finilist, link) {
|
||||
obj = elm->obj;
|
||||
if (obj->refcount > 0 && !force) {
|
||||
continue;
|
||||
Obj_Entry * const obj = elm->obj;
|
||||
if (!obj->z_initfirst) {
|
||||
if (obj->refcount > 0 && !force) {
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* XXX This can race against a concurrent dlclose().
|
||||
* XXX In that case, the object could be unmapped before
|
||||
* XXX the fini() call or the fini_array has completed.
|
||||
*/
|
||||
_rtld_call_fini_function(obj, mask, cur_objgen);
|
||||
if (_rtld_objgen != cur_objgen) {
|
||||
dbg(("restarting fini iteration"));
|
||||
_rtld_objlist_clear(&finilist);
|
||||
goto restart;
|
||||
}
|
||||
if (obj->fini == NULL || obj->fini_called || obj->z_initfirst) {
|
||||
continue;
|
||||
}
|
||||
dbg (("calling fini function %s at %p", obj->path,
|
||||
(void *)obj->fini));
|
||||
obj->fini_called = 1;
|
||||
(*obj->fini)();
|
||||
}
|
||||
|
||||
/* Second pass: objects marked with DF_1_INITFIRST. */
|
||||
SIMPLEQ_FOREACH(elm, &finilist, link) {
|
||||
obj = elm->obj;
|
||||
Obj_Entry * const obj = elm->obj;
|
||||
if (obj->refcount > 0 && !force) {
|
||||
continue;
|
||||
}
|
||||
if (obj->fini == NULL || obj->fini_called) {
|
||||
continue;
|
||||
/* XXX See above for the race condition here */
|
||||
_rtld_call_fini_function(obj, mask, cur_objgen);
|
||||
if (_rtld_objgen != cur_objgen) {
|
||||
dbg(("restarting fini iteration"));
|
||||
_rtld_objlist_clear(&finilist);
|
||||
goto restart;
|
||||
}
|
||||
dbg (("calling fini function %s at %p (DF_1_INITFIRST)",
|
||||
obj->path, (void *)obj->fini));
|
||||
obj->fini_called = 1;
|
||||
(*obj->fini)();
|
||||
}
|
||||
|
||||
_rtld_objlist_clear(&finilist);
|
||||
}
|
||||
|
||||
static void
|
||||
_rtld_call_init_functions()
|
||||
_rtld_call_init_function(Obj_Entry *obj, sigset_t *mask, u_int cur_objgen)
|
||||
{
|
||||
if (obj->init_arraysz == 0 && (obj->init_called || obj->init == NULL)) {
|
||||
return;
|
||||
}
|
||||
if (!obj->init_called && obj->init != NULL) {
|
||||
dbg (("calling init function %s at %p%s",
|
||||
obj->path, (void *)obj->init,
|
||||
obj->z_initfirst ? " (DF_1_INITFIRST)" : ""));
|
||||
obj->init_called = 1;
|
||||
_rtld_call_initfini_function(obj->init, mask);
|
||||
}
|
||||
|
||||
#ifdef HAVE_INITFINI_ARRAY
|
||||
/*
|
||||
* Now process the init_array if it exists. Simply go from
|
||||
* start to end. We need to make restartable so just advance
|
||||
* the array pointer and decrement the size each time through
|
||||
* the loop.
|
||||
*/
|
||||
while (obj->init_arraysz > 0 && _rtld_objgen == cur_objgen) {
|
||||
fptr_t init = *obj->init_array++;
|
||||
obj->init_arraysz--;
|
||||
dbg (("calling init_array function %s at %p%s",
|
||||
obj->path, (void *)init,
|
||||
obj->z_initfirst ? " (DF_1_INITFIRST)" : ""));
|
||||
_rtld_call_initfini_function(init, mask);
|
||||
}
|
||||
#endif /* HAVE_INITFINI_ARRAY */
|
||||
}
|
||||
|
||||
static void
|
||||
_rtld_call_init_functions(sigset_t *mask)
|
||||
{
|
||||
Objlist_Entry *elm;
|
||||
Objlist initlist;
|
||||
Obj_Entry *obj;
|
||||
u_int cur_objgen;
|
||||
|
||||
dbg(("_rtld_call_init_functions()"));
|
||||
|
||||
restart:
|
||||
cur_objgen = ++_rtld_objgen;
|
||||
SIMPLEQ_INIT(&initlist);
|
||||
_rtld_initlist_tsort(&initlist, 0);
|
||||
|
||||
/* First pass: objects marked with DF_1_INITFIRST. */
|
||||
SIMPLEQ_FOREACH(elm, &initlist, link) {
|
||||
obj = elm->obj;
|
||||
if (obj->init == NULL || obj->init_called || !obj->z_initfirst) {
|
||||
continue;
|
||||
Obj_Entry * const obj = elm->obj;
|
||||
if (obj->z_initfirst) {
|
||||
_rtld_call_init_function(obj, mask, cur_objgen);
|
||||
if (_rtld_objgen != cur_objgen) {
|
||||
dbg(("restarting init iteration"));
|
||||
_rtld_objlist_clear(&initlist);
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
dbg (("calling init function %s at %p (DF_1_INITFIRST)",
|
||||
obj->path, (void *)obj->init));
|
||||
obj->init_called = 1;
|
||||
(*obj->init)();
|
||||
}
|
||||
|
||||
/* Second pass: all other objects. */
|
||||
SIMPLEQ_FOREACH(elm, &initlist, link) {
|
||||
obj = elm->obj;
|
||||
if (obj->init == NULL || obj->init_called) {
|
||||
continue;
|
||||
_rtld_call_init_function(elm->obj, mask, cur_objgen);
|
||||
if (_rtld_objgen != cur_objgen) {
|
||||
dbg(("restarting init iteration"));
|
||||
_rtld_objlist_clear(&initlist);
|
||||
goto restart;
|
||||
}
|
||||
dbg (("calling init function %s at %p", obj->path,
|
||||
(void *)obj->init));
|
||||
obj->init_called = 1;
|
||||
(*obj->init)();
|
||||
}
|
||||
|
||||
_rtld_objlist_clear(&initlist);
|
||||
@@ -290,9 +381,21 @@ _rtld_init(caddr_t mapbase, caddr_t relocbase, const char *execname)
|
||||
static void
|
||||
_rtld_exit(void)
|
||||
{
|
||||
sigset_t mask;
|
||||
|
||||
dbg(("rtld_exit()"));
|
||||
|
||||
_rtld_call_fini_functions(1);
|
||||
_rtld_exclusive_enter(&mask);
|
||||
|
||||
_rtld_call_fini_functions(&mask, 1);
|
||||
|
||||
_rtld_exclusive_exit(&mask);
|
||||
}
|
||||
|
||||
__dso_public void *
|
||||
_dlauxinfo(void)
|
||||
{
|
||||
return auxinfo;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -317,8 +420,8 @@ _rtld(Elf_Addr *sp, Elf_Addr relocbase)
|
||||
*pAUX_ruid, *pAUX_rgid;
|
||||
const AuxInfo *pAUX_pagesz;
|
||||
char **env, **oenvp;
|
||||
const AuxInfo *aux;
|
||||
const AuxInfo *auxp;
|
||||
Obj_Entry *obj;
|
||||
Elf_Addr *const osp = sp;
|
||||
bool bind_now = 0;
|
||||
const char *ld_bind_now, *ld_preload, *ld_library_path;
|
||||
@@ -328,10 +431,13 @@ _rtld(Elf_Addr *sp, Elf_Addr relocbase)
|
||||
const char **real___progname;
|
||||
const Obj_Entry **real___mainprog_obj;
|
||||
char ***real_environ;
|
||||
sigset_t mask;
|
||||
#ifdef DEBUG
|
||||
int i = 0;
|
||||
const char *ld_debug;
|
||||
#endif
|
||||
#ifdef RTLD_DEBUG
|
||||
int i = 0;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* On entry, the dynamic linker itself has not been relocated yet.
|
||||
@@ -345,8 +451,10 @@ _rtld(Elf_Addr *sp, Elf_Addr relocbase)
|
||||
debug = 1;
|
||||
dbg(("sp = %p, argc = %ld, argv = %p <%s> relocbase %p", sp,
|
||||
(long)sp[2], &sp[3], (char *) sp[3], (void *)relocbase));
|
||||
#if 0
|
||||
dbg(("got is at %p, dynamic is at %p", _GLOBAL_OFFSET_TABLE_,
|
||||
&_DYNAMIC));
|
||||
#endif
|
||||
dbg(("_ctype_ is %p", _ctype_));
|
||||
#endif
|
||||
|
||||
@@ -361,7 +469,7 @@ _rtld(Elf_Addr *sp, Elf_Addr relocbase)
|
||||
dbg(("env[%d] = %p %s", i++, (void *)sp[-1], (char *)sp[-1]));
|
||||
#endif
|
||||
}
|
||||
aux = (const AuxInfo *) sp;
|
||||
auxinfo = (AuxInfo *) sp;
|
||||
|
||||
pAUX_base = pAUX_entry = pAUX_execfd = NULL;
|
||||
pAUX_phdr = pAUX_phent = pAUX_phnum = NULL;
|
||||
@@ -371,7 +479,7 @@ _rtld(Elf_Addr *sp, Elf_Addr relocbase)
|
||||
execname = NULL;
|
||||
|
||||
/* Digest the auxiliary vector. */
|
||||
for (auxp = aux; auxp->a_type != AT_NULL; ++auxp) {
|
||||
for (auxp = auxinfo; auxp->a_type != AT_NULL; ++auxp) {
|
||||
switch (auxp->a_type) {
|
||||
case AT_BASE:
|
||||
pAUX_base = auxp;
|
||||
@@ -575,6 +683,21 @@ _rtld(Elf_Addr *sp, Elf_Addr relocbase)
|
||||
if (_rtld_load_needed_objects(_rtld_objmain, _RTLD_MAIN) == -1)
|
||||
_rtld_die();
|
||||
|
||||
dbg(("checking for required versions"));
|
||||
for (obj = _rtld_objlist; obj != NULL; obj = obj->next) {
|
||||
if (_rtld_verify_object_versions(obj) == -1)
|
||||
_rtld_die();
|
||||
}
|
||||
|
||||
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
|
||||
dbg(("initializing initial Thread Local Storage offsets"));
|
||||
/*
|
||||
* All initial objects get the TLS space from the static block.
|
||||
*/
|
||||
for (obj = _rtld_objlist; obj != NULL; obj = obj->next)
|
||||
_rtld_tls_offset_allocate(obj);
|
||||
#endif
|
||||
|
||||
dbg(("relocating objects"));
|
||||
if (_rtld_relocate_objects(_rtld_objmain, bind_now) == -1)
|
||||
_rtld_die();
|
||||
@@ -583,6 +706,16 @@ _rtld(Elf_Addr *sp, Elf_Addr relocbase)
|
||||
if (_rtld_do_copy_relocations(_rtld_objmain) == -1)
|
||||
_rtld_die();
|
||||
|
||||
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
|
||||
dbg(("initializing Thread Local Storage for main thread"));
|
||||
/*
|
||||
* Set up TLS area for the main thread.
|
||||
* This has to be done after all relocations are processed,
|
||||
* since .tdata may contain relocations.
|
||||
*/
|
||||
_rtld_tls_initial_allocation();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set the __progname, environ and, __mainprog_obj before
|
||||
* calling anything that might use them.
|
||||
@@ -608,12 +741,16 @@ _rtld(Elf_Addr *sp, Elf_Addr relocbase)
|
||||
if (real___mainprog_obj)
|
||||
*real___mainprog_obj = _rtld_objmain;
|
||||
|
||||
_rtld_exclusive_enter(&mask);
|
||||
|
||||
dbg(("calling _init functions"));
|
||||
_rtld_call_init_functions();
|
||||
_rtld_call_init_functions(&mask);
|
||||
|
||||
dbg(("control at program entry point = %p, obj = %p, exit = %p",
|
||||
_rtld_objmain->entry, _rtld_objmain, _rtld_exit));
|
||||
|
||||
_rtld_exclusive_exit(&mask);
|
||||
|
||||
/*
|
||||
* Return with the entry point and the exit procedure in at the top
|
||||
* of stack.
|
||||
@@ -646,7 +783,7 @@ _rtld_dlcheck(void *handle)
|
||||
break;
|
||||
|
||||
if (obj == NULL || obj->dl_refcount == 0) {
|
||||
xwarnx("Invalid shared object handle %p", handle);
|
||||
_rtld_error("Invalid shared object handle %p", handle);
|
||||
return NULL;
|
||||
}
|
||||
return obj;
|
||||
@@ -721,7 +858,7 @@ _rtld_init_dag1(Obj_Entry *root, Obj_Entry *obj)
|
||||
* Note, this is called only for objects loaded by dlopen().
|
||||
*/
|
||||
static void
|
||||
_rtld_unload_object(Obj_Entry *root, bool do_fini_funcs)
|
||||
_rtld_unload_object(sigset_t *mask, Obj_Entry *root, bool do_fini_funcs)
|
||||
{
|
||||
|
||||
_rtld_unref_dag(root);
|
||||
@@ -732,7 +869,7 @@ _rtld_unload_object(Obj_Entry *root, bool do_fini_funcs)
|
||||
|
||||
/* Finalize objects that are about to be unmapped. */
|
||||
if (do_fini_funcs)
|
||||
_rtld_call_fini_functions(0);
|
||||
_rtld_call_fini_functions(mask, 0);
|
||||
|
||||
/* Remove the DAG from all objects' DAG lists. */
|
||||
SIMPLEQ_FOREACH(elm, &root->dagmembers, link)
|
||||
@@ -808,20 +945,31 @@ __strong_alias(__dlclose,dlclose)
|
||||
int
|
||||
dlclose(void *handle)
|
||||
{
|
||||
Obj_Entry *root = _rtld_dlcheck(handle);
|
||||
Obj_Entry *root;
|
||||
sigset_t mask;
|
||||
|
||||
if (root == NULL)
|
||||
dbg(("dlclose of %p", handle));
|
||||
|
||||
_rtld_exclusive_enter(&mask);
|
||||
|
||||
root = _rtld_dlcheck(handle);
|
||||
|
||||
if (root == NULL) {
|
||||
_rtld_exclusive_exit(&mask);
|
||||
return -1;
|
||||
}
|
||||
|
||||
_rtld_debug.r_state = RT_DELETE;
|
||||
_rtld_debug_state();
|
||||
|
||||
--root->dl_refcount;
|
||||
_rtld_unload_object(root, true);
|
||||
_rtld_unload_object(&mask, root, true);
|
||||
|
||||
_rtld_debug.r_state = RT_CONSISTENT;
|
||||
_rtld_debug_state();
|
||||
|
||||
_rtld_exclusive_exit(&mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -844,6 +992,12 @@ dlopen(const char *name, int mode)
|
||||
int flags = _RTLD_DLOPEN;
|
||||
bool nodelete;
|
||||
bool now;
|
||||
sigset_t mask;
|
||||
int result;
|
||||
|
||||
dbg(("dlopen of %s %d", name, mode));
|
||||
|
||||
_rtld_exclusive_enter(&mask);
|
||||
|
||||
flags |= (mode & RTLD_GLOBAL) ? _RTLD_GLOBAL : 0;
|
||||
flags |= (mode & RTLD_NOLOAD) ? _RTLD_NOLOAD : 0;
|
||||
@@ -866,15 +1020,23 @@ dlopen(const char *name, int mode)
|
||||
if (*old_obj_tail != NULL) { /* We loaded something new. */
|
||||
assert(*old_obj_tail == obj);
|
||||
|
||||
if (_rtld_load_needed_objects(obj, flags) == -1 ||
|
||||
(_rtld_init_dag(obj),
|
||||
_rtld_relocate_objects(obj,
|
||||
(now || obj->z_now))) == -1) {
|
||||
_rtld_unload_object(obj, false);
|
||||
result = _rtld_load_needed_objects(obj, flags);
|
||||
if (result != -1) {
|
||||
Objlist_Entry *entry;
|
||||
_rtld_init_dag(obj);
|
||||
SIMPLEQ_FOREACH(entry, &obj->dagmembers, link) {
|
||||
result = _rtld_verify_object_versions(entry->obj);
|
||||
if (result == -1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result == -1 || _rtld_relocate_objects(obj,
|
||||
(now || obj->z_now)) == -1) {
|
||||
_rtld_unload_object(&mask, obj, false);
|
||||
obj->dl_refcount--;
|
||||
obj = NULL;
|
||||
} else {
|
||||
_rtld_call_init_functions();
|
||||
_rtld_call_init_functions(&mask);
|
||||
}
|
||||
}
|
||||
if (obj != NULL) {
|
||||
@@ -888,6 +1050,8 @@ dlopen(const char *name, int mode)
|
||||
_rtld_debug.r_state = RT_CONSISTENT;
|
||||
_rtld_debug_state();
|
||||
|
||||
_rtld_exclusive_exit(&mask);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -906,8 +1070,8 @@ _rtld_objmain_sym(const char *name)
|
||||
obj = _rtld_objmain;
|
||||
_rtld_donelist_init(&donelist);
|
||||
|
||||
def = _rtld_symlook_list(name, hash, &_rtld_list_main, &obj, false,
|
||||
&donelist);
|
||||
def = _rtld_symlook_list(name, hash, &_rtld_list_main, &obj, 0,
|
||||
NULL, &donelist);
|
||||
|
||||
if (def != NULL)
|
||||
return obj->relocbase + def->st_value;
|
||||
@@ -922,17 +1086,29 @@ hackish_return_address(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
__strong_alias(__dlsym,dlsym)
|
||||
void *
|
||||
dlsym(void *handle, const char *name)
|
||||
#ifdef __HAVE_FUNCTION_DESCRIPTORS
|
||||
#define lookup_mutex_enter() _rtld_exclusive_enter(&mask)
|
||||
#define lookup_mutex_exit() _rtld_exclusive_exit(&mask)
|
||||
#else
|
||||
#define lookup_mutex_enter() _rtld_shared_enter()
|
||||
#define lookup_mutex_exit() _rtld_shared_exit()
|
||||
#endif
|
||||
|
||||
static void *
|
||||
do_dlsym(void *handle, const char *name, const Ver_Entry *ventry, void *retaddr)
|
||||
{
|
||||
const Obj_Entry *obj;
|
||||
unsigned long hash;
|
||||
const Elf_Sym *def;
|
||||
const Obj_Entry *defobj;
|
||||
void *retaddr;
|
||||
DoneList donelist;
|
||||
|
||||
DoneList donelist;
|
||||
const u_int flags = SYMLOOK_DLSYM | SYMLOOK_IN_PLT;
|
||||
#ifdef __HAVE_FUNCTION_DESCRIPTORS
|
||||
sigset_t mask;
|
||||
#endif
|
||||
|
||||
lookup_mutex_enter();
|
||||
|
||||
hash = _rtld_elf_hash(name);
|
||||
def = NULL;
|
||||
defobj = NULL;
|
||||
@@ -942,19 +1118,15 @@ dlsym(void *handle, const char *name)
|
||||
case (intptr_t)RTLD_NEXT:
|
||||
case (intptr_t)RTLD_DEFAULT:
|
||||
case (intptr_t)RTLD_SELF:
|
||||
#ifdef __powerpc__
|
||||
retaddr = hackish_return_address();
|
||||
#else
|
||||
retaddr = __builtin_return_address(0);
|
||||
#endif
|
||||
if ((obj = _rtld_obj_from_addr(retaddr)) == NULL) {
|
||||
_rtld_error("Cannot determine caller's shared object");
|
||||
lookup_mutex_exit();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch ((intptr_t)handle) {
|
||||
case (intptr_t)NULL: /* Just the caller's shared object. */
|
||||
def = _rtld_symlook_obj(name, hash, obj, false);
|
||||
def = _rtld_symlook_obj(name, hash, obj, flags, ventry);
|
||||
defobj = obj;
|
||||
break;
|
||||
|
||||
@@ -965,7 +1137,7 @@ dlsym(void *handle, const char *name)
|
||||
case (intptr_t)RTLD_SELF: /* Caller included */
|
||||
for (; obj; obj = obj->next) {
|
||||
if ((def = _rtld_symlook_obj(name, hash, obj,
|
||||
false)) != NULL) {
|
||||
flags, ventry)) != NULL) {
|
||||
defobj = obj;
|
||||
break;
|
||||
}
|
||||
@@ -974,7 +1146,7 @@ dlsym(void *handle, const char *name)
|
||||
|
||||
case (intptr_t)RTLD_DEFAULT:
|
||||
def = _rtld_symlook_default(name, hash, obj, &defobj,
|
||||
false);
|
||||
flags, ventry);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -983,15 +1155,17 @@ dlsym(void *handle, const char *name)
|
||||
break;
|
||||
|
||||
default:
|
||||
if ((obj = _rtld_dlcheck(handle)) == NULL)
|
||||
if ((obj = _rtld_dlcheck(handle)) == NULL) {
|
||||
lookup_mutex_exit();
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
_rtld_donelist_init(&donelist);
|
||||
|
||||
if (obj->mainprog) {
|
||||
/* Search main program and all libraries loaded by it */
|
||||
def = _rtld_symlook_list(name, hash, &_rtld_list_main,
|
||||
&defobj, false, &donelist);
|
||||
&defobj, flags, ventry, &donelist);
|
||||
} else {
|
||||
Needed_Entry fake;
|
||||
DoneList depth;
|
||||
@@ -1003,25 +1177,73 @@ dlsym(void *handle, const char *name)
|
||||
|
||||
_rtld_donelist_init(&depth);
|
||||
def = _rtld_symlook_needed(name, hash, &fake, &defobj,
|
||||
false, &donelist, &depth);
|
||||
flags, ventry, &donelist, &depth);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (def != NULL) {
|
||||
void *p;
|
||||
#ifdef __HAVE_FUNCTION_DESCRIPTORS
|
||||
if (ELF_ST_TYPE(def->st_info) == STT_FUNC)
|
||||
return (void *)_rtld_function_descriptor_alloc(defobj,
|
||||
if (ELF_ST_TYPE(def->st_info) == STT_FUNC) {
|
||||
p = (void *)_rtld_function_descriptor_alloc(defobj,
|
||||
def, 0);
|
||||
lookup_mutex_exit();
|
||||
return p;
|
||||
}
|
||||
#endif /* __HAVE_FUNCTION_DESCRIPTORS */
|
||||
return defobj->relocbase + def->st_value;
|
||||
p = defobj->relocbase + def->st_value;
|
||||
lookup_mutex_exit();
|
||||
return p;
|
||||
}
|
||||
|
||||
_rtld_error("Undefined symbol \"%s\"", name);
|
||||
lookup_mutex_exit();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__strong_alias(__dlsym,dlsym)
|
||||
void *
|
||||
dlsym(void *handle, const char *name)
|
||||
{
|
||||
void *retaddr;
|
||||
|
||||
dbg(("dlsym of %s in %p", name, handle));
|
||||
|
||||
#ifdef __powerpc__
|
||||
retaddr = hackish_return_address();
|
||||
#else
|
||||
retaddr = __builtin_return_address(0);
|
||||
#endif
|
||||
return do_dlsym(handle, name, NULL, retaddr);
|
||||
}
|
||||
|
||||
__strong_alias(__dlvsym,dlvsym)
|
||||
void *
|
||||
dlvsym(void *handle, const char *name, const char *version)
|
||||
{
|
||||
Ver_Entry *ventry = NULL;
|
||||
Ver_Entry ver_entry;
|
||||
void *retaddr;
|
||||
|
||||
dbg(("dlvsym of %s@%s in %p", name, version ? version : NULL, handle));
|
||||
|
||||
if (version != NULL) {
|
||||
ver_entry.name = version;
|
||||
ver_entry.file = NULL;
|
||||
ver_entry.hash = _rtld_elf_hash(version);
|
||||
ver_entry.flags = 0;
|
||||
ventry = &ver_entry;
|
||||
}
|
||||
#ifdef __powerpc__
|
||||
retaddr = hackish_return_address();
|
||||
#else
|
||||
retaddr = __builtin_return_address(0);
|
||||
#endif
|
||||
return do_dlsym(handle, name, ventry, retaddr);
|
||||
}
|
||||
|
||||
__strong_alias(__dladdr,dladdr)
|
||||
int
|
||||
dladdr(const void *addr, Dl_info *info)
|
||||
@@ -1030,7 +1252,14 @@ dladdr(const void *addr, Dl_info *info)
|
||||
const Elf_Sym *def, *best_def;
|
||||
void *symbol_addr;
|
||||
unsigned long symoffset;
|
||||
|
||||
#ifdef __HAVE_FUNCTION_DESCRIPTORS
|
||||
sigset_t mask;
|
||||
#endif
|
||||
|
||||
dbg(("dladdr of %p", addr));
|
||||
|
||||
lookup_mutex_enter();
|
||||
|
||||
#ifdef __HAVE_FUNCTION_DESCRIPTORS
|
||||
addr = _rtld_function_descriptor_function(addr);
|
||||
#endif /* __HAVE_FUNCTION_DESCRIPTORS */
|
||||
@@ -1038,6 +1267,7 @@ dladdr(const void *addr, Dl_info *info)
|
||||
obj = _rtld_obj_from_addr(addr);
|
||||
if (obj == NULL) {
|
||||
_rtld_error("No shared object contains address");
|
||||
lookup_mutex_enter();
|
||||
return 0;
|
||||
}
|
||||
info->dli_fname = obj->path;
|
||||
@@ -1085,6 +1315,7 @@ dladdr(const void *addr, Dl_info *info)
|
||||
best_def, 0);
|
||||
#endif /* __HAVE_FUNCTION_DESCRIPTORS */
|
||||
|
||||
lookup_mutex_exit();
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1095,6 +1326,10 @@ dlinfo(void *handle, int req, void *v)
|
||||
const Obj_Entry *obj;
|
||||
void *retaddr;
|
||||
|
||||
dbg(("dlinfo for %p %d", handle, req));
|
||||
|
||||
_rtld_shared_enter();
|
||||
|
||||
if (handle == RTLD_SELF) {
|
||||
#ifdef __powerpc__
|
||||
retaddr = hackish_return_address();
|
||||
@@ -1103,11 +1338,12 @@ dlinfo(void *handle, int req, void *v)
|
||||
#endif
|
||||
if ((obj = _rtld_obj_from_addr(retaddr)) == NULL) {
|
||||
_rtld_error("Cannot determine caller's shared object");
|
||||
_rtld_shared_exit();
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if ((obj = _rtld_dlcheck(handle)) == NULL) {
|
||||
_rtld_error("Invalid handle");
|
||||
_rtld_shared_exit();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -1123,9 +1359,11 @@ dlinfo(void *handle, int req, void *v)
|
||||
|
||||
default:
|
||||
_rtld_error("Invalid request");
|
||||
_rtld_shared_exit();
|
||||
return -1;
|
||||
}
|
||||
|
||||
_rtld_shared_exit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1137,27 +1375,33 @@ dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), void *pa
|
||||
const Obj_Entry *obj;
|
||||
int error = 0;
|
||||
|
||||
dbg(("dl_iterate_phdr"));
|
||||
|
||||
_rtld_shared_enter();
|
||||
|
||||
for (obj = _rtld_objlist; obj != NULL; obj = obj->next) {
|
||||
phdr_info.dlpi_addr = (Elf_Addr)obj->relocbase;
|
||||
phdr_info.dlpi_name = STAILQ_FIRST(&obj->names) ?
|
||||
STAILQ_FIRST(&obj->names)->name : obj->path;
|
||||
phdr_info.dlpi_phdr = obj->phdr;
|
||||
phdr_info.dlpi_phnum = obj->phsize / sizeof(obj->phdr[0]);
|
||||
#if 1
|
||||
phdr_info.dlpi_tls_modid = 0;
|
||||
phdr_info.dlpi_tls_data = 0;
|
||||
#else
|
||||
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
|
||||
phdr_info.dlpi_tls_modid = obj->tlsindex;
|
||||
phdr_info.dlpi_tls_data = obj->tlsinit;
|
||||
#else
|
||||
phdr_info.dlpi_tls_modid = 0;
|
||||
phdr_info.dlpi_tls_data = 0;
|
||||
#endif
|
||||
phdr_info.dlpi_adds = _rtld_objloads;
|
||||
phdr_info.dlpi_subs = _rtld_objloads - _rtld_objcount;
|
||||
|
||||
/* XXXlocking: exit point */
|
||||
error = callback(&phdr_info, sizeof(phdr_info), param);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
|
||||
_rtld_shared_exit();
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -1182,7 +1426,8 @@ void
|
||||
_rtld_debug_state(void)
|
||||
{
|
||||
|
||||
/* do nothing */
|
||||
/* Prevent optimizer from removing calls to this function */
|
||||
__insn_barrier();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1267,3 +1512,130 @@ _rtld_objlist_remove(Objlist *list, Obj_Entry *obj)
|
||||
xfree(elm);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__minix)
|
||||
void _rtld_shared_enter(void) {}
|
||||
void _rtld_shared_exit(void) {}
|
||||
void _rtld_exclusive_enter(sigset_t *mask) {}
|
||||
void _rtld_exclusive_exit(sigset_t *mask) {}
|
||||
#else
|
||||
#define RTLD_EXCLUSIVE_MASK 0x80000000U
|
||||
static volatile unsigned int _rtld_mutex;
|
||||
static volatile unsigned int _rtld_waiter_exclusive;
|
||||
static volatile unsigned int _rtld_waiter_shared;
|
||||
|
||||
void
|
||||
_rtld_shared_enter(void)
|
||||
{
|
||||
unsigned int cur;
|
||||
lwpid_t waiter, self = 0;
|
||||
|
||||
membar_enter();
|
||||
|
||||
for (;;) {
|
||||
cur = _rtld_mutex;
|
||||
/*
|
||||
* First check if we are currently not exclusively locked.
|
||||
*/
|
||||
if ((cur & RTLD_EXCLUSIVE_MASK) == 0) {
|
||||
/* Yes, so increment use counter */
|
||||
if (atomic_cas_uint(&_rtld_mutex, cur, cur + 1) != cur)
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Someone has an exclusive lock. Puts us on the waiter list.
|
||||
*/
|
||||
if (!self)
|
||||
self = _lwp_self();
|
||||
if (cur == (self | RTLD_EXCLUSIVE_MASK)) {
|
||||
if (_rtld_mutex_may_recurse)
|
||||
return;
|
||||
_rtld_error("dead lock detected");
|
||||
_rtld_die();
|
||||
}
|
||||
waiter = atomic_swap_uint(&_rtld_waiter_shared, self);
|
||||
/*
|
||||
* Check for race against _rtld_exclusive_exit before sleeping.
|
||||
*/
|
||||
if ((_rtld_mutex & RTLD_EXCLUSIVE_MASK) ||
|
||||
_rtld_waiter_exclusive)
|
||||
_lwp_park(NULL, -1, __UNVOLATILE(&_rtld_mutex), NULL);
|
||||
/* Try to remove us from the waiter list. */
|
||||
atomic_cas_uint(&_rtld_waiter_shared, self, 0);
|
||||
if (waiter)
|
||||
_lwp_unpark(waiter, __UNVOLATILE(&_rtld_mutex));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_rtld_shared_exit(void)
|
||||
{
|
||||
lwpid_t waiter;
|
||||
|
||||
/*
|
||||
* Shared lock taken after an exclusive lock.
|
||||
* Just assume this is a partial recursion.
|
||||
*/
|
||||
if (_rtld_mutex & RTLD_EXCLUSIVE_MASK)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Wakeup LWPs waiting for an exclusive lock if this is the last
|
||||
* LWP on the shared lock.
|
||||
*/
|
||||
if (atomic_dec_uint_nv(&_rtld_mutex))
|
||||
return;
|
||||
if ((waiter = _rtld_waiter_exclusive) != 0)
|
||||
_lwp_unpark(waiter, __UNVOLATILE(&_rtld_mutex));
|
||||
|
||||
membar_exit();
|
||||
}
|
||||
|
||||
void
|
||||
_rtld_exclusive_enter(sigset_t *mask)
|
||||
{
|
||||
lwpid_t waiter, self = _lwp_self();
|
||||
unsigned int locked_value = (unsigned int)self | RTLD_EXCLUSIVE_MASK;
|
||||
unsigned int cur;
|
||||
sigset_t blockmask;
|
||||
|
||||
sigfillset(&blockmask);
|
||||
sigdelset(&blockmask, SIGTRAP); /* Allow the debugger */
|
||||
sigprocmask(SIG_BLOCK, &blockmask, mask);
|
||||
|
||||
membar_enter();
|
||||
|
||||
for (;;) {
|
||||
if (atomic_cas_uint(&_rtld_mutex, 0, locked_value) == 0)
|
||||
break;
|
||||
waiter = atomic_swap_uint(&_rtld_waiter_exclusive, self);
|
||||
cur = _rtld_mutex;
|
||||
if (cur == locked_value) {
|
||||
_rtld_error("dead lock detected");
|
||||
_rtld_die();
|
||||
}
|
||||
if (cur)
|
||||
_lwp_park(NULL, -1, __UNVOLATILE(&_rtld_mutex), NULL);
|
||||
atomic_cas_uint(&_rtld_waiter_exclusive, self, 0);
|
||||
if (waiter)
|
||||
_lwp_unpark(waiter, __UNVOLATILE(&_rtld_mutex));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_rtld_exclusive_exit(sigset_t *mask)
|
||||
{
|
||||
lwpid_t waiter;
|
||||
|
||||
_rtld_mutex = 0;
|
||||
if ((waiter = _rtld_waiter_exclusive) != 0)
|
||||
_lwp_unpark(waiter, __UNVOLATILE(&_rtld_mutex));
|
||||
|
||||
if ((waiter = _rtld_waiter_shared) != 0)
|
||||
_lwp_unpark(waiter, __UNVOLATILE(&_rtld_mutex));
|
||||
|
||||
membar_exit();
|
||||
sigprocmask(SIG_SETMASK, mask, NULL);
|
||||
}
|
||||
#endif /* !defined(__minix) */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $NetBSD: rtld.h,v 1.99 2011/01/16 15:56:37 matt Exp $ */
|
||||
/* $NetBSD: rtld.h,v 1.110 2012/08/15 03:46:06 matt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright 1996 John D. Polstra.
|
||||
@@ -35,12 +35,14 @@
|
||||
#define RTLD_H
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/exec_elf.h>
|
||||
#include <sys/tls.h>
|
||||
#include "rtldenv.h"
|
||||
#include "link.h"
|
||||
|
||||
@@ -102,6 +104,15 @@ typedef struct _rtld_search_path_t {
|
||||
size_t sp_pathlen;
|
||||
} Search_Path;
|
||||
|
||||
typedef struct Struct_Ver_Entry {
|
||||
Elf_Word hash;
|
||||
u_int flags;
|
||||
const char *name;
|
||||
const char *file;
|
||||
} Ver_Entry;
|
||||
|
||||
/* Ver_Entry.flags */
|
||||
#define VER_INFO_HIDDEN 0x01
|
||||
|
||||
#define RTLD_MAX_ENTRY 10
|
||||
#define RTLD_MAX_LIBRARY 4
|
||||
@@ -129,6 +140,8 @@ typedef struct _rtld_library_xform_t {
|
||||
#define RTLD_MAGIC 0xd550b87a
|
||||
#define RTLD_VERSION 1
|
||||
|
||||
typedef void (*fptr_t)(void);
|
||||
|
||||
typedef struct Struct_Obj_Entry {
|
||||
Elf32_Word magic; /* Magic number (sanity check) */
|
||||
Elf32_Word version; /* Version number of struct format */
|
||||
@@ -176,10 +189,15 @@ typedef struct Struct_Obj_Entry {
|
||||
Search_Path *rpaths; /* Search path specified in object */
|
||||
Needed_Entry *needed; /* Shared objects needed by this (%) */
|
||||
|
||||
void (*init)(void); /* Initialization function to call */
|
||||
void (*fini)(void); /* Termination function to call */
|
||||
fptr_t init; /* Initialization function to call */
|
||||
fptr_t fini; /* Termination function to call */
|
||||
|
||||
/* Entry points for dlopen() and friends. */
|
||||
/*
|
||||
* BACKWARDS COMPAT Entry points for dlopen() and friends.
|
||||
*
|
||||
* DO NOT MOVE OR ADD TO THE LIST
|
||||
*
|
||||
*/
|
||||
void *(*dlopen)(const char *, int);
|
||||
void *(*dlsym)(void *, const char *);
|
||||
char *(*dlerror)(void);
|
||||
@@ -211,6 +229,10 @@ typedef struct Struct_Obj_Entry {
|
||||
dlopen'ed */
|
||||
phdr_loaded:1, /* Phdr is loaded and doesn't need to
|
||||
* be freed. */
|
||||
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
|
||||
tls_done:1, /* True if static TLS offset
|
||||
* has been allocated */
|
||||
#endif
|
||||
ref_nodel:1; /* Refcount increased to prevent dlclose */
|
||||
|
||||
struct link_map linkmap; /* for GDB */
|
||||
@@ -231,9 +253,37 @@ typedef struct Struct_Obj_Entry {
|
||||
size_t pathlen; /* Pathname length */
|
||||
STAILQ_HEAD(, Struct_Name_Entry) names; /* List of names for this object we
|
||||
know about. */
|
||||
|
||||
#ifdef __powerpc__
|
||||
Elf_Addr *gotptr; /* GOT table (secure-plt only) */
|
||||
#endif
|
||||
|
||||
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
|
||||
/* Thread Local Storage support for this module */
|
||||
size_t tlsindex; /* Index in DTV */
|
||||
void *tlsinit; /* Base address of TLS init block */
|
||||
size_t tlsinitsize; /* Size of TLS init block */
|
||||
size_t tlssize; /* Size of TLS block */
|
||||
size_t tlsoffset; /* Offset in the static TLS block */
|
||||
size_t tlsalign; /* Needed alignment for static TLS */
|
||||
#endif
|
||||
|
||||
/* symbol versioning */
|
||||
const Elf_Verneed *verneed; /* Required versions. */
|
||||
Elf_Word verneednum; /* Number of entries in verneed table */
|
||||
const Elf_Verdef *verdef; /* Provided versions. */
|
||||
Elf_Word verdefnum; /* Number of entries in verdef table */
|
||||
const Elf_Versym *versyms; /* Symbol versions table */
|
||||
|
||||
Ver_Entry *vertab; /* Versions required/defined by this
|
||||
* object */
|
||||
int vertabnum; /* Number of entries in vertab */
|
||||
|
||||
/* init_array/fini_array */
|
||||
fptr_t *init_array; /* start of init array */
|
||||
size_t init_arraysz; /* # of entries in it */
|
||||
fptr_t *fini_array; /* start of fini array */
|
||||
size_t fini_arraysz; /* # of entries in it */
|
||||
} Obj_Entry;
|
||||
|
||||
typedef struct Struct_DoneList {
|
||||
@@ -262,12 +312,20 @@ extern Elf_Sym _rtld_sym_zero;
|
||||
|
||||
#define RTLD_MODEMASK 0x3
|
||||
|
||||
/* Flags to be passed into _rtld_symlook_ family of functions. */
|
||||
#define SYMLOOK_IN_PLT 0x01 /* Lookup for PLT symbol */
|
||||
#define SYMLOOK_DLSYM 0x02 /* Return newes versioned symbol.
|
||||
Used by dlsym. */
|
||||
|
||||
/* Flags for _rtld_load_object() and friends. */
|
||||
#define _RTLD_GLOBAL 0x01 /* Add object to global DAG. */
|
||||
#define _RTLD_MAIN 0x02
|
||||
#define _RTLD_NOLOAD 0x04 /* dlopen() specified RTLD_NOLOAD. */
|
||||
#define _RTLD_DLOPEN 0x08 /* Load_object() called from dlopen(). */
|
||||
|
||||
/* Preallocation for static TLS model */
|
||||
#define RTLD_STATIC_TLS_RESERVATION 64
|
||||
|
||||
/* rtld.c */
|
||||
|
||||
/* We export these symbols using _rtld_symbol_lookup and is_exported. */
|
||||
@@ -280,12 +338,14 @@ __dso_public int dlinfo(void *, int, void *);
|
||||
__dso_public int dl_iterate_phdr(int (*)(struct dl_phdr_info *, size_t, void *),
|
||||
void *);
|
||||
|
||||
__dso_public void *_dlauxinfo(void) __pure;
|
||||
|
||||
/* These aren't exported */
|
||||
void _rtld_error(const char *, ...)
|
||||
__attribute__((__format__(__printf__,1,2)));
|
||||
void _rtld_die(void) __attribute__((__noreturn__));
|
||||
void *_rtld_objmain_sym(const char *);
|
||||
void _rtld_debug_state(void);
|
||||
__dso_public void _rtld_debug_state(void) __noinline;
|
||||
void _rtld_linkmap_add(Obj_Entry *);
|
||||
void _rtld_linkmap_delete(Obj_Entry *);
|
||||
void _rtld_objlist_push_head(Objlist *, Obj_Entry *);
|
||||
@@ -293,6 +353,11 @@ void _rtld_objlist_push_tail(Objlist *, Obj_Entry *);
|
||||
Objlist_Entry *_rtld_objlist_find(Objlist *, const Obj_Entry *);
|
||||
void _rtld_ref_dag(Obj_Entry *);
|
||||
|
||||
void _rtld_shared_enter(void);
|
||||
void _rtld_shared_exit(void);
|
||||
void _rtld_exclusive_enter(sigset_t *);
|
||||
void _rtld_exclusive_exit(sigset_t *);
|
||||
|
||||
/* expand.c */
|
||||
size_t _rtld_expand_path(char *, size_t, const char *, const char *,\
|
||||
const char *);
|
||||
@@ -327,23 +392,62 @@ Obj_Entry *_rtld_load_library(const char *, const Obj_Entry *, int);
|
||||
/* symbol.c */
|
||||
unsigned long _rtld_elf_hash(const char *);
|
||||
const Elf_Sym *_rtld_symlook_obj(const char *, unsigned long,
|
||||
const Obj_Entry *, bool);
|
||||
const Obj_Entry *, u_int, const Ver_Entry *);
|
||||
const Elf_Sym *_rtld_find_symdef(unsigned long, const Obj_Entry *,
|
||||
const Obj_Entry **, bool);
|
||||
const Obj_Entry **, u_int);
|
||||
const Elf_Sym *_rtld_find_plt_symdef(unsigned long, const Obj_Entry *,
|
||||
const Obj_Entry **, bool);
|
||||
|
||||
const Elf_Sym *_rtld_symlook_list(const char *, unsigned long,
|
||||
const Objlist *, const Obj_Entry **, bool, DoneList *);
|
||||
const Objlist *, const Obj_Entry **, u_int, const Ver_Entry *, DoneList *);
|
||||
const Elf_Sym *_rtld_symlook_default(const char *, unsigned long,
|
||||
const Obj_Entry *, const Obj_Entry **, bool);
|
||||
const Obj_Entry *, const Obj_Entry **, u_int, const Ver_Entry *);
|
||||
const Elf_Sym *_rtld_symlook_needed(const char *, unsigned long,
|
||||
const Needed_Entry *, const Obj_Entry **, bool,
|
||||
const Needed_Entry *, const Obj_Entry **, u_int, const Ver_Entry *,
|
||||
DoneList *, DoneList *);
|
||||
#ifdef COMBRELOC
|
||||
void _rtld_combreloc_reset(const Obj_Entry *);
|
||||
#endif
|
||||
|
||||
/* symver.c */
|
||||
int _rtld_object_match_name(const Obj_Entry *, const char *);
|
||||
int _rtld_verify_object_versions(Obj_Entry *);
|
||||
|
||||
static __inline const Ver_Entry *
|
||||
_rtld_fetch_ventry(const Obj_Entry *obj, unsigned long symnum)
|
||||
{
|
||||
Elf_Half vernum;
|
||||
|
||||
if (obj->vertab) {
|
||||
vernum = VER_NDX(obj->versyms[symnum].vs_vers);
|
||||
if (vernum >= obj->vertabnum) {
|
||||
_rtld_error("%s: symbol %s has wrong verneed value %d",
|
||||
obj->path, &obj->strtab[symnum], vernum);
|
||||
} else if (obj->vertab[vernum].hash) {
|
||||
return &obj->vertab[vernum];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
|
||||
/* tls.c */
|
||||
void *_rtld_tls_get_addr(void *, size_t, size_t);
|
||||
void _rtld_tls_initial_allocation(void);
|
||||
void *_rtld_tls_module_allocate(size_t index);
|
||||
int _rtld_tls_offset_allocate(Obj_Entry *);
|
||||
void _rtld_tls_offset_free(Obj_Entry *);
|
||||
|
||||
extern size_t _rtld_tls_dtv_generation;
|
||||
extern size_t _rtld_tls_max_index;
|
||||
|
||||
__dso_public extern void *__tls_get_addr(void *);
|
||||
#ifdef __i386__
|
||||
__dso_public extern void *___tls_get_addr(void *)
|
||||
__attribute__((__regparm__(1)));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* map_object.c */
|
||||
struct stat;
|
||||
Obj_Entry *_rtld_map_object(const char *, int, const struct stat *);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $NetBSD: rtldenv.h,v 1.10 2010/10/29 15:08:17 christos Exp $ */
|
||||
/* $NetBSD: rtldenv.h,v 1.11 2011/12/11 11:05:11 joerg Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright 1996 Matt Thomas <matt@3am-software.com>
|
||||
@@ -57,7 +57,7 @@ void xerr(int, const char *, ...)
|
||||
void xerrx(int, const char *, ...)
|
||||
__attribute__((__noreturn__, __format__(__printf__, 2, 3)));
|
||||
|
||||
void xassert(const char *, int, const char *);
|
||||
void xassert(const char *, int, const char *) __dead;
|
||||
const char *xstrerror(int);
|
||||
int xunsetenv(const char *);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $NetBSD: symbol.c,v 1.54 2010/10/16 10:27:07 skrll Exp $ */
|
||||
/* $NetBSD: symbol.c,v 1.61 2012/08/15 03:46:07 matt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright 1996 John D. Polstra.
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: symbol.c,v 1.54 2010/10/16 10:27:07 skrll Exp $");
|
||||
__RCSID("$NetBSD: symbol.c,v 1.61 2012/08/15 03:46:07 matt Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <err.h>
|
||||
@@ -59,8 +59,6 @@ __RCSID("$NetBSD: symbol.c,v 1.54 2010/10/16 10:27:07 skrll Exp $");
|
||||
#include "debug.h"
|
||||
#include "rtld.h"
|
||||
|
||||
typedef void (*fptr_t)(void);
|
||||
|
||||
/*
|
||||
* If the given object is already in the donelist, return true. Otherwise
|
||||
* add the object to the list and return false.
|
||||
@@ -89,10 +87,20 @@ _rtld_is_exported(const Elf_Sym *def)
|
||||
(fptr_t)dlopen,
|
||||
(fptr_t)dlclose,
|
||||
(fptr_t)dlsym,
|
||||
(fptr_t)dlvsym,
|
||||
(fptr_t)dlerror,
|
||||
(fptr_t)dladdr,
|
||||
(fptr_t)dlinfo,
|
||||
(fptr_t)dl_iterate_phdr,
|
||||
(fptr_t)_dlauxinfo,
|
||||
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
|
||||
(fptr_t)_rtld_tls_allocate,
|
||||
(fptr_t)_rtld_tls_free,
|
||||
(fptr_t)__tls_get_addr,
|
||||
#ifdef __i386__
|
||||
(fptr_t)___tls_get_addr,
|
||||
#endif
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
int i;
|
||||
@@ -131,7 +139,8 @@ _rtld_elf_hash(const char *name)
|
||||
|
||||
const Elf_Sym *
|
||||
_rtld_symlook_list(const char *name, unsigned long hash, const Objlist *objlist,
|
||||
const Obj_Entry **defobj_out, bool in_plt, DoneList *dlp)
|
||||
const Obj_Entry **defobj_out, u_int flags, const Ver_Entry *ventry,
|
||||
DoneList *dlp)
|
||||
{
|
||||
const Elf_Sym *symp;
|
||||
const Elf_Sym *def;
|
||||
@@ -145,8 +154,8 @@ _rtld_symlook_list(const char *name, unsigned long hash, const Objlist *objlist,
|
||||
continue;
|
||||
rdbg(("search object %p (%s) for %s", elm->obj, elm->obj->path,
|
||||
name));
|
||||
if ((symp = _rtld_symlook_obj(name, hash, elm->obj, in_plt))
|
||||
!= NULL) {
|
||||
symp = _rtld_symlook_obj(name, hash, elm->obj, flags, ventry);
|
||||
if (symp != NULL) {
|
||||
if ((def == NULL) ||
|
||||
(ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
|
||||
def = symp;
|
||||
@@ -168,8 +177,8 @@ _rtld_symlook_list(const char *name, unsigned long hash, const Objlist *objlist,
|
||||
*/
|
||||
const Elf_Sym *
|
||||
_rtld_symlook_needed(const char *name, unsigned long hash,
|
||||
const Needed_Entry *needed, const Obj_Entry **defobj_out, bool inplt,
|
||||
DoneList *breadth, DoneList *depth)
|
||||
const Needed_Entry *needed, const Obj_Entry **defobj_out, u_int flags,
|
||||
const Ver_Entry *ventry, DoneList *breadth, DoneList *depth)
|
||||
{
|
||||
const Elf_Sym *def, *def_w;
|
||||
const Needed_Entry *n;
|
||||
@@ -182,7 +191,8 @@ _rtld_symlook_needed(const char *name, unsigned long hash,
|
||||
continue;
|
||||
if (_rtld_donelist_check(breadth, obj))
|
||||
continue;
|
||||
if ((def = _rtld_symlook_obj(name, hash, obj, inplt)) == NULL)
|
||||
def = _rtld_symlook_obj(name, hash, obj, flags, ventry);
|
||||
if (def == NULL)
|
||||
continue;
|
||||
defobj = obj;
|
||||
if (ELF_ST_BIND(def->st_info) != STB_WEAK) {
|
||||
@@ -201,7 +211,7 @@ _rtld_symlook_needed(const char *name, unsigned long hash,
|
||||
if (_rtld_donelist_check(depth, obj))
|
||||
continue;
|
||||
def_w = _rtld_symlook_needed(name, hash, obj->needed, &defobj1,
|
||||
inplt, breadth, depth);
|
||||
flags, ventry, breadth, depth);
|
||||
if (def_w == NULL)
|
||||
continue;
|
||||
if (def == NULL || ELF_ST_BIND(def_w->st_info) != STB_WEAK) {
|
||||
@@ -227,9 +237,12 @@ _rtld_symlook_needed(const char *name, unsigned long hash,
|
||||
*/
|
||||
const Elf_Sym *
|
||||
_rtld_symlook_obj(const char *name, unsigned long hash,
|
||||
const Obj_Entry *obj, bool in_plt)
|
||||
const Obj_Entry *obj, u_int flags, const Ver_Entry *ventry)
|
||||
{
|
||||
unsigned long symnum;
|
||||
const Elf_Sym *vsymp = NULL;
|
||||
Elf_Half verndx;
|
||||
int vcount = 0;
|
||||
|
||||
for (symnum = obj->buckets[fast_remainder32(hash, obj->nbuckets,
|
||||
obj->nbuckets_m, obj->nbuckets_s1, obj->nbuckets_s2)];
|
||||
@@ -241,30 +254,106 @@ _rtld_symlook_obj(const char *name, unsigned long hash,
|
||||
assert(symnum < obj->nchains);
|
||||
symp = obj->symtab + symnum;
|
||||
strp = obj->strtab + symp->st_name;
|
||||
rdbg(("check \"%s\" vs \"%s\" in %p", name, strp, obj));
|
||||
if (name[1] == strp[1] && !strcmp(name, strp)) {
|
||||
if (symp->st_shndx != SHN_UNDEF)
|
||||
return symp;
|
||||
#ifndef __mips__
|
||||
/*
|
||||
* XXX DANGER WILL ROBINSON!
|
||||
* If we have a function pointer in the executable's
|
||||
* data section, it points to the executable's PLT
|
||||
* slot, and there is NO relocation emitted. To make
|
||||
* the function pointer comparable to function pointers
|
||||
* in shared libraries, we must resolve data references
|
||||
* in the libraries to point to PLT slots in the
|
||||
* executable, if they exist.
|
||||
*/
|
||||
else if (!in_plt && symp->st_value != 0 &&
|
||||
ELF_ST_TYPE(symp->st_info) == STT_FUNC)
|
||||
return symp;
|
||||
rdbg(("check \"%s\" vs \"%s\" in %s", name, strp, obj->path));
|
||||
if (name[1] != strp[1] || strcmp(name, strp))
|
||||
continue;
|
||||
#ifdef __mips__
|
||||
if (symp->st_shndx == SHN_UNDEF)
|
||||
continue;
|
||||
#else
|
||||
/*
|
||||
* XXX DANGER WILL ROBINSON!
|
||||
* If we have a function pointer in the executable's
|
||||
* data section, it points to the executable's PLT
|
||||
* slot, and there is NO relocation emitted. To make
|
||||
* the function pointer comparable to function pointers
|
||||
* in shared libraries, we must resolve data references
|
||||
* in the libraries to point to PLT slots in the
|
||||
* executable, if they exist.
|
||||
*/
|
||||
if (symp->st_shndx == SHN_UNDEF &&
|
||||
((flags & SYMLOOK_IN_PLT) ||
|
||||
symp->st_value == 0 ||
|
||||
ELF_ST_TYPE(symp->st_info) != STT_FUNC))
|
||||
continue;
|
||||
#endif
|
||||
else
|
||||
return NULL;
|
||||
|
||||
if (ventry == NULL) {
|
||||
if (obj->versyms != NULL) {
|
||||
verndx = VER_NDX(obj->versyms[symnum].vs_vers);
|
||||
if (verndx > obj->vertabnum) {
|
||||
_rtld_error("%s: symbol %s references "
|
||||
"wrong version %d", obj->path,
|
||||
&obj->strtab[symnum], verndx);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are not called from dlsym (i.e. this
|
||||
* is a normal 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 is the only
|
||||
* symbol with this name exported by the shared
|
||||
* object, it will be returned as a match at the
|
||||
* end of the function. If symbol is global
|
||||
* (verndx < 2) accept it unconditionally.
|
||||
*/
|
||||
if (!(flags & SYMLOOK_DLSYM) &&
|
||||
verndx == VER_NDX_GIVEN) {
|
||||
return symp;
|
||||
} else if (verndx >= VER_NDX_GIVEN) {
|
||||
if (!(obj->versyms[symnum].vs_vers & VER_NDX_HIDDEN)) {
|
||||
if (vsymp == NULL)
|
||||
vsymp = symp;
|
||||
vcount++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return symp;
|
||||
} else {
|
||||
if (obj->versyms == NULL) {
|
||||
if (_rtld_object_match_name(obj, ventry->name)){
|
||||
_rtld_error("%s: object %s should "
|
||||
"provide version %s for symbol %s",
|
||||
_rtld_objself.path, obj->path,
|
||||
ventry->name, &obj->strtab[symnum]);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
verndx = VER_NDX(obj->versyms[symnum].vs_vers);
|
||||
if (verndx > obj->vertabnum) {
|
||||
_rtld_error("%s: symbol %s references "
|
||||
"wrong version %d", obj->path,
|
||||
&obj->strtab[symnum], verndx);
|
||||
continue;
|
||||
}
|
||||
if (obj->vertab[verndx].hash != ventry->hash ||
|
||||
strcmp(obj->vertab[verndx].name, ventry->name)) {
|
||||
/*
|
||||
* Version does not match. Look if this
|
||||
* is a global symbol and if it is not
|
||||
* hidden. If global symbol (verndx < 2)
|
||||
* is available, use it. Do not return
|
||||
* symbol if we are called by dlvsym,
|
||||
* because dlvsym looks for a specific
|
||||
* version and default one is not what
|
||||
* dlvsym wants.
|
||||
*/
|
||||
if ((flags & SYMLOOK_DLSYM) ||
|
||||
(obj->versyms[symnum].vs_vers & VER_NDX_HIDDEN) ||
|
||||
(verndx >= VER_NDX_GIVEN))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return symp;
|
||||
}
|
||||
}
|
||||
|
||||
if (vcount == 1)
|
||||
return vsymp;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -291,7 +380,7 @@ _rtld_combreloc_reset(const Obj_Entry *obj)
|
||||
*/
|
||||
const Elf_Sym *
|
||||
_rtld_find_symdef(unsigned long symnum, const Obj_Entry *refobj,
|
||||
const Obj_Entry **defobj_out, bool in_plt)
|
||||
const Obj_Entry **defobj_out, u_int flags)
|
||||
{
|
||||
const Elf_Sym *ref;
|
||||
const Elf_Sym *def;
|
||||
@@ -312,7 +401,7 @@ _rtld_find_symdef(unsigned long symnum, const Obj_Entry *refobj,
|
||||
static const Elf_Sym *last_def;
|
||||
|
||||
if (symnum == last_symnum && refobj == _rtld_last_refobj
|
||||
&& in_plt == false) {
|
||||
&& !(flags & SYMLOOK_IN_PLT)) {
|
||||
*defobj_out = last_defobj;
|
||||
return last_def;
|
||||
}
|
||||
@@ -334,7 +423,8 @@ _rtld_find_symdef(unsigned long symnum, const Obj_Entry *refobj,
|
||||
|
||||
hash = _rtld_elf_hash(name);
|
||||
defobj = NULL;
|
||||
def = _rtld_symlook_default(name, hash, refobj, &defobj, in_plt);
|
||||
def = _rtld_symlook_default(name, hash, refobj, &defobj, flags,
|
||||
_rtld_fetch_ventry(refobj, symnum));
|
||||
} else {
|
||||
rdbg(("STB_LOCAL symbol %s in %s", name, refobj->path));
|
||||
def = ref;
|
||||
@@ -354,7 +444,7 @@ _rtld_find_symdef(unsigned long symnum, const Obj_Entry *refobj,
|
||||
if (def != NULL) {
|
||||
*defobj_out = defobj;
|
||||
#ifdef COMBRELOC
|
||||
if (in_plt == false) {
|
||||
if (!(flags & SYMLOOK_IN_PLT)) {
|
||||
/*
|
||||
* Cache the lookup arguments and results if this was
|
||||
* non-PLT lookup.
|
||||
@@ -368,7 +458,8 @@ _rtld_find_symdef(unsigned long symnum, const Obj_Entry *refobj,
|
||||
} else {
|
||||
rdbg(("lookup failed"));
|
||||
_rtld_error("%s: Undefined %ssymbol \"%s\" (symnum = %ld)",
|
||||
refobj->path, in_plt ? "PLT " : "", name, symnum);
|
||||
refobj->path, (flags & SYMLOOK_IN_PLT) ? "PLT " : "",
|
||||
name, symnum);
|
||||
}
|
||||
return def;
|
||||
}
|
||||
@@ -377,7 +468,8 @@ const Elf_Sym *
|
||||
_rtld_find_plt_symdef(unsigned long symnum, const Obj_Entry *obj,
|
||||
const Obj_Entry **defobj, bool imm)
|
||||
{
|
||||
const Elf_Sym *def = _rtld_find_symdef(symnum, obj, defobj, true);
|
||||
const Elf_Sym *def = _rtld_find_symdef(symnum, obj, defobj,
|
||||
SYMLOOK_IN_PLT);
|
||||
if (__predict_false(def == NULL))
|
||||
return NULL;
|
||||
|
||||
@@ -404,7 +496,8 @@ _rtld_find_plt_symdef(unsigned long symnum, const Obj_Entry *obj,
|
||||
*/
|
||||
const Elf_Sym *
|
||||
_rtld_symlook_default(const char *name, unsigned long hash,
|
||||
const Obj_Entry *refobj, const Obj_Entry **defobj_out, bool in_plt)
|
||||
const Obj_Entry *refobj, const Obj_Entry **defobj_out, u_int flags,
|
||||
const Ver_Entry *ventry)
|
||||
{
|
||||
const Elf_Sym *def;
|
||||
const Elf_Sym *symp;
|
||||
@@ -420,7 +513,7 @@ _rtld_symlook_default(const char *name, unsigned long hash,
|
||||
/* Look first in the referencing object if linked symbolically. */
|
||||
if (refobj->symbolic && !_rtld_donelist_check(&donelist, refobj)) {
|
||||
rdbg(("search referencing object for %s", name));
|
||||
symp = _rtld_symlook_obj(name, hash, refobj, in_plt);
|
||||
symp = _rtld_symlook_obj(name, hash, refobj, flags, ventry);
|
||||
if (symp != NULL) {
|
||||
def = symp;
|
||||
defobj = refobj;
|
||||
@@ -431,7 +524,7 @@ _rtld_symlook_default(const char *name, unsigned long hash,
|
||||
if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
|
||||
rdbg(("search _rtld_list_main for %s", name));
|
||||
symp = _rtld_symlook_list(name, hash, &_rtld_list_main, &obj,
|
||||
in_plt, &donelist);
|
||||
flags, ventry, &donelist);
|
||||
if (symp != NULL &&
|
||||
(def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
|
||||
def = symp;
|
||||
@@ -443,7 +536,7 @@ _rtld_symlook_default(const char *name, unsigned long hash,
|
||||
if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
|
||||
rdbg(("search _rtld_list_global for %s", name));
|
||||
symp = _rtld_symlook_list(name, hash, &_rtld_list_global,
|
||||
&obj, in_plt, &donelist);
|
||||
&obj, flags, ventry, &donelist);
|
||||
if (symp != NULL &&
|
||||
(def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
|
||||
def = symp;
|
||||
@@ -458,7 +551,7 @@ _rtld_symlook_default(const char *name, unsigned long hash,
|
||||
rdbg(("search DAG with root %p (%s) for %s", elm->obj,
|
||||
elm->obj->path, name));
|
||||
symp = _rtld_symlook_list(name, hash, &elm->obj->dagmembers,
|
||||
&obj, in_plt, &donelist);
|
||||
&obj, flags, ventry, &donelist);
|
||||
if (symp != NULL &&
|
||||
(def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
|
||||
def = symp;
|
||||
@@ -475,7 +568,8 @@ _rtld_symlook_default(const char *name, unsigned long hash,
|
||||
*/
|
||||
if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
|
||||
rdbg(("Search the dynamic linker itself."));
|
||||
symp = _rtld_symlook_obj(name, hash, &_rtld_objself, in_plt);
|
||||
symp = _rtld_symlook_obj(name, hash, &_rtld_objself, flags,
|
||||
ventry);
|
||||
if (symp != NULL && _rtld_is_exported(symp)) {
|
||||
def = symp;
|
||||
defobj = &_rtld_objself;
|
||||
|
||||
317
libexec/ld.elf_so/symver.c
Normal file
317
libexec/ld.elf_so/symver.c
Normal file
@@ -0,0 +1,317 @@
|
||||
/* $NetBSD: symver.c,v 1.1 2011/06/25 05:45:12 nonaka Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright 1996, 1997, 1998, 1999, 2000 John D. Polstra.
|
||||
* Copyright 2003 Alexander Kabaev <kan@FreeBSD.ORG>.
|
||||
* Copyright 2009, 2010, 2011 Konstantin Belousov <kib@FreeBSD.ORG>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD: head/libexec/rtld-elf/rtld.c 220004 2011-03-25 18:23:10Z avg $
|
||||
*/
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2011 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by NONAKA Kimihiro.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: symver.c,v 1.1 2011/06/25 05:45:12 nonaka Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/exec_elf.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "rtld.h"
|
||||
|
||||
|
||||
int
|
||||
_rtld_object_match_name(const Obj_Entry *obj, const char *name)
|
||||
{
|
||||
Name_Entry *entry;
|
||||
|
||||
STAILQ_FOREACH(entry, &obj->names, link) {
|
||||
dbg(("name: %s, entry->name: %s", name, entry->name));
|
||||
if (strcmp(name, entry->name) == 0)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Obj_Entry *
|
||||
locate_dependency(const Obj_Entry *obj, const char *name)
|
||||
{
|
||||
const Objlist_Entry *entry;
|
||||
const Needed_Entry *needed;
|
||||
|
||||
SIMPLEQ_FOREACH(entry, &_rtld_list_main, link) {
|
||||
if (_rtld_object_match_name(entry->obj, name))
|
||||
return entry->obj;
|
||||
}
|
||||
|
||||
for (needed = obj->needed; needed != NULL; needed = needed->next) {
|
||||
dbg(("needed: name: %s, str: %s", name,
|
||||
&obj->strtab[needed->name]));
|
||||
if (strcmp(name, &obj->strtab[needed->name]) == 0 ||
|
||||
(needed->obj != NULL && _rtld_object_match_name(needed->obj, name))) {
|
||||
/*
|
||||
* If there is DT_NEEDED for the name we are looking
|
||||
* for, we are all set. Note that object might not be
|
||||
* found if dependency was not loaded yet, so the
|
||||
* function can return NULL here. This is expected
|
||||
* and handled properly by the caller.
|
||||
*/
|
||||
return needed->obj;
|
||||
}
|
||||
}
|
||||
|
||||
_rtld_error("%s: Unexpected inconsistency: dependency %s not found",
|
||||
obj->path, name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
check_object_provided_version(Obj_Entry *refobj, const Obj_Entry *depobj,
|
||||
const Elf_Vernaux *vna)
|
||||
{
|
||||
const char *vername = &refobj->strtab[vna->vna_name];
|
||||
const char *depstrtab = depobj->strtab;
|
||||
const Elf_Verdef *vd = depobj->verdef;
|
||||
const Elf_Word hash = vna->vna_hash;
|
||||
|
||||
if (vd == NULL) {
|
||||
_rtld_error("%s: version %s required by %s not defined",
|
||||
depobj->path, vername, refobj->path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (;; vd = (const Elf_Verdef *)((const char *)vd + vd->vd_next)) {
|
||||
if (vd->vd_version != VER_DEF_CURRENT) {
|
||||
_rtld_error(
|
||||
"%s: Unsupported version %d of Elf_Verdef entry",
|
||||
depobj->path, vd->vd_version);
|
||||
return -1;
|
||||
}
|
||||
dbg(("hash: 0x%x, vd_hash: 0x%x", hash, vd->vd_hash));
|
||||
if (hash == vd->vd_hash) {
|
||||
const Elf_Verdaux *vda = (const Elf_Verdaux *)
|
||||
((const char *)vd + vd->vd_aux);
|
||||
dbg(("vername: %s, str: %s", vername,
|
||||
&depstrtab[vda->vda_name]));
|
||||
if (strcmp(vername, &depstrtab[vda->vda_name]) == 0)
|
||||
return 0;
|
||||
}
|
||||
if (vd->vd_next == 0)
|
||||
break;
|
||||
}
|
||||
if (vna->vna_flags & VER_FLG_WEAK)
|
||||
return 0;
|
||||
|
||||
_rtld_error("%s: version %s required by %s not found", depobj->path,
|
||||
vername, refobj->path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
_rtld_verify_object_versions(Obj_Entry *obj)
|
||||
{
|
||||
const char *strtab = obj->strtab;
|
||||
const Elf_Verneed *vn;
|
||||
const Elf_Vernaux *vna;
|
||||
const Elf_Verdef *vd;
|
||||
const Elf_Verdaux *vda;
|
||||
const Obj_Entry *depobj;
|
||||
int maxvertab, vernum;
|
||||
|
||||
dbg(("obj->path: %s", obj->path));
|
||||
|
||||
/*
|
||||
* If we don't have string table or objects that have their version
|
||||
* requirements already checked, we must be ok.
|
||||
*/
|
||||
if (strtab == NULL || obj->vertab != NULL)
|
||||
return 0;
|
||||
|
||||
maxvertab = 0;
|
||||
|
||||
/*
|
||||
* Walk over defined and required version records and figure out
|
||||
* max index used by any of them. Do very basic sanity checking
|
||||
* while there.
|
||||
*/
|
||||
for (vn = obj->verneed;
|
||||
vn != NULL;
|
||||
vn = (const Elf_Verneed *)((const char *)vn + vn->vn_next)) {
|
||||
|
||||
if (vn->vn_version != VER_NEED_CURRENT) {
|
||||
_rtld_error(
|
||||
"%s: Unsupported version %d of Elf_Verneed entry",
|
||||
obj->path, vn->vn_version);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dbg(("verneed: vn_file: %d, str: %s",
|
||||
vn->vn_file, &strtab[vn->vn_file]));
|
||||
depobj = locate_dependency(obj, &strtab[vn->vn_file]);
|
||||
assert(depobj != NULL);
|
||||
|
||||
for (vna = (const Elf_Vernaux *)((const char *)vn + vn->vn_aux);
|
||||
/*CONSTCOND*/1;
|
||||
vna = (const Elf_Vernaux *)((const char *)vna + vna->vna_next)) {
|
||||
|
||||
if (check_object_provided_version(obj, depobj, vna) == -1)
|
||||
return -1;
|
||||
|
||||
vernum = VER_NEED_IDX(vna->vna_other);
|
||||
if (vernum > maxvertab)
|
||||
maxvertab = vernum;
|
||||
|
||||
if (vna->vna_next == 0) {
|
||||
/* No more symbols. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (vn->vn_next == 0) {
|
||||
/* No more dependencies. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (vd = obj->verdef;
|
||||
vd != NULL;
|
||||
vd = (const Elf_Verdef *)((const char *)vd + vd->vd_next)) {
|
||||
|
||||
if (vd->vd_version != VER_DEF_CURRENT) {
|
||||
_rtld_error(
|
||||
"%s: Unsupported version %d of Elf_Verdef entry",
|
||||
obj->path, vd->vd_version);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dbg(("verdef: vn_ndx: 0x%x", vd->vd_ndx));
|
||||
vernum = VER_DEF_IDX(vd->vd_ndx);
|
||||
if (vernum > maxvertab)
|
||||
maxvertab = vernum;
|
||||
|
||||
if (vd->vd_next == 0) {
|
||||
/* No more definitions. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dbg(("maxvertab: %d", maxvertab));
|
||||
if (maxvertab == 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Store version information in array indexable by version index.
|
||||
* Verify that object version requirements are satisfied along the
|
||||
* way.
|
||||
*/
|
||||
obj->vertabnum = maxvertab + 1;
|
||||
obj->vertab = (Ver_Entry *)xcalloc(obj->vertabnum * sizeof(Ver_Entry));
|
||||
|
||||
for (vn = obj->verneed;
|
||||
vn != NULL;
|
||||
vn = (const Elf_Verneed *)((const char *)vn + vn->vn_next)) {
|
||||
|
||||
for (vna = (const Elf_Vernaux *)((const char *)vn + vn->vn_aux);
|
||||
/*CONSTCOND*/1;
|
||||
vna = (const Elf_Vernaux *)((const char *)vna + vna->vna_next)) {
|
||||
|
||||
vernum = VER_NEED_IDX(vna->vna_other);
|
||||
assert(vernum <= maxvertab);
|
||||
obj->vertab[vernum].hash = vna->vna_hash;
|
||||
obj->vertab[vernum].name = &strtab[vna->vna_name];
|
||||
obj->vertab[vernum].file = &strtab[vn->vn_file];
|
||||
obj->vertab[vernum].flags =
|
||||
(vna->vna_other & VER_NEED_HIDDEN)
|
||||
? VER_INFO_HIDDEN : 0;
|
||||
dbg(("verneed: vernum: %d, hash: 0x%x, name: %s, "
|
||||
"file: %s, flags: 0x%x", vernum,
|
||||
obj->vertab[vernum].hash, obj->vertab[vernum].name,
|
||||
obj->vertab[vernum].file,
|
||||
obj->vertab[vernum].flags));
|
||||
|
||||
if (vna->vna_next == 0) {
|
||||
/* No more symbols. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (vn->vn_next == 0) {
|
||||
/* No more dependencies. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (vd = obj->verdef;
|
||||
vd != NULL;
|
||||
vd = (const Elf_Verdef *)((const char *)vd + vd->vd_next)) {
|
||||
|
||||
if ((vd->vd_flags & VER_FLG_BASE) == 0) {
|
||||
vernum = VER_DEF_IDX(vd->vd_ndx);
|
||||
assert(vernum <= maxvertab);
|
||||
vda = (const Elf_Verdaux *)
|
||||
((const char *)vd + vd->vd_aux);
|
||||
obj->vertab[vernum].hash = vd->vd_hash;
|
||||
obj->vertab[vernum].name = &strtab[vda->vda_name];
|
||||
obj->vertab[vernum].file = NULL;
|
||||
obj->vertab[vernum].flags = 0;
|
||||
dbg(("verdef: vernum: %d, hash: 0x%x, name: %s",
|
||||
vernum, obj->vertab[vernum].hash,
|
||||
obj->vertab[vernum].name));
|
||||
}
|
||||
|
||||
if (vd->vd_next == 0) {
|
||||
/* No more definitions. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
304
libexec/ld.elf_so/tls.c
Normal file
304
libexec/ld.elf_so/tls.c
Normal file
@@ -0,0 +1,304 @@
|
||||
/* $NetBSD: tls.c,v 1.7 2011/04/23 16:40:08 joerg Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 2011 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Joerg Sonnenberger.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: tls.c,v 1.7 2011/04/23 16:40:08 joerg Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/ucontext.h>
|
||||
#include <lwp.h>
|
||||
#include <string.h>
|
||||
#include "rtld.h"
|
||||
|
||||
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
|
||||
|
||||
static struct tls_tcb *_rtld_tls_allocate_locked(void);
|
||||
|
||||
#ifndef TLS_DTV_OFFSET
|
||||
#define TLS_DTV_OFFSET 0
|
||||
#endif
|
||||
|
||||
static size_t _rtld_tls_static_space; /* Static TLS space allocated */
|
||||
static size_t _rtld_tls_static_offset; /* Next offset for static TLS to use */
|
||||
size_t _rtld_tls_dtv_generation = 1;
|
||||
size_t _rtld_tls_max_index = 1;
|
||||
|
||||
#define DTV_GENERATION(dtv) ((size_t)((dtv)[0]))
|
||||
#define DTV_MAX_INDEX(dtv) ((size_t)((dtv)[-1]))
|
||||
#define SET_DTV_GENERATION(dtv, val) (dtv)[0] = (void *)(size_t)(val)
|
||||
#define SET_DTV_MAX_INDEX(dtv, val) (dtv)[-1] = (void *)(size_t)(val)
|
||||
|
||||
void *
|
||||
_rtld_tls_get_addr(void *tls, size_t idx, size_t offset)
|
||||
{
|
||||
struct tls_tcb *tcb = tls;
|
||||
void **dtv, **new_dtv;
|
||||
sigset_t mask;
|
||||
|
||||
_rtld_exclusive_enter(&mask);
|
||||
|
||||
dtv = tcb->tcb_dtv;
|
||||
|
||||
if (__predict_false(DTV_GENERATION(dtv) != _rtld_tls_dtv_generation)) {
|
||||
size_t to_copy = DTV_MAX_INDEX(dtv);
|
||||
|
||||
new_dtv = xcalloc((2 + _rtld_tls_max_index) * sizeof(*dtv));
|
||||
++new_dtv;
|
||||
if (to_copy > _rtld_tls_max_index)
|
||||
to_copy = _rtld_tls_max_index;
|
||||
memcpy(new_dtv + 1, dtv + 1, to_copy * sizeof(*dtv));
|
||||
xfree(dtv - 1);
|
||||
dtv = tcb->tcb_dtv = new_dtv;
|
||||
SET_DTV_MAX_INDEX(dtv, _rtld_tls_max_index);
|
||||
SET_DTV_GENERATION(dtv, _rtld_tls_dtv_generation);
|
||||
}
|
||||
|
||||
if (__predict_false(dtv[idx] == NULL))
|
||||
dtv[idx] = _rtld_tls_module_allocate(idx);
|
||||
|
||||
_rtld_exclusive_exit(&mask);
|
||||
|
||||
return (uint8_t *)dtv[idx] + offset;
|
||||
}
|
||||
|
||||
void
|
||||
_rtld_tls_initial_allocation(void)
|
||||
{
|
||||
struct tls_tcb *tcb;
|
||||
|
||||
_rtld_tls_static_space = _rtld_tls_static_offset +
|
||||
RTLD_STATIC_TLS_RESERVATION;
|
||||
|
||||
#ifndef __HAVE_TLS_VARIANT_I
|
||||
_rtld_tls_static_space = roundup2(_rtld_tls_static_space,
|
||||
sizeof(void *));
|
||||
#endif
|
||||
|
||||
tcb = _rtld_tls_allocate_locked();
|
||||
#ifdef __HAVE___LWP_SETTCB
|
||||
__lwp_settcb(tcb);
|
||||
#ifdef __powerpc__
|
||||
/*
|
||||
* Save the tcb pointer so that libc can retrieve it. Older
|
||||
* crt0 will obliterate r2 so there is code in libc to restore it.
|
||||
*/
|
||||
_lwp_setprivate(tcb);
|
||||
#endif
|
||||
#else
|
||||
_lwp_setprivate(tcb);
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct tls_tcb *
|
||||
_rtld_tls_allocate_locked(void)
|
||||
{
|
||||
Obj_Entry *obj;
|
||||
struct tls_tcb *tcb;
|
||||
uint8_t *p, *q;
|
||||
|
||||
p = xcalloc(_rtld_tls_static_space + sizeof(struct tls_tcb));
|
||||
#ifdef __HAVE_TLS_VARIANT_I
|
||||
tcb = (struct tls_tcb *)p;
|
||||
p += sizeof(struct tls_tcb);
|
||||
#else
|
||||
p += _rtld_tls_static_space;
|
||||
tcb = (struct tls_tcb *)p;
|
||||
tcb->tcb_self = tcb;
|
||||
#endif
|
||||
tcb->tcb_dtv = xcalloc(sizeof(*tcb->tcb_dtv) * (2 + _rtld_tls_max_index));
|
||||
++tcb->tcb_dtv;
|
||||
SET_DTV_MAX_INDEX(tcb->tcb_dtv, _rtld_tls_max_index);
|
||||
SET_DTV_GENERATION(tcb->tcb_dtv, _rtld_tls_dtv_generation);
|
||||
|
||||
for (obj = _rtld_objlist; obj != NULL; obj = obj->next) {
|
||||
if (obj->tlssize) {
|
||||
#ifdef __HAVE_TLS_VARIANT_I
|
||||
q = p + obj->tlsoffset;
|
||||
#else
|
||||
q = p - obj->tlsoffset;
|
||||
#endif
|
||||
memcpy(q, obj->tlsinit, obj->tlsinitsize);
|
||||
tcb->tcb_dtv[obj->tlsindex] = q;
|
||||
}
|
||||
}
|
||||
|
||||
return tcb;
|
||||
}
|
||||
|
||||
struct tls_tcb *
|
||||
_rtld_tls_allocate(void)
|
||||
{
|
||||
struct tls_tcb *tcb;
|
||||
sigset_t mask;
|
||||
|
||||
_rtld_exclusive_enter(&mask);
|
||||
tcb = _rtld_tls_allocate_locked();
|
||||
_rtld_exclusive_exit(&mask);
|
||||
|
||||
return tcb;
|
||||
}
|
||||
|
||||
void
|
||||
_rtld_tls_free(struct tls_tcb *tcb)
|
||||
{
|
||||
size_t i, max_index;
|
||||
uint8_t *p;
|
||||
sigset_t mask;
|
||||
|
||||
_rtld_exclusive_enter(&mask);
|
||||
|
||||
max_index = DTV_MAX_INDEX(tcb->tcb_dtv);
|
||||
for (i = 1; i <= max_index; ++i)
|
||||
xfree(tcb->tcb_dtv[i]);
|
||||
xfree(tcb->tcb_dtv - 1);
|
||||
|
||||
#ifdef __HAVE_TLS_VARIANT_I
|
||||
p = (uint8_t *)tcb;
|
||||
#else
|
||||
p = (uint8_t *)tcb - _rtld_tls_static_space;
|
||||
#endif
|
||||
xfree(p);
|
||||
|
||||
_rtld_exclusive_exit(&mask);
|
||||
}
|
||||
|
||||
void *
|
||||
_rtld_tls_module_allocate(size_t idx)
|
||||
{
|
||||
Obj_Entry *obj;
|
||||
uint8_t *p;
|
||||
|
||||
for (obj = _rtld_objlist; obj != NULL; obj = obj->next) {
|
||||
if (obj->tlsindex == idx)
|
||||
break;
|
||||
}
|
||||
if (obj == NULL) {
|
||||
_rtld_error("Module for TLS index %zu missing", idx);
|
||||
_rtld_die();
|
||||
}
|
||||
|
||||
p = xmalloc(obj->tlssize);
|
||||
memcpy(p, obj->tlsinit, obj->tlsinitsize);
|
||||
memset(p + obj->tlsinitsize, 0, obj->tlssize - obj->tlsinitsize);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
int
|
||||
_rtld_tls_offset_allocate(Obj_Entry *obj)
|
||||
{
|
||||
size_t offset, next_offset;
|
||||
|
||||
if (obj->tls_done)
|
||||
return 0;
|
||||
if (obj->tlssize == 0) {
|
||||
obj->tlsoffset = 0;
|
||||
obj->tls_done = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __HAVE_TLS_VARIANT_I
|
||||
offset = roundup2(_rtld_tls_static_offset, obj->tlsalign);
|
||||
next_offset = offset + obj->tlssize;
|
||||
#else
|
||||
offset = roundup2(_rtld_tls_static_offset + obj->tlssize,
|
||||
obj->tlsalign);
|
||||
next_offset = offset;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check if the static allocation was already done.
|
||||
* This happens if dynamically loaded modules want to use
|
||||
* static TLS space.
|
||||
*
|
||||
* XXX Keep an actual free list and callbacks for initialisation.
|
||||
*/
|
||||
if (_rtld_tls_static_space) {
|
||||
if (obj->tlsinitsize) {
|
||||
_rtld_error("%s: Use of initialized "
|
||||
"Thread Local Storage with model initial-exec "
|
||||
"and dlopen is not supported",
|
||||
obj->path);
|
||||
return -1;
|
||||
}
|
||||
if (next_offset > _rtld_tls_static_space) {
|
||||
_rtld_error("%s: No space available "
|
||||
"for static Thread Local Storage",
|
||||
obj->path);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
obj->tlsoffset = offset;
|
||||
_rtld_tls_static_offset = next_offset;
|
||||
obj->tls_done = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
_rtld_tls_offset_free(Obj_Entry *obj)
|
||||
{
|
||||
|
||||
/*
|
||||
* XXX See above.
|
||||
*/
|
||||
obj->tls_done = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef __HAVE_COMMON___TLS_GET_ADDR
|
||||
/*
|
||||
* The fast path is access to an already allocated DTV entry.
|
||||
* This checks the current limit and the entry without needing any
|
||||
* locking. Entries are only freed on dlclose() and it is an application
|
||||
* bug if code of the module is still running at that point.
|
||||
*/
|
||||
void *
|
||||
__tls_get_addr(void *arg_)
|
||||
{
|
||||
size_t *arg = (size_t *)arg_;
|
||||
void **dtv;
|
||||
#ifdef __HAVE___LWP_GETTCB_FAST
|
||||
struct tls_tcb * const tcb = __lwp_gettcb_fast();
|
||||
#else
|
||||
struct tls_tcb * const tcb = __lwp_getprivate_fast();
|
||||
#endif
|
||||
size_t idx = arg[0], offset = arg[1] + TLS_DTV_OFFSET;
|
||||
|
||||
dtv = tcb->tcb_dtv;
|
||||
|
||||
if (__predict_true(idx < DTV_MAX_INDEX(dtv) && dtv[idx] != NULL))
|
||||
return (uint8_t *)dtv[idx] + offset;
|
||||
|
||||
return _rtld_tls_get_addr(tcb, idx, offset);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HAVE_TLS_VARIANT_I || __HAVE_TLS_VARIANT_II */
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $NetBSD: xmalloc.c,v 1.10 2010/12/03 23:07:49 joerg Exp $ */
|
||||
/* $NetBSD: xmalloc.c,v 1.11 2011/05/25 14:41:46 christos Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright 1996 John D. Polstra.
|
||||
@@ -61,6 +61,8 @@
|
||||
*/
|
||||
|
||||
#ifdef __minix
|
||||
/* Minix mmap can do this. */
|
||||
#define mmap minix_mmap
|
||||
#define munmap minix_munmap
|
||||
#endif
|
||||
|
||||
@@ -81,7 +83,7 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: xmalloc.c,v 1.10 2010/12/03 23:07:49 joerg Exp $");
|
||||
__RCSID("$NetBSD: xmalloc.c,v 1.11 2011/05/25 14:41:46 christos Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <stdlib.h>
|
||||
@@ -152,6 +154,7 @@ static union overhead *nextf[NBUCKETS];
|
||||
|
||||
static size_t pagesz; /* page size */
|
||||
static size_t pagebucket; /* page size bucket */
|
||||
static size_t pageshift; /* page size shift */
|
||||
|
||||
#ifdef MSTATS
|
||||
/*
|
||||
@@ -207,6 +210,7 @@ imalloc(size_t nbytes)
|
||||
bucket++;
|
||||
}
|
||||
pagebucket = bucket;
|
||||
pageshift = ffs(pagesz) - 1;
|
||||
}
|
||||
/*
|
||||
* Convert amount of memory requested into closest block size
|
||||
@@ -281,13 +285,13 @@ morecore(size_t bucket)
|
||||
#endif
|
||||
if (sz < pagesz) {
|
||||
amt = pagesz;
|
||||
nblks = amt / sz;
|
||||
nblks = amt >> (bucket + 3);
|
||||
} else {
|
||||
amt = sz + pagesz;
|
||||
nblks = 1;
|
||||
}
|
||||
if (amt > PAGEPOOL_SIZE)
|
||||
if (morepages(amt/pagesz + NPOOLPAGES) == 0)
|
||||
if (morepages((amt >> pageshift) + NPOOLPAGES) == 0)
|
||||
return;
|
||||
op = (union overhead *)pagepool_start;
|
||||
pagepool_start += amt;
|
||||
@@ -413,10 +417,6 @@ mstats(char *s)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Minix mmap can do this. */
|
||||
#ifdef __minix
|
||||
#define mmap minix_mmap
|
||||
#endif
|
||||
|
||||
static int
|
||||
morepages(int n)
|
||||
|
||||
Reference in New Issue
Block a user