nolibc changes for 6.20/7.0

Highlights:
 
 * All time-related functionality uses 64-bit timestamps for
   y2038 compatibility.
 * fread() and fskeek() support.
 * ptrace() support.
 * Addition of libc-test to the regular kselftests.
 * Smaller cleanups and fixes to the code and build system.
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQTg4lxklFHAidmUs57B+h1jyw5bOAUCaYZbJAAKCRDB+h1jyw5b
 OBltAP9YupAeS60SqY48GGi4WEWqaEcdOrDI0xOC67UVK0xWeQD/bJiY51f5AQKa
 rHUnbHzQGyTBmJ6dRJBzYs7c09EqdQQ=
 =ai2F
 -----END PGP SIGNATURE-----

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

Pull nolibc updates from Thomas Weißschuh:

 - All time-related functionality uses 64-bit timestamps for
   y2038 compatibility

 - fread() and fskeek() support

 - ptrace() support

 - Addition of libc-test to the regular kselftests

 - Smaller cleanups and fixes to the code and build system

* tag 'nolibc-20260206-for-7.0-1' of git://git.kernel.org/pub/scm/linux/kernel/git/nolibc/linux-nolibc: (25 commits)
  tools/nolibc: Add a simple test for writing to a FILE and reading it back
  tools/nolibc: Add fseek() to stdio.h
  tools/nolibc: Add fread() to stdio.h
  selftests/nolibc: also test libc-test through regular selftest framework
  selftests/nolibc: scope custom flags to the nolibc-test target
  selftests/nolibc: try to read from stdin in readv_zero test
  selftests/nolibc: always build sparc32 tests with -mcpu=v8
  tools/nolibc: align sys_vfork() with sys_fork()
  selftests/nolibc: drop NOLIBC_SYSROOT=0 logic
  selftests/nolibc: add static assertions around time types handling
  tools/nolibc: add __nolibc_static_assert()
  tools/nolibc: add compiler version detection macros
  tools/nolibc: remove time conversions
  selftests/nolibc: test compatibility of nolibc and kernel time types
  tools/nolibc: always use 64-bit time types
  tools/nolibc: use custom structs timespec and timeval
  tools/nolibc/select: avoid libgcc 64-bit multiplications
  tools/nolibc/gettimeofday: avoid libgcc 64-bit divisions
  tools/nolibc: prefer explicit 64-bit time-related system calls
  tools/nolibc/time: drop invocation of gettimeofday system call
  ...
This commit is contained in:
Linus Torvalds 2026-02-09 20:15:14 -08:00
commit 861ea34546
17 changed files with 304 additions and 158 deletions

View file

@ -54,6 +54,7 @@ all_files := \
sys/mman.h \
sys/mount.h \
sys/prctl.h \
sys/ptrace.h \
sys/random.h \
sys/reboot.h \
sys/resource.h \
@ -103,9 +104,12 @@ headers_standalone: headers
$(Q)$(MAKE) -C $(srctree) headers
$(Q)$(MAKE) -C $(srctree) headers_install INSTALL_HDR_PATH=$(OUTPUT)sysroot
CFLAGS_s390 := -m64
CFLAGS := $(CFLAGS_$(ARCH))
headers_check: headers_standalone
$(Q)for header in $(filter-out crt.h std.h,$(all_files)); do \
$(CC) $(CLANG_CROSS_FLAGS) -Wall -Werror -nostdinc -fsyntax-only -x c /dev/null \
$(CC) $(CFLAGS) $(CLANG_CROSS_FLAGS) -Wall -Werror -nostdinc -fsyntax-only -x c /dev/null \
-I$(or $(objtree),$(srctree))/usr/include -include $$header -include $$header || exit 1; \
done

View file

