mirror of https://gitee.com/Nocallback/glibc.git
Browse Source
After static dlopen, a copy of ld.so is loaded into the inner namespace, but that copy is not initialized at all. Some architectures run into serious problems as result, which is why the _dl_var_init mechanism was invented. With libpthread moving into libc and parts into ld.so, more architectures impacted, so it makes sense to switch to a generic mechanism which performs the partial initialization. As a result, getauxval now works after static dlopen (bug 20802). Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>codonell/c-utf8
8 changed files with 208 additions and 13 deletions
@ -0,0 +1,56 @@ |
|||
/* Partial initialization of ld.so loaded via static dlopen.
|
|||
Copyright (C) 2021 Free Software Foundation, Inc. |
|||
This file is part of the GNU C Library. |
|||
|
|||
The GNU C Library is free software; you can redistribute it and/or |
|||
modify it under the terms of the GNU Lesser General Public |
|||
License as published by the Free Software Foundation; either |
|||
version 2.1 of the License, or (at your option) any later version. |
|||
|
|||
The GNU C Library is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|||
Lesser General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU Lesser General Public |
|||
License along with the GNU C Library; if not, see |
|||
<https://www.gnu.org/licenses/>. */
|
|||
|
|||
#include <assert.h> |
|||
|
|||
/* Very special case: This object is built into the static libc, but
|
|||
must know the layout of _rtld_global_ro. */ |
|||
#define SHARED |
|||
#include <ldsodefs.h> |
|||
|
|||
#include <rtld_static_init.h> |
|||
|
|||
void |
|||
__rtld_static_init (struct link_map *map) |
|||
{ |
|||
const ElfW(Sym) *sym |
|||
= _dl_lookup_direct (map, "_rtld_global_ro", |
|||
0x9f28436a, /* dl_new_hash output. */ |
|||
"GLIBC_PRIVATE", |
|||
0x0963cf85); /* _dl_elf_hash output. */ |
|||
assert (sym != NULL); |
|||
struct rtld_global_ro *dl = DL_SYMBOL_ADDRESS (map, sym); |
|||
|
|||
/* Perform partial initialization here. Note that this runs before
|
|||
ld.so is relocated, so only members initialized without |
|||
relocations can be written here. */ |
|||
#ifdef HAVE_AUX_VECTOR |
|||
extern __typeof (dl->_dl_auxv) _dl_auxv attribute_hidden; |
|||
dl->_dl_auxv = _dl_auxv; |
|||
extern __typeof (dl->_dl_clktck) _dl_clktck attribute_hidden; |
|||
dl->_dl_clktck = _dl_clktck; |
|||
#endif |
|||
extern __typeof (dl->_dl_hwcap) _dl_hwcap attribute_hidden; |
|||
dl->_dl_hwcap = _dl_hwcap; |
|||
extern __typeof (dl->_dl_hwcap2) _dl_hwcap2 attribute_hidden; |
|||
dl->_dl_hwcap2 = _dl_hwcap2; |
|||
extern __typeof (dl->_dl_pagesize) _dl_pagesize attribute_hidden; |
|||
dl->_dl_pagesize = _dl_pagesize; |
|||
|
|||
__rtld_static_init_arch (map, dl); |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
/* Wrapper for getauxval testing.
|
|||
Copyright (C) 2021 Free Software Foundation, Inc. |
|||
This file is part of the GNU C Library. |
|||
|
|||
The GNU C Library is free software; you can redistribute it and/or |
|||
modify it under the terms of the GNU Lesser General Public |
|||
License as published by the Free Software Foundation; either |
|||
version 2.1 of the License, or (at your option) any later version. |
|||
|
|||
The GNU C Library is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|||
Lesser General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU Lesser General Public |
|||
License along with the GNU C Library; if not, see |
|||
<https://www.gnu.org/licenses/>. */
|
|||
|
|||
#include <errno.h> |
|||
#include <sys/auxv.h> |
|||
|
|||
unsigned long |
|||
getauxval_wrapper (unsigned long type, int *errnop) |
|||
{ |
|||
errno = *errnop; |
|||
unsigned long result = getauxval (type); |
|||
*errnop = errno; |
|||
return result; |
|||
} |
|||
@ -0,0 +1,66 @@ |
|||
/* Test getauxval from a dynamic library after static dlopen.
|
|||
Copyright (C) 2021 Free Software Foundation, Inc. |
|||
This file is part of the GNU C Library. |
|||
|
|||
The GNU C Library is free software; you can redistribute it and/or |
|||
modify it under the terms of the GNU Lesser General Public |
|||
License as published by the Free Software Foundation; either |
|||
version 2.1 of the License, or (at your option) any later version. |
|||
|
|||
The GNU C Library is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|||
Lesser General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU Lesser General Public |
|||
License along with the GNU C Library; if not, see |
|||
<https://www.gnu.org/licenses/>. */
|
|||
|
|||
#include <dlfcn.h> |
|||
#include <errno.h> |
|||
#include <stdio.h> |
|||
#include <support/check.h> |
|||
#include <support/xdlfcn.h> |
|||
#include <sys/auxv.h> |
|||
|
|||
unsigned long getauxval_wrapper (unsigned long type, int *errnop); |
|||
|
|||
static int |
|||
do_test (void) |
|||
{ |
|||
unsigned long outer_random = getauxval (AT_RANDOM); |
|||
if (outer_random == 0) |
|||
FAIL_UNSUPPORTED ("getauxval does not support AT_RANDOM"); |
|||
|
|||
unsigned long missing_auxv_type; |
|||
for (missing_auxv_type = AT_RANDOM + 1; ; ++missing_auxv_type) |
|||
{ |
|||
errno = 0; |
|||
if (getauxval (missing_auxv_type) == 0 && errno != 0) |
|||
{ |
|||
TEST_COMPARE (errno, ENOENT); |
|||
break; |
|||
} |
|||
} |
|||
printf ("info: first missing type: %lu\n", missing_auxv_type); |
|||
|
|||
void *handle = xdlopen ("tst-auxvalmod.so", RTLD_LAZY); |
|||
void *ptr = xdlsym (handle, "getauxval_wrapper"); |
|||
|
|||
__typeof__ (getauxval_wrapper) *wrapper = ptr; |
|||
int inner_errno = 0; |
|||
unsigned long inner_random = wrapper (AT_RANDOM, &inner_errno); |
|||
TEST_COMPARE (outer_random, inner_random); |
|||
|
|||
inner_errno = 0; |
|||
TEST_COMPARE (wrapper (missing_auxv_type, &inner_errno), 0); |
|||
TEST_COMPARE (inner_errno, ENOENT); |
|||
|
|||
TEST_COMPARE (getauxval (AT_HWCAP), wrapper (AT_HWCAP, &inner_errno)); |
|||
TEST_COMPARE (getauxval (AT_HWCAP2), wrapper (AT_HWCAP2, &inner_errno)); |
|||
|
|||
xdlclose (handle); |
|||
return 0; |
|||
} |
|||
|
|||
#include <support/test-driver.c> |
|||
@ -0,0 +1,24 @@ |
|||
/* Partial initialization of ld.so loaded via static dlopen. Generic helper.
|
|||
Copyright (C) 2021 Free Software Foundation, Inc. |
|||
This file is part of the GNU C Library. |
|||
|
|||
The GNU C Library is free software; you can redistribute it and/or |
|||
modify it under the terms of the GNU Lesser General Public |
|||
License as published by the Free Software Foundation; either |
|||
version 2.1 of the License, or (at your option) any later version. |
|||
|
|||
The GNU C Library is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|||
Lesser General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU Lesser General Public |
|||
License along with the GNU C Library; if not, see |
|||
<https://www.gnu.org/licenses/>. */
|
|||
|
|||
static inline void |
|||
__rtld_static_init_arch (struct link_map *map, struct rtld_global_ro *dl) |
|||
{ |
|||
/* The generic helper does not perform any additional
|
|||
initialization. */ |
|||
} |
|||
Loading…
Reference in new issue