Merge tag 'nolibc-20251130-for-6.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/nolibc/linux-nolibc

Pull nolibc updates from Thomas Weißschuh:

 - Preparations to the use of nolibc in UML:
     - Cleanup of sparse warnings
     - Library mode without _start()
     - More consistency when disabling errno

 - Unconditional installation of all architecture support files

 - Always 64-bit wide ino_t and off_t

 - Various cleanups and bug fixes

* tag 'nolibc-20251130-for-6.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/nolibc/linux-nolibc: (25 commits)
  selftests/nolibc: error out on linker warnings
  selftests/nolibc: use lld to link loongarch binaries
  tools/nolibc: remove more __nolibc_enosys() fallbacks
  tools/nolibc: remove now superfluous overflow check in llseek
  tools/nolibc: use 64-bit off_t
  tools/nolibc: prefer the llseek syscall
  tools/nolibc: handle 64-bit off_t for llseek
  tools/nolibc: use 64-bit ino_t
  tools/nolibc: avoid using plain integer as NULL pointer
  tools/nolibc: add support for fchdir()
  tools/nolibc: clean up outdated comments in generic arch.h
  tools/nolibc: make the "headers" target install all supported archs
  tools/nolibc: add the more portable inttypes.h
  tools/nolibc: provide the portable sys/select.h
  tools/nolibc: add missing memchr() to string.h
  tools/nolibc: fix misleading help message regarding installation path
  tools/nolibc: add uio.h with readv and writev
  tools/nolibc: add option to disable runtime
  tools/nolibc: use __fallthrough__ rather than fallthrough
  tools/nolibc: implement %m if errno is not defined
  ...
This commit is contained in:
Linus Torvalds
2025-12-03 09:23:25 -08:00
37 changed files with 290 additions and 163 deletions

View File

@@ -23,7 +23,7 @@ else
Q=@
endif
arch_file := arch-$(ARCH).h
arch_files := arch.h $(wildcard arch-*.h)
all_files := \
compiler.h \
crt.h \
@@ -33,6 +33,7 @@ all_files := \
errno.h \
fcntl.h \
getopt.h \
inttypes.h \
limits.h \
math.h \
nolibc.h \
@@ -56,12 +57,14 @@ all_files := \
sys/random.h \
sys/reboot.h \
sys/resource.h \
sys/select.h \
sys/stat.h \
sys/syscall.h \
sys/sysmacros.h \
sys/time.h \
sys/timerfd.h \
sys/types.h \
sys/uio.h \
sys/utsname.h \
sys/wait.h \
time.h \
@@ -79,7 +82,7 @@ help:
@echo "Supported targets under nolibc:"
@echo " all call \"headers\""
@echo " clean clean the sysroot"
@echo " headers prepare a sysroot in tools/include/nolibc/sysroot"
@echo " headers prepare a multi-arch sysroot in \$${OUTPUT}sysroot"
@echo " headers_standalone like \"headers\", and also install kernel headers"
@echo " help this help"
@echo ""
@@ -90,18 +93,11 @@ help:
@echo " OUTPUT = $(OUTPUT)"
@echo ""
# installs headers for all archs at once.
headers:
$(Q)mkdir -p $(OUTPUT)sysroot
$(Q)mkdir -p $(OUTPUT)sysroot/include
$(Q)cp --parents $(all_files) $(OUTPUT)sysroot/include/
$(Q)if [ "$(ARCH)" = "i386" -o "$(ARCH)" = "x86_64" ]; then \
cat arch-x86.h; \
elif [ -e "$(arch_file)" ]; then \
cat $(arch_file); \
else \
echo "Fatal: architecture $(ARCH) not yet supported by nolibc." >&2; \
exit 1; \
fi > $(OUTPUT)sysroot/include/arch.h
$(Q)mkdir -p "$(OUTPUT)sysroot"
$(Q)mkdir -p "$(OUTPUT)sysroot/include"
$(Q)cp --parents $(arch_files) $(all_files) "$(OUTPUT)sysroot/include/"
headers_standalone: headers
$(Q)$(MAKE) -C $(srctree) headers

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -139,6 +139,7 @@
_arg1; \
})
#ifndef NOLIBC_NO_RUNTIME
/* startup code */
void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void)
{
@@ -150,6 +151,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;

View File

@@ -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 */

View File

@@ -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);

