mirror of
git://sourceware.org/git/glibc.git
synced 2024-11-27 03:41:23 +08:00
nptl: fix potential merge of __rseq_* relro symbols
While working on a patch to add support for the extensible rseq ABI, we
came across an issue where a new 'const' variable would be merged with
the existing '__rseq_size' variable. We tracked this to the use of
'-fmerge-all-constants' which allows the compiler to merge identical
constant variables. This means that all 'const' variables in a compile
unit that are of the same size and are initialized to the same value can
be merged.
In this specific case, on 32 bit systems 'unsigned int' and 'ptrdiff_t'
are both 4 bytes and initialized to 0 which should trigger the merge.
However for reasons we haven't delved into when the attribute 'section
(".data.rel.ro")' is added to the mix, only variables of the same exact
types are merged. As far as we know this behavior is not specified
anywhere and could change with a new compiler version, hence this patch.
Move the definitions of these variables into an assembler file and add
hidden writable aliases for internal use. This has the added bonus of
removing the asm workaround to set the values on rseq registration.
Tested on Debian 12 with GCC 12.2.
Signed-off-by: Michael Jeanson <mjeanson@efficios.com>
Reviewed-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Reviewed-by: Florian Weimer <fweimer@redhat.com>
(cherry picked from commit 2b92982e23
)
This commit is contained in:
parent
712453634c
commit
7bfc35959d
@ -74,6 +74,7 @@ dl-routines = \
|
||||
dl-printf \
|
||||
dl-profile \
|
||||
dl-reloc \
|
||||
dl-rseq-symbols \
|
||||
dl-runtime \
|
||||
dl-scope \
|
||||
dl-setup_hash \
|
||||
|
64
elf/dl-rseq-symbols.S
Normal file
64
elf/dl-rseq-symbols.S
Normal file
@ -0,0 +1,64 @@
|
||||
/* Define symbols used by rseq.
|
||||
Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <sysdep.h>
|
||||
|
||||
#if __WORDSIZE == 64
|
||||
#define RSEQ_OFFSET_SIZE 8
|
||||
#else
|
||||
#define RSEQ_OFFSET_SIZE 4
|
||||
#endif
|
||||
|
||||
/* Some targets define a macro to denote the zero register. */
|
||||
#undef zero
|
||||
|
||||
/* Define 2 symbols: '__rseq_size' is public const and '_rseq_size' (an
|
||||
alias of '__rseq_size') is hidden and writable for internal use by the
|
||||
dynamic linker which will initialize the value both symbols point to
|
||||
before copy relocations take place. */
|
||||
|
||||
.globl __rseq_size
|
||||
.type __rseq_size, %object
|
||||
.size __rseq_size, 4
|
||||
.hidden _rseq_size
|
||||
.globl _rseq_size
|
||||
.type _rseq_size, %object
|
||||
.size _rseq_size, 4
|
||||
.section .data.rel.ro
|
||||
.balign 4
|
||||
__rseq_size:
|
||||
_rseq_size:
|
||||
.zero 4
|
||||
|
||||
/* Define 2 symbols: '__rseq_offset' is public const and '_rseq_offset' (an
|
||||
alias of '__rseq_offset') is hidden and writable for internal use by the
|
||||
dynamic linker which will initialize the value both symbols point to
|
||||
before copy relocations take place. */
|
||||
|
||||
.globl __rseq_offset
|
||||
.type __rseq_offset, %object
|
||||
.size __rseq_offset, RSEQ_OFFSET_SIZE
|
||||
.hidden _rseq_offset
|
||||
.globl _rseq_offset
|
||||
.type _rseq_offset, %object
|
||||
.size _rseq_offset, RSEQ_OFFSET_SIZE
|
||||
.section .data.rel.ro
|
||||
.balign RSEQ_OFFSET_SIZE
|
||||
__rseq_offset:
|
||||
_rseq_offset:
|
||||
.zero RSEQ_OFFSET_SIZE
|
@ -45,8 +45,10 @@ rtld_mutex_dummy (pthread_mutex_t *lock)
|
||||
#endif
|
||||
|
||||
const unsigned int __rseq_flags;
|
||||
const unsigned int __rseq_size attribute_relro;
|
||||
const ptrdiff_t __rseq_offset attribute_relro;
|
||||
|
||||
/* The variables are in .data.relro but are not yet write-protected. */
|
||||
extern unsigned int _rseq_size attribute_hidden;
|
||||
extern ptrdiff_t _rseq_offset attribute_hidden;
|
||||
|
||||
void
|
||||
__tls_pre_init_tp (void)
|
||||
@ -105,10 +107,7 @@ __tls_init_tp (void)
|
||||
do_rseq = TUNABLE_GET (rseq, int, NULL);
|
||||
if (rseq_register_current_thread (pd, do_rseq))
|
||||
{
|
||||
/* We need a writable view of the variables. They are in
|
||||
.data.relro and are not yet write-protected. */
|
||||
extern unsigned int size __asm__ ("__rseq_size");
|
||||
size = sizeof (pd->rseq_area);
|
||||
_rseq_size = sizeof (pd->rseq_area);
|
||||
}
|
||||
|
||||
#ifdef RSEQ_SIG
|
||||
@ -117,8 +116,7 @@ __tls_init_tp (void)
|
||||
all targets support __thread_pointer, so set __rseq_offset only
|
||||
if the rseq registration may have happened because RSEQ_SIG is
|
||||
defined. */
|
||||
extern ptrdiff_t offset __asm__ ("__rseq_offset");
|
||||
offset = (char *) &pd->rseq_area - (char *) __thread_pointer ();
|
||||
_rseq_offset = (char *) &pd->rseq_area - (char *) __thread_pointer ();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user