[libc-commits] [libc] 1801c35 - [libc] add syscall function

Michael Jones via libc-commits libc-commits at lists.llvm.org
Fri Sep 30 15:46:37 PDT 2022


Author: Michael Jones
Date: 2022-09-30T15:46:28-07:00
New Revision: 1801c356f61f0caef367138e889ad60b116b5760

URL: https://github.com/llvm/llvm-project/commit/1801c356f61f0caef367138e889ad60b116b5760
DIFF: https://github.com/llvm/llvm-project/commit/1801c356f61f0caef367138e889ad60b116b5760.diff

LOG: [libc] add syscall function

Add the syscall wrapper function and tests. It's implemented using a
macro to guarantee the minimum number of arguments.

Reviewed By: sivachandra, lntue

Differential Revision: https://reviews.llvm.org/D134919

Added: 
    libc/src/unistd/linux/syscall.cpp
    libc/src/unistd/syscall.h
    libc/test/src/unistd/syscall_test.cpp

Modified: 
    libc/config/linux/x86_64/entrypoints.txt
    libc/include/llvm-libc-macros/linux/unistd-macros.h
    libc/loader/linux/aarch64/start.cpp
    libc/loader/linux/x86_64/start.cpp
    libc/spec/posix.td
    libc/src/__support/File/linux_dir.cpp
    libc/src/__support/File/linux_file.cpp
    libc/src/__support/OSUtil/linux/aarch64/syscall.h
    libc/src/__support/OSUtil/linux/arm/syscall.h
    libc/src/__support/OSUtil/linux/io.h
    libc/src/__support/OSUtil/linux/quick_exit.h
    libc/src/__support/OSUtil/linux/syscall.h
    libc/src/__support/OSUtil/linux/x86_64/syscall.h
    libc/src/__support/threads/linux/callonce.cpp
    libc/src/__support/threads/linux/mutex.h
    libc/src/__support/threads/linux/thread.cpp
    libc/src/fcntl/linux/creat.cpp
    libc/src/fcntl/linux/open.cpp
    libc/src/fcntl/linux/openat.cpp
    libc/src/sched/linux/sched_getaffinity.cpp
    libc/src/sched/linux/sched_setaffinity.cpp
    libc/src/signal/linux/__restore.cpp
    libc/src/signal/linux/raise.cpp
    libc/src/signal/linux/sigaction.cpp
    libc/src/signal/linux/signal_utils.h
    libc/src/signal/linux/sigprocmask.cpp
    libc/src/stdio/linux/remove.cpp
    libc/src/stdlib/linux/_Exit.cpp
    libc/src/sys/mman/linux/madvise.cpp
    libc/src/sys/mman/linux/mmap.cpp
    libc/src/sys/mman/linux/mprotect.cpp
    libc/src/sys/mman/linux/munmap.cpp
    libc/src/sys/mman/linux/posix_madvise.cpp
    libc/src/sys/resource/linux/getrlimit.cpp
    libc/src/sys/resource/linux/setrlimit.cpp
    libc/src/sys/sendfile/linux/sendfile.cpp
    libc/src/sys/stat/linux/chmod.cpp
    libc/src/sys/stat/linux/fchmod.cpp
    libc/src/sys/stat/linux/fchmodat.cpp
    libc/src/sys/stat/linux/kernel_statx.h
    libc/src/sys/stat/linux/mkdir.cpp
    libc/src/sys/stat/linux/mkdirat.cpp
    libc/src/sys/utsname/linux/uname.cpp
    libc/src/threads/linux/CndVar.h
    libc/src/threads/linux/call_once.cpp
    libc/src/time/clock_gettime.cpp
    libc/src/time/nanosleep.cpp
    libc/src/unistd/CMakeLists.txt
    libc/src/unistd/linux/CMakeLists.txt
    libc/src/unistd/linux/access.cpp
    libc/src/unistd/linux/chdir.cpp
    libc/src/unistd/linux/close.cpp
    libc/src/unistd/linux/dup.cpp
    libc/src/unistd/linux/dup2.cpp
    libc/src/unistd/linux/dup3.cpp
    libc/src/unistd/linux/fchdir.cpp
    libc/src/unistd/linux/fsync.cpp
    libc/src/unistd/linux/ftruncate.cpp
    libc/src/unistd/linux/geteuid.cpp
    libc/src/unistd/linux/getpid.cpp
    libc/src/unistd/linux/getppid.cpp
    libc/src/unistd/linux/getuid.cpp
    libc/src/unistd/linux/link.cpp
    libc/src/unistd/linux/linkat.cpp
    libc/src/unistd/linux/lseek.cpp
    libc/src/unistd/linux/pread.cpp
    libc/src/unistd/linux/pwrite.cpp
    libc/src/unistd/linux/read.cpp
    libc/src/unistd/linux/readlink.cpp
    libc/src/unistd/linux/readlinkat.cpp
    libc/src/unistd/linux/rmdir.cpp
    libc/src/unistd/linux/symlink.cpp
    libc/src/unistd/linux/symlinkat.cpp
    libc/src/unistd/linux/truncate.cpp
    libc/src/unistd/linux/unlink.cpp
    libc/src/unistd/linux/unlinkat.cpp
    libc/src/unistd/linux/write.cpp
    libc/test/src/__support/OSUtil/linux/x86_64/syscall_test.cpp
    libc/test/src/sched/affinity_test.cpp
    libc/test/src/unistd/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 6745b548b3eae..42da9adf83070 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -154,6 +154,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.unistd.rmdir
     libc.src.unistd.symlink
     libc.src.unistd.symlinkat
+    libc.src.unistd.__llvm_libc_syscall
     libc.src.unistd.truncate
     libc.src.unistd.unlink
     libc.src.unistd.unlinkat

diff  --git a/libc/include/llvm-libc-macros/linux/unistd-macros.h b/libc/include/llvm-libc-macros/linux/unistd-macros.h
index 41f8f917ced79..9fbb9ae28d4af 100644
--- a/libc/include/llvm-libc-macros/linux/unistd-macros.h
+++ b/libc/include/llvm-libc-macros/linux/unistd-macros.h
@@ -15,4 +15,13 @@
 #define W_OK 2
 #define R_OK 4
 
+// Macro to set up the call to the __llvm_libc_syscall function
+// This is to prevent the call from having fewer than 6 arguments, since six
+// arguments are always passed to the syscall. Unnecessary arguments are
+// ignored.
+#define __syscall_helper(sysno, arg1, arg2, arg3, arg4, arg5, arg6, ...)       \
+  __llvm_libc_syscall((long)(sysno), (long)(arg1), (long)(arg2), (long)(arg3), \
+                      (long)(arg4), (long)(arg5), (long)(arg6))
+#define syscall(...) __syscall_helper(__VA_ARGS__, 0, 1, 2, 3, 4, 5, 6)
+
 #endif // __LLVM_LIBC_MACROS_LINUX_UNISTD_MACROS_H