View File

@@ -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);
@@ -351,7 +355,7 @@ void *memcpy(void *dst, const void *src, size_t len);
void *memset(void *dst, int c, size_t len);
__asm__ (
".section .text.nolibc_memmove_memcpy\n"
".pushsection .text.nolibc_memmove_memcpy\n"
".weak memmove\n"
".weak memcpy\n"
"memmove:\n"
@@ -371,8 +375,9 @@ __asm__ (
"rep movsb\n\t"
"cld\n\t"
"retq\n"
".popsection\n"
".section .text.nolibc_memset\n"
".pushsection .text.nolibc_memset\n"
".weak memset\n"
"memset:\n"
"xchgl %eax, %esi\n\t"
@@ -381,6 +386,7 @@ __asm__ (
"rep stosb\n\t"
"popq %rax\n\t"
"retq\n"
".popsection\n"
);
#endif /* !defined(__x86_64__) */

View File

@@ -3,15 +3,6 @@
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
*/
/* Below comes the architecture-specific code. For each architecture, we have
* the syscall declarations and the _start code definition. This is the only
* global part. On all architectures the kernel puts everything in the stack
* before jumping to _start just above us, without any return address (_start
* is not a function but an entry point). So at the stack pointer we find argc.
* Then argv[] begins, and ends at the first NULL. Then we have envp which
* starts and ends with a NULL as well. So envp=argv+argc+1.
*/
#ifndef _NOLIBC_ARCH_H
#define _NOLIBC_ARCH_H

View File

@@ -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) */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -78,7 +78,7 @@ int getopt(int argc, char * const argv[], const char *optstring)
return '?';
}
if (optstring[i] == ':') {
optarg = 0;
optarg = NULL;
if (optstring[i + 1] != ':' || __optpos) {
optarg = argv[optind++];
if (__optpos)

View File

@@ -0,0 +1,3 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
#include "nolibc.h"

View File

@@ -104,11 +104,13 @@
#include "sys/random.h"
#include "sys/reboot.h"
#include "sys/resource.h"
#include "sys/select.h"
#include "sys/stat.h"
#include "sys/syscall.h"
#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"

View File

@@ -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 */

View File

@@ -20,13 +20,13 @@
/* those are commonly provided by sys/types.h */
typedef unsigned int dev_t;
typedef unsigned long ino_t;
typedef uint64_t ino_t;
typedef unsigned int mode_t;
typedef signed int pid_t;
typedef unsigned int uid_t;
typedef unsigned int gid_t;
typedef unsigned long nlink_t;
typedef signed long off_t;
typedef int64_t off_t;
typedef signed long blksize_t;
typedef signed long blkcnt_t;
typedef __kernel_time_t time_t;

View File

@@ -321,11 +321,13 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char
if (!outstr)
outstr="(null)";
}
#ifndef NOLIBC_IGNORE_ERRNO
else if (c == 'm') {
#ifdef NOLIBC_IGNORE_ERRNO
outstr = "unknown error";
#else
outstr = strerror(errno);
}
#endif /* NOLIBC_IGNORE_ERRNO */
}
else if (c == '%') {
/* queue it verbatim */
continue;
@@ -600,7 +602,11 @@ int sscanf(const char *str, const char *format, ...)
static __attribute__((unused))
void perror(const char *msg)
{
#ifdef NOLIBC_IGNORE_ERRNO
fprintf(stderr, "%s%sunknown error\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "");
#else
fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno);
#endif
}
static __attribute__((unused))

View File

@@ -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)

View File

