[libc-commits] [libc] [llvm] [libc][NFC] Port raw syscall users to existing syscall_wrappers (PR #208039)

Mikhail R. Gadelha via libc-commits libc-commits at lists.llvm.org
Wed Jul 8 08:25:59 PDT 2026


https://github.com/mikhailramalho updated https://github.com/llvm/llvm-project/pull/208039

>From b5b0a16cabfb183f82c560573a63e56629971db2 Mon Sep 17 00:00:00 2001
From: "Mikhail R. Gadelha" <mikhail at igalia.com>
Date: Mon, 6 Jul 2026 22:26:14 -0300
Subject: [PATCH 1/4] [libc][NFC] Port raw syscall users to existing
 syscall_wrappers

Several call sites still invoked syscall_impl directly (or carried
their own SYS_* fallback ladders) for syscalls that already have a
wrapper in src/__support/OSUtil/linux/syscall_wrappers:

- shm_unlink: drop the local SYS_unlink/SYS_unlinkat ladder, use
  linux_syscalls::unlink (resolves the TODO).
- remove: use linux_syscalls::unlinkat.
- sched_getaffinity: use linux_syscalls::sched_getaffinity.
- ftok: use linux_syscalls::statx with the shared kernel_statx_types
  and delete the private sys/ipc/linux/kernel_statx.h wrapper.
- File/linux/file.cpp, File/linux/dir.cpp, threads/linux/thread.cpp:
  use the read/write/close wrappers.

No functional change intended.
---
 libc/src/__support/File/linux/CMakeLists.txt  |  4 +++
 libc/src/__support/File/linux/dir.cpp         |  7 ++--
 libc/src/__support/File/linux/file.cpp        | 29 ++++++++--------
 .../__support/threads/linux/CMakeLists.txt    |  3 ++
 libc/src/__support/threads/linux/thread.cpp   | 26 ++++++++------
 libc/src/sched/linux/CMakeLists.txt           |  3 +-
 libc/src/sched/linux/sched_getaffinity.cpp    | 14 ++++----
 libc/src/stdio/linux/CMakeLists.txt           |  4 +--
 libc/src/stdio/linux/remove.cpp               | 15 ++++----
 libc/src/sys/ipc/linux/CMakeLists.txt         | 15 ++------
 libc/src/sys/ipc/linux/ftok.cpp               | 12 ++++---
 libc/src/sys/ipc/linux/kernel_statx.h         | 34 -------------------
 libc/src/sys/mman/linux/CMakeLists.txt        |  1 +
 libc/src/sys/mman/linux/shm_unlink.cpp        | 23 ++++---------
 .../llvm-project-overlay/libc/BUILD.bazel     | 10 +++---
 15 files changed, 82 insertions(+), 118 deletions(-)
 delete mode 100644 libc/src/sys/ipc/linux/kernel_statx.h

diff --git a/libc/src/__support/File/linux/CMakeLists.txt b/libc/src/__support/File/linux/CMakeLists.txt
index ba64ecf41a76e..bd2a20439b999 100644
--- a/libc/src/__support/File/linux/CMakeLists.txt
+++ b/libc/src/__support/File/linux/CMakeLists.txt
@@ -13,8 +13,11 @@ add_object_library(
     libc.include.sys_stat
     libc.src.__support.CPP.new
     libc.src.__support.OSUtil.osutil
+    libc.src.__support.OSUtil.linux.syscall_wrappers.close
     libc.src.__support.OSUtil.linux.syscall_wrappers.lseek
     libc.src.__support.OSUtil.linux.syscall_wrappers.open
+    libc.src.__support.OSUtil.linux.syscall_wrappers.read
+    libc.src.__support.OSUtil.linux.syscall_wrappers.write
     libc.src.__support.error_or
     libc.src.__support.File.file
     libc.src.errno.errno
@@ -31,6 +34,7 @@ add_object_library(
     libc.hdr.sys_stat_macros
     libc.src.__support.OSUtil.linux.stat.kernel_statx_types
     libc.src.__support.OSUtil.osutil
+    libc.src.__support.OSUtil.linux.syscall_wrappers.close
     libc.src.__support.OSUtil.linux.syscall_wrappers.open
     libc.src.__support.OSUtil.linux.syscall_wrappers.statx
     libc.src.__support.OSUtil.linux.syscall_wrappers.fcntl
diff --git a/libc/src/__support/File/linux/dir.cpp b/libc/src/__support/File/linux/dir.cpp
index 77f9a51952c3b..e2b93271107c5 100644
--- a/libc/src/__support/File/linux/dir.cpp
+++ b/libc/src/__support/File/linux/dir.cpp
@@ -15,6 +15,7 @@
 #include "hdr/fcntl_macros.h"    // For open flags
 #include "hdr/sys_stat_macros.h" // For S_ISDIR
 #include "src/__support/OSUtil/linux/stat/kernel_statx_types.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/close.h"
 #include "src/__support/OSUtil/linux/syscall_wrappers/fcntl.h"
 #include "src/__support/OSUtil/linux/syscall_wrappers/open.h"
 #include "src/__support/OSUtil/linux/syscall_wrappers/statx.h"
@@ -42,9 +43,9 @@ ErrorOr<size_t> platform_fetch_dirents(int fd, cpp::span<uint8_t> buffer) {
 }
 
 int platform_closedir(int fd) {
-  int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_close, fd);
-  if (ret < 0)
-    return static_cast<int>(-ret);
+  auto ret = linux_syscalls::close(fd);
+  if (!ret)
+    return ret.error();
   return 0;
 }
 
diff --git a/libc/src/__support/File/linux/file.cpp b/libc/src/__support/File/linux/file.cpp
index e89b3d118deb1..b022037673762 100644
--- a/libc/src/__support/File/linux/file.cpp
+++ b/libc/src/__support/File/linux/file.cpp
@@ -13,37 +13,36 @@
 #include "src/__support/CPP/new.h"
 #include "src/__support/File/file.h"
 #include "src/__support/OSUtil/fcntl.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/close.h"
 #include "src/__support/OSUtil/linux/syscall_wrappers/lseek.h"
 #include "src/__support/OSUtil/linux/syscall_wrappers/open.h"
-#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/OSUtil/linux/syscall_wrappers/read.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/write.h"
 #include "src/__support/alloc-checker.h"
 #include "src/__support/libc_errno.h" // For error macros
 #include "src/__support/macros/config.h"
 
 #include "hdr/fcntl_macros.h" // For mode_t and other flags to the open syscall
 #include <sys/stat.h>         // For S_IS*, S_IF*, and S_IR* flags.
-#include <sys/syscall.h>      // For syscall numbers
 
 namespace LIBC_NAMESPACE_DECL {
 
 FileIOResult linux_file_write(File *f, const void *data, size_t size) {
   auto *lf = reinterpret_cast<LinuxFile *>(f);
-  int ret =
-      LIBC_NAMESPACE::syscall_impl<int>(SYS_write, lf->get_fd(), data, size);
-  if (ret < 0) {
-    return {0, -ret};
+  auto ret = linux_syscalls::write(lf->get_fd(), data, size);
+  if (!ret) {
+    return {0, ret.error()};
   }
-  return ret;
+  return static_cast<size_t>(ret.value());
 }
 
 FileIOResult linux_file_read(File *f, void *buf, size_t size) {
   auto *lf = reinterpret_cast<LinuxFile *>(f);
-  int ret =
-      LIBC_NAMESPACE::syscall_impl<int>(SYS_read, lf->get_fd(), buf, size);
-  if (ret < 0) {
-    return {0, -ret};
+  auto ret = linux_syscalls::read(lf->get_fd(), buf, size);
+  if (!ret) {
+    return {0, ret.error()};
   }
-  return ret;
+  return static_cast<size_t>(ret.value());
 }
 
 ErrorOr<off_t> linux_file_seek(File *f, off_t offset, int whence) {
@@ -54,9 +53,9 @@ ErrorOr<off_t> linux_file_seek(File *f, off_t offset, int whence) {
 int linux_file_close(File *f) {
   File::remove_file(f);
   auto *lf = reinterpret_cast<LinuxFile *>(f);
-  int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_close, lf->get_fd());
-  if (ret < 0) {
-    return -ret;
+  auto ret = linux_syscalls::close(lf->get_fd());
+  if (!ret) {
+    return ret.error();
   }
   delete lf;
   return 0;
diff --git a/libc/src/__support/threads/linux/CMakeLists.txt b/libc/src/__support/threads/linux/CMakeLists.txt
index 8344c6c0462a3..f9f2a455cd7a1 100644
--- a/libc/src/__support/threads/linux/CMakeLists.txt
+++ b/libc/src/__support/threads/linux/CMakeLists.txt
@@ -41,10 +41,13 @@ add_object_library(
     libc.src.__support.CPP.string_view
     libc.src.__support.common
     libc.src.__support.error_or
+    libc.src.__support.OSUtil.linux.syscall_wrappers.close
     libc.src.__support.OSUtil.linux.syscall_wrappers.mmap
     libc.src.__support.OSUtil.linux.syscall_wrappers.mprotect
     libc.src.__support.OSUtil.linux.syscall_wrappers.munmap
     libc.src.__support.OSUtil.linux.syscall_wrappers.open
+    libc.src.__support.OSUtil.linux.syscall_wrappers.read
+    libc.src.__support.OSUtil.linux.syscall_wrappers.write
     libc.src.__support.threads.thread_common
   COMPILE_OPTIONS
     ${libc_opt_high_flag}
diff --git a/libc/src/__support/threads/linux/thread.cpp b/libc/src/__support/threads/linux/thread.cpp
index 64e043862ff74..1983ff67768bc 100644
--- a/libc/src/__support/threads/linux/thread.cpp
+++ b/libc/src/__support/threads/linux/thread.cpp
@@ -11,10 +11,13 @@
 #include "src/__support/CPP/atomic.h"
 #include "src/__support/CPP/string_view.h"
 #include "src/__support/CPP/stringstream.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/close.h"
 #include "src/__support/OSUtil/linux/syscall_wrappers/mmap.h"
 #include "src/__support/OSUtil/linux/syscall_wrappers/mprotect.h"
 #include "src/__support/OSUtil/linux/syscall_wrappers/munmap.h"
 #include "src/__support/OSUtil/linux/syscall_wrappers/open.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/read.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/write.h"
 #include "src/__support/OSUtil/syscall.h" // For syscall functions.
 #include "src/__support/common.h"
 #include "src/__support/error_or.h"
@@ -435,13 +438,13 @@ int Thread::set_name(const cpp::string_view &name) {
   if (!fd)
     return fd.error();
 
-  int retval = LIBC_NAMESPACE::syscall_impl<int>(SYS_write, fd.value(),
-                                                 name.data(), name.size());
-  LIBC_NAMESPACE::syscall_impl<long>(SYS_close, fd.value());
+  auto write_result = linux_syscalls::write(fd.value(), name.data(),
+                                            name.size());
+  linux_syscalls::close(fd.value());
 
-  if (retval < 0)
-    return -retval;
-  else if (retval != int(name.size()))
+  if (!write_result)
+    return write_result.error();
+  else if (write_result.value() != static_cast<ssize_t>(name.size()))
     return EIO;
   else
     return 0;
@@ -471,11 +474,12 @@ int Thread::get_name(cpp::StringStream &name) const {
   if (!fd)
     return fd.error();
 
-  int retval = LIBC_NAMESPACE::syscall_impl<int>(SYS_read, fd.value(),
-                                                 name_buffer, NAME_SIZE_MAX);
-  LIBC_NAMESPACE::syscall_impl<long>(SYS_close, fd.value());
-  if (retval < 0)
-    return -retval;
+  auto read_result =
+      linux_syscalls::read(fd.value(), name_buffer, NAME_SIZE_MAX);
+  linux_syscalls::close(fd.value());
+  if (!read_result)
+    return read_result.error();
+  int retval = static_cast<int>(read_result.value());
   if (retval == NAME_SIZE_MAX)
     return ERANGE;
   if (name_buffer[retval - 1] == '\n')
diff --git a/libc/src/sched/linux/CMakeLists.txt b/libc/src/sched/linux/CMakeLists.txt
index 9ffb59b8c0d06..85d298f311d38 100644
--- a/libc/src/sched/linux/CMakeLists.txt
+++ b/libc/src/sched/linux/CMakeLists.txt
@@ -20,7 +20,8 @@ add_entrypoint_object(
     libc.hdr.types.cpu_set_t
     libc.hdr.types.pid_t
     libc.hdr.types.size_t
-    libc.src.__support.OSUtil.osutil
+    libc.src.__support.CPP.span
+    libc.src.__support.OSUtil.linux.syscall_wrappers.sched_getaffinity
     libc.src.errno.errno
 )
 
diff --git a/libc/src/sched/linux/sched_getaffinity.cpp b/libc/src/sched/linux/sched_getaffinity.cpp
index d652f7f7ddc35..ddb34aed5e3b4 100644
--- a/libc/src/sched/linux/sched_getaffinity.cpp
+++ b/libc/src/sched/linux/sched_getaffinity.cpp
@@ -9,7 +9,8 @@
 #include "src/sched/sched_getaffinity.h"
 
 #include "hdr/stdint_proxy.h"
-#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/CPP/span.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/sched_getaffinity.h"
 #include "src/__support/common.h"
 #include "src/__support/libc_errno.h"
 #include "src/__support/macros/config.h"
@@ -17,18 +18,19 @@
 #include "hdr/types/cpu_set_t.h"
 #include "hdr/types/pid_t.h"
 #include "hdr/types/size_t.h"
-#include <sys/syscall.h> // For syscall numbers.
 
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(int, sched_getaffinity,
                    (pid_t tid, size_t cpuset_size, cpu_set_t *mask)) {
-  int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_sched_getaffinity, tid,
-                                              cpuset_size, mask);
-  if (ret < 0) {
-    libc_errno = -ret;
+  auto result = linux_syscalls::sched_getaffinity(
+      tid, cpp::span<unsigned char>(reinterpret_cast<unsigned char *>(mask),
+                                    cpuset_size));
+  if (!result) {
+    libc_errno = result.error();
     return -1;
   }
+  int ret = result.value();
   if (size_t(ret) < cpuset_size) {
     // This means that only |ret| bytes in |mask| have been set. We will have to
     // zero out the remaining bytes.
diff --git a/libc/src/stdio/linux/CMakeLists.txt b/libc/src/stdio/linux/CMakeLists.txt
index 1552060c52550..218875c78e246 100644
--- a/libc/src/stdio/linux/CMakeLists.txt
+++ b/libc/src/stdio/linux/CMakeLists.txt
@@ -5,10 +5,10 @@ add_entrypoint_object(
   HDRS
     ../remove.h
   DEPENDS
+    libc.hdr.errno_macros
     libc.hdr.fcntl_macros
     libc.include.unistd
-    libc.include.sys_syscall
-    libc.src.__support.OSUtil.osutil
+    libc.src.__support.OSUtil.linux.syscall_wrappers.unlinkat
     libc.src.errno.errno
 )
 
diff --git a/libc/src/stdio/linux/remove.cpp b/libc/src/stdio/linux/remove.cpp
index ac755db0bc781..2e1a581474359 100644
--- a/libc/src/stdio/linux/remove.cpp
+++ b/libc/src/stdio/linux/remove.cpp
@@ -8,26 +8,25 @@
 
 #include "src/stdio/remove.h"
 
-#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/OSUtil/linux/syscall_wrappers/unlinkat.h"
 #include "src/__support/common.h"
 
+#include "hdr/errno_macros.h" // For EISDIR.
 #include "hdr/fcntl_macros.h" // For AT_* macros.
 #include "src/__support/libc_errno.h"
 #include "src/__support/macros/config.h"
-#include <sys/syscall.h> // For syscall numbers.
 
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(int, remove, (const char *path)) {
   // We first try unlinking it as a file. If it is ia file, it will succeed. If
   // it fails with EISDIR, we will try unlinking it as a directory.
-  int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_unlinkat, AT_FDCWD, path, 0);
-  if (ret == -EISDIR)
-    ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_unlinkat, AT_FDCWD, path,
-                                            AT_REMOVEDIR);
-  if (ret >= 0)
+  auto ret = linux_syscalls::unlinkat(AT_FDCWD, path, 0);
+  if (!ret && ret.error() == EISDIR)
+    ret = linux_syscalls::unlinkat(AT_FDCWD, path, AT_REMOVEDIR);
+  if (ret)
     return 0;
-  libc_errno = -ret;
+  libc_errno = ret.error();
   return -1;
 }
 
diff --git a/libc/src/sys/ipc/linux/CMakeLists.txt b/libc/src/sys/ipc/linux/CMakeLists.txt
index d5b2d1b8ab77c..b237e998e6e2c 100644
--- a/libc/src/sys/ipc/linux/CMakeLists.txt
+++ b/libc/src/sys/ipc/linux/CMakeLists.txt
@@ -1,14 +1,3 @@
-add_header_library(
-  kernel_statx
-  HDRS
-    kernel_statx.h
-  DEPENDS
-    libc.hdr.fcntl_macros
-    libc.include.sys_syscall
-    libc.src.__support.error_or
-    libc.src.__support.OSUtil.osutil
-)
-
 add_entrypoint_object(
   ftok
   SRCS
@@ -16,8 +5,10 @@ add_entrypoint_object(
   HDRS
     ../ftok.h
   DEPENDS
-    .kernel_statx
+    libc.hdr.fcntl_macros
     libc.hdr.types.key_t
+    libc.src.__support.OSUtil.linux.stat.kernel_statx_types
+    libc.src.__support.OSUtil.linux.syscall_wrappers.statx
     libc.src.__support.common
     libc.src.errno.errno
 )
diff --git a/libc/src/sys/ipc/linux/ftok.cpp b/libc/src/sys/ipc/linux/ftok.cpp
index 28762ac6e33f1..1aa78292bfc62 100644
--- a/libc/src/sys/ipc/linux/ftok.cpp
+++ b/libc/src/sys/ipc/linux/ftok.cpp
@@ -7,18 +7,20 @@
 //===----------------------------------------------------------------------===//
 #include "src/sys/ipc/ftok.h"
 
+#include "hdr/fcntl_macros.h" // For AT_FDCWD.
+#include "src/__support/OSUtil/linux/stat/kernel_statx_types.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/statx.h"
 #include "src/__support/common.h"
-#include "src/__support/error_or.h"
 #include "src/__support/libc_errno.h"
 
-#include "kernel_statx.h"
-
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(key_t, ftok, (const char *path, int id)) {
-  struct statx xbuf;
+  internal::kernel_statx_buf xbuf;
 
-  ErrorOr<int> err = statx_for_ftok(path, xbuf);
+  auto err = linux_syscalls::statx(AT_FDCWD, path, 0,
+                                   internal::KERNEL_STATX_BASIC_STATS_MASK,
+                                   &xbuf);
 
   if (!err.has_value()) {
     libc_errno = err.error();
diff --git a/libc/src/sys/ipc/linux/kernel_statx.h b/libc/src/sys/ipc/linux/kernel_statx.h
deleted file mode 100644
index 7613e1b50f20d..0000000000000
--- a/libc/src/sys/ipc/linux/kernel_statx.h
+++ /dev/null
@@ -1,34 +0,0 @@
-//===-- Wrapper over SYS_statx syscall for ftok ---------------------------===//
-//
-// 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_IPC_LINUX_KERNEL_STATX_H
-#define LLVM_LIBC_SRC_SYS_IPC_LINUX_KERNEL_STATX_H
-
-#include "hdr/fcntl_macros.h"
-#include "src/__support/OSUtil/syscall.h"
-#include "src/__support/error_or.h"
-#include "sys/syscall.h"
-
-#include <linux/stat.h>
-
-namespace LIBC_NAMESPACE_DECL {
-
-LIBC_INLINE ErrorOr<int> statx_for_ftok(const char *path, struct statx &xbuf) {
-
-  // store the file stats metadata into xbuf
-  int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_statx, AT_FDCWD, path, 0,
-                                              STATX_BASIC_STATS, &xbuf);
-
-  if (ret < 0)
-    return Error(-ret);
-  return 0;
-}
-
-} // namespace LIBC_NAMESPACE_DECL
-
-#endif // LLVM_LIBC_SRC_SYS_IPC_LINUX_KERNEL_STATX_H
diff --git a/libc/src/sys/mman/linux/CMakeLists.txt b/libc/src/sys/mman/linux/CMakeLists.txt
index e8d9ed384c9b0..6987261e53e07 100644
--- a/libc/src/sys/mman/linux/CMakeLists.txt
+++ b/libc/src/sys/mman/linux/CMakeLists.txt
@@ -306,6 +306,7 @@ add_entrypoint_object(
   HDRS
     ../shm_unlink.h
   DEPENDS
+    libc.src.__support.OSUtil.linux.syscall_wrappers.unlink
     libc.src.errno.errno
     .shm_common
 )
diff --git a/libc/src/sys/mman/linux/shm_unlink.cpp b/libc/src/sys/mman/linux/shm_unlink.cpp
index 7671b1918b83c..70eab7e9b4bff 100644
--- a/libc/src/sys/mman/linux/shm_unlink.cpp
+++ b/libc/src/sys/mman/linux/shm_unlink.cpp
@@ -8,37 +8,26 @@
 
 #include "src/sys/mman/shm_unlink.h"
 
-#include "hdr/fcntl_macros.h"
-#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
-#include "src/__support/libc_errno.h"     // For internal errno.
+#include "src/__support/OSUtil/linux/syscall_wrappers/unlink.h"
+#include "src/__support/libc_errno.h" // For internal errno.
 #include "src/__support/macros/config.h"
 #include "src/sys/mman/linux/shm_common.h"
-#include <sys/syscall.h> // For SYS_unlink, SYS_unlinkat
 
 namespace LIBC_NAMESPACE_DECL {
 
-// TODO: move the unlink syscall to a shared utility.
-
 LLVM_LIBC_FUNCTION(int, shm_unlink, (const char *name)) {
   auto path_result = shm_common::translate_name(name);
   if (!path_result.has_value()) {
     libc_errno = path_result.error();
     return -1;
   }
-#ifdef SYS_unlink
-  int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_unlink, path_result->data());
-#elif defined(SYS_unlinkat)
-  int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_unlinkat, AT_FDCWD,
-                                              path_result->data(), 0);
-#else
-#error "unlink and unlinkat syscalls not available."
-#endif
 
-  if (ret < 0) {
-    libc_errno = -ret;
+  auto result = linux_syscalls::unlink(path_result->data());
+  if (!result) {
+    libc_errno = result.error();
     return -1;
   }
-  return ret;
+  return 0;
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index 56ef8876c9e2d..59be503e06502 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -1553,9 +1553,11 @@ libc_support_library(
         ":__support_libc_errno",
         ":__support_macros_config",
         ":__support_osutil_fcntl",
+        ":__support_osutil_linux_syscall_wrappers_close",
         ":__support_osutil_linux_syscall_wrappers_lseek",
         ":__support_osutil_linux_syscall_wrappers_open",
-        ":__support_osutil_syscall",
+        ":__support_osutil_linux_syscall_wrappers_read",
+        ":__support_osutil_linux_syscall_wrappers_write",
         ":hdr_fcntl_macros",
         ":hdr_stdint_proxy",
         ":hdr_stdio_macros",
@@ -15447,8 +15449,9 @@ libc_function(
         ":__support_common",
         ":__support_libc_errno",
         ":__support_macros_config",
-        ":__support_osutil_syscall",
+        ":__support_osutil_linux_syscall_wrappers_unlinkat",
         ":errno",
+        ":hdr_errno_macros",
         ":hdr_fcntl_macros",
         ":hdr_stdio_overlay",
         ":types_FILE",
@@ -15835,9 +15838,8 @@ libc_function(
         ":__support_common",
         ":__support_libc_errno",
         ":__support_macros_config",
-        ":__support_osutil_syscall",
+        ":__support_osutil_linux_syscall_wrappers_unlink",
         ":errno",
-        ":hdr_fcntl_macros",
         ":shm_common",
         ":types_mode_t",
     ],

>From 3dcb792c8521a6bfb160f1127d7602473e58b7ba Mon Sep 17 00:00:00 2001
From: "Mikhail R. Gadelha" <mikhail at igalia.com>
Date: Tue, 7 Jul 2026 12:37:01 -0300
Subject: [PATCH 2/4] [libc][NFC] Port more raw syscall users to existing
 syscall_wrappers

Use the read/close wrappers in auxv.h, the close wrapper in posix_spawn,
and the getrandom wrapper in the x86_64 startup TLS setup (safe pre-TLS
since wrappers report errors via ErrorOr, not errno). Also drop the
redundant SYS_utimensat guard in utimes.cpp; the wrapper owns syscall
selection and already has the #error fallback.
---
 .../src/__support/OSUtil/linux/CMakeLists.txt |  3 +++
 libc/src/__support/OSUtil/linux/auxv.h        | 21 ++++++++++++-------
 libc/src/spawn/linux/CMakeLists.txt           |  1 +
 libc/src/spawn/linux/posix_spawn.cpp          |  3 ++-
 libc/src/sys/time/linux/CMakeLists.txt        |  2 --
 libc/src/sys/time/linux/utimes.cpp            |  8 -------
 libc/startup/linux/x86_64/CMakeLists.txt      |  1 +
 libc/startup/linux/x86_64/tls.cpp             | 11 +++++-----
 8 files changed, 26 insertions(+), 24 deletions(-)

diff --git a/libc/src/__support/OSUtil/linux/CMakeLists.txt b/libc/src/__support/OSUtil/linux/CMakeLists.txt
index 1f11067f0154f..b237cc0a811ef 100644
--- a/libc/src/__support/OSUtil/linux/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/CMakeLists.txt
@@ -32,12 +32,15 @@ add_header_library(
   HDRS
     auxv.h
   DEPENDS
+    libc.hdr.errno_macros
     libc.hdr.fcntl_macros
     libc.hdr.sys_auxv_macros
     libc.hdr.sys_mman_macros
+    libc.src.__support.OSUtil.linux.syscall_wrappers.close
     libc.src.__support.OSUtil.linux.syscall_wrappers.mmap
     libc.src.__support.OSUtil.linux.syscall_wrappers.munmap
     libc.src.__support.OSUtil.linux.syscall_wrappers.open
+    libc.src.__support.OSUtil.linux.syscall_wrappers.read
     libc.src.__support.OSUtil.osutil
     libc.src.__support.common
     libc.src.__support.CPP.optional
diff --git a/libc/src/__support/OSUtil/linux/auxv.h b/libc/src/__support/OSUtil/linux/auxv.h
index b4c990f9721bc..a6c28e078fdb8 100644
--- a/libc/src/__support/OSUtil/linux/auxv.h
+++ b/libc/src/__support/OSUtil/linux/auxv.h
@@ -9,12 +9,15 @@
 #ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_AUXV_H
 #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_AUXV_H
 
+#include "hdr/errno_macros.h"    // For EINTR
 #include "hdr/fcntl_macros.h"    // For open flags
 #include "hdr/sys_auxv_macros.h" // For AT_ macros
 #include "hdr/sys_mman_macros.h" // For mmap flags
+#include "src/__support/OSUtil/linux/syscall_wrappers/close.h"
 #include "src/__support/OSUtil/linux/syscall_wrappers/mmap.h"
 #include "src/__support/OSUtil/linux/syscall_wrappers/munmap.h"
 #include "src/__support/OSUtil/linux/syscall_wrappers/open.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/read.h"
 #include "src/__support/OSUtil/syscall.h"
 #include "src/__support/common.h"
 #include "src/__support/threads/callonce.h"
@@ -122,18 +125,20 @@ LIBC_INLINE void Vector::fallback_initialize_unsync() {
   uint8_t *cursor = reinterpret_cast<uint8_t *>(vector);
   bool has_error = false;
   while (avaiable_size != 0) {
-    long bytes_read =
-        syscall_impl<long>(SYS_read, fd.value(), cursor, avaiable_size);
-    if (bytes_read <= 0) {
-      if (bytes_read == -EINTR)
+    ErrorOr<ssize_t> bytes_read =
+        linux_syscalls::read(fd.value(), cursor, avaiable_size);
+    if (!bytes_read.has_value()) {
+      if (bytes_read.error() == EINTR)
         continue;
-      has_error = bytes_read < 0;
+      has_error = true;
       break;
     }
-    avaiable_size -= bytes_read;
-    cursor += bytes_read;
+    if (bytes_read.value() == 0)
+      break;
+    avaiable_size -= bytes_read.value();
+    cursor += bytes_read.value();
   }
-  syscall_impl<long>(SYS_close, fd.value());
+  linux_syscalls::close(fd.value());
   if (has_error) {
     linux_syscalls::munmap(vector, AUXV_MMAP_SIZE);
     return;
diff --git a/libc/src/spawn/linux/CMakeLists.txt b/libc/src/spawn/linux/CMakeLists.txt
index 42057e9f12fec..6d1db1a2a1ec4 100644
--- a/libc/src/spawn/linux/CMakeLists.txt
+++ b/libc/src/spawn/linux/CMakeLists.txt
@@ -11,6 +11,7 @@ add_entrypoint_object(
     libc.include.sys_syscall
     libc.include.signal
     libc.src.__support.OSUtil.osutil
+    libc.src.__support.OSUtil.linux.syscall_wrappers.close
     libc.src.__support.OSUtil.linux.syscall_wrappers.open
     libc.src.spawn.file_actions
     libc.src.signal.linux.signal_utils
diff --git a/libc/src/spawn/linux/posix_spawn.cpp b/libc/src/spawn/linux/posix_spawn.cpp
index 301be6d7c8762..75084a94f26f0 100644
--- a/libc/src/spawn/linux/posix_spawn.cpp
+++ b/libc/src/spawn/linux/posix_spawn.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/spawn/posix_spawn.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/close.h"
 #include "src/__support/OSUtil/linux/syscall_wrappers/open.h"
 #include "src/__support/OSUtil/syscall.h" // For internal syscall function.
 #include "src/__support/common.h"
@@ -39,7 +40,7 @@ pid_t fork() {
 #endif
 }
 
-void close(int fd) { LIBC_NAMESPACE::syscall_impl<long>(SYS_close, fd); }
+void close(int fd) { linux_syscalls::close(fd); }
 
 // We use dup3 if dup2 is not available, similar to our implementation of dup2
 bool dup2(int fd, int newfd) {
diff --git a/libc/src/sys/time/linux/CMakeLists.txt b/libc/src/sys/time/linux/CMakeLists.txt
index 60fbd14f73174..52724268c73ba 100644
--- a/libc/src/sys/time/linux/CMakeLists.txt
+++ b/libc/src/sys/time/linux/CMakeLists.txt
@@ -8,10 +8,8 @@ add_entrypoint_object(
     libc.hdr.types.struct_timespec
     libc.hdr.types.struct_timeval
     libc.hdr.fcntl_macros
-    libc.src.__support.OSUtil.osutil
     libc.src.__support.OSUtil.linux.syscall_wrappers.utimensat
     libc.include.sys_stat
-    libc.include.sys_syscall
     libc.include.fcntl
     libc.src.__support.libc_errno
 )
diff --git a/libc/src/sys/time/linux/utimes.cpp b/libc/src/sys/time/linux/utimes.cpp
index abb56183cf7c3..02101c3e38314 100644
--- a/libc/src/sys/time/linux/utimes.cpp
+++ b/libc/src/sys/time/linux/utimes.cpp
@@ -13,17 +13,12 @@
 #include "hdr/types/struct_timeval.h"
 
 #include "src/__support/OSUtil/linux/syscall_wrappers/utimensat.h"
-#include "src/__support/OSUtil/syscall.h"
 #include "src/__support/libc_errno.h"
 
-#include <sys/syscall.h>
-
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(int, utimes,
                    (const char *path, const struct timeval times[2])) {
-#if defined(SYS_utimensat) || defined(SYS_utimensat_time64)
-
   // the utimensat syscall requires a timespec struct, not timeval.
   struct timespec ts[2];
   struct timespec *ts_ptr = nullptr; // default value if times is nullptr
@@ -64,8 +59,5 @@ LLVM_LIBC_FUNCTION(int, utimes,
   }
 
   return 0;
-#else
-#error "utimensat or utimensat_time64 syscalls not available."
-#endif // SYS_utimensat || SYS_utimensat_time64
 }
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/startup/linux/x86_64/CMakeLists.txt b/libc/startup/linux/x86_64/CMakeLists.txt
index 12dc0eeef42e9..19417b345d7cf 100644
--- a/libc/startup/linux/x86_64/CMakeLists.txt
+++ b/libc/startup/linux/x86_64/CMakeLists.txt
@@ -7,6 +7,7 @@ add_startup_object(
     libc.hdr.sys_mman_macros
     libc.include.sys_syscall
     libc.src.__support.OSUtil.osutil
+    libc.src.__support.OSUtil.linux.syscall_wrappers.getrandom
     libc.src.__support.OSUtil.linux.syscall_wrappers.mmap
     libc.src.__support.OSUtil.linux.syscall_wrappers.munmap
     libc.src.string.memory_utils.inline_memcpy
diff --git a/libc/startup/linux/x86_64/tls.cpp b/libc/startup/linux/x86_64/tls.cpp
index 7856bdd14daae..98c5fbeb9d84b 100644
--- a/libc/startup/linux/x86_64/tls.cpp
+++ b/libc/startup/linux/x86_64/tls.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "hdr/sys_mman_macros.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/getrandom.h"
 #include "src/__support/OSUtil/linux/syscall_wrappers/mmap.h"
 #include "src/__support/OSUtil/linux/syscall_wrappers/munmap.h"
 #include "src/__support/macros/config.h"
@@ -57,11 +58,11 @@ void init_tls(TLSDescriptor &tls_descriptor) {
   // Setting the stack guard to a random value.
   // We cannot call the get_random function here as the function sets errno on
   // failure. Since errno is implemented via a thread local variable, we cannot
-  // use errno before TLS is setup.
-  long stack_guard_retval =
-      syscall_impl(SYS_getrandom, reinterpret_cast<long>(stack_guard_addr),
-                   sizeof(uint64_t), 0);
-  if (stack_guard_retval < 0)
+  // use errno before TLS is setup. The linux_syscalls wrapper is safe as it
+  // reports errors via ErrorOr instead of errno.
+  ErrorOr<ssize_t> stack_guard_retval =
+      linux_syscalls::getrandom(stack_guard_addr, sizeof(uint64_t), 0);
+  if (!stack_guard_retval.has_value())
     syscall_impl(SYS_exit, 1);
 
   tls_descriptor = {tls_size_with_addr, reinterpret_cast<uintptr_t>(tls_addr),

>From 93b087d1cc2d5a84d9edad194844321bb88a3d9e Mon Sep 17 00:00:00 2001
From: "Mikhail R. Gadelha" <mikhail at igalia.com>
Date: Tue, 7 Jul 2026 12:40:51 -0300
Subject: [PATCH 3/4] [libc][bazel] Add missing auxv deps for syscall wrapper
 port

Follow-up to 3dcb792c8521: mirror the new close/read wrapper and
errno_macros dependencies of auxv.h in the Bazel overlay.
---
 utils/bazel/llvm-project-overlay/libc/BUILD.bazel | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index 59be503e06502..b749584409395 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -2715,11 +2715,14 @@ libc_support_library(
     }),
     deps = [
         ":__support_common",
+        ":__support_osutil_linux_syscall_wrappers_close",
         ":__support_osutil_linux_syscall_wrappers_mmap",
         ":__support_osutil_linux_syscall_wrappers_munmap",
         ":__support_osutil_linux_syscall_wrappers_open",
+        ":__support_osutil_linux_syscall_wrappers_read",
         ":__support_osutil_syscall",
         ":__support_threads_callonce",
+        ":hdr_errno_macros",
         ":hdr_fcntl_macros",
         ":hdr_sys_auxv_macros",
         ":hdr_sys_mman_macros",

>From 8834f42249f2f9db94e6bd3149759cc9c53342cf Mon Sep 17 00:00:00 2001
From: "Mikhail R. Gadelha" <mikhail at igalia.com>
Date: Wed, 8 Jul 2026 12:25:02 -0300
Subject: [PATCH 4/4] [libc][NFC] Drop the close helper in posix_spawn

The helper became a trivial forward to linux_syscalls::close after the
syscall wrapper port, and the dup2 equivalent was already removed when
posix_spawn switched to calling the wrappers directly.
---
 libc/src/spawn/linux/posix_spawn.cpp | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/libc/src/spawn/linux/posix_spawn.cpp b/libc/src/spawn/linux/posix_spawn.cpp
index ce752b3de834e..17f985cbc9fc7 100644
--- a/libc/src/spawn/linux/posix_spawn.cpp
+++ b/libc/src/spawn/linux/posix_spawn.cpp
@@ -41,8 +41,6 @@ pid_t fork() {
 #endif
 }
 
-void close(int fd) { linux_syscalls::close(fd); }
-
 // All exits from child_process are error exits. So, we use a simple
 // exit implementation which exits with code 127.
 void exit() {
@@ -76,7 +74,7 @@ void child_process(const char *__restrict path,
         if (actual_fd != open_act->fd) {
           bool dup2_result =
               linux_syscalls::dup2(actual_fd, open_act->fd).has_value();
-          close(actual_fd); // The old fd is not needed anymore.
+          linux_syscalls::close(actual_fd); // The old fd is not needed anymore.
           if (!dup2_result)
             exit();
         }
@@ -84,7 +82,7 @@ void child_process(const char *__restrict path,
       }
       case BaseSpawnFileAction::CLOSE: {
         auto *close_act = reinterpret_cast<SpawnFileCloseAction *>(act);
-        close(close_act->fd);
+        linux_syscalls::close(close_act->fd);
         break;
       }
       case BaseSpawnFileAction::DUP2: {



More information about the libc-commits mailing list