@ -5,6 +5,10 @@
#ifndef _NOLIBC_ARCH_S390_H
#define _NOLIBC_ARCH_S390_H
#include "types.h"
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/unistd.h>
@ -186,4 +190,11 @@ pid_t sys_fork(void)
}
#define sys_fork sys_fork
static __attribute__((unused))
pid_t sys_vfork(void)
{
return my_syscall5(__NR_clone, 0, CLONE_VM | CLONE_VFORK | SIGCHLD, 0, 0, 0);
}
#define sys_vfork sys_vfork
#endif /* _NOLIBC_ARCH_S390_H */

View file

@ -47,4 +47,28 @@
# define __nolibc_fallthrough do { } while (0)
#endif /* __nolibc_has_attribute(fallthrough) */
#define __nolibc_version(_major, _minor, _patch) ((_major) * 10000 + (_minor) * 100 + (_patch))
#ifdef __GNUC__
# define __nolibc_gnuc_version \
__nolibc_version(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
#else
# define __nolibc_gnuc_version 0
#endif /* __GNUC__ */
#ifdef __clang__
# define __nolibc_clang_version \
__nolibc_version(__clang_major__, __clang_minor__, __clang_patchlevel__)
#else
# define __nolibc_clang_version 0
#endif /* __clang__ */
#if __STDC_VERSION__ >= 201112L || \
__nolibc_gnuc_version >= __nolibc_version(4, 6, 0) || \
__nolibc_clang_version >= __nolibc_version(3, 0, 0)
# define __nolibc_static_assert(_t) _Static_assert(_t, "")
#else
# define __nolibc_static_assert(_t)
#endif
#endif /* _NOLIBC_COMPILER_H */

View file

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

View file

@ -23,15 +23,7 @@
static __attribute__((unused))
int sys_poll(struct pollfd *fds, int nfds, int timeout)
{
#if defined(__NR_ppoll)
struct timespec t;
if (timeout >= 0) {
t.tv_sec = timeout / 1000;
t.tv_nsec = (timeout % 1000) * 1000000;
}
return my_syscall5(__NR_ppoll, fds, nfds, (timeout >= 0) ? &t : NULL, NULL, 0);
#elif defined(__NR_ppoll_time64)
#if defined(__NR_ppoll_time64)
struct __kernel_timespec t;
if (timeout >= 0) {
@ -40,7 +32,13 @@ int sys_poll(struct pollfd *fds, int nfds, int timeout)
}
return my_syscall5(__NR_ppoll_time64, fds, nfds, (timeout >= 0) ? &t : NULL, NULL, 0);
#else
return my_syscall3(__NR_poll, fds, nfds, timeout);
struct __kernel_old_timespec t;
if (timeout >= 0) {
t.tv_sec = timeout / 1000;
t.tv_nsec = (timeout % 1000) * 1000000;
}
return my_syscall5(__NR_ppoll, fds, nfds, (timeout >= 0) ? &t : NULL, NULL, 0);
#endif
}

View file

@ -29,6 +29,6 @@ typedef unsigned long nlink_t;
typedef int64_t off_t;
typedef signed long blksize_t;
typedef signed long blkcnt_t;
typedef __kernel_time_t time_t;
typedef __kernel_time64_t time_t;
#endif /* _NOLIBC_STD_H */

View file

@ -170,7 +170,7 @@ int putchar(int c)
}
/* fwrite(), puts(), fputs(). Note that puts() emits '\n' but not fputs(). */
/* fwrite(), fread(), puts(), fputs(). Note that puts() emits '\n' but not fputs(). */
/* internal fwrite()-like function which only takes a size and returns 0 on
* success or EOF on error. It automatically retries on short writes.
@ -204,6 +204,38 @@ size_t fwrite(const void *s, size_t size, size_t nmemb, FILE *stream)
return written;
}
/* internal fread()-like function which only takes a size and returns 0 on
* success or EOF on error. It automatically retries on short reads.
*/
static __attribute__((unused))
int _fread(void *buf, size_t size, FILE *stream)
{
int fd = fileno(stream);
ssize_t ret;
while (size) {
ret = read(fd, buf, size);
if (ret <= 0)
return EOF;
size -= ret;
buf += ret;
}
return 0;
}
static __attribute__((unused))
size_t fread(void *s, size_t size, size_t nmemb, FILE *stream)
{
size_t nread;
for (nread = 0; nread < nmemb; nread++) {
if (_fread(s, size, stream) != 0)
break;
s += size;
}
return nread;
}
static __attribute__((unused))
int fputs(const char *s, FILE *stream)
{
@ -240,6 +272,25 @@ char *fgets(char *s, int size, FILE *stream)
}
/* fseek */
static __attribute__((unused))
int fseek(FILE *stream, long offset, int whence)
{
int fd = fileno(stream);
off_t ret;
ret = lseek(fd, offset, whence);
/* lseek() and fseek() differ in that lseek returns the new
* position or -1, fseek() returns either 0 or -1.
*/
if (ret >= 0)
return 0;
return -1;
}
/* minimal printf(). It supports the following formats:
* - %[l*]{d,u,c,x,p}
* - %s

View file

@ -22,7 +22,7 @@
#include <linux/time.h>
#include <linux/auxvec.h>
#include <linux/fcntl.h> /* for O_* and AT_* */
#include <linux/sched.h> /* for clone_args */
#include <linux/sched.h> /* for CLONE_* */
#include <linux/stat.h> /* for statx() */
#include "errno.h"
@ -363,19 +363,11 @@ pid_t fork(void)
static __attribute__((unused))
pid_t sys_vfork(void)
{
#if defined(__NR_vfork)
#if defined(__NR_clone)
/* See the note in sys_fork(). */
return my_syscall5(__NR_clone, CLONE_VM | CLONE_VFORK | SIGCHLD, 0, 0, 0, 0);
#elif defined(__NR_vfork)
return my_syscall0(__NR_vfork);
#else
/*
* clone() could be used but has different argument orders per
* architecture.
*/
struct clone_args args = {
.flags = CLONE_VM | CLONE_VFORK,
.exit_signal = SIGCHLD,
};
return my_syscall2(__NR_clone3, &args, sizeof(args));
#endif
}
#endif

