diff --git a/distrib/sets/lists/debug/mi b/distrib/sets/lists/debug/mi index ff71dc1e5590..5c55c7895edc 100644 --- a/distrib/sets/lists/debug/mi +++ b/distrib/sets/lists/debug/mi @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.243 2018/02/17 08:07:06 wiz Exp $ +# $NetBSD: mi,v 1.244 2018/03/09 20:20:48 joerg Exp $ ./etc/mtree/set.debug comp-sys-root ./usr/lib comp-sys-usr compatdir ./usr/lib/i18n/libBIG5_g.a comp-c-debuglib debuglib,compatfile @@ -1865,6 +1865,7 @@ ./usr/libdata/debug/usr/tests/kyua-testers/stacktrace_helper.debug tests-kyua-tests debug,atf,kyua,compattestfile ./usr/libdata/debug/usr/tests/kyua-testers/stacktrace_test.debug tests-kyua-tests debug,atf,kyua,compattestfile ./usr/libdata/debug/usr/tests/kyua-testers/text_test.debug tests-kyua-tests debug,atf,kyua,compattestfile +./usr/libdata/debug/usr/tests/lib/csu/h_ifunc_static.debug tests-lib-debug debug,atf,compattestfile ./usr/libdata/debug/usr/tests/lib/csu/h_initfini.debug tests-obsolete obsolete,compattestfile ./usr/libdata/debug/usr/tests/lib/csu/h_initfini1.debug tests-lib-debug debug,atf,compattestfile ./usr/libdata/debug/usr/tests/lib/csu/h_initfini2.debug tests-lib-debug debug,atf,compattestfile diff --git a/distrib/sets/lists/tests/mi b/distrib/sets/lists/tests/mi index ee02b74eeae8..33b6c48915f1 100644 --- a/distrib/sets/lists/tests/mi +++ b/distrib/sets/lists/tests/mi @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.775 2018/02/22 14:24:03 martin Exp $ +# $NetBSD: mi,v 1.776 2018/03/09 20:20:48 joerg Exp $ # # Note: don't delete entries from here - mark them as "obsolete" instead. # @@ -2399,11 +2399,13 @@ ./usr/tests/lib/csu tests-lib-tests compattestfile,atf ./usr/tests/lib/csu/Atffile tests-lib-tests compattestfile,atf ./usr/tests/lib/csu/Kyuafile tests-lib-tests compattestfile,atf,kyua +./usr/tests/lib/csu/h_ifunc_static tests-lib-tests compattestfile,atf ./usr/tests/lib/csu/h_initfini tests-obsolete obsolete ./usr/tests/lib/csu/h_initfini1 tests-lib-tests compattestfile,atf ./usr/tests/lib/csu/h_initfini2 tests-lib-tests compattestfile,atf ./usr/tests/lib/csu/h_initfini3 tests-lib-tests compattestfile,atf ./usr/tests/lib/csu/t_crt0 tests-lib-tests compattestfile,atf +./usr/tests/lib/csu/t_ifunc_static tests-lib-tests compattestfile,atf ./usr/tests/lib/libbluetooth tests-lib-tests compattestfile,atf ./usr/tests/lib/libbluetooth/Atffile tests-lib-tests compattestfile,atf ./usr/tests/lib/libbluetooth/Kyuafile tests-lib-tests compattestfile,atf,kyua diff --git a/lib/csu/common/crt0-common.c b/lib/csu/common/crt0-common.c index e1b0bd93c4a6..7c2aba2b2f65 100644 --- a/lib/csu/common/crt0-common.c +++ b/lib/csu/common/crt0-common.c @@ -1,4 +1,4 @@ -/* $NetBSD: crt0-common.c,v 1.14 2016/06/07 12:07:35 joerg Exp $ */ +/* $NetBSD: crt0-common.c,v 1.15 2018/03/09 20:20:47 joerg Exp $ */ /* * Copyright (c) 1998 Christos Zoulas @@ -36,7 +36,7 @@ */ #include -__RCSID("$NetBSD: crt0-common.c,v 1.14 2016/06/07 12:07:35 joerg Exp $"); +__RCSID("$NetBSD: crt0-common.c,v 1.15 2018/03/09 20:20:47 joerg Exp $"); #include #include @@ -127,6 +127,74 @@ _fini(void) } #endif /* HAVE_INITFINI_ARRAY */ +#if defined(__x86_64__) || defined(__powerpc__) || defined(__sparc__) +#define HAS_IPLTA +static void fix_iplta(void) __noinline; +#elif defined(__i386__) || defined(__arm__) +#define HAS_IPLT +static void fix_iplt(void) __noinline; +#endif + + +#ifdef HAS_IPLTA +#include +extern const Elf_Rela __rela_iplt_start[] __dso_hidden __weak; +extern const Elf_Rela __rela_iplt_end[] __dso_hidden __weak; + +static void +fix_iplta(void) +{ + const Elf_Rela *rela, *relalim; + uintptr_t relocbase = 0; + Elf_Addr *where, target; + + rela = __rela_iplt_start; + relalim = __rela_iplt_end; +#if DEBUG + printf("%p - %p\n", rela, relalim); +#endif + for (; rela < relalim; ++rela) { + if (ELF_R_TYPE(rela->r_info) != R_TYPE(IRELATIVE)) + abort(); + where = (Elf_Addr *)(relocbase + rela->r_offset); +#if DEBUG + printf("location: %p\n", where); +#endif + target = (Elf_Addr)(relocbase + rela->r_addend); +#if DEBUG + printf("target: %p\n", (void *)target); +#endif + target = ((Elf_Addr(*)(void))target)(); +#if DEBUG + printf("...resolves to: %p\n", (void *)target); +#endif + *where = target; + } +} +#endif +#ifdef HAS_IPLT +extern const Elf_Rel __rel_iplt_start[] __dso_hidden __weak; +extern const Elf_Rel __rel_iplt_end[] __dso_hidden __weak; + +static void +fix_iplt(void) +{ + const Elf_Rel *rel, *rellim; + uintptr_t relocbase = 0; + Elf_Addr *where, target; + + rel = __rel_iplt_start; + rellim = __rel_iplt_end; + for (; rel < rellim; ++rel) { + if (ELF_R_TYPE(rel->r_info) != R_TYPE(IRELATIVE)) + abort(); + where = (Elf_Addr *)(relocbase + rel->r_offset); + target = ((Elf_Addr(*)(void))*where)(); + *where = target; + } +} +#endif + void ___start(void (*cleanup)(void), /* from shared loader */ const Obj_Entry *obj, /* from shared loader */ @@ -162,6 +230,15 @@ ___start(void (*cleanup)(void), /* from shared loader */ _libc_init(); + if (&rtld_DYNAMIC == NULL) { +#ifdef HAS_IPLTA + fix_iplta(); +#endif +#ifdef HAS_IPLT + fix_iplt(); +#endif + } + #ifdef HAVE_INITFINI_ARRAY _preinit(); #endif diff --git a/tests/lib/csu/Makefile b/tests/lib/csu/Makefile index 1c282249cefe..37f87e3f191c 100644 --- a/tests/lib/csu/Makefile +++ b/tests/lib/csu/Makefile @@ -1,11 +1,11 @@ -# $NetBSD: Makefile,v 1.5 2016/04/04 09:52:02 joerg Exp $ +# $NetBSD: Makefile,v 1.6 2018/03/09 20:20:47 joerg Exp $ NOMAN= # defined .include TESTSDIR= ${TESTSBASE}/lib/csu -TESTS_SH= t_crt0 +TESTS_SH= t_crt0 t_ifunc_static TESTS_SUBDIRS= SUBDIR+= dso @@ -24,4 +24,8 @@ SRCS.h_initfini3= h_initfini3.cxx h_initfini_common.cxx \ ${SRCS_CHECK_STACK} LDADD.h_initfini3+= -Wl,-rpath,${TESTSDIR} +PROGS+= h_ifunc_static +SRCS.h_ifunc_static= h_ifunc_static.c +LDSTATIC.h_ifunc_static=-static + .include diff --git a/tests/lib/csu/h_ifunc_static.c b/tests/lib/csu/h_ifunc_static.c new file mode 100644 index 000000000000..622fe6da501f --- /dev/null +++ b/tests/lib/csu/h_ifunc_static.c @@ -0,0 +1,64 @@ +/* $NetBSD: h_ifunc_static.c,v 1.1 2018/03/09 20:20:47 joerg Exp $ */ + +/*- + * Copyright (c) 2018 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 +#include + +static long long +ifunc1(void) +{ + return 0xdeadbeefll; +} + +static long long +ifunc2(void) +{ + return 0xbeefdeadll; +} + +static __attribute__((used)) +long long (*resolve_ifunc(void))(void) +{ + const char *e = getenv("USE_IFUNC2"); + return e && strcmp(e, "1") == 0 ? ifunc2 : ifunc1; +} + +__ifunc(ifunc, resolve_ifunc); +extern long long ifunc(void); + +int +main(int argc, char **argv) +{ + + if (argc != 2) + return 1; + return atoll(argv[1]) != ifunc(); +} diff --git a/tests/lib/csu/t_ifunc_static.sh b/tests/lib/csu/t_ifunc_static.sh new file mode 100644 index 000000000000..51debbe7a7ab --- /dev/null +++ b/tests/lib/csu/t_ifunc_static.sh @@ -0,0 +1,56 @@ +# $NetBSD: t_ifunc_static.sh,v 1.1 2018/03/09 20:20:47 joerg Exp $ +# +# Copyright (c) 2018 The NetBSD Foundation, Inc. +# 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 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. +# + +atf_test_case ifunc_static +ifunc_static_head() +{ + atf_set "descr" "Checks support for ifunc relocations in static binaries" +} +ifunc_static_body() +{ + case `uname -m` in + i386|amd64|*ppc*|*sparc*|*arm*) + ;; + *) + atf_skip "ifunc is supposed only on ARM, i386, PowerPC, SPARC and x86-64" + ;; + esac + + USE_IFUNC2=0 "$(atf_get_srcdir)/h_ifunc_static" 3735928559 + atf_check_equal $? 0 + USE_IFUNC2=0 "$(atf_get_srcdir)/h_ifunc_static" 3203391149 + atf_check_equal $? 1 + USE_IFUNC2=1 "$(atf_get_srcdir)/h_ifunc_static" 3735928559 + atf_check_equal $? 1 + USE_IFUNC2=1 "$(atf_get_srcdir)/h_ifunc_static" 3203391149 + atf_check_equal $? 0 +} + +atf_init_test_cases() +{ + atf_add_test_case ifunc_static +}