[libc-commits] [libc] Force to inline syscall_impl on all platforms (PR #186849)
Jakob Koschel via libc-commits
libc-commits at lists.llvm.org
Tue Mar 24 03:57:26 PDT 2026
https://github.com/jakos-sec updated https://github.com/llvm/llvm-project/pull/186849
>From 3f6f48c19cedb60c40bb38dd2b953fef24441e29 Mon Sep 17 00:00:00 2001
From: Jakob Koschel <jakobkoschel at google.com>
Date: Mon, 16 Mar 2026 17:35:25 +0000
Subject: [PATCH 1/2] Force to inline syscall_impl on all platforms
With currently only LIBC_INLINE, we just hint the compiler to inline
the function which however in practice is not always the case.
Since we added `[[gnu::always_inline]]` on linux/x86_64 it makes sense
to do it on all platforms consistently.
---
.../__support/OSUtil/darwin/aarch64/syscall.h | 25 +++++++++++--------
.../__support/OSUtil/linux/aarch64/syscall.h | 25 +++++++++++--------
libc/src/__support/OSUtil/linux/arm/syscall.h | 25 +++++++++++--------
.../src/__support/OSUtil/linux/i386/syscall.h | 24 ++++++++++--------
.../__support/OSUtil/linux/riscv/syscall.h | 25 +++++++++++--------
5 files changed, 74 insertions(+), 50 deletions(-)
diff --git a/libc/src/__support/OSUtil/darwin/aarch64/syscall.h b/libc/src/__support/OSUtil/darwin/aarch64/syscall.h
index dc98c07a8ba33..8e273f487fd75 100644
--- a/libc/src/__support/OSUtil/darwin/aarch64/syscall.h
+++ b/libc/src/__support/OSUtil/darwin/aarch64/syscall.h
@@ -47,46 +47,51 @@
namespace LIBC_NAMESPACE_DECL {
-LIBC_INLINE long syscall_impl(long number) {
+[[gnu::always_inline]] LIBC_INLINE long syscall_impl(long number) {
REGISTER_DECL_0;
SYSCALL_INSTR(REGISTER_CONSTRAINT_0);
return x0;
}
-LIBC_INLINE long syscall_impl(long number, long arg1) {
+[[gnu::always_inline]] LIBC_INLINE long syscall_impl(long number, long arg1) {
REGISTER_DECL_1;
SYSCALL_INSTR(REGISTER_CONSTRAINT_1);
return x0;
}
-LIBC_INLINE long syscall_impl(long number, long arg1, long arg2) {
+[[gnu::always_inline]] LIBC_INLINE long syscall_impl(long number, long arg1,
+ long arg2) {
REGISTER_DECL_2;
SYSCALL_INSTR(REGISTER_CONSTRAINT_2);
return x0;
}
-LIBC_INLINE long syscall_impl(long number, long arg1, long arg2, long arg3) {
+[[gnu::always_inline]] LIBC_INLINE long syscall_impl(long number, long arg1,
+ long arg2, long arg3) {
REGISTER_DECL_3;
SYSCALL_INSTR(REGISTER_CONSTRAINT_3);
return x0;
}
-LIBC_INLINE long syscall_impl(long number, long arg1, long arg2, long arg3,
- long arg4) {
+[[gnu::always_inline]] LIBC_INLINE long
+syscall_impl(long number, long arg1, long arg2, long arg3, long arg4) {
REGISTER_DECL_4;
SYSCALL_INSTR(REGISTER_CONSTRAINT_4);
return x0;
}
-LIBC_INLINE long syscall_impl(long number, long arg1, long arg2, long arg3,
- long arg4, long arg5) {
+[[gnu::always_inline]] LIBC_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;
}
-LIBC_INLINE long syscall_impl(long number, long arg1, long arg2, long arg3,
- long arg4, long arg5, long arg6) {
+[[gnu::always_inline]] LIBC_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/aarch64/syscall.h b/libc/src/__support/OSUtil/linux/aarch64/syscall.h
index f28392de5dced..c211c0e4cf11a 100644
--- a/libc/src/__support/OSUtil/linux/aarch64/syscall.h
+++ b/libc/src/__support/OSUtil/linux/aarch64/syscall.h
@@ -45,46 +45,51 @@
namespace LIBC_NAMESPACE_DECL {
-LIBC_INLINE long syscall_impl(long number) {
+[[gnu::always_inline]] LIBC_INLINE long syscall_impl(long number) {
REGISTER_DECL_0;
SYSCALL_INSTR(REGISTER_CONSTRAINT_0);
return x0;
}
-LIBC_INLINE long syscall_impl(long number, long arg1) {
+[[gnu::always_inline]] LIBC_INLINE long syscall_impl(long number, long arg1) {
REGISTER_DECL_1;
SYSCALL_INSTR(REGISTER_CONSTRAINT_1);
return x0;
}
-LIBC_INLINE long syscall_impl(long number, long arg1, long arg2) {
+[[gnu::always_inline]] LIBC_INLINE long syscall_impl(long number, long arg1,
+ long arg2) {
REGISTER_DECL_2;
SYSCALL_INSTR(REGISTER_CONSTRAINT_2);
return x0;
}
-LIBC_INLINE long syscall_impl(long number, long arg1, long arg2, long arg3) {
+[[gnu::always_inline]] LIBC_INLINE long syscall_impl(long number, long arg1,
+ long arg2, long arg3) {
REGISTER_DECL_3;
SYSCALL_INSTR(REGISTER_CONSTRAINT_3);
return x0;
}
-LIBC_INLINE long syscall_impl(long number, long arg1, long arg2, long arg3,
- long arg4) {
+[[gnu::always_inline]] LIBC_INLINE long
+syscall_impl(long number, long arg1, long arg2, long arg3, long arg4) {
REGISTER_DECL_4;
SYSCALL_INSTR(REGISTER_CONSTRAINT_4);
return x0;
}
-LIBC_INLINE long syscall_impl(long number, long arg1, long arg2, long arg3,
- long arg4, long arg5) {
+[[gnu::always_inline]] LIBC_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;
}
-LIBC_INLINE long syscall_impl(long number, long arg1, long arg2, long arg3,
- long arg4, long arg5, long arg6) {
+[[gnu::always_inline]] LIBC_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 d1058c84281fe..252c8c80249b3 100644
--- a/libc/src/__support/OSUtil/linux/arm/syscall.h
+++ b/libc/src/__support/OSUtil/linux/arm/syscall.h
@@ -63,46 +63,51 @@
namespace LIBC_NAMESPACE_DECL {
-LIBC_INLINE long syscall_impl(long number) {
+[[gnu::always_inline]] LIBC_INLINE long syscall_impl(long number) {
REGISTER_DECL_0;
SYSCALL_INSTR(REGISTER_CONSTRAINT_0);
return r0;
}
-LIBC_INLINE long syscall_impl(long number, long arg1) {
+[[gnu::always_inline]] LIBC_INLINE long syscall_impl(long number, long arg1) {
REGISTER_DECL_1;
SYSCALL_INSTR(REGISTER_CONSTRAINT_1);
return r0;
}
-LIBC_INLINE long syscall_impl(long number, long arg1, long arg2) {
+[[gnu::always_inline]] LIBC_INLINE long syscall_impl(long number, long arg1,
+ long arg2) {
REGISTER_DECL_2;
SYSCALL_INSTR(REGISTER_CONSTRAINT_2);
return r0;
}
-LIBC_INLINE long syscall_impl(long number, long arg1, long arg2, long arg3) {
+[[gnu::always_inline]] LIBC_INLINE long syscall_impl(long number, long arg1,
+ long arg2, long arg3) {
REGISTER_DECL_3;
SYSCALL_INSTR(REGISTER_CONSTRAINT_3);
return r0;
}
-LIBC_INLINE long syscall_impl(long number, long arg1, long arg2, long arg3,
- long arg4) {
+[[gnu::always_inline]] LIBC_INLINE long
+syscall_impl(long number, long arg1, long arg2, long arg3, long arg4) {
REGISTER_DECL_4;
SYSCALL_INSTR(REGISTER_CONSTRAINT_4);
return r0;
}
-LIBC_INLINE long syscall_impl(long number, long arg1, long arg2, long arg3,
- long arg4, long arg5) {
+[[gnu::always_inline]] LIBC_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;
}
-LIBC_INLINE long syscall_impl(long number, long arg1, long arg2, long arg3,
- long arg4, long arg5, long arg6) {
+[[gnu::always_inline]] LIBC_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/i386/syscall.h b/libc/src/__support/OSUtil/linux/i386/syscall.h
index 88d7f2fb2c49f..76fb83cbb35a8 100644
--- a/libc/src/__support/OSUtil/linux/i386/syscall.h
+++ b/libc/src/__support/OSUtil/linux/i386/syscall.h
@@ -14,19 +14,20 @@
namespace LIBC_NAMESPACE_DECL {
-LIBC_INLINE long syscall_impl(long num) {
+[[gnu::always_inline]] LIBC_INLINE long syscall_impl(long num) {
long ret;
LIBC_INLINE_ASM("int $128" : "=a"(ret) : "a"(num) : "memory");
return ret;
}
-LIBC_INLINE long syscall_impl(long num, long arg1) {
+[[gnu::always_inline]] LIBC_INLINE long syscall_impl(long num, long arg1) {
long ret;
LIBC_INLINE_ASM("int $128" : "=a"(ret) : "a"(num), "b"(arg1) : "memory");
return ret;
}
-LIBC_INLINE long syscall_impl(long num, long arg1, long arg2) {
+[[gnu::always_inline]] LIBC_INLINE long syscall_impl(long num, long arg1,
+ long arg2) {
long ret;
LIBC_INLINE_ASM("int $128"
: "=a"(ret)
@@ -35,7 +36,8 @@ LIBC_INLINE long syscall_impl(long num, long arg1, long arg2) {
return ret;
}
-LIBC_INLINE long syscall_impl(long num, long arg1, long arg2, long arg3) {
+[[gnu::always_inline]] LIBC_INLINE long syscall_impl(long num, long arg1,
+ long arg2, long arg3) {
long ret;
LIBC_INLINE_ASM("int $128"
: "=a"(ret)
@@ -44,8 +46,8 @@ LIBC_INLINE long syscall_impl(long num, long arg1, long arg2, long arg3) {
return ret;
}
-LIBC_INLINE long syscall_impl(long num, long arg1, long arg2, long arg3,
- long arg4) {
+[[gnu::always_inline]] LIBC_INLINE long
+syscall_impl(long num, long arg1, long arg2, long arg3, long arg4) {
long ret;
LIBC_INLINE_ASM("int $128"
: "=a"(ret)
@@ -54,8 +56,8 @@ LIBC_INLINE long syscall_impl(long num, long arg1, long arg2, long arg3,
return ret;
}
-LIBC_INLINE long syscall_impl(long num, long arg1, long arg2, long arg3,
- long arg4, long arg5) {
+[[gnu::always_inline]] LIBC_INLINE long
+syscall_impl(long num, long arg1, long arg2, long arg3, long arg4, long arg5) {
long ret;
LIBC_INLINE_ASM("int $128"
: "=a"(ret)
@@ -65,8 +67,10 @@ LIBC_INLINE long syscall_impl(long num, long arg1, long arg2, long arg3,
return ret;
}
-LIBC_INLINE long syscall_impl(long num, long arg1, long arg2, long arg3,
- long arg4, long arg5, long arg6) {
+[[gnu::always_inline]] LIBC_INLINE long syscall_impl(long num, long arg1,
+ long arg2, long arg3,
+ long arg4, long arg5,
+ long arg6) {
long ret;
LIBC_INLINE_ASM(R"(
push %[arg6]
diff --git a/libc/src/__support/OSUtil/linux/riscv/syscall.h b/libc/src/__support/OSUtil/linux/riscv/syscall.h
index e460e9bb56e67..1fabc400b1c70 100644
--- a/libc/src/__support/OSUtil/linux/riscv/syscall.h
+++ b/libc/src/__support/OSUtil/linux/riscv/syscall.h
@@ -45,46 +45,51 @@
namespace LIBC_NAMESPACE_DECL {
-LIBC_INLINE long syscall_impl(long number) {
+[[gnu::always_inline]] LIBC_INLINE long syscall_impl(long number) {
REGISTER_DECL_0;
SYSCALL_INSTR(REGISTER_CONSTRAINT_0);
return a0;
}
-LIBC_INLINE long syscall_impl(long number, long arg1) {
+[[gnu::always_inline]] LIBC_INLINE long syscall_impl(long number, long arg1) {
REGISTER_DECL_1;
SYSCALL_INSTR(REGISTER_CONSTRAINT_1);
return a0;
}
-LIBC_INLINE long syscall_impl(long number, long arg1, long arg2) {
+[[gnu::always_inline]] LIBC_INLINE long syscall_impl(long number, long arg1,
+ long arg2) {
REGISTER_DECL_2;
SYSCALL_INSTR(REGISTER_CONSTRAINT_2);
return a0;
}
-LIBC_INLINE long syscall_impl(long number, long arg1, long arg2, long arg3) {
+[[gnu::always_inline]] LIBC_INLINE long syscall_impl(long number, long arg1,
+ long arg2, long arg3) {
REGISTER_DECL_3;
SYSCALL_INSTR(REGISTER_CONSTRAINT_3);
return a0;
}
-LIBC_INLINE long syscall_impl(long number, long arg1, long arg2, long arg3,
- long arg4) {
+[[gnu::always_inline]] LIBC_INLINE long
+syscall_impl(long number, long arg1, long arg2, long arg3, long arg4) {
REGISTER_DECL_4;
SYSCALL_INSTR(REGISTER_CONSTRAINT_4);
return a0;
}
-LIBC_INLINE long syscall_impl(long number, long arg1, long arg2, long arg3,
- long arg4, long arg5) {
+[[gnu::always_inline]] LIBC_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 a0;
}
-LIBC_INLINE long syscall_impl(long number, long arg1, long arg2, long arg3,
- long arg4, long arg5, long arg6) {
+[[gnu::always_inline]] LIBC_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 a0;
>From 3d6e076e019e818272881099af4ab9c069359344 Mon Sep 17 00:00:00 2001
From: Jakob Koschel <jakobkoschel at google.com>
Date: Tue, 24 Mar 2026 10:57:05 +0000
Subject: [PATCH 2/2] add comment for reason of gnu::always_inline on
syscall_impl
---
libc/src/__support/OSUtil/linux/x86_64/syscall.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/libc/src/__support/OSUtil/linux/x86_64/syscall.h b/libc/src/__support/OSUtil/linux/x86_64/syscall.h
index f069d46185d0f..25ff5faf081b1 100644
--- a/libc/src/__support/OSUtil/linux/x86_64/syscall.h
+++ b/libc/src/__support/OSUtil/linux/x86_64/syscall.h
@@ -16,6 +16,11 @@
namespace LIBC_NAMESPACE_DECL {
+// In order for SHSTK (CET ShadowStack) to work, we are required to force
+// inlining the syscall_impl, since we cannot return from an untracked call
+// after enabling support throught the system call.
+// For consistency, we do this consistently on all platforms, but can split it
+// into force-inlined and regular inlined functions in the future if necessary.
[[gnu::always_inline]] LIBC_INLINE long syscall_impl(long __number) {
long retcode;
LIBC_INLINE_ASM("syscall"
More information about the libc-commits
mailing list