View file

@ -0,0 +1,33 @@
/* 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 <linux/ptrace.h>
/*
* long ptrace(int op, pid_t pid, void *addr, void *data);
*/
static __attribute__((unused))
long sys_ptrace(int op, pid_t pid, void *addr, void *data)
{
return my_syscall4(__NR_ptrace, op, pid, addr, data);
}
static __attribute__((unused))
ssize_t ptrace(int op, pid_t pid, void *addr, void *data)
{
return __sysret(sys_ptrace(op, pid, addr, data));
}
#endif /* _NOLIBC_SYS_PTRACE_H */

View file

@ -63,33 +63,22 @@ typedef struct {
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
#if defined(__NR_pselect6_time64)
struct __kernel_timespec t;
if (timeout) {
t.tv_sec = timeout->tv_sec;
t.tv_nsec = timeout->tv_usec * 1000;
t.tv_nsec = (uint32_t)timeout->tv_usec * 1000;
}
return my_syscall6(__NR_pselect6_time64, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL);
#else
struct __kernel_old_timespec t;
if (timeout) {
t.tv_sec = timeout->tv_sec;
t.tv_nsec = (uint32_t)timeout->tv_usec * 1000;
}
return my_syscall6(__NR_pselect6, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL);
#endif
}

View file

@ -22,9 +22,6 @@ static int sys_clock_gettime(clockid_t clockid, struct timespec *tp);
static __attribute__((unused))
int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
{
#ifdef __NR_gettimeofday
return my_syscall2(__NR_gettimeofday, tv, tz);
#else
(void) tz; /* Non-NULL tz is undefined behaviour */
struct timespec tp;
@ -33,11 +30,10 @@ int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
ret = sys_clock_gettime(CLOCK_REALTIME, &tp);
if (!ret && tv) {
tv->tv_sec = tp.tv_sec;
tv->tv_usec = tp.tv_nsec / 1000;
tv->tv_usec = (uint32_t)tp.tv_nsec / 1000;
}
return ret;
#endif
}
static __attribute__((unused))