@@ -93,6 +93,21 @@ void *memset(void *dst, int b, size_t len)
}
#endif /* #ifndef NOLIBC_ARCH_HAS_MEMSET */
#ifndef NOLIBC_ARCH_HAS_MEMCHR
static __attribute__((unused))
void *memchr(const void *s, int c, size_t len)
{
char *p = (char *)s;
while (len--) {
if (*p == (char)c)
return p;
p++;
}
return NULL;
}
#endif /* #ifndef NOLIBC_ARCH_HAS_MEMCHR */
static __attribute__((unused))
char *strchr(const char *s, int c)
{

View File

@@ -106,7 +106,7 @@ static __attribute__((unused))
void *sbrk(intptr_t inc)
{
/* first call to find current end */
void *ret = sys_brk(0);
void *ret = sys_brk(NULL);
if (ret && sys_brk(ret + inc) == ret + inc)
return ret + inc;
@@ -118,6 +118,7 @@ void *sbrk(intptr_t inc)
/*
* int chdir(const char *path);
* int fchdir(int fildes);
*/
static __attribute__((unused))
@@ -132,6 +133,18 @@ int chdir(const char *path)
return __sysret(sys_chdir(path));
}
static __attribute__((unused))
int sys_fchdir(int fildes)
{
return my_syscall1(__NR_fchdir, fildes);
}
static __attribute__((unused))
int fchdir(int fildes)
{
return __sysret(sys_fchdir(fildes));
}
/*
* int chmod(const char *path, mode_t mode);
@@ -512,6 +525,7 @@ pid_t gettid(void)
return sys_gettid();
}
#ifndef NOLIBC_NO_RUNTIME
static unsigned long getauxval(unsigned long key);
/*
@@ -523,7 +537,7 @@ int getpagesize(void)
{
return __sysret((int)getauxval(AT_PAGESZ) ?: -ENOENT);
}
#endif /* NOLIBC_NO_RUNTIME */
/*
* uid_t getuid(void);
@@ -591,23 +605,20 @@ int link(const char *old, const char *new)
static __attribute__((unused))
off_t sys_lseek(int fd, off_t offset, int whence)
{
#if defined(__NR_lseek)
return my_syscall3(__NR_lseek, fd, offset, whence);
#else
#if defined(__NR_llseek)
__kernel_loff_t loff = 0;
off_t result;
int ret;
/* Only exists on 32bit where nolibc off_t is also 32bit */
ret = my_syscall5(__NR_llseek, fd, 0, offset, &loff, whence);
ret = my_syscall5(__NR_llseek, fd, offset >> 32, (uint32_t)offset, &loff, whence);
if (ret < 0)
result = ret;
else if (loff != (off_t)loff)
result = -EOVERFLOW;
else
result = loff;
return result;
#else
return my_syscall3(__NR_lseek, fd, offset, whence);
#endif
}
@@ -755,51 +766,6 @@ int sched_yield(void)
}
/*
* int select(int nfds, fd_set *read_fds, fd_set *write_fds,
* fd_set *except_fds, struct timeval *timeout);
*/
static __attribute__((unused))
int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout)
{
#if defined(__ARCH_WANT_SYS_OLD_SELECT) && !defined(__NR__newselect)
struct sel_arg_struct {
unsigned long n;
fd_set *r, *w, *e;
struct timeval *t;
} arg = { .n = nfds, .r = rfds, .w = wfds, .e = efds, .t = timeout };
return my_syscall1(__NR_select, &arg);
#elif defined(__NR__newselect)
return my_syscall5(__NR__newselect, nfds, rfds, wfds, efds, timeout);
#elif defined(__NR_select)
return my_syscall5(__NR_select, nfds, rfds, wfds, efds, timeout);
#elif defined(__NR_pselect6)
struct timespec t;
if (timeout) {
t.tv_sec = timeout->tv_sec;
t.tv_nsec = timeout->tv_usec * 1000;
}
return my_syscall6(__NR_pselect6, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL);
#else
struct __kernel_timespec t;
if (timeout) {
t.tv_sec = timeout->tv_sec;
t.tv_nsec = timeout->tv_usec * 1000;
}
return my_syscall6(__NR_pselect6_time64, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL);
#endif
}
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));
}
/*
* int setpgid(pid_t pid, pid_t pgid);
*/

View File

@@ -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 */

View File

@@ -31,11 +31,6 @@ void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd,
}
#endif
/* Note that on Linux, MAP_FAILED is -1 so we can use the generic __sysret()
* which returns -1 upon error and still satisfy user land that checks for
* MAP_FAILED.
*/
static __attribute__((unused))
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
{

View File

@@ -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, 0));
return __sysret(sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, NULL));
}
#endif /* _NOLIBC_SYS_REBOOT_H */

