1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-30 22:43:12 +03:00
Files
glibc/sysdeps/i386/dl-tls-get-addr.c
H.J. Lu 848f0e46f0 i386: Update ___tls_get_addr to preserve vector registers
Compiler generates the following instruction sequence for dynamic TLS
access:

	leal	tls_var@tlsgd(,%ebx,1), %eax
	call	___tls_get_addr@PLT

CALL instruction is transparent to compiler which assumes all registers,
except for EFLAGS, AX, CX, and DX, are unchanged after CALL.  But
___tls_get_addr is a normal function which doesn't preserve any vector
registers.

1. Rename the generic __tls_get_addr function to ___tls_get_addr_internal.
2. Change ___tls_get_addr to a wrapper function with implementations for
FNSAVE, FXSAVE, XSAVE and XSAVEC to save and restore all vector registers.
3. dl-tlsdesc-dynamic.h has:

_dl_tlsdesc_dynamic:
	/* Like all TLS resolvers, preserve call-clobbered registers.
	   We need two scratch regs anyway.  */
	subl	$32, %esp
	cfi_adjust_cfa_offset (32)

It is wrong to use

	movl	%ebx, -28(%esp)
	movl	%esp, %ebx
	cfi_def_cfa_register(%ebx)
	...
	mov	%ebx, %esp
	cfi_def_cfa_register(%esp)
	movl	-28(%esp), %ebx

to preserve EBX on stack.  Fix it with:

	movl	%ebx, 28(%esp)
	movl	%esp, %ebx
	cfi_def_cfa_register(%ebx)
	...
	mov	%ebx, %esp
	cfi_def_cfa_register(%esp)
	movl	28(%esp), %ebx

4. Update _dl_tlsdesc_dynamic to call ___tls_get_addr_internal directly.
5. Add have-test-mtls-traditional to compile tst-tls23-mod.c with
traditional TLS variant to verify the fix.
6. Define DL_RUNTIME_RESOLVE_REALIGN_STACK in sysdeps/x86/sysdep.h.

This fixes BZ #32996.

Co-Authored-By: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2025-06-19 04:30:31 +08:00

69 lines
2.3 KiB
C

/* Ifunc selector for ___tls_get_addr.
Copyright (C) 2025 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/>. */
#ifdef SHARED
# define ___tls_get_addr __redirect____tls_get_addr
# include <dl-tls.h>
# undef ___tls_get_addr
# undef __tls_get_addr
# define SYMBOL_NAME ___tls_get_addr
# include <init-arch.h>
extern __typeof (REDIRECT_NAME) OPTIMIZE (fnsave) attribute_hidden;
extern __typeof (REDIRECT_NAME) OPTIMIZE (fxsave) attribute_hidden;
extern __typeof (REDIRECT_NAME) OPTIMIZE (xsave) attribute_hidden;
extern __typeof (REDIRECT_NAME) OPTIMIZE (xsavec) attribute_hidden;
static inline void *
IFUNC_SELECTOR (void)
{
const struct cpu_features* cpu_features = __get_cpu_features ();
if (cpu_features->xsave_state_size != 0)
{
if (CPU_FEATURE_USABLE_P (cpu_features, XSAVEC))
return OPTIMIZE (xsavec);
else
return OPTIMIZE (xsave);
}
else if (CPU_FEATURE_USABLE_P (cpu_features, FXSR))
return OPTIMIZE (fxsave);
return OPTIMIZE (fnsave);
}
libc_ifunc_redirected (__redirect____tls_get_addr, ___tls_get_addr,
IFUNC_SELECTOR ());
/* The special thing about the x86 TLS ABI is that we have two
variants of the __tls_get_addr function with different calling
conventions. The GNU version, which we are mostly concerned here,
takes the parameter in a register. The name is changed by adding
an additional underscore at the beginning. The Sun version uses
the normal calling convention. */
rtld_hidden_proto (___tls_get_addr)
rtld_hidden_def (___tls_get_addr)
void *
__tls_get_addr (tls_index *ti)
{
return ___tls_get_addr (ti);
}
#endif