mirror of
https://github.com/torvalds/linux.git
synced 2024-09-20 23:13:00 +00:00
nolibc updates for v6.7
o Add stdarg.h header and a few additional system-call upgrades. o Add support for constructors and destructors. o Add tests to verify the ability to link multiple .o files against nolibc. o Numerous string-function optimizations and improvements. o Prevent redundant kernel relinks by avoiding embedding of initramfs into the kernel image. o Allow building i386 with multiarch compiler and make ppc64le use qemu-system-ppc64. o Miscellaneous fixups, including addition of -nostdinc for nolibc-test, avoiding -Wstringop-overflow warnings, and avoiding unused parameter warnings for ENOSYS fallbacks. -----BEGIN PGP SIGNATURE----- iQJHBAABCgAxFiEEbK7UrM+RBIrCoViJnr8S83LZ+4wFAmU3A1ETHHBhdWxtY2tA a2VybmVsLm9yZwAKCRCevxLzctn7jGyAEACRJX0s3JBvxRz5zKOA+l41sAN3DZ9z ygKIghnlNeDXQEFSqkZXb9Pa8BUPaVnFet3X5gUy8/0jcbXPPjIHU68U6EGQWk3f y5uTaxhTQkC+5gLyRhvq7FtjWxwYlg24D2e6ctrEw4pCt18PfkEhxof5PBhg/71K UVrZ55cRvXG7CTLSm5p1+jNkAOJuNfV+zD32QuV9V+7CwNLU088TZS9jGALFjKC0 UyE8E5uvmTQ6QQOl64Z6GNhpQual/2BslIGDVtb/+/Ii5Ch2nA8gV2YiC8cVPzpz r8yxqSEwfmiTNDPFH6PRIAx/optfgV/uScyyCNEiLwh/gFcag04BjC9GpWy5jKzA akchr0n+7yfJTpzzNmM38OAoaqMgzcPedxW2RDP5Eeb4cw0AKoy7bD3WeBRfmpgl tAgd8Gl7vpvSjecQSZfCY1hJ4F/qS2CfnObL4/EbHxIOfyLo0A6eEKLIf9PP02bT w2YJkZVSprKi8CXvIaV5KAhxXUGp07FJ5PHYLFFjinez/e6ksb7AH/ltrnAULMoV Ig3aQCYJ4oOFFVjH+h9+fFrqbI87Xo13UfO6PtkJU3gV749prqRIAg6FCTU0HkIz TSvy/PEFAxaXvNSGsSXikxQxvx3Fph9laoxQ1dSgEZSXKY43v1sfnXp1h5vGDdKH GPWaEtEBfNVUdg== =UKBQ -----END PGP SIGNATURE----- Merge tag 'nolibc.2023.10.23a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu Pull nolibc updates from Paul McKenney: - Add stdarg.h header and a few additional system-call upgrades - Add support for constructors and destructors - Add tests to verify the ability to link multiple .o files against nolibc - Numerous string-function optimizations and improvements - Prevent redundant kernel relinks by avoiding embedding of initramfs into the kernel image - Allow building i386 with multiarch compiler and make ppc64le use qemu-system-ppc64 - Miscellaneous fixups, including addition of -nostdinc for nolibc-test, avoiding -Wstringop-overflow warnings, and avoiding unused parameter warnings for ENOSYS fallbacks * tag 'nolibc.2023.10.23a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu: selftests/nolibc: add tests for multi-object linkage selftests/nolibc: use qemu-system-ppc64 for ppc64le tools/nolibc: add support for constructors and destructors tools/nolibc: drop test for getauxval(AT_PAGESZ) tools/nolibc: automatically detect necessity to use pselect6 tools/nolibc: don't define new syscall number tools/nolibc: avoid unused parameter warnings for ENOSYS fallbacks selftests/nolibc: allow building i386 with multiarch compiler selftests/nolibc: don't embed initramfs into kernel image selftests/nolibc: libc-test: avoid -Wstringop-overflow warnings tools/nolibc: string: Remove the `_nolibc_memcpy_up()` function tools/nolibc: string: Remove the `_nolibc_memcpy_down()` function tools/nolibc: x86-64: Use `rep stosb` for `memset()` tools/nolibc: x86-64: Use `rep movsb` for `memcpy()` and `memmove()` selftests/nolibc: use -nostdinc for nolibc-test tools/nolibc: add stdarg.h header
This commit is contained in:
commit
c9049984f0
|
@ -34,6 +34,7 @@ all_files := \
|
|||
signal.h \
|
||||
stackprotector.h \
|
||||
std.h \
|
||||
stdarg.h \
|
||||
stdint.h \
|
||||
stdlib.h \
|
||||
string.h \
|
||||
|
|
|
@ -20,10 +20,7 @@
|
|||
* - the arguments are cast to long and assigned into the target registers
|
||||
* which are then simply passed as registers to the asm code, so that we
|
||||
* don't have to experience issues with register constraints.
|
||||
*
|
||||
* On aarch64, select() is not implemented so we have to use pselect6().
|
||||
*/
|
||||
#define __ARCH_WANT_SYS_PSELECT6
|
||||
|
||||
#define my_syscall0(num) \
|
||||
({ \
|
||||
|
|
|
@ -19,10 +19,8 @@
|
|||
* - the arguments are cast to long and assigned into the target
|
||||
* registers which are then simply passed as registers to the asm code,
|
||||
* so that we don't have to experience issues with register constraints.
|
||||
*
|
||||
* On LoongArch, select() is not implemented so we have to use pselect6().
|
||||
*/
|
||||
#define __ARCH_WANT_SYS_PSELECT6
|
||||
|
||||
#define _NOLIBC_SYSCALL_CLOBBERLIST \
|
||||
"memory", "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8"
|
||||
|
||||
|
|
|
@ -19,10 +19,7 @@
|
|||
* - the arguments are cast to long and assigned into the target
|
||||
* registers which are then simply passed as registers to the asm code,
|
||||
* so that we don't have to experience issues with register constraints.
|
||||
*
|
||||
* On riscv, select() is not implemented so we have to use pselect6().
|
||||
*/
|
||||
#define __ARCH_WANT_SYS_PSELECT6
|
||||
|
||||
#define my_syscall0(num) \
|
||||
({ \
|
||||
|
|
|
@ -173,4 +173,46 @@ void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_
|
|||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#define NOLIBC_ARCH_HAS_MEMMOVE
|
||||
void *memmove(void *dst, const void *src, size_t len);
|
||||
|
||||
#define NOLIBC_ARCH_HAS_MEMCPY
|
||||
void *memcpy(void *dst, const void *src, size_t len);
|
||||
|
||||
#define NOLIBC_ARCH_HAS_MEMSET
|
||||
void *memset(void *dst, int c, size_t len);
|
||||
|
||||
__asm__ (
|
||||
".section .text.nolibc_memmove_memcpy\n"
|
||||
".weak memmove\n"
|
||||
".weak memcpy\n"
|
||||
"memmove:\n"
|
||||
"memcpy:\n"
|
||||
"movq %rdx, %rcx\n\t"
|
||||
"movq %rdi, %rax\n\t"
|
||||
"movq %rdi, %rdx\n\t"
|
||||
"subq %rsi, %rdx\n\t"
|
||||
"cmpq %rcx, %rdx\n\t"
|
||||
"jb .Lbackward_copy\n\t"
|
||||
"rep movsb\n\t"
|
||||
"retq\n"
|
||||
".Lbackward_copy:"
|
||||
"leaq -1(%rdi, %rcx, 1), %rdi\n\t"
|
||||
"leaq -1(%rsi, %rcx, 1), %rsi\n\t"
|
||||
"std\n\t"
|
||||
"rep movsb\n\t"
|
||||
"cld\n\t"
|
||||
"retq\n"
|
||||
|
||||
".section .text.nolibc_memset\n"
|
||||
".weak memset\n"
|
||||
"memset:\n"
|
||||
"xchgl %eax, %esi\n\t"
|
||||
"movq %rdx, %rcx\n\t"
|
||||
"pushq %rdi\n\t"
|
||||
"rep stosb\n\t"
|
||||
"popq %rax\n\t"
|
||||
"retq\n"
|
||||
);
|
||||
|
||||
#endif /* _NOLIBC_ARCH_X86_64_H */
|
||||
|
|
|
@ -13,12 +13,23 @@ const unsigned long *_auxv __attribute__((weak));
|
|||
static void __stack_chk_init(void);
|
||||
static void exit(int);
|
||||
|
||||
extern void (*const __preinit_array_start[])(void) __attribute__((weak));
|
||||
extern void (*const __preinit_array_end[])(void) __attribute__((weak));
|
||||
|
||||
extern void (*const __init_array_start[])(void) __attribute__((weak));
|
||||
extern void (*const __init_array_end[])(void) __attribute__((weak));
|
||||
|
||||
extern void (*const __fini_array_start[])(void) __attribute__((weak));
|
||||
extern void (*const __fini_array_end[])(void) __attribute__((weak));
|
||||
|
||||
__attribute__((weak))
|
||||
void _start_c(long *sp)
|
||||
{
|
||||
long argc;
|
||||
char **argv;
|
||||
char **envp;
|
||||
int exitcode;
|
||||
void (* const *func)(void);
|
||||
const unsigned long *auxv;
|
||||
/* silence potential warning: conflicting types for 'main' */
|
||||
int _nolibc_main(int, char **, char **) __asm__ ("main");
|
||||
|
@ -55,8 +66,18 @@ void _start_c(long *sp)
|
|||
;
|
||||
_auxv = auxv;
|
||||
|
||||
for (func = __preinit_array_start; func < __preinit_array_end; func++)
|
||||
(*func)();
|
||||
for (func = __init_array_start; func < __init_array_end; func++)
|
||||
(*func)();
|
||||
|
||||
/* go to application */
|
||||
exit(_nolibc_main(argc, argv, envp));
|
||||
exitcode = _nolibc_main(argc, argv, envp);
|
||||
|
||||
for (func = __fini_array_end; func > __fini_array_start;)
|
||||
(*--func)();
|
||||
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
#endif /* _NOLIBC_CRT_H */
|
||||
|
|
|
@ -74,10 +74,10 @@
|
|||
* -I../nolibc -o hello hello.c -lgcc
|
||||
*
|
||||
* The available standard (but limited) include files are:
|
||||
* ctype.h, errno.h, signal.h, stdio.h, stdlib.h, string.h, time.h
|
||||
* ctype.h, errno.h, signal.h, stdarg.h, stdio.h, stdlib.h, string.h, time.h
|
||||
*
|
||||
* In addition, the following ones are expected to be provided by the compiler:
|
||||
* float.h, stdarg.h, stddef.h
|
||||
* float.h, stddef.h
|
||||
*
|
||||
* The following ones which are part to the C standard are not provided:
|
||||
* assert.h, locale.h, math.h, setjmp.h, limits.h
|
||||
|
|
16
tools/include/nolibc/stdarg.h
Normal file
16
tools/include/nolibc/stdarg.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
|
||||
/*
|
||||
* Variadic argument support for NOLIBC
|
||||
* Copyright (C) 2005-2020 Rich Felker, et al.
|
||||
*/
|
||||
|
||||
#ifndef _NOLIBC_STDARG_H
|
||||
#define _NOLIBC_STDARG_H
|
||||
|
||||
typedef __builtin_va_list va_list;
|
||||
#define va_start(v, l) __builtin_va_start(v, l)
|
||||
#define va_end(v) __builtin_va_end(v)
|
||||
#define va_arg(v, l) __builtin_va_arg(v, l)
|
||||
#define va_copy(d, s) __builtin_va_copy(d, s)
|
||||
|
||||
#endif /* _NOLIBC_STDARG_H */
|
|
@ -7,13 +7,12 @@
|
|||
#ifndef _NOLIBC_STDIO_H
|
||||
#define _NOLIBC_STDIO_H
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "std.h"
|
||||
#include "arch.h"
|
||||
#include "errno.h"
|
||||
#include "types.h"
|
||||
#include "sys.h"
|
||||
#include "stdarg.h"
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
|
|
|
@ -27,28 +27,7 @@ int memcmp(const void *s1, const void *s2, size_t n)
|
|||
return c1;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
void *_nolibc_memcpy_up(void *dst, const void *src, size_t len)
|
||||
{
|
||||
size_t pos = 0;
|
||||
|
||||
while (pos < len) {
|
||||
((char *)dst)[pos] = ((const char *)src)[pos];
|
||||
pos++;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
void *_nolibc_memcpy_down(void *dst, const void *src, size_t len)
|
||||
{
|
||||
while (len) {
|
||||
len--;
|
||||
((char *)dst)[len] = ((const char *)src)[len];
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
#ifndef NOLIBC_ARCH_HAS_MEMMOVE
|
||||
/* might be ignored by the compiler without -ffreestanding, then found as
|
||||
* missing.
|
||||
*/
|
||||
|
@ -72,14 +51,24 @@ void *memmove(void *dst, const void *src, size_t len)
|
|||
}
|
||||
return dst;
|
||||
}
|
||||
#endif /* #ifndef NOLIBC_ARCH_HAS_MEMMOVE */
|
||||
|
||||
#ifndef NOLIBC_ARCH_HAS_MEMCPY
|
||||
/* must be exported, as it's used by libgcc on ARM */
|
||||
__attribute__((weak,unused,section(".text.nolibc_memcpy")))
|
||||
void *memcpy(void *dst, const void *src, size_t len)
|
||||
{
|
||||
return _nolibc_memcpy_up(dst, src, len);
|
||||
}
|
||||
size_t pos = 0;
|
||||
|
||||
while (pos < len) {
|
||||
((char *)dst)[pos] = ((const char *)src)[pos];
|
||||
pos++;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
#endif /* #ifndef NOLIBC_ARCH_HAS_MEMCPY */
|
||||
|
||||
#ifndef NOLIBC_ARCH_HAS_MEMSET
|
||||
/* might be ignored by the compiler without -ffreestanding, then found as
|
||||
* missing.
|
||||
*/
|
||||
|
@ -95,6 +84,7 @@ void *memset(void *dst, int b, size_t len)
|
|||
}
|
||||
return dst;
|
||||
}
|
||||
#endif /* #ifndef NOLIBC_ARCH_HAS_MEMSET */
|
||||
|
||||
static __attribute__((unused))
|
||||
char *strchr(const char *s, int c)
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#ifndef _NOLIBC_SYS_H
|
||||
#define _NOLIBC_SYS_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "std.h"
|
||||
|
||||
/* system includes */
|
||||
|
@ -25,6 +24,7 @@
|
|||
|
||||
#include "arch.h"
|
||||
#include "errno.h"
|
||||
#include "stdarg.h"
|
||||
#include "types.h"
|
||||
|
||||
|
||||
|
@ -43,6 +43,16 @@
|
|||
: __sysret_arg; /* return original value */ \
|
||||
})
|
||||
|
||||
/* Syscall ENOSYS helper: Avoids unused-parameter warnings and provides a
|
||||
* debugging hook.
|
||||
*/
|
||||
|
||||
static __inline__ int __nolibc_enosys(const char *syscall, ...)
|
||||
{
|
||||
(void)syscall;
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
|
||||
/* Functions in this file only describe syscalls. They're declared static so
|
||||
* that the compiler usually decides to inline them while still being allowed
|
||||
|
@ -133,7 +143,7 @@ int sys_chmod(const char *path, mode_t mode)
|
|||
#elif defined(__NR_chmod)
|
||||
return my_syscall2(__NR_chmod, path, mode);
|
||||
#else
|
||||
return -ENOSYS;
|
||||
return __nolibc_enosys(__func__, path, mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -156,7 +166,7 @@ int sys_chown(const char *path, uid_t owner, gid_t group)
|
|||
#elif defined(__NR_chown)
|
||||
return my_syscall3(__NR_chown, path, owner, group);
|
||||
#else
|
||||
return -ENOSYS;
|
||||
return __nolibc_enosys(__func__, path, owner, group);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -230,7 +240,7 @@ int sys_dup2(int old, int new)
|
|||
#elif defined(__NR_dup2)
|
||||
return my_syscall2(__NR_dup2, old, new);
|
||||
#else
|
||||
return -ENOSYS;
|
||||
return __nolibc_enosys(__func__, old, new);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -312,7 +322,7 @@ pid_t sys_fork(void)
|
|||
#elif defined(__NR_fork)
|
||||
return my_syscall0(__NR_fork);
|
||||
#else
|
||||
return -ENOSYS;
|
||||
return __nolibc_enosys(__func__);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
@ -486,7 +496,7 @@ int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
|
|||
#ifdef __NR_gettimeofday
|
||||
return my_syscall2(__NR_gettimeofday, tv, tz);
|
||||
#else
|
||||
return -ENOSYS;
|
||||
return __nolibc_enosys(__func__, tv, tz);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -563,7 +573,7 @@ int sys_link(const char *old, const char *new)
|
|||
#elif defined(__NR_link)
|
||||
return my_syscall2(__NR_link, old, new);
|
||||
#else
|
||||
return -ENOSYS;
|
||||
return __nolibc_enosys(__func__, old, new);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -584,7 +594,7 @@ off_t sys_lseek(int fd, off_t offset, int whence)
|
|||
#ifdef __NR_lseek
|
||||
return my_syscall3(__NR_lseek, fd, offset, whence);
|
||||
#else
|
||||
return -ENOSYS;
|
||||
return __nolibc_enosys(__func__, fd, offset, whence);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -607,7 +617,7 @@ int sys_mkdir(const char *path, mode_t mode)
|
|||
#elif defined(__NR_mkdir)
|
||||
return my_syscall2(__NR_mkdir, path, mode);
|
||||
#else
|
||||
return -ENOSYS;
|
||||
return __nolibc_enosys(__func__, path, mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -629,7 +639,7 @@ int sys_rmdir(const char *path)
|
|||
#elif defined(__NR_unlinkat)
|
||||
return my_syscall3(__NR_unlinkat, AT_FDCWD, path, AT_REMOVEDIR);
|
||||
#else
|
||||
return -ENOSYS;
|
||||
return __nolibc_enosys(__func__, path);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -652,7 +662,7 @@ long sys_mknod(const char *path, mode_t mode, dev_t dev)
|
|||
#elif defined(__NR_mknod)
|
||||
return my_syscall3(__NR_mknod, path, mode, dev);
|
||||
#else
|
||||
return -ENOSYS;
|
||||
return __nolibc_enosys(__func__, path, mode, dev);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -742,7 +752,7 @@ int sys_open(const char *path, int flags, mode_t mode)
|
|||
#elif defined(__NR_open)
|
||||
return my_syscall3(__NR_open, path, flags, mode);
|
||||
#else
|
||||
return -ENOSYS;
|
||||
return __nolibc_enosys(__func__, path, flags, mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -842,7 +852,7 @@ int sys_poll(struct pollfd *fds, int nfds, int timeout)
|
|||
#elif defined(__NR_poll)
|
||||
return my_syscall3(__NR_poll, fds, nfds, timeout);
|
||||
#else
|
||||
return -ENOSYS;
|
||||
return __nolibc_enosys(__func__, fds, nfds, timeout);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -920,7 +930,11 @@ int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeva
|
|||
struct timeval *t;
|
||||
} arg = { .n = nfds, .r = rfds, .w = wfds, .e = efds, .t = timeout };
|
||||
return my_syscall1(__NR_select, &arg);
|
||||
#elif defined(__ARCH_WANT_SYS_PSELECT6) && defined(__NR_pselect6)
|
||||
#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) {
|
||||
|
@ -928,13 +942,8 @@ int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeva
|
|||
t.tv_nsec = timeout->tv_usec * 1000;
|
||||
}
|
||||
return my_syscall6(__NR_pselect6, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL);
|
||||
#elif defined(__NR__newselect) || defined(__NR_select)
|
||||
#ifndef __NR__newselect
|
||||
#define __NR__newselect __NR_select
|
||||
#endif
|
||||
return my_syscall5(__NR__newselect, nfds, rfds, wfds, efds, timeout);
|
||||
#else
|
||||
return -ENOSYS;
|
||||
return __nolibc_enosys(__func__, nfds, rfds, wfds, efds, timeout);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -989,7 +998,7 @@ int sys_statx(int fd, const char *path, int flags, unsigned int mask, struct sta
|
|||
#ifdef __NR_statx
|
||||
return my_syscall5(__NR_statx, fd, path, flags, mask, buf);
|
||||
#else
|
||||
return -ENOSYS;
|
||||
return __nolibc_enosys(__func__, fd, path, flags, mask, buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1047,7 +1056,7 @@ int sys_symlink(const char *old, const char *new)
|
|||
#elif defined(__NR_symlink)
|
||||
return my_syscall2(__NR_symlink, old, new);
|
||||
#else
|
||||
return -ENOSYS;
|
||||
return __nolibc_enosys(__func__, old, new);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1104,7 +1113,7 @@ int sys_unlink(const char *path)
|
|||
#elif defined(__NR_unlink)
|
||||
return my_syscall1(__NR_unlink, path);
|
||||
#else
|
||||
return -ENOSYS;
|
||||
return __nolibc_enosys(__func__, path);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1127,7 +1136,7 @@ pid_t sys_wait4(pid_t pid, int *status, int options, struct rusage *rusage)
|
|||
#ifdef __NR_wait4
|
||||
return my_syscall4(__NR_wait4, pid, status, options, rusage);
|
||||
#else
|
||||
return -ENOSYS;
|
||||
return __nolibc_enosys(__func__, pid, status, options, rusage);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
1
tools/testing/selftests/nolibc/.gitignore
vendored
1
tools/testing/selftests/nolibc/.gitignore
vendored
|
@ -1,4 +1,5 @@
|
|||
/initramfs/
|
||||
/initramfs.cpio
|
||||
/libc-test
|
||||
/nolibc-test
|
||||
/run.out
|
||||
|
|
|
@ -82,7 +82,7 @@ QEMU_ARCH_arm = arm
|
|||
QEMU_ARCH_mips = mipsel # works with malta_defconfig
|
||||
QEMU_ARCH_ppc = ppc
|
||||
QEMU_ARCH_ppc64 = ppc64
|
||||
QEMU_ARCH_ppc64le = ppc64le
|
||||
QEMU_ARCH_ppc64le = ppc64
|
||||
QEMU_ARCH_riscv = riscv64
|
||||
QEMU_ARCH_s390 = s390x
|
||||
QEMU_ARCH_loongarch = loongarch64
|
||||
|
@ -113,6 +113,7 @@ else
|
|||
Q=@
|
||||
endif
|
||||
|
||||
CFLAGS_i386 = $(call cc-option,-m32)
|
||||
CFLAGS_ppc = -m32 -mbig-endian -mno-vsx $(call cc-option,-mmultiple)
|
||||
CFLAGS_ppc64 = -m64 -mbig-endian -mno-vsx $(call cc-option,-mmultiple)
|
||||
CFLAGS_ppc64le = -m64 -mlittle-endian -mno-vsx $(call cc-option,-mabi=elfv2)
|
||||
|
@ -131,18 +132,20 @@ REPORT ?= awk '/\[OK\][\r]*$$/{p++} /\[FAIL\][\r]*$$/{if (!f) printf("\n"); f++
|
|||
|
||||
help:
|
||||
@echo "Supported targets under selftests/nolibc:"
|
||||
@echo " all call the \"run\" target below"
|
||||
@echo " help this help"
|
||||
@echo " sysroot create the nolibc sysroot here (uses \$$ARCH)"
|
||||
@echo " nolibc-test build the executable (uses \$$CC and \$$CROSS_COMPILE)"
|
||||
@echo " libc-test build an executable using the compiler's default libc instead"
|
||||
@echo " run-user runs the executable under QEMU (uses \$$XARCH, \$$TEST)"
|
||||
@echo " initramfs prepare the initramfs with nolibc-test"
|
||||
@echo " defconfig create a fresh new default config (uses \$$XARCH)"
|
||||
@echo " kernel (re)build the kernel with the initramfs (uses \$$XARCH)"
|
||||
@echo " run runs the kernel in QEMU after building it (uses \$$XARCH, \$$TEST)"
|
||||
@echo " rerun runs a previously prebuilt kernel in QEMU (uses \$$XARCH, \$$TEST)"
|
||||
@echo " clean clean the sysroot, initramfs, build and output files"
|
||||
@echo " all call the \"run\" target below"
|
||||
@echo " help this help"
|
||||
@echo " sysroot create the nolibc sysroot here (uses \$$ARCH)"
|
||||
@echo " nolibc-test build the executable (uses \$$CC and \$$CROSS_COMPILE)"
|
||||
@echo " libc-test build an executable using the compiler's default libc instead"
|
||||
@echo " run-user runs the executable under QEMU (uses \$$XARCH, \$$TEST)"
|
||||
@echo " initramfs.cpio prepare the initramfs archive with nolibc-test"
|
||||
@echo " initramfs prepare the initramfs tree with nolibc-test"
|
||||
@echo " defconfig create a fresh new default config (uses \$$XARCH)"
|
||||
@echo " kernel (re)build the kernel (uses \$$XARCH)"
|
||||
@echo " kernel-standalone (re)build the kernel with the initramfs (uses \$$XARCH)"
|
||||
@echo " run runs the kernel in QEMU after building it (uses \$$XARCH, \$$TEST)"
|
||||
@echo " rerun runs a previously prebuilt kernel in QEMU (uses \$$XARCH, \$$TEST)"
|
||||
@echo " clean clean the sysroot, initramfs, build and output files"
|
||||
@echo ""
|
||||
@echo "The output file is \"run.out\". Test ranges may be passed using \$$TEST."
|
||||
@echo ""
|
||||
|
@ -168,17 +171,17 @@ sysroot/$(ARCH)/include:
|
|||
$(Q)mv sysroot/sysroot sysroot/$(ARCH)
|
||||
|
||||
ifneq ($(NOLIBC_SYSROOT),0)
|
||||
nolibc-test: nolibc-test.c sysroot/$(ARCH)/include
|
||||
nolibc-test: nolibc-test.c nolibc-test-linkage.c sysroot/$(ARCH)/include
|
||||
$(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ \
|
||||
-nostdlib -static -Isysroot/$(ARCH)/include $< -lgcc
|
||||
-nostdlib -nostdinc -static -Isysroot/$(ARCH)/include nolibc-test.c nolibc-test-linkage.c -lgcc
|
||||
else
|
||||
nolibc-test: nolibc-test.c
|
||||
nolibc-test: nolibc-test.c nolibc-test-linkage.c
|
||||
$(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ \
|
||||
-nostdlib -static -include ../../../include/nolibc/nolibc.h $< -lgcc
|
||||
-nostdlib -static -include ../../../include/nolibc/nolibc.h nolibc-test.c nolibc-test-linkage.c -lgcc
|
||||
endif
|
||||
|
||||
libc-test: nolibc-test.c
|
||||
$(QUIET_CC)$(HOSTCC) -o $@ $<
|
||||
libc-test: nolibc-test.c nolibc-test-linkage.c
|
||||
$(QUIET_CC)$(HOSTCC) -o $@ nolibc-test.c nolibc-test-linkage.c
|
||||
|
||||
# local libc-test
|
||||
run-libc-test: libc-test
|
||||
|
@ -195,6 +198,9 @@ run-user: nolibc-test
|
|||
$(Q)qemu-$(QEMU_ARCH) ./nolibc-test > "$(CURDIR)/run.out" || :
|
||||
$(Q)$(REPORT) $(CURDIR)/run.out
|
||||
|
||||
initramfs.cpio: kernel nolibc-test
|
||||
$(QUIET_GEN)echo 'file /init nolibc-test 755 0 0' | $(srctree)/usr/gen_init_cpio - > initramfs.cpio
|
||||
|
||||
initramfs: nolibc-test
|
||||
$(QUIET_MKDIR)mkdir -p initramfs
|
||||
$(call QUIET_INSTALL, initramfs/init)
|
||||
|
@ -203,17 +209,20 @@ initramfs: nolibc-test
|
|||
defconfig:
|
||||
$(Q)$(MAKE) -C $(srctree) ARCH=$(ARCH) CC=$(CC) CROSS_COMPILE=$(CROSS_COMPILE) mrproper $(DEFCONFIG) prepare
|
||||
|
||||
kernel: initramfs
|
||||
kernel:
|
||||
$(Q)$(MAKE) -C $(srctree) ARCH=$(ARCH) CC=$(CC) CROSS_COMPILE=$(CROSS_COMPILE) $(IMAGE_NAME)
|
||||
|
||||
kernel-standalone: initramfs
|
||||
$(Q)$(MAKE) -C $(srctree) ARCH=$(ARCH) CC=$(CC) CROSS_COMPILE=$(CROSS_COMPILE) $(IMAGE_NAME) CONFIG_INITRAMFS_SOURCE=$(CURDIR)/initramfs
|
||||
|
||||
# run the tests after building the kernel
|
||||
run: kernel
|
||||
$(Q)qemu-system-$(QEMU_ARCH) -display none -no-reboot -kernel "$(srctree)/$(IMAGE)" -serial stdio $(QEMU_ARGS) > "$(CURDIR)/run.out"
|
||||
run: kernel initramfs.cpio
|
||||
$(Q)qemu-system-$(QEMU_ARCH) -display none -no-reboot -kernel "$(srctree)/$(IMAGE)" -initrd initramfs.cpio -serial stdio $(QEMU_ARGS) > "$(CURDIR)/run.out"
|
||||
$(Q)$(REPORT) $(CURDIR)/run.out
|
||||
|
||||
# re-run the tests from an existing kernel
|
||||
rerun:
|
||||
$(Q)qemu-system-$(QEMU_ARCH) -display none -no-reboot -kernel "$(srctree)/$(IMAGE)" -serial stdio $(QEMU_ARGS) > "$(CURDIR)/run.out"
|
||||
$(Q)qemu-system-$(QEMU_ARCH) -display none -no-reboot -kernel "$(srctree)/$(IMAGE)" -initrd initramfs.cpio -serial stdio $(QEMU_ARGS) > "$(CURDIR)/run.out"
|
||||
$(Q)$(REPORT) $(CURDIR)/run.out
|
||||
|
||||
# report with existing test log
|
||||
|
@ -227,6 +236,8 @@ clean:
|
|||
$(Q)rm -f nolibc-test
|
||||
$(call QUIET_CLEAN, libc-test)
|
||||
$(Q)rm -f libc-test
|
||||
$(call QUIET_CLEAN, initramfs.cpio)
|
||||
$(Q)rm -rf initramfs.cpio
|
||||
$(call QUIET_CLEAN, initramfs)
|
||||
$(Q)rm -rf initramfs
|
||||
$(call QUIET_CLEAN, run.out)
|
||||
|
|
26
tools/testing/selftests/nolibc/nolibc-test-linkage.c
Normal file
26
tools/testing/selftests/nolibc/nolibc-test-linkage.c
Normal file
|
@ -0,0 +1,26 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#include "nolibc-test-linkage.h"
|
||||
|
||||
#ifndef NOLIBC
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
void *linkage_test_errno_addr(void)
|
||||
{
|
||||
return &errno;
|
||||
}
|
||||
|
||||
int linkage_test_constructor_test_value;
|
||||
|
||||
__attribute__((constructor))
|
||||
static void constructor1(void)
|
||||
{
|
||||
linkage_test_constructor_test_value = 2;
|
||||
}
|
||||
|
||||
__attribute__((constructor))
|
||||
static void constructor2(void)
|
||||
{
|
||||
linkage_test_constructor_test_value *= 3;
|
||||
}
|
9
tools/testing/selftests/nolibc/nolibc-test-linkage.h
Normal file
9
tools/testing/selftests/nolibc/nolibc-test-linkage.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#ifndef _NOLIBC_TEST_LINKAGE_H
|
||||
#define _NOLIBC_TEST_LINKAGE_H
|
||||
|
||||
void *linkage_test_errno_addr(void);
|
||||
extern int linkage_test_constructor_test_value;
|
||||
|
||||
#endif /* _NOLIBC_TEST_LINKAGE_H */
|
|
@ -41,6 +41,8 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#include "nolibc-test-linkage.h"
|
||||
|
||||
/* for the type of int_fast16_t and int_fast32_t, musl differs from glibc and nolibc */
|
||||
#define SINT_MAX_OF_TYPE(type) (((type)1 << (sizeof(type) * 8 - 2)) - (type)1 + ((type)1 << (sizeof(type) * 8 - 2)))
|
||||
#define SINT_MIN_OF_TYPE(type) (-SINT_MAX_OF_TYPE(type) - 1)
|
||||
|
@ -57,6 +59,9 @@ static int test_argc;
|
|||
/* will be used by some test cases as readable file, please don't write it */
|
||||
static const char *argv0;
|
||||
|
||||
/* will be used by constructor tests */
|
||||
static int constructor_test_value;
|
||||
|
||||
/* definition of a series of tests */
|
||||
struct test {
|
||||
const char *name; /* test name */
|
||||
|
@ -594,6 +599,19 @@ int expect_strne(const char *expr, int llen, const char *cmp)
|
|||
#define CASE_TEST(name) \
|
||||
case __LINE__: llen += printf("%d %s", test, #name);
|
||||
|
||||
/* constructors validate that they are executed in definition order */
|
||||
__attribute__((constructor))
|
||||
static void constructor1(void)
|
||||
{
|
||||
constructor_test_value = 1;
|
||||
}
|
||||
|
||||
__attribute__((constructor))
|
||||
static void constructor2(void)
|
||||
{
|
||||
constructor_test_value *= 2;
|
||||
}
|
||||
|
||||
int run_startup(int min, int max)
|
||||
{
|
||||
int test;
|
||||
|
@ -630,7 +648,9 @@ int run_startup(int min, int max)
|
|||
CASE_TEST(environ_HOME); EXPECT_PTRNZ(1, getenv("HOME")); break;
|
||||
CASE_TEST(auxv_addr); EXPECT_PTRGT(test_auxv != (void *)-1, test_auxv, brk); break;
|
||||
CASE_TEST(auxv_AT_UID); EXPECT_EQ(1, getauxval(AT_UID), getuid()); break;
|
||||
CASE_TEST(auxv_AT_PAGESZ); EXPECT_GE(1, getauxval(AT_PAGESZ), 4096); break;
|
||||
CASE_TEST(constructor); EXPECT_EQ(1, constructor_test_value, 2); break;
|
||||
CASE_TEST(linkage_errno); EXPECT_PTREQ(1, linkage_test_errno_addr(), &errno); break;
|
||||
CASE_TEST(linkage_constr); EXPECT_EQ(1, linkage_test_constructor_test_value, 6); break;
|
||||
case __LINE__:
|
||||
return ret; /* must be last */
|
||||
/* note: do not set any defaults so as to permit holes above */
|
||||
|
@ -894,14 +914,14 @@ int run_syscall(int min, int max)
|
|||
CASE_TEST(lseek_0); EXPECT_SYSER(1, lseek(0, 0, SEEK_SET), -1, ESPIPE); break;
|
||||
CASE_TEST(mkdir_root); EXPECT_SYSER(1, mkdir("/", 0755), -1, EEXIST); break;
|
||||
CASE_TEST(mmap_bad); EXPECT_PTRER(1, mmap(NULL, 0, PROT_READ, MAP_PRIVATE, 0, 0), MAP_FAILED, EINVAL); break;
|
||||
CASE_TEST(munmap_bad); EXPECT_SYSER(1, munmap((void *)1, 0), -1, EINVAL); break;
|
||||
CASE_TEST(munmap_bad); EXPECT_SYSER(1, munmap(NULL, 0), -1, EINVAL); break;
|
||||
CASE_TEST(mmap_munmap_good); EXPECT_SYSZR(1, test_mmap_munmap()); break;
|
||||
CASE_TEST(open_tty); EXPECT_SYSNE(1, tmp = open("/dev/null", 0), -1); if (tmp != -1) close(tmp); break;
|
||||
CASE_TEST(open_blah); EXPECT_SYSER(1, tmp = open("/proc/self/blah", 0), -1, ENOENT); if (tmp != -1) close(tmp); break;
|
||||
CASE_TEST(pipe); EXPECT_SYSZR(1, test_pipe()); break;
|
||||
CASE_TEST(poll_null); EXPECT_SYSZR(1, poll(NULL, 0, 0)); break;
|
||||
CASE_TEST(poll_stdout); EXPECT_SYSNE(1, ({ struct pollfd fds = { 1, POLLOUT, 0}; poll(&fds, 1, 0); }), -1); break;
|
||||
CASE_TEST(poll_fault); EXPECT_SYSER(1, poll((void *)1, 1, 0), -1, EFAULT); break;
|
||||
CASE_TEST(poll_fault); EXPECT_SYSER(1, poll(NULL, 1, 0), -1, EFAULT); break;
|
||||
CASE_TEST(prctl); EXPECT_SYSER(1, prctl(PR_SET_NAME, (unsigned long)NULL, 0, 0, 0), -1, EFAULT); break;
|
||||
CASE_TEST(read_badf); EXPECT_SYSER(1, read(-1, &tmp, 1), -1, EBADF); break;
|
||||
CASE_TEST(rmdir_blah); EXPECT_SYSER(1, rmdir("/blah"), -1, ENOENT); break;
|
||||
|
@ -910,7 +930,7 @@ int run_syscall(int min, int max)
|
|||
CASE_TEST(select_stdout); EXPECT_SYSNE(1, ({ fd_set fds; FD_ZERO(&fds); FD_SET(1, &fds); select(2, NULL, &fds, NULL, NULL); }), -1); break;
|
||||
CASE_TEST(select_fault); EXPECT_SYSER(1, select(1, (void *)1, NULL, NULL, 0), -1, EFAULT); break;
|
||||
CASE_TEST(stat_blah); EXPECT_SYSER(1, stat("/proc/self/blah", &stat_buf), -1, ENOENT); break;
|
||||
CASE_TEST(stat_fault); EXPECT_SYSER(1, stat((void *)1, &stat_buf), -1, EFAULT); break;
|
||||
CASE_TEST(stat_fault); EXPECT_SYSER(1, stat(NULL, &stat_buf), -1, EFAULT); break;
|
||||
CASE_TEST(stat_timestamps); EXPECT_SYSZR(1, test_stat_timestamps()); break;
|
||||
CASE_TEST(symlink_root); EXPECT_SYSER(1, symlink("/", "/"), -1, EEXIST); break;
|
||||
CASE_TEST(unlink_root); EXPECT_SYSER(1, unlink("/"), -1, EISDIR); break;
|
||||
|
|
Loading…
Reference in New Issue
Block a user