From 9e78f6f6e7134a5f299cc8de77370218f8019237 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Wed, 30 Nov 2016 15:59:57 +0100 Subject: Implement _dl_catch_error, _dl_signal_error in libc.so [BZ #16628] This change moves the main implementation of _dl_catch_error, _dl_signal_error to libc.so, where TLS variables can be used directly. This removes a writable function pointer from the rtld_global variable. For use during initial relocation, minimal implementations of these functions are provided in ld.so. These are eventually interposed by the libc.so implementations. This is implemented by compiling elf/dl-error-skeleton.c twice, via elf/dl-error.c and elf/dl-error-minimal.c. As a side effect of this change, the static version of dl-error.c no longer includes support for the _dl_signal_cerror/_dl_receive_error mechanism because it is only used in ld.so. --- elf/Versions | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'elf/Versions') diff --git a/elf/Versions b/elf/Versions index 23deda984f..05e5449f4d 100644 --- a/elf/Versions +++ b/elf/Versions @@ -26,6 +26,9 @@ libc { _dl_open_hook; _dl_sym; _dl_vsym; __libc_dlclose; __libc_dlopen_mode; __libc_dlsym; + + # Internal error handling support. Interposes the functions in ld.so. + _dl_signal_error; _dl_catch_error; } } @@ -64,5 +67,8 @@ ld { # Pointer protection. __pointer_chk_guard; + + # Internal error handling support. Interposed by libc.so. + _dl_signal_error; _dl_catch_error; } } -- cgit v1.2.3 From b04beebf0731c0da49bf9113bf299acf56e4c2e5 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Wed, 30 Nov 2016 16:23:58 +0100 Subject: ld.so: Remove __libc_memalign It is no longer needed since commit 6c444ad6e953dbdf9c7be065308a0a777 (elf: Do not use memalign for TCB/TLS blocks allocation [BZ #17730]). Applications do not link against ld.so and will use the definition in libc.so, so there is no ABI impact. --- ChangeLog | 57 ++++++++++++++++++++++ elf/Versions | 4 +- elf/dl-minimal.c | 18 +++---- sysdeps/generic/localplt.data | 6 +-- sysdeps/nacl/ld.abilist | 1 - sysdeps/unix/sysv/linux/aarch64/ld.abilist | 1 - sysdeps/unix/sysv/linux/aarch64/localplt.data | 7 ++- sysdeps/unix/sysv/linux/alpha/ld.abilist | 1 - sysdeps/unix/sysv/linux/alpha/localplt.data | 7 ++- sysdeps/unix/sysv/linux/arm/ld.abilist | 1 - sysdeps/unix/sysv/linux/arm/localplt.data | 7 ++- sysdeps/unix/sysv/linux/hppa/ld.abilist | 1 - sysdeps/unix/sysv/linux/hppa/localplt.data | 6 +-- sysdeps/unix/sysv/linux/i386/ld.abilist | 1 - sysdeps/unix/sysv/linux/i386/localplt.data | 6 +-- sysdeps/unix/sysv/linux/ia64/ld.abilist | 1 - sysdeps/unix/sysv/linux/ia64/localplt.data | 6 +-- sysdeps/unix/sysv/linux/m68k/coldfire/ld.abilist | 1 - sysdeps/unix/sysv/linux/m68k/localplt.data | 6 +-- sysdeps/unix/sysv/linux/m68k/m680x0/ld.abilist | 1 - sysdeps/unix/sysv/linux/microblaze/ld.abilist | 1 - sysdeps/unix/sysv/linux/microblaze/localplt.data | 7 ++- sysdeps/unix/sysv/linux/mips/mips32/ld.abilist | 1 - sysdeps/unix/sysv/linux/mips/mips64/n32/ld.abilist | 1 - sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist | 1 - sysdeps/unix/sysv/linux/nios2/ld.abilist | 1 - sysdeps/unix/sysv/linux/nios2/localplt.data | 6 +-- .../sysv/linux/powerpc/powerpc32/fpu/localplt.data | 6 +-- .../unix/sysv/linux/powerpc/powerpc32/ld.abilist | 1 - .../linux/powerpc/powerpc32/nofpu/localplt.data | 6 +-- .../sysv/linux/powerpc/powerpc64/ld-le.abilist | 1 - .../unix/sysv/linux/powerpc/powerpc64/ld.abilist | 1 - .../sysv/linux/powerpc/powerpc64/localplt.data | 6 +-- sysdeps/unix/sysv/linux/s390/localplt.data | 13 +---- sysdeps/unix/sysv/linux/s390/s390-32/ld.abilist | 1 - sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist | 1 - sysdeps/unix/sysv/linux/sh/ld.abilist | 1 - sysdeps/unix/sysv/linux/sh/localplt.data | 6 +-- sysdeps/unix/sysv/linux/sparc/sparc32/ld.abilist | 1 - .../unix/sysv/linux/sparc/sparc32/localplt.data | 6 +-- sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist | 1 - .../unix/sysv/linux/sparc/sparc64/localplt.data | 6 +-- .../sysv/linux/tile/tilegx/tilegx32/ld.abilist | 1 - .../sysv/linux/tile/tilegx/tilegx64/ld.abilist | 1 - sysdeps/unix/sysv/linux/tile/tilepro/ld.abilist | 1 - sysdeps/unix/sysv/linux/x86_64/64/ld.abilist | 1 - sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist | 1 - sysdeps/x86_64/localplt.data | 6 +-- 48 files changed, 106 insertions(+), 119 deletions(-) (limited to 'elf/Versions') diff --git a/ChangeLog b/ChangeLog index d01747866e..09c2e52afd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,60 @@ +2016-11-30 Florian Weimer + + Remove __libc_memalign from ld.so because it is unused. + * elf/dl-minimal.c: Update comment on the malloc implementation. + (malloc): Renamed from __libc_memalign, replacing the original + malloc implementation. Replace the align parameter with + MALLOC_ALIGNMENT. + * elf/Versions (ld): Update comment and remove __libc_memalign. + * sysdeps/nacl/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/aarch64/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/alpha/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/arm/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/hppa/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/i386/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/ia64/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/m68k/coldfire/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/m68k/m680x0/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/microblaze/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/mips/mips32/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/mips/mips64/n32/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/nios2/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/ld-le.abilist: Likewise. + * sysdeps/unix/sysv/linux/s390/s390-32/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/sh/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc32/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/tile/tilepro/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/x86_64/64/ld.abilist: Likewise. + * sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist: Likewise. + * sysdeps/generic/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/aarch64/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/alpha/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/arm/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/hppa/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/i386/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/ia64/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/m68k/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/microblaze/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/nios2/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data + (ld.so): Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data + (ld.so): Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data (ld.so): + Likewise. + * sysdeps/unix/sysv/linux/s390/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/sh/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data (ld.so): Likewise. + * sysdeps/x86_64/localplt.data (ld.so): Likewise. + 2016-11-30 Florian Weimer [BZ #16628] diff --git a/elf/Versions b/elf/Versions index 05e5449f4d..08f76a7a20 100644 --- a/elf/Versions +++ b/elf/Versions @@ -34,8 +34,8 @@ libc { ld { GLIBC_2.0 { - # Function from libc.so which must be shared with libc. - __libc_memalign; calloc; free; malloc; realloc; + # Functions which are interposed from libc.so. + calloc; free; malloc; realloc; _r_debug; } diff --git a/elf/dl-minimal.c b/elf/dl-minimal.c index 6034b5a3fa..116ec4978c 100644 --- a/elf/dl-minimal.c +++ b/elf/dl-minimal.c @@ -31,8 +31,10 @@ #include -/* Minimal `malloc' allocator for use while loading shared libraries. - No block is ever freed. */ +/* Minimal malloc allocator for used during initial link. After the + initial link, a full malloc implementation is interposed, either + the one in libc, or a different one supplied by the user through + interposition. */ static void *alloc_ptr, *alloc_end, *alloc_last_block; @@ -49,7 +51,7 @@ extern unsigned long int weak_function strtoul (const char *nptr, /* Allocate an aligned memory block. */ void * weak_function -__libc_memalign (size_t align, size_t n) +malloc (size_t n) { if (alloc_end == 0) { @@ -62,8 +64,8 @@ __libc_memalign (size_t align, size_t n) } /* Make sure the allocation pointer is ideally aligned. */ - alloc_ptr = (void *) 0 + (((alloc_ptr - (void *) 0) + align - 1) - & ~(align - 1)); + alloc_ptr = (void *) 0 + (((alloc_ptr - (void *) 0) + MALLOC_ALIGNMENT - 1) + & ~(MALLOC_ALIGNMENT - 1)); if (alloc_ptr + n >= alloc_end || n >= -(uintptr_t) alloc_ptr) { @@ -88,12 +90,6 @@ __libc_memalign (size_t align, size_t n) return alloc_last_block; } -void * weak_function -malloc (size_t n) -{ - return __libc_memalign (MALLOC_ALIGNMENT, n); -} - /* We use this function occasionally since the real implementation may be optimized when it can assume the memory it returns already is set to NUL. */ diff --git a/sysdeps/generic/localplt.data b/sysdeps/generic/localplt.data index 5cf53a4c21..81c741b038 100644 --- a/sysdeps/generic/localplt.data +++ b/sysdeps/generic/localplt.data @@ -7,10 +7,8 @@ libc.so: malloc libc.so: memalign libc.so: realloc libm.so: matherr -# The dynamic loader uses __libc_memalign internally to allocate aligned -# TLS storage. The other malloc family of functions are expected to allow -# user symbol interposition. -ld.so: __libc_memalign +# The main malloc is interposed into the dynamic linker, for +# allocations after the initial link (when dlopen is used). ld.so: malloc ld.so: calloc ld.so: realloc diff --git a/sysdeps/nacl/ld.abilist b/sysdeps/nacl/ld.abilist index 242f6d0723..0a52a24cad 100644 --- a/sysdeps/nacl/ld.abilist +++ b/sysdeps/nacl/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.22 GLIBC_2.22 A -GLIBC_2.22 __libc_memalign F GLIBC_2.22 __libc_stack_end D 0x4 GLIBC_2.22 __stack_chk_guard D 0x4 GLIBC_2.22 __tls_get_addr F diff --git a/sysdeps/unix/sysv/linux/aarch64/ld.abilist b/sysdeps/unix/sysv/linux/aarch64/ld.abilist index ab08a9845f..ec7f6174c5 100644 --- a/sysdeps/unix/sysv/linux/aarch64/ld.abilist +++ b/sysdeps/unix/sysv/linux/aarch64/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.17 GLIBC_2.17 A -GLIBC_2.17 __libc_memalign F GLIBC_2.17 __libc_stack_end D 0x8 GLIBC_2.17 __stack_chk_guard D 0x8 GLIBC_2.17 __tls_get_addr F diff --git a/sysdeps/unix/sysv/linux/aarch64/localplt.data b/sysdeps/unix/sysv/linux/aarch64/localplt.data index e431f368e3..bb18ff9bb2 100644 --- a/sysdeps/unix/sysv/linux/aarch64/localplt.data +++ b/sysdeps/unix/sysv/linux/aarch64/localplt.data @@ -7,11 +7,10 @@ libc.so: malloc libc.so: memalign libc.so: realloc libm.so: matherr -# The dynamic loader needs __tls_get_addr for TLS, and uses __libc_memalign -# internally to allocate aligned TLS storage. The other malloc family of -# functions are expected to allow user symbol interposition. +# The dynamic loader needs __tls_get_addr for TLS. ld.so: __tls_get_addr -ld.so: __libc_memalign +# The main malloc is interposed into the dynamic linker, for +# allocations after the initial link (when dlopen is used). ld.so: malloc ld.so: calloc ld.so: realloc diff --git a/sysdeps/unix/sysv/linux/alpha/ld.abilist b/sysdeps/unix/sysv/linux/alpha/ld.abilist index 9faf6eb2c6..ca34294610 100644 --- a/sysdeps/unix/sysv/linux/alpha/ld.abilist +++ b/sysdeps/unix/sysv/linux/alpha/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.0 GLIBC_2.0 A -GLIBC_2.0 __libc_memalign F GLIBC_2.0 _r_debug D 0x28 GLIBC_2.0 calloc F GLIBC_2.0 free F diff --git a/sysdeps/unix/sysv/linux/alpha/localplt.data b/sysdeps/unix/sysv/linux/alpha/localplt.data index 298439365f..cca17f1e34 100644 --- a/sysdeps/unix/sysv/linux/alpha/localplt.data +++ b/sysdeps/unix/sysv/linux/alpha/localplt.data @@ -24,11 +24,10 @@ libm.so: matherr # We used to offer inline functions that used this, so it must be exported. # Ought to reorg things such that carg isn't thus forced to use a plt. libm.so: __atan2 -# The dynamic loader needs __tls_get_addr for TLS, and uses __libc_memalign -# internally to allocate aligned TLS storage. The other malloc family of -# functions are expected to allow user symbol interposition. +# The dynamic loader needs __tls_get_addr for TLS. ld.so: __tls_get_addr ? -ld.so: __libc_memalign + RELA R_ALPHA_GLOB_DAT +# The main malloc is interposed into the dynamic linker, for +# allocations after the initial link (when dlopen is used). ld.so: malloc + RELA R_ALPHA_GLOB_DAT ld.so: calloc + RELA R_ALPHA_GLOB_DAT ld.so: realloc + RELA R_ALPHA_GLOB_DAT diff --git a/sysdeps/unix/sysv/linux/arm/ld.abilist b/sysdeps/unix/sysv/linux/arm/ld.abilist index 4de351ea3f..cbf3a3cb2e 100644 --- a/sysdeps/unix/sysv/linux/arm/ld.abilist +++ b/sysdeps/unix/sysv/linux/arm/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.4 GLIBC_2.4 A -GLIBC_2.4 __libc_memalign F GLIBC_2.4 __libc_stack_end D 0x4 GLIBC_2.4 __stack_chk_guard D 0x4 GLIBC_2.4 __tls_get_addr F diff --git a/sysdeps/unix/sysv/linux/arm/localplt.data b/sysdeps/unix/sysv/linux/arm/localplt.data index a5ccd7fa58..8bc876dd03 100644 --- a/sysdeps/unix/sysv/linux/arm/localplt.data +++ b/sysdeps/unix/sysv/linux/arm/localplt.data @@ -7,11 +7,10 @@ libc.so: realloc libm.so: matherr libpthread.so: __errno_location libpthread.so: raise -# The dynamic loader needs __tls_get_addr for TLS, and uses __libc_memalign -# internally to allocate aligned TLS storage. The other malloc family of -# functions are expected to allow user symbol interposition. +# The dynamic loader needs __tls_get_addr for TLS. ld.so: __tls_get_addr -ld.so: __libc_memalign +# The main malloc is interposed into the dynamic linker, for +# allocations after the initial link (when dlopen is used). ld.so: malloc ld.so: calloc ld.so: realloc diff --git a/sysdeps/unix/sysv/linux/hppa/ld.abilist b/sysdeps/unix/sysv/linux/hppa/ld.abilist index dc3ebf48c5..fc1c60ea17 100644 --- a/sysdeps/unix/sysv/linux/hppa/ld.abilist +++ b/sysdeps/unix/sysv/linux/hppa/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.2 GLIBC_2.2 A -GLIBC_2.2 __libc_memalign F GLIBC_2.2 __libc_stack_end D 0x4 GLIBC_2.2 _dl_mcount F GLIBC_2.2 _r_debug D 0x14 diff --git a/sysdeps/unix/sysv/linux/hppa/localplt.data b/sysdeps/unix/sysv/linux/hppa/localplt.data index fea8c9cbf6..9dd81b47c8 100644 --- a/sysdeps/unix/sysv/linux/hppa/localplt.data +++ b/sysdeps/unix/sysv/linux/hppa/localplt.data @@ -13,10 +13,8 @@ libc.so: sigprocmask libc.so: __errno_location libm.so: matherr libpthread.so: __errno_location -# The dynamic loader uses __libc_memalign internally to allocate aligned -# TLS storage. The other malloc family of functions are expected to allow -# user symbol interposition. -ld.so: __libc_memalign +# The main malloc is interposed into the dynamic linker, for +# allocations after the initial link (when dlopen is used). ld.so: malloc ld.so: calloc ld.so: realloc diff --git a/sysdeps/unix/sysv/linux/i386/ld.abilist b/sysdeps/unix/sysv/linux/i386/ld.abilist index b8914ed642..ddf9e78ec2 100644 --- a/sysdeps/unix/sysv/linux/i386/ld.abilist +++ b/sysdeps/unix/sysv/linux/i386/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.0 GLIBC_2.0 A -GLIBC_2.0 __libc_memalign F GLIBC_2.0 _r_debug D 0x14 GLIBC_2.0 calloc F GLIBC_2.0 free F diff --git a/sysdeps/unix/sysv/linux/i386/localplt.data b/sysdeps/unix/sysv/linux/i386/localplt.data index 48bcc42a67..2c2584956d 100644 --- a/sysdeps/unix/sysv/linux/i386/localplt.data +++ b/sysdeps/unix/sysv/linux/i386/localplt.data @@ -7,10 +7,8 @@ libc.so: malloc + REL R_386_GLOB_DAT libc.so: memalign + REL R_386_GLOB_DAT libc.so: realloc + REL R_386_GLOB_DAT libm.so: matherr -# The dynamic loader uses __libc_memalign internally to allocate aligned -# TLS storage. The other malloc family of functions are expected to allow -# user symbol interposition. -ld.so: __libc_memalign + REL R_386_GLOB_DAT +# The main malloc is interposed into the dynamic linker, for +# allocations after the initial link (when dlopen is used). ld.so: malloc + REL R_386_GLOB_DAT ld.so: calloc + REL R_386_GLOB_DAT ld.so: realloc + REL R_386_GLOB_DAT diff --git a/sysdeps/unix/sysv/linux/ia64/ld.abilist b/sysdeps/unix/sysv/linux/ia64/ld.abilist index 9041ccbe60..9b45d5e90c 100644 --- a/sysdeps/unix/sysv/linux/ia64/ld.abilist +++ b/sysdeps/unix/sysv/linux/ia64/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.2 GLIBC_2.2 A -GLIBC_2.2 __libc_memalign F GLIBC_2.2 __libc_stack_end D 0x8 GLIBC_2.2 _dl_mcount F GLIBC_2.2 _r_debug D 0x28 diff --git a/sysdeps/unix/sysv/linux/ia64/localplt.data b/sysdeps/unix/sysv/linux/ia64/localplt.data index df63530b6c..fd2b98c8b6 100644 --- a/sysdeps/unix/sysv/linux/ia64/localplt.data +++ b/sysdeps/unix/sysv/linux/ia64/localplt.data @@ -6,10 +6,8 @@ libc.so: realloc libm.so: matherr libm.so: matherrf libm.so: matherrl -# The dynamic loader uses __libc_memalign internally to allocate aligned -# TLS storage. The other malloc family of functions are expected to allow -# user symbol interposition. -ld.so: __libc_memalign +# The main malloc is interposed into the dynamic linker, for +# allocations after the initial link (when dlopen is used). ld.so: malloc ld.so: calloc ld.so: realloc diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/ld.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/ld.abilist index 4de351ea3f..cbf3a3cb2e 100644 --- a/sysdeps/unix/sysv/linux/m68k/coldfire/ld.abilist +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.4 GLIBC_2.4 A -GLIBC_2.4 __libc_memalign F GLIBC_2.4 __libc_stack_end D 0x4 GLIBC_2.4 __stack_chk_guard D 0x4 GLIBC_2.4 __tls_get_addr F diff --git a/sysdeps/unix/sysv/linux/m68k/localplt.data b/sysdeps/unix/sysv/linux/m68k/localplt.data index abfbd34f41..1a2acfdb93 100644 --- a/sysdeps/unix/sysv/linux/m68k/localplt.data +++ b/sysdeps/unix/sysv/linux/m68k/localplt.data @@ -6,10 +6,8 @@ libc.so: malloc libc.so: memalign libc.so: realloc libm.so: matherr -# The dynamic loader uses __libc_memalign internally to allocate aligned -# TLS storage. The other malloc family of functions are expected to allow -# user symbol interposition. -ld.so: __libc_memalign +# The main malloc is interposed into the dynamic linker, for +# allocations after the initial link (when dlopen is used). ld.so: malloc ld.so: calloc ld.so: realloc diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/ld.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/ld.abilist index ee3458906d..3907c9da33 100644 --- a/sysdeps/unix/sysv/linux/m68k/m680x0/ld.abilist +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.0 GLIBC_2.0 A -GLIBC_2.0 __libc_memalign F GLIBC_2.0 _r_debug D 0x14 GLIBC_2.0 calloc F GLIBC_2.0 free F diff --git a/sysdeps/unix/sysv/linux/microblaze/ld.abilist b/sysdeps/unix/sysv/linux/microblaze/ld.abilist index f486acb399..265085edc8 100644 --- a/sysdeps/unix/sysv/linux/microblaze/ld.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.18 GLIBC_2.18 A -GLIBC_2.18 __libc_memalign F GLIBC_2.18 __libc_stack_end D 0x4 GLIBC_2.18 __stack_chk_guard D 0x4 GLIBC_2.18 __tls_get_addr F diff --git a/sysdeps/unix/sysv/linux/microblaze/localplt.data b/sysdeps/unix/sysv/linux/microblaze/localplt.data index 697fdd0186..07bcf3b29a 100644 --- a/sysdeps/unix/sysv/linux/microblaze/localplt.data +++ b/sysdeps/unix/sysv/linux/microblaze/localplt.data @@ -6,11 +6,10 @@ libc.so: memalign libc.so: realloc libm.so: matherr libpthread.so: __errno_location -# The dynamic loader needs __tls_get_addr for TLS, and uses __libc_memalign -# internally to allocate aligned TLS storage. The other malloc family of -# functions are expected to allow user symbol interposition. +# The dynamic loader needs __tls_get_addr for TLS. ld.so: __tls_get_addr -ld.so: __libc_memalign +# The main malloc is interposed into the dynamic linker, for +# allocations after the initial link (when dlopen is used). ld.so: malloc ld.so: calloc ld.so: realloc diff --git a/sysdeps/unix/sysv/linux/mips/mips32/ld.abilist b/sysdeps/unix/sysv/linux/mips/mips32/ld.abilist index afdb905811..651b952524 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/ld.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.0 GLIBC_2.0 A -GLIBC_2.0 __libc_memalign F GLIBC_2.0 _r_debug D 0x14 GLIBC_2.0 calloc F GLIBC_2.0 free F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/ld.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/ld.abilist index 6993e70bfa..bf55148c79 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/ld.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.0 GLIBC_2.0 A -GLIBC_2.0 __libc_memalign F GLIBC_2.0 _r_debug D 0x14 GLIBC_2.0 calloc F GLIBC_2.0 free F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist index 759e99b00c..f7ba5fd730 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.0 GLIBC_2.0 A -GLIBC_2.0 __libc_memalign F GLIBC_2.0 _r_debug D 0x28 GLIBC_2.0 calloc F GLIBC_2.0 free F diff --git a/sysdeps/unix/sysv/linux/nios2/ld.abilist b/sysdeps/unix/sysv/linux/nios2/ld.abilist index 389bdaa0cb..a127464b4b 100644 --- a/sysdeps/unix/sysv/linux/nios2/ld.abilist +++ b/sysdeps/unix/sysv/linux/nios2/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.21 GLIBC_2.21 A -GLIBC_2.21 __libc_memalign F GLIBC_2.21 __libc_stack_end D 0x4 GLIBC_2.21 __stack_chk_guard D 0x4 GLIBC_2.21 __tls_get_addr F diff --git a/sysdeps/unix/sysv/linux/nios2/localplt.data b/sysdeps/unix/sysv/linux/nios2/localplt.data index a7d774dcf8..584963d202 100644 --- a/sysdeps/unix/sysv/linux/nios2/localplt.data +++ b/sysdeps/unix/sysv/linux/nios2/localplt.data @@ -27,10 +27,8 @@ libc.so: __nedf2 libc.so: __eqdf2 libc.so: __extendsfdf2 libm.so: matherr -# The dynamic loader uses __libc_memalign internally to allocate aligned -# TLS storage. The other malloc family of functions are expected to allow -# user symbol interposition. -ld.so: __libc_memalign +# The main malloc is interposed into the dynamic linker, for +# allocations after the initial link (when dlopen is used). ld.so: malloc ld.so: calloc ld.so: realloc diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data index 4ef5bf4a7f..50006317c7 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data @@ -5,10 +5,8 @@ libc.so: malloc libc.so: memalign libc.so: realloc libm.so: matherr -# The dynamic loader uses __libc_memalign internally to allocate aligned -# TLS storage. The other malloc family of functions are expected to allow -# user symbol interposition. -ld.so: __libc_memalign +# The main malloc is interposed into the dynamic linker, for +# allocations after the initial link (when dlopen is used). ld.so: malloc ld.so: calloc ld.so: realloc diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/ld.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/ld.abilist index 2eb4d5fef1..100d133495 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/ld.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.0 GLIBC_2.0 A -GLIBC_2.0 __libc_memalign F GLIBC_2.0 _r_debug D 0x14 GLIBC_2.0 calloc F GLIBC_2.0 free F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data index c9194264dd..1c20d2f2b4 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data @@ -35,10 +35,8 @@ libc.so: realloc libm.so: copysignl ? libm.so: fabsl libm.so: matherr -# The dynamic loader uses __libc_memalign internally to allocate aligned -# TLS storage. The other malloc family of functions are expected to allow -# user symbol interposition. -ld.so: __libc_memalign +# The main malloc is interposed into the dynamic linker, for +# allocations after the initial link (when dlopen is used). ld.so: malloc ld.so: calloc ld.so: realloc diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/ld-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/ld-le.abilist index 27d451b46b..ef6159baa8 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/ld-le.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/ld-le.abilist @@ -1,5 +1,4 @@ GLIBC_2.17 GLIBC_2.17 A -GLIBC_2.17 __libc_memalign F GLIBC_2.17 __libc_stack_end D 0x8 GLIBC_2.17 __tls_get_addr F GLIBC_2.17 _dl_mcount F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/ld.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/ld.abilist index 8914eb06b4..2c3b74cc20 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/ld.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/ld.abilist @@ -3,7 +3,6 @@ GLIBC_2.22 __tls_get_addr_opt F GLIBC_2.23 GLIBC_2.23 A GLIBC_2.23 __parse_hwcap_and_convert_at_platform F GLIBC_2.3 GLIBC_2.3 A -GLIBC_2.3 __libc_memalign F GLIBC_2.3 __libc_stack_end D 0x8 GLIBC_2.3 __tls_get_addr F GLIBC_2.3 _dl_mcount F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data index 2d434726cc..6f8ed25922 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data @@ -4,10 +4,8 @@ libc.so: malloc libc.so: memalign libc.so: realloc libm.so: matherr -# The dynamic loader uses __libc_memalign internally to allocate aligned -# TLS storage. The other malloc family of functions are expected to -# allow user symbol interposition. -ld.so: __libc_memalign +# The main malloc is interposed into the dynamic linker, for +# allocations after the initial link (when dlopen is used). ld.so: malloc ld.so: calloc ld.so: realloc diff --git a/sysdeps/unix/sysv/linux/s390/localplt.data b/sysdeps/unix/sysv/linux/s390/localplt.data index bd1adddb1f..50006317c7 100644 --- a/sysdeps/unix/sysv/linux/s390/localplt.data +++ b/sysdeps/unix/sysv/linux/s390/localplt.data @@ -5,17 +5,8 @@ libc.so: malloc libc.so: memalign libc.so: realloc libm.so: matherr -# The dynamic loader uses __libc_memalign internally to allocate aligned -# TLS storage. The other malloc family of functions are expected to allow -# user symbol interposition. -# It is also allowed to call __libc_memalign via function-pointer loaded from -# GOT instead of calling via a plt-stub. In this case there is a R_390_GLOB_DAT -# relocation in section .rela.dyn instead of R_390_JMP_SLOT in .rela.plt. -# After commit "elf: Do not use memalign for TCB/TLS blocks allocation -# [BZ #17730]" __libc_memalign is only called in elf/dl-minimal.c: malloc() in -# ld.so and gcc -O2/-O3 leads to R_390_GLOB_DAT. If build with -# -fno-optimize-sibling-calls an R_390_JMP_SLOT is generated. -ld.so: __libc_memalign + RELA R_390_GLOB_DAT +# The main malloc is interposed into the dynamic linker, for +# allocations after the initial link (when dlopen is used). ld.so: malloc ld.so: calloc ld.so: realloc diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/ld.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/ld.abilist index ec7491f5d7..c16b2c1344 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-32/ld.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-32/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.0 GLIBC_2.0 A -GLIBC_2.0 __libc_memalign F GLIBC_2.0 _r_debug D 0x14 GLIBC_2.0 calloc F GLIBC_2.0 free F diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist index c2e0d9660a..5e604f5376 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.2 GLIBC_2.2 A -GLIBC_2.2 __libc_memalign F GLIBC_2.2 __libc_stack_end D 0x8 GLIBC_2.2 _dl_mcount F GLIBC_2.2 _r_debug D 0x28 diff --git a/sysdeps/unix/sysv/linux/sh/ld.abilist b/sysdeps/unix/sysv/linux/sh/ld.abilist index dc3ebf48c5..fc1c60ea17 100644 --- a/sysdeps/unix/sysv/linux/sh/ld.abilist +++ b/sysdeps/unix/sysv/linux/sh/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.2 GLIBC_2.2 A -GLIBC_2.2 __libc_memalign F GLIBC_2.2 __libc_stack_end D 0x4 GLIBC_2.2 _dl_mcount F GLIBC_2.2 _r_debug D 0x14 diff --git a/sysdeps/unix/sysv/linux/sh/localplt.data b/sysdeps/unix/sysv/linux/sh/localplt.data index e6fb930cf7..f1f5effc24 100644 --- a/sysdeps/unix/sysv/linux/sh/localplt.data +++ b/sysdeps/unix/sysv/linux/sh/localplt.data @@ -10,10 +10,8 @@ libc.so: _Unwind_Find_FDE libc.so: _exit libc.so: __errno_location libm.so: matherr -# The dynamic loader uses __libc_memalign internally to allocate aligned -# TLS storage. The other malloc family of functions are expected to allow -# user symbol interposition. -ld.so: __libc_memalign +# The main malloc is interposed into the dynamic linker, for +# allocations after the initial link (when dlopen is used). ld.so: malloc ld.so: calloc ld.so: realloc diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/ld.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/ld.abilist index 3acaae2290..fb4bcb016d 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/ld.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.0 GLIBC_2.0 A -GLIBC_2.0 __libc_memalign F GLIBC_2.0 _r_debug D 0x14 GLIBC_2.0 calloc F GLIBC_2.0 free F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data b/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data index d5b5895a5c..c9786fd6ea 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data @@ -16,10 +16,8 @@ libc.so: malloc libc.so: memalign libc.so: realloc libm.so: matherr -# The dynamic loader uses __libc_memalign internally to allocate -# aligned TLS storage. The other malloc family of functions are -# expected to allow user symbol interposition. -ld.so: __libc_memalign +# The main malloc is interposed into the dynamic linker, for +# allocations after the initial link (when dlopen is used). ld.so: malloc ld.so: calloc ld.so: realloc diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist index 9041ccbe60..9b45d5e90c 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.2 GLIBC_2.2 A -GLIBC_2.2 __libc_memalign F GLIBC_2.2 __libc_stack_end D 0x8 GLIBC_2.2 _dl_mcount F GLIBC_2.2 _r_debug D 0x28 diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data b/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data index edceab57c3..912bd1a16e 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data @@ -18,10 +18,8 @@ libc.so: malloc libc.so: memalign libc.so: realloc libm.so: matherr -# The dynamic loader uses __libc_memalign internally to allocate -# aligned TLS storage. The other malloc family of functions are -# expected to allow user symbol interposition. -ld.so: __libc_memalign +# The main malloc is interposed into the dynamic linker, for +# allocations after the initial link (when dlopen is used). ld.so: malloc ld.so: calloc ld.so: realloc diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/ld.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/ld.abilist index 3ab170cc91..f166310147 100644 --- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/ld.abilist +++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.12 GLIBC_2.12 A -GLIBC_2.12 __libc_memalign F GLIBC_2.12 __libc_stack_end D 0x4 GLIBC_2.12 __tls_get_addr F GLIBC_2.12 _dl_mcount F diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/ld.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/ld.abilist index aa6cbabfc3..ab74e7ecd1 100644 --- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/ld.abilist +++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.12 GLIBC_2.12 A -GLIBC_2.12 __libc_memalign F GLIBC_2.12 __libc_stack_end D 0x8 GLIBC_2.12 __tls_get_addr F GLIBC_2.12 _dl_mcount F diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/ld.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/ld.abilist index 3ab170cc91..f166310147 100644 --- a/sysdeps/unix/sysv/linux/tile/tilepro/ld.abilist +++ b/sysdeps/unix/sysv/linux/tile/tilepro/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.12 GLIBC_2.12 A -GLIBC_2.12 __libc_memalign F GLIBC_2.12 __libc_stack_end D 0x4 GLIBC_2.12 __tls_get_addr F GLIBC_2.12 _dl_mcount F diff --git a/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist b/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist index 9e09ac6936..07cab4bd7a 100644 --- a/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.2.5 GLIBC_2.2.5 A -GLIBC_2.2.5 __libc_memalign F GLIBC_2.2.5 __libc_stack_end D 0x8 GLIBC_2.2.5 _dl_mcount F GLIBC_2.2.5 _r_debug D 0x28 diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist index d595038b2b..236357bd83 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist @@ -1,5 +1,4 @@ GLIBC_2.16 GLIBC_2.16 A -GLIBC_2.16 __libc_memalign F GLIBC_2.16 __libc_stack_end D 0x4 GLIBC_2.16 __tls_get_addr F GLIBC_2.16 _dl_mcount F diff --git a/sysdeps/x86_64/localplt.data b/sysdeps/x86_64/localplt.data index 28096f893e..014a9f4554 100644 --- a/sysdeps/x86_64/localplt.data +++ b/sysdeps/x86_64/localplt.data @@ -9,10 +9,8 @@ libc.so: malloc + RELA R_X86_64_GLOB_DAT libc.so: memalign + RELA R_X86_64_GLOB_DAT libc.so: realloc + RELA R_X86_64_GLOB_DAT libm.so: matherr -# The dynamic loader uses __libc_memalign internally to allocate aligned -# TLS storage. The other malloc family of functions are expected to allow -# user symbol interposition. -ld.so: __libc_memalign + RELA R_X86_64_GLOB_DAT +# The main malloc is interposed into the dynamic linker, for +# allocations after the initial link (when dlopen is used). ld.so: malloc + RELA R_X86_64_GLOB_DAT ld.so: calloc + RELA R_X86_64_GLOB_DAT ld.so: realloc + RELA R_X86_64_GLOB_DAT -- cgit v1.2.3 From d08ab9ced75e0d88827e0bb58183612afb7fe1fd Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Wed, 21 Dec 2016 14:30:56 +0100 Subject: Remove unused function _dl_tls_setup Commit 7a5e3d9d633c828d84a9535f26b202a6179978e7 (elf: Assume TLS is initialized in _dl_map_object_from_fd) removed the last call of _dl_tls_setup, but did not remove the function itself. --- ChangeLog | 7 +++++++ csu/libc-tls.c | 19 ------------------- elf/Versions | 2 +- elf/dl-tls.c | 34 +--------------------------------- sysdeps/generic/ldsodefs.h | 6 ------ 5 files changed, 9 insertions(+), 59 deletions(-) (limited to 'elf/Versions') diff --git a/ChangeLog b/ChangeLog index 30f1c82243..b8436d37f6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2016-12-21 Florian Weimer + + * csu/libc-tls.c (_dl_tls_setup): Remove. + * elf/dl-tls.c (_dl_tls_setup): Likewise. + * elf/Versions (GLIBC_PRIVATE): Remove _dl_tls_setup. + * sysdeps/generic/ldsodefs.h (_dl_tls_setup): Remove declaration. + 2016-12-21 Nick Alcock [BZ #7065] diff --git a/csu/libc-tls.c b/csu/libc-tls.c index 235ac798ed..8f922341de 100644 --- a/csu/libc-tls.c +++ b/csu/libc-tls.c @@ -216,25 +216,6 @@ __libc_setup_tls (size_t tcbsize, size_t tcbalign) init_static_tls (memsz, MAX (TLS_TCB_ALIGN, max_align)); } -/* This is called only when the data structure setup was skipped at startup, - when there was no need for it then. Now we have dynamically loaded - something needing TLS, or libpthread needs it. */ -int -internal_function -_dl_tls_setup (void) -{ - init_slotinfo (); - init_static_tls ( -#if TLS_TCB_AT_TP - TLS_TCB_SIZE, -#else - 0, -#endif - TLS_TCB_ALIGN); - return 0; -} - - /* This is the minimal initialization function used when libpthread is not used. */ void diff --git a/elf/Versions b/elf/Versions index 08f76a7a20..3d57e36fd2 100644 --- a/elf/Versions +++ b/elf/Versions @@ -59,7 +59,7 @@ ld { _dl_allocate_tls; _dl_allocate_tls_init; _dl_argv; _dl_find_dso_for_object; _dl_get_tls_static_info; _dl_deallocate_tls; _dl_make_stack_executable; _dl_out_of_memory; - _dl_rtld_di_serinfo; _dl_starting_up; _dl_tls_setup; + _dl_rtld_di_serinfo; _dl_starting_up; _rtld_global; _rtld_global_ro; # Only here for gdb while a better method is developed. diff --git a/elf/dl-tls.c b/elf/dl-tls.c index 60f4c1da5c..97bd9779c6 100644 --- a/elf/dl-tls.c +++ b/elf/dl-tls.c @@ -274,39 +274,7 @@ _dl_determine_tlsoffset (void) /* The alignment requirement for the static TLS block. */ GL(dl_tls_static_align) = max_align; } - - -/* This is called only when the data structure setup was skipped at startup, - when there was no need for it then. Now we have dynamically loaded - something needing TLS, or libpthread needs it. */ -int -internal_function -_dl_tls_setup (void) -{ - assert (GL(dl_tls_dtv_slotinfo_list) == NULL); - assert (GL(dl_tls_max_dtv_idx) == 0); - - const size_t nelem = 2 + TLS_SLOTINFO_SURPLUS; - - GL(dl_tls_dtv_slotinfo_list) - = calloc (1, (sizeof (struct dtv_slotinfo_list) - + nelem * sizeof (struct dtv_slotinfo))); - if (GL(dl_tls_dtv_slotinfo_list) == NULL) - return -1; - - GL(dl_tls_dtv_slotinfo_list)->len = nelem; - - /* Number of elements in the static TLS block. It can't be zero - because of various assumptions. The one element is null. */ - GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx) = 1; - - /* This initializes more variables for us. */ - _dl_determine_tlsoffset (); - - return 0; -} -rtld_hidden_def (_dl_tls_setup) -#endif +#endif /* SHARED */ static void * internal_function diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index 288f5fe32e..34d7ec152d 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -994,12 +994,6 @@ extern size_t _dl_count_modids (void) internal_function attribute_hidden; /* Calculate offset of the TLS blocks in the static TLS block. */ extern void _dl_determine_tlsoffset (void) internal_function attribute_hidden; -/* Set up the data structures for TLS, when they were not set up at startup. - Returns nonzero on malloc failure. - This is called from _dl_map_object_from_fd or by libpthread. */ -extern int _dl_tls_setup (void) internal_function; -rtld_hidden_proto (_dl_tls_setup) - /* Allocate memory for static TLS block (unless MEM is nonzero) and dtv. */ extern void *_dl_allocate_tls (void *mem) internal_function; rtld_hidden_proto (_dl_allocate_tls) -- cgit v1.2.3 From 67e58f39412ecd4467034761f3f074283c90f3c8 Mon Sep 17 00:00:00 2001 From: Siddhesh Poyarekar Date: Sat, 31 Dec 2016 23:32:17 +0530 Subject: Add framework for tunables The tunables framework allows us to uniformly manage and expose global variables inside glibc as switches to users. tunables/README has instructions for glibc developers to add new tunables. Tunables support can be enabled by passing the --enable-tunables configure flag to the configure script. This patch only adds a framework and does not pose any limitations on how tunable values are read from the user. It also adds environment variables used in malloc behaviour tweaking to the tunables framework as a PoC of the compatibility interface. * manual/install.texi: Add --enable-tunables option. * INSTALL: Regenerate. * README.tunables: New file. * Makeconfig (CPPFLAGS): Define TOP_NAMESPACE. (before-compile): Generate dl-tunable-list.h early. * config.h.in: Add HAVE_TUNABLES. * config.make.in: Add have-tunables. * configure.ac: Add --enable-tunables option. * configure: Regenerate. * csu/init-first.c (__libc_init_first): Move __libc_init_secure earlier... * csu/init-first.c (LIBC_START_MAIN):... to here. Include dl-tunables.h, libc-internal.h. (LIBC_START_MAIN) [!SHARED]: Initialize tunables for static binaries. * elf/Makefile (dl-routines): Add dl-tunables. * elf/Versions (ld): Add __tunable_set_val to GLIBC_PRIVATE namespace. * elf/dl-support (_dl_nondynamic_init): Unset MALLOC_CHECK_ only when !HAVE_TUNABLES. * elf/rtld.c (process_envvars): Likewise. * elf/dl-sysdep.c [HAVE_TUNABLES]: Include dl-tunables.h (_dl_sysdep_start): Call __tunables_init. * elf/dl-tunable-types.h: New file. * elf/dl-tunables.c: New file. * elf/dl-tunables.h: New file. * elf/dl-tunables.list: New file. * malloc/tst-malloc-usable-static.c: New test case. * malloc/Makefile (tests-static): Add it. * malloc/arena.c [HAVE_TUNABLES]: Include dl-tunables.h. Define TUNABLE_NAMESPACE. (DL_TUNABLE_CALLBACK (set_mallopt_check)): New function. (DL_TUNABLE_CALLBACK_FNDECL): New macro. Use it to define callback functions. (ptmalloc_init): Set tunable values. * scripts/gen-tunables.awk: New file. * sysdeps/mach/hurd/dl-sysdep.c: Include dl-tunables.h. (_dl_sysdep_start): Call __tunables_init. --- ChangeLog | 41 +++++ INSTALL | 5 + Makeconfig | 16 ++ README.tunables | 85 ++++++++++ config.h.in | 3 + config.make.in | 1 + configure | 16 ++ configure.ac | 10 ++ csu/init-first.c | 2 - csu/libc-start.c | 8 + elf/Makefile | 5 + elf/Versions | 3 + elf/dl-support.c | 2 + elf/dl-sysdep.c | 4 + elf/dl-tunable-types.h | 46 ++++++ elf/dl-tunables.c | 320 ++++++++++++++++++++++++++++++++++++++ elf/dl-tunables.h | 88 +++++++++++ elf/dl-tunables.list | 69 ++++++++ elf/rtld.c | 2 + malloc/Makefile | 2 + malloc/arena.c | 54 +++++++ malloc/tst-malloc-usable-static.c | 1 + manual/install.texi | 5 + scripts/gen-tunables.awk | 157 +++++++++++++++++++ sysdeps/mach/hurd/dl-sysdep.c | 4 + 25 files changed, 947 insertions(+), 2 deletions(-) create mode 100644 README.tunables create mode 100644 elf/dl-tunable-types.h create mode 100644 elf/dl-tunables.c create mode 100644 elf/dl-tunables.h create mode 100644 elf/dl-tunables.list create mode 100644 malloc/tst-malloc-usable-static.c create mode 100644 scripts/gen-tunables.awk (limited to 'elf/Versions') diff --git a/ChangeLog b/ChangeLog index d219e5432b..85a4ac30df 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,44 @@ +2016-12-31 Siddhesh Poyarekar + + * manual/install.texi: Add --enable-tunables option. + * INSTALL: Regenerate. + * README.tunables: New file. + * Makeconfig (CPPFLAGS): Define TOP_NAMESPACE. + (before-compile): Generate dl-tunable-list.h early. + * config.h.in: Add HAVE_TUNABLES. + * config.make.in: Add have-tunables. + * configure.ac: Add --enable-tunables option. + * configure: Regenerate. + * csu/init-first.c (__libc_init_first): Move + __libc_init_secure earlier... + * csu/init-first.c (LIBC_START_MAIN):... to here. + Include dl-tunables.h, libc-internal.h. + (LIBC_START_MAIN) [!SHARED]: Initialize tunables for static + binaries. + * elf/Makefile (dl-routines): Add dl-tunables. + * elf/Versions (ld): Add __tunable_set_val to GLIBC_PRIVATE + namespace. + * elf/dl-support (_dl_nondynamic_init): Unset MALLOC_CHECK_ + only when !HAVE_TUNABLES. + * elf/rtld.c (process_envvars): Likewise. + * elf/dl-sysdep.c [HAVE_TUNABLES]: Include dl-tunables.h + (_dl_sysdep_start): Call __tunables_init. + * elf/dl-tunable-types.h: New file. + * elf/dl-tunables.c: New file. + * elf/dl-tunables.h: New file. + * elf/dl-tunables.list: New file. + * malloc/tst-malloc-usable-static.c: New test case. + * malloc/Makefile (tests-static): Add it. + * malloc/arena.c [HAVE_TUNABLES]: Include dl-tunables.h. + Define TUNABLE_NAMESPACE. + (DL_TUNABLE_CALLBACK (set_mallopt_check)): New function. + (DL_TUNABLE_CALLBACK_FNDECL): New macro. Use it to define + callback functions. + (ptmalloc_init): Set tunable values. + * scripts/gen-tunables.awk: New file. + * sysdeps/mach/hurd/dl-sysdep.c: Include dl-tunables.h. + (_dl_sysdep_start): Call __tunables_init. + 2016-12-31 Florian Weimer * resolv/resolv.h (RES_BLAST): Deprecate. diff --git a/INSTALL b/INSTALL index 104f36b0bf..25619fc520 100644 --- a/INSTALL +++ b/INSTALL @@ -169,6 +169,11 @@ will be used, and CFLAGS sets optimization options for the compiler. By default for x86_64, the GNU C Library is built with the vector math library. Use this option to disable the vector math library. +'--enable-tunables' + Tunables support allows additional library parameters to be + customized at runtime. This is an experimental feature and affects + startup time and is thus disabled by default. + '--build=BUILD-SYSTEM' '--host=HOST-SYSTEM' These options are for cross-compiling. If you specify both options diff --git a/Makeconfig b/Makeconfig index 0158eaa76e..b173e4cc08 100644 --- a/Makeconfig +++ b/Makeconfig @@ -934,6 +934,11 @@ CPPFLAGS = $(config-extra-cppflags) $(CPPUNDEFS) $(CPPFLAGS-config) \ $(foreach lib,$(libof-$(basename $(@F))) \ $(libof-$( $@.tmp + mv $@.tmp $@ +endif + common-generated += libc-modules.h libc-modules.stmp # The name under which the run-time dynamic linker is installed. diff --git a/README.tunables b/README.tunables new file mode 100644 index 0000000000..df74f3b24b --- /dev/null +++ b/README.tunables @@ -0,0 +1,85 @@ + TUNABLE FRAMEWORK + ================= + +Tunables is a feature in the GNU C Library that allows application authors and +distribution maintainers to alter the runtime library behaviour to match their +workload. + +The tunable framework allows modules within glibc to register variables that +may be tweaked through an environment variable. It aims to enforce a strict +namespace rule to bring consistency to naming of these tunable environment +variables across the project. This document is a guide for glibc developers to +add tunables to the framework. + +ADDING A NEW TUNABLE +-------------------- + +The TOP_NAMESPACE macro is defined by default as 'glibc'. If distributions +intend to add their own tunables, they should do so in a different top +namespace by overriding the TOP_NAMESPACE macro for that tunable. Downstream +implementations are discouraged from using the 'glibc' top namespace for +tunables they don't already have consensus to push upstream. + +There are two steps to adding a tunable: + +1. Add a tunable ID: + +Modules that wish to use the tunables interface must define the +TUNABLE_NAMESPACE macro. Following this, for each tunable you want to +add, make an entry in elf/dl-tunables.list. The format of the file is as +follows: + +TOP_NAMESPACE { + NAMESPACE1 { + TUNABLE1 { + # tunable attributes, one per line + } + # A tunable with default attributes, i.e. string variable. + TUNABLE2 + TUNABLE3 { + # its attributes + } + } + NAMESPACE2 { + ... + } +} + +The list of allowed attributes are: + +- type: Data type. Defaults to STRING. Allowed types are: + INT_32, SIZE_T and STRING. + +- minval: Optional minimum acceptable value. For a string type + this is the minimum length of the value. + +- maxval: Optional maximum acceptable value. For a string type + this is the maximum length of the value. + +- env_alias: An alias environment variable + +- is_secure: Specify whether the tunable should be read for setuid + binaries. True allows the tunable to be read for + setuid binaries while false disables it. Note that + even if this is set as true and the value is read, it + may not be used if it does not validate against the + acceptable values or is not considered safe by the + module. + +2. Call either the TUNABLE_SET_VALUE and pass into it the tunable name and a + pointer to the variable that should be set with the tunable value. + If additional work needs to be done after setting the value, use the + TUNABLE_SET_VALUE_WITH_CALLBACK instead and additionally pass a pointer to + the function that should be called if the tunable value has been set. + +FUTURE WORK +----------- + +The framework currently only allows a one-time initialization of variables +through environment variables and in some cases, modification of variables via +an API call. A future goals for this project include: + +- Setting system-wide and user-wide defaults for tunables through some + mechanism like a configuration file. + +- Allow tweaking of some tunables at runtime diff --git a/config.h.in b/config.h.in index 82f95a6dbd..7bfe923c06 100644 --- a/config.h.in +++ b/config.h.in @@ -256,4 +256,7 @@ /* PowerPC32 uses fctidz for floating point to long long conversions. */ #define HAVE_PPC_FCTIDZ 0 +/* Build glibc with tunables support. */ +#define HAVE_TUNABLES 0 + #endif diff --git a/config.make.in b/config.make.in index 4422025e59..2f8dae213d 100644 --- a/config.make.in +++ b/config.make.in @@ -96,6 +96,7 @@ use-nscd = @use_nscd@ build-hardcoded-path-in-tests= @hardcoded_path_in_tests@ build-pt-chown = @build_pt_chown@ enable-lock-elision = @enable_lock_elision@ +have-tunables = @have_tunables@ # Build tools. CC = @CC@ diff --git a/configure b/configure index c88f6fe88c..d80d738fd1 100755 --- a/configure +++ b/configure @@ -666,6 +666,7 @@ libc_cv_ssp base_machine add_on_subdirs add_ons +have_tunables build_pt_chown build_nscd link_obsolete_rpc @@ -782,6 +783,7 @@ enable_systemtap enable_build_nscd enable_nscd enable_pt_chown +enable_tunables enable_mathvec with_cpu ' @@ -1452,6 +1454,7 @@ Optional Features: --disable-build-nscd disable building and installing the nscd daemon --disable-nscd library functions will not contact the nscd daemon --enable-pt_chown Enable building and installing pt_chown + --enable-tunables Enable tunables support --enable-mathvec Enable building and installing mathvec [default depends on architecture] @@ -3698,6 +3701,19 @@ if test "$build_pt_chown" = yes; then fi +# Check whether --enable-tunables was given. +if test "${enable_tunables+set}" = set; then : + enableval=$enable_tunables; have_tunables=$enableval +else + have_tunables=no +fi + + +if test "$have_tunables" = yes; then + $as_echo "#define HAVE_TUNABLES 1" >>confdefs.h + +fi + # The abi-tags file uses a fairly simplistic model for name recognition that # can't distinguish i486-pc-linux-gnu fully from i486-pc-gnu. So we mutate a # $host_os of `gnu*' here to be `gnu-gnu*' just so that it can tell. diff --git a/configure.ac b/configure.ac index 2782bfaf08..22f5cab200 100644 --- a/configure.ac +++ b/configure.ac @@ -421,6 +421,16 @@ if test "$build_pt_chown" = yes; then AC_DEFINE(HAVE_PT_CHOWN) fi +AC_ARG_ENABLE([tunables], + [AS_HELP_STRING([--enable-tunables], + [Enable tunables support])], + [have_tunables=$enableval], + [have_tunables=no]) +AC_SUBST(have_tunables) +if test "$have_tunables" = yes; then + AC_DEFINE(HAVE_TUNABLES) +fi + # The abi-tags file uses a fairly simplistic model for name recognition that # can't distinguish i486-pc-linux-gnu fully from i486-pc-gnu. So we mutate a # $host_os of `gnu*' here to be `gnu-gnu*' just so that it can tell. diff --git a/csu/init-first.c b/csu/init-first.c index 77c6e1cb9e..465f25b722 100644 --- a/csu/init-first.c +++ b/csu/init-first.c @@ -72,8 +72,6 @@ _init (int argc, char **argv, char **envp) __environ = envp; #ifndef SHARED - __libc_init_secure (); - /* First the initialization which normally would be done by the dynamic linker. */ _dl_non_dynamic_init (); diff --git a/csu/libc-start.c b/csu/libc-start.c index cc59073abe..15db9b4684 100644 --- a/csu/libc-start.c +++ b/csu/libc-start.c @@ -21,6 +21,9 @@ #include #include #include +#include + +#include extern void __libc_init_first (int argc, char **argv, char **envp); @@ -174,6 +177,11 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), } } + /* Initialize very early so that tunables can use it. */ + __libc_init_secure (); + + __tunables_init (__environ); + /* Perform IREL{,A} relocations. */ apply_irel (); diff --git a/elf/Makefile b/elf/Makefile index 8a2ce02cd5..de28d99224 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -35,6 +35,11 @@ dl-routines = $(addprefix dl-,load lookup object reloc deps hwcaps \ ifeq (yes,$(use-ldconfig)) dl-routines += dl-cache endif + +ifeq (yes,$(have-tunables)) +dl-routines += dl-tunables +endif + all-dl-routines = $(dl-routines) $(sysdep-dl-routines) # But they are absent from the shared libc, because that code is in ld.so. elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin \ diff --git a/elf/Versions b/elf/Versions index 3d57e36fd2..6abe9db8bd 100644 --- a/elf/Versions +++ b/elf/Versions @@ -70,5 +70,8 @@ ld { # Internal error handling support. Interposed by libc.so. _dl_signal_error; _dl_catch_error; + + # Set value of a tunable. + __tunable_set_val; } } diff --git a/elf/dl-support.c b/elf/dl-support.c index c30194c7b7..d350d6d0d0 100644 --- a/elf/dl-support.c +++ b/elf/dl-support.c @@ -354,8 +354,10 @@ _dl_non_dynamic_init (void) cp = (const char *) __rawmemchr (cp, '\0') + 1; } +#if !HAVE_TUNABLES if (__access ("/etc/suid-debug", F_OK) != 0) __unsetenv ("MALLOC_CHECK_"); +#endif } #ifdef DL_PLATFORM_INIT diff --git a/elf/dl-sysdep.c b/elf/dl-sysdep.c index eaa71556d2..4283767fe0 100644 --- a/elf/dl-sysdep.c +++ b/elf/dl-sysdep.c @@ -44,6 +44,8 @@ #include #include +#include + extern char **_environ attribute_hidden; extern char _end[] attribute_hidden; @@ -219,6 +221,8 @@ _dl_sysdep_start (void **start_argptr, } #endif + __tunables_init (_environ); + #ifdef DL_SYSDEP_INIT DL_SYSDEP_INIT; #endif diff --git a/elf/dl-tunable-types.h b/elf/dl-tunable-types.h new file mode 100644 index 0000000000..d1591b6efb --- /dev/null +++ b/elf/dl-tunable-types.h @@ -0,0 +1,46 @@ +/* Tunable type information. + + Copyright (C) 2016 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 + . */ + +#ifndef _TUNABLE_TYPES_H_ +# define _TUNABLE_TYPES_H_ +#include + +typedef void (*tunable_callback_t) (void *); + +typedef enum +{ + TUNABLE_TYPE_INT_32, + TUNABLE_TYPE_SIZE_T, + TUNABLE_TYPE_STRING +} tunable_type_code_t; + +typedef struct +{ + tunable_type_code_t type_code; + int64_t min; + int64_t max; +} tunable_type_t; + +typedef union +{ + int64_t numval; + const char *strval; +} tunable_val_t; + +#endif diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c new file mode 100644 index 0000000000..472747b3da --- /dev/null +++ b/elf/dl-tunables.c @@ -0,0 +1,320 @@ +/* The tunable framework. See the README.tunables to know how to use the + tunable in a glibc module. + + Copyright (C) 2016 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 + . */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define TUNABLES_INTERNAL 1 +#include "dl-tunables.h" + +/* Compare environment names, bounded by the name hardcoded in glibc. */ +static bool +is_name (const char *orig, const char *envname) +{ + for (;*orig != '\0' && *envname != '\0'; envname++, orig++) + if (*orig != *envname) + break; + + /* The ENVNAME is immediately followed by a value. */ + if (*orig == '\0' && *envname == '=') + return true; + else + return false; +} + +static char ** +get_next_env (char **envp, char **name, size_t *namelen, char **val) +{ + while (envp != NULL && *envp != NULL) + { + char *envline = *envp; + int len = 0; + + while (envline[len] != '\0' && envline[len] != '=') + len++; + + /* Just the name and no value, go to the next one. */ + if (envline[len] == '\0') + continue; + + *name = envline; + *namelen = len; + *val = &envline[len + 1]; + + return ++envp; + } + + return NULL; +} + +static int +tunables_unsetenv (char **ep, const char *name) +{ + while (*ep != NULL) + { + size_t cnt = 0; + + while ((*ep)[cnt] == name[cnt] && name[cnt] != '\0') + ++cnt; + + if (name[cnt] == '\0' && (*ep)[cnt] == '=') + { + /* Found it. Remove this pointer by moving later ones to + the front. */ + char **dp = ep; + + do + dp[0] = dp[1]; + while (*dp++); + /* Continue the loop in case NAME appears again. */ + } + else + ++ep; + } + + return 0; +} + +/* A stripped down strtoul-like implementation for very early use. It does not + set errno if the result is outside bounds because it gets called before + errno may have been set up. */ +static unsigned long int +tunables_strtoul (const char *nptr) +{ + unsigned long int result = 0; + long int sign = 1; + unsigned max_digit; + + while (*nptr == ' ' || *nptr == '\t') + ++nptr; + + if (*nptr == '-') + { + sign = -1; + ++nptr; + } + else if (*nptr == '+') + ++nptr; + + if (*nptr < '0' || *nptr > '9') + return 0UL; + + int base = 10; + max_digit = 9; + if (*nptr == '0') + { + if (nptr[1] == 'x' || nptr[1] == 'X') + { + base = 16; + nptr += 2; + } + else + { + base = 8; + max_digit = 7; + } + } + + while (1) + { + unsigned long int digval; + if (*nptr >= '0' && *nptr <= '0' + max_digit) + digval = *nptr - '0'; + else if (base == 16) + { + if (*nptr >= 'a' && *nptr <= 'f') + digval = *nptr - 'a' + 10; + else if (*nptr >= 'A' && *nptr <= 'F') + digval = *nptr - 'A' + 10; + else + break; + } + else + break; + + if (result > ULONG_MAX / base + || (result == ULONG_MAX / base && digval > ULONG_MAX % base)) + return ULONG_MAX; + result *= base; + result += digval; + ++nptr; + } + + return result * sign; +} + +/* Initialize the internal type if the value validates either using the + explicit constraints of the tunable or with the implicit constraints of its + type. */ +static void +tunable_set_val_if_valid_range (tunable_t *cur, const char *strval, + int64_t default_min, int64_t default_max) +{ + int64_t val = tunables_strtoul (strval); + + int64_t min = cur->type.min; + int64_t max = cur->type.max; + + if (min == max) + { + min = default_min; + max = default_max; + } + + if (val >= min && val <= max) + { + cur->val.numval = val; + cur->strval = strval; + } +} + +/* Validate range of the input value and initialize the tunable CUR if it looks + good. */ +static void +tunable_initialize (tunable_t *cur, const char *strval) +{ + switch (cur->type.type_code) + { + case TUNABLE_TYPE_INT_32: + { + tunable_set_val_if_valid_range (cur, strval, INT32_MIN, INT32_MAX); + break; + } + case TUNABLE_TYPE_SIZE_T: + { + tunable_set_val_if_valid_range (cur, strval, 0, SIZE_MAX); + break; + } + case TUNABLE_TYPE_STRING: + { + cur->val.strval = cur->strval = strval; + break; + } + default: + __builtin_unreachable (); + } +} + +/* Disable a tunable if it is set. */ +static void +disable_tunable (tunable_id_t id, char **envp) +{ + const char *env_alias = tunable_list[id].env_alias; + + if (env_alias != NULL) + tunables_unsetenv (envp, tunable_list[id].env_alias); +} + +/* Disable the glibc.malloc.check tunable in SETUID/SETGID programs unless + the system administrator overrides it by creating the /etc/suid-debug + file. This is a special case where we want to conditionally enable/disable + a tunable even for setuid binaries. We use the special version of access() + to avoid setting ERRNO, which is a TLS variable since TLS has not yet been + set up. */ +static inline void +__always_inline +maybe_disable_malloc_check (void) +{ + if (__libc_enable_secure && __access_noerrno ("/etc/suid-debug", F_OK) != 0) + disable_tunable (TUNABLE_ENUM_NAME(glibc, malloc, check), __environ); +} + +/* Initialize the tunables list from the environment. For now we only use the + ENV_ALIAS to find values. Later we will also use the tunable names to find + values. */ +void +__tunables_init (char **envp) +{ + char *envname = NULL; + char *envval = NULL; + size_t len = 0; + + maybe_disable_malloc_check (); + + while ((envp = get_next_env (envp, &envname, &len, &envval)) != NULL) + { + for (int i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++) + { + tunable_t *cur = &tunable_list[i]; + + /* Skip over tunables that have either been set already or should be + skipped. */ + if (cur->strval != NULL || cur->env_alias == NULL + || (__libc_enable_secure && !cur->is_secure)) + continue; + + const char *name = cur->env_alias; + + /* We have a match. Initialize and move on to the next line. */ + if (is_name (name, envname)) + { + tunable_initialize (cur, envval); + break; + } + } + } +} + +/* Set the tunable value. This is called by the module that the tunable exists + in. */ +void +__tunable_set_val (tunable_id_t id, void *valp, tunable_callback_t callback) +{ + tunable_t *cur = &tunable_list[id]; + + /* Don't do anything if our tunable was not set during initialization or if + it failed validation. */ + if (cur->strval == NULL) + return; + + if (valp == NULL) + goto cb; + + switch (cur->type.type_code) + { + case TUNABLE_TYPE_INT_32: + { + *((int32_t *) valp) = (int32_t) cur->val.numval; + break; + } + case TUNABLE_TYPE_SIZE_T: + { + *((size_t *) valp) = (size_t) cur->val.numval; + break; + } + case TUNABLE_TYPE_STRING: + { + *((const char **)valp) = cur->val.strval; + break; + } + default: + __builtin_unreachable (); + } + +cb: + if (callback) + callback (&cur->val); +} diff --git a/elf/dl-tunables.h b/elf/dl-tunables.h new file mode 100644 index 0000000000..a3f5472b45 --- /dev/null +++ b/elf/dl-tunables.h @@ -0,0 +1,88 @@ +/* The tunable framework. See the README to know how to use the tunable in + a glibc module. + + Copyright (C) 2016 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 + . */ + +#ifndef _TUNABLES_H_ +#define _TUNABLES_H_ + +#if !HAVE_TUNABLES +static inline void +__always_inline +__tunables_init (char **unused __attribute_unused) +{ + /* This is optimized out if tunables are not enabled. */ +} +#else + +# include +# include "dl-tunable-types.h" + +/* A tunable. */ +struct _tunable +{ + const char *name; /* Internal name of the tunable. */ + tunable_type_t type; /* Data type of the tunable. */ + tunable_val_t val; /* The value. */ + const char *strval; /* The string containing the value, + points into envp. */ + bool is_secure; /* Whether the tunable must be read + even for setuid binaries. Note that + even if the tunable is read, it may + not get used by the target module if + the value is considered unsafe. */ + /* Compatibility elements. */ + const char *env_alias; /* The compatibility environment + variable name. */ +}; + +typedef struct _tunable tunable_t; + +/* Full name for a tunable is top_ns.tunable_ns.id. */ +# define TUNABLE_NAME_S(top,ns,id) #top "." #ns "." #id + +# define TUNABLE_ENUM_NAME(top,ns,id) TUNABLE_ENUM_NAME1 (top,ns,id) +# define TUNABLE_ENUM_NAME1(top,ns,id) top ## _ ## ns ## _ ## id + +# include "dl-tunable-list.h" + +extern void __tunables_init (char **); +extern void __tunable_set_val (tunable_id_t, void *, tunable_callback_t); + +/* Check if the tunable has been set to a non-default value and if it is, copy + it over into __VAL. */ +# define TUNABLE_SET_VAL(__id,__val) \ +({ \ + __tunable_set_val \ + (TUNABLE_ENUM_NAME (TOP_NAMESPACE, TUNABLE_NAMESPACE, __id), (__val), \ + NULL); \ +}) + +/* Same as TUNABLE_SET_VAL, but also call the callback function __CB. */ +# define TUNABLE_SET_VAL_WITH_CALLBACK(__id,__val,__cb) \ +({ \ + __tunable_set_val \ + (TUNABLE_ENUM_NAME (TOP_NAMESPACE, TUNABLE_NAMESPACE, __id), (__val), \ + DL_TUNABLE_CALLBACK (__cb)); \ +}) + +/* Namespace sanity for callback functions. Use this macro to keep the + namespace of the modules clean. */ +# define DL_TUNABLE_CALLBACK(__name) _dl_tunable_ ## __name +#endif +#endif diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list new file mode 100644 index 0000000000..11504c49e3 --- /dev/null +++ b/elf/dl-tunables.list @@ -0,0 +1,69 @@ +# Copyright (C) 2016 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 +# . + +# Allowed attributes for tunables: +# +# type: Defaults to STRING +# minval: Optional minimum acceptable value +# maxval: Optional maximum acceptable value +# env_alias: An alias environment variable +# is_secure: Specify whether the environment variable should be read for +# setuid binaries. + +glibc { + malloc { + check { + type: INT_32 + minval: 0 + maxval: 3 + env_alias: MALLOC_CHECK_ + is_secure: true + } + top_pad { + type: SIZE_T + env_alias: MALLOC_TOP_PAD_ + } + perturb { + type: INT_32 + minval: 0 + maxval: 0xff + env_alias: MALLOC_PERTURB_ + } + mmap_threshold { + type: SIZE_T + env_alias: MALLOC_MMAP_THRESHOLD_ + } + trim_threshold { + type: SIZE_T + env_alias: MALLOC_TRIM_THRESHOLD_ + } + mmap_max { + type: INT_32 + env_alias: MALLOC_MMAP_MAX_ + } + arena_max { + type: SIZE_T + env_alias: MALLOC_ARENA_MAX + minval: 1 + } + arena_test { + type: SIZE_T + env_alias: MALLOC_ARENA_TEST + minval: 1 + } + } +} diff --git a/elf/rtld.c b/elf/rtld.c index 4ec25d7c30..a60ead693b 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -2510,7 +2510,9 @@ process_envvars (enum mode *modep) if (__access ("/etc/suid-debug", F_OK) != 0) { +#if !HAVE_TUNABLES unsetenv ("MALLOC_CHECK_"); +#endif GLRO(dl_debug_mask) = 0; } diff --git a/malloc/Makefile b/malloc/Makefile index b8efcd68bc..4e4104ec8b 100644 --- a/malloc/Makefile +++ b/malloc/Makefile @@ -37,6 +37,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \ tests-static := \ tst-interpose-static-nothread \ tst-interpose-static-thread \ + tst-malloc-usable-static tests += $(tests-static) test-srcs = tst-mtrace @@ -158,6 +159,7 @@ endif tst-mcheck-ENV = MALLOC_CHECK_=3 tst-malloc-usable-ENV = MALLOC_CHECK_=3 +tst-malloc-usable-static-ENV = $(tst-malloc-usable-ENV) # Uncomment this for test releases. For public releases it is too expensive. #CPPFLAGS-malloc.o += -DMALLOC_DEBUG=1 diff --git a/malloc/arena.c b/malloc/arena.c index eed42471a7..234035f14f 100644 --- a/malloc/arena.c +++ b/malloc/arena.c @@ -19,6 +19,11 @@ #include +#if HAVE_TUNABLES +# define TUNABLE_NAMESPACE malloc +#endif +#include + /* Compile-time constants. */ #define HEAP_MIN_SIZE (32 * 1024) @@ -204,6 +209,34 @@ __malloc_fork_unlock_child (void) __libc_lock_init (list_lock); } +#if HAVE_TUNABLES +static inline int do_set_mallopt_check (int32_t value); +void +DL_TUNABLE_CALLBACK (set_mallopt_check) (void *valp) +{ + int32_t value = *(int32_t *) valp; + do_set_mallopt_check (value); + if (check_action != 0) + __malloc_check_init (); +} + +# define DL_TUNABLE_CALLBACK_FNDECL(__name, __type) \ +static inline int do_ ## __name (__type value); \ +void \ +DL_TUNABLE_CALLBACK (__name) (void *valp) \ +{ \ + __type value = *(__type *) valp; \ + do_ ## __name (value); \ +} + +DL_TUNABLE_CALLBACK_FNDECL (set_mmap_threshold, size_t) +DL_TUNABLE_CALLBACK_FNDECL (set_mmaps_max, int32_t) +DL_TUNABLE_CALLBACK_FNDECL (set_top_pad, size_t) +DL_TUNABLE_CALLBACK_FNDECL (set_perturb_byte, int32_t) +DL_TUNABLE_CALLBACK_FNDECL (set_trim_threshold, size_t) +DL_TUNABLE_CALLBACK_FNDECL (set_arena_max, size_t) +DL_TUNABLE_CALLBACK_FNDECL (set_arena_test, size_t) +#else /* Initialization routine. */ #include extern char **_environ; @@ -238,6 +271,7 @@ next_env_entry (char ***position) return result; } +#endif #ifdef SHARED @@ -272,6 +306,24 @@ ptmalloc_init (void) #endif thread_arena = &main_arena; + +#if HAVE_TUNABLES + /* Ensure initialization/consolidation and do it under a lock so that a + thread attempting to use the arena in parallel waits on us till we + finish. */ + __libc_lock_lock (main_arena.mutex); + malloc_consolidate (&main_arena); + + TUNABLE_SET_VAL_WITH_CALLBACK (check, NULL, set_mallopt_check); + TUNABLE_SET_VAL_WITH_CALLBACK (top_pad, NULL, set_top_pad); + TUNABLE_SET_VAL_WITH_CALLBACK (perturb, NULL, set_perturb_byte); + TUNABLE_SET_VAL_WITH_CALLBACK (mmap_threshold, NULL, set_mmap_threshold); + TUNABLE_SET_VAL_WITH_CALLBACK (trim_threshold, NULL, set_trim_threshold); + TUNABLE_SET_VAL_WITH_CALLBACK (mmap_max, NULL, set_mmaps_max); + TUNABLE_SET_VAL_WITH_CALLBACK (arena_max, NULL, set_arena_max); + TUNABLE_SET_VAL_WITH_CALLBACK (arena_test, NULL, set_arena_test); + __libc_lock_unlock (main_arena.mutex); +#else const char *s = NULL; if (__glibc_likely (_environ != NULL)) { @@ -340,6 +392,8 @@ ptmalloc_init (void) if (check_action != 0) __malloc_check_init (); } +#endif + #if HAVE_MALLOC_INIT_HOOK void (*hook) (void) = atomic_forced_read (__malloc_initialize_hook); if (hook != NULL) diff --git a/malloc/tst-malloc-usable-static.c b/malloc/tst-malloc-usable-static.c new file mode 100644 index 0000000000..8907db01a5 --- /dev/null +++ b/malloc/tst-malloc-usable-static.c @@ -0,0 +1 @@ +#include diff --git a/manual/install.texi b/manual/install.texi index d02e87091f..d41296294e 100644 --- a/manual/install.texi +++ b/manual/install.texi @@ -200,6 +200,11 @@ configure with @option{--disable-werror}. By default for x86_64, @theglibc{} is built with the vector math library. Use this option to disable the vector math library. +@item --enable-tunables +Tunables support allows additional library parameters to be customized at +runtime. This is an experimental feature and affects startup time and is thus +disabled by default. + @item --build=@var{build-system} @itemx --host=@var{host-system} These options are for cross-compiling. If you specify both options and diff --git a/scripts/gen-tunables.awk b/scripts/gen-tunables.awk new file mode 100644 index 0000000000..b65b5a4a33 --- /dev/null +++ b/scripts/gen-tunables.awk @@ -0,0 +1,157 @@ +# Generate dl-tunable-list.h from dl-tunables.list + +BEGIN { + tunable="" + ns="" + top_ns="" +} + +# Skip over blank lines and comments. +/^#/ { + next +} + +/^[ \t]*$/ { + next +} + +# Beginning of either a top namespace, tunable namespace or a tunable, decided +# on the current value of TUNABLE, NS or TOP_NS. +$2 == "{" { + if (top_ns == "") { + top_ns = $1 + } + else if (ns == "") { + ns = $1 + } + else if (tunable == "") { + tunable = $1 + } + else { + printf ("Unexpected occurrence of '{': %s:%d\n", FILENAME, FNR) + exit 1 + } + + next +} + +# End of either a top namespace, tunable namespace or a tunable. +$1 == "}" { + if (tunable != "") { + # Tunables definition ended, now fill in default attributes. + if (!types[top_ns][ns][tunable]) { + types[top_ns][ns][tunable] = "STRING" + } + if (!minvals[top_ns][ns][tunable]) { + minvals[top_ns][ns][tunable] = "0" + } + if (!maxvals[top_ns][ns][tunable]) { + maxvals[top_ns][ns][tunable] = "0" + } + if (!env_alias[top_ns][ns][tunable]) { + env_alias[top_ns][ns][tunable] = "NULL" + } + if (!is_secure[top_ns][ns][tunable]) { + is_secure[top_ns][ns][tunable] = "false" + } + + tunable = "" + } + else if (ns != "") { + ns = "" + } + else if (top_ns != "") { + top_ns = "" + } + else { + printf ("syntax error: extra }: %s:%d\n", FILENAME, FNR) + exit 1 + } + next +} + +# Everything else, which could either be a tunable without any attributes or a +# tunable attribute. +{ + if (ns == "") { + printf("Line %d: Invalid tunable outside a namespace: %s\n", NR, $0) + exit 1 + } + + if (tunable == "") { + # We encountered a tunable without any attributes, so note it with a + # default. + types[top_ns][ns][$1] = "STRING" + next + } + + # Otherwise, we have encountered a tunable attribute. + split($0, arr, ":") + attr = gensub(/^[ \t]+|[ \t]+$/, "", "g", arr[1]) + val = gensub(/^[ \t]+|[ \t]+$/, "", "g", arr[2]) + + if (attr == "type") { + types[top_ns][ns][tunable] = val + } + else if (attr == "minval") { + minvals[top_ns][ns][tunable] = val + } + else if (attr == "maxval") { + maxvals[top_ns][ns][tunable] = val + } + else if (attr == "env_alias") { + env_alias[top_ns][ns][tunable] = sprintf("\"%s\"", val) + } + else if (attr == "is_secure") { + if (val == "true" || val == "false") { + is_secure[top_ns][ns][tunable] = val + } + else { + printf("Line %d: Invalid value (%s) for is_secure: %s, ", NR, val, + $0) + print("Allowed values are 'true' or 'false'") + exit 1 + } + } +} + +END { + if (ns != "") { + print "Unterminated namespace. Is a closing brace missing?" + exit 1 + } + + print "/* AUTOGENERATED by gen-tunables.awk. */" + print "#ifndef _TUNABLES_H_" + print "# error \"Do not include this file directly.\"" + print "# error \"Include tunables.h instead.\"" + print "#endif" + + # Now, the enum names + print "\ntypedef enum" + print "{" + for (t in types) { + for (n in types[t]) { + for (m in types[t][n]) { + printf (" TUNABLE_ENUM_NAME(%s, %s, %s),\n", t, n, m); + } + } + } + print "} tunable_id_t;\n" + + # Finally, the tunable list. + print "\n#ifdef TUNABLES_INTERNAL" + print "static tunable_t tunable_list[] = {" + for (t in types) { + for (n in types[t]) { + for (m in types[t][n]) { + printf (" {TUNABLE_NAME_S(%s, %s, %s)", t, n, m) + printf (", {TUNABLE_TYPE_%s, %s, %s}, {.numval = 0}, NULL, %s, %s},\n", + types[t][n][m], minvals[t][n][m], maxvals[t][n][m], + is_secure[t][n][m], env_alias[t][n][m]); + } + } + } + print "};" + print "#endif" +} diff --git a/sysdeps/mach/hurd/dl-sysdep.c b/sysdeps/mach/hurd/dl-sysdep.c index d730f82280..42bccdab79 100644 --- a/sysdeps/mach/hurd/dl-sysdep.c +++ b/sysdeps/mach/hurd/dl-sysdep.c @@ -44,6 +44,8 @@ #include #include +#include + extern void __mach_init (void); extern int _dl_argc; @@ -143,6 +145,8 @@ _dl_sysdep_start (void **start_argptr, __libc_enable_secure = _dl_hurd_data->flags & EXEC_SECURE; + __tunables_init (_environ); + if (_dl_hurd_data->flags & EXEC_STACK_ARGS && _dl_hurd_data->user_entry == 0) _dl_hurd_data->user_entry = (vm_address_t) ENTRY_POINT; -- cgit v1.2.3 From 44330b6d32904fdc8b6835a112e0ba0aee9f4ef3 Mon Sep 17 00:00:00 2001 From: Siddhesh Poyarekar Date: Thu, 1 Jun 2017 20:24:46 +0530 Subject: tunables: Clean up hooks to get and set tunables The TUNABLE_SET_VALUE and family of macros (and my later attempt to add a TUNABLE_GET) never quite went together very well because the overall interface was not clearly defined. This patch is an attempt to do just that. This patch consolidates the API to two simple sets of macros, TUNABLE_GET* and TUNABLE_SET*. If TUNABLE_NAMESPACE is defined, TUNABLE_GET takes just the tunable name, type and a (optionally NULL) callback function to get the value of the tunable. The callback function, if non-NULL, is called if the tunable was externally set (i.e. via GLIBC_TUNABLES or any future mechanism). For example: val = TUNABLE_GET (check, int32_t, check_callback) returns the value of the glibc.malloc.check tunable (assuming TUNABLE_NAMESPACE is set to malloc) as an int32_t into VAL after calling check_callback. Likewise, TUNABLE_SET can be used to set the value of the tunable, although this is currently possible only in the dynamic linker before it relocates itself. For example: TUNABLE_SET (check, int32_t, 2) will set glibc.malloc.check to 2. Of course, this is not possible since we set (or read) glibc.malloc.check long after it is relocated. To access or set a tunable outside of TUNABLE_NAMESPACE, use the TUNABLE_GET_FULL and TUNABLE_SET_FULL macros, which have the following prototype: TUNABLE_GET_FULL (glibc, tune, hwcap_mask, uint64_t, NULL) TUNABLE_SET_FULL (glibc, tune, hwcap_mask, uint64_t, 0xffff) In future the tunable list may get split into mutable and immutable tunables where mutable tunables can be modified by the library and userspace after relocation as well and TUNABLE_SET will be more useful than it currently is. However whenever we actually do that split, we will have to ensure that the mutable tunables are protected with locks. * elf/Versions (__tunable_set_val): Rename to __tunable_get_val. * elf/dl-tunables.c: Likewise. (do_tunable_update_val): New function. (__tunable_set_val): New function. (__tunable_get_val): Call CB only if the tunable was externally initialized. (tunables_strtoul): Replace strval with initialized. * elf/dl-tunables.h (strval): Replace with a bool initialized. (TUNABLE_ENUM_NAME, TUNABLE_ENUM_NAME1): Adjust names to prevent collision. (__tunable_set_val): New function. (TUNABLE_GET, TUNABLE_GET_FULL): New macros. (TUNABLE_SET, TUNABLE_SET_FULL): Likewise. (TUNABLE_SET_VAL): Remove. (TUNABLE_SET_VAL_WITH_CALLBACK): Likewise. * README.tunables: Document the new macros. * malloc/arena.c (ptmalloc_init): Adjust. --- ChangeLog | 20 ++++++++++++++++ README.tunables | 69 ++++++++++++++++++++++++++++++++++++++++++++++--------- elf/Versions | 2 +- elf/dl-tunables.c | 58 +++++++++++++++++++++++++++++----------------- elf/dl-tunables.h | 53 +++++++++++++++++++++++++++--------------- malloc/arena.c | 36 ++++++++++++++--------------- 6 files changed, 168 insertions(+), 70 deletions(-) (limited to 'elf/Versions') diff --git a/ChangeLog b/ChangeLog index b42bdb8565..b85c6182ff 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2017-06-07 Siddhesh Poyarekar + + * elf/Versions (__tunable_set_val): Rename to __tunable_get_val. + * elf/dl-tunables.c: Likewise. + (do_tunable_update_val): New function. + (__tunable_set_val): New function. + (__tunable_get_val): Call CB only if the tunable was externally + initialized. + (tunables_strtoul): Replace strval with initialized. + * elf/dl-tunables.h (strval): Replace with a bool initialized. + (TUNABLE_ENUM_NAME, TUNABLE_ENUM_NAME1): Adjust names to + prevent collision. + (__tunable_set_val): New function. + (TUNABLE_GET, TUNABLE_GET_FULL): New macros. + (TUNABLE_SET, TUNABLE_SET_FULL): Likewise. + (TUNABLE_SET_VAL): Remove. + (TUNABLE_SET_VAL_WITH_CALLBACK): Likewise. + * README.tunables: Document the new macros. + * malloc/arena.c (ptmalloc_init): Adjust. + 2017-06-06 H.J. Lu * sysdeps/x86_64/multiarch/Makefile (sysdep_routines): Add diff --git a/README.tunables b/README.tunables index 0e9b0d7a47..3967679f43 100644 --- a/README.tunables +++ b/README.tunables @@ -20,14 +20,12 @@ namespace by overriding the TOP_NAMESPACE macro for that tunable. Downstream implementations are discouraged from using the 'glibc' top namespace for tunables they don't already have consensus to push upstream. -There are two steps to adding a tunable: +There are three steps to adding a tunable: -1. Add a tunable ID: +1. Add a tunable to the list and fully specify its properties: -Modules that wish to use the tunables interface must define the -TUNABLE_NAMESPACE macro. Following this, for each tunable you want to -add, make an entry in elf/dl-tunables.list. The format of the file is as -follows: +For each tunable you want to add, make an entry in elf/dl-tunables.list. The +format of the file is as follows: TOP_NAMESPACE { NAMESPACE1 { @@ -69,11 +67,60 @@ The list of allowed attributes are: non-AT_SECURE subprocesses. NONE: Read all the time. -2. Call either the TUNABLE_SET_VALUE and pass into it the tunable name and a - pointer to the variable that should be set with the tunable value. - If additional work needs to be done after setting the value, use the - TUNABLE_SET_VALUE_WITH_CALLBACK instead and additionally pass a pointer to - the function that should be called if the tunable value has been set. +2. Use TUNABLE_GET/TUNABLE_SET to get and set tunables. + +3. OPTIONAL: If tunables in a namespace are being used multiple times within a + specific module, set the TUNABLE_NAMESPACE macro to reduce the amount of + typing. + +GETTING AND SETTING TUNABLES +---------------------------- + +When the TUNABLE_NAMESPACE macro is defined, one may get tunables in that +module using the TUNABLE_GET macro as follows: + + val = TUNABLE_GET (check, int32_t, TUNABLE_CALLBACK (check_callback)) + +where 'check' is the tunable name, 'int32_t' is the C type of the tunable and +'check_callback' is the function to call if the tunable got initialized to a +non-default value. The macro returns the value as type 'int32_t'. + +The callback function should be defined as follows: + + void + TUNABLE_CALLBACK (check_callback) (int32_t *valp) + { + ... + } + +where it can expect the tunable value to be passed in VALP. + +Tunables in the module can be updated using: + + TUNABLE_SET (check, int32_t, val) + +where 'check' is the tunable name, 'int32_t' is the C type of the tunable and +'val' is a value of same type. + +To get and set tunables in a different namespace from that module, use the full +form of the macros as follows: + + val = TUNABLE_GET_FULL (glibc, tune, hwcap_mask, uint64_t, NULL) + + TUNABLE_SET_FULL (glibc, tune, hwcap_mask, uint64_t, val) + +where 'glibc' is the top namespace, 'tune' is the tunable namespace and the +remaining arguments are the same as the short form macros. + +When TUNABLE_NAMESPACE is not defined in a module, TUNABLE_GET is equivalent to +TUNABLE_GET_FULL, so you will need to provide full namespace information for +both macros. Likewise for TUNABLE_SET and TUNABLE_SET_FULL. + +** IMPORTANT NOTE ** + +The tunable list is set as read-only after the dynamic linker relocates itself, +so setting tunable values must be limited only to tunables within the dynamic +linker, that too before relocation. FUTURE WORK ----------- diff --git a/elf/Versions b/elf/Versions index 6abe9db8bd..c59facdbd7 100644 --- a/elf/Versions +++ b/elf/Versions @@ -72,6 +72,6 @@ ld { _dl_signal_error; _dl_catch_error; # Set value of a tunable. - __tunable_set_val; + __tunable_get_val; } } diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c index b6e6b3da52..76e8c5cae1 100644 --- a/elf/dl-tunables.c +++ b/elf/dl-tunables.c @@ -184,19 +184,17 @@ tunables_strtoul (const char *nptr) if ((__type) (__val) >= min && (__type) (val) <= max) \ { \ (__cur)->val.numval = val; \ - (__cur)->strval = strval; \ + (__cur)->initialized = true; \ } \ }) -/* Validate range of the input value and initialize the tunable CUR if it looks - good. */ static void -tunable_initialize (tunable_t *cur, const char *strval) +do_tunable_update_val (tunable_t *cur, const void *valp) { uint64_t val; if (cur->type.type_code != TUNABLE_TYPE_STRING) - val = tunables_strtoul (strval); + val = *((int64_t *) valp); switch (cur->type.type_code) { @@ -217,7 +215,7 @@ tunable_initialize (tunable_t *cur, const char *strval) } case TUNABLE_TYPE_STRING: { - cur->val.strval = cur->strval = strval; + cur->val.strval = valp; break; } default: @@ -225,6 +223,35 @@ tunable_initialize (tunable_t *cur, const char *strval) } } +/* Validate range of the input value and initialize the tunable CUR if it looks + good. */ +static void +tunable_initialize (tunable_t *cur, const char *strval) +{ + uint64_t val; + const void *valp; + + if (cur->type.type_code != TUNABLE_TYPE_STRING) + { + val = tunables_strtoul (strval); + valp = &val; + } + else + { + cur->initialized = true; + valp = strval; + } + do_tunable_update_val (cur, valp); +} + +void +__tunable_set_val (tunable_id_t id, void *valp) +{ + tunable_t *cur = &tunable_list[id]; + + do_tunable_update_val (cur, valp); +} + #if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring /* Parse the tunable string TUNESTR and adjust it to drop any tunables that may be unsafe for AT_SECURE processes so that it can be used as the new @@ -375,7 +402,7 @@ __tunables_init (char **envp) /* Skip over tunables that have either been set already or should be skipped. */ - if (cur->strval != NULL || cur->env_alias == NULL) + if (cur->initialized || cur->env_alias == NULL) continue; const char *name = cur->env_alias; @@ -426,20 +453,10 @@ __tunables_init (char **envp) /* Set the tunable value. This is called by the module that the tunable exists in. */ void -__tunable_set_val (tunable_id_t id, void *valp, tunable_callback_t callback) +__tunable_get_val (tunable_id_t id, void *valp, tunable_callback_t callback) { tunable_t *cur = &tunable_list[id]; - /* Don't do anything if our tunable was not set during initialization or if - it failed validation. */ - if (cur->strval == NULL) - return; - - /* Caller does not need the value, just call the callback with our tunable - value. */ - if (valp == NULL) - goto cb; - switch (cur->type.type_code) { case TUNABLE_TYPE_UINT_64: @@ -466,9 +483,8 @@ __tunable_set_val (tunable_id_t id, void *valp, tunable_callback_t callback) __builtin_unreachable (); } -cb: - if (callback) + if (cur->initialized && callback != NULL) callback (&cur->val); } -rtld_hidden_def (__tunable_set_val) +rtld_hidden_def (__tunable_get_val) diff --git a/elf/dl-tunables.h b/elf/dl-tunables.h index 20ee51254e..6c49dcbf47 100644 --- a/elf/dl-tunables.h +++ b/elf/dl-tunables.h @@ -39,8 +39,8 @@ struct _tunable const char *name; /* Internal name of the tunable. */ tunable_type_t type; /* Data type of the tunable. */ tunable_val_t val; /* The value. */ - const char *strval; /* The string containing the value, - points into envp. */ + bool initialized; /* Flag to indicate that the tunable is + initialized. */ tunable_seclevel_t security_level; /* Specify the security level for the tunable with respect to AT_SECURE programs. See description of @@ -61,37 +61,52 @@ typedef struct _tunable tunable_t; /* Full name for a tunable is top_ns.tunable_ns.id. */ # define TUNABLE_NAME_S(top,ns,id) #top "." #ns "." #id -# define TUNABLE_ENUM_NAME(top,ns,id) TUNABLE_ENUM_NAME1 (top,ns,id) -# define TUNABLE_ENUM_NAME1(top,ns,id) top ## _ ## ns ## _ ## id +# define TUNABLE_ENUM_NAME(__top,__ns,__id) TUNABLE_ENUM_NAME1 (__top,__ns,__id) +# define TUNABLE_ENUM_NAME1(__top,__ns,__id) __top ## _ ## __ns ## _ ## __id # include "dl-tunable-list.h" extern void __tunables_init (char **); -extern void __tunable_set_val (tunable_id_t, void *, tunable_callback_t); - +extern void __tunable_get_val (tunable_id_t, void *, tunable_callback_t); +extern void __tunable_set_val (tunable_id_t, void *); rtld_hidden_proto (__tunables_init) -rtld_hidden_proto (__tunable_set_val) +rtld_hidden_proto (__tunable_get_val) + +/* Define TUNABLE_GET and TUNABLE_SET in short form if TOP_NAMESPACE and + TUNABLE_NAMESPACE are defined. This is useful shorthand to get and set + tunables within a module. */ +#if defined TOP_NAMESPACE && defined TUNABLE_NAMESPACE +# define TUNABLE_GET(__id, __type, __cb) \ + TUNABLE_GET_FULL (TOP_NAMESPACE, TUNABLE_NAMESPACE, __id, __type, __cb) +# define TUNABLE_SET(__id, __type, __val) \ + TUNABLE_SET_FULL (TOP_NAMESPACE, TUNABLE_NAMESPACE, __id, __type, __val) +#else +# define TUNABLE_GET(__top, __ns, __id, __type, __cb) \ + TUNABLE_GET_FULL (__top, __ns, __id, __type, __cb) +# define TUNABLE_SET(__top, __ns, __id, __type, __val) \ + TUNABLE_SET_FULL (__top, __ns, __id, __type, __val) +#endif -/* Check if the tunable has been set to a non-default value and if it is, copy - it over into __VAL. */ -# define TUNABLE_SET_VAL(__id,__val) \ +/* Get and return a tunable value. If the tunable was set externally and __CB + is defined then call __CB before returning the value. */ +# define TUNABLE_GET_FULL(__top, __ns, __id, __type, __cb) \ ({ \ - __tunable_set_val \ - (TUNABLE_ENUM_NAME (TOP_NAMESPACE, TUNABLE_NAMESPACE, __id), (__val), \ - NULL); \ + tunable_id_t id = TUNABLE_ENUM_NAME (__top, __ns, __id); \ + __type ret; \ + __tunable_get_val (id, &ret, __cb); \ + ret; \ }) -/* Same as TUNABLE_SET_VAL, but also call the callback function __CB. */ -# define TUNABLE_SET_VAL_WITH_CALLBACK(__id,__val,__cb) \ +/* Set a tunable value. */ +# define TUNABLE_SET_FULL(__top, __ns, __id, __type, __val) \ ({ \ - __tunable_set_val \ - (TUNABLE_ENUM_NAME (TOP_NAMESPACE, TUNABLE_NAMESPACE, __id), (__val), \ - DL_TUNABLE_CALLBACK (__cb)); \ + __tunable_set_val (TUNABLE_ENUM_NAME (__top, __ns, __id), \ + & (__type) {__val}); \ }) /* Namespace sanity for callback functions. Use this macro to keep the namespace of the modules clean. */ -# define DL_TUNABLE_CALLBACK(__name) _dl_tunable_ ## __name +# define TUNABLE_CALLBACK(__name) _dl_tunable_ ## __name # define TUNABLES_FRONTEND_valstring 1 /* The default value for TUNABLES_FRONTEND. */ diff --git a/malloc/arena.c b/malloc/arena.c index d49e4a21c8..660d638c93 100644 --- a/malloc/arena.c +++ b/malloc/arena.c @@ -212,7 +212,7 @@ __malloc_fork_unlock_child (void) #if HAVE_TUNABLES static inline int do_set_mallopt_check (int32_t value); void -DL_TUNABLE_CALLBACK (set_mallopt_check) (tunable_val_t *valp) +TUNABLE_CALLBACK (set_mallopt_check) (tunable_val_t *valp) { int32_t value = (int32_t) valp->numval; do_set_mallopt_check (value); @@ -220,22 +220,22 @@ DL_TUNABLE_CALLBACK (set_mallopt_check) (tunable_val_t *valp) __malloc_check_init (); } -# define DL_TUNABLE_CALLBACK_FNDECL(__name, __type) \ +# define TUNABLE_CALLBACK_FNDECL(__name, __type) \ static inline int do_ ## __name (__type value); \ void \ -DL_TUNABLE_CALLBACK (__name) (tunable_val_t *valp) \ +TUNABLE_CALLBACK (__name) (tunable_val_t *valp) \ { \ __type value = (__type) (valp)->numval; \ do_ ## __name (value); \ } -DL_TUNABLE_CALLBACK_FNDECL (set_mmap_threshold, size_t) -DL_TUNABLE_CALLBACK_FNDECL (set_mmaps_max, int32_t) -DL_TUNABLE_CALLBACK_FNDECL (set_top_pad, size_t) -DL_TUNABLE_CALLBACK_FNDECL (set_perturb_byte, int32_t) -DL_TUNABLE_CALLBACK_FNDECL (set_trim_threshold, size_t) -DL_TUNABLE_CALLBACK_FNDECL (set_arena_max, size_t) -DL_TUNABLE_CALLBACK_FNDECL (set_arena_test, size_t) +TUNABLE_CALLBACK_FNDECL (set_mmap_threshold, size_t) +TUNABLE_CALLBACK_FNDECL (set_mmaps_max, int32_t) +TUNABLE_CALLBACK_FNDECL (set_top_pad, size_t) +TUNABLE_CALLBACK_FNDECL (set_perturb_byte, int32_t) +TUNABLE_CALLBACK_FNDECL (set_trim_threshold, size_t) +TUNABLE_CALLBACK_FNDECL (set_arena_max, size_t) +TUNABLE_CALLBACK_FNDECL (set_arena_test, size_t) #else /* Initialization routine. */ #include @@ -314,14 +314,14 @@ ptmalloc_init (void) __libc_lock_lock (main_arena.mutex); malloc_consolidate (&main_arena); - TUNABLE_SET_VAL_WITH_CALLBACK (check, NULL, set_mallopt_check); - TUNABLE_SET_VAL_WITH_CALLBACK (top_pad, NULL, set_top_pad); - TUNABLE_SET_VAL_WITH_CALLBACK (perturb, NULL, set_perturb_byte); - TUNABLE_SET_VAL_WITH_CALLBACK (mmap_threshold, NULL, set_mmap_threshold); - TUNABLE_SET_VAL_WITH_CALLBACK (trim_threshold, NULL, set_trim_threshold); - TUNABLE_SET_VAL_WITH_CALLBACK (mmap_max, NULL, set_mmaps_max); - TUNABLE_SET_VAL_WITH_CALLBACK (arena_max, NULL, set_arena_max); - TUNABLE_SET_VAL_WITH_CALLBACK (arena_test, NULL, set_arena_test); + TUNABLE_GET (check, int32_t, TUNABLE_CALLBACK (set_mallopt_check)); + TUNABLE_GET (top_pad, size_t, TUNABLE_CALLBACK (set_top_pad)); + TUNABLE_GET (perturb, int32_t, TUNABLE_CALLBACK (set_perturb_byte)); + TUNABLE_GET (mmap_threshold, size_t, TUNABLE_CALLBACK (set_mmap_threshold)); + TUNABLE_GET (trim_threshold, size_t, TUNABLE_CALLBACK (set_trim_threshold)); + TUNABLE_GET (mmap_max, int32_t, TUNABLE_CALLBACK (set_mmaps_max)); + TUNABLE_GET (arena_max, size_t, TUNABLE_CALLBACK (set_arena_max)); + TUNABLE_GET (arena_test, size_t, TUNABLE_CALLBACK (set_arena_test)); __libc_lock_unlock (main_arena.mutex); #else const char *s = NULL; -- cgit v1.2.3 From 52243b520e2d336431ea410ef3aa1f766642f1d2 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Fri, 16 Jun 2017 06:45:55 -0700 Subject: Remove _dl_out_of_memory from elf/Versions Since _dl_out_of_memory is static in elf/dl-error-skeleton.c: static const char _dl_out_of_memory[] = "out of memory"; remove _dl_out_of_memory from elf/Versions. * elf/Versions (ld): Remove _dl_out_of_memory. --- ChangeLog | 4 ++++ elf/Versions | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'elf/Versions') diff --git a/ChangeLog b/ChangeLog index 3581804a07..f4ac921321 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2017-06-16 H.J. Lu + + * elf/Versions (ld): Remove _dl_out_of_memory. + 2017-06-16 Joseph Myers * timezone/private.h: Update from tzcode 2017b. diff --git a/elf/Versions b/elf/Versions index c59facdbd7..e65f2fac20 100644 --- a/elf/Versions +++ b/elf/Versions @@ -58,7 +58,7 @@ ld { __libc_enable_secure; _dl_allocate_tls; _dl_allocate_tls_init; _dl_argv; _dl_find_dso_for_object; _dl_get_tls_static_info; - _dl_deallocate_tls; _dl_make_stack_executable; _dl_out_of_memory; + _dl_deallocate_tls; _dl_make_stack_executable; _dl_rtld_di_serinfo; _dl_starting_up; _rtld_global; _rtld_global_ro; -- cgit v1.2.3 From 2449ae7b2da24c9940962304a3e44bc80e389265 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Thu, 10 Aug 2017 13:40:22 +0200 Subject: ld.so: Introduce struct dl_exception This commit separates allocating and raising exceptions. This simplifies catching and re-raising them because it is no longer necessary to make a temporary, on-stack copy of the exception message. --- ChangeLog | 60 ++++++ elf/Makefile | 5 +- elf/Versions | 5 + elf/dl-deps.c | 39 +--- elf/dl-error-skeleton.c | 147 ++++++++------- elf/dl-exception.c | 202 +++++++++++++++++++++ elf/dl-lookup.c | 48 ++--- elf/dl-open.c | 31 +--- elf/dl-sym.c | 23 +-- elf/dl-version.c | 65 +++---- sysdeps/generic/ldsodefs.h | 107 ++++++++--- sysdeps/generic/localplt.data | 2 + sysdeps/unix/sysv/linux/aarch64/localplt.data | 2 + sysdeps/unix/sysv/linux/alpha/localplt.data | 2 + sysdeps/unix/sysv/linux/arm/localplt.data | 2 + sysdeps/unix/sysv/linux/hppa/localplt.data | 2 + sysdeps/unix/sysv/linux/i386/localplt.data | 2 + sysdeps/unix/sysv/linux/ia64/localplt.data | 2 + sysdeps/unix/sysv/linux/m68k/localplt.data | 2 + sysdeps/unix/sysv/linux/microblaze/localplt.data | 2 + sysdeps/unix/sysv/linux/nios2/localplt.data | 2 + .../sysv/linux/powerpc/powerpc32/fpu/localplt.data | 2 + .../linux/powerpc/powerpc32/nofpu/localplt.data | 2 + .../sysv/linux/powerpc/powerpc64/localplt.data | 2 + sysdeps/unix/sysv/linux/s390/localplt.data | 2 + sysdeps/unix/sysv/linux/sh/localplt.data | 2 + .../unix/sysv/linux/sparc/sparc32/localplt.data | 2 + .../unix/sysv/linux/sparc/sparc64/localplt.data | 2 + sysdeps/x86_64/localplt.data | 2 + 29 files changed, 529 insertions(+), 239 deletions(-) create mode 100644 elf/dl-exception.c (limited to 'elf/Versions') diff --git a/ChangeLog b/ChangeLog index 6648ce1676..dcf86261ca 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,63 @@ +2017-08-10 Florian Weimer + + Introduce ld.so exceptions. + * sysdeps/generic/ldsodefs.h (struct dl_exception): Define. + (_dl_exception_create, _dl_exception_create_format) + (_dl_exception_free, _dl_signal_exception, _dl_signal_cexception) + (_dl_catch_exception): Declare. + (_dl_catch_error): Update comment. + * elf/dl-error-skeleton.c (struct catch): Replace objname, + errstring, malloced members with exception member. + (_dl_out_of_memory): Remove. + (fatal_error): New function, extracted from _dl_signal_error. + (_dl_signal_exception, _dl_signal_cexception): New functions. + (_dl_signal_error): Call _dl_exception_create to allocate an + exception object. + (_dl_catch_exception): New function, based on _dl_catch_error. + (_dl_catch_error): Implement using _dl_catch_exception. + * elf/dl-exception.c: New file. + * elf/Makefile (dl-routines): Add dl-exception. + (elide-routines.os): Likewise. + * elf/Version (ld/GLIBC_PRIVATE): Add _dl_exception_create, + _dl_exception_create_format, _dl_exception_free. + * elf/dl-deps.c (_dl_map_object_deps): Use _dl_catch_exception and + _dl_signal_exception. + * elf/dl-lookup.c (make_string): Remove. + (_dl_lookup_symbol_x): Use _dl_exception_create_format, + _dl_signal_cexception, _dl_exception_free. + * elf/dl-open.c (_dl_open): Use _dl_catch_exception and + _dl_signal_exception. + * elf/dl-sym.c (do_sym): Likewise. + * elf/dl-version.c (make_string): Remove. + (match_symbol): Use _dl_exception_create_format, + _dl_signal_cexception, _dl_exception_free. + (_dl_check_map_versions): Likewise. + * sysdeps/generic/localplt.data (ld.so): Add _dl_signal_exception, + _dl_catch_exception. + * sysdeps/unix/sysv/linux/aarch64/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/alpha/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/arm/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/hppa/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/i386/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/ia64/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/m68k/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/microblaze/localplt.data (ld.so): + Likewise. + * sysdeps/unix/sysv/linux/nios2/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data + (ld.so): Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data + (ld.so): Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data (ld.so): + Likewise. + * sysdeps/unix/sysv/linux/s390/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/sh/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data (ld.so): + Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data (ld.so): + Likewise. + * sysdeps/x86_64/localplt.data (ld.so): Likewise. + 2017-08-10 Florian Weimer * inet/net-internal.h (__inet6_scopeid_pton): Remove diff --git a/elf/Makefile b/elf/Makefile index b54ebf8a98..d314a5fa7e 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -31,7 +31,8 @@ routines = $(all-dl-routines) dl-support dl-iteratephdr \ dl-routines = $(addprefix dl-,load lookup object reloc deps hwcaps \ runtime init fini debug misc \ version profile tls origin scope \ - execstack caller open close trampoline) + execstack caller open close trampoline \ + exception) ifeq (yes,$(use-ldconfig)) dl-routines += dl-cache endif @@ -51,7 +52,7 @@ endif all-dl-routines = $(dl-routines) $(sysdep-dl-routines) # But they are absent from the shared libc, because that code is in ld.so. elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin \ - dl-sysdep + dl-sysdep dl-exception shared-only-routines += dl-caller # ld.so uses those routines, plus some special stuff for being the program diff --git a/elf/Versions b/elf/Versions index e65f2fac20..79ffaf73d2 100644 --- a/elf/Versions +++ b/elf/Versions @@ -28,6 +28,7 @@ libc { __libc_dlclose; __libc_dlopen_mode; __libc_dlsym; # Internal error handling support. Interposes the functions in ld.so. + _dl_signal_exception; _dl_catch_exception; _dl_signal_error; _dl_catch_error; } } @@ -68,7 +69,11 @@ ld { # Pointer protection. __pointer_chk_guard; + # Internal error handling support. + _dl_exception_create; _dl_exception_create_format; _dl_exception_free; + # Internal error handling support. Interposed by libc.so. + _dl_signal_exception; _dl_catch_exception; _dl_signal_error; _dl_catch_error; # Set value of a tunable. diff --git a/elf/dl-deps.c b/elf/dl-deps.c index 1b8bac6593..7c82d42be9 100644 --- a/elf/dl-deps.c +++ b/elf/dl-deps.c @@ -165,8 +165,7 @@ _dl_map_object_deps (struct link_map *map, const char *name; int errno_saved; int errno_reason; - const char *errstring; - const char *objname; + struct dl_exception exception; /* No loaded object so far. */ nlist = 0; @@ -200,7 +199,6 @@ _dl_map_object_deps (struct link_map *map, alloca means we cannot use recursive function calls. */ errno_saved = errno; errno_reason = 0; - errstring = NULL; errno = 0; name = NULL; for (runp = known; runp; ) @@ -250,17 +248,9 @@ _dl_map_object_deps (struct link_map *map, /* Store the tag in the argument structure. */ args.name = name; - bool malloced; - int err = _dl_catch_error (&objname, &errstring, &malloced, - openaux, &args); - if (__glibc_unlikely (errstring != NULL)) + int err = _dl_catch_exception (&exception, openaux, &args); + if (__glibc_unlikely (exception.errstring != NULL)) { - char *new_errstring = strdupa (errstring); - objname = strdupa (objname); - if (malloced) - free ((char *) errstring); - errstring = new_errstring; - if (err) errno_reason = err; else @@ -313,31 +303,18 @@ _dl_map_object_deps (struct link_map *map, /* We must be prepared that the addressed shared object is not available. For filter objects the dependency must be available. */ - bool malloced; - int err = _dl_catch_error (&objname, &errstring, &malloced, - openaux, &args); - - if (__glibc_unlikely (errstring != NULL)) + int err = _dl_catch_exception (&exception, openaux, &args); + if (__glibc_unlikely (exception.errstring != NULL)) { if (d->d_tag == DT_AUXILIARY) { /* We are not interested in the error message. */ - assert (errstring != NULL); - if (malloced) - free ((char *) errstring); - + _dl_exception_free (&exception); /* Simply ignore this error and continue the work. */ continue; } else { - - char *new_errstring = strdupa (errstring); - objname = strdupa (objname); - if (malloced) - free ((char *) errstring); - errstring = new_errstring; - if (err) errno_reason = err; else @@ -683,6 +660,6 @@ Filters not supported with LD_TRACE_PRELINKING")); _dl_scope_free (old_l_initfini); if (errno_reason) - _dl_signal_error (errno_reason == -1 ? 0 : errno_reason, objname, - NULL, errstring); + _dl_signal_exception (errno_reason == -1 ? 0 : errno_reason, + &exception, NULL); } diff --git a/elf/dl-error-skeleton.c b/elf/dl-error-skeleton.c index 8e5888d4bd..8de6c87abf 100644 --- a/elf/dl-error-skeleton.c +++ b/elf/dl-error-skeleton.c @@ -39,10 +39,7 @@ _dl_signal_error. */ struct catch { - const char **objname; /* Object/File name. */ - const char **errstring; /* Error detail filled in here. */ - bool *malloced; /* Nonzero if the string is malloced - by the libc malloc. */ + struct dl_exception *exception; /* The exception data is stored there. */ volatile int *errcode; /* Return value of _dl_signal_error. */ jmp_buf env; /* longjmp here on error. */ }; @@ -60,11 +57,6 @@ static __thread struct catch *catch_hook attribute_tls_model_ie; static struct catch *catch_hook; #endif -/* This message we return as a last resort. We define the string in a - variable since we have to avoid freeing it and so have to enable - a pointer comparison. See below and in dlfcn/dlerror.c. */ -static const char _dl_out_of_memory[] = "out of memory"; - #if DL_ERROR_BOOTSTRAP /* This points to a function which is called when an continuable error is received. Unlike the handling of `catch' this function may return. @@ -76,6 +68,41 @@ static const char _dl_out_of_memory[] = "out of memory"; static receiver_fct receiver; #endif /* DL_ERROR_BOOTSTRAP */ +/* Lossage while resolving the program's own symbols is always fatal. */ +static void +__attribute__ ((noreturn)) +fatal_error (int errcode, const char *objname, const char *occasion, + const char *errstring) +{ + char buffer[1024]; + _dl_fatal_printf ("%s: %s: %s%s%s%s%s\n", + RTLD_PROGNAME, + occasion ?: N_("error while loading shared libraries"), + objname, *objname ? ": " : "", + errstring, errcode ? ": " : "", + (errcode + ? __strerror_r (errcode, buffer, sizeof buffer) + : "")); +} + +void +_dl_signal_exception (int errcode, struct dl_exception *exception, + const char *occasion) +{ + struct catch *lcatch = catch_hook; + if (lcatch != NULL) + { + *lcatch->exception = *exception; + *lcatch->errcode = errcode; + + /* We do not restore the signal mask because none was saved. */ + __longjmp (lcatch->env[0].__jmpbuf, 1); + } + else + fatal_error (errcode, exception->objname, occasion, exception->errstring); +} +libc_hidden_def (_dl_signal_exception) + void internal_function _dl_signal_error (int errcode, const char *objname, const char *occation, @@ -86,65 +113,42 @@ _dl_signal_error (int errcode, const char *objname, const char *occation, if (! errstring) errstring = N_("DYNAMIC LINKER BUG!!!"); - if (objname == NULL) - objname = ""; if (lcatch != NULL) { - /* We are inside _dl_catch_error. Return to it. We have to - duplicate the error string since it might be allocated on the - stack. The object name is always a string constant. */ - size_t len_objname = strlen (objname) + 1; - size_t len_errstring = strlen (errstring) + 1; - - char *errstring_copy = malloc (len_objname + len_errstring); - if (errstring_copy != NULL) - { - /* Make a copy of the object file name and the error string. */ - *lcatch->objname = memcpy (__mempcpy (errstring_copy, - errstring, len_errstring), - objname, len_objname); - *lcatch->errstring = errstring_copy; - - /* If the main executable is relocated it means the libc's malloc - is used. */ - bool malloced = true; -#ifdef SHARED - malloced = (GL(dl_ns)[LM_ID_BASE]._ns_loaded != NULL - && (GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_relocated != 0)); -#endif - *lcatch->malloced = malloced; - } - else - { - /* This is better than nothing. */ - *lcatch->objname = ""; - *lcatch->errstring = _dl_out_of_memory; - *lcatch->malloced = false; - } - + _dl_exception_create (lcatch->exception, objname, errstring); *lcatch->errcode = errcode; /* We do not restore the signal mask because none was saved. */ __longjmp (lcatch->env[0].__jmpbuf, 1); } else - { - /* Lossage while resolving the program's own symbols is always fatal. */ - char buffer[1024]; - _dl_fatal_printf ("%s: %s: %s%s%s%s%s\n", - RTLD_PROGNAME, - occation ?: N_("error while loading shared libraries"), - objname, *objname ? ": " : "", - errstring, errcode ? ": " : "", - (errcode - ? __strerror_r (errcode, buffer, sizeof buffer) - : "")); - } + fatal_error (errcode, objname, occation, errstring); } libc_hidden_def (_dl_signal_error) #if DL_ERROR_BOOTSTRAP +void +_dl_signal_cexception (int errcode, struct dl_exception *exception, + const char *occasion) +{ + if (__builtin_expect (GLRO(dl_debug_mask) + & ~(DL_DEBUG_STATISTICS|DL_DEBUG_PRELINK), 0)) + _dl_debug_printf ("%s: error: %s: %s (%s)\n", + exception->objname, occasion, + exception->errstring, receiver ? "continued" : "fatal"); + + if (receiver) + { + /* We are inside _dl_receive_error. Call the user supplied + handler and resume the work. The receiver will still be + installed. */ + (*receiver) (errcode, exception->objname, exception->errstring); + } + else + _dl_signal_exception (errcode, exception, occasion); +} + void internal_function _dl_signal_cerror (int errcode, const char *objname, const char *occation, @@ -167,11 +171,9 @@ _dl_signal_cerror (int errcode, const char *objname, const char *occation, } #endif /* DL_ERROR_BOOTSTRAP */ - int -internal_function -_dl_catch_error (const char **objname, const char **errstring, - bool *mallocedp, void (*operate) (void *), void *args) +_dl_catch_exception (struct dl_exception *exception, + void (*operate) (void *), void *args) { /* We need not handle `receiver' since setting a `catch' is handled before it. */ @@ -184,9 +186,7 @@ _dl_catch_error (const char **objname, const char **errstring, struct catch c; /* Don't use an initializer since we don't need to clear C.env. */ - c.objname = objname; - c.errstring = errstring; - c.malloced = mallocedp; + c.exception = exception; c.errcode = &errcode; struct catch *const old = catch_hook; @@ -197,17 +197,30 @@ _dl_catch_error (const char **objname, const char **errstring, { (*operate) (args); catch_hook = old; - *objname = NULL; - *errstring = NULL; - *mallocedp = false; + *exception = (struct dl_exception) { NULL }; return 0; } - /* We get here only if we longjmp'd out of OPERATE. _dl_signal_error has - already stored values into *OBJNAME, *ERRSTRING, and *MALLOCEDP. */ + /* We get here only if we longjmp'd out of OPERATE. + _dl_signal_exception has already stored values into + *EXCEPTION. */ catch_hook = old; return errcode; } +libc_hidden_def (_dl_catch_exception) + +int +internal_function +_dl_catch_error (const char **objname, const char **errstring, + bool *mallocedp, void (*operate) (void *), void *args) +{ + struct dl_exception exception; + int errorcode = _dl_catch_exception (&exception, operate, args); + *objname = exception.objname; + *errstring = exception.errstring; + *mallocedp = exception.message_buffer == exception.errstring; + return errorcode; +} libc_hidden_def (_dl_catch_error) #if DL_ERROR_BOOTSTRAP diff --git a/elf/dl-exception.c b/elf/dl-exception.c new file mode 100644 index 0000000000..b4d0ca7578 --- /dev/null +++ b/elf/dl-exception.c @@ -0,0 +1,202 @@ +/* ld.so error exception allocation and deallocation. + Copyright (C) 1995-2017 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 + . */ + +#include +#include +#include +#include +#include +#include +#include + +/* This message we return as a last resort. We define the string in a + variable since we have to avoid freeing it and so have to enable + a pointer comparison. See below and in dlfcn/dlerror.c. */ +static const char _dl_out_of_memory[] = "out of memory"; + +/* Dummy allocation object used if allocating the message buffer + fails. */ +static void +oom_exception (struct dl_exception *exception) +{ + exception->objname = ""; + exception->errstring = _dl_out_of_memory; + exception->message_buffer = NULL; +} + +static void +__attribute__ ((noreturn)) +length_mismatch (void) +{ + _dl_fatal_printf ("Fatal error: " + "length accounting in _dl_exception_create_format\n"); +} + +/* Adjust the message buffer to indicate whether it is possible to + free it. EXCEPTION->errstring must be a potentially deallocatable + pointer. */ +static void +adjust_message_buffer (struct dl_exception *exception) +{ + /* If the main executable is relocated it means the libc's malloc + is used. */ + bool malloced = true; +#ifdef SHARED + malloced = (GL(dl_ns)[LM_ID_BASE]._ns_loaded != NULL + && (GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_relocated != 0)); +#endif + if (malloced) + exception->message_buffer = (char *) exception->errstring; + else + exception->message_buffer = NULL; +} + +void +_dl_exception_create (struct dl_exception *exception, const char *objname, + const char *errstring) +{ + if (objname == NULL) + objname = ""; + size_t len_objname = strlen (objname) + 1; + size_t len_errstring = strlen (errstring) + 1; + char *errstring_copy = malloc (len_objname + len_errstring); + if (errstring_copy != NULL) + { + /* Make a copy of the object file name and the error string. */ + exception->objname = memcpy (__mempcpy (errstring_copy, + errstring, len_errstring), + objname, len_objname); + exception->errstring = errstring_copy; + adjust_message_buffer (exception); + } + else + oom_exception (exception); +} +rtld_hidden_def (_dl_exception_create) + +void +_dl_exception_create_format (struct dl_exception *exception, const char *objname, + const char *fmt, ...) +{ + if (objname == NULL) + objname = ""; + size_t len_objname = strlen (objname) + 1; + /* Compute the length of the result. Include room for two NUL + bytes. */ + size_t length = len_objname + 1; + { + va_list ap; + va_start (ap, fmt); + for (const char *p = fmt; *p != '\0'; ++p) + if (*p == '%') + { + ++p; + switch (*p) + { + case 's': + length += strlen (va_arg (ap, const char *)); + break; + default: + /* Assumed to be '%'. */ + ++length; + break; + } + } + else + ++length; + va_end (ap); + } + + if (length > PTRDIFF_MAX) + { + oom_exception (exception); + return; + } + char *errstring = malloc (length); + if (errstring == NULL) + { + oom_exception (exception); + return; + } + exception->errstring = errstring; + adjust_message_buffer (exception); + + /* Copy the error message to errstring. */ + { + /* Next byte to be written in errstring. */ + char *wptr = errstring; + /* End of the allocated string. */ + char *const end = errstring + length; + + va_list ap; + va_start (ap, fmt); + + for (const char *p = fmt; *p != '\0'; ++p) + if (*p == '%') + { + ++p; + switch (*p) + { + case 's': + { + const char *ptr = va_arg (ap, const char *); + size_t len_ptr = strlen (ptr); + if (len_ptr > end - wptr) + length_mismatch (); + wptr = __mempcpy (wptr, ptr, len_ptr); + } + break; + case '%': + if (wptr == end) + length_mismatch (); + *wptr = '%'; + ++wptr; + break; + default: + _dl_fatal_printf ("Fatal error:" + " invalid format in exception string\n"); + } + } + else + { + if (wptr == end) + length_mismatch (); + *wptr = *p; + ++wptr; + } + + if (wptr == end) + length_mismatch (); + *wptr = '\0'; + ++wptr; + if (len_objname != end - wptr) + length_mismatch (); + exception->objname = memcpy (wptr, objname, len_objname); + } +} +rtld_hidden_def (_dl_exception_create_format) + +void +_dl_exception_free (struct dl_exception *exception) +{ + free (exception->message_buffer); + exception->objname = NULL; + exception->errstring = NULL; + exception->message_buffer = NULL; +} +rtld_hidden_def (_dl_exception_free) diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c index 3d2369dbf2..645dc3ebb4 100644 --- a/elf/dl-lookup.c +++ b/elf/dl-lookup.c @@ -47,23 +47,6 @@ struct sym_val }; -#define make_string(string, rest...) \ - ({ \ - const char *all[] = { string, ## rest }; \ - size_t len, cnt; \ - char *result, *cp; \ - \ - len = 1; \ - for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \ - len += strlen (all[cnt]); \ - \ - cp = result = alloca (len); \ - for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \ - cp = __stpcpy (cp, all[cnt]); \ - \ - result; \ - }) - /* Statistics function. */ #ifdef SHARED # define bump_num_relocations() ++GL(dl_num_relocations) @@ -843,17 +826,16 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map, for unversioned lookups. */ assert (version != NULL); const char *reference_name = undef_map ? undef_map->l_name : ""; - + struct dl_exception exception; /* XXX We cannot translate the message. */ - _dl_signal_cerror (0, DSO_FILENAME (reference_name), - N_("relocation error"), - make_string ("symbol ", undef_name, ", version ", - version->name, - " not defined in file ", - version->filename, - " with link time reference", - res == -2 - ? " (no version symbols)" : "")); + _dl_exception_create_format + (&exception, DSO_FILENAME (reference_name), + "symbol %s version %s not defined in file %s" + " with link time reference%s", + undef_name, version->name, version->filename, + res == -2 ? " (no version symbols)" : ""); + _dl_signal_cexception (0, &exception, N_("relocation error")); + _dl_exception_free (&exception); *ref = NULL; return 0; } @@ -869,12 +851,14 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map, const char *versionstr = version ? ", version " : ""; const char *versionname = (version && version->name ? version->name : ""); - + struct dl_exception exception; /* XXX We cannot translate the message. */ - _dl_signal_cerror (0, DSO_FILENAME (reference_name), - N_("symbol lookup error"), - make_string ("undefined symbol: ", undef_name, - versionstr, versionname)); + _dl_exception_create_format + (&exception, DSO_FILENAME (reference_name), + "undefined symbol: %s%s%s", + undef_name, versionstr, versionname); + _dl_signal_cexception (0, &exception, N_("symbol lookup error")); + _dl_exception_free (&exception); } *ref = NULL; return 0; diff --git a/elf/dl-open.c b/elf/dl-open.c index cec54db413..91a1d1a4f8 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -643,11 +643,8 @@ no more namespaces available for dlmopen()")); args.argv = argv; args.env = env; - const char *objname; - const char *errstring; - bool malloced; - int errcode = _dl_catch_error (&objname, &errstring, &malloced, - dl_open_worker, &args); + struct dl_exception exception; + int errcode = _dl_catch_exception (&exception, dl_open_worker, &args); #if defined USE_LDCONFIG && !defined MAP_COPY /* We must unmap the cache file. */ @@ -655,7 +652,7 @@ no more namespaces available for dlmopen()")); #endif /* See if an error occurred during loading. */ - if (__glibc_unlikely (errstring != NULL)) + if (__glibc_unlikely (exception.errstring != NULL)) { /* Remove the object from memory. It may be in an inconsistent state if relocation failed, for example. */ @@ -679,28 +676,8 @@ no more namespaces available for dlmopen()")); /* Release the lock. */ __rtld_lock_unlock_recursive (GL(dl_load_lock)); - /* Make a local copy of the error string so that we can release the - memory allocated for it. */ - size_t len_errstring = strlen (errstring) + 1; - char *local_errstring; - if (objname == errstring + len_errstring) - { - size_t total_len = len_errstring + strlen (objname) + 1; - local_errstring = alloca (total_len); - memcpy (local_errstring, errstring, total_len); - objname = local_errstring + len_errstring; - } - else - { - local_errstring = alloca (len_errstring); - memcpy (local_errstring, errstring, len_errstring); - } - - if (malloced) - free ((char *) errstring); - /* Reraise the error. */ - _dl_signal_error (errcode, objname, NULL, local_errstring); + _dl_signal_exception (errcode, &exception, NULL); } assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT); diff --git a/elf/dl-sym.c b/elf/dl-sym.c index 7cd6e97643..fb54a91858 100644 --- a/elf/dl-sym.c +++ b/elf/dl-sym.c @@ -119,26 +119,11 @@ do_sym (void *handle, const char *name, void *who, args.refp = &ref; THREAD_GSCOPE_SET_FLAG (); - - const char *objname; - const char *errstring = NULL; - bool malloced; - int err = _dl_catch_error (&objname, &errstring, &malloced, - call_dl_lookup, &args); - + struct dl_exception exception; + int err = _dl_catch_exception (&exception, call_dl_lookup, &args); THREAD_GSCOPE_RESET_FLAG (); - - if (__glibc_unlikely (errstring != NULL)) - { - /* The lookup was unsuccessful. Rethrow the error. */ - char *errstring_dup = strdupa (errstring); - char *objname_dup = strdupa (objname); - if (malloced) - free ((char *) errstring); - - _dl_signal_error (err, objname_dup, NULL, errstring_dup); - /* NOTREACHED */ - } + if (__glibc_unlikely (exception.errstring != NULL)) + _dl_signal_exception (err, &exception, NULL); result = args.map; } diff --git a/elf/dl-version.c b/elf/dl-version.c index c00078e5e4..c0d76ad42a 100644 --- a/elf/dl-version.c +++ b/elf/dl-version.c @@ -27,25 +27,6 @@ #include - -#define make_string(string, rest...) \ - ({ \ - const char *all[] = { string, ## rest }; \ - size_t len, cnt; \ - char *result, *cp; \ - \ - len = 1; \ - for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \ - len += strlen (all[cnt]); \ - \ - cp = result = alloca (len); \ - for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \ - cp = __stpcpy (cp, all[cnt]); \ - \ - result; \ - }) - - static inline struct link_map * __attribute ((always_inline)) find_needed (const char *name, struct link_map *map) @@ -78,8 +59,8 @@ match_symbol (const char *name, Lmid_t ns, ElfW(Word) hash, const char *string, ElfW(Addr) def_offset; ElfW(Verdef) *def; /* Initialize to make the compiler happy. */ - const char *errstring = NULL; int result = 0; + struct dl_exception exception; /* Display information about what we are doing while debugging. */ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_VERSIONS)) @@ -96,8 +77,9 @@ checking for version `%s' in file %s [%lu] required by file %s [%lu]\n", if (verbose) { /* XXX We cannot translate the messages. */ - errstring = make_string ("\ -no version information available (required by ", name, ")"); + _dl_exception_create_format + (&exception, DSO_FILENAME (map->l_name), + "no version information available (required by %s)", name); goto call_cerror; } return 0; @@ -116,10 +98,10 @@ no version information available (required by ", name, ")"); char buf[20]; buf[sizeof (buf) - 1] = '\0'; /* XXX We cannot translate the message. */ - errstring = make_string ("unsupported version ", - _itoa (def->vd_version, - &buf[sizeof (buf) - 1], 10, 0), - " of Verdef record"); + _dl_exception_create_format + (&exception, DSO_FILENAME (map->l_name), + "unsupported version %s of Verdef record", + _itoa (def->vd_version, &buf[sizeof (buf) - 1], 10, 0)); result = 1; goto call_cerror; } @@ -150,20 +132,22 @@ no version information available (required by ", name, ")"); if (verbose) { /* XXX We cannot translate the message. */ - errstring = make_string ("weak version `", string, - "' not found (required by ", name, ")"); + _dl_exception_create_format + (&exception, DSO_FILENAME (map->l_name), + "weak version `%s' not found (required by %s)", string, name); goto call_cerror; } return 0; } /* XXX We cannot translate the message. */ - errstring = make_string ("version `", string, "' not found (required by ", - name, ")"); + _dl_exception_create_format + (&exception, DSO_FILENAME (map->l_name), + "version `%s' not found (required by %s)", string, name); result = 1; call_cerror: - _dl_signal_cerror (0, DSO_FILENAME (map->l_name), - N_("version lookup error"), errstring); + _dl_signal_cexception (0, &exception, N_("version lookup error")); + _dl_exception_free (&exception); return result; } @@ -181,8 +165,8 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode) /* We need to find out which is the highest version index used in a dependecy. */ unsigned int ndx_high = 0; + struct dl_exception exception; /* Initialize to make the compiler happy. */ - const char *errstring = NULL; int errval = 0; /* If we don't have a string table, we must be ok. */ @@ -205,13 +189,12 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode) char buf[20]; buf[sizeof (buf) - 1] = '\0'; /* XXX We cannot translate the message. */ - errstring = make_string ("unsupported version ", - _itoa (ent->vn_version, - &buf[sizeof (buf) - 1], 10, 0), - " of Verneed record\n"); + _dl_exception_create_format + (&exception, DSO_FILENAME (map->l_name), + "unsupported version %s of Verneed record", + _itoa (ent->vn_version, &buf[sizeof (buf) - 1], 10, 0)); call_error: - _dl_signal_error (errval, DSO_FILENAME (map->l_name), - NULL, errstring); + _dl_signal_exception (errval, &exception, NULL); } while (1) @@ -293,7 +276,9 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode) calloc (ndx_high + 1, sizeof (*map->l_versions)); if (__glibc_unlikely (map->l_versions == NULL)) { - errstring = N_("cannot allocate version reference table"); + _dl_exception_create + (&exception, DSO_FILENAME (map->l_name), + N_("cannot allocate version reference table")); errval = ENOMEM; goto call_error; } diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index 4508365871..1c0b9cb32e 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -732,31 +732,88 @@ _dl_dprintf (int fd, const char *fmt, ...) while (1) -/* This function is called by all the internal dynamic linker functions - when they encounter an error. ERRCODE is either an `errno' code or - zero; OBJECT is the name of the problematical shared object, or null if - it is a general problem; ERRSTRING is a string describing the specific - problem. */ +/* An exception raised by the _dl_signal_error function family and + caught by _dl_catch_error function family. Exceptions themselves + are copied as part of the raise operation, but the strings are + not. */ +struct dl_exception +{ + const char *objname; + const char *errstring; + + /* This buffer typically stores both objname and errstring + above. */ + char *message_buffer; +}; + +/* Creates a new exception. This calls malloc; if allocation fails, + dummy values are inserted. OBJECT is the name of the problematical + shared object, or null if its a general problem. ERRSTRING is a + string describing the specific problem. */ +void _dl_exception_create (struct dl_exception *, const char *object, + const char *errstring) + __attribute__ ((nonnull (1, 3))); +rtld_hidden_proto (_dl_exception_create) + +/* Like _dl_exception_create, but create errstring from a format + string FMT. Currently, only "%s" and "%%" are supported as format + directives. */ +void _dl_exception_create_format (struct dl_exception *, const char *objname, + const char *fmt, ...) + __attribute__ ((nonnull (1, 3), format (printf, 3, 4))); +rtld_hidden_proto (_dl_exception_create_format) + +/* Deallocate the exception, freeing allocated buffers (if + possible). */ +void _dl_exception_free (struct dl_exception *) + __attribute__ ((nonnull (1))); +rtld_hidden_proto (_dl_exception_free) + +/* This function is called by all the internal dynamic linker + functions when they encounter an error. ERRCODE is either an + `errno' code or zero; it specifies the return value of + _dl_catch_error. OCCASION is included in the error message if the + process is terminated immediately. */ +void _dl_signal_exception (int errcode, struct dl_exception *, + const char *occasion) + __attribute__ ((__noreturn__)); +libc_hidden_proto (_dl_signal_exception) + +/* Like _dl_signal_exception, but creates the exception first. */ extern void _dl_signal_error (int errcode, const char *object, - const char *occurred, const char *errstring) + const char *occasion, const char *errstring) internal_function __attribute__ ((__noreturn__)); libc_hidden_proto (_dl_signal_error) -/* Like _dl_signal_error, but may return when called in the context of - _dl_receive_error. This is only used during ld.so bootstrap. In - static and profiled builds, this is equivalent to - _dl_signal_error. */ +/* Like _dl_signal_exception, but may return when called in the + context of _dl_receive_error. This is only used during ld.so + bootstrap. In static and profiled builds, this is equivalent to + _dl_signal_exception. */ +#if IS_IN (rtld) +extern void _dl_signal_cexception (int errcode, struct dl_exception *, + const char *occasion) attribute_hidden; +#else +__attribute__ ((always_inline)) +static inline void +_dl_signal_cexception (int errcode, struct dl_exception *exception, + const char *occasion) +{ + _dl_signal_exception (errcode, exception, occasion); +} +#endif + +/* See _dl_signal_cexception above. */ #if IS_IN (rtld) extern void _dl_signal_cerror (int errcode, const char *object, - const char *occation, const char *errstring) + const char *occasion, const char *errstring) internal_function attribute_hidden; #else __attribute__ ((always_inline)) static inline void _dl_signal_cerror (int errcode, const char *object, - const char *occation, const char *errstring) + const char *occasion, const char *errstring) { - _dl_signal_error (errcode, object, occation, errstring); + _dl_signal_error (errcode, object, occasion, errstring); } #endif @@ -768,20 +825,28 @@ extern void _dl_receive_error (receiver_fct fct, void (*operate) (void *), void *args) internal_function attribute_hidden; -/* Call OPERATE, catching errors from `dl_signal_error'. If there is no - error, *ERRSTRING is set to null. If there is an error, *ERRSTRING is - set to a string constructed from the strings passed to _dl_signal_error, - and the error code passed is the return value and *OBJNAME is set to - the object name which experienced the problems. ERRSTRING if nonzero - points to a malloc'ed string which the caller has to free after use. - ARGS is passed as argument to OPERATE. MALLOCEDP is set to true only - if the returned string is allocated using the libc's malloc. */ +/* Call OPERATE, catching errors from `_dl_signal_error' and related + functions. If there is no error, *ERRSTRING is set to null. If + there is an error, *ERRSTRING is set to a string constructed from + the strings passed to _dl_signal_error, and the error code passed + is the return value and *OBJNAME is set to the object name which + experienced the problems. ERRSTRING if nonzero points to a + malloc'ed string which the caller has to free after use. ARGS is + passed as argument to OPERATE. MALLOCEDP is set to true only if + the returned string is allocated using the libc's malloc. */ extern int _dl_catch_error (const char **objname, const char **errstring, bool *mallocedp, void (*operate) (void *), void *args) internal_function; libc_hidden_proto (_dl_catch_error) +/* Call OPERATE (ARGS). If no error occurs, set *EXCEPTION to zero. + Otherwise, store a copy of the raised exception in *EXCEPTION, + which has to be freed by _dl_exception_free. */ +int _dl_catch_exception (struct dl_exception *exception, + void (*operate) (void *), void *args); +libc_hidden_proto (_dl_catch_exception) + /* Open the shared object NAME and map in its segments. LOADER's DT_RPATH is used in searching for NAME. If the object is already opened, returns its existing map. */ diff --git a/sysdeps/generic/localplt.data b/sysdeps/generic/localplt.data index 81c741b038..2d5c66ae28 100644 --- a/sysdeps/generic/localplt.data +++ b/sysdeps/generic/localplt.data @@ -16,3 +16,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/aarch64/localplt.data b/sysdeps/unix/sysv/linux/aarch64/localplt.data index bb18ff9bb2..a60053b914 100644 --- a/sysdeps/unix/sysv/linux/aarch64/localplt.data +++ b/sysdeps/unix/sysv/linux/aarch64/localplt.data @@ -18,3 +18,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/alpha/localplt.data b/sysdeps/unix/sysv/linux/alpha/localplt.data index 1f0e3b494e..c69eb04ce5 100644 --- a/sysdeps/unix/sysv/linux/alpha/localplt.data +++ b/sysdeps/unix/sysv/linux/alpha/localplt.data @@ -35,3 +35,5 @@ ld.so: free + RELA R_ALPHA_GLOB_DAT # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error + RELA R_ALPHA_GLOB_DAT ld.so: _dl_catch_error + RELA R_ALPHA_GLOB_DAT +ld.so: _dl_signal_exception + RELA R_ALPHA_GLOB_DAT +ld.so: _dl_catch_exception + RELA R_ALPHA_GLOB_DAT diff --git a/sysdeps/unix/sysv/linux/arm/localplt.data b/sysdeps/unix/sysv/linux/arm/localplt.data index 19d3299d98..7bd541c28a 100644 --- a/sysdeps/unix/sysv/linux/arm/localplt.data +++ b/sysdeps/unix/sysv/linux/arm/localplt.data @@ -17,3 +17,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/hppa/localplt.data b/sysdeps/unix/sysv/linux/hppa/localplt.data index db9e24b090..3279c0af05 100644 --- a/sysdeps/unix/sysv/linux/hppa/localplt.data +++ b/sysdeps/unix/sysv/linux/hppa/localplt.data @@ -21,3 +21,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/i386/localplt.data b/sysdeps/unix/sysv/linux/i386/localplt.data index 8ea4333846..f6f20a5d15 100644 --- a/sysdeps/unix/sysv/linux/i386/localplt.data +++ b/sysdeps/unix/sysv/linux/i386/localplt.data @@ -16,3 +16,5 @@ ld.so: free + REL R_386_GLOB_DAT # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error + REL R_386_GLOB_DAT ld.so: _dl_catch_error + REL R_386_GLOB_DAT +ld.so: _dl_signal_exception + REL R_386_GLOB_DAT +ld.so: _dl_catch_exception + REL R_386_GLOB_DAT diff --git a/sysdeps/unix/sysv/linux/ia64/localplt.data b/sysdeps/unix/sysv/linux/ia64/localplt.data index fd2b98c8b6..3820e2a4e6 100644 --- a/sysdeps/unix/sysv/linux/ia64/localplt.data +++ b/sysdeps/unix/sysv/linux/ia64/localplt.data @@ -15,3 +15,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/m68k/localplt.data b/sysdeps/unix/sysv/linux/m68k/localplt.data index 1a2acfdb93..c70d6ea301 100644 --- a/sysdeps/unix/sysv/linux/m68k/localplt.data +++ b/sysdeps/unix/sysv/linux/m68k/localplt.data @@ -15,3 +15,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/microblaze/localplt.data b/sysdeps/unix/sysv/linux/microblaze/localplt.data index ca476bedd8..8ca23897df 100644 --- a/sysdeps/unix/sysv/linux/microblaze/localplt.data +++ b/sysdeps/unix/sysv/linux/microblaze/localplt.data @@ -16,3 +16,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/nios2/localplt.data b/sysdeps/unix/sysv/linux/nios2/localplt.data index b0d6dcae55..4430a5891e 100644 --- a/sysdeps/unix/sysv/linux/nios2/localplt.data +++ b/sysdeps/unix/sysv/linux/nios2/localplt.data @@ -36,3 +36,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data index 50006317c7..e822e0a480 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data @@ -14,3 +14,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data index 1c20d2f2b4..fead931d4e 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data @@ -44,3 +44,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data index 6f8ed25922..c1209336d2 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data @@ -13,3 +13,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/s390/localplt.data b/sysdeps/unix/sysv/linux/s390/localplt.data index 50006317c7..e822e0a480 100644 --- a/sysdeps/unix/sysv/linux/s390/localplt.data +++ b/sysdeps/unix/sysv/linux/s390/localplt.data @@ -14,3 +14,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/sh/localplt.data b/sysdeps/unix/sysv/linux/sh/localplt.data index f1f5effc24..2753547d97 100644 --- a/sysdeps/unix/sysv/linux/sh/localplt.data +++ b/sysdeps/unix/sysv/linux/sh/localplt.data @@ -19,3 +19,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data b/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data index 2f6ff3c3a6..1668f4017e 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data @@ -26,3 +26,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data b/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data index 912bd1a16e..b881b9096d 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data @@ -27,3 +27,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/x86_64/localplt.data b/sysdeps/x86_64/localplt.data index a1840cff31..c27a02b66a 100644 --- a/sysdeps/x86_64/localplt.data +++ b/sysdeps/x86_64/localplt.data @@ -18,3 +18,5 @@ ld.so: free + RELA R_X86_64_GLOB_DAT # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error + RELA R_X86_64_GLOB_DAT ld.so: _dl_catch_error + RELA R_X86_64_GLOB_DAT +ld.so: _dl_signal_exception + RELA R_X86_64_GLOB_DAT +ld.so: _dl_catch_exception + RELA R_X86_64_GLOB_DAT -- cgit v1.2.3 From 82eef55f8fad3e00c53050de5d6ebea08df488b3 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Thu, 4 Jan 2018 18:46:17 +0100 Subject: elf: Support dlvsym within libc.so This commit adds a new _dl_open_hook entry for dlvsym and implements the function using the existing dl_lookup_symbol_x function supplied by the dynamic loader. A new hook variable, _dl_open_hook2, is introduced, which should make this change suitable for backporting: For old statically linked binaries, __libc_dlvsym will always return NULL. --- ChangeLog | 25 +++++++++ elf/Makefile | 16 ++++-- elf/Versions | 4 +- elf/dl-libc.c | 73 ++++++++++++++++++++++++- elf/tst-libc_dlvsym-dso.c | 25 +++++++++ elf/tst-libc_dlvsym-static.c | 32 +++++++++++ elf/tst-libc_dlvsym.c | 34 ++++++++++++ elf/tst-libc_dlvsym.h | 125 +++++++++++++++++++++++++++++++++++++++++++ include/dlfcn.h | 2 + 9 files changed, 330 insertions(+), 6 deletions(-) create mode 100644 elf/tst-libc_dlvsym-dso.c create mode 100644 elf/tst-libc_dlvsym-static.c create mode 100644 elf/tst-libc_dlvsym.c create mode 100644 elf/tst-libc_dlvsym.h (limited to 'elf/Versions') diff --git a/ChangeLog b/ChangeLog index 878a738a32..7f0c2ebb0e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +2018-01-04 Florian Weimer + + Add support for calling dlvsym from libc.so. + * include/dlfcn.h (__libc_dlvsym): Declare. + * elf/Makefile (tests-static-internal): Add + tst-libc_dlvsym-static. + (tests-internal): Add tst-libc_dlvsym. + (modules-names): Add tst-libc_dlvsym-dso. + (tst-libc_dlvsym, tst-libc_dlvsym-static): Link with libdl. + (tst-libc_dlvsym-dso.so): Link with libdl, libsupport. + (tst-libc_dlvsym.out, tst-libc_dlvsym-static.out): The shared + object tst-libc_dlvsym-dso.so needs to be built before running + these tests. + (tst-libc_dlvsym-static-ENV): Set LD_LIBRARY_PATH. + * elf/Versions: Export __libc_dlvsym. + * elf/dl-libc.c (struct do_dlvsym_args): New. + (do_dlvsym, __libc_dlvsym): New functions. + (struct dl_open_hook, _dl_open_hook): Add dlvsym member. + (_dl_open_hook2): New variable. + (__libc_register_dl_open_hook): Set it. + * elf/tst-libc_dlvsym-dso.c: New file. + * elf/tst-libc_dlvsym-static.c: Likewise. + * elf/tst-libc_dlvsym.c: Likewise. + * elf/tst-libc_dlvsym.h: Likewise. + 2018-01-03 Samuel Thibault * support/support_enter_mount_namespace.c [!CLONE_NEWNS]: Do not diff --git a/elf/Makefile b/elf/Makefile index 8967ac2685..2a432d8bee 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -151,7 +151,7 @@ tests-static-normal := tst-leaks1-static tst-array1-static tst-array5-static \ tst-linkall-static tst-env-setuid tst-env-setuid-tunables tests-static-internal := tst-tls1-static tst-tls2-static \ tst-ptrguard1-static tst-stackguard1-static \ - tst-tls1-static-non-pie + tst-tls1-static-non-pie tst-libc_dlvsym-static CRT-tst-tls1-static-non-pie := $(csu-objpfx)crt1.o tst-tls1-static-non-pie-no-pie = yes @@ -192,7 +192,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ tests-internal += loadtest unload unload2 circleload1 \ neededtest neededtest2 neededtest3 neededtest4 \ tst-tls3 tst-tls6 tst-tls7 tst-tls8 tst-dlmopen2 \ - tst-ptrguard1 tst-stackguard1 + tst-ptrguard1 tst-stackguard1 tst-libc_dlvsym ifeq ($(build-hardcoded-path-in-tests),yes) tests += tst-dlopen-aout tst-dlopen-aout-no-pie = yes @@ -272,7 +272,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12 \ tst-latepthreadmod $(tst-tls-many-dynamic-modules) \ tst-nodelete-dlclose-dso tst-nodelete-dlclose-plugin \ - tst-main1mod + tst-main1mod tst-libc_dlvsym-dso ifeq (yes,$(have-mtls-dialect-gnu2)) tests += tst-gnu2-tls1 modules-names += tst-gnu2-tls1mod @@ -1436,3 +1436,13 @@ CRT-tst-main1 := $(csu-objpfx)crt1.o tst-main1-no-pie = yes LDLIBS-tst-main1 = $(libsupport) tst-main1mod.so-no-z-defs = yes + +# Both the main program and the DSO for tst-libc_dlvsym need to link +# against libdl. +$(objpfx)tst-libc_dlvsym: $(libdl) +$(objpfx)tst-libc_dlvsym-dso.so: $(libsupport) $(libdl) +$(objpfx)tst-libc_dlvsym.out: $(objpfx)tst-libc_dlvsym-dso.so +$(objpfx)tst-libc_dlvsym-static: $(common-objpfx)dlfcn/libdl.a +tst-libc_dlvsym-static-ENV = \ + LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)dlfcn +$(objpfx)tst-libc_dlvsym-static.out: $(objpfx)tst-libc_dlvsym-dso.so diff --git a/elf/Versions b/elf/Versions index 79ffaf73d2..3b09901f6c 100644 --- a/elf/Versions +++ b/elf/Versions @@ -23,9 +23,9 @@ libc { GLIBC_PRIVATE { # functions used in other libraries _dl_addr; - _dl_open_hook; + _dl_open_hook; _dl_open_hook2; _dl_sym; _dl_vsym; - __libc_dlclose; __libc_dlopen_mode; __libc_dlsym; + __libc_dlclose; __libc_dlopen_mode; __libc_dlsym; __libc_dlvsym; # Internal error handling support. Interposes the functions in ld.so. _dl_signal_exception; _dl_catch_exception; diff --git a/elf/dl-libc.c b/elf/dl-libc.c index c6818e0313..fc01f5514d 100644 --- a/elf/dl-libc.c +++ b/elf/dl-libc.c @@ -20,6 +20,7 @@ #include #include #include +#include extern int __libc_argc attribute_hidden; extern char **__libc_argv attribute_hidden; @@ -78,6 +79,15 @@ struct do_dlsym_args const ElfW(Sym) *ref; }; +struct do_dlvsym_args +{ + /* dlvsym is like dlsym. */ + struct do_dlsym_args dlsym; + + /* But dlvsym needs a version as well. */ + struct r_found_version version; +}; + static void do_dlopen (void *ptr) { @@ -98,6 +108,18 @@ do_dlsym (void *ptr) DL_LOOKUP_RETURN_NEWEST, NULL); } +static void +do_dlvsym (void *ptr) +{ + struct do_dlvsym_args *args = ptr; + args->dlsym.ref = NULL; + args->dlsym.loadbase + = GLRO(dl_lookup_symbol_x) (args->dlsym.name, args->dlsym.map, + &args->dlsym.ref, + args->dlsym.map->l_local_scope, + &args->version, 0, 0, NULL); +} + static void do_dlclose (void *ptr) { @@ -112,6 +134,7 @@ struct dl_open_hook void *(*dlopen_mode) (const char *name, int mode); void *(*dlsym) (void *map, const char *name); int (*dlclose) (void *map); + void *(*dlvsym) (void *map, const char *name, const char *version); }; #ifdef SHARED @@ -119,6 +142,15 @@ extern struct dl_open_hook *_dl_open_hook; libc_hidden_proto (_dl_open_hook); struct dl_open_hook *_dl_open_hook __attribute__ ((nocommon)); libc_hidden_data_def (_dl_open_hook); + +/* The dlvsym member was added retroactively to struct dl_open_hook. + Static applications which have it will set _dl_open_hook2 in + addition to _dl_open_hook. */ +extern struct dl_open_hook *_dl_open_hook2; +libc_hidden_proto (_dl_open_hook2); +struct dl_open_hook *_dl_open_hook2 __attribute__ ((nocommon)); +libc_hidden_data_def (_dl_open_hook2); + #else static void do_dlsym_private (void *ptr) @@ -142,7 +174,8 @@ static struct dl_open_hook _dl_open_hook = { .dlopen_mode = __libc_dlopen_mode, .dlsym = __libc_dlsym, - .dlclose = __libc_dlclose + .dlclose = __libc_dlclose, + .dlvsym = __libc_dlvsym, }; #endif @@ -192,6 +225,11 @@ __libc_register_dl_open_hook (struct link_map *map) hook = (struct dl_open_hook **) __libc_dlsym_private (map, "_dl_open_hook"); if (hook != NULL) *hook = &_dl_open_hook; + + /* For dlvsym support. */ + hook = (struct dl_open_hook **) __libc_dlsym_private (map, "_dl_open_hook2"); + if (hook != NULL) + *hook = &_dl_open_hook; } #endif @@ -211,6 +249,39 @@ __libc_dlsym (void *map, const char *name) } libc_hidden_def (__libc_dlsym) +/* Replacement for dlvsym. MAP must be a real map. This function + returns NULL without setting the dlerror value in case of static + dlopen from an old binary. */ +void * +__libc_dlvsym (void *map, const char *name, const char *version) +{ +#ifdef SHARED + if (!rtld_active ()) + { + /* The static application is too old and does not provide the + dlvsym hook. */ + if (_dl_open_hook2 == NULL) + return NULL; + return _dl_open_hook2->dlvsym (map, name, version); + } +#endif + + struct do_dlvsym_args args; + args.dlsym.map = map; + args.dlsym.name = name; + + /* See _dl_vsym in dl-sym.c. */ + args.version.name = version; + args.version.hidden = 1; + args.version.hash = _dl_elf_hash (version); + args.version.filename = NULL; + + return (dlerror_run (do_dlvsym, &args) ? NULL + : (void *) (DL_SYMBOL_ADDRESS (args.dlsym.loadbase, + args.dlsym.ref))); +} +libc_hidden_def (__libc_dlvsym) + int __libc_dlclose (void *map) { diff --git a/elf/tst-libc_dlvsym-dso.c b/elf/tst-libc_dlvsym-dso.c new file mode 100644 index 0000000000..d74c1ead61 --- /dev/null +++ b/elf/tst-libc_dlvsym-dso.c @@ -0,0 +1,25 @@ +/* Compare dlvsym and __libc_dlvsym results. Shared object code. + Copyright (C) 2017 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 + . */ + +#include "tst-libc_dlvsym.h" + +void +compare_vsyms_global (void) +{ + compare_vsyms (); +} diff --git a/elf/tst-libc_dlvsym-static.c b/elf/tst-libc_dlvsym-static.c new file mode 100644 index 0000000000..955f28d754 --- /dev/null +++ b/elf/tst-libc_dlvsym-static.c @@ -0,0 +1,32 @@ +/* Compare dlvsym and __libc_dlvsym results. Static version. + Copyright (C) 2017 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 + . */ + +#include + +static int +do_test (void) +{ + void *handle = xdlopen ("tst-libc_dlvsym-dso.so", RTLD_LAZY); + void (*compare) (void) = xdlsym (handle, "compare_vsyms_global"); + compare (); + xdlclose (handle); + + return 0; +} + +#include diff --git a/elf/tst-libc_dlvsym.c b/elf/tst-libc_dlvsym.c new file mode 100644 index 0000000000..864db4ee6a --- /dev/null +++ b/elf/tst-libc_dlvsym.c @@ -0,0 +1,34 @@ +/* Compare dlvsym and __libc_dlvsym results. Dynamic version. + Copyright (C) 2017 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 + . */ + +#include "tst-libc_dlvsym.h" + +static int +do_test (void) +{ + compare_vsyms (); + + void *handle = xdlopen ("tst-libc_dlvsym-dso.so", RTLD_LAZY); + void (*compare) (void) = xdlsym (handle, "compare_vsyms_global"); + compare (); + xdlclose (handle); + + return 0; +} + +#include diff --git a/elf/tst-libc_dlvsym.h b/elf/tst-libc_dlvsym.h new file mode 100644 index 0000000000..6b1d8d5b3a --- /dev/null +++ b/elf/tst-libc_dlvsym.h @@ -0,0 +1,125 @@ +/* Compare dlvsym and __libc_dlvsym results. Common code. + Copyright (C) 2017 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 + . */ + +/* compare_vsyms is the main entry point for these tests. + + Indirectly, It calls __libc_dlvsym (from libc.so; internal + interface) and dlvsym (from libdl.so; public interface) to compare + the results for a selected set of symbols in libc.so which + typically have more than one symbol version. The two functions are + implemented by somewhat different code, and this test checks that + their results are the same. + + The versions are generated to range from GLIBC_2.0 to GLIBC_2.Y, + with Y being the current __GLIBC_MINOR__ version plus two. In + addition, there is a list of special symbol versions of the form + GLIBC_2.Y.Z, which were used for some releases. + + Comparing the two dlvsym results at versions which do not actually + exist does not test much, but it will not contribute to false test + failures, either. */ + +#include +#include +#include +#include +#include +#include + +/* Run consistency check for versioned symbol NAME@VERSION. NB: We + may execute in a shared object, so exit on error for proper error + reporting. */ +static void +compare_vsyms_0 (void *libc_handle, const char *name, const char *version, + bool *pfound) +{ + void *dlvsym_address = dlvsym (libc_handle, name, version); + void *libc_dlvsym_address + = __libc_dlvsym (libc_handle, name, version); + if (dlvsym_address != libc_dlvsym_address) + FAIL_EXIT1 ("%s@%s mismatch: %p != %p", + name, version, dlvsym_address, libc_dlvsym_address); + if (dlvsym_address != NULL) + *pfound = true; +} + + +/* Run consistency check for versioned symbol NAME at multiple symbol + version. */ +static void +compare_vsyms_1 (void *libc_handle, const char *name) +{ + bool found = false; + + /* Historic versions which do not follow the usual GLIBC_2.Y + pattern, to increase test coverage. Not all architectures have + those, but probing additional versions does not hurt. */ + static const char special_versions[][12] = + { + "GLIBC_2.1.1", + "GLIBC_2.1.2", + "GLIBC_2.1.3", + "GLIBC_2.1.4", + "GLIBC_2.2.1", + "GLIBC_2.2.2", + "GLIBC_2.2.3", + "GLIBC_2.2.4", + "GLIBC_2.2.5", + "GLIBC_2.2.6", + "GLIBC_2.3.2", + "GLIBC_2.3.3", + "GLIBC_2.3.4", + }; + for (int i = 0; i < array_length (special_versions); ++i) + compare_vsyms_0 (libc_handle, name, special_versions[i], &found); + + /* Iterate to an out-of-range version, to cover some unused symbols + as well. */ + for (int minor_version = 0; minor_version <= __GLIBC_MINOR__ + 2; + ++minor_version) + { + char version[30]; + snprintf (version, sizeof (version), "GLIBC_%d.%d", + __GLIBC__, minor_version); + compare_vsyms_0 (libc_handle, name, version, &found); + } + + if (!found) + FAIL_EXIT1 ("symbol %s not found at any version", name); +} + +/* Run consistency checks for various symbols which usually have + multiple versions. */ +static void +compare_vsyms (void) +{ + /* The minor version loop in compare_vsyms_1 needs updating in case + we ever switch to glibc 3.0. */ + if (__GLIBC__ != 2) + FAIL_EXIT1 ("unexpected glibc major version: %d", __GLIBC__); + + /* __libc_dlvsym does not recognize the special RTLD_* handles, so + obtain an explicit handle for libc.so. */ + void *libc_handle = xdlopen (LIBC_SO, RTLD_LAZY | RTLD_NOLOAD); + + compare_vsyms_1 (libc_handle, "_sys_errlist"); + compare_vsyms_1 (libc_handle, "_sys_siglist"); + compare_vsyms_1 (libc_handle, "quick_exit"); + + xdlclose (libc_handle); +} diff --git a/include/dlfcn.h b/include/dlfcn.h index 526086f1a0..12ef913e19 100644 --- a/include/dlfcn.h +++ b/include/dlfcn.h @@ -35,9 +35,11 @@ extern char **__libc_argv attribute_hidden; __libc_dlopen_mode (name, RTLD_LAZY | __RTLD_DLOPEN) extern void *__libc_dlopen_mode (const char *__name, int __mode); extern void *__libc_dlsym (void *__map, const char *__name); +extern void *__libc_dlvsym (void *map, const char *name, const char *version); extern int __libc_dlclose (void *__map); libc_hidden_proto (__libc_dlopen_mode) libc_hidden_proto (__libc_dlsym) +libc_hidden_proto (__libc_dlvsym) libc_hidden_proto (__libc_dlclose) /* Locate shared object containing the given address. */ -- cgit v1.2.3