From: Benjamin Berg benjamin.berg@intel.com
This patchset is an attempt to start a nolibc port of UML. The goal is to port UML to use nolibc in smaller chunks to make the switch more manageable.
There are three parts to this patchset: * Two patches to use tools/include headers instead of kernel headers for userspace files. * A few nolibc fixes and a new NOLIBC_NO_STARTCODE compile flag for it * Finally nolibc build support for UML and switching two files while adding the appropriate support in nolibc itself.
v1 of this patchset was https://lore.kernel.org/all/20250915071115.1429196-1-benjamin@sipsolutions.n...
Changes in v2: - add sys/uio.h and sys/ptrace.h to nolibc - Use NOLIBC_NO_RUNTIME to disable nolibc startup code - Fix out-of-tree build - various small improvements and cleanups
Should the nolibc changes be merged separately or could everything go through the same branch?
Also, what about tools/include/linux/compiler.h? It seems that was added for the tracing code, but it is not clear to me who might ACK that fix.
Benjamin
Benjamin Berg (11): tools compiler.h: fix __used definition um: use tools/include for user files tools/nolibc/stdio: remove perror if NOLIBC_IGNORE_ERRNO is set tools/nolibc/dirent: avoid errno in readdir_r tools/nolibc: use __fallthrough__ rather than fallthrough tools/nolibc: add option to disable runtime um: add infrastructure to build files using nolibc um: use nolibc for the --showconfig implementation tools/nolibc: add uio.h with readv and writev tools/nolibc: add ptrace support um: switch ptrace FP register access to nolibc
arch/um/Makefile | 38 +++++++++++--- arch/um/include/shared/init.h | 2 +- arch/um/include/shared/os.h | 2 + arch/um/include/shared/user.h | 6 --- arch/um/kernel/Makefile | 2 +- arch/um/kernel/skas/stub.c | 1 + arch/um/kernel/skas/stub_exe.c | 4 +- arch/um/os-Linux/skas/process.c | 6 +-- arch/um/os-Linux/start_up.c | 4 +- arch/um/scripts/Makefile.rules | 10 +++- arch/x86/um/Makefile | 6 ++- arch/x86/um/os-Linux/Makefile | 5 +- arch/x86/um/os-Linux/registers.c | 16 ++---- arch/x86/um/user-offsets.c | 1 - tools/include/linux/compiler.h | 2 +- tools/include/nolibc/Makefile | 2 + tools/include/nolibc/arch-arm.h | 2 + tools/include/nolibc/arch-arm64.h | 2 + tools/include/nolibc/arch-loongarch.h | 2 + tools/include/nolibc/arch-m68k.h | 2 + tools/include/nolibc/arch-mips.h | 2 + tools/include/nolibc/arch-powerpc.h | 2 + tools/include/nolibc/arch-riscv.h | 2 + tools/include/nolibc/arch-s390.h | 2 + tools/include/nolibc/arch-sh.h | 2 + tools/include/nolibc/arch-sparc.h | 2 + tools/include/nolibc/arch-x86.h | 4 ++ tools/include/nolibc/compiler.h | 4 +- tools/include/nolibc/crt.h | 3 ++ tools/include/nolibc/dirent.h | 6 +-- tools/include/nolibc/nolibc.h | 2 + tools/include/nolibc/stackprotector.h | 2 + tools/include/nolibc/stdio.h | 2 + tools/include/nolibc/stdlib.h | 2 + tools/include/nolibc/sys.h | 3 +- tools/include/nolibc/sys/auxv.h | 3 ++ tools/include/nolibc/sys/ptrace.h | 52 ++++++++++++++++++++ tools/include/nolibc/sys/uio.h | 49 ++++++++++++++++++ tools/testing/selftests/nolibc/nolibc-test.c | 11 +++++ 39 files changed, 222 insertions(+), 48 deletions(-) create mode 100644 tools/include/nolibc/sys/ptrace.h create mode 100644 tools/include/nolibc/sys/uio.h
From: Benjamin Berg benjamin.berg@intel.com
The define mapped to __attribute__((__unused__)) instead of using __used__. Having the wrong definition here may result in the linker incorrectly removing the symbol. Also, this now matches the definition in include/linux/compiler_attributes.h.
Fixes: e58e871becec ("tools/lib/lockdep: Remove private kernel headers") Signed-off-by: Benjamin Berg benjamin.berg@intel.com Reviewed-by: Thomas Weißschuh linux@weissschuh.net --- tools/include/linux/compiler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/include/linux/compiler.h b/tools/include/linux/compiler.h index 33411ca0cc90..b2c40621d441 100644 --- a/tools/include/linux/compiler.h +++ b/tools/include/linux/compiler.h @@ -127,7 +127,7 @@ #endif
#ifndef __used -# define __used __attribute__((__unused__)) +# define __used __attribute__((__used__)) #endif
#ifndef __packed
From: Benjamin Berg benjamin.berg@intel.com
Using the kernel headers directly from the userspace parts of UML is problematic. Switch to use the headers from the tools/include subdirectory instead. These contain stripped down versions that work well for UML and only relatively small adjustments are needed to make it work.
This adds code to create two symlinks so that the userspace code can still find asm-offsets.h and user_constants.h. Other than that, some includes are moved into USER_CFLAGS instead of handling them in Makefile.rules.
Signed-off-by: Benjamin Berg benjamin.berg@intel.com
--- v2: - Fix out-of-tree building --- arch/um/Makefile | 18 ++++++++++++------ arch/um/include/shared/init.h | 2 +- arch/um/include/shared/user.h | 5 ----- arch/um/kernel/skas/stub.c | 1 + arch/um/kernel/skas/stub_exe.c | 4 ++-- arch/um/os-Linux/skas/process.c | 6 ++---- arch/um/os-Linux/start_up.c | 4 ++-- arch/um/scripts/Makefile.rules | 2 +- arch/x86/um/Makefile | 6 ++++-- arch/x86/um/user-offsets.c | 1 - 10 files changed, 25 insertions(+), 24 deletions(-)
diff --git a/arch/um/Makefile b/arch/um/Makefile index 7be0143b5ba3..f7c509262568 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -42,7 +42,7 @@ include $(srctree)/$(HOST_DIR)/Makefile.um core-y += $(HOST_DIR)/um/
SHARED_HEADERS := $(ARCH_DIR)/include/shared -ARCH_INCLUDE := -I$(srctree)/$(SHARED_HEADERS) +ARCH_INCLUDE := -I$(srctree)/$(SHARED_HEADERS) -I$(objtree)/$(SHARED_HEADERS) ARCH_INCLUDE += -I$(srctree)/$(HOST_DIR)/um/shared KBUILD_CPPFLAGS += -I$(srctree)/$(HOST_DIR)/um
@@ -70,10 +70,13 @@ KBUILD_AFLAGS += $(ARCH_INCLUDE)
USER_CFLAGS = $(patsubst $(KERNEL_DEFINES),,$(patsubst -I%,,$(KBUILD_CFLAGS))) \ $(ARCH_INCLUDE) $(MODE_INCLUDE) $(filter -I%,$(CFLAGS)) \ - -D_FILE_OFFSET_BITS=64 -idirafter $(srctree)/include \ - -idirafter $(objtree)/include -D__KERNEL__ -D__UM_HOST__ \ - -include $(srctree)/include/linux/compiler-version.h \ - -include $(srctree)/include/linux/kconfig.h + -idirafter $(srctree)/tools/include \ + -D__UM_HOST__ \ + -include $(srctree)/tools/include/linux/compiler.h \ + -include $(srctree)/tools/include/linux/kconfig.h \ + -include $(objtree)/include/generated/autoconf.h \ + -include $(srctree)/include/linux/kern_levels.h \ + -include $(srctree)/$(ARCH_DIR)/include/shared/user.h
#This will adjust *FLAGS accordingly to the platform. include $(srctree)/$(ARCH_DIR)/Makefile-os-Linux @@ -116,6 +119,9 @@ archheaders:
archprepare: $(Q)$(MAKE) $(build)=$(HOST_DIR)/um include/generated/user_constants.h + $(Q)mkdir -p $(ARCH_DIR)/include/shared/generated + $(Q)ln -fs ../../../../../include/generated/user_constants.h $(ARCH_DIR)/include/shared/generated/ + $(Q)ln -fs ../../../../../include/generated/asm-offsets.h $(ARCH_DIR)/include/shared/generated/
LINK-$(CONFIG_LD_SCRIPT_STATIC) += -static LINK-$(CONFIG_LD_SCRIPT_DYN) += -no-pie @@ -147,7 +153,7 @@ export CFLAGS_vmlinux := $(LINK-y) $(LINK_WRAPS) $(LD_FLAGS_CMDLINE) $(CC_FLAGS_ # When cleaning we don't include .config, so we don't include # TT or skas makefiles and don't clean skas_ptregs.h. CLEAN_FILES += linux x.i gmon.out -MRPROPER_FILES += $(HOST_DIR)/include/generated +MRPROPER_FILES += $(HOST_DIR)/include/generated $(ARCH_DIR)/include/shared/generated
archclean: @find . ( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \ diff --git a/arch/um/include/shared/init.h b/arch/um/include/shared/init.h index 1a659e2e8cc3..d201705bedb3 100644 --- a/arch/um/include/shared/init.h +++ b/arch/um/include/shared/init.h @@ -41,7 +41,7 @@ typedef int (*initcall_t)(void); typedef void (*exitcall_t)(void);
-#include <linux/compiler_types.h> +#define __section(section) __attribute__((__section__(section)))
/* These are for everybody (although not all archs will actually discard it in modules) */ diff --git a/arch/um/include/shared/user.h b/arch/um/include/shared/user.h index 139eb78a4767..c9b853e1282f 100644 --- a/arch/um/include/shared/user.h +++ b/arch/um/include/shared/user.h @@ -16,13 +16,8 @@ */ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-/* This is to get size_t and NULL */ -#ifndef __UM_HOST__ #include <linux/types.h> -#else #include <stddef.h> -#include <sys/types.h> -#endif
extern void panic(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); diff --git a/arch/um/kernel/skas/stub.c b/arch/um/kernel/skas/stub.c index 67cab46a602c..6c9bb1511ea2 100644 --- a/arch/um/kernel/skas/stub.c +++ b/arch/um/kernel/skas/stub.c @@ -5,6 +5,7 @@
#include <sysdep/stub.h>
+#include <linux/init.h> #include <linux/futex.h> #include <sys/socket.h> #include <errno.h> diff --git a/arch/um/kernel/skas/stub_exe.c b/arch/um/kernel/skas/stub_exe.c index cbafaa684e66..0563838c01d1 100644 --- a/arch/um/kernel/skas/stub_exe.c +++ b/arch/um/kernel/skas/stub_exe.c @@ -4,8 +4,8 @@ #include <asm/unistd.h> #include <sysdep/stub.h> #include <stub-data.h> -#include <linux/filter.h> -#include <linux/seccomp.h> +#include <uapi/linux/filter.h> +#include <uapi/linux/seccomp.h> #include <generated/asm-offsets.h>
void _start(void); diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index 78f48fa9db8b..8ad7e863af97 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c @@ -29,9 +29,7 @@ #include <sysdep/stub.h> #include <sysdep/mcontext.h> #include <linux/futex.h> -#include <linux/threads.h> #include <timetravel.h> -#include <asm-generic/rwonce.h> #include "../internal.h"
int is_skas_winch(int pid, int fd, void *data) @@ -204,7 +202,7 @@ void wait_stub_done_seccomp(struct mm_id *mm_idp, int running, int wait_sigsys) * Either way, if PID is negative, then we have no * choice but to kill the task. */ - if (__READ_ONCE(mm_idp->pid) < 0) + if (READ_ONCE(mm_idp->pid) < 0) goto out_kill;
ret = syscall(__NR_futex, &data->futex, @@ -217,7 +215,7 @@ void wait_stub_done_seccomp(struct mm_id *mm_idp, int running, int wait_sigsys) } } while (data->futex == FUTEX_IN_CHILD);
- if (__READ_ONCE(mm_idp->pid) < 0) + if (READ_ONCE(mm_idp->pid) < 0) goto out_kill;
running = 0; diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index a827c2e01aa5..8971f4fdddab 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -28,8 +28,8 @@ #include <stdbool.h> #include <stub-data.h> #include <sys/prctl.h> -#include <linux/seccomp.h> -#include <linux/filter.h> +#include <uapi/linux/seccomp.h> +#include <uapi/linux/filter.h> #include <sysdep/mcontext.h> #include <sysdep/stub.h> #include <registers.h> diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules index a8b7d9dab0a6..b4a2e0058503 100644 --- a/arch/um/scripts/Makefile.rules +++ b/arch/um/scripts/Makefile.rules @@ -9,7 +9,7 @@ USER_OBJS += $(filter %_user.o,$(obj-y) $(USER_SINGLE_OBJS)) USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
$(USER_OBJS:.o=.%): \ - c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) -include $(srctree)/include/linux/kern_levels.h -include user.h $(CFLAGS_$(basetarget).o) + c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) $(CFLAGS_$(basetarget).o)
# These are like USER_OBJS but filter USER_CFLAGS through unprofile instead of # using it directly. diff --git a/arch/x86/um/Makefile b/arch/x86/um/Makefile index b42c31cd2390..d8a120bace25 100644 --- a/arch/x86/um/Makefile +++ b/arch/x86/um/Makefile @@ -38,8 +38,10 @@ subarch-$(CONFIG_MODULES) += ../kernel/module.o
USER_OBJS := bugs_$(BITS).o ptrace_user.o fault.o
-$(obj)/user-offsets.s: c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) \ - -Iarch/x86/include/generated +$(obj)/user-offsets.s: c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) \ + -Iarch/x86/include/generated \ + -include $(srctree)/include/linux/kbuild.h + targets += user-offsets.s
include/generated/user_constants.h: $(obj)/user-offsets.s FORCE diff --git a/arch/x86/um/user-offsets.c b/arch/x86/um/user-offsets.c index d6e1cd9956bf..74fc9763b76e 100644 --- a/arch/x86/um/user-offsets.c +++ b/arch/x86/um/user-offsets.c @@ -8,7 +8,6 @@ #define __FRAME_OFFSETS #include <linux/ptrace.h> #include <asm/types.h> -#include <linux/kbuild.h>
#define DEFINE_LONGS(sym, val) \ COMMENT(#val " / sizeof(unsigned long)"); \
From: Benjamin Berg benjamin.berg@intel.com
There is no errno variable when NOLIBC_IGNORE_ERRNO is defined. As such, the perror function does not make any sense then and cannot compile.
Fixes: acab7bcdb1bc ("tools/nolibc/stdio: add perror() to report the errno value") Signed-off-by: Benjamin Berg benjamin.berg@intel.com Acked-by: Thomas Weißschuh linux@weissschuh.net --- tools/include/nolibc/stdio.h | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 7630234408c5..c512159b8374 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -597,11 +597,13 @@ int sscanf(const char *str, const char *format, ...) return ret; }
+#ifndef NOLIBC_IGNORE_ERRNO static __attribute__((unused)) void perror(const char *msg) { fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno); } +#endif
static __attribute__((unused)) int setvbuf(FILE *stream __attribute__((unused)),
Hi Benjamin,
On Fri, Sep 19, 2025 at 05:34:12PM +0200, Benjamin Berg wrote:
From: Benjamin Berg benjamin.berg@intel.com
There is no errno variable when NOLIBC_IGNORE_ERRNO is defined. As such, the perror function does not make any sense then and cannot compile.
Fixes: acab7bcdb1bc ("tools/nolibc/stdio: add perror() to report the errno value") Signed-off-by: Benjamin Berg benjamin.berg@intel.com Acked-by: Thomas Weißschuh linux@weissschuh.net
tools/include/nolibc/stdio.h | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 7630234408c5..c512159b8374 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -597,11 +597,13 @@ int sscanf(const char *str, const char *format, ...) return ret; } +#ifndef NOLIBC_IGNORE_ERRNO static __attribute__((unused)) void perror(const char *msg) { fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno); } +#endif
Please instead place the ifndef inside the function so that code calling perror() continues to build. The original goal of that macro was to further shrink programs at the expense of losing error details. But we should be able to continue to build working programs with that macro defined. There's nothing hard set in stone regarding this but here it's easy to preserve a working behavior by having something like this for example:
static __attribute__((unused)) void perror(const char *msg) { +#ifdef NOLIBC_IGNORE_ERRNO + fprintf(stderr, "%s\n", (msg && *msg) ? msg : "unknown error"); +#else fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno); +#endif }
thanks! Willy
On 2025-09-21 09:55:11+0200, Willy Tarreau wrote:
Hi Benjamin,
On Fri, Sep 19, 2025 at 05:34:12PM +0200, Benjamin Berg wrote:
From: Benjamin Berg benjamin.berg@intel.com
There is no errno variable when NOLIBC_IGNORE_ERRNO is defined. As such, the perror function does not make any sense then and cannot compile.
Fixes: acab7bcdb1bc ("tools/nolibc/stdio: add perror() to report the errno value") Signed-off-by: Benjamin Berg benjamin.berg@intel.com Acked-by: Thomas Weißschuh linux@weissschuh.net
tools/include/nolibc/stdio.h | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 7630234408c5..c512159b8374 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -597,11 +597,13 @@ int sscanf(const char *str, const char *format, ...) return ret; } +#ifndef NOLIBC_IGNORE_ERRNO static __attribute__((unused)) void perror(const char *msg) { fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno); } +#endif
Please instead place the ifndef inside the function so that code calling perror() continues to build. The original goal of that macro was to further shrink programs at the expense of losing error details. But we should be able to continue to build working programs with that macro defined. There's nothing hard set in stone regarding this but here it's easy to preserve a working behavior by having something like this for example:
static __attribute__((unused)) void perror(const char *msg) { +#ifdef NOLIBC_IGNORE_ERRNO
- fprintf(stderr, "%s\n", (msg && *msg) ? msg : "unknown error");
+#else fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno); +#endif }
For the plain `errno` variable and printf(%m) we don't have such fallbacks. With NOLIBC_IGNORE_ERRNO the compilation either fails or the results are undefined. Personally I prefer not defining perror() here.
Thomas
Hi,
On Sun, 2025-09-21 at 18:37 +0200, Thomas Weißschuh wrote:
On 2025-09-21 09:55:11+0200, Willy Tarreau wrote:
Hi Benjamin,
On Fri, Sep 19, 2025 at 05:34:12PM +0200, Benjamin Berg wrote:
From: Benjamin Berg benjamin.berg@intel.com
There is no errno variable when NOLIBC_IGNORE_ERRNO is defined. As such, the perror function does not make any sense then and cannot compile.
Fixes: acab7bcdb1bc ("tools/nolibc/stdio: add perror() to report the errno value") Signed-off-by: Benjamin Berg benjamin.berg@intel.com Acked-by: Thomas Weißschuh linux@weissschuh.net
tools/include/nolibc/stdio.h | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 7630234408c5..c512159b8374 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -597,11 +597,13 @@ int sscanf(const char *str, const char *format, ...) return ret; } +#ifndef NOLIBC_IGNORE_ERRNO static __attribute__((unused)) void perror(const char *msg) { fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno); } +#endif
Please instead place the ifndef inside the function so that code calling perror() continues to build. The original goal of that macro was to further shrink programs at the expense of losing error details. But we should be able to continue to build working programs with that macro defined. There's nothing hard set in stone regarding this but here it's easy to preserve a working behavior by having something like this for example:
static __attribute__((unused)) void perror(const char *msg) { +#ifdef NOLIBC_IGNORE_ERRNO + fprintf(stderr, "%s\n", (msg && *msg) ? msg : "unknown error"); +#else fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno); +#endif }
For the plain `errno` variable and printf(%m) we don't have such fallbacks. With NOLIBC_IGNORE_ERRNO the compilation either fails or the results are undefined. Personally I prefer not defining perror() here.
So, with NOLIBC_IGNORE_ERRNO, we do not have the "errno" variable either and code using it will break. I actually think that this is a good thing and it is part of the reason that I wanted to explicitly set the flag for UML.
This also ties to the question of the other mail. I prefer "errno" not to be available if it is not actually safe to use. UML does use threads in some places (and may use it extensively in the future). The current "errno" implementation is not threadsafe and I see neither an obvious way nor a need to change that. By setting NOLIBC_IGNORE_ERRNO any unsafe code will not compile and can be changed to use the sys_* functions to avoid errno.
Benjamin
On Sun, Sep 21, 2025 at 07:05:24PM +0200, Benjamin Berg wrote:
This also ties to the question of the other mail. I prefer "errno" not to be available if it is not actually safe to use. UML does use threads in some places (and may use it extensively in the future). The current "errno" implementation is not threadsafe and I see neither an obvious way nor a need to change that. By setting NOLIBC_IGNORE_ERRNO any unsafe code will not compile and can be changed to use the sys_* functions to avoid errno.
That's the point I disagree with because here we're not using errno more than printf() or dirent(). Why fix dirent() to build without errno and break perror() ? Why not also break printf() then ? All of this must be consistent. We're unbreaking some arbitrary functions and breaking other arbitrary ones, that's not logical.
I'm totally fine with saying that errno shouldn't be defined when building without errno, but all functions must continue to be defined. perror() is used to print an error message, it's a valid use case just as printf() and should remain.
If we disable perror for this, then we must also disable usage of printf for consistency (and I don't want this either).
Willy
Hi,
On Sun, 2025-09-21 at 19:13 +0200, Willy Tarreau wrote:
On Sun, Sep 21, 2025 at 07:05:24PM +0200, Benjamin Berg wrote:
This also ties to the question of the other mail. I prefer "errno" not to be available if it is not actually safe to use. UML does use threads in some places (and may use it extensively in the future). The current "errno" implementation is not threadsafe and I see neither an obvious way nor a need to change that. By setting NOLIBC_IGNORE_ERRNO any unsafe code will not compile and can be changed to use the sys_* functions to avoid errno.
That's the point I disagree with because here we're not using errno more than printf() or dirent(). Why fix dirent() to build without errno and break perror() ? Why not also break printf() then ? All of this must be consistent. We're unbreaking some arbitrary functions and breaking other arbitrary ones, that's not logical.
I'm totally fine with saying that errno shouldn't be defined when building without errno, but all functions must continue to be defined. perror() is used to print an error message, it's a valid use case just as printf() and should remain.
If we disable perror for this, then we must also disable usage of printf for consistency (and I don't want this either).
Right, fair enough. It is true that it does not really hurt to keep perror defined. I doubt there is much code out there, but I also don't really have a a strong argument against keeping perror. After all, it will "just" result in a bad error messages rather than undefined behaviour.
Benjamin
On Sun, Sep 21, 2025 at 07:16:50PM +0200, Benjamin Berg wrote:
Hi,
On Sun, 2025-09-21 at 19:13 +0200, Willy Tarreau wrote:
On Sun, Sep 21, 2025 at 07:05:24PM +0200, Benjamin Berg wrote:
This also ties to the question of the other mail. I prefer "errno" not to be available if it is not actually safe to use. UML does use threads in some places (and may use it extensively in the future). The current "errno" implementation is not threadsafe and I see neither an obvious way nor a need to change that. By setting NOLIBC_IGNORE_ERRNO any unsafe code will not compile and can be changed to use the sys_* functions to avoid errno.
That's the point I disagree with because here we're not using errno more than printf() or dirent(). Why fix dirent() to build without errno and break perror() ? Why not also break printf() then ? All of this must be consistent. We're unbreaking some arbitrary functions and breaking other arbitrary ones, that's not logical.
I'm totally fine with saying that errno shouldn't be defined when building without errno, but all functions must continue to be defined. perror() is used to print an error message, it's a valid use case just as printf() and should remain.
If we disable perror for this, then we must also disable usage of printf for consistency (and I don't want this either).
Right, fair enough. It is true that it does not really hurt to keep perror defined. I doubt there is much code out there, but I also don't really have a a strong argument against keeping perror. After all, it will "just" result in a bad error messages rather than undefined behaviour.
It shouldn't be a "bad" error message, just a limited one, which is the main purpose of ignoring errno (i.e. where we're running we don't care about error details since the user only needs to know that it failed, or may even not know about it at all). perror *does* display the caller's error message. I'm personally fine with seeing:
"open(): unknown error"
for:
if (open(path, O_RDONLY) < 0) perror("open()");
when building without errno.
Willy
On 2025-09-21 19:13:23+0200, Willy Tarreau wrote:
On Sun, Sep 21, 2025 at 07:05:24PM +0200, Benjamin Berg wrote:
This also ties to the question of the other mail. I prefer "errno" not to be available if it is not actually safe to use. UML does use threads in some places (and may use it extensively in the future). The current "errno" implementation is not threadsafe and I see neither an obvious way nor a need to change that. By setting NOLIBC_IGNORE_ERRNO any unsafe code will not compile and can be changed to use the sys_* functions to avoid errno.
That's the point I disagree with because here we're not using errno more than printf() or dirent(). Why fix dirent() to build without errno and break perror() ? Why not also break printf() then ? All of this must be consistent. We're unbreaking some arbitrary functions and breaking other arbitrary ones, that's not logical.
printf() is already broken. So by breaking perror() it would have been consistent :-/.
I'm totally fine with saying that errno shouldn't be defined when building without errno, but all functions must continue to be defined. perror() is used to print an error message, it's a valid use case just as printf() and should remain.
If we disable perror for this, then we must also disable usage of printf for consistency (and I don't want this either).
Then let's also fix printf(). Benjamin, do you want to add this to your series? It should be consitent with the perror() fallback.
Thomas
On Sun, Sep 21, 2025 at 08:26:35PM +0200, Thomas Weißschuh wrote:
I'm totally fine with saying that errno shouldn't be defined when building without errno, but all functions must continue to be defined. perror() is used to print an error message, it's a valid use case just as printf() and should remain.
If we disable perror for this, then we must also disable usage of printf for consistency (and I don't want this either).
Then let's also fix printf(). Benjamin, do you want to add this to your series? It should be consitent with the perror() fallback.
Yes that would be great given that the series focuses on fixing errno usage.
Thanks, Willy
On Sun, Sep 21, 2025 at 06:37:30PM +0200, Thomas Weißschuh wrote:
On 2025-09-21 09:55:11+0200, Willy Tarreau wrote:
Hi Benjamin,
On Fri, Sep 19, 2025 at 05:34:12PM +0200, Benjamin Berg wrote:
From: Benjamin Berg benjamin.berg@intel.com
There is no errno variable when NOLIBC_IGNORE_ERRNO is defined. As such, the perror function does not make any sense then and cannot compile.
Fixes: acab7bcdb1bc ("tools/nolibc/stdio: add perror() to report the errno value") Signed-off-by: Benjamin Berg benjamin.berg@intel.com Acked-by: Thomas Weißschuh linux@weissschuh.net
tools/include/nolibc/stdio.h | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 7630234408c5..c512159b8374 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -597,11 +597,13 @@ int sscanf(const char *str, const char *format, ...) return ret; } +#ifndef NOLIBC_IGNORE_ERRNO static __attribute__((unused)) void perror(const char *msg) { fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno); } +#endif
Please instead place the ifndef inside the function so that code calling perror() continues to build. The original goal of that macro was to further shrink programs at the expense of losing error details. But we should be able to continue to build working programs with that macro defined. There's nothing hard set in stone regarding this but here it's easy to preserve a working behavior by having something like this for example:
static __attribute__((unused)) void perror(const char *msg) { +#ifdef NOLIBC_IGNORE_ERRNO
- fprintf(stderr, "%s\n", (msg && *msg) ? msg : "unknown error");
+#else fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno); +#endif }
For the plain `errno` variable and printf(%m) we don't have such fallbacks. With NOLIBC_IGNORE_ERRNO the compilation either fails or the results are undefined. Personally I prefer not defining perror() here.
For me it's still a problem because that breaks the original purpose and current behavior. You cannot anymore compare the size of with/without errno for example, like here:
text data bss dec hex filename 20659 24 39424 60107 eacb init 19836 24 39424 59284 e794 init-noerrno
Perror doesn't just display the error name/number, it also prints a message about that error that doesn't need errno.
For "%m", that's fair enough, I didn't notice that one. We could imagine improving it by just emitting "?" or any such thing. But right now it will indeed proceed like you describe (that's already the case, it's not changed by this patch).
I don't want to block that patch but I'm annoyed that it unfairly blocks a legitimate error function that normally provides sufficient context in error paths so that errno can be ignored, such as here:
if (open(path, O_RDONLY) < 0) { perror("open()"); return -1; }
What's even more problematic is that Benjamin precisely fixed two other breakage cases in the same series for the same reason that they were blocking the build without errno, so it would be more consistent that this one isn't newly broken.
Willy
From: Benjamin Berg benjamin.berg@intel.com
Using errno is not possible when NOLIBC_IGNORE_ERRNO is set. Use sys_lseek instead of lseek as that avoids using errno.
Fixes: 665fa8dea90d ("tools/nolibc: add support for directory access") Signed-off-by: Benjamin Berg benjamin.berg@intel.com Acked-by: Thomas Weißschuh linux@weissschuh.net --- tools/include/nolibc/dirent.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/tools/include/nolibc/dirent.h b/tools/include/nolibc/dirent.h index 758b95c48e7a..61a122a60327 100644 --- a/tools/include/nolibc/dirent.h +++ b/tools/include/nolibc/dirent.h @@ -86,9 +86,9 @@ 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 = lseek(fd, ldir->d_off, SEEK_SET); - if (ret == -1) - return errno; + ret = sys_lseek(fd, ldir->d_off, SEEK_SET); + if (ret < 0) + return -ret;
entry->d_ino = ldir->d_ino; /* the destination should always be big enough */
From: Benjamin Berg benjamin.berg@intel.com
Use the version of the attribute with underscores to avoid issues if fallthrough has been defined by another header file already.
Signed-off-by: Benjamin Berg benjamin.berg@intel.com Acked-by: Thomas Weißschuh linux@weissschuh.net --- tools/include/nolibc/compiler.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tools/include/nolibc/compiler.h b/tools/include/nolibc/compiler.h index 369cfb5a0e78..87090bbc53e0 100644 --- a/tools/include/nolibc/compiler.h +++ b/tools/include/nolibc/compiler.h @@ -41,8 +41,8 @@ # define __no_stack_protector __attribute__((__optimize__("-fno-stack-protector"))) #endif /* __nolibc_has_attribute(no_stack_protector) */
-#if __nolibc_has_attribute(fallthrough) -# define __nolibc_fallthrough do { } while (0); __attribute__((fallthrough)) +#if __nolibc_has_attribute(__fallthrough__) +# define __nolibc_fallthrough do { } while (0); __attribute__((__fallthrough__)) #else # define __nolibc_fallthrough do { } while (0) #endif /* __nolibc_has_attribute(fallthrough) */
From: Benjamin Berg benjamin.berg@intel.com
In principle, it is possible to use nolibc for only some object files in a program. In that case, the startup code in _start and _start_c is not going to be used. Add the NOLIBC_NO_RUNTIME compile time option to disable it entirely and also remove anything that depends on it.
Doing this avoids warnings from modpost for UML as the _start_c code references the main function from the .init.text section while it is not inside .init itself.
Signed-off-by: Benjamin Berg benjamin.berg@intel.com
--- v2: - Renamed from NOLIBC_NO_STARTCODE to NOLIBC_NO_RUNTIME - Put the #ifdef around relevant comments --- tools/include/nolibc/arch-arm.h | 2 ++ tools/include/nolibc/arch-arm64.h | 2 ++ tools/include/nolibc/arch-loongarch.h | 2 ++ tools/include/nolibc/arch-m68k.h | 2 ++ tools/include/nolibc/arch-mips.h | 2 ++ tools/include/nolibc/arch-powerpc.h | 2 ++ tools/include/nolibc/arch-riscv.h | 2 ++ tools/include/nolibc/arch-s390.h | 2 ++ tools/include/nolibc/arch-sh.h | 2 ++ tools/include/nolibc/arch-sparc.h | 2 ++ tools/include/nolibc/arch-x86.h | 4 ++++ tools/include/nolibc/crt.h | 3 +++ tools/include/nolibc/stackprotector.h | 2 ++ tools/include/nolibc/stdlib.h | 2 ++ tools/include/nolibc/sys.h | 3 ++- tools/include/nolibc/sys/auxv.h | 3 +++ 16 files changed, 36 insertions(+), 1 deletion(-)
diff --git a/tools/include/nolibc/arch-arm.h b/tools/include/nolibc/arch-arm.h index 1f66e7e5a444..251c42579028 100644 --- a/tools/include/nolibc/arch-arm.h +++ b/tools/include/nolibc/arch-arm.h @@ -184,6 +184,7 @@ _arg1; \ })
+#ifndef NOLIBC_NO_RUNTIME /* startup code */ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void) { @@ -193,5 +194,6 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s ); __nolibc_entrypoint_epilogue(); } +#endif /* NOLIBC_NO_RUNTIME */
#endif /* _NOLIBC_ARCH_ARM_H */ diff --git a/tools/include/nolibc/arch-arm64.h b/tools/include/nolibc/arch-arm64.h index 02a3f74c8ec8..080a55a7144e 100644 --- a/tools/include/nolibc/arch-arm64.h +++ b/tools/include/nolibc/arch-arm64.h @@ -141,6 +141,7 @@ _arg1; \ })
+#ifndef NOLIBC_NO_RUNTIME /* startup code */ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void) { @@ -150,4 +151,5 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s ); __nolibc_entrypoint_epilogue(); } +#endif /* NOLIBC_NO_RUNTIME */ #endif /* _NOLIBC_ARCH_ARM64_H */ diff --git a/tools/include/nolibc/arch-loongarch.h b/tools/include/nolibc/arch-loongarch.h index 5511705303ea..c894176c3f89 100644 --- a/tools/include/nolibc/arch-loongarch.h +++ b/tools/include/nolibc/arch-loongarch.h @@ -142,6 +142,7 @@ _arg1; \ })
+#ifndef NOLIBC_NO_RUNTIME /* startup code */ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void) { @@ -151,5 +152,6 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s ); __nolibc_entrypoint_epilogue(); } +#endif /* NOLIBC_NO_RUNTIME */
#endif /* _NOLIBC_ARCH_LOONGARCH_H */ diff --git a/tools/include/nolibc/arch-m68k.h b/tools/include/nolibc/arch-m68k.h index 6dac1845f298..2a4fbada5e79 100644 --- a/tools/include/nolibc/arch-m68k.h +++ b/tools/include/nolibc/arch-m68k.h @@ -128,6 +128,7 @@ _num; \ })
+#ifndef NOLIBC_NO_RUNTIME void _start(void); void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void) { @@ -137,5 +138,6 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s ); __nolibc_entrypoint_epilogue(); } +#endif /* NOLIBC_NO_RUNTIME */
#endif /* _NOLIBC_ARCH_M68K_H */ diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h index 0cbac63b249a..a72506ceec6b 100644 --- a/tools/include/nolibc/arch-mips.h +++ b/tools/include/nolibc/arch-mips.h @@ -245,6 +245,7 @@
#endif /* _ABIO32 */
+#ifndef NOLIBC_NO_RUNTIME /* startup code, note that it's called __start on MIPS */ void __start(void); void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector __start(void) @@ -266,5 +267,6 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector __ ); __nolibc_entrypoint_epilogue(); } +#endif /* NOLIBC_NO_RUNTIME */
#endif /* _NOLIBC_ARCH_MIPS_H */ diff --git a/tools/include/nolibc/arch-powerpc.h b/tools/include/nolibc/arch-powerpc.h index 204564bbcd32..e0c7e0b81f7c 100644 --- a/tools/include/nolibc/arch-powerpc.h +++ b/tools/include/nolibc/arch-powerpc.h @@ -183,6 +183,7 @@ #endif #endif /* !__powerpc64__ */
+#ifndef NOLIBC_NO_RUNTIME /* startup code */ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void) { @@ -215,5 +216,6 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s #endif __nolibc_entrypoint_epilogue(); } +#endif /* NOLIBC_NO_RUNTIME */
#endif /* _NOLIBC_ARCH_POWERPC_H */ diff --git a/tools/include/nolibc/arch-riscv.h b/tools/include/nolibc/arch-riscv.h index 885383a86c38..1c00cacf57e1 100644 --- a/tools/include/nolibc/arch-riscv.h +++ b/tools/include/nolibc/arch-riscv.h @@ -139,6 +139,7 @@ _arg1; \ })
+#ifndef NOLIBC_NO_RUNTIME /* startup code */ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void) { @@ -152,5 +153,6 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s ); __nolibc_entrypoint_epilogue(); } +#endif /* NOLIBC_NO_RUNTIME */
#endif /* _NOLIBC_ARCH_RISCV_H */ diff --git a/tools/include/nolibc/arch-s390.h b/tools/include/nolibc/arch-s390.h index df4c3cc713ac..6237211385c0 100644 --- a/tools/include/nolibc/arch-s390.h +++ b/tools/include/nolibc/arch-s390.h @@ -139,6 +139,7 @@ _arg1; \ })
+#ifndef NOLIBC_NO_RUNTIME /* startup code */ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void) { @@ -155,6 +156,7 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s ); __nolibc_entrypoint_epilogue(); } +#endif /* NOLIBC_NO_RUNTIME */
struct s390_mmap_arg_struct { unsigned long addr; diff --git a/tools/include/nolibc/arch-sh.h b/tools/include/nolibc/arch-sh.h index a96b8914607e..7a421197d104 100644 --- a/tools/include/nolibc/arch-sh.h +++ b/tools/include/nolibc/arch-sh.h @@ -140,6 +140,7 @@ _ret; \ })
+#ifndef NOLIBC_NO_RUNTIME /* startup code */ void _start_wrapper(void); void __attribute__((weak,noreturn)) __nolibc_entrypoint __no_stack_protector _start_wrapper(void) @@ -158,5 +159,6 @@ void __attribute__((weak,noreturn)) __nolibc_entrypoint __no_stack_protector _st ); __nolibc_entrypoint_epilogue(); } +#endif /* NOLIBC_NO_RUNTIME */
#endif /* _NOLIBC_ARCH_SH_H */ diff --git a/tools/include/nolibc/arch-sparc.h b/tools/include/nolibc/arch-sparc.h index ca420d843e25..2ebb5686e105 100644 --- a/tools/include/nolibc/arch-sparc.h +++ b/tools/include/nolibc/arch-sparc.h @@ -152,6 +152,7 @@ _arg1; \ })
+#ifndef NOLIBC_NO_RUNTIME /* startup code */ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void) { @@ -169,6 +170,7 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s ); __nolibc_entrypoint_epilogue(); } +#endif /* NOLIBC_NO_RUNTIME */
static pid_t getpid(void);
diff --git a/tools/include/nolibc/arch-x86.h b/tools/include/nolibc/arch-x86.h index d3efc0c3b8ad..11abb8bd7eec 100644 --- a/tools/include/nolibc/arch-x86.h +++ b/tools/include/nolibc/arch-x86.h @@ -157,6 +157,7 @@ _eax; \ })
+#ifndef NOLIBC_NO_RUNTIME /* startup code */ /* * i386 System V ABI mandates: @@ -176,6 +177,7 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s ); __nolibc_entrypoint_epilogue(); } +#endif /* NOLIBC_NO_RUNTIME */
#else /* !defined(__x86_64__) */
@@ -323,6 +325,7 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s _ret; \ })
+#ifndef NOLIBC_NO_RUNTIME /* startup code */ /* * x86-64 System V ABI mandates: @@ -340,6 +343,7 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s ); __nolibc_entrypoint_epilogue(); } +#endif /* NOLIBC_NO_RUNTIME */
#define NOLIBC_ARCH_HAS_MEMMOVE void *memmove(void *dst, const void *src, size_t len); diff --git a/tools/include/nolibc/crt.h b/tools/include/nolibc/crt.h index 961cfe777c35..d9262998dae9 100644 --- a/tools/include/nolibc/crt.h +++ b/tools/include/nolibc/crt.h @@ -7,6 +7,8 @@ #ifndef _NOLIBC_CRT_H #define _NOLIBC_CRT_H
+#ifndef NOLIBC_NO_RUNTIME + #include "compiler.h"
char **environ __attribute__((weak)); @@ -88,4 +90,5 @@ void _start_c(long *sp) exit(exitcode); }
+#endif /* NOLIBC_NO_RUNTIME */ #endif /* _NOLIBC_CRT_H */ diff --git a/tools/include/nolibc/stackprotector.h b/tools/include/nolibc/stackprotector.h index c71a2c257177..7123aa056cb0 100644 --- a/tools/include/nolibc/stackprotector.h +++ b/tools/include/nolibc/stackprotector.h @@ -9,6 +9,7 @@
#include "compiler.h"
+#ifndef NOLIBC_NO_RUNTIME #if defined(_NOLIBC_STACKPROTECTOR)
#include "sys.h" @@ -49,5 +50,6 @@ static __no_stack_protector void __stack_chk_init(void) #else /* !defined(_NOLIBC_STACKPROTECTOR) */ static void __stack_chk_init(void) {} #endif /* defined(_NOLIBC_STACKPROTECTOR) */ +#endif /* NOLIBC_NO_RUNTIME */
#endif /* _NOLIBC_STACKPROTECTOR_H */ diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h index 5fd99a480f82..f184e108ed0a 100644 --- a/tools/include/nolibc/stdlib.h +++ b/tools/include/nolibc/stdlib.h @@ -100,6 +100,7 @@ void free(void *ptr) munmap(heap, heap->len); }
+#ifndef NOLIBC_NO_RUNTIME /* getenv() tries to find the environment variable named <name> in the * environment array pointed to by global variable "environ" which must be * declared as a char **, and must be terminated by a NULL (it is recommended @@ -122,6 +123,7 @@ char *getenv(const char *name) } return NULL; } +#endif /* NOLIBC_NO_RUNTIME */
static __attribute__((unused)) void *malloc(size_t len) diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 295e71d34aba..a48f5117bfce 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -509,6 +509,7 @@ pid_t gettid(void) return sys_gettid(); }
+#ifndef NOLIBC_NO_RUNTIME static unsigned long getauxval(unsigned long key);
/* @@ -520,7 +521,7 @@ int getpagesize(void) { return __sysret((int)getauxval(AT_PAGESZ) ?: -ENOENT); } - +#endif /* NOLIBC_NO_RUNTIME */
/* * uid_t getuid(void); diff --git a/tools/include/nolibc/sys/auxv.h b/tools/include/nolibc/sys/auxv.h index c52463d6c18d..0e98325e7347 100644 --- a/tools/include/nolibc/sys/auxv.h +++ b/tools/include/nolibc/sys/auxv.h @@ -10,6 +10,8 @@ #ifndef _NOLIBC_SYS_AUXV_H #define _NOLIBC_SYS_AUXV_H
+#ifndef NOLIBC_NO_RUNTIME + #include "../crt.h"
static __attribute__((unused)) @@ -38,4 +40,5 @@ unsigned long getauxval(unsigned long type) return ret; }
+#endif /* NOLIBC_NO_RUNTIME */ #endif /* _NOLIBC_SYS_AUXV_H */
On 2025-09-19 17:34:15+0200, Benjamin Berg wrote:
From: Benjamin Berg benjamin.berg@intel.com
In principle, it is possible to use nolibc for only some object files in a program. In that case, the startup code in _start and _start_c is not going to be used. Add the NOLIBC_NO_RUNTIME compile time option to disable it entirely and also remove anything that depends on it.
Doing this avoids warnings from modpost for UML as the _start_c code references the main function from the .init.text section while it is not inside .init itself.
Signed-off-by: Benjamin Berg benjamin.berg@intel.com
Acked-by: Thomas Weißschuh linux@weissschuh.net
v2:
- Renamed from NOLIBC_NO_STARTCODE to NOLIBC_NO_RUNTIME
- Put the #ifdef around relevant comments
tools/include/nolibc/arch-arm.h | 2 ++ tools/include/nolibc/arch-arm64.h | 2 ++ tools/include/nolibc/arch-loongarch.h | 2 ++ tools/include/nolibc/arch-m68k.h | 2 ++ tools/include/nolibc/arch-mips.h | 2 ++ tools/include/nolibc/arch-powerpc.h | 2 ++ tools/include/nolibc/arch-riscv.h | 2 ++ tools/include/nolibc/arch-s390.h | 2 ++ tools/include/nolibc/arch-sh.h | 2 ++ tools/include/nolibc/arch-sparc.h | 2 ++ tools/include/nolibc/arch-x86.h | 4 ++++ tools/include/nolibc/crt.h | 3 +++ tools/include/nolibc/stackprotector.h | 2 ++ tools/include/nolibc/stdlib.h | 2 ++ tools/include/nolibc/sys.h | 3 ++- tools/include/nolibc/sys/auxv.h | 3 +++ 16 files changed, 36 insertions(+), 1 deletion(-)
(...)
From: Benjamin Berg benjamin.berg@intel.com
Add NOLIBC_CFLAGS and NOLIBC_OBJS to build files against nolibc rather than libc. With this it is possible to move to nolibc in smaller steps.
Set NOLIBC_IGNORE_ERRNO, as the nolibc errno implementation is overly simple and cannot handle threading. nolibc provides sys_* functions that do not emulate the libc errno behaviour and can be used instead.
Guard the syscall definition as it is a macro in nolibc.
Signed-off-by: Benjamin Berg benjamin.berg@intel.com
--- v2: - Do not include nolibc.h via CFLAGS - Make syscall guard more explicit - Remove __UM_NOLIBC__ define, it is not needed - Fix out-of-tree building --- arch/um/Makefile | 20 +++++++++++++++++++- arch/um/include/shared/os.h | 2 ++ arch/um/include/shared/user.h | 1 - arch/um/scripts/Makefile.rules | 8 +++++++- 4 files changed, 28 insertions(+), 3 deletions(-)
diff --git a/arch/um/Makefile b/arch/um/Makefile index f7c509262568..c3a81df50911 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -78,6 +78,24 @@ USER_CFLAGS = $(patsubst $(KERNEL_DEFINES),,$(patsubst -I%,,$(KBUILD_CFLAGS))) \ -include $(srctree)/include/linux/kern_levels.h \ -include $(srctree)/$(ARCH_DIR)/include/shared/user.h
+NOLIBC_CFLAGS = $(patsubst $(KERNEL_DEFINES),,$(patsubst -I%,,$(KBUILD_CFLAGS))) \ + $(ARCH_INCLUDE) $(MODE_INCLUDE) $(filter -I%,$(CFLAGS)) \ + -I $(srctree)/tools/include \ + -D__EXPORTED_HEADERS__ \ + -D__UM_HOST__ \ + -DNOLIBC_NO_RUNTIME \ + -DNOLIBC_IGNORE_ERRNO \ + -nostdlib -nostdinc -static \ + -I$(srctree)/include/uapi \ + -I$(srctree)/$(HOST_DIR)/include/uapi \ + -I$(objtree)/$(HOST_DIR)/include/generated/uapi \ + -I $(srctree)/tools/include/nolibc \ + -I $(srctree)/usr/include \ + -include $(objtree)/include/generated/autoconf.h \ + -include $(srctree)/tools/include/linux/kconfig.h \ + -include $(srctree)/include/linux/kern_levels.h \ + -include $(srctree)/$(ARCH_DIR)/include/shared/user.h + #This will adjust *FLAGS accordingly to the platform. include $(srctree)/$(ARCH_DIR)/Makefile-os-Linux
@@ -160,4 +178,4 @@ archclean: -o -name '*.gcov' ) -type f -print | xargs rm -f $(Q)$(MAKE) -f $(srctree)/Makefile ARCH=$(HEADER_ARCH) clean
-export HEADER_ARCH SUBARCH USER_CFLAGS CFLAGS_NO_HARDENING DEV_NULL_PATH +export HEADER_ARCH SUBARCH USER_CFLAGS NOLIBC_CFLAGS CFLAGS_NO_HARDENING DEV_NULL_PATH diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h index b35cc8ce333b..a131ae9e00db 100644 --- a/arch/um/include/shared/os.h +++ b/arch/um/include/shared/os.h @@ -327,7 +327,9 @@ extern int __ignore_sigio_fd(int fd); /* tty.c */ extern int get_pty(void);
+#ifndef NOLIBC long syscall(long number, ...); +#endif
/* irqflags tracing */ extern void block_signals_trace(void); diff --git a/arch/um/include/shared/user.h b/arch/um/include/shared/user.h index c9b853e1282f..e32bdd032029 100644 --- a/arch/um/include/shared/user.h +++ b/arch/um/include/shared/user.h @@ -16,7 +16,6 @@ */ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-#include <linux/types.h> #include <stddef.h>
extern void panic(const char *fmt, ...) diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules index b4a2e0058503..5f07551935c3 100644 --- a/arch/um/scripts/Makefile.rules +++ b/arch/um/scripts/Makefile.rules @@ -11,6 +11,12 @@ USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) $(USER_OBJS:.o=.%): \ c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) $(CFLAGS_$(basetarget).o)
+# Similar USER_OBJS but compiled against nolibc (may include kernel headers?) +NOLIBC_OBJS := $(foreach file,$(NOLIBC_OBJS),$(obj)/$(file)) + +$(NOLIBC_OBJS:.o=.%): \ + c_flags = -Wp,-MD,$(depfile) $(NOLIBC_CFLAGS) $(CFLAGS_$(basetarget).o) + # These are like USER_OBJS but filter USER_CFLAGS through unprofile instead of # using it directly. UNPROFILE_OBJS := $(foreach file,$(UNPROFILE_OBJS),$(obj)/$(file)) @@ -18,7 +24,7 @@ UNPROFILE_OBJS := $(foreach file,$(UNPROFILE_OBJS),$(obj)/$(file)) $(UNPROFILE_OBJS:.o=.%): \ c_flags = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS)) $(CFLAGS_$(basetarget).o)
-$(USER_OBJS) $(UNPROFILE_OBJS): \ +$(USER_OBJS) $(NOLIBC_OBJS) $(UNPROFILE_OBJS): \ CHECKFLAGS := $(patsubst $(NOSTDINC_FLAGS),,$(CHECKFLAGS))
# The stubs can't try to call mcount or update basic block data
Hi Benjamin,
On Fri, Sep 19, 2025 at 05:34:16PM +0200, Benjamin Berg wrote:
From: Benjamin Berg benjamin.berg@intel.com
Add NOLIBC_CFLAGS and NOLIBC_OBJS to build files against nolibc rather than libc. With this it is possible to move to nolibc in smaller steps.
Set NOLIBC_IGNORE_ERRNO, as the nolibc errno implementation is overly simple and cannot handle threading. nolibc provides sys_* functions that do not emulate the libc errno behaviour and can be used instead.
Just for my understanding, in case we can improve portability, why is it needed to disable errno processing here ? Even if it's limited, it shouldn't cause trouble. I mean that if a program works with it defined, logically it should also work without since the only difference is that the errno global variable will not be defined nor assigned on syscall returns.
Guard the syscall definition as it is a macro in nolibc.
This one is interesting:
--- a/arch/um/include/shared/os.h +++ b/arch/um/include/shared/os.h @@ -327,7 +327,9 @@ extern int __ignore_sigio_fd(int fd); /* tty.c */ extern int get_pty(void);
+#ifndef NOLIBC long syscall(long number, ...); +#endif
In nolibc, the syscall() definition indeed looks like this now:
#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(N, ...) _syscall(N, __VA_ARGS__) #define syscall(...) _syscall_n(_syscall_narg(__VA_ARGS__), ##__VA_ARGS__)
Except by mapping all syscalls to _syscall(6, ...) and always passing 6 args, I'm not seeing any easy way to dynamically adapt to the number of arguments if we wanted to move it to a function. Also, a static function would still conflict with the definition above. I'm wondering about what extent the documented "long syscall(number, ...)" is valid in fact, as I doubt it's really implemented anywhere as a generic function taking the maximum amount of args.
Thus I think that the guard is indeed the only option to reconciliate these two incompatible approaches. By the way I think it could be more future- proof to do the guard on the syscall macro definition itself (which would thus also resist it being passed by "-Dsyscall(x)=(...)" or any other form:
+#ifndef syscall long syscall(long number, ...); +#endif
Regards, Willy
From: Benjamin Berg benjamin.berg@intel.com
This is one of the simplest files and it can be switched over to use nolibc without any modifications.
Signed-off-by: Benjamin Berg benjamin.berg@intel.com --- arch/um/kernel/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index b8f4e9281599..4b206a40b611 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -26,7 +26,7 @@ obj-$(CONFIG_OF) += dtb.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_STACKTRACE) += stacktrace.o
-USER_OBJS := config.o +NOLIBC_OBJS := config.o
include $(srctree)/arch/um/scripts/Makefile.rules
From: Benjamin Berg benjamin.berg@intel.com
This is generally useful and struct iovec is also needed for other purposes such as ptrace.
Signed-off-by: Benjamin Berg benjamin.berg@intel.com --- tools/include/nolibc/Makefile | 1 + tools/include/nolibc/nolibc.h | 1 + tools/include/nolibc/sys/uio.h | 49 ++++++++++++++++++++ tools/testing/selftests/nolibc/nolibc-test.c | 9 ++++ 4 files changed, 60 insertions(+) create mode 100644 tools/include/nolibc/sys/uio.h
diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile index 143c2d2c2ba6..9bbbba32dac6 100644 --- a/tools/include/nolibc/Makefile +++ b/tools/include/nolibc/Makefile @@ -62,6 +62,7 @@ all_files := \ sys/time.h \ sys/timerfd.h \ sys/types.h \ + sys/uio.h \ sys/utsname.h \ sys/wait.h \ time.h \ diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index c199ade200c2..b4bc1c9b883d 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -109,6 +109,7 @@ #include "sys/sysmacros.h" #include "sys/time.h" #include "sys/timerfd.h" +#include "sys/uio.h" #include "sys/utsname.h" #include "sys/wait.h" #include "ctype.h" diff --git a/tools/include/nolibc/sys/uio.h b/tools/include/nolibc/sys/uio.h new file mode 100644 index 000000000000..7ad42b927d2f --- /dev/null +++ b/tools/include/nolibc/sys/uio.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * uio for NOLIBC + * Copyright (C) 2017-2021 Willy Tarreau w@1wt.eu + * Copyright (C) 2025 Intel Corporation + */ + +/* make sure to include all global symbols */ +#include "../nolibc.h" + +#ifndef _NOLIBC_SYS_UIO_H +#define _NOLIBC_SYS_UIO_H + +#include "../sys.h" +#include <linux/uio.h> + + +/* + * 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) +{ + return my_syscall3(__NR_readv, fd, iovec, count); +} + +static __attribute__((unused)) +ssize_t readv(int fd, const struct iovec *iovec, int 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) +{ + return my_syscall3(__NR_writev, fd, iovec, count); +} + +static __attribute__((unused)) +ssize_t writev(int fd, const struct iovec *iovec, int count) +{ + return __sysret(sys_writev(fd, iovec, count)); +} + + +#endif /* _NOLIBC_SYS_UIO_H */ diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index a297ee0d6d07..1907128bc3f6 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -25,6 +25,7 @@ #include <sys/sysmacros.h> #include <sys/time.h> #include <sys/timerfd.h> +#include <sys/uio.h> #include <sys/utsname.h> #include <sys/wait.h> #include <dirent.h> @@ -1283,6 +1284,10 @@ int run_syscall(int min, int max) int proc; int test; int tmp; + struct iovec iov_one = { + .iov_base = &tmp, + .iov_len = 1, + }; int ret = 0; void *p1, *p2; int has_gettid = 1; @@ -1395,6 +1400,10 @@ int run_syscall(int min, int max) CASE_TEST(waitpid_child); EXPECT_SYSER(1, waitpid(getpid(), &tmp, WNOHANG), -1, ECHILD); break; CASE_TEST(write_badf); EXPECT_SYSER(1, write(-1, &tmp, 1), -1, EBADF); break; CASE_TEST(write_zero); EXPECT_SYSZR(1, write(1, &tmp, 0)); break; + CASE_TEST(readv_badf); EXPECT_SYSER(1, readv(-1, &iov_one, 1), -1, EBADF); break; + CASE_TEST(readv_zero); EXPECT_SYSZR(1, readv(1, 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(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(namespace); EXPECT_SYSZR(euid0 && proc, test_namespace()); break;
On 2025-09-19 17:34:18+0200, Benjamin Berg wrote:
From: Benjamin Berg benjamin.berg@intel.com
This is generally useful and struct iovec is also needed for other purposes such as ptrace.
Signed-off-by: Benjamin Berg benjamin.berg@intel.com
Acked-by: Thomas Weißschuh linux@weissschuh.net
tools/include/nolibc/Makefile | 1 + tools/include/nolibc/nolibc.h | 1 + tools/include/nolibc/sys/uio.h | 49 ++++++++++++++++++++ tools/testing/selftests/nolibc/nolibc-test.c | 9 ++++ 4 files changed, 60 insertions(+) create mode 100644 tools/include/nolibc/sys/uio.h
(...)
From: Benjamin Berg benjamin.berg@intel.com
Add ptrace support, as it will be useful in UML.
Signed-off-by: Benjamin Berg benjamin.berg@intel.com --- tools/include/nolibc/Makefile | 1 + tools/include/nolibc/nolibc.h | 1 + tools/include/nolibc/sys/ptrace.h | 52 ++++++++++++++++++++ tools/testing/selftests/nolibc/nolibc-test.c | 2 + 4 files changed, 56 insertions(+) create mode 100644 tools/include/nolibc/sys/ptrace.h
diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile index 9bbbba32dac6..8e0cac3ac522 100644 --- a/tools/include/nolibc/Makefile +++ b/tools/include/nolibc/Makefile @@ -53,6 +53,7 @@ all_files := \ sys/mman.h \ sys/mount.h \ sys/prctl.h \ + sys/ptrace.h \ sys/random.h \ sys/reboot.h \ sys/resource.h \ diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index b4bc1c9b883d..590eef545ca6 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -101,6 +101,7 @@ #include "sys/mman.h" #include "sys/mount.h" #include "sys/prctl.h" +#include "sys/ptrace.h" #include "sys/random.h" #include "sys/reboot.h" #include "sys/resource.h" diff --git a/tools/include/nolibc/sys/ptrace.h b/tools/include/nolibc/sys/ptrace.h new file mode 100644 index 000000000000..3119abdeeecb --- /dev/null +++ b/tools/include/nolibc/sys/ptrace.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * ptrace for NOLIBC + * Copyright (C) 2017-2021 Willy Tarreau w@1wt.eu + * Copyright (C) 2025 Intel Corporation + */ + +/* make sure to include all global symbols */ +#include "../nolibc.h" + +#ifndef _NOLIBC_SYS_PTRACE_H +#define _NOLIBC_SYS_PTRACE_H + +#include "../sys.h" +#include "uio.h" + + +#include <linux/ptrace.h> + +/* + * long ptrace(int op, pid_t pid, void *addr, void *data); + * + * However, addr may also be an integer in some cases. + */ +static __attribute__((unused)) +long sys_vptrace(int op, pid_t pid, va_list args) +{ + return my_syscall4(__NR_ptrace, op, pid, + va_arg(args, void *), va_arg(args, void *)); +} + +static __attribute__((unused)) +ssize_t sys_ptrace(int op, pid_t pid, ...) +{ + va_list args; + + va_start(args, pid); + return sys_vptrace(op, pid, args); + va_end(args); +} + +static __attribute__((unused)) +ssize_t ptrace(int op, pid_t pid, ...) +{ + va_list args; + + va_start(args, pid); + return __sysret(sys_vptrace(op, pid, args)); + va_end(args); +} + +#endif /* _NOLIBC_SYS_PTRACE_H */ diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 1907128bc3f6..4c1b9ee32b7d 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -17,6 +17,7 @@ #include <sys/mman.h> #include <sys/mount.h> #include <sys/prctl.h> +#include <sys/ptrace.h> #include <sys/random.h> #include <sys/reboot.h> #include <sys/resource.h> @@ -1404,6 +1405,7 @@ int run_syscall(int min, int max) CASE_TEST(readv_zero); EXPECT_SYSZR(1, readv(1, 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(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(namespace); EXPECT_SYSZR(euid0 && proc, test_namespace()); break;
On 2025-09-19 17:34:19+0200, Benjamin Berg wrote:
From: Benjamin Berg benjamin.berg@intel.com
Add ptrace support, as it will be useful in UML.
Signed-off-by: Benjamin Berg benjamin.berg@intel.com
tools/include/nolibc/Makefile | 1 + tools/include/nolibc/nolibc.h | 1 + tools/include/nolibc/sys/ptrace.h | 52 ++++++++++++++++++++ tools/testing/selftests/nolibc/nolibc-test.c | 2 + 4 files changed, 56 insertions(+) create mode 100644 tools/include/nolibc/sys/ptrace.h
(...)
diff --git a/tools/include/nolibc/sys/ptrace.h b/tools/include/nolibc/sys/ptrace.h new file mode 100644 index 000000000000..3119abdeeecb --- /dev/null +++ b/tools/include/nolibc/sys/ptrace.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/*
- ptrace for NOLIBC
- Copyright (C) 2017-2021 Willy Tarreau w@1wt.eu
- Copyright (C) 2025 Intel Corporation
- */
+/* make sure to include all global symbols */ +#include "../nolibc.h"
+#ifndef _NOLIBC_SYS_PTRACE_H +#define _NOLIBC_SYS_PTRACE_H
+#include "../sys.h" +#include "uio.h"
+#include <linux/ptrace.h>
+/*
- long ptrace(int op, pid_t pid, void *addr, void *data);
- However, addr may also be an integer in some cases.
This comment is a bit confusing. It reads like it can be an integer as in 'int' datatype. But the kernel expects an integer compatible with 'void *', so 'unsigned long'. I think we can drop the comment.
- */
+static __attribute__((unused)) +long sys_vptrace(int op, pid_t pid, va_list args) +{
- return my_syscall4(__NR_ptrace, op, pid,
va_arg(args, void *), va_arg(args, void *));
+}
+static __attribute__((unused)) +ssize_t sys_ptrace(int op, pid_t pid, ...)
ptrace(2) does not document addr and data to be optional. While it does acknowledge the fact that it is variadic on glibc, users are still recommended to always supply all arguments. I'd prefer to keep it simple and avoid the va_list.
+{
- va_list args;
- va_start(args, pid);
- return sys_vptrace(op, pid, args);
- va_end(args);
+}
+static __attribute__((unused)) +ssize_t ptrace(int op, pid_t pid, ...) +{
- va_list args;
- va_start(args, pid);
- return __sysret(sys_vptrace(op, pid, args));
- va_end(args);
+}
+#endif /* _NOLIBC_SYS_PTRACE_H */
(...)
On Sat, Sep 20, 2025 at 11:27:19AM +0200, Thomas Weißschuh wrote:
+/*
- long ptrace(int op, pid_t pid, void *addr, void *data);
- However, addr may also be an integer in some cases.
This comment is a bit confusing. It reads like it can be an integer as in 'int' datatype. But the kernel expects an integer compatible with 'void *', so 'unsigned long'. I think we can drop the comment.
Or if the point is to insist that void* is not strictly required, a comment might as well say "types for addr and data are ignored and will be cast to void*". But given that the man page indicates two void*, I think that callers are expected to cast ints to void* in any case, and if so maybe indeed not saying anything about it would be better.
- */
+static __attribute__((unused)) +long sys_vptrace(int op, pid_t pid, va_list args) +{
- return my_syscall4(__NR_ptrace, op, pid,
va_arg(args, void *), va_arg(args, void *));
+}
+static __attribute__((unused)) +ssize_t sys_ptrace(int op, pid_t pid, ...)
ptrace(2) does not document addr and data to be optional. While it does acknowledge the fact that it is variadic on glibc, users are still recommended to always supply all arguments. I'd prefer to keep it simple and avoid the va_list.
The man indeed says they are *ignored*, not optional. I agree then that it would be better not doing simpler than the standard and have to roll back later. Let's just pass unused arguments to the system.
Thanks, Willy
From: Benjamin Berg benjamin.berg@intel.com
The registers.c file only contains the routines for floating point register access in ptrace mode and initial size detection. After the addition of sys/uio.h and sys/ptrace.h to nolibc it can be moved to use it by using the sys_ptrace() wrapper.
Signed-off-by: Benjamin Berg benjamin.berg@intel.com
--- v2: - Use new sys_ptrace from nolibc --- arch/x86/um/os-Linux/Makefile | 5 ++++- arch/x86/um/os-Linux/registers.c | 16 ++++------------ 2 files changed, 8 insertions(+), 13 deletions(-)
diff --git a/arch/x86/um/os-Linux/Makefile b/arch/x86/um/os-Linux/Makefile index 77a308aaa5ec..d37320430822 100644 --- a/arch/x86/um/os-Linux/Makefile +++ b/arch/x86/um/os-Linux/Makefile @@ -3,10 +3,13 @@ # Licensed under the GPL #
-obj-y = registers.o mcontext.o +obj-y = mcontext.o
obj-$(CONFIG_X86_32) += tls.o
USER_OBJS := $(obj-y)
+obj-y += registers.o +NOLIBC_OBJS := registers.o + include $(srctree)/arch/um/scripts/Makefile.rules diff --git a/arch/x86/um/os-Linux/registers.c b/arch/x86/um/os-Linux/registers.c index eb1cdadc8a61..e570e29c3d73 100644 --- a/arch/x86/um/os-Linux/registers.c +++ b/arch/x86/um/os-Linux/registers.c @@ -28,9 +28,7 @@ int get_fp_registers(int pid, unsigned long *regs) .iov_len = host_fp_size, };
- if (ptrace(PTRACE_GETREGSET, pid, ptrace_regset, &iov) < 0) - return -errno; - return 0; + return sys_ptrace(PTRACE_GETREGSET, pid, ptrace_regset, &iov); }
int put_fp_registers(int pid, unsigned long *regs) @@ -40,9 +38,7 @@ int put_fp_registers(int pid, unsigned long *regs) .iov_len = host_fp_size, };
- if (ptrace(PTRACE_SETREGSET, pid, ptrace_regset, &iov) < 0) - return -errno; - return 0; + return sys_ptrace(PTRACE_SETREGSET, pid, ptrace_regset, &iov); }
int arch_init_registers(int pid) @@ -60,9 +56,7 @@ int arch_init_registers(int pid)
/* GDB has x86_xsave_length, which uses x86_cpuid_count */ ptrace_regset = NT_X86_XSTATE; - ret = ptrace(PTRACE_GETREGSET, pid, ptrace_regset, &iov); - if (ret) - ret = -errno; + ret = sys_ptrace(PTRACE_GETREGSET, pid, ptrace_regset, &iov);
if (ret == -ENODEV) { #ifdef CONFIG_X86_32 @@ -71,9 +65,7 @@ int arch_init_registers(int pid) ptrace_regset = NT_PRFPREG; #endif iov.iov_len = 2 * 1024 * 1024; - ret = ptrace(PTRACE_GETREGSET, pid, ptrace_regset, &iov); - if (ret) - ret = -errno; + ret = sys_ptrace(PTRACE_GETREGSET, pid, ptrace_regset, &iov); }
munmap(iov.iov_base, 2 * 1024 * 1024);
Hi Benjamin,
kernel test robot noticed the following build errors:
[auto build test ERROR on uml/next] [also build test ERROR on uml/fixes shuah-kselftest/next shuah-kselftest/fixes linus/master v6.17-rc6 next-20250919] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Benjamin-Berg/tools-compiler-... base: https://git.kernel.org/pub/scm/linux/kernel/git/uml/linux next patch link: https://lore.kernel.org/r/20250919153420.727385-12-benjamin%40sipsolutions.n... patch subject: [PATCH v2 11/11] um: switch ptrace FP register access to nolibc config: um-allnoconfig (https://download.01.org/0day-ci/archive/20250920/202509200433.l6pWDPhh-lkp@i...) compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 7c861bcedf61607b6c087380ac711eb7ff918ca6) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250920/202509200433.l6pWDPhh-lkp@i...)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot lkp@intel.com | Closes: https://lore.kernel.org/oe-kbuild-all/202509200433.l6pWDPhh-lkp@intel.com/
All error/warnings (new ones prefixed by >>):
arch/x86/um/os-Linux/registers.c:11:10: fatal error: 'sys/user.h' file not found
11 | #include <sys/user.h> | ^~~~~~~~~~~~ 1 error generated. --
clang: warning: no such include directory: './arch/um/include/shared' [-Wmissing-include-dirs]
vim +11 arch/x86/um/os-Linux/registers.c
14c8a77e1bbd69 arch/um/os-Linux/sys-i386/registers.c Jeff Dike 2008-06-12 @11 #include <sys/user.h> 38b64aed786d59 arch/x86/um/os-Linux/registers.c Richard Weinberger 2011-08-18 12 #endif 37185b33240870 arch/x86/um/os-Linux/registers.c Al Viro 2012-10-08 13 #include <longjmp.h> 37185b33240870 arch/x86/um/os-Linux/registers.c Al Viro 2012-10-08 14 #include <sysdep/ptrace_user.h> a78ff1112263fd arch/x86/um/os-Linux/registers.c Eli Cooper 2016-03-20 15 #include <sys/uio.h> a78ff1112263fd arch/x86/um/os-Linux/registers.c Eli Cooper 2016-03-20 16 #include <asm/sigcontext.h> a78ff1112263fd arch/x86/um/os-Linux/registers.c Eli Cooper 2016-03-20 17 #include <linux/elf.h> dbba7f704aa0c3 arch/x86/um/os-Linux/registers.c Al Viro 2021-09-20 18 #include <registers.h> 3f17fed2149192 arch/x86/um/os-Linux/registers.c Benjamin Berg 2024-10-23 19 #include <sys/mman.h> ^1da177e4c3f41 arch/um/os-Linux/sys-i386/registers.c Linus Torvalds 2005-04-16 20
On Fri, Sep 19, 2025 at 05:34:09PM +0200, Benjamin Berg wrote:
From: Benjamin Berg benjamin.berg@intel.com
This patchset is an attempt to start a nolibc port of UML.
It would be useful to explain why that is desirable.
On 2025-09-19 17:34:09+0200, Benjamin Berg wrote:
From: Benjamin Berg benjamin.berg@intel.com
This patchset is an attempt to start a nolibc port of UML. The goal is to port UML to use nolibc in smaller chunks to make the switch more manageable.
There are three parts to this patchset:
- Two patches to use tools/include headers instead of kernel headers for userspace files.
- A few nolibc fixes and a new NOLIBC_NO_STARTCODE compile flag for it
- Finally nolibc build support for UML and switching two files while adding the appropriate support in nolibc itself.
v1 of this patchset was https://lore.kernel.org/all/20250915071115.1429196-1-benjamin@sipsolutions.n...
Changes in v2:
- add sys/uio.h and sys/ptrace.h to nolibc
- Use NOLIBC_NO_RUNTIME to disable nolibc startup code
- Fix out-of-tree build
- various small improvements and cleanups
Should the nolibc changes be merged separately or could everything go through the same branch?
Both work for me. But only for the next cycle.
Also, what about tools/include/linux/compiler.h? It seems that was added for the tracing code, but it is not clear to me who might ACK that fix.
Some files in tools/ are orphaned. In the past I got some reviews, included the change in my tree and mentioned it to Linus in my regular pull request.
(...)
Thomas
linux-kselftest-mirror@lists.linaro.org