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:
2012-11-15 12:06:41 +01:00
parent f6aac1c3b5
commit f14fb60209
1285 changed files with 44244 additions and 14308 deletions

View File

@@ -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

View 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.

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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

View 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();
}

View File

@@ -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 */

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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) */

View File

@@ -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 *);

View File

@@ -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 *);

View File

@@ -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
View 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
View 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 */

View File

@@ -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)