[libcxx-commits] [libc] [libcxx] [libunwind] [WIP] Enough to get `libc` to build `clang` on `aarch64` (PR #97231)

Izaak Schroeder via libcxx-commits libcxx-commits at lists.llvm.org
Tue Jul 2 14:30:52 PDT 2024


https://github.com/izaakschroeder updated https://github.com/llvm/llvm-project/pull/97231

>From 31dc769c1866a4a0100dde0a3743c215a9a5f5eb Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Sun, 30 Jun 2024 13:33:16 -0700
Subject: [PATCH 01/40] [libc]: add missing aarch64 headers

---
 libc/config/linux/aarch64/entrypoints.txt | 3 +++
 libc/config/linux/aarch64/headers.txt     | 6 ++++++
 2 files changed, 9 insertions(+)

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 8a26536cea9a0..b59400db81fed 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -308,6 +308,9 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.unistd.unlink
     libc.src.unistd.unlinkat
     libc.src.unistd.write
+
+    # XXX
+    libc.src.assert.__assert_fail
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/config/linux/aarch64/headers.txt b/libc/config/linux/aarch64/headers.txt
index 7d25877cefcc8..ed126d6128871 100644
--- a/libc/config/linux/aarch64/headers.txt
+++ b/libc/config/linux/aarch64/headers.txt
@@ -31,4 +31,10 @@ set(TARGET_PUBLIC_HEADERS
     libc.include.sys_ioctl
     # Disabled due to epoll_wait syscalls not being available on this platform.
     # libc.include.sys_epoll
+
+    # XXX
+    libc.include.sys_auxv
+    libc.include.fcntl
+    libc.include.sched
+    libc.include.sys_stat
 )

>From a5f8ee220c088a39d9b4bf60986166e83ffafffa Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Sun, 30 Jun 2024 13:33:38 -0700
Subject: [PATCH 02/40] [libunwind]: remove needless `sys/uio.h`

No reference to `readv` or `writev`.
---
 libunwind/src/UnwindCursor.hpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 66fe8e2a32cca..677e842d8a22b 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -36,7 +36,6 @@
 #include <errno.h>
 #include <signal.h>
 #include <sys/syscall.h>
-#include <sys/uio.h>
 #include <unistd.h>
 #define _LIBUNWIND_CHECK_LINUX_SIGRETURN 1
 #endif

>From 1083aecfe1be3c1cf427d4ffd2b4fad3d5129d4c Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Sun, 30 Jun 2024 13:44:52 -0700
Subject: [PATCH 03/40] [libc]: function spec for `getauxval`

---
 libc/spec/gnu_ext.td | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/libc/spec/gnu_ext.td b/libc/spec/gnu_ext.td
index 161bb4e4a0d9d..e360c766c5c54 100644
--- a/libc/spec/gnu_ext.td
+++ b/libc/spec/gnu_ext.td
@@ -237,7 +237,11 @@ def GnuExtensions : StandardSpec<"GNUExtensions"> {
       [], // Types
       [], // Enumerations
       [
-        //TODO: Add getauxval here
+          FunctionSpec<
+              "getauxval",
+              RetValSpec<UnsignedLongType>,
+              [ArgSpec<UnsignedLongType>]
+          >,
       ]  // Functions
   >;
 

>From e9628ce037c225c3769cec2589745f7978e7edc4 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Sun, 30 Jun 2024 14:06:19 -0700
Subject: [PATCH 04/40] [libc]: hack `ExitCallbackList` always public

---
 libc/src/stdlib/exit_handler.h | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/libc/src/stdlib/exit_handler.h b/libc/src/stdlib/exit_handler.h
index 8494c2f2e526e..db731a46f44c9 100644
--- a/libc/src/stdlib/exit_handler.h
+++ b/libc/src/stdlib/exit_handler.h
@@ -31,10 +31,8 @@ struct AtExitUnit {
 
 #if defined(LIBC_TARGET_ARCH_IS_GPU)
 using ExitCallbackList = FixedVector<AtExitUnit, 64>;
-#elif defined(LIBC_COPT_PUBLIC_PACKAGING)
-using ExitCallbackList = ReverseOrderBlockStore<AtExitUnit, 32>;
 #else
-using ExitCallbackList = FixedVector<AtExitUnit, CALLBACK_LIST_SIZE_FOR_TESTS>;
+using ExitCallbackList = ReverseOrderBlockStore<AtExitUnit, 32>;
 #endif
 
 extern ExitCallbackList atexit_callbacks;

>From e3ed9aac99ede8be5d6d228f43c652423206e67c Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Sun, 30 Jun 2024 14:15:21 -0700
Subject: [PATCH 05/40] [libc]: add `Scrt1.o`

---
 libc/startup/linux/CMakeLists.txt | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/libc/startup/linux/CMakeLists.txt b/libc/startup/linux/CMakeLists.txt
index 336c5d0f6bfa2..b721d15091227 100644
--- a/libc/startup/linux/CMakeLists.txt
+++ b/libc/startup/linux/CMakeLists.txt
@@ -118,6 +118,15 @@ merge_relocatable_object(
   .do_start
 )
 
+# HACK: Is this even ok?
+# For reference: `Scrt1` is used when `-fpie` vs `crt1` for `-fno-pie`
+merge_relocatable_object(
+  Scrt1
+  .${LIBC_TARGET_ARCHITECTURE}.start
+  .${LIBC_TARGET_ARCHITECTURE}.tls
+  .do_start
+)
+
 add_startup_object(
   crti
   SRC
@@ -131,7 +140,7 @@ add_startup_object(
 )
 
 add_custom_target(libc-startup)
-set(startup_components crt1 crti crtn)
+set(startup_components Scrt1 crt1 crti crtn)
 foreach(target IN LISTS startup_components)
   set(fq_target_name libc.startup.linux.${target})
   add_dependencies(libc-startup ${fq_target_name})

>From 1f98bd663772b963c192293ad7359fe0ffdada25 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Mon, 1 Jul 2024 12:07:37 -0700
Subject: [PATCH 06/40] [libc]: `sys_time.utimes` placeholder

---
 libc/config/linux/aarch64/entrypoints.txt |  1 +
 libc/config/linux/x86_64/entrypoints.txt  |  3 +++
 libc/spec/linux.td                        | 12 +++++++++++-
 libc/spec/spec.td                         |  1 +
 libc/src/sys/CMakeLists.txt               |  1 +
 libc/src/sys/time/CMakeLists.txt          | 10 ++++++++++
 libc/src/sys/time/linux/CMakeLists.txt    | 12 ++++++++++++
 libc/src/sys/time/linux/utimes.cpp        | 12 ++++++++++++
 libc/src/sys/time/utimes.h                | 18 ++++++++++++++++++
 9 files changed, 69 insertions(+), 1 deletion(-)
 create mode 100644 libc/src/sys/time/CMakeLists.txt
 create mode 100644 libc/src/sys/time/linux/CMakeLists.txt
 create mode 100644 libc/src/sys/time/linux/utimes.cpp
 create mode 100644 libc/src/sys/time/utimes.h

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index b59400db81fed..f259f30f8b377 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -311,6 +311,7 @@ set(TARGET_LIBC_ENTRYPOINTS
 
     # XXX
     libc.src.assert.__assert_fail
+    libc.src.sys_time.utimes
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index e1922ca94b97e..05ab170127a9d 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -330,6 +330,9 @@ set(TARGET_LIBC_ENTRYPOINTS
 
     # wchar.h entrypoints
     libc.src.wchar.wctob
+
+    # XXX
+    libc.src.sys_time.utimes
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/spec/linux.td b/libc/spec/linux.td
index 82630ff413c73..faeefd70f2263 100644
--- a/libc/spec/linux.td
+++ b/libc/spec/linux.td
@@ -148,7 +148,17 @@ def Linux : StandardSpec<"Linux"> {
       ],
       [StructTimevalType], // Types
       [], // Enumerations
-      []  // Functions
+      [
+        FunctionSpec<
+          "utimes",
+          RetValSpec<IntType>,
+          [
+            ArgSpec<IntType>,
+            ArgSpec<ConstCharPtr>,
+            ArgSpec<ConstStructTimevalPtr>,
+          ]
+        >,
+      ]  // Functions
   >;
 
 
diff --git a/libc/spec/spec.td b/libc/spec/spec.td
index a3a5db7465b39..17c0589ab1d55 100644
--- a/libc/spec/spec.td
+++ b/libc/spec/spec.td
@@ -148,6 +148,7 @@ def StructRUsagePtr : PtrType<StructRUsage>;
 
 def StructTimevalType : NamedType<"struct timeval">;
 def StructTimevalPtr : PtrType<StructTimevalType>;
+def ConstStructTimevalPtr : ConstType<StructTimevalPtr>;
 def RestrictedStructTimevalPtr : RestrictedPtrType<StructTimevalType>;
 
 def SuSecondsT : NamedType<"suseconds_t">;
diff --git a/libc/src/sys/CMakeLists.txt b/libc/src/sys/CMakeLists.txt
index adc666b94202f..fba5f86d0b08c 100644
--- a/libc/src/sys/CMakeLists.txt
+++ b/libc/src/sys/CMakeLists.txt
@@ -11,3 +11,4 @@ add_subdirectory(statvfs)
 add_subdirectory(utsname)
 add_subdirectory(wait)
 add_subdirectory(prctl)
+add_subdirectory(time)
diff --git a/libc/src/sys/time/CMakeLists.txt b/libc/src/sys/time/CMakeLists.txt
new file mode 100644
index 0000000000000..f599cddaaeeb3
--- /dev/null
+++ b/libc/src/sys/time/CMakeLists.txt
@@ -0,0 +1,10 @@
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+  add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+endif()
+
+add_entrypoint_object(
+  utimes
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.utimes
+)
diff --git a/libc/src/sys/time/linux/CMakeLists.txt b/libc/src/sys/time/linux/CMakeLists.txt
new file mode 100644
index 0000000000000..da5f698e3515c
--- /dev/null
+++ b/libc/src/sys/time/linux/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_entrypoint_object(
+  utimes
+  SRCS
+    utimes.cpp
+  HDRS
+    ../utimes.h
+  DEPENDS
+    libc.include.sys_time
+    libc.include.sys_syscall
+    libc.src.__support.OSUtil.osutil
+    libc.src.errno.errno
+)
diff --git a/libc/src/sys/time/linux/utimes.cpp b/libc/src/sys/time/linux/utimes.cpp
new file mode 100644
index 0000000000000..b3528ab4b48e4
--- /dev/null
+++ b/libc/src/sys/time/linux/utimes.cpp
@@ -0,0 +1,12 @@
+#include "src/sys/time/utimes.h"
+
+#include "src/__support/common.h"
+#include "src/errno/libc_errno.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(int, utimes, (int, const char *, const struct timeval[2])) {
+  return EINVAL;
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/sys/time/utimes.h b/libc/src/sys/time/utimes.h
new file mode 100644
index 0000000000000..eb2bcc3f15f25
--- /dev/null
+++ b/libc/src/sys/time/utimes.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for socket ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SYS_TIME_UTIMES_H
+#define LLVM_LIBC_SRC_SYS_TIME_UTIMES_H
+
+namespace LIBC_NAMESPACE {
+
+int utimes(int dirfd, const char *pathname, const struct timeval times[2]);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_SYS_TIME_UTIMES_H

>From 346f42492df209476f42f5a4fd84a8d508bbf1cc Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Mon, 1 Jul 2024 13:13:16 -0700
Subject: [PATCH 07/40] [libc]: add missing `<sys/statvfs.h>` and friends

---
 libc/config/linux/aarch64/entrypoints.txt | 2 ++
 libc/config/linux/aarch64/headers.txt     | 1 +
 libc/config/linux/x86_64/headers.txt      | 3 +++
 libc/spec/posix.td                        | 5 ++++-
 4 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index f259f30f8b377..e2a8a8de378b1 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -312,6 +312,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     # XXX
     libc.src.assert.__assert_fail
     libc.src.sys_time.utimes
+    libc.src.sys.statvfs.fstatvfs
+    libc.src.sys.statvfs.statvfs
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/config/linux/aarch64/headers.txt b/libc/config/linux/aarch64/headers.txt
index ed126d6128871..b310da522a50c 100644
--- a/libc/config/linux/aarch64/headers.txt
+++ b/libc/config/linux/aarch64/headers.txt
@@ -34,6 +34,7 @@ set(TARGET_PUBLIC_HEADERS
 
     # XXX
     libc.include.sys_auxv
+    libc.include.sys_statvfs
     libc.include.fcntl
     libc.include.sched
     libc.include.sys_stat
diff --git a/libc/config/linux/x86_64/headers.txt b/libc/config/linux/x86_64/headers.txt
index 44d640b75e2bf..7e9d26c4821fc 100644
--- a/libc/config/linux/x86_64/headers.txt
+++ b/libc/config/linux/x86_64/headers.txt
@@ -49,4 +49,7 @@ set(TARGET_PUBLIC_HEADERS
     libc.include.sys_types
     libc.include.sys_utsname
     libc.include.sys_wait
+
+    # XXX
+    libc.include.sys_statvfs
 )
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index d14047548e104..4220842b71954 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -135,6 +135,9 @@ def POSIX : StandardSpec<"POSIX"> {
   PtrType PThreadTPtr = PtrType<PThreadTType>;
   RestrictedPtrType RestrictedPThreadTPtr = RestrictedPtrType<PThreadTType>;
 
+  NamedType FsFilCntTType = NamedType<"fsfilcnt_t">;
+  NamedType FsBlkCntTType = NamedType<"fsblkcnt_t">;
+
   HeaderSpec Errno = HeaderSpec<
       "errno.h",
       [
@@ -928,7 +931,7 @@ def POSIX : StandardSpec<"POSIX"> {
   HeaderSpec SysStatvfs = HeaderSpec<
       "sys/statvfs.h",
       [], // Macros
-      [StructStatvfs], // Types
+      [StructStatvfs, FsFilCntTType, FsBlkCntTType], // Types
       [], // Enumerations
       [
         FunctionSpec<

>From 570638ec0baff5bbcccb6339265321823b9559e0 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Mon, 1 Jul 2024 13:14:21 -0700
Subject: [PATCH 08/40] [libc]: add basic `ioctl` function

---
 libc/config/linux/aarch64/entrypoints.txt |  3 ++-
 libc/config/linux/x86_64/entrypoints.txt  |  3 ++-
 libc/src/sys/CMakeLists.txt               |  1 +
 libc/src/sys/ioctl/CMakeLists.txt         | 10 ++++++++++
 libc/src/sys/ioctl/ioctl.h                | 18 +++++++++++++++++
 libc/src/sys/ioctl/linux/CMakeLists.txt   | 12 ++++++++++++
 libc/src/sys/ioctl/linux/ioctl.cpp        | 24 +++++++++++++++++++++++
 7 files changed, 69 insertions(+), 2 deletions(-)
 create mode 100644 libc/src/sys/ioctl/CMakeLists.txt
 create mode 100644 libc/src/sys/ioctl/ioctl.h
 create mode 100644 libc/src/sys/ioctl/linux/CMakeLists.txt
 create mode 100644 libc/src/sys/ioctl/linux/ioctl.cpp

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index e2a8a8de378b1..f58debcf9f38c 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -311,9 +311,10 @@ set(TARGET_LIBC_ENTRYPOINTS
 
     # XXX
     libc.src.assert.__assert_fail
-    libc.src.sys_time.utimes
+    libc.src.sys.time.utimes
     libc.src.sys.statvfs.fstatvfs
     libc.src.sys.statvfs.statvfs
+    libc.src.sys.ioctl.ioctl
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 05ab170127a9d..ba88ee253230f 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -332,7 +332,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.wchar.wctob
 
     # XXX
-    libc.src.sys_time.utimes
+    libc.src.sys.time.utimes
+    libc.src.sys.ioctl.ioctl
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/src/sys/CMakeLists.txt b/libc/src/sys/CMakeLists.txt
index fba5f86d0b08c..de8677e9cc933 100644
--- a/libc/src/sys/CMakeLists.txt
+++ b/libc/src/sys/CMakeLists.txt
@@ -11,4 +11,5 @@ add_subdirectory(statvfs)
 add_subdirectory(utsname)
 add_subdirectory(wait)
 add_subdirectory(prctl)
+add_subdirectory(ioctl)
 add_subdirectory(time)
diff --git a/libc/src/sys/ioctl/CMakeLists.txt b/libc/src/sys/ioctl/CMakeLists.txt
new file mode 100644
index 0000000000000..099a1b96389fc
--- /dev/null
+++ b/libc/src/sys/ioctl/CMakeLists.txt
@@ -0,0 +1,10 @@
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+  add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+endif()
+
+add_entrypoint_object(
+  ioctl
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.ioctl
+)
diff --git a/libc/src/sys/ioctl/ioctl.h b/libc/src/sys/ioctl/ioctl.h
new file mode 100644
index 0000000000000..1d4789146c40f
--- /dev/null
+++ b/libc/src/sys/ioctl/ioctl.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for socket ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SYS_IOCTL_IOCTL_H
+#define LLVM_LIBC_SRC_SYS_IOCTL_IOCTL_H
+
+namespace LIBC_NAMESPACE {
+
+int ioctl(int fd, int req, ...);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_SYS_IOCTL_IOCTL_H
diff --git a/libc/src/sys/ioctl/linux/CMakeLists.txt b/libc/src/sys/ioctl/linux/CMakeLists.txt
new file mode 100644
index 0000000000000..876f35aaee66c
--- /dev/null
+++ b/libc/src/sys/ioctl/linux/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_entrypoint_object(
+  ioctl
+  SRCS
+    ioctl.cpp
+  HDRS
+    ../ioctl.h
+  DEPENDS
+    libc.include.sys_ioctl
+    libc.include.sys_syscall
+    libc.src.__support.OSUtil.osutil
+    libc.src.errno.errno
+)
diff --git a/libc/src/sys/ioctl/linux/ioctl.cpp b/libc/src/sys/ioctl/linux/ioctl.cpp
new file mode 100644
index 0000000000000..9b455f62d47a1
--- /dev/null
+++ b/libc/src/sys/ioctl/linux/ioctl.cpp
@@ -0,0 +1,24 @@
+#include <stdarg.h>
+#include <sys/syscall.h> // For syscall numbers.
+
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/common.h"
+#include "src/sys/ioctl/ioctl.h"
+
+#include "src/errno/libc_errno.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(int, ioctl, (int fd, int req, ...)) {
+  void *arg;
+  va_list ap;
+  va_start(ap, req);
+  arg = va_arg(ap, void *);
+  va_end(ap);
+  int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_ioctl, fd, req, arg);
+  // FIXME(@izaakschroeder): There is probably more to do here.
+  // See: https://github.com/kraj/musl/blob/kraj/master/src/misc/ioctl.c
+  return ret;
+}
+
+} // namespace LIBC_NAMESPACE

>From 57bd7864d6322bec928050eeb66ef4ba0f33a5e3 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Mon, 1 Jul 2024 16:23:01 -0700
Subject: [PATCH 09/40] [libc]: add `dlfcn.h` placeholder

---
 libc/config/linux/aarch64/entrypoints.txt    |  4 ++
 libc/config/linux/aarch64/headers.txt        |  1 +
 libc/config/linux/x86_64/entrypoints.txt     |  4 ++
 libc/config/linux/x86_64/headers.txt         |  1 +
 libc/include/CMakeLists.txt                  |  9 ++++
 libc/include/dlfcn.h.def                     | 17 ++++++++
 libc/include/llvm-libc-macros/CMakeLists.txt |  6 +++
 libc/include/llvm-libc-macros/dlfcn-macros.h | 23 +++++++++++
 libc/spec/posix.td                           | 35 ++++++++++++++++
 libc/src/CMakeLists.txt                      |  1 +
 libc/src/dlfcn/CMakeLists.txt                | 43 ++++++++++++++++++++
 libc/src/dlfcn/dlclose.cpp                   | 17 ++++++++
 libc/src/dlfcn/dlclose.h                     | 18 ++++++++
 libc/src/dlfcn/dlerror.cpp                   | 19 +++++++++
 libc/src/dlfcn/dlerror.h                     | 18 ++++++++
 libc/src/dlfcn/dlopen.cpp                    | 17 ++++++++
 libc/src/dlfcn/dlopen.h                      | 18 ++++++++
 libc/src/dlfcn/dlsym.cpp                     | 17 ++++++++
 libc/src/dlfcn/dlsym.h                       | 18 ++++++++
 19 files changed, 286 insertions(+)
 create mode 100644 libc/include/dlfcn.h.def
 create mode 100644 libc/include/llvm-libc-macros/dlfcn-macros.h
 create mode 100644 libc/src/dlfcn/CMakeLists.txt
 create mode 100644 libc/src/dlfcn/dlclose.cpp
 create mode 100644 libc/src/dlfcn/dlclose.h
 create mode 100644 libc/src/dlfcn/dlerror.cpp
 create mode 100644 libc/src/dlfcn/dlerror.h
 create mode 100644 libc/src/dlfcn/dlopen.cpp
 create mode 100644 libc/src/dlfcn/dlopen.h
 create mode 100644 libc/src/dlfcn/dlsym.cpp
 create mode 100644 libc/src/dlfcn/dlsym.h

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index f58debcf9f38c..1d7dde40e371e 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -315,6 +315,10 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.sys.statvfs.fstatvfs
     libc.src.sys.statvfs.statvfs
     libc.src.sys.ioctl.ioctl
+    libc.src.dlfcn.dlopen
+    libc.src.dlfcn.dlsym
+    libc.src.dlfcn.dlclose
+    libc.src.dlfcn.dlerror
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/config/linux/aarch64/headers.txt b/libc/config/linux/aarch64/headers.txt
index b310da522a50c..4f47b09b26b77 100644
--- a/libc/config/linux/aarch64/headers.txt
+++ b/libc/config/linux/aarch64/headers.txt
@@ -38,4 +38,5 @@ set(TARGET_PUBLIC_HEADERS
     libc.include.fcntl
     libc.include.sched
     libc.include.sys_stat
+    libc.include.dlfcn
 )
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index ba88ee253230f..e5feb4ebed805 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -334,6 +334,10 @@ set(TARGET_LIBC_ENTRYPOINTS
     # XXX
     libc.src.sys.time.utimes
     libc.src.sys.ioctl.ioctl
+    libc.src.dlfcn.dlopen
+    libc.src.dlfcn.dlsym
+    libc.src.dlfcn.dlclose
+    libc.src.dlfcn.dlerror
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/config/linux/x86_64/headers.txt b/libc/config/linux/x86_64/headers.txt
index 7e9d26c4821fc..16af88b54e4ab 100644
--- a/libc/config/linux/x86_64/headers.txt
+++ b/libc/config/linux/x86_64/headers.txt
@@ -52,4 +52,5 @@ set(TARGET_PUBLIC_HEADERS
 
     # XXX
     libc.include.sys_statvfs
+    libc.include.dlfcn
 )
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 3ab7817d8568b..f8ef35078a8c4 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -51,6 +51,15 @@ add_gen_header(
     .llvm_libc_common_h
 )
 
+add_gen_header(
+  dlfcn
+  DEF_FILE dlfcn.h.def
+  GEN_HDR dlfcn.h
+  DEPENDS
+    .llvm-libc-macros.dlfcn_macros
+    .llvm_libc_common_h
+)
+
 add_gen_header(
   features
   DEF_FILE features.h.def
diff --git a/libc/include/dlfcn.h.def b/libc/include/dlfcn.h.def
new file mode 100644
index 0000000000000..31395871c6b97
--- /dev/null
+++ b/libc/include/dlfcn.h.def
@@ -0,0 +1,17 @@
+//===-- C standard library header dlfcn.h ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_DLFCN_H
+#define LLVM_LIBC_DLFCN_H
+
+#include "__llvm-libc-common.h"
+#include "llvm-libc-macros/dlfcn-macros.h"
+
+%%public_api()
+
+#endif // LLVM_LIBC_DLFCN_H
diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt
index f6af11abd4dd7..5bf573e4e98df 100644
--- a/libc/include/llvm-libc-macros/CMakeLists.txt
+++ b/libc/include/llvm-libc-macros/CMakeLists.txt
@@ -277,3 +277,9 @@ add_macro_header(
   HDR
     stdckdint-macros.h
 )
+
+add_macro_header(
+  dlfcn_macros
+  HDR
+    dlfcn-macros.h
+)
\ No newline at end of file
diff --git a/libc/include/llvm-libc-macros/dlfcn-macros.h b/libc/include/llvm-libc-macros/dlfcn-macros.h
new file mode 100644
index 0000000000000..dcd202b9ab435
--- /dev/null
+++ b/libc/include/llvm-libc-macros/dlfcn-macros.h
@@ -0,0 +1,23 @@
+//===-- Definition of macros from dlfcn.h ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_MACROS_DLFCN_MACROS_H
+#define LLVM_LIBC_MACROS_DLFCN_MACROS_H
+
+#define RTLD_LAZY 0x00001
+#define RTLD_NOW 0x00002
+#define RTLD_GLOBAL 0x00100
+#define RTLD_LOCAL 0
+
+// Non-standard stuff here
+#define RTLD_BINDING_MASK 0x3
+#define RTLD_NOLOAD 0x00004
+#define RTLD_DEEPBIND 0x00008
+#define RTLD_NODELETE 0x01000
+
+#endif // LLVM_LIBC_MACROS_DLFCN_MACROS_H
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index 4220842b71954..ccbe31b698b03 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -225,6 +225,40 @@ def POSIX : StandardSpec<"POSIX"> {
       []  // Functions
   >;
 
+  HeaderSpec DlFcn = HeaderSpec<
+    "dlfcn.h",
+    [
+      Macro<"RTLD_LAZY">,
+      Macro<"RTLD_NOW">,
+      Macro<"RTLD_GLOBAL">,
+      Macro<"RTLD_LOCAL">,
+    ],
+    [],  // Types
+    [], // Enumerations
+    [
+      FunctionSpec<
+          "dlclose",
+          RetValSpec<IntType>,
+          [ArgSpec<VoidPtr>]
+      >,
+      FunctionSpec<
+          "dlerror",
+          RetValSpec<CharPtr>,
+          []
+      >,
+      FunctionSpec<
+          "dlopen",
+          RetValSpec<VoidPtr>,
+          [ArgSpec<ConstCharPtr>, ArgSpec<IntType>]
+      >,
+      FunctionSpec<
+          "dlsym",
+          RetValSpec<VoidPtr>,
+          [ArgSpec<VoidRestrictedPtr>, ArgSpec<ConstCharRestrictedPtr>]
+      >,
+    ]
+  >;
+
   HeaderSpec FCntl = HeaderSpec<
     "fcntl.h",
     [], // Macros
@@ -1693,6 +1727,7 @@ def POSIX : StandardSpec<"POSIX"> {
     ArpaInet,
     CType,
     Dirent,
+    DlFcn,
     Errno,
     FCntl,
     PThread,
diff --git a/libc/src/CMakeLists.txt b/libc/src/CMakeLists.txt
index 09b16be1e2d42..f011fe25226e5 100644
--- a/libc/src/CMakeLists.txt
+++ b/libc/src/CMakeLists.txt
@@ -11,6 +11,7 @@ add_subdirectory(stdio)
 add_subdirectory(stdlib)
 add_subdirectory(string)
 add_subdirectory(wchar)
+add_subdirectory(dlfcn)
 
 if(${LIBC_TARGET_OS} STREQUAL "linux")
   add_subdirectory(dirent)
diff --git a/libc/src/dlfcn/CMakeLists.txt b/libc/src/dlfcn/CMakeLists.txt
new file mode 100644
index 0000000000000..5534f2dfb8853
--- /dev/null
+++ b/libc/src/dlfcn/CMakeLists.txt
@@ -0,0 +1,43 @@
+add_entrypoint_object(
+  dlclose
+  SRCS
+    dlclose.cpp
+  HDRS
+    dlclose.h
+  DEPENDS
+    libc.include.dlfcn
+    libc.src.errno.errno
+)
+
+add_entrypoint_object(
+  dlerror
+  SRCS
+    dlerror.cpp
+  HDRS
+    dlerror.h
+  DEPENDS
+    libc.include.dlfcn
+    libc.src.errno.errno
+)
+
+add_entrypoint_object(
+  dlopen
+  SRCS
+    dlopen.cpp
+  HDRS
+    dlopen.h
+  DEPENDS
+    libc.include.dlfcn
+    libc.src.errno.errno
+)
+
+add_entrypoint_object(
+  dlsym
+  SRCS
+    dlsym.cpp
+  HDRS
+    dlsym.h
+  DEPENDS
+    libc.include.dlfcn
+    libc.src.errno.errno
+)
diff --git a/libc/src/dlfcn/dlclose.cpp b/libc/src/dlfcn/dlclose.cpp
new file mode 100644
index 0000000000000..6dc1892120ddd
--- /dev/null
+++ b/libc/src/dlfcn/dlclose.cpp
@@ -0,0 +1,17 @@
+//===-- Implementation of dlclose -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "dlclose.h"
+
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(int, dlclose, (void *)) { return -1; }
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/dlfcn/dlclose.h b/libc/src/dlfcn/dlclose.h
new file mode 100644
index 0000000000000..27c0207d726e4
--- /dev/null
+++ b/libc/src/dlfcn/dlclose.h
@@ -0,0 +1,18 @@
+//===-- Implementation header of dlclose ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_DLFCN_DLCLOSE_H
+#define LLVM_LIBC_SRC_DLFCN_DLCLOSE_H
+
+namespace LIBC_NAMESPACE {
+
+int dlclose(void *);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_DLFCN_DLCLOSE_H
diff --git a/libc/src/dlfcn/dlerror.cpp b/libc/src/dlfcn/dlerror.cpp
new file mode 100644
index 0000000000000..8c3611d9c639e
--- /dev/null
+++ b/libc/src/dlfcn/dlerror.cpp
@@ -0,0 +1,19 @@
+//===-- Implementation of delerror ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "dlerror.h"
+
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(char *, dlerror, ()) {
+  return const_cast<char *>("unsupported");
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/dlfcn/dlerror.h b/libc/src/dlfcn/dlerror.h
new file mode 100644
index 0000000000000..966496016d3eb
--- /dev/null
+++ b/libc/src/dlfcn/dlerror.h
@@ -0,0 +1,18 @@
+//===-- Implementation header of dlerror ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_DLFCN_DLERROR_H
+#define LLVM_LIBC_SRC_DLFCN_DLERROR_H
+
+namespace LIBC_NAMESPACE {
+
+char *dlerror();
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_DLFCN_DLERROR_H
diff --git a/libc/src/dlfcn/dlopen.cpp b/libc/src/dlfcn/dlopen.cpp
new file mode 100644
index 0000000000000..835d981e19237
--- /dev/null
+++ b/libc/src/dlfcn/dlopen.cpp
@@ -0,0 +1,17 @@
+//===-- Implementation of dlopen -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "dlopen.h"
+
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(void *, dlopen, (const char *, int)) { return nullptr; }
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/dlfcn/dlopen.h b/libc/src/dlfcn/dlopen.h
new file mode 100644
index 0000000000000..4565953efd494
--- /dev/null
+++ b/libc/src/dlfcn/dlopen.h
@@ -0,0 +1,18 @@
+//===-- Implementation header of dlopen -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_DLFCN_DLOPEN_H
+#define LLVM_LIBC_SRC_DLFCN_DLOPEN_H
+
+namespace LIBC_NAMESPACE {
+
+void *dlopen(const char *, int);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_DLFCN_DLOPEN_H
diff --git a/libc/src/dlfcn/dlsym.cpp b/libc/src/dlfcn/dlsym.cpp
new file mode 100644
index 0000000000000..98d678caece90
--- /dev/null
+++ b/libc/src/dlfcn/dlsym.cpp
@@ -0,0 +1,17 @@
+//===-- Implementation of dlsym ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "dlsym.h"
+
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(void *, dlsym, (void *, const char *)) { return nullptr; }
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/dlfcn/dlsym.h b/libc/src/dlfcn/dlsym.h
new file mode 100644
index 0000000000000..8157ac3e3fd4c
--- /dev/null
+++ b/libc/src/dlfcn/dlsym.h
@@ -0,0 +1,18 @@
+//===-- Implementation header of dlsym --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_DLFCN_DLSYM_H
+#define LLVM_LIBC_SRC_DLFCN_DLSYM_H
+
+namespace LIBC_NAMESPACE {
+
+void *dlsym(void *, const char *);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_DLFCN_DLSYM_H

>From 56c789f670e50a82f656e3190a9b0cd45ef99efa Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Mon, 1 Jul 2024 19:40:07 -0700
Subject: [PATCH 10/40] [libc]: add `link.h`

---
 libc/config/linux/aarch64/entrypoints.txt     |  2 ++
 libc/config/linux/aarch64/headers.txt         |  2 ++
 libc/config/linux/api.td                      | 13 ++++++++
 libc/config/linux/x86_64/entrypoints.txt      |  2 ++
 libc/config/linux/x86_64/headers.txt          |  2 ++
 libc/include/CMakeLists.txt                   | 20 +++++++++++++
 libc/include/elf.h.def                        | 14 +++++++++
 libc/include/link.h.def                       | 16 ++++++++++
 libc/include/llvm-libc-macros/CMakeLists.txt  |  8 ++++-
 libc/include/llvm-libc-macros/elf-macros.h    | 18 +++++++++++
 libc/include/llvm-libc-macros/link-macros.h   | 26 ++++++++++++++--
 libc/include/llvm-libc-types/CMakeLists.txt   |  3 ++
 libc/include/llvm-libc-types/Dl_info.h        | 19 ++++++++++++
 .../__dl_iterate_phdr_callback_t.h            | 17 +++++++++++
 .../llvm-libc-types/struct_dl_phdr_info.h     | 26 ++++++++++++++++
 libc/spec/linux.td                            | 30 +++++++++++++++++++
 libc/spec/posix.td                            | 10 ++++++-
 libc/src/CMakeLists.txt                       |  1 +
 libc/src/dlfcn/CMakeLists.txt                 | 11 +++++++
 libc/src/dlfcn/dladdr.cpp                     | 17 +++++++++++
 libc/src/dlfcn/dladdr.h                       | 20 +++++++++++++
 libc/src/link/CMakeLists.txt                  |  9 ++++++
 libc/src/link/dl_iterate_phdr.cpp             | 21 +++++++++++++
 libc/src/link/dl_iterate_phdr.h               | 20 +++++++++++++
 24 files changed, 323 insertions(+), 4 deletions(-)
 create mode 100644 libc/include/elf.h.def
 create mode 100644 libc/include/link.h.def
 create mode 100644 libc/include/llvm-libc-macros/elf-macros.h
 create mode 100644 libc/include/llvm-libc-types/Dl_info.h
 create mode 100644 libc/include/llvm-libc-types/__dl_iterate_phdr_callback_t.h
 create mode 100644 libc/include/llvm-libc-types/struct_dl_phdr_info.h
 create mode 100644 libc/src/dlfcn/dladdr.cpp
 create mode 100644 libc/src/dlfcn/dladdr.h
 create mode 100644 libc/src/link/CMakeLists.txt
 create mode 100644 libc/src/link/dl_iterate_phdr.cpp
 create mode 100644 libc/src/link/dl_iterate_phdr.h

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 1d7dde40e371e..d20e36daff5a4 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -319,6 +319,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.dlfcn.dlsym
     libc.src.dlfcn.dlclose
     libc.src.dlfcn.dlerror
+    libc.src.dlfcn.dladdr
+    libc.src.link.dl_iterate_phdr
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/config/linux/aarch64/headers.txt b/libc/config/linux/aarch64/headers.txt
index 4f47b09b26b77..6ed200ab7fa7d 100644
--- a/libc/config/linux/aarch64/headers.txt
+++ b/libc/config/linux/aarch64/headers.txt
@@ -39,4 +39,6 @@ set(TARGET_PUBLIC_HEADERS
     libc.include.sched
     libc.include.sys_stat
     libc.include.dlfcn
+    libc.include.link
+    libc.include.elf
 )
diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index eb0090c80b0da..3ff99f263f811 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -308,3 +308,16 @@ def SearchAPI : PublicAPI<"search.h"> {
 def SysStatvfsAPI : PublicAPI<"sys/statvfs.h"> {
   let Types = ["fsblkcnt_t", "fsfilcnt_t", "struct statvfs"];
 }
+
+def LinkAPI : PublicAPI<"link.h"> {
+  let Types = [
+    "struct dl_phdr_info",
+    "__dl_iterate_phdr_callback_t"
+  ];
+}
+
+def DlfcnAPI : PublicAPI<"dlfcn.h"> {
+  let Types = [
+    "Dl_info"
+  ];
+}
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index e5feb4ebed805..a340e637204b8 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -338,6 +338,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.dlfcn.dlsym
     libc.src.dlfcn.dlclose
     libc.src.dlfcn.dlerror
+    libc.src.dlfcn.dladdr
+    libc.src.link.dl_iterate_phdr
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/config/linux/x86_64/headers.txt b/libc/config/linux/x86_64/headers.txt
index 16af88b54e4ab..6dc50f61d9a6b 100644
--- a/libc/config/linux/x86_64/headers.txt
+++ b/libc/config/linux/x86_64/headers.txt
@@ -53,4 +53,6 @@ set(TARGET_PUBLIC_HEADERS
     # XXX
     libc.include.sys_statvfs
     libc.include.dlfcn
+    libc.include.link
+    libc.include.elf
 )
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index f8ef35078a8c4..a39c1c118165f 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -56,6 +56,7 @@ add_gen_header(
   DEF_FILE dlfcn.h.def
   GEN_HDR dlfcn.h
   DEPENDS
+    .llvm-libc-types.Dl_info
     .llvm-libc-macros.dlfcn_macros
     .llvm_libc_common_h
 )
@@ -367,6 +368,25 @@ add_gen_header(
     .llvm-libc-types.posix_spawn_file_actions_t
 )
 
+add_gen_header(
+  link
+  DEF_FILE link.h.def
+  GEN_HDR link.h
+  DEPENDS
+    .llvm_libc_common_h
+    .llvm-libc-types.struct_dl_phdr_info
+    .llvm-libc-types.__dl_iterate_phdr_callback_t
+    .llvm-libc-macros.link_macros
+)
+
+add_gen_header(
+  elf
+  DEF_FILE elf.h.def
+  GEN_HDR elf.h
+  DEPENDS
+    .llvm-libc-macros.elf_macros
+)
+
 # TODO: Not all platforms will have a include/sys directory. Add the sys
 # directory and the targets for sys/*.h files conditional to the OS requiring
 # them.
diff --git a/libc/include/elf.h.def b/libc/include/elf.h.def
new file mode 100644
index 0000000000000..1c9d11929029f
--- /dev/null
+++ b/libc/include/elf.h.def
@@ -0,0 +1,14 @@
+//===-- C standard library header elf.h -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_ELF_H
+#define LLVM_LIBC_ELF_H
+
+#include "llvm-libc-macros/elf-macros.h"
+
+#endif // LLVM_LIBC_ELF_H
diff --git a/libc/include/link.h.def b/libc/include/link.h.def
new file mode 100644
index 0000000000000..353398e4f3c88
--- /dev/null
+++ b/libc/include/link.h.def
@@ -0,0 +1,16 @@
+//===-- C standard library header link.h ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_LINK_H
+#define LLVM_LIBC_LINK_H
+
+#include "llvm-libc-macros/link-macros.h"
+
+%%public_api()
+
+#endif // LLVM_LIBC_LINK_H
diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt
index 5bf573e4e98df..60c8f5a9cd3de 100644
--- a/libc/include/llvm-libc-macros/CMakeLists.txt
+++ b/libc/include/llvm-libc-macros/CMakeLists.txt
@@ -282,4 +282,10 @@ add_macro_header(
   dlfcn_macros
   HDR
     dlfcn-macros.h
-)
\ No newline at end of file
+)
+
+add_macro_header(
+  elf_macros
+  HDR
+    elf-macros.h
+)
diff --git a/libc/include/llvm-libc-macros/elf-macros.h b/libc/include/llvm-libc-macros/elf-macros.h
new file mode 100644
index 0000000000000..fa4442abf0f5c
--- /dev/null
+++ b/libc/include/llvm-libc-macros/elf-macros.h
@@ -0,0 +1,18 @@
+//===-- Definition of macros from elf.h -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_MACROS_ELF_MACROS_H
+#define LLVM_LIBC_MACROS_ELF_MACROS_H
+
+#if __has_include(<linux/elf.h>)
+#include <linux/elf.h>
+#else
+#error "cannot use <sys/elf.h> without proper system headers."
+#endif
+
+#endif // LLVM_LIBC_MACROS_ELF_MACROS_H
diff --git a/libc/include/llvm-libc-macros/link-macros.h b/libc/include/llvm-libc-macros/link-macros.h
index 5c8cadab8e71c..f7461d9527a47 100644
--- a/libc/include/llvm-libc-macros/link-macros.h
+++ b/libc/include/llvm-libc-macros/link-macros.h
@@ -6,8 +6,30 @@
 //
 //===----------------------------------------------------------------------===//
 
+#ifndef LLVM_LIBC_MACROS_LINK_MACROS_H
+#define LLVM_LIBC_MACROS_LINK_MACROS_H
+
+#include "elf-macros.h"
+
 #ifdef __LP64__
-#define ElfW(type) Elf64_ ## type
+#define ElfW(type) Elf64_##type
 #else
-#define ElfW(type) Elf32_ ## type
+#define ElfW(type) Elf32_##type
+#endif
+
+struct link_map {
+  ElfW(Addr) l_addr;
+  char *l_name;
+  ElfW(Dyn) * l_ld;
+  struct link_map *l_next, *l_prev;
+};
+
+struct r_debug {
+  int r_version;
+  struct link_map *r_map;
+  ElfW(Addr) r_brk;
+  enum { RT_CONSISTENT, RT_ADD, RT_DELETE } r_state;
+  ElfW(Addr) r_ldbase;
+};
+
 #endif
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index d8b975572e0dd..016ec14b077e8 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -89,6 +89,9 @@ add_header(thrd_t HDR thrd_t.h DEPENDS .__thread_type)
 add_header(tss_t HDR tss_t.h)
 add_header(tss_dtor_t HDR tss_dtor_t.h)
 add_header(__atexithandler_t HDR __atexithandler_t.h)
+add_header(Dl_info HDR Dl_info.h)
+add_header(struct_dl_phdr_info HDR struct_dl_phdr_info.h)
+add_header(__dl_iterate_phdr_callback_t HDR __dl_iterate_phdr_callback_t.h)
 add_header(speed_t HDR speed_t.h)
 add_header(tcflag_t HDR tcflag_t.h)
 add_header(struct_termios HDR struct_termios.h DEPENDS .cc_t .speed_t .tcflag_t)
diff --git a/libc/include/llvm-libc-types/Dl_info.h b/libc/include/llvm-libc-types/Dl_info.h
new file mode 100644
index 0000000000000..bee32015c4008
--- /dev/null
+++ b/libc/include/llvm-libc-types/Dl_info.h
@@ -0,0 +1,19 @@
+//===-- Definition of type Dl_info ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_TYPES_DL_INFO_H
+#define LLVM_LIBC_TYPES_DL_INFO_H
+
+typedef struct {
+	const char *dli_fname;
+	void *dli_fbase;
+	const char *dli_sname;
+	void *dli_saddr;
+} Dl_info;
+
+#endif // LLVM_LIBC_TYPES_DL_INFO_H
diff --git a/libc/include/llvm-libc-types/__dl_iterate_phdr_callback_t.h b/libc/include/llvm-libc-types/__dl_iterate_phdr_callback_t.h
new file mode 100644
index 0000000000000..9d73e88076e00
--- /dev/null
+++ b/libc/include/llvm-libc-types/__dl_iterate_phdr_callback_t.h
@@ -0,0 +1,17 @@
+//===-- Definition of __dl_iterate_phdr_callback_t type -------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_TYPES___DL_ITERATE_PHDR_CALLBACK_T_H
+#define LLVM_LIBC_TYPES___DL_ITERATE_PHDR_CALLBACK_T_H
+
+#include "llvm-libc-types/size_t.h"
+
+typedef int (*__dl_iterate_phdr_callback_t)(struct dl_phdr_info *info,
+                                            size_t size, void *data);
+
+#endif // LLVM_LIBC_TYPES___DL_ITERATE_PHDR_CALLBACK_T_H
diff --git a/libc/include/llvm-libc-types/struct_dl_phdr_info.h b/libc/include/llvm-libc-types/struct_dl_phdr_info.h
new file mode 100644
index 0000000000000..8bbd7811bbe2a
--- /dev/null
+++ b/libc/include/llvm-libc-types/struct_dl_phdr_info.h
@@ -0,0 +1,26 @@
+//===-- Definition of type struct dl_phdr_info ----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_TYPES_STRUCT_DL_PHDR_INFO_H
+#define LLVM_LIBC_TYPES_STRUCT_DL_PHDR_INFO_H
+
+#include "llvm-libc-types/size_t.h"
+#include "llvm-libc-macros/link-macros.h"
+
+struct dl_phdr_info {
+  ElfW(Addr) dlpi_addr;
+  const char *dlpi_name;
+  const ElfW(Phdr) * dlpi_phdr;
+  ElfW(Half) dlpi_phnum;
+  unsigned long long int dlpi_adds;
+  unsigned long long int dlpi_subs;
+  size_t dlpi_tls_modid;
+  void *dlpi_tls_data;
+};
+
+#endif // LLVM_LIBC_TYPES_STRUCT_DL_PHDR_INFO_H
diff --git a/libc/spec/linux.td b/libc/spec/linux.td
index faeefd70f2263..f64b27dc9e796 100644
--- a/libc/spec/linux.td
+++ b/libc/spec/linux.td
@@ -3,6 +3,9 @@ def StructEpollEventPtr : PtrType<StructEpollEvent>;
 
 def StructEpollData : NamedType<"struct epoll_data">;
 
+def StructDlPhdrInfo : NamedType<"struct dl_phdr_info">;
+def DlIteratePhdrCallback : NamedType<"__dl_iterate_phdr_callback_t">;
+
 def Linux : StandardSpec<"Linux"> {
   HeaderSpec Errno = HeaderSpec<
       "errno.h",
@@ -274,8 +277,35 @@ def Linux : StandardSpec<"Linux"> {
       ]
   >;
 
+  HeaderSpec Link = HeaderSpec<
+     "link.h",
+      [], // Macros
+      [StructDlPhdrInfo, DlIteratePhdrCallback], // Types
+      [], // Enumerations
+      [
+        FunctionSpec<
+          "dl_iterate_phdr",
+          RetValSpec<IntType>,
+          [
+            ArgSpec<DlIteratePhdrCallback>,
+            ArgSpec<VoidPtr>
+          ]
+        >,
+      ]  // Functions
+  >;
+
+  HeaderSpec Elf = HeaderSpec<
+     "elf.h",
+      [], // Macros
+      [], // Types
+      [], // Enumerations
+      []  // Functions
+  >;
+
   let Headers = [
+    Elf,
     Errno,
+    Link,
     SysEpoll,
     SysMMan,
     SysPrctl,
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index ccbe31b698b03..93235664a593e 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -21,6 +21,9 @@ def PThreadOnceT : NamedType<"pthread_once_t">;
 def PThreadOnceTPtr : PtrType<PThreadOnceT>;
 def PThreadOnceCallback : NamedType<"__pthread_once_func_t">;
 
+def DlInfo : NamedType<"Dl_info">;
+def DlInfoPtr : PtrType<DlInfo>;
+
 def InoT : NamedType<"ino_t">;
 def UidT : NamedType<"uid_t">;
 def GidT : NamedType<"gid_t">;
@@ -233,9 +236,14 @@ def POSIX : StandardSpec<"POSIX"> {
       Macro<"RTLD_GLOBAL">,
       Macro<"RTLD_LOCAL">,
     ],
-    [],  // Types
+    [DlInfo],  // Types
     [], // Enumerations
     [
+      FunctionSpec<
+          "dladdr",
+          RetValSpec<IntType>,
+          [ArgSpec<ConstVoidPtr>, ArgSpec<DlInfoPtr>]
+      >,
       FunctionSpec<
           "dlclose",
           RetValSpec<IntType>,
diff --git a/libc/src/CMakeLists.txt b/libc/src/CMakeLists.txt
index f011fe25226e5..9ff88cffc487c 100644
--- a/libc/src/CMakeLists.txt
+++ b/libc/src/CMakeLists.txt
@@ -12,6 +12,7 @@ add_subdirectory(stdlib)
 add_subdirectory(string)
 add_subdirectory(wchar)
 add_subdirectory(dlfcn)
+add_subdirectory(link)
 
 if(${LIBC_TARGET_OS} STREQUAL "linux")
   add_subdirectory(dirent)
diff --git a/libc/src/dlfcn/CMakeLists.txt b/libc/src/dlfcn/CMakeLists.txt
index 5534f2dfb8853..5321499b2e334 100644
--- a/libc/src/dlfcn/CMakeLists.txt
+++ b/libc/src/dlfcn/CMakeLists.txt
@@ -1,3 +1,14 @@
+add_entrypoint_object(
+  dladdr
+  SRCS
+    dladdr.cpp
+  HDRS
+    dladdr.h
+  DEPENDS
+    libc.include.dlfcn
+    libc.src.errno.errno
+)
+
 add_entrypoint_object(
   dlclose
   SRCS
diff --git a/libc/src/dlfcn/dladdr.cpp b/libc/src/dlfcn/dladdr.cpp
new file mode 100644
index 0000000000000..00ff1845fbe3e
--- /dev/null
+++ b/libc/src/dlfcn/dladdr.cpp
@@ -0,0 +1,17 @@
+//===-- Implementation of dladdr -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "dladdr.h"
+
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(int, dladdr, (const void *, Dl_info *)) { return 0; }
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/dlfcn/dladdr.h b/libc/src/dlfcn/dladdr.h
new file mode 100644
index 0000000000000..be9a7fec7a5ef
--- /dev/null
+++ b/libc/src/dlfcn/dladdr.h
@@ -0,0 +1,20 @@
+//===-- Implementation header of dladdr ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_DLFCN_DLADDR_H
+#define LLVM_LIBC_SRC_DLFCN_DLADDR_H
+
+namespace LIBC_NAMESPACE {
+
+#include "include/llvm-libc-types/Dl_info.h"
+
+int dladdr(const void *,Dl_info *);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_DLFCN_DLADDR_H
diff --git a/libc/src/link/CMakeLists.txt b/libc/src/link/CMakeLists.txt
new file mode 100644
index 0000000000000..06f5e05e624fd
--- /dev/null
+++ b/libc/src/link/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_entrypoint_object(
+  dl_iterate_phdr
+  SRCS
+    dl_iterate_phdr.cpp
+  HDRS
+    dl_iterate_phdr.h
+  DEPENDS
+    libc.src.__support.common
+)
diff --git a/libc/src/link/dl_iterate_phdr.cpp b/libc/src/link/dl_iterate_phdr.cpp
new file mode 100644
index 0000000000000..bfb34b0c7061a
--- /dev/null
+++ b/libc/src/link/dl_iterate_phdr.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of dl_iterate_phdr
+//----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "dl_iterate_phdr.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(int, dl_iterate_phdr,
+                   (__dl_iterate_phdr_callback_t, void *)) {
+  // HACK(@izaakschroeder): Not implemented
+  return -1;
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/link/dl_iterate_phdr.h b/libc/src/link/dl_iterate_phdr.h
new file mode 100644
index 0000000000000..b7f7951e883a8
--- /dev/null
+++ b/libc/src/link/dl_iterate_phdr.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for dl_iterate_phdr ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_LINK_DL_ITERATE_PHDR_H
+#define LLVM_LIBC_SRC_LINK_DL_ITERATE_PHDR_H
+
+namespace LIBC_NAMESPACE {
+
+#include "include/llvm-libc-types/__dl_iterate_phdr_callback_t.h"
+
+int dl_iterate_phdr(__dl_iterate_phdr_callback_t, void *);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_LINK_DL_ITERATE_PHDR_H

>From 4207b205b3ebe6665cd1a36c4735ad145c0fac18 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Mon, 1 Jul 2024 23:23:32 -0700
Subject: [PATCH 11/40] [libc]: `dirent.h` for aarch64

---
 libc/config/linux/aarch64/headers.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libc/config/linux/aarch64/headers.txt b/libc/config/linux/aarch64/headers.txt
index 6ed200ab7fa7d..a859670beca51 100644
--- a/libc/config/linux/aarch64/headers.txt
+++ b/libc/config/linux/aarch64/headers.txt
@@ -41,4 +41,5 @@ set(TARGET_PUBLIC_HEADERS
     libc.include.dlfcn
     libc.include.link
     libc.include.elf
+    libc.include.dirent
 )

>From f98f5940d6be752d308cba5508e1904c27788ef3 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Mon, 1 Jul 2024 23:25:14 -0700
Subject: [PATCH 12/40] fixup! fix `utimes` types

---
 libc/spec/linux.td                 | 1 -
 libc/src/sys/time/linux/utimes.cpp | 2 +-
 libc/src/sys/time/utimes.h         | 2 +-
 3 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/libc/spec/linux.td b/libc/spec/linux.td
index f64b27dc9e796..ea0c231c8b3ba 100644
--- a/libc/spec/linux.td
+++ b/libc/spec/linux.td
@@ -156,7 +156,6 @@ def Linux : StandardSpec<"Linux"> {
           "utimes",
           RetValSpec<IntType>,
           [
-            ArgSpec<IntType>,
             ArgSpec<ConstCharPtr>,
             ArgSpec<ConstStructTimevalPtr>,
           ]
diff --git a/libc/src/sys/time/linux/utimes.cpp b/libc/src/sys/time/linux/utimes.cpp
index b3528ab4b48e4..acf318bec7d91 100644
--- a/libc/src/sys/time/linux/utimes.cpp
+++ b/libc/src/sys/time/linux/utimes.cpp
@@ -5,7 +5,7 @@
 
 namespace LIBC_NAMESPACE {
 
-LLVM_LIBC_FUNCTION(int, utimes, (int, const char *, const struct timeval[2])) {
+LLVM_LIBC_FUNCTION(int, utimes, (const char *, const struct timeval[2])) {
   return EINVAL;
 }
 
diff --git a/libc/src/sys/time/utimes.h b/libc/src/sys/time/utimes.h
index eb2bcc3f15f25..93d5d4d1e9aef 100644
--- a/libc/src/sys/time/utimes.h
+++ b/libc/src/sys/time/utimes.h
@@ -11,7 +11,7 @@
 
 namespace LIBC_NAMESPACE {
 
-int utimes(int dirfd, const char *pathname, const struct timeval times[2]);
+int utimes(const char *pathname, const struct timeval times[2]);
 
 } // namespace LIBC_NAMESPACE
 

>From bc7c5dab7fbcc39e1d1eeda3123990533a3b6a8f Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Mon, 1 Jul 2024 23:30:16 -0700
Subject: [PATCH 13/40] fixup! additional `dirent` entrypoints

---
 libc/config/linux/aarch64/entrypoints.txt | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index d20e36daff5a4..2eee2c73023fe 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -321,6 +321,10 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.dlfcn.dlerror
     libc.src.dlfcn.dladdr
     libc.src.link.dl_iterate_phdr
+    libc.src.dirent.closedir
+    libc.src.dirent.dirfd
+    libc.src.dirent.opendir
+    libc.src.dirent.readdir
 )
 
 set(TARGET_LIBM_ENTRYPOINTS

>From 0c9c7c1ad4fb670c37443de6e11e642b60cdcc97 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Mon, 1 Jul 2024 23:39:56 -0700
Subject: [PATCH 14/40] fixup! ioctl add missing def

---
 libc/spec/posix.td | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index 93235664a593e..196fb46764d1b 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -1487,7 +1487,13 @@ def POSIX : StandardSpec<"POSIX"> {
     ],  // Macros
     [], // Types
     [], // Enumerations
-    []  // Functions
+    [
+      FunctionSpec<
+        "ioctl",
+        RetValSpec<IntType>,
+        [ArgSpec<IntType>, ArgSpec<IntType>, ArgSpec<VarArgType>]
+      >
+    ]  // Functions
   >;
 
   HeaderSpec Spawn = HeaderSpec<

>From d142e13e9fd8b206d8c6e6ebb33687246bbce68c Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 00:11:54 -0700
Subject: [PATCH 15/40] [libc]: `<sys/resource.h>` on aarch64

---
 libc/config/linux/aarch64/headers.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libc/config/linux/aarch64/headers.txt b/libc/config/linux/aarch64/headers.txt
index a859670beca51..9b8573b07865f 100644
--- a/libc/config/linux/aarch64/headers.txt
+++ b/libc/config/linux/aarch64/headers.txt
@@ -42,4 +42,5 @@ set(TARGET_PUBLIC_HEADERS
     libc.include.link
     libc.include.elf
     libc.include.dirent
+    libc.include.sys_resource
 )

>From 96b360a0271f0392f9a5af9521822144c87c8415 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 00:32:14 -0700
Subject: [PATCH 16/40] [libc]: `<sys/types.h>` on aarch64

---
 libc/config/linux/aarch64/headers.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libc/config/linux/aarch64/headers.txt b/libc/config/linux/aarch64/headers.txt
index 9b8573b07865f..d6b3312dd3de5 100644
--- a/libc/config/linux/aarch64/headers.txt
+++ b/libc/config/linux/aarch64/headers.txt
@@ -43,4 +43,5 @@ set(TARGET_PUBLIC_HEADERS
     libc.include.elf
     libc.include.dirent
     libc.include.sys_resource
+    libc.include.sys_types
 )

>From f5b9c1b88140b9294f081636b8dd9d6ce117e858 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 00:33:15 -0700
Subject: [PATCH 17/40] [libc]: support `getrusage`

---
 libc/config/linux/aarch64/entrypoints.txt     |  1 +
 libc/config/linux/api.td                      |  2 +-
 libc/config/linux/x86_64/entrypoints.txt      |  1 +
 libc/include/CMakeLists.txt                   |  1 +
 .../linux/sys-resource-macros.h               |  4 +++
 libc/spec/posix.td                            |  9 +++++-
 libc/src/sys/resource/CMakeLists.txt          |  7 +++++
 libc/src/sys/resource/getrusage.h             | 20 ++++++++++++
 libc/src/sys/resource/linux/CMakeLists.txt    | 13 ++++++++
 libc/src/sys/resource/linux/getrusage.cpp     | 31 +++++++++++++++++++
 10 files changed, 87 insertions(+), 2 deletions(-)
 create mode 100644 libc/src/sys/resource/getrusage.h
 create mode 100644 libc/src/sys/resource/linux/getrusage.cpp

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 2eee2c73023fe..91f60a58ce681 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -325,6 +325,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.dirent.dirfd
     libc.src.dirent.opendir
     libc.src.dirent.readdir
+    libc.src.sys.resource.getrusage
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index 3ff99f263f811..c32af904123b9 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -235,7 +235,7 @@ def SysSocketAPI : PublicAPI<"sys/socket.h"> {
 }
 
 def SysResourceAPI : PublicAPI<"sys/resource.h"> {
-  let Types = ["rlim_t", "struct rlimit"];
+  let Types = ["rlim_t", "struct rlimit", "struct rusage"];
 }
 
 def SysStatAPI : PublicAPI<"sys/stat.h"> {
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index a340e637204b8..94eef74f48f25 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -340,6 +340,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.dlfcn.dlerror
     libc.src.dlfcn.dladdr
     libc.src.link.dl_iterate_phdr
+    libc.src.sys.resource.getrusage
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index a39c1c118165f..f707b42bd98fe 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -470,6 +470,7 @@ add_gen_header(
     .llvm-libc-macros.sys_resource_macros
     .llvm-libc-types.rlim_t
     .llvm-libc-types.struct_rlimit
+    .llvm-libc-types.struct_rusage
 )
 
 add_gen_header(
diff --git a/libc/include/llvm-libc-macros/linux/sys-resource-macros.h b/libc/include/llvm-libc-macros/linux/sys-resource-macros.h
index c9d93c30c35a4..5af6e658e015a 100644
--- a/libc/include/llvm-libc-macros/linux/sys-resource-macros.h
+++ b/libc/include/llvm-libc-macros/linux/sys-resource-macros.h
@@ -28,4 +28,8 @@
 
 #define RLIM_INFINITY (~0UL)
 
+#define RUSAGE_SELF     0
+#define RUSAGE_CHILDREN (~0UL)
+#define RUSAGE_THREAD   1
+
 #endif // LLVM_LIBC_MACROS_LINUX_SYS_RESOURCE_MACROS_H
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index 196fb46764d1b..18476d95d860a 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -889,10 +889,12 @@ def POSIX : StandardSpec<"POSIX"> {
   NamedType StructRLimitType = NamedType<"struct rlimit">;
   PtrType StructRLimitPtr = PtrType<StructRLimitType>;
   ConstType ConstStructRLimitPtr = ConstType<StructRLimitType>;
+  NamedType StructRUsageType = NamedType<"struct rusage">;
+  PtrType StructRUsagePtr = PtrType<StructRUsageType>;
   HeaderSpec SysResource = HeaderSpec<
     "sys/resource.h",
     [], // Macros
-    [RLimTType, StructRLimitType], // Types
+    [RLimTType, StructRLimitType, StructRUsageType], // Types
     [], // Enumerations
     [
         FunctionSpec<
@@ -900,6 +902,11 @@ def POSIX : StandardSpec<"POSIX"> {
           RetValSpec<IntType>,
           [ArgSpec<StructRLimitPtr>]
         >,
+        FunctionSpec<
+          "getrusage",
+          RetValSpec<IntType>,
+          [ArgSpec<IntType>, ArgSpec<StructRUsagePtr>]
+        >,
         FunctionSpec<
           "setrlimit",
           RetValSpec<IntType>,
diff --git a/libc/src/sys/resource/CMakeLists.txt b/libc/src/sys/resource/CMakeLists.txt
index 8319b6399650c..ac5f676588994 100644
--- a/libc/src/sys/resource/CMakeLists.txt
+++ b/libc/src/sys/resource/CMakeLists.txt
@@ -9,6 +9,13 @@ add_entrypoint_object(
     .${LIBC_TARGET_OS}.getrlimit
 )
 
+add_entrypoint_object(
+  getrusage
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.getrusage
+)
+
 add_entrypoint_object(
   setrlimit
   ALIAS
diff --git a/libc/src/sys/resource/getrusage.h b/libc/src/sys/resource/getrusage.h
new file mode 100644
index 0000000000000..443eb76c736a2
--- /dev/null
+++ b/libc/src/sys/resource/getrusage.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for getrusage ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SYS_RESOURCE_GETRUSAGE_H
+#define LLVM_LIBC_SRC_SYS_RESOURCE_GETRUSAGE_H
+
+#include <sys/resource.h>
+
+namespace LIBC_NAMESPACE {
+
+int getrusage(int who, struct rusage *usage);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_SYS_RESOURCE_GETRUSAGE_H
diff --git a/libc/src/sys/resource/linux/CMakeLists.txt b/libc/src/sys/resource/linux/CMakeLists.txt
index 19f3901c98a29..bd53962490b90 100644
--- a/libc/src/sys/resource/linux/CMakeLists.txt
+++ b/libc/src/sys/resource/linux/CMakeLists.txt
@@ -11,6 +11,19 @@ add_entrypoint_object(
     libc.src.errno.errno
 )
 
+add_entrypoint_object(
+  getrusage
+  SRCS
+    getrusage.cpp
+  HDRS
+    ../getrusage.h
+  DEPENDS
+    libc.include.sys_resource
+    libc.include.sys_syscall
+    libc.src.__support.OSUtil.osutil
+    libc.src.errno.errno
+)
+
 add_entrypoint_object(
   setrlimit
   SRCS
diff --git a/libc/src/sys/resource/linux/getrusage.cpp b/libc/src/sys/resource/linux/getrusage.cpp
new file mode 100644
index 0000000000000..af6961e7bc6d9
--- /dev/null
+++ b/libc/src/sys/resource/linux/getrusage.cpp
@@ -0,0 +1,31 @@
+//===-- Linux implementation of getrlimit ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/sys/resource/getrusage.h"
+
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/common.h"
+
+#include "src/errno/libc_errno.h"
+
+#include <sys/resource.h> // For struct rusage
+#include <sys/syscall.h>  // For syscall numbers.
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(int, getrusage, (int who, struct rusage *usage)) {
+  int ret =
+      LIBC_NAMESPACE::syscall_impl<int>(SYS_getrusage, who, usage);
+  if (ret < 0) {
+    libc_errno = -ret;
+    return -1;
+  }
+  return 0;
+}
+
+} // namespace LIBC_NAMESPACE

>From c5ceed82ce3157f6ea2090e14361745a1be1bec8 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 01:21:05 -0700
Subject: [PATCH 18/40] [libc]: add `<sys/prctl.h>` on aarch64

---
 libc/config/linux/aarch64/headers.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libc/config/linux/aarch64/headers.txt b/libc/config/linux/aarch64/headers.txt
index d6b3312dd3de5..dcaf5e55f4fc6 100644
--- a/libc/config/linux/aarch64/headers.txt
+++ b/libc/config/linux/aarch64/headers.txt
@@ -44,4 +44,5 @@ set(TARGET_PUBLIC_HEADERS
     libc.include.dirent
     libc.include.sys_resource
     libc.include.sys_types
+    libc.include.sys_prctl
 )

>From 3f7f620af2fc0cc3e670975aeb17423e26062a2b Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 01:31:09 -0700
Subject: [PATCH 19/40] [libc]: missing `prctl` export

---
 libc/spec/linux.td | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/libc/spec/linux.td b/libc/spec/linux.td
index ea0c231c8b3ba..9c1782df8eba9 100644
--- a/libc/spec/linux.td
+++ b/libc/spec/linux.td
@@ -115,7 +115,19 @@ def Linux : StandardSpec<"Linux"> {
       [], // Macros
       [], // Types
       [], // Enumerations
-      []  // Functions
+      [
+        FunctionSpec<
+        "prctl",
+          RetValSpec<IntType>,
+          [
+            ArgSpec<IntType>, 
+            ArgSpec<UnsignedLongType>, 
+            ArgSpec<UnsignedLongType>, 
+            ArgSpec<UnsignedLongType>, 
+            ArgSpec<UnsignedLongType>
+          ]
+      >
+      ]  // Functions
   >;
 
   HeaderSpec SysRandom = HeaderSpec<

>From a987fe3fc04d6a8a7b1e63dafdd529042c2d4ac4 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 11:21:32 -0700
Subject: [PATCH 20/40] [libc]: add `locale.h` stubs

---
 libc/config/linux/aarch64/entrypoints.txt     |  7 +++
 libc/config/linux/aarch64/headers.txt         |  1 +
 libc/config/linux/api.td                      |  7 +++
 libc/config/linux/x86_64/entrypoints.txt      |  7 +++
 libc/config/linux/x86_64/headers.txt          |  1 +
 libc/include/CMakeLists.txt                   | 11 ++++
 libc/include/llvm-libc-macros/CMakeLists.txt  |  6 ++
 libc/include/llvm-libc-macros/locale-macros.h | 32 ++++++++++
 libc/include/llvm-libc-types/CMakeLists.txt   |  2 +
 libc/include/llvm-libc-types/locale_t.h       | 18 ++++++
 libc/include/llvm-libc-types/struct_lconv.h   | 39 ++++++++++++
 libc/include/locale.h.def                     | 16 +++++
 libc/spec/posix.td                            | 57 ++++++++++++++++++
 libc/src/CMakeLists.txt                       |  1 +
 libc/src/locale/CMakeLists.txt                | 60 +++++++++++++++++++
 libc/src/locale/duplocale.cpp                 | 18 ++++++
 libc/src/locale/duplocale.h                   | 20 +++++++
 libc/src/locale/freelocale.cpp                | 18 ++++++
 libc/src/locale/freelocale.h                  | 20 +++++++
 libc/src/locale/localeconv.cpp                | 46 ++++++++++++++
 libc/src/locale/localeconv.h                  | 20 +++++++
 libc/src/locale/newlocale.cpp                 | 18 ++++++
 libc/src/locale/newlocale.h                   | 20 +++++++
 libc/src/locale/setlocale.cpp                 | 18 ++++++
 libc/src/locale/setlocale.h                   | 18 ++++++
 libc/src/locale/uselocale.cpp                 | 18 ++++++
 libc/src/locale/uselocale.h                   | 20 +++++++
 27 files changed, 519 insertions(+)
 create mode 100644 libc/include/llvm-libc-macros/locale-macros.h
 create mode 100644 libc/include/llvm-libc-types/locale_t.h
 create mode 100644 libc/include/llvm-libc-types/struct_lconv.h
 create mode 100644 libc/include/locale.h.def
 create mode 100644 libc/src/locale/CMakeLists.txt
 create mode 100644 libc/src/locale/duplocale.cpp
 create mode 100644 libc/src/locale/duplocale.h
 create mode 100644 libc/src/locale/freelocale.cpp
 create mode 100644 libc/src/locale/freelocale.h
 create mode 100644 libc/src/locale/localeconv.cpp
 create mode 100644 libc/src/locale/localeconv.h
 create mode 100644 libc/src/locale/newlocale.cpp
 create mode 100644 libc/src/locale/newlocale.h
 create mode 100644 libc/src/locale/setlocale.cpp
 create mode 100644 libc/src/locale/setlocale.h
 create mode 100644 libc/src/locale/uselocale.cpp
 create mode 100644 libc/src/locale/uselocale.h

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 91f60a58ce681..95061460bd321 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -326,6 +326,13 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.dirent.opendir
     libc.src.dirent.readdir
     libc.src.sys.resource.getrusage
+    libc.src.wchar.wctob
+    libc.src.locale.duplocale
+    libc.src.locale.freelocale
+    libc.src.locale.localeconv
+    libc.src.locale.newlocale
+    libc.src.locale.setlocale
+    libc.src.locale.uselocale
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/config/linux/aarch64/headers.txt b/libc/config/linux/aarch64/headers.txt
index dcaf5e55f4fc6..0b88a2bc610c6 100644
--- a/libc/config/linux/aarch64/headers.txt
+++ b/libc/config/linux/aarch64/headers.txt
@@ -45,4 +45,5 @@ set(TARGET_PUBLIC_HEADERS
     libc.include.sys_resource
     libc.include.sys_types
     libc.include.sys_prctl
+    libc.include.locale
 )
diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index c32af904123b9..1b6b051b11a26 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -321,3 +321,10 @@ def DlfcnAPI : PublicAPI<"dlfcn.h"> {
     "Dl_info"
   ];
 }
+
+def LocaleAPI : PublicAPI<"locale.h"> {
+  let Types = [
+    "struct lconv",
+    "locale_t"
+  ];
+}
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 94eef74f48f25..dde73fb097b6c 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -341,6 +341,13 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.dlfcn.dladdr
     libc.src.link.dl_iterate_phdr
     libc.src.sys.resource.getrusage
+    libc.src.locale.duplocale
+    libc.src.locale.freelocale
+    libc.src.locale.localeconv
+    libc.src.locale.newlocale
+    libc.src.locale.setlocale
+    libc.src.locale.uselocale
+ 
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/config/linux/x86_64/headers.txt b/libc/config/linux/x86_64/headers.txt
index 6dc50f61d9a6b..95c0e062f3859 100644
--- a/libc/config/linux/x86_64/headers.txt
+++ b/libc/config/linux/x86_64/headers.txt
@@ -55,4 +55,5 @@ set(TARGET_PUBLIC_HEADERS
     libc.include.dlfcn
     libc.include.link
     libc.include.elf
+    libc.include.locale
 )
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index f707b42bd98fe..039b86a3b10c1 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -379,6 +379,17 @@ add_gen_header(
     .llvm-libc-macros.link_macros
 )
 
+add_gen_header(
+  locale
+  DEF_FILE locale.h.def
+  GEN_HDR locale.h
+  DEPENDS
+    .llvm_libc_common_h
+    .llvm-libc-types.struct_lconv
+    .llvm-libc-types.locale_t
+    .llvm-libc-macros.locale_macros
+)
+
 add_gen_header(
   elf
   DEF_FILE elf.h.def
diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt
index 60c8f5a9cd3de..5802191ac1fcf 100644
--- a/libc/include/llvm-libc-macros/CMakeLists.txt
+++ b/libc/include/llvm-libc-macros/CMakeLists.txt
@@ -289,3 +289,9 @@ add_macro_header(
   HDR
     elf-macros.h
 )
+
+add_macro_header(
+  locale_macros
+  HDR
+    locale-macros.h
+)
diff --git a/libc/include/llvm-libc-macros/locale-macros.h b/libc/include/llvm-libc-macros/locale-macros.h
new file mode 100644
index 0000000000000..3c9098cb97207
--- /dev/null
+++ b/libc/include/llvm-libc-macros/locale-macros.h
@@ -0,0 +1,32 @@
+//===-- Definition of macros from locale.h --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_MACROS_LOCALE_MACROS_H
+#define LLVM_LIBC_MACROS_LOCALE_MACROS_H
+
+// HACK(@izaakschroeder): Stubs
+#define LC_ALL 0
+#define LC_COLLATE 0
+#define LC_CTYPE 0
+#define LC_MESSAGES 0
+#define LC_MONETARY 0
+#define LC_NUMERIC 0
+#define LC_TIME 0
+
+// HACK(@izaakschroeder): Stubs
+#define LC_ALL_MASK 0
+#define LC_COLLATE_MASK 0
+#define LC_CTYPE_MASK 0
+#define LC_MESSAGES_MASK 0
+#define LC_MONETARY_MASK 0
+#define LC_NUMERIC_MASK 0
+#define LC_TIME_MASK 0
+
+
+
+#endif // LLVM_LIBC_MACROS_LOCALE_MACROS_H
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index 016ec14b077e8..60f8be295186d 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -92,6 +92,8 @@ add_header(__atexithandler_t HDR __atexithandler_t.h)
 add_header(Dl_info HDR Dl_info.h)
 add_header(struct_dl_phdr_info HDR struct_dl_phdr_info.h)
 add_header(__dl_iterate_phdr_callback_t HDR __dl_iterate_phdr_callback_t.h)
+add_header(struct_lconv HDR struct_lconv.h)
+add_header(locale_t HDR locale_t.h)
 add_header(speed_t HDR speed_t.h)
 add_header(tcflag_t HDR tcflag_t.h)
 add_header(struct_termios HDR struct_termios.h DEPENDS .cc_t .speed_t .tcflag_t)
diff --git a/libc/include/llvm-libc-types/locale_t.h b/libc/include/llvm-libc-types/locale_t.h
new file mode 100644
index 0000000000000..48e47ece1a742
--- /dev/null
+++ b/libc/include/llvm-libc-types/locale_t.h
@@ -0,0 +1,18 @@
+
+//===-- Definition of type locale_t ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_TYPES_LOCALE_T_H
+#define LLVM_LIBC_TYPES_LOCALE_T_H
+
+// HACK(@izaakschroeder): Placeholder
+typedef struct {
+  int dummy;
+} locale_t;
+
+#endif // LLVM_LIBC_TYPES_LOCALE_T_H
diff --git a/libc/include/llvm-libc-types/struct_lconv.h b/libc/include/llvm-libc-types/struct_lconv.h
new file mode 100644
index 0000000000000..a5067a2d373d4
--- /dev/null
+++ b/libc/include/llvm-libc-types/struct_lconv.h
@@ -0,0 +1,39 @@
+//===-- Definition of type struct lconv -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_TYPES_STRUCT_LCONV_H
+#define LLVM_LIBC_TYPES_STRUCT_LCONV_H
+
+struct lconv {
+  char *currency_symbol;
+	char *decimal_point;
+  char *grouping;
+  char *int_curr_symbol;
+  char *mon_decimal_point;
+  char *mon_grouping;
+	char *mon_thousands_sep;
+  char *negative_sign;
+  char *positive_sign;
+	char *thousands_sep;
+  char frac_digits;
+  char int_frac_digits;
+  char int_p_cs_precedes;
+	char int_p_sep_by_space;
+	char int_n_cs_precedes;
+	char int_n_sep_by_space;
+  char int_n_sign_posn;
+	char int_p_sign_posn;
+  char n_cs_precedes;
+	char n_sep_by_space;
+  char n_sign_posn;
+	char p_cs_precedes;
+	char p_sep_by_space;
+	char p_sign_posn;	
+};
+
+#endif // LLVM_LIBC_TYPES_STRUCT_LCONV_H
diff --git a/libc/include/locale.h.def b/libc/include/locale.h.def
new file mode 100644
index 0000000000000..de284933b8b21
--- /dev/null
+++ b/libc/include/locale.h.def
@@ -0,0 +1,16 @@
+//===-- C standard library header locale.h --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_LOCALE_H
+#define LLVM_LIBC_LOCALE_H
+
+#include "llvm-libc-macros/locale-macros.h"
+
+%%public_api()
+
+#endif // LLVM_LIBC_LINK_H
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index 18476d95d860a..db8dff0442c01 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -24,6 +24,10 @@ def PThreadOnceCallback : NamedType<"__pthread_once_func_t">;
 def DlInfo : NamedType<"Dl_info">;
 def DlInfoPtr : PtrType<DlInfo>;
 
+def StructLconv : NamedType<"struct lconv">;
+def StructLconvPtr : PtrType<StructLconv>;
+def LocaleT : NamedType<"locale_t">;
+
 def InoT : NamedType<"ino_t">;
 def UidT : NamedType<"uid_t">;
 def GidT : NamedType<"gid_t">;
@@ -1744,6 +1748,58 @@ def POSIX : StandardSpec<"POSIX"> {
     []  // Functions
   >;
 
+  HeaderSpec Locale = HeaderSpec<
+     "locale.h",
+      [], // Macros
+      [LocaleT, StructLconv], // Types
+      [], // Enumerations
+      [
+        FunctionSpec<
+          "duplocale",
+          RetValSpec<LocaleT>,
+          [
+            ArgSpec<LocaleT>
+          ]
+        >,
+        FunctionSpec<
+          "freelocale",
+          RetValSpec<VoidType>,
+          [
+            ArgSpec<LocaleT>
+          ]
+        >,
+        FunctionSpec<
+          "localeconv",
+          RetValSpec<StructLconvPtr>,
+          []
+        >,
+        FunctionSpec<
+          "newlocale",
+          RetValSpec<LocaleT>,
+          [
+            ArgSpec<IntType>,
+            ArgSpec<ConstCharPtr>,
+            ArgSpec<LocaleT>
+          ]
+        >,
+        FunctionSpec<
+          "setlocale",
+          RetValSpec<CharPtr>,
+          [
+            ArgSpec<IntType>,
+            ArgSpec<ConstCharPtr>
+          ]
+        >,
+        FunctionSpec<
+          "uselocale",
+          RetValSpec<LocaleT>,
+          [
+            ArgSpec<LocaleT>
+          ]
+        >
+      ]  // Functions
+  >;
+
   let Headers = [
     ArpaInet,
     CType,
@@ -1751,6 +1807,7 @@ def POSIX : StandardSpec<"POSIX"> {
     DlFcn,
     Errno,
     FCntl,
+    Locale,
     PThread,
     Sched,
     Signal,
diff --git a/libc/src/CMakeLists.txt b/libc/src/CMakeLists.txt
index 9ff88cffc487c..d117ea325b35c 100644
--- a/libc/src/CMakeLists.txt
+++ b/libc/src/CMakeLists.txt
@@ -13,6 +13,7 @@ add_subdirectory(string)
 add_subdirectory(wchar)
 add_subdirectory(dlfcn)
 add_subdirectory(link)
+add_subdirectory(locale)
 
 if(${LIBC_TARGET_OS} STREQUAL "linux")
   add_subdirectory(dirent)
diff --git a/libc/src/locale/CMakeLists.txt b/libc/src/locale/CMakeLists.txt
new file mode 100644
index 0000000000000..be955c39f496f
--- /dev/null
+++ b/libc/src/locale/CMakeLists.txt
@@ -0,0 +1,60 @@
+add_entrypoint_object(
+  duplocale
+  SRCS
+    duplocale.cpp
+  HDRS
+    duplocale.h
+  DEPENDS
+    libc.src.__support.common
+)
+
+add_entrypoint_object(
+  freelocale
+  SRCS
+    freelocale.cpp
+  HDRS
+    freelocale.h
+  DEPENDS
+    libc.src.__support.common
+)
+
+add_entrypoint_object(
+  localeconv
+  SRCS
+    localeconv.cpp
+  HDRS
+    localeconv.h
+  DEPENDS
+    libc.src.__support.common
+    libc.include.limits
+)
+
+add_entrypoint_object(
+  newlocale
+  SRCS
+    newlocale.cpp
+  HDRS
+    newlocale.h
+  DEPENDS
+    libc.src.__support.common
+)
+
+add_entrypoint_object(
+  setlocale
+  SRCS
+    setlocale.cpp
+  HDRS
+    setlocale.h
+  DEPENDS
+    libc.src.__support.common
+)
+
+add_entrypoint_object(
+  uselocale
+  SRCS
+    uselocale.cpp
+  HDRS
+    uselocale.h
+  DEPENDS
+    libc.src.__support.common
+)
diff --git a/libc/src/locale/duplocale.cpp b/libc/src/locale/duplocale.cpp
new file mode 100644
index 0000000000000..ab6441a01f1b6
--- /dev/null
+++ b/libc/src/locale/duplocale.cpp
@@ -0,0 +1,18 @@
+//===-- Implementation of duplocale ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "duplocale.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(locale_t, duplocale, (locale_t locale)) {
+  return locale;
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/locale/duplocale.h b/libc/src/locale/duplocale.h
new file mode 100644
index 0000000000000..87a613beada09
--- /dev/null
+++ b/libc/src/locale/duplocale.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for duplocale ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_LOCALE_DUPLOCALE_H
+#define LLVM_LIBC_SRC_LOCALE_DUPLOCALE_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+locale_t duplocale(locale_t);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_LINK_DL_ITERATE_PHDR_H
diff --git a/libc/src/locale/freelocale.cpp b/libc/src/locale/freelocale.cpp
new file mode 100644
index 0000000000000..317b6cb0002df
--- /dev/null
+++ b/libc/src/locale/freelocale.cpp
@@ -0,0 +1,18 @@
+//===-- Implementation of freelocale --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "freelocale.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(void, freelocale, (locale_t)) {
+  // ...
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/locale/freelocale.h b/libc/src/locale/freelocale.h
new file mode 100644
index 0000000000000..eec66b618ebe7
--- /dev/null
+++ b/libc/src/locale/freelocale.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for freelocale --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_LOCALE_FREELOCALE_H
+#define LLVM_LIBC_SRC_LOCALE_FREELOCALE_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+void freelocale(locale_t);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_LOCALE_FREELOCALE_H
diff --git a/libc/src/locale/localeconv.cpp b/libc/src/locale/localeconv.cpp
new file mode 100644
index 0000000000000..c36ef8f1ef85e
--- /dev/null
+++ b/libc/src/locale/localeconv.cpp
@@ -0,0 +1,46 @@
+//===-- Implementation of localeconv --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <limits.h>
+#include "localeconv.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+static const struct lconv posix_lconv = {
+  .currency_symbol = const_cast<char*>(""),
+	.decimal_point = const_cast<char*>("."),
+  .grouping = const_cast<char*>(""),
+  .int_curr_symbol = const_cast<char*>(""),
+  .mon_decimal_point = const_cast<char*>(""),
+  .mon_grouping = const_cast<char*>(""),
+	.mon_thousands_sep = const_cast<char*>(""),
+  .negative_sign = const_cast<char*>(""),
+  .positive_sign = const_cast<char*>(""),
+	.thousands_sep = const_cast<char*>(""),
+  .frac_digits = CHAR_MAX,
+  .int_frac_digits = CHAR_MAX,
+  .int_p_cs_precedes = CHAR_MAX,
+	.int_p_sep_by_space = CHAR_MAX,
+	.int_n_cs_precedes = CHAR_MAX,
+	.int_n_sep_by_space = CHAR_MAX,
+  .int_n_sign_posn = CHAR_MAX,
+	.int_p_sign_posn = CHAR_MAX,
+  .n_cs_precedes = CHAR_MAX,
+	.n_sep_by_space = CHAR_MAX,
+  .n_sign_posn = CHAR_MAX,
+	.p_cs_precedes = CHAR_MAX,
+	.p_sep_by_space = CHAR_MAX,
+	.p_sign_posn = CHAR_MAX,
+};
+
+LLVM_LIBC_FUNCTION(struct lconv *, localeconv, ()) {
+  return const_cast<struct lconv *>(&posix_lconv);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/locale/localeconv.h b/libc/src/locale/localeconv.h
new file mode 100644
index 0000000000000..e095be7334365
--- /dev/null
+++ b/libc/src/locale/localeconv.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for localeconv --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_LOCALE_LOCALECONV_H
+#define LLVM_LIBC_SRC_LOCALE_LOCALECONV_H
+
+#include "include/llvm-libc-types/struct_lconv.h"
+
+namespace LIBC_NAMESPACE {
+
+struct lconv *localeconv(void);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_LOCALE_LOCALECONV_H
diff --git a/libc/src/locale/newlocale.cpp b/libc/src/locale/newlocale.cpp
new file mode 100644
index 0000000000000..332f40bd7ba8f
--- /dev/null
+++ b/libc/src/locale/newlocale.cpp
@@ -0,0 +1,18 @@
+//===-- Implementation of newlocale ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "newlocale.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(locale_t, newlocale, (int, const char *, locale_t locale)) {
+  return locale;
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/locale/newlocale.h b/libc/src/locale/newlocale.h
new file mode 100644
index 0000000000000..d8a0f66e7f060
--- /dev/null
+++ b/libc/src/locale/newlocale.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for newlocale ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_LOCALE_NEWLOCALE_H
+#define LLVM_LIBC_SRC_LOCALE_NEWLOCALE_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+locale_t newlocale(int, const char *, locale_t);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_LOCALE_NEWLOCALE_H
diff --git a/libc/src/locale/setlocale.cpp b/libc/src/locale/setlocale.cpp
new file mode 100644
index 0000000000000..bc8797b5e9f01
--- /dev/null
+++ b/libc/src/locale/setlocale.cpp
@@ -0,0 +1,18 @@
+//===-- Implementation of setlocale ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "setlocale.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(char *, setlocale, (int, const char *)) {
+  return const_cast<char*>("unsupported");
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/locale/setlocale.h b/libc/src/locale/setlocale.h
new file mode 100644
index 0000000000000..a438c8426a2b7
--- /dev/null
+++ b/libc/src/locale/setlocale.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for setlocale ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_LOCALE_SETLOCALE_H
+#define LLVM_LIBC_SRC_LOCALE_SETLOCALE_H
+
+namespace LIBC_NAMESPACE {
+
+char *setlocale(int, const char *);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_LOCALE_SETLOCALE_H
diff --git a/libc/src/locale/uselocale.cpp b/libc/src/locale/uselocale.cpp
new file mode 100644
index 0000000000000..6266e24f4954c
--- /dev/null
+++ b/libc/src/locale/uselocale.cpp
@@ -0,0 +1,18 @@
+//===-- Implementation of uselocale ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "uselocale.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(locale_t, uselocale, (locale_t locale)) {
+  return locale;
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/locale/uselocale.h b/libc/src/locale/uselocale.h
new file mode 100644
index 0000000000000..48abb54cbfcfe
--- /dev/null
+++ b/libc/src/locale/uselocale.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for uselocale ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_LOCALE_USELOCALE_H
+#define LLVM_LIBC_SRC_LOCALE_USELOCALE_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+locale_t uselocale(locale_t);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_LOCALE_USELOCALE_H

>From 8510d10b55bcd2c67f994d54d394d07ac3e72bb9 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 11:42:49 -0700
Subject: [PATCH 21/40] [libcxx]: allow default rune table as config

---
 libcxx/CMakeLists.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt
index e098bd574eec7..dcbb372b905bd 100644
--- a/libcxx/CMakeLists.txt
+++ b/libcxx/CMakeLists.txt
@@ -767,6 +767,7 @@ config_define(${LIBCXX_ABI_NAMESPACE} _LIBCPP_ABI_NAMESPACE)
 config_define_if(LIBCXX_ABI_FORCE_ITANIUM _LIBCPP_ABI_FORCE_ITANIUM)
 config_define_if(LIBCXX_ABI_FORCE_MICROSOFT _LIBCPP_ABI_FORCE_MICROSOFT)
 config_define_if_not(LIBCXX_ENABLE_THREADS _LIBCPP_HAS_NO_THREADS)
+config_define_if(LIBCXX_ENABLE_DEFAULT_RUNE_TABLE _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE)
 config_define_if_not(LIBCXX_ENABLE_MONOTONIC_CLOCK _LIBCPP_HAS_NO_MONOTONIC_CLOCK)
 if (NOT LIBCXX_TYPEINFO_COMPARISON_IMPLEMENTATION STREQUAL "default")
   config_define("${LIBCXX_TYPEINFO_COMPARISON_IMPLEMENTATION}" _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION)

>From 598b78297ee62721c707326f74f8f2ced5965488 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 11:48:06 -0700
Subject: [PATCH 22/40] [libcxx]: swap `__Fuchsia__` for `__LLVM_LIBC__`

---
 libcxx/include/__config | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/libcxx/include/__config b/libcxx/include/__config
index dfb14fd6a380c..3eac00bc1592b 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -844,7 +844,7 @@ typedef __char32_t char32_t;
         defined(__EMSCRIPTEN__)
 // clang-format on
 #      define _LIBCPP_HAS_THREAD_API_PTHREAD
-#    elif defined(__Fuchsia__)
+#    elif defined(__LLVM_LIBC__)
 // TODO(44575): Switch to C11 thread API when possible.
 #      define _LIBCPP_HAS_THREAD_API_PTHREAD
 #    elif defined(_LIBCPP_WIN32API)
@@ -895,7 +895,7 @@ typedef __char32_t char32_t;
 //               respective stakeholders.
 // clang-format off
 #  if (defined(_LIBCPP_HAS_THREAD_API_PTHREAD) && defined(__GLIBC__)) ||                                               \
-      (defined(_LIBCPP_HAS_THREAD_API_C11) && defined(__Fuchsia__)) ||                                                 \
+      (defined(_LIBCPP_HAS_THREAD_API_C11) && defined(__LLVM_LIBC__)) ||                                                 \
        defined(_LIBCPP_HAS_THREAD_API_WIN32)
 // clang-format on
 #    define _LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION
@@ -909,11 +909,11 @@ typedef __char32_t char32_t;
 //
 // TODO(EricWF): This is potentially true for some pthread implementations
 // as well.
-#  if (defined(_LIBCPP_HAS_THREAD_API_C11) && defined(__Fuchsia__)) || defined(_LIBCPP_HAS_THREAD_API_WIN32)
+#  if (defined(_LIBCPP_HAS_THREAD_API_C11) && defined(__LLVM_LIBC__)) || defined(_LIBCPP_HAS_THREAD_API_WIN32)
 #    define _LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION
 #  endif
 
-#  if defined(__BIONIC__) || defined(__NuttX__) || defined(__Fuchsia__) || defined(__wasi__) ||                        \
+#  if defined(__BIONIC__) || defined(__NuttX__) || defined(__LLVM_LIBC__) || defined(__wasi__) ||                        \
       defined(_LIBCPP_HAS_MUSL_LIBC) || defined(__OpenBSD__)
 #    define _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE
 #  endif

>From 50c85f7ee8d50a73e4575a3d2f63b47509f2dda3 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 11:52:24 -0700
Subject: [PATCH 23/40] [libcxx]: no `catopen` for llvm libc

---
 libcxx/include/locale | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/include/locale b/libcxx/include/locale
index 19e81e110b69c..46318683b3cef 100644
--- a/libcxx/include/locale
+++ b/libcxx/include/locale
@@ -217,7 +217,7 @@ template <class charT> class messages_byname;
 
 #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
 // Most unix variants have catopen.  These are the specific ones that don't.
-#  if !defined(__BIONIC__) && !defined(_NEWLIB_VERSION) && !defined(__EMSCRIPTEN__)
+#  if !defined(__BIONIC__) && !defined(_NEWLIB_VERSION) && !defined(__EMSCRIPTEN__) && !defined(__LLVM_LIBC__)
 #    define _LIBCPP_HAS_CATOPEN 1
 #    include <nl_types.h>
 #  endif

>From b6219c90d24b7a9a3d64cb6359a815569cf4e90a Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 12:26:49 -0700
Subject: [PATCH 24/40] wip! more locale stuff

---
 libc/config/linux/aarch64/entrypoints.txt |  6 +++
 libc/config/linux/x86_64/entrypoints.txt  |  4 ++
 libc/include/llvm-libc-types/locale_t.h   |  8 ++--
 libc/spec/stdc.td                         | 10 +++++
 libc/src/stdlib/CMakeLists.txt            | 48 +++++++++++++++++++++++
 libc/src/stdlib/strtod_l.cpp              | 21 ++++++++++
 libc/src/stdlib/strtod_l.h                | 20 ++++++++++
 libc/src/stdlib/strtof_l.cpp              | 20 ++++++++++
 libc/src/stdlib/strtof_l.h                | 20 ++++++++++
 libc/src/stdlib/strtold_l.cpp             | 21 ++++++++++
 libc/src/stdlib/strtold_l.h               | 20 ++++++++++
 libc/src/stdlib/strtoll_l.cpp             | 22 +++++++++++
 libc/src/stdlib/strtoll_l.h               | 21 ++++++++++
 13 files changed, 237 insertions(+), 4 deletions(-)
 create mode 100644 libc/src/stdlib/strtod_l.cpp
 create mode 100644 libc/src/stdlib/strtod_l.h
 create mode 100644 libc/src/stdlib/strtof_l.cpp
 create mode 100644 libc/src/stdlib/strtof_l.h
 create mode 100644 libc/src/stdlib/strtold_l.cpp
 create mode 100644 libc/src/stdlib/strtold_l.h
 create mode 100644 libc/src/stdlib/strtoll_l.cpp
 create mode 100644 libc/src/stdlib/strtoll_l.h

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 95061460bd321..85a9d35b38d83 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -333,6 +333,12 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.locale.newlocale
     libc.src.locale.setlocale
     libc.src.locale.uselocale
+    libc.src.stdio.scanf
+    libc.src.stdio.sscanf
+    libc.src.stdlib.strtof_l
+    libc.src.stdlib.strtod_l
+    libc.src.stdlib.strtold_l
+    libc.src.stdlib.strtoull_l
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index dde73fb097b6c..a8ba2aa9bcb6d 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -347,6 +347,10 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.locale.newlocale
     libc.src.locale.setlocale
     libc.src.locale.uselocale
+    libc.src.stdlib.strtof_l
+    libc.src.stdlib.strtod_l
+    libc.src.stdlib.strtold_l
+    libc.src.stdlib.strtoull_l
  
 )
 
diff --git a/libc/include/llvm-libc-types/locale_t.h b/libc/include/llvm-libc-types/locale_t.h
index 48e47ece1a742..32014588532a8 100644
--- a/libc/include/llvm-libc-types/locale_t.h
+++ b/libc/include/llvm-libc-types/locale_t.h
@@ -10,9 +10,9 @@
 #ifndef LLVM_LIBC_TYPES_LOCALE_T_H
 #define LLVM_LIBC_TYPES_LOCALE_T_H
 
-// HACK(@izaakschroeder): Placeholder
-typedef struct {
-  int dummy;
-} locale_t;
+// HACK(@izaakschroeder): Placeholder.
+// NOTE: According to `libcxx` the `locale_t` type has to be at least
+// coercible to a `bool`.
+typedef void* locale_t;
 
 #endif // LLVM_LIBC_TYPES_LOCALE_T_H
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 481515ad439ed..0153fd1835872 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -8,6 +8,7 @@ def StdC : StandardSpec<"stdc"> {
   NamedType DivTType = NamedType<"div_t">;
   NamedType LDivTType = NamedType<"ldiv_t">;
   NamedType LLDivTType = NamedType<"lldiv_t">;
+  NamedType LocaleTType = NamedType<"locale_t">;
 
   NamedType JmpBuf = NamedType<"jmp_buf">;
 
@@ -1135,6 +1136,15 @@ def StdC : StandardSpec<"stdc"> {
           FunctionSpec<"strtoul", RetValSpec<UnsignedLongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>]>,
           FunctionSpec<"strtoull", RetValSpec<UnsignedLongLongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>]>,
 
+
+          FunctionSpec<"strtof_l", RetValSpec<FloatType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<LocaleTType>]>,
+          FunctionSpec<"strtod_l", RetValSpec<DoubleType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<LocaleTType>]>,
+          FunctionSpec<"strtold_l", RetValSpec<LongDoubleType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<LocaleTType>]>,
+          FunctionSpec<"strtol_l", RetValSpec<LongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>, ArgSpec<LocaleTType>]>,
+          FunctionSpec<"strtoll_l", RetValSpec<LongLongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>, ArgSpec<LocaleTType>]>,
+          FunctionSpec<"strtoul_l", RetValSpec<UnsignedLongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>, ArgSpec<LocaleTType>]>,
+          FunctionSpec<"strtoull_l", RetValSpec<UnsignedLongLongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>, ArgSpec<LocaleTType>]>,
+
           FunctionSpec<"malloc", RetValSpec<VoidPtr>, [ArgSpec<SizeTType>]>,
           FunctionSpec<"calloc", RetValSpec<VoidPtr>, [ArgSpec<SizeTType>, ArgSpec<SizeTType>]>,
           FunctionSpec<"realloc", RetValSpec<VoidPtr>, [ArgSpec<VoidPtr>, ArgSpec<SizeTType>]>,
diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt
index 677bf358c82c4..88995f73b313c 100644
--- a/libc/src/stdlib/CMakeLists.txt
+++ b/libc/src/stdlib/CMakeLists.txt
@@ -516,3 +516,51 @@ add_entrypoint_object(
   DEPENDS
     .${LIBC_TARGET_OS}.abort
 )
+
+add_entrypoint_object(
+  strtof_l
+  SRCS
+    strtof_l.cpp
+  HDRS
+    strtof_l.h
+  DEPENDS
+    libc.src.stdlib.strtof
+    libc.src.errno.errno
+    .llvm-libc-types.locale_t
+)
+
+add_entrypoint_object(
+  strtod_l
+  SRCS
+    strtod_l.cpp
+  HDRS
+    strtod_l.h
+  DEPENDS
+    libc.src.stdlib.strtod
+    libc.src.errno.errno
+    .llvm-libc-types.locale_t
+)
+
+add_entrypoint_object(
+  strtold_l
+  SRCS
+    strtold_l.cpp
+  HDRS
+    strtold_l.h
+  DEPENDS
+    libc.src.stdlib.strtold
+    libc.src.errno.errno
+    .llvm-libc-types.locale_t
+)
+
+add_entrypoint_object(
+  strtoull_l
+  SRCS
+    strtoull_l.cpp
+  HDRS
+    strtoull_l.h
+  DEPENDS
+    libc.src.stdlib.strtoull_l
+    libc.src.errno.errno
+    .llvm-libc-types.locale_t
+)
diff --git a/libc/src/stdlib/strtod_l.cpp b/libc/src/stdlib/strtod_l.cpp
new file mode 100644
index 0000000000000..44670b0c1853e
--- /dev/null
+++ b/libc/src/stdlib/strtod_l.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of strtod_l -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdlib/strtod_l.h"
+#include "src/stdlib/strtod.h"
+#include "src/__support/common.h"
+
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(double, strtod_l,
+                   (const char *__restrict str, char **__restrict str_end, locale_t)) {
+  return strtod(str, str_end);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdlib/strtod_l.h b/libc/src/stdlib/strtod_l.h
new file mode 100644
index 0000000000000..49da430d17fed
--- /dev/null
+++ b/libc/src/stdlib/strtod_l.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for strtod_l -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDLIB_STRTOD_L_H
+#define LLVM_LIBC_SRC_STDLIB_STRTOD_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+double strtod_l(const char *__restrict str, char **__restrict str_end, locale_t locale);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDLIB_STRTOD_L_H
diff --git a/libc/src/stdlib/strtof_l.cpp b/libc/src/stdlib/strtof_l.cpp
new file mode 100644
index 0000000000000..f8e480fc10411
--- /dev/null
+++ b/libc/src/stdlib/strtof_l.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of strtof_l -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdlib/strtof_l.h"
+#include "src/stdlib/strtof.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(float, strtof_l,
+                   (const char *__restrict str, char **__restrict str_end, locale_t)) {
+  return strtof(str, str_end);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdlib/strtof_l.h b/libc/src/stdlib/strtof_l.h
new file mode 100644
index 0000000000000..290b7825d1d04
--- /dev/null
+++ b/libc/src/stdlib/strtof_l.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for strtof_l -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDLIB_STRTOF_L_H
+#define LLVM_LIBC_SRC_STDLIB_STRTOF_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+float strtof_l(const char *__restrict str, char **__restrict str_end, locale_t locale);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDLIB_STRTOF_L_H
diff --git a/libc/src/stdlib/strtold_l.cpp b/libc/src/stdlib/strtold_l.cpp
new file mode 100644
index 0000000000000..0756d81ea4c2b
--- /dev/null
+++ b/libc/src/stdlib/strtold_l.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of strtold_l ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdlib/strtold_l.h"
+#include "src/stdlib/strtold.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(long double, strtold_l,
+                   (const char *__restrict str, char **__restrict str_end, locale_t)) {
+
+  return strtold(str, str_end);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdlib/strtold_l.h b/libc/src/stdlib/strtold_l.h
new file mode 100644
index 0000000000000..e66e68c9dc463
--- /dev/null
+++ b/libc/src/stdlib/strtold_l.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for strtold_l ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDLIB_STRTOLD_L_H
+#define LLVM_LIBC_SRC_STDLIB_STRTOLD_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+long double strtold_l(const char *__restrict str, char **__restrict str_end, locale_t locale);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDLIB_STRTOLD_L_H
diff --git a/libc/src/stdlib/strtoll_l.cpp b/libc/src/stdlib/strtoll_l.cpp
new file mode 100644
index 0000000000000..d48d1b1c13449
--- /dev/null
+++ b/libc/src/stdlib/strtoll_l.cpp
@@ -0,0 +1,22 @@
+//===-- Implementation of strtoll_l ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdlib/strtoll_l.h"
+#include "src/stdlib/strtoll.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(long long, strtoll_l,
+                   (const char *__restrict str, char **__restrict str_end,
+                    int base, locale_t)) {
+ 
+  return strtoll(str, str_end, base);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdlib/strtoll_l.h b/libc/src/stdlib/strtoll_l.h
new file mode 100644
index 0000000000000..b0e1122e64880
--- /dev/null
+++ b/libc/src/stdlib/strtoll_l.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for strtoll -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDLIB_STRTOLL_L_H
+#define LLVM_LIBC_SRC_STDLIB_STRTOLL_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+long long strtoll_l(const char *__restrict str, char **__restrict str_end,
+                  int base, locale_t);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDLIB_STRTOLL_L_H

>From eecf66309472d5a90b91bb0989a7003c4afc2a16 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 12:30:00 -0700
Subject: [PATCH 25/40] fixup! locale type ref

---
 libc/src/stdlib/CMakeLists.txt | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt
index 88995f73b313c..4eb363ec74351 100644
--- a/libc/src/stdlib/CMakeLists.txt
+++ b/libc/src/stdlib/CMakeLists.txt
@@ -526,7 +526,7 @@ add_entrypoint_object(
   DEPENDS
     libc.src.stdlib.strtof
     libc.src.errno.errno
-    .llvm-libc-types.locale_t
+    libc.include.llvm-libc-types.locale_t
 )
 
 add_entrypoint_object(
@@ -538,7 +538,7 @@ add_entrypoint_object(
   DEPENDS
     libc.src.stdlib.strtod
     libc.src.errno.errno
-    .llvm-libc-types.locale_t
+    libc.include.llvm-libc-types.locale_t
 )
 
 add_entrypoint_object(
@@ -550,7 +550,7 @@ add_entrypoint_object(
   DEPENDS
     libc.src.stdlib.strtold
     libc.src.errno.errno
-    .llvm-libc-types.locale_t
+    libc.include.llvm-libc-types.locale_t
 )
 
 add_entrypoint_object(
@@ -562,5 +562,5 @@ add_entrypoint_object(
   DEPENDS
     libc.src.stdlib.strtoull_l
     libc.src.errno.errno
-    .llvm-libc-types.locale_t
+    libc.include.llvm-libc-types.locale_t
 )

>From 6c17d9f48fea986234e71ad2268a810fd7600770 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 12:32:35 -0700
Subject: [PATCH 26/40] fixup! locale recursive target

---
 libc/src/stdlib/CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt
index 4eb363ec74351..c7c9853c37568 100644
--- a/libc/src/stdlib/CMakeLists.txt
+++ b/libc/src/stdlib/CMakeLists.txt
@@ -560,7 +560,7 @@ add_entrypoint_object(
   HDRS
     strtoull_l.h
   DEPENDS
-    libc.src.stdlib.strtoull_l
+    libc.src.stdlib.strtoull
     libc.src.errno.errno
     libc.include.llvm-libc-types.locale_t
 )

>From 1e04f9a649b1b36fc3bbd9cf02c0a201e8a8a9b9 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 12:37:37 -0700
Subject: [PATCH 27/40] fixup! locale whoops

---
 libc/config/linux/aarch64/entrypoints.txt |  1 +
 libc/config/linux/x86_64/entrypoints.txt  |  2 +-
 libc/src/stdlib/CMakeLists.txt            | 12 ++++++++++++
 3 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 85a9d35b38d83..1e116cb9e5f03 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -339,6 +339,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.stdlib.strtod_l
     libc.src.stdlib.strtold_l
     libc.src.stdlib.strtoull_l
+    libc.src.stdlib.strtoll_l
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index a8ba2aa9bcb6d..a85f7548b7d5e 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -351,7 +351,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.stdlib.strtod_l
     libc.src.stdlib.strtold_l
     libc.src.stdlib.strtoull_l
- 
+    libc.src.stdlib.strtoll_l
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt
index c7c9853c37568..4fc93c7bcdb91 100644
--- a/libc/src/stdlib/CMakeLists.txt
+++ b/libc/src/stdlib/CMakeLists.txt
@@ -564,3 +564,15 @@ add_entrypoint_object(
     libc.src.errno.errno
     libc.include.llvm-libc-types.locale_t
 )
+
+add_entrypoint_object(
+  strtoll_l
+  SRCS
+    strtoll_l.cpp
+  HDRS
+    strtoll_l.h
+  DEPENDS
+    libc.src.stdlib.strtoll
+    libc.src.errno.errno
+    libc.include.llvm-libc-types.locale_t
+)

>From a9b420cc8981af8342fd0ec538da1ab4eeec490f Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 12:39:52 -0700
Subject: [PATCH 28/40] fixup! locale lol forgot file

---
 libc/src/stdlib/strtoull_l.cpp | 22 ++++++++++++++++++++++
 libc/src/stdlib/strtoull_l.h   | 21 +++++++++++++++++++++
 2 files changed, 43 insertions(+)
 create mode 100644 libc/src/stdlib/strtoull_l.cpp
 create mode 100644 libc/src/stdlib/strtoull_l.h

diff --git a/libc/src/stdlib/strtoull_l.cpp b/libc/src/stdlib/strtoull_l.cpp
new file mode 100644
index 0000000000000..039d1ed61ba81
--- /dev/null
+++ b/libc/src/stdlib/strtoull_l.cpp
@@ -0,0 +1,22 @@
+//===-- Implementation of strtoull_l --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdlib/strtoull_l.h"
+#include "src/stdlib/strtoull.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(unsigned long long, strtoull,
+                   (const char *__restrict str, char **__restrict str_end,
+                    int base, locale_t)) {
+
+  return strtoull(str, str_end, base);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdlib/strtoull_l.h b/libc/src/stdlib/strtoull_l.h
new file mode 100644
index 0000000000000..3c22c00074942
--- /dev/null
+++ b/libc/src/stdlib/strtoull_l.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for strtoull_l --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDLIB_STRTOULL_H
+#define LLVM_LIBC_SRC_STDLIB_STRTOULL_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+unsigned long long strtoull_l(const char *__restrict str,
+                            char **__restrict str_end, int base, locale_t locale);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDLIB_STRTOULL_H

>From eac22733934993e11752ef1eefe43215d7356564 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 12:41:23 -0700
Subject: [PATCH 29/40] fixup! locale fix header def

---
 libc/src/stdlib/strtoull_l.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/libc/src/stdlib/strtoull_l.h b/libc/src/stdlib/strtoull_l.h
index 3c22c00074942..a7c1ae197f9d5 100644
--- a/libc/src/stdlib/strtoull_l.h
+++ b/libc/src/stdlib/strtoull_l.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_LIBC_SRC_STDLIB_STRTOULL_H
-#define LLVM_LIBC_SRC_STDLIB_STRTOULL_H
+#ifndef LLVM_LIBC_SRC_STDLIB_STRTOULL_L_H
+#define LLVM_LIBC_SRC_STDLIB_STRTOULL_L_H
 
 #include "include/llvm-libc-types/locale_t.h"
 
@@ -18,4 +18,4 @@ unsigned long long strtoull_l(const char *__restrict str,
 
 } // namespace LIBC_NAMESPACE
 
-#endif // LLVM_LIBC_SRC_STDLIB_STRTOULL_H
+#endif // LLVM_LIBC_SRC_STDLIB_STRTOULL_L_H

>From 81391e6c53c4b3ba868b0b65ea296850b8a1569d Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 12:48:37 -0700
Subject: [PATCH 30/40] fixup! locale add stdlib locale_t

---
 libc/include/locale.h.def | 2 ++
 libc/include/stdlib.h.def | 1 +
 2 files changed, 3 insertions(+)

diff --git a/libc/include/locale.h.def b/libc/include/locale.h.def
index de284933b8b21..656344031d927 100644
--- a/libc/include/locale.h.def
+++ b/libc/include/locale.h.def
@@ -10,6 +10,8 @@
 #define LLVM_LIBC_LOCALE_H
 
 #include "llvm-libc-macros/locale-macros.h"
+#include "llvm-libc-types/locale_t.h"
+#include "llvm-libc-types/struct_lconv.h"
 
 %%public_api()
 
diff --git a/libc/include/stdlib.h.def b/libc/include/stdlib.h.def
index d523f7a53024a..34a11d4e78a77 100644
--- a/libc/include/stdlib.h.def
+++ b/libc/include/stdlib.h.def
@@ -11,6 +11,7 @@
 
 #include "__llvm-libc-common.h"
 #include "llvm-libc-macros/stdlib-macros.h"
+#include "llvm-libc-types/locale_t.h"
 
 %%public_api()
 

>From 88f05c205e65fbdc77b56d7a53f6f08c55f2ae0f Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 12:52:18 -0700
Subject: [PATCH 31/40] fixup! locale fn name

---
 libc/src/stdlib/strtoull_l.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/stdlib/strtoull_l.cpp b/libc/src/stdlib/strtoull_l.cpp
index 039d1ed61ba81..4a246826a413d 100644
--- a/libc/src/stdlib/strtoull_l.cpp
+++ b/libc/src/stdlib/strtoull_l.cpp
@@ -12,7 +12,7 @@
 
 namespace LIBC_NAMESPACE {
 
-LLVM_LIBC_FUNCTION(unsigned long long, strtoull,
+LLVM_LIBC_FUNCTION(unsigned long long, strtoull_l,
                    (const char *__restrict str, char **__restrict str_end,
                     int base, locale_t)) {
 

>From 1d00a3ef251d1751f557d986a65ea1a9764c5309 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 13:24:11 -0700
Subject: [PATCH 32/40] fixup! more locale funcs

---
 libc/config/linux/aarch64/entrypoints.txt |  5 +++++
 libc/config/linux/x86_64/entrypoints.txt  |  2 ++
 libc/include/ctype.h.def                  |  1 +
 libc/spec/stdc.td                         | 10 ++++++++++
 libc/src/ctype/CMakeLists.txt             | 24 +++++++++++++++++++++++
 libc/src/ctype/isdigit_l.cpp              | 19 ++++++++++++++++++
 libc/src/ctype/isdigit_l.h                | 20 +++++++++++++++++++
 libc/src/ctype/isxdigit_l.cpp             | 23 ++++++++++++++++++++++
 libc/src/ctype/isxdigit_l.h               | 20 +++++++++++++++++++
 9 files changed, 124 insertions(+)
 create mode 100644 libc/src/ctype/isdigit_l.cpp
 create mode 100644 libc/src/ctype/isdigit_l.h
 create mode 100644 libc/src/ctype/isxdigit_l.cpp
 create mode 100644 libc/src/ctype/isxdigit_l.h

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 1e116cb9e5f03..18afdb6e7ce19 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -310,6 +310,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.unistd.write
 
     # XXX
+    libc.src.stdio.ungetc
+    libc.src.stdio.getc
     libc.src.assert.__assert_fail
     libc.src.sys.time.utimes
     libc.src.sys.statvfs.fstatvfs
@@ -340,6 +342,9 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.stdlib.strtold_l
     libc.src.stdlib.strtoull_l
     libc.src.stdlib.strtoll_l
+    libc.src.ctype.isdigit_l
+    libc.src.ctype.isxdigit_l
+    
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index a85f7548b7d5e..fa86cbba1aafc 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -352,6 +352,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.stdlib.strtold_l
     libc.src.stdlib.strtoull_l
     libc.src.stdlib.strtoll_l
+    libc.src.ctype.isdigit_l
+    libc.src.ctype.isxdigit_l
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/include/ctype.h.def b/libc/include/ctype.h.def
index a9bb786931ead..a6fc61a61fced 100644
--- a/libc/include/ctype.h.def
+++ b/libc/include/ctype.h.def
@@ -10,6 +10,7 @@
 #define LLVM_LIBC_CTYPE_H
 
 #include "__llvm-libc-common.h"
+#include "llvm-libc-types/locale_t.h"
 
 %%public_api()
 
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 0153fd1835872..3326e0786f27f 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -108,6 +108,16 @@ def StdC : StandardSpec<"stdc"> {
               RetValSpec<IntType>,
               [ArgSpec<IntType>]
           >,
+          FunctionSpec<
+              "isdigit_l",
+              RetValSpec<IntType>,
+              [ArgSpec<IntType, LocaleTType>]
+          >,
+          FunctionSpec<
+              "isxdigit_l",
+              RetValSpec<IntType>,
+              [ArgSpec<IntType, LocaleTType>]
+          >,
       ]
   >;
 
diff --git a/libc/src/ctype/CMakeLists.txt b/libc/src/ctype/CMakeLists.txt
index ae4eec9615dc1..ebe1948dbbb08 100644
--- a/libc/src/ctype/CMakeLists.txt
+++ b/libc/src/ctype/CMakeLists.txt
@@ -146,3 +146,27 @@ add_entrypoint_object(
   DEPENDS
     libc.src.__support.ctype_utils
 )
+
+add_entrypoint_object(
+  isdigit_l
+  SRCS
+    isdigit_l.cpp
+  HDRS
+    isdigit_l.h
+  DEPENDS
+    libc.src.ctype.isdigit
+    libc.include.llvm-libc-types.locale_t
+    libc.src.__support.ctype_utils
+)
+
+add_entrypoint_object(
+  isxdigit_l
+  SRCS
+    isxdigit_l.cpp
+  HDRS
+    isxdigit_l.h
+  DEPENDS
+    libc.src.ctype.isxdigit
+    libc.include.llvm-libc-types.locale_t
+    libc.src.__support.ctype_utils
+)
diff --git a/libc/src/ctype/isdigit_l.cpp b/libc/src/ctype/isdigit_l.cpp
new file mode 100644
index 0000000000000..24efd563582cc
--- /dev/null
+++ b/libc/src/ctype/isdigit_l.cpp
@@ -0,0 +1,19 @@
+//===-- Implementation of isdigit------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/ctype/isdigit_l.h"
+#include "src/ctype/isdigit.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(int, isdigit_l, (int c, locale_t)) {
+  return isdigit(c);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/ctype/isdigit_l.h b/libc/src/ctype/isdigit_l.h
new file mode 100644
index 0000000000000..eca38c198b816
--- /dev/null
+++ b/libc/src/ctype/isdigit_l.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for isdigit_l -----------------------*-C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_CTYPE_ISDIGIT_L_H
+#define LLVM_LIBC_SRC_CTYPE_ISDIGIT_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+int isdigit_l(int c, locale_t locale);
+
+} // namespace LIBC_NAMESPACE
+
+#endif //  LLVM_LIBC_SRC_CTYPE_ISDIGIT_L_H
diff --git a/libc/src/ctype/isxdigit_l.cpp b/libc/src/ctype/isxdigit_l.cpp
new file mode 100644
index 0000000000000..cdb6c0543898a
--- /dev/null
+++ b/libc/src/ctype/isxdigit_l.cpp
@@ -0,0 +1,23 @@
+//===-- Implementation of isxdigit_l---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/ctype/isxdigit_l.h"
+#include "src/ctype/isxdigit.h"
+#include "src/__support/ctype_utils.h"
+
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+// TODO: Currently restricted to default locale.
+// These should be extended using locale information.
+LLVM_LIBC_FUNCTION(int, isxdigit_l, (int c, locale_t)) {
+  return isxdigit(c);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/ctype/isxdigit_l.h b/libc/src/ctype/isxdigit_l.h
new file mode 100644
index 0000000000000..875f584ba0a10
--- /dev/null
+++ b/libc/src/ctype/isxdigit_l.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for isxdigit_l ----------------------*-C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_CTYPE_ISXDIGIT_L_H
+#define LLVM_LIBC_SRC_CTYPE_ISXDIGIT_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+int isxdigit_l(int c, locale_t);
+
+} // namespace LIBC_NAMESPACE
+
+#endif //  LLVM_LIBC_SRC_CTYPE_ISXDIGIT_L_H

>From 47aa7633c9dfe714d73d9cbab28a1f4aa46697a4 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 13:24:31 -0700
Subject: [PATCH 33/40] fixup! locale MB_CUR_MAX macro

---
 libc/include/llvm-libc-macros/stdlib-macros.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/libc/include/llvm-libc-macros/stdlib-macros.h b/libc/include/llvm-libc-macros/stdlib-macros.h
index 5fcbfef97b328..f53328b3d9e99 100644
--- a/libc/include/llvm-libc-macros/stdlib-macros.h
+++ b/libc/include/llvm-libc-macros/stdlib-macros.h
@@ -19,4 +19,8 @@
 
 #define RAND_MAX 2147483647
 
+// N.B. If current thread is utf8 then this is 4
+// otherwise it is 1. Leaving at 4 to be safe.
+#define MB_CUR_MAX 4
+
 #endif // LLVM_LIBC_MACROS_STDLIB_MACROS_H

>From 09af3109f6da7f1adcad593aaf5957f52871c9cb Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 13:25:04 -0700
Subject: [PATCH 34/40] [libc]: add `vsscanf` and `vaprintf`

---
 libc/config/linux/aarch64/entrypoints.txt |  2 ++
 libc/config/linux/x86_64/entrypoints.txt  |  2 ++
 libc/spec/stdc.td                         | 14 ++++++++++++
 libc/src/stdio/CMakeLists.txt             | 20 ++++++++++++++++
 libc/src/stdio/vaprintf.cpp               | 27 ++++++++++++++++++++++
 libc/src/stdio/vaprintf.h                 | 22 ++++++++++++++++++
 libc/src/stdio/vsscanf.cpp                | 28 +++++++++++++++++++++++
 libc/src/stdio/vsscanf.h                  | 21 +++++++++++++++++
 8 files changed, 136 insertions(+)
 create mode 100644 libc/src/stdio/vaprintf.cpp
 create mode 100644 libc/src/stdio/vaprintf.h
 create mode 100644 libc/src/stdio/vsscanf.cpp
 create mode 100644 libc/src/stdio/vsscanf.h

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 18afdb6e7ce19..8e2ee32f7f933 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -344,6 +344,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.stdlib.strtoll_l
     libc.src.ctype.isdigit_l
     libc.src.ctype.isxdigit_l
+    libc.src.stdio.vsscanf
+    libc.src.stdio.vaprintf
     
 )
 
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index fa86cbba1aafc..d1a6211c2d0eb 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -354,6 +354,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.stdlib.strtoll_l
     libc.src.ctype.isdigit_l
     libc.src.ctype.isxdigit_l
+    libc.src.stdio.vsscanf
+    libc.src.stdio.vaprintf
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 3326e0786f27f..79634e71d8dac 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -975,6 +975,20 @@ def StdC : StandardSpec<"stdc"> {
               RetValSpec<IntType>,
               [ArgSpec<IntType>, ArgSpec<FILEPtr>]
           >,
+          FunctionSpec<
+              "vaprintf",
+              RetValSpec<IntType>,
+              [ArgSpec<CharPtr>,
+               ArgSpec<ConstCharPtr>,
+               ArgSpec<VaListType>]
+          >,
+          FunctionSpec<
+              "vsscanf",
+              RetValSpec<IntType>,
+              [ArgSpec<ConstCharPtr>,
+               ArgSpec<ConstCharPtr>,
+               ArgSpec<VaListType>]
+          >,
       ],
       [
           ObjectSpec<
diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt
index a659d9e847a9e..6bbb7a7db76dd 100644
--- a/libc/src/stdio/CMakeLists.txt
+++ b/libc/src/stdio/CMakeLists.txt
@@ -203,6 +203,26 @@ add_entrypoint_object(
     libc.src.stdio.printf_core.vfprintf_internal
 )
 
+add_entrypoint_object(
+  vaprintf
+  SRCS
+    vaprintf.cpp
+  HDRS
+    vaprintf.h
+  DEPENDS
+    libc.src.__support.arg_list
+)
+
+add_entrypoint_object(
+  vsscanf
+  SRCS
+    vsscanf.cpp
+  HDRS
+    vsscanf.h
+  DEPENDS
+    libc.src.__support.arg_list
+)
+
 add_stdio_entrypoint_object(
   fileno
   SRCS
diff --git a/libc/src/stdio/vaprintf.cpp b/libc/src/stdio/vaprintf.cpp
new file mode 100644
index 0000000000000..21e9ff0ba64a4
--- /dev/null
+++ b/libc/src/stdio/vaprintf.cpp
@@ -0,0 +1,27 @@
+//===-- Implementation of vaprintf ------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdio/vaprintf.h"
+
+#include "src/__support/arg_list.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(int, vaprintf,
+                   (char *, const char *,
+                    va_list vlist)) {
+  internal::ArgList args(vlist); // This holder class allows for easier copying
+                                 // and pointer semantics, as well as handling
+                                 // destruction automatically.
+  return -1;
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdio/vaprintf.h b/libc/src/stdio/vaprintf.h
new file mode 100644
index 0000000000000..6a6521c622fd8
--- /dev/null
+++ b/libc/src/stdio/vaprintf.h
@@ -0,0 +1,22 @@
+//===-- Implementation header of vaprintf -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDIO_VAPRINTF_H
+#define LLVM_LIBC_SRC_STDIO_VAPRINTF_H
+
+#include <stdarg.h>
+#include <stdio.h>
+
+namespace LIBC_NAMESPACE {
+
+int vaprintf(char * s, const char * format,
+             va_list vlist);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDIO_VAPRINTF_H
diff --git a/libc/src/stdio/vsscanf.cpp b/libc/src/stdio/vsscanf.cpp
new file mode 100644
index 0000000000000..b5c9173387ea0
--- /dev/null
+++ b/libc/src/stdio/vsscanf.cpp
@@ -0,0 +1,28 @@
+//===-- Implementation of vsscanf -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdio/vsscanf.h"
+
+#include "src/__support/arg_list.h"
+
+#include <stdarg.h>
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(int, vsscanf,
+                   (const char *, const char *,
+                    va_list vlist)) {
+  internal::ArgList args(vlist); // This holder class allows for easier copying
+                                 // and pointer semantics, as well as handling
+                                 // destruction automatically.
+
+  
+  return -1;
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdio/vsscanf.h b/libc/src/stdio/vsscanf.h
new file mode 100644
index 0000000000000..5f32f7ed351b1
--- /dev/null
+++ b/libc/src/stdio/vsscanf.h
@@ -0,0 +1,21 @@
+//===-- Implementation header of vsscanf ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDIO_VSSCANF_H
+#define LLVM_LIBC_SRC_STDIO_VSSCANF_H
+
+#include <stdarg.h>
+
+namespace LIBC_NAMESPACE {
+
+int vsscanf(const char * s, const char * format,
+             va_list vlist);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDIO_VSSCANF_H

>From 15ac0f03a991b78de4afef5ff312d3f49957a1b9 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 13:27:16 -0700
Subject: [PATCH 35/40] fixup! locale _l typedef fixes

---
 libc/spec/stdc.td | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 79634e71d8dac..92f3a3c0fb833 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -111,12 +111,12 @@ def StdC : StandardSpec<"stdc"> {
           FunctionSpec<
               "isdigit_l",
               RetValSpec<IntType>,
-              [ArgSpec<IntType, LocaleTType>]
+              [ArgSpec<IntType>, ArgSpec<LocaleTType>]
           >,
           FunctionSpec<
               "isxdigit_l",
               RetValSpec<IntType>,
-              [ArgSpec<IntType, LocaleTType>]
+              [ArgSpec<IntType>, ArgSpec<LocaleTType>]
           >,
       ]
   >;

>From 91ad488a1c64a3dca054718af9cb6721f8171b83 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 13:33:02 -0700
Subject: [PATCH 36/40] fixup! vaprintf -> vasprintf

---
 libc/config/linux/aarch64/entrypoints.txt      |  2 +-
 libc/config/linux/x86_64/entrypoints.txt       |  2 +-
 libc/spec/stdc.td                              |  4 ++--
 libc/src/stdio/CMakeLists.txt                  |  6 +++---
 libc/src/stdio/{vaprintf.cpp => vasprintf.cpp} |  8 ++++----
 libc/src/stdio/{vaprintf.h => vasprintf.h}     | 10 +++++-----
 6 files changed, 16 insertions(+), 16 deletions(-)
 rename libc/src/stdio/{vaprintf.cpp => vasprintf.cpp} (79%)
 rename libc/src/stdio/{vaprintf.h => vasprintf.h} (64%)

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 8e2ee32f7f933..ef490412a2d64 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -345,7 +345,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.ctype.isdigit_l
     libc.src.ctype.isxdigit_l
     libc.src.stdio.vsscanf
-    libc.src.stdio.vaprintf
+    libc.src.stdio.vasprintf
     
 )
 
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index d1a6211c2d0eb..a9741fad2c31a 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -355,7 +355,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.ctype.isdigit_l
     libc.src.ctype.isxdigit_l
     libc.src.stdio.vsscanf
-    libc.src.stdio.vaprintf
+    libc.src.stdio.vasprintf
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 92f3a3c0fb833..9bde311fdc71e 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -976,9 +976,9 @@ def StdC : StandardSpec<"stdc"> {
               [ArgSpec<IntType>, ArgSpec<FILEPtr>]
           >,
           FunctionSpec<
-              "vaprintf",
+              "vasprintf",
               RetValSpec<IntType>,
-              [ArgSpec<CharPtr>,
+              [ArgSpec<CharRestrictedPtrPtr>,
                ArgSpec<ConstCharPtr>,
                ArgSpec<VaListType>]
           >,
diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt
index 6bbb7a7db76dd..909361b808fa0 100644
--- a/libc/src/stdio/CMakeLists.txt
+++ b/libc/src/stdio/CMakeLists.txt
@@ -204,11 +204,11 @@ add_entrypoint_object(
 )
 
 add_entrypoint_object(
-  vaprintf
+  vasprintf
   SRCS
-    vaprintf.cpp
+    vasprintf.cpp
   HDRS
-    vaprintf.h
+    vasprintf.h
   DEPENDS
     libc.src.__support.arg_list
 )
diff --git a/libc/src/stdio/vaprintf.cpp b/libc/src/stdio/vasprintf.cpp
similarity index 79%
rename from libc/src/stdio/vaprintf.cpp
rename to libc/src/stdio/vasprintf.cpp
index 21e9ff0ba64a4..d625d98e83706 100644
--- a/libc/src/stdio/vaprintf.cpp
+++ b/libc/src/stdio/vasprintf.cpp
@@ -1,4 +1,4 @@
-//===-- Implementation of vaprintf ------------------------------*- C++ -*-===//
+//===-- Implementation of vasprintf -----------------------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "src/stdio/vaprintf.h"
+#include "src/stdio/vasprintf.h"
 
 #include "src/__support/arg_list.h"
 
@@ -15,8 +15,8 @@
 
 namespace LIBC_NAMESPACE {
 
-LLVM_LIBC_FUNCTION(int, vaprintf,
-                   (char *, const char *,
+LLVM_LIBC_FUNCTION(int, vasprintf,
+                   (char **__restrict, const char *,
                     va_list vlist)) {
   internal::ArgList args(vlist); // This holder class allows for easier copying
                                  // and pointer semantics, as well as handling
diff --git a/libc/src/stdio/vaprintf.h b/libc/src/stdio/vasprintf.h
similarity index 64%
rename from libc/src/stdio/vaprintf.h
rename to libc/src/stdio/vasprintf.h
index 6a6521c622fd8..f9b1d85ef81fb 100644
--- a/libc/src/stdio/vaprintf.h
+++ b/libc/src/stdio/vasprintf.h
@@ -1,4 +1,4 @@
-//===-- Implementation header of vaprintf -----------------------*- C++ -*-===//
+//===-- Implementation header of vasprintf ----------------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,17 +6,17 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_LIBC_SRC_STDIO_VAPRINTF_H
-#define LLVM_LIBC_SRC_STDIO_VAPRINTF_H
+#ifndef LLVM_LIBC_SRC_STDIO_VASPRINTF_H
+#define LLVM_LIBC_SRC_STDIO_VASPRINTF_H
 
 #include <stdarg.h>
 #include <stdio.h>
 
 namespace LIBC_NAMESPACE {
 
-int vaprintf(char * s, const char * format,
+int vasprintf(char **__restrict s, const char * format,
              va_list vlist);
 
 } // namespace LIBC_NAMESPACE
 
-#endif // LLVM_LIBC_SRC_STDIO_VAPRINTF_H
+#endif // LLVM_LIBC_SRC_STDIO_VASPRINTF_H

>From 59e2b1d33928c7992a98d2a0ebed36cf6b00d2fe Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 13:38:47 -0700
Subject: [PATCH 37/40] [libcxx]: no `<langinfo.h>` in llvm libc

---
 libcxx/src/locale.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/src/locale.cpp b/libcxx/src/locale.cpp
index 4efdc63c09661..d114640ab7104 100644
--- a/libcxx/src/locale.cpp
+++ b/libcxx/src/locale.cpp
@@ -34,7 +34,7 @@
 #  define _CTYPE_DISABLE_MACROS
 #endif
 
-#if !defined(_LIBCPP_MSVCRT) && !defined(__MINGW32__) && !defined(__BIONIC__) && !defined(__NuttX__)
+#if !defined(_LIBCPP_MSVCRT) && !defined(__MINGW32__) && !defined(__BIONIC__) && !defined(__NuttX__)  && !defined(__LLVM_LIBC__)
 #  include <langinfo.h>
 #endif
 

>From 3e9557c0c3f1c704c51586891fca9a5d3dd577ab Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 14:01:47 -0700
Subject: [PATCH 38/40] fixup! more locale funcs

---
 libc/config/linux/aarch64/entrypoints.txt |  8 ++++
 libc/config/linux/x86_64/entrypoints.txt  |  6 +++
 libc/spec/stdc.td                         | 20 +++++++++
 libc/src/ctype/CMakeLists.txt             | 49 +++++++++++++++++++++++
 libc/src/ctype/islower_l.cpp              | 22 ++++++++++
 libc/src/ctype/islower_l.h                | 20 +++++++++
 libc/src/ctype/isupper_l.cpp              | 22 ++++++++++
 libc/src/ctype/isupper_l.h                | 20 +++++++++
 libc/src/ctype/tolower_l.cpp              | 20 +++++++++
 libc/src/ctype/tolower_l.h                | 20 +++++++++
 libc/src/ctype/toupper_l.cpp              | 23 +++++++++++
 libc/src/ctype/toupper_l.h                | 20 +++++++++
 libc/src/string/CMakeLists.txt            | 22 ++++++++++
 libc/src/string/strcoll_l.cpp             | 21 ++++++++++
 libc/src/string/strcoll_l.h               | 20 +++++++++
 libc/src/string/strxfrm_l.cpp             | 23 +++++++++++
 libc/src/string/strxfrm_l.h               | 21 ++++++++++
 17 files changed, 357 insertions(+)
 create mode 100644 libc/src/ctype/islower_l.cpp
 create mode 100644 libc/src/ctype/islower_l.h
 create mode 100644 libc/src/ctype/isupper_l.cpp
 create mode 100644 libc/src/ctype/isupper_l.h
 create mode 100644 libc/src/ctype/tolower_l.cpp
 create mode 100644 libc/src/ctype/tolower_l.h
 create mode 100644 libc/src/ctype/toupper_l.cpp
 create mode 100644 libc/src/ctype/toupper_l.h
 create mode 100644 libc/src/string/strcoll_l.cpp
 create mode 100644 libc/src/string/strcoll_l.h
 create mode 100644 libc/src/string/strxfrm_l.cpp
 create mode 100644 libc/src/string/strxfrm_l.h

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index ef490412a2d64..ebef5927fdfeb 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -310,6 +310,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.unistd.write
 
     # XXX
+    libc.src.string.strxfrm
+    libc.src.string.strcoll
     libc.src.stdio.ungetc
     libc.src.stdio.getc
     libc.src.assert.__assert_fail
@@ -344,6 +346,12 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.stdlib.strtoll_l
     libc.src.ctype.isdigit_l
     libc.src.ctype.isxdigit_l
+    libc.src.ctype.islower_l
+    libc.src.ctype.isupper_l
+    libc.src.ctype.tolower_l
+    libc.src.ctype.toupper_l
+    libc.src.string.strxfrm_l
+    libc.src.string.strcoll_l
     libc.src.stdio.vsscanf
     libc.src.stdio.vasprintf
     
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index a9741fad2c31a..98527abb3fd67 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -354,6 +354,12 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.stdlib.strtoll_l
     libc.src.ctype.isdigit_l
     libc.src.ctype.isxdigit_l
+    libc.src.ctype.islower_l
+    libc.src.ctype.isupper_l
+    libc.src.ctype.tolower_l
+    libc.src.ctype.toupper_l
+    libc.src.string.strxfrm_l
+    libc.src.string.strcoll_l
     libc.src.stdio.vsscanf
     libc.src.stdio.vasprintf
 )
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 9bde311fdc71e..fa3f2238097e6 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -118,6 +118,26 @@ def StdC : StandardSpec<"stdc"> {
               RetValSpec<IntType>,
               [ArgSpec<IntType>, ArgSpec<LocaleTType>]
           >,
+          FunctionSpec<
+              "tolower_l",
+              RetValSpec<IntType>,
+              [ArgSpec<IntType>, ArgSpec<LocaleTType>]
+          >,
+          FunctionSpec<
+              "toupper_l",
+              RetValSpec<IntType>,
+              [ArgSpec<IntType>, ArgSpec<LocaleTType>]
+          >,
+          FunctionSpec<
+              "islower_l",
+              RetValSpec<IntType>,
+              [ArgSpec<IntType>, ArgSpec<LocaleTType>]
+          >,
+          FunctionSpec<
+              "isupper_l",
+              RetValSpec<IntType>,
+              [ArgSpec<IntType>, ArgSpec<LocaleTType>]
+          >,
       ]
   >;
 
diff --git a/libc/src/ctype/CMakeLists.txt b/libc/src/ctype/CMakeLists.txt
index ebe1948dbbb08..19e5ef609e93c 100644
--- a/libc/src/ctype/CMakeLists.txt
+++ b/libc/src/ctype/CMakeLists.txt
@@ -170,3 +170,52 @@ add_entrypoint_object(
     libc.include.llvm-libc-types.locale_t
     libc.src.__support.ctype_utils
 )
+
+
+add_entrypoint_object(
+  islower_l
+  SRCS
+    islower_l.cpp
+  HDRS
+    islower_l.h
+  DEPENDS
+    libc.src.ctype.islower
+    libc.include.llvm-libc-types.locale_t
+    libc.src.__support.ctype_utils
+)
+
+add_entrypoint_object(
+  isupper_l
+  SRCS
+    isupper_l.cpp
+  HDRS
+    isupper_l.h
+  DEPENDS
+    libc.src.ctype.isupper
+    libc.include.llvm-libc-types.locale_t
+    libc.src.__support.ctype_utils
+)
+
+add_entrypoint_object(
+  tolower_l
+  SRCS
+    tolower_l.cpp
+  HDRS
+    tolower_l.h
+  DEPENDS
+    libc.src.ctype.tolower
+    libc.include.llvm-libc-types.locale_t
+    libc.src.__support.ctype_utils
+)
+
+add_entrypoint_object(
+  toupper_l
+  SRCS
+    toupper_l.cpp
+  HDRS
+    toupper_l.h
+  DEPENDS
+    libc.src.ctype.toupper
+    libc.include.llvm-libc-types.locale_t
+    libc.src.__support.ctype_utils
+)
diff --git a/libc/src/ctype/islower_l.cpp b/libc/src/ctype/islower_l.cpp
new file mode 100644
index 0000000000000..45977dc637fbb
--- /dev/null
+++ b/libc/src/ctype/islower_l.cpp
@@ -0,0 +1,22 @@
+//===-- Implementation of islower_l----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/ctype/islower_l.h"
+#include "src/ctype/islower.h"
+
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+// TODO: Currently restricted to default locale.
+// These should be extended using locale information.
+LLVM_LIBC_FUNCTION(int, islower_l, (int c, locale_t)) {
+  return islower(c);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/ctype/islower_l.h b/libc/src/ctype/islower_l.h
new file mode 100644
index 0000000000000..dee277ce9af97
--- /dev/null
+++ b/libc/src/ctype/islower_l.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for islower_l -----------------------*-C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_CTYPE_ISLOWER_L_H
+#define LLVM_LIBC_SRC_CTYPE_ISLOWER_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+int islower_l(int c, locale_t locale);
+
+} // namespace LIBC_NAMESPACE
+
+#endif //  LLVM_LIBC_SRC_CTYPE_ISLOWER_L_H
diff --git a/libc/src/ctype/isupper_l.cpp b/libc/src/ctype/isupper_l.cpp
new file mode 100644
index 0000000000000..e3b1250b940af
--- /dev/null
+++ b/libc/src/ctype/isupper_l.cpp
@@ -0,0 +1,22 @@
+//===-- Implementation of isupper_l----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/ctype/isupper_l.h"
+#include "src/ctype/isupper.h"
+
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+// TODO: Currently restricted to default locale.
+// These should be extended using locale information.
+LLVM_LIBC_FUNCTION(int, isupper_l, (int c, locale_t)) {
+  return isupper(c);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/ctype/isupper_l.h b/libc/src/ctype/isupper_l.h
new file mode 100644
index 0000000000000..fbd49c97cb7fa
--- /dev/null
+++ b/libc/src/ctype/isupper_l.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for isupper -------------------------*-C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_CTYPE_ISUPPER_L_H
+#define LLVM_LIBC_SRC_CTYPE_ISUPPER_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+int isupper_l(int c, locale_t locale);
+
+} // namespace LIBC_NAMESPACE
+
+#endif //  LLVM_LIBC_SRC_CTYPE_ISUPPER_L_H
diff --git a/libc/src/ctype/tolower_l.cpp b/libc/src/ctype/tolower_l.cpp
new file mode 100644
index 0000000000000..c89c6d7038138
--- /dev/null
+++ b/libc/src/ctype/tolower_l.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of tolower_l----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/ctype/tolower_l.h"
+#include "src/ctype/tolower.h"
+
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+// TODO: Currently restricted to default locale.
+// These should be extended using locale information.
+LLVM_LIBC_FUNCTION(int, tolower_l, (int c, locale_t)) { return tolower(c); }
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/ctype/tolower_l.h b/libc/src/ctype/tolower_l.h
new file mode 100644
index 0000000000000..624526dbe8f30
--- /dev/null
+++ b/libc/src/ctype/tolower_l.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for tolower_l -----------------------*-C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_CTYPE_TOLOWER_L_H
+#define LLVM_LIBC_SRC_CTYPE_TOLOWER_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+int tolower_l(int c, locale_t locale);
+
+} // namespace LIBC_NAMESPACE
+
+#endif //  LLVM_LIBC_SRC_CTYPE_TOLOWER_L_H
diff --git a/libc/src/ctype/toupper_l.cpp b/libc/src/ctype/toupper_l.cpp
new file mode 100644
index 0000000000000..5806f22d699e6
--- /dev/null
+++ b/libc/src/ctype/toupper_l.cpp
@@ -0,0 +1,23 @@
+//===-- Implementation of toupper_l----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/ctype/toupper_l.h"
+#include "src/ctype/toupper.h"
+#include "src/__support/ctype_utils.h"
+
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+// TODO: Currently restricted to default locale.
+// These should be extended using locale information.
+LLVM_LIBC_FUNCTION(int, toupper_l, (int c, locale_t)) {
+  return toupper(c);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/ctype/toupper_l.h b/libc/src/ctype/toupper_l.h
new file mode 100644
index 0000000000000..22a6b5c968b63
--- /dev/null
+++ b/libc/src/ctype/toupper_l.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for toupper_l -----------------------*-C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_CTYPE_TOUPPER_L_H
+#define LLVM_LIBC_SRC_CTYPE_TOUPPER_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+int toupper_l(int c, locale_t locale);
+
+} // namespace LIBC_NAMESPACE
+
+#endif //  LLVM_LIBC_SRC_CTYPE_TOUPPER_L_H
diff --git a/libc/src/string/CMakeLists.txt b/libc/src/string/CMakeLists.txt
index 56588ffafb86f..794e9206aded4 100644
--- a/libc/src/string/CMakeLists.txt
+++ b/libc/src/string/CMakeLists.txt
@@ -452,6 +452,28 @@ add_entrypoint_object(
     .memory_utils.inline_memset
 )
 
+add_entrypoint_object(
+  strcoll_l
+  SRCS
+    strcoll_l.cpp
+  HDRS
+    strcoll_l.h
+  DEPENDS
+    .strcoll
+    libc.include.llvm-libc-types.locale_t
+)
+
+add_entrypoint_object(
+  strxfrm_l
+  SRCS
+    strxfrm_l.cpp
+  HDRS
+    strxfrm_l.h
+  DEPENDS
+    .strxfrm
+    libc.include.llvm-libc-types.locale_t
+)
+
 # Helper to define a function with multiple implementations
 # - Computes flags to satisfy required/rejected features and arch,
 # - Declares an entry point,
diff --git a/libc/src/string/strcoll_l.cpp b/libc/src/string/strcoll_l.cpp
new file mode 100644
index 0000000000000..5392b3553b3b1
--- /dev/null
+++ b/libc/src/string/strcoll_l.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of strcoll_l ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/string/strcoll_l.h"
+#include "src/string/strcoll.h"
+
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+// TODO: Add support for locales.
+LLVM_LIBC_FUNCTION(int, strcoll_l, (const char *left, const char *right, locale_t)) {
+  return strcoll(left, right);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/string/strcoll_l.h b/libc/src/string/strcoll_l.h
new file mode 100644
index 0000000000000..0eee80125a942
--- /dev/null
+++ b/libc/src/string/strcoll_l.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for strcoll_l ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STRING_STRCOLL_L_H
+#define LLVM_LIBC_SRC_STRING_STRCOLL_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+int strcoll_l(const char *left, const char *right, locale_t locale);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STRING_STRCOLL_L_H
diff --git a/libc/src/string/strxfrm_l.cpp b/libc/src/string/strxfrm_l.cpp
new file mode 100644
index 0000000000000..28f20985c28b4
--- /dev/null
+++ b/libc/src/string/strxfrm_l.cpp
@@ -0,0 +1,23 @@
+//===-- Implementation of strxfrm_l ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/string/strxfrm_l.h"
+#include "src/string/strxfrm.h"
+
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+// TODO: Add support for locales.
+LLVM_LIBC_FUNCTION(size_t, strxfrm_l,
+                   (char *__restrict dest, const char *__restrict src,
+                    size_t n, locale_t)) {
+  return strxfrm(dest, src, n);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/string/strxfrm_l.h b/libc/src/string/strxfrm_l.h
new file mode 100644
index 0000000000000..ae958a16f3254
--- /dev/null
+++ b/libc/src/string/strxfrm_l.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for strxfrm_l -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STRING_STRXFRM_L_H
+#define LLVM_LIBC_SRC_STRING_STRXFRM_L_H
+
+#include <stddef.h> // For size_t
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+size_t strxfrm_l(char *__restrict dest, const char *__restrict src, size_t n, locale_t locale);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STRING_STRXFRM_L_H

>From 5de914c7c85d66eb4074ebc33dd6e584985a0349 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 14:25:08 -0700
Subject: [PATCH 39/40] fixup! more locale stuff and strftime

---
 libc/config/linux/aarch64/entrypoints.txt |  3 +-
 libc/config/linux/x86_64/entrypoints.txt  |  2 ++
 libc/spec/stdc.td                         | 37 +++++++++++++++++++++++
 libc/src/time/CMakeLists.txt              | 24 +++++++++++++++
 libc/src/time/strftime.cpp                | 21 +++++++++++++
 libc/src/time/strftime.h                  | 22 ++++++++++++++
 libc/src/time/strftime_l.cpp              | 22 ++++++++++++++
 libc/src/time/strftime_l.h                | 24 +++++++++++++++
 8 files changed, 154 insertions(+), 1 deletion(-)
 create mode 100644 libc/src/time/strftime.cpp
 create mode 100644 libc/src/time/strftime.h
 create mode 100644 libc/src/time/strftime_l.cpp
 create mode 100644 libc/src/time/strftime_l.h

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index ebef5927fdfeb..67201cb7b983d 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -354,7 +354,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.string.strcoll_l
     libc.src.stdio.vsscanf
     libc.src.stdio.vasprintf
-    
+    libc.src.time.strftime
+    libc.src.time.strftime_l
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 98527abb3fd67..88cafa239d1b3 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -362,6 +362,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.string.strcoll_l
     libc.src.stdio.vsscanf
     libc.src.stdio.vasprintf
+    libc.src.time.strftime
+    libc.src.time.strftime_l
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index fa3f2238097e6..34fd70f54409b 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -2,6 +2,8 @@ def StdC : StandardSpec<"stdc"> {
 
   NamedType StructTmType = NamedType<"struct tm">;
   PtrType StructTmPtr = PtrType<StructTmType>;
+  RestrictedPtrType StructTmRestrictedPtr = RestrictedPtrType<StructTmType>;
+  
   PtrType TimeTTypePtr = PtrType<TimeTType>;
   NamedType ClockT = NamedType<"clock_t">;
 
@@ -1189,6 +1191,20 @@ def StdC : StandardSpec<"stdc"> {
           FunctionSpec<"strtoul_l", RetValSpec<UnsignedLongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>, ArgSpec<LocaleTType>]>,
           FunctionSpec<"strtoull_l", RetValSpec<UnsignedLongLongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>, ArgSpec<LocaleTType>]>,
 
+          FunctionSpec<
+              "strxfrm_l",
+              RetValSpec<SizeTType>,
+              [ArgSpec<CharRestrictedPtr>,
+               ArgSpec<ConstCharRestrictedPtr>,
+               ArgSpec<SizeTType>,
+               ArgSpec<LocaleTType>]
+          >,
+          FunctionSpec<
+              "strcoll_l",
+              RetValSpec<IntType>,
+              [ArgSpec<ConstCharPtr>, ArgSpec<ConstCharPtr>, ArgSpec<LocaleTType>]
+          >,
+
           FunctionSpec<"malloc", RetValSpec<VoidPtr>, [ArgSpec<SizeTType>]>,
           FunctionSpec<"calloc", RetValSpec<VoidPtr>, [ArgSpec<SizeTType>, ArgSpec<SizeTType>]>,
           FunctionSpec<"realloc", RetValSpec<VoidPtr>, [ArgSpec<VoidPtr>, ArgSpec<SizeTType>]>,
@@ -1490,6 +1506,27 @@ def StdC : StandardSpec<"stdc"> {
               RetValSpec<TimeTType>,
               [ArgSpec<StructTmPtr>]
           >,
+          FunctionSpec<
+              "strftime",
+              RetValSpec<SizeTType>,
+              [
+                ArgSpec<CharRestrictedPtr>,
+                ArgSpec<SizeTType>,
+                ArgSpec<ConstCharRestrictedPtr>,
+                ArgSpec<StructTmRestrictedPtr>
+              ]
+          >,
+          FunctionSpec<
+              "strftime_l",
+              RetValSpec<SizeTType>,
+              [
+                ArgSpec<CharRestrictedPtr>,
+                ArgSpec<SizeTType>,
+                ArgSpec<ConstCharRestrictedPtr>,
+                ArgSpec<StructTmRestrictedPtr>,
+                ArgSpec<LocaleTType>
+              ]
+          >,          
           FunctionSpec<
               "time",
               RetValSpec<TimeTType>,
diff --git a/libc/src/time/CMakeLists.txt b/libc/src/time/CMakeLists.txt
index 5680718715974..b71da9ddf8665 100644
--- a/libc/src/time/CMakeLists.txt
+++ b/libc/src/time/CMakeLists.txt
@@ -80,6 +80,30 @@ add_entrypoint_object(
     libc.src.errno.errno
 )
 
+add_entrypoint_object(
+  strftime
+  SRCS
+    strftime.cpp
+  HDRS
+    strftime.h
+  DEPENDS
+    .time_utils
+    libc.include.time
+)
+
+add_entrypoint_object(
+  strftime_l
+  SRCS
+    strftime_l.cpp
+  HDRS
+    strftime_l.h
+  DEPENDS
+    .strftime
+    .time_utils
+    libc.include.time
+    libc.include.llvm-libc-types.locale_t
+)
+
 add_entrypoint_object(
   time
   ALIAS
diff --git a/libc/src/time/strftime.cpp b/libc/src/time/strftime.cpp
new file mode 100644
index 0000000000000..8eee127ff7df8
--- /dev/null
+++ b/libc/src/time/strftime.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of strftime function -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/time/strftime.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+
+LLVM_LIBC_FUNCTION(size_t, strftime, (char*__restrict, size_t,
+                       const char *__restrict,
+                       const struct tm *__restrict)) {
+  return 0;
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/time/strftime.h b/libc/src/time/strftime.h
new file mode 100644
index 0000000000000..be1f2144c747f
--- /dev/null
+++ b/libc/src/time/strftime.h
@@ -0,0 +1,22 @@
+//===-- Implementation header of strftime -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_TIME_STRFTIME_H
+#define LLVM_LIBC_SRC_TIME_STRFTIME_H
+
+#include <time.h>
+
+namespace LIBC_NAMESPACE {
+
+size_t strftime(char*__restrict s, size_t max,
+                       const char *__restrict format,
+                       const struct tm *__restrict tm);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_TIME_STRFTIME_H
diff --git a/libc/src/time/strftime_l.cpp b/libc/src/time/strftime_l.cpp
new file mode 100644
index 0000000000000..61fe199614010
--- /dev/null
+++ b/libc/src/time/strftime_l.cpp
@@ -0,0 +1,22 @@
+//===-- Implementation of strftime_l function -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/time/strftime_l.h"
+#include "src/time/strftime.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+
+LLVM_LIBC_FUNCTION(size_t, strftime_l, (char*__restrict arg1, size_t arg2,
+                       const char *__restrict arg3,
+                       const struct tm *__restrict arg4, locale_t)) {
+  return strftime(arg1, arg2, arg3, arg4);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/time/strftime_l.h b/libc/src/time/strftime_l.h
new file mode 100644
index 0000000000000..44b0ae902fdb4
--- /dev/null
+++ b/libc/src/time/strftime_l.h
@@ -0,0 +1,24 @@
+//===-- Implementation header of strftime_l ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_TIME_STRFTIME_L_H
+#define LLVM_LIBC_SRC_TIME_STRFTIME_L_H
+
+#include <time.h>
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+size_t strftime_l(char*__restrict s, size_t max,
+                       const char *__restrict format,
+                       const struct tm *__restrict tm,
+                       locale_t locale);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_TIME_STRFTIME_L_H

>From bfec5e7a968713f55a8c1961ef2cbedb3ffe8437 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 14:30:12 -0700
Subject: [PATCH 40/40] fixup! strftime add size_t

---
 libc/src/time/CMakeLists.txt | 2 ++
 libc/src/time/strftime.h     | 1 +
 libc/src/time/strftime_l.h   | 1 +
 3 files changed, 4 insertions(+)

diff --git a/libc/src/time/CMakeLists.txt b/libc/src/time/CMakeLists.txt
index b71da9ddf8665..18f391fb16510 100644
--- a/libc/src/time/CMakeLists.txt
+++ b/libc/src/time/CMakeLists.txt
@@ -89,6 +89,7 @@ add_entrypoint_object(
   DEPENDS
     .time_utils
     libc.include.time
+    libc.include.llvm-libc-types.size_t
 )
 
 add_entrypoint_object(
@@ -102,6 +103,7 @@ add_entrypoint_object(
     .time_utils
     libc.include.time
     libc.include.llvm-libc-types.locale_t
+    libc.include.llvm-libc-types.size_t
 )
 
 add_entrypoint_object(
diff --git a/libc/src/time/strftime.h b/libc/src/time/strftime.h
index be1f2144c747f..93890175b6044 100644
--- a/libc/src/time/strftime.h
+++ b/libc/src/time/strftime.h
@@ -10,6 +10,7 @@
 #define LLVM_LIBC_SRC_TIME_STRFTIME_H
 
 #include <time.h>
+#include "include/llvm-libc-types/size_t.h"
 
 namespace LIBC_NAMESPACE {
 
diff --git a/libc/src/time/strftime_l.h b/libc/src/time/strftime_l.h
index 44b0ae902fdb4..9d4786665ba2f 100644
--- a/libc/src/time/strftime_l.h
+++ b/libc/src/time/strftime_l.h
@@ -11,6 +11,7 @@
 
 #include <time.h>
 #include "include/llvm-libc-types/locale_t.h"
+#include "include/llvm-libc-types/size_t.h"
 
 namespace LIBC_NAMESPACE {
 



More information about the libcxx-commits mailing list