View File

@@ -0,0 +1,103 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
#include "../nolibc.h"
#ifndef _NOLIBC_SYS_SELECT_H
#define _NOLIBC_SYS_SELECT_H
#include <linux/time.h>
#include <linux/unistd.h>
/* commonly an fd_set represents 256 FDs */
#ifndef FD_SETSIZE
#define FD_SETSIZE 256
#endif
#define FD_SETIDXMASK (8 * sizeof(unsigned long))
#define FD_SETBITMASK (8 * sizeof(unsigned long)-1)
/* for select() */
typedef struct {
unsigned long fds[(FD_SETSIZE + FD_SETBITMASK) / FD_SETIDXMASK];
} fd_set;
#define FD_CLR(fd, set) do { \
fd_set *__set = (set); \
int __fd = (fd); \
if (__fd >= 0) \
__set->fds[__fd / FD_SETIDXMASK] &= \
~(1U << (__fd & FD_SETBITMASK)); \
} while (0)
#define FD_SET(fd, set) do { \
fd_set *__set = (set); \
int __fd = (fd); \
if (__fd >= 0) \
__set->fds[__fd / FD_SETIDXMASK] |= \
1 << (__fd & FD_SETBITMASK); \
} while (0)
#define FD_ISSET(fd, set) ({ \
fd_set *__set = (set); \
int __fd = (fd); \
int __r = 0; \
if (__fd >= 0) \
__r = !!(__set->fds[__fd / FD_SETIDXMASK] & \
1U << (__fd & FD_SETBITMASK)); \
__r; \
})
#define FD_ZERO(set) do { \
fd_set *__set = (set); \
int __idx; \
int __size = (FD_SETSIZE+FD_SETBITMASK) / FD_SETIDXMASK;\
for (__idx = 0; __idx < __size; __idx++) \
__set->fds[__idx] = 0; \
} while (0)
/*
* int select(int nfds, fd_set *read_fds, fd_set *write_fds,
* fd_set *except_fds, struct timeval *timeout);
*/
static __attribute__((unused))
int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout)
{
#if defined(__ARCH_WANT_SYS_OLD_SELECT) && !defined(__NR__newselect)
struct sel_arg_struct {
unsigned long n;
fd_set *r, *w, *e;
struct timeval *t;
} arg = { .n = nfds, .r = rfds, .w = wfds, .e = efds, .t = timeout };
return my_syscall1(__NR_select, &arg);
#elif defined(__NR__newselect)
return my_syscall5(__NR__newselect, nfds, rfds, wfds, efds, timeout);
#elif defined(__NR_select)
return my_syscall5(__NR_select, nfds, rfds, wfds, efds, timeout);
#elif defined(__NR_pselect6)
struct timespec t;
if (timeout) {
t.tv_sec = timeout->tv_sec;
t.tv_nsec = timeout->tv_usec * 1000;
}
return my_syscall6(__NR_pselect6, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL);
#else
struct __kernel_timespec t;
if (timeout) {
t.tv_sec = timeout->tv_sec;
t.tv_nsec = timeout->tv_usec * 1000;
}
return my_syscall6(__NR_pselect6_time64, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL);
#endif
}
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));
}
#endif /* _NOLIBC_SYS_SELECT_H */

View File

@@ -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 */

View File

