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

Izaak Schroeder via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 2 11:26:30 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/20] [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/20] [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/20] [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/20] [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/20] [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/20] [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/20] [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/20] [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/20] [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/20] [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/20] [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/20] 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/20] 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/20] 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/20] [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/20] [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/20] [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/20] [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/20] [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 eb2f2370ebf3241b4dfa462b1898f6501e665bc1 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/20] [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..54807eb3083fc 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..53bbfc6ff0e25
--- /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 = {
+	.decimal_point = ".",
+	.thousands_sep = "",
+	.grouping = "",
+	.int_curr_symbol = "",
+	.currency_symbol = "",
+	.mon_decimal_point = "",
+	.mon_thousands_sep = "",
+	.mon_grouping = "",
+	.positive_sign = "",
+	.negative_sign = "",
+	.int_frac_digits = CHAR_MAX,
+	.frac_digits = CHAR_MAX,
+	.p_cs_precedes = CHAR_MAX,
+	.p_sep_by_space = CHAR_MAX,
+	.n_cs_precedes = CHAR_MAX,
+	.n_sep_by_space = CHAR_MAX,
+	.p_sign_posn = CHAR_MAX,
+	.n_sign_posn = 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_p_sign_posn = CHAR_MAX,
+	.int_n_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



More information about the cfe-commits mailing list