[libc-commits] [libc] 8c3bde8 - [libc][threads] Add architecture-specific Thread Control Block definitions (#220607)
via libc-commits
libc-commits at lists.llvm.org
Thu Sep 3 23:54:11 PDT 2026
Author: Pavel Labath
Date: 2026-09-04T08:54:06+02:00
New Revision: 8c3bde8c34e086f8e75e21f0293f507798f868d4
URL: https://github.com/llvm/llvm-project/commit/8c3bde8c34e086f8e75e21f0293f507798f868d4
DIFF: https://github.com/llvm/llvm-project/commit/8c3bde8c34e086f8e75e21f0293f507798f868d4.diff
LOG: [libc][threads] Add architecture-specific Thread Control Block definitions (#220607)
Add TCB structures and low-level thread-pointer accessor primitives for
Linux (x86_64, aarch64, riscv), and update init_tls code to use the
struct fields instead of manually computing raw pointer offsets.
I've set aside space for the ThreadAttributes pointer inside the
ABI-reserved slot for the thread library, but I'm not actually using
that value yet. I'll do that in the next patch, which will replace the
`thread_local self` object with this pointer.
Added:
libc/src/__support/threads/linux/aarch64/tcb.h
libc/src/__support/threads/linux/riscv/tcb.h
libc/src/__support/threads/linux/tcb.h
libc/src/__support/threads/linux/x86_64/tcb.h
libc/src/__support/threads/tcb.h
Modified:
libc/src/__support/threads/CMakeLists.txt
libc/src/__support/threads/linux/CMakeLists.txt
libc/startup/linux/aarch64/CMakeLists.txt
libc/startup/linux/aarch64/tls.cpp
libc/startup/linux/riscv/CMakeLists.txt
libc/startup/linux/riscv/tls.cpp
libc/startup/linux/x86_64/CMakeLists.txt
libc/startup/linux/x86_64/tls.cpp
Removed:
################################################################################
diff --git a/libc/src/__support/threads/CMakeLists.txt b/libc/src/__support/threads/CMakeLists.txt
index 67a176f87a9fd..1f14e3aab4768 100644
--- a/libc/src/__support/threads/CMakeLists.txt
+++ b/libc/src/__support/threads/CMakeLists.txt
@@ -36,6 +36,17 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
add_subdirectory(${LIBC_TARGET_OS})
endif()
+if(TARGET libc.src.__support.threads.${LIBC_TARGET_OS}.tcb)
+ add_header_library(
+ tcb
+ HDRS
+ tcb.h
+ DEPENDS
+ .${LIBC_TARGET_OS}.tcb
+ libc.src.__support.macros.properties.os
+ )
+endif()
+
if(TARGET libc.src.__support.threads.${LIBC_TARGET_OS}.futex_utils)
add_header_library(
futex_utils
diff --git a/libc/src/__support/threads/linux/CMakeLists.txt b/libc/src/__support/threads/linux/CMakeLists.txt
index 7d349f6d9bd00..51e9d4005ad0d 100644
--- a/libc/src/__support/threads/linux/CMakeLists.txt
+++ b/libc/src/__support/threads/linux/CMakeLists.txt
@@ -1,3 +1,19 @@
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE}/tcb.h)
+ add_header_library(
+ tcb
+ HDRS
+ tcb.h
+ ${LIBC_TARGET_ARCHITECTURE}/tcb.h
+ DEPENDS
+ libc.hdr.offsetof_macros
+ libc.hdr.stdint_proxy
+ libc.src.__support.threads.thread_attributes
+ libc.src.__support.macros.attributes
+ libc.src.__support.macros.config
+ libc.src.__support.macros.properties.architectures
+ )
+endif()
+
add_header_library(
futex_word_type
HDRS
diff --git a/libc/src/__support/threads/linux/aarch64/tcb.h b/libc/src/__support/threads/linux/aarch64/tcb.h
new file mode 100644
index 0000000000000..74bdf7ffc9bfe
--- /dev/null
+++ b/libc/src/__support/threads/linux/aarch64/tcb.h
@@ -0,0 +1,41 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Defines the Thread Control Block (TCB) for Linux AArch64.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_AARCH64_TCB_H
+#define LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_AARCH64_TCB_H
+
+#include "hdr/stdint_proxy.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/threads/thread_attributes.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+struct ThreadControlBlock {
+ uintptr_t dtv;
+ ThreadAttributes *attrib;
+};
+
+LIBC_INLINE ThreadControlBlock *get_tcb() {
+ ThreadControlBlock *tp;
+ asm("mrs %0, tpidr_el0" : "=r"(tp));
+ return tp;
+}
+
+LIBC_INLINE ThreadAttributes *get_current_thread_attrib() {
+ return get_tcb()->attrib;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_AARCH64_TCB_H
diff --git a/libc/src/__support/threads/linux/riscv/tcb.h b/libc/src/__support/threads/linux/riscv/tcb.h
new file mode 100644
index 0000000000000..a3d09e894c930
--- /dev/null
+++ b/libc/src/__support/threads/linux/riscv/tcb.h
@@ -0,0 +1,41 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Defines the Thread Control Block (TCB) for Linux RISC-V.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_RISCV_TCB_H
+#define LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_RISCV_TCB_H
+
+#include "hdr/stdint_proxy.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/threads/thread_attributes.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+struct ThreadControlBlock {
+ uintptr_t dtv;
+ ThreadAttributes *attrib;
+};
+
+LIBC_INLINE ThreadControlBlock *get_tcb() {
+ ThreadControlBlock *tp;
+ asm("mv %0, tp" : "=r"(tp));
+ return tp - 1;
+}
+
+LIBC_INLINE ThreadAttributes *get_current_thread_attrib() {
+ return get_tcb()->attrib;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_RISCV_TCB_H
diff --git a/libc/src/__support/threads/linux/tcb.h b/libc/src/__support/threads/linux/tcb.h
new file mode 100644
index 0000000000000..e9abd07423aec
--- /dev/null
+++ b/libc/src/__support/threads/linux/tcb.h
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Defines Linux architecture-level Thread Control Block dispatcher.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_TCB_H
+#define LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_TCB_H
+
+#include "src/__support/macros/properties/architectures.h"
+
+#if defined(LIBC_TARGET_ARCH_IS_X86_64)
+#include "src/__support/threads/linux/x86_64/tcb.h"
+#elif defined(LIBC_TARGET_ARCH_IS_AARCH64)
+#include "src/__support/threads/linux/aarch64/tcb.h"
+#elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV)
+#include "src/__support/threads/linux/riscv/tcb.h"
+#else
+#error "Unsupported architecture for Linux Thread Control Block"
+#endif
+
+#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_TCB_H
diff --git a/libc/src/__support/threads/linux/x86_64/tcb.h b/libc/src/__support/threads/linux/x86_64/tcb.h
new file mode 100644
index 0000000000000..c4ff19afb5fb5
--- /dev/null
+++ b/libc/src/__support/threads/linux/x86_64/tcb.h
@@ -0,0 +1,51 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Defines the Thread Control Block (TCB) for Linux x86_64.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_X86_64_TCB_H
+#define LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_X86_64_TCB_H
+
+#include "hdr/offsetof_macros.h"
+#include "hdr/stdint_proxy.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/threads/thread_attributes.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+struct ThreadControlBlock {
+ uintptr_t self;
+ uintptr_t dtv;
+ ThreadAttributes *attrib;
+ uintptr_t reserved[2];
+ uintptr_t stack_guard;
+};
+static_assert(offsetof(ThreadControlBlock, stack_guard) == 0x28,
+ "Offset defined by the ABI");
+
+LIBC_INLINE ThreadControlBlock *get_tcb() {
+ ThreadControlBlock *tcb;
+ asm("mov %%fs:0, %0" : "=r"(tcb));
+ return tcb;
+}
+
+LIBC_INLINE ThreadAttributes *get_current_thread_attrib() {
+ ThreadAttributes *attrib;
+ asm("mov %%fs:%c1, %0"
+ : "=r"(attrib)
+ : "i"(offsetof(ThreadControlBlock, attrib)));
+ return attrib;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_X86_64_TCB_H
diff --git a/libc/src/__support/threads/tcb.h b/libc/src/__support/threads/tcb.h
new file mode 100644
index 0000000000000..04af422c35df4
--- /dev/null
+++ b/libc/src/__support/threads/tcb.h
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Defines OS-level Thread Control Block dispatcher.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_TCB_H
+#define LLVM_LIBC_SRC___SUPPORT_THREADS_TCB_H
+
+#include "src/__support/macros/properties/os.h"
+
+#if defined(LIBC_TARGET_OS_IS_LINUX)
+#include "src/__support/threads/linux/tcb.h"
+#else
+#error "Unsupported OS for Thread Control Block"
+#endif
+
+#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_TCB_H
diff --git a/libc/startup/linux/aarch64/CMakeLists.txt b/libc/startup/linux/aarch64/CMakeLists.txt
index e733010a0a509..512ce24ba1658 100644
--- a/libc/startup/linux/aarch64/CMakeLists.txt
+++ b/libc/startup/linux/aarch64/CMakeLists.txt
@@ -9,6 +9,7 @@ add_startup_object(
libc.src.__support.OSUtil.linux.syscall_wrappers.mmap
libc.src.__support.OSUtil.linux.syscall_wrappers.munmap
libc.src.__support.OSUtil.osutil
+ libc.src.__support.threads.tcb
libc.src.string.memory_utils.inline_memcpy
COMPILE_OPTIONS
-fno-omit-frame-pointer
diff --git a/libc/startup/linux/aarch64/tls.cpp b/libc/startup/linux/aarch64/tls.cpp
index bc35b85bdec46..f16e833014ccb 100644
--- a/libc/startup/linux/aarch64/tls.cpp
+++ b/libc/startup/linux/aarch64/tls.cpp
@@ -12,7 +12,7 @@
#include "src/__support/OSUtil/linux/syscall_wrappers/munmap.h"
#include "src/__support/OSUtil/syscall.h"
#include "src/__support/macros/config.h"
-#include "src/__support/threads/thread.h"
+#include "src/__support/threads/tcb.h"
#include "src/string/memory_utils/inline_memcpy.h"
#include <arm_acle.h>
@@ -33,20 +33,20 @@ void init_tls(TLSDescriptor &tls_descriptor) {
// aarch64 follows the variant 1 TLS layout:
//
// 1. First entry is the dynamic thread vector pointer
- // 2. Second entry is a 8-byte reserved word.
+ // 2. Second entry is a 8-byte reserved word (used for attrib).
// 3. Padding for alignment.
// 4. The TLS data from the ELF image.
//
// The thread pointer points to the first entry.
- const uintptr_t size_of_pointers = 2 * sizeof(uintptr_t);
+ const uintptr_t TCB_SIZE = sizeof(ThreadControlBlock);
uintptr_t padding = 0;
const uintptr_t ALIGNMENT_MASK = app.tls.align - 1;
- uintptr_t
diff = size_of_pointers & ALIGNMENT_MASK;
+ uintptr_t
diff = TCB_SIZE & ALIGNMENT_MASK;
if (
diff != 0)
padding += (ALIGNMENT_MASK -
diff ) + 1;
- uintptr_t alloc_size = size_of_pointers + padding + app.tls.size;
+ uintptr_t alloc_size = TCB_SIZE + padding + app.tls.size;
ErrorOr<void *> mmap_ret =
linux_syscalls::mmap(nullptr, alloc_size, PROT_READ | PROT_WRITE,
@@ -54,7 +54,7 @@ void init_tls(TLSDescriptor &tls_descriptor) {
if (!mmap_ret.has_value())
syscall_impl<long>(SYS_exit, 1);
uintptr_t thread_ptr = uintptr_t(mmap_ret.value());
- uintptr_t tls_addr = thread_ptr + size_of_pointers + padding;
+ uintptr_t tls_addr = thread_ptr + TCB_SIZE + padding;
inline_memcpy(reinterpret_cast<char *>(tls_addr),
reinterpret_cast<const char *>(app.tls.address),
app.tls.init_size);
diff --git a/libc/startup/linux/riscv/CMakeLists.txt b/libc/startup/linux/riscv/CMakeLists.txt
index 28654aef44c7c..be09b7e620d04 100644
--- a/libc/startup/linux/riscv/CMakeLists.txt
+++ b/libc/startup/linux/riscv/CMakeLists.txt
@@ -9,6 +9,7 @@ add_startup_object(
libc.src.__support.OSUtil.linux.syscall_wrappers.mmap
libc.src.__support.OSUtil.linux.syscall_wrappers.munmap
libc.src.__support.OSUtil.osutil
+ libc.src.__support.threads.tcb
libc.src.string.memory_utils.inline_memcpy
COMPILE_OPTIONS
-fno-omit-frame-pointer
diff --git a/libc/startup/linux/riscv/tls.cpp b/libc/startup/linux/riscv/tls.cpp
index 87edca12c5b87..9e0721195499b 100644
--- a/libc/startup/linux/riscv/tls.cpp
+++ b/libc/startup/linux/riscv/tls.cpp
@@ -12,7 +12,7 @@
#include "src/__support/OSUtil/linux/syscall_wrappers/munmap.h"
#include "src/__support/OSUtil/syscall.h"
#include "src/__support/macros/config.h"
-#include "src/__support/threads/thread.h"
+#include "src/__support/threads/tcb.h"
#include "src/string/memory_utils/inline_memcpy.h"
#include <sys/syscall.h>
@@ -25,15 +25,15 @@ void init_tls(TLSDescriptor &tls_descriptor) {
return;
}
- // riscv64 follows the variant 1 TLS layout:
- const uintptr_t size_of_pointers = 2 * sizeof(uintptr_t);
+ // riscv follows the variant 1 TLS layout:
+ const uintptr_t TCB_SIZE = sizeof(ThreadControlBlock);
uintptr_t padding = 0;
const uintptr_t ALIGNMENT_MASK = app.tls.align - 1;
- uintptr_t
diff = size_of_pointers & ALIGNMENT_MASK;
+ uintptr_t
diff = TCB_SIZE & ALIGNMENT_MASK;
if (
diff != 0)
padding += (ALIGNMENT_MASK -
diff ) + 1;
- uintptr_t alloc_size = size_of_pointers + padding + app.tls.size;
+ uintptr_t alloc_size = TCB_SIZE + padding + app.tls.size;
ErrorOr<void *> mmap_ret =
linux_syscalls::mmap(nullptr, alloc_size, PROT_READ | PROT_WRITE,
@@ -41,7 +41,7 @@ void init_tls(TLSDescriptor &tls_descriptor) {
if (!mmap_ret.has_value())
syscall_impl<long>(SYS_exit, 1);
uintptr_t thread_ptr = uintptr_t(mmap_ret.value());
- uintptr_t tls_addr = thread_ptr + size_of_pointers + padding;
+ uintptr_t tls_addr = thread_ptr + TCB_SIZE + padding;
inline_memcpy(reinterpret_cast<char *>(tls_addr),
reinterpret_cast<const char *>(app.tls.address),
app.tls.init_size);
diff --git a/libc/startup/linux/x86_64/CMakeLists.txt b/libc/startup/linux/x86_64/CMakeLists.txt
index d458d9ac89316..a0938d403411e 100644
--- a/libc/startup/linux/x86_64/CMakeLists.txt
+++ b/libc/startup/linux/x86_64/CMakeLists.txt
@@ -10,6 +10,7 @@ add_startup_object(
libc.src.__support.OSUtil.linux.syscall_wrappers.getrandom
libc.src.__support.OSUtil.linux.syscall_wrappers.mmap
libc.src.__support.OSUtil.linux.syscall_wrappers.munmap
+ libc.src.__support.threads.tcb
libc.src.string.memory_utils.inline_memcpy
COMPILE_OPTIONS
-fno-stack-protector
diff --git a/libc/startup/linux/x86_64/tls.cpp b/libc/startup/linux/x86_64/tls.cpp
index 13f6491295fe8..5810955c5d24d 100644
--- a/libc/startup/linux/x86_64/tls.cpp
+++ b/libc/startup/linux/x86_64/tls.cpp
@@ -12,6 +12,7 @@
#include "src/__support/OSUtil/linux/syscall_wrappers/mmap.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/munmap.h"
#include "src/__support/macros/config.h"
+#include "src/__support/threads/tcb.h"
#include "src/string/memory_utils/inline_memcpy.h"
#include <asm/prctl.h>
@@ -32,15 +33,10 @@ void init_tls(TLSDescriptor &tls_descriptor) {
if (tls_size != app.tls.size)
tls_size += app.tls.align;
- // Per the x86_64 TLS ABI, the entry pointed to by the thread pointer is the
- // address of the TLS block. So, we add more size to accomodate this address
- // entry.
- // We also need to include space for the stack canary. The canary is at
- // offset 0x28 (40) and is of size uintptr_t.
- uintptr_t tls_size_with_addr = tls_size + sizeof(uintptr_t) + 40;
+ uintptr_t tls_size_with_tcb = tls_size + sizeof(ThreadControlBlock);
ErrorOr<void *> mmap_ret =
- linux_syscalls::mmap(nullptr, tls_size_with_addr, PROT_READ | PROT_WRITE,
+ linux_syscalls::mmap(nullptr, tls_size_with_tcb, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (!mmap_ret.has_value())
syscall_impl<long>(SYS_exit, 1);
@@ -49,23 +45,23 @@ void init_tls(TLSDescriptor &tls_descriptor) {
// x86_64 TLS faces down from the thread pointer with the first entry
// pointing to the address of the first real TLS byte.
uintptr_t end_ptr = reinterpret_cast<uintptr_t>(tls_addr) + tls_size;
- *reinterpret_cast<uintptr_t *>(end_ptr) = end_ptr;
+ auto *tcb = reinterpret_cast<ThreadControlBlock *>(end_ptr);
+ tcb->self = end_ptr;
inline_memcpy(reinterpret_cast<char *>(tls_addr),
reinterpret_cast<const char *>(app.tls.address),
app.tls.init_size);
- uintptr_t *stack_guard_addr = reinterpret_cast<uintptr_t *>(end_ptr + 40);
// Setting the stack guard to a random value.
// We cannot call the get_random function here as the function sets errno on
// failure. Since errno is implemented via a thread local variable, we cannot
// use errno before TLS is setup. The linux_syscalls wrapper is safe as it
// reports errors via ErrorOr instead of errno.
ErrorOr<ssize_t> stack_guard_retval =
- linux_syscalls::getrandom(stack_guard_addr, sizeof(uint64_t), 0);
+ linux_syscalls::getrandom(&tcb->stack_guard, sizeof(tcb->stack_guard), 0);
if (!stack_guard_retval.has_value())
syscall_impl(SYS_exit, 1);
- tls_descriptor = {tls_size_with_addr, reinterpret_cast<uintptr_t>(tls_addr),
+ tls_descriptor = {tls_size_with_tcb, reinterpret_cast<uintptr_t>(tls_addr),
end_ptr};
return;
}
More information about the libc-commits
mailing list