aboutsummaryrefslogtreecommitdiffstats
diff options
authorThierry Reding <treding@nvidia.com>2026-04-30 10:34:51 +0200
committerThierry Reding <treding@nvidia.com>2026-04-30 10:34:51 +0200
commit6338a5ac3b71eb9f1854f8c285cf89a89d6bddfd (patch)
tree3bd51a9c444a28513958644634811b7c07bcca3b
parent0f37233298c530de490c3e663b72425aa3905cdd (diff)
parent266df86c4893fed1a7f027e767fe1c7f6456b100 (diff)
downloadlinux-next-6338a5ac3b71eb9f1854f8c285cf89a89d6bddfd.tar.gz
Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/nolibc/linux-nolibc.git
-rw-r--r--tools/include/nolibc/Makefile2
-rw-r--r--tools/include/nolibc/alloca.h15
-rw-r--r--tools/include/nolibc/arch-arm.h2
-rw-r--r--tools/include/nolibc/arch-arm64.h2
-rw-r--r--tools/include/nolibc/arch-loongarch.h2
-rw-r--r--tools/include/nolibc/arch-m68k.h2
-rw-r--r--tools/include/nolibc/arch-mips.h96
-rw-r--r--tools/include/nolibc/arch-powerpc.h8
-rw-r--r--tools/include/nolibc/arch-riscv.h2
-rw-r--r--tools/include/nolibc/arch-s390.h2
-rw-r--r--tools/include/nolibc/arch-sh.h2
-rw-r--r--tools/include/nolibc/arch-sparc.h2
-rw-r--r--tools/include/nolibc/arch-x86.h74
-rw-r--r--tools/include/nolibc/assert.h36
-rw-r--r--tools/include/nolibc/compiler.h4
-rw-r--r--tools/include/nolibc/crt.h8
-rw-r--r--tools/include/nolibc/fcntl.h14
-rw-r--r--tools/include/nolibc/nolibc.h2
-rw-r--r--tools/include/nolibc/stackprotector.h2
-rw-r--r--tools/include/nolibc/sys.h32
-rw-r--r--tools/include/nolibc/sys/mman.h6
-rw-r--r--tools/testing/selftests/nolibc/nolibc-test.c82
22 files changed, 287 insertions, 110 deletions
diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile
index 7455097cff693..872c318f50d41 100644
--- a/tools/include/nolibc/Makefile
+++ b/tools/include/nolibc/Makefile
@@ -20,6 +20,8 @@ OUTPUT ?= $(CURDIR)/
architectures := arm arm64 loongarch m68k mips powerpc riscv s390 sh sparc x86
arch_files := arch.h $(addsuffix .h, $(addprefix arch-, $(architectures)))
all_files := \
+ alloca.h \
+ assert.h \
byteswap.h \
compiler.h \
crt.h \
diff --git a/tools/include/nolibc/alloca.h b/tools/include/nolibc/alloca.h
new file mode 100644
index 0000000000000..448233a79e6ee
--- /dev/null
+++ b/tools/include/nolibc/alloca.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
+/*
+ * alloca() for NOLIBC
+ * Copyright (C) 2026 Thomas Weißschuh <linux@weissschuh.net>
+ */
+
+/* make sure to include all global symbols */
+#include "nolibc.h"
+
+#ifndef _NOLIBC_ALLOCA_H
+#define _NOLIBC_ALLOCA_H
+
+#define alloca(size) __builtin_alloca(size)
+
+#endif /* _NOLIBC_ALLOCA_H */
diff --git a/tools/include/nolibc/arch-arm.h b/tools/include/nolibc/arch-arm.h
index a4d3a777a051b..72a2b28170e28 100644
--- a/tools/include/nolibc/arch-arm.h
+++ b/tools/include/nolibc/arch-arm.h
@@ -186,7 +186,7 @@
#ifndef NOLIBC_NO_RUNTIME
/* startup code */
-void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void)
+void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start(void)
{
__asm__ volatile (
"mov r0, sp\n" /* save stack pointer to %r0, as arg1 of _start_c */
diff --git a/tools/include/nolibc/arch-arm64.h b/tools/include/nolibc/arch-arm64.h
index 28b3c7536ad6d..814bcc13b4b22 100644
--- a/tools/include/nolibc/arch-arm64.h
+++ b/tools/include/nolibc/arch-arm64.h
@@ -143,7 +143,7 @@
#ifndef NOLIBC_NO_RUNTIME
/* startup code */
-void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void)
+void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start(void)
{
__asm__ volatile (
"mov x0, sp\n" /* save stack pointer to x0, as arg1 of _start_c */
diff --git a/tools/include/nolibc/arch-loongarch.h b/tools/include/nolibc/arch-loongarch.h
index 86fb34bbf1857..3abed96a15e86 100644
--- a/tools/include/nolibc/arch-loongarch.h
+++ b/tools/include/nolibc/arch-loongarch.h
@@ -144,7 +144,7 @@
#ifndef NOLIBC_NO_RUNTIME
/* startup code */
-void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void)
+void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start(void)
{
__asm__ volatile (
"move $a0, $sp\n" /* save stack pointer to $a0, as arg1 of _start_c */
diff --git a/tools/include/nolibc/arch-m68k.h b/tools/include/nolibc/arch-m68k.h
index 81d34c219a421..341f434a530c5 100644
--- a/tools/include/nolibc/arch-m68k.h
+++ b/tools/include/nolibc/arch-m68k.h
@@ -130,7 +130,7 @@
#ifndef NOLIBC_NO_RUNTIME
void _start(void);
-void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void)
+void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start(void)
{
__asm__ volatile (
"movel %sp, %sp@-\n"
diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h
index bb9d580ea1b16..1400653c76c1e 100644
--- a/tools/include/nolibc/arch-mips.h
+++ b/tools/include/nolibc/arch-mips.h
@@ -55,6 +55,8 @@
#define _NOLIBC_SYSCALL_STACK_RESERVE "addiu $sp, $sp, -32\n"
#define _NOLIBC_SYSCALL_STACK_UNRESERVE "addiu $sp, $sp, 32\n"
+#define _NOLIBC_SYSCALL_REG register long
+
#else /* _ABIN32 || _ABI64 */
/* binutils, GCC and clang disagree about register aliases, use numbers instead. */
@@ -66,12 +68,14 @@
#define _NOLIBC_SYSCALL_STACK_RESERVE
#define _NOLIBC_SYSCALL_STACK_UNRESERVE
+#define _NOLIBC_SYSCALL_REG register long long
+
#endif /* _ABIO32 */
#define __nolibc_syscall0(num) \
({ \
- register long _num __asm__ ("v0") = (num); \
- register long _arg4 __asm__ ("a3"); \
+ _NOLIBC_SYSCALL_REG _num __asm__ ("v0") = (num); \
+ _NOLIBC_SYSCALL_REG _arg4 __asm__ ("a3"); \
\
__asm__ volatile ( \
_NOLIBC_SYSCALL_STACK_RESERVE \
@@ -86,9 +90,9 @@
#define __nolibc_syscall1(num, arg1) \
({ \
- register long _num __asm__ ("v0") = (num); \
- register long _arg1 __asm__ ("a0") = (long)(arg1); \
- register long _arg4 __asm__ ("a3"); \
+ _NOLIBC_SYSCALL_REG _num __asm__ ("v0") = (num); \
+ _NOLIBC_SYSCALL_REG _arg1 __asm__ ("a0") = __nolibc_arg_to_reg(arg1); \
+ _NOLIBC_SYSCALL_REG _arg4 __asm__ ("a3"); \
\
__asm__ volatile ( \
_NOLIBC_SYSCALL_STACK_RESERVE \
@@ -104,10 +108,10 @@
#define __nolibc_syscall2(num, arg1, arg2) \
({ \
- register long _num __asm__ ("v0") = (num); \
- register long _arg1 __asm__ ("a0") = (long)(arg1); \
- register long _arg2 __asm__ ("a1") = (long)(arg2); \
- register long _arg4 __asm__ ("a3"); \
+ _NOLIBC_SYSCALL_REG _num __asm__ ("v0") = (num); \
+ _NOLIBC_SYSCALL_REG _arg1 __asm__ ("a0") = __nolibc_arg_to_reg(arg1); \
+ _NOLIBC_SYSCALL_REG _arg2 __asm__ ("a1") = __nolibc_arg_to_reg(arg2); \
+ _NOLIBC_SYSCALL_REG _arg4 __asm__ ("a3"); \
\
__asm__ volatile ( \
_NOLIBC_SYSCALL_STACK_RESERVE \
@@ -123,11 +127,11 @@
#define __nolibc_syscall3(num, arg1, arg2, arg3) \
({ \
- register long _num __asm__ ("v0") = (num); \
- register long _arg1 __asm__ ("a0") = (long)(arg1); \
- register long _arg2 __asm__ ("a1") = (long)(arg2); \
- register long _arg3 __asm__ ("a2") = (long)(arg3); \
- register long _arg4 __asm__ ("a3"); \
+ _NOLIBC_SYSCALL_REG _num __asm__ ("v0") = (num); \
+ _NOLIBC_SYSCALL_REG _arg1 __asm__ ("a0") = __nolibc_arg_to_reg(arg1); \
+ _NOLIBC_SYSCALL_REG _arg2 __asm__ ("a1") = __nolibc_arg_to_reg(arg2); \
+ _NOLIBC_SYSCALL_REG _arg3 __asm__ ("a2") = __nolibc_arg_to_reg(arg3); \
+ _NOLIBC_SYSCALL_REG _arg4 __asm__ ("a3"); \
\
__asm__ volatile ( \
_NOLIBC_SYSCALL_STACK_RESERVE \
@@ -143,11 +147,11 @@
#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \
({ \
- register long _num __asm__ ("v0") = (num); \
- register long _arg1 __asm__ ("a0") = (long)(arg1); \
- register long _arg2 __asm__ ("a1") = (long)(arg2); \
- register long _arg3 __asm__ ("a2") = (long)(arg3); \
- register long _arg4 __asm__ ("a3") = (long)(arg4); \
+ _NOLIBC_SYSCALL_REG _num __asm__ ("v0") = (num); \
+ _NOLIBC_SYSCALL_REG _arg1 __asm__ ("a0") = __nolibc_arg_to_reg(arg1); \
+ _NOLIBC_SYSCALL_REG _arg2 __asm__ ("a1") = __nolibc_arg_to_reg(arg2); \
+ _NOLIBC_SYSCALL_REG _arg3 __asm__ ("a2") = __nolibc_arg_to_reg(arg3); \
+ _NOLIBC_SYSCALL_REG _arg4 __asm__ ("a3") = __nolibc_arg_to_reg(arg4); \
\
__asm__ volatile ( \
_NOLIBC_SYSCALL_STACK_RESERVE \
@@ -165,12 +169,12 @@
#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
({ \
- register long _num __asm__ ("v0") = (num); \
- register long _arg1 __asm__ ("a0") = (long)(arg1); \
- register long _arg2 __asm__ ("a1") = (long)(arg2); \
- register long _arg3 __asm__ ("a2") = (long)(arg3); \
- register long _arg4 __asm__ ("a3") = (long)(arg4); \
- register long _arg5 = (long)(arg5); \
+ _NOLIBC_SYSCALL_REG _num __asm__ ("v0") = (num); \
+ _NOLIBC_SYSCALL_REG _arg1 __asm__ ("a0") = __nolibc_arg_to_reg(arg1); \
+ _NOLIBC_SYSCALL_REG _arg2 __asm__ ("a1") = __nolibc_arg_to_reg(arg2); \
+ _NOLIBC_SYSCALL_REG _arg3 __asm__ ("a2") = __nolibc_arg_to_reg(arg3); \
+ _NOLIBC_SYSCALL_REG _arg4 __asm__ ("a3") = __nolibc_arg_to_reg(arg4); \
+ _NOLIBC_SYSCALL_REG _arg5 = __nolibc_arg_to_reg(arg5); \
\
__asm__ volatile ( \
_NOLIBC_SYSCALL_STACK_RESERVE \
@@ -187,13 +191,13 @@
#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
- register long _num __asm__ ("v0") = (num); \
- register long _arg1 __asm__ ("a0") = (long)(arg1); \
- register long _arg2 __asm__ ("a1") = (long)(arg2); \
- register long _arg3 __asm__ ("a2") = (long)(arg3); \
- register long _arg4 __asm__ ("a3") = (long)(arg4); \
- register long _arg5 = (long)(arg5); \
- register long _arg6 = (long)(arg6); \
+ _NOLIBC_SYSCALL_REG _num __asm__ ("v0") = (num); \
+ _NOLIBC_SYSCALL_REG _arg1 __asm__ ("a0") = __nolibc_arg_to_reg(arg1); \
+ _NOLIBC_SYSCALL_REG _arg2 __asm__ ("a1") = __nolibc_arg_to_reg(arg2); \
+ _NOLIBC_SYSCALL_REG _arg3 __asm__ ("a2") = __nolibc_arg_to_reg(arg3); \
+ _NOLIBC_SYSCALL_REG _arg4 __asm__ ("a3") = __nolibc_arg_to_reg(arg4); \
+ _NOLIBC_SYSCALL_REG _arg5 = __nolibc_arg_to_reg(arg5); \
+ _NOLIBC_SYSCALL_REG _arg6 = __nolibc_arg_to_reg(arg6); \
\
__asm__ volatile ( \
_NOLIBC_SYSCALL_STACK_RESERVE \
@@ -214,12 +218,12 @@
#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
({ \
- register long _num __asm__ ("v0") = (num); \
- register long _arg1 __asm__ ("$4") = (long)(arg1); \
- register long _arg2 __asm__ ("$5") = (long)(arg2); \
- register long _arg3 __asm__ ("$6") = (long)(arg3); \
- register long _arg4 __asm__ ("$7") = (long)(arg4); \
- register long _arg5 __asm__ ("$8") = (long)(arg5); \
+ _NOLIBC_SYSCALL_REG _num __asm__ ("v0") = (num); \
+ _NOLIBC_SYSCALL_REG _arg1 __asm__ ("$4") = __nolibc_arg_to_reg(arg1); \
+ _NOLIBC_SYSCALL_REG _arg2 __asm__ ("$5") = __nolibc_arg_to_reg(arg2); \
+ _NOLIBC_SYSCALL_REG _arg3 __asm__ ("$6") = __nolibc_arg_to_reg(arg3); \
+ _NOLIBC_SYSCALL_REG _arg4 __asm__ ("$7") = __nolibc_arg_to_reg(arg4); \
+ _NOLIBC_SYSCALL_REG _arg5 __asm__ ("$8") = __nolibc_arg_to_reg(arg5); \
\
__asm__ volatile ( \
"syscall\n" \
@@ -233,13 +237,13 @@
#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
- register long _num __asm__ ("v0") = (num); \
- register long _arg1 __asm__ ("$4") = (long)(arg1); \
- register long _arg2 __asm__ ("$5") = (long)(arg2); \
- register long _arg3 __asm__ ("$6") = (long)(arg3); \
- register long _arg4 __asm__ ("$7") = (long)(arg4); \
- register long _arg5 __asm__ ("$8") = (long)(arg5); \
- register long _arg6 __asm__ ("$9") = (long)(arg6); \
+ _NOLIBC_SYSCALL_REG _num __asm__ ("v0") = (num); \
+ _NOLIBC_SYSCALL_REG _arg1 __asm__ ("$4") = __nolibc_arg_to_reg(arg1); \
+ _NOLIBC_SYSCALL_REG _arg2 __asm__ ("$5") = __nolibc_arg_to_reg(arg2); \
+ _NOLIBC_SYSCALL_REG _arg3 __asm__ ("$6") = __nolibc_arg_to_reg(arg3); \
+ _NOLIBC_SYSCALL_REG _arg4 __asm__ ("$7") = __nolibc_arg_to_reg(arg4); \
+ _NOLIBC_SYSCALL_REG _arg5 __asm__ ("$8") = __nolibc_arg_to_reg(arg5); \
+ _NOLIBC_SYSCALL_REG _arg6 __asm__ ("$9") = __nolibc_arg_to_reg(arg6); \
\
__asm__ volatile ( \
"syscall\n" \
@@ -257,7 +261,7 @@
#ifndef NOLIBC_NO_RUNTIME
/* startup code, note that it's called __start on MIPS */
void __start(void);
-void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector __start(void)
+void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector __start(void)
{
__asm__ volatile (
"move $a0, $sp\n" /* save stack pointer to $a0, as arg1 of _start_c */
diff --git a/tools/include/nolibc/arch-powerpc.h b/tools/include/nolibc/arch-powerpc.h
index ef878868aa4ad..111cda70f2cc6 100644
--- a/tools/include/nolibc/arch-powerpc.h
+++ b/tools/include/nolibc/arch-powerpc.h
@@ -177,15 +177,15 @@
* "omit-frame-pointer" fails with __attribute__((no_stack_protector)) but
* works with __attribute__((__optimize__("-fno-stack-protector")))
*/
-#ifdef __no_stack_protector
-#undef __no_stack_protector
-#define __no_stack_protector __attribute__((__optimize__("-fno-stack-protector")))
+#ifdef __nolibc_no_stack_protector
+#undef __nolibc_no_stack_protector
+#define __nolibc_no_stack_protector __attribute__((__optimize__("-fno-stack-protector")))
#endif
#endif /* !__powerpc64__ */
#ifndef NOLIBC_NO_RUNTIME
/* startup code */
-void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void)
+void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start(void)
{
#ifdef __powerpc64__
#if _CALL_ELF == 2
diff --git a/tools/include/nolibc/arch-riscv.h b/tools/include/nolibc/arch-riscv.h
index 386ebb9f5b087..1e84ed2e63b3e 100644
--- a/tools/include/nolibc/arch-riscv.h
+++ b/tools/include/nolibc/arch-riscv.h
@@ -141,7 +141,7 @@
#ifndef NOLIBC_NO_RUNTIME
/* startup code */
-void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void)
+void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start(void)
{
__asm__ volatile (
".option push\n"
diff --git a/tools/include/nolibc/arch-s390.h b/tools/include/nolibc/arch-s390.h
index 4e69123ae4840..3f05c01aecc63 100644
--- a/tools/include/nolibc/arch-s390.h
+++ b/tools/include/nolibc/arch-s390.h
@@ -145,7 +145,7 @@
#ifndef NOLIBC_NO_RUNTIME
/* startup code */
-void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void)
+void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start(void)
{
__asm__ volatile (
"lgr %r2, %r15\n" /* save stack pointer to %r2, as arg1 of _start_c */
diff --git a/tools/include/nolibc/arch-sh.h b/tools/include/nolibc/arch-sh.h
index b5a64ceeec974..a32378fd621fd 100644
--- a/tools/include/nolibc/arch-sh.h
+++ b/tools/include/nolibc/arch-sh.h
@@ -143,7 +143,7 @@
#ifndef NOLIBC_NO_RUNTIME
/* startup code */
void _start_wrapper(void);
-void __attribute__((weak,noreturn)) __nolibc_entrypoint __no_stack_protector _start_wrapper(void)
+void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start_wrapper(void)
{
__asm__ volatile (
".global _start\n" /* The C function will have a prologue, */
diff --git a/tools/include/nolibc/arch-sparc.h b/tools/include/nolibc/arch-sparc.h
index 240539d069a80..ddae9bc10dfe3 100644
--- a/tools/include/nolibc/arch-sparc.h
+++ b/tools/include/nolibc/arch-sparc.h
@@ -154,7 +154,7 @@
#ifndef NOLIBC_NO_RUNTIME
/* startup code */
-void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void)
+void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start(void)
{
__asm__ volatile (
/*
diff --git a/tools/include/nolibc/arch-x86.h b/tools/include/nolibc/arch-x86.h
index 769ba01a8629f..fe152ac2650ba 100644
--- a/tools/include/nolibc/arch-x86.h
+++ b/tools/include/nolibc/arch-x86.h
@@ -165,7 +165,7 @@
* 2) The deepest stack frame should be set to zero
*
*/
-void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void)
+void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start(void)
{
__asm__ volatile (
"xor %ebp, %ebp\n" /* zero the stack frame */
@@ -202,8 +202,8 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s
#define __nolibc_syscall0(num) \
({ \
- long _ret; \
- register long _num __asm__ ("rax") = (num); \
+ long long _ret; \
+ register long long _num __asm__ ("rax") = (num); \
\
__asm__ volatile ( \
"syscall\n" \
@@ -216,9 +216,9 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s
#define __nolibc_syscall1(num, arg1) \
({ \
- long _ret; \
- register long _num __asm__ ("rax") = (num); \
- register long _arg1 __asm__ ("rdi") = (long)(arg1); \
+ long long _ret; \
+ register long long _num __asm__ ("rax") = (num); \
+ register long long _arg1 __asm__ ("rdi") = __nolibc_arg_to_reg(arg1); \
\
__asm__ volatile ( \
"syscall\n" \
@@ -232,10 +232,10 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s
#define __nolibc_syscall2(num, arg1, arg2) \
({ \
- long _ret; \
- register long _num __asm__ ("rax") = (num); \
- register long _arg1 __asm__ ("rdi") = (long)(arg1); \
- register long _arg2 __asm__ ("rsi") = (long)(arg2); \
+ long long _ret; \
+ register long long _num __asm__ ("rax") = (num); \
+ register long long _arg1 __asm__ ("rdi") = __nolibc_arg_to_reg(arg1); \
+ register long long _arg2 __asm__ ("rsi") = __nolibc_arg_to_reg(arg2); \
\
__asm__ volatile ( \
"syscall\n" \
@@ -249,11 +249,11 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s
#define __nolibc_syscall3(num, arg1, arg2, arg3) \
({ \
- long _ret; \
- register long _num __asm__ ("rax") = (num); \
- register long _arg1 __asm__ ("rdi") = (long)(arg1); \
- register long _arg2 __asm__ ("rsi") = (long)(arg2); \
- register long _arg3 __asm__ ("rdx") = (long)(arg3); \
+ long long _ret; \
+ register long long _num __asm__ ("rax") = (num); \
+ register long long _arg1 __asm__ ("rdi") = __nolibc_arg_to_reg(arg1); \
+ register long long _arg2 __asm__ ("rsi") = __nolibc_arg_to_reg(arg2); \
+ register long long _arg3 __asm__ ("rdx") = __nolibc_arg_to_reg(arg3); \
\
__asm__ volatile ( \
"syscall\n" \
@@ -267,12 +267,12 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s
#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \
({ \
- long _ret; \
- register long _num __asm__ ("rax") = (num); \
- register long _arg1 __asm__ ("rdi") = (long)(arg1); \
- register long _arg2 __asm__ ("rsi") = (long)(arg2); \
- register long _arg3 __asm__ ("rdx") = (long)(arg3); \
- register long _arg4 __asm__ ("r10") = (long)(arg4); \
+ long long _ret; \
+ register long long _num __asm__ ("rax") = (num); \
+ register long long _arg1 __asm__ ("rdi") = __nolibc_arg_to_reg(arg1); \
+ register long long _arg2 __asm__ ("rsi") = __nolibc_arg_to_reg(arg2); \
+ register long long _arg3 __asm__ ("rdx") = __nolibc_arg_to_reg(arg3); \
+ register long long _arg4 __asm__ ("r10") = __nolibc_arg_to_reg(arg4); \
\
__asm__ volatile ( \
"syscall\n" \
@@ -286,13 +286,13 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s
#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
({ \
- long _ret; \
- register long _num __asm__ ("rax") = (num); \
- register long _arg1 __asm__ ("rdi") = (long)(arg1); \
- register long _arg2 __asm__ ("rsi") = (long)(arg2); \
- register long _arg3 __asm__ ("rdx") = (long)(arg3); \
- register long _arg4 __asm__ ("r10") = (long)(arg4); \
- register long _arg5 __asm__ ("r8") = (long)(arg5); \
+ long long _ret; \
+ register long long _num __asm__ ("rax") = (num); \
+ register long long _arg1 __asm__ ("rdi") = __nolibc_arg_to_reg(arg1); \
+ register long long _arg2 __asm__ ("rsi") = __nolibc_arg_to_reg(arg2); \
+ register long long _arg3 __asm__ ("rdx") = __nolibc_arg_to_reg(arg3); \
+ register long long _arg4 __asm__ ("r10") = __nolibc_arg_to_reg(arg4); \
+ register long long _arg5 __asm__ ("r8") = __nolibc_arg_to_reg(arg5); \
\
__asm__ volatile ( \
"syscall\n" \
@@ -306,14 +306,14 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s
#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
- long _ret; \
- register long _num __asm__ ("rax") = (num); \
- register long _arg1 __asm__ ("rdi") = (long)(arg1); \
- register long _arg2 __asm__ ("rsi") = (long)(arg2); \
- register long _arg3 __asm__ ("rdx") = (long)(arg3); \
- register long _arg4 __asm__ ("r10") = (long)(arg4); \
- register long _arg5 __asm__ ("r8") = (long)(arg5); \
- register long _arg6 __asm__ ("r9") = (long)(arg6); \
+ long long _ret; \
+ register long long _num __asm__ ("rax") = (num); \
+ register long long _arg1 __asm__ ("rdi") = __nolibc_arg_to_reg(arg1); \
+ register long long _arg2 __asm__ ("rsi") = __nolibc_arg_to_reg(arg2); \
+ register long long _arg3 __asm__ ("rdx") = __nolibc_arg_to_reg(arg3); \
+ register long long _arg4 __asm__ ("r10") = __nolibc_arg_to_reg(arg4); \
+ register long long _arg5 __asm__ ("r8") = __nolibc_arg_to_reg(arg5); \
+ register long long _arg6 __asm__ ("r9") = __nolibc_arg_to_reg(arg6); \
\
__asm__ volatile ( \
"syscall\n" \
@@ -333,7 +333,7 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s
* 2) The deepest stack frame should be zero (the %rbp).
*
*/
-void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void)
+void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start(void)
{
__asm__ volatile (
"xor %ebp, %ebp\n" /* zero the stack frame */
diff --git a/tools/include/nolibc/assert.h b/tools/include/nolibc/assert.h
new file mode 100644
index 0000000000000..84ff8ad9ab077
--- /dev/null
+++ b/tools/include/nolibc/assert.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
+/*
+ * Assert for NOLIBC
+ * Copyright (C) 2026 Thomas Weißschuh <linux@weissschuh.net>
+ */
+
+/* make sure to include all global symbols */
+#include "nolibc.h"
+
+#ifndef _NOLIBC_ASSERT_H
+#define _NOLIBC_ASSERT_H
+
+#include "errno.h"
+#include "stdio.h"
+#include "stdlib.h"
+
+#endif /* _NOLIBC_ASSERT_H */
+
+/* NDEBUG needs to be evaluated on *each* inclusion */
+#ifdef assert
+#undef assert
+#endif
+
+#ifndef NDEBUG
+#define assert(expr) \
+({ \
+ if (!(expr)) { \
+ fprintf(stderr, "%s: %s:%d: %s: Assertion `%s' failed.\n", \
+ program_invocation_short_name, __FILE__, __LINE__, __func__, \
+ #expr); \
+ abort(); \
+ } \
+})
+#else
+#define assert(expr) ((void)0)
+#endif
diff --git a/tools/include/nolibc/compiler.h b/tools/include/nolibc/compiler.h
index b56570bf9f69e..f2d7a81d0d7c6 100644
--- a/tools/include/nolibc/compiler.h
+++ b/tools/include/nolibc/compiler.h
@@ -36,9 +36,9 @@
#endif /* defined(__SSP__) ... */
#if __nolibc_has_attribute(no_stack_protector)
-# define __no_stack_protector __attribute__((no_stack_protector))
+# define __nolibc_no_stack_protector __attribute__((no_stack_protector))
#else
-# define __no_stack_protector __attribute__((__optimize__("-fno-stack-protector")))
+# define __nolibc_no_stack_protector __attribute__((__optimize__("-fno-stack-protector")))
#endif /* __nolibc_has_attribute(no_stack_protector) */
#if __nolibc_has_attribute(__fallthrough__)
diff --git a/tools/include/nolibc/crt.h b/tools/include/nolibc/crt.h
index d8ce91fd2e3b1..714256228914e 100644
--- a/tools/include/nolibc/crt.h
+++ b/tools/include/nolibc/crt.h
@@ -7,6 +7,10 @@
#ifndef _NOLIBC_CRT_H
#define _NOLIBC_CRT_H
+#define __nolibc_arg_to_reg(_a) \
+ __builtin_choose_expr(__builtin_classify_type(_a) == __builtin_classify_type(NULL), \
+ (unsigned long)(_a), (_a))
+
#ifndef NOLIBC_NO_RUNTIME
#include "compiler.h"
@@ -47,7 +51,7 @@ char *__nolibc_program_invocation_short_name(char *long_name)
#endif /* NOLIBC_IGNORE_ERRNO */
void _start_c(long *sp);
-__attribute__((weak,used)) __nolibc_no_sanitize_undefined
+__attribute__((weak,used)) __nolibc_no_sanitize_undefined __nolibc_no_stack_protector
void _start_c(long *sp)
{
long argc;
@@ -89,7 +93,7 @@ void _start_c(long *sp)
/* find _auxv */
for (auxv = (void *)envp; *auxv++;)
- ;
+ __asm__("");
_auxv = auxv;
#ifndef NOLIBC_IGNORE_ERRNO
diff --git a/tools/include/nolibc/fcntl.h b/tools/include/nolibc/fcntl.h
index ed2f5553c65a0..014910a8e928d 100644
--- a/tools/include/nolibc/fcntl.h
+++ b/tools/include/nolibc/fcntl.h
@@ -29,6 +29,8 @@ int openat(int dirfd, const char *path, int flags, ...)
{
mode_t mode = 0;
+ flags |= O_LARGEFILE;
+
if (flags & O_CREAT) {
va_list args;
@@ -55,6 +57,8 @@ int open(const char *path, int flags, ...)
{
mode_t mode = 0;
+ flags |= O_LARGEFILE;
+
if (flags & O_CREAT) {
va_list args;
@@ -66,4 +70,14 @@ int open(const char *path, int flags, ...)
return __sysret(_sys_open(path, flags, mode));
}
+/*
+ * int creat(const char *path, mode_t mode);
+ */
+
+static __attribute__((unused))
+int creat(const char *path, mode_t mode)
+{
+ return open(path, O_CREAT | O_WRONLY | O_TRUNC, mode);
+}
+
#endif /* _NOLIBC_FCNTL_H */
diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h
index f4120f65fe794..faa94f2472816 100644
--- a/tools/include/nolibc/nolibc.h
+++ b/tools/include/nolibc/nolibc.h
@@ -133,6 +133,8 @@
#include "err.h"
#include "byteswap.h"
#include "endian.h"
+#include "assert.h"
+#include "alloca.h"
/* Used by programs to avoid std includes */
#define NOLIBC
diff --git a/tools/include/nolibc/stackprotector.h b/tools/include/nolibc/stackprotector.h
index ae8b1d3a374dc..e11c20c754654 100644
--- a/tools/include/nolibc/stackprotector.h
+++ b/tools/include/nolibc/stackprotector.h
@@ -40,7 +40,7 @@ void __stack_chk_fail_local(void)
__attribute__((weak,used,section(".data.nolibc_stack_chk")))
uintptr_t __stack_chk_guard;
-static __no_stack_protector void __stack_chk_init(void)
+static __nolibc_no_stack_protector void __stack_chk_init(void)
{
__nolibc_syscall3(__NR_getrandom, &__stack_chk_guard, sizeof(__stack_chk_guard), 0);
/* a bit more randomness in case getrandom() fails, ensure the guard is never 0 */
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h
index 6335fd51f07f5..33f9c970ae576 100644
--- a/tools/include/nolibc/sys.h
+++ b/tools/include/nolibc/sys.h
@@ -45,16 +45,30 @@
: __sysret_arg; /* return original value */ \
})
-/* Syscall ENOSYS helper: Avoids unused-parameter warnings and provides a
- * debugging hook.
+/* Syscall ENOSYS helper: Avoids unused-parameter warnings, provides compile
+ * time validation and a debugging hook.
*/
+#if defined(NOLIBC_COMPILE_TIME_ENOSYS)
static __inline__ int __nolibc_enosys(const char *syscall, ...)
{
(void)syscall;
return -ENOSYS;
}
+#elif __nolibc_has_attribute(error)
+__attribute__((error("system call not implemented")))
+extern int __nolibc_enosys(const char *syscall, ...);
+
+#else
+static __inline__ int __nolibc_enosys(const char *syscall, ...)
+{
+ extern int __nolibc_enosys_error;
+ (void)syscall;
+
+ return __nolibc_enosys_error;
+}
+#endif
/* Functions in this file only describe syscalls. They're declared static so
* that the compiler usually decides to inline them while still being allowed
@@ -87,7 +101,7 @@ static __inline__ int __nolibc_enosys(const char *syscall, ...)
static __attribute__((unused))
void *_sys_brk(void *addr)
{
- return (void *)__nolibc_syscall1(__NR_brk, addr);
+ return (void *)(unsigned long)__nolibc_syscall1(__NR_brk, addr);
}
static __attribute__((unused))
@@ -597,12 +611,18 @@ int link(const char *old, const char *new)
static __attribute__((unused))
off_t _sys_lseek(int fd, off_t offset, int whence)
{
-#if defined(__NR_llseek)
+#if defined(__NR_llseek) || defined(__NR__llseek)
__kernel_loff_t loff = 0;
+ int ret, nr_llseek;
off_t result;
- int ret;
- ret = __nolibc_syscall5(__NR_llseek, fd, offset >> 32, (uint32_t)offset, &loff, whence);
+#if defined(__NR_llseek)
+ nr_llseek = __NR_llseek;
+#else
+ nr_llseek = __NR__llseek;
+#endif
+
+ ret = __nolibc_syscall5(nr_llseek, fd, offset >> 32, (uint32_t)offset, &loff, whence);
if (ret < 0)
result = ret;
else
diff --git a/tools/include/nolibc/sys/mman.h b/tools/include/nolibc/sys/mman.h
index 91d77a51412d4..72bc1d43d1d4c 100644
--- a/tools/include/nolibc/sys/mman.h
+++ b/tools/include/nolibc/sys/mman.h
@@ -27,7 +27,7 @@ void *_sys_mmap(void *addr, size_t length, int prot, int flags, int fd,
n = __NR_mmap;
#endif
- return (void *)__nolibc_syscall6(n, addr, length, prot, flags, fd, offset);
+ return (void *)(unsigned long)__nolibc_syscall6(n, addr, length, prot, flags, fd, offset);
}
#endif
@@ -46,8 +46,8 @@ void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
static __attribute__((unused))
void *_sys_mremap(void *old_address, size_t old_size, size_t new_size, int flags, void *new_address)
{
- return (void *)__nolibc_syscall5(__NR_mremap, old_address, old_size,
- new_size, flags, new_address);
+ return (void *)(unsigned long)__nolibc_syscall5(__NR_mremap, old_address, old_size,
+ new_size, flags, new_address);
}
static __attribute__((unused))
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index d3c4facb54c07..08610cacf0308 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -2,6 +2,7 @@
#define _GNU_SOURCE
#define _LARGEFILE64_SOURCE
+#define _FILE_OFFSET_BITS 64
/* libc-specific include files
* The program may be built in 3 ways:
@@ -45,6 +46,7 @@
#include <stdbool.h>
#include <byteswap.h>
#include <endian.h>
+#include <alloca.h>
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
@@ -797,7 +799,7 @@ int test_getdents64(const char *dir)
int fd, ret;
int err;
- ret = fd = open(dir, O_RDONLY | O_DIRECTORY, 0);
+ ret = fd = open(dir, O_RDONLY | O_DIRECTORY);
if (ret < 0)
return ret;
@@ -1298,6 +1300,23 @@ int test_openat(void)
return 0;
}
+int test_nolibc_enosys(void)
+{
+ if (true)
+ return 0;
+
+#if defined(NOLIBC)
+ /*
+ * __nolibc_enosys() will fail the compilation.
+ * Make sure it can be optimized away if not actually called.
+ */
+ if (__nolibc_enosys("something") != -ENOSYS)
+ return 1;
+#endif
+
+ return 0;
+}
+
int test_namespace(void)
{
int original_ns, new_ns, ret;
@@ -1364,6 +1383,52 @@ out:
return ret;
}
+int test_large_file(void)
+{
+ off_t large_seek = ((off_t)UINT32_MAX) + 100;
+ int fd, ret, saved_errno;
+ ssize_t written;
+ off_t off;
+
+#if defined(__mips__) && defined(_ABIN32)
+ /* https://lore.kernel.org/qemu-devel/fed03914-a95a-4522-a432-f129264cb2ac@t-8ch.de/ */
+ if (getpid() != 1)
+ return 0;
+#endif
+
+ if (large_seek < UINT32_MAX) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+
+ fd = open("/tmp", O_TMPFILE | O_RDWR, 0644);
+ if (fd == -1)
+ return -1;
+
+ off = lseek(fd, large_seek, SEEK_CUR);
+ if (off == -1) {
+ ret = off;
+ goto out;
+ } else if (off != large_seek) {
+ errno = ERANGE;
+ ret = -1;
+ goto out;
+ }
+
+ written = write(fd, "1", 1);
+ if (written == -1) {
+ ret = written;
+ goto out;
+ }
+
+ ret = 0;
+out:
+ saved_errno = errno;
+ close(fd);
+ errno = saved_errno;
+ return ret;
+}
+
/* Run syscall tests between IDs <min> and <max>.
* Return 0 on success, non-zero on failure.
*/
@@ -1466,6 +1531,7 @@ int run_syscall(int min, int max)
CASE_TEST(munmap_bad); EXPECT_SYSER(1, munmap(NULL, 0), -1, EINVAL); break;
CASE_TEST(mmap_munmap_good); EXPECT_SYSZR(1, test_mmap_munmap()); break;
CASE_TEST(nanosleep); ts.tv_nsec = -1; EXPECT_SYSER(1, nanosleep(&ts, NULL), -1, EINVAL); break;
+ CASE_TEST(nolibc_enosys); EXPECT_ZR(is_nolibc, test_nolibc_enosys()); break;
CASE_TEST(open_tty); EXPECT_SYSNE(1, tmp = open("/dev/null", O_RDONLY), -1); if (tmp != -1) close(tmp); break;
CASE_TEST(open_blah); EXPECT_SYSER(1, tmp = open("/proc/self/blah", O_RDONLY), -1, ENOENT); if (tmp != -1) close(tmp); break;
CASE_TEST(openat_dir); EXPECT_SYSZR(1, test_openat()); break;
@@ -1508,6 +1574,7 @@ int run_syscall(int min, int max)
CASE_TEST(_syscall_noargs); EXPECT_SYSEQ(is_nolibc, _syscall(__NR_getpid), getpid()); break;
CASE_TEST(_syscall_args); EXPECT_SYSEQ(is_nolibc, _syscall(__NR_statx, 0, NULL, 0, 0, NULL), -EFAULT); break;
CASE_TEST(namespace); EXPECT_SYSZR(euid0 && proc, test_namespace()); break;
+ CASE_TEST(largefile); EXPECT_SYSZR(1, test_large_file()); break;
case __LINE__:
return ret; /* must be last */
/* note: do not set any defaults so as to permit holes above */
@@ -1516,6 +1583,18 @@ int run_syscall(int min, int max)
return ret;
}
+int test_alloca(void)
+{
+ uint64_t *x;
+
+ x = alloca(sizeof(*x));
+
+ *x = 0x1234;
+ __asm__ ("" : "+r" (x));
+
+ return *x - 0x1234;
+}
+
int test_difftime(void)
{
if (difftime(200., 100.) != 100.)
@@ -1731,6 +1810,7 @@ int run_stdlib(int min, int max)
CASE_TEST(toupper_noop); EXPECT_EQ(1, toupper('A'), 'A'); break;
CASE_TEST(abs); EXPECT_EQ(1, abs(-10), 10); break;
CASE_TEST(abs_noop); EXPECT_EQ(1, abs(10), 10); break;
+ CASE_TEST(alloca); EXPECT_ZR(1, test_alloca()); break;
CASE_TEST(difftime); EXPECT_ZR(1, test_difftime()); break;
CASE_TEST(memchr_foobar6_o); EXPECT_STREQ(1, memchr("foobar", 'o', 6), "oobar"); break;
CASE_TEST(memchr_foobar3_b); EXPECT_STRZR(1, memchr("foobar", 'b', 3)); break;