mirror of
https://sourceware.org/git/glibc.git
synced 2024-12-05 03:01:05 +00:00
0c76fc3c2b
Register rseq TLS for each thread (including main), and unregister for
each thread (excluding main). "rseq" stands for Restartable Sequences.
See the rseq(2) man page proposed here:
https://lkml.org/lkml/2018/9/19/647
Those are based on glibc master branch commit 3ee1e0ec5c
.
The rseq system call was merged into Linux 4.18.
The TLS_STATIC_SURPLUS define is increased to leave additional room for
dlopen'd initial-exec TLS, which keeps elf/tst-auditmany working.
The increase (76 bytes) is larger than 32 bytes because it has not been
increased in quite a while. The cost in terms of additional TLS storage
is quite significant, but it will also obscure some initial-exec-related
dlopen failures.
204 lines
7.3 KiB
C
204 lines
7.3 KiB
C
/* Restartable Sequences exported symbols. Linux header.
|
|
Copyright (C) 2020 Free Software Foundation, Inc.
|
|
|
|
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/>. */
|
|
|
|
#ifndef _SYS_RSEQ_H
|
|
#define _SYS_RSEQ_H 1
|
|
|
|
/* Architecture-specific rseq signature. */
|
|
#include <bits/rseq.h>
|
|
|
|
#include <stdint.h>
|
|
#include <sys/cdefs.h>
|
|
|
|
#ifdef __has_include
|
|
# if __has_include ("linux/rseq.h")
|
|
# define __GLIBC_HAVE_KERNEL_RSEQ
|
|
# endif
|
|
#else
|
|
# include <linux/version.h>
|
|
# if LINUX_VERSION_CODE >= KERNEL_VERSION (4, 18, 0)
|
|
# define __GLIBC_HAVE_KERNEL_RSEQ
|
|
# endif
|
|
#endif
|
|
|
|
/* Rely on GNU extensions for older standards and tls model. */
|
|
#ifdef __GNUC__
|
|
# define __rseq_tls_model_ie __attribute__ ((__tls_model__ ("initial-exec")))
|
|
#else
|
|
/* Specifying the TLS model on the declaration is optional. */
|
|
# define __rseq_tls_model_ie /* Nothing. */
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
# if __cplusplus >= 201103L
|
|
# define __rseq_tls_storage_class thread_local
|
|
# endif
|
|
#elif (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) >= 201112L
|
|
# define __rseq_tls_storage_class _Thread_local
|
|
#endif
|
|
|
|
/* Fall back to __thread for TLS storage class. */
|
|
#ifndef __rseq_tls_storage_class
|
|
# define __rseq_tls_storage_class __thread
|
|
#endif
|
|
|
|
#ifdef __GLIBC_HAVE_KERNEL_RSEQ
|
|
/* We use the structures declarations from the kernel headers. */
|
|
# include <linux/rseq.h>
|
|
#else /* __GLIBC_HAVE_KERNEL_RSEQ */
|
|
/* We use a copy of the include/uapi/linux/rseq.h kernel header. */
|
|
|
|
# include <asm/byteorder.h>
|
|
|
|
enum rseq_cpu_id_state
|
|
{
|
|
RSEQ_CPU_ID_UNINITIALIZED = -1,
|
|
RSEQ_CPU_ID_REGISTRATION_FAILED = -2,
|
|
};
|
|
|
|
enum rseq_flags
|
|
{
|
|
RSEQ_FLAG_UNREGISTER = (1 << 0),
|
|
};
|
|
|
|
enum rseq_cs_flags_bit
|
|
{
|
|
RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT_BIT = 0,
|
|
RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL_BIT = 1,
|
|
RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT = 2,
|
|
};
|
|
|
|
enum rseq_cs_flags
|
|
{
|
|
RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT =
|
|
(1U << RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT_BIT),
|
|
RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL =
|
|
(1U << RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL_BIT),
|
|
RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE =
|
|
(1U << RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT),
|
|
};
|
|
|
|
/* struct rseq_cs is aligned on 32 bytes to ensure it is always
|
|
contained within a single cache-line. It is usually declared as
|
|
link-time constant data. */
|
|
struct rseq_cs
|
|
{
|
|
/* Version of this structure. */
|
|
uint32_t version;
|
|
/* enum rseq_cs_flags. */
|
|
uint32_t flags;
|
|
uint64_t start_ip;
|
|
/* Offset from start_ip. */
|
|
uint64_t post_commit_offset;
|
|
uint64_t abort_ip;
|
|
} __attribute__ ((__aligned__ (32)));
|
|
|
|
/* struct rseq is aligned on 32 bytes to ensure it is always
|
|
contained within a single cache-line.
|
|
|
|
A single struct rseq per thread is allowed. */
|
|
struct rseq
|
|
{
|
|
/* Restartable sequences cpu_id_start field. Updated by the
|
|
kernel. Read by user-space with single-copy atomicity
|
|
semantics. This field should only be read by the thread which
|
|
registered this data structure. Aligned on 32-bit. Always
|
|
contains a value in the range of possible CPUs, although the
|
|
value may not be the actual current CPU (e.g. if rseq is not
|
|
initialized). This CPU number value should always be compared
|
|
against the value of the cpu_id field before performing a rseq
|
|
commit or returning a value read from a data structure indexed
|
|
using the cpu_id_start value. */
|
|
uint32_t cpu_id_start;
|
|
/* Restartable sequences cpu_id field. Updated by the kernel.
|
|
Read by user-space with single-copy atomicity semantics. This
|
|
field should only be read by the thread which registered this
|
|
data structure. Aligned on 32-bit. Values
|
|
RSEQ_CPU_ID_UNINITIALIZED and RSEQ_CPU_ID_REGISTRATION_FAILED
|
|
have a special semantic: the former means "rseq uninitialized",
|
|
and latter means "rseq initialization failed". This value is
|
|
meant to be read within rseq critical sections and compared
|
|
with the cpu_id_start value previously read, before performing
|
|
the commit instruction, or read and compared with the
|
|
cpu_id_start value before returning a value loaded from a data
|
|
structure indexed using the cpu_id_start value. */
|
|
uint32_t cpu_id;
|
|
/* Restartable sequences rseq_cs field.
|
|
|
|
Contains NULL when no critical section is active for the current
|
|
thread, or holds a pointer to the currently active struct rseq_cs.
|
|
|
|
Updated by user-space, which sets the address of the currently
|
|
active rseq_cs at the beginning of assembly instruction sequence
|
|
block, and set to NULL by the kernel when it restarts an assembly
|
|
instruction sequence block, as well as when the kernel detects that
|
|
it is preempting or delivering a signal outside of the range
|
|
targeted by the rseq_cs. Also needs to be set to NULL by user-space
|
|
before reclaiming memory that contains the targeted struct rseq_cs.
|
|
|
|
Read and set by the kernel. Set by user-space with single-copy
|
|
atomicity semantics. This field should only be updated by the
|
|
thread which registered this data structure. Aligned on 64-bit. */
|
|
union
|
|
{
|
|
uint64_t ptr64;
|
|
# ifdef __LP64__
|
|
uint64_t ptr;
|
|
# else /* __LP64__ */
|
|
struct
|
|
{
|
|
# if (defined (__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN)) || defined (__BIG_ENDIAN)
|
|
uint32_t padding; /* Initialized to zero. */
|
|
uint32_t ptr32;
|
|
# else /* LITTLE */
|
|
uint32_t ptr32;
|
|
uint32_t padding; /* Initialized to zero. */
|
|
# endif /* ENDIAN */
|
|
} ptr;
|
|
# endif /* __LP64__ */
|
|
} rseq_cs;
|
|
|
|
/* Restartable sequences flags field.
|
|
|
|
This field should only be updated by the thread which
|
|
registered this data structure. Read by the kernel.
|
|
Mainly used for single-stepping through rseq critical sections
|
|
with debuggers.
|
|
|
|
- RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT
|
|
Inhibit instruction sequence block restart on preemption
|
|
for this thread.
|
|
- RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL
|
|
Inhibit instruction sequence block restart on signal
|
|
delivery for this thread.
|
|
- RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE
|
|
Inhibit instruction sequence block restart on migration for
|
|
this thread. */
|
|
uint32_t flags;
|
|
} __attribute__ ((__aligned__ (32)));
|
|
|
|
#endif /* __GLIBC_HAVE_KERNEL_RSEQ */
|
|
|
|
/* Allocations of struct rseq and struct rseq_cs on the heap need to
|
|
be aligned on 32 bytes. Therefore, use of malloc is discouraged
|
|
because it does not guarantee alignment. posix_memalign should be
|
|
used instead. */
|
|
|
|
extern __rseq_tls_storage_class struct rseq __rseq_abi __rseq_tls_model_ie;
|
|
|
|
#endif /* sys/rseq.h */
|