From 55f1d6a9d6780e779e882a4d2d1b3db311835798 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 23 Feb 2026 22:40:14 +0100 Subject: [PATCH 01/61] tools/nolibc: rename my_syscallX() to __nolibc_syscallX() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The naming convention of the my_syscallX() macros is a bit unfortunate. They may conflict with application code and the name is very generic. Switch to __nolibc_syscallX(). The leading underscores place the symbols in the implementation-defined namespace, avoiding conflicting names. It is also clearer that these are non-standard extensions from nolibc. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260223-nolibc-namespacing-v1-1-52574ffebb2c@weissschuh.net --- tools/include/nolibc/arch-arm.h | 14 ++-- tools/include/nolibc/arch-arm64.h | 14 ++-- tools/include/nolibc/arch-loongarch.h | 14 ++-- tools/include/nolibc/arch-m68k.h | 14 ++-- tools/include/nolibc/arch-mips.h | 18 ++--- tools/include/nolibc/arch-powerpc.h | 14 ++-- tools/include/nolibc/arch-riscv.h | 14 ++-- tools/include/nolibc/arch-s390.h | 20 ++--- tools/include/nolibc/arch-sh.h | 14 ++-- tools/include/nolibc/arch-sparc.h | 18 ++--- tools/include/nolibc/arch-x86.h | 68 ++++++++-------- tools/include/nolibc/fcntl.h | 4 +- tools/include/nolibc/nolibc.h | 6 +- tools/include/nolibc/poll.h | 4 +- tools/include/nolibc/sched.h | 4 +- tools/include/nolibc/stackprotector.h | 8 +- tools/include/nolibc/sys.h | 110 +++++++++++++------------- tools/include/nolibc/sys/ioctl.h | 2 +- tools/include/nolibc/sys/mman.h | 8 +- tools/include/nolibc/sys/mount.h | 2 +- tools/include/nolibc/sys/prctl.h | 2 +- tools/include/nolibc/sys/ptrace.h | 2 +- tools/include/nolibc/sys/random.h | 2 +- tools/include/nolibc/sys/reboot.h | 2 +- tools/include/nolibc/sys/resource.h | 2 +- tools/include/nolibc/sys/select.h | 6 +- tools/include/nolibc/sys/stat.h | 2 +- tools/include/nolibc/sys/syscall.h | 2 +- tools/include/nolibc/sys/timerfd.h | 10 +-- tools/include/nolibc/sys/uio.h | 4 +- tools/include/nolibc/sys/utsname.h | 2 +- tools/include/nolibc/sys/wait.h | 2 +- tools/include/nolibc/time.h | 28 +++---- tools/include/nolibc/unistd.h | 2 +- 34 files changed, 220 insertions(+), 218 deletions(-) diff --git a/tools/include/nolibc/arch-arm.h b/tools/include/nolibc/arch-arm.h index 251c42579028..a4d3a777a051 100644 --- a/tools/include/nolibc/arch-arm.h +++ b/tools/include/nolibc/arch-arm.h @@ -50,7 +50,7 @@ #endif /* end THUMB */ -#define my_syscall0(num) \ +#define __nolibc_syscall0(num) \ ({ \ register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ register long _arg1 __asm__ ("r0"); \ @@ -67,7 +67,7 @@ _arg1; \ }) -#define my_syscall1(num, arg1) \ +#define __nolibc_syscall1(num, arg1) \ ({ \ register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ register long _arg1 __asm__ ("r0") = (long)(arg1); \ @@ -84,7 +84,7 @@ _arg1; \ }) -#define my_syscall2(num, arg1, arg2) \ +#define __nolibc_syscall2(num, arg1, arg2) \ ({ \ register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ register long _arg1 __asm__ ("r0") = (long)(arg1); \ @@ -102,7 +102,7 @@ _arg1; \ }) -#define my_syscall3(num, arg1, arg2, arg3) \ +#define __nolibc_syscall3(num, arg1, arg2, arg3) \ ({ \ register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ register long _arg1 __asm__ ("r0") = (long)(arg1); \ @@ -121,7 +121,7 @@ _arg1; \ }) -#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \ ({ \ register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ register long _arg1 __asm__ ("r0") = (long)(arg1); \ @@ -141,7 +141,7 @@ _arg1; \ }) -#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ ({ \ register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ register long _arg1 __asm__ ("r0") = (long)(arg1); \ @@ -162,7 +162,7 @@ _arg1; \ }) -#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ ({ \ register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ register long _arg1 __asm__ ("r0") = (long)(arg1); \ diff --git a/tools/include/nolibc/arch-arm64.h b/tools/include/nolibc/arch-arm64.h index 080a55a7144e..28b3c7536ad6 100644 --- a/tools/include/nolibc/arch-arm64.h +++ b/tools/include/nolibc/arch-arm64.h @@ -22,7 +22,7 @@ * don't have to experience issues with register constraints. */ -#define my_syscall0(num) \ +#define __nolibc_syscall0(num) \ ({ \ register long _num __asm__ ("x8") = (num); \ register long _arg1 __asm__ ("x0"); \ @@ -36,7 +36,7 @@ _arg1; \ }) -#define my_syscall1(num, arg1) \ +#define __nolibc_syscall1(num, arg1) \ ({ \ register long _num __asm__ ("x8") = (num); \ register long _arg1 __asm__ ("x0") = (long)(arg1); \ @@ -51,7 +51,7 @@ _arg1; \ }) -#define my_syscall2(num, arg1, arg2) \ +#define __nolibc_syscall2(num, arg1, arg2) \ ({ \ register long _num __asm__ ("x8") = (num); \ register long _arg1 __asm__ ("x0") = (long)(arg1); \ @@ -67,7 +67,7 @@ _arg1; \ }) -#define my_syscall3(num, arg1, arg2, arg3) \ +#define __nolibc_syscall3(num, arg1, arg2, arg3) \ ({ \ register long _num __asm__ ("x8") = (num); \ register long _arg1 __asm__ ("x0") = (long)(arg1); \ @@ -84,7 +84,7 @@ _arg1; \ }) -#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \ ({ \ register long _num __asm__ ("x8") = (num); \ register long _arg1 __asm__ ("x0") = (long)(arg1); \ @@ -102,7 +102,7 @@ _arg1; \ }) -#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ ({ \ register long _num __asm__ ("x8") = (num); \ register long _arg1 __asm__ ("x0") = (long)(arg1); \ @@ -121,7 +121,7 @@ _arg1; \ }) -#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ ({ \ register long _num __asm__ ("x8") = (num); \ register long _arg1 __asm__ ("x0") = (long)(arg1); \ diff --git a/tools/include/nolibc/arch-loongarch.h b/tools/include/nolibc/arch-loongarch.h index c894176c3f89..86fb34bbf185 100644 --- a/tools/include/nolibc/arch-loongarch.h +++ b/tools/include/nolibc/arch-loongarch.h @@ -24,7 +24,7 @@ #define _NOLIBC_SYSCALL_CLOBBERLIST \ "memory", "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8" -#define my_syscall0(num) \ +#define __nolibc_syscall0(num) \ ({ \ register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0"); \ @@ -38,7 +38,7 @@ _arg1; \ }) -#define my_syscall1(num, arg1) \ +#define __nolibc_syscall1(num, arg1) \ ({ \ register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ @@ -52,7 +52,7 @@ _arg1; \ }) -#define my_syscall2(num, arg1, arg2) \ +#define __nolibc_syscall2(num, arg1, arg2) \ ({ \ register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ @@ -68,7 +68,7 @@ _arg1; \ }) -#define my_syscall3(num, arg1, arg2, arg3) \ +#define __nolibc_syscall3(num, arg1, arg2, arg3) \ ({ \ register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ @@ -85,7 +85,7 @@ _arg1; \ }) -#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \ ({ \ register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ @@ -103,7 +103,7 @@ _arg1; \ }) -#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ ({ \ register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ @@ -122,7 +122,7 @@ _arg1; \ }) -#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ ({ \ register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ diff --git a/tools/include/nolibc/arch-m68k.h b/tools/include/nolibc/arch-m68k.h index 2a4fbada5e79..81d34c219a42 100644 --- a/tools/include/nolibc/arch-m68k.h +++ b/tools/include/nolibc/arch-m68k.h @@ -15,7 +15,7 @@ #define _NOLIBC_SYSCALL_CLOBBERLIST "memory" -#define my_syscall0(num) \ +#define __nolibc_syscall0(num) \ ({ \ register long _num __asm__ ("d0") = (num); \ \ @@ -28,7 +28,7 @@ _num; \ }) -#define my_syscall1(num, arg1) \ +#define __nolibc_syscall1(num, arg1) \ ({ \ register long _num __asm__ ("d0") = (num); \ register long _arg1 __asm__ ("d1") = (long)(arg1); \ @@ -42,7 +42,7 @@ _num; \ }) -#define my_syscall2(num, arg1, arg2) \ +#define __nolibc_syscall2(num, arg1, arg2) \ ({ \ register long _num __asm__ ("d0") = (num); \ register long _arg1 __asm__ ("d1") = (long)(arg1); \ @@ -57,7 +57,7 @@ _num; \ }) -#define my_syscall3(num, arg1, arg2, arg3) \ +#define __nolibc_syscall3(num, arg1, arg2, arg3) \ ({ \ register long _num __asm__ ("d0") = (num); \ register long _arg1 __asm__ ("d1") = (long)(arg1); \ @@ -73,7 +73,7 @@ _num; \ }) -#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \ ({ \ register long _num __asm__ ("d0") = (num); \ register long _arg1 __asm__ ("d1") = (long)(arg1); \ @@ -90,7 +90,7 @@ _num; \ }) -#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ ({ \ register long _num __asm__ ("d0") = (num); \ register long _arg1 __asm__ ("d1") = (long)(arg1); \ @@ -108,7 +108,7 @@ _num; \ }) -#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ ({ \ register long _num __asm__ ("d0") = (num); \ register long _arg1 __asm__ ("d1") = (long)(arg1); \ diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h index a72506ceec6b..bd4a9b57e1f0 100644 --- a/tools/include/nolibc/arch-mips.h +++ b/tools/include/nolibc/arch-mips.h @@ -59,7 +59,7 @@ #endif /* _ABIO32 */ -#define my_syscall0(num) \ +#define __nolibc_syscall0(num) \ ({ \ register long _num __asm__ ("v0") = (num); \ register long _arg4 __asm__ ("a3"); \ @@ -75,7 +75,7 @@ _arg4 ? -_num : _num; \ }) -#define my_syscall1(num, arg1) \ +#define __nolibc_syscall1(num, arg1) \ ({ \ register long _num __asm__ ("v0") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ @@ -93,7 +93,7 @@ _arg4 ? -_num : _num; \ }) -#define my_syscall2(num, arg1, arg2) \ +#define __nolibc_syscall2(num, arg1, arg2) \ ({ \ register long _num __asm__ ("v0") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ @@ -112,7 +112,7 @@ _arg4 ? -_num : _num; \ }) -#define my_syscall3(num, arg1, arg2, arg3) \ +#define __nolibc_syscall3(num, arg1, arg2, arg3) \ ({ \ register long _num __asm__ ("v0") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ @@ -132,7 +132,7 @@ _arg4 ? -_num : _num; \ }) -#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \ ({ \ register long _num __asm__ ("v0") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ @@ -154,7 +154,7 @@ #if defined(_ABIO32) -#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ ({ \ register long _num __asm__ ("v0") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ @@ -176,7 +176,7 @@ _arg4 ? -_num : _num; \ }) -#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ ({ \ register long _num __asm__ ("v0") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ @@ -203,7 +203,7 @@ #else /* _ABIN32 || _ABI64 */ -#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ ({ \ register long _num __asm__ ("v0") = (num); \ register long _arg1 __asm__ ("$4") = (long)(arg1); \ @@ -222,7 +222,7 @@ _arg4 ? -_num : _num; \ }) -#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ ({ \ register long _num __asm__ ("v0") = (num); \ register long _arg1 __asm__ ("$4") = (long)(arg1); \ diff --git a/tools/include/nolibc/arch-powerpc.h b/tools/include/nolibc/arch-powerpc.h index e0c7e0b81f7c..ef878868aa4a 100644 --- a/tools/include/nolibc/arch-powerpc.h +++ b/tools/include/nolibc/arch-powerpc.h @@ -25,7 +25,7 @@ #define _NOLIBC_SYSCALL_CLOBBERLIST \ "memory", "cr0", "r12", "r11", "r10", "r9" -#define my_syscall0(num) \ +#define __nolibc_syscall0(num) \ ({ \ register long _ret __asm__ ("r3"); \ register long _num __asm__ ("r0") = (num); \ @@ -42,7 +42,7 @@ _ret; \ }) -#define my_syscall1(num, arg1) \ +#define __nolibc_syscall1(num, arg1) \ ({ \ register long _ret __asm__ ("r3"); \ register long _num __asm__ ("r0") = (num); \ @@ -61,7 +61,7 @@ }) -#define my_syscall2(num, arg1, arg2) \ +#define __nolibc_syscall2(num, arg1, arg2) \ ({ \ register long _ret __asm__ ("r3"); \ register long _num __asm__ ("r0") = (num); \ @@ -81,7 +81,7 @@ }) -#define my_syscall3(num, arg1, arg2, arg3) \ +#define __nolibc_syscall3(num, arg1, arg2, arg3) \ ({ \ register long _ret __asm__ ("r3"); \ register long _num __asm__ ("r0") = (num); \ @@ -102,7 +102,7 @@ }) -#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \ ({ \ register long _ret __asm__ ("r3"); \ register long _num __asm__ ("r0") = (num); \ @@ -125,7 +125,7 @@ }) -#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ ({ \ register long _ret __asm__ ("r3"); \ register long _num __asm__ ("r0") = (num); \ @@ -148,7 +148,7 @@ _ret; \ }) -#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ ({ \ register long _ret __asm__ ("r3"); \ register long _num __asm__ ("r0") = (num); \ diff --git a/tools/include/nolibc/arch-riscv.h b/tools/include/nolibc/arch-riscv.h index 1c00cacf57e1..386ebb9f5b08 100644 --- a/tools/include/nolibc/arch-riscv.h +++ b/tools/include/nolibc/arch-riscv.h @@ -21,7 +21,7 @@ * so that we don't have to experience issues with register constraints. */ -#define my_syscall0(num) \ +#define __nolibc_syscall0(num) \ ({ \ register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0"); \ @@ -35,7 +35,7 @@ _arg1; \ }) -#define my_syscall1(num, arg1) \ +#define __nolibc_syscall1(num, arg1) \ ({ \ register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ @@ -49,7 +49,7 @@ _arg1; \ }) -#define my_syscall2(num, arg1, arg2) \ +#define __nolibc_syscall2(num, arg1, arg2) \ ({ \ register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ @@ -65,7 +65,7 @@ _arg1; \ }) -#define my_syscall3(num, arg1, arg2, arg3) \ +#define __nolibc_syscall3(num, arg1, arg2, arg3) \ ({ \ register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ @@ -82,7 +82,7 @@ _arg1; \ }) -#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \ ({ \ register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ @@ -100,7 +100,7 @@ _arg1; \ }) -#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ ({ \ register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ @@ -119,7 +119,7 @@ _arg1; \ }) -#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ ({ \ register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ diff --git a/tools/include/nolibc/arch-s390.h b/tools/include/nolibc/arch-s390.h index 904281e95f99..d301b636e083 100644 --- a/tools/include/nolibc/arch-s390.h +++ b/tools/include/nolibc/arch-s390.h @@ -28,7 +28,7 @@ * */ -#define my_syscall0(num) \ +#define __nolibc_syscall0(num) \ ({ \ register long _num __asm__ ("1") = (num); \ register long _rc __asm__ ("2"); \ @@ -42,7 +42,7 @@ _rc; \ }) -#define my_syscall1(num, arg1) \ +#define __nolibc_syscall1(num, arg1) \ ({ \ register long _num __asm__ ("1") = (num); \ register long _arg1 __asm__ ("2") = (long)(arg1); \ @@ -56,7 +56,7 @@ _arg1; \ }) -#define my_syscall2(num, arg1, arg2) \ +#define __nolibc_syscall2(num, arg1, arg2) \ ({ \ register long _num __asm__ ("1") = (num); \ register long _arg1 __asm__ ("2") = (long)(arg1); \ @@ -71,7 +71,7 @@ _arg1; \ }) -#define my_syscall3(num, arg1, arg2, arg3) \ +#define __nolibc_syscall3(num, arg1, arg2, arg3) \ ({ \ register long _num __asm__ ("1") = (num); \ register long _arg1 __asm__ ("2") = (long)(arg1); \ @@ -87,7 +87,7 @@ _arg1; \ }) -#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \ ({ \ register long _num __asm__ ("1") = (num); \ register long _arg1 __asm__ ("2") = (long)(arg1); \ @@ -104,7 +104,7 @@ _arg1; \ }) -#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ ({ \ register long _num __asm__ ("1") = (num); \ register long _arg1 __asm__ ("2") = (long)(arg1); \ @@ -123,7 +123,7 @@ _arg1; \ }) -#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ ({ \ register long _num __asm__ ("1") = (num); \ register long _arg1 __asm__ ("2") = (long)(arg1); \ @@ -179,21 +179,21 @@ void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, .offset = (unsigned long)offset }; - return (void *)my_syscall1(__NR_mmap, &args); + return (void *)__nolibc_syscall1(__NR_mmap, &args); } #define sys_mmap sys_mmap static __attribute__((unused)) pid_t sys_fork(void) { - return my_syscall5(__NR_clone, 0, SIGCHLD, 0, 0, 0); + return __nolibc_syscall5(__NR_clone, 0, SIGCHLD, 0, 0, 0); } #define sys_fork sys_fork static __attribute__((unused)) pid_t sys_vfork(void) { - return my_syscall5(__NR_clone, 0, CLONE_VM | CLONE_VFORK | SIGCHLD, 0, 0, 0); + return __nolibc_syscall5(__NR_clone, 0, CLONE_VM | CLONE_VFORK | SIGCHLD, 0, 0, 0); } #define sys_vfork sys_vfork diff --git a/tools/include/nolibc/arch-sh.h b/tools/include/nolibc/arch-sh.h index 7a421197d104..b5a64ceeec97 100644 --- a/tools/include/nolibc/arch-sh.h +++ b/tools/include/nolibc/arch-sh.h @@ -19,7 +19,7 @@ * - syscall return value is in r0 */ -#define my_syscall0(num) \ +#define __nolibc_syscall0(num) \ ({ \ register long _num __asm__ ("r3") = (num); \ register long _ret __asm__ ("r0"); \ @@ -33,7 +33,7 @@ _ret; \ }) -#define my_syscall1(num, arg1) \ +#define __nolibc_syscall1(num, arg1) \ ({ \ register long _num __asm__ ("r3") = (num); \ register long _ret __asm__ ("r0"); \ @@ -48,7 +48,7 @@ _ret; \ }) -#define my_syscall2(num, arg1, arg2) \ +#define __nolibc_syscall2(num, arg1, arg2) \ ({ \ register long _num __asm__ ("r3") = (num); \ register long _ret __asm__ ("r0"); \ @@ -64,7 +64,7 @@ _ret; \ }) -#define my_syscall3(num, arg1, arg2, arg3) \ +#define __nolibc_syscall3(num, arg1, arg2, arg3) \ ({ \ register long _num __asm__ ("r3") = (num); \ register long _ret __asm__ ("r0"); \ @@ -81,7 +81,7 @@ _ret; \ }) -#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \ ({ \ register long _num __asm__ ("r3") = (num); \ register long _ret __asm__ ("r0"); \ @@ -99,7 +99,7 @@ _ret; \ }) -#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ ({ \ register long _num __asm__ ("r3") = (num); \ register long _ret __asm__ ("r0"); \ @@ -119,7 +119,7 @@ _ret; \ }) -#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ ({ \ register long _num __asm__ ("r3") = (num); \ register long _ret __asm__ ("r0"); \ diff --git a/tools/include/nolibc/arch-sparc.h b/tools/include/nolibc/arch-sparc.h index 2ebb5686e105..02aca6579cb2 100644 --- a/tools/include/nolibc/arch-sparc.h +++ b/tools/include/nolibc/arch-sparc.h @@ -38,7 +38,7 @@ #endif /* __arch64__ */ -#define my_syscall0(num) \ +#define __nolibc_syscall0(num) \ ({ \ register long _num __asm__ ("g1") = (num); \ register long _arg1 __asm__ ("o0"); \ @@ -52,7 +52,7 @@ _arg1; \ }) -#define my_syscall1(num, arg1) \ +#define __nolibc_syscall1(num, arg1) \ ({ \ register long _num __asm__ ("g1") = (num); \ register long _arg1 __asm__ ("o0") = (long)(arg1); \ @@ -66,7 +66,7 @@ _arg1; \ }) -#define my_syscall2(num, arg1, arg2) \ +#define __nolibc_syscall2(num, arg1, arg2) \ ({ \ register long _num __asm__ ("g1") = (num); \ register long _arg1 __asm__ ("o0") = (long)(arg1); \ @@ -81,7 +81,7 @@ _arg1; \ }) -#define my_syscall3(num, arg1, arg2, arg3) \ +#define __nolibc_syscall3(num, arg1, arg2, arg3) \ ({ \ register long _num __asm__ ("g1") = (num); \ register long _arg1 __asm__ ("o0") = (long)(arg1); \ @@ -97,7 +97,7 @@ _arg1; \ }) -#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \ ({ \ register long _num __asm__ ("g1") = (num); \ register long _arg1 __asm__ ("o0") = (long)(arg1); \ @@ -114,7 +114,7 @@ _arg1; \ }) -#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ ({ \ register long _num __asm__ ("g1") = (num); \ register long _arg1 __asm__ ("o0") = (long)(arg1); \ @@ -132,7 +132,7 @@ _arg1; \ }) -#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ ({ \ register long _num __asm__ ("g1") = (num); \ register long _arg1 __asm__ ("o0") = (long)(arg1); \ @@ -180,7 +180,7 @@ pid_t sys_fork(void) pid_t parent, ret; parent = getpid(); - ret = my_syscall0(__NR_fork); + ret = __nolibc_syscall0(__NR_fork); /* The syscall returns the parent pid in the child instead of 0 */ if (ret == parent) @@ -196,7 +196,7 @@ pid_t sys_vfork(void) pid_t parent, ret; parent = getpid(); - ret = my_syscall0(__NR_vfork); + ret = __nolibc_syscall0(__NR_vfork); /* The syscall returns the parent pid in the child instead of 0 */ if (ret == parent) diff --git a/tools/include/nolibc/arch-x86.h b/tools/include/nolibc/arch-x86.h index f6c43ac5377b..769ba01a8629 100644 --- a/tools/include/nolibc/arch-x86.h +++ b/tools/include/nolibc/arch-x86.h @@ -30,7 +30,7 @@ */ #define __ARCH_WANT_SYS_OLD_SELECT -#define my_syscall0(num) \ +#define __nolibc_syscall0(num) \ ({ \ long _ret; \ register long _num __asm__ ("eax") = (num); \ @@ -44,7 +44,7 @@ _ret; \ }) -#define my_syscall1(num, arg1) \ +#define __nolibc_syscall1(num, arg1) \ ({ \ long _ret; \ register long _num __asm__ ("eax") = (num); \ @@ -60,7 +60,7 @@ _ret; \ }) -#define my_syscall2(num, arg1, arg2) \ +#define __nolibc_syscall2(num, arg1, arg2) \ ({ \ long _ret; \ register long _num __asm__ ("eax") = (num); \ @@ -77,7 +77,7 @@ _ret; \ }) -#define my_syscall3(num, arg1, arg2, arg3) \ +#define __nolibc_syscall3(num, arg1, arg2, arg3) \ ({ \ long _ret; \ register long _num __asm__ ("eax") = (num); \ @@ -95,7 +95,7 @@ _ret; \ }) -#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \ ({ \ long _ret; \ register long _num __asm__ ("eax") = (num); \ @@ -114,7 +114,7 @@ _ret; \ }) -#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ ({ \ long _ret; \ register long _num __asm__ ("eax") = (num); \ @@ -134,27 +134,27 @@ _ret; \ }) -#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ -({ \ - long _eax = (long)(num); \ - long _arg6 = (long)(arg6); /* Always in memory */ \ - __asm__ volatile ( \ - "pushl %[_arg6]\n\t" \ - "pushl %%ebp\n\t" \ - "movl 4(%%esp),%%ebp\n\t" \ - "int $0x80\n\t" \ - "popl %%ebp\n\t" \ - "addl $4,%%esp\n\t" \ - : "+a"(_eax) /* %eax */ \ - : "b"(arg1), /* %ebx */ \ - "c"(arg2), /* %ecx */ \ - "d"(arg3), /* %edx */ \ - "S"(arg4), /* %esi */ \ - "D"(arg5), /* %edi */ \ - [_arg6]"m"(_arg6) /* memory */ \ - : "memory", "cc" \ - ); \ - _eax; \ +#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +({ \ + long _eax = (long)(num); \ + long _arg6 = (long)(arg6); /* Always in memory */ \ + __asm__ volatile ( \ + "pushl %[_arg6]\n\t" \ + "pushl %%ebp\n\t" \ + "movl 4(%%esp),%%ebp\n\t" \ + "int $0x80\n\t" \ + "popl %%ebp\n\t" \ + "addl $4,%%esp\n\t" \ + : "+a"(_eax) /* %eax */ \ + : "b"(arg1), /* %ebx */ \ + "c"(arg2), /* %ecx */ \ + "d"(arg3), /* %edx */ \ + "S"(arg4), /* %esi */ \ + "D"(arg5), /* %edi */ \ + [_arg6]"m"(_arg6) /* memory */ \ + : "memory", "cc" \ + ); \ + _eax; \ }) #ifndef NOLIBC_NO_RUNTIME @@ -200,7 +200,7 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s * */ -#define my_syscall0(num) \ +#define __nolibc_syscall0(num) \ ({ \ long _ret; \ register long _num __asm__ ("rax") = (num); \ @@ -214,7 +214,7 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s _ret; \ }) -#define my_syscall1(num, arg1) \ +#define __nolibc_syscall1(num, arg1) \ ({ \ long _ret; \ register long _num __asm__ ("rax") = (num); \ @@ -230,7 +230,7 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s _ret; \ }) -#define my_syscall2(num, arg1, arg2) \ +#define __nolibc_syscall2(num, arg1, arg2) \ ({ \ long _ret; \ register long _num __asm__ ("rax") = (num); \ @@ -247,7 +247,7 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s _ret; \ }) -#define my_syscall3(num, arg1, arg2, arg3) \ +#define __nolibc_syscall3(num, arg1, arg2, arg3) \ ({ \ long _ret; \ register long _num __asm__ ("rax") = (num); \ @@ -265,7 +265,7 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s _ret; \ }) -#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \ ({ \ long _ret; \ register long _num __asm__ ("rax") = (num); \ @@ -284,7 +284,7 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s _ret; \ }) -#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ ({ \ long _ret; \ register long _num __asm__ ("rax") = (num); \ @@ -304,7 +304,7 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s _ret; \ }) -#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ ({ \ long _ret; \ register long _num __asm__ ("rax") = (num); \ diff --git a/tools/include/nolibc/fcntl.h b/tools/include/nolibc/fcntl.h index bff2e542f20f..8d82768dea9d 100644 --- a/tools/include/nolibc/fcntl.h +++ b/tools/include/nolibc/fcntl.h @@ -21,7 +21,7 @@ static __attribute__((unused)) int sys_openat(int dirfd, const char *path, int flags, mode_t mode) { - return my_syscall4(__NR_openat, dirfd, path, flags, mode); + return __nolibc_syscall4(__NR_openat, dirfd, path, flags, mode); } static __attribute__((unused)) @@ -47,7 +47,7 @@ int openat(int dirfd, const char *path, int flags, ...) static __attribute__((unused)) int sys_open(const char *path, int flags, mode_t mode) { - return my_syscall4(__NR_openat, AT_FDCWD, path, flags, mode); + return __nolibc_syscall4(__NR_openat, AT_FDCWD, path, flags, mode); } static __attribute__((unused)) diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 9c7f43b9218b..d1d08b7f8599 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -12,14 +12,14 @@ * * Syscalls are split into 3 levels: * - The lower level is the arch-specific syscall() definition, consisting in - * assembly code in compound expressions. These are called my_syscall0() to - * my_syscall6() depending on the number of arguments. All input arguments + * assembly code in compound expressions. These are called __nolibc_syscall0() to + * __nolibc_syscall6() depending on the number of arguments. All input arguments * are castto a long stored in a register. These expressions always return * the syscall's return value as a signed long value which is often either * a pointer or the negated errno value. * * - The second level is mostly architecture-independent. It is made of - * static functions called sys_() which rely on my_syscallN() + * static functions called sys_() which rely on __nolibc_syscallN() * depending on the syscall definition. These functions are responsible * for exposing the appropriate types for the syscall arguments (int, * pointers, etc) and for setting the appropriate return type (often int). diff --git a/tools/include/nolibc/poll.h b/tools/include/nolibc/poll.h index e854c94647b1..ea5a6d08c43c 100644 --- a/tools/include/nolibc/poll.h +++ b/tools/include/nolibc/poll.h @@ -30,7 +30,7 @@ int sys_poll(struct pollfd *fds, int nfds, int timeout) t.tv_sec = timeout / 1000; t.tv_nsec = (timeout % 1000) * 1000000; } - return my_syscall5(__NR_ppoll_time64, fds, nfds, (timeout >= 0) ? &t : NULL, NULL, 0); + return __nolibc_syscall5(__NR_ppoll_time64, fds, nfds, (timeout >= 0) ? &t : NULL, NULL, 0); #else struct __kernel_old_timespec t; @@ -38,7 +38,7 @@ int sys_poll(struct pollfd *fds, int nfds, int timeout) t.tv_sec = timeout / 1000; t.tv_nsec = (timeout % 1000) * 1000000; } - return my_syscall5(__NR_ppoll, fds, nfds, (timeout >= 0) ? &t : NULL, NULL, 0); + return __nolibc_syscall5(__NR_ppoll, fds, nfds, (timeout >= 0) ? &t : NULL, NULL, 0); #endif } diff --git a/tools/include/nolibc/sched.h b/tools/include/nolibc/sched.h index 32221562c166..b1af7fa6672d 100644 --- a/tools/include/nolibc/sched.h +++ b/tools/include/nolibc/sched.h @@ -21,7 +21,7 @@ static __attribute__((unused)) int sys_setns(int fd, int nstype) { - return my_syscall2(__NR_setns, fd, nstype); + return __nolibc_syscall2(__NR_setns, fd, nstype); } static __attribute__((unused)) @@ -38,7 +38,7 @@ int setns(int fd, int nstype) static __attribute__((unused)) int sys_unshare(int flags) { - return my_syscall1(__NR_unshare, flags); + return __nolibc_syscall1(__NR_unshare, flags); } static __attribute__((unused)) diff --git a/tools/include/nolibc/stackprotector.h b/tools/include/nolibc/stackprotector.h index 7123aa056cb0..ae8b1d3a374d 100644 --- a/tools/include/nolibc/stackprotector.h +++ b/tools/include/nolibc/stackprotector.h @@ -24,9 +24,9 @@ __attribute__((weak,used,noreturn,section(".text.nolibc_stack_chk"))) void __stack_chk_fail(void) { pid_t pid; - my_syscall3(__NR_write, STDERR_FILENO, "!!Stack smashing detected!!\n", 28); - pid = my_syscall0(__NR_getpid); - my_syscall2(__NR_kill, pid, SIGABRT); + __nolibc_syscall3(__NR_write, STDERR_FILENO, "!!Stack smashing detected!!\n", 28); + pid = __nolibc_syscall0(__NR_getpid); + __nolibc_syscall2(__NR_kill, pid, SIGABRT); for (;;); } @@ -42,7 +42,7 @@ uintptr_t __stack_chk_guard; static __no_stack_protector void __stack_chk_init(void) { - my_syscall3(__NR_getrandom, &__stack_chk_guard, sizeof(__stack_chk_guard), 0); + __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 */ if (__stack_chk_guard != (uintptr_t) &__stack_chk_guard) __stack_chk_guard ^= (uintptr_t) &__stack_chk_guard; diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 403ee9ce8389..bc1c76cb2f63 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -87,7 +87,7 @@ static __inline__ int __nolibc_enosys(const char *syscall, ...) static __attribute__((unused)) void *sys_brk(void *addr) { - return (void *)my_syscall1(__NR_brk, addr); + return (void *)__nolibc_syscall1(__NR_brk, addr); } static __attribute__((unused)) @@ -124,7 +124,7 @@ void *sbrk(intptr_t inc) static __attribute__((unused)) int sys_chdir(const char *path) { - return my_syscall1(__NR_chdir, path); + return __nolibc_syscall1(__NR_chdir, path); } static __attribute__((unused)) @@ -136,7 +136,7 @@ int chdir(const char *path) static __attribute__((unused)) int sys_fchdir(int fildes) { - return my_syscall1(__NR_fchdir, fildes); + return __nolibc_syscall1(__NR_fchdir, fildes); } static __attribute__((unused)) @@ -154,9 +154,9 @@ static __attribute__((unused)) int sys_chmod(const char *path, mode_t mode) { #if defined(__NR_fchmodat) - return my_syscall4(__NR_fchmodat, AT_FDCWD, path, mode, 0); + return __nolibc_syscall4(__NR_fchmodat, AT_FDCWD, path, mode, 0); #else - return my_syscall2(__NR_chmod, path, mode); + return __nolibc_syscall2(__NR_chmod, path, mode); #endif } @@ -175,9 +175,9 @@ static __attribute__((unused)) int sys_chown(const char *path, uid_t owner, gid_t group) { #if defined(__NR_fchownat) - return my_syscall5(__NR_fchownat, AT_FDCWD, path, owner, group, 0); + return __nolibc_syscall5(__NR_fchownat, AT_FDCWD, path, owner, group, 0); #else - return my_syscall3(__NR_chown, path, owner, group); + return __nolibc_syscall3(__NR_chown, path, owner, group); #endif } @@ -195,7 +195,7 @@ int chown(const char *path, uid_t owner, gid_t group) static __attribute__((unused)) int sys_chroot(const char *path) { - return my_syscall1(__NR_chroot, path); + return __nolibc_syscall1(__NR_chroot, path); } static __attribute__((unused)) @@ -212,7 +212,7 @@ int chroot(const char *path) static __attribute__((unused)) int sys_close(int fd) { - return my_syscall1(__NR_close, fd); + return __nolibc_syscall1(__NR_close, fd); } static __attribute__((unused)) @@ -229,7 +229,7 @@ int close(int fd) static __attribute__((unused)) int sys_dup(int fd) { - return my_syscall1(__NR_dup, fd); + return __nolibc_syscall1(__NR_dup, fd); } static __attribute__((unused)) @@ -256,13 +256,13 @@ int sys_dup2(int old, int new) #endif if (old == new) { - ret = my_syscall2(nr_fcntl, old, F_GETFD); + ret = __nolibc_syscall2(nr_fcntl, old, F_GETFD); return ret < 0 ? ret : old; } - return my_syscall3(__NR_dup3, old, new, 0); + return __nolibc_syscall3(__NR_dup3, old, new, 0); #else - return my_syscall2(__NR_dup2, old, new); + return __nolibc_syscall2(__NR_dup2, old, new); #endif } @@ -281,7 +281,7 @@ int dup2(int old, int new) static __attribute__((unused)) int sys_dup3(int old, int new, int flags) { - return my_syscall3(__NR_dup3, old, new, flags); + return __nolibc_syscall3(__NR_dup3, old, new, flags); } static __attribute__((unused)) @@ -299,7 +299,7 @@ int dup3(int old, int new, int flags) static __attribute__((unused)) int sys_execve(const char *filename, char *const argv[], char *const envp[]) { - return my_syscall3(__NR_execve, filename, argv, envp); + return __nolibc_syscall3(__NR_execve, filename, argv, envp); } static __attribute__((unused)) @@ -316,7 +316,7 @@ int execve(const char *filename, char *const argv[], char *const envp[]) static __attribute__((noreturn,unused)) void sys_exit(int status) { - my_syscall1(__NR_exit, status & 255); + __nolibc_syscall1(__NR_exit, status & 255); while(1); /* shut the "noreturn" warnings. */ } @@ -346,9 +346,9 @@ pid_t sys_fork(void) * have a different API, but most archs have the flags on first arg and * will not use the rest with no other flag. */ - return my_syscall5(__NR_clone, SIGCHLD, 0, 0, 0, 0); + return __nolibc_syscall5(__NR_clone, SIGCHLD, 0, 0, 0, 0); #else - return my_syscall0(__NR_fork); + return __nolibc_syscall0(__NR_fork); #endif } #endif @@ -365,9 +365,9 @@ pid_t sys_vfork(void) { #if defined(__NR_clone) /* See the note in sys_fork(). */ - return my_syscall5(__NR_clone, CLONE_VM | CLONE_VFORK | SIGCHLD, 0, 0, 0, 0); + return __nolibc_syscall5(__NR_clone, CLONE_VM | CLONE_VFORK | SIGCHLD, 0, 0, 0, 0); #elif defined(__NR_vfork) - return my_syscall0(__NR_vfork); + return __nolibc_syscall0(__NR_vfork); #endif } #endif @@ -385,7 +385,7 @@ pid_t vfork(void) static __attribute__((unused)) int sys_fsync(int fd) { - return my_syscall1(__NR_fsync, fd); + return __nolibc_syscall1(__NR_fsync, fd); } static __attribute__((unused)) @@ -402,7 +402,7 @@ int fsync(int fd) static __attribute__((unused)) int sys_getdents64(int fd, struct linux_dirent64 *dirp, int count) { - return my_syscall3(__NR_getdents64, fd, dirp, count); + return __nolibc_syscall3(__NR_getdents64, fd, dirp, count); } static __attribute__((unused)) @@ -420,9 +420,9 @@ static __attribute__((unused)) uid_t sys_geteuid(void) { #if defined(__NR_geteuid32) - return my_syscall0(__NR_geteuid32); + return __nolibc_syscall0(__NR_geteuid32); #else - return my_syscall0(__NR_geteuid); + return __nolibc_syscall0(__NR_geteuid); #endif } @@ -440,7 +440,7 @@ uid_t geteuid(void) static __attribute__((unused)) pid_t sys_getpgid(pid_t pid) { - return my_syscall1(__NR_getpgid, pid); + return __nolibc_syscall1(__NR_getpgid, pid); } static __attribute__((unused)) @@ -474,7 +474,7 @@ pid_t getpgrp(void) static __attribute__((unused)) pid_t sys_getpid(void) { - return my_syscall0(__NR_getpid); + return __nolibc_syscall0(__NR_getpid); } static __attribute__((unused)) @@ -491,7 +491,7 @@ pid_t getpid(void) static __attribute__((unused)) pid_t sys_getppid(void) { - return my_syscall0(__NR_getppid); + return __nolibc_syscall0(__NR_getppid); } static __attribute__((unused)) @@ -508,7 +508,7 @@ pid_t getppid(void) static __attribute__((unused)) pid_t sys_gettid(void) { - return my_syscall0(__NR_gettid); + return __nolibc_syscall0(__NR_gettid); } static __attribute__((unused)) @@ -539,9 +539,9 @@ static __attribute__((unused)) uid_t sys_getuid(void) { #if defined(__NR_getuid32) - return my_syscall0(__NR_getuid32); + return __nolibc_syscall0(__NR_getuid32); #else - return my_syscall0(__NR_getuid); + return __nolibc_syscall0(__NR_getuid); #endif } @@ -559,7 +559,7 @@ uid_t getuid(void) static __attribute__((unused)) int sys_kill(pid_t pid, int signal) { - return my_syscall2(__NR_kill, pid, signal); + return __nolibc_syscall2(__NR_kill, pid, signal); } static __attribute__((unused)) @@ -577,9 +577,9 @@ static __attribute__((unused)) int sys_link(const char *old, const char *new) { #if defined(__NR_linkat) - return my_syscall5(__NR_linkat, AT_FDCWD, old, AT_FDCWD, new, 0); + return __nolibc_syscall5(__NR_linkat, AT_FDCWD, old, AT_FDCWD, new, 0); #else - return my_syscall2(__NR_link, old, new); + return __nolibc_syscall2(__NR_link, old, new); #endif } @@ -602,7 +602,7 @@ off_t sys_lseek(int fd, off_t offset, int whence) off_t result; int ret; - ret = my_syscall5(__NR_llseek, fd, offset >> 32, (uint32_t)offset, &loff, whence); + ret = __nolibc_syscall5(__NR_llseek, fd, offset >> 32, (uint32_t)offset, &loff, whence); if (ret < 0) result = ret; else @@ -610,7 +610,7 @@ off_t sys_lseek(int fd, off_t offset, int whence) return result; #else - return my_syscall3(__NR_lseek, fd, offset, whence); + return __nolibc_syscall3(__NR_lseek, fd, offset, whence); #endif } @@ -629,9 +629,9 @@ static __attribute__((unused)) int sys_mkdir(const char *path, mode_t mode) { #if defined(__NR_mkdirat) - return my_syscall3(__NR_mkdirat, AT_FDCWD, path, mode); + return __nolibc_syscall3(__NR_mkdirat, AT_FDCWD, path, mode); #else - return my_syscall2(__NR_mkdir, path, mode); + return __nolibc_syscall2(__NR_mkdir, path, mode); #endif } @@ -649,9 +649,9 @@ static __attribute__((unused)) int sys_rmdir(const char *path) { #if defined(__NR_rmdir) - return my_syscall1(__NR_rmdir, path); + return __nolibc_syscall1(__NR_rmdir, path); #else - return my_syscall3(__NR_unlinkat, AT_FDCWD, path, AT_REMOVEDIR); + return __nolibc_syscall3(__NR_unlinkat, AT_FDCWD, path, AT_REMOVEDIR); #endif } @@ -670,9 +670,9 @@ static __attribute__((unused)) long sys_mknod(const char *path, mode_t mode, dev_t dev) { #if defined(__NR_mknodat) - return my_syscall4(__NR_mknodat, AT_FDCWD, path, mode, dev); + return __nolibc_syscall4(__NR_mknodat, AT_FDCWD, path, mode, dev); #else - return my_syscall3(__NR_mknod, path, mode, dev); + return __nolibc_syscall3(__NR_mknod, path, mode, dev); #endif } @@ -691,7 +691,7 @@ int mknod(const char *path, mode_t mode, dev_t dev) static __attribute__((unused)) int sys_pipe2(int pipefd[2], int flags) { - return my_syscall2(__NR_pipe2, pipefd, flags); + return __nolibc_syscall2(__NR_pipe2, pipefd, flags); } static __attribute__((unused)) @@ -714,7 +714,7 @@ int pipe(int pipefd[2]) static __attribute__((unused)) int sys_pivot_root(const char *new, const char *old) { - return my_syscall2(__NR_pivot_root, new, old); + return __nolibc_syscall2(__NR_pivot_root, new, old); } static __attribute__((unused)) @@ -731,7 +731,7 @@ int pivot_root(const char *new, const char *old) static __attribute__((unused)) ssize_t sys_read(int fd, void *buf, size_t count) { - return my_syscall3(__NR_read, fd, buf, count); + return __nolibc_syscall3(__NR_read, fd, buf, count); } static __attribute__((unused)) @@ -748,7 +748,7 @@ ssize_t read(int fd, void *buf, size_t count) static __attribute__((unused)) int sys_sched_yield(void) { - return my_syscall0(__NR_sched_yield); + return __nolibc_syscall0(__NR_sched_yield); } static __attribute__((unused)) @@ -765,7 +765,7 @@ int sched_yield(void) static __attribute__((unused)) int sys_setpgid(pid_t pid, pid_t pgid) { - return my_syscall2(__NR_setpgid, pid, pgid); + return __nolibc_syscall2(__NR_setpgid, pid, pgid); } static __attribute__((unused)) @@ -792,7 +792,7 @@ pid_t setpgrp(void) static __attribute__((unused)) pid_t sys_setsid(void) { - return my_syscall0(__NR_setsid); + return __nolibc_syscall0(__NR_setsid); } static __attribute__((unused)) @@ -810,9 +810,9 @@ static __attribute__((unused)) int sys_symlink(const char *old, const char *new) { #if defined(__NR_symlinkat) - return my_syscall3(__NR_symlinkat, old, AT_FDCWD, new); + return __nolibc_syscall3(__NR_symlinkat, old, AT_FDCWD, new); #else - return my_syscall2(__NR_symlink, old, new); + return __nolibc_syscall2(__NR_symlink, old, new); #endif } @@ -830,7 +830,7 @@ int symlink(const char *old, const char *new) static __attribute__((unused)) mode_t sys_umask(mode_t mode) { - return my_syscall1(__NR_umask, mode); + return __nolibc_syscall1(__NR_umask, mode); } static __attribute__((unused)) @@ -847,7 +847,7 @@ mode_t umask(mode_t mode) static __attribute__((unused)) int sys_umount2(const char *path, int flags) { - return my_syscall2(__NR_umount2, path, flags); + return __nolibc_syscall2(__NR_umount2, path, flags); } static __attribute__((unused)) @@ -865,9 +865,9 @@ static __attribute__((unused)) int sys_unlink(const char *path) { #if defined(__NR_unlinkat) - return my_syscall3(__NR_unlinkat, AT_FDCWD, path, 0); + return __nolibc_syscall3(__NR_unlinkat, AT_FDCWD, path, 0); #else - return my_syscall1(__NR_unlink, path); + return __nolibc_syscall1(__NR_unlink, path); #endif } @@ -885,7 +885,7 @@ int unlink(const char *path) static __attribute__((unused)) ssize_t sys_write(int fd, const void *buf, size_t count) { - return my_syscall3(__NR_write, fd, buf, count); + return __nolibc_syscall3(__NR_write, fd, buf, count); } static __attribute__((unused)) @@ -902,7 +902,7 @@ ssize_t write(int fd, const void *buf, size_t count) static __attribute__((unused)) int sys_memfd_create(const char *name, unsigned int flags) { - return my_syscall2(__NR_memfd_create, name, flags); + return __nolibc_syscall2(__NR_memfd_create, name, flags); } static __attribute__((unused)) diff --git a/tools/include/nolibc/sys/ioctl.h b/tools/include/nolibc/sys/ioctl.h index fc880687e02a..289cc1494f2c 100644 --- a/tools/include/nolibc/sys/ioctl.h +++ b/tools/include/nolibc/sys/ioctl.h @@ -21,7 +21,7 @@ static __attribute__((unused)) long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) { - return my_syscall3(__NR_ioctl, fd, cmd, arg); + return __nolibc_syscall3(__NR_ioctl, fd, cmd, arg); } #define ioctl(fd, cmd, arg) __sysret(sys_ioctl(fd, cmd, (unsigned long)(arg))) diff --git a/tools/include/nolibc/sys/mman.h b/tools/include/nolibc/sys/mman.h index 77084ac3405a..5679fdda0a87 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 *)my_syscall6(n, addr, length, prot, flags, fd, offset); + return (void *)__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 *)my_syscall5(__NR_mremap, old_address, old_size, - new_size, flags, new_address); + return (void *)__nolibc_syscall5(__NR_mremap, old_address, old_size, + new_size, flags, new_address); } static __attribute__((unused)) @@ -65,7 +65,7 @@ void *mremap(void *old_address, size_t old_size, size_t new_size, int flags, voi static __attribute__((unused)) int sys_munmap(void *addr, size_t length) { - return my_syscall2(__NR_munmap, addr, length); + return __nolibc_syscall2(__NR_munmap, addr, length); } static __attribute__((unused)) diff --git a/tools/include/nolibc/sys/mount.h b/tools/include/nolibc/sys/mount.h index e39ec02ea24c..1f8d14da276f 100644 --- a/tools/include/nolibc/sys/mount.h +++ b/tools/include/nolibc/sys/mount.h @@ -23,7 +23,7 @@ static __attribute__((unused)) int sys_mount(const char *src, const char *tgt, const char *fst, unsigned long flags, const void *data) { - return my_syscall5(__NR_mount, src, tgt, fst, flags, data); + return __nolibc_syscall5(__NR_mount, src, tgt, fst, flags, data); } static __attribute__((unused)) diff --git a/tools/include/nolibc/sys/prctl.h b/tools/include/nolibc/sys/prctl.h index 0205907b6ac8..b019b4618328 100644 --- a/tools/include/nolibc/sys/prctl.h +++ b/tools/include/nolibc/sys/prctl.h @@ -23,7 +23,7 @@ static __attribute__((unused)) int sys_prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) { - return my_syscall5(__NR_prctl, option, arg2, arg3, arg4, arg5); + return __nolibc_syscall5(__NR_prctl, option, arg2, arg3, arg4, arg5); } static __attribute__((unused)) diff --git a/tools/include/nolibc/sys/ptrace.h b/tools/include/nolibc/sys/ptrace.h index 72ca28541633..6cde77e93ceb 100644 --- a/tools/include/nolibc/sys/ptrace.h +++ b/tools/include/nolibc/sys/ptrace.h @@ -21,7 +21,7 @@ static __attribute__((unused)) long sys_ptrace(int op, pid_t pid, void *addr, void *data) { - return my_syscall4(__NR_ptrace, op, pid, addr, data); + return __nolibc_syscall4(__NR_ptrace, op, pid, addr, data); } static __attribute__((unused)) diff --git a/tools/include/nolibc/sys/random.h b/tools/include/nolibc/sys/random.h index cd5d25c571a8..af9a270fc29d 100644 --- a/tools/include/nolibc/sys/random.h +++ b/tools/include/nolibc/sys/random.h @@ -22,7 +22,7 @@ static __attribute__((unused)) ssize_t sys_getrandom(void *buf, size_t buflen, unsigned int flags) { - return my_syscall3(__NR_getrandom, buf, buflen, flags); + return __nolibc_syscall3(__NR_getrandom, buf, buflen, flags); } static __attribute__((unused)) diff --git a/tools/include/nolibc/sys/reboot.h b/tools/include/nolibc/sys/reboot.h index 38274c64a722..20431025ccc6 100644 --- a/tools/include/nolibc/sys/reboot.h +++ b/tools/include/nolibc/sys/reboot.h @@ -22,7 +22,7 @@ static __attribute__((unused)) ssize_t sys_reboot(int magic1, int magic2, int cmd, void *arg) { - return my_syscall4(__NR_reboot, magic1, magic2, cmd, arg); + return __nolibc_syscall4(__NR_reboot, magic1, magic2, cmd, arg); } static __attribute__((unused)) diff --git a/tools/include/nolibc/sys/resource.h b/tools/include/nolibc/sys/resource.h index b990f914dc56..ff3c65f5fade 100644 --- a/tools/include/nolibc/sys/resource.h +++ b/tools/include/nolibc/sys/resource.h @@ -23,7 +23,7 @@ static __attribute__((unused)) int sys_prlimit64(pid_t pid, int resource, const struct rlimit64 *new_limit, struct rlimit64 *old_limit) { - return my_syscall4(__NR_prlimit64, pid, resource, new_limit, old_limit); + return __nolibc_syscall4(__NR_prlimit64, pid, resource, new_limit, old_limit); } static __attribute__((unused)) diff --git a/tools/include/nolibc/sys/select.h b/tools/include/nolibc/sys/select.h index 80cb3755ba18..fcbcf4d0f8d1 100644 --- a/tools/include/nolibc/sys/select.h +++ b/tools/include/nolibc/sys/select.h @@ -70,7 +70,8 @@ int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeva t.tv_sec = timeout->tv_sec; t.tv_nsec = (uint32_t)timeout->tv_usec * 1000; } - return my_syscall6(__NR_pselect6_time64, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL); + return __nolibc_syscall6(__NR_pselect6_time64, nfds, rfds, wfds, efds, + timeout ? &t : NULL, NULL); #else struct __kernel_old_timespec t; @@ -78,7 +79,8 @@ int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeva t.tv_sec = timeout->tv_sec; t.tv_nsec = (uint32_t)timeout->tv_usec * 1000; } - return my_syscall6(__NR_pselect6, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL); + return __nolibc_syscall6(__NR_pselect6, nfds, rfds, wfds, efds, + timeout ? &t : NULL, NULL); #endif } diff --git a/tools/include/nolibc/sys/stat.h b/tools/include/nolibc/sys/stat.h index 8b4d80e3ea03..2777217793db 100644 --- a/tools/include/nolibc/sys/stat.h +++ b/tools/include/nolibc/sys/stat.h @@ -26,7 +26,7 @@ static __attribute__((unused)) int sys_statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf) { #ifdef __NR_statx - return my_syscall5(__NR_statx, fd, path, flags, mask, buf); + return __nolibc_syscall5(__NR_statx, fd, path, flags, mask, buf); #else return __nolibc_enosys(__func__, fd, path, flags, mask, buf); #endif diff --git a/tools/include/nolibc/sys/syscall.h b/tools/include/nolibc/sys/syscall.h index 4bf97f1386a0..8cbcae4a32aa 100644 --- a/tools/include/nolibc/sys/syscall.h +++ b/tools/include/nolibc/sys/syscall.h @@ -12,7 +12,7 @@ #define __syscall_narg(_0, _1, _2, _3, _4, _5, _6, N, ...) N #define _syscall_narg(...) __syscall_narg(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) -#define _syscall(N, ...) __sysret(my_syscall##N(__VA_ARGS__)) +#define _syscall(N, ...) __sysret(__nolibc_syscall##N(__VA_ARGS__)) #define _syscall_n(N, ...) _syscall(N, __VA_ARGS__) #define syscall(...) _syscall_n(_syscall_narg(__VA_ARGS__), ##__VA_ARGS__) diff --git a/tools/include/nolibc/sys/timerfd.h b/tools/include/nolibc/sys/timerfd.h index 29fd92bd47d2..87f89c789b3b 100644 --- a/tools/include/nolibc/sys/timerfd.h +++ b/tools/include/nolibc/sys/timerfd.h @@ -19,7 +19,7 @@ static __attribute__((unused)) int sys_timerfd_create(int clockid, int flags) { - return my_syscall2(__NR_timerfd_create, clockid, flags); + return __nolibc_syscall2(__NR_timerfd_create, clockid, flags); } static __attribute__((unused)) @@ -34,10 +34,10 @@ int sys_timerfd_gettime(int fd, struct itimerspec *curr_value) { #if defined(__NR_timerfd_gettime64) __nolibc_assert_time64_type(curr_value->it_value.tv_sec); - return my_syscall2(__NR_timerfd_gettime64, fd, curr_value); + return __nolibc_syscall2(__NR_timerfd_gettime64, fd, curr_value); #else __nolibc_assert_native_time64(); - return my_syscall2(__NR_timerfd_gettime, fd, curr_value); + return __nolibc_syscall2(__NR_timerfd_gettime, fd, curr_value); #endif } @@ -54,10 +54,10 @@ int sys_timerfd_settime(int fd, int flags, { #if defined(__NR_timerfd_settime64) __nolibc_assert_time64_type(new_value->it_value.tv_sec); - return my_syscall4(__NR_timerfd_settime64, fd, flags, new_value, old_value); + return __nolibc_syscall4(__NR_timerfd_settime64, fd, flags, new_value, old_value); #else __nolibc_assert_native_time64(); - return my_syscall4(__NR_timerfd_settime, fd, flags, new_value, old_value); + return __nolibc_syscall4(__NR_timerfd_settime, fd, flags, new_value, old_value); #endif } diff --git a/tools/include/nolibc/sys/uio.h b/tools/include/nolibc/sys/uio.h index 7ad42b927d2f..21ff8c626dfe 100644 --- a/tools/include/nolibc/sys/uio.h +++ b/tools/include/nolibc/sys/uio.h @@ -21,7 +21,7 @@ static __attribute__((unused)) ssize_t sys_readv(int fd, const struct iovec *iovec, int count) { - return my_syscall3(__NR_readv, fd, iovec, count); + return __nolibc_syscall3(__NR_readv, fd, iovec, count); } static __attribute__((unused)) @@ -36,7 +36,7 @@ ssize_t readv(int fd, const struct iovec *iovec, int count) static __attribute__((unused)) ssize_t sys_writev(int fd, const struct iovec *iovec, int count) { - return my_syscall3(__NR_writev, fd, iovec, count); + return __nolibc_syscall3(__NR_writev, fd, iovec, count); } static __attribute__((unused)) diff --git a/tools/include/nolibc/sys/utsname.h b/tools/include/nolibc/sys/utsname.h index 01023e1bb439..25992d644525 100644 --- a/tools/include/nolibc/sys/utsname.h +++ b/tools/include/nolibc/sys/utsname.h @@ -30,7 +30,7 @@ struct utsname { static __attribute__((unused)) int sys_uname(struct utsname *buf) { - return my_syscall1(__NR_uname, buf); + return __nolibc_syscall1(__NR_uname, buf); } static __attribute__((unused)) diff --git a/tools/include/nolibc/sys/wait.h b/tools/include/nolibc/sys/wait.h index 9d9319ba92cb..bc11100e7f82 100644 --- a/tools/include/nolibc/sys/wait.h +++ b/tools/include/nolibc/sys/wait.h @@ -23,7 +23,7 @@ static __attribute__((unused)) int sys_waitid(int which, pid_t pid, siginfo_t *infop, int options, struct rusage *rusage) { - return my_syscall5(__NR_waitid, which, pid, infop, options, rusage); + return __nolibc_syscall5(__NR_waitid, which, pid, infop, options, rusage); } static __attribute__((unused)) diff --git a/tools/include/nolibc/time.h b/tools/include/nolibc/time.h index f9257d6a7878..4d93d5188cec 100644 --- a/tools/include/nolibc/time.h +++ b/tools/include/nolibc/time.h @@ -37,10 +37,10 @@ int sys_clock_getres(clockid_t clockid, struct timespec *res) { #if defined(__NR_clock_getres_time64) __nolibc_assert_time64_type(res->tv_sec); - return my_syscall2(__NR_clock_getres_time64, clockid, res); + return __nolibc_syscall2(__NR_clock_getres_time64, clockid, res); #else __nolibc_assert_native_time64(); - return my_syscall2(__NR_clock_getres, clockid, res); + return __nolibc_syscall2(__NR_clock_getres, clockid, res); #endif } @@ -55,10 +55,10 @@ int sys_clock_gettime(clockid_t clockid, struct timespec *tp) { #if defined(__NR_clock_gettime64) __nolibc_assert_time64_type(tp->tv_sec); - return my_syscall2(__NR_clock_gettime64, clockid, tp); + return __nolibc_syscall2(__NR_clock_gettime64, clockid, tp); #else __nolibc_assert_native_time64(); - return my_syscall2(__NR_clock_gettime, clockid, tp); + return __nolibc_syscall2(__NR_clock_gettime, clockid, tp); #endif } @@ -73,10 +73,10 @@ int sys_clock_settime(clockid_t clockid, struct timespec *tp) { #if defined(__NR_clock_settime64) __nolibc_assert_time64_type(tp->tv_sec); - return my_syscall2(__NR_clock_settime64, clockid, tp); + return __nolibc_syscall2(__NR_clock_settime64, clockid, tp); #else __nolibc_assert_native_time64(); - return my_syscall2(__NR_clock_settime, clockid, tp); + return __nolibc_syscall2(__NR_clock_settime, clockid, tp); #endif } @@ -92,10 +92,10 @@ int sys_clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqt { #if defined(__NR_clock_nanosleep_time64) __nolibc_assert_time64_type(rqtp->tv_sec); - return my_syscall4(__NR_clock_nanosleep_time64, clockid, flags, rqtp, rmtp); + return __nolibc_syscall4(__NR_clock_nanosleep_time64, clockid, flags, rqtp, rmtp); #else __nolibc_assert_native_time64(); - return my_syscall4(__NR_clock_nanosleep, clockid, flags, rqtp, rmtp); + return __nolibc_syscall4(__NR_clock_nanosleep, clockid, flags, rqtp, rmtp); #endif } @@ -143,7 +143,7 @@ time_t time(time_t *tptr) static __attribute__((unused)) int sys_timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) { - return my_syscall3(__NR_timer_create, clockid, evp, timerid); + return __nolibc_syscall3(__NR_timer_create, clockid, evp, timerid); } static __attribute__((unused)) @@ -155,7 +155,7 @@ int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) static __attribute__((unused)) int sys_timer_delete(timer_t timerid) { - return my_syscall1(__NR_timer_delete, timerid); + return __nolibc_syscall1(__NR_timer_delete, timerid); } static __attribute__((unused)) @@ -169,10 +169,10 @@ int sys_timer_gettime(timer_t timerid, struct itimerspec *curr_value) { #if defined(__NR_timer_gettime64) __nolibc_assert_time64_type(curr_value->it_value.tv_sec); - return my_syscall2(__NR_timer_gettime64, timerid, curr_value); + return __nolibc_syscall2(__NR_timer_gettime64, timerid, curr_value); #else __nolibc_assert_native_time64(); - return my_syscall2(__NR_timer_gettime, timerid, curr_value); + return __nolibc_syscall2(__NR_timer_gettime, timerid, curr_value); #endif } @@ -188,10 +188,10 @@ int sys_timer_settime(timer_t timerid, int flags, { #if defined(__NR_timer_settime64) __nolibc_assert_time64_type(new_value->it_value.tv_sec); - return my_syscall4(__NR_timer_settime64, timerid, flags, new_value, old_value); + return __nolibc_syscall4(__NR_timer_settime64, timerid, flags, new_value, old_value); #else __nolibc_assert_native_time64(); - return my_syscall4(__NR_timer_settime, timerid, flags, new_value, old_value); + return __nolibc_syscall4(__NR_timer_settime, timerid, flags, new_value, old_value); #endif } diff --git a/tools/include/nolibc/unistd.h b/tools/include/nolibc/unistd.h index bb5e80f3f05d..6456d60daa02 100644 --- a/tools/include/nolibc/unistd.h +++ b/tools/include/nolibc/unistd.h @@ -33,7 +33,7 @@ static __attribute__((unused)) int sys_faccessat(int fd, const char *path, int amode, int flag) { - return my_syscall4(__NR_faccessat, fd, path, amode, flag); + return __nolibc_syscall4(__NR_faccessat, fd, path, amode, flag); } static __attribute__((unused)) From 8ba600aa577f73cc551747fdf121afc7d04afcea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 18 Mar 2026 18:00:33 +0100 Subject: [PATCH 02/61] selftests/nolibc: fix test_file_stream() on musl libc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fwrite() modifying errno is non-standard. Only validate this behavior on those libc implementations which implement it. Fixes: a5f00be9b3b0 ("tools/nolibc: Add a simple test for writing to a FILE and reading it back") Signed-off-by: Thomas Weißschuh --- tools/testing/selftests/nolibc/nolibc-test.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 1b9d3b2e2491..1aca8468eac4 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -74,6 +74,14 @@ static const int is_nolibc = #endif ; +static const int is_glibc = +#ifdef __GLIBC__ + 1 +#else + 0 +#endif +; + /* definition of a series of tests */ struct test { const char *name; /* test name */ @@ -866,7 +874,7 @@ int test_file_stream(void) errno = 0; r = fwrite("foo", 1, 3, f); - if (r != 0 || errno != EBADF) { + if (r != 0 || ((is_nolibc || is_glibc) && errno != EBADF)) { fclose(f); return -1; } From 27532c645e61da541173d43fbe03d234f68232f9 Mon Sep 17 00:00:00 2001 From: David Laight Date: Mon, 23 Feb 2026 10:17:21 +0000 Subject: [PATCH 03/61] selftests/nolibc: Fix build with host headers and libc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Many systems don't have strlcpy() or strlcat() and readdir_r() is deprecated. This makes the tests fail to build with the host headers. Disable the 'directories' test and define strlcpy(), strlcat() and readdir_r() using #defines so that the code compiles. Fixes: 6fe8360b16acb ("selftests/nolibc: also test libc-test through regular selftest framework") Signed-off-by: David Laight Link: https://patch.msgid.link/20260223101735.2922-4-david.laight.linux@gmail.com Signed-off-by: Thomas Weißschuh --- tools/testing/selftests/nolibc/nolibc-test.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 1aca8468eac4..801b2ad18853 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -82,6 +82,20 @@ static const int is_glibc = #endif ; +#if !defined(NOLIBC) +/* Some disabled tests may not compile. */ + +/* strlcat() and strlcpy() may not be in the system headers. */ +#undef strlcat +#undef strlcpy +#define strlcat(d, s, l) 0 +#define strlcpy(d, s, l) 0 + +/* readdir_r() is likely to be marked deprecated */ +#undef readdir_r +#define readdir_r(dir, dirent, result) ((errno = EINVAL), -1) +#endif + /* definition of a series of tests */ struct test { const char *name; /* test name */ @@ -1416,7 +1430,7 @@ int run_syscall(int min, int max) CASE_TEST(fork); EXPECT_SYSZR(1, test_fork(FORK_STANDARD)); break; CASE_TEST(getdents64_root); EXPECT_SYSNE(1, test_getdents64("/"), -1); break; CASE_TEST(getdents64_null); EXPECT_SYSER(1, test_getdents64("/dev/null"), -1, ENOTDIR); break; - CASE_TEST(directories); EXPECT_SYSZR(proc, test_dirent()); break; + CASE_TEST(directories); EXPECT_SYSZR(is_nolibc && proc, test_dirent()); break; CASE_TEST(getrandom); EXPECT_SYSZR(1, test_getrandom()); break; CASE_TEST(gettimeofday_tv); EXPECT_SYSZR(1, gettimeofday(&tv, NULL)); break; CASE_TEST(gettimeofday_tv_tz);EXPECT_SYSZR(1, gettimeofday(&tv, &tz)); break; From 35908c5a1703052d1fe63da42c8115252a38e141 Mon Sep 17 00:00:00 2001 From: David Laight Date: Mon, 23 Feb 2026 10:17:20 +0000 Subject: [PATCH 04/61] tools/nolibc: Optimise and common up the number to ascii functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement u[64]to[ah]_r() using a common function that uses multiply by reciprocal to generate the least significant digit first and then reverses the string. On 32bit this is five multiplies (with 64bit product) for each output digit. I think the old utoa_r() always did 36 multiplies and a lot of subtracts - so this is likely faster even for 32bit values. Definitely better for 64bit values (especially small ones). Clearly shifts are faster for base 16, but reversing the output buffer makes a big difference. Sharing the code reduces the footprint (unless gcc decides to constant fold the functions). Definitely helps vfprintf() where the constants get loaded and a single call is done. Also makes it cheap to add octal support to vfprintf for completeness. Signed-off-by: David Laight Link: https://patch.msgid.link/20260223101735.2922-3-david.laight.linux@gmail.com Acked-by: Willy Tarreau [Thomas: skip int128 multiplication on SPARC and clang] Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/stdlib.h | 173 +++++++++++++++++----------------- 1 file changed, 84 insertions(+), 89 deletions(-) diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h index f184e108ed0a..73b6a771a9f4 100644 --- a/tools/include/nolibc/stdlib.h +++ b/tools/include/nolibc/stdlib.h @@ -188,34 +188,89 @@ void *realloc(void *old_ptr, size_t new_size) return ret; } +/* Converts the unsigned 64bit integer to base ascii into + * buffer , which must be long enough to store the number and the + * trailing zero. The buffer is filled from the first byte, and the number + * of characters emitted (not counting the trailing zero) is returned. + * The function uses 'multiply by reciprocal' for the divisions and + * requires the caller pass the correct reciprocal. + * + * Note that unlike __div64_const32() in asm-generic/div64.h there isn't + * an extra shift done (by ___p), the reciprocal has to be lower resulting + * in a slightly low quotient. + * Keep things simple by correcting for the error. + * This also saves calculating the 'low * low' product (e2 below) which is + * very unlikely to be significant. + * + * Some maths: + * recip = p2 / base - e1; // With e1 < base. + * q = (recip * in - e2) / p2; // With e2 < p2. + * = base / in - (e1 * in + e2) / p2; + * > base / in - (e1 * p2 + p2) / p2; + * = base / in - ((e1 + 1) * p2) / p2; + * > base / in - base; + * So the maximum error is less than 'base'. + * Hence the largest possible digit is '2 * base - 1'. + * For base 10 e1 is 6 and you can get digits of 15 (eg from 2**64-1). + * Error e1 is largest for a base that is a factor of 2**64+1, the smallest is 274177 + * and converting 2**42-1 in base 274177 does generate a digit of 274177+274175. + * This all means only a single correction is needed rather than a loop. + * + * __int128 isn't used for mips because gcc prior to 10.0 will call + * __multi3 for MIPS64r6. The same also happens for SPARC and clang. + */ +#define _NOLIBC_U64TOA_RECIP(base) ((base) & 1 ? ~0ull / (base) : (1ull << 63) / ((base) / 2)) +static __attribute__((unused, noinline)) +int _nolibc_u64toa_base(uint64_t in, char *buffer, unsigned int base, uint64_t recip) +{ + unsigned int digits = 0; + unsigned int dig; + uint64_t q; + char *p; + + /* Generate least significant digit first */ + do { +#if defined(__SIZEOF_INT128__) && !defined(__mips__) && !defined(__sparc__) + q = ((unsigned __int128)in * recip) >> 64; +#else + uint64_t p = (uint32_t)in * (recip >> 32); + q = (in >> 32) * (recip >> 32) + (p >> 32); + p = (uint32_t)p + (in >> 32) * (uint32_t)recip; + q += p >> 32; +#endif + dig = in - q * base; + /* Correct for any rounding errors */ + if (dig >= base) { + dig -= base; + q++; + } + if (dig > 9) + dig += 'a' - '0' - 10; + buffer[digits++] = '0' + dig; + } while ((in = q)); + + buffer[digits] = 0; + + /* Order reverse to result */ + for (p = buffer + digits - 1; p > buffer; buffer++, p--) { + dig = *buffer; + *buffer = *p; + *p = dig; + } + + return digits; +} + /* Converts the unsigned long integer to its hex representation into * buffer , which must be long enough to store the number and the * trailing zero (17 bytes for "ffffffffffffffff" or 9 for "ffffffff"). The * buffer is filled from the first byte, and the number of characters emitted - * (not counting the trailing zero) is returned. The function is constructed - * in a way to optimize the code size and avoid any divide that could add a - * dependency on large external functions. + * (not counting the trailing zero) is returned. */ -static __attribute__((unused)) +static __inline__ __attribute__((unused)) int utoh_r(unsigned long in, char *buffer) { - signed char pos = (~0UL > 0xfffffffful) ? 60 : 28; - int digits = 0; - int dig; - - do { - dig = in >> pos; - in -= (uint64_t)dig << pos; - pos -= 4; - if (dig || digits || pos < 0) { - if (dig > 9) - dig += 'a' - '0' - 10; - buffer[digits++] = '0' + dig; - } - } while (pos >= 0); - - buffer[digits] = 0; - return digits; + return _nolibc_u64toa_base(in, buffer, 16, _NOLIBC_U64TOA_RECIP(16)); } /* converts unsigned long to an hex string using the static itoa_buffer @@ -233,30 +288,11 @@ char *utoh(unsigned long in) * trailing zero (21 bytes for 18446744073709551615 in 64-bit, 11 for * 4294967295 in 32-bit). The buffer is filled from the first byte, and the * number of characters emitted (not counting the trailing zero) is returned. - * The function is constructed in a way to optimize the code size and avoid - * any divide that could add a dependency on large external functions. */ -static __attribute__((unused)) +static __inline__ __attribute__((unused)) int utoa_r(unsigned long in, char *buffer) { - unsigned long lim; - int digits = 0; - int pos = (~0UL > 0xfffffffful) ? 19 : 9; - int dig; - - do { - for (dig = 0, lim = 1; dig < pos; dig++) - lim *= 10; - - if (digits || in >= lim || !pos) { - for (dig = 0; in >= lim; dig++) - in -= lim; - buffer[digits++] = '0' + dig; - } - } while (pos--); - - buffer[digits] = 0; - return digits; + return _nolibc_u64toa_base(in, buffer, 10, _NOLIBC_U64TOA_RECIP(10)); } /* Converts the signed long integer to its string representation into @@ -324,34 +360,12 @@ char *utoa(unsigned long in) * buffer , which must be long enough to store the number and the * trailing zero (17 bytes for "ffffffffffffffff"). The buffer is filled from * the first byte, and the number of characters emitted (not counting the - * trailing zero) is returned. The function is constructed in a way to optimize - * the code size and avoid any divide that could add a dependency on large - * external functions. + * trailing zero) is returned. */ -static __attribute__((unused)) +static __inline__ __attribute__((unused)) int u64toh_r(uint64_t in, char *buffer) { - signed char pos = 60; - int digits = 0; - int dig; - - do { - if (sizeof(long) >= 8) { - dig = (in >> pos) & 0xF; - } else { - /* 32-bit platforms: avoid a 64-bit shift */ - uint32_t d = (pos >= 32) ? (in >> 32) : in; - dig = (d >> (pos & 31)) & 0xF; - } - if (dig > 9) - dig += 'a' - '0' - 10; - pos -= 4; - if (dig || digits || pos < 0) - buffer[digits++] = '0' + dig; - } while (pos >= 0); - - buffer[digits] = 0; - return digits; + return _nolibc_u64toa_base(in, buffer, 16, _NOLIBC_U64TOA_RECIP(16)); } /* converts uint64_t to an hex string using the static itoa_buffer and @@ -368,31 +382,12 @@ char *u64toh(uint64_t in) * buffer , which must be long enough to store the number and the * trailing zero (21 bytes for 18446744073709551615). The buffer is filled from * the first byte, and the number of characters emitted (not counting the - * trailing zero) is returned. The function is constructed in a way to optimize - * the code size and avoid any divide that could add a dependency on large - * external functions. + * trailing zero) is returned. */ -static __attribute__((unused)) +static __inline__ __attribute__((unused)) int u64toa_r(uint64_t in, char *buffer) { - unsigned long long lim; - int digits = 0; - int pos = 19; /* start with the highest possible digit */ - int dig; - - do { - for (dig = 0, lim = 1; dig < pos; dig++) - lim *= 10; - - if (digits || in >= lim || !pos) { - for (dig = 0; in >= lim; dig++) - in -= lim; - buffer[digits++] = '0' + dig; - } - } while (pos--); - - buffer[digits] = 0; - return digits; + return _nolibc_u64toa_base(in, buffer, 10, _NOLIBC_U64TOA_RECIP(10)); } /* Converts the signed 64-bit integer to its string representation into From f675ae28fcdf7db93a8c1a6964f062725b1e06a0 Mon Sep 17 00:00:00 2001 From: David Laight Date: Mon, 23 Feb 2026 10:17:24 +0000 Subject: [PATCH 05/61] tools/nolibc/printf: Change variables 'c' to 'ch' and 'tmpbuf[]' to 'outbuf[]' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changing 'c' makes the code slightly easier to read because the variable stands out from the single character literals (especially 'c'). Change tmpbuf[] to outbuf[] because 'out' points into it. The following patches pretty much rewrite the function so the churn is limited. Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260223101735.2922-7-david.laight.linux@gmail.com Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/stdio.h | 38 ++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 233318b0d0f0..77d7669cdb80 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -301,16 +301,16 @@ typedef int (*__nolibc_printf_cb)(intptr_t state, const char *buf, size_t size); static __attribute__((unused, format(printf, 4, 0))) int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char *fmt, va_list args) { - char escape, lpref, c; + char escape, lpref, ch; unsigned long long v; unsigned int written, width; size_t len, ofs, w; - char tmpbuf[21]; + char outbuf[21]; const char *outstr; written = ofs = escape = lpref = 0; while (1) { - c = fmt[ofs++]; + ch = fmt[ofs++]; width = 0; if (escape) { @@ -318,17 +318,17 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char escape = 0; /* width */ - while (c >= '0' && c <= '9') { + while (ch >= '0' && ch <= '9') { width *= 10; - width += c - '0'; + width += ch - '0'; - c = fmt[ofs++]; + ch = fmt[ofs++]; } - if (c == 'c' || c == 'd' || c == 'u' || c == 'x' || c == 'p') { - char *out = tmpbuf; + if (ch == 'c' || ch == 'd' || ch == 'u' || ch == 'x' || ch == 'p') { + char *out = outbuf; - if (c == 'p') + if (ch == 'p') v = va_arg(args, unsigned long); else if (lpref) { if (lpref > 1) @@ -338,7 +338,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char } else v = va_arg(args, unsigned int); - if (c == 'd') { + if (ch == 'd') { /* sign-extend the value */ if (lpref == 0) v = (long long)(int)v; @@ -346,7 +346,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char v = (long long)(long)v; } - switch (c) { + switch (ch) { case 'c': out[0] = v; out[1] = 0; @@ -365,30 +365,30 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char u64toh_r(v, out); break; } - outstr = tmpbuf; + outstr = outbuf; } - else if (c == 's') { + else if (ch == 's') { outstr = va_arg(args, char *); if (!outstr) outstr="(null)"; } - else if (c == 'm') { + else if (ch == 'm') { #ifdef NOLIBC_IGNORE_ERRNO outstr = "unknown error"; #else outstr = strerror(errno); #endif /* NOLIBC_IGNORE_ERRNO */ } - else if (c == '%') { + else if (ch == '%') { /* queue it verbatim */ continue; } else { /* modifiers or final 0 */ - if (c == 'l') { + if (ch == 'l') { /* long format prefix, maintain the escape */ lpref++; - } else if (c == 'j') { + } else if (ch == 'j') { lpref = 2; } escape = 1; @@ -399,7 +399,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char } /* not an escape sequence */ - if (c == 0 || c == '%') { + if (ch == 0 || ch == '%') { /* flush pending data on escape or end */ escape = 1; lpref = 0; @@ -420,7 +420,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char written += len; do_escape: - if (c == 0) + if (ch == 0) break; fmt += ofs; ofs = 0; From 4045e7b19bbf7338452cda11e64cfe7ae3361964 Mon Sep 17 00:00:00 2001 From: David Laight Date: Mon, 2 Mar 2026 10:17:54 +0000 Subject: [PATCH 06/61] tools/nolibc/printf: Move snprintf length check to callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move output truncation to the snprintf() callback. This simplifies the main code and fixes truncation of padded fields. Add a zero length callback to 'finalise' the buffer rather than doing it in snprintf() itself. Fixes: e90ce42e81381 ("tools/nolibc: implement width padding in printf()") Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260302101815.3043-3-david.laight.linux@gmail.com [Thomas: clean up Fixes trailer] Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/stdio.h | 96 +++++++++++++++++++++++++----------- 1 file changed, 68 insertions(+), 28 deletions(-) diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 77d7669cdb80..a4df72d9a2d3 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -295,16 +295,25 @@ int fseek(FILE *stream, long offset, int whence) * - %[l*]{d,u,c,x,p} * - %s * - unknown modifiers are ignored. + * + * Called by vfprintf() and snprintf() to do the actual formatting. + * The callers provide a callback function to save the formatted data. + * The callback function is called multiple times: + * - for each group of literal characters in the format string. + * - for field padding. + * - for each conversion specifier. + * - with (NULL, 0) at the end of the __nolibc_printf. + * If the callback returns non-zero __nolibc_printf() immediately returns -1. */ -typedef int (*__nolibc_printf_cb)(intptr_t state, const char *buf, size_t size); +typedef int (*__nolibc_printf_cb)(void *state, const char *buf, size_t size); -static __attribute__((unused, format(printf, 4, 0))) -int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char *fmt, va_list args) +static __attribute__((unused, format(printf, 3, 0))) +int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list args) { char escape, lpref, ch; unsigned long long v; unsigned int written, width; - size_t len, ofs, w; + size_t len, ofs; char outbuf[21]; const char *outstr; @@ -406,17 +415,13 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char outstr = fmt; len = ofs - 1; flush_str: - if (n) { - w = len < n ? len : n; - n -= w; - while (width-- > w) { - if (cb(state, " ", 1) != 0) - return -1; - written += 1; - } - if (cb(state, outstr, w) != 0) + while (width-- > len) { + if (cb(state, " ", 1) != 0) return -1; + written += 1; } + if (cb(state, outstr, len) != 0) + return -1; written += len; do_escape: @@ -429,18 +434,25 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char /* literal char, just queue it */ } + + /* Request a final '\0' be added to the snprintf() output. + * This may be the only call of the cb() function. + */ + if (cb(state, NULL, 0) != 0) + return -1; + return written; } -static int __nolibc_fprintf_cb(intptr_t state, const char *buf, size_t size) +static int __nolibc_fprintf_cb(void *stream, const char *buf, size_t size) { - return _fwrite(buf, size, (FILE *)state); + return _fwrite(buf, size, stream); } static __attribute__((unused, format(printf, 2, 0))) int vfprintf(FILE *stream, const char *fmt, va_list args) { - return __nolibc_printf(__nolibc_fprintf_cb, (intptr_t)stream, SIZE_MAX, fmt, args); + return __nolibc_printf(__nolibc_fprintf_cb, stream, fmt, args); } static __attribute__((unused, format(printf, 1, 0))) @@ -498,26 +510,54 @@ int dprintf(int fd, const char *fmt, ...) return ret; } -static int __nolibc_sprintf_cb(intptr_t _state, const char *buf, size_t size) -{ - char **state = (char **)_state; +struct __nolibc_sprintf_cb_state { + char *buf; + size_t space; +}; + +static int __nolibc_sprintf_cb(void *v_state, const char *buf, size_t size) +{ + struct __nolibc_sprintf_cb_state *state = v_state; + size_t space = state->space; + char *tgt; + + /* Truncate the request to fit in the output buffer space. + * The last byte is reserved for the terminating '\0'. + * state->space can only be zero for snprintf(NULL, 0, fmt, args) + * so this normally lets through calls with 'size == 0'. + */ + if (size >= space) { + if (space <= 1) + return 0; + size = space - 1; + } + tgt = state->buf; + + /* __nolibc_printf() ends with cb(state, NULL, 0) to request the output + * buffer be '\0' terminated. + * That will be the only cb() call for, eg, snprintf(buf, sz, ""). + * Zero lengths can occur at other times (eg "%s" for an empty string). + * Unconditionally write the '\0' byte to reduce code size, it is + * normally overwritten by the data being output. + * There is no point adding a '\0' after copied data - there is always + * another call. + */ + *tgt = '\0'; + if (size) { + state->space = space - size; + state->buf = tgt + size; + memcpy(tgt, buf, size); + } - memcpy(*state, buf, size); - *state += size; return 0; } static __attribute__((unused, format(printf, 3, 0))) int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) { - char *state = buf; - int ret; + struct __nolibc_sprintf_cb_state state = { .buf = buf, .space = size }; - ret = __nolibc_printf(__nolibc_sprintf_cb, (intptr_t)&state, size, fmt, args); - if (ret < 0) - return ret; - buf[(size_t)ret < size ? (size_t)ret : size - 1] = '\0'; - return ret; + return __nolibc_printf(__nolibc_sprintf_cb, &state, fmt, args); } static __attribute__((unused, format(printf, 3, 4))) From b42f02da2bf99460a7b1c5c25008f2e4a65ea4e3 Mon Sep 17 00:00:00 2001 From: David Laight Date: Mon, 2 Mar 2026 10:17:55 +0000 Subject: [PATCH 07/61] selftests/nolibc: Return correct value when printf test fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correctly return 1 (the number of errors) when strcmp() fails rather than the return value from strncmp() which is the signed difference between the mismatching characters. Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260302101815.3043-4-david.laight.linux@gmail.com Signed-off-by: Thomas Weißschuh --- tools/testing/selftests/nolibc/nolibc-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 801b2ad18853..7588212df124 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1691,7 +1691,7 @@ static int expect_vfprintf(int llen, int c, const char *expected, const char *fm } llen += printf(" \"%s\" = \"%s\"", expected, buf); - ret = strncmp(expected, buf, c); + ret = strncmp(expected, buf, c) != 0; result(llen, ret ? FAIL : OK); return ret; From 9aa8a4afd4e6407a4d4521c325855c4467a88b73 Mon Sep 17 00:00:00 2001 From: David Laight Date: Mon, 2 Mar 2026 10:17:56 +0000 Subject: [PATCH 08/61] selftests/nolibc: check vsnprintf() output buffer before the length MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check the string matches before checking the returned length. Only print the string once when it matches. Makes it a lot easier to diagnose any incorrect output. Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260302101815.3043-5-david.laight.linux@gmail.com Signed-off-by: Thomas Weißschuh --- tools/testing/selftests/nolibc/nolibc-test.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 7588212df124..bfe793caa963 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1676,25 +1676,27 @@ static int expect_vfprintf(int llen, int c, const char *expected, const char *fm char buf[100]; va_list args; ssize_t w; - int ret; - va_start(args, fmt); /* Only allow writing 21 bytes, to test truncation */ w = vsnprintf(buf, 21, fmt, args); va_end(args); + llen += printf(" \"%s\"", buf); + if (strncmp(expected, buf, c)) { + llen += printf(" should be \"%s\"", expected); + result(llen, FAIL); + return 1; + } + if (w != c) { llen += printf(" written(%d) != %d", (int)w, c); result(llen, FAIL); return 1; } - llen += printf(" \"%s\" = \"%s\"", expected, buf); - ret = strncmp(expected, buf, c) != 0; - - result(llen, ret ? FAIL : OK); - return ret; + result(llen, OK); + return 0; } static int test_scanf(void) From f36e1ec61a6adb135d1b4021bc849c6acb96f50c Mon Sep 17 00:00:00 2001 From: David Laight Date: Mon, 2 Mar 2026 10:17:57 +0000 Subject: [PATCH 09/61] selftests/nolibc: Use length of 'expected' string to check snprintf() output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of requiring the test cases specifying both the length and expected output, take the length from the expected output. Tests that expect the output be truncated are changed to specify the un-truncated output. Change the strncmp() to a memcmp() with an extra check that the output is actually terminated. Append a '+' to the printed output (after the final ") when the output is truncated. Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260302101815.3043-6-david.laight.linux@gmail.com Signed-off-by: Thomas Weißschuh --- tools/testing/selftests/nolibc/nolibc-test.c | 67 ++++++++++++-------- 1 file changed, 41 insertions(+), 26 deletions(-) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index bfe793caa963..154cc5711a4c 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1668,29 +1668,44 @@ int run_stdlib(int min, int max) return ret; } -#define EXPECT_VFPRINTF(c, expected, fmt, ...) \ - ret += expect_vfprintf(llen, c, expected, fmt, ##__VA_ARGS__) +#define EXPECT_VFPRINTF(expected, fmt, ...) \ + ret += expect_vfprintf(llen, expected, fmt, ##__VA_ARGS__) -static int expect_vfprintf(int llen, int c, const char *expected, const char *fmt, ...) +#define VFPRINTF_LEN 20 +static int expect_vfprintf(int llen, const char *expected, const char *fmt, ...) { - char buf[100]; + char buf[VFPRINTF_LEN + 80]; + unsigned int cmp_len; va_list args; - ssize_t w; + ssize_t w, expected_len; va_start(args, fmt); - /* Only allow writing 21 bytes, to test truncation */ - w = vsnprintf(buf, 21, fmt, args); + /* Limit buffer length to test truncation */ + w = vsnprintf(buf, VFPRINTF_LEN + 1, fmt, args); va_end(args); llen += printf(" \"%s\"", buf); - if (strncmp(expected, buf, c)) { - llen += printf(" should be \"%s\"", expected); + + expected_len = strlen(expected); + if (expected_len > VFPRINTF_LEN) { + /* Indicate truncated in test output */ + llen += printf("+"); + cmp_len = VFPRINTF_LEN; + } else { + cmp_len = expected_len; + } + + if (memcmp(expected, buf, cmp_len) || buf[cmp_len]) { + /* Copy and truncate until "%.*s" supported */ + memcpy(buf, expected, cmp_len); + buf[cmp_len] = 0; + llen += printf(" should be \"%s\"", buf); result(llen, FAIL); return 1; } - if (w != c) { - llen += printf(" written(%d) != %d", (int)w, c); + if (w != expected_len) { + llen += printf(" written(%d) != %d", (int)w, (int)expected_len); result(llen, FAIL); return 1; } @@ -1817,21 +1832,21 @@ static int run_printf(int min, int max) * test numbers. */ switch (test + __LINE__ + 1) { - CASE_TEST(empty); EXPECT_VFPRINTF(0, "", ""); break; - CASE_TEST(simple); EXPECT_VFPRINTF(3, "foo", "foo"); break; - CASE_TEST(string); EXPECT_VFPRINTF(3, "foo", "%s", "foo"); break; - CASE_TEST(number); EXPECT_VFPRINTF(4, "1234", "%d", 1234); break; - CASE_TEST(negnumber); EXPECT_VFPRINTF(5, "-1234", "%d", -1234); break; - CASE_TEST(unsigned); EXPECT_VFPRINTF(5, "12345", "%u", 12345); break; - CASE_TEST(char); EXPECT_VFPRINTF(1, "c", "%c", 'c'); break; - CASE_TEST(hex); EXPECT_VFPRINTF(1, "f", "%x", 0xf); break; - CASE_TEST(pointer); EXPECT_VFPRINTF(3, "0x1", "%p", (void *) 0x1); break; - CASE_TEST(uintmax_t); EXPECT_VFPRINTF(20, "18446744073709551615", "%ju", 0xffffffffffffffffULL); break; - CASE_TEST(intmax_t); EXPECT_VFPRINTF(20, "-9223372036854775807", "%jd", 0x8000000000000001LL); break; - CASE_TEST(truncation); EXPECT_VFPRINTF(25, "01234567890123456789", "%s", "0123456789012345678901234"); break; - CASE_TEST(string_width); EXPECT_VFPRINTF(10, " 1", "%10s", "1"); break; - CASE_TEST(number_width); EXPECT_VFPRINTF(10, " 1", "%10d", 1); break; - CASE_TEST(width_trunc); EXPECT_VFPRINTF(25, " ", "%25d", 1); break; + CASE_TEST(empty); EXPECT_VFPRINTF("", ""); break; + CASE_TEST(simple); EXPECT_VFPRINTF("foo", "foo"); break; + CASE_TEST(string); EXPECT_VFPRINTF("foo", "%s", "foo"); break; + CASE_TEST(number); EXPECT_VFPRINTF("1234", "%d", 1234); break; + CASE_TEST(negnumber); EXPECT_VFPRINTF("-1234", "%d", -1234); break; + CASE_TEST(unsigned); EXPECT_VFPRINTF("12345", "%u", 12345); break; + CASE_TEST(char); EXPECT_VFPRINTF("c", "%c", 'c'); break; + CASE_TEST(hex); EXPECT_VFPRINTF("f", "%x", 0xf); break; + CASE_TEST(pointer); EXPECT_VFPRINTF("0x1", "%p", (void *) 0x1); break; + CASE_TEST(uintmax_t); EXPECT_VFPRINTF("18446744073709551615", "%ju", 0xffffffffffffffffULL); break; + CASE_TEST(intmax_t); EXPECT_VFPRINTF("-9223372036854775807", "%jd", 0x8000000000000001LL); break; + CASE_TEST(truncation); EXPECT_VFPRINTF("0123456789012345678901234", "%s", "0123456789012345678901234"); break; + CASE_TEST(string_width); EXPECT_VFPRINTF(" 1", "%10s", "1"); break; + CASE_TEST(number_width); EXPECT_VFPRINTF(" 1", "%10d", 1); break; + CASE_TEST(width_trunc); EXPECT_VFPRINTF(" 1", "%25d", 1); break; CASE_TEST(scanf); EXPECT_ZR(1, test_scanf()); break; CASE_TEST(strerror); EXPECT_ZR(1, test_strerror()); break; CASE_TEST(printf_error); EXPECT_ZR(1, test_printf_error()); break; From 4ea2dedd502e2b4bfa8a47f2aaaaac4eab01e00d Mon Sep 17 00:00:00 2001 From: David Laight Date: Mon, 2 Mar 2026 10:17:58 +0000 Subject: [PATCH 10/61] selftests/nolibc: Check that snprintf() doesn't write beyond the buffer end MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fill buf[] with known data and check the vsnprintf() doesn't write beyond the specified buffer length. Would have picked up the bug in field padding. Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260302101815.3043-7-david.laight.linux@gmail.com Signed-off-by: Thomas Weißschuh --- tools/testing/selftests/nolibc/nolibc-test.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 154cc5711a4c..5dc0edfe8d9a 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1679,6 +1679,10 @@ static int expect_vfprintf(int llen, const char *expected, const char *fmt, ...) va_list args; ssize_t w, expected_len; + /* Fill and terminate buf[] to check for overlong/absent writes */ + memset(buf, 0xa5, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = 0; + va_start(args, fmt); /* Limit buffer length to test truncation */ w = vsnprintf(buf, VFPRINTF_LEN + 1, fmt, args); @@ -1710,6 +1714,15 @@ static int expect_vfprintf(int llen, const char *expected, const char *fmt, ...) return 1; } + /* Check for any overwrites after the actual data. */ + while (++cmp_len < sizeof(buf) - 1) { + if ((unsigned char)buf[cmp_len] != 0xa5) { + llen += printf(" overwrote buf[%d] with 0x%x", cmp_len, buf[cmp_len]); + result(llen, FAIL); + return 1; + } + } + result(llen, OK); return 0; } From cf3470882435c82742ab869d4e2d414de55e7e59 Mon Sep 17 00:00:00 2001 From: David Laight Date: Mon, 2 Mar 2026 10:17:59 +0000 Subject: [PATCH 11/61] selftests/nolibc: Let EXPECT_VFPRINTF() tests be skipped MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tests that check explicit nolibc behavior (eg "%m") or test places where the nolibc behaviour deviates from the libc need skipping when compiled to use the host libc. Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260302101815.3043-8-david.laight.linux@gmail.com Signed-off-by: Thomas Weißschuh --- tools/testing/selftests/nolibc/nolibc-test.c | 34 ++++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 5dc0edfe8d9a..5e7b5c8ec13b 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1668,8 +1668,8 @@ int run_stdlib(int min, int max) return ret; } -#define EXPECT_VFPRINTF(expected, fmt, ...) \ - ret += expect_vfprintf(llen, expected, fmt, ##__VA_ARGS__) +#define EXPECT_VFPRINTF(cond, expected, fmt, ...) \ + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_vfprintf(llen, expected, fmt, ##__VA_ARGS__); } while (0) #define VFPRINTF_LEN 20 static int expect_vfprintf(int llen, const char *expected, const char *fmt, ...) @@ -1845,21 +1845,21 @@ static int run_printf(int min, int max) * test numbers. */ switch (test + __LINE__ + 1) { - CASE_TEST(empty); EXPECT_VFPRINTF("", ""); break; - CASE_TEST(simple); EXPECT_VFPRINTF("foo", "foo"); break; - CASE_TEST(string); EXPECT_VFPRINTF("foo", "%s", "foo"); break; - CASE_TEST(number); EXPECT_VFPRINTF("1234", "%d", 1234); break; - CASE_TEST(negnumber); EXPECT_VFPRINTF("-1234", "%d", -1234); break; - CASE_TEST(unsigned); EXPECT_VFPRINTF("12345", "%u", 12345); break; - CASE_TEST(char); EXPECT_VFPRINTF("c", "%c", 'c'); break; - CASE_TEST(hex); EXPECT_VFPRINTF("f", "%x", 0xf); break; - CASE_TEST(pointer); EXPECT_VFPRINTF("0x1", "%p", (void *) 0x1); break; - CASE_TEST(uintmax_t); EXPECT_VFPRINTF("18446744073709551615", "%ju", 0xffffffffffffffffULL); break; - CASE_TEST(intmax_t); EXPECT_VFPRINTF("-9223372036854775807", "%jd", 0x8000000000000001LL); break; - CASE_TEST(truncation); EXPECT_VFPRINTF("0123456789012345678901234", "%s", "0123456789012345678901234"); break; - CASE_TEST(string_width); EXPECT_VFPRINTF(" 1", "%10s", "1"); break; - CASE_TEST(number_width); EXPECT_VFPRINTF(" 1", "%10d", 1); break; - CASE_TEST(width_trunc); EXPECT_VFPRINTF(" 1", "%25d", 1); break; + CASE_TEST(empty); EXPECT_VFPRINTF(1, "", ""); break; + CASE_TEST(simple); EXPECT_VFPRINTF(1, "foo", "foo"); break; + CASE_TEST(string); EXPECT_VFPRINTF(1, "foo", "%s", "foo"); break; + CASE_TEST(number); EXPECT_VFPRINTF(1, "1234", "%d", 1234); break; + CASE_TEST(negnumber); EXPECT_VFPRINTF(1, "-1234", "%d", -1234); break; + CASE_TEST(unsigned); EXPECT_VFPRINTF(1, "12345", "%u", 12345); break; + CASE_TEST(char); EXPECT_VFPRINTF(1, "c", "%c", 'c'); break; + CASE_TEST(hex); EXPECT_VFPRINTF(1, "f", "%x", 0xf); break; + CASE_TEST(pointer); EXPECT_VFPRINTF(1, "0x1", "%p", (void *) 0x1); break; + CASE_TEST(uintmax_t); EXPECT_VFPRINTF(1, "18446744073709551615", "%ju", 0xffffffffffffffffULL); break; + CASE_TEST(intmax_t); EXPECT_VFPRINTF(1, "-9223372036854775807", "%jd", 0x8000000000000001LL); break; + CASE_TEST(truncation); EXPECT_VFPRINTF(1, "0123456789012345678901234", "%s", "0123456789012345678901234"); break; + CASE_TEST(string_width); EXPECT_VFPRINTF(1, " 1", "%10s", "1"); break; + CASE_TEST(number_width); EXPECT_VFPRINTF(1, " 1", "%10d", 1); break; + CASE_TEST(width_trunc); EXPECT_VFPRINTF(1, " 1", "%25d", 1); break; CASE_TEST(scanf); EXPECT_ZR(1, test_scanf()); break; CASE_TEST(strerror); EXPECT_ZR(1, test_strerror()); break; CASE_TEST(printf_error); EXPECT_ZR(1, test_printf_error()); break; From 6702425cd50ebb9a71d6b441df4b0df4f58d160a Mon Sep 17 00:00:00 2001 From: David Laight Date: Sun, 8 Mar 2026 11:37:26 +0000 Subject: [PATCH 12/61] tools/nolibc: Add _NOLIBC_OPTIMIZER_HIDE_VAR() to compiler.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Needed to stop compiler 'optimisations' bloating code. Equivalent to the definition in include/linux/compiler.h Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260308113742.12649-2-david.laight.linux@gmail.com Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/compiler.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/include/nolibc/compiler.h b/tools/include/nolibc/compiler.h index a8c7619dcdde..f03f84cfadce 100644 --- a/tools/include/nolibc/compiler.h +++ b/tools/include/nolibc/compiler.h @@ -71,4 +71,7 @@ # define __nolibc_static_assert(_t) #endif +/* Make the optimizer believe the variable can be manipulated arbitrarily. */ +#define _NOLIBC_OPTIMIZER_HIDE_VAR(var) __asm__ ("" : "+r" (var)) + #endif /* _NOLIBC_COMPILER_H */ From ab7cd329a837711b88600e5d776836f16a0e8de8 Mon Sep 17 00:00:00 2001 From: David Laight Date: Sun, 8 Mar 2026 11:37:27 +0000 Subject: [PATCH 13/61] selftests/nolibc: Rename w to written in expect_vfprintf() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Single character variable names don't make code easy to read. Rename 'w' (used for the return value from snprintf()) 'written'. Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260308113742.12649-3-david.laight.linux@gmail.com Signed-off-by: Thomas Weißschuh --- tools/testing/selftests/nolibc/nolibc-test.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 5e7b5c8ec13b..5c3bf96f57bb 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1677,7 +1677,7 @@ static int expect_vfprintf(int llen, const char *expected, const char *fmt, ...) char buf[VFPRINTF_LEN + 80]; unsigned int cmp_len; va_list args; - ssize_t w, expected_len; + ssize_t written, expected_len; /* Fill and terminate buf[] to check for overlong/absent writes */ memset(buf, 0xa5, sizeof(buf) - 1); @@ -1685,7 +1685,7 @@ static int expect_vfprintf(int llen, const char *expected, const char *fmt, ...) va_start(args, fmt); /* Limit buffer length to test truncation */ - w = vsnprintf(buf, VFPRINTF_LEN + 1, fmt, args); + written = vsnprintf(buf, VFPRINTF_LEN + 1, fmt, args); va_end(args); llen += printf(" \"%s\"", buf); @@ -1708,8 +1708,8 @@ static int expect_vfprintf(int llen, const char *expected, const char *fmt, ...) return 1; } - if (w != expected_len) { - llen += printf(" written(%d) != %d", (int)w, (int)expected_len); + if (written != expected_len) { + llen += printf(" written(%d) != %d", (int)written, (int)expected_len); result(llen, FAIL); return 1; } From 2177dd375d087012907e389f787b21ac38bb1785 Mon Sep 17 00:00:00 2001 From: David Laight Date: Sun, 8 Mar 2026 11:37:28 +0000 Subject: [PATCH 14/61] tools/nolibc: Implement strerror() in terms of strerror_r() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit strerror() can be the only part of a program that has a .data section. This requires 4k in the program file. Add a simple implementation of strerror_r() and use that in strerror() so that the "errno=" string is copied at run-time. Use __builtin_memcpy() because that optimises away the input string and just writes the required constants to the target buffer. Code size change largely depends on whether the inlining decision for strerror() changes. Change the tests to use the normal EXPECT_VFPRINTF() when testing %m. Skip the tests when !is_nolibc. Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260308113742.12649-4-david.laight.linux@gmail.com Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/stdio.h | 22 +++++++++++++++++--- tools/testing/selftests/nolibc/nolibc-test.c | 20 ++---------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index a4df72d9a2d3..b324fc438ea0 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -722,14 +722,30 @@ int setvbuf(FILE *stream __attribute__((unused)), return 0; } +static __attribute__((unused)) +int strerror_r(int errnum, char *buf, size_t buflen) +{ + if (buflen < 18) + return ERANGE; + + __builtin_memcpy(buf, "errno=", 6); + i64toa_r(errnum, buf + 6); + return 0; +} + static __attribute__((unused)) const char *strerror(int errno) { - static char buf[18] = "errno="; + static char buf[18]; + char *b = buf; - i64toa_r(errno, &buf[6]); + /* Force gcc to use 'register offset' to access buf[]. */ + _NOLIBC_OPTIMIZER_HIDE_VAR(b); - return buf; + /* Use strerror_r() to avoid having the only .data in small programs. */ + strerror_r(errno, b, sizeof(buf)); + + return b; } #endif /* _NOLIBC_STDIO_H */ diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 5c3bf96f57bb..d8949aa1dee3 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1794,23 +1794,6 @@ static int test_scanf(void) return 0; } -int test_strerror(void) -{ - char buf[100]; - ssize_t ret; - - memset(buf, 'A', sizeof(buf)); - - errno = EINVAL; - ret = snprintf(buf, sizeof(buf), "%m"); - if (is_nolibc) { - if (ret < 6 || memcmp(buf, "errno=", 6)) - return 1; - } - - return 0; -} - static int test_printf_error(void) { int fd, ret, saved_errno; @@ -1860,8 +1843,9 @@ static int run_printf(int min, int max) CASE_TEST(string_width); EXPECT_VFPRINTF(1, " 1", "%10s", "1"); break; CASE_TEST(number_width); EXPECT_VFPRINTF(1, " 1", "%10d", 1); break; CASE_TEST(width_trunc); EXPECT_VFPRINTF(1, " 1", "%25d", 1); break; + CASE_TEST(errno); errno = 22; EXPECT_VFPRINTF(is_nolibc, "errno=22", "%m"); break; + CASE_TEST(errno-neg); errno = -22; EXPECT_VFPRINTF(is_nolibc, " errno=-22", "%12m"); break; CASE_TEST(scanf); EXPECT_ZR(1, test_scanf()); break; - CASE_TEST(strerror); EXPECT_ZR(1, test_strerror()); break; CASE_TEST(printf_error); EXPECT_ZR(1, test_printf_error()); break; case __LINE__: return ret; /* must be last */ From c0a08eb87f60daec1c1549c067945abfee711f86 Mon Sep 17 00:00:00 2001 From: David Laight Date: Sun, 8 Mar 2026 11:37:29 +0000 Subject: [PATCH 15/61] tools/nolibc: Rename the 'errnum' parameter to strerror() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change the parameter variable name from 'errno' to 'errnum'. Matches any documentation and avoids any issues that might happen if errno is actually a #define (which is not uncommon). Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260308113742.12649-5-david.laight.linux@gmail.com Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/stdio.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index b324fc438ea0..985e7f0834bf 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -734,7 +734,7 @@ int strerror_r(int errnum, char *buf, size_t buflen) } static __attribute__((unused)) -const char *strerror(int errno) +const char *strerror(int errnum) { static char buf[18]; char *b = buf; @@ -743,7 +743,7 @@ const char *strerror(int errno) _NOLIBC_OPTIMIZER_HIDE_VAR(b); /* Use strerror_r() to avoid having the only .data in small programs. */ - strerror_r(errno, b, sizeof(buf)); + strerror_r(errnum, b, sizeof(buf)); return b; } From a2fa5a752ce67c11a9d6d6535165195073ce0c46 Mon Sep 17 00:00:00 2001 From: David Laight Date: Sun, 8 Mar 2026 11:37:30 +0000 Subject: [PATCH 16/61] tools/nolibc/printf: Output pad characters in 16 byte chunks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simple to do and saves calls to the callback function. Change variables written, width and len to 'signed int' to get better code. Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260308113742.12649-6-david.laight.linux@gmail.com Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/stdio.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 985e7f0834bf..bdecc703511c 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -312,8 +312,8 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list { char escape, lpref, ch; unsigned long long v; - unsigned int written, width; - size_t len, ofs; + int written, width, len; + size_t ofs; char outbuf[21]; const char *outstr; @@ -415,10 +415,14 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list outstr = fmt; len = ofs - 1; flush_str: - while (width-- > len) { - if (cb(state, " ", 1) != 0) + width -= len; + while (width > 0) { + /* Output pad in 16 byte blocks with the small block first. */ + int pad_len = ((width - 1) & 15) + 1; + width -= pad_len; + written += pad_len; + if (cb(state, " ", pad_len) != 0) return -1; - written += 1; } if (cb(state, outstr, len) != 0) return -1; From b3d30efd052360c11abe1259a15dfcf2448b37be Mon Sep 17 00:00:00 2001 From: David Laight Date: Sun, 8 Mar 2026 11:37:31 +0000 Subject: [PATCH 17/61] tools/nolibc/printf: Simplify __nolibc_printf() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the check for the length modifiers into the format processing between the field width and conversion specifier. This lets the loop be simplified and a 'fast scan' for a format start used. If an error is detected (eg an invalid conversion specifier) then copy the invalid format to the output buffer. Reduces code size by about 10% on x86-64. Some versions of gcc bloat this version by generating a jump table. All goes away in the later patches. Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260308113742.12649-7-david.laight.linux@gmail.com Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/stdio.h | 106 ++++++++++++++++++----------------- 1 file changed, 54 insertions(+), 52 deletions(-) diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index bdecc703511c..876bb2b2eb73 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -310,28 +310,52 @@ typedef int (*__nolibc_printf_cb)(void *state, const char *buf, size_t size); static __attribute__((unused, format(printf, 3, 0))) int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list args) { - char escape, lpref, ch; + char lpref, ch; unsigned long long v; int written, width, len; - size_t ofs; char outbuf[21]; const char *outstr; - written = ofs = escape = lpref = 0; + written = 0; while (1) { - ch = fmt[ofs++]; - width = 0; + outstr = fmt; + ch = *fmt++; + if (!ch) + break; - if (escape) { - /* we're in an escape sequence, ofs == 1 */ - escape = 0; + width = 0; + if (ch != '%') { + while (*fmt && *fmt != '%') + fmt++; + /* Output characters from the format string. */ + len = fmt - outstr; + } else { + /* we're in a format sequence */ + + ch = *fmt++; /* width */ while (ch >= '0' && ch <= '9') { width *= 10; width += ch - '0'; - ch = fmt[ofs++]; + ch = *fmt++; + } + + /* Length modifiers */ + if (ch == 'l') { + lpref = 1; + ch = *fmt++; + if (ch == 'l') { + lpref = 2; + ch = *fmt++; + } + } else if (ch == 'j') { + /* intmax_t is long long */ + lpref = 2; + ch = *fmt++; + } else { + lpref = 0; } if (ch == 'c' || ch == 'd' || ch == 'u' || ch == 'x' || ch == 'p') { @@ -387,56 +411,34 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list #else outstr = strerror(errno); #endif /* NOLIBC_IGNORE_ERRNO */ - } - else if (ch == '%') { - /* queue it verbatim */ - continue; - } - else { - /* modifiers or final 0 */ - if (ch == 'l') { - /* long format prefix, maintain the escape */ - lpref++; - } else if (ch == 'j') { - lpref = 2; + } else { + if (ch != '%') { + /* Invalid format: back up to output the format characters */ + fmt = outstr + 1; + /* and output a '%' now. */ } - escape = 1; - goto do_escape; + /* %% is documented as a 'conversion specifier'. + * Any flags, precision or length modifier are ignored. + */ + width = 0; + outstr = "%"; } len = strlen(outstr); - goto flush_str; } - /* not an escape sequence */ - if (ch == 0 || ch == '%') { - /* flush pending data on escape or end */ - escape = 1; - lpref = 0; - outstr = fmt; - len = ofs - 1; - flush_str: - width -= len; - while (width > 0) { - /* Output pad in 16 byte blocks with the small block first. */ - int pad_len = ((width - 1) & 15) + 1; - width -= pad_len; - written += pad_len; - if (cb(state, " ", pad_len) != 0) - return -1; - } - if (cb(state, outstr, len) != 0) + written += len; + + width -= len; + while (width > 0) { + /* Output pad in 16 byte blocks with the small block first. */ + int pad_len = ((width - 1) & 15) + 1; + width -= pad_len; + written += pad_len; + if (cb(state, " ", pad_len) != 0) return -1; - - written += len; - do_escape: - if (ch == 0) - break; - fmt += ofs; - ofs = 0; - continue; } - - /* literal char, just queue it */ + if (cb(state, outstr, len) != 0) + return -1; } /* Request a final '\0' be added to the snprintf() output. From c5b9173ce9a110618edcb5bd92c8c724b6edf41f Mon Sep 17 00:00:00 2001 From: David Laight Date: Sun, 8 Mar 2026 11:37:32 +0000 Subject: [PATCH 18/61] tools/nolibc/printf: Use goto and reduce indentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upcoming changes will need to use goto to jump to the code that outputs characters. Use 'goto do_output' to output a known number of characters. Use 'goto do_strlen_output' to output a '\0' terminated string. Removes a level of indentation from the format processing code. The change is best reviewed using 'git diff -b' after applying it. Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260308113742.12649-8-david.laight.linux@gmail.com Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/stdio.h | 205 +++++++++++++++++++---------------- 1 file changed, 110 insertions(+), 95 deletions(-) diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 876bb2b2eb73..0365f48fb049 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -329,103 +329,118 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list fmt++; /* Output characters from the format string. */ len = fmt - outstr; - } else { - /* we're in a format sequence */ - - ch = *fmt++; - - /* width */ - while (ch >= '0' && ch <= '9') { - width *= 10; - width += ch - '0'; - - ch = *fmt++; - } - - /* Length modifiers */ - if (ch == 'l') { - lpref = 1; - ch = *fmt++; - if (ch == 'l') { - lpref = 2; - ch = *fmt++; - } - } else if (ch == 'j') { - /* intmax_t is long long */ - lpref = 2; - ch = *fmt++; - } else { - lpref = 0; - } - - if (ch == 'c' || ch == 'd' || ch == 'u' || ch == 'x' || ch == 'p') { - char *out = outbuf; - - if (ch == 'p') - v = va_arg(args, unsigned long); - else if (lpref) { - if (lpref > 1) - v = va_arg(args, unsigned long long); - else - v = va_arg(args, unsigned long); - } else - v = va_arg(args, unsigned int); - - if (ch == 'd') { - /* sign-extend the value */ - if (lpref == 0) - v = (long long)(int)v; - else if (lpref == 1) - v = (long long)(long)v; - } - - switch (ch) { - case 'c': - out[0] = v; - out[1] = 0; - break; - case 'd': - i64toa_r(v, out); - break; - case 'u': - u64toa_r(v, out); - break; - case 'p': - *(out++) = '0'; - *(out++) = 'x'; - __nolibc_fallthrough; - default: /* 'x' and 'p' above */ - u64toh_r(v, out); - break; - } - outstr = outbuf; - } - else if (ch == 's') { - outstr = va_arg(args, char *); - if (!outstr) - outstr="(null)"; - } - else if (ch == 'm') { -#ifdef NOLIBC_IGNORE_ERRNO - outstr = "unknown error"; -#else - outstr = strerror(errno); -#endif /* NOLIBC_IGNORE_ERRNO */ - } else { - if (ch != '%') { - /* Invalid format: back up to output the format characters */ - fmt = outstr + 1; - /* and output a '%' now. */ - } - /* %% is documented as a 'conversion specifier'. - * Any flags, precision or length modifier are ignored. - */ - width = 0; - outstr = "%"; - } - len = strlen(outstr); + goto do_output; } + /* we're in a format sequence */ + + ch = *fmt++; + + /* width */ + while (ch >= '0' && ch <= '9') { + width *= 10; + width += ch - '0'; + + ch = *fmt++; + } + + /* Length modifiers */ + if (ch == 'l') { + lpref = 1; + ch = *fmt++; + if (ch == 'l') { + lpref = 2; + ch = *fmt++; + } + } else if (ch == 'j') { + /* intmax_t is long long */ + lpref = 2; + ch = *fmt++; + } else { + lpref = 0; + } + + if (ch == 'c' || ch == 'd' || ch == 'u' || ch == 'x' || ch == 'p') { + char *out = outbuf; + + if (ch == 'p') { + v = va_arg(args, unsigned long); + } else if (lpref) { + if (lpref > 1) + v = va_arg(args, unsigned long long); + else + v = va_arg(args, unsigned long); + } else { + v = va_arg(args, unsigned int); + } + + if (ch == 'd') { + /* sign-extend the value */ + if (lpref == 0) + v = (long long)(int)v; + else if (lpref == 1) + v = (long long)(long)v; + } + + switch (ch) { + case 'c': + out[0] = v; + out[1] = 0; + break; + case 'd': + i64toa_r(v, out); + break; + case 'u': + u64toa_r(v, out); + break; + case 'p': + *(out++) = '0'; + *(out++) = 'x'; + __nolibc_fallthrough; + default: /* 'x' and 'p' above */ + u64toh_r(v, out); + break; + } + outstr = outbuf; + goto do_strlen_output; + } + + if (ch == 's') { + outstr = va_arg(args, char *); + if (!outstr) + outstr = "(null)"; + goto do_strlen_output; + } + + if (ch == 'm') { +#ifdef NOLIBC_IGNORE_ERRNO + outstr = "unknown error"; +#else + outstr = strerror(errno); +#endif /* NOLIBC_IGNORE_ERRNO */ + goto do_strlen_output; + } + + if (ch != '%') { + /* Invalid format: back up to output the format characters */ + fmt = outstr + 1; + /* and output a '%' now. */ + } + /* %% is documented as a 'conversion specifier'. + * Any flags, precision or length modifier are ignored. + */ + len = 1; + width = 0; + outstr = fmt - 1; + goto do_output; + +do_strlen_output: + /* Open coded strlen() (slightly smaller). */ + for (len = 0;; len++) + if (!outstr[len]) + break; + +do_output: written += len; width -= len; From 85f1152778f8cdc563ada12a3fc48c962b408d94 Mon Sep 17 00:00:00 2001 From: David Laight Date: Sun, 8 Mar 2026 11:37:33 +0000 Subject: [PATCH 19/61] tools/nolibc/printf: Use bit-masks to hold requested flag, length and conversion chars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use flags bits (1u << (ch & 31)) for the flags, length modifiers, and conversion specifiers. This makes it easy to test for multiple values at once. Detect the conversion flags " #+-0" although they are currently all ignored. Unconditionally generate the signed values (for %d) to remove a second set of checks for the size. Separate out the formatting of single characters from numbers. Output the sign for negative values then negate and treat as unsigned. Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260308113742.12649-9-david.laight.linux@gmail.com Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/stdio.h | 154 ++++++++++++++++++++++++----------- 1 file changed, 106 insertions(+), 48 deletions(-) diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 0365f48fb049..f5a176bffc93 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -291,10 +291,14 @@ int fseek(FILE *stream, long offset, int whence) } -/* minimal printf(). It supports the following formats: - * - %[l*]{d,u,c,x,p} - * - %s - * - unknown modifiers are ignored. +/* printf(). Supports the following integer and string formats. + * - %[#-+ 0][width][{l,ll,j}]{c,d,u,x,p,s,m,%} + * - %% generates a single % + * - %m outputs strerror(errno). + * - The modifiers [#-+ 0] are currently ignored. + * - No support for precision or variable widths. + * - No support for floating point or wide characters. + * - Invalid formats are copied to the output buffer. * * Called by vfprintf() and snprintf() to do the actual formatting. * The callers provide a callback function to save the formatted data. @@ -305,15 +309,43 @@ int fseek(FILE *stream, long offset, int whence) * - with (NULL, 0) at the end of the __nolibc_printf. * If the callback returns non-zero __nolibc_printf() immediately returns -1. */ + typedef int (*__nolibc_printf_cb)(void *state, const char *buf, size_t size); +/* This code uses 'flag' variables that are indexed by the low 6 bits + * of characters to optimise checks for multiple characters. + * + * _NOLIBC_PF_FLAGS_CONTAIN(flags, 'a', 'b'. ...) + * returns non-zero if the bit for any of the specified characters is set. + * + * _NOLIBC_PF_CHAR_IS_ONE_OF(ch, 'a', 'b'. ...) + * returns the flag bit for ch if it is one of the specified characters. + * All the characters must be in the same 32 character block (non-alphabetic, + * upper case, or lower case) of the ASCII character set. + */ +#define _NOLIBC_PF_FLAG(ch) (1u << ((ch) & 0x1f)) +#define _NOLIBC_PF_FLAG_NZ(ch) ((ch) ? _NOLIBC_PF_FLAG(ch) : 0) +#define _NOLIBC_PF_FLAG8(cmp_1, cmp_2, cmp_3, cmp_4, cmp_5, cmp_6, cmp_7, cmp_8, ...) \ + (_NOLIBC_PF_FLAG_NZ(cmp_1) | _NOLIBC_PF_FLAG_NZ(cmp_2) | \ + _NOLIBC_PF_FLAG_NZ(cmp_3) | _NOLIBC_PF_FLAG_NZ(cmp_4) | \ + _NOLIBC_PF_FLAG_NZ(cmp_5) | _NOLIBC_PF_FLAG_NZ(cmp_6) | \ + _NOLIBC_PF_FLAG_NZ(cmp_7) | _NOLIBC_PF_FLAG_NZ(cmp_8)) +#define _NOLIBC_PF_FLAGS_CONTAIN(flags, ...) \ + ((flags) & _NOLIBC_PF_FLAG8(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0)) +#define _NOLIBC_PF_CHAR_IS_ONE_OF(ch, cmp_1, ...) \ + ((unsigned int)(ch) - (cmp_1 & 0xe0) > 0x1f ? 0 : \ + _NOLIBC_PF_FLAGS_CONTAIN(_NOLIBC_PF_FLAG(ch), cmp_1, __VA_ARGS__)) + static __attribute__((unused, format(printf, 3, 0))) int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list args) { - char lpref, ch; + char ch; unsigned long long v; + long long signed_v; int written, width, len; + unsigned int flags, ch_flag; char outbuf[21]; + char *out; const char *outstr; written = 0; @@ -324,6 +356,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list break; width = 0; + flags = 0; if (ch != '%') { while (*fmt && *fmt != '%') fmt++; @@ -334,7 +367,14 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list /* we're in a format sequence */ - ch = *fmt++; + /* Conversion flag characters */ + while (1) { + ch = *fmt++; + ch_flag = _NOLIBC_PF_CHAR_IS_ONE_OF(ch, ' ', '#', '+', '-', '0'); + if (!ch_flag) + break; + flags |= ch_flag; + } /* width */ while (ch >= '0' && ch <= '9') { @@ -344,63 +384,78 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list ch = *fmt++; } - /* Length modifiers */ - if (ch == 'l') { - lpref = 1; - ch = *fmt++; - if (ch == 'l') { - lpref = 2; - ch = *fmt++; + /* Length modifier. + * They miss the conversion flags characters " #+-0" so can go into flags. + * Change ll to j (both always 64bits). + */ + ch_flag = _NOLIBC_PF_CHAR_IS_ONE_OF(ch, 'l', 'j'); + if (ch_flag != 0) { + if (ch == 'l' && fmt[0] == 'l') { + fmt++; + ch_flag = _NOLIBC_PF_FLAG('j'); } - } else if (ch == 'j') { - /* intmax_t is long long */ - lpref = 2; + flags |= ch_flag; ch = *fmt++; - } else { - lpref = 0; } - if (ch == 'c' || ch == 'd' || ch == 'u' || ch == 'x' || ch == 'p') { - char *out = outbuf; + /* Conversion specifiers. */ - if (ch == 'p') { + /* Numeric and pointer conversion specifiers. + * + * Use an explicit bound check (rather than _NOLIBC_PF_CHAR_IS_ONE_OF()) + * so ch_flag can be used later. + */ + ch_flag = _NOLIBC_PF_FLAG(ch); + if ((ch >= 'a' && ch <= 'z') && + _NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'c', 'd', 'u', 'x', 'p')) { + /* 'long' is needed for pointer conversions and ltz lengths. + * A single test can be used provided 'p' (the same bit as '0') + * is masked from flags. + */ + if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag | (flags & ~_NOLIBC_PF_FLAG('p')), + 'p', 'l')) { v = va_arg(args, unsigned long); - } else if (lpref) { - if (lpref > 1) - v = va_arg(args, unsigned long long); - else - v = va_arg(args, unsigned long); + signed_v = (long)v; + } else if (_NOLIBC_PF_FLAGS_CONTAIN(flags, 'j')) { + v = va_arg(args, unsigned long long); + signed_v = v; } else { v = va_arg(args, unsigned int); + signed_v = (int)v; } - if (ch == 'd') { - /* sign-extend the value */ - if (lpref == 0) - v = (long long)(int)v; - else if (lpref == 1) - v = (long long)(long)v; + if (ch == 'c') { + /* "%c" - single character. */ + outbuf[0] = v; + len = 1; + outstr = outbuf; + goto do_output; } - switch (ch) { - case 'c': - out[0] = v; - out[1] = 0; - break; - case 'd': - i64toa_r(v, out); - break; - case 'u': + out = outbuf; + + if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'd')) { + /* "%d" and "%i" - signed decimal numbers. */ + if (signed_v < 0) { + *out++ = '-'; + v = -(signed_v + 1); + v++; + } + } + + /* Convert the number to ascii in the required base. */ + if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'd', 'u')) { + /* Base 10 */ u64toa_r(v, out); - break; - case 'p': - *(out++) = '0'; - *(out++) = 'x'; - __nolibc_fallthrough; - default: /* 'x' and 'p' above */ + } else { + /* Base 16 */ + if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'p')) { + *(out++) = '0'; + *(out++) = 'x'; + } u64toh_r(v, out); - break; } + outstr = outbuf; goto do_strlen_output; } @@ -443,6 +498,9 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list do_output: written += len; + /* Stop gcc back-merging this code into one of the conditionals above. */ + _NOLIBC_OPTIMIZER_HIDE_VAR(len); + width -= len; while (width > 0) { /* Output pad in 16 byte blocks with the small block first. */ From 125632871929e9bf5b0bc907c8fef2d326e4623a Mon Sep 17 00:00:00 2001 From: David Laight Date: Sun, 8 Mar 2026 11:37:34 +0000 Subject: [PATCH 20/61] tools/nolibc/printf: Add support for length modifiers tzqL and formats iX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Length modifiers t (ptrdiff_t) and z (size_t) are aliases for l (long), q and L are 64bit the same as j (intmax). Format i is an alias for d and X similar to x but upper case. Supporting them is mostly just adding the relevant bit to the bit pattern used for matching characters. Although %X is detected the output will be lower case. Change/add tests to use conversions i and X, and length modifiers L and ll. Use the correct minimum value for "%Li". Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260308113742.12649-10-david.laight.linux@gmail.com [Thomas: Fix up testcases for musl libc] Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/stdio.h | 27 ++++++++++++-------- tools/testing/selftests/nolibc/nolibc-test.c | 14 +++++++--- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index f5a176bffc93..7382b00707fb 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -291,10 +291,11 @@ int fseek(FILE *stream, long offset, int whence) } -/* printf(). Supports the following integer and string formats. - * - %[#-+ 0][width][{l,ll,j}]{c,d,u,x,p,s,m,%} +/* printf(). Supports most of the normal integer and string formats. + * - %[#-+ 0][width][{l,t,z,ll,L,j,q}]{c,d,i,u,x,X,p,s,m,%} * - %% generates a single % * - %m outputs strerror(errno). + * - %X outputs a..f the same as %x. * - The modifiers [#-+ 0] are currently ignored. * - No support for precision or variable widths. * - No support for floating point or wide characters. @@ -386,9 +387,11 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list /* Length modifier. * They miss the conversion flags characters " #+-0" so can go into flags. - * Change ll to j (both always 64bits). + * Change both L and ll to j (all always 64bit). */ - ch_flag = _NOLIBC_PF_CHAR_IS_ONE_OF(ch, 'l', 'j'); + if (ch == 'L') + ch = 'j'; + ch_flag = _NOLIBC_PF_CHAR_IS_ONE_OF(ch, 'l', 't', 'z', 'j', 'q'); if (ch_flag != 0) { if (ch == 'l' && fmt[0] == 'l') { fmt++; @@ -403,20 +406,22 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list /* Numeric and pointer conversion specifiers. * * Use an explicit bound check (rather than _NOLIBC_PF_CHAR_IS_ONE_OF()) - * so ch_flag can be used later. + * so that 'X' can be allowed through. + * 'X' gets treated and 'x' because _NOLIBC_PF_FLAG() returns the same + * value for both. */ ch_flag = _NOLIBC_PF_FLAG(ch); - if ((ch >= 'a' && ch <= 'z') && - _NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'c', 'd', 'u', 'x', 'p')) { + if (((ch >= 'a' && ch <= 'z') || ch == 'X') && + _NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'c', 'd', 'i', 'u', 'x', 'p')) { /* 'long' is needed for pointer conversions and ltz lengths. * A single test can be used provided 'p' (the same bit as '0') * is masked from flags. */ if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag | (flags & ~_NOLIBC_PF_FLAG('p')), - 'p', 'l')) { + 'p', 'l', 't', 'z')) { v = va_arg(args, unsigned long); signed_v = (long)v; - } else if (_NOLIBC_PF_FLAGS_CONTAIN(flags, 'j')) { + } else if (_NOLIBC_PF_FLAGS_CONTAIN(flags, 'j', 'q')) { v = va_arg(args, unsigned long long); signed_v = v; } else { @@ -434,7 +439,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list out = outbuf; - if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'd')) { + if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'd', 'i')) { /* "%d" and "%i" - signed decimal numbers. */ if (signed_v < 0) { *out++ = '-'; @@ -444,7 +449,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list } /* Convert the number to ascii in the required base. */ - if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'd', 'u')) { + if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'd', 'i', 'u')) { /* Base 10 */ u64toa_r(v, out); } else { diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index d8949aa1dee3..6fa2346c655a 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1834,11 +1834,19 @@ static int run_printf(int min, int max) CASE_TEST(number); EXPECT_VFPRINTF(1, "1234", "%d", 1234); break; CASE_TEST(negnumber); EXPECT_VFPRINTF(1, "-1234", "%d", -1234); break; CASE_TEST(unsigned); EXPECT_VFPRINTF(1, "12345", "%u", 12345); break; + CASE_TEST(signed_max); EXPECT_VFPRINTF(1, "2147483647", "%i", ~0u >> 1); break; + CASE_TEST(signed_min); EXPECT_VFPRINTF(1, "-2147483648", "%i", (~0u >> 1) + 1); break; + CASE_TEST(unsigned_max); EXPECT_VFPRINTF(1, "4294967295", "%u", ~0u); break; CASE_TEST(char); EXPECT_VFPRINTF(1, "c", "%c", 'c'); break; - CASE_TEST(hex); EXPECT_VFPRINTF(1, "f", "%x", 0xf); break; + CASE_TEST(hex_nolibc); EXPECT_VFPRINTF(is_nolibc, "|f|d|", "|%x|%X|", 0xf, 0xd); break; + CASE_TEST(hex_libc); EXPECT_VFPRINTF(!is_nolibc, "|f|D|", "|%x|%X|", 0xf, 0xd); break; CASE_TEST(pointer); EXPECT_VFPRINTF(1, "0x1", "%p", (void *) 0x1); break; - CASE_TEST(uintmax_t); EXPECT_VFPRINTF(1, "18446744073709551615", "%ju", 0xffffffffffffffffULL); break; - CASE_TEST(intmax_t); EXPECT_VFPRINTF(1, "-9223372036854775807", "%jd", 0x8000000000000001LL); break; + CASE_TEST(percent); EXPECT_VFPRINTF(1, "a%d42%69%", "a%%d%d%%%d%%", 42, 69); break; + CASE_TEST(perc_qual); EXPECT_VFPRINTF(is_nolibc || is_glibc, "a%d2", "a%-14l%d%d", 2); break; + CASE_TEST(invalid); EXPECT_VFPRINTF(is_nolibc || is_glibc, "a%12yx3%y42%P", "a%12yx%d%y%d%P", 3, 42); break; + CASE_TEST(intmax_max); EXPECT_VFPRINTF(1, "9223372036854775807", "%lld", ~0ULL >> 1); break; + CASE_TEST(intmax_min); EXPECT_VFPRINTF(is_nolibc || is_glibc, "-9223372036854775808", "%Li", (~0ULL >> 1) + 1); break; + CASE_TEST(uintmax_max); EXPECT_VFPRINTF(1, "18446744073709551615", "%ju", ~0ULL); break; CASE_TEST(truncation); EXPECT_VFPRINTF(1, "0123456789012345678901234", "%s", "0123456789012345678901234"); break; CASE_TEST(string_width); EXPECT_VFPRINTF(1, " 1", "%10s", "1"); break; CASE_TEST(number_width); EXPECT_VFPRINTF(1, " 1", "%10d", 1); break; From b43be424343407661d5e7c79a3584a37b91a88bb Mon Sep 17 00:00:00 2001 From: David Laight Date: Sun, 8 Mar 2026 11:37:35 +0000 Subject: [PATCH 21/61] tools/nolibc/printf: Handle "%s" with the numeric formats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoids the extra va_arg() call with is non-trivial on a lot of modern ABI. Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260308113742.12649-11-david.laight.linux@gmail.com Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/stdio.h | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 7382b00707fb..a377f164c70d 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -412,13 +412,13 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list */ ch_flag = _NOLIBC_PF_FLAG(ch); if (((ch >= 'a' && ch <= 'z') || ch == 'X') && - _NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'c', 'd', 'i', 'u', 'x', 'p')) { - /* 'long' is needed for pointer conversions and ltz lengths. + _NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'c', 'd', 'i', 'u', 'x', 'p', 's')) { + /* 'long' is needed for pointer/string conversions and ltz lengths. * A single test can be used provided 'p' (the same bit as '0') * is masked from flags. */ if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag | (flags & ~_NOLIBC_PF_FLAG('p')), - 'p', 'l', 't', 'z')) { + 'p', 's', 'l', 't', 'z')) { v = va_arg(args, unsigned long); signed_v = (long)v; } else if (_NOLIBC_PF_FLAGS_CONTAIN(flags, 'j', 'q')) { @@ -437,6 +437,14 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list goto do_output; } + if (ch == 's') { + /* "%s" - character string. */ + outstr = (const char *)(uintptr_t)v; + if (!outstr) + outstr = "(null)"; + goto do_strlen_output; + } + out = outbuf; if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'd', 'i')) { @@ -465,13 +473,6 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list goto do_strlen_output; } - if (ch == 's') { - outstr = va_arg(args, char *); - if (!outstr) - outstr = "(null)"; - goto do_strlen_output; - } - if (ch == 'm') { #ifdef NOLIBC_IGNORE_ERRNO outstr = "unknown error"; From 8df70ee45b1383114cdcaa9b2fe7449cdf5f46d5 Mon Sep 17 00:00:00 2001 From: David Laight Date: Sun, 8 Mar 2026 11:37:36 +0000 Subject: [PATCH 22/61] tools/nolibc/printf: Prepend sign to converted number MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of appending the converted number to the sign, convert first and then prepend the sign (or "0x"). Use the length returned by u64toh_r() instead of calling strlen(). Needed so that zero padding can be inserted between the sign and digits in an upcoming patch. Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260308113742.12649-12-david.laight.linux@gmail.com Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/stdio.h | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index a377f164c70d..3620aa643c81 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -345,9 +345,10 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list long long signed_v; int written, width, len; unsigned int flags, ch_flag; - char outbuf[21]; + char outbuf[2 + 22 + 1]; char *out; const char *outstr; + unsigned int sign_prefix; written = 0; while (1) { @@ -445,32 +446,49 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list goto do_strlen_output; } - out = outbuf; + /* The 'sign_prefix' can be zero, one or two ("0x") characters. + * Prepended least significant byte first stopping on a zero byte. + */ + sign_prefix = 0; if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'd', 'i')) { /* "%d" and "%i" - signed decimal numbers. */ if (signed_v < 0) { - *out++ = '-'; + sign_prefix = '-'; v = -(signed_v + 1); v++; } } + /* The value is converted offset into the buffer so that + * the sign/prefix can be added in front. + * The longest digit string is 22 + 1 for octal conversions, the + * space is reserved even though octal isn't currently supported. + */ + out = outbuf + 2; + /* Convert the number to ascii in the required base. */ if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'd', 'i', 'u')) { /* Base 10 */ - u64toa_r(v, out); + len = u64toa_r(v, out); } else { /* Base 16 */ if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'p')) { - *(out++) = '0'; - *(out++) = 'x'; + /* "%p" needs "0x" prepending. */ + sign_prefix = '0' << 8 | 'x'; } - u64toh_r(v, out); + len = u64toh_r(v, out); } - outstr = outbuf; - goto do_strlen_output; + /* Add the 0, 1 or 2 ("0x") sign/prefix characters at the front. */ + for (; sign_prefix; sign_prefix >>= 8) { + /* Force gcc to increment len inside the loop. */ + _NOLIBC_OPTIMIZER_HIDE_VAR(len); + len++; + *--out = sign_prefix; + } + outstr = out; + goto do_output; } if (ch == 'm') { From a30d20588fb8507540d267505a8876bc37bb3ec7 Mon Sep 17 00:00:00 2001 From: David Laight Date: Sun, 8 Mar 2026 11:37:37 +0000 Subject: [PATCH 23/61] tools/nolibc/printf: Add support for conversion flags space and plus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flags ' ' and '+' are sign characters for positive numbers. Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260308113742.12649-13-david.laight.linux@gmail.com Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/stdio.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 3620aa643c81..65e113f135d4 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -296,7 +296,7 @@ int fseek(FILE *stream, long offset, int whence) * - %% generates a single % * - %m outputs strerror(errno). * - %X outputs a..f the same as %x. - * - The modifiers [#-+ 0] are currently ignored. + * - The modifiers [#-0] are currently ignored. * - No support for precision or variable widths. * - No support for floating point or wide characters. * - Invalid formats are copied to the output buffer. @@ -457,6 +457,10 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list sign_prefix = '-'; v = -(signed_v + 1); v++; + } else if (_NOLIBC_PF_FLAGS_CONTAIN(flags, '+')) { + sign_prefix = '+'; + } else if (_NOLIBC_PF_FLAGS_CONTAIN(flags, ' ')) { + sign_prefix = ' '; } } From 5eae5f1a01aff6f9773547265167d7a680c6fbc3 Mon Sep 17 00:00:00 2001 From: David Laight Date: Sun, 8 Mar 2026 11:37:38 +0000 Subject: [PATCH 24/61] tools/nolibc/printf: Special case 0 and add support for %#x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The output for %#x is almost the same as that for %p, both output in hexadecimal with a leading "0x". However for zero %#x should just output "0" (the same as decimal and ocal). For %p match glibc and output "(nil)" rather than "0x0" or "0". Add tests for "%#x", "% d", "%+d" and passing NULL to "%p". Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260308113742.12649-14-david.laight.linux@gmail.com [Thomas: fix up testcases for musl libc] Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/stdio.h | 38 ++++++++++++++------ tools/testing/selftests/nolibc/nolibc-test.c | 3 ++ 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 65e113f135d4..db714b1ce274 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -296,7 +296,7 @@ int fseek(FILE *stream, long offset, int whence) * - %% generates a single % * - %m outputs strerror(errno). * - %X outputs a..f the same as %x. - * - The modifiers [#-0] are currently ignored. + * - The modifiers [-0] are currently ignored. * - No support for precision or variable widths. * - No support for floating point or wide characters. * - Invalid formats are copied to the output buffer. @@ -410,8 +410,11 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list * so that 'X' can be allowed through. * 'X' gets treated and 'x' because _NOLIBC_PF_FLAG() returns the same * value for both. + * + * We need to check for "%p" or "%#x" later, merging here gives better code. + * But '#' collides with 'c' so shift right. */ - ch_flag = _NOLIBC_PF_FLAG(ch); + ch_flag = _NOLIBC_PF_FLAG(ch) | (flags & _NOLIBC_PF_FLAG('#')) >> 1; if (((ch >= 'a' && ch <= 'z') || ch == 'X') && _NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'c', 'd', 'i', 'u', 'x', 'p', 's')) { /* 'long' is needed for pointer/string conversions and ltz lengths. @@ -471,17 +474,30 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list */ out = outbuf + 2; - /* Convert the number to ascii in the required base. */ - if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'd', 'i', 'u')) { - /* Base 10 */ - len = u64toa_r(v, out); - } else { - /* Base 16 */ + if (v == 0) { + /* There are special rules for zero. */ if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'p')) { - /* "%p" needs "0x" prepending. */ - sign_prefix = '0' << 8 | 'x'; + /* "%p" match glibc, precision is ignored */ + outstr = "(nil)"; + len = 5; + goto do_output; + } + /* All other formats (including "%#x") just output "0". */ + out[0] = '0'; + len = 1; + } else { + /* Convert the number to ascii in the required base. */ + if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'd', 'i', 'u')) { + /* Base 10 */ + len = u64toa_r(v, out); + } else { + /* Base 16 */ + if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'p', '#' - 1)) { + /* "%p" and "%#x" need "0x" prepending. */ + sign_prefix = '0' << 8 | 'x'; + } + len = u64toh_r(v, out); } - len = u64toh_r(v, out); } /* Add the 0, 1 or 2 ("0x") sign/prefix characters at the front. */ diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 6fa2346c655a..9644087267d1 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1833,6 +1833,7 @@ static int run_printf(int min, int max) CASE_TEST(string); EXPECT_VFPRINTF(1, "foo", "%s", "foo"); break; CASE_TEST(number); EXPECT_VFPRINTF(1, "1234", "%d", 1234); break; CASE_TEST(negnumber); EXPECT_VFPRINTF(1, "-1234", "%d", -1234); break; + CASE_TEST(num_sign); EXPECT_VFPRINTF(1, "| 1|+2|+3|+4|5|", "|% d|%+d|% +d|%+ d|%#d|", 1, 2, 3, 4, 5); break; CASE_TEST(unsigned); EXPECT_VFPRINTF(1, "12345", "%u", 12345); break; CASE_TEST(signed_max); EXPECT_VFPRINTF(1, "2147483647", "%i", ~0u >> 1); break; CASE_TEST(signed_min); EXPECT_VFPRINTF(1, "-2147483648", "%i", (~0u >> 1) + 1); break; @@ -1840,7 +1841,9 @@ static int run_printf(int min, int max) CASE_TEST(char); EXPECT_VFPRINTF(1, "c", "%c", 'c'); break; CASE_TEST(hex_nolibc); EXPECT_VFPRINTF(is_nolibc, "|f|d|", "|%x|%X|", 0xf, 0xd); break; CASE_TEST(hex_libc); EXPECT_VFPRINTF(!is_nolibc, "|f|D|", "|%x|%X|", 0xf, 0xd); break; + CASE_TEST(hex_alt); EXPECT_VFPRINTF(1, "|0x1| 0x2| 0|", "|%#x|%#5x|%#5x|", 1, 2, 0); break; CASE_TEST(pointer); EXPECT_VFPRINTF(1, "0x1", "%p", (void *) 0x1); break; + CASE_TEST(pointer_NULL); EXPECT_VFPRINTF(is_nolibc || is_glibc, "(nil)", "%p", (void *)0); break; CASE_TEST(percent); EXPECT_VFPRINTF(1, "a%d42%69%", "a%%d%d%%%d%%", 42, 69); break; CASE_TEST(perc_qual); EXPECT_VFPRINTF(is_nolibc || is_glibc, "a%d2", "a%-14l%d%d", 2); break; CASE_TEST(invalid); EXPECT_VFPRINTF(is_nolibc || is_glibc, "a%12yx3%y42%P", "a%12yx%d%y%d%P", 3, 42); break; From b5f3f59cf4384a8c9e60fa4bb1a8f4ad71126a90 Mon Sep 17 00:00:00 2001 From: David Laight Date: Sun, 8 Mar 2026 11:37:39 +0000 Subject: [PATCH 25/61] tools/nolibc/printf: Add support for left aligning fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Output the characters before or after the pad - writing the pad takes more code. Include additional/changed tests Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260308113742.12649-15-david.laight.linux@gmail.com Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/stdio.h | 6 +++++- tools/testing/selftests/nolibc/nolibc-test.c | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index db714b1ce274..c8a463ed73c7 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -545,7 +545,11 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list /* Stop gcc back-merging this code into one of the conditionals above. */ _NOLIBC_OPTIMIZER_HIDE_VAR(len); + /* Output the characters on the required side of any padding. */ width -= len; + flags = _NOLIBC_PF_FLAGS_CONTAIN(flags, '-'); + if (flags && cb(state, outstr, len) != 0) + return -1; while (width > 0) { /* Output pad in 16 byte blocks with the small block first. */ int pad_len = ((width - 1) & 15) + 1; @@ -554,7 +558,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list if (cb(state, " ", pad_len) != 0) return -1; } - if (cb(state, outstr, len) != 0) + if (!flags && cb(state, outstr, len) != 0) return -1; } diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 9644087267d1..2a83d5ea2d46 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1853,9 +1853,11 @@ static int run_printf(int min, int max) CASE_TEST(truncation); EXPECT_VFPRINTF(1, "0123456789012345678901234", "%s", "0123456789012345678901234"); break; CASE_TEST(string_width); EXPECT_VFPRINTF(1, " 1", "%10s", "1"); break; CASE_TEST(number_width); EXPECT_VFPRINTF(1, " 1", "%10d", 1); break; + CASE_TEST(number_left); EXPECT_VFPRINTF(1, "|-5 |", "|%-8d|", -5); break; + CASE_TEST(string_align); EXPECT_VFPRINTF(1, "|foo |", "|%-8s|", "foo"); break; CASE_TEST(width_trunc); EXPECT_VFPRINTF(1, " 1", "%25d", 1); break; CASE_TEST(errno); errno = 22; EXPECT_VFPRINTF(is_nolibc, "errno=22", "%m"); break; - CASE_TEST(errno-neg); errno = -22; EXPECT_VFPRINTF(is_nolibc, " errno=-22", "%12m"); break; + CASE_TEST(errno-neg); errno = -22; EXPECT_VFPRINTF(is_nolibc, "errno=-22 ", "%-12m"); break; CASE_TEST(scanf); EXPECT_ZR(1, test_scanf()); break; CASE_TEST(printf_error); EXPECT_ZR(1, test_printf_error()); break; case __LINE__: From d3d3f64f8e964f8af6ac72294e65caad5acc452e Mon Sep 17 00:00:00 2001 From: David Laight Date: Sun, 8 Mar 2026 11:37:40 +0000 Subject: [PATCH 26/61] tools/nolibc/printf: Add support for zero padding and field precision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Includes support for variable field widths (eg "%*.*d"). Zero padding is limited to 31 zero characters. This is wider than the largest numeric field so shouldn't be a problem. All the standard printf formats are now supported except octal and floating point. Add tests for new features Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260308113742.12649-16-david.laight.linux@gmail.com [Thomas: fixup testcases for musl libc] Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/stdio.h | 80 ++++++++++++++++---- tools/testing/selftests/nolibc/nolibc-test.c | 19 ++++- 2 files changed, 81 insertions(+), 18 deletions(-) diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index c8a463ed73c7..1294004afb30 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -292,12 +292,10 @@ int fseek(FILE *stream, long offset, int whence) /* printf(). Supports most of the normal integer and string formats. - * - %[#-+ 0][width][{l,t,z,ll,L,j,q}]{c,d,i,u,x,X,p,s,m,%} + * - %[#0-+ ][width|*[.precision|*}][{l,t,z,ll,L,j,q}]{c,d,i,u,x,X,p,s,m,%} * - %% generates a single % * - %m outputs strerror(errno). * - %X outputs a..f the same as %x. - * - The modifiers [-0] are currently ignored. - * - No support for precision or variable widths. * - No support for floating point or wide characters. * - Invalid formats are copied to the output buffer. * @@ -343,9 +341,9 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list char ch; unsigned long long v; long long signed_v; - int written, width, len; + int written, width, precision, len; unsigned int flags, ch_flag; - char outbuf[2 + 22 + 1]; + char outbuf[2 + 31 + 22 + 1]; char *out; const char *outstr; unsigned int sign_prefix; @@ -378,12 +376,24 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list flags |= ch_flag; } - /* width */ - while (ch >= '0' && ch <= '9') { - width *= 10; - width += ch - '0'; - - ch = *fmt++; + /* Width and precision */ + for (;; ch = *fmt++) { + if (ch == '*') { + precision = va_arg(args, unsigned int); + ch = *fmt++; + } else { + for (precision = 0; ch >= '0' && ch <= '9'; ch = *fmt++) + precision = precision * 10 + (ch - '0'); + } + if (_NOLIBC_PF_FLAGS_CONTAIN(flags, '.')) + break; + width = precision; + if (ch != '.') { + /* Default precision for strings */ + precision = INT_MAX; + break; + } + flags |= _NOLIBC_PF_FLAG('.'); } /* Length modifier. @@ -444,8 +454,12 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list if (ch == 's') { /* "%s" - character string. */ outstr = (const char *)(uintptr_t)v; - if (!outstr) + if (!outstr) { outstr = "(null)"; + /* Match glibc, nothing output if precision too small */ + len = precision >= 6 ? 6 : 0; + goto do_output; + } goto do_strlen_output; } @@ -468,11 +482,11 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list } /* The value is converted offset into the buffer so that - * the sign/prefix can be added in front. + * 31 zero pad characters and the sign/prefix can be added in front. * The longest digit string is 22 + 1 for octal conversions, the * space is reserved even though octal isn't currently supported. */ - out = outbuf + 2; + out = outbuf + 2 + 31; if (v == 0) { /* There are special rules for zero. */ @@ -482,6 +496,11 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list len = 5; goto do_output; } + if (!precision) { + /* Explicit %nn.0d, no digits output */ + len = 0; + goto prepend_sign; + } /* All other formats (including "%#x") just output "0". */ out[0] = '0'; len = 1; @@ -500,6 +519,35 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list } } + /* Add zero padding */ + if (_NOLIBC_PF_FLAGS_CONTAIN(flags, '0', '.')) { + if (!_NOLIBC_PF_FLAGS_CONTAIN(flags, '.')) { + if (_NOLIBC_PF_FLAGS_CONTAIN(flags, '-')) + /* Left justify overrides zero pad */ + goto prepend_sign; + /* eg "%05d", Zero pad to field width less sign. + * Note that precision can end up negative so all + * the variables have to be 'signed int'. + */ + precision = width; + if (sign_prefix) { + precision--; + if (sign_prefix >= 256) + precision--; + } + } + if (precision > 31) + /* Don't run off the start of outbuf[], arbitrary limit + * longer than the longest number field. */ + precision = 31; + for (; len < precision; len++) { + /* Stop gcc generating horrid code and memset(). */ + _NOLIBC_OPTIMIZER_HIDE_VAR(len); + *--out = '0'; + } + } + +prepend_sign: /* Add the 0, 1 or 2 ("0x") sign/prefix characters at the front. */ for (; sign_prefix; sign_prefix >>= 8) { /* Force gcc to increment len inside the loop. */ @@ -534,8 +582,8 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list goto do_output; do_strlen_output: - /* Open coded strlen() (slightly smaller). */ - for (len = 0;; len++) + /* Open coded strnlen() (slightly smaller). */ + for (len = 0; len < precision; len++) if (!outstr[len]) break; diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 2a83d5ea2d46..9695d9b359cd 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1838,12 +1838,15 @@ static int run_printf(int min, int max) CASE_TEST(signed_max); EXPECT_VFPRINTF(1, "2147483647", "%i", ~0u >> 1); break; CASE_TEST(signed_min); EXPECT_VFPRINTF(1, "-2147483648", "%i", (~0u >> 1) + 1); break; CASE_TEST(unsigned_max); EXPECT_VFPRINTF(1, "4294967295", "%u", ~0u); break; - CASE_TEST(char); EXPECT_VFPRINTF(1, "c", "%c", 'c'); break; + CASE_TEST(char); EXPECT_VFPRINTF(1, "|c|d| e|", "|%c|%.0c|%4c|", 'c', 'd', 'e'); break; CASE_TEST(hex_nolibc); EXPECT_VFPRINTF(is_nolibc, "|f|d|", "|%x|%X|", 0xf, 0xd); break; CASE_TEST(hex_libc); EXPECT_VFPRINTF(!is_nolibc, "|f|D|", "|%x|%X|", 0xf, 0xd); break; CASE_TEST(hex_alt); EXPECT_VFPRINTF(1, "|0x1| 0x2| 0|", "|%#x|%#5x|%#5x|", 1, 2, 0); break; + CASE_TEST(hex_alt_prec); EXPECT_VFPRINTF(1, "| 0x02|0x03| 0x123|", "|%#5.2x|%#04x|%#6.2x|", 2, 3, 0x123); break; + CASE_TEST(hex_0_alt); EXPECT_VFPRINTF(1, "|0|0000| 00|", "|%#x|%#04x|%#5.2x|", 0, 0, 0); break; CASE_TEST(pointer); EXPECT_VFPRINTF(1, "0x1", "%p", (void *) 0x1); break; - CASE_TEST(pointer_NULL); EXPECT_VFPRINTF(is_nolibc || is_glibc, "(nil)", "%p", (void *)0); break; + CASE_TEST(pointer_NULL); EXPECT_VFPRINTF(is_nolibc || is_glibc, "|(nil)|(nil)|", "|%p|%.4p|", (void *)0, (void *)0); break; + CASE_TEST(string_NULL); EXPECT_VFPRINTF(is_nolibc || is_glibc, "|(null)||(null)|", "|%s|%.5s|%.6s|", (void *)0, (void *)0, (void *)0); break; CASE_TEST(percent); EXPECT_VFPRINTF(1, "a%d42%69%", "a%%d%d%%%d%%", 42, 69); break; CASE_TEST(perc_qual); EXPECT_VFPRINTF(is_nolibc || is_glibc, "a%d2", "a%-14l%d%d", 2); break; CASE_TEST(invalid); EXPECT_VFPRINTF(is_nolibc || is_glibc, "a%12yx3%y42%P", "a%12yx%d%y%d%P", 3, 42); break; @@ -1852,10 +1855,22 @@ static int run_printf(int min, int max) CASE_TEST(uintmax_max); EXPECT_VFPRINTF(1, "18446744073709551615", "%ju", ~0ULL); break; CASE_TEST(truncation); EXPECT_VFPRINTF(1, "0123456789012345678901234", "%s", "0123456789012345678901234"); break; CASE_TEST(string_width); EXPECT_VFPRINTF(1, " 1", "%10s", "1"); break; + CASE_TEST(string_trunc); EXPECT_VFPRINTF(1, " 12345", "%10.5s", "1234567890"); break; CASE_TEST(number_width); EXPECT_VFPRINTF(1, " 1", "%10d", 1); break; CASE_TEST(number_left); EXPECT_VFPRINTF(1, "|-5 |", "|%-8d|", -5); break; CASE_TEST(string_align); EXPECT_VFPRINTF(1, "|foo |", "|%-8s|", "foo"); break; CASE_TEST(width_trunc); EXPECT_VFPRINTF(1, " 1", "%25d", 1); break; + CASE_TEST(width_tr_lft); EXPECT_VFPRINTF(1, "1 ", "%-30d", 1); break; + CASE_TEST(number_pad); EXPECT_VFPRINTF(1, "0000000005", "%010d", 5); break; + CASE_TEST(number_pad); EXPECT_VFPRINTF(1, "|0000000005|0x1234|", "|%010d|%#01x|", 5, 0x1234); break; + CASE_TEST(num_pad_neg); EXPECT_VFPRINTF(1, "-000000005", "%010d", -5); break; + CASE_TEST(num_pad_hex); EXPECT_VFPRINTF(1, "00fffffffb", "%010x", -5); break; + CASE_TEST(num_pad_trunc);EXPECT_VFPRINTF(is_nolibc, " 0000000000000000000000000000005", "%035d", 5); break; /* max 31 '0' can be added */ + CASE_TEST(num_p_tr_libc);EXPECT_VFPRINTF(!is_nolibc, "00000000000000000000000000000000005", "%035d", 5); break; + CASE_TEST(number_prec); EXPECT_VFPRINTF(1, " 00005", "%10.5d", 5); break; + CASE_TEST(num_prec_neg); EXPECT_VFPRINTF(1, " -00005", "%10.5d", -5); break; + CASE_TEST(num_prec_var); EXPECT_VFPRINTF(1, " -00005", "%*.*d", 10, 5, -5); break; + CASE_TEST(num_0_prec_0); EXPECT_VFPRINTF(1, "|| |+||||", "|%.0d|% .0d|%+.0d|%.0u|%.0x|%#.0x|", 0, 0, 0, 0, 0, 0); break; CASE_TEST(errno); errno = 22; EXPECT_VFPRINTF(is_nolibc, "errno=22", "%m"); break; CASE_TEST(errno-neg); errno = -22; EXPECT_VFPRINTF(is_nolibc, "errno=-22 ", "%-12m"); break; CASE_TEST(scanf); EXPECT_ZR(1, test_scanf()); break; From 248c7cf60c808f09044af1ce1d2c7c707696dc1e Mon Sep 17 00:00:00 2001 From: David Laight Date: Sun, 8 Mar 2026 11:37:41 +0000 Subject: [PATCH 27/61] tools/nolibc/printf: Add support for octal output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Octal output isn't often used, but adding it costs very little. Supporting "%#o" is mildly annoying, it has to add a leading '0' if there isn't one present. In simple cases this is the same as adding a sign of '0' - but that adds an extra '0' in a few places. So you need 3 tests, %o, # and no leading '0' (which can only be checked after the zero pad for precision). If all the test are deferred until after zero padding then too many values are 'live' across the call to _nolibc_u64toa_base() and get spilled to stack. Hence the check that ignores the 'sign' if it is the same as the first character of the output string. Add tests for octal output. Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260308113742.12649-17-david.laight.linux@gmail.com [Thomas: avoid a -Wsign-compare] Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/stdio.h | 50 ++++++++++++++------ tools/testing/selftests/nolibc/nolibc-test.c | 9 ++-- 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 1294004afb30..8f7e1948a651 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -292,7 +292,7 @@ int fseek(FILE *stream, long offset, int whence) /* printf(). Supports most of the normal integer and string formats. - * - %[#0-+ ][width|*[.precision|*}][{l,t,z,ll,L,j,q}]{c,d,i,u,x,X,p,s,m,%} + * - %[#0-+ ][width|*[.precision|*}][{l,t,z,ll,L,j,q}]{c,d,i,u,o,x,X,p,s,m,%} * - %% generates a single % * - %m outputs strerror(errno). * - %X outputs a..f the same as %x. @@ -426,7 +426,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list */ ch_flag = _NOLIBC_PF_FLAG(ch) | (flags & _NOLIBC_PF_FLAG('#')) >> 1; if (((ch >= 'a' && ch <= 'z') || ch == 'X') && - _NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'c', 'd', 'i', 'u', 'x', 'p', 's')) { + _NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'c', 'd', 'i', 'u', 'o', 'x', 'p', 's')) { /* 'long' is needed for pointer/string conversions and ltz lengths. * A single test can be used provided 'p' (the same bit as '0') * is masked from flags. @@ -479,12 +479,19 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list } else if (_NOLIBC_PF_FLAGS_CONTAIN(flags, ' ')) { sign_prefix = ' '; } + } else { + /* "#o" requires that the output always starts with a '0'. + * This needs another check after any zero padding to avoid + * adding an extra leading '0'. + */ + if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'o') && + _NOLIBC_PF_FLAGS_CONTAIN(ch_flag, '#' - 1)) + sign_prefix = '0'; } /* The value is converted offset into the buffer so that * 31 zero pad characters and the sign/prefix can be added in front. - * The longest digit string is 22 + 1 for octal conversions, the - * space is reserved even though octal isn't currently supported. + * The longest digit string is 22 + 1 for octal conversions. */ out = outbuf + 2 + 31; @@ -497,7 +504,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list goto do_output; } if (!precision) { - /* Explicit %nn.0d, no digits output */ + /* Explicit %nn.0d, no digits output (except for %#.0o) */ len = 0; goto prepend_sign; } @@ -506,17 +513,23 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list len = 1; } else { /* Convert the number to ascii in the required base. */ + unsigned long long recip; + unsigned int base; if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'd', 'i', 'u')) { - /* Base 10 */ - len = u64toa_r(v, out); + base = 10; + recip = _NOLIBC_U64TOA_RECIP(10); + } else if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'o')) { + base = 8; + recip = _NOLIBC_U64TOA_RECIP(8); } else { - /* Base 16 */ + base = 16; + recip = _NOLIBC_U64TOA_RECIP(16); if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'p', '#' - 1)) { /* "%p" and "%#x" need "0x" prepending. */ sign_prefix = '0' << 8 | 'x'; } - len = u64toh_r(v, out); } + len = _nolibc_u64toa_base(v, out, base, recip); } /* Add zero padding */ @@ -547,13 +560,20 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list } } + /* %#o has set sign_prefix to '0', but we don't want so add an extra + * leading zero here. + * Since the only other byte values of sign_prefix are ' ', '+' and '-' + * it is enough to check that out[] doesn't already start with sign_prefix. + */ + if (sign_prefix - *out) { prepend_sign: - /* Add the 0, 1 or 2 ("0x") sign/prefix characters at the front. */ - for (; sign_prefix; sign_prefix >>= 8) { - /* Force gcc to increment len inside the loop. */ - _NOLIBC_OPTIMIZER_HIDE_VAR(len); - len++; - *--out = sign_prefix; + /* Add the 0, 1 or 2 ("0x") sign/prefix characters at the front. */ + for (; sign_prefix; sign_prefix >>= 8) { + /* Force gcc to increment len inside the loop. */ + _NOLIBC_OPTIMIZER_HIDE_VAR(len); + len++; + *--out = sign_prefix; + } } outstr = out; goto do_output; diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 9695d9b359cd..7836162dcd2f 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1671,7 +1671,7 @@ int run_stdlib(int min, int max) #define EXPECT_VFPRINTF(cond, expected, fmt, ...) \ do { if (!(cond)) result(llen, SKIPPED); else ret += expect_vfprintf(llen, expected, fmt, ##__VA_ARGS__); } while (0) -#define VFPRINTF_LEN 20 +#define VFPRINTF_LEN 25 static int expect_vfprintf(int llen, const char *expected, const char *fmt, ...) { char buf[VFPRINTF_LEN + 80]; @@ -1839,6 +1839,9 @@ static int run_printf(int min, int max) CASE_TEST(signed_min); EXPECT_VFPRINTF(1, "-2147483648", "%i", (~0u >> 1) + 1); break; CASE_TEST(unsigned_max); EXPECT_VFPRINTF(1, "4294967295", "%u", ~0u); break; CASE_TEST(char); EXPECT_VFPRINTF(1, "|c|d| e|", "|%c|%.0c|%4c|", 'c', 'd', 'e'); break; + CASE_TEST(octal); EXPECT_VFPRINTF(1, "|17| 0033||", "|%o|%6.4o|%.0o|", 017, 033, 0); break; + CASE_TEST(octal_max); EXPECT_VFPRINTF(1, "1777777777777777777777", "%llo", ~0ULL); break; + CASE_TEST(octal_alt); EXPECT_VFPRINTF(1, "|0|01|02|034|0|", "|%#o|%#o|%#02o|%#02o|%#.0o|", 0, 1, 2, 034, 0); break; CASE_TEST(hex_nolibc); EXPECT_VFPRINTF(is_nolibc, "|f|d|", "|%x|%X|", 0xf, 0xd); break; CASE_TEST(hex_libc); EXPECT_VFPRINTF(!is_nolibc, "|f|D|", "|%x|%X|", 0xf, 0xd); break; CASE_TEST(hex_alt); EXPECT_VFPRINTF(1, "|0x1| 0x2| 0|", "|%#x|%#5x|%#5x|", 1, 2, 0); break; @@ -1853,13 +1856,13 @@ static int run_printf(int min, int max) CASE_TEST(intmax_max); EXPECT_VFPRINTF(1, "9223372036854775807", "%lld", ~0ULL >> 1); break; CASE_TEST(intmax_min); EXPECT_VFPRINTF(is_nolibc || is_glibc, "-9223372036854775808", "%Li", (~0ULL >> 1) + 1); break; CASE_TEST(uintmax_max); EXPECT_VFPRINTF(1, "18446744073709551615", "%ju", ~0ULL); break; - CASE_TEST(truncation); EXPECT_VFPRINTF(1, "0123456789012345678901234", "%s", "0123456789012345678901234"); break; + CASE_TEST(truncation); EXPECT_VFPRINTF(1, "012345678901234567890123456789", "%s", "012345678901234567890123456789"); break; CASE_TEST(string_width); EXPECT_VFPRINTF(1, " 1", "%10s", "1"); break; CASE_TEST(string_trunc); EXPECT_VFPRINTF(1, " 12345", "%10.5s", "1234567890"); break; CASE_TEST(number_width); EXPECT_VFPRINTF(1, " 1", "%10d", 1); break; CASE_TEST(number_left); EXPECT_VFPRINTF(1, "|-5 |", "|%-8d|", -5); break; CASE_TEST(string_align); EXPECT_VFPRINTF(1, "|foo |", "|%-8s|", "foo"); break; - CASE_TEST(width_trunc); EXPECT_VFPRINTF(1, " 1", "%25d", 1); break; + CASE_TEST(width_trunc); EXPECT_VFPRINTF(1, " 1", "%30d", 1); break; CASE_TEST(width_tr_lft); EXPECT_VFPRINTF(1, "1 ", "%-30d", 1); break; CASE_TEST(number_pad); EXPECT_VFPRINTF(1, "0000000005", "%010d", 5); break; CASE_TEST(number_pad); EXPECT_VFPRINTF(1, "|0000000005|0x1234|", "|%010d|%#01x|", 5, 0x1234); break; From 9bc019e7ba1f797ad7e24ebb33f4fa0be011ce5b Mon Sep 17 00:00:00 2001 From: David Laight Date: Sun, 8 Mar 2026 11:37:42 +0000 Subject: [PATCH 28/61] selftests/nolibc: Use printf variable field widths and precisions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that printf supports '*' for field widths and precisions then can be used to simplify the test output. - aligning the "[OK]" strings. - reporting the expected sprintf() output when there is a mismatch. Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260308113742.12649-18-david.laight.linux@gmail.com Signed-off-by: Thomas Weißschuh --- tools/testing/selftests/nolibc/nolibc-test.c | 26 ++++---------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 7836162dcd2f..0ca695acbc44 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -164,21 +164,6 @@ static const char *errorname(int err) } } -static void align_result(size_t llen) -{ - const size_t align = 64; - char buf[align]; - size_t n; - - if (llen >= align) - return; - - n = align - llen; - memset(buf, ' ', n); - buf[n] = '\0'; - fputs(buf, stdout); -} - enum RESULT { OK, FAIL, @@ -196,8 +181,10 @@ static void result(int llen, enum RESULT r) else msg = " [FAIL]"; - align_result(llen); - puts(msg); + llen = 64 - llen; + if (llen < 0) + llen = 0; + printf("%*s%s\n", llen, "", msg); } /* The tests below are intended to be used by the macroes, which evaluate @@ -1700,10 +1687,7 @@ static int expect_vfprintf(int llen, const char *expected, const char *fmt, ...) } if (memcmp(expected, buf, cmp_len) || buf[cmp_len]) { - /* Copy and truncate until "%.*s" supported */ - memcpy(buf, expected, cmp_len); - buf[cmp_len] = 0; - llen += printf(" should be \"%s\"", buf); + llen += printf(" should be \"%.*s\"", VFPRINTF_LEN, expected); result(llen, FAIL); return 1; } From e83b07dc8c05a55d02057b1484724a0b188f6f8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Tue, 17 Mar 2026 09:40:36 +0100 Subject: [PATCH 29/61] tools/nolibc: MIPS: fix clobbers of 'lo' and 'hi' registers on different ISAs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All MIPS ISAs before r6 use the 'lo' and 'hi' special registers. These are clobbered by system calls and need to be marked as such to avoid miscompilations. Currently nolibc ties the clobbers to the ABI. But this is wrong and leads to ISA<->ABI combinations which are not handled correctly, leading to compiler errors or miscompilations. Handle all different combinations of ABI and ISA. Fixes: a6a2a8a42972 ("tools/nolibc: MIPS: add support for N64 and N32 ABIs") Fixes: 66b6f755ad45 ("rcutorture: Import a copy of nolibc") Suggested-by: Maciej W. Rozycki Link: https://lore.kernel.org/lkml/alpine.DEB.2.21.2603141744240.55200@angie.orcam.me.uk/ Signed-off-by: Thomas Weißschuh Link: https://patch.msgid.link/20260317-nolibc-mips-clobber-v2-1-5b9a97761a9e@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/arch-mips.h | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h index bd4a9b57e1f0..bb9d580ea1b1 100644 --- a/tools/include/nolibc/arch-mips.h +++ b/tools/include/nolibc/arch-mips.h @@ -39,11 +39,19 @@ * - stack is 16-byte aligned */ +#if !defined(__mips_isa_rev) || __mips_isa_rev < 6 +#define _NOLIBC_SYSCALL_CLOBBER_HI_LO "hi", "lo" +#else +#define _NOLIBC_SYSCALL_CLOBBER_HI_LO "$0" +#endif + #if defined(_ABIO32) #define _NOLIBC_SYSCALL_CLOBBERLIST \ - "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" + "memory", "cc", "at", "v1", \ + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", \ + _NOLIBC_SYSCALL_CLOBBER_HI_LO + #define _NOLIBC_SYSCALL_STACK_RESERVE "addiu $sp, $sp, -32\n" #define _NOLIBC_SYSCALL_STACK_UNRESERVE "addiu $sp, $sp, 32\n" @@ -52,7 +60,8 @@ /* binutils, GCC and clang disagree about register aliases, use numbers instead. */ #define _NOLIBC_SYSCALL_CLOBBERLIST \ "memory", "cc", "at", "v1", \ - "10", "11", "12", "13", "14", "15", "24", "25" + "10", "11", "12", "13", "14", "15", "24", "25", \ + _NOLIBC_SYSCALL_CLOBBER_HI_LO #define _NOLIBC_SYSCALL_STACK_RESERVE #define _NOLIBC_SYSCALL_STACK_UNRESERVE From e2900176327bb2fb1e8f831ba76b1b16264bc27a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 11 Mar 2026 23:00:49 +0100 Subject: [PATCH 30/61] selftests/nolibc: add a variable for nolibc-test source files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The list of the nolibc-test source files is repeated many times. Another source file is about to be added, adding to the mess. Introduce a common variable instead. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260311-nolibc-err-h-v1-1-735a9de7f15d@weissschuh.net --- tools/testing/selftests/nolibc/Makefile | 4 ++-- tools/testing/selftests/nolibc/Makefile.include | 2 ++ tools/testing/selftests/nolibc/Makefile.nolibc | 8 ++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile index 0370489d938b..6bace04227a7 100644 --- a/tools/testing/selftests/nolibc/Makefile +++ b/tools/testing/selftests/nolibc/Makefile @@ -13,9 +13,9 @@ $(OUTPUT)/nolibc-test: CFLAGS = -nostdlib -nostdinc -static \ -isystem $(top_srcdir)/tools/include/nolibc -isystem $(top_srcdir)/usr/include \ $(CFLAGS_NOLIBC_TEST) $(OUTPUT)/nolibc-test: LDLIBS = $(if $(LLVM),,-lgcc) -$(OUTPUT)/nolibc-test: nolibc-test.c nolibc-test-linkage.c | headers +$(OUTPUT)/nolibc-test: $(NOLIBC_TEST_SOURCES) | headers -$(OUTPUT)/libc-test: nolibc-test.c nolibc-test-linkage.c +$(OUTPUT)/libc-test: $(NOLIBC_TEST_SOURCES) $(call msg,CC,,$@) $(Q)$(LINK.c) $^ -o $@ diff --git a/tools/testing/selftests/nolibc/Makefile.include b/tools/testing/selftests/nolibc/Makefile.include index 66287fafbbe0..6455373d56be 100644 --- a/tools/testing/selftests/nolibc/Makefile.include +++ b/tools/testing/selftests/nolibc/Makefile.include @@ -8,3 +8,5 @@ _CFLAGS_SANITIZER ?= $(call cc-option,-fsanitize=undefined -fsanitize-trap=all) CFLAGS_NOLIBC_TEST ?= -Os -fno-ident -fno-asynchronous-unwind-tables -std=c89 -W -Wall -Wextra \ $(call cc-option,-fno-stack-protector) $(call cc-option,-Wmissing-prototypes) \ $(_CFLAGS_STACKPROTECTOR) $(_CFLAGS_SANITIZER) + +NOLIBC_TEST_SOURCES := nolibc-test.c nolibc-test-linkage.c diff --git a/tools/testing/selftests/nolibc/Makefile.nolibc b/tools/testing/selftests/nolibc/Makefile.nolibc index f5704193038f..2d32cec1105f 100644 --- a/tools/testing/selftests/nolibc/Makefile.nolibc +++ b/tools/testing/selftests/nolibc/Makefile.nolibc @@ -302,12 +302,12 @@ sysroot/$(ARCH)/include: $(Q)$(MAKE) -C $(srctree)/tools/include/nolibc ARCH=$(ARCH) OUTPUT=$(CURDIR)/sysroot/ headers_standalone headers_check $(Q)mv sysroot/sysroot sysroot/$(ARCH) -nolibc-test: nolibc-test.c nolibc-test-linkage.c sysroot/$(ARCH)/include +nolibc-test: $(NOLIBC_TEST_SOURCES) sysroot/$(ARCH)/include $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ \ - -nostdlib -nostdinc -static -Isysroot/$(ARCH)/include nolibc-test.c nolibc-test-linkage.c $(LIBGCC) + -nostdlib -nostdinc -static -Isysroot/$(ARCH)/include $(NOLIBC_TEST_SOURCES) $(LIBGCC) -libc-test: nolibc-test.c nolibc-test-linkage.c - $(QUIET_CC)$(HOSTCC) -o $@ nolibc-test.c nolibc-test-linkage.c +libc-test: $(NOLIBC_TEST_SOURCES) + $(QUIET_CC)$(HOSTCC) -o $@ $(NOLIBC_TEST_SOURCES) # local libc-test run-libc-test: libc-test From 5662ec000d97d7a84ad4e3f34768ef08c869d0e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 11 Mar 2026 23:00:50 +0100 Subject: [PATCH 31/61] selftests/nolibc: validate NOLIBC_IGNORE_ERRNO compilation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When NOLIBC_IGNORE_ERRNO is set, various bits of nolibc are disabled. Make sure that all the ifdeffery does not result in any compilation errors by compiling a dummy source file. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260311-nolibc-err-h-v1-2-735a9de7f15d@weissschuh.net --- tools/testing/selftests/nolibc/Makefile.include | 2 +- tools/testing/selftests/nolibc/nolibc-test-ignore-errno.c | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/nolibc/nolibc-test-ignore-errno.c diff --git a/tools/testing/selftests/nolibc/Makefile.include b/tools/testing/selftests/nolibc/Makefile.include index 6455373d56be..41a0039f774c 100644 --- a/tools/testing/selftests/nolibc/Makefile.include +++ b/tools/testing/selftests/nolibc/Makefile.include @@ -9,4 +9,4 @@ CFLAGS_NOLIBC_TEST ?= -Os -fno-ident -fno-asynchronous-unwind-tables -std=c89 - $(call cc-option,-fno-stack-protector) $(call cc-option,-Wmissing-prototypes) \ $(_CFLAGS_STACKPROTECTOR) $(_CFLAGS_SANITIZER) -NOLIBC_TEST_SOURCES := nolibc-test.c nolibc-test-linkage.c +NOLIBC_TEST_SOURCES := nolibc-test.c nolibc-test-linkage.c nolibc-test-ignore-errno.c diff --git a/tools/testing/selftests/nolibc/nolibc-test-ignore-errno.c b/tools/testing/selftests/nolibc/nolibc-test-ignore-errno.c new file mode 100644 index 000000000000..aea816da4fca --- /dev/null +++ b/tools/testing/selftests/nolibc/nolibc-test-ignore-errno.c @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#define NOLIBC_IGNORE_ERRNO + +/* Include all of nolibc and make sure everything compiles */ +#include From b74be922745989573eedee2a91d987711ef968bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 18 Mar 2026 16:50:16 +0100 Subject: [PATCH 32/61] tools/nolibc: add support for program_invocation_{,short_}name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the GNU extensions 'program_invocation_name' and 'program_invocation_short_name'. These are useful to print error messages, which by convention include the program name. As these are global variables which take up memory even if not used, similar to 'errno', gate them behind NOLIBC_IGNORE_ERRNO. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260318-nolibc-err-h-v4-1-08247a694bd9@weissschuh.net --- tools/include/nolibc/crt.h | 26 +++++++++++++++ tools/include/nolibc/errno.h | 4 +++ tools/testing/selftests/nolibc/nolibc-test.c | 34 ++++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/tools/include/nolibc/crt.h b/tools/include/nolibc/crt.h index d9262998dae9..5bb492555f13 100644 --- a/tools/include/nolibc/crt.h +++ b/tools/include/nolibc/crt.h @@ -17,6 +17,7 @@ const unsigned long *_auxv __attribute__((weak)); void _start(void); static void __stack_chk_init(void); static void exit(int); +static char *strrchr(const char *s, int c); extern void (*const __preinit_array_start[])(int, char **, char**) __attribute__((weak)); extern void (*const __preinit_array_end[])(int, char **, char**) __attribute__((weak)); @@ -27,6 +28,24 @@ extern void (*const __init_array_end[])(int, char **, char**) __attribute__((wea extern void (*const __fini_array_start[])(void) __attribute__((weak)); extern void (*const __fini_array_end[])(void) __attribute__((weak)); +#ifndef NOLIBC_IGNORE_ERRNO +extern char *program_invocation_name __attribute__((weak)); +extern char *program_invocation_short_name __attribute__((weak)); + +static __inline__ +char *__nolibc_program_invocation_short_name(char *long_name) +{ + + char *short_name; + + short_name = strrchr(long_name, '/'); + if (!short_name || !short_name[0]) + return long_name; + + return short_name + 1; +} +#endif /* NOLIBC_IGNORE_ERRNO */ + void _start_c(long *sp); __attribute__((weak,used)) #if __nolibc_has_feature(undefined_behavior_sanitizer) @@ -76,6 +95,13 @@ void _start_c(long *sp) ; _auxv = auxv; +#ifndef NOLIBC_IGNORE_ERRNO + if (argc > 0 && argv[0]) { + program_invocation_name = argv[0]; + program_invocation_short_name = __nolibc_program_invocation_short_name(argv[0]); + } +#endif /* NOLIBC_IGNORE_ERRNO */ + for (ctor_func = __preinit_array_start; ctor_func < __preinit_array_end; ctor_func++) (*ctor_func)(argc, argv, envp); for (ctor_func = __init_array_start; ctor_func < __init_array_end; ctor_func++) diff --git a/tools/include/nolibc/errno.h b/tools/include/nolibc/errno.h index 08a33c40ec0c..bab83692ea1c 100644 --- a/tools/include/nolibc/errno.h +++ b/tools/include/nolibc/errno.h @@ -15,8 +15,12 @@ #ifndef NOLIBC_IGNORE_ERRNO #define SET_ERRNO(v) do { errno = (v); } while (0) int errno __attribute__((weak)); +char *program_invocation_name __attribute__((weak)) = ""; +char *program_invocation_short_name __attribute__((weak)) = ""; #else #define SET_ERRNO(v) do { } while (0) +#define program_invocation_name "" +#define program_invocation_short_name "" #endif diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 0ca695acbc44..1efd10152e83 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -42,6 +42,7 @@ #include #include #include +#include #pragma GCC diagnostic ignored "-Wmissing-prototypes" @@ -710,6 +711,37 @@ static void constructor2(int argc, char **argv, char **envp) constructor_test_value |= 1 << 1; } +int test_program_invocation_name(void) +{ + char buf[100]; + char *dirsep; + ssize_t r; + int fd; + + fd = open("/proc/self/cmdline", O_RDONLY); + if (fd == -1) + return 1; + + r = read(fd, buf, sizeof(buf)); + close(fd); + if (r < 1 || r == sizeof(buf)) + return 1; + + buf[r - 1] = '\0'; + + if (strcmp(program_invocation_name, buf) != 0) + return 1; + + dirsep = strrchr(buf, '/'); + if (!dirsep || dirsep[1] == '\0') + return 1; + + if (strcmp(program_invocation_short_name, dirsep + 1) != 0) + return 1; + + return 0; +} + int run_startup(int min, int max) { int test; @@ -724,6 +756,7 @@ int run_startup(int min, int max) #ifdef NOLIBC test_auxv = _auxv; #endif + bool proc = access("/proc", R_OK) == 0; for (test = min; test >= 0 && test <= max; test++) { int llen = 0; /* line length */ @@ -749,6 +782,7 @@ int run_startup(int min, int max) CASE_TEST(constructor); EXPECT_EQ(is_nolibc, constructor_test_value, 0x3); break; CASE_TEST(linkage_errno); EXPECT_PTREQ(1, linkage_test_errno_addr(), &errno); break; CASE_TEST(linkage_constr); EXPECT_EQ(1, linkage_test_constructor_test_value, 0x3); break; + CASE_TEST(prog_name); EXPECT_ZR(proc, test_program_invocation_name()); break; case __LINE__: return ret; /* must be last */ /* note: do not set any defaults so as to permit holes above */ From 9da0f529c089f00e6ab8b552d7407e612b7245a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 18 Mar 2026 16:50:17 +0100 Subject: [PATCH 33/61] tools/nolibc: add err.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a few convenient helpers to print error and warning messages. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260318-nolibc-err-h-v4-2-08247a694bd9@weissschuh.net --- tools/include/nolibc/Makefile | 1 + tools/include/nolibc/err.h | 87 +++++++++++++++++++++++++++++++++++ tools/include/nolibc/nolibc.h | 1 + 3 files changed, 89 insertions(+) create mode 100644 tools/include/nolibc/err.h diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile index 1958dda98895..5d242312943f 100644 --- a/tools/include/nolibc/Makefile +++ b/tools/include/nolibc/Makefile @@ -30,6 +30,7 @@ all_files := \ ctype.h \ dirent.h \ elf.h \ + err.h \ errno.h \ fcntl.h \ getopt.h \ diff --git a/tools/include/nolibc/err.h b/tools/include/nolibc/err.h new file mode 100644 index 000000000000..e22ae87a7289 --- /dev/null +++ b/tools/include/nolibc/err.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * formatted error message for NOLIBC + * Copyright (C) 2026 Thomas Weißschuh + */ + +/* make sure to include all global symbols */ +#include "nolibc.h" + +#ifndef _NOLIBC_ERR_H +#define _NOLIBC_ERR_H + +#include "errno.h" +#include "stdarg.h" +#include "sys.h" + +static __attribute__((unused)) +void vwarn(const char *fmt, va_list args) +{ + fprintf(stderr, "%s: ", program_invocation_short_name); + vfprintf(stderr, fmt, args); + fprintf(stderr, ": %m\n"); +} + +static __attribute__((unused)) +void vwarnx(const char *fmt, va_list args) +{ + fprintf(stderr, "%s: ", program_invocation_short_name); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); +} + +static __attribute__((unused)) +void warn(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vwarn(fmt, args); + va_end(args); +} + +static __attribute__((unused)) +void warnx(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vwarnx(fmt, args); + va_end(args); +} + +static __attribute__((noreturn, unused)) +void verr(int eval, const char *fmt, va_list args) +{ + vwarn(fmt, args); + exit(eval); +} + +static __attribute__((noreturn, unused)) +void verrx(int eval, const char *fmt, va_list args) +{ + warnx(fmt, args); + exit(eval); +} + +static __attribute__((noreturn, unused)) +void err(int eval, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + verr(eval, fmt, args); + va_end(args); +} + +static __attribute__((noreturn, unused)) +void errx(int eval, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + verrx(eval, fmt, args); + va_end(args); +} + +#endif /* _NOLIBC_ERR_H */ diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index d1d08b7f8599..fe8195483b6d 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -130,6 +130,7 @@ #include "getopt.h" #include "poll.h" #include "math.h" +#include "err.h" /* Used by programs to avoid std includes */ #define NOLIBC From 3eb97c4cbd4d874e7e327ec512f6169934e12b8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 18 Mar 2026 17:12:42 +0100 Subject: [PATCH 34/61] tools/nolibc: avoid -Wundef warning for __STDC_VERSION__ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With -std=c89 the macro __STDC_VERSION__ is not defined. While undefined identifiers in '#if' directives are assumed to be '0', with -Wundef a warning is emitted. Avoid the warning by explicitly falling back to '0' if __STDC_VERSION__ is not provided by the preprocessor. Fixes: 37219aa5b123 ("tools/nolibc: add __nolibc_static_assert()") Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260318-nolibc-wundef-v1-1-fcb7f9ac7298@weissschuh.net --- tools/include/nolibc/compiler.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/include/nolibc/compiler.h b/tools/include/nolibc/compiler.h index f03f84cfadce..1c410a62c528 100644 --- a/tools/include/nolibc/compiler.h +++ b/tools/include/nolibc/compiler.h @@ -47,6 +47,12 @@ # define __nolibc_fallthrough do { } while (0) #endif /* __nolibc_has_attribute(fallthrough) */ +#if defined(__STDC_VERSION__) +# define __nolibc_stdc_version __STDC_VERSION__ +#else +# define __nolibc_stdc_version 0 +#endif + #define __nolibc_version(_major, _minor, _patch) ((_major) * 10000 + (_minor) * 100 + (_patch)) #ifdef __GNUC__ @@ -63,7 +69,7 @@ # define __nolibc_clang_version 0 #endif /* __clang__ */ -#if __STDC_VERSION__ >= 201112L || \ +#if __nolibc_stdc_version >= 201112L || \ __nolibc_gnuc_version >= __nolibc_version(4, 6, 0) || \ __nolibc_clang_version >= __nolibc_version(3, 0, 0) # define __nolibc_static_assert(_t) _Static_assert(_t, "") From c8f6a4bbad3b1a96572d1ac1d5c37bae109fa664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 18 Mar 2026 17:12:43 +0100 Subject: [PATCH 35/61] selftests/nolibc: enable -Wundef MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Users might use -Wundef, so also use it in the nolibc testsuite to ensure no warnings are triggered. The existing line with warning options is getting too long, so move all warnings to a dedicated line. Acked-by: Willy Tarreau Signed-off-by: Thomas Weißschuh Link: https://patch.msgid.link/20260318-nolibc-wundef-v1-2-fcb7f9ac7298@weissschuh.net --- tools/testing/selftests/nolibc/Makefile.include | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/nolibc/Makefile.include b/tools/testing/selftests/nolibc/Makefile.include index 41a0039f774c..96fe2bc2191e 100644 --- a/tools/testing/selftests/nolibc/Makefile.include +++ b/tools/testing/selftests/nolibc/Makefile.include @@ -5,7 +5,8 @@ _CFLAGS_STACKPROTECTOR ?= $(call try-run, \ echo 'void foo(void) {}' | $(CC) -x c - -o - -S $(CLANG_CROSS_FLAGS) $(__CFLAGS_STACKPROTECTOR) | grep -q __stack_chk_guard, \ $(__CFLAGS_STACKPROTECTOR)) _CFLAGS_SANITIZER ?= $(call cc-option,-fsanitize=undefined -fsanitize-trap=all) -CFLAGS_NOLIBC_TEST ?= -Os -fno-ident -fno-asynchronous-unwind-tables -std=c89 -W -Wall -Wextra \ +CFLAGS_NOLIBC_TEST ?= -Os -fno-ident -fno-asynchronous-unwind-tables -std=c89 \ + -W -Wall -Wextra -Wundef \ $(call cc-option,-fno-stack-protector) $(call cc-option,-Wmissing-prototypes) \ $(_CFLAGS_STACKPROTECTOR) $(_CFLAGS_SANITIZER) From 6285f0881ec68034399d13552f7243e69e6e37bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Thu, 19 Mar 2026 17:20:17 +0100 Subject: [PATCH 36/61] tools/nolibc: rename sys_foo() functions to _sys_foo() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sys_foo() naming scheme used by the syscall wrappers may collide with application symbols. Especially as 'sys_' is an obvious naming scheme an application may choose for its own custom systemcall wrappers. Avoid these conflicts by using an leading underscore which moves the names into the implementation's namespace. This naming scheme was chosen over a '__nolibc_' prefix, as these functions are not an implementation detail but a documented interface meant to be used by applications. While this may break some existing users, adapting them should be straightforward. Given that nolibc is most-likely vendored, no unexpected breakage should happen. No in-tree users are affected. These conflicts happen when compiling some of the kernel selftests with nolibc. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260319-nolibc-namespacing-v1-1-33c22eaddb5e@weissschuh.net --- tools/include/nolibc/arch-s390.h | 14 +-- tools/include/nolibc/arch-sparc.h | 8 +- tools/include/nolibc/dirent.h | 4 +- tools/include/nolibc/fcntl.h | 8 +- tools/include/nolibc/nolibc.h | 6 +- tools/include/nolibc/poll.h | 4 +- tools/include/nolibc/sched.h | 8 +- tools/include/nolibc/signal.h | 2 +- tools/include/nolibc/stdlib.h | 2 +- tools/include/nolibc/sys.h | 178 ++++++++++++++-------------- tools/include/nolibc/sys/ioctl.h | 4 +- tools/include/nolibc/sys/mman.h | 16 +-- tools/include/nolibc/sys/mount.h | 6 +- tools/include/nolibc/sys/prctl.h | 6 +- tools/include/nolibc/sys/ptrace.h | 4 +- tools/include/nolibc/sys/random.h | 4 +- tools/include/nolibc/sys/reboot.h | 4 +- tools/include/nolibc/sys/resource.h | 8 +- tools/include/nolibc/sys/select.h | 4 +- tools/include/nolibc/sys/stat.h | 6 +- tools/include/nolibc/sys/time.h | 8 +- tools/include/nolibc/sys/timerfd.h | 14 +-- tools/include/nolibc/sys/uio.h | 8 +- tools/include/nolibc/sys/utsname.h | 4 +- tools/include/nolibc/sys/wait.h | 4 +- tools/include/nolibc/time.h | 40 +++---- tools/include/nolibc/unistd.h | 10 +- 27 files changed, 192 insertions(+), 192 deletions(-) diff --git a/tools/include/nolibc/arch-s390.h b/tools/include/nolibc/arch-s390.h index d301b636e083..4e69123ae484 100644 --- a/tools/include/nolibc/arch-s390.h +++ b/tools/include/nolibc/arch-s390.h @@ -167,8 +167,8 @@ struct s390_mmap_arg_struct { }; static __attribute__((unused)) -void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, - off_t offset) +void *_sys_mmap(void *addr, size_t length, int prot, int flags, int fd, + off_t offset) { struct s390_mmap_arg_struct args = { .addr = (unsigned long)addr, @@ -181,20 +181,20 @@ void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, return (void *)__nolibc_syscall1(__NR_mmap, &args); } -#define sys_mmap sys_mmap +#define _sys_mmap _sys_mmap static __attribute__((unused)) -pid_t sys_fork(void) +pid_t _sys_fork(void) { return __nolibc_syscall5(__NR_clone, 0, SIGCHLD, 0, 0, 0); } -#define sys_fork sys_fork +#define _sys_fork _sys_fork static __attribute__((unused)) -pid_t sys_vfork(void) +pid_t _sys_vfork(void) { return __nolibc_syscall5(__NR_clone, 0, CLONE_VM | CLONE_VFORK | SIGCHLD, 0, 0, 0); } -#define sys_vfork sys_vfork +#define _sys_vfork _sys_vfork #endif /* _NOLIBC_ARCH_S390_H */ diff --git a/tools/include/nolibc/arch-sparc.h b/tools/include/nolibc/arch-sparc.h index 02aca6579cb2..240539d069a8 100644 --- a/tools/include/nolibc/arch-sparc.h +++ b/tools/include/nolibc/arch-sparc.h @@ -175,7 +175,7 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s static pid_t getpid(void); static __attribute__((unused)) -pid_t sys_fork(void) +pid_t _sys_fork(void) { pid_t parent, ret; @@ -188,10 +188,10 @@ pid_t sys_fork(void) else return ret; } -#define sys_fork sys_fork +#define _sys_fork _sys_fork static __attribute__((unused)) -pid_t sys_vfork(void) +pid_t _sys_vfork(void) { pid_t parent, ret; @@ -204,6 +204,6 @@ pid_t sys_vfork(void) else return ret; } -#define sys_vfork sys_vfork +#define _sys_vfork _sys_vfork #endif /* _NOLIBC_ARCH_SPARC_H */ diff --git a/tools/include/nolibc/dirent.h b/tools/include/nolibc/dirent.h index 61a122a60327..4e02ef25e72d 100644 --- a/tools/include/nolibc/dirent.h +++ b/tools/include/nolibc/dirent.h @@ -73,7 +73,7 @@ int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) fd = ~i; - ret = sys_getdents64(fd, ldir, sizeof(buf)); + ret = _sys_getdents64(fd, ldir, sizeof(buf)); if (ret < 0) return -ret; if (ret == 0) { @@ -86,7 +86,7 @@ int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) * readdir() can only return one entry at a time. * Make sure the non-returned ones are not skipped. */ - ret = sys_lseek(fd, ldir->d_off, SEEK_SET); + ret = _sys_lseek(fd, ldir->d_off, SEEK_SET); if (ret < 0) return -ret; diff --git a/tools/include/nolibc/fcntl.h b/tools/include/nolibc/fcntl.h index 8d82768dea9d..ed2f5553c65a 100644 --- a/tools/include/nolibc/fcntl.h +++ b/tools/include/nolibc/fcntl.h @@ -19,7 +19,7 @@ */ static __attribute__((unused)) -int sys_openat(int dirfd, const char *path, int flags, mode_t mode) +int _sys_openat(int dirfd, const char *path, int flags, mode_t mode) { return __nolibc_syscall4(__NR_openat, dirfd, path, flags, mode); } @@ -37,7 +37,7 @@ int openat(int dirfd, const char *path, int flags, ...) va_end(args); } - return __sysret(sys_openat(dirfd, path, flags, mode)); + return __sysret(_sys_openat(dirfd, path, flags, mode)); } /* @@ -45,7 +45,7 @@ int openat(int dirfd, const char *path, int flags, ...) */ static __attribute__((unused)) -int sys_open(const char *path, int flags, mode_t mode) +int _sys_open(const char *path, int flags, mode_t mode) { return __nolibc_syscall4(__NR_openat, AT_FDCWD, path, flags, mode); } @@ -63,7 +63,7 @@ int open(const char *path, int flags, ...) va_end(args); } - return __sysret(sys_open(path, flags, mode)); + return __sysret(_sys_open(path, flags, mode)); } #endif /* _NOLIBC_FCNTL_H */ diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index fe8195483b6d..294bac1b9039 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -19,17 +19,17 @@ * a pointer or the negated errno value. * * - The second level is mostly architecture-independent. It is made of - * static functions called sys_() which rely on __nolibc_syscallN() + * static functions called _sys_() which rely on __nolibc_syscallN() * depending on the syscall definition. These functions are responsible * for exposing the appropriate types for the syscall arguments (int, * pointers, etc) and for setting the appropriate return type (often int). * A few of them are architecture-specific because the syscalls are not all * mapped exactly the same among architectures. For example, some archs do - * not implement select() and need pselect6() instead, so the sys_select() + * not implement select() and need pselect6() instead, so the _sys_select() * function will have to abstract this. * * - The third level is the libc call definition. It exposes the lower raw - * sys_() calls in a way that looks like what a libc usually does, + * _sys_() calls in a way that looks like what a libc usually does, * takes care of specific input values, and of setting errno upon error. * There can be minor variations compared to standard libc calls. * diff --git a/tools/include/nolibc/poll.h b/tools/include/nolibc/poll.h index ea5a6d08c43c..dbcf883da237 100644 --- a/tools/include/nolibc/poll.h +++ b/tools/include/nolibc/poll.h @@ -21,7 +21,7 @@ */ static __attribute__((unused)) -int sys_poll(struct pollfd *fds, int nfds, int timeout) +int _sys_poll(struct pollfd *fds, int nfds, int timeout) { #if defined(__NR_ppoll_time64) struct __kernel_timespec t; @@ -45,7 +45,7 @@ int sys_poll(struct pollfd *fds, int nfds, int timeout) static __attribute__((unused)) int poll(struct pollfd *fds, int nfds, int timeout) { - return __sysret(sys_poll(fds, nfds, timeout)); + return __sysret(_sys_poll(fds, nfds, timeout)); } #endif /* _NOLIBC_POLL_H */ diff --git a/tools/include/nolibc/sched.h b/tools/include/nolibc/sched.h index b1af7fa6672d..7a5f6d9484c8 100644 --- a/tools/include/nolibc/sched.h +++ b/tools/include/nolibc/sched.h @@ -19,7 +19,7 @@ */ static __attribute__((unused)) -int sys_setns(int fd, int nstype) +int _sys_setns(int fd, int nstype) { return __nolibc_syscall2(__NR_setns, fd, nstype); } @@ -27,7 +27,7 @@ int sys_setns(int fd, int nstype) static __attribute__((unused)) int setns(int fd, int nstype) { - return __sysret(sys_setns(fd, nstype)); + return __sysret(_sys_setns(fd, nstype)); } @@ -36,7 +36,7 @@ int setns(int fd, int nstype) */ static __attribute__((unused)) -int sys_unshare(int flags) +int _sys_unshare(int flags) { return __nolibc_syscall1(__NR_unshare, flags); } @@ -44,7 +44,7 @@ int sys_unshare(int flags) static __attribute__((unused)) int unshare(int flags) { - return __sysret(sys_unshare(flags)); + return __sysret(_sys_unshare(flags)); } #endif /* _NOLIBC_SCHED_H */ diff --git a/tools/include/nolibc/signal.h b/tools/include/nolibc/signal.h index ac13e53ac31d..99a0489fe3e8 100644 --- a/tools/include/nolibc/signal.h +++ b/tools/include/nolibc/signal.h @@ -20,7 +20,7 @@ int raise(int signal); __attribute__((weak,unused,section(".text.nolibc_raise"))) int raise(int signal) { - return sys_kill(sys_getpid(), signal); + return _sys_kill(_sys_getpid(), signal); } #endif /* _NOLIBC_SIGNAL_H */ diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h index 73b6a771a9f4..2113a8e7695d 100644 --- a/tools/include/nolibc/stdlib.h +++ b/tools/include/nolibc/stdlib.h @@ -55,7 +55,7 @@ void abort(void); __attribute__((weak,unused,noreturn,section(".text.nolibc_abort"))) void abort(void) { - sys_kill(sys_getpid(), SIGABRT); + _sys_kill(_sys_getpid(), SIGABRT); for (;;); } diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index bc1c76cb2f63..6335fd51f07f 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -63,7 +63,7 @@ static __inline__ int __nolibc_enosys(const char *syscall, ...) * - the "internal" ones, which matches the raw syscall interface at the * kernel level, which may sometimes slightly differ from the documented * libc-level ones. For example most of them return either a valid value - * or -errno. All of these are prefixed with "sys_". They may be called + * or -errno. All of these are prefixed with "_sys_". They may be called * by non-portable applications if desired. * * - the "exported" ones, whose interface must closely match the one @@ -85,7 +85,7 @@ static __inline__ int __nolibc_enosys(const char *syscall, ...) */ static __attribute__((unused)) -void *sys_brk(void *addr) +void *_sys_brk(void *addr) { return (void *)__nolibc_syscall1(__NR_brk, addr); } @@ -93,7 +93,7 @@ void *sys_brk(void *addr) static __attribute__((unused)) int brk(void *addr) { - void *ret = sys_brk(addr); + void *ret = _sys_brk(addr); if (!ret) { SET_ERRNO(ENOMEM); @@ -106,9 +106,9 @@ static __attribute__((unused)) void *sbrk(intptr_t inc) { /* first call to find current end */ - void *ret = sys_brk(NULL); + void *ret = _sys_brk(NULL); - if (ret && sys_brk(ret + inc) == ret + inc) + if (ret && _sys_brk(ret + inc) == ret + inc) return ret + inc; SET_ERRNO(ENOMEM); @@ -122,7 +122,7 @@ void *sbrk(intptr_t inc) */ static __attribute__((unused)) -int sys_chdir(const char *path) +int _sys_chdir(const char *path) { return __nolibc_syscall1(__NR_chdir, path); } @@ -130,11 +130,11 @@ int sys_chdir(const char *path) static __attribute__((unused)) int chdir(const char *path) { - return __sysret(sys_chdir(path)); + return __sysret(_sys_chdir(path)); } static __attribute__((unused)) -int sys_fchdir(int fildes) +int _sys_fchdir(int fildes) { return __nolibc_syscall1(__NR_fchdir, fildes); } @@ -142,7 +142,7 @@ int sys_fchdir(int fildes) static __attribute__((unused)) int fchdir(int fildes) { - return __sysret(sys_fchdir(fildes)); + return __sysret(_sys_fchdir(fildes)); } @@ -151,7 +151,7 @@ int fchdir(int fildes) */ static __attribute__((unused)) -int sys_chmod(const char *path, mode_t mode) +int _sys_chmod(const char *path, mode_t mode) { #if defined(__NR_fchmodat) return __nolibc_syscall4(__NR_fchmodat, AT_FDCWD, path, mode, 0); @@ -163,7 +163,7 @@ int sys_chmod(const char *path, mode_t mode) static __attribute__((unused)) int chmod(const char *path, mode_t mode) { - return __sysret(sys_chmod(path, mode)); + return __sysret(_sys_chmod(path, mode)); } @@ -172,7 +172,7 @@ int chmod(const char *path, mode_t mode) */ static __attribute__((unused)) -int sys_chown(const char *path, uid_t owner, gid_t group) +int _sys_chown(const char *path, uid_t owner, gid_t group) { #if defined(__NR_fchownat) return __nolibc_syscall5(__NR_fchownat, AT_FDCWD, path, owner, group, 0); @@ -184,7 +184,7 @@ int sys_chown(const char *path, uid_t owner, gid_t group) static __attribute__((unused)) int chown(const char *path, uid_t owner, gid_t group) { - return __sysret(sys_chown(path, owner, group)); + return __sysret(_sys_chown(path, owner, group)); } @@ -193,7 +193,7 @@ int chown(const char *path, uid_t owner, gid_t group) */ static __attribute__((unused)) -int sys_chroot(const char *path) +int _sys_chroot(const char *path) { return __nolibc_syscall1(__NR_chroot, path); } @@ -201,7 +201,7 @@ int sys_chroot(const char *path) static __attribute__((unused)) int chroot(const char *path) { - return __sysret(sys_chroot(path)); + return __sysret(_sys_chroot(path)); } @@ -210,7 +210,7 @@ int chroot(const char *path) */ static __attribute__((unused)) -int sys_close(int fd) +int _sys_close(int fd) { return __nolibc_syscall1(__NR_close, fd); } @@ -218,7 +218,7 @@ int sys_close(int fd) static __attribute__((unused)) int close(int fd) { - return __sysret(sys_close(fd)); + return __sysret(_sys_close(fd)); } @@ -227,7 +227,7 @@ int close(int fd) */ static __attribute__((unused)) -int sys_dup(int fd) +int _sys_dup(int fd) { return __nolibc_syscall1(__NR_dup, fd); } @@ -235,7 +235,7 @@ int sys_dup(int fd) static __attribute__((unused)) int dup(int fd) { - return __sysret(sys_dup(fd)); + return __sysret(_sys_dup(fd)); } @@ -244,7 +244,7 @@ int dup(int fd) */ static __attribute__((unused)) -int sys_dup2(int old, int new) +int _sys_dup2(int old, int new) { #if defined(__NR_dup3) int ret, nr_fcntl; @@ -269,7 +269,7 @@ int sys_dup2(int old, int new) static __attribute__((unused)) int dup2(int old, int new) { - return __sysret(sys_dup2(old, new)); + return __sysret(_sys_dup2(old, new)); } @@ -279,7 +279,7 @@ int dup2(int old, int new) #if defined(__NR_dup3) static __attribute__((unused)) -int sys_dup3(int old, int new, int flags) +int _sys_dup3(int old, int new, int flags) { return __nolibc_syscall3(__NR_dup3, old, new, flags); } @@ -287,7 +287,7 @@ int sys_dup3(int old, int new, int flags) static __attribute__((unused)) int dup3(int old, int new, int flags) { - return __sysret(sys_dup3(old, new, flags)); + return __sysret(_sys_dup3(old, new, flags)); } #endif @@ -297,7 +297,7 @@ int dup3(int old, int new, int flags) */ static __attribute__((unused)) -int sys_execve(const char *filename, char *const argv[], char *const envp[]) +int _sys_execve(const char *filename, char *const argv[], char *const envp[]) { return __nolibc_syscall3(__NR_execve, filename, argv, envp); } @@ -305,7 +305,7 @@ int sys_execve(const char *filename, char *const argv[], char *const envp[]) static __attribute__((unused)) int execve(const char *filename, char *const argv[], char *const envp[]) { - return __sysret(sys_execve(filename, argv, envp)); + return __sysret(_sys_execve(filename, argv, envp)); } @@ -314,7 +314,7 @@ int execve(const char *filename, char *const argv[], char *const envp[]) */ static __attribute__((noreturn,unused)) -void sys_exit(int status) +void _sys_exit(int status) { __nolibc_syscall1(__NR_exit, status & 255); while(1); /* shut the "noreturn" warnings. */ @@ -323,7 +323,7 @@ void sys_exit(int status) static __attribute__((noreturn,unused)) void _exit(int status) { - sys_exit(status); + _sys_exit(status); } static __attribute__((noreturn,unused)) @@ -337,9 +337,9 @@ void exit(int status) * pid_t fork(void); */ -#ifndef sys_fork +#ifndef _sys_fork static __attribute__((unused)) -pid_t sys_fork(void) +pid_t _sys_fork(void) { #if defined(__NR_clone) /* note: some archs only have clone() and not fork(). Different archs @@ -356,15 +356,15 @@ pid_t sys_fork(void) static __attribute__((unused)) pid_t fork(void) { - return __sysret(sys_fork()); + return __sysret(_sys_fork()); } -#ifndef sys_vfork +#ifndef _sys_vfork static __attribute__((unused)) -pid_t sys_vfork(void) +pid_t _sys_vfork(void) { #if defined(__NR_clone) - /* See the note in sys_fork(). */ + /* See the note in _sys_fork(). */ return __nolibc_syscall5(__NR_clone, CLONE_VM | CLONE_VFORK | SIGCHLD, 0, 0, 0, 0); #elif defined(__NR_vfork) return __nolibc_syscall0(__NR_vfork); @@ -375,7 +375,7 @@ pid_t sys_vfork(void) static __attribute__((unused)) pid_t vfork(void) { - return __sysret(sys_vfork()); + return __sysret(_sys_vfork()); } /* @@ -383,7 +383,7 @@ pid_t vfork(void) */ static __attribute__((unused)) -int sys_fsync(int fd) +int _sys_fsync(int fd) { return __nolibc_syscall1(__NR_fsync, fd); } @@ -391,7 +391,7 @@ int sys_fsync(int fd) static __attribute__((unused)) int fsync(int fd) { - return __sysret(sys_fsync(fd)); + return __sysret(_sys_fsync(fd)); } @@ -400,7 +400,7 @@ int fsync(int fd) */ static __attribute__((unused)) -int sys_getdents64(int fd, struct linux_dirent64 *dirp, int count) +int _sys_getdents64(int fd, struct linux_dirent64 *dirp, int count) { return __nolibc_syscall3(__NR_getdents64, fd, dirp, count); } @@ -408,7 +408,7 @@ int sys_getdents64(int fd, struct linux_dirent64 *dirp, int count) static __attribute__((unused)) int getdents64(int fd, struct linux_dirent64 *dirp, int count) { - return __sysret(sys_getdents64(fd, dirp, count)); + return __sysret(_sys_getdents64(fd, dirp, count)); } @@ -417,7 +417,7 @@ int getdents64(int fd, struct linux_dirent64 *dirp, int count) */ static __attribute__((unused)) -uid_t sys_geteuid(void) +uid_t _sys_geteuid(void) { #if defined(__NR_geteuid32) return __nolibc_syscall0(__NR_geteuid32); @@ -429,7 +429,7 @@ uid_t sys_geteuid(void) static __attribute__((unused)) uid_t geteuid(void) { - return sys_geteuid(); + return _sys_geteuid(); } @@ -438,7 +438,7 @@ uid_t geteuid(void) */ static __attribute__((unused)) -pid_t sys_getpgid(pid_t pid) +pid_t _sys_getpgid(pid_t pid) { return __nolibc_syscall1(__NR_getpgid, pid); } @@ -446,7 +446,7 @@ pid_t sys_getpgid(pid_t pid) static __attribute__((unused)) pid_t getpgid(pid_t pid) { - return __sysret(sys_getpgid(pid)); + return __sysret(_sys_getpgid(pid)); } @@ -455,15 +455,15 @@ pid_t getpgid(pid_t pid) */ static __attribute__((unused)) -pid_t sys_getpgrp(void) +pid_t _sys_getpgrp(void) { - return sys_getpgid(0); + return _sys_getpgid(0); } static __attribute__((unused)) pid_t getpgrp(void) { - return sys_getpgrp(); + return _sys_getpgrp(); } @@ -472,7 +472,7 @@ pid_t getpgrp(void) */ static __attribute__((unused)) -pid_t sys_getpid(void) +pid_t _sys_getpid(void) { return __nolibc_syscall0(__NR_getpid); } @@ -480,7 +480,7 @@ pid_t sys_getpid(void) static __attribute__((unused)) pid_t getpid(void) { - return sys_getpid(); + return _sys_getpid(); } @@ -489,7 +489,7 @@ pid_t getpid(void) */ static __attribute__((unused)) -pid_t sys_getppid(void) +pid_t _sys_getppid(void) { return __nolibc_syscall0(__NR_getppid); } @@ -497,7 +497,7 @@ pid_t sys_getppid(void) static __attribute__((unused)) pid_t getppid(void) { - return sys_getppid(); + return _sys_getppid(); } @@ -506,7 +506,7 @@ pid_t getppid(void) */ static __attribute__((unused)) -pid_t sys_gettid(void) +pid_t _sys_gettid(void) { return __nolibc_syscall0(__NR_gettid); } @@ -514,7 +514,7 @@ pid_t sys_gettid(void) static __attribute__((unused)) pid_t gettid(void) { - return sys_gettid(); + return _sys_gettid(); } #ifndef NOLIBC_NO_RUNTIME @@ -536,7 +536,7 @@ int getpagesize(void) */ static __attribute__((unused)) -uid_t sys_getuid(void) +uid_t _sys_getuid(void) { #if defined(__NR_getuid32) return __nolibc_syscall0(__NR_getuid32); @@ -548,7 +548,7 @@ uid_t sys_getuid(void) static __attribute__((unused)) uid_t getuid(void) { - return sys_getuid(); + return _sys_getuid(); } @@ -557,7 +557,7 @@ uid_t getuid(void) */ static __attribute__((unused)) -int sys_kill(pid_t pid, int signal) +int _sys_kill(pid_t pid, int signal) { return __nolibc_syscall2(__NR_kill, pid, signal); } @@ -565,7 +565,7 @@ int sys_kill(pid_t pid, int signal) static __attribute__((unused)) int kill(pid_t pid, int signal) { - return __sysret(sys_kill(pid, signal)); + return __sysret(_sys_kill(pid, signal)); } @@ -574,7 +574,7 @@ int kill(pid_t pid, int signal) */ static __attribute__((unused)) -int sys_link(const char *old, const char *new) +int _sys_link(const char *old, const char *new) { #if defined(__NR_linkat) return __nolibc_syscall5(__NR_linkat, AT_FDCWD, old, AT_FDCWD, new, 0); @@ -586,7 +586,7 @@ int sys_link(const char *old, const char *new) static __attribute__((unused)) int link(const char *old, const char *new) { - return __sysret(sys_link(old, new)); + return __sysret(_sys_link(old, new)); } @@ -595,7 +595,7 @@ int link(const char *old, const char *new) */ static __attribute__((unused)) -off_t sys_lseek(int fd, off_t offset, int whence) +off_t _sys_lseek(int fd, off_t offset, int whence) { #if defined(__NR_llseek) __kernel_loff_t loff = 0; @@ -617,7 +617,7 @@ off_t sys_lseek(int fd, off_t offset, int whence) static __attribute__((unused)) off_t lseek(int fd, off_t offset, int whence) { - return __sysret(sys_lseek(fd, offset, whence)); + return __sysret(_sys_lseek(fd, offset, whence)); } @@ -626,7 +626,7 @@ off_t lseek(int fd, off_t offset, int whence) */ static __attribute__((unused)) -int sys_mkdir(const char *path, mode_t mode) +int _sys_mkdir(const char *path, mode_t mode) { #if defined(__NR_mkdirat) return __nolibc_syscall3(__NR_mkdirat, AT_FDCWD, path, mode); @@ -638,7 +638,7 @@ int sys_mkdir(const char *path, mode_t mode) static __attribute__((unused)) int mkdir(const char *path, mode_t mode) { - return __sysret(sys_mkdir(path, mode)); + return __sysret(_sys_mkdir(path, mode)); } /* @@ -646,7 +646,7 @@ int mkdir(const char *path, mode_t mode) */ static __attribute__((unused)) -int sys_rmdir(const char *path) +int _sys_rmdir(const char *path) { #if defined(__NR_rmdir) return __nolibc_syscall1(__NR_rmdir, path); @@ -658,7 +658,7 @@ int sys_rmdir(const char *path) static __attribute__((unused)) int rmdir(const char *path) { - return __sysret(sys_rmdir(path)); + return __sysret(_sys_rmdir(path)); } @@ -667,7 +667,7 @@ int rmdir(const char *path) */ static __attribute__((unused)) -long sys_mknod(const char *path, mode_t mode, dev_t dev) +long _sys_mknod(const char *path, mode_t mode, dev_t dev) { #if defined(__NR_mknodat) return __nolibc_syscall4(__NR_mknodat, AT_FDCWD, path, mode, dev); @@ -679,7 +679,7 @@ long sys_mknod(const char *path, mode_t mode, dev_t dev) static __attribute__((unused)) int mknod(const char *path, mode_t mode, dev_t dev) { - return __sysret(sys_mknod(path, mode, dev)); + return __sysret(_sys_mknod(path, mode, dev)); } @@ -689,7 +689,7 @@ int mknod(const char *path, mode_t mode, dev_t dev) */ static __attribute__((unused)) -int sys_pipe2(int pipefd[2], int flags) +int _sys_pipe2(int pipefd[2], int flags) { return __nolibc_syscall2(__NR_pipe2, pipefd, flags); } @@ -697,7 +697,7 @@ int sys_pipe2(int pipefd[2], int flags) static __attribute__((unused)) int pipe2(int pipefd[2], int flags) { - return __sysret(sys_pipe2(pipefd, flags)); + return __sysret(_sys_pipe2(pipefd, flags)); } static __attribute__((unused)) @@ -712,7 +712,7 @@ int pipe(int pipefd[2]) */ static __attribute__((unused)) -int sys_pivot_root(const char *new, const char *old) +int _sys_pivot_root(const char *new, const char *old) { return __nolibc_syscall2(__NR_pivot_root, new, old); } @@ -720,7 +720,7 @@ int sys_pivot_root(const char *new, const char *old) static __attribute__((unused)) int pivot_root(const char *new, const char *old) { - return __sysret(sys_pivot_root(new, old)); + return __sysret(_sys_pivot_root(new, old)); } @@ -729,7 +729,7 @@ int pivot_root(const char *new, const char *old) */ static __attribute__((unused)) -ssize_t sys_read(int fd, void *buf, size_t count) +ssize_t _sys_read(int fd, void *buf, size_t count) { return __nolibc_syscall3(__NR_read, fd, buf, count); } @@ -737,7 +737,7 @@ ssize_t sys_read(int fd, void *buf, size_t count) static __attribute__((unused)) ssize_t read(int fd, void *buf, size_t count) { - return __sysret(sys_read(fd, buf, count)); + return __sysret(_sys_read(fd, buf, count)); } @@ -746,7 +746,7 @@ ssize_t read(int fd, void *buf, size_t count) */ static __attribute__((unused)) -int sys_sched_yield(void) +int _sys_sched_yield(void) { return __nolibc_syscall0(__NR_sched_yield); } @@ -754,7 +754,7 @@ int sys_sched_yield(void) static __attribute__((unused)) int sched_yield(void) { - return __sysret(sys_sched_yield()); + return __sysret(_sys_sched_yield()); } @@ -763,7 +763,7 @@ int sched_yield(void) */ static __attribute__((unused)) -int sys_setpgid(pid_t pid, pid_t pgid) +int _sys_setpgid(pid_t pid, pid_t pgid) { return __nolibc_syscall2(__NR_setpgid, pid, pgid); } @@ -771,7 +771,7 @@ int sys_setpgid(pid_t pid, pid_t pgid) static __attribute__((unused)) int setpgid(pid_t pid, pid_t pgid) { - return __sysret(sys_setpgid(pid, pgid)); + return __sysret(_sys_setpgid(pid, pgid)); } /* @@ -790,7 +790,7 @@ pid_t setpgrp(void) */ static __attribute__((unused)) -pid_t sys_setsid(void) +pid_t _sys_setsid(void) { return __nolibc_syscall0(__NR_setsid); } @@ -798,7 +798,7 @@ pid_t sys_setsid(void) static __attribute__((unused)) pid_t setsid(void) { - return __sysret(sys_setsid()); + return __sysret(_sys_setsid()); } @@ -807,7 +807,7 @@ pid_t setsid(void) */ static __attribute__((unused)) -int sys_symlink(const char *old, const char *new) +int _sys_symlink(const char *old, const char *new) { #if defined(__NR_symlinkat) return __nolibc_syscall3(__NR_symlinkat, old, AT_FDCWD, new); @@ -819,7 +819,7 @@ int sys_symlink(const char *old, const char *new) static __attribute__((unused)) int symlink(const char *old, const char *new) { - return __sysret(sys_symlink(old, new)); + return __sysret(_sys_symlink(old, new)); } @@ -828,7 +828,7 @@ int symlink(const char *old, const char *new) */ static __attribute__((unused)) -mode_t sys_umask(mode_t mode) +mode_t _sys_umask(mode_t mode) { return __nolibc_syscall1(__NR_umask, mode); } @@ -836,7 +836,7 @@ mode_t sys_umask(mode_t mode) static __attribute__((unused)) mode_t umask(mode_t mode) { - return sys_umask(mode); + return _sys_umask(mode); } @@ -845,7 +845,7 @@ mode_t umask(mode_t mode) */ static __attribute__((unused)) -int sys_umount2(const char *path, int flags) +int _sys_umount2(const char *path, int flags) { return __nolibc_syscall2(__NR_umount2, path, flags); } @@ -853,7 +853,7 @@ int sys_umount2(const char *path, int flags) static __attribute__((unused)) int umount2(const char *path, int flags) { - return __sysret(sys_umount2(path, flags)); + return __sysret(_sys_umount2(path, flags)); } @@ -862,7 +862,7 @@ int umount2(const char *path, int flags) */ static __attribute__((unused)) -int sys_unlink(const char *path) +int _sys_unlink(const char *path) { #if defined(__NR_unlinkat) return __nolibc_syscall3(__NR_unlinkat, AT_FDCWD, path, 0); @@ -874,7 +874,7 @@ int sys_unlink(const char *path) static __attribute__((unused)) int unlink(const char *path) { - return __sysret(sys_unlink(path)); + return __sysret(_sys_unlink(path)); } @@ -883,7 +883,7 @@ int unlink(const char *path) */ static __attribute__((unused)) -ssize_t sys_write(int fd, const void *buf, size_t count) +ssize_t _sys_write(int fd, const void *buf, size_t count) { return __nolibc_syscall3(__NR_write, fd, buf, count); } @@ -891,7 +891,7 @@ ssize_t sys_write(int fd, const void *buf, size_t count) static __attribute__((unused)) ssize_t write(int fd, const void *buf, size_t count) { - return __sysret(sys_write(fd, buf, count)); + return __sysret(_sys_write(fd, buf, count)); } @@ -900,7 +900,7 @@ ssize_t write(int fd, const void *buf, size_t count) */ static __attribute__((unused)) -int sys_memfd_create(const char *name, unsigned int flags) +int _sys_memfd_create(const char *name, unsigned int flags) { return __nolibc_syscall2(__NR_memfd_create, name, flags); } @@ -908,7 +908,7 @@ int sys_memfd_create(const char *name, unsigned int flags) static __attribute__((unused)) int memfd_create(const char *name, unsigned int flags) { - return __sysret(sys_memfd_create(name, flags)); + return __sysret(_sys_memfd_create(name, flags)); } #endif /* _NOLIBC_SYS_H */ diff --git a/tools/include/nolibc/sys/ioctl.h b/tools/include/nolibc/sys/ioctl.h index 289cc1494f2c..f062a7b806cf 100644 --- a/tools/include/nolibc/sys/ioctl.h +++ b/tools/include/nolibc/sys/ioctl.h @@ -19,11 +19,11 @@ */ static __attribute__((unused)) -long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +long _sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) { return __nolibc_syscall3(__NR_ioctl, fd, cmd, arg); } -#define ioctl(fd, cmd, arg) __sysret(sys_ioctl(fd, cmd, (unsigned long)(arg))) +#define ioctl(fd, cmd, arg) __sysret(_sys_ioctl(fd, cmd, (unsigned long)(arg))) #endif /* _NOLIBC_SYS_IOCTL_H */ diff --git a/tools/include/nolibc/sys/mman.h b/tools/include/nolibc/sys/mman.h index 5679fdda0a87..91d77a51412d 100644 --- a/tools/include/nolibc/sys/mman.h +++ b/tools/include/nolibc/sys/mman.h @@ -13,10 +13,10 @@ #include "../arch.h" #include "../sys.h" -#ifndef sys_mmap +#ifndef _sys_mmap static __attribute__((unused)) -void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, - off_t offset) +void *_sys_mmap(void *addr, size_t length, int prot, int flags, int fd, + off_t offset) { int n; @@ -34,7 +34,7 @@ void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, static __attribute__((unused)) void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { - void *ret = sys_mmap(addr, length, prot, flags, fd, offset); + void *ret = _sys_mmap(addr, length, prot, flags, fd, offset); if ((unsigned long)ret >= -4095UL) { SET_ERRNO(-(long)ret); @@ -44,7 +44,7 @@ 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) +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); @@ -53,7 +53,7 @@ void *sys_mremap(void *old_address, size_t old_size, size_t new_size, int flags, static __attribute__((unused)) void *mremap(void *old_address, size_t old_size, size_t new_size, int flags, void *new_address) { - void *ret = sys_mremap(old_address, old_size, new_size, flags, new_address); + void *ret = _sys_mremap(old_address, old_size, new_size, flags, new_address); if ((unsigned long)ret >= -4095UL) { SET_ERRNO(-(long)ret); @@ -63,7 +63,7 @@ void *mremap(void *old_address, size_t old_size, size_t new_size, int flags, voi } static __attribute__((unused)) -int sys_munmap(void *addr, size_t length) +int _sys_munmap(void *addr, size_t length) { return __nolibc_syscall2(__NR_munmap, addr, length); } @@ -71,7 +71,7 @@ int sys_munmap(void *addr, size_t length) static __attribute__((unused)) int munmap(void *addr, size_t length) { - return __sysret(sys_munmap(addr, length)); + return __sysret(_sys_munmap(addr, length)); } #endif /* _NOLIBC_SYS_MMAN_H */ diff --git a/tools/include/nolibc/sys/mount.h b/tools/include/nolibc/sys/mount.h index 1f8d14da276f..8d3128ebc536 100644 --- a/tools/include/nolibc/sys/mount.h +++ b/tools/include/nolibc/sys/mount.h @@ -20,8 +20,8 @@ * const void *data); */ static __attribute__((unused)) -int sys_mount(const char *src, const char *tgt, const char *fst, - unsigned long flags, const void *data) +int _sys_mount(const char *src, const char *tgt, const char *fst, + unsigned long flags, const void *data) { return __nolibc_syscall5(__NR_mount, src, tgt, fst, flags, data); } @@ -31,7 +31,7 @@ int mount(const char *src, const char *tgt, const char *fst, unsigned long flags, const void *data) { - return __sysret(sys_mount(src, tgt, fst, flags, data)); + return __sysret(_sys_mount(src, tgt, fst, flags, data)); } #endif /* _NOLIBC_SYS_MOUNT_H */ diff --git a/tools/include/nolibc/sys/prctl.h b/tools/include/nolibc/sys/prctl.h index b019b4618328..3e11d3e5af12 100644 --- a/tools/include/nolibc/sys/prctl.h +++ b/tools/include/nolibc/sys/prctl.h @@ -20,8 +20,8 @@ */ static __attribute__((unused)) -int sys_prctl(int option, unsigned long arg2, unsigned long arg3, - unsigned long arg4, unsigned long arg5) +int _sys_prctl(int option, unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5) { return __nolibc_syscall5(__NR_prctl, option, arg2, arg3, arg4, arg5); } @@ -30,7 +30,7 @@ static __attribute__((unused)) int prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) { - return __sysret(sys_prctl(option, arg2, arg3, arg4, arg5)); + return __sysret(_sys_prctl(option, arg2, arg3, arg4, arg5)); } #endif /* _NOLIBC_SYS_PRCTL_H */ diff --git a/tools/include/nolibc/sys/ptrace.h b/tools/include/nolibc/sys/ptrace.h index 6cde77e93ceb..4c4820f4f336 100644 --- a/tools/include/nolibc/sys/ptrace.h +++ b/tools/include/nolibc/sys/ptrace.h @@ -19,7 +19,7 @@ * long ptrace(int op, pid_t pid, void *addr, void *data); */ static __attribute__((unused)) -long sys_ptrace(int op, pid_t pid, void *addr, void *data) +long _sys_ptrace(int op, pid_t pid, void *addr, void *data) { return __nolibc_syscall4(__NR_ptrace, op, pid, addr, data); } @@ -27,7 +27,7 @@ long sys_ptrace(int op, pid_t pid, void *addr, void *data) static __attribute__((unused)) ssize_t ptrace(int op, pid_t pid, void *addr, void *data) { - return __sysret(sys_ptrace(op, pid, addr, data)); + return __sysret(_sys_ptrace(op, pid, addr, data)); } #endif /* _NOLIBC_SYS_PTRACE_H */ diff --git a/tools/include/nolibc/sys/random.h b/tools/include/nolibc/sys/random.h index af9a270fc29d..6d055b00bd90 100644 --- a/tools/include/nolibc/sys/random.h +++ b/tools/include/nolibc/sys/random.h @@ -20,7 +20,7 @@ */ static __attribute__((unused)) -ssize_t sys_getrandom(void *buf, size_t buflen, unsigned int flags) +ssize_t _sys_getrandom(void *buf, size_t buflen, unsigned int flags) { return __nolibc_syscall3(__NR_getrandom, buf, buflen, flags); } @@ -28,7 +28,7 @@ ssize_t sys_getrandom(void *buf, size_t buflen, unsigned int flags) static __attribute__((unused)) ssize_t getrandom(void *buf, size_t buflen, unsigned int flags) { - return __sysret(sys_getrandom(buf, buflen, flags)); + return __sysret(_sys_getrandom(buf, buflen, flags)); } #endif /* _NOLIBC_SYS_RANDOM_H */ diff --git a/tools/include/nolibc/sys/reboot.h b/tools/include/nolibc/sys/reboot.h index 20431025ccc6..73cbca37c1f0 100644 --- a/tools/include/nolibc/sys/reboot.h +++ b/tools/include/nolibc/sys/reboot.h @@ -20,7 +20,7 @@ */ static __attribute__((unused)) -ssize_t sys_reboot(int magic1, int magic2, int cmd, void *arg) +ssize_t _sys_reboot(int magic1, int magic2, int cmd, void *arg) { return __nolibc_syscall4(__NR_reboot, magic1, magic2, cmd, arg); } @@ -28,7 +28,7 @@ ssize_t sys_reboot(int magic1, int magic2, int cmd, void *arg) static __attribute__((unused)) int reboot(int cmd) { - return __sysret(sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, NULL)); + return __sysret(_sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, NULL)); } #endif /* _NOLIBC_SYS_REBOOT_H */ diff --git a/tools/include/nolibc/sys/resource.h b/tools/include/nolibc/sys/resource.h index ff3c65f5fade..f35de1c4e9ad 100644 --- a/tools/include/nolibc/sys/resource.h +++ b/tools/include/nolibc/sys/resource.h @@ -20,8 +20,8 @@ */ static __attribute__((unused)) -int sys_prlimit64(pid_t pid, int resource, - const struct rlimit64 *new_limit, struct rlimit64 *old_limit) +int _sys_prlimit64(pid_t pid, int resource, + const struct rlimit64 *new_limit, struct rlimit64 *old_limit) { return __nolibc_syscall4(__NR_prlimit64, pid, resource, new_limit, old_limit); } @@ -32,7 +32,7 @@ int getrlimit(int resource, struct rlimit *rlim) struct rlimit64 rlim64; int ret; - ret = __sysret(sys_prlimit64(0, resource, NULL, &rlim64)); + ret = __sysret(_sys_prlimit64(0, resource, NULL, &rlim64)); rlim->rlim_cur = rlim64.rlim_cur; rlim->rlim_max = rlim64.rlim_max; @@ -47,7 +47,7 @@ int setrlimit(int resource, const struct rlimit *rlim) .rlim_max = rlim->rlim_max, }; - return __sysret(sys_prlimit64(0, resource, &rlim64, NULL)); + return __sysret(_sys_prlimit64(0, resource, &rlim64, NULL)); } #endif /* _NOLIBC_SYS_RESOURCE_H */ diff --git a/tools/include/nolibc/sys/select.h b/tools/include/nolibc/sys/select.h index fcbcf4d0f8d1..6d65d9ef3d6a 100644 --- a/tools/include/nolibc/sys/select.h +++ b/tools/include/nolibc/sys/select.h @@ -61,7 +61,7 @@ typedef struct { */ static __attribute__((unused)) -int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout) +int _sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout) { #if defined(__NR_pselect6_time64) struct __kernel_timespec t; @@ -87,7 +87,7 @@ int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeva static __attribute__((unused)) int select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout) { - return __sysret(sys_select(nfds, rfds, wfds, efds, timeout)); + return __sysret(_sys_select(nfds, rfds, wfds, efds, timeout)); } diff --git a/tools/include/nolibc/sys/stat.h b/tools/include/nolibc/sys/stat.h index 2777217793db..b2ef34a617ca 100644 --- a/tools/include/nolibc/sys/stat.h +++ b/tools/include/nolibc/sys/stat.h @@ -23,7 +23,7 @@ */ static __attribute__((unused)) -int sys_statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf) +int _sys_statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf) { #ifdef __NR_statx return __nolibc_syscall5(__NR_statx, fd, path, flags, mask, buf); @@ -35,7 +35,7 @@ int sys_statx(int fd, const char *path, int flags, unsigned int mask, struct sta static __attribute__((unused)) int statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf) { - return __sysret(sys_statx(fd, path, flags, mask, buf)); + return __sysret(_sys_statx(fd, path, flags, mask, buf)); } @@ -45,7 +45,7 @@ int fstatat(int fd, const char *path, struct stat *buf, int flag) struct statx statx; long ret; - ret = __sysret(sys_statx(fd, path, flag | AT_NO_AUTOMOUNT, STATX_BASIC_STATS, &statx)); + ret = __sysret(_sys_statx(fd, path, flag | AT_NO_AUTOMOUNT, STATX_BASIC_STATS, &statx)); if (ret == -1) return ret; diff --git a/tools/include/nolibc/sys/time.h b/tools/include/nolibc/sys/time.h index afdb7e326df1..c3bb47f69f06 100644 --- a/tools/include/nolibc/sys/time.h +++ b/tools/include/nolibc/sys/time.h @@ -13,21 +13,21 @@ #include "../arch.h" #include "../sys.h" -static int sys_clock_gettime(clockid_t clockid, struct timespec *tp); +static int _sys_clock_gettime(clockid_t clockid, struct timespec *tp); /* * int gettimeofday(struct timeval *tv, struct timezone *tz); */ static __attribute__((unused)) -int sys_gettimeofday(struct timeval *tv, struct timezone *tz) +int _sys_gettimeofday(struct timeval *tv, struct timezone *tz) { (void) tz; /* Non-NULL tz is undefined behaviour */ struct timespec tp; int ret; - ret = sys_clock_gettime(CLOCK_REALTIME, &tp); + ret = _sys_clock_gettime(CLOCK_REALTIME, &tp); if (!ret && tv) { tv->tv_sec = tp.tv_sec; tv->tv_usec = (uint32_t)tp.tv_nsec / 1000; @@ -39,7 +39,7 @@ int sys_gettimeofday(struct timeval *tv, struct timezone *tz) static __attribute__((unused)) int gettimeofday(struct timeval *tv, struct timezone *tz) { - return __sysret(sys_gettimeofday(tv, tz)); + return __sysret(_sys_gettimeofday(tv, tz)); } #endif /* _NOLIBC_SYS_TIME_H */ diff --git a/tools/include/nolibc/sys/timerfd.h b/tools/include/nolibc/sys/timerfd.h index 87f89c789b3b..cb7fef37a7a4 100644 --- a/tools/include/nolibc/sys/timerfd.h +++ b/tools/include/nolibc/sys/timerfd.h @@ -17,7 +17,7 @@ static __attribute__((unused)) -int sys_timerfd_create(int clockid, int flags) +int _sys_timerfd_create(int clockid, int flags) { return __nolibc_syscall2(__NR_timerfd_create, clockid, flags); } @@ -25,12 +25,12 @@ int sys_timerfd_create(int clockid, int flags) static __attribute__((unused)) int timerfd_create(int clockid, int flags) { - return __sysret(sys_timerfd_create(clockid, flags)); + return __sysret(_sys_timerfd_create(clockid, flags)); } static __attribute__((unused)) -int sys_timerfd_gettime(int fd, struct itimerspec *curr_value) +int _sys_timerfd_gettime(int fd, struct itimerspec *curr_value) { #if defined(__NR_timerfd_gettime64) __nolibc_assert_time64_type(curr_value->it_value.tv_sec); @@ -44,13 +44,13 @@ int sys_timerfd_gettime(int fd, struct itimerspec *curr_value) static __attribute__((unused)) int timerfd_gettime(int fd, struct itimerspec *curr_value) { - return __sysret(sys_timerfd_gettime(fd, curr_value)); + return __sysret(_sys_timerfd_gettime(fd, curr_value)); } static __attribute__((unused)) -int sys_timerfd_settime(int fd, int flags, - const struct itimerspec *new_value, struct itimerspec *old_value) +int _sys_timerfd_settime(int fd, int flags, + const struct itimerspec *new_value, struct itimerspec *old_value) { #if defined(__NR_timerfd_settime64) __nolibc_assert_time64_type(new_value->it_value.tv_sec); @@ -65,7 +65,7 @@ static __attribute__((unused)) int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itimerspec *old_value) { - return __sysret(sys_timerfd_settime(fd, flags, new_value, old_value)); + return __sysret(_sys_timerfd_settime(fd, flags, new_value, old_value)); } #endif /* _NOLIBC_SYS_TIMERFD_H */ diff --git a/tools/include/nolibc/sys/uio.h b/tools/include/nolibc/sys/uio.h index 21ff8c626dfe..06bf17ddd5d2 100644 --- a/tools/include/nolibc/sys/uio.h +++ b/tools/include/nolibc/sys/uio.h @@ -19,7 +19,7 @@ * ssize_t readv(int fd, const struct iovec *iovec, int count); */ static __attribute__((unused)) -ssize_t sys_readv(int fd, const struct iovec *iovec, int count) +ssize_t _sys_readv(int fd, const struct iovec *iovec, int count) { return __nolibc_syscall3(__NR_readv, fd, iovec, count); } @@ -27,14 +27,14 @@ ssize_t sys_readv(int fd, const struct iovec *iovec, int count) static __attribute__((unused)) ssize_t readv(int fd, const struct iovec *iovec, int count) { - return __sysret(sys_readv(fd, iovec, count)); + return __sysret(_sys_readv(fd, iovec, count)); } /* * ssize_t writev(int fd, const struct iovec *iovec, int count); */ static __attribute__((unused)) -ssize_t sys_writev(int fd, const struct iovec *iovec, int count) +ssize_t _sys_writev(int fd, const struct iovec *iovec, int count) { return __nolibc_syscall3(__NR_writev, fd, iovec, count); } @@ -42,7 +42,7 @@ ssize_t sys_writev(int fd, const struct iovec *iovec, int count) static __attribute__((unused)) ssize_t writev(int fd, const struct iovec *iovec, int count) { - return __sysret(sys_writev(fd, iovec, count)); + return __sysret(_sys_writev(fd, iovec, count)); } diff --git a/tools/include/nolibc/sys/utsname.h b/tools/include/nolibc/sys/utsname.h index 25992d644525..2aaf873b7985 100644 --- a/tools/include/nolibc/sys/utsname.h +++ b/tools/include/nolibc/sys/utsname.h @@ -28,7 +28,7 @@ struct utsname { }; static __attribute__((unused)) -int sys_uname(struct utsname *buf) +int _sys_uname(struct utsname *buf) { return __nolibc_syscall1(__NR_uname, buf); } @@ -36,7 +36,7 @@ int sys_uname(struct utsname *buf) static __attribute__((unused)) int uname(struct utsname *buf) { - return __sysret(sys_uname(buf)); + return __sysret(_sys_uname(buf)); } #endif /* _NOLIBC_SYS_UTSNAME_H */ diff --git a/tools/include/nolibc/sys/wait.h b/tools/include/nolibc/sys/wait.h index bc11100e7f82..7a1feb2b66fc 100644 --- a/tools/include/nolibc/sys/wait.h +++ b/tools/include/nolibc/sys/wait.h @@ -21,7 +21,7 @@ */ static __attribute__((unused)) -int sys_waitid(int which, pid_t pid, siginfo_t *infop, int options, struct rusage *rusage) +int _sys_waitid(int which, pid_t pid, siginfo_t *infop, int options, struct rusage *rusage) { return __nolibc_syscall5(__NR_waitid, which, pid, infop, options, rusage); } @@ -29,7 +29,7 @@ int sys_waitid(int which, pid_t pid, siginfo_t *infop, int options, struct rusag static __attribute__((unused)) int waitid(int which, pid_t pid, siginfo_t *infop, int options) { - return __sysret(sys_waitid(which, pid, infop, options, NULL)); + return __sysret(_sys_waitid(which, pid, infop, options, NULL)); } diff --git a/tools/include/nolibc/time.h b/tools/include/nolibc/time.h index 4d93d5188cec..9ba930710ff9 100644 --- a/tools/include/nolibc/time.h +++ b/tools/include/nolibc/time.h @@ -33,7 +33,7 @@ */ static __attribute__((unused)) -int sys_clock_getres(clockid_t clockid, struct timespec *res) +int _sys_clock_getres(clockid_t clockid, struct timespec *res) { #if defined(__NR_clock_getres_time64) __nolibc_assert_time64_type(res->tv_sec); @@ -47,11 +47,11 @@ int sys_clock_getres(clockid_t clockid, struct timespec *res) static __attribute__((unused)) int clock_getres(clockid_t clockid, struct timespec *res) { - return __sysret(sys_clock_getres(clockid, res)); + return __sysret(_sys_clock_getres(clockid, res)); } static __attribute__((unused)) -int sys_clock_gettime(clockid_t clockid, struct timespec *tp) +int _sys_clock_gettime(clockid_t clockid, struct timespec *tp) { #if defined(__NR_clock_gettime64) __nolibc_assert_time64_type(tp->tv_sec); @@ -65,11 +65,11 @@ int sys_clock_gettime(clockid_t clockid, struct timespec *tp) static __attribute__((unused)) int clock_gettime(clockid_t clockid, struct timespec *tp) { - return __sysret(sys_clock_gettime(clockid, tp)); + return __sysret(_sys_clock_gettime(clockid, tp)); } static __attribute__((unused)) -int sys_clock_settime(clockid_t clockid, struct timespec *tp) +int _sys_clock_settime(clockid_t clockid, struct timespec *tp) { #if defined(__NR_clock_settime64) __nolibc_assert_time64_type(tp->tv_sec); @@ -83,12 +83,12 @@ int sys_clock_settime(clockid_t clockid, struct timespec *tp) static __attribute__((unused)) int clock_settime(clockid_t clockid, struct timespec *tp) { - return __sysret(sys_clock_settime(clockid, tp)); + return __sysret(_sys_clock_settime(clockid, tp)); } static __attribute__((unused)) -int sys_clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqtp, - struct timespec *rmtp) +int _sys_clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqtp, + struct timespec *rmtp) { #if defined(__NR_clock_nanosleep_time64) __nolibc_assert_time64_type(rqtp->tv_sec); @@ -104,7 +104,7 @@ int clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqtp, struct timespec *rmtp) { /* Directly return a positive error number */ - return -sys_clock_nanosleep(clockid, flags, rqtp, rmtp); + return -_sys_clock_nanosleep(clockid, flags, rqtp, rmtp); } static __inline__ @@ -116,7 +116,7 @@ double difftime(time_t time1, time_t time2) static __inline__ int nanosleep(const struct timespec *rqtp, struct timespec *rmtp) { - return __sysret(sys_clock_nanosleep(CLOCK_REALTIME, 0, rqtp, rmtp)); + return __sysret(_sys_clock_nanosleep(CLOCK_REALTIME, 0, rqtp, rmtp)); } @@ -126,7 +126,7 @@ time_t time(time_t *tptr) struct timeval tv; /* note, cannot fail here */ - sys_gettimeofday(&tv, NULL); + _sys_gettimeofday(&tv, NULL); if (tptr) *tptr = tv.tv_sec; @@ -141,7 +141,7 @@ time_t time(time_t *tptr) */ static __attribute__((unused)) -int sys_timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) +int _sys_timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) { return __nolibc_syscall3(__NR_timer_create, clockid, evp, timerid); } @@ -149,11 +149,11 @@ int sys_timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) static __attribute__((unused)) int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) { - return __sysret(sys_timer_create(clockid, evp, timerid)); + return __sysret(_sys_timer_create(clockid, evp, timerid)); } static __attribute__((unused)) -int sys_timer_delete(timer_t timerid) +int _sys_timer_delete(timer_t timerid) { return __nolibc_syscall1(__NR_timer_delete, timerid); } @@ -161,11 +161,11 @@ int sys_timer_delete(timer_t timerid) static __attribute__((unused)) int timer_delete(timer_t timerid) { - return __sysret(sys_timer_delete(timerid)); + return __sysret(_sys_timer_delete(timerid)); } static __attribute__((unused)) -int sys_timer_gettime(timer_t timerid, struct itimerspec *curr_value) +int _sys_timer_gettime(timer_t timerid, struct itimerspec *curr_value) { #if defined(__NR_timer_gettime64) __nolibc_assert_time64_type(curr_value->it_value.tv_sec); @@ -179,12 +179,12 @@ int sys_timer_gettime(timer_t timerid, struct itimerspec *curr_value) static __attribute__((unused)) int timer_gettime(timer_t timerid, struct itimerspec *curr_value) { - return __sysret(sys_timer_gettime(timerid, curr_value)); + return __sysret(_sys_timer_gettime(timerid, curr_value)); } static __attribute__((unused)) -int sys_timer_settime(timer_t timerid, int flags, - const struct itimerspec *new_value, struct itimerspec *old_value) +int _sys_timer_settime(timer_t timerid, int flags, + const struct itimerspec *new_value, struct itimerspec *old_value) { #if defined(__NR_timer_settime64) __nolibc_assert_time64_type(new_value->it_value.tv_sec); @@ -199,7 +199,7 @@ static __attribute__((unused)) int timer_settime(timer_t timerid, int flags, const struct itimerspec *new_value, struct itimerspec *old_value) { - return __sysret(sys_timer_settime(timerid, flags, new_value, old_value)); + return __sysret(_sys_timer_settime(timerid, flags, new_value, old_value)); } #endif /* _NOLIBC_TIME_H */ diff --git a/tools/include/nolibc/unistd.h b/tools/include/nolibc/unistd.h index 6456d60daa02..5882a6862066 100644 --- a/tools/include/nolibc/unistd.h +++ b/tools/include/nolibc/unistd.h @@ -31,7 +31,7 @@ */ static __attribute__((unused)) -int sys_faccessat(int fd, const char *path, int amode, int flag) +int _sys_faccessat(int fd, const char *path, int amode, int flag) { return __nolibc_syscall4(__NR_faccessat, fd, path, amode, flag); } @@ -39,7 +39,7 @@ int sys_faccessat(int fd, const char *path, int amode, int flag) static __attribute__((unused)) int faccessat(int fd, const char *path, int amode, int flag) { - return __sysret(sys_faccessat(fd, path, amode, flag)); + return __sysret(_sys_faccessat(fd, path, amode, flag)); } static __attribute__((unused)) @@ -54,7 +54,7 @@ int msleep(unsigned int msecs) { struct timeval my_timeval = { msecs / 1000, (msecs % 1000) * 1000 }; - if (sys_select(0, NULL, NULL, NULL, &my_timeval) < 0) + if (_sys_select(0, NULL, NULL, NULL, &my_timeval) < 0) return (my_timeval.tv_sec * 1000) + (my_timeval.tv_usec / 1000) + !!(my_timeval.tv_usec % 1000); @@ -67,7 +67,7 @@ unsigned int sleep(unsigned int seconds) { struct timeval my_timeval = { seconds, 0 }; - if (sys_select(0, NULL, NULL, NULL, &my_timeval) < 0) + if (_sys_select(0, NULL, NULL, NULL, &my_timeval) < 0) return my_timeval.tv_sec + !!my_timeval.tv_usec; else return 0; @@ -78,7 +78,7 @@ int usleep(unsigned int usecs) { struct timeval my_timeval = { usecs / 1000000, usecs % 1000000 }; - return sys_select(0, NULL, NULL, NULL, &my_timeval); + return _sys_select(0, NULL, NULL, NULL, &my_timeval); } static __attribute__((unused)) From 1dff9ac2c85860af67a74777fa6d31c2ad07a15a Mon Sep 17 00:00:00 2001 From: David Laight Date: Mon, 23 Mar 2026 11:22:47 +0000 Subject: [PATCH 37/61] tools/nolibc/printf: Support negative variable width and precision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For (eg) "%*.*s" treat a negative field width as a request to left align the output (the same as the '-' flag), and a negative precision to request the default precision. Set the default precision to -1 (not INT_MAX) and add explicit checks to the string handling for negative values (makes the tet unsigned). For numeric output check for 'precision >= 0' instead of testing _NOLIBC_PF_FLAGS_CONTAIN(flags, '.'). This needs an inverted test, some extra goto and removes an indentation. The changed conditionals fix printf("%0-#o", 0) - but '0' and '-' shouldn't both be specified. Signed-off-by: David Laight Link: https://patch.msgid.link/20260323112247.3196-1-david.laight.linux@gmail.com Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/stdio.h | 68 +++++++++++--------- tools/testing/selftests/nolibc/nolibc-test.c | 5 +- 2 files changed, 41 insertions(+), 32 deletions(-) diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 8f7e1948a651..b6d14a58cfe7 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -347,6 +347,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list char *out; const char *outstr; unsigned int sign_prefix; + int got_width; written = 0; while (1) { @@ -377,23 +378,28 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list } /* Width and precision */ - for (;; ch = *fmt++) { + for (got_width = 0;; ch = *fmt++) { if (ch == '*') { - precision = va_arg(args, unsigned int); + precision = va_arg(args, int); ch = *fmt++; } else { for (precision = 0; ch >= '0' && ch <= '9'; ch = *fmt++) precision = precision * 10 + (ch - '0'); } - if (_NOLIBC_PF_FLAGS_CONTAIN(flags, '.')) + if (got_width) break; width = precision; if (ch != '.') { /* Default precision for strings */ - precision = INT_MAX; + precision = -1; break; } - flags |= _NOLIBC_PF_FLAG('.'); + got_width = 1; + } + /* A negative width (e.g. from "%*s") requests left justify. */ + if (width < 0) { + width = -width; + flags |= _NOLIBC_PF_FLAG('-'); } /* Length modifier. @@ -457,7 +463,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list if (!outstr) { outstr = "(null)"; /* Match glibc, nothing output if precision too small */ - len = precision >= 6 ? 6 : 0; + len = precision < 0 || precision >= 6 ? 6 : 0; goto do_output; } goto do_strlen_output; @@ -533,32 +539,34 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list } /* Add zero padding */ - if (_NOLIBC_PF_FLAGS_CONTAIN(flags, '0', '.')) { - if (!_NOLIBC_PF_FLAGS_CONTAIN(flags, '.')) { - if (_NOLIBC_PF_FLAGS_CONTAIN(flags, '-')) - /* Left justify overrides zero pad */ - goto prepend_sign; - /* eg "%05d", Zero pad to field width less sign. - * Note that precision can end up negative so all - * the variables have to be 'signed int'. - */ - precision = width; - if (sign_prefix) { + if (precision < 0) { + /* No explicit precision (or negative from "%.*s"). */ + if (!_NOLIBC_PF_FLAGS_CONTAIN(flags, '0')) + goto no_zero_padding; + if (_NOLIBC_PF_FLAGS_CONTAIN(flags, '-')) + /* Left justify overrides zero pad */ + goto no_zero_padding; + /* eg "%05d", Zero pad to field width less sign. + * Note that precision can end up negative so all + * the variables have to be 'signed int'. + */ + precision = width; + if (sign_prefix) { + precision--; + if (sign_prefix >= 256) precision--; - if (sign_prefix >= 256) - precision--; - } - } - if (precision > 31) - /* Don't run off the start of outbuf[], arbitrary limit - * longer than the longest number field. */ - precision = 31; - for (; len < precision; len++) { - /* Stop gcc generating horrid code and memset(). */ - _NOLIBC_OPTIMIZER_HIDE_VAR(len); - *--out = '0'; } } + if (precision > 31) + /* Don't run off the start of outbuf[], arbitrary limit + * longer than the longest number field. */ + precision = 31; + for (; len < precision; len++) { + /* Stop gcc generating horrid code and memset(). */ + _NOLIBC_OPTIMIZER_HIDE_VAR(len); + *--out = '0'; + } +no_zero_padding: /* %#o has set sign_prefix to '0', but we don't want so add an extra * leading zero here. @@ -603,7 +611,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list do_strlen_output: /* Open coded strnlen() (slightly smaller). */ - for (len = 0; len < precision; len++) + for (len = 0; precision < 0 || len < precision; len++) if (!outstr[len]) break; diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 1efd10152e83..e6fef6eb1db1 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1859,7 +1859,7 @@ static int run_printf(int min, int max) CASE_TEST(char); EXPECT_VFPRINTF(1, "|c|d| e|", "|%c|%.0c|%4c|", 'c', 'd', 'e'); break; CASE_TEST(octal); EXPECT_VFPRINTF(1, "|17| 0033||", "|%o|%6.4o|%.0o|", 017, 033, 0); break; CASE_TEST(octal_max); EXPECT_VFPRINTF(1, "1777777777777777777777", "%llo", ~0ULL); break; - CASE_TEST(octal_alt); EXPECT_VFPRINTF(1, "|0|01|02|034|0|", "|%#o|%#o|%#02o|%#02o|%#.0o|", 0, 1, 2, 034, 0); break; + CASE_TEST(octal_alt); EXPECT_VFPRINTF(1, "|0|01|02|034|0|0|", "|%#o|%#o|%#02o|%#02o|%#.0o|%0-#o|", 0, 1, 2, 034, 0, 0); break; CASE_TEST(hex_nolibc); EXPECT_VFPRINTF(is_nolibc, "|f|d|", "|%x|%X|", 0xf, 0xd); break; CASE_TEST(hex_libc); EXPECT_VFPRINTF(!is_nolibc, "|f|D|", "|%x|%X|", 0xf, 0xd); break; CASE_TEST(hex_alt); EXPECT_VFPRINTF(1, "|0x1| 0x2| 0|", "|%#x|%#5x|%#5x|", 1, 2, 0); break; @@ -1877,6 +1877,7 @@ static int run_printf(int min, int max) CASE_TEST(truncation); EXPECT_VFPRINTF(1, "012345678901234567890123456789", "%s", "012345678901234567890123456789"); break; CASE_TEST(string_width); EXPECT_VFPRINTF(1, " 1", "%10s", "1"); break; CASE_TEST(string_trunc); EXPECT_VFPRINTF(1, " 12345", "%10.5s", "1234567890"); break; + CASE_TEST(string_var); EXPECT_VFPRINTF(1, "| ab|ef | ij|kl |", "|%*.*s|%*.*s|%*.*s|%*.*s|", 3, 2, "abcd", -3, 2, "efgh", 3, -1, "ij", -3, -1, "kl"); break; CASE_TEST(number_width); EXPECT_VFPRINTF(1, " 1", "%10d", 1); break; CASE_TEST(number_left); EXPECT_VFPRINTF(1, "|-5 |", "|%-8d|", -5); break; CASE_TEST(string_align); EXPECT_VFPRINTF(1, "|foo |", "|%-8s|", "foo"); break; @@ -1890,7 +1891,7 @@ static int run_printf(int min, int max) CASE_TEST(num_p_tr_libc);EXPECT_VFPRINTF(!is_nolibc, "00000000000000000000000000000000005", "%035d", 5); break; CASE_TEST(number_prec); EXPECT_VFPRINTF(1, " 00005", "%10.5d", 5); break; CASE_TEST(num_prec_neg); EXPECT_VFPRINTF(1, " -00005", "%10.5d", -5); break; - CASE_TEST(num_prec_var); EXPECT_VFPRINTF(1, " -00005", "%*.*d", 10, 5, -5); break; + CASE_TEST(number_var); EXPECT_VFPRINTF(1, "| -00005|5 |", "|%*.*d|%*.*d|", 10, 5, -5, -2, -10, 5); break; CASE_TEST(num_0_prec_0); EXPECT_VFPRINTF(1, "|| |+||||", "|%.0d|% .0d|%+.0d|%.0u|%.0x|%#.0x|", 0, 0, 0, 0, 0, 0); break; CASE_TEST(errno); errno = 22; EXPECT_VFPRINTF(is_nolibc, "errno=22", "%m"); break; CASE_TEST(errno-neg); errno = -22; EXPECT_VFPRINTF(is_nolibc, "errno=-22 ", "%-12m"); break; From 5bf4b30ed49b9af281bdf11c788f382faa432cfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 1 Apr 2026 17:08:28 +0200 Subject: [PATCH 38/61] tools/nolibc: drop superfluous invocation of 'make headers' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The headers_install target of the toplevel Makefile will already make sure that the headers are up-to-date. Drop the superfluous explicit invocation. Signed-off-by: Thomas Weißschuh Link: https://patch.msgid.link/20260401-nolibc-cleanup-v1-1-bcf4c9f5c1be@weissschuh.net --- tools/include/nolibc/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile index 5d242312943f..76cfbfddf3c6 100644 --- a/tools/include/nolibc/Makefile +++ b/tools/include/nolibc/Makefile @@ -102,7 +102,6 @@ headers: $(Q)cp --parents $(arch_files) $(all_files) "$(OUTPUT)sysroot/include/" headers_standalone: headers - $(Q)$(MAKE) -C $(srctree) headers $(Q)$(MAKE) -C $(srctree) headers_install INSTALL_HDR_PATH=$(OUTPUT)sysroot CFLAGS_s390 := -m64 From 010d03d0e8fb0a2690d5a79c6580d8c4f32c937e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 1 Apr 2026 17:08:29 +0200 Subject: [PATCH 39/61] tools/nolibc: drop superfluous invocation of mkdir MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The call to 'mkdir -p $(OUTPUT)sysroot/include' will also create the sysroot directory. Drop the unnecessary explicit invocation of mkdir. Signed-off-by: Thomas Weißschuh Link: https://patch.msgid.link/20260401-nolibc-cleanup-v1-2-bcf4c9f5c1be@weissschuh.net --- tools/include/nolibc/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile index 76cfbfddf3c6..22e2f54cd5ca 100644 --- a/tools/include/nolibc/Makefile +++ b/tools/include/nolibc/Makefile @@ -97,7 +97,6 @@ help: # installs headers for all archs at once. headers: - $(Q)mkdir -p "$(OUTPUT)sysroot" $(Q)mkdir -p "$(OUTPUT)sysroot/include" $(Q)cp --parents $(arch_files) $(all_files) "$(OUTPUT)sysroot/include/" From b972b37cb6b8216922c1e817b0bab4cfed55fc44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 1 Apr 2026 17:08:30 +0200 Subject: [PATCH 40/61] tools/nolibc: drop superfluous definition of Q MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Q is already defined by tools/scripts/Makefile.include which is included at the top of tools/include/nolibc/Makefile. Signed-off-by: Thomas Weißschuh Link: https://patch.msgid.link/20260401-nolibc-cleanup-v1-3-bcf4c9f5c1be@weissschuh.net --- tools/include/nolibc/Makefile | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile index 22e2f54cd5ca..03f789b21017 100644 --- a/tools/include/nolibc/Makefile +++ b/tools/include/nolibc/Makefile @@ -17,12 +17,6 @@ endif # it defaults to this nolibc directory. OUTPUT ?= $(CURDIR)/ -ifeq ($(V),1) -Q= -else -Q=@ -endif - arch_files := arch.h $(wildcard arch-*.h) all_files := \ compiler.h \ From 7933969e1f733e18795a755cd9822ccf510140a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 1 Apr 2026 17:08:31 +0200 Subject: [PATCH 41/61] tools/nolibc: explicitly list architecture headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Relying on $(wildcard) is brittle and non-deterministic. similar to all the other headers. Switch the list of architecture headers to an explicit list, Link: https://patch.msgid.link/20260401-nolibc-cleanup-v1-4-bcf4c9f5c1be@weissschuh.net Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile index 03f789b21017..db6db4e6d99e 100644 --- a/tools/include/nolibc/Makefile +++ b/tools/include/nolibc/Makefile @@ -17,7 +17,8 @@ endif # it defaults to this nolibc directory. OUTPUT ?= $(CURDIR)/ -arch_files := arch.h $(wildcard arch-*.h) +architectures := arm arm64 loongarch m68k mips powerpc riscv s390 sh sparc x86 +arch_files := arch.h $(addsuffix .h, $(addprefix arch-, $(architectures))) all_files := \ compiler.h \ crt.h \ From 9c0ff257fbbe7f42a81c7b4eeefe8dfc9e8f52b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sat, 4 Apr 2026 10:08:18 +0200 Subject: [PATCH 42/61] selftests/nolibc: add some tests for makedev() and friends MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These functions/macros are about to be changed. Add some tests to make sure they continue working. As they only handle small dev_t values, only test those for now. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260404-nolibc-makedev-v2-1-456a429bf60c@weissschuh.net --- tools/testing/selftests/nolibc/nolibc-test.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index e6fef6eb1db1..4a9b6eb9e477 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1680,6 +1680,9 @@ int run_stdlib(int min, int max) 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; CASE_TEST(time_types); EXPECT_ZR(is_nolibc, test_time_types()); break; + CASE_TEST(makedev); EXPECT_EQ(1, makedev(0x12, 0x34), 0x1234); break; + CASE_TEST(major); EXPECT_EQ(1, major(0x1234), 0x12); break; + CASE_TEST(minor); EXPECT_EQ(1, minor(0x1234), 0x34); break; case __LINE__: return ret; /* must be last */ From 5afc7e9b90b82e0c43615dcf2ff0559909714d83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sat, 4 Apr 2026 10:08:19 +0200 Subject: [PATCH 43/61] selftests/nolibc: add a test for stat().st_rdev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The handling of 'dev_t' values is about to be changed. Add a test to make sure they are returned correctly from stat(). Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260404-nolibc-makedev-v2-2-456a429bf60c@weissschuh.net --- tools/testing/selftests/nolibc/nolibc-test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 4a9b6eb9e477..88d076f67402 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1485,6 +1485,7 @@ int run_syscall(int min, int max) CASE_TEST(select_fault); EXPECT_SYSER(1, select(1, (void *)1, NULL, NULL, 0), -1, EFAULT); break; CASE_TEST(stat_blah); EXPECT_SYSER(1, stat("/proc/self/blah", &stat_buf), -1, ENOENT); break; CASE_TEST(stat_fault); EXPECT_SYSER(1, stat(NULL, &stat_buf), -1, EFAULT); break; + CASE_TEST(stat_rdev); EXPECT_SYSZR(1, ({ int ret = stat("/dev/null", &stat_buf); ret ?: stat_buf.st_rdev != makedev(1, 3); })); break; CASE_TEST(stat_timestamps); EXPECT_SYSZR(1, test_stat_timestamps()); break; CASE_TEST(symlink_root); EXPECT_SYSER(1, symlink("/", "/"), -1, EEXIST); break; CASE_TEST(timer); EXPECT_SYSZR(1, test_timer()); break; From 70091eada34c9ebc650dc88dd0e8c9246c5df8f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sat, 4 Apr 2026 10:08:20 +0200 Subject: [PATCH 44/61] tools/nolibc: move the logic of makedev() and friends into functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Functions make it easier to keep the input and output types straight and avoid duplicate evaluations of their arguments. Also these functions will become a bit more complex to handle full 64-bit 'dev_t' which is easier to read in a function. Still stay compatible with code which expects these to be macros. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260404-nolibc-makedev-v2-3-456a429bf60c@weissschuh.net --- tools/include/nolibc/sys/sysmacros.h | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/tools/include/nolibc/sys/sysmacros.h b/tools/include/nolibc/sys/sysmacros.h index 37c33f030f02..347a95341ea2 100644 --- a/tools/include/nolibc/sys/sysmacros.h +++ b/tools/include/nolibc/sys/sysmacros.h @@ -13,8 +13,25 @@ #include "../std.h" /* WARNING, it only deals with the 4096 first majors and 256 first minors */ -#define makedev(major, minor) ((dev_t)((((major) & 0xfff) << 8) | ((minor) & 0xff))) -#define major(dev) ((unsigned int)(((dev) >> 8) & 0xfff)) -#define minor(dev) ((unsigned int)((dev) & 0xff)) +static __inline__ dev_t __nolibc_makedev(unsigned int maj, unsigned int min) +{ + return ((maj & 0xfff) << 8) | (min & 0xff); +} + +#define makedev(maj, min) __nolibc_makedev(maj, min) + +static __inline__ unsigned int __nolibc_major(dev_t dev) +{ + return (dev >> 8) & 0xfff; +} + +#define major(dev) __nolibc_major(dev) + +static __inline__ unsigned int __nolibc_minor(dev_t dev) +{ + return dev & 0xff; +} + +#define minor(dev) __nolibc_minor(dev) #endif /* _NOLIBC_SYS_SYSMACROS_H */ From df4ef52c1d4737ca68ce8f1ade5f61abad219055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sat, 4 Apr 2026 10:08:21 +0200 Subject: [PATCH 45/61] tools/nolibc: make dev_t 64 bits wide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit statx() returns both 32-bit minor and major numbers. For both of them to fit into the 'dev_t' in 'struct stat', that needs to be 64 bits wide. The other uses of 'dev_t' in nolibc are makedev() and friends and mknod(). makedev() and friends are going to be adapted in an upcoming commit and mknod() will silently truncate 'dev_t' to 'unsigned int' in the kernel, similar to other libcs. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260404-nolibc-makedev-v2-4-456a429bf60c@weissschuh.net --- tools/include/nolibc/std.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/include/nolibc/std.h b/tools/include/nolibc/std.h index b9a116123902..dc2dc46f8ca8 100644 --- a/tools/include/nolibc/std.h +++ b/tools/include/nolibc/std.h @@ -19,7 +19,7 @@ #include /* those are commonly provided by sys/types.h */ -typedef unsigned int dev_t; +typedef uint64_t dev_t; typedef uint64_t ino_t; typedef unsigned int mode_t; typedef signed int pid_t; From 572246dcddb5455d62d5d152fe31105542b10ff5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sat, 4 Apr 2026 10:08:22 +0200 Subject: [PATCH 46/61] tools/nolibc: handle all major and minor numbers in makedev() and friends MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the limitation of only handling small major and minor numbers. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260404-nolibc-makedev-v2-5-456a429bf60c@weissschuh.net --- tools/include/nolibc/sys/sysmacros.h | 8 ++++---- tools/testing/selftests/nolibc/nolibc-test.c | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tools/include/nolibc/sys/sysmacros.h b/tools/include/nolibc/sys/sysmacros.h index 347a95341ea2..ff9dd85ca59c 100644 --- a/tools/include/nolibc/sys/sysmacros.h +++ b/tools/include/nolibc/sys/sysmacros.h @@ -12,24 +12,24 @@ #include "../std.h" -/* WARNING, it only deals with the 4096 first majors and 256 first minors */ static __inline__ dev_t __nolibc_makedev(unsigned int maj, unsigned int min) { - return ((maj & 0xfff) << 8) | (min & 0xff); + return (((dev_t)maj & ~0xfff) << 32) | ((maj & 0xfff) << 8) | + (((dev_t)min & ~0xff) << 12) | (min & 0xff); } #define makedev(maj, min) __nolibc_makedev(maj, min) static __inline__ unsigned int __nolibc_major(dev_t dev) { - return (dev >> 8) & 0xfff; + return ((dev >> 32) & ~0xfff) | ((dev >> 8) & 0xfff); } #define major(dev) __nolibc_major(dev) static __inline__ unsigned int __nolibc_minor(dev_t dev) { - return dev & 0xff; + return ((dev >> 12) & ~0xff) | (dev & 0xff); } #define minor(dev) __nolibc_minor(dev) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 88d076f67402..7606a8b68d28 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1684,6 +1684,9 @@ int run_stdlib(int min, int max) CASE_TEST(makedev); EXPECT_EQ(1, makedev(0x12, 0x34), 0x1234); break; CASE_TEST(major); EXPECT_EQ(1, major(0x1234), 0x12); break; CASE_TEST(minor); EXPECT_EQ(1, minor(0x1234), 0x34); break; + CASE_TEST(makedev_big); EXPECT_EQ(1, makedev(0x11223344, 0x55667788), 0x1122355667734488); break; + CASE_TEST(major_big); EXPECT_EQ(1, major(0x1122355667734488), 0x11223344); break; + CASE_TEST(minor_big); EXPECT_EQ(1, minor(0x1122355667734488), 0x55667788); break; case __LINE__: return ret; /* must be last */ From 867fb336a65ac59260674382168d2d93896ffa8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sat, 4 Apr 2026 10:08:23 +0200 Subject: [PATCH 47/61] tools/nolibc: use makedev() in fstatat() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fstatat() contains two open-coded copies of makedev() to handle minor numbers >= 256. Now that the regular makedev() handles both large minor and major numbers correctly use the common function. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260404-nolibc-makedev-v2-6-456a429bf60c@weissschuh.net --- tools/include/nolibc/sys/stat.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tools/include/nolibc/sys/stat.h b/tools/include/nolibc/sys/stat.h index b2ef34a617ca..07ae715ff253 100644 --- a/tools/include/nolibc/sys/stat.h +++ b/tools/include/nolibc/sys/stat.h @@ -13,6 +13,7 @@ #include "../arch.h" #include "../types.h" #include "../sys.h" +#include "../sys/sysmacros.h" /* * int statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf); @@ -49,17 +50,13 @@ int fstatat(int fd, const char *path, struct stat *buf, int flag) if (ret == -1) return ret; - buf->st_dev = ((statx.stx_dev_minor & 0xff) - | (statx.stx_dev_major << 8) - | ((statx.stx_dev_minor & ~0xff) << 12)); + buf->st_dev = makedev(statx.stx_dev_major, statx.stx_dev_minor); buf->st_ino = statx.stx_ino; buf->st_mode = statx.stx_mode; buf->st_nlink = statx.stx_nlink; buf->st_uid = statx.stx_uid; buf->st_gid = statx.stx_gid; - buf->st_rdev = ((statx.stx_rdev_minor & 0xff) - | (statx.stx_rdev_major << 8) - | ((statx.stx_rdev_minor & ~0xff) << 12)); + buf->st_rdev = makedev(statx.stx_rdev_major, statx.stx_rdev_minor); buf->st_size = statx.stx_size; buf->st_blksize = statx.stx_blksize; buf->st_blocks = statx.stx_blocks; From fd2e9f820005d63769a6662c276b1f52a72ed041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 1 Apr 2026 17:07:27 +0200 Subject: [PATCH 48/61] tools/nolibc: use __builtin_offsetof() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current custom implementation of offsetof() fails UBSAN: runtime error: member access within null pointer of type 'struct ...' This means that all its users, including container_of(), free() and realloc(), fail. Use __builtin_offsetof() instead which does not have this issue and has been available since GCC 4 and clang 3. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260401-nolibc-asprintf-v1-1-46292313439f@weissschuh.net --- tools/include/nolibc/stddef.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/include/nolibc/stddef.h b/tools/include/nolibc/stddef.h index ecbd13eab1f5..a3976341afdd 100644 --- a/tools/include/nolibc/stddef.h +++ b/tools/include/nolibc/stddef.h @@ -18,7 +18,7 @@ #endif #ifndef offsetof -#define offsetof(TYPE, FIELD) ((size_t) &((TYPE *)0)->FIELD) +#define offsetof(TYPE, FIELD) __builtin_offsetof(TYPE, FIELD) #endif #endif /* _NOLIBC_STDDEF_H */ From 12496aad10c5671d66e160487326de942cd440ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 1 Apr 2026 17:07:29 +0200 Subject: [PATCH 49/61] tools/nolibc: add support for asprintf() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for dynamically allocating formatted strings through asprintf() and vasprintf(). Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260401-nolibc-asprintf-v1-3-46292313439f@weissschuh.net --- tools/include/nolibc/stdio.h | 50 ++++++++++++++++++++ tools/testing/selftests/nolibc/nolibc-test.c | 24 ++++++++++ 2 files changed, 74 insertions(+) diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index b6d14a58cfe7..ebdd413d13ec 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -795,6 +795,56 @@ int sprintf(char *buf, const char *fmt, ...) return ret; } +static __attribute__((unused, format(printf, 2, 0))) +int __nolibc_vasprintf(char **strp, const char *fmt, va_list args1, va_list args2) +{ + int len1, len2; + char *buf; + + len1 = vsnprintf(NULL, 0, fmt, args1); + if (len1 < 0) + return -1; + + buf = malloc(len1 + 1); + if (!buf) + return -1; + + len2 = vsnprintf(buf, len1 + 1, fmt, args2); + if (len2 < 0) { + free(buf); + return -1; + } + + *strp = buf; + return len1; +} + +static __attribute__((unused, format(printf, 2, 0))) +int vasprintf(char **strp, const char *fmt, va_list args) +{ + va_list args2; + int ret; + + va_copy(args2, args); + ret = __nolibc_vasprintf(strp, fmt, args, args2); + va_end(args2); + + return ret; +} + +static __attribute__((unused, format(printf, 2, 3))) +int asprintf(char **strp, const char *fmt, ...) +{ + va_list args; + int ret; + + va_start(args, fmt); + ret = vasprintf(strp, fmt, args); + va_end(args); + + return ret; +} + static __attribute__((unused)) int vsscanf(const char *str, const char *format, va_list args) { diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 7606a8b68d28..91d95a152568 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1841,6 +1841,29 @@ static int test_printf_error(void) return 0; } +int test_asprintf(void) +{ + char *str; + int ret; + + ret = asprintf(&str, "foo%s", "bar"); + if (ret == -1) + return 1; + + if (ret != 6) { + free(str); + return 2; + } + + if (memcmp(str, "foobar", 6) != 0) { + free(str); + return 3; + } + + free(str); + return 0; +} + static int run_printf(int min, int max) { int test; @@ -1904,6 +1927,7 @@ static int run_printf(int min, int max) CASE_TEST(errno-neg); errno = -22; EXPECT_VFPRINTF(is_nolibc, "errno=-22 ", "%-12m"); break; CASE_TEST(scanf); EXPECT_ZR(1, test_scanf()); break; CASE_TEST(printf_error); EXPECT_ZR(1, test_printf_error()); break; + CASE_TEST(asprintf); EXPECT_ZR(1, test_asprintf()); break; case __LINE__: return ret; /* must be last */ /* note: do not set any defaults so as to permit holes above */ From 1e3c374e9fd5ef0bf1ebcb866505b1aad404959e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sat, 4 Apr 2026 13:50:19 +0200 Subject: [PATCH 50/61] tools/nolibc: check for overflow in calloc() without divisions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On some architectures without native division instructions the division can generate calls into libgcc/compiler-rt. This library might not be available, so its use should be avoided. Use the compiler builtin to check for overflows without needing a division. The builtin has been available since GCC 3 and clang 3.8. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260404-nolibc-asprintf-v2-1-17d2d0df9763@weissschuh.net --- tools/include/nolibc/stdlib.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h index 2113a8e7695d..1816c2368b68 100644 --- a/tools/include/nolibc/stdlib.h +++ b/tools/include/nolibc/stdlib.h @@ -145,9 +145,9 @@ void *malloc(size_t len) static __attribute__((unused)) void *calloc(size_t size, size_t nmemb) { - size_t x = size * nmemb; + size_t x; - if (__builtin_expect(size && ((x / size) != nmemb), 0)) { + if (__builtin_expect(__builtin_mul_overflow(size, nmemb, &x), 0)) { SET_ERRNO(ENOMEM); return NULL; } From e70a7bb5755997d845f641f5d46d8af4ea68fc8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sat, 4 Apr 2026 13:50:20 +0200 Subject: [PATCH 51/61] selftests/nolibc: test the memory allocator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The memory allocator has not seen any testing so far. Add a simple testcase for it. Suggested-by: Willy Tarreau Link: https://lore.kernel.org/lkml/adDRK8D6YBZgv36H@1wt.eu/ Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260404-nolibc-asprintf-v2-2-17d2d0df9763@weissschuh.net --- tools/testing/selftests/nolibc/nolibc-test.c | 55 ++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 91d95a152568..dd10402267ee 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1555,6 +1555,60 @@ int test_time_types(void) return 0; } +int test_malloc(void) +{ + size_t sz_array1, sz_array2, sz_array3; + int *array1, *array2, *array3; + int pagesize = getpagesize(); + size_t idx; + + if (pagesize < 0) + return 1; + + /* Dependent on the page size, as that is the granularity of our allocator. */ + sz_array1 = pagesize / 2; + array1 = malloc(sz_array1 * sizeof(*array1)); + if (!array1) + return 2; + + for (idx = 0; idx < sz_array1; idx++) + array1[idx] = idx; + + sz_array2 = pagesize * 2; + array2 = calloc(sz_array2, sizeof(*array2)); + if (!array2) { + free(array1); + return 3; + } + + for (idx = 0; idx < sz_array2; idx++) { + if (array2[idx] != 0) { + free(array2); + return 4; + } + array2[idx] = idx + sz_array1; + } + + /* Resize array1 into array3 and append array2 at the end. */ + sz_array3 = sz_array1 + sz_array2; + array3 = realloc(array1, sz_array3 * sizeof(*array3)); + if (!array3) { + free(array2); + free(array1); + return 5; + } + memcpy(array3 + sz_array1, array2, sizeof(*array2) * sz_array2); + free(array2); + + /* The contents must be contiguous now. */ + for (idx = 0; idx < sz_array3; idx++) + if (array3[idx] != (int)idx) + return 6; + + free(array3); + return 0; +} + int run_stdlib(int min, int max) { int test; @@ -1687,6 +1741,7 @@ int run_stdlib(int min, int max) CASE_TEST(makedev_big); EXPECT_EQ(1, makedev(0x11223344, 0x55667788), 0x1122355667734488); break; CASE_TEST(major_big); EXPECT_EQ(1, major(0x1122355667734488), 0x11223344); break; CASE_TEST(minor_big); EXPECT_EQ(1, minor(0x1122355667734488), 0x55667788); break; + CASE_TEST(malloc); EXPECT_ZR(1, test_malloc()); break; case __LINE__: return ret; /* must be last */ From 08b96aa962209de015de6c4a51e8cadbd1b21d0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sat, 4 Apr 2026 14:59:03 +0200 Subject: [PATCH 52/61] selftests/nolibc: only use libgcc when really necessary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nolibc should work without libgcc to be compatible with as many toolchains as possible. Currently the functionality tested by nolibc-test does not contain any dependencies, make sure it stays this way by not linking libgcc anymore. On the ppc target GCC always emits references to '_restgpr_' functions, so keep linking libgcc there. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260404-nolibc-libgcc-v1-1-eb3ecfe0e176@weissschuh.net --- tools/testing/selftests/nolibc/Makefile.nolibc | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/tools/testing/selftests/nolibc/Makefile.nolibc b/tools/testing/selftests/nolibc/Makefile.nolibc index 2d32cec1105f..f30bc68470cc 100644 --- a/tools/testing/selftests/nolibc/Makefile.nolibc +++ b/tools/testing/selftests/nolibc/Makefile.nolibc @@ -232,23 +232,14 @@ ifeq ($(origin XARCH),command line) CFLAGS_XARCH = $(CFLAGS_$(XARCH)) endif +LDLIBS_ppc = $(if $(LLVM),,-lgcc) +LDLIBS = $(LDLIBS_$(XARCH)) + include Makefile.include CFLAGS ?= $(CFLAGS_NOLIBC_TEST) $(CFLAGS_XARCH) $(CFLAGS_EXTRA) LDFLAGS := -LIBGCC := -lgcc - -ifeq ($(ARCH),x86) -# Not needed on x86, probably not present for x32 -LIBGCC := -endif - -ifneq ($(LLVM),) -# Not needed for clang -LIBGCC := -endif - # Modify CFLAGS based on LLVM= include $(srctree)/tools/scripts/Makefile.include @@ -304,7 +295,7 @@ sysroot/$(ARCH)/include: nolibc-test: $(NOLIBC_TEST_SOURCES) sysroot/$(ARCH)/include $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ \ - -nostdlib -nostdinc -static -Isysroot/$(ARCH)/include $(NOLIBC_TEST_SOURCES) $(LIBGCC) + -nostdlib -nostdinc -static -Isysroot/$(ARCH)/include $(NOLIBC_TEST_SOURCES) $(LDLIBS) libc-test: $(NOLIBC_TEST_SOURCES) $(QUIET_CC)$(HOSTCC) -o $@ $(NOLIBC_TEST_SOURCES) From 3f5059f01de1aca30e7f793da0a0b5bf2740cb7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sun, 5 Apr 2026 11:06:23 +0200 Subject: [PATCH 53/61] tools/nolibc: rename the internal macros used in syscall() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These macros are the internal implementation of syscall(). They can not be used by users. Align them with the standard naming scheme for internal symbols. The current name also prevents the addition of an application-usable _syscall() symbol. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260405-nolibc-syscall-v1-1-e5b12bc63211@weissschuh.net --- tools/include/nolibc/sys/syscall.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/include/nolibc/sys/syscall.h b/tools/include/nolibc/sys/syscall.h index 8cbcae4a32aa..b673f3d0c0f8 100644 --- a/tools/include/nolibc/sys/syscall.h +++ b/tools/include/nolibc/sys/syscall.h @@ -10,10 +10,10 @@ #ifndef _NOLIBC_SYS_SYSCALL_H #define _NOLIBC_SYS_SYSCALL_H -#define __syscall_narg(_0, _1, _2, _3, _4, _5, _6, N, ...) N -#define _syscall_narg(...) __syscall_narg(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) -#define _syscall(N, ...) __sysret(__nolibc_syscall##N(__VA_ARGS__)) -#define _syscall_n(N, ...) _syscall(N, __VA_ARGS__) -#define syscall(...) _syscall_n(_syscall_narg(__VA_ARGS__), ##__VA_ARGS__) +#define ___nolibc_syscall_narg(_0, _1, _2, _3, _4, _5, _6, N, ...) N +#define __nolibc_syscall_narg(...) ___nolibc_syscall_narg(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) +#define __nolibc_syscall(N, ...) __sysret(__nolibc_syscall##N(__VA_ARGS__)) +#define __nolibc_syscall_n(N, ...) __nolibc_syscall(N, __VA_ARGS__) +#define syscall(...) __nolibc_syscall_n(__nolibc_syscall_narg(__VA_ARGS__), ##__VA_ARGS__) #endif /* _NOLIBC_SYS_SYSCALL_H */ From 022bbb5a41fd6463887dfb7de22f5be8262239a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sun, 5 Apr 2026 11:06:24 +0200 Subject: [PATCH 54/61] tools/nolibc: move the call to __sysret() into syscall() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit __sysret() transforms the return value from the kernel into the libc return value convention. There is no reason for it to be called in the middle of the internals of the syscall() implementation macros. Move the call up, directly into syscall(), to make the code simpler. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260405-nolibc-syscall-v1-2-e5b12bc63211@weissschuh.net --- tools/include/nolibc/sys/syscall.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/include/nolibc/sys/syscall.h b/tools/include/nolibc/sys/syscall.h index b673f3d0c0f8..3f43fac3d7b8 100644 --- a/tools/include/nolibc/sys/syscall.h +++ b/tools/include/nolibc/sys/syscall.h @@ -12,8 +12,8 @@ #define ___nolibc_syscall_narg(_0, _1, _2, _3, _4, _5, _6, N, ...) N #define __nolibc_syscall_narg(...) ___nolibc_syscall_narg(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) -#define __nolibc_syscall(N, ...) __sysret(__nolibc_syscall##N(__VA_ARGS__)) +#define __nolibc_syscall(N, ...) __nolibc_syscall##N(__VA_ARGS__) #define __nolibc_syscall_n(N, ...) __nolibc_syscall(N, __VA_ARGS__) -#define syscall(...) __nolibc_syscall_n(__nolibc_syscall_narg(__VA_ARGS__), ##__VA_ARGS__) +#define syscall(...) __sysret(__nolibc_syscall_n(__nolibc_syscall_narg(__VA_ARGS__), ##__VA_ARGS__)) #endif /* _NOLIBC_SYS_SYSCALL_H */ From 2eb64b936d3b6332ae44bbf91277f912be5597e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sun, 5 Apr 2026 11:06:25 +0200 Subject: [PATCH 55/61] tools/nolibc: add the _syscall() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The standard syscall() function or macro uses the libc return value convention. Errors returned from the kernel as negative values are stored in errno and -1 is returned. Users who want to avoid using errno don't have a way to call raw syscalls and check the returned error. Add a new macro _syscall() which works like the standard syscall() but passes through the return value from the kernel unchanged. The naming scheme and return values match the named _sys_foo() system call wrappers already part of nolibc. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260405-nolibc-syscall-v1-3-e5b12bc63211@weissschuh.net --- tools/include/nolibc/sys/syscall.h | 3 ++- tools/testing/selftests/nolibc/nolibc-test.c | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/include/nolibc/sys/syscall.h b/tools/include/nolibc/sys/syscall.h index 3f43fac3d7b8..7f06314fcf0d 100644 --- a/tools/include/nolibc/sys/syscall.h +++ b/tools/include/nolibc/sys/syscall.h @@ -14,6 +14,7 @@ #define __nolibc_syscall_narg(...) ___nolibc_syscall_narg(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) #define __nolibc_syscall(N, ...) __nolibc_syscall##N(__VA_ARGS__) #define __nolibc_syscall_n(N, ...) __nolibc_syscall(N, __VA_ARGS__) -#define syscall(...) __sysret(__nolibc_syscall_n(__nolibc_syscall_narg(__VA_ARGS__), ##__VA_ARGS__)) +#define _syscall(...) __nolibc_syscall_n(__nolibc_syscall_narg(__VA_ARGS__), ##__VA_ARGS__) +#define syscall(...) __sysret(_syscall(__VA_ARGS__)) #endif /* _NOLIBC_SYS_SYSCALL_H */ diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index dd10402267ee..4bcf46867603 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -95,6 +95,8 @@ static const int is_glibc = /* readdir_r() is likely to be marked deprecated */ #undef readdir_r #define readdir_r(dir, dirent, result) ((errno = EINVAL), -1) + +#define _syscall(...) 0 #endif /* definition of a series of tests */ @@ -1507,6 +1509,8 @@ int run_syscall(int min, int max) CASE_TEST(ptrace); EXPECT_SYSER(1, ptrace(PTRACE_CONT, getpid(), NULL, NULL), -1, ESRCH); break; CASE_TEST(syscall_noargs); EXPECT_SYSEQ(1, syscall(__NR_getpid), getpid()); break; CASE_TEST(syscall_args); EXPECT_SYSER(1, syscall(__NR_statx, 0, NULL, 0, 0, NULL), -1, EFAULT); break; + 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 __LINE__: return ret; /* must be last */ From ce834c9cb984a9b85160a2c3a3821e179fa502fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sun, 5 Apr 2026 17:31:05 +0200 Subject: [PATCH 56/61] tools/nolibc: add byteorder conversions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add some standard functions to convert between different byte orders. Conveniently the UAPI headers provide all the necessary functionality. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260405-nolibc-bswap-v1-1-f7699ca9cee0@weissschuh.net --- tools/include/nolibc/Makefile | 2 ++ tools/include/nolibc/byteswap.h | 21 +++++++++++++ tools/include/nolibc/endian.h | 32 ++++++++++++++++++++ tools/include/nolibc/nolibc.h | 2 ++ tools/testing/selftests/nolibc/nolibc-test.c | 13 ++++++++ 5 files changed, 70 insertions(+) create mode 100644 tools/include/nolibc/byteswap.h create mode 100644 tools/include/nolibc/endian.h diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile index db6db4e6d99e..7455097cff69 100644 --- a/tools/include/nolibc/Makefile +++ b/tools/include/nolibc/Makefile @@ -20,11 +20,13 @@ 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 := \ + byteswap.h \ compiler.h \ crt.h \ ctype.h \ dirent.h \ elf.h \ + endian.h \ err.h \ errno.h \ fcntl.h \ diff --git a/tools/include/nolibc/byteswap.h b/tools/include/nolibc/byteswap.h new file mode 100644 index 000000000000..45bbf9609d7a --- /dev/null +++ b/tools/include/nolibc/byteswap.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * Byte swapping for NOLIBC + * Copyright (C) 2026 Thomas Weißschuh + */ + +/* make sure to include all global symbols */ +#include "nolibc.h" + +#ifndef _NOLIBC_BYTESWAP_H +#define _NOLIBC_BYTESWAP_H + +#include "stdint.h" + +#include + +#define bswap_16(_x) __swab16(_x) +#define bswap_32(_x) __swab32(_x) +#define bswap_64(_x) __swab64(_x) + +#endif /* _NOLIBC_BYTESWAP_H */ diff --git a/tools/include/nolibc/endian.h b/tools/include/nolibc/endian.h new file mode 100644 index 000000000000..ccc016ecd5ec --- /dev/null +++ b/tools/include/nolibc/endian.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * Byte order conversion for NOLIBC + * Copyright (C) 2026 Thomas Weißschuh + */ + +/* make sure to include all global symbols */ +#include "nolibc.h" + +#ifndef _NOLIBC_ENDIAN_H +#define _NOLIBC_ENDIAN_H + +#include "stdint.h" + +#include + +#define htobe16(_x) __cpu_to_be16(_x) +#define htole16(_x) __cpu_to_le16(_x) +#define be16toh(_x) __be16_to_cpu(_x) +#define le16toh(_x) __le16_to_cpu(_x) + +#define htobe32(_x) __cpu_to_be32(_x) +#define htole32(_x) __cpu_to_le32(_x) +#define be32toh(_x) __be32_to_cpu(_x) +#define le32toh(_x) __le32_to_cpu(_x) + +#define htobe64(_x) __cpu_to_be64(_x) +#define htole64(_x) __cpu_to_le64(_x) +#define be64toh(_x) __be64_to_cpu(_x) +#define le64toh(_x) __le64_to_cpu(_x) + +#endif /* _NOLIBC_ENDIAN_H */ diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 294bac1b9039..f4120f65fe79 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -131,6 +131,8 @@ #include "poll.h" #include "math.h" #include "err.h" +#include "byteswap.h" +#include "endian.h" /* Used by programs to avoid std includes */ #define NOLIBC diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 4bcf46867603..bb13f9f9aa7c 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -43,6 +43,8 @@ #include #include #include +#include +#include #pragma GCC diagnostic ignored "-Wmissing-prototypes" @@ -67,6 +69,8 @@ static const char *argv0; /* will be used by constructor tests */ static int constructor_test_value; +static const int is_le = __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__; + static const int is_nolibc = #ifdef NOLIBC 1 @@ -1746,6 +1750,15 @@ int run_stdlib(int min, int max) CASE_TEST(major_big); EXPECT_EQ(1, major(0x1122355667734488), 0x11223344); break; CASE_TEST(minor_big); EXPECT_EQ(1, minor(0x1122355667734488), 0x55667788); break; CASE_TEST(malloc); EXPECT_ZR(1, test_malloc()); break; + CASE_TEST(bswap_16); EXPECT_EQ(1, bswap_16(0x0123), 0x2301); break; + CASE_TEST(bswap_32); EXPECT_EQ(1, bswap_32(0x01234567), 0x67452301); break; + CASE_TEST(bswap_64); EXPECT_EQ(1, bswap_64(0x0123456789abcdef), 0xefcdab8967452301); break; + CASE_TEST(htobe16); EXPECT_EQ(1, htobe16(is_le ? 0x0123 : 0x2301), 0x2301); break; + CASE_TEST(htole16); EXPECT_EQ(1, htole16(is_le ? 0x0123 : 0x2301), 0x0123); break; + CASE_TEST(htobe32); EXPECT_EQ(1, htobe32(is_le ? 0x01234567 : 0x67452301), 0x67452301); break; + CASE_TEST(htole32); EXPECT_EQ(1, htole32(is_le ? 0x01234567 : 0x67452301), 0x01234567); break; + CASE_TEST(htobe64); EXPECT_EQ(1, htobe64(is_le ? 0x0123456789000000 : 0x8967452301), 0x8967452301); break; + CASE_TEST(htole64); EXPECT_EQ(1, htole64(is_le ? 0x0123456789 : 0x8967452301000000), 0x0123456789); break; case __LINE__: return ret; /* must be last */ From 9a5206f2564128ada61ba1d29aeafa0a439dca00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sun, 4 Jan 2026 20:05:26 +0100 Subject: [PATCH 57/61] selftests/nolibc: explicitly handle ENOSYS from ptrace() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The automatic ENOSYS handling in EXPECT_SYSER() is about to be removed. ptrace() will return legitimately return ENOSYS on qemu-user, so handle it explicitly. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260406-nolibc-no-skip-enosys-v1-1-c046b1ac7d73@weissschuh.net/ --- tools/testing/selftests/nolibc/nolibc-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index bb13f9f9aa7c..81cd9f917799 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1510,7 +1510,7 @@ int run_syscall(int min, int max) CASE_TEST(readv_zero); EXPECT_SYSZR(1, readv(0, NULL, 0)); break; CASE_TEST(writev_badf); EXPECT_SYSER(1, writev(-1, &iov_one, 1), -1, EBADF); break; CASE_TEST(writev_zero); EXPECT_SYSZR(1, writev(1, NULL, 0)); break; - CASE_TEST(ptrace); EXPECT_SYSER(1, ptrace(PTRACE_CONT, getpid(), NULL, NULL), -1, ESRCH); break; + CASE_TEST(ptrace); tmp = ptrace(PTRACE_CONT, getpid(), NULL, NULL); EXPECT_SYSER(tmp != -1 && errno != ENOSYS, tmp, -1, EFAULT); break; CASE_TEST(syscall_noargs); EXPECT_SYSEQ(1, syscall(__NR_getpid), getpid()); break; CASE_TEST(syscall_args); EXPECT_SYSER(1, syscall(__NR_statx, 0, NULL, 0, 0, NULL), -1, EFAULT); break; CASE_TEST(_syscall_noargs); EXPECT_SYSEQ(is_nolibc, _syscall(__NR_getpid), getpid()); break; From 598b670af347bc8d998866b1e795e40a3bb168de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sun, 4 Jan 2026 16:14:42 +0100 Subject: [PATCH 58/61] selftests/nolibc: don't skip tests for unimplemented syscalls anymore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The automatic skipping of tests on ENOSYS returns was introduced in commit 349afc8a52f8 ("selftests/nolibc: skip tests for unimplemented syscalls"). It handled the fact that nolibc would return ENOSYS for many syscall wrappers on riscv32. Nowadays nolibc handles all these correctly, so this logic is not used anymore. To make missing nolibc functionality more obvious fail the tests again if something is not implemented. Revert the mentioned commit again. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260406-nolibc-no-skip-enosys-v1-2-c046b1ac7d73@weissschuh.net/ --- tools/testing/selftests/nolibc/nolibc-test.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 81cd9f917799..d3c4facb54c0 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -320,10 +320,7 @@ int expect_syszr(int expr, int llen) { int ret = 0; - if (errno == ENOSYS) { - llen += printf(" = ENOSYS"); - result(llen, SKIPPED); - } else if (expr) { + if (expr) { ret = 1; llen += printf(" = %d %s ", expr, errorname(errno)); result(llen, FAIL); @@ -363,10 +360,7 @@ int expect_sysne(int expr, int llen, int val) { int ret = 0; - if (errno == ENOSYS) { - llen += printf(" = ENOSYS"); - result(llen, SKIPPED); - } else if (expr == val) { + if (expr == val) { ret = 1; llen += printf(" = %d %s ", expr, errorname(errno)); result(llen, FAIL); @@ -391,9 +385,7 @@ int expect_syserr2(int expr, int expret, int experr1, int experr2, int llen) int _errno = errno; llen += printf(" = %d %s ", expr, errorname(_errno)); - if (errno == ENOSYS) { - result(llen, SKIPPED); - } else if (expr != expret || (_errno != experr1 && _errno != experr2)) { + if (expr != expret || (_errno != experr1 && _errno != experr2)) { ret = 1; if (experr2 == 0) llen += printf(" != (%d %s) ", expret, errorname(experr1)); From 08ab9580726edcc12019d2097b56b88de1142ca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 8 Apr 2026 23:03:56 +0200 Subject: [PATCH 59/61] tools/nolibc: create __nolibc_no_sanitize_ubsan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The logic to disable UBSAN will become a bit more complicated. Move it out into compiler.h, so crt.h stays readable. Signed-off-by: Thomas Weißschuh Link: https://patch.msgid.link/20260408-nolibc-gcc-15-v1-1-330d0c40f894@weissschuh.net --- tools/include/nolibc/compiler.h | 6 ++++++ tools/include/nolibc/crt.h | 5 +---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tools/include/nolibc/compiler.h b/tools/include/nolibc/compiler.h index 1c410a62c528..b1239344d894 100644 --- a/tools/include/nolibc/compiler.h +++ b/tools/include/nolibc/compiler.h @@ -80,4 +80,10 @@ /* Make the optimizer believe the variable can be manipulated arbitrarily. */ #define _NOLIBC_OPTIMIZER_HIDE_VAR(var) __asm__ ("" : "+r" (var)) +#if __nolibc_has_feature(undefined_behavior_sanitizer) +# define __nolibc_no_sanitize_undefined __attribute__((no_sanitize("function"))) +#else +# define __nolibc_no_sanitize_undefined +#endif + #endif /* _NOLIBC_COMPILER_H */ diff --git a/tools/include/nolibc/crt.h b/tools/include/nolibc/crt.h index 5bb492555f13..d8ce91fd2e3b 100644 --- a/tools/include/nolibc/crt.h +++ b/tools/include/nolibc/crt.h @@ -47,10 +47,7 @@ char *__nolibc_program_invocation_short_name(char *long_name) #endif /* NOLIBC_IGNORE_ERRNO */ void _start_c(long *sp); -__attribute__((weak,used)) -#if __nolibc_has_feature(undefined_behavior_sanitizer) - __attribute__((no_sanitize("function"))) -#endif +__attribute__((weak,used)) __nolibc_no_sanitize_undefined void _start_c(long *sp) { long argc; From 3495279d05d62b07d7594c75d4380f51d04410dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 8 Apr 2026 23:03:57 +0200 Subject: [PATCH 60/61] tools/nolibc: support UBSAN on gcc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The UBSAN implementation in gcc requires a slightly different function attribute to skip instrumentation. Extend __nolibc_no_sanitize_undefined to also handle gcc. Signed-off-by: Thomas Weißschuh Link: https://patch.msgid.link/20260408-nolibc-gcc-15-v1-2-330d0c40f894@weissschuh.net --- tools/include/nolibc/compiler.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/include/nolibc/compiler.h b/tools/include/nolibc/compiler.h index b1239344d894..b56570bf9f69 100644 --- a/tools/include/nolibc/compiler.h +++ b/tools/include/nolibc/compiler.h @@ -81,7 +81,11 @@ #define _NOLIBC_OPTIMIZER_HIDE_VAR(var) __asm__ ("" : "+r" (var)) #if __nolibc_has_feature(undefined_behavior_sanitizer) -# define __nolibc_no_sanitize_undefined __attribute__((no_sanitize("function"))) +# if defined(__clang__) +# define __nolibc_no_sanitize_undefined __attribute__((no_sanitize("function"))) +# else +# define __nolibc_no_sanitize_undefined __attribute__((no_sanitize_undefined)) +# endif #else # define __nolibc_no_sanitize_undefined #endif From b070dc36291fec966ad915f80a4f239b5c70c290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 8 Apr 2026 23:03:58 +0200 Subject: [PATCH 61/61] selftests/nolibc: use gcc 15 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Newer compilers tend to detect more problematic code. Update the testsuite to use gcc 15.2.0 by default. Signed-off-by: Thomas Weißschuh Link: https://patch.msgid.link/20260408-nolibc-gcc-15-v1-3-330d0c40f894@weissschuh.net --- tools/testing/selftests/nolibc/run-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/nolibc/run-tests.sh b/tools/testing/selftests/nolibc/run-tests.sh index 3917cfb8fdc4..cd439096fdf3 100755 --- a/tools/testing/selftests/nolibc/run-tests.sh +++ b/tools/testing/selftests/nolibc/run-tests.sh @@ -7,7 +7,7 @@ set -e trap 'echo Aborting...' 'ERR' -crosstool_version=13.2.0 +crosstool_version=15.2.0 hostarch=x86_64 nproc=$(( $(nproc) + 2)) cache_dir="${XDG_CACHE_HOME:-"$HOME"/.cache}"