@@ -65,23 +65,29 @@ pid_t waitpid(pid_t pid, int *status, int options)
switch (info.si_code) {
case 0:
*status = 0;
if (status)
*status = 0;
break;
case CLD_EXITED:
*status = (info.si_status & 0xff) << 8;
if (status)
*status = (info.si_status & 0xff) << 8;
break;
case CLD_KILLED:
*status = info.si_status & 0x7f;
if (status)
*status = info.si_status & 0x7f;
break;
case CLD_DUMPED:
*status = (info.si_status & 0x7f) | 0x80;
if (status)
*status = (info.si_status & 0x7f) | 0x80;
break;
case CLD_STOPPED:
case CLD_TRAPPED:
*status = (info.si_status << 8) + 0x7f;
if (status)
*status = (info.si_status << 8) + 0x7f;
break;
case CLD_CONTINUED:
*status = 0xffff;
if (status)
*status = 0xffff;
break;
default:
return -1;

View File

@@ -89,13 +89,11 @@ int sys_clock_settime(clockid_t clockid, struct timespec *tp)
{
#if defined(__NR_clock_settime)
return my_syscall2(__NR_clock_settime, clockid, tp);
#elif defined(__NR_clock_settime64)
#else
struct __kernel_timespec ktp;
__nolibc_timespec_user_to_kernel(tp, &ktp);
return my_syscall2(__NR_clock_settime64, clockid, &ktp);
#else
return __nolibc_enosys(__func__, clockid, tp);
#endif
}
@@ -111,7 +109,7 @@ int sys_clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqt
{
#if defined(__NR_clock_nanosleep)
return my_syscall4(__NR_clock_nanosleep, clockid, flags, rqtp, rmtp);
#elif defined(__NR_clock_nanosleep_time64)
#else
struct __kernel_timespec krqtp, krmtp;
int ret;
@@ -120,8 +118,6 @@ int sys_clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqt
if (rmtp)
__nolibc_timespec_kernel_to_user(&krmtp, rmtp);
return ret;
#else
return __nolibc_enosys(__func__, clockid, flags, rqtp, rmtp);
#endif
}
@@ -195,7 +191,7 @@ int sys_timer_gettime(timer_t timerid, struct itimerspec *curr_value)
{
#if defined(__NR_timer_gettime)
return my_syscall2(__NR_timer_gettime, timerid, curr_value);
#elif defined(__NR_timer_gettime64)
#else
struct __kernel_itimerspec kcurr_value;
int ret;
@@ -203,8 +199,6 @@ int sys_timer_gettime(timer_t timerid, struct itimerspec *curr_value)
__nolibc_timespec_kernel_to_user(&kcurr_value.it_interval, &curr_value->it_interval);
__nolibc_timespec_kernel_to_user(&kcurr_value.it_value, &curr_value->it_value);
return ret;
#else
return __nolibc_enosys(__func__, timerid, curr_value);
#endif
}
@@ -220,7 +214,7 @@ int sys_timer_settime(timer_t timerid, int flags,
{
#if defined(__NR_timer_settime)
return my_syscall4(__NR_timer_settime, timerid, flags, new_value, old_value);
#elif defined(__NR_timer_settime64)
#else
struct __kernel_itimerspec knew_value, kold_value;
int ret;
@@ -232,8 +226,6 @@ int sys_timer_settime(timer_t timerid, int flags,
__nolibc_timespec_kernel_to_user(&kold_value.it_value, &old_value->it_value);
}
return ret;
#else
return __nolibc_enosys(__func__, timerid, flags, new_value, old_value);
#endif
}

View File

@@ -70,11 +70,6 @@
#define DT_LNK 0xa
#define DT_SOCK 0xc
/* commonly an fd_set represents 256 FDs */
#ifndef FD_SETSIZE
#define FD_SETSIZE 256
#endif
/* PATH_MAX and MAXPATHLEN are often used and found with plenty of different
* values.
*/
@@ -115,48 +110,6 @@
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
#define FD_SETIDXMASK (8 * sizeof(unsigned long))
#define FD_SETBITMASK (8 * sizeof(unsigned long)-1)
/* for select() */
typedef struct {
unsigned long fds[(FD_SETSIZE + FD_SETBITMASK) / FD_SETIDXMASK];
} fd_set;
#define FD_CLR(fd, set) do { \
fd_set *__set = (set); \
int __fd = (fd); \
if (__fd >= 0) \
__set->fds[__fd / FD_SETIDXMASK] &= \
~(1U << (__fd & FD_SETBITMASK)); \
} while (0)
#define FD_SET(fd, set) do { \
fd_set *__set = (set); \
int __fd = (fd); \
if (__fd >= 0) \
__set->fds[__fd / FD_SETIDXMASK] |= \
1 << (__fd & FD_SETBITMASK); \
} while (0)
#define FD_ISSET(fd, set) ({ \
fd_set *__set = (set); \
int __fd = (fd); \
int __r = 0; \
if (__fd >= 0) \
__r = !!(__set->fds[__fd / FD_SETIDXMASK] & \
1U << (__fd & FD_SETBITMASK)); \
__r; \
})
#define FD_ZERO(set) do { \
fd_set *__set = (set); \
int __idx; \
int __size = (FD_SETSIZE+FD_SETBITMASK) / FD_SETIDXMASK;\
for (__idx = 0; __idx < __size; __idx++) \
__set->fds[__idx] = 0; \
} while (0)
/* for getdents64() */
struct linux_dirent64 {
uint64_t d_ino;

View File

@@ -54,7 +54,7 @@ int msleep(unsigned int msecs)
{
struct timeval my_timeval = { msecs / 1000, (msecs % 1000) * 1000 };
if (sys_select(0, 0, 0, 0, &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, 0, 0, 0, &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, 0, 0, 0, &my_timeval);
return sys_select(0, NULL, NULL, NULL, &my_timeval);
}
static __attribute__((unused))

View File

@@ -225,6 +225,7 @@ CFLAGS_mipsn32le = -EL -mabi=n32 -fPIC -march=mips64r2
CFLAGS_mipsn32be = -EB -mabi=n32 -march=mips64r6
CFLAGS_mips64le = -EL -mabi=64 -march=mips64r6
CFLAGS_mips64be = -EB -mabi=64 -march=mips64r2
CFLAGS_loongarch = $(if $(LLVM),-fuse-ld=lld)
CFLAGS_sparc32 = $(call cc-option,-m32)
CFLAGS_sh4 = -ml -m4
ifeq ($(origin XARCH),command line)

View File

@@ -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>
@@ -1282,6 +1283,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;
@@ -1343,6 +1348,8 @@ int run_syscall(int min, int max)
CASE_TEST(dup3_0); tmp = dup3(0, 100, 0); EXPECT_SYSNE(1, tmp, -1); close(tmp); break;
CASE_TEST(dup3_m1); tmp = dup3(-1, 100, 0); EXPECT_SYSER(1, tmp, -1, EBADF); if (tmp != -1) close(tmp); break;
CASE_TEST(execve_root); EXPECT_SYSER(1, execve("/", (char*[]){ [0] = "/", [1] = NULL }, NULL), -1, EACCES); break;
CASE_TEST(fchdir_stdin); EXPECT_SYSER(1, fchdir(STDIN_FILENO), -1, ENOTDIR); break;
CASE_TEST(fchdir_badfd); EXPECT_SYSER(1, fchdir(-1), -1, EBADF); break;
CASE_TEST(file_stream); EXPECT_SYSZR(1, test_file_stream()); break;
CASE_TEST(fork); EXPECT_SYSZR(1, test_fork(FORK_STANDARD)); break;
CASE_TEST(getdents64_root); EXPECT_SYSNE(1, test_getdents64("/"), -1); break;
@@ -1395,6 +1402,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;
@@ -1540,6 +1551,8 @@ int run_stdlib(int min, int max)
CASE_TEST(abs); EXPECT_EQ(1, abs(-10), 10); break;
CASE_TEST(abs_noop); EXPECT_EQ(1, abs(10), 10); break;
CASE_TEST(difftime); EXPECT_ZR(1, test_difftime()); break;
CASE_TEST(memchr_foobar6_o); EXPECT_STREQ(1, memchr("foobar", 'o', 6), "oobar"); break;
CASE_TEST(memchr_foobar3_b); EXPECT_STRZR(1, memchr("foobar", 'b', 3)); break;
case __LINE__:
return ret; /* must be last */

View File

@@ -169,7 +169,7 @@ test_arch() {
cross_compile=$(realpath "${download_location}gcc-${crosstool_version}-nolibc/${ct_arch}-${ct_abi}/bin/${ct_arch}-${ct_abi}-")
build_dir="${build_location}/${arch}"
if [ "$werror" -ne 0 ]; then
CFLAGS_EXTRA="$CFLAGS_EXTRA -Werror"
CFLAGS_EXTRA="$CFLAGS_EXTRA -Werror -Wl,--fatal-warnings"
fi
MAKE=(make -f Makefile.nolibc -j"${nproc}" XARCH="${arch}" CROSS_COMPILE="${cross_compile}" LLVM="${llvm}" O="${build_dir}")