View file

@ -32,16 +32,12 @@ int timerfd_create(int clockid, int flags)
static __attribute__((unused))
int sys_timerfd_gettime(int fd, struct itimerspec *curr_value)
{
#if defined(__NR_timerfd_gettime)
return my_syscall2(__NR_timerfd_gettime, fd, curr_value);
#if defined(__NR_timerfd_gettime64)
__nolibc_assert_time64_type(curr_value->it_value.tv_sec);
return my_syscall2(__NR_timerfd_gettime64, fd, curr_value);
#else
struct __kernel_itimerspec kcurr_value;
int ret;
ret = my_syscall2(__NR_timerfd_gettime64, fd, &kcurr_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;
__nolibc_assert_native_time64();
return my_syscall2(__NR_timerfd_gettime, fd, curr_value);
#endif
}
@ -56,20 +52,12 @@ static __attribute__((unused))
int sys_timerfd_settime(int fd, int flags,
const struct itimerspec *new_value, struct itimerspec *old_value)
{
#if defined(__NR_timerfd_settime)
return my_syscall4(__NR_timerfd_settime, fd, flags, new_value, old_value);
#if defined(__NR_timerfd_settime64)
__nolibc_assert_time64_type(new_value->it_value.tv_sec);
return my_syscall4(__NR_timerfd_settime64, fd, flags, new_value, old_value);
#else
struct __kernel_itimerspec knew_value, kold_value;
int ret;
__nolibc_timespec_user_to_kernel(&new_value->it_value, &knew_value.it_value);
__nolibc_timespec_user_to_kernel(&new_value->it_interval, &knew_value.it_interval);
ret = my_syscall4(__NR_timerfd_settime64, fd, flags, &knew_value, &kold_value);
if (old_value) {
__nolibc_timespec_kernel_to_user(&kold_value.it_interval, &old_value->it_interval);
__nolibc_timespec_kernel_to_user(&kold_value.it_value, &old_value->it_value);
}
return ret;
__nolibc_assert_native_time64();
return my_syscall4(__NR_timerfd_settime, fd, flags, new_value, old_value);
#endif
}

View file

@ -18,19 +18,11 @@
#include <linux/signal.h>
#include <linux/time.h>
static __inline__
void __nolibc_timespec_user_to_kernel(const struct timespec *ts, struct __kernel_timespec *kts)
{
kts->tv_sec = ts->tv_sec;
kts->tv_nsec = ts->tv_nsec;
}
#define __nolibc_assert_time64_type(t) \
__nolibc_static_assert(sizeof(t) == 8)
static __inline__
void __nolibc_timespec_kernel_to_user(const struct __kernel_timespec *kts, struct timespec *ts)
{
ts->tv_sec = kts->tv_sec;
ts->tv_nsec = kts->tv_nsec;
}
#define __nolibc_assert_native_time64() \
__nolibc_assert_time64_type(__kernel_old_time_t)
/*
* int clock_getres(clockid_t clockid, struct timespec *res);
@ -43,16 +35,12 @@ void __nolibc_timespec_kernel_to_user(const struct __kernel_timespec *kts, struc
static __attribute__((unused))
int sys_clock_getres(clockid_t clockid, struct timespec *res)
{
#if defined(__NR_clock_getres)
return my_syscall2(__NR_clock_getres, clockid, res);
#if defined(__NR_clock_getres_time64)
__nolibc_assert_time64_type(res->tv_sec);
return my_syscall2(__NR_clock_getres_time64, clockid, res);
#else
struct __kernel_timespec kres;
int ret;
ret = my_syscall2(__NR_clock_getres_time64, clockid, &kres);
if (res)
__nolibc_timespec_kernel_to_user(&kres, res);
return ret;
__nolibc_assert_native_time64();
return my_syscall2(__NR_clock_getres, clockid, res);
#endif
}
@ -65,16 +53,12 @@ int clock_getres(clockid_t clockid, struct timespec *res)
static __attribute__((unused))
int sys_clock_gettime(clockid_t clockid, struct timespec *tp)
{
#if defined(__NR_clock_gettime)
return my_syscall2(__NR_clock_gettime, clockid, tp);
#if defined(__NR_clock_gettime64)
__nolibc_assert_time64_type(tp->tv_sec);
return my_syscall2(__NR_clock_gettime64, clockid, tp);
#else
struct __kernel_timespec ktp;
int ret;
ret = my_syscall2(__NR_clock_gettime64, clockid, &ktp);
if (tp)
__nolibc_timespec_kernel_to_user(&ktp, tp);
return ret;
__nolibc_assert_native_time64();
return my_syscall2(__NR_clock_gettime, clockid, tp);
#endif
}
@ -87,13 +71,12 @@ int clock_gettime(clockid_t clockid, struct timespec *tp)
static __attribute__((unused))
int sys_clock_settime(clockid_t clockid, struct timespec *tp)
{
#if defined(__NR_clock_settime)
return my_syscall2(__NR_clock_settime, clockid, tp);
#if defined(__NR_clock_settime64)
__nolibc_assert_time64_type(tp->tv_sec);
return my_syscall2(__NR_clock_settime64, clockid, tp);
#else
struct __kernel_timespec ktp;
__nolibc_timespec_user_to_kernel(tp, &ktp);
return my_syscall2(__NR_clock_settime64, clockid, &ktp);
__nolibc_assert_native_time64();
return my_syscall2(__NR_clock_settime, clockid, tp);
#endif
}
@ -107,17 +90,12 @@ static __attribute__((unused))
int sys_clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqtp,
struct timespec *rmtp)
{
#if defined(__NR_clock_nanosleep)
return my_syscall4(__NR_clock_nanosleep, clockid, flags, rqtp, rmtp);
#if defined(__NR_clock_nanosleep_time64)
__nolibc_assert_time64_type(rqtp->tv_sec);
return my_syscall4(__NR_clock_nanosleep_time64, clockid, flags, rqtp, rmtp);
#else
struct __kernel_timespec krqtp, krmtp;
int ret;
__nolibc_timespec_user_to_kernel(rqtp, &krqtp);
ret = my_syscall4(__NR_clock_nanosleep_time64, clockid, flags, &krqtp, &krmtp);
if (rmtp)
__nolibc_timespec_kernel_to_user(&krmtp, rmtp);
return ret;
__nolibc_assert_native_time64();
return my_syscall4(__NR_clock_nanosleep, clockid, flags, rqtp, rmtp);
#endif
}
@ -189,16 +167,12 @@ int timer_delete(timer_t timerid)
static __attribute__((unused))
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);
#if defined(__NR_timer_gettime64)
__nolibc_assert_time64_type(curr_value->it_value.tv_sec);
return my_syscall2(__NR_timer_gettime64, timerid, curr_value);
#else
struct __kernel_itimerspec kcurr_value;
int ret;
ret = my_syscall2(__NR_timer_gettime64, timerid, &kcurr_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;
__nolibc_assert_native_time64();
return my_syscall2(__NR_timer_gettime, timerid, curr_value);
#endif
}
@ -212,20 +186,12 @@ static __attribute__((unused))
int sys_timer_settime(timer_t timerid, int flags,
const struct itimerspec *new_value, struct itimerspec *old_value)
{
#if defined(__NR_timer_settime)
return my_syscall4(__NR_timer_settime, timerid, flags, new_value, old_value);
#if defined(__NR_timer_settime64)
__nolibc_assert_time64_type(new_value->it_value.tv_sec);
return my_syscall4(__NR_timer_settime64, timerid, flags, new_value, old_value);
#else
struct __kernel_itimerspec knew_value, kold_value;
int ret;
__nolibc_timespec_user_to_kernel(&new_value->it_value, &knew_value.it_value);
__nolibc_timespec_user_to_kernel(&new_value->it_interval, &knew_value.it_interval);
ret = my_syscall4(__NR_timer_settime64, timerid, flags, &knew_value, &kold_value);
if (old_value) {
__nolibc_timespec_kernel_to_user(&kold_value.it_interval, &old_value->it_interval);
__nolibc_timespec_kernel_to_user(&kold_value.it_value, &old_value->it_value);
}
return ret;
__nolibc_assert_native_time64();
return my_syscall4(__NR_timer_settime, timerid, flags, new_value, old_value);
#endif
}

View file

@ -13,9 +13,24 @@
#include "std.h"
#include <linux/mman.h>
#include <linux/stat.h>
#include <linux/time.h>
#include <linux/time_types.h>
#include <linux/wait.h>
struct timespec {
time_t tv_sec;
int64_t tv_nsec;
};
#define _STRUCT_TIMESPEC
/* Never use with system calls */
struct timeval {
time_t tv_sec;
int64_t tv_usec;
};
#define timeval __nolibc_kernel_timeval
#include <linux/time.h>
#undef timeval
/* Only the generic macros and types may be defined here. The arch-specific
* ones such as the O_RDONLY and related macros used by fcntl() and open()

View file

@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
TEST_GEN_PROGS := nolibc-test
TEST_GEN_PROGS := nolibc-test libc-test
include ../lib.mk
include $(top_srcdir)/scripts/Makefile.compiler
@ -9,16 +9,16 @@ cc-option = $(call __cc-option, $(CC),,$(1),$(2))
include Makefile.include
CFLAGS = -nostdlib -nostdinc -static \
$(OUTPUT)/nolibc-test: CFLAGS = -nostdlib -nostdinc -static \
-isystem $(top_srcdir)/tools/include/nolibc -isystem $(top_srcdir)/usr/include \
$(CFLAGS_NOLIBC_TEST)
ifeq ($(LLVM),)
LDLIBS := -lgcc
endif
$(OUTPUT)/nolibc-test: LDLIBS = $(if $(LLVM),,-lgcc)
$(OUTPUT)/nolibc-test: nolibc-test.c nolibc-test-linkage.c | headers
$(OUTPUT)/libc-test: nolibc-test.c nolibc-test-linkage.c
$(call msg,CC,,$@)
$(Q)$(LINK.c) $^ -o $@
help:
@echo "For the custom nolibc testsuite use '$(MAKE) -f Makefile.nolibc'; available targets:"
@$(MAKE) -f Makefile.nolibc help

View file

@ -226,7 +226,7 @@ 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_sparc32 = $(call cc-option,-m32) -mcpu=v8
CFLAGS_sh4 = -ml -m4
ifeq ($(origin XARCH),command line)
CFLAGS_XARCH = $(CFLAGS_$(XARCH))
@ -302,15 +302,9 @@ sysroot/$(ARCH)/include:
$(Q)$(MAKE) -C $(srctree)/tools/include/nolibc ARCH=$(ARCH) OUTPUT=$(CURDIR)/sysroot/ headers_standalone headers_check
$(Q)mv sysroot/sysroot sysroot/$(ARCH)
ifneq ($(NOLIBC_SYSROOT),0)
nolibc-test: nolibc-test.c nolibc-test-linkage.c sysroot/$(ARCH)/include
$(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ \
-nostdlib -nostdinc -static -Isysroot/$(ARCH)/include nolibc-test.c nolibc-test-linkage.c $(LIBGCC)
else
nolibc-test: nolibc-test.c nolibc-test-linkage.c
$(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ \
-nostdlib -static -include $(srctree)/tools/include/nolibc/nolibc.h nolibc-test.c nolibc-test-linkage.c $(LIBGCC)
endif
libc-test: nolibc-test.c nolibc-test-linkage.c
$(QUIET_CC)$(HOSTCC) -o $@ nolibc-test.c nolibc-test-linkage.c

View file

@ -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>
@ -877,6 +878,58 @@ int test_file_stream(void)
return 0;
}
int test_file_stream_wsr(void)
{
const char dataout[] = "foo";
const size_t datasz = sizeof(dataout);
char datain[datasz];
int fd, r;
FILE *f;
fd = open("/tmp", O_TMPFILE | O_RDWR, 0644);
if (fd == -1)
return -1;
f = fdopen(fd, "w+");
if (!f)
return -1;
errno = 0;
r = fwrite(dataout, 1, datasz, f);
if (r != datasz)
return -1;
/* Attempt to read from the file without rewinding,
* we should read 0 items.
*/
r = fread(datain, 1, datasz, f);
if (r)
return -1;
/* Rewind the file to the start */
r = fseek(f, 0, SEEK_SET);
if (r)
return -1;
/* Attempt to read back more than was written to
* make sure we handle short reads properly.
* fread() should return the number of complete items.
*/
r = fread(datain, 1, datasz + 1, f);
if (r != datasz)
return -1;
/* Data we read should match the data we just wrote */
if (memcmp(datain, dataout, datasz) != 0)
return -1;
r = fclose(f);
if (r)
return -1;
return 0;
}
enum fork_type {
FORK_STANDARD,
FORK_VFORK,
@ -1351,6 +1404,7 @@ int run_syscall(int min, int max)
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(file_stream_wsr); EXPECT_SYSZR(1, test_file_stream_wsr()); break;
CASE_TEST(fork); EXPECT_SYSZR(1, test_fork(FORK_STANDARD)); break;
CASE_TEST(getdents64_root); EXPECT_SYSNE(1, test_getdents64("/"), -1); break;
CASE_TEST(getdents64_null); EXPECT_SYSER(1, test_getdents64("/dev/null"), -1, ENOTDIR); break;
@ -1403,9 +1457,10 @@ int run_syscall(int min, int max)
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(readv_zero); EXPECT_SYSZR(1, readv(0, NULL, 0)); break;
CASE_TEST(writev_badf); EXPECT_SYSER(1, writev(-1, &iov_one, 1), -1, EBADF); break;
CASE_TEST(writev_zero); EXPECT_SYSZR(1, writev(1, NULL, 0)); break;
CASE_TEST(ptrace); EXPECT_SYSER(1, ptrace(PTRACE_CONT, getpid(), NULL, NULL), -1, ESRCH); break;
CASE_TEST(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;
@ -1428,6 +1483,34 @@ int test_difftime(void)
return 0;
}
int test_time_types(void)
{
#ifdef NOLIBC
struct __kernel_timespec kts;
struct timespec ts;
if (!__builtin_types_compatible_p(time_t, __kernel_time64_t))
return 1;
if (sizeof(ts) != sizeof(kts))
return 1;
if (!__builtin_types_compatible_p(__typeof__(ts.tv_sec), __typeof__(kts.tv_sec)))
return 1;
if (!__builtin_types_compatible_p(__typeof__(ts.tv_nsec), __typeof__(kts.tv_nsec)))
return 1;
if (offsetof(__typeof__(ts), tv_sec) != offsetof(__typeof__(kts), tv_sec))
return 1;
if (offsetof(__typeof__(ts), tv_nsec) != offsetof(__typeof__(kts), tv_nsec))
return 1;
#endif /* NOLIBC */
return 0;
}
int run_stdlib(int min, int max)
{
int test;
@ -1553,6 +1636,7 @@ int run_stdlib(int min, int max)
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_TEST(time_types); EXPECT_ZR(is_nolibc, test_time_types()); break;
case __LINE__:
return ret; /* must be last */