[libc-commits] [libc] 4057f8e - [libc] Move Linux TLS routines from crt1.o into libc.a (#225418)

via libc-commits libc-commits at lists.llvm.org
Tue Sep 22 22:46:45 PDT 2026


Author: Jeff Bailey
Date: 2026-09-23T06:46:39+01:00
New Revision: 4057f8e45b7fcadf99b60763c873802f8add8770

URL: https://github.com/llvm/llvm-project/commit/4057f8e45b7fcadf99b60763c873802f8add8770
DIFF: https://github.com/llvm/llvm-project/commit/4057f8e45b7fcadf99b60763c873802f8add8770.diff

LOG: [libc] Move Linux TLS routines from crt1.o into libc.a (#225418)

init_tls, cleanup_tls, and set_thread_ptr are per-thread routines used
by both Thread::run in libc.a and main-thread startup in crt1.o, but
tls.cpp was previously only merged into crt1.o. Linking libc.a without
crt1.o (such as a self-contained shared library statically linking
libc.a, or an executable built with -nostartfiles) failed with undefined
hidden symbols when thread.cpp.o was pulled in.

Move {x86_64,aarch64,riscv}/tls.cpp from libc/startup/linux/ to
libc/src/__support/threads/linux/ alongside tcb.h (matching prior
migrations of auxv and program_invocation_name from startup into src so
dependencies flow from startup -> src). Expose them via a forwarding
ALIAS target libc.src.__support.threads.linux.tls depended on by both
thread and do_start, and remove tls from merge_relocatable_object(crt1).

Mark init_tls with [[gnu::flatten]] and compile tls with
${libc_opt_high_flag}. Once tls.cpp.o is in libc.a rather than first on
the link line inside crt1.o, an earlier object compiled with
-fstack-protector-strong can otherwise win COMDAT selection for
LIBC_INLINE helpers (e.g. linux_syscalls::getrandom) in -O0 builds and
read %fs:0x28 before set_thread_ptr initializes the thread pointer.

Change AppProperties app in libc/config/linux/app.h from extern
[[gnu::weak]] (which resolved to NULL without crt1.o) to
LIBC_INLINE_VAR, providing a COMDAT-deduplicated .bss definition shared
by crt1.o and libc.a, matching auxv::value.

Assisted-by: Automated tooling, human reviewed.

Added: 
    libc/src/__support/threads/linux/aarch64/CMakeLists.txt
    libc/src/__support/threads/linux/aarch64/tls.cpp
    libc/src/__support/threads/linux/riscv/CMakeLists.txt
    libc/src/__support/threads/linux/riscv/tls.cpp
    libc/src/__support/threads/linux/x86_64/CMakeLists.txt
    libc/src/__support/threads/linux/x86_64/tls.cpp

Modified: 
    libc/config/linux/app.h
    libc/src/__support/threads/linux/CMakeLists.txt
    libc/startup/linux/CMakeLists.txt
    libc/startup/linux/aarch64/CMakeLists.txt
    libc/startup/linux/do_start.cpp
    libc/startup/linux/riscv/CMakeLists.txt
    libc/startup/linux/x86_64/CMakeLists.txt

Removed: 
    libc/startup/linux/aarch64/tls.cpp
    libc/startup/linux/riscv/tls.cpp
    libc/startup/linux/x86_64/tls.cpp


################################################################################
diff  --git a/libc/config/linux/app.h b/libc/config/linux/app.h
index ff4070eead0ca4..35d14f24df4617 100644
--- a/libc/config/linux/app.h
+++ b/libc/config/linux/app.h
@@ -10,6 +10,7 @@
 #define LLVM_LIBC_CONFIG_LINUX_APP_H
 
 #include "hdr/stdint_proxy.h"
+#include "src/__support/macros/attributes.h"
 #include "src/__support/macros/config.h"
 #include "src/__support/macros/properties/architectures.h"
 
@@ -61,7 +62,7 @@ struct AppProperties {
   uintptr_t *env_ptr;
 };
 
-[[gnu::weak]] extern AppProperties app;
+LIBC_INLINE_VAR AppProperties app;
 
 // The descriptor of a thread's TLS area.
 struct TLSDescriptor {

diff  --git a/libc/src/__support/threads/linux/CMakeLists.txt b/libc/src/__support/threads/linux/CMakeLists.txt
index ae449c1af799d7..fe9cb41b12877f 100644
--- a/libc/src/__support/threads/linux/CMakeLists.txt
+++ b/libc/src/__support/threads/linux/CMakeLists.txt
@@ -40,12 +40,27 @@ add_header_library(
     libc.src.__support.time.abs_timeout
 )
 
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
+  add_subdirectory(${LIBC_TARGET_ARCHITECTURE})
+endif()
+
+if(TARGET libc.src.__support.threads.linux.${LIBC_TARGET_ARCHITECTURE}.tls)
+  add_object_library(
+    tls
+    ALIAS
+    DEPENDS
+      .${LIBC_TARGET_ARCHITECTURE}.tls
+  )
+  set(thread_tls_dep .tls)
+endif()
+
 add_object_library(
   thread
   SRCS
     thread.cpp
   DEPENDS
     .futex_utils
+    ${thread_tls_dep}
     libc.config.app_h
     libc.include.sys_syscall
     libc.hdr.fcntl_macros

diff  --git a/libc/src/__support/threads/linux/aarch64/CMakeLists.txt b/libc/src/__support/threads/linux/aarch64/CMakeLists.txt
new file mode 100644
index 00000000000000..b83ccbb1ee05fb
--- /dev/null
+++ b/libc/src/__support/threads/linux/aarch64/CMakeLists.txt
@@ -0,0 +1,20 @@
+add_object_library(
+  tls
+  SRCS
+    tls.cpp
+  DEPENDS
+    libc.config.app_h
+    libc.hdr.sys_mman_macros
+    libc.include.sys_syscall
+    libc.src.__support.OSUtil.osutil
+    libc.src.__support.OSUtil.linux.syscall_wrappers.mmap
+    libc.src.__support.OSUtil.linux.syscall_wrappers.munmap
+    libc.src.__support.threads.linux.tcb
+    libc.src.string.memory_utils.inline_memcpy
+  COMPILE_OPTIONS
+    ${libc_opt_high_flag}
+    -fno-stack-protector
+    -fno-omit-frame-pointer
+    -ffreestanding
+    -fno-builtin
+)

diff  --git a/libc/startup/linux/aarch64/tls.cpp b/libc/src/__support/threads/linux/aarch64/tls.cpp
similarity index 96%
rename from libc/startup/linux/aarch64/tls.cpp
rename to libc/src/__support/threads/linux/aarch64/tls.cpp
index c7a4364ea2e2f3..fef46c109fa338 100644
--- a/libc/startup/linux/aarch64/tls.cpp
+++ b/libc/src/__support/threads/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/tcb.h"
+#include "src/__support/threads/linux/tcb.h"
 #include "src/string/memory_utils/inline_memcpy.h"
 
 #include <arm_acle.h>
@@ -23,7 +23,7 @@
 
 namespace LIBC_NAMESPACE_DECL {
 
-void init_tls(TLSDescriptor &tls_descriptor) {
+[[gnu::flatten]] void init_tls(TLSDescriptor &tls_descriptor) {
   // aarch64 follows the variant 1 TLS layout:
   //
   // 1. First entry is the dynamic thread vector pointer

diff  --git a/libc/src/__support/threads/linux/riscv/CMakeLists.txt b/libc/src/__support/threads/linux/riscv/CMakeLists.txt
new file mode 100644
index 00000000000000..b83ccbb1ee05fb
--- /dev/null
+++ b/libc/src/__support/threads/linux/riscv/CMakeLists.txt
@@ -0,0 +1,20 @@
+add_object_library(
+  tls
+  SRCS
+    tls.cpp
+  DEPENDS
+    libc.config.app_h
+    libc.hdr.sys_mman_macros
+    libc.include.sys_syscall
+    libc.src.__support.OSUtil.osutil
+    libc.src.__support.OSUtil.linux.syscall_wrappers.mmap
+    libc.src.__support.OSUtil.linux.syscall_wrappers.munmap
+    libc.src.__support.threads.linux.tcb
+    libc.src.string.memory_utils.inline_memcpy
+  COMPILE_OPTIONS
+    ${libc_opt_high_flag}
+    -fno-stack-protector
+    -fno-omit-frame-pointer
+    -ffreestanding
+    -fno-builtin
+)

diff  --git a/libc/startup/linux/riscv/tls.cpp b/libc/src/__support/threads/linux/riscv/tls.cpp
similarity index 94%
rename from libc/startup/linux/riscv/tls.cpp
rename to libc/src/__support/threads/linux/riscv/tls.cpp
index f6d60ee3e6d27f..5bd338dbd991da 100644
--- a/libc/startup/linux/riscv/tls.cpp
+++ b/libc/src/__support/threads/linux/riscv/tls.cpp
@@ -12,13 +12,13 @@
 #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/tcb.h"
+#include "src/__support/threads/linux/tcb.h"
 #include "src/string/memory_utils/inline_memcpy.h"
 #include <sys/syscall.h>
 
 namespace LIBC_NAMESPACE_DECL {
 
-void init_tls(TLSDescriptor &tls_descriptor) {
+[[gnu::flatten]] void init_tls(TLSDescriptor &tls_descriptor) {
   // riscv follows the variant 1 TLS layout:
   const uintptr_t TCB_SIZE = sizeof(ThreadControlBlock);
   uintptr_t padding = 0;

diff  --git a/libc/src/__support/threads/linux/x86_64/CMakeLists.txt b/libc/src/__support/threads/linux/x86_64/CMakeLists.txt
new file mode 100644
index 00000000000000..e827fb2d7e9c07
--- /dev/null
+++ b/libc/src/__support/threads/linux/x86_64/CMakeLists.txt
@@ -0,0 +1,21 @@
+add_object_library(
+  tls
+  SRCS
+    tls.cpp
+  DEPENDS
+    libc.config.app_h
+    libc.hdr.sys_mman_macros
+    libc.include.sys_syscall
+    libc.src.__support.OSUtil.osutil
+    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.linux.tcb
+    libc.src.string.memory_utils.inline_memcpy
+  COMPILE_OPTIONS
+    ${libc_opt_high_flag}
+    -fno-stack-protector
+    -fno-omit-frame-pointer
+    -ffreestanding
+    -fno-builtin
+)

diff  --git a/libc/startup/linux/x86_64/tls.cpp b/libc/src/__support/threads/linux/x86_64/tls.cpp
similarity index 96%
rename from libc/startup/linux/x86_64/tls.cpp
rename to libc/src/__support/threads/linux/x86_64/tls.cpp
index f7436f60e065e8..82462e3975ae08 100644
--- a/libc/startup/linux/x86_64/tls.cpp
+++ b/libc/src/__support/threads/linux/x86_64/tls.cpp
@@ -12,7 +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/__support/threads/linux/tcb.h"
 #include "src/string/memory_utils/inline_memcpy.h"
 
 #include <asm/prctl.h>
@@ -21,7 +21,7 @@
 namespace LIBC_NAMESPACE_DECL {
 
 // TODO: Also generalize this routine and handle dynamic loading properly.
-void init_tls(TLSDescriptor &tls_descriptor) {
+[[gnu::flatten]] void init_tls(TLSDescriptor &tls_descriptor) {
   // We will assume the alignment is always a power of two.
   uintptr_t tls_size = app.tls.size & -app.tls.align;
   if (tls_size != app.tls.size)

diff  --git a/libc/startup/linux/CMakeLists.txt b/libc/startup/linux/CMakeLists.txt
index e798b00e8819ae..04647dc4c612ca 100644
--- a/libc/startup/linux/CMakeLists.txt
+++ b/libc/startup/linux/CMakeLists.txt
@@ -124,6 +124,7 @@ add_object_library(
     libc.src.__support.threads.tcb
     libc.src.__support.threads.thread
     libc.src.__support.threads.linux.futex_utils
+    libc.src.__support.threads.linux.tls
     libc.src.__support.macros.config
     libc.startup.linux.${LIBC_TARGET_ARCHITECTURE}.irelative
     libc.src.link._r_debug
@@ -142,7 +143,6 @@ add_object_library(
 merge_relocatable_object(
   crt1
   .${LIBC_TARGET_ARCHITECTURE}.start
-  .${LIBC_TARGET_ARCHITECTURE}.tls
   .${LIBC_TARGET_ARCHITECTURE}.irelative
   .do_start
   .gnu_property_section

diff  --git a/libc/startup/linux/aarch64/CMakeLists.txt b/libc/startup/linux/aarch64/CMakeLists.txt
index 512ce24ba16587..a50d6d55e47d2d 100644
--- a/libc/startup/linux/aarch64/CMakeLists.txt
+++ b/libc/startup/linux/aarch64/CMakeLists.txt
@@ -1,21 +1,3 @@
-add_startup_object(
-  tls
-  SRC
-  tls.cpp
-  DEPENDS
-    libc.config.app_h
-    libc.hdr.sys_mman_macros
-    libc.include.sys_syscall
-    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
-    -ffreestanding # To avoid compiler warnings about calling the main function.
-)
-
 add_startup_object(
   start
   SRC

diff  --git a/libc/startup/linux/do_start.cpp b/libc/startup/linux/do_start.cpp
index b38929b66996f4..54b5dbebaafd42 100644
--- a/libc/startup/linux/do_start.cpp
+++ b/libc/startup/linux/do_start.cpp
@@ -55,7 +55,6 @@ void _r_debug_state() { // NOLINT
 }
 
 namespace LIBC_NAMESPACE_DECL {
-AppProperties app;
 
 static struct link_map main_map;
 

diff  --git a/libc/startup/linux/riscv/CMakeLists.txt b/libc/startup/linux/riscv/CMakeLists.txt
index be09b7e620d042..bca19fb374d241 100644
--- a/libc/startup/linux/riscv/CMakeLists.txt
+++ b/libc/startup/linux/riscv/CMakeLists.txt
@@ -1,21 +1,3 @@
-add_startup_object(
-  tls
-  SRC
-  tls.cpp
-  DEPENDS
-    libc.config.app_h
-    libc.hdr.sys_mman_macros
-    libc.include.sys_syscall
-    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
-    -ffreestanding # To avoid compiler warnings about calling the main function.
-)
-
 add_startup_object(
   start
   SRC

diff  --git a/libc/startup/linux/x86_64/CMakeLists.txt b/libc/startup/linux/x86_64/CMakeLists.txt
index a0938d403411e5..ac0a95f8f2d1d2 100644
--- a/libc/startup/linux/x86_64/CMakeLists.txt
+++ b/libc/startup/linux/x86_64/CMakeLists.txt
@@ -1,24 +1,3 @@
-add_startup_object(
-  tls
-  SRC
-  tls.cpp
-  DEPENDS
-    libc.config.app_h
-    libc.hdr.sys_mman_macros
-    libc.include.sys_syscall
-    libc.src.__support.OSUtil.osutil
-    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
-    -fno-omit-frame-pointer
-    -ffreestanding
-    -fno-builtin
-)
-
 add_startup_object(
   start
   SRC


        


More information about the libc-commits mailing list