diff  --git a/libc/loader/linux/aarch64/start.cpp b/libc/loader/linux/aarch64/start.cpp
index a28f6a323a80e..7234c2a105049 100644
--- a/libc/loader/linux/aarch64/start.cpp
+++ b/libc/loader/linux/aarch64/start.cpp
@@ -68,13 +68,13 @@ void init_tls(TLSDescriptor &tls_descriptor) {
   // We cannot call the mmap function here as the functions set errno on
   // failure. Since errno is implemented via a thread local variable, we cannot
   // use errno before TLS is setup.
-  long mmap_ret_val = __llvm_libc::syscall(MMAP_SYSCALL_NUMBER, nullptr,
-                                           alloc_size, PROT_READ | PROT_WRITE,
-                                           MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+  long mmap_ret_val = __llvm_libc::syscall_impl(
+      MMAP_SYSCALL_NUMBER, nullptr, alloc_size, PROT_READ | PROT_WRITE,
+      MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
   // We cannot check the return value with MAP_FAILED as that is the return
   // of the mmap function and not the mmap syscall.
   if (mmap_ret_val < 0 && static_cast<uintptr_t>(mmap_ret_val) > -app.pageSize)
-    __llvm_libc::syscall(SYS_exit, 1);
+    __llvm_libc::syscall_impl(SYS_exit, 1);
   uintptr_t thread_ptr = uintptr_t(reinterpret_cast<uintptr_t *>(mmap_ret_val));
   uintptr_t tls_addr = thread_ptr + size_of_pointers + padding;
   __llvm_libc::inline_memcpy(reinterpret_cast<char *>(tls_addr),
@@ -88,7 +88,7 @@ void init_tls(TLSDescriptor &tls_descriptor) {
 void cleanup_tls(uintptr_t addr, uintptr_t size) {
   if (size == 0)
     return;
-  __llvm_libc::syscall(SYS_munmap, addr, size);
+  __llvm_libc::syscall_impl(SYS_munmap, addr, size);
 }
 
 static void set_thread_ptr(uintptr_t val) { __arm_wsr64("tpidr_el0", val); }
@@ -133,9 +133,9 @@ struct AuxEntry {
 };
 
 __attribute__((noinline)) static void do_start() {
-  auto tid = __llvm_libc::syscall(SYS_gettid);
+  auto tid = __llvm_libc::syscall_impl(SYS_gettid);
   if (tid <= 0)
-    __llvm_libc::syscall(SYS_exit, 1);
+    __llvm_libc::syscall_impl(SYS_exit, 1);
   __llvm_libc::main_thread_attrib.tid = tid;
 
   // After the argv array, is a 8-byte long NULL value before the array of env

diff  --git a/libc/loader/linux/x86_64/start.cpp b/libc/loader/linux/x86_64/start.cpp
index 3353588b1256b..19670fa1a41db 100644
--- a/libc/loader/linux/x86_64/start.cpp
+++ b/libc/loader/linux/x86_64/start.cpp
@@ -58,13 +58,13 @@ void init_tls(TLSDescriptor &tls_descriptor) {
   // We cannot call the mmap function here as the functions set errno on
   // failure. Since errno is implemented via a thread local variable, we cannot
   // use errno before TLS is setup.
-  long mmapRetVal = __llvm_libc::syscall(
+  long mmapRetVal = __llvm_libc::syscall_impl(
       mmapSyscallNumber, nullptr, tlsSizeWithAddr, PROT_READ | PROT_WRITE,
       MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
   // We cannot check the return value with MAP_FAILED as that is the return
   // of the mmap function and not the mmap syscall.
   if (mmapRetVal < 0 && static_cast<uintptr_t>(mmapRetVal) > -app.pageSize)
-    __llvm_libc::syscall(SYS_exit, 1);
+    __llvm_libc::syscall_impl(SYS_exit, 1);
   uintptr_t *tlsAddr = reinterpret_cast<uintptr_t *>(mmapRetVal);
 
   // x86_64 TLS faces down from the thread pointer with the first entry
@@ -83,13 +83,14 @@ void init_tls(TLSDescriptor &tls_descriptor) {
 void cleanup_tls(uintptr_t addr, uintptr_t size) {
   if (size == 0)
     return;
-  __llvm_libc::syscall(SYS_munmap, addr, size);
+  __llvm_libc::syscall_impl(SYS_munmap, addr, size);
 }
 
 // Sets the thread pointer to |val|. Returns true on success, false on failure.
 static bool set_thread_ptr(uintptr_t val) {
-  return __llvm_libc::syscall(SYS_arch_prctl, ARCH_SET_FS, val) == -1 ? false
-                                                                      : true;
+  return __llvm_libc::syscall_impl(SYS_arch_prctl, ARCH_SET_FS, val) == -1
+             ? false
+             : true;
 }
 
 using InitCallback = void(int, char **, char **);
@@ -152,9 +153,9 @@ extern "C" void _start() {
   __asm__ __volatile__("andq $0xfffffffffffffff0, %%rsp\n\t" ::: "%rsp");
   __asm__ __volatile__("andq $0xfffffffffffffff0, %%rbp\n\t" ::: "%rbp");
 
-  auto tid = __llvm_libc::syscall(SYS_gettid);
+  auto tid = __llvm_libc::syscall_impl(SYS_gettid);
   if (tid <= 0)
-    __llvm_libc::syscall(SYS_exit, 1);
+    __llvm_libc::syscall_impl(SYS_exit, 1);
   __llvm_libc::main_thread_attrib.tid = tid;
 
   // After the argv array, is a 8-byte long NULL value before the array of env
@@ -202,7 +203,7 @@ extern "C" void _start() {
   __llvm_libc::TLSDescriptor tls;
   __llvm_libc::init_tls(tls);
   if (tls.size != 0 && !__llvm_libc::set_thread_ptr(tls.tp))
-    __llvm_libc::syscall(SYS_exit, 1);
+    __llvm_libc::syscall_impl(SYS_exit, 1);
 
   __llvm_libc::self.attrib = &__llvm_libc::main_thread_attrib;
   __llvm_libc::main_thread_attrib.atexit_callback_mgr =

diff  --git a/libc/spec/posix.td b/libc/spec/posix.td
index d3464e7d655a5..3f31723c43d79 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -482,6 +482,11 @@ def POSIX : StandardSpec<"POSIX"> {
           RetValSpec<IntType>,
           [ArgSpec<IntType>, ArgSpec<ConstCharPtr>, ArgSpec<IntType>, ArgSpec<ConstCharPtr>]
         >,
+        FunctionSpec<
+          "__llvm_libc_syscall",
+          RetValSpec<LongType>,
+          [ArgSpec<LongType>,ArgSpec<LongType>,ArgSpec<LongType>,ArgSpec<LongType>,ArgSpec<LongType>,ArgSpec<LongType>,ArgSpec<LongType>]
+        >,
         FunctionSpec<
           "truncate",
           RetValSpec<IntType>,

diff  --git a/libc/src/__support/File/linux_dir.cpp b/libc/src/__support/File/linux_dir.cpp
index 99d2436ecaec4..82274e1fce94c 100644
--- a/libc/src/__support/File/linux_dir.cpp
+++ b/libc/src/__support/File/linux_dir.cpp
@@ -19,9 +19,9 @@ namespace __llvm_libc {
 int platform_opendir(const char *name) {
   int open_flags = O_RDONLY | O_DIRECTORY | O_CLOEXEC;
 #ifdef SYS_open
-  int fd = __llvm_libc::syscall(SYS_open, name, open_flags);
+  int fd = __llvm_libc::syscall_impl(SYS_open, name, open_flags);
 #elif defined(SYS_openat)
-  int fd = __llvm_libc::syscall(SYS_openat, AT_FDCWD, name, open_flags);
+  int fd = __llvm_libc::syscall_impl(SYS_openat, AT_FDCWD, name, open_flags);
 #else
 #error                                                                         \
     "SYS_open and SYS_openat syscalls not available to perform an open operation."
@@ -36,7 +36,7 @@ int platform_opendir(const char *name) {
 
 size_t platform_fetch_dirents(int fd, cpp::span<uint8_t> buffer) {
   long size =
-      __llvm_libc::syscall(SYS_getdents, fd, buffer.data(), buffer.size());
+      __llvm_libc::syscall_impl(SYS_getdents, fd, buffer.data(), buffer.size());
   if (size < 0) {
     errno = -size;
     return 0;
@@ -45,7 +45,7 @@ size_t platform_fetch_dirents(int fd, cpp::span<uint8_t> buffer) {
 }
 
 bool platform_closedir(int fd) {
-  long ret = __llvm_libc::syscall(SYS_close, fd);
+  long ret = __llvm_libc::syscall_impl(SYS_close, fd);
   if (ret < 0) {
     errno = -ret;
     return false;

diff  --git a/libc/src/__support/File/linux_file.cpp b/libc/src/__support/File/linux_file.cpp
index 98abb6e1f64a8..782cee48e4715 100644
--- a/libc/src/__support/File/linux_file.cpp
+++ b/libc/src/__support/File/linux_file.cpp
@@ -53,7 +53,7 @@ namespace {
 
 size_t write_func(File *f, const void *data, size_t size) {
   auto *lf = reinterpret_cast<LinuxFile *>(f);
-  long ret = __llvm_libc::syscall(SYS_write, lf->get_fd(), data, size);
+  long ret = __llvm_libc::syscall_impl(SYS_write, lf->get_fd(), data, size);
   if (ret < 0) {
     errno = -ret;
     return 0;
@@ -63,7 +63,7 @@ size_t write_func(File *f, const void *data, size_t size) {
 
 size_t read_func(File *f, void *buf, size_t size) {
   auto *lf = reinterpret_cast<LinuxFile *>(f);
-  long ret = __llvm_libc::syscall(SYS_read, lf->get_fd(), buf, size);
+  long ret = __llvm_libc::syscall_impl(SYS_read, lf->get_fd(), buf, size);
   if (ret < 0) {
     errno = -ret;
     return 0;
@@ -74,11 +74,11 @@ size_t read_func(File *f, void *buf, size_t size) {
 int seek_func(File *f, long offset, int whence) {
   auto *lf = reinterpret_cast<LinuxFile *>(f);
 #ifdef SYS_lseek
-  long ret = __llvm_libc::syscall(SYS_lseek, lf->get_fd(), offset, whence);
+  long ret = __llvm_libc::syscall_impl(SYS_lseek, lf->get_fd(), offset, whence);
 #elif defined(SYS__llseek)
   long result;
-  long ret = __llvm_libc::syscall(SYS__llseek, lf->get_fd(), offset >> 32,
-                                  offset, &result, whence);
+  long ret = __llvm_libc::syscall_impl(SYS__llseek, lf->get_fd(), offset >> 32,
+                                       offset, &result, whence);
 #else
 #error "lseek and _llseek syscalls not available to perform a seek operation."
 #endif
@@ -92,7 +92,7 @@ int seek_func(File *f, long offset, int whence) {
 
 int close_func(File *f) {
   auto *lf = reinterpret_cast<LinuxFile *>(f);
-  long ret = __llvm_libc::syscall(SYS_close, lf->get_fd());
+  long ret = __llvm_libc::syscall_impl(SYS_close, lf->get_fd());
   if (ret < 0) {
     errno = -ret;
     return -1;
@@ -102,7 +102,7 @@ int close_func(File *f) {
 
 int flush_func(File *f) {
   auto *lf = reinterpret_cast<LinuxFile *>(f);
-  long ret = __llvm_libc::syscall(SYS_fsync, lf->get_fd());
+  long ret = __llvm_libc::syscall_impl(SYS_fsync, lf->get_fd());
   if (ret < 0) {
     errno = -ret;
     return -1;
@@ -144,10 +144,10 @@ File *openfile(const char *path, const char *mode) {
       S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
 
 #ifdef SYS_open
-  int fd = __llvm_libc::syscall(SYS_open, path, open_flags, OPEN_MODE);
+  int fd = __llvm_libc::syscall_impl(SYS_open, path, open_flags, OPEN_MODE);
 #elif defined(SYS_openat)
-  int fd =
-      __llvm_libc::syscall(SYS_openat, AT_FDCWD, path, open_flags, OPEN_MODE);
+  int fd = __llvm_libc::syscall_impl(SYS_openat, AT_FDCWD, path, open_flags,
+                                     OPEN_MODE);
 #else
 #error "SYS_open and SYS_openat syscalls not available to perform a file open."
 #endif

diff  --git a/libc/src/__support/OSUtil/linux/aarch64/syscall.h b/libc/src/__support/OSUtil/linux/aarch64/syscall.h
index 841f63e368453..2d1f0669e8f76 100644
--- a/libc/src/__support/OSUtil/linux/aarch64/syscall.h
+++ b/libc/src/__support/OSUtil/linux/aarch64/syscall.h
@@ -44,50 +44,52 @@
 
 namespace __llvm_libc {
 
-__attribute__((always_inline)) inline long syscall(long number) {
+__attribute__((always_inline)) inline long syscall_impl(long number) {
   REGISTER_DECL_0;
   SYSCALL_INSTR(REGISTER_CONSTRAINT_0);
   return x0;
 }
 
-__attribute__((always_inline)) inline long syscall(long number, long arg1) {
+__attribute__((always_inline)) inline long syscall_impl(long number,
+                                                        long arg1) {
   REGISTER_DECL_1;
   SYSCALL_INSTR(REGISTER_CONSTRAINT_1);
   return x0;
 }
 
-__attribute__((always_inline)) inline long syscall(long number, long arg1,
-                                                   long arg2) {
+__attribute__((always_inline)) inline long syscall_impl(long number, long arg1,
+                                                        long arg2) {
   REGISTER_DECL_2;
   SYSCALL_INSTR(REGISTER_CONSTRAINT_2);
   return x0;
 }
 
-__attribute__((always_inline)) inline long syscall(long number, long arg1,
-                                                   long arg2, long arg3) {
+__attribute__((always_inline)) inline long syscall_impl(long number, long arg1,
+                                                        long arg2, long arg3) {
   REGISTER_DECL_3;
   SYSCALL_INSTR(REGISTER_CONSTRAINT_3);
   return x0;
 }
 
 __attribute__((always_inline)) inline long
-syscall(long number, long arg1, long arg2, long arg3, long arg4) {
+syscall_impl(long number, long arg1, long arg2, long arg3, long arg4) {
   REGISTER_DECL_4;
   SYSCALL_INSTR(REGISTER_CONSTRAINT_4);
   return x0;
 }
 
-__attribute__((always_inline)) inline long
-syscall(long number, long arg1, long arg2, long arg3, long arg4, long arg5) {
+__attribute__((always_inline)) inline long syscall_impl(long number, long arg1,
+                                                        long arg2, long arg3,
+                                                        long arg4, long arg5) {
   REGISTER_DECL_5;
   SYSCALL_INSTR(REGISTER_CONSTRAINT_5);
   return x0;
 }
 
-__attribute__((always_inline)) inline long syscall(long number, long arg1,
-                                                   long arg2, long arg3,
-                                                   long arg4, long arg5,
-                                                   long arg6) {
+__attribute__((always_inline)) inline long syscall_impl(long number, long arg1,
+                                                        long arg2, long arg3,
+                                                        long arg4, long arg5,
+                                                        long arg6) {
   REGISTER_DECL_6;
   SYSCALL_INSTR(REGISTER_CONSTRAINT_6);
   return x0;

diff  --git a/libc/src/__support/OSUtil/linux/arm/syscall.h b/libc/src/__support/OSUtil/linux/arm/syscall.h
index 79cfff8859eee..268d4093cec2d 100644
--- a/libc/src/__support/OSUtil/linux/arm/syscall.h
+++ b/libc/src/__support/OSUtil/linux/arm/syscall.h
@@ -50,50 +50,52 @@
 
 namespace __llvm_libc {
 
-__attribute__((always_inline)) inline long syscall(long number) {
+__attribute__((always_inline)) inline long syscall_impl(long number) {
   REGISTER_DECL_0;
   SYSCALL_INSTR(REGISTER_CONSTRAINT_0);
   return r0;
 }
 
-__attribute__((always_inline)) inline long syscall(long number, long arg1) {
+__attribute__((always_inline)) inline long syscall_impl(long number,
+                                                        long arg1) {
   REGISTER_DECL_1;
   SYSCALL_INSTR(REGISTER_CONSTRAINT_1);
   return r0;
 }
 
-__attribute__((always_inline)) inline long syscall(long number, long arg1,
-                                                   long arg2) {
+__attribute__((always_inline)) inline long syscall_impl(long number, long arg1,
+                                                        long arg2) {
   REGISTER_DECL_2;
   SYSCALL_INSTR(REGISTER_CONSTRAINT_2);
   return r0;
 }
 
-__attribute__((always_inline)) inline long syscall(long number, long arg1,
-                                                   long arg2, long arg3) {
+__attribute__((always_inline)) inline long syscall_impl(long number, long arg1,
+                                                        long arg2, long arg3) {
   REGISTER_DECL_3;
   SYSCALL_INSTR(REGISTER_CONSTRAINT_3);
   return r0;
 }
 
 __attribute__((always_inline)) inline long
-syscall(long number, long arg1, long arg2, long arg3, long arg4) {
+syscall_impl(long number, long arg1, long arg2, long arg3, long arg4) {
   REGISTER_DECL_4;
   SYSCALL_INSTR(REGISTER_CONSTRAINT_4);
   return r0;
 }
 
-__attribute__((always_inline)) inline long
-syscall(long number, long arg1, long arg2, long arg3, long arg4, long arg5) {
+__attribute__((always_inline)) inline long syscall_impl(long number, long arg1,
+                                                        long arg2, long arg3,
+                                                        long arg4, long arg5) {
   REGISTER_DECL_5;
   SYSCALL_INSTR(REGISTER_CONSTRAINT_5);
   return r0;
 }
 
-__attribute__((always_inline)) inline long syscall(long number, long arg1,
-                                                   long arg2, long arg3,
-                                                   long arg4, long arg5,
-                                                   long arg6) {
+__attribute__((always_inline)) inline long syscall_impl(long number, long arg1,
+                                                        long arg2, long arg3,
+                                                        long arg4, long arg5,
+                                                        long arg6) {
   REGISTER_DECL_6;
   SYSCALL_INSTR(REGISTER_CONSTRAINT_6);
   return r0;

diff  --git a/libc/src/__support/OSUtil/linux/io.h b/libc/src/__support/OSUtil/linux/io.h
index fa63ecda831fb..b99f828446fc5 100644
--- a/libc/src/__support/OSUtil/linux/io.h
+++ b/libc/src/__support/OSUtil/linux/io.h
@@ -17,8 +17,8 @@
 namespace __llvm_libc {
 
 static inline void write_to_stderr(const char *msg) {
-  __llvm_libc::syscall(SYS_write, 2 /* stderr */, msg,
-                       internal::string_length(msg));
+  __llvm_libc::syscall_impl(SYS_write, 2 /* stderr */, msg,
+                            internal::string_length(msg));
 }
 
 } // namespace __llvm_libc

diff  --git a/libc/src/__support/OSUtil/linux/quick_exit.h b/libc/src/__support/OSUtil/linux/quick_exit.h
index c985c630be35a..ca755de19522f 100644
--- a/libc/src/__support/OSUtil/linux/quick_exit.h
+++ b/libc/src/__support/OSUtil/linux/quick_exit.h
@@ -17,8 +17,8 @@ namespace __llvm_libc {
 
 static inline void quick_exit(int status) {
   for (;;) {
-    __llvm_libc::syscall(SYS_exit_group, status);
-    __llvm_libc::syscall(SYS_exit, status);
+    __llvm_libc::syscall_impl(SYS_exit_group, status);
+    __llvm_libc::syscall_impl(SYS_exit, status);
   }
 }
 

diff  --git a/libc/src/__support/OSUtil/linux/syscall.h b/libc/src/__support/OSUtil/linux/syscall.h
index 1756ee65e16d3..645145a3044cf 100644
--- a/libc/src/__support/OSUtil/linux/syscall.h
+++ b/libc/src/__support/OSUtil/linux/syscall.h
@@ -22,9 +22,10 @@
 namespace __llvm_libc {
 
 template <typename... Ts>
-__attribute__((always_inline)) inline long syscall(long __number, Ts... ts) {
+__attribute__((always_inline)) inline long syscall_impl(long __number,
+                                                        Ts... ts) {
   static_assert(sizeof...(Ts) <= 6, "Too many arguments for syscall");
-  return syscall(__number, (long)ts...);
+  return syscall_impl(__number, (long)ts...);
 }
 
 } // namespace __llvm_libc

diff  --git a/libc/src/__support/OSUtil/linux/x86_64/syscall.h b/libc/src/__support/OSUtil/linux/x86_64/syscall.h
index c6f88a6ec853a..1bb401abd2f28 100644
--- a/libc/src/__support/OSUtil/linux/x86_64/syscall.h
+++ b/libc/src/__support/OSUtil/linux/x86_64/syscall.h
@@ -15,7 +15,7 @@
 
 namespace __llvm_libc {
 
-__attribute__((always_inline)) inline long syscall(long __number) {
+__attribute__((always_inline)) inline long syscall_impl(long __number) {
   long retcode;
   LIBC_INLINE_ASM("syscall"
                   : "=a"(retcode)
@@ -24,7 +24,8 @@ __attribute__((always_inline)) inline long syscall(long __number) {
   return retcode;
 }
 
-__attribute__((always_inline)) inline long syscall(long __number, long __arg1) {
+__attribute__((always_inline)) inline long syscall_impl(long __number,
+                                                        long __arg1) {
   long retcode;
   LIBC_INLINE_ASM("syscall"
                   : "=a"(retcode)
@@ -33,8 +34,8 @@ __attribute__((always_inline)) inline long syscall(long __number, long __arg1) {
   return retcode;
 }
 
-__attribute__((always_inline)) inline long syscall(long __number, long __arg1,
-                                                   long __arg2) {
+__attribute__((always_inline)) inline long
+syscall_impl(long __number, long __arg1, long __arg2) {
   long retcode;
   LIBC_INLINE_ASM("syscall"
                   : "=a"(retcode)
@@ -43,8 +44,8 @@ __attribute__((always_inline)) inline long syscall(long __number, long __arg1,
   return retcode;
 }
 
-__attribute__((always_inline)) inline long syscall(long __number, long __arg1,
-                                                   long __arg2, long __arg3) {
+__attribute__((always_inline)) inline long
+syscall_impl(long __number, long __arg1, long __arg2, long __arg3) {
   long retcode;
   LIBC_INLINE_ASM("syscall"
                   : "=a"(retcode)
@@ -54,7 +55,8 @@ __attribute__((always_inline)) inline long syscall(long __number, long __arg1,
 }
 
 __attribute__((always_inline)) inline long
-syscall(long __number, long __arg1, long __arg2, long __arg3, long __arg4) {
+syscall_impl(long __number, long __arg1, long __arg2, long __arg3,
+             long __arg4) {
   long retcode;
   register long r10 __asm__("r10") = __arg4;
   LIBC_INLINE_ASM("syscall"
@@ -65,9 +67,9 @@ syscall(long __number, long __arg1, long __arg2, long __arg3, long __arg4) {
   return retcode;
 }
 
-__attribute__((always_inline)) inline long syscall(long __number, long __arg1,
-                                                   long __arg2, long __arg3,
-                                                   long __arg4, long __arg5) {
+__attribute__((always_inline)) inline long
+syscall_impl(long __number, long __arg1, long __arg2, long __arg3, long __arg4,
+             long __arg5) {
   long retcode;
   register long r10 __asm__("r10") = __arg4;
   register long r8 __asm__("r8") = __arg5;
@@ -79,10 +81,9 @@ __attribute__((always_inline)) inline long syscall(long __number, long __arg1,
   return retcode;
 }
 
-__attribute__((always_inline)) inline long syscall(long __number, long __arg1,
-                                                   long __arg2, long __arg3,
-                                                   long __arg4, long __arg5,
-                                                   long __arg6) {
+__attribute__((always_inline)) inline long
+syscall_impl(long __number, long __arg1, long __arg2, long __arg3, long __arg4,
+             long __arg5, long __arg6) {
   long retcode;
   register long r10 __asm__("r10") = __arg4;
   register long r8 __asm__("r8") = __arg5;
@@ -96,7 +97,6 @@ __attribute__((always_inline)) inline long syscall(long __number, long __arg1,
 }
 
 #undef SYSCALL_CLOBBER_LIST
-
 } // namespace __llvm_libc
 
 #endif // LLVM_LIBC_SRC_SUPPORT_OSUTIL_LINUX_X86_64_SYSCALL_H

diff  --git a/libc/src/__support/threads/linux/callonce.cpp b/libc/src/__support/threads/linux/callonce.cpp
index 1aab6fc9c4497..7dc957f0129cd 100644
--- a/libc/src/__support/threads/linux/callonce.cpp
+++ b/libc/src/__support/threads/linux/callonce.cpp
@@ -34,9 +34,9 @@ int callonce(CallOnceFlag *flag, CallOnceCallback *func) {
     func();
     auto status = futex_word->exchange(FINISH);
     if (status == WAITING) {
-      __llvm_libc::syscall(SYS_futex, &futex_word->val, FUTEX_WAKE_PRIVATE,
-                           INT_MAX, // Wake all waiters.
-                           0, 0, 0);
+      __llvm_libc::syscall_impl(SYS_futex, &futex_word->val, FUTEX_WAKE_PRIVATE,
+                                INT_MAX, // Wake all waiters.
+                                0, 0, 0);
     }
     return 0;
   }
@@ -44,9 +44,10 @@ int callonce(CallOnceFlag *flag, CallOnceCallback *func) {
   FutexWordType status = START;
   if (futex_word->compare_exchange_strong(status, WAITING) ||
       status == WAITING) {
-    __llvm_libc::syscall(SYS_futex, &futex_word->val, FUTEX_WAIT_PRIVATE,
-                         WAITING, // Block only if status is still |WAITING|.
-                         0, 0, 0);
+    __llvm_libc::syscall_impl(
+        SYS_futex, &futex_word->val, FUTEX_WAIT_PRIVATE,
+        WAITING, // Block only if status is still |WAITING|.
+        0, 0, 0);
   }
 
   return 0;

diff  --git a/libc/src/__support/threads/linux/mutex.h b/libc/src/__support/threads/linux/mutex.h
index 0133b2069d845..19221c97aeffb 100644
--- a/libc/src/__support/threads/linux/mutex.h
+++ b/libc/src/__support/threads/linux/mutex.h
@@ -76,8 +76,9 @@ struct Mutex {
         // futex syscall will block if the futex data is still
         // `LockState::Waiting` (the 4th argument to the syscall function
         // below.)
-        __llvm_libc::syscall(SYS_futex, &futex_word.val, FUTEX_WAIT_PRIVATE,
-                             FutexWordType(LockState::Waiting), 0, 0, 0);
+        __llvm_libc::syscall_impl(SYS_futex, &futex_word.val,
+                                  FUTEX_WAIT_PRIVATE,
+                                  FutexWordType(LockState::Waiting), 0, 0, 0);
         was_waiting = true;
         // Once woken up/unblocked, try everything all over.
         continue;
@@ -90,8 +91,8 @@ struct Mutex {
           // we will wait for the futex to be woken up. Note again that the
           // following syscall will block only if the futex data is still
           // `LockState::Waiting`.
-          __llvm_libc::syscall(SYS_futex, &futex_word, FUTEX_WAIT_PRIVATE,
-                               FutexWordType(LockState::Waiting), 0, 0, 0);
+          __llvm_libc::syscall_impl(SYS_futex, &futex_word, FUTEX_WAIT_PRIVATE,
+                                    FutexWordType(LockState::Waiting), 0, 0, 0);
           was_waiting = true;
         }
         continue;
@@ -108,8 +109,8 @@ struct Mutex {
       if (futex_word.compare_exchange_strong(mutex_status,
                                              FutexWordType(LockState::Free))) {
         // If any thread is waiting to be woken up, then do it.
-        __llvm_libc::syscall(SYS_futex, &futex_word, FUTEX_WAKE_PRIVATE, 1, 0,
-                             0, 0);
+        __llvm_libc::syscall_impl(SYS_futex, &futex_word, FUTEX_WAKE_PRIVATE, 1,
+                                  0, 0, 0);
         return MutexError::NONE;
       }
 

diff  --git a/libc/src/__support/threads/linux/thread.cpp b/libc/src/__support/threads/linux/thread.cpp
index 08661c63e75f5..15f38c0a0eba2 100644
--- a/libc/src/__support/threads/linux/thread.cpp
+++ b/libc/src/__support/threads/linux/thread.cpp
@@ -56,13 +56,13 @@ static constexpr unsigned CLONE_SYSCALL_FLAGS =
 
 static inline cpp::ErrorOr<void *> alloc_stack(size_t size) {
   long mmap_result =
-      __llvm_libc::syscall(MMAP_SYSCALL_NUMBER,
-                           0, // No special address
-                           size,
-                           PROT_READ | PROT_WRITE,      // Read and write stack
-                           MAP_ANONYMOUS | MAP_PRIVATE, // Process private
-                           -1, // Not backed by any file
-                           0   // No offset
+      __llvm_libc::syscall_impl(MMAP_SYSCALL_NUMBER,
+                                0, // No special address
+                                size,
+                                PROT_READ | PROT_WRITE, // Read and write stack
+                                MAP_ANONYMOUS | MAP_PRIVATE, // Process private
+                                -1, // Not backed by any file
+                                0   // No offset
       );
   if (mmap_result < 0 && (uintptr_t(mmap_result) >= UINTPTR_MAX - size))
     return cpp::Error{int(-mmap_result)};
@@ -70,7 +70,7 @@ static inline cpp::ErrorOr<void *> alloc_stack(size_t size) {
 }
 
 static inline void free_stack(void *stack, size_t size) {
-  __llvm_libc::syscall(SYS_munmap, stack, size);
+  __llvm_libc::syscall_impl(SYS_munmap, stack, size);
 }
 
 struct Thread;
@@ -192,7 +192,7 @@ int Thread::run(ThreadStyle style, ThreadRunner runner, void *arg, void *stack,
   // variables from this function will not be availalbe to the child thread.
 #ifdef LLVM_LIBC_ARCH_X86_64
   long register clone_result asm("rax");
-  clone_result = __llvm_libc::syscall(
+  clone_result = __llvm_libc::syscall_impl(
       SYS_clone, CLONE_SYSCALL_FLAGS, adjusted_stack,
       &attrib->tid,    // The address where the child tid is written
       &clear_tid->val, // The futex where the child thread status is signalled
@@ -200,7 +200,7 @@ int Thread::run(ThreadStyle style, ThreadRunner runner, void *arg, void *stack,
   );
 #elif defined(LLVM_LIBC_ARCH_AARCH64)
   long register clone_result asm("x0");
-  clone_result = __llvm_libc::syscall(
+  clone_result = __llvm_libc::syscall_impl(
       SYS_clone, CLONE_SYSCALL_FLAGS, adjusted_stack,
       &attrib->tid,   // The address where the child tid is written
       tls.tp,         // The thread pointer value for the new thread.
@@ -264,8 +264,8 @@ void Thread::wait() {
   while (clear_tid->load() != 0) {
     // We cannot do a FUTEX_WAIT_PRIVATE here as the kernel does a
     // FUTEX_WAKE and not a FUTEX_WAKE_PRIVATE.
-    __llvm_libc::syscall(SYS_futex, &clear_tid->val, FUTEX_WAIT,
-                         CLEAR_TID_VALUE, nullptr);
+    __llvm_libc::syscall_impl(SYS_futex, &clear_tid->val, FUTEX_WAIT,
+                              CLEAR_TID_VALUE, nullptr);
   }
 }
 
@@ -293,7 +293,7 @@ int Thread::set_name(const cpp::string_view &name) {
   if (*this == self) {
     // If we are setting the name of the current thread, then we can
     // use the syscall to set the name.
-    int retval = __llvm_libc::syscall(SYS_prctl, PR_SET_NAME, name.data());
+    int retval = __llvm_libc::syscall_impl(SYS_prctl, PR_SET_NAME, name.data());
     if (retval < 0)
       return -retval;
     else
@@ -304,15 +304,17 @@ int Thread::set_name(const cpp::string_view &name) {
   cpp::StringStream path_stream(path_name_buffer);
   construct_thread_name_file_path(path_stream, attrib->tid);
 #ifdef SYS_open
-  int fd = __llvm_libc::syscall(SYS_open, path_name_buffer, O_RDWR);
+  int fd = __llvm_libc::syscall_impl(SYS_open, path_name_buffer, O_RDWR);
 #else
-  int fd = __llvm_libc::syscall(SYS_openat, AT_FDCWD, path_name_buffer, O_RDWR);
+  int fd =
+      __llvm_libc::syscall_impl(SYS_openat, AT_FDCWD, path_name_buffer, O_RDWR);
 #endif
   if (fd < 0)
     return -fd;
 
-  int retval = __llvm_libc::syscall(SYS_write, fd, name.data(), name.size());
-  __llvm_libc::syscall(SYS_close, fd);
+  int retval =
+      __llvm_libc::syscall_impl(SYS_write, fd, name.data(), name.size());
+  __llvm_libc::syscall_impl(SYS_close, fd);
 
   if (retval < 0)
     return -retval;
@@ -331,7 +333,7 @@ int Thread::get_name(cpp::StringStream &name) const {
   if (*this == self) {
     // If we are getting the name of the current thread, then we can
     // use the syscall to get the name.
-    int retval = __llvm_libc::syscall(SYS_prctl, PR_GET_NAME, name_buffer);
+    int retval = __llvm_libc::syscall_impl(SYS_prctl, PR_GET_NAME, name_buffer);
     if (retval < 0)
       return -retval;
     name << name_buffer;
@@ -342,16 +344,17 @@ int Thread::get_name(cpp::StringStream &name) const {
   cpp::StringStream path_stream(path_name_buffer);
   construct_thread_name_file_path(path_stream, attrib->tid);
 #ifdef SYS_open
-  int fd = __llvm_libc::syscall(SYS_open, path_name_buffer, O_RDONLY);
+  int fd = __llvm_libc::syscall_impl(SYS_open, path_name_buffer, O_RDONLY);
 #else
-  int fd =
-      __llvm_libc::syscall(SYS_openat, AT_FDCWD, path_name_buffer, O_RDONLY);
+  int fd = __llvm_libc::syscall_impl(SYS_openat, AT_FDCWD, path_name_buffer,
+                                     O_RDONLY);
 #endif
   if (fd < 0)
     return -fd;
 
-  int retval = __llvm_libc::syscall(SYS_read, fd, name_buffer, NAME_SIZE_MAX);
-  __llvm_libc::syscall(SYS_close, fd);
+  int retval =
+      __llvm_libc::syscall_impl(SYS_read, fd, name_buffer, NAME_SIZE_MAX);
+  __llvm_libc::syscall_impl(SYS_close, fd);
   if (retval < 0)
     return -retval;
   if (retval == NAME_SIZE_MAX)
@@ -385,13 +388,13 @@ void thread_exit(ThreadReturnValue retval, ThreadStyle style) {
 
     // Set the CLEAR_TID address to nullptr to prevent the kernel
     // from signalling at a non-existent futex location.
-    __llvm_libc::syscall(SYS_set_tid_address, 0);
+    __llvm_libc::syscall_impl(SYS_set_tid_address, 0);
   }
 
   if (style == ThreadStyle::POSIX)
-    __llvm_libc::syscall(SYS_exit, retval.posix_retval);
+    __llvm_libc::syscall_impl(SYS_exit, retval.posix_retval);
   else
-    __llvm_libc::syscall(SYS_exit, retval.stdc_retval);
+    __llvm_libc::syscall_impl(SYS_exit, retval.stdc_retval);
 }
 
 } // namespace __llvm_libc

diff  --git a/libc/src/fcntl/linux/creat.cpp b/libc/src/fcntl/linux/creat.cpp
index 9bca317006699..4cf7b792b4d58 100644
--- a/libc/src/fcntl/linux/creat.cpp
+++ b/libc/src/fcntl/linux/creat.cpp
@@ -19,11 +19,11 @@ namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, creat, (const char *path, int mode_flags)) {
 #ifdef SYS_open
-  int fd = __llvm_libc::syscall(SYS_open, path, O_CREAT | O_WRONLY | O_TRUNC,
-                                mode_flags);
+  int fd = __llvm_libc::syscall_impl(SYS_open, path,
+                                     O_CREAT | O_WRONLY | O_TRUNC, mode_flags);
 #else
-  int fd = __llvm_libc::syscall(SYS_openat, AT_FDCWD, path,
-                                O_CREAT | O_WRONLY | O_TRUNC, mode_flags);
+  int fd = __llvm_libc::syscall_impl(SYS_openat, AT_FDCWD, path,
+                                     O_CREAT | O_WRONLY | O_TRUNC, mode_flags);
 #endif
 
   if (fd > 0)

diff  --git a/libc/src/fcntl/linux/open.cpp b/libc/src/fcntl/linux/open.cpp
index 3b8e08a7169ab..8fe68debcdcfe 100644
--- a/libc/src/fcntl/linux/open.cpp
+++ b/libc/src/fcntl/linux/open.cpp
@@ -30,9 +30,10 @@ LLVM_LIBC_FUNCTION(int, open, (const char *path, int flags, ...)) {
   }
 
 #ifdef SYS_open
-  int fd = __llvm_libc::syscall(SYS_open, path, flags, mode_flags);
+  int fd = __llvm_libc::syscall_impl(SYS_open, path, flags, mode_flags);
 #else
-  int fd = __llvm_libc::syscall(SYS_openat, AT_FDCWD, path, flags, mode_flags);
+  int fd =
+      __llvm_libc::syscall_impl(SYS_openat, AT_FDCWD, path, flags, mode_flags);
 #endif
   if (fd > 0)
     return fd;

diff  --git a/libc/src/fcntl/linux/openat.cpp b/libc/src/fcntl/linux/openat.cpp
index b55fa92206f51..23e2c6b89cdcb 100644
--- a/libc/src/fcntl/linux/openat.cpp
+++ b/libc/src/fcntl/linux/openat.cpp
@@ -29,7 +29,7 @@ LLVM_LIBC_FUNCTION(int, openat, (int dfd, const char *path, int flags, ...)) {
     va_end(varargs);
   }
 
-  int fd = __llvm_libc::syscall(SYS_openat, dfd, path, flags, mode_flags);
+  int fd = __llvm_libc::syscall_impl(SYS_openat, dfd, path, flags, mode_flags);
   if (fd > 0)
     return fd;
 

diff  --git a/libc/src/sched/linux/sched_getaffinity.cpp b/libc/src/sched/linux/sched_getaffinity.cpp
index 5d45d15e303db..a4c3de9808f0b 100644
--- a/libc/src/sched/linux/sched_getaffinity.cpp
+++ b/libc/src/sched/linux/sched_getaffinity.cpp
@@ -21,7 +21,7 @@ namespace __llvm_libc {
 LLVM_LIBC_FUNCTION(int, sched_getaffinity,
                    (pid_t tid, size_t cpuset_size, cpu_set_t *mask)) {
   long ret =
-      __llvm_libc::syscall(SYS_sched_getaffinity, tid, cpuset_size, mask);
+      __llvm_libc::syscall_impl(SYS_sched_getaffinity, tid, cpuset_size, mask);
   if (ret < 0) {
     errno = -ret;
     return -1;

diff  --git a/libc/src/sched/linux/sched_setaffinity.cpp b/libc/src/sched/linux/sched_setaffinity.cpp
index 4f22aaaa508cf..6feb9977912bb 100644
--- a/libc/src/sched/linux/sched_setaffinity.cpp
+++ b/libc/src/sched/linux/sched_setaffinity.cpp
@@ -20,7 +20,7 @@ namespace __llvm_libc {
 LLVM_LIBC_FUNCTION(int, sched_setaffinity,
                    (pid_t tid, size_t cpuset_size, const cpu_set_t *mask)) {
   long ret =
-      __llvm_libc::syscall(SYS_sched_setaffinity, tid, cpuset_size, mask);
+      __llvm_libc::syscall_impl(SYS_sched_setaffinity, tid, cpuset_size, mask);
   if (ret < 0) {
     errno = -ret;
     return -1;

diff  --git a/libc/src/signal/linux/__restore.cpp b/libc/src/signal/linux/__restore.cpp
index b76b5b858acc3..f73c1b7296ac0 100644
--- a/libc/src/signal/linux/__restore.cpp
+++ b/libc/src/signal/linux/__restore.cpp
@@ -19,6 +19,6 @@ extern "C" void __restore_rt()
     __attribute__((no_sanitize("all"),
                    hidden));
 
-extern "C" void __restore_rt() { __llvm_libc::syscall(SYS_rt_sigreturn); }
+extern "C" void __restore_rt() { __llvm_libc::syscall_impl(SYS_rt_sigreturn); }
 
 } // namespace __llvm_libc

diff  --git a/libc/src/signal/linux/raise.cpp b/libc/src/signal/linux/raise.cpp
index eb880d1bd7057..6371273635d2b 100644
--- a/libc/src/signal/linux/raise.cpp
+++ b/libc/src/signal/linux/raise.cpp
@@ -16,9 +16,9 @@ namespace __llvm_libc {
 LLVM_LIBC_FUNCTION(int, raise, (int sig)) {
   ::sigset_t sigset;
   block_all_signals(sigset);
-  long pid = __llvm_libc::syscall(SYS_getpid);
-  long tid = __llvm_libc::syscall(SYS_gettid);
-  int ret = __llvm_libc::syscall(SYS_tgkill, pid, tid, sig);
+  long pid = __llvm_libc::syscall_impl(SYS_getpid);
+  long tid = __llvm_libc::syscall_impl(SYS_gettid);
+  int ret = __llvm_libc::syscall_impl(SYS_tgkill, pid, tid, sig);
   restore_signals(sigset);
   return ret;
 }

diff  --git a/libc/src/signal/linux/sigaction.cpp b/libc/src/signal/linux/sigaction.cpp
index c6324005a6d1c..a229e142fd157 100644
--- a/libc/src/signal/linux/sigaction.cpp
+++ b/libc/src/signal/linux/sigaction.cpp
@@ -34,8 +34,9 @@ LLVM_LIBC_FUNCTION(int, sigaction,
   }
 
   KernelSigaction kernel_old;
-  int ret = syscall(SYS_rt_sigaction, signal, libc_new ? &kernel_new : nullptr,
-                    libc_old ? &kernel_old : nullptr, sizeof(sigset_t));
+  int ret = __llvm_libc::syscall_impl(
+      SYS_rt_sigaction, signal, libc_new ? &kernel_new : nullptr,
+      libc_old ? &kernel_old : nullptr, sizeof(sigset_t));
   if (ret) {
     errno = -ret;
     return -1;

diff  --git a/libc/src/signal/linux/signal_utils.h b/libc/src/signal/linux/signal_utils.h
index 8eba593e4e610..7c45e0862d524 100644
--- a/libc/src/signal/linux/signal_utils.h
+++ b/libc/src/signal/linux/signal_utils.h
@@ -95,13 +95,13 @@ constexpr inline bool delete_signal(sigset_t &set, int signal) {
 
 static inline int block_all_signals(sigset_t &set) {
   sigset_t full = full_set();
-  return __llvm_libc::syscall(SYS_rt_sigprocmask, SIG_BLOCK, &full, &set,
-                              sizeof(sigset_t));
+  return __llvm_libc::syscall_impl(SYS_rt_sigprocmask, SIG_BLOCK, &full, &set,
+                                   sizeof(sigset_t));
 }
 
 static inline int restore_signals(const sigset_t &set) {
-  return __llvm_libc::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &set, nullptr,
-                              sizeof(sigset_t));
+  return __llvm_libc::syscall_impl(SYS_rt_sigprocmask, SIG_SETMASK, &set,
+                                   nullptr, sizeof(sigset_t));
 }
 
 } // namespace __llvm_libc

diff  --git a/libc/src/signal/linux/sigprocmask.cpp b/libc/src/signal/linux/sigprocmask.cpp
index 343fd0f41bc4b..cd205815eff57 100644
--- a/libc/src/signal/linux/sigprocmask.cpp
+++ b/libc/src/signal/linux/sigprocmask.cpp
@@ -21,8 +21,8 @@ namespace __llvm_libc {
 LLVM_LIBC_FUNCTION(int, sigprocmask,
                    (int how, const sigset_t *__restrict set,
                     sigset_t *__restrict oldset)) {
-  int ret = __llvm_libc::syscall(SYS_rt_sigprocmask, how, set, oldset,
-                                 sizeof(sigset_t));
+  int ret = __llvm_libc::syscall_impl(SYS_rt_sigprocmask, how, set, oldset,
+                                      sizeof(sigset_t));
   if (!ret)
     return 0;
 

diff  --git a/libc/src/stdio/linux/remove.cpp b/libc/src/stdio/linux/remove.cpp
index cdada40bdfa68..2a868a78abf6a 100644
--- a/libc/src/stdio/linux/remove.cpp
+++ b/libc/src/stdio/linux/remove.cpp
@@ -20,9 +20,9 @@ namespace __llvm_libc {
 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 = __llvm_libc::syscall(SYS_unlinkat, AT_FDCWD, path, 0);
+  int ret = __llvm_libc::syscall_impl(SYS_unlinkat, AT_FDCWD, path, 0);
   if (ret == -EISDIR)
-    ret = __llvm_libc::syscall(SYS_unlinkat, AT_FDCWD, path, AT_REMOVEDIR);
+    ret = __llvm_libc::syscall_impl(SYS_unlinkat, AT_FDCWD, path, AT_REMOVEDIR);
   if (ret >= 0)
     return 0;
   errno = -ret;

diff  --git a/libc/src/stdlib/linux/_Exit.cpp b/libc/src/stdlib/linux/_Exit.cpp
index 51b0a48c7521b..0300a08847cea 100644
--- a/libc/src/stdlib/linux/_Exit.cpp
+++ b/libc/src/stdlib/linux/_Exit.cpp
@@ -16,8 +16,8 @@ namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(void, _Exit, (int status)) {
   for (;;) {
-    __llvm_libc::syscall(SYS_exit_group, status);
-    __llvm_libc::syscall(SYS_exit, status);
+    __llvm_libc::syscall_impl(SYS_exit_group, status);
+    __llvm_libc::syscall_impl(SYS_exit, status);
   }
 }
 

diff  --git a/libc/src/sys/mman/linux/madvise.cpp b/libc/src/sys/mman/linux/madvise.cpp
index 6dcc19a792ebe..3e6e574d1f14e 100644
--- a/libc/src/sys/mman/linux/madvise.cpp
+++ b/libc/src/sys/mman/linux/madvise.cpp
@@ -19,8 +19,8 @@ namespace __llvm_libc {
 // This function is currently linux only. It has to be refactored suitably if
 // madvise is to be supported on non-linux operating systems also.
 LLVM_LIBC_FUNCTION(int, madvise, (void *addr, size_t size, int advice)) {
-  long ret_val = __llvm_libc::syscall(SYS_madvise, reinterpret_cast<long>(addr),
-                                      size, advice);
+  long ret_val = __llvm_libc::syscall_impl(
+      SYS_madvise, reinterpret_cast<long>(addr), size, advice);
 
   // A negative return value indicates an error with the magnitude of the
   // value being the error code.

diff  --git a/libc/src/sys/mman/linux/mmap.cpp b/libc/src/sys/mman/linux/mmap.cpp
index 6ae482a8409ad..f08877e466c15 100644
--- a/libc/src/sys/mman/linux/mmap.cpp
+++ b/libc/src/sys/mman/linux/mmap.cpp
@@ -40,8 +40,8 @@ LLVM_LIBC_FUNCTION(void *, mmap,
 #endif
 
   long ret_val =
-      __llvm_libc::syscall(syscall_number, reinterpret_cast<long>(addr), size,
-                           prot, flags, fd, offset);
+      __llvm_libc::syscall_impl(syscall_number, reinterpret_cast<long>(addr),
+                                size, prot, flags, fd, offset);
 
   // The mmap/mmap2 syscalls return negative values on error. These negative
   // values are actually the negative values of the error codes. So, fix them

diff  --git a/libc/src/sys/mman/linux/mprotect.cpp b/libc/src/sys/mman/linux/mprotect.cpp
index 9a295d947ba7d..6ea35c279d54e 100644
--- a/libc/src/sys/mman/linux/mprotect.cpp
+++ b/libc/src/sys/mman/linux/mprotect.cpp
@@ -19,8 +19,8 @@ namespace __llvm_libc {
 // This function is currently linux only. It has to be refactored suitably if
 // mprotect is to be supported on non-linux operating systems also.
 LLVM_LIBC_FUNCTION(int, mprotect, (void *addr, size_t size, int prot)) {
-  long ret_val = __llvm_libc::syscall(SYS_mprotect,
-                                      reinterpret_cast<long>(addr), size, prot);
+  long ret_val = __llvm_libc::syscall_impl(
+      SYS_mprotect, reinterpret_cast<long>(addr), size, prot);
 
   // A negative return value indicates an error with the magnitude of the
   // value being the error code.

diff  --git a/libc/src/sys/mman/linux/munmap.cpp b/libc/src/sys/mman/linux/munmap.cpp
index 2abeb3134242b..3be5a8977299e 100644
--- a/libc/src/sys/mman/linux/munmap.cpp
+++ b/libc/src/sys/mman/linux/munmap.cpp
@@ -20,7 +20,7 @@ namespace __llvm_libc {
 // mmap is to be supported on non-linux operating systems also.
 LLVM_LIBC_FUNCTION(int, munmap, (void *addr, size_t size)) {
   long ret_val =
-      __llvm_libc::syscall(SYS_munmap, reinterpret_cast<long>(addr), size);
+      __llvm_libc::syscall_impl(SYS_munmap, reinterpret_cast<long>(addr), size);
 
   // A negative return value indicates an error with the magnitude of the
   // value being the error code.

diff  --git a/libc/src/sys/mman/linux/posix_madvise.cpp b/libc/src/sys/mman/linux/posix_madvise.cpp
index 2d36747f76d30..51e8477d678e8 100644
--- a/libc/src/sys/mman/linux/posix_madvise.cpp
+++ b/libc/src/sys/mman/linux/posix_madvise.cpp
@@ -23,8 +23,8 @@ LLVM_LIBC_FUNCTION(int, posix_madvise, (void *addr, size_t size, int advice)) {
   if (advice == POSIX_MADV_DONTNEED) {
     return 0;
   }
-  long ret_val = __llvm_libc::syscall(SYS_madvise, reinterpret_cast<long>(addr),
-                                      size, advice);
+  long ret_val = __llvm_libc::syscall_impl(
+      SYS_madvise, reinterpret_cast<long>(addr), size, advice);
   return ret_val < 0 ? -ret_val : 0;
 }
 

diff  --git a/libc/src/sys/resource/linux/getrlimit.cpp b/libc/src/sys/resource/linux/getrlimit.cpp
index a9d1d2754a97f..613c1a78e6709 100644
--- a/libc/src/sys/resource/linux/getrlimit.cpp
+++ b/libc/src/sys/resource/linux/getrlimit.cpp
@@ -18,7 +18,7 @@
 namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, getrlimit, (int res, struct rlimit *limits)) {
-  long ret = __llvm_libc::syscall(SYS_prlimit64, 0, res, nullptr, limits);
+  long ret = __llvm_libc::syscall_impl(SYS_prlimit64, 0, res, nullptr, limits);
   if (ret < 0) {
     errno = -ret;
     return -1;

diff  --git a/libc/src/sys/resource/linux/setrlimit.cpp b/libc/src/sys/resource/linux/setrlimit.cpp
index efca4c565b91b..b0c1ea52e783e 100644
--- a/libc/src/sys/resource/linux/setrlimit.cpp
+++ b/libc/src/sys/resource/linux/setrlimit.cpp
@@ -18,7 +18,7 @@
 namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, setrlimit, (int res, const struct rlimit *limits)) {
-  long ret = __llvm_libc::syscall(SYS_prlimit64, 0, res, limits, nullptr);
+  long ret = __llvm_libc::syscall_impl(SYS_prlimit64, 0, res, limits, nullptr);
   if (ret < 0) {
     errno = -ret;
     return -1;

diff  --git a/libc/src/sys/sendfile/linux/sendfile.cpp b/libc/src/sys/sendfile/linux/sendfile.cpp
index 8beaae2607bab..1f8a2c4421b3c 100644
--- a/libc/src/sys/sendfile/linux/sendfile.cpp
+++ b/libc/src/sys/sendfile/linux/sendfile.cpp
@@ -19,7 +19,8 @@ namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(ssize_t, sendfile,
                    (int out_fd, int in_fd, off_t *offset, size_t count)) {
-  long ret = __llvm_libc::syscall(SYS_sendfile, in_fd, out_fd, offset, count);
+  long ret =
+      __llvm_libc::syscall_impl(SYS_sendfile, in_fd, out_fd, offset, count);
   if (ret < 0) {
     errno = -ret;
     return -1;

diff  --git a/libc/src/sys/stat/linux/chmod.cpp b/libc/src/sys/stat/linux/chmod.cpp
index 5e092f24461a3..1b8c6ee19b58a 100644
--- a/libc/src/sys/stat/linux/chmod.cpp
+++ b/libc/src/sys/stat/linux/chmod.cpp
@@ -20,9 +20,9 @@ namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, chmod, (const char *path, mode_t mode)) {
 #ifdef SYS_chmod
-  long ret = __llvm_libc::syscall(SYS_chmod, path, mode);
+  long ret = __llvm_libc::syscall_impl(SYS_chmod, path, mode);
 #elif defined(SYS_fchmodat)
-  long ret = __llvm_libc::syscall(SYS_fchmodat, AT_FDCWD, path, mode);
+  long ret = __llvm_libc::syscall_impl(SYS_fchmodat, AT_FDCWD, path, mode);
 #else
 #error "chmod and chmodat syscalls not available."
 #endif

diff  --git a/libc/src/sys/stat/linux/fchmod.cpp b/libc/src/sys/stat/linux/fchmod.cpp
index 5edf3a51aa2d7..c6ce8d9acb8fc 100644
--- a/libc/src/sys/stat/linux/fchmod.cpp
+++ b/libc/src/sys/stat/linux/fchmod.cpp
@@ -19,7 +19,7 @@
 namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, fchmod, (int fd, mode_t mode)) {
-  long ret = __llvm_libc::syscall(SYS_fchmod, fd, mode);
+  long ret = __llvm_libc::syscall_impl(SYS_fchmod, fd, mode);
   if (ret < 0) {
     errno = -ret;
     return -1;

diff  --git a/libc/src/sys/stat/linux/fchmodat.cpp b/libc/src/sys/stat/linux/fchmodat.cpp
index 6c880bda6e404..82a9a831eef55 100644
--- a/libc/src/sys/stat/linux/fchmodat.cpp
+++ b/libc/src/sys/stat/linux/fchmodat.cpp
@@ -19,7 +19,7 @@ namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, fchmodat,
                    (int dirfd, const char *path, mode_t mode, int flags)) {
-  long ret = __llvm_libc::syscall(SYS_fchmodat, dirfd, path, mode, flags);
+  long ret = __llvm_libc::syscall_impl(SYS_fchmodat, dirfd, path, mode, flags);
   if (ret < 0) {
     errno = -ret;
     return -1;

diff  --git a/libc/src/sys/stat/linux/kernel_statx.h b/libc/src/sys/stat/linux/kernel_statx.h
index 3f14f4dca8cc6..7260f155f512b 100644
--- a/libc/src/sys/stat/linux/kernel_statx.h
+++ b/libc/src/sys/stat/linux/kernel_statx.h
@@ -73,8 +73,8 @@ inline int statx(int dirfd, const char *__restrict path, int flags,
                  struct stat *__restrict statbuf) {
   // We make a statx syscall and copy out the result into the |statbuf|.
   ::statx_buf xbuf;
-  long ret =
-      syscall(SYS_statx, dirfd, path, flags, ::STATX_BASIC_STATS_MASK, &xbuf);
+  long ret = __llvm_libc::syscall_impl(SYS_statx, dirfd, path, flags,
+                                       ::STATX_BASIC_STATS_MASK, &xbuf);
   if (ret < 0) {
     errno = -ret;
     return -1;

diff  --git a/libc/src/sys/stat/linux/mkdir.cpp b/libc/src/sys/stat/linux/mkdir.cpp
index aac100dae98ed..404ea0f7be41a 100644
--- a/libc/src/sys/stat/linux/mkdir.cpp
+++ b/libc/src/sys/stat/linux/mkdir.cpp
@@ -20,9 +20,9 @@ namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, mkdir, (const char *path, mode_t mode)) {
 #ifdef SYS_mkdir
-  long ret = __llvm_libc::syscall(SYS_mkdir, path, mode);
+  long ret = __llvm_libc::syscall_impl(SYS_mkdir, path, mode);
 #elif defined(SYS_mkdirat)
-  long ret = __llvm_libc::syscall(SYS_mkdirat, AT_FDCWD, path, mode);
+  long ret = __llvm_libc::syscall_impl(SYS_mkdirat, AT_FDCWD, path, mode);
 #else
 #error "mkdir and mkdirat syscalls not available."
 #endif

diff  --git a/libc/src/sys/stat/linux/mkdirat.cpp b/libc/src/sys/stat/linux/mkdirat.cpp
index 9b4197dfefae8..0ab146942f5af 100644
--- a/libc/src/sys/stat/linux/mkdirat.cpp
+++ b/libc/src/sys/stat/linux/mkdirat.cpp
@@ -19,7 +19,7 @@ namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, mkdirat, (int dfd, const char *path, mode_t mode)) {
 #ifdef SYS_mkdirat
-  long ret = __llvm_libc::syscall(SYS_mkdirat, dfd, path, mode);
+  long ret = __llvm_libc::syscall_impl(SYS_mkdirat, dfd, path, mode);
 #else
 #error "mkdirat syscalls not available."
 #endif

diff  --git a/libc/src/sys/utsname/linux/uname.cpp b/libc/src/sys/utsname/linux/uname.cpp
index 42bdf2544913b..86724b3ffcc31 100644
--- a/libc/src/sys/utsname/linux/uname.cpp
+++ b/libc/src/sys/utsname/linux/uname.cpp
@@ -18,7 +18,7 @@
 namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, uname, (struct utsname * name)) {
-  long ret = __llvm_libc::syscall(SYS_uname, name);
+  long ret = __llvm_libc::syscall_impl(SYS_uname, name);
 
   if (ret >= 0)
     return 1;

diff  --git a/libc/src/threads/linux/CndVar.h b/libc/src/threads/linux/CndVar.h
index 009cb9f06c3f3..c526277d62c7d 100644
--- a/libc/src/threads/linux/CndVar.h
+++ b/libc/src/threads/linux/CndVar.h
@@ -84,8 +84,8 @@ struct CndVar {
       }
     }
 
-    __llvm_libc::syscall(SYS_futex, &waiter.futex_word.val, FUTEX_WAIT,
-                         WS_Waiting, 0, 0, 0);
+    __llvm_libc::syscall_impl(SYS_futex, &waiter.futex_word.val, FUTEX_WAIT,
+                              WS_Waiting, 0, 0, 0);
 
     // At this point, if locking |m| fails, we can simply return as the
     // queued up waiter would have been removed from the queue.
@@ -109,7 +109,7 @@ struct CndVar {
 
     qmtx.futex_word = FutexWordType(Mutex::LockState::Free);
 
-    __llvm_libc::syscall(
+    __llvm_libc::syscall_impl(
         SYS_futex, &qmtx.futex_word.val, FUTEX_WAKE_OP, 1, 1,
         &first->futex_word.val,
         FUTEX_OP(FUTEX_OP_SET, WS_Signalled, FUTEX_OP_CMP_EQ, WS_Waiting));
@@ -126,7 +126,7 @@ struct CndVar {
       // atomically update the waiter status to WS_Signalled before waking
       // up the waiter. A dummy location is used for the other futex of
       // FUTEX_WAKE_OP.
-      __llvm_libc::syscall(
+      __llvm_libc::syscall_impl(
           SYS_futex, &dummy_futex_word, FUTEX_WAKE_OP, 1, 1,
           &waiter->futex_word.val,
           FUTEX_OP(FUTEX_OP_SET, WS_Signalled, FUTEX_OP_CMP_EQ, WS_Waiting));

diff  --git a/libc/src/threads/linux/call_once.cpp b/libc/src/threads/linux/call_once.cpp
index e04c4e47853b8..ac87a0d877d3b 100644
--- a/libc/src/threads/linux/call_once.cpp
+++ b/libc/src/threads/linux/call_once.cpp
@@ -46,9 +46,9 @@ LLVM_LIBC_FUNCTION(void, call_once,
     func();
     auto status = futex_word->exchange(FINISH);
     if (status == WAITING) {
-      __llvm_libc::syscall(SYS_futex, &futex_word->val, FUTEX_WAKE_PRIVATE,
-                           INT_MAX, // Wake all waiters.
-                           0, 0, 0);
+      __llvm_libc::syscall_impl(SYS_futex, &futex_word->val, FUTEX_WAKE_PRIVATE,
+                                INT_MAX, // Wake all waiters.
+                                0, 0, 0);
     }
     return;
   }
@@ -56,9 +56,10 @@ LLVM_LIBC_FUNCTION(void, call_once,
   FutexWordType status = START;
   if (futex_word->compare_exchange_strong(status, WAITING) ||
       status == WAITING) {
-    __llvm_libc::syscall(SYS_futex, &futex_word->val, FUTEX_WAIT_PRIVATE,
-                         WAITING, // Block only if status is still |WAITING|.
-                         0, 0, 0);
+    __llvm_libc::syscall_impl(
+        SYS_futex, &futex_word->val, FUTEX_WAIT_PRIVATE,
+        WAITING, // Block only if status is still |WAITING|.
+        0, 0, 0);
   }
 }
 

diff  --git a/libc/src/time/clock_gettime.cpp b/libc/src/time/clock_gettime.cpp
index 420dc367e571e..407135b6d3ebf 100644
--- a/libc/src/time/clock_gettime.cpp
+++ b/libc/src/time/clock_gettime.cpp
@@ -21,8 +21,8 @@ namespace __llvm_libc {
 LLVM_LIBC_FUNCTION(int, clock_gettime,
                    (clockid_t clockid, struct timespec *tp)) {
   long ret_val =
-      __llvm_libc::syscall(SYS_clock_gettime, static_cast<long>(clockid),
-                           reinterpret_cast<long>(tp));
+      __llvm_libc::syscall_impl(SYS_clock_gettime, static_cast<long>(clockid),
+                                reinterpret_cast<long>(tp));
   // A negative return value indicates an error with the magnitude of the
   // value being the error code.
   if (ret_val < 0) {

diff  --git a/libc/src/time/nanosleep.cpp b/libc/src/time/nanosleep.cpp
index 2eb5e97aff090..d586b6aee5cd3 100644
--- a/libc/src/time/nanosleep.cpp
+++ b/libc/src/time/nanosleep.cpp
@@ -18,7 +18,7 @@ namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, nanosleep,
                    (const struct timespec *req, struct timespec *rem)) {
-  int ret = __llvm_libc::syscall(SYS_nanosleep, req, rem);
+  int ret = __llvm_libc::syscall_impl(SYS_nanosleep, req, rem);
   if (ret < 0) {
     errno = -ret;
     return -1;

diff  --git a/libc/src/unistd/CMakeLists.txt b/libc/src/unistd/CMakeLists.txt
index 437556c3a4585..1e54f4cd4d351 100644
--- a/libc/src/unistd/CMakeLists.txt
+++ b/libc/src/unistd/CMakeLists.txt
@@ -170,6 +170,13 @@ add_entrypoint_object(
     .${LIBC_TARGET_OS}.symlinkat
 )
 
+add_entrypoint_object(
+  __llvm_libc_syscall
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.__llvm_libc_syscall
+)
+
 add_entrypoint_object(
   truncate
   ALIAS

diff  --git a/libc/src/unistd/linux/CMakeLists.txt b/libc/src/unistd/linux/CMakeLists.txt
index 6c1bf34f70392..0bbde7a102ab6 100644
--- a/libc/src/unistd/linux/CMakeLists.txt
+++ b/libc/src/unistd/linux/CMakeLists.txt
@@ -314,6 +314,18 @@ add_entrypoint_object(
     libc.src.errno.errno
 )
 
+add_entrypoint_object(
+  __llvm_libc_syscall
+  SRCS
+    syscall.cpp
+  HDRS
+    ../syscall.h
+  DEPENDS
+    libc.include.unistd
+    libc.src.__support.OSUtil.osutil
+    libc.src.errno.errno
+)
+
 add_entrypoint_object(
   truncate
   SRCS

diff  --git a/libc/src/unistd/linux/access.cpp b/libc/src/unistd/linux/access.cpp
index 41fd3793f9077..1862faaeefdd4 100644
--- a/libc/src/unistd/linux/access.cpp
+++ b/libc/src/unistd/linux/access.cpp
@@ -19,9 +19,9 @@ namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, access, (const char *path, int mode)) {
 #ifdef SYS_access
-  long ret = __llvm_libc::syscall(SYS_access, path, mode);
+  long ret = __llvm_libc::syscall_impl(SYS_access, path, mode);
 #elif defined(SYS_faccessat)
-  long ret = __llvm_libc::syscall(SYS_faccessat, AT_FDCWD, path, mode, 0);
+  long ret = __llvm_libc::syscall_impl(SYS_faccessat, AT_FDCWD, path, mode, 0);
 #else
 #error "access syscalls not available."
 #endif

diff  --git a/libc/src/unistd/linux/chdir.cpp b/libc/src/unistd/linux/chdir.cpp
index 93ae33861c98a..9a8bc1d93f08b 100644
--- a/libc/src/unistd/linux/chdir.cpp
+++ b/libc/src/unistd/linux/chdir.cpp
@@ -17,7 +17,7 @@
 namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, chdir, (const char *path)) {
-  long ret = __llvm_libc::syscall(SYS_chdir, path);
+  long ret = __llvm_libc::syscall_impl(SYS_chdir, path);
   if (ret < 0) {
     errno = -ret;
     return -1;

diff  --git a/libc/src/unistd/linux/close.cpp b/libc/src/unistd/linux/close.cpp
index 5380c078ded71..850222e8b7ec6 100644
--- a/libc/src/unistd/linux/close.cpp
+++ b/libc/src/unistd/linux/close.cpp
@@ -17,7 +17,7 @@
 namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, close, (int fd)) {
-  long ret = __llvm_libc::syscall(SYS_close, fd);
+  long ret = __llvm_libc::syscall_impl(SYS_close, fd);
   if (ret < 0) {
     errno = -ret;
     return -1;

diff  --git a/libc/src/unistd/linux/dup.cpp b/libc/src/unistd/linux/dup.cpp
index 9706b98897a80..9e537dc88bb42 100644
--- a/libc/src/unistd/linux/dup.cpp
+++ b/libc/src/unistd/linux/dup.cpp
@@ -17,7 +17,7 @@
 namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, dup, (int fd)) {
-  long ret = __llvm_libc::syscall(SYS_dup, fd);
+  long ret = __llvm_libc::syscall_impl(SYS_dup, fd);
   if (ret < 0) {
     errno = -ret;
     return -1;

diff  --git a/libc/src/unistd/linux/dup2.cpp b/libc/src/unistd/linux/dup2.cpp
index e066a7c471692..760adc6b7bb64 100644
--- a/libc/src/unistd/linux/dup2.cpp
+++ b/libc/src/unistd/linux/dup2.cpp
@@ -20,20 +20,20 @@ namespace __llvm_libc {
 LLVM_LIBC_FUNCTION(int, dup2, (int oldfd, int newfd)) {
 #ifdef SYS_dup2
   // If dup2 syscall is available, we make use of directly.
-  long ret = __llvm_libc::syscall(SYS_dup2, oldfd, newfd);
+  long ret = __llvm_libc::syscall_impl(SYS_dup2, oldfd, newfd);
 #elif defined(SYS_dup3)
   // If dup2 syscall is not available, we try using the dup3 syscall. However,
   // dup3 fails if oldfd is the same as newfd. So, we handle that case
   // separately before making the dup3 syscall.
   if (oldfd == newfd) {
     // Check if oldfd is actually a valid file descriptor.
-    long ret = __llvm_libc::syscall(SYS_fcntl, oldfd, F_GETFD);
+    long ret = __llvm_libc::syscall_impl(SYS_fcntl, oldfd, F_GETFD);
     if (ret >= 0)
       return oldfd;
     errno = -ret;
     return -1;
   }
-  long ret = __llvm_libc::syscall(SYS_dup3, oldfd, newfd, 0);
+  long ret = __llvm_libc::syscall_impl(SYS_dup3, oldfd, newfd, 0);
 #else
 #error "SYS_dup2 and SYS_dup3 not available for the target."
 #endif

diff  --git a/libc/src/unistd/linux/dup3.cpp b/libc/src/unistd/linux/dup3.cpp
index 193ff3e278dd8..8f6930900f0f8 100644
--- a/libc/src/unistd/linux/dup3.cpp
+++ b/libc/src/unistd/linux/dup3.cpp
@@ -18,7 +18,7 @@ namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, dup3, (int oldfd, int newfd, int flags)) {
   // If dup2 syscall is available, we make use of directly.
-  long ret = __llvm_libc::syscall(SYS_dup3, oldfd, newfd, flags);
+  long ret = __llvm_libc::syscall_impl(SYS_dup3, oldfd, newfd, flags);
   if (ret >= 0)
     return ret;
   errno = -ret;

diff  --git a/libc/src/unistd/linux/fchdir.cpp b/libc/src/unistd/linux/fchdir.cpp
index 86af84d4ebfd6..2d5aea3efa5d3 100644
--- a/libc/src/unistd/linux/fchdir.cpp
+++ b/libc/src/unistd/linux/fchdir.cpp
@@ -17,7 +17,7 @@
 namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, fchdir, (int fd)) {
-  long ret = __llvm_libc::syscall(SYS_fchdir, fd);
+  long ret = __llvm_libc::syscall_impl(SYS_fchdir, fd);
   if (ret < 0) {
     errno = -ret;
     return -1;

diff  --git a/libc/src/unistd/linux/fsync.cpp b/libc/src/unistd/linux/fsync.cpp
index 2ee9cc945babe..1665611321bb7 100644
--- a/libc/src/unistd/linux/fsync.cpp
+++ b/libc/src/unistd/linux/fsync.cpp
@@ -17,7 +17,7 @@
 namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, fsync, (int fd)) {
-  long ret = __llvm_libc::syscall(SYS_fsync, fd);
+  long ret = __llvm_libc::syscall_impl(SYS_fsync, fd);
   if (ret < 0) {
     errno = -ret;
     return -1;

diff  --git a/libc/src/unistd/linux/ftruncate.cpp b/libc/src/unistd/linux/ftruncate.cpp
index 38de44100162a..f96d31e6c4985 100644
--- a/libc/src/unistd/linux/ftruncate.cpp
+++ b/libc/src/unistd/linux/ftruncate.cpp
@@ -18,7 +18,7 @@
 namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, ftruncate, (int fd, off_t len)) {
-  int ret = __llvm_libc::syscall(SYS_ftruncate, fd, len);
+  int ret = __llvm_libc::syscall_impl(SYS_ftruncate, fd, len);
   if (ret < 0) {
     errno = -ret;
     return -1;

diff  --git a/libc/src/unistd/linux/geteuid.cpp b/libc/src/unistd/linux/geteuid.cpp
index 734da5abd4847..213d961032876 100644
--- a/libc/src/unistd/linux/geteuid.cpp
+++ b/libc/src/unistd/linux/geteuid.cpp
@@ -16,7 +16,7 @@
 namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(uid_t, geteuid, ()) {
-  return __llvm_libc::syscall(SYS_geteuid);
+  return __llvm_libc::syscall_impl(SYS_geteuid);
 }
 
 } // namespace __llvm_libc

diff  --git a/libc/src/unistd/linux/getpid.cpp b/libc/src/unistd/linux/getpid.cpp
index d00112f8b929b..f04e751bc75f3 100644
--- a/libc/src/unistd/linux/getpid.cpp
+++ b/libc/src/unistd/linux/getpid.cpp
@@ -16,7 +16,7 @@
 namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(pid_t, getpid, ()) {
-  return __llvm_libc::syscall(SYS_getpid);
+  return __llvm_libc::syscall_impl(SYS_getpid);
 }
 
 } // namespace __llvm_libc

diff  --git a/libc/src/unistd/linux/getppid.cpp b/libc/src/unistd/linux/getppid.cpp
index be5ab23cfcb34..7a19d8dcc563d 100644
--- a/libc/src/unistd/linux/getppid.cpp
+++ b/libc/src/unistd/linux/getppid.cpp
@@ -16,7 +16,7 @@
 namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(pid_t, getppid, ()) {
-  return __llvm_libc::syscall(SYS_getppid);
+  return __llvm_libc::syscall_impl(SYS_getppid);
 }
 
 } // namespace __llvm_libc

diff  --git a/libc/src/unistd/linux/getuid.cpp b/libc/src/unistd/linux/getuid.cpp
index 716fa61de762c..b31ee49c83a89 100644
--- a/libc/src/unistd/linux/getuid.cpp
+++ b/libc/src/unistd/linux/getuid.cpp
@@ -16,7 +16,7 @@
 namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(uid_t, getuid, ()) {
-  return __llvm_libc::syscall(SYS_getuid);
+  return __llvm_libc::syscall_impl(SYS_getuid);
 }
 
 } // namespace __llvm_libc

diff  --git a/libc/src/unistd/linux/link.cpp b/libc/src/unistd/linux/link.cpp
index 9f6f915d16135..2d77c37686ed8 100644
--- a/libc/src/unistd/linux/link.cpp
+++ b/libc/src/unistd/linux/link.cpp
@@ -19,10 +19,10 @@ namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, link, (const char *path1, const char *path2)) {
 #ifdef SYS_link
-  long ret = __llvm_libc::syscall(SYS_link, path1, path2);
+  long ret = __llvm_libc::syscall_impl(SYS_link, path1, path2);
 #elif defined(SYS_linkat)
-  long ret =
-      __llvm_libc::syscall(SYS_linkat, AT_FDCWD, path1, AT_FDCWD, path2, 0);
+  long ret = __llvm_libc::syscall_impl(SYS_linkat, AT_FDCWD, path1, AT_FDCWD,
+                                       path2, 0);
 #else
 #error "SYS_link or SYS_linkat not available."
 #endif

diff  --git a/libc/src/unistd/linux/linkat.cpp b/libc/src/unistd/linux/linkat.cpp
index ef5761173dd0a..170cd0abee34d 100644
--- a/libc/src/unistd/linux/linkat.cpp
+++ b/libc/src/unistd/linux/linkat.cpp
@@ -20,7 +20,8 @@ namespace __llvm_libc {
 LLVM_LIBC_FUNCTION(int, linkat,
                    (int fd1, const char *path1, int fd2, const char *path2,
                     int flags)) {
-  long ret = __llvm_libc::syscall(SYS_linkat, fd1, path1, fd2, path2, flags);
+  long ret =
+      __llvm_libc::syscall_impl(SYS_linkat, fd1, path1, fd2, path2, flags);
   if (ret < 0) {
     errno = -ret;
     return -1;

diff  --git a/libc/src/unistd/linux/lseek.cpp b/libc/src/unistd/linux/lseek.cpp
index 4afddd37c695b..07f93baa9469e 100644
--- a/libc/src/unistd/linux/lseek.cpp
+++ b/libc/src/unistd/linux/lseek.cpp
@@ -20,11 +20,11 @@ namespace __llvm_libc {
 LLVM_LIBC_FUNCTION(off_t, lseek, (int fd, off_t offset, int whence)) {
   off_t result;
 #ifdef SYS_lseek
-  long ret = __llvm_libc::syscall(SYS_lseek, fd, offset, whence);
+  long ret = __llvm_libc::syscall_impl(SYS_lseek, fd, offset, whence);
   result = ret;
 #elif defined(SYS__llseek)
-  long ret = __llvm_libc::syscall(SYS__llseek, fd, offset >> 32, offset,
-                                  &result, whence);
+  long ret = __llvm_libc::syscall_impl(SYS__llseek, fd, offset >> 32, offset,
+                                       &result, whence);
 #else
 #error "lseek and _llseek syscalls not available."
 #endif

diff  --git a/libc/src/unistd/linux/pread.cpp b/libc/src/unistd/linux/pread.cpp
index 24f4d472e84f7..1434f9781c2df 100644
--- a/libc/src/unistd/linux/pread.cpp
+++ b/libc/src/unistd/linux/pread.cpp
@@ -18,7 +18,7 @@ namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(ssize_t, pread,
                    (int fd, void *buf, size_t count, off_t offset)) {
-  long ret = __llvm_libc::syscall(SYS_pread64, fd, buf, count, offset);
+  long ret = __llvm_libc::syscall_impl(SYS_pread64, fd, buf, count, offset);
   if (ret < 0) {
     errno = -ret;
     return -1;

diff  --git a/libc/src/unistd/linux/pwrite.cpp b/libc/src/unistd/linux/pwrite.cpp
index d26f87660de9c..597d266696b89 100644
--- a/libc/src/unistd/linux/pwrite.cpp
+++ b/libc/src/unistd/linux/pwrite.cpp
@@ -18,7 +18,7 @@ namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(ssize_t, pwrite,
                    (int fd, const void *buf, size_t count, off_t offset)) {
-  long ret = __llvm_libc::syscall(SYS_pwrite64, fd, buf, count, offset);
+  long ret = __llvm_libc::syscall_impl(SYS_pwrite64, fd, buf, count, offset);
   if (ret < 0) {
     errno = -ret;
     return -1;

diff  --git a/libc/src/unistd/linux/read.cpp b/libc/src/unistd/linux/read.cpp
index 309976374b998..468409d08e6f7 100644
--- a/libc/src/unistd/linux/read.cpp
+++ b/libc/src/unistd/linux/read.cpp
@@ -17,7 +17,7 @@
 namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(ssize_t, read, (int fd, void *buf, size_t count)) {
-  long ret = __llvm_libc::syscall(SYS_read, fd, buf, count);
+  long ret = __llvm_libc::syscall_impl(SYS_read, fd, buf, count);
   if (ret < 0) {
     errno = -ret;
     return -1;

diff  --git a/libc/src/unistd/linux/readlink.cpp b/libc/src/unistd/linux/readlink.cpp
index 354cdb2dc4e70..713620e43c9aa 100644
--- a/libc/src/unistd/linux/readlink.cpp
+++ b/libc/src/unistd/linux/readlink.cpp
@@ -21,10 +21,10 @@ LLVM_LIBC_FUNCTION(ssize_t, readlink,
                    (const char *__restrict path, char *__restrict buf,
                     size_t bufsize)) {
 #ifdef SYS_readlink
-  ssize_t ret = __llvm_libc::syscall(SYS_readlink, path, buf, bufsize);
+  ssize_t ret = __llvm_libc::syscall_impl(SYS_readlink, path, buf, bufsize);
 #elif defined(SYS_readlinkat)
   ssize_t ret =
-      __llvm_libc::syscall(SYS_readlinkat, AT_FDCWD, path, buf, bufsize);
+      __llvm_libc::syscall_impl(SYS_readlinkat, AT_FDCWD, path, buf, bufsize);
 #else
 #error "SYS_readlink or SYS_readlinkat not available."
 #endif

diff  --git a/libc/src/unistd/linux/readlinkat.cpp b/libc/src/unistd/linux/readlinkat.cpp
index ceb4061a84cd2..8b0994a2622dc 100644
--- a/libc/src/unistd/linux/readlinkat.cpp
+++ b/libc/src/unistd/linux/readlinkat.cpp
@@ -20,7 +20,8 @@ namespace __llvm_libc {
 LLVM_LIBC_FUNCTION(ssize_t, readlinkat,
                    (int fd, const char *__restrict path, char *__restrict buf,
                     size_t bufsize)) {
-  ssize_t ret = __llvm_libc::syscall(SYS_readlinkat, fd, path, buf, bufsize);
+  ssize_t ret =
+      __llvm_libc::syscall_impl(SYS_readlinkat, fd, path, buf, bufsize);
   if (ret < 0) {
     errno = -ret;
     return -1;

diff  --git a/libc/src/unistd/linux/rmdir.cpp b/libc/src/unistd/linux/rmdir.cpp
index 8bc180550021b..144a0902ffaf6 100644
--- a/libc/src/unistd/linux/rmdir.cpp
+++ b/libc/src/unistd/linux/rmdir.cpp
@@ -19,9 +19,10 @@ namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, rmdir, (const char *path)) {
 #ifdef SYS_rmdir
-  long ret = __llvm_libc::syscall(SYS_rmdir, path);
+  long ret = __llvm_libc::syscall_impl(SYS_rmdir, path);
 #elif defined(SYS_unlinkat)
-  long ret = __llvm_libc::syscall(SYS_unlinkat, AT_FDCWD, path, AT_REMOVEDIR);
+  long ret =
+      __llvm_libc::syscall_impl(SYS_unlinkat, AT_FDCWD, path, AT_REMOVEDIR);
 #else
 #error "rmdir and unlinkat syscalls not available."
 #endif

diff  --git a/libc/src/unistd/linux/symlink.cpp b/libc/src/unistd/linux/symlink.cpp
index add7b95f756dc..caa07b0b4f9cb 100644
--- a/libc/src/unistd/linux/symlink.cpp
+++ b/libc/src/unistd/linux/symlink.cpp
@@ -19,9 +19,9 @@ namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, symlink, (const char *path1, const char *path2)) {
 #ifdef SYS_symlink
-  long ret = __llvm_libc::syscall(SYS_symlink, path1, path2);
+  long ret = __llvm_libc::syscall_impl(SYS_symlink, path1, path2);
 #elif defined(SYS_symlinkat)
-  long ret = __llvm_libc::syscall(SYS_symlinkat, path1, AT_FDCWD, path2);
+  long ret = __llvm_libc::syscall_impl(SYS_symlinkat, path1, AT_FDCWD, path2);
 #else
 #error "SYS_symlink or SYS_symlinkat not available."
 #endif

diff  --git a/libc/src/unistd/linux/symlinkat.cpp b/libc/src/unistd/linux/symlinkat.cpp
index e0edfc842dd68..25377b6959347 100644
--- a/libc/src/unistd/linux/symlinkat.cpp
+++ b/libc/src/unistd/linux/symlinkat.cpp
@@ -19,7 +19,7 @@ namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, symlinkat,
                    (const char *path1, int fd, const char *path2)) {
-  long ret = __llvm_libc::syscall(SYS_symlinkat, path1, fd, path2);
+  long ret = __llvm_libc::syscall_impl(SYS_symlinkat, path1, fd, path2);
   if (ret < 0) {
     errno = -ret;
     return -1;

diff  --git a/libc/src/unistd/linux/syscall.cpp b/libc/src/unistd/linux/syscall.cpp
new file mode 100644
index 0000000000000..83884043484f3
--- /dev/null
+++ b/libc/src/unistd/linux/syscall.cpp
@@ -0,0 +1,33 @@
+//===-- Linux implementation of syscall -----------------------------------===//
+//
+// 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/unistd/syscall.h"
+
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/common.h"
+
+#include <errno.h>
+#include <stdarg.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(long, __llvm_libc_syscall,
+                   (long number, long arg1, long arg2, long arg3, long arg4,
+                    long arg5, long arg6)) {
+  long ret =
+      __llvm_libc::syscall_impl(number, arg1, arg2, arg3, arg4, arg5, arg6);
+  // Syscalls may return large positive values that overflow, but will never
+  // return values between -4096 and -1
+  if (static_cast<unsigned long>(ret) > -4096UL) {
+    errno = -ret;
+    return -1;
+  }
+  return ret;
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/unistd/linux/truncate.cpp b/libc/src/unistd/linux/truncate.cpp
index c24bfa8e47b70..9ab05c15b81a1 100644
--- a/libc/src/unistd/linux/truncate.cpp
+++ b/libc/src/unistd/linux/truncate.cpp
@@ -18,7 +18,7 @@
 namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, truncate, (const char *path, off_t len)) {
-  int ret = __llvm_libc::syscall(SYS_truncate, path, len);
+  int ret = __llvm_libc::syscall_impl(SYS_truncate, path, len);
   if (ret < 0) {
     errno = -ret;
     return -1;

diff  --git a/libc/src/unistd/linux/unlink.cpp b/libc/src/unistd/linux/unlink.cpp
index 386a84e7679e2..019b081e280c9 100644
--- a/libc/src/unistd/linux/unlink.cpp
+++ b/libc/src/unistd/linux/unlink.cpp
@@ -19,9 +19,9 @@ namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, unlink, (const char *path)) {
 #ifdef SYS_unlink
-  long ret = __llvm_libc::syscall(SYS_unlink, path);
+  long ret = __llvm_libc::syscall_impl(SYS_unlink, path);
 #elif defined(SYS_unlinkat)
-  long ret = __llvm_libc::syscall(SYS_unlinkat, AT_FDCWD, path, 0);
+  long ret = __llvm_libc::syscall_impl(SYS_unlinkat, AT_FDCWD, path, 0);
 #else
 #error "Unlink syscalls not available."
 #endif

diff  --git a/libc/src/unistd/linux/unlinkat.cpp b/libc/src/unistd/linux/unlinkat.cpp
index dcfea888453f0..9ca6108a68973 100644
--- a/libc/src/unistd/linux/unlinkat.cpp
+++ b/libc/src/unistd/linux/unlinkat.cpp
@@ -19,7 +19,7 @@ namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, unlinkat, (int dfd, const char *path, int flags)) {
 #ifdef SYS_unlinkat
-  long ret = __llvm_libc::syscall(SYS_unlinkat, dfd, path, flags);
+  long ret = __llvm_libc::syscall_impl(SYS_unlinkat, dfd, path, flags);
 #else
 #error "unlinkat syscall not available."
 #endif

diff  --git a/libc/src/unistd/linux/write.cpp b/libc/src/unistd/linux/write.cpp
index 68ff1fa3d848e..599ff4b232916 100644
--- a/libc/src/unistd/linux/write.cpp
+++ b/libc/src/unistd/linux/write.cpp
@@ -17,7 +17,7 @@
 namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(ssize_t, write, (int fd, const void *buf, size_t count)) {
-  long ret = __llvm_libc::syscall(SYS_write, fd, buf, count);
+  long ret = __llvm_libc::syscall_impl(SYS_write, fd, buf, count);
   if (ret < 0) {
     errno = -ret;
     return -1;

diff  --git a/libc/src/unistd/syscall.h b/libc/src/unistd/syscall.h
new file mode 100644
index 0000000000000..81ff64ebcf5a1
--- /dev/null
+++ b/libc/src/unistd/syscall.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for syscall -----------------------*- 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_UNISTD_SYSCALL_H
+#define LLVM_LIBC_SRC_UNISTD_SYSCALL_H
+
+#include <stdarg.h>
+#include <unistd.h>
+
+namespace __llvm_libc {
+
+long __llvm_libc_syscall(long number, long arg1, long arg2, long arg3,
+                         long arg4, long arg5, long arg6);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_UNISTD_SYSCALL_H

diff  --git a/libc/test/src/__support/OSUtil/linux/x86_64/syscall_test.cpp b/libc/test/src/__support/OSUtil/linux/x86_64/syscall_test.cpp
index 4869e0028df0a..18f9908738517 100644
--- a/libc/test/src/__support/OSUtil/linux/x86_64/syscall_test.cpp
+++ b/libc/test/src/__support/OSUtil/linux/x86_64/syscall_test.cpp
@@ -16,28 +16,29 @@ TEST(LlvmLibcX86_64_SyscallTest, APITest) {
 
   using __llvm_libc::cpp::function;
 
-  function<long(long)> f([](long n) { return __llvm_libc::syscall(n); });
+  function<long(long)> f([](long n) { return __llvm_libc::syscall_impl(n); });
   function<long(long, long)> f1(
-      [](long n, long a1) { return __llvm_libc::syscall(n, a1); });
-  function<long(long, long, long)> f2(
-      [](long n, long a1, long a2) { return __llvm_libc::syscall(n, a1, a2); });
+      [](long n, long a1) { return __llvm_libc::syscall_impl(n, a1); });
+  function<long(long, long, long)> f2([](long n, long a1, long a2) {
+    return __llvm_libc::syscall_impl(n, a1, a2);
+  });
   function<long(long, long, long, long)> f3(
       [](long n, long a1, long a2, long a3) {
-        return __llvm_libc::syscall(n, a1, a2, a3);
+        return __llvm_libc::syscall_impl(n, a1, a2, a3);
       });
   function<long(long, long, long, long, long)> f4(
       [](long n, long a1, long a2, long a3, long a4) {
-        return __llvm_libc::syscall(n, a1, a2, a3, a4);
+        return __llvm_libc::syscall_impl(n, a1, a2, a3, a4);
       });
   function<long(long, long, long, long, long, long)> f5(
       [](long n, long a1, long a2, long a3, long a4, long a5) {
-        return __llvm_libc::syscall(n, a1, a2, a3, a4, a5);
+        return __llvm_libc::syscall_impl(n, a1, a2, a3, a4, a5);
       });
   function<long(long, long, long, long, long, long, long)> f6(
       [](long n, long a1, long a2, long a3, long a4, long a5, long a6) {
-        return __llvm_libc::syscall(n, a1, a2, a3, a4, a5, a6);
+        return __llvm_libc::syscall_impl(n, a1, a2, a3, a4, a5, a6);
       });
 
   function<long(long, void *)> not_long_type(
-      [](long n, void *a1) { return __llvm_libc::syscall(n, a1); });
+      [](long n, void *a1) { return __llvm_libc::syscall_impl(n, a1); });
 }

diff  --git a/libc/test/src/sched/affinity_test.cpp b/libc/test/src/sched/affinity_test.cpp
index 860a479cd16a5..446e85721e91f 100644
--- a/libc/test/src/sched/affinity_test.cpp
+++ b/libc/test/src/sched/affinity_test.cpp
@@ -19,7 +19,7 @@ TEST(LlvmLibcSchedAffinityTest, SmokeTest) {
   cpu_set_t mask;
   errno = 0;
   using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
-  pid_t tid = __llvm_libc::syscall(SYS_gettid);
+  pid_t tid = __llvm_libc::syscall_impl(SYS_gettid);
   ASSERT_GT(tid, pid_t(0));
   // We just get and set the same mask.
   ASSERT_THAT(__llvm_libc::sched_getaffinity(tid, sizeof(cpu_set_t), &mask),
@@ -30,7 +30,7 @@ TEST(LlvmLibcSchedAffinityTest, SmokeTest) {
 
 TEST(LlvmLibcSchedAffinityTest, BadMask) {
   using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
-  pid_t tid = __llvm_libc::syscall(SYS_gettid);
+  pid_t tid = __llvm_libc::syscall_impl(SYS_gettid);
 
   errno = 0;
   ASSERT_THAT(__llvm_libc::sched_getaffinity(tid, sizeof(cpu_set_t), nullptr),

diff  --git a/libc/test/src/unistd/CMakeLists.txt b/libc/test/src/unistd/CMakeLists.txt
index 8f35efe947e55..448116e140b23 100644
--- a/libc/test/src/unistd/CMakeLists.txt
+++ b/libc/test/src/unistd/CMakeLists.txt
@@ -361,3 +361,18 @@ add_libc_unittest(
   DEPENDS
     libc.src.unistd.geteuid
 )
+
+add_libc_unittest(
+  syscall_test
+  SUITE
+    libc_unistd_unittests
+  SRCS
+    syscall_test.cpp
+  DEPENDS
+    libc.src.unistd.__llvm_libc_syscall
+    libc.include.errno
+    libc.include.unistd
+    libc.include.fcntl
+    libc.include.sys_syscall
+    libc.test.errno_setter_matcher
+)

diff  --git a/libc/test/src/unistd/syscall_test.cpp b/libc/test/src/unistd/syscall_test.cpp
new file mode 100644
index 0000000000000..e4c50545b1e37
--- /dev/null
+++ b/libc/test/src/unistd/syscall_test.cpp
@@ -0,0 +1,115 @@
+//===-- Unittests for syscalls --------------------------------------------===//
+//
+// 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/unistd/syscall.h"
+#include "test/ErrnoSetterMatcher.h"
+#include "utils/UnitTest/Test.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/syscall.h> // For syscall numbers.
+#include <unistd.h>
+
+using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
+
+// We only do a smoke test here. Actual functionality tests are
+// done by the unit tests of the syscall wrappers like mmap.
+// The goal is to test syscalls with a wide number of args.
+
+// There is no function named "syscall" in llvm-libc, we instead use a macro to
+// set up the arguments properly. We still need to specify the namespace though
+// because the macro generates a call to the actual internal function
+// (__llvm_libc_syscall) which is inside the namespace.
+TEST(LlvmLibcSyscallTest, TrivialCall) {
+  errno = 0;
+
+  ASSERT_GE(__llvm_libc::syscall(SYS_gettid), 0l);
+  ASSERT_EQ(errno, 0);
+}
+
+TEST(LlvmLibcSyscallTest, SymlinkCreateDestroy) {
+  constexpr const char LINK_VAL[] = "syscall_readlink_test_value";
+  constexpr const char LINK[] = "testdata/syscall_readlink.test.link";
+
+  ASSERT_GE(__llvm_libc::syscall(SYS_symlink, LINK_VAL, LINK), 0l);
+  ASSERT_EQ(errno, 0);
+
+  char buf[sizeof(LINK_VAL)];
+
+  ASSERT_GE(__llvm_libc::syscall(SYS_readlink, LINK, buf, sizeof(buf)), 0l);
+  ASSERT_EQ(errno, 0);
+
+  ASSERT_GE(__llvm_libc::syscall(SYS_unlink, LINK), 0l);
+  ASSERT_EQ(errno, 0);
+}
+
+TEST(LlvmLibcSyscallTest, FileReadWrite) {
+  constexpr const char HELLO[] = "hello";
+  constexpr int HELLO_SIZE = sizeof(HELLO);
+
+  constexpr const char *TEST_FILE = "testdata/syscall_pread_pwrite.test";
+
+  int fd =
+      __llvm_libc::syscall(SYS_open, TEST_FILE, O_WRONLY | O_CREAT, S_IRWXU);
+  ASSERT_GT(fd, 0);
+  ASSERT_EQ(errno, 0);
+
+  ASSERT_GE(__llvm_libc::syscall(SYS_pwrite64, fd, HELLO, HELLO_SIZE, 0), 0l);
+  ASSERT_EQ(errno, 0);
+
+  ASSERT_GE(__llvm_libc::syscall(SYS_fsync, fd), 0l);
+  ASSERT_EQ(errno, 0);
+
+  ASSERT_GE(__llvm_libc::syscall(SYS_close, fd), 0l);
+  ASSERT_EQ(errno, 0);
+}
+
+TEST(LlvmLibcSyscallTest, FileLinkCreateDestroy) {
+  constexpr const char *TEST_DIR = "testdata";
+  constexpr const char *TEST_FILE = "syscall_linkat.test";
+  constexpr const char *TEST_FILE_PATH = "testdata/syscall_linkat.test";
+  constexpr const char *TEST_FILE_LINK = "syscall_linkat.test.link";
+  constexpr const char *TEST_FILE_LINK_PATH =
+      "testdata/syscall_linkat.test.link";
+
+  // The test strategy is as follows:
+  //   1. Create a normal file
+  //   2. Create a link to that file.
+  //   3. Open the link to check that the link was created.
+  //   4. Cleanup the file and its link.
+
+  int write_fd = __llvm_libc::syscall(SYS_open, TEST_FILE_PATH,
+                                      O_WRONLY | O_CREAT, S_IRWXU);
+  ASSERT_GT(write_fd, 0);
+  ASSERT_EQ(errno, 0);
+
+  ASSERT_GE(__llvm_libc::syscall(SYS_close, write_fd), 0l);
+  ASSERT_EQ(errno, 0);
+
+  int dir_fd = __llvm_libc::syscall(SYS_open, TEST_DIR, O_DIRECTORY, 0);
+  ASSERT_GT(dir_fd, 0);
+  ASSERT_EQ(errno, 0);
+
+  ASSERT_GE(__llvm_libc::syscall(SYS_linkat, dir_fd, TEST_FILE, dir_fd,
+                                 TEST_FILE_LINK, 0),
+            0l);
+  ASSERT_EQ(errno, 0);
+
+  int link_fd = __llvm_libc::syscall(SYS_open, TEST_FILE_LINK_PATH, O_PATH, 0);
+  ASSERT_GT(link_fd, 0);
+  ASSERT_EQ(errno, 0);
+
+  ASSERT_GE(__llvm_libc::syscall(SYS_unlink, TEST_FILE_PATH), 0l);
+  ASSERT_EQ(errno, 0);
+
+  ASSERT_GE(__llvm_libc::syscall(SYS_unlink, TEST_FILE_LINK_PATH), 0l);
+  ASSERT_EQ(errno, 0);
+
+  ASSERT_GE(__llvm_libc::syscall(SYS_close, dir_fd), 0l);
+  ASSERT_EQ(errno, 0);
+}


        


More information about the libc-commits mailing list