mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 03:44:45 +01:00
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:
commit
861ea34546
17 changed files with 304 additions and 158 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
33
tools/include/nolibc/sys/ptrace.h
Normal file
33
tools/include/nolibc/sys/ptrace.h
Normal 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 */
|
||||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue