[libc-commits] [libc] [libcxx] [llvm] libcxx build test (PR #193840)
Schrodinger ZHU Yifan via libc-commits
libc-commits at lists.llvm.org
Fri Apr 24 08:51:12 PDT 2026
https://github.com/SchrodingerZhu updated https://github.com/llvm/llvm-project/pull/193840
>From c98e83145a800ddb2fa3c3fef2dac6f6edb6727f Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Fri, 24 Apr 2026 11:19:24 -0400
Subject: [PATCH 01/16] [libc] implement recursive mutex and fix wrong
initializer
---
.../include/llvm-libc-macros/pthread-macros.h | 14 +--
libc/include/llvm-libc-types/CMakeLists.txt | 2 +-
libc/include/llvm-libc-types/__mutex_type.h | 17 ++--
libc/src/__support/threads/CMakeLists.txt | 2 +
libc/src/__support/threads/fork_callbacks.cpp | 4 +-
libc/src/__support/threads/linux/barrier.cpp | 7 +-
libc/src/__support/threads/mutex_common.h | 1 +
libc/src/__support/threads/thread.cpp | 8 +-
libc/src/__support/threads/unix_mutex.h | 96 ++++++++++++-------
libc/src/pthread/pthread_mutex_init.cpp | 38 ++++++--
libc/src/stdlib/atexit.cpp | 3 +-
libc/src/threads/mtx_init.cpp | 14 +--
.../integration/src/pthread/CMakeLists.txt | 3 +
.../src/pthread/pthread_mutex_test.cpp | 76 ++++++++++++++-
.../test/integration/src/threads/mtx_test.cpp | 25 +++++
15 files changed, 233 insertions(+), 77 deletions(-)
diff --git a/libc/include/llvm-libc-macros/pthread-macros.h b/libc/include/llvm-libc-macros/pthread-macros.h
index 58019403bb333..5fb8857ef37ab 100644
--- a/libc/include/llvm-libc-macros/pthread-macros.h
+++ b/libc/include/llvm-libc-macros/pthread-macros.h
@@ -32,16 +32,18 @@
#ifdef __linux__
#define PTHREAD_MUTEX_INITIALIZER \
{ \
- /* .__timed = */ 0, /* .__recursive = */ 0, \
- /* .__robust = */ 0, /* .__owner = */ NULL, \
- /* .__lock_count = */ 0, /* .__futex_word = */ {0}, \
+ /* .__ftxw = */ {0}, /* .__priority_inherit = */ 0, \
+ /* .__recursive = */ 0, /* .__robust = */ 0, \
+ /* .__pshared = */ 0, /* .__owner = */ 0, \
+ /* .__lock_count = */ 0, \
}
#else
#define PTHREAD_MUTEX_INITIALIZER \
{ \
- /* .__timed = */ 0, /* .__recursive = */ 0, \
- /* .__robust = */ 0, /* .__owner = */ NULL, \
- /* .__lock_count = */ 0, \
+ /* .__ftxw = */ {0}, /* .__priority_inherit = */ 0, \
+ /* .__recursive = */ 0, /* .__robust = */ 0, \
+ /* .__pshared = */ 0, /* .__owner = */ 0, \
+ /* .__lock_count = */ 0, \
}
#endif
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index 4cd889e4789a2..8eb9b540f6f3c 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -17,7 +17,7 @@ add_header(__exec_argv_t HDR __exec_argv_t.h)
add_header(__exec_envp_t HDR __exec_envp_t.h)
add_header(__futex_word HDR __futex_word.h)
add_header(pid_t HDR pid_t.h)
-add_header(__mutex_type HDR __mutex_type.h DEPENDS .__futex_word .pid_t)
+add_header(__mutex_type HDR __mutex_type.h DEPENDS .__futex_word .pid_t .size_t)
add_header(__barrier_type HDR __barrier_type.h)
add_header(__pthread_once_func_t HDR __pthread_once_func_t.h)
add_header(__pthread_start_t HDR __pthread_start_t.h)
diff --git a/libc/include/llvm-libc-types/__mutex_type.h b/libc/include/llvm-libc-types/__mutex_type.h
index 8355616261495..455eceb3c3955 100644
--- a/libc/include/llvm-libc-types/__mutex_type.h
+++ b/libc/include/llvm-libc-types/__mutex_type.h
@@ -10,20 +10,23 @@
#define LLVM_LIBC_TYPES___MUTEX_TYPE_H
#include "__futex_word.h"
+#include "pid_t.h"
+#include "size_t.h"
typedef struct {
- unsigned char __timed;
- unsigned char __recursive;
- unsigned char __robust;
-
- void *__owner;
- unsigned long long __lock_count;
-
#ifdef __linux__
__futex_word __ftxw;
#else
#error "Mutex type not defined for the target platform."
#endif
+
+ unsigned int __priority_inherit : 1;
+ unsigned int __recursive : 1;
+ unsigned int __robust : 1;
+ unsigned int __pshared : 1;
+
+ pid_t __owner;
+ size_t __lock_count;
} __mutex_type;
#endif // LLVM_LIBC_TYPES___MUTEX_TYPE_H
diff --git a/libc/src/__support/threads/CMakeLists.txt b/libc/src/__support/threads/CMakeLists.txt
index b603a2cfbb0e1..0846a78bbf904 100644
--- a/libc/src/__support/threads/CMakeLists.txt
+++ b/libc/src/__support/threads/CMakeLists.txt
@@ -75,6 +75,7 @@ if(TARGET libc.src.__support.threads.${LIBC_TARGET_OS}.futex_utils)
unix_mutex.h
DEPENDS
.raw_mutex
+ libc.src.__support.CPP.atomic
)
add_header_library(
@@ -162,6 +163,7 @@ if(TARGET libc.src.__support.threads.futex_utils)
libc.src.__support.threads.sleep
libc.src.__support.time.monotonicity
libc.src.__support.time.abs_timeout
+ libc.src.__support.threads.identifier
)
endif()
diff --git a/libc/src/__support/threads/fork_callbacks.cpp b/libc/src/__support/threads/fork_callbacks.cpp
index 49fb41a975826..b8e6b2b1ba10a 100644
--- a/libc/src/__support/threads/fork_callbacks.cpp
+++ b/libc/src/__support/threads/fork_callbacks.cpp
@@ -34,8 +34,8 @@ class AtForkCallbackManager {
public:
constexpr AtForkCallbackManager()
- : mtx(/*timed=*/false, /*recursive=*/false, /*robust=*/false,
- /*pshared=*/false),
+ : mtx(/*is_priority_inherit=*/false, /*is_recursive=*/false,
+ /*is_robust=*/false, /*is_pshared=*/false),
next_index(0) {}
bool register_triple(const ForkCallbackTriple &triple) {
diff --git a/libc/src/__support/threads/linux/barrier.cpp b/libc/src/__support/threads/linux/barrier.cpp
index 80f25f8ac7a21..882f6fa61887a 100644
--- a/libc/src/__support/threads/linux/barrier.cpp
+++ b/libc/src/__support/threads/linux/barrier.cpp
@@ -28,10 +28,9 @@ int Barrier::init(Barrier *b,
new (&b->entering) CndVar(attr ? attr->pshared : false);
new (&b->exiting) CndVar(attr ? attr->pshared : false);
- auto mutex_err = Mutex::init(&b->m, false, false, false,
- /*pshared=*/attr ? attr->pshared : false);
- if (mutex_err != MutexError::NONE)
- return EAGAIN;
+ new (&b->m) Mutex(/*is_priority_inherit=*/false, /*is_recursive=*/false,
+ /*is_robust=*/false,
+ /*is_pshared=*/attr ? attr->pshared : false);
return 0;
}
diff --git a/libc/src/__support/threads/mutex_common.h b/libc/src/__support/threads/mutex_common.h
index 9913f69a6a61a..1c71c5c78bc24 100644
--- a/libc/src/__support/threads/mutex_common.h
+++ b/libc/src/__support/threads/mutex_common.h
@@ -19,6 +19,7 @@ enum class MutexError : int {
TIMEOUT,
UNLOCK_WITHOUT_LOCK,
BAD_LOCK_STATE,
+ OVERFLOW,
};
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/__support/threads/thread.cpp b/libc/src/__support/threads/thread.cpp
index 9618d7829161a..ae179f068b88e 100644
--- a/libc/src/__support/threads/thread.cpp
+++ b/libc/src/__support/threads/thread.cpp
@@ -53,8 +53,8 @@ class TSSKeyMgr {
public:
constexpr TSSKeyMgr()
- : mtx(/*timed=*/false, /*recursive=*/false, /*robust=*/false,
- /*pshared=*/false) {}
+ : mtx(/*is_priority_inherit=*/false, /*is_recursive=*/false,
+ /*is_robust=*/false, /*is_pshared=*/false) {}
cpp::optional<unsigned int> new_key(TSSDtor *dtor) {
cpp::lock_guard lock(mtx);
@@ -112,8 +112,8 @@ class ThreadAtExitCallbackMgr {
public:
constexpr ThreadAtExitCallbackMgr()
- : mtx(/*timed=*/false, /*recursive=*/false, /*robust=*/false,
- /*pshared=*/false) {}
+ : mtx(/*is_priority_inherit=*/false, /*is_recursive=*/false,
+ /*is_robust=*/false, /*is_pshared=*/false) {}
int add_callback(AtExitCallback *callback, void *obj) {
cpp::lock_guard lock(mtx);
diff --git a/libc/src/__support/threads/unix_mutex.h b/libc/src/__support/threads/unix_mutex.h
index ac05e2528ddca..9f304c5e81159 100644
--- a/libc/src/__support/threads/unix_mutex.h
+++ b/libc/src/__support/threads/unix_mutex.h
@@ -10,9 +10,13 @@
#define LLVM_LIBC_SRC___SUPPORT_THREADS_UNIX_MUTEX_H
#include "hdr/types/pid_t.h"
+#include "hdr/types/size_t.h"
+#include "src/__support/CPP/atomic.h"
#include "src/__support/CPP/optional.h"
#include "src/__support/libc_assert.h"
#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"
+#include "src/__support/threads/identifier.h"
#include "src/__support/threads/mutex_common.h"
#include "src/__support/threads/raw_mutex.h"
@@ -20,37 +24,44 @@ namespace LIBC_NAMESPACE_DECL {
// TODO: support shared/recursive/robust mutexes.
class Mutex final : private RawMutex {
- // reserved timed, may be useful when combined with other flags.
- unsigned char timed;
- unsigned char recursive;
- unsigned char robust;
- unsigned char pshared;
+ // Use bitfields to allow encoding more attributes.
+ // TODO: also track errorchecking mutex type explicitly?
+ LIBC_PREFERED_TYPE(bool) unsigned int priority_inherit : 1;
+ LIBC_PREFERED_TYPE(bool) unsigned int recursive : 1;
+ LIBC_PREFERED_TYPE(bool) unsigned int robust : 1;
+ LIBC_PREFERED_TYPE(bool) unsigned int pshared : 1;
// TLS address may not work across forked processes. Use thread id instead.
- pid_t owner;
- unsigned long long lock_count;
+ cpp::Atomic<pid_t> owner;
+ size_t lock_count;
// CndVar needs to access Mutex as RawMutex
friend class CndVar;
-public:
- LIBC_INLINE constexpr Mutex(bool is_timed, bool is_recursive, bool is_robust,
- bool is_pshared)
- : RawMutex(), timed(is_timed), recursive(is_recursive), robust(is_robust),
- pshared(is_pshared), owner(0), lock_count(0) {}
-
- LIBC_INLINE static MutexError init(Mutex *mutex, bool is_timed, bool isrecur,
- bool isrobust, bool is_pshared) {
- RawMutex::init(mutex);
- mutex->timed = is_timed;
- mutex->recursive = isrecur;
- mutex->robust = isrobust;
- mutex->pshared = is_pshared;
- mutex->owner = 0;
- mutex->lock_count = 0;
- return MutexError::NONE;
+ template <class LockRoutine>
+ LIBC_INLINE MutexError lock_impl(LockRoutine do_lock) {
+ if (is_recursive() && owner == internal::gettid()) {
+ if (LIBC_UNLIKELY(lock_count == cpp::numeric_limits<size_t>::max()))
+ return MutexError::OVERFLOW;
+ lock_count++;
+ return MutexError::NONE;
+ }
+
+ MutexError res = do_lock();
+ if (is_recursive() && res == MutexError::NONE) {
+ owner = internal::gettid();
+ lock_count = 1;
+ }
+ return res;
}
+public:
+ LIBC_INLINE constexpr Mutex(bool is_priority_inherit, bool is_recursive,
+ bool is_robust, bool is_pshared)
+ : RawMutex(), priority_inherit(is_priority_inherit),
+ recursive(is_recursive), robust(is_robust), pshared(is_pshared),
+ owner(0), lock_count(0) {}
+
LIBC_INLINE static MutexError destroy(Mutex *lock) {
LIBC_ASSERT(lock->owner == 0 && lock->lock_count == 0 &&
"Mutex destroyed while being locked.");
@@ -60,20 +71,33 @@ class Mutex final : private RawMutex {
// TODO: record owner and lock count.
LIBC_INLINE MutexError lock() {
- // Since timeout is not specified, we do not need to check the return value.
- this->RawMutex::lock(
- /* timeout=*/cpp::nullopt, this->pshared);
- return MutexError::NONE;
+ return lock_impl([this] {
+ // Since timeout is not specified, we do not need to check the return
+ // value.
+ // TODO: check deadlock? POSIX made it optional.
+ this->RawMutex::lock(/* timeout=*/cpp::nullopt, this->pshared);
+ return MutexError::NONE;
+ });
}
// TODO: record owner and lock count.
LIBC_INLINE MutexError timed_lock(internal::AbsTimeout abs_time) {
- if (this->RawMutex::lock(abs_time, this->pshared))
- return MutexError::NONE;
- return MutexError::TIMEOUT;
+ return lock_impl([this, abs_time] {
+ // TODO: check deadlock? POSIX made it optional.
+ if (this->RawMutex::lock(abs_time, this->pshared))
+ return MutexError::NONE;
+ return MutexError::TIMEOUT;
+ });
}
LIBC_INLINE MutexError unlock() {
+ if (is_recursive() && owner == internal::gettid()) {
+ lock_count--;
+ if (lock_count == 0)
+ owner = 0;
+ else
+ return MutexError::NONE;
+ }
if (this->RawMutex::unlock(this->pshared))
return MutexError::NONE;
return MutexError::UNLOCK_WITHOUT_LOCK;
@@ -81,16 +105,20 @@ class Mutex final : private RawMutex {
// TODO: record owner and lock count.
LIBC_INLINE MutexError try_lock() {
- if (this->RawMutex::try_lock())
- return MutexError::NONE;
- return MutexError::BUSY;
+ return lock_impl([this] {
+ if (this->RawMutex::try_lock())
+ return MutexError::NONE;
+ return MutexError::BUSY;
+ });
}
LIBC_INLINE bool can_be_requeued() const {
- return !this->pshared && !this->robust;
+ return !this->pshared && !this->robust && !this->recursive &&
+ !this->priority_inherit;
}
LIBC_INLINE bool is_robust() const { return this->robust; }
+ LIBC_INLINE bool is_recursive() const { return this->recursive; }
};
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pthread/pthread_mutex_init.cpp b/libc/src/pthread/pthread_mutex_init.cpp
index 94052e53d8c0a..0fa6f80161c4d 100644
--- a/libc/src/pthread/pthread_mutex_init.cpp
+++ b/libc/src/pthread/pthread_mutex_init.cpp
@@ -9,6 +9,7 @@
#include "pthread_mutex_init.h"
#include "pthread_mutexattr.h"
+#include "src/__support/CPP/new.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/__support/threads/mutex.h"
@@ -17,20 +18,41 @@
namespace LIBC_NAMESPACE_DECL {
-static_assert(sizeof(Mutex) <= sizeof(pthread_mutex_t),
- "The public pthread_mutex_t type cannot accommodate the internal "
+static_assert(sizeof(Mutex) == sizeof(pthread_mutex_t) &&
+ alignof(Mutex) == alignof(pthread_mutex_t),
+ "The public pthread_mutex_t type must exactly match the internal "
"mutex type.");
LLVM_LIBC_FUNCTION(int, pthread_mutex_init,
(pthread_mutex_t * m,
const pthread_mutexattr_t *__restrict attr)) {
auto mutexattr = attr == nullptr ? DEFAULT_MUTEXATTR : *attr;
- auto err =
- Mutex::init(reinterpret_cast<Mutex *>(m), /*is_timed=*/true,
- get_mutexattr_type(mutexattr) & PTHREAD_MUTEX_RECURSIVE,
- get_mutexattr_robust(mutexattr) & PTHREAD_MUTEX_ROBUST,
- get_mutexattr_pshared(mutexattr) & PTHREAD_PROCESS_SHARED);
- return err == MutexError::NONE ? 0 : EAGAIN;
+ bool is_recursive = false;
+ switch (get_mutexattr_type(mutexattr)) {
+ case PTHREAD_MUTEX_NORMAL:
+ case PTHREAD_MUTEX_ERRORCHECK:
+ break;
+ case PTHREAD_MUTEX_RECURSIVE:
+ is_recursive = true;
+ break;
+ }
+
+ bool is_robust = false;
+ if (get_mutexattr_robust(mutexattr) == PTHREAD_MUTEX_ROBUST)
+ is_robust = true;
+
+ bool is_pshared = false;
+ switch (get_mutexattr_pshared(mutexattr)) {
+ case PTHREAD_PROCESS_PRIVATE:
+ break;
+ case PTHREAD_PROCESS_SHARED:
+ is_pshared = true;
+ break;
+ }
+
+ new (m) Mutex(/*is_priority_inherit=*/false, /*is_recursive=*/is_recursive,
+ /*is_robust=*/is_robust, /*is_pshared=*/is_pshared);
+ return 0;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/atexit.cpp b/libc/src/stdlib/atexit.cpp
index c8a15dd3cfef2..5b924be3a63ed 100644
--- a/libc/src/stdlib/atexit.cpp
+++ b/libc/src/stdlib/atexit.cpp
@@ -15,7 +15,8 @@
namespace LIBC_NAMESPACE_DECL {
constinit ExitCallbackList atexit_callbacks;
-Mutex handler_list_mtx(false, false, false, false);
+Mutex handler_list_mtx(/*is_priority_inherit=*/false, /*is_recursive=*/false,
+ /*is_robust=*/false, /*is_pshared=*/false);
extern "C" {
diff --git a/libc/src/threads/mtx_init.cpp b/libc/src/threads/mtx_init.cpp
index eb0ba5010584e..c6b0278c52f77 100644
--- a/libc/src/threads/mtx_init.cpp
+++ b/libc/src/threads/mtx_init.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "src/threads/mtx_init.h"
+#include "src/__support/CPP/new.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/__support/threads/mutex.h"
@@ -15,15 +16,16 @@
namespace LIBC_NAMESPACE_DECL {
-static_assert(sizeof(Mutex) <= sizeof(mtx_t),
- "The public mtx_t type cannot accommodate the internal mutex "
+static_assert(sizeof(Mutex) == sizeof(mtx_t) &&
+ alignof(Mutex) == alignof(mtx_t),
+ "The public mtx_t type must exactly match the internal mutex "
"type.");
LLVM_LIBC_FUNCTION(int, mtx_init, (mtx_t * m, int type)) {
- auto err = Mutex::init(reinterpret_cast<Mutex *>(m), type & mtx_timed,
- type & mtx_recursive, /* is_robust */ false,
- /* is_pshared */ false);
- return err == MutexError::NONE ? thrd_success : thrd_error;
+ new (m) Mutex(/*is_priority_inherit=*/false,
+ /*is_recursive=*/static_cast<bool>(type & mtx_recursive),
+ /*is_robust=*/false, /*is_pshared=*/false);
+ return thrd_success;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/integration/src/pthread/CMakeLists.txt b/libc/test/integration/src/pthread/CMakeLists.txt
index 71cb039f7761e..eceebb42f18c4 100644
--- a/libc/test/integration/src/pthread/CMakeLists.txt
+++ b/libc/test/integration/src/pthread/CMakeLists.txt
@@ -15,6 +15,9 @@ add_integration_test(
libc.src.pthread.pthread_mutex_lock
libc.src.pthread.pthread_mutex_trylock
libc.src.pthread.pthread_mutex_unlock
+ libc.src.pthread.pthread_mutexattr_destroy
+ libc.src.pthread.pthread_mutexattr_init
+ libc.src.pthread.pthread_mutexattr_settype
libc.src.pthread.pthread_create
libc.src.pthread.pthread_join
)
diff --git a/libc/test/integration/src/pthread/pthread_mutex_test.cpp b/libc/test/integration/src/pthread/pthread_mutex_test.cpp
index 488954c0ef255..b8d71c6f48d2a 100644
--- a/libc/test/integration/src/pthread/pthread_mutex_test.cpp
+++ b/libc/test/integration/src/pthread/pthread_mutex_test.cpp
@@ -15,6 +15,9 @@
#include "src/pthread/pthread_mutex_lock.h"
#include "src/pthread/pthread_mutex_trylock.h"
#include "src/pthread/pthread_mutex_unlock.h"
+#include "src/pthread/pthread_mutexattr_destroy.h"
+#include "src/pthread/pthread_mutexattr_init.h"
+#include "src/pthread/pthread_mutexattr_settype.h"
#include "test/IntegrationTest/test.h"
#include <pthread.h>
@@ -143,6 +146,73 @@ void trylock_test() {
LIBC_NAMESPACE::pthread_mutex_destroy(&trylock_mutex);
}
+void *trylock_other_thread(void *arg) {
+ auto *mutex = reinterpret_cast<pthread_mutex_t *>(arg);
+ int result = LIBC_NAMESPACE::pthread_mutex_trylock(mutex);
+ if (result == 0)
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(mutex), 0);
+ return reinterpret_cast<void *>(uintptr_t(result));
+}
+
+void recursive_mutex_test() {
+ pthread_mutexattr_t attr;
+ pthread_mutex_t recursive_mutex;
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutexattr_init(&attr), 0);
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutexattr_settype(&attr,
+ PTHREAD_MUTEX_RECURSIVE),
+ 0);
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_init(&recursive_mutex, &attr), 0);
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutexattr_destroy(&attr), 0);
+
+ ASSERT_TRUE(recursive_mutex.__recursive);
+ ASSERT_EQ(recursive_mutex.__owner, 0);
+ ASSERT_EQ(recursive_mutex.__lock_count, size_t(0));
+
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_lock(&recursive_mutex), 0);
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_lock(&recursive_mutex), 0);
+
+ pthread_t thread;
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_create(&thread, nullptr, trylock_other_thread,
+ &recursive_mutex),
+ 0);
+ void *retval = nullptr;
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_join(thread, &retval), 0);
+ ASSERT_EQ(uintptr_t(retval), uintptr_t(EBUSY));
+
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(&recursive_mutex), 0);
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(&recursive_mutex), 0);
+ ASSERT_EQ(recursive_mutex.__owner, 0);
+ ASSERT_EQ(recursive_mutex.__lock_count, size_t(0));
+
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_trylock(&recursive_mutex), 0);
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(&recursive_mutex), 0);
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_destroy(&recursive_mutex), 0);
+}
+
+void initializer_acts_the_same_as_null_attr() {
+ pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+ pthread_mutex_t mutex_from_init;
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_init(&mutex_from_init, nullptr), 0);
+
+ ASSERT_EQ(mutex.__ftxw.__word, mutex_from_init.__ftxw.__word);
+ ASSERT_EQ(mutex.__priority_inherit, mutex_from_init.__priority_inherit);
+ ASSERT_EQ(mutex.__recursive, mutex_from_init.__recursive);
+ ASSERT_EQ(mutex.__robust, mutex_from_init.__robust);
+ ASSERT_EQ(mutex.__pshared, mutex_from_init.__pshared);
+ ASSERT_EQ(mutex.__owner, mutex_from_init.__owner);
+ ASSERT_EQ(mutex.__lock_count, mutex_from_init.__lock_count);
+
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_lock(&mutex), 0);
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_trylock(&mutex), EBUSY);
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(&mutex), 0);
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_destroy(&mutex), 0);
+
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_lock(&mutex_from_init), 0);
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_trylock(&mutex_from_init), EBUSY);
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(&mutex_from_init), 0);
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_destroy(&mutex_from_init), 0);
+}
+
static constexpr int THREAD_COUNT = 10;
static pthread_mutex_t multiple_waiter_lock;
static pthread_mutex_t counter_lock;
@@ -199,14 +269,12 @@ void multiple_waiters() {
LIBC_NAMESPACE::pthread_mutex_destroy(&counter_lock);
}
-// Test the initializer
-[[maybe_unused]]
-static pthread_mutex_t test_initializer = PTHREAD_MUTEX_INITIALIZER;
-
TEST_MAIN() {
relay_counter();
wait_and_step();
trylock_test();
+ recursive_mutex_test();
+ initializer_acts_the_same_as_null_attr();
multiple_waiters();
return 0;
}
diff --git a/libc/test/integration/src/threads/mtx_test.cpp b/libc/test/integration/src/threads/mtx_test.cpp
index 0b0a9faae24a6..18bdbc748d5fa 100644
--- a/libc/test/integration/src/threads/mtx_test.cpp
+++ b/libc/test/integration/src/threads/mtx_test.cpp
@@ -138,6 +138,30 @@ void wait_and_step() {
LIBC_NAMESPACE::mtx_destroy(&step_lock);
}
+void recursive_mutex_test() {
+ mtx_t recursive_mutex;
+ ASSERT_EQ(LIBC_NAMESPACE::mtx_init(&recursive_mutex, mtx_recursive),
+ static_cast<int>(thrd_success));
+
+ ASSERT_TRUE(recursive_mutex.__recursive);
+ ASSERT_EQ(recursive_mutex.__owner, 0);
+ ASSERT_EQ(recursive_mutex.__lock_count, size_t(0));
+
+ ASSERT_EQ(LIBC_NAMESPACE::mtx_lock(&recursive_mutex),
+ static_cast<int>(thrd_success));
+ ASSERT_EQ(LIBC_NAMESPACE::mtx_lock(&recursive_mutex),
+ static_cast<int>(thrd_success));
+
+ ASSERT_EQ(LIBC_NAMESPACE::mtx_unlock(&recursive_mutex),
+ static_cast<int>(thrd_success));
+ ASSERT_EQ(LIBC_NAMESPACE::mtx_unlock(&recursive_mutex),
+ static_cast<int>(thrd_success));
+ ASSERT_EQ(recursive_mutex.__owner, 0);
+ ASSERT_EQ(recursive_mutex.__lock_count, size_t(0));
+
+ LIBC_NAMESPACE::mtx_destroy(&recursive_mutex);
+}
+
static constexpr int THREAD_COUNT = 10;
static mtx_t multiple_waiter_lock;
static mtx_t counter_lock;
@@ -197,6 +221,7 @@ void multiple_waiters() {
TEST_MAIN() {
relay_counter();
wait_and_step();
+ recursive_mutex_test();
multiple_waiters();
return 0;
}
>From 25b2a4ad2ea7f200eeceef5aba82db1bfee569a1 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Fri, 24 Apr 2026 11:29:45 -0400
Subject: [PATCH 02/16] fix
---
.../src/pthread/pthread_mutex_test.cpp | 40 +++++++++++++------
.../test/integration/src/threads/mtx_test.cpp | 22 +++++++---
2 files changed, 45 insertions(+), 17 deletions(-)
diff --git a/libc/test/integration/src/pthread/pthread_mutex_test.cpp b/libc/test/integration/src/pthread/pthread_mutex_test.cpp
index b8d71c6f48d2a..f45c5f1fb7d6e 100644
--- a/libc/test/integration/src/pthread/pthread_mutex_test.cpp
+++ b/libc/test/integration/src/pthread/pthread_mutex_test.cpp
@@ -18,6 +18,7 @@
#include "src/pthread/pthread_mutexattr_destroy.h"
#include "src/pthread/pthread_mutexattr_init.h"
#include "src/pthread/pthread_mutexattr_settype.h"
+#include "src/string/memory_utils/inline_memcpy.h"
#include "test/IntegrationTest/test.h"
#include <pthread.h>
@@ -25,6 +26,15 @@
constexpr int START = 0;
constexpr int MAX = 10000;
+static pthread_mutex_t snapshot_mutex(const void *mutex_storage) {
+ pthread_mutex_t snapshot;
+ // The original storage may currently hold libc's internal mutex
+ // representation. Copy the bytes into pthread_mutex_t storage before
+ // inspection to avoid strict aliasing violations.
+ LIBC_NAMESPACE::inline_memcpy(&snapshot, mutex_storage, sizeof(snapshot));
+ return snapshot;
+}
+
pthread_mutex_t mutex;
static int shared_int = START;
@@ -164,9 +174,10 @@ void recursive_mutex_test() {
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_init(&recursive_mutex, &attr), 0);
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutexattr_destroy(&attr), 0);
- ASSERT_TRUE(recursive_mutex.__recursive);
- ASSERT_EQ(recursive_mutex.__owner, 0);
- ASSERT_EQ(recursive_mutex.__lock_count, size_t(0));
+ pthread_mutex_t snapshot = snapshot_mutex(&recursive_mutex);
+ ASSERT_TRUE(snapshot.__recursive);
+ ASSERT_EQ(snapshot.__owner, 0);
+ ASSERT_EQ(snapshot.__lock_count, size_t(0));
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_lock(&recursive_mutex), 0);
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_lock(&recursive_mutex), 0);
@@ -181,8 +192,9 @@ void recursive_mutex_test() {
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(&recursive_mutex), 0);
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(&recursive_mutex), 0);
- ASSERT_EQ(recursive_mutex.__owner, 0);
- ASSERT_EQ(recursive_mutex.__lock_count, size_t(0));
+ snapshot = snapshot_mutex(&recursive_mutex);
+ ASSERT_EQ(snapshot.__owner, 0);
+ ASSERT_EQ(snapshot.__lock_count, size_t(0));
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_trylock(&recursive_mutex), 0);
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(&recursive_mutex), 0);
@@ -194,13 +206,17 @@ void initializer_acts_the_same_as_null_attr() {
pthread_mutex_t mutex_from_init;
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_init(&mutex_from_init, nullptr), 0);
- ASSERT_EQ(mutex.__ftxw.__word, mutex_from_init.__ftxw.__word);
- ASSERT_EQ(mutex.__priority_inherit, mutex_from_init.__priority_inherit);
- ASSERT_EQ(mutex.__recursive, mutex_from_init.__recursive);
- ASSERT_EQ(mutex.__robust, mutex_from_init.__robust);
- ASSERT_EQ(mutex.__pshared, mutex_from_init.__pshared);
- ASSERT_EQ(mutex.__owner, mutex_from_init.__owner);
- ASSERT_EQ(mutex.__lock_count, mutex_from_init.__lock_count);
+ pthread_mutex_t mutex_snapshot = snapshot_mutex(&mutex);
+ pthread_mutex_t mutex_from_init_snapshot = snapshot_mutex(&mutex_from_init);
+ ASSERT_EQ(mutex_snapshot.__ftxw.__word,
+ mutex_from_init_snapshot.__ftxw.__word);
+ ASSERT_EQ(mutex_snapshot.__priority_inherit,
+ mutex_from_init_snapshot.__priority_inherit);
+ ASSERT_EQ(mutex_snapshot.__recursive, mutex_from_init_snapshot.__recursive);
+ ASSERT_EQ(mutex_snapshot.__robust, mutex_from_init_snapshot.__robust);
+ ASSERT_EQ(mutex_snapshot.__pshared, mutex_from_init_snapshot.__pshared);
+ ASSERT_EQ(mutex_snapshot.__owner, mutex_from_init_snapshot.__owner);
+ ASSERT_EQ(mutex_snapshot.__lock_count, mutex_from_init_snapshot.__lock_count);
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_lock(&mutex), 0);
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_trylock(&mutex), EBUSY);
diff --git a/libc/test/integration/src/threads/mtx_test.cpp b/libc/test/integration/src/threads/mtx_test.cpp
index 18bdbc748d5fa..5aa2d6d1b3f50 100644
--- a/libc/test/integration/src/threads/mtx_test.cpp
+++ b/libc/test/integration/src/threads/mtx_test.cpp
@@ -12,6 +12,7 @@
#include "src/threads/mtx_unlock.h"
#include "src/threads/thrd_create.h"
#include "src/threads/thrd_join.h"
+#include "src/string/memory_utils/inline_memcpy.h"
#include "test/IntegrationTest/test.h"
@@ -20,6 +21,15 @@
constexpr int START = 0;
constexpr int MAX = 10000;
+static mtx_t snapshot_mutex(const void *mutex_storage) {
+ mtx_t snapshot;
+ // The original storage may currently hold libc's internal mutex
+ // representation. Copy the bytes into mtx_t storage before inspection to
+ // avoid strict aliasing violations.
+ LIBC_NAMESPACE::inline_memcpy(&snapshot, mutex_storage, sizeof(snapshot));
+ return snapshot;
+}
+
mtx_t mutex;
static int shared_int = START;
@@ -143,9 +153,10 @@ void recursive_mutex_test() {
ASSERT_EQ(LIBC_NAMESPACE::mtx_init(&recursive_mutex, mtx_recursive),
static_cast<int>(thrd_success));
- ASSERT_TRUE(recursive_mutex.__recursive);
- ASSERT_EQ(recursive_mutex.__owner, 0);
- ASSERT_EQ(recursive_mutex.__lock_count, size_t(0));
+ mtx_t snapshot = snapshot_mutex(&recursive_mutex);
+ ASSERT_TRUE(snapshot.__recursive);
+ ASSERT_EQ(snapshot.__owner, 0);
+ ASSERT_EQ(snapshot.__lock_count, size_t(0));
ASSERT_EQ(LIBC_NAMESPACE::mtx_lock(&recursive_mutex),
static_cast<int>(thrd_success));
@@ -156,8 +167,9 @@ void recursive_mutex_test() {
static_cast<int>(thrd_success));
ASSERT_EQ(LIBC_NAMESPACE::mtx_unlock(&recursive_mutex),
static_cast<int>(thrd_success));
- ASSERT_EQ(recursive_mutex.__owner, 0);
- ASSERT_EQ(recursive_mutex.__lock_count, size_t(0));
+ snapshot = snapshot_mutex(&recursive_mutex);
+ ASSERT_EQ(snapshot.__owner, 0);
+ ASSERT_EQ(snapshot.__lock_count, size_t(0));
LIBC_NAMESPACE::mtx_destroy(&recursive_mutex);
}
>From 62cd690365ea9fdffb2ab9f32545fa72f270aff8 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Fri, 24 Apr 2026 11:32:05 -0400
Subject: [PATCH 03/16] fix
---
libc/include/llvm-libc-macros/pthread-macros.h | 16 ++++++++--------
.../src/pthread/pthread_mutex_test.cpp | 10 +++++-----
libc/test/integration/src/threads/mtx_test.cpp | 2 +-
3 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/libc/include/llvm-libc-macros/pthread-macros.h b/libc/include/llvm-libc-macros/pthread-macros.h
index 5fb8857ef37ab..1619ad123d2c1 100644
--- a/libc/include/llvm-libc-macros/pthread-macros.h
+++ b/libc/include/llvm-libc-macros/pthread-macros.h
@@ -32,18 +32,18 @@
#ifdef __linux__
#define PTHREAD_MUTEX_INITIALIZER \
{ \
- /* .__ftxw = */ {0}, /* .__priority_inherit = */ 0, \
- /* .__recursive = */ 0, /* .__robust = */ 0, \
- /* .__pshared = */ 0, /* .__owner = */ 0, \
- /* .__lock_count = */ 0, \
+ /* .__ftxw = */ {0}, /* .__priority_inherit = */ 0, \
+ /* .__recursive = */ 0, /* .__robust = */ 0, \
+ /* .__pshared = */ 0, /* .__owner = */ 0, \
+ /* .__lock_count = */ 0, \
}
#else
#define PTHREAD_MUTEX_INITIALIZER \
{ \
- /* .__ftxw = */ {0}, /* .__priority_inherit = */ 0, \
- /* .__recursive = */ 0, /* .__robust = */ 0, \
- /* .__pshared = */ 0, /* .__owner = */ 0, \
- /* .__lock_count = */ 0, \
+ /* .__ftxw = */ {0}, /* .__priority_inherit = */ 0, \
+ /* .__recursive = */ 0, /* .__robust = */ 0, \
+ /* .__pshared = */ 0, /* .__owner = */ 0, \
+ /* .__lock_count = */ 0, \
}
#endif
diff --git a/libc/test/integration/src/pthread/pthread_mutex_test.cpp b/libc/test/integration/src/pthread/pthread_mutex_test.cpp
index f45c5f1fb7d6e..7e323189431cd 100644
--- a/libc/test/integration/src/pthread/pthread_mutex_test.cpp
+++ b/libc/test/integration/src/pthread/pthread_mutex_test.cpp
@@ -168,9 +168,9 @@ void recursive_mutex_test() {
pthread_mutexattr_t attr;
pthread_mutex_t recursive_mutex;
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutexattr_init(&attr), 0);
- ASSERT_EQ(LIBC_NAMESPACE::pthread_mutexattr_settype(&attr,
- PTHREAD_MUTEX_RECURSIVE),
- 0);
+ ASSERT_EQ(
+ LIBC_NAMESPACE::pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE),
+ 0);
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_init(&recursive_mutex, &attr), 0);
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutexattr_destroy(&attr), 0);
@@ -183,8 +183,8 @@ void recursive_mutex_test() {
ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_lock(&recursive_mutex), 0);
pthread_t thread;
- ASSERT_EQ(LIBC_NAMESPACE::pthread_create(&thread, nullptr, trylock_other_thread,
- &recursive_mutex),
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_create(
+ &thread, nullptr, trylock_other_thread, &recursive_mutex),
0);
void *retval = nullptr;
ASSERT_EQ(LIBC_NAMESPACE::pthread_join(thread, &retval), 0);
diff --git a/libc/test/integration/src/threads/mtx_test.cpp b/libc/test/integration/src/threads/mtx_test.cpp
index 5aa2d6d1b3f50..909c4f2c5c760 100644
--- a/libc/test/integration/src/threads/mtx_test.cpp
+++ b/libc/test/integration/src/threads/mtx_test.cpp
@@ -6,13 +6,13 @@
//
//===----------------------------------------------------------------------===//
+#include "src/string/memory_utils/inline_memcpy.h"
#include "src/threads/mtx_destroy.h"
#include "src/threads/mtx_init.h"
#include "src/threads/mtx_lock.h"
#include "src/threads/mtx_unlock.h"
#include "src/threads/thrd_create.h"
#include "src/threads/thrd_join.h"
-#include "src/string/memory_utils/inline_memcpy.h"
#include "test/IntegrationTest/test.h"
>From 05ca6aa5866745441323d6bc3a99eb2fc4d61e3d Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 17:28:43 -0400
Subject: [PATCH 04/16] additional fix
---
libc/config/linux/aarch64/entrypoints.txt | 3 +
libc/config/linux/x86_64/entrypoints.txt | 3 +
libc/src/link/CMakeLists.txt | 1 +
libc/src/link/dl_iterate_phdr.cpp | 131 +++++++++++++++++-
libcxx/include/__cxx03/__thread/id.h | 14 +-
.../__cxx03/__thread/support/pthread.h | 14 +-
libcxx/include/__cxx03/__thread/thread.h | 4 +-
libcxx/include/__mbstate_t.h | 2 +
libcxx/include/__thread/formatter.h | 5 +-
libcxx/include/__thread/id.h | 14 +-
libcxx/include/__thread/support/pthread.h | 14 +-
libcxx/include/__thread/thread.h | 2 +-
runtimes/CMakeLists.txt | 9 ++
13 files changed, 187 insertions(+), 29 deletions(-)
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index b15edc5e3e102..79073faf08c40 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -108,6 +108,9 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.inttypes.strtoimax
libc.src.inttypes.strtoumax
+ # link.h entrypoints
+ libc.src.link.dl_iterate_phdr
+
# stdbit.h entrypoints
libc.src.stdbit.stdc_bit_ceil_uc
libc.src.stdbit.stdc_bit_ceil_ui
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 27569f0fae82b..cc2e74240dbe5 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -110,6 +110,9 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.inttypes.strtoimax
libc.src.inttypes.strtoumax
+ # link.h entrypoints
+ libc.src.link.dl_iterate_phdr
+
# stdbit.h entrypoints
libc.src.stdbit.stdc_bit_ceil_uc
libc.src.stdbit.stdc_bit_ceil_ui
diff --git a/libc/src/link/CMakeLists.txt b/libc/src/link/CMakeLists.txt
index 55f5edfab7d93..35fe9e87c74f2 100644
--- a/libc/src/link/CMakeLists.txt
+++ b/libc/src/link/CMakeLists.txt
@@ -5,5 +5,6 @@ add_entrypoint_object(
HDRS
dl_iterate_phdr.h
DEPENDS
+ libc.src.__support.OSUtil.linux.auxv
libc.hdr.stdint_proxy
)
diff --git a/libc/src/link/dl_iterate_phdr.cpp b/libc/src/link/dl_iterate_phdr.cpp
index 7964411598d4a..7aa2be4f497f6 100644
--- a/libc/src/link/dl_iterate_phdr.cpp
+++ b/libc/src/link/dl_iterate_phdr.cpp
@@ -8,18 +8,141 @@
#include "dl_iterate_phdr.h"
+#include "hdr/sys_auxv_macros.h"
+#include "src/__support/OSUtil/linux/auxv.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
+#include <elf.h>
+
+extern "C" {
+[[gnu::weak]] extern const char __ehdr_start;
+[[gnu::weak]] extern const char __executable_start;
+}
+
namespace LIBC_NAMESPACE_DECL {
+namespace {
+
+LIBC_INLINE bool is_valid_elf(const ElfW(Ehdr) *ehdr) {
+ if (ehdr == nullptr)
+ return false;
+
+ return ehdr->e_ident[EI_MAG0] == ELFMAG0 &&
+ ehdr->e_ident[EI_MAG1] == ELFMAG1 &&
+ ehdr->e_ident[EI_MAG2] == ELFMAG2 &&
+ ehdr->e_ident[EI_MAG3] == ELFMAG3;
+}
+
+LIBC_INLINE const ElfW(Ehdr) *get_executable_ehdr() {
+ const ElfW(Ehdr) *ehdr = nullptr;
+
+ if (&__ehdr_start != nullptr)
+ ehdr = reinterpret_cast<const ElfW(Ehdr) *>(&__ehdr_start);
+ else if (&__executable_start != nullptr)
+ ehdr = reinterpret_cast<const ElfW(Ehdr) *>(&__executable_start);
+
+ return is_valid_elf(ehdr) ? ehdr : nullptr;
+}
+
+LIBC_INLINE ElfW(Addr) get_executable_load_bias(const ElfW(Ehdr) *ehdr,
+ const ElfW(Phdr) *phdr_table,
+ ElfW(Half) phnum) {
+ if (phdr_table != nullptr) {
+ const uintptr_t runtime_phdr = reinterpret_cast<uintptr_t>(phdr_table);
+ for (ElfW(Half) i = 0; i < phnum; ++i) {
+ if (phdr_table[i].p_type == PT_PHDR)
+ return static_cast<ElfW(Addr)>(runtime_phdr - phdr_table[i].p_vaddr);
+ }
+ }
+
+ // For PIE binaries the ELF header is mapped at the load bias. ET_EXEC uses
+ // absolute virtual addresses, so report zero there.
+ if (ehdr != nullptr && ehdr->e_type == ET_DYN)
+ return reinterpret_cast<ElfW(Addr)>(ehdr);
+
+ return 0;
+}
+
+LIBC_INLINE int call_with_executable(__dl_iterate_phdr_callback_t callback,
+ void *arg) {
+ const ElfW(Ehdr) *ehdr = get_executable_ehdr();
+ if (ehdr == nullptr)
+ return -1;
+
+ cpp::optional<unsigned long> aux_phdr_val = auxv::get(AT_PHDR);
+ cpp::optional<unsigned long> aux_phnum_val = auxv::get(AT_PHNUM);
+ auto *aux_phdr = reinterpret_cast<const ElfW(Phdr) *>(
+ aux_phdr_val ? *aux_phdr_val : 0);
+ const auto aux_phnum = static_cast<ElfW(Half)>(aux_phnum_val ? *aux_phnum_val
+ : 0);
+
+ const ElfW(Phdr) *phdr =
+ aux_phdr != nullptr ? aux_phdr
+ : reinterpret_cast<const ElfW(Phdr) *>(
+ reinterpret_cast<uintptr_t>(ehdr) + ehdr->e_phoff);
+ const ElfW(Half) phnum = aux_phnum != 0 ? aux_phnum : ehdr->e_phnum;
+
+ dl_phdr_info exe_info = {};
+ exe_info.dlpi_addr = get_executable_load_bias(ehdr, phdr, phnum);
+ exe_info.dlpi_name = nullptr;
+ exe_info.dlpi_phdr = phdr;
+ exe_info.dlpi_phnum = phnum;
+ exe_info.dlpi_adds = 0;
+ exe_info.dlpi_subs = 0;
+ exe_info.dlpi_tls_modid = 0;
+ exe_info.dlpi_tls_data = nullptr;
+ return callback(&exe_info, sizeof(exe_info), arg);
+}
+
+LIBC_INLINE int call_with_vdso(__dl_iterate_phdr_callback_t callback,
+ void *arg) {
+ cpp::optional<unsigned long> aux_vdso = auxv::get(AT_SYSINFO_EHDR);
+ auto *ehdr_vdso =
+ reinterpret_cast<const ElfW(Ehdr) *>(aux_vdso ? *aux_vdso : 0);
+ if (!is_valid_elf(ehdr_vdso))
+ return 0;
+
+ auto *phdr = reinterpret_cast<const ElfW(Phdr) *>(
+ reinterpret_cast<uintptr_t>(ehdr_vdso) + ehdr_vdso->e_phoff);
+
+ dl_phdr_info vdso_info = {};
+ vdso_info.dlpi_name = nullptr;
+ vdso_info.dlpi_phdr = phdr;
+ vdso_info.dlpi_phnum = ehdr_vdso->e_phnum;
+ vdso_info.dlpi_adds = 0;
+ vdso_info.dlpi_subs = 0;
+ vdso_info.dlpi_tls_modid = 0;
+ vdso_info.dlpi_tls_data = nullptr;
+
+ for (ElfW(Half) i = 0; i < ehdr_vdso->e_phnum; ++i) {
+ if (phdr[i].p_type == PT_LOAD) {
+ vdso_info.dlpi_addr = reinterpret_cast<ElfW(Addr)>(ehdr_vdso) -
+ static_cast<ElfW(Addr)>(phdr[i].p_vaddr);
+ break;
+ }
+ }
+
+ return callback(&vdso_info, sizeof(vdso_info), arg);
+}
+
+} // namespace
+
LLVM_LIBC_FUNCTION(int, dl_iterate_phdr,
(__dl_iterate_phdr_callback_t callback, void *arg)) {
- // FIXME: For pure static linking, this can report just the executable with
- // info from __ehdr_start or AT_{PHDR,PHNUM} decoding, and its PT_TLS; and it
- // could report the vDSO.
- (void)callback, (void)arg;
+#if defined(LIBC_TARGET_ARCH_IS_X86_64) || defined(LIBC_TARGET_ARCH_IS_AARCH64)
+ if (callback == nullptr)
+ return -1;
+
+ int rc = call_with_executable(callback, arg);
+ if (rc != 0)
+ return rc;
+ return call_with_vdso(callback, arg);
+#else
+ (void)callback;
+ (void)arg;
return 0;
+#endif
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libcxx/include/__cxx03/__thread/id.h b/libcxx/include/__cxx03/__thread/id.h
index 66b54c55d3146..44f926120b9bf 100644
--- a/libcxx/include/__cxx03/__thread/id.h
+++ b/libcxx/include/__cxx03/__thread/id.h
@@ -41,9 +41,9 @@ class _LIBCPP_TEMPLATE_VIS __thread_id {
static _LIBCPP_HIDE_FROM_ABI bool
__lt_impl(__thread_id __x, __thread_id __y) _NOEXCEPT { // id==0 is always less than any other thread_id
- if (__x.__id_ == 0)
- return __y.__id_ != 0;
- if (__y.__id_ == 0)
+ if (__libcpp_thread_isnull(&__x.__id_))
+ return !__libcpp_thread_isnull(&__y.__id_);
+ if (__libcpp_thread_isnull(&__y.__id_))
return false;
return __libcpp_thread_id_less(__x.__id_, __y.__id_);
}
@@ -51,7 +51,7 @@ class _LIBCPP_TEMPLATE_VIS __thread_id {
public:
_LIBCPP_HIDE_FROM_ABI __thread_id() _NOEXCEPT : __id_(0) {}
- _LIBCPP_HIDE_FROM_ABI void __reset() { __id_ = 0; }
+ _LIBCPP_HIDE_FROM_ABI void __reset() { std::memset(&__id_, 0, sizeof(__libcpp_thread_id)); }
friend _LIBCPP_HIDE_FROM_ABI bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT;
friend _LIBCPP_HIDE_FROM_ABI bool operator<(__thread_id __x, __thread_id __y) _NOEXCEPT;
@@ -72,9 +72,9 @@ class _LIBCPP_TEMPLATE_VIS __thread_id {
inline _LIBCPP_HIDE_FROM_ABI bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT {
// Don't pass id==0 to underlying routines
- if (__x.__id_ == 0)
- return __y.__id_ == 0;
- if (__y.__id_ == 0)
+ if (__libcpp_thread_isnull(&__x.__id_))
+ return __libcpp_thread_isnull(&__y.__id_);
+ if (__libcpp_thread_isnull(&__y.__id_))
return false;
return __libcpp_thread_id_equal(__x.__id_, __y.__id_);
}
diff --git a/libcxx/include/__cxx03/__thread/support/pthread.h b/libcxx/include/__cxx03/__thread/support/pthread.h
index 4ec5531003e02..b94b21c37a23e 100644
--- a/libcxx/include/__cxx03/__thread/support/pthread.h
+++ b/libcxx/include/__cxx03/__thread/support/pthread.h
@@ -152,12 +152,12 @@ typedef pthread_t __libcpp_thread_id;
// Returns non-zero if the thread ids are equal, otherwise 0
inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_id_equal(__libcpp_thread_id __t1, __libcpp_thread_id __t2) {
- return __t1 == __t2;
+ return std::memcmp(&__t1, &__t2, sizeof(__libcpp_thread_id)) == 0;
}
// Returns non-zero if t1 < t2, otherwise 0
inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_id_less(__libcpp_thread_id __t1, __libcpp_thread_id __t2) {
- return __t1 < __t2;
+ return std::memcmp(&__t1, &__t2, sizeof(__libcpp_thread_id)) < 0;
}
//
@@ -175,7 +175,15 @@ inline _LIBCPP_HIDE_FROM_ABI __libcpp_thread_id __libcpp_thread_get_id(const __l
}
inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_isnull(const __libcpp_thread_t* __t) {
- return __libcpp_thread_get_id(__t) == 0;
+ union {
+ char bytes[sizeof(__libcpp_thread_id)];
+ __libcpp_thread_id __id;
+ } u;
+ u.__id = __libcpp_thread_get_id(__t);
+ for (size_t i = 0; i < sizeof(__libcpp_thread_id); ++i)
+ if (u.bytes[i] != 0)
+ return false;
+ return true;
}
inline _LIBCPP_HIDE_FROM_ABI int __libcpp_thread_create(__libcpp_thread_t* __t, void* (*__func)(void*), void* __arg) {
diff --git a/libcxx/include/__cxx03/__thread/thread.h b/libcxx/include/__cxx03/__thread/thread.h
index f9a5ed45aea99..f88dd42af22f6 100644
--- a/libcxx/include/__cxx03/__thread/thread.h
+++ b/libcxx/include/__cxx03/__thread/thread.h
@@ -110,9 +110,9 @@ void __thread_specific_ptr<_Tp>::set_pointer(pointer __p) {
}
template <>
-struct _LIBCPP_TEMPLATE_VIS hash<__thread_id> : public __unary_function<__thread_id, size_t> {
+struct hash<__thread_id> : public __unary_function<__thread_id, size_t> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(__thread_id __v) const _NOEXCEPT {
- return hash<__libcpp_thread_id>()(__v.__id_);
+ return hash<__INTPTR_TYPE__>()(__builtin_bit_cast(__INTPTR_TYPE__, __v.__id_));
}
};
diff --git a/libcxx/include/__mbstate_t.h b/libcxx/include/__mbstate_t.h
index d331ba622d37f..d7ff5b8dd4adc 100644
--- a/libcxx/include/__mbstate_t.h
+++ b/libcxx/include/__mbstate_t.h
@@ -39,6 +39,8 @@
# define __NEED_mbstate_t
# include <bits/alltypes.h>
# undef __NEED_mbstate_t
+#elif __has_include(<llvm-libc-types/mbstate_t.h>)
+# include <llvm-libc-types/mbstate_t.h>
#elif __has_include(<bits/types/mbstate_t.h>)
# include <bits/types/mbstate_t.h> // works on most Unixes
#elif __has_include(<sys/_types/_mbstate_t.h>)
diff --git a/libcxx/include/__thread/formatter.h b/libcxx/include/__thread/formatter.h
index 826607d47b469..1d35dfd7e80cf 100644
--- a/libcxx/include/__thread/formatter.h
+++ b/libcxx/include/__thread/formatter.h
@@ -58,14 +58,15 @@ struct formatter<__thread_id, _CharT> {
using _Tp = decltype(__get_underlying_id(__id));
using _Cp = conditional_t<integral<_Tp>, _Tp, conditional_t<is_pointer_v<_Tp>, uintptr_t, void>>;
- static_assert(!is_same_v<_Cp, void>, "unsupported thread::id type, please file a bug report");
+ // static_assert(!is_same_v<_Cp, void>, "unsupported thread::id type, please file a bug report");
__format_spec::__parsed_specifications<_CharT> __specs = __parser_.__get_parsed_std_specifications(__ctx);
if constexpr (is_pointer_v<_Tp>) {
__specs.__std_.__alternate_form_ = true;
__specs.__std_.__type_ = __format_spec::__type::__hexadecimal_lower_case;
}
- return __formatter::__format_integer(reinterpret_cast<_Cp>(__get_underlying_id(__id)), __ctx, __specs);
+ return __formatter::__format_integer(
+ __builtin_bit_cast(__INTPTR_TYPE__, __get_underlying_id(__id)), __ctx, __specs);
}
__format_spec::__parser<_CharT> __parser_{.__alignment_ = __format_spec::__alignment::__right};
diff --git a/libcxx/include/__thread/id.h b/libcxx/include/__thread/id.h
index 14a51fc9ee880..e04d2016670ef 100644
--- a/libcxx/include/__thread/id.h
+++ b/libcxx/include/__thread/id.h
@@ -42,9 +42,9 @@ class __thread_id {
static _LIBCPP_HIDE_FROM_ABI bool
__lt_impl(__thread_id __x, __thread_id __y) _NOEXCEPT { // id==0 is always less than any other thread_id
- if (__x.__id_ == 0)
- return __y.__id_ != 0;
- if (__y.__id_ == 0)
+ if (__libcpp_thread_isnull(&__x.__id_))
+ return !__libcpp_thread_isnull(&__y.__id_);
+ if (__libcpp_thread_isnull(&__y.__id_))
return false;
return __libcpp_thread_id_less(__x.__id_, __y.__id_);
}
@@ -52,7 +52,7 @@ class __thread_id {
public:
_LIBCPP_HIDE_FROM_ABI __thread_id() _NOEXCEPT : __id_(0) {}
- _LIBCPP_HIDE_FROM_ABI void __reset() { __id_ = 0; }
+ _LIBCPP_HIDE_FROM_ABI void __reset() { std::memset(&__id_, 0, sizeof(__libcpp_thread_id)); }
friend _LIBCPP_HIDE_FROM_ABI bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT;
# if _LIBCPP_STD_VER <= 17
@@ -77,9 +77,9 @@ class __thread_id {
inline _LIBCPP_HIDE_FROM_ABI bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT {
// Don't pass id==0 to underlying routines
- if (__x.__id_ == 0)
- return __y.__id_ == 0;
- if (__y.__id_ == 0)
+ if (__libcpp_thread_isnull(&__x.__id_))
+ return __libcpp_thread_isnull(&__y.__id_);
+ if (__libcpp_thread_isnull(&__y.__id_))
return false;
return __libcpp_thread_id_equal(__x.__id_, __y.__id_);
}
diff --git a/libcxx/include/__thread/support/pthread.h b/libcxx/include/__thread/support/pthread.h
index 4cf5c0342467b..7478793a61a31 100644
--- a/libcxx/include/__thread/support/pthread.h
+++ b/libcxx/include/__thread/support/pthread.h
@@ -152,12 +152,12 @@ typedef pthread_t __libcpp_thread_id;
// Returns non-zero if the thread ids are equal, otherwise 0
inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_id_equal(__libcpp_thread_id __t1, __libcpp_thread_id __t2) {
- return __t1 == __t2;
+ return std::memcmp(&__t1, &__t2, sizeof(__libcpp_thread_id)) == 0;
}
// Returns non-zero if t1 < t2, otherwise 0
inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_id_less(__libcpp_thread_id __t1, __libcpp_thread_id __t2) {
- return __t1 < __t2;
+ return std::memcmp(&__t1, &__t2, sizeof(__libcpp_thread_id)) < 0;
}
//
@@ -175,7 +175,15 @@ inline _LIBCPP_HIDE_FROM_ABI __libcpp_thread_id __libcpp_thread_get_id(const __l
}
inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_isnull(const __libcpp_thread_t* __t) {
- return __libcpp_thread_get_id(__t) == 0;
+ union {
+ char bytes[sizeof(__libcpp_thread_id)];
+ __libcpp_thread_id __id;
+ } u;
+ u.__id = __libcpp_thread_get_id(__t);
+ for (size_t i = 0; i < sizeof(__libcpp_thread_id); ++i)
+ if (u.bytes[i] != 0)
+ return false;
+ return true;
}
inline _LIBCPP_HIDE_FROM_ABI int __libcpp_thread_create(__libcpp_thread_t* __t, void* (*__func)(void*), void* __arg) {
diff --git a/libcxx/include/__thread/thread.h b/libcxx/include/__thread/thread.h
index b2f51aa816c10..efa99ddfcc0a8 100644
--- a/libcxx/include/__thread/thread.h
+++ b/libcxx/include/__thread/thread.h
@@ -123,7 +123,7 @@ void __thread_specific_ptr<_Tp>::set_pointer(pointer __p) {
template <>
struct hash<__thread_id> : public __unary_function<__thread_id, size_t> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(__thread_id __v) const _NOEXCEPT {
- return hash<__libcpp_thread_id>()(__v.__id_);
+ return hash<__INTPTR_TYPE__>()(__builtin_bit_cast(__INTPTR_TYPE__, __v.__id_));
}
};
diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index 75551ba0c651a..61a43356694f3 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -59,6 +59,15 @@ foreach(proj ${LLVM_ENABLE_RUNTIMES})
endif()
endforeach()
+# The in-tree LLVM libc only provides a complete public C header set in
+# full-build mode. Consumers like libc++, libc++abi, and libunwind need those
+# headers to avoid falling back to the host libc in overlay mode.
+if(DEFINED RUNTIMES_USE_LIBC AND RUNTIMES_USE_LIBC STREQUAL "llvm-libc")
+ message(STATUS "Enabling LLVM_LIBC_FULL_BUILD because RUNTIMES_USE_LIBC=llvm-libc")
+ set(LLVM_LIBC_FULL_BUILD ON CACHE BOOL
+ "Build and test LLVM libc as if it is the full libc" FORCE)
+endif()
+
function(runtime_register_component name)
set_property(GLOBAL APPEND PROPERTY SUB_COMPONENTS ${name})
endfunction()
>From 9d290e107ce76dfed3aad227c9f43f997e3bbb4e Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 17:53:13 -0400
Subject: [PATCH 05/16] more fixes
---
libc/include/llvm-libc-types/__thread_type.h | 4 +--
libc/src/pthread/pthread_self.cpp | 3 +-
libc/src/threads/thrd_current.cpp | 3 +-
libcxx/include/__cxx03/__thread/id.h | 14 ++++----
.../__cxx03/__thread/support/pthread.h | 14 ++------
libcxx/include/__cxx03/__thread/thread.h | 4 +--
libcxx/include/__thread/formatter.h | 5 ++-
libcxx/include/__thread/id.h | 14 ++++----
libcxx/include/__thread/support/pthread.h | 14 ++------
libcxx/include/__thread/thread.h | 2 +-
run.sh | 33 +++++++++++++++++++
11 files changed, 61 insertions(+), 49 deletions(-)
create mode 100755 run.sh
diff --git a/libc/include/llvm-libc-types/__thread_type.h b/libc/include/llvm-libc-types/__thread_type.h
index 645573f544a99..e2f4829e9fd7f 100644
--- a/libc/include/llvm-libc-types/__thread_type.h
+++ b/libc/include/llvm-libc-types/__thread_type.h
@@ -9,8 +9,6 @@
#ifndef LLVM_LIBC_TYPES___THREAD_TYPE_H
#define LLVM_LIBC_TYPES___THREAD_TYPE_H
-typedef struct {
- void *__attrib;
-} __thread_type;
+typedef void *__thread_type;
#endif // LLVM_LIBC_TYPES___THREAD_TYPE_H
diff --git a/libc/src/pthread/pthread_self.cpp b/libc/src/pthread/pthread_self.cpp
index c3169ec1ca5c4..e810b033170cb 100644
--- a/libc/src/pthread/pthread_self.cpp
+++ b/libc/src/pthread/pthread_self.cpp
@@ -20,8 +20,7 @@ static_assert(sizeof(pthread_t) == sizeof(LIBC_NAMESPACE::Thread),
"Mismatch between pthread_t and internal Thread.");
LLVM_LIBC_FUNCTION(pthread_t, pthread_self, ()) {
- pthread_t th;
- th.__attrib = self.attrib;
+ pthread_t th = self.attrib;
return th;
}
diff --git a/libc/src/threads/thrd_current.cpp b/libc/src/threads/thrd_current.cpp
index 634159712b629..29a0de13ef85e 100644
--- a/libc/src/threads/thrd_current.cpp
+++ b/libc/src/threads/thrd_current.cpp
@@ -19,8 +19,7 @@ static_assert(sizeof(thrd_t) == sizeof(LIBC_NAMESPACE::Thread),
"Mismatch between thrd_t and internal Thread.");
LLVM_LIBC_FUNCTION(thrd_t, thrd_current, ()) {
- thrd_t th;
- th.__attrib = self.attrib;
+ thrd_t th = self.attrib;
return th;
}
diff --git a/libcxx/include/__cxx03/__thread/id.h b/libcxx/include/__cxx03/__thread/id.h
index 44f926120b9bf..66b54c55d3146 100644
--- a/libcxx/include/__cxx03/__thread/id.h
+++ b/libcxx/include/__cxx03/__thread/id.h
@@ -41,9 +41,9 @@ class _LIBCPP_TEMPLATE_VIS __thread_id {
static _LIBCPP_HIDE_FROM_ABI bool
__lt_impl(__thread_id __x, __thread_id __y) _NOEXCEPT { // id==0 is always less than any other thread_id
- if (__libcpp_thread_isnull(&__x.__id_))
- return !__libcpp_thread_isnull(&__y.__id_);
- if (__libcpp_thread_isnull(&__y.__id_))
+ if (__x.__id_ == 0)
+ return __y.__id_ != 0;
+ if (__y.__id_ == 0)
return false;
return __libcpp_thread_id_less(__x.__id_, __y.__id_);
}
@@ -51,7 +51,7 @@ class _LIBCPP_TEMPLATE_VIS __thread_id {
public:
_LIBCPP_HIDE_FROM_ABI __thread_id() _NOEXCEPT : __id_(0) {}
- _LIBCPP_HIDE_FROM_ABI void __reset() { std::memset(&__id_, 0, sizeof(__libcpp_thread_id)); }
+ _LIBCPP_HIDE_FROM_ABI void __reset() { __id_ = 0; }
friend _LIBCPP_HIDE_FROM_ABI bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT;
friend _LIBCPP_HIDE_FROM_ABI bool operator<(__thread_id __x, __thread_id __y) _NOEXCEPT;
@@ -72,9 +72,9 @@ class _LIBCPP_TEMPLATE_VIS __thread_id {
inline _LIBCPP_HIDE_FROM_ABI bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT {
// Don't pass id==0 to underlying routines
- if (__libcpp_thread_isnull(&__x.__id_))
- return __libcpp_thread_isnull(&__y.__id_);
- if (__libcpp_thread_isnull(&__y.__id_))
+ if (__x.__id_ == 0)
+ return __y.__id_ == 0;
+ if (__y.__id_ == 0)
return false;
return __libcpp_thread_id_equal(__x.__id_, __y.__id_);
}
diff --git a/libcxx/include/__cxx03/__thread/support/pthread.h b/libcxx/include/__cxx03/__thread/support/pthread.h
index b94b21c37a23e..4ec5531003e02 100644
--- a/libcxx/include/__cxx03/__thread/support/pthread.h
+++ b/libcxx/include/__cxx03/__thread/support/pthread.h
@@ -152,12 +152,12 @@ typedef pthread_t __libcpp_thread_id;
// Returns non-zero if the thread ids are equal, otherwise 0
inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_id_equal(__libcpp_thread_id __t1, __libcpp_thread_id __t2) {
- return std::memcmp(&__t1, &__t2, sizeof(__libcpp_thread_id)) == 0;
+ return __t1 == __t2;
}
// Returns non-zero if t1 < t2, otherwise 0
inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_id_less(__libcpp_thread_id __t1, __libcpp_thread_id __t2) {
- return std::memcmp(&__t1, &__t2, sizeof(__libcpp_thread_id)) < 0;
+ return __t1 < __t2;
}
//
@@ -175,15 +175,7 @@ inline _LIBCPP_HIDE_FROM_ABI __libcpp_thread_id __libcpp_thread_get_id(const __l
}
inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_isnull(const __libcpp_thread_t* __t) {
- union {
- char bytes[sizeof(__libcpp_thread_id)];
- __libcpp_thread_id __id;
- } u;
- u.__id = __libcpp_thread_get_id(__t);
- for (size_t i = 0; i < sizeof(__libcpp_thread_id); ++i)
- if (u.bytes[i] != 0)
- return false;
- return true;
+ return __libcpp_thread_get_id(__t) == 0;
}
inline _LIBCPP_HIDE_FROM_ABI int __libcpp_thread_create(__libcpp_thread_t* __t, void* (*__func)(void*), void* __arg) {
diff --git a/libcxx/include/__cxx03/__thread/thread.h b/libcxx/include/__cxx03/__thread/thread.h
index f88dd42af22f6..f9a5ed45aea99 100644
--- a/libcxx/include/__cxx03/__thread/thread.h
+++ b/libcxx/include/__cxx03/__thread/thread.h
@@ -110,9 +110,9 @@ void __thread_specific_ptr<_Tp>::set_pointer(pointer __p) {
}
template <>
-struct hash<__thread_id> : public __unary_function<__thread_id, size_t> {
+struct _LIBCPP_TEMPLATE_VIS hash<__thread_id> : public __unary_function<__thread_id, size_t> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(__thread_id __v) const _NOEXCEPT {
- return hash<__INTPTR_TYPE__>()(__builtin_bit_cast(__INTPTR_TYPE__, __v.__id_));
+ return hash<__libcpp_thread_id>()(__v.__id_);
}
};
diff --git a/libcxx/include/__thread/formatter.h b/libcxx/include/__thread/formatter.h
index 1d35dfd7e80cf..826607d47b469 100644
--- a/libcxx/include/__thread/formatter.h
+++ b/libcxx/include/__thread/formatter.h
@@ -58,15 +58,14 @@ struct formatter<__thread_id, _CharT> {
using _Tp = decltype(__get_underlying_id(__id));
using _Cp = conditional_t<integral<_Tp>, _Tp, conditional_t<is_pointer_v<_Tp>, uintptr_t, void>>;
- // static_assert(!is_same_v<_Cp, void>, "unsupported thread::id type, please file a bug report");
+ static_assert(!is_same_v<_Cp, void>, "unsupported thread::id type, please file a bug report");
__format_spec::__parsed_specifications<_CharT> __specs = __parser_.__get_parsed_std_specifications(__ctx);
if constexpr (is_pointer_v<_Tp>) {
__specs.__std_.__alternate_form_ = true;
__specs.__std_.__type_ = __format_spec::__type::__hexadecimal_lower_case;
}
- return __formatter::__format_integer(
- __builtin_bit_cast(__INTPTR_TYPE__, __get_underlying_id(__id)), __ctx, __specs);
+ return __formatter::__format_integer(reinterpret_cast<_Cp>(__get_underlying_id(__id)), __ctx, __specs);
}
__format_spec::__parser<_CharT> __parser_{.__alignment_ = __format_spec::__alignment::__right};
diff --git a/libcxx/include/__thread/id.h b/libcxx/include/__thread/id.h
index e04d2016670ef..14a51fc9ee880 100644
--- a/libcxx/include/__thread/id.h
+++ b/libcxx/include/__thread/id.h
@@ -42,9 +42,9 @@ class __thread_id {
static _LIBCPP_HIDE_FROM_ABI bool
__lt_impl(__thread_id __x, __thread_id __y) _NOEXCEPT { // id==0 is always less than any other thread_id
- if (__libcpp_thread_isnull(&__x.__id_))
- return !__libcpp_thread_isnull(&__y.__id_);
- if (__libcpp_thread_isnull(&__y.__id_))
+ if (__x.__id_ == 0)
+ return __y.__id_ != 0;
+ if (__y.__id_ == 0)
return false;
return __libcpp_thread_id_less(__x.__id_, __y.__id_);
}
@@ -52,7 +52,7 @@ class __thread_id {
public:
_LIBCPP_HIDE_FROM_ABI __thread_id() _NOEXCEPT : __id_(0) {}
- _LIBCPP_HIDE_FROM_ABI void __reset() { std::memset(&__id_, 0, sizeof(__libcpp_thread_id)); }
+ _LIBCPP_HIDE_FROM_ABI void __reset() { __id_ = 0; }
friend _LIBCPP_HIDE_FROM_ABI bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT;
# if _LIBCPP_STD_VER <= 17
@@ -77,9 +77,9 @@ class __thread_id {
inline _LIBCPP_HIDE_FROM_ABI bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT {
// Don't pass id==0 to underlying routines
- if (__libcpp_thread_isnull(&__x.__id_))
- return __libcpp_thread_isnull(&__y.__id_);
- if (__libcpp_thread_isnull(&__y.__id_))
+ if (__x.__id_ == 0)
+ return __y.__id_ == 0;
+ if (__y.__id_ == 0)
return false;
return __libcpp_thread_id_equal(__x.__id_, __y.__id_);
}
diff --git a/libcxx/include/__thread/support/pthread.h b/libcxx/include/__thread/support/pthread.h
index 7478793a61a31..4cf5c0342467b 100644
--- a/libcxx/include/__thread/support/pthread.h
+++ b/libcxx/include/__thread/support/pthread.h
@@ -152,12 +152,12 @@ typedef pthread_t __libcpp_thread_id;
// Returns non-zero if the thread ids are equal, otherwise 0
inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_id_equal(__libcpp_thread_id __t1, __libcpp_thread_id __t2) {
- return std::memcmp(&__t1, &__t2, sizeof(__libcpp_thread_id)) == 0;
+ return __t1 == __t2;
}
// Returns non-zero if t1 < t2, otherwise 0
inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_id_less(__libcpp_thread_id __t1, __libcpp_thread_id __t2) {
- return std::memcmp(&__t1, &__t2, sizeof(__libcpp_thread_id)) < 0;
+ return __t1 < __t2;
}
//
@@ -175,15 +175,7 @@ inline _LIBCPP_HIDE_FROM_ABI __libcpp_thread_id __libcpp_thread_get_id(const __l
}
inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_isnull(const __libcpp_thread_t* __t) {
- union {
- char bytes[sizeof(__libcpp_thread_id)];
- __libcpp_thread_id __id;
- } u;
- u.__id = __libcpp_thread_get_id(__t);
- for (size_t i = 0; i < sizeof(__libcpp_thread_id); ++i)
- if (u.bytes[i] != 0)
- return false;
- return true;
+ return __libcpp_thread_get_id(__t) == 0;
}
inline _LIBCPP_HIDE_FROM_ABI int __libcpp_thread_create(__libcpp_thread_t* __t, void* (*__func)(void*), void* __arg) {
diff --git a/libcxx/include/__thread/thread.h b/libcxx/include/__thread/thread.h
index efa99ddfcc0a8..b2f51aa816c10 100644
--- a/libcxx/include/__thread/thread.h
+++ b/libcxx/include/__thread/thread.h
@@ -123,7 +123,7 @@ void __thread_specific_ptr<_Tp>::set_pointer(pointer __p) {
template <>
struct hash<__thread_id> : public __unary_function<__thread_id, size_t> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(__thread_id __v) const _NOEXCEPT {
- return hash<__INTPTR_TYPE__>()(__builtin_bit_cast(__INTPTR_TYPE__, __v.__id_));
+ return hash<__libcpp_thread_id>()(__v.__id_);
}
};
diff --git a/run.sh b/run.sh
new file mode 100755
index 0000000000000..c61b75a141388
--- /dev/null
+++ b/run.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+cd /home/schrodingerzy/Documents/llvm-project
+ninja -C build-libcxx-llvm libc/include/generate-libc-headers cxx-test-depends
+
+root="$(mktemp -d)"
+cleanup() {
+ rm -rf "$root"
+}
+trap cleanup EXIT
+
+mkdir -p "$root/usr/include" "$root/usr/local/include"
+
+# Preserve Linux UAPI headers without pulling in the full host C library headers.
+cp -a /usr/include/linux "$root/usr/include/"
+cp -a /usr/include/asm "$root/usr/include/"
+cp -a /usr/include/asm-generic "$root/usr/include/"
+
+# Overlay local libc and install headers so they win over the host copies.
+cp -a build-libcxx-llvm/libc/include/. "$root/usr/include/"
+cp -a build-libcxx-llvm/libcxx/test-suite-install/include/. "$root/usr/include/"
+
+bwrap \
+ --ro-bind / / \
+ --bind /home/schrodingerzy/Documents/llvm-project /home/schrodingerzy/Documents/llvm-project \
+ --dev-bind /dev /dev \
+ --proc /proc \
+ --tmpfs /tmp \
+ --chdir /home/schrodingerzy/Documents/llvm-project \
+ --ro-bind "$root/usr/local/include" /usr/local/include \
+ --ro-bind "$root/usr/include" /usr/include \
+ build-libcxx-llvm/bin/llvm-lit -sv -j8 build-libcxx-llvm/libcxx/test
>From 4126fd35dec7f6d437381d074c2bb6baffef6e1e Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 20:54:29 -0400
Subject: [PATCH 06/16] update
---
run.sh | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 186 insertions(+), 16 deletions(-)
diff --git a/run.sh b/run.sh
index c61b75a141388..ba6af7d55d7aa 100755
--- a/run.sh
+++ b/run.sh
@@ -1,33 +1,203 @@
#!/usr/bin/env bash
set -euo pipefail
-cd /home/schrodingerzy/Documents/llvm-project
-ninja -C build-libcxx-llvm libc/include/generate-libc-headers cxx-test-depends
+repo=/home/schrodingerzy/Documents/llvm-project
+build="$repo/build-libcxx-llvm"
+base_compiler=/usr/bin/clang++
+lit_jobs="${LIT_JOBS:-4}"
+
+cd "$repo"
+
+root="$(mktemp -d "$build/run-sandbox.XXXXXX")"
+launcher_shims="$root/shims"
+sysroot="$root/sysroot"
+wrapper="$root/clang++-llvm-libc"
+lit_wrapper="$root/llvm-lit-fork"
+empty_include="$root/empty-usr-local-include"
+fortify_shim_c="$root/fortify-shim.c"
+fortify_shim_o="$root/fortify-shim.o"
-root="$(mktemp -d)"
cleanup() {
rm -rf "$root"
}
trap cleanup EXIT
-mkdir -p "$root/usr/include" "$root/usr/local/include"
+mkdir -p "$launcher_shims"
+cat > "$launcher_shims/sccache" <<'EOF'
+#!/usr/bin/env bash
+exec "$@"
+EOF
+chmod +x "$launcher_shims/sccache"
+export PATH="$launcher_shims:$PATH"
+
+if (($# == 0)); then
+ targets=("$build/libcxx/test")
+else
+ targets=("$@")
+fi
+
+ninja -C "$build" \
+ libc/include/generate-libc-headers \
+ crt1.o \
+ libc.a \
+ libm.a \
+ lib/libunwind.a \
+ clang_rt.builtins-x86_64 \
+ cxx-test-depends
+
+mkdir -p "$sysroot/usr/include" "$empty_include"
+
+# Preserve Linux UAPI headers, but do not copy libc++ into /usr/include.
+cp -a /usr/include/linux "$sysroot/usr/include/"
+cp -a /usr/include/asm "$sysroot/usr/include/"
+cp -a /usr/include/asm-generic "$sysroot/usr/include/"
+cp -a "$build/libc/include/." "$sysroot/usr/include/"
+
+crtbegin="$("$base_compiler" --print-file-name=crtbeginT.o)"
+crtend="$("$base_compiler" --print-file-name=crtend.o)"
+builtins="$build/compiler-rt/lib/linux/libclang_rt.builtins-x86_64.a"
+
+cat > "$fortify_shim_c" <<'EOF'
+typedef __SIZE_TYPE__ size_t;
+
+__attribute__((noreturn)) static void __llvm_libcxx_test_chk_fail(void) {
+ __builtin_trap();
+}
+
+static void *__llvm_libcxx_test_memcpy(void *dst, const void *src, size_t len) {
+ unsigned char *out = (unsigned char *)dst;
+ const unsigned char *in = (const unsigned char *)src;
+ for (size_t i = 0; i < len; ++i)
+ out[i] = in[i];
+ return dst;
+}
+
+static void *__llvm_libcxx_test_memmove(void *dst, const void *src, size_t len) {
+ unsigned char *out = (unsigned char *)dst;
+ const unsigned char *in = (const unsigned char *)src;
+ if (out == in || len == 0)
+ return dst;
+ if (out < in || out >= in + len) {
+ for (size_t i = 0; i < len; ++i)
+ out[i] = in[i];
+ } else {
+ for (size_t i = len; i != 0; --i)
+ out[i - 1] = in[i - 1];
+ }
+ return dst;
+}
+
+static void *__llvm_libcxx_test_memset(void *dst, int value, size_t len) {
+ unsigned char *out = (unsigned char *)dst;
+ unsigned char byte = (unsigned char)value;
+ for (size_t i = 0; i < len; ++i)
+ out[i] = byte;
+ return dst;
+}
+
+void *__memcpy_chk(void *dst, const void *src, size_t len, size_t dstlen) {
+ if (len > dstlen)
+ __llvm_libcxx_test_chk_fail();
+ return __llvm_libcxx_test_memcpy(dst, src, len);
+}
+
+void *__memmove_chk(void *dst, const void *src, size_t len, size_t dstlen) {
+ if (len > dstlen)
+ __llvm_libcxx_test_chk_fail();
+ return __llvm_libcxx_test_memmove(dst, src, len);
+}
+
+void *__memset_chk(void *dst, int value, size_t len, size_t dstlen) {
+ if (len > dstlen)
+ __llvm_libcxx_test_chk_fail();
+ return __llvm_libcxx_test_memset(dst, value, len);
+}
+EOF
+
+"$base_compiler" \
+ -c \
+ -x c \
+ -fno-stack-protector \
+ -ffreestanding \
+ "$fortify_shim_c" \
+ -o "$fortify_shim_o"
+
+cat > "$wrapper" <<EOF
+#!/usr/bin/env bash
+set -euo pipefail
+
+base_compiler=$base_compiler
+sysroot=$sysroot
+repo=$repo
+build=$build
+crtbegin=$crtbegin
+crtend=$crtend
+builtins=$builtins
+fortify_shim_o=$fortify_shim_o
+
+linking=1
+for arg in "\$@"; do
+ case "\$arg" in
+ -c|-E|-S|-fsyntax-only|-emit-ast)
+ linking=0
+ ;;
+ esac
+done
+
+common_args=(
+ -nostdlibinc
+ -isystem "\$sysroot/usr/include"
+ -fno-stack-protector
+ -Wno-missing-braces
+)
+
+if (( linking )); then
+ exec "\$base_compiler" \
+ "\$@" \
+ "\${common_args[@]}" \
+ -nodefaultlibs \
+ -nostartfiles \
+ -static \
+ "$build/libc/startup/linux/crt1.o" \
+ "\$crtbegin" \
+ -L "$build/libc/lib" \
+ -lunwind \
+ -lc \
+ -lm \
+ "\$fortify_shim_o" \
+ "\$builtins" \
+ "\$crtend"
+else
+ exec "\$base_compiler" "\$@" "\${common_args[@]}"
+fi
+EOF
+
+chmod +x "$wrapper"
+
+cat > "$lit_wrapper" <<EOF
+#!/usr/bin/env python3
+import multiprocessing as mp
+import runpy
+import sys
-# Preserve Linux UAPI headers without pulling in the full host C library headers.
-cp -a /usr/include/linux "$root/usr/include/"
-cp -a /usr/include/asm "$root/usr/include/"
-cp -a /usr/include/asm-generic "$root/usr/include/"
+mp.set_start_method("fork")
+sys.argv[0] = "$build/bin/llvm-lit"
+runpy.run_path("$build/bin/llvm-lit", run_name="__main__")
+EOF
-# Overlay local libc and install headers so they win over the host copies.
-cp -a build-libcxx-llvm/libc/include/. "$root/usr/include/"
-cp -a build-libcxx-llvm/libcxx/test-suite-install/include/. "$root/usr/include/"
+chmod +x "$lit_wrapper"
bwrap \
--ro-bind / / \
- --bind /home/schrodingerzy/Documents/llvm-project /home/schrodingerzy/Documents/llvm-project \
+ --bind "$repo" "$repo" \
--dev-bind /dev /dev \
--proc /proc \
--tmpfs /tmp \
- --chdir /home/schrodingerzy/Documents/llvm-project \
- --ro-bind "$root/usr/local/include" /usr/local/include \
- --ro-bind "$root/usr/include" /usr/include \
- build-libcxx-llvm/bin/llvm-lit -sv -j8 build-libcxx-llvm/libcxx/test
+ --chdir "$repo" \
+ --ro-bind "$sysroot/usr/include" /usr/include \
+ --ro-bind "$empty_include" /usr/local/include \
+ "$lit_wrapper" \
+ -sv \
+ "-j$lit_jobs" \
+ --param "compiler=$wrapper" \
+ "${targets[@]}"
>From 9b39cd4cd0a0e8e02f5ae52d8b7cc0b0f4f9b848 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 21:31:26 -0400
Subject: [PATCH 07/16] update
---
run.sh | 30 +++++++++++++++++++++++++++---
1 file changed, 27 insertions(+), 3 deletions(-)
diff --git a/run.sh b/run.sh
index ba6af7d55d7aa..1d72520f4d2ee 100755
--- a/run.sh
+++ b/run.sh
@@ -1,13 +1,37 @@
#!/usr/bin/env bash
set -euo pipefail
-repo=/home/schrodingerzy/Documents/llvm-project
-build="$repo/build-libcxx-llvm"
-base_compiler=/usr/bin/clang++
+repo="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
+build="${BUILD_DIR:-$repo/build-libcxx-llvm}"
+base_c_compiler="${CC:-/usr/bin/clang}"
+base_compiler="${CXX:-/usr/bin/clang++}"
lit_jobs="${LIT_JOBS:-4}"
cd "$repo"
+if [[ ! -f "$build/CMakeCache.txt" ]]; then
+ mkdir -p "$build"
+ cmake \
+ -S "$repo/runtimes" \
+ -B "$build" \
+ -G Ninja \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DCMAKE_C_COMPILER="$base_c_compiler" \
+ -DCMAKE_CXX_COMPILER="$base_compiler" \
+ -DCMAKE_C_COMPILER_LAUNCHER= \
+ -DCMAKE_CXX_COMPILER_LAUNCHER= \
+ -DLIBCXX_ENABLE_FILESYSTEM=OFF \
+ -DLIBCXX_ENABLE_WIDE_CHARACTERS=OFF \
+ -DLLVM_LIBC_INCLUDE_SCUDO=ON \
+ -DCOMPILER_RT_BUILD_SCUDO_STANDALONE_WITH_LLVM_LIBC=ON \
+ -DCOMPILER_RT_BUILD_GWP_ASAN=OFF \
+ -DCOMPILER_RT_SCUDO_STANDALONE_BUILD_SHARED=OFF \
+ -DRUNTIMES_USE_LIBC=llvm-libc \
+ -DLLVM_ENABLE_RUNTIMES="libc;compiler-rt;libunwind;libcxxabi;libcxx" \
+ -DLIBCXX_INCLUDE_TESTS=ON \
+ -DLIBCXX_INCLUDE_BENCHMARKS=OFF
+fi
+
root="$(mktemp -d "$build/run-sandbox.XXXXXX")"
launcher_shims="$root/shims"
sysroot="$root/sysroot"
>From 1e741134c79831287cb972820905d12c37c77fb5 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 21:37:27 -0400
Subject: [PATCH 08/16] update
---
run.sh | 31 +++++++++++++++++++++++++++++--
1 file changed, 29 insertions(+), 2 deletions(-)
diff --git a/run.sh b/run.sh
index 1d72520f4d2ee..81fbc98195c60 100755
--- a/run.sh
+++ b/run.sh
@@ -6,6 +6,19 @@ build="${BUILD_DIR:-$repo/build-libcxx-llvm}"
base_c_compiler="${CC:-/usr/bin/clang}"
base_compiler="${CXX:-/usr/bin/clang++}"
lit_jobs="${LIT_JOBS:-4}"
+host_arch="$(uname -m)"
+
+case "$host_arch" in
+ x86_64)
+ compiler_rt_arch=x86_64
+ ;;
+ aarch64|arm64)
+ compiler_rt_arch=aarch64
+ ;;
+ *)
+ compiler_rt_arch="$host_arch"
+ ;;
+esac
cd "$repo"
@@ -32,6 +45,21 @@ if [[ ! -f "$build/CMakeCache.txt" ]]; then
-DLIBCXX_INCLUDE_BENCHMARKS=OFF
fi
+builtins_target="clang_rt.builtins-$compiler_rt_arch"
+builtins="$build/compiler-rt/lib/linux/libclang_rt.builtins-$compiler_rt_arch.a"
+if [[ ! -f "$builtins" ]]; then
+ builtins="$(find "$build/compiler-rt/lib" -name "libclang_rt.builtins-$compiler_rt_arch.a" -print -quit)"
+fi
+if [[ -z "${builtins:-}" || ! -f "$builtins" ]]; then
+ builtins="$(find "$build/compiler-rt/lib" -name 'libclang_rt.builtins-*.a' -print -quit)"
+ if [[ -z "${builtins:-}" ]]; then
+ echo "unable to locate compiler-rt builtins archive under $build/compiler-rt/lib" >&2
+ exit 1
+ fi
+ builtins_target="$(basename "$builtins" .a)"
+ builtins_target="${builtins_target#lib}"
+fi
+
root="$(mktemp -d "$build/run-sandbox.XXXXXX")"
launcher_shims="$root/shims"
sysroot="$root/sysroot"
@@ -66,7 +94,7 @@ ninja -C "$build" \
libc.a \
libm.a \
lib/libunwind.a \
- clang_rt.builtins-x86_64 \
+ "$builtins_target" \
cxx-test-depends
mkdir -p "$sysroot/usr/include" "$empty_include"
@@ -79,7 +107,6 @@ cp -a "$build/libc/include/." "$sysroot/usr/include/"
crtbegin="$("$base_compiler" --print-file-name=crtbeginT.o)"
crtend="$("$base_compiler" --print-file-name=crtend.o)"
-builtins="$build/compiler-rt/lib/linux/libclang_rt.builtins-x86_64.a"
cat > "$fortify_shim_c" <<'EOF'
typedef __SIZE_TYPE__ size_t;
>From b97f230f72595b2f44fa066b1840723d833cafa4 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 21:39:18 -0400
Subject: [PATCH 09/16] update
---
run.sh | 34 +++++++++++++++++++++++-----------
1 file changed, 23 insertions(+), 11 deletions(-)
diff --git a/run.sh b/run.sh
index 81fbc98195c60..1bb52e3dede78 100755
--- a/run.sh
+++ b/run.sh
@@ -46,18 +46,18 @@ if [[ ! -f "$build/CMakeCache.txt" ]]; then
fi
builtins_target="clang_rt.builtins-$compiler_rt_arch"
-builtins="$build/compiler-rt/lib/linux/libclang_rt.builtins-$compiler_rt_arch.a"
-if [[ ! -f "$builtins" ]]; then
- builtins="$(find "$build/compiler-rt/lib" -name "libclang_rt.builtins-$compiler_rt_arch.a" -print -quit)"
-fi
-if [[ -z "${builtins:-}" || ! -f "$builtins" ]]; then
- builtins="$(find "$build/compiler-rt/lib" -name 'libclang_rt.builtins-*.a' -print -quit)"
- if [[ -z "${builtins:-}" ]]; then
- echo "unable to locate compiler-rt builtins archive under $build/compiler-rt/lib" >&2
- exit 1
+builtins_target_candidates="$(ninja -C "$build" -t targets all | sed -n 's/:.*//; /^clang_rt\.builtins-/p; /^libclang_rt\.builtins-.*\.a$/p')"
+if ! grep -qx "$builtins_target" <<<"$builtins_target_candidates"; then
+ alt_target="libclang_rt.builtins-$compiler_rt_arch.a"
+ if grep -qx "$alt_target" <<<"$builtins_target_candidates"; then
+ builtins_target="$alt_target"
+ else
+ builtins_target="$(head -n 1 <<<"$builtins_target_candidates")"
+ if [[ -z "$builtins_target" ]]; then
+ echo "unable to locate a compiler-rt builtins target in $build" >&2
+ exit 1
+ fi
fi
- builtins_target="$(basename "$builtins" .a)"
- builtins_target="${builtins_target#lib}"
fi
root="$(mktemp -d "$build/run-sandbox.XXXXXX")"
@@ -97,6 +97,18 @@ ninja -C "$build" \
"$builtins_target" \
cxx-test-depends
+builtins="$build/compiler-rt/lib/linux/libclang_rt.builtins-$compiler_rt_arch.a"
+if [[ ! -f "$builtins" ]]; then
+ builtins="$(find "$build/compiler-rt/lib" -name "libclang_rt.builtins-$compiler_rt_arch.a" -print -quit)"
+fi
+if [[ -z "${builtins:-}" || ! -f "$builtins" ]]; then
+ builtins="$(find "$build/compiler-rt/lib" -name 'libclang_rt.builtins-*.a' -print -quit)"
+ if [[ -z "${builtins:-}" ]]; then
+ echo "unable to locate compiler-rt builtins archive under $build/compiler-rt/lib" >&2
+ exit 1
+ fi
+fi
+
mkdir -p "$sysroot/usr/include" "$empty_include"
# Preserve Linux UAPI headers, but do not copy libc++ into /usr/include.
>From a0e1f45dd0dffd9e4eb9f9fb959a4d82d1320b78 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 21:42:53 -0400
Subject: [PATCH 10/16] update
---
libc/config/linux/aarch64/entrypoints.txt | 1 +
libc/config/linux/riscv/entrypoints.txt | 1 +
2 files changed, 2 insertions(+)
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 79073faf08c40..c23d1214c6e6a 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -18,6 +18,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.ctype.toupper
# dlfcn.h entrypoints
+ libc.src.dlfcn.dladdr
libc.src.dlfcn.dlclose
libc.src.dlfcn.dlerror
libc.src.dlfcn.dlopen
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 6478aed3b0391..ff82dd479665a 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -18,6 +18,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.ctype.toupper
# dlfcn.h entrypoints
+ libc.src.dlfcn.dladdr
libc.src.dlfcn.dlclose
libc.src.dlfcn.dlerror
libc.src.dlfcn.dlopen
>From 7780c4697bd19d08c05ca2aed725205b98f07cd9 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 21:45:02 -0400
Subject: [PATCH 11/16] update
---
run.sh | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/run.sh b/run.sh
index 1bb52e3dede78..ba3a44812353a 100755
--- a/run.sh
+++ b/run.sh
@@ -33,6 +33,14 @@ if [[ ! -f "$build/CMakeCache.txt" ]]; then
-DCMAKE_CXX_COMPILER="$base_compiler" \
-DCMAKE_C_COMPILER_LAUNCHER= \
-DCMAKE_CXX_COMPILER_LAUNCHER= \
+ -DLIBUNWIND_ENABLE_SHARED=OFF \
+ -DLIBUNWIND_ENABLE_STATIC=ON \
+ -DLIBCXXABI_ENABLE_SHARED=OFF \
+ -DLIBCXXABI_ENABLE_STATIC=ON \
+ -DLIBCXXABI_ENABLE_STATIC_UNWINDER=ON \
+ -DLIBCXX_ENABLE_SHARED=OFF \
+ -DLIBCXX_ENABLE_STATIC=ON \
+ -DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=ON \
-DLIBCXX_ENABLE_FILESYSTEM=OFF \
-DLIBCXX_ENABLE_WIDE_CHARACTERS=OFF \
-DLLVM_LIBC_INCLUDE_SCUDO=ON \
>From 5283a3d305ead8fd4e3d2824c3ef1de75f5d0e2f Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 21:53:16 -0400
Subject: [PATCH 12/16] update
---
libc/config/linux/aarch64/entrypoints.txt | 307 +++++++++++++++++++---
1 file changed, 269 insertions(+), 38 deletions(-)
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index c23d1214c6e6a..cc2e74240dbe5 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -37,6 +37,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.poll.poll
# sched.h entrypoints
+ libc.src.sched.getcpu
libc.src.sched.sched_get_priority_max
libc.src.sched.sched_get_priority_min
libc.src.sched.sched_getaffinity
@@ -185,6 +186,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdbit.stdc_trailing_zeros_us
# stdlib.h entrypoints
+ libc.src.stdlib.a64l
libc.src.stdlib.abs
libc.src.stdlib.atof
libc.src.stdlib.atoi
@@ -192,6 +194,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdlib.atoll
libc.src.stdlib.bsearch
libc.src.stdlib.div
+ libc.src.stdlib.l64a
libc.src.stdlib.labs
libc.src.stdlib.ldiv
libc.src.stdlib.llabs
@@ -203,8 +206,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdlib.srand
libc.src.stdlib.strfromd
libc.src.stdlib.strfromf
- # TODO: long double support is buggy with clang-11. Re-enable when buildbots are upgraded.
- # libc.src.stdlib.strfroml
+ libc.src.stdlib.strfroml
libc.src.stdlib.strtod
libc.src.stdlib.strtof
libc.src.stdlib.strtol
@@ -257,6 +259,9 @@ set(TARGET_LIBC_ENTRYPOINTS
# sys/ioctl.h entrypoints
libc.src.sys.ioctl.ioctl
+ # sys/ipc.h entrypoints
+ libc.src.sys.ipc.ftok
+
# sys/mman.h entrypoints
libc.src.sys.mman.madvise
libc.src.sys.mman.mincore
@@ -270,6 +275,11 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.sys.mman.munlock
libc.src.sys.mman.munlockall
libc.src.sys.mman.munmap
+ libc.src.sys.mman.pkey_alloc
+ libc.src.sys.mman.pkey_free
+ libc.src.sys.mman.pkey_get
+ libc.src.sys.mman.pkey_mprotect
+ libc.src.sys.mman.pkey_set
libc.src.sys.mman.remap_file_pages
libc.src.sys.mman.posix_madvise
libc.src.sys.mman.shm_open
@@ -282,6 +292,11 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.sys.resource.getrlimit
libc.src.sys.resource.setrlimit
+ # sys/sem.h entrypoints
+ libc.src.sys.sem.semget
+ libc.src.sys.sem.semctl
+ libc.src.sys.sem.semop
+
# sys/sendfile entrypoints
libc.src.sys.sendfile.sendfile
@@ -300,6 +315,9 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.sys.statvfs.fstatvfs
libc.src.sys.statvfs.statvfs
+ # sys/time.h entrypoints
+ libc.src.sys.time.utimes
+
# sys/utsname.h entrypoints
libc.src.sys.utsname.uname
@@ -330,6 +348,7 @@ set(TARGET_LIBC_ENTRYPOINTS
# unistd.h entrypoints
libc.src.unistd.access
libc.src.unistd.chdir
+ libc.src.unistd.chown
libc.src.unistd.close
libc.src.unistd.dup
libc.src.unistd.dup2
@@ -350,6 +369,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.unistd.getppid
libc.src.unistd.getsid
libc.src.unistd.gettid
+ libc.src.unistd.getgid
libc.src.unistd.getuid
libc.src.unistd.isatty
libc.src.unistd.link
@@ -374,8 +394,42 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.unistd.write
# wchar.h entrypoints
+ libc.src.wchar.btowc
libc.src.wchar.wcslen
+ libc.src.wchar.wcsnlen
libc.src.wchar.wctob
+ libc.src.wchar.wmemmove
+ libc.src.wchar.wmemset
+ libc.src.wchar.wcschr
+ libc.src.wchar.wcsncmp
+ libc.src.wchar.wcsxfrm
+ libc.src.wchar.wcscmp
+ libc.src.wchar.wcspbrk
+ libc.src.wchar.wcsrchr
+ libc.src.wchar.wcsspn
+ libc.src.wchar.wcscspn
+ libc.src.wchar.wcsdup
+ libc.src.wchar.wmemcmp
+ libc.src.wchar.wmempcpy
+ libc.src.wchar.wmemcpy
+ libc.src.wchar.wcsncpy
+ libc.src.wchar.wcscat
+ libc.src.wchar.wcsstr
+ libc.src.wchar.wcsncat
+ libc.src.wchar.wcslcat
+ libc.src.wchar.wcscpy
+ libc.src.wchar.wcslcpy
+ libc.src.wchar.wmemchr
+ libc.src.wchar.wcpcpy
+ libc.src.wchar.wcpncpy
+ libc.src.wchar.wcstod
+ libc.src.wchar.wcstof
+ libc.src.wchar.wcstok
+ libc.src.wchar.wcstol
+ libc.src.wchar.wcstold
+ libc.src.wchar.wcstoll
+ libc.src.wchar.wcstoul
+ libc.src.wchar.wcstoull
# wctype.h entrypoints
libc.src.wctype.iswalpha
@@ -473,16 +527,17 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.cosf
libc.src.math.coshf
libc.src.math.cospif
- libc.src.math.daddl
- libc.src.math.ddivl
libc.src.math.dfmal
libc.src.math.dmull
libc.src.math.dsqrtl
+ libc.src.math.daddl
+ libc.src.math.ddivl
libc.src.math.dsubl
libc.src.math.erff
libc.src.math.exp
libc.src.math.exp10
libc.src.math.exp10f
+ libc.src.math.exp10m1f
libc.src.math.exp2
libc.src.math.exp2f
libc.src.math.exp2m1f
@@ -498,6 +553,10 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.fdim
libc.src.math.fdimf
libc.src.math.fdiml
+ libc.src.math.fdiv
+ libc.src.math.fdivl
+ libc.src.math.ffma
+ libc.src.math.ffmal
libc.src.math.floor
libc.src.math.floorf
libc.src.math.floorl
@@ -691,40 +750,50 @@ endif()
if(LIBC_TYPES_HAS_FLOAT16)
list(APPEND TARGET_LIBM_ENTRYPOINTS
# math.h C23 _Float16 entrypoints
+ libc.src.math.acosf16
libc.src.math.acoshf16
+ libc.src.math.acospif16
+ libc.src.math.asinf16
+ libc.src.math.asinhf16
libc.src.math.asinpif16
+ libc.src.math.atanf16
libc.src.math.atan2f16
+ libc.src.math.atanhf16
+ libc.src.math.atanpif16
libc.src.math.canonicalizef16
libc.src.math.ceilf16
libc.src.math.copysignf16
+ libc.src.math.cosf16
+ libc.src.math.coshf16
libc.src.math.cospif16
libc.src.math.erff16
libc.src.math.erfcf16
+ libc.src.math.exp10f16
+ libc.src.math.exp10m1f16
+ libc.src.math.exp2f16
+ libc.src.math.exp2m1f16
libc.src.math.expf16
+ libc.src.math.expm1f16
libc.src.math.f16add
libc.src.math.f16addf
- # libc.src.math.f16addl
+ libc.src.math.f16addl
libc.src.math.f16div
libc.src.math.f16divf
- # libc.src.math.f16divl
+ libc.src.math.f16divl
libc.src.math.f16fma
libc.src.math.f16fmaf
- # libc.src.math.f16fmal
+ libc.src.math.f16fmal
libc.src.math.f16mul
libc.src.math.f16mulf
- # libc.src.math.f16mull
+ libc.src.math.f16mull
libc.src.math.f16sqrt
libc.src.math.f16sqrtf
- # libc.src.math.f16sqrtl
+ libc.src.math.f16sqrtl
libc.src.math.f16sub
libc.src.math.f16subf
- # libc.src.math.f16subl
+ libc.src.math.f16subl
libc.src.math.fabsf16
libc.src.math.fdimf16
- libc.src.math.fdiv
- libc.src.math.fdivl
- libc.src.math.ffma
- libc.src.math.ffmal
libc.src.math.floorf16
libc.src.math.fmaf16
libc.src.math.fmaxf16
@@ -737,11 +806,12 @@ if(LIBC_TYPES_HAS_FLOAT16)
libc.src.math.fminimum_magf16
libc.src.math.fminimum_numf16
libc.src.math.fminimumf16
- # libc.src.math.fmodf16
+ libc.src.math.fmodf16
libc.src.math.frexpf16
libc.src.math.fromfpf16
libc.src.math.fromfpxf16
libc.src.math.getpayloadf16
+ libc.src.math.hypotf16
libc.src.math.ilogbf16
libc.src.math.iscanonicalf16
libc.src.math.issignalingf16
@@ -749,20 +819,20 @@ if(LIBC_TYPES_HAS_FLOAT16)
libc.src.math.llogbf16
libc.src.math.llrintf16
libc.src.math.llroundf16
+ libc.src.math.log10f16
libc.src.math.log10p1f16
+ libc.src.math.log2f16
libc.src.math.log2p1f16
libc.src.math.logbf16
+ libc.src.math.logf16
libc.src.math.lrintf16
libc.src.math.lroundf16
- # libc.src.math.modff16
+ libc.src.math.modff16
libc.src.math.nanf16
libc.src.math.nearbyintf16
libc.src.math.nextafterf16
libc.src.math.nextdownf16
- # Temporarily disable nexttowardf16 on aarch64 because the conversion
- # between _Float16 and long double will crash clang-11. This is fixed in
- # clang-12 and after: https://godbolt.org/z/8ceT9454c
- # libc.src.math.nexttowardf16
+ libc.src.math.nexttowardf16
libc.src.math.nextupf16
libc.src.math.remainderf16
libc.src.math.remquof16
@@ -775,8 +845,13 @@ if(LIBC_TYPES_HAS_FLOAT16)
libc.src.math.scalbnf16
libc.src.math.setpayloadf16
libc.src.math.setpayloadsigf16
+ libc.src.math.sinf16
+ libc.src.math.sinhf16
libc.src.math.sinpif16
libc.src.math.sqrtf16
+ libc.src.math.tanf16
+ libc.src.math.tanhf16
+ libc.src.math.tanpif16
libc.src.math.totalorderf16
libc.src.math.totalordermagf16
libc.src.math.truncf16
@@ -784,17 +859,17 @@ if(LIBC_TYPES_HAS_FLOAT16)
libc.src.math.ufromfpxf16
)
- # if(LIBC_TYPES_HAS_FLOAT128)
- # list(APPEND TARGET_LIBM_ENTRYPOINTS
- # # math.h C23 mixed _Float16 and _Float128 entrypoints
- # libc.src.math.f16addf128
- # libc.src.math.f16divf128
- # libc.src.math.f16fmaf128
- # libc.src.math.f16mulf128
- # libc.src.math.f16sqrtf128
- # libc.src.math.f16subf128
- # )
- # endif()
+ if(LIBC_TYPES_HAS_FLOAT128)
+ list(APPEND TARGET_LIBM_ENTRYPOINTS
+ # math.h C23 mixed _Float16 and _Float128 entrypoints
+ libc.src.math.f16addf128
+ libc.src.math.f16divf128
+ libc.src.math.f16fmaf128
+ libc.src.math.f16mulf128
+ libc.src.math.f16sqrtf128
+ libc.src.math.f16subf128
+ )
+ endif()
endif()
if(LIBC_TYPES_HAS_CFLOAT128)
@@ -811,6 +886,7 @@ if(LIBC_TYPES_HAS_FLOAT128)
list(APPEND TARGET_LIBM_ENTRYPOINTS
# math.h C23 _Float128 entrypoints
libc.src.math.atan2f128
+ libc.src.math.atan2l
libc.src.math.canonicalizef128
libc.src.math.ceilf128
libc.src.math.copysignf128
@@ -965,8 +1041,120 @@ if(LIBC_TYPES_HAS_FLOAT128)
)
endif()
+if(LIBC_COMPILER_HAS_FIXED_POINT)
+ list(APPEND TARGET_LIBM_ENTRYPOINTS
+ # stdfix.h _Fract and _Accum entrypoints
+ libc.src.stdfix.abshk
+ libc.src.stdfix.abshr
+ libc.src.stdfix.absk
+ libc.src.stdfix.abslk
+ libc.src.stdfix.abslr
+ libc.src.stdfix.absr
+ libc.src.stdfix.exphk
+ libc.src.stdfix.expk
+ libc.src.stdfix.roundhk
+ libc.src.stdfix.roundhr
+ libc.src.stdfix.roundk
+ libc.src.stdfix.roundlk
+ libc.src.stdfix.roundlr
+ libc.src.stdfix.roundr
+ libc.src.stdfix.rounduhk
+ libc.src.stdfix.rounduhr
+ libc.src.stdfix.rounduk
+ libc.src.stdfix.roundulk
+ libc.src.stdfix.roundulr
+ libc.src.stdfix.roundur
+ libc.src.stdfix.sqrtuhk
+ libc.src.stdfix.sqrtuhr
+ libc.src.stdfix.sqrtuk
+ libc.src.stdfix.sqrtur
+ # libc.src.stdfix.sqrtulk
+ libc.src.stdfix.sqrtulr
+ libc.src.stdfix.uhksqrtus
+ libc.src.stdfix.uksqrtui
+ libc.src.stdfix.hrbits
+ libc.src.stdfix.uhrbits
+ libc.src.stdfix.rbits
+ libc.src.stdfix.urbits
+ libc.src.stdfix.lrbits
+ libc.src.stdfix.ulrbits
+ libc.src.stdfix.hkbits
+ libc.src.stdfix.uhkbits
+ libc.src.stdfix.kbits
+ libc.src.stdfix.ukbits
+ libc.src.stdfix.lkbits
+ libc.src.stdfix.ulkbits
+ libc.src.stdfix.bitshr
+ libc.src.stdfix.bitsr
+ libc.src.stdfix.bitslr
+ libc.src.stdfix.bitshk
+ libc.src.stdfix.bitsk
+ libc.src.stdfix.bitslk
+ libc.src.stdfix.bitsuhr
+ libc.src.stdfix.bitsur
+ libc.src.stdfix.bitsulr
+ libc.src.stdfix.bitsuhk
+ libc.src.stdfix.bitsuk
+ libc.src.stdfix.bitsulk
+ libc.src.stdfix.countlshr
+ libc.src.stdfix.countlsr
+ libc.src.stdfix.countlslr
+ libc.src.stdfix.countlshk
+ libc.src.stdfix.countlsk
+ libc.src.stdfix.countlslk
+ libc.src.stdfix.countlsuhr
+ libc.src.stdfix.countlsur
+ libc.src.stdfix.countlsulr
+ libc.src.stdfix.countlsuhk
+ libc.src.stdfix.countlsuk
+ libc.src.stdfix.countlsulk
+ libc.src.stdfix.idivr
+ libc.src.stdfix.idivlr
+ libc.src.stdfix.idivk
+ libc.src.stdfix.idivlk
+ libc.src.stdfix.idivur
+ libc.src.stdfix.idivulr
+ libc.src.stdfix.idivuk
+ libc.src.stdfix.idivulk
+ libc.src.stdfix.rdivi
+ )
+endif()
+
if(LLVM_LIBC_FULL_BUILD)
list(APPEND TARGET_LIBC_ENTRYPOINTS
+ # ctype.h entrypoints
+ libc.src.ctype.isalnum_l
+ libc.src.ctype.isalpha_l
+ libc.src.ctype.isblank_l
+ libc.src.ctype.iscntrl_l
+ libc.src.ctype.isdigit_l
+ libc.src.ctype.isgraph_l
+ libc.src.ctype.islower_l
+ libc.src.ctype.isprint_l
+ libc.src.ctype.ispunct_l
+ libc.src.ctype.isspace_l
+ libc.src.ctype.isupper_l
+ libc.src.ctype.isxdigit_l
+ libc.src.ctype.tolower_l
+ libc.src.ctype.toupper_l
+
+ # stdlib.h entrypoints
+ libc.src.stdlib.strtod_l
+ libc.src.stdlib.strtof_l
+ libc.src.stdlib.strtol_l
+ libc.src.stdlib.strtold_l
+ libc.src.stdlib.strtoll_l
+ libc.src.stdlib.strtoul_l
+ libc.src.stdlib.strtoull_l
+
+ # string.h entrypoints
+ libc.src.string.strcoll_l
+ libc.src.string.strxfrm_l
+
+ # strings.h entrypoints
+ libc.src.strings.strcasecmp_l
+ libc.src.strings.strncasecmp_l
+
# assert.h entrypoints
libc.src.assert.__assert_fail
@@ -1021,6 +1209,9 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.pthread.pthread_join
libc.src.pthread.pthread_key_create
libc.src.pthread.pthread_key_delete
+ libc.src.pthread.pthread_barrier_init
+ libc.src.pthread.pthread_barrier_wait
+ libc.src.pthread.pthread_barrier_destroy
libc.src.pthread.pthread_mutex_destroy
libc.src.pthread.pthread_mutex_init
libc.src.pthread.pthread_mutex_lock
@@ -1067,16 +1258,16 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.sched.__sched_setcpuset
libc.src.sched.__sched_getcpuisset
- # strings.h entrypoints
- libc.src.strings.strcasecmp_l
- libc.src.strings.strncasecmp_l
-
# setjmp.h entrypoints
libc.src.setjmp.longjmp
libc.src.setjmp.setjmp
libc.src.setjmp.siglongjmp
libc.src.setjmp.sigsetjmp
+ # ucontext.h entrypoints
+ libc.src.ucontext.getcontext
+ libc.src.ucontext.setcontext
+
# stdio.h entrypoints
libc.src.stdio.clearerr
libc.src.stdio.clearerr_unlocked
@@ -1128,7 +1319,11 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.stdlib.atexit
libc.src.stdlib.exit
libc.src.stdlib.getenv
+ libc.src.stdlib.mbstowcs
+ libc.src.stdlib.mbtowc
libc.src.stdlib.quick_exit
+ libc.src.stdlib.wcstombs
+ libc.src.stdlib.wctomb
# signal.h entrypoints
libc.src.signal.kill
@@ -1202,11 +1397,24 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.time.gettimeofday
libc.src.time.gmtime
libc.src.time.gmtime_r
+ libc.src.time.localtime
+ libc.src.time.localtime_r
libc.src.time.mktime
libc.src.time.nanosleep
+ libc.src.time.strftime
+ libc.src.time.strftime_l
libc.src.time.time
libc.src.time.timespec_get
+ # locale.h entrypoints
+ libc.src.locale.localeconv
+ libc.src.locale.duplocale
+ libc.src.locale.freelocale
+ libc.src.locale.localeconv
+ libc.src.locale.newlocale
+ libc.src.locale.setlocale
+ libc.src.locale.uselocale
+
# unistd.h entrypoints
libc.src.unistd.__llvm_libc_syscall
libc.src.unistd._exit
@@ -1226,20 +1434,43 @@ if(LLVM_LIBC_FULL_BUILD)
# sys/socket.h entrypoints
libc.src.sys.socket.accept
libc.src.sys.socket.accept4
+ libc.src.sys.socket.socket
libc.src.sys.socket.bind
libc.src.sys.socket.connect
libc.src.sys.socket.getsockopt
libc.src.sys.socket.listen
- libc.src.sys.socket.setsockopt
libc.src.sys.socket.shutdown
- libc.src.sys.socket.socket
+ libc.src.sys.socket.socketpair
+ libc.src.sys.socket.setsockopt
+ libc.src.sys.socket.send
+ libc.src.sys.socket.sendto
+ libc.src.sys.socket.sendmsg
+ libc.src.sys.socket.recv
+ libc.src.sys.socket.recvfrom
+ libc.src.sys.socket.recvmsg
+
+ # wchar.h entrypoints
+ libc.src.wchar.mblen
+ libc.src.wchar.mbrlen
+ libc.src.wchar.mbsinit
+ libc.src.wchar.mbrtowc
+ libc.src.wchar.mbsrtowcs
+ libc.src.wchar.mbsnrtowcs
+ libc.src.wchar.wcrtomb
+ libc.src.wchar.wcsrtombs
+ libc.src.wchar.wcsnrtombs
+
+ # nl_types.h entrypoints
+ libc.src.nl_types.catopen
+ libc.src.nl_types.catclose
+ libc.src.nl_types.catgets
)
endif()
set(TARGET_LIBMVEC_ENTRYPOINTS)
if(LIBC_COMPILER_HAS_EXT_VECTOR_TYPE)
- list(APPEND TARGET_LIBMVEC_ENTRYPOINTS
+list(APPEND TARGET_LIBMVEC_ENTRYPOINTS
libc.src.mathvec.expf
)
endif()
>From a27186e76f364e75988e00da478d2d1359b14ecb Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 21:55:19 -0400
Subject: [PATCH 13/16] update
---
libc/config/linux/aarch64/entrypoints.txt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index cc2e74240dbe5..27d948aa89536 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1265,8 +1265,8 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.setjmp.sigsetjmp
# ucontext.h entrypoints
- libc.src.ucontext.getcontext
- libc.src.ucontext.setcontext
+ #libc.src.ucontext.getcontext
+ #libc.src.ucontext.setcontext
# stdio.h entrypoints
libc.src.stdio.clearerr
>From 6d04f1f416a353646c95e810c518114f0c1b2dc5 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 22:00:57 -0400
Subject: [PATCH 14/16] update
---
libc/config/linux/aarch64/headers.txt | 3 +++
1 file changed, 3 insertions(+)
diff --git a/libc/config/linux/aarch64/headers.txt b/libc/config/linux/aarch64/headers.txt
index 4784fc5d29ddc..0e5d5c753aed1 100644
--- a/libc/config/linux/aarch64/headers.txt
+++ b/libc/config/linux/aarch64/headers.txt
@@ -20,6 +20,7 @@ set(TARGET_PUBLIC_HEADERS
libc.include.malloc
libc.include.math
libc.include.netinet_in
+ libc.include.nl_types
libc.include.poll
libc.include.pthread
libc.include.sched
@@ -38,12 +39,14 @@ set(TARGET_PUBLIC_HEADERS
libc.include.sys_auxv
libc.include.sys_epoll
libc.include.sys_ioctl
+ libc.include.sys_ipc
libc.include.sys_mman
libc.include.sys_prctl
libc.include.sys_queue
libc.include.sys_random
libc.include.sys_resource
libc.include.sys_select
+ libc.include.sys_sem
libc.include.sys_socket
libc.include.sys_stat
libc.include.sys_statvfs
>From 14533f2114d1c3d6ee3fc8c123061ce97f4306d7 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 22:13:51 -0400
Subject: [PATCH 15/16] update
---
run.sh | 44 +++++++++++++++++++++++++++++++++++++++++---
1 file changed, 41 insertions(+), 3 deletions(-)
diff --git a/run.sh b/run.sh
index ba3a44812353a..764d1a1bc976b 100755
--- a/run.sh
+++ b/run.sh
@@ -7,6 +7,9 @@ base_c_compiler="${CC:-/usr/bin/clang}"
base_compiler="${CXX:-/usr/bin/clang++}"
lit_jobs="${LIT_JOBS:-4}"
host_arch="$(uname -m)"
+multiarch_triple=""
+configure_c_flags="${CFLAGS:-}"
+configure_cxx_flags="${CXXFLAGS:-}"
case "$host_arch" in
x86_64)
@@ -22,6 +25,22 @@ esac
cd "$repo"
+for candidate in \
+ "$("$base_c_compiler" -print-multiarch 2>/dev/null || true)" \
+ "$("$base_compiler" -print-multiarch 2>/dev/null || true)" \
+ "$("$base_c_compiler" -dumpmachine 2>/dev/null || true)" \
+ "$("$base_compiler" -dumpmachine 2>/dev/null || true)"; do
+ if [[ -n "$candidate" && -d "/usr/include/$candidate" ]]; then
+ multiarch_triple="$candidate"
+ break
+ fi
+done
+
+if [[ -n "$multiarch_triple" ]]; then
+ configure_c_flags="${configure_c_flags:+$configure_c_flags }-idirafter/usr/include/$multiarch_triple"
+ configure_cxx_flags="${configure_cxx_flags:+$configure_cxx_flags }-idirafter/usr/include/$multiarch_triple"
+fi
+
if [[ ! -f "$build/CMakeCache.txt" ]]; then
mkdir -p "$build"
cmake \
@@ -31,6 +50,8 @@ if [[ ! -f "$build/CMakeCache.txt" ]]; then
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER="$base_c_compiler" \
-DCMAKE_CXX_COMPILER="$base_compiler" \
+ -DCMAKE_C_FLAGS="$configure_c_flags" \
+ -DCMAKE_CXX_FLAGS="$configure_cxx_flags" \
-DCMAKE_C_COMPILER_LAUNCHER= \
-DCMAKE_CXX_COMPILER_LAUNCHER= \
-DLIBUNWIND_ENABLE_SHARED=OFF \
@@ -76,6 +97,7 @@ lit_wrapper="$root/llvm-lit-fork"
empty_include="$root/empty-usr-local-include"
fortify_shim_c="$root/fortify-shim.c"
fortify_shim_o="$root/fortify-shim.o"
+multiarch_include_dir=""
cleanup() {
rm -rf "$root"
@@ -120,9 +142,21 @@ fi
mkdir -p "$sysroot/usr/include" "$empty_include"
# Preserve Linux UAPI headers, but do not copy libc++ into /usr/include.
-cp -a /usr/include/linux "$sysroot/usr/include/"
-cp -a /usr/include/asm "$sysroot/usr/include/"
-cp -a /usr/include/asm-generic "$sysroot/usr/include/"
+if [[ -d /usr/include/linux ]]; then
+ cp -a /usr/include/linux "$sysroot/usr/include/"
+fi
+if [[ -d /usr/include/asm-generic ]]; then
+ cp -a /usr/include/asm-generic "$sysroot/usr/include/"
+fi
+if [[ -n "$multiarch_triple" ]]; then
+ multiarch_include_dir="$sysroot/usr/include/$multiarch_triple"
+ mkdir -p "$multiarch_include_dir"
+fi
+if [[ -d /usr/include/asm ]]; then
+ cp -a /usr/include/asm "${multiarch_include_dir:-$sysroot/usr/include}/"
+elif [[ -n "$multiarch_triple" && -d "/usr/include/$multiarch_triple/asm" ]]; then
+ cp -a "/usr/include/$multiarch_triple/asm" "$multiarch_include_dir/"
+fi
cp -a "$build/libc/include/." "$sysroot/usr/include/"
crtbegin="$("$base_compiler" --print-file-name=crtbeginT.o)"
@@ -205,6 +239,7 @@ crtbegin=$crtbegin
crtend=$crtend
builtins=$builtins
fortify_shim_o=$fortify_shim_o
+multiarch_include_dir=$multiarch_include_dir
linking=1
for arg in "\$@"; do
@@ -221,6 +256,9 @@ common_args=(
-fno-stack-protector
-Wno-missing-braces
)
+if [[ -n "\$multiarch_include_dir" ]]; then
+ common_args+=(-isystem "\$multiarch_include_dir")
+fi
if (( linking )); then
exec "\$base_compiler" \
>From cf28c16c5b30a85cda2a17a524ab211277f3bdbf Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 23:53:53 -0400
Subject: [PATCH 16/16] update
---
run.sh | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/run.sh b/run.sh
index 764d1a1bc976b..846b0c6121747 100755
--- a/run.sh
+++ b/run.sh
@@ -26,6 +26,14 @@ esac
cd "$repo"
for candidate in \
+ "$(
+ case "$host_arch" in
+ x86_64) echo x86_64-linux-gnu ;;
+ aarch64|arm64) echo aarch64-linux-gnu ;;
+ riscv64) echo riscv64-linux-gnu ;;
+ *) ;;
+ esac
+ )" \
"$("$base_c_compiler" -print-multiarch 2>/dev/null || true)" \
"$("$base_compiler" -print-multiarch 2>/dev/null || true)" \
"$("$base_c_compiler" -dumpmachine 2>/dev/null || true)" \
@@ -36,6 +44,10 @@ for candidate in \
fi
done
+if [[ -z "$multiarch_triple" ]]; then
+ multiarch_triple="$(find /usr/include -mindepth 1 -maxdepth 1 -type d -name '*-linux-gnu' -exec test -d '{}/asm' ';' -print -quit | xargs -r basename)"
+fi
+
if [[ -n "$multiarch_triple" ]]; then
configure_c_flags="${configure_c_flags:+$configure_c_flags }-idirafter/usr/include/$multiarch_triple"
configure_cxx_flags="${configure_cxx_flags:+$configure_cxx_flags }-idirafter/usr/include/$multiarch_triple"
@@ -98,6 +110,7 @@ empty_include="$root/empty-usr-local-include"
fortify_shim_c="$root/fortify-shim.c"
fortify_shim_o="$root/fortify-shim.o"
multiarch_include_dir=""
+asm_source_dir=""
cleanup() {
rm -rf "$root"
@@ -152,10 +165,14 @@ if [[ -n "$multiarch_triple" ]]; then
multiarch_include_dir="$sysroot/usr/include/$multiarch_triple"
mkdir -p "$multiarch_include_dir"
fi
-if [[ -d /usr/include/asm ]]; then
- cp -a /usr/include/asm "${multiarch_include_dir:-$sysroot/usr/include}/"
-elif [[ -n "$multiarch_triple" && -d "/usr/include/$multiarch_triple/asm" ]]; then
- cp -a "/usr/include/$multiarch_triple/asm" "$multiarch_include_dir/"
+if [[ -n "$multiarch_triple" && -d "/usr/include/$multiarch_triple/asm" ]]; then
+ asm_source_dir="$(readlink -f "/usr/include/$multiarch_triple/asm")"
+elif [[ -d /usr/include/asm ]]; then
+ asm_source_dir="$(readlink -f /usr/include/asm)"
+fi
+if [[ -n "$asm_source_dir" ]]; then
+ mkdir -p "${multiarch_include_dir:-$sysroot/usr/include}/asm"
+ cp -a "$asm_source_dir/." "${multiarch_include_dir:-$sysroot/usr/include}/asm/"
fi
cp -a "$build/libc/include/." "$sysroot/usr/include/"
More information about the libc-commits
mailing list