mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-14 15:54:15 +08:00
nolibc updates for v6.5
o Add stackprotector support. o Fix RISC-V load-store instruction syntax to support 32-bit binaries, plus fixes for generic 32-bit support. o Fix use of s390 sys_fork(). o Add my_syscall6() for ARM. o Support different platforms having different errno definitions. o Fix ppoll/ppoll_time64 arguments (add the fifth argument). o Force use of little endian on MIPS. o Improved testing, for example, better handling of different compilers and compiler versions, comparing nolibc behavior to that of libc, and additional test cases. o Improve syntax and header ordering. o Use existing <linux/reboot.h> instead of redefining constants. o Add syscall(). -----BEGIN PGP SIGNATURE----- iQJHBAABCgAxFiEEbK7UrM+RBIrCoViJnr8S83LZ+4wFAmSUv78THHBhdWxtY2tA a2VybmVsLm9yZwAKCRCevxLzctn7jIUUD/9kEmF9BgeXerrsOx3omRgt7DbZR1Kj UYEI0mzydqQc92ZuS87VsM56rOA5SUDUDCPgTkkPCpo1anqo22+9FfFLU6M7EoEJ CNISlLtb7S1MdM9hND0RlxKoHxthcVcpUThVzAGMmuTNukJudwVBr085iiOS20VO taR5oHbPEE6pMmhbEsurmUHwTaqeCnuSZqmUoHnzatOidRByZDL7/mPr8y+lhtwo MP0wkS9ie6OTs7shH2/tt683ZY/v/JZnoOmokl7YxN6vsWeTxX7H3W4jdSGrPqW5 H+OaMVZV5QPG3EFN6MhvdMSAGWLXohMtMuSLc/BACwJ8u073LvJgJHoBahiVPXn7 y0bJbZbnXvkpp+Hqxh4argarwtQum3KAUrNLO/vIWSjJN1HbT0rhc1sRhAM+cta8 3a2nSsGf4xW8ToHgg2Q9PNzJSHxtIX1LxSEboS0IyRSYsdUS9E8gxugVIfyH9Rle gyasoSjepqwLVz6JnWiFIizHLPpEc22a3wSoRm6MzRKFaY+f8+KW6si7GgmSNmdA LJk5tid+2Unjz7BhXJ14XHRBpHYdQRQ4uA42EcUSc1CFc4/0rodGJ0hi03SXDGWY dH11x/yKW54lWZqyYUA/KAcJm8jwCFIWfGRvY9DHrA0Sh5aEyeNH3Brx1iITqnht svgWtwUsBJYIMQ== =Is+H -----END PGP SIGNATURE----- Merge tag 'nolibc.2023.06.22a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu Pull nolibc updates from Paul McKenney: - Add stackprotector support - Fix RISC-V load-store instruction syntax to support 32-bit binaries, plus fixes for generic 32-bit support - Fix use of s390 sys_fork() - Add my_syscall6() for ARM - Support different platforms having different errno definitions - Fix ppoll/ppoll_time64 arguments (add the fifth argument) - Force use of little endian on MIPS - Improved testing, for example, better handling of different compilers and compiler versions, comparing nolibc behavior to that of libc, and additional test cases - Improve syntax and header ordering - Use existing <linux/reboot.h> instead of redefining constants - Add syscall() * tag 'nolibc.2023.06.22a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu: (53 commits) selftests/nolibc: make sure gcc always use little endian on MIPS selftests/nolibc: also count skipped and failed tests in output selftests/nolibc: add new gettimeofday test cases selftests/nolibc: remove gettimeofday_bad1/2 completely selftests/nolibc: support two errnos with EXPECT_SYSER2() tools/nolibc: open: fix up compile warning for arm tools/nolibc: arm: add missing my_syscall6 selftests/nolibc: use INT_MAX instead of __INT_MAX__ selftests/nolibc: not include limits.h for nolibc selftests/nolibc: fix up compile warning with glibc on x86_64 selftests/nolibc: allow specify extra arguments for qemu selftests/nolibc: remove test gettimeofday_null tools/nolibc: ensure fast64 integer types have 64 bits selftests/nolibc: test_fork: fix up duplicated print tools/nolibc: ppoll/ppoll_time64: add a missing argument selftests/nolibc: remove the duplicated gettimeofday_bad2 selftests/nolibc: print name instead of number for EOVERFLOW tools/nolibc: support nanoseconds in stat() selftests/nolibc: prevent coredumps during test execution tools/nolibc: add support for prctl() ...
This commit is contained in:
commit
b19edac599
@ -25,8 +25,23 @@ endif
|
||||
|
||||
nolibc_arch := $(patsubst arm64,aarch64,$(ARCH))
|
||||
arch_file := arch-$(nolibc_arch).h
|
||||
all_files := ctype.h errno.h nolibc.h signal.h stackprotector.h std.h stdint.h \
|
||||
stdio.h stdlib.h string.h sys.h time.h types.h unistd.h
|
||||
all_files := \
|
||||
compiler.h \
|
||||
ctype.h \
|
||||
errno.h \
|
||||
nolibc.h \
|
||||
signal.h \
|
||||
stackprotector.h \
|
||||
std.h \
|
||||
stdint.h \
|
||||
stdlib.h \
|
||||
string.h \
|
||||
sys.h \
|
||||
time.h \
|
||||
types.h \
|
||||
unistd.h \
|
||||
stdio.h \
|
||||
|
||||
|
||||
# install all headers needed to support a bare-metal compiler
|
||||
all: headers
|
||||
|
@ -7,6 +7,8 @@
|
||||
#ifndef _NOLIBC_ARCH_AARCH64_H
|
||||
#define _NOLIBC_ARCH_AARCH64_H
|
||||
|
||||
#include "compiler.h"
|
||||
|
||||
/* The struct returned by the newfstatat() syscall. Differs slightly from the
|
||||
* x86_64's stat one by field ordering, so be careful.
|
||||
*/
|
||||
@ -173,27 +175,30 @@ char **environ __attribute__((weak));
|
||||
const unsigned long *_auxv __attribute__((weak));
|
||||
|
||||
/* startup code */
|
||||
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void)
|
||||
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
|
||||
{
|
||||
__asm__ volatile (
|
||||
"ldr x0, [sp]\n" // argc (x0) was in the stack
|
||||
"add x1, sp, 8\n" // argv (x1) = sp
|
||||
"lsl x2, x0, 3\n" // envp (x2) = 8*argc ...
|
||||
"add x2, x2, 8\n" // + 8 (skip null)
|
||||
"add x2, x2, x1\n" // + argv
|
||||
"adrp x3, environ\n" // x3 = &environ (high bits)
|
||||
"str x2, [x3, #:lo12:environ]\n" // store envp into environ
|
||||
"mov x4, x2\n" // search for auxv (follows NULL after last env)
|
||||
#ifdef _NOLIBC_STACKPROTECTOR
|
||||
"bl __stack_chk_init\n" /* initialize stack protector */
|
||||
#endif
|
||||
"ldr x0, [sp]\n" /* argc (x0) was in the stack */
|
||||
"add x1, sp, 8\n" /* argv (x1) = sp */
|
||||
"lsl x2, x0, 3\n" /* envp (x2) = 8*argc ... */
|
||||
"add x2, x2, 8\n" /* + 8 (skip null) */
|
||||
"add x2, x2, x1\n" /* + argv */
|
||||
"adrp x3, environ\n" /* x3 = &environ (high bits) */
|
||||
"str x2, [x3, #:lo12:environ]\n" /* store envp into environ */
|
||||
"mov x4, x2\n" /* search for auxv (follows NULL after last env) */
|
||||
"0:\n"
|
||||
"ldr x5, [x4], 8\n" // x5 = *x4; x4 += 8
|
||||
"cbnz x5, 0b\n" // and stop at NULL after last env
|
||||
"adrp x3, _auxv\n" // x3 = &_auxv (high bits)
|
||||
"str x4, [x3, #:lo12:_auxv]\n" // store x4 into _auxv
|
||||
"and sp, x1, -16\n" // sp must be 16-byte aligned in the callee
|
||||
"bl main\n" // main() returns the status code, we'll exit with it.
|
||||
"mov x8, 93\n" // NR_exit == 93
|
||||
"ldr x5, [x4], 8\n" /* x5 = *x4; x4 += 8 */
|
||||
"cbnz x5, 0b\n" /* and stop at NULL after last env */
|
||||
"adrp x3, _auxv\n" /* x3 = &_auxv (high bits) */
|
||||
"str x4, [x3, #:lo12:_auxv]\n" /* store x4 into _auxv */
|
||||
"and sp, x1, -16\n" /* sp must be 16-byte aligned in the callee */
|
||||
"bl main\n" /* main() returns the status code, we'll exit with it. */
|
||||
"mov x8, 93\n" /* NR_exit == 93 */
|
||||
"svc #0\n"
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
#endif // _NOLIBC_ARCH_AARCH64_H
|
||||
#endif /* _NOLIBC_ARCH_AARCH64_H */
|
||||
|
@ -7,6 +7,8 @@
|
||||
#ifndef _NOLIBC_ARCH_ARM_H
|
||||
#define _NOLIBC_ARCH_ARM_H
|
||||
|
||||
#include "compiler.h"
|
||||
|
||||
/* The struct returned by the stat() syscall, 32-bit only, the syscall returns
|
||||
* exactly 56 bytes (stops before the unused array). In big endian, the format
|
||||
* differs as devices are returned as short only.
|
||||
@ -196,41 +198,67 @@ struct sys_stat_struct {
|
||||
_arg1; \
|
||||
})
|
||||
|
||||
#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
|
||||
({ \
|
||||
register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
|
||||
register long _arg1 __asm__ ("r0") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("r1") = (long)(arg2); \
|
||||
register long _arg3 __asm__ ("r2") = (long)(arg3); \
|
||||
register long _arg4 __asm__ ("r3") = (long)(arg4); \
|
||||
register long _arg5 __asm__ ("r4") = (long)(arg5); \
|
||||
register long _arg6 __asm__ ("r5") = (long)(arg6); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
_NOLIBC_THUMB_SET_R7 \
|
||||
"svc #0\n" \
|
||||
_NOLIBC_THUMB_RESTORE_R7 \
|
||||
: "=r"(_arg1), "=r" (_num) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
|
||||
"r"(_arg6), "r"(_num) \
|
||||
: "memory", "cc", "lr" \
|
||||
); \
|
||||
_arg1; \
|
||||
})
|
||||
|
||||
|
||||
char **environ __attribute__((weak));
|
||||
const unsigned long *_auxv __attribute__((weak));
|
||||
|
||||
/* startup code */
|
||||
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void)
|
||||
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
|
||||
{
|
||||
__asm__ volatile (
|
||||
"pop {%r0}\n" // argc was in the stack
|
||||
"mov %r1, %sp\n" // argv = sp
|
||||
#ifdef _NOLIBC_STACKPROTECTOR
|
||||
"bl __stack_chk_init\n" /* initialize stack protector */
|
||||
#endif
|
||||
"pop {%r0}\n" /* argc was in the stack */
|
||||
"mov %r1, %sp\n" /* argv = sp */
|
||||
|
||||
"add %r2, %r0, $1\n" // envp = (argc + 1) ...
|
||||
"lsl %r2, %r2, $2\n" // * 4 ...
|
||||
"add %r2, %r2, %r1\n" // + argv
|
||||
"ldr %r3, 1f\n" // r3 = &environ (see below)
|
||||
"str %r2, [r3]\n" // store envp into environ
|
||||
"add %r2, %r0, $1\n" /* envp = (argc + 1) ... */
|
||||
"lsl %r2, %r2, $2\n" /* * 4 ... */
|
||||
"add %r2, %r2, %r1\n" /* + argv */
|
||||
"ldr %r3, 1f\n" /* r3 = &environ (see below) */
|
||||
"str %r2, [r3]\n" /* store envp into environ */
|
||||
|
||||
"mov r4, r2\n" // search for auxv (follows NULL after last env)
|
||||
"mov r4, r2\n" /* search for auxv (follows NULL after last env) */
|
||||
"0:\n"
|
||||
"mov r5, r4\n" // r5 = r4
|
||||
"add r4, r4, #4\n" // r4 += 4
|
||||
"ldr r5,[r5]\n" // r5 = *r5 = *(r4-4)
|
||||
"cmp r5, #0\n" // and stop at NULL after last env
|
||||
"mov r5, r4\n" /* r5 = r4 */
|
||||
"add r4, r4, #4\n" /* r4 += 4 */
|
||||
"ldr r5,[r5]\n" /* r5 = *r5 = *(r4-4) */
|
||||
"cmp r5, #0\n" /* and stop at NULL after last env */
|
||||
"bne 0b\n"
|
||||
"ldr %r3, 2f\n" // r3 = &_auxv (low bits)
|
||||
"str r4, [r3]\n" // store r4 into _auxv
|
||||
"ldr %r3, 2f\n" /* r3 = &_auxv (low bits) */
|
||||
"str r4, [r3]\n" /* store r4 into _auxv */
|
||||
|
||||
"mov %r3, $8\n" // AAPCS : sp must be 8-byte aligned in the
|
||||
"neg %r3, %r3\n" // callee, and bl doesn't push (lr=pc)
|
||||
"and %r3, %r3, %r1\n" // so we do sp = r1(=sp) & r3(=-8);
|
||||
"mov %sp, %r3\n" //
|
||||
"mov %r3, $8\n" /* AAPCS : sp must be 8-byte aligned in the */
|
||||
"neg %r3, %r3\n" /* callee, and bl doesn't push (lr=pc) */
|
||||
"and %r3, %r3, %r1\n" /* so we do sp = r1(=sp) & r3(=-8); */
|
||||
"mov %sp, %r3\n"
|
||||
|
||||
"bl main\n" // main() returns the status code, we'll exit with it.
|
||||
"movs r7, $1\n" // NR_exit == 1
|
||||
"bl main\n" /* main() returns the status code, we'll exit with it. */
|
||||
"movs r7, $1\n" /* NR_exit == 1 */
|
||||
"svc $0x00\n"
|
||||
".align 2\n" // below are the pointers to a few variables
|
||||
".align 2\n" /* below are the pointers to a few variables */
|
||||
"1:\n"
|
||||
".word environ\n"
|
||||
"2:\n"
|
||||
@ -239,4 +267,4 @@ void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void)
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#endif // _NOLIBC_ARCH_ARM_H
|
||||
#endif /* _NOLIBC_ARCH_ARM_H */
|
||||
|
@ -7,6 +7,8 @@
|
||||
#ifndef _NOLIBC_ARCH_I386_H
|
||||
#define _NOLIBC_ARCH_I386_H
|
||||
|
||||
#include "compiler.h"
|
||||
|
||||
/* The struct returned by the stat() syscall, 32-bit only, the syscall returns
|
||||
* exactly 56 bytes (stops before the unused array).
|
||||
*/
|
||||
@ -181,8 +183,6 @@ struct sys_stat_struct {
|
||||
char **environ __attribute__((weak));
|
||||
const unsigned long *_auxv __attribute__((weak));
|
||||
|
||||
#define __ARCH_SUPPORTS_STACK_PROTECTOR
|
||||
|
||||
/* startup code */
|
||||
/*
|
||||
* i386 System V ABI mandates:
|
||||
@ -190,35 +190,35 @@ const unsigned long *_auxv __attribute__((weak));
|
||||
* 2) The deepest stack frame should be set to zero
|
||||
*
|
||||
*/
|
||||
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"),no_stack_protector)) _start(void)
|
||||
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
|
||||
{
|
||||
__asm__ volatile (
|
||||
#ifdef NOLIBC_STACKPROTECTOR
|
||||
"call __stack_chk_init\n" // initialize stack protector
|
||||
#ifdef _NOLIBC_STACKPROTECTOR
|
||||
"call __stack_chk_init\n" /* initialize stack protector */
|
||||
#endif
|
||||
"pop %eax\n" // argc (first arg, %eax)
|
||||
"mov %esp, %ebx\n" // argv[] (second arg, %ebx)
|
||||
"lea 4(%ebx,%eax,4),%ecx\n" // then a NULL then envp (third arg, %ecx)
|
||||
"mov %ecx, environ\n" // save environ
|
||||
"xor %ebp, %ebp\n" // zero the stack frame
|
||||
"mov %ecx, %edx\n" // search for auxv (follows NULL after last env)
|
||||
"pop %eax\n" /* argc (first arg, %eax) */
|
||||
"mov %esp, %ebx\n" /* argv[] (second arg, %ebx) */
|
||||
"lea 4(%ebx,%eax,4),%ecx\n" /* then a NULL then envp (third arg, %ecx) */
|
||||
"mov %ecx, environ\n" /* save environ */
|
||||
"xor %ebp, %ebp\n" /* zero the stack frame */
|
||||
"mov %ecx, %edx\n" /* search for auxv (follows NULL after last env) */
|
||||
"0:\n"
|
||||
"add $4, %edx\n" // search for auxv using edx, it follows the
|
||||
"cmp -4(%edx), %ebp\n" // ... NULL after last env (ebp is zero here)
|
||||
"add $4, %edx\n" /* search for auxv using edx, it follows the */
|
||||
"cmp -4(%edx), %ebp\n" /* ... NULL after last env (ebp is zero here) */
|
||||
"jnz 0b\n"
|
||||
"mov %edx, _auxv\n" // save it into _auxv
|
||||
"and $-16, %esp\n" // x86 ABI : esp must be 16-byte aligned before
|
||||
"sub $4, %esp\n" // the call instruction (args are aligned)
|
||||
"push %ecx\n" // push all registers on the stack so that we
|
||||
"push %ebx\n" // support both regparm and plain stack modes
|
||||
"mov %edx, _auxv\n" /* save it into _auxv */
|
||||
"and $-16, %esp\n" /* x86 ABI : esp must be 16-byte aligned before */
|
||||
"sub $4, %esp\n" /* the call instruction (args are aligned) */
|
||||
"push %ecx\n" /* push all registers on the stack so that we */
|
||||
"push %ebx\n" /* support both regparm and plain stack modes */
|
||||
"push %eax\n"
|
||||
"call main\n" // main() returns the status code in %eax
|
||||
"mov %eax, %ebx\n" // retrieve exit code (32-bit int)
|
||||
"movl $1, %eax\n" // NR_exit == 1
|
||||
"int $0x80\n" // exit now
|
||||
"hlt\n" // ensure it does not
|
||||
"call main\n" /* main() returns the status code in %eax */
|
||||
"mov %eax, %ebx\n" /* retrieve exit code (32-bit int) */
|
||||
"movl $1, %eax\n" /* NR_exit == 1 */
|
||||
"int $0x80\n" /* exit now */
|
||||
"hlt\n" /* ensure it does not */
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#endif // _NOLIBC_ARCH_I386_H
|
||||
#endif /* _NOLIBC_ARCH_I386_H */
|
||||
|
@ -7,6 +7,8 @@
|
||||
#ifndef _NOLIBC_ARCH_LOONGARCH_H
|
||||
#define _NOLIBC_ARCH_LOONGARCH_H
|
||||
|
||||
#include "compiler.h"
|
||||
|
||||
/* Syscalls for LoongArch :
|
||||
* - stack is 16-byte aligned
|
||||
* - syscall number is passed in a7
|
||||
@ -158,7 +160,7 @@ const unsigned long *_auxv __attribute__((weak));
|
||||
#define LONG_ADDI "addi.w"
|
||||
#define LONG_SLL "slli.w"
|
||||
#define LONG_BSTRINS "bstrins.w"
|
||||
#else // __loongarch_grlen == 64
|
||||
#else /* __loongarch_grlen == 64 */
|
||||
#define LONGLOG "3"
|
||||
#define SZREG "8"
|
||||
#define REG_L "ld.d"
|
||||
@ -170,31 +172,34 @@ const unsigned long *_auxv __attribute__((weak));
|
||||
#endif
|
||||
|
||||
/* startup code */
|
||||
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void)
|
||||
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
|
||||
{
|
||||
__asm__ volatile (
|
||||
REG_L " $a0, $sp, 0\n" // argc (a0) was in the stack
|
||||
LONG_ADDI " $a1, $sp, "SZREG"\n" // argv (a1) = sp + SZREG
|
||||
LONG_SLL " $a2, $a0, "LONGLOG"\n" // envp (a2) = SZREG*argc ...
|
||||
LONG_ADDI " $a2, $a2, "SZREG"\n" // + SZREG (skip null)
|
||||
LONG_ADD " $a2, $a2, $a1\n" // + argv
|
||||
#ifdef _NOLIBC_STACKPROTECTOR
|
||||
"bl __stack_chk_init\n" /* initialize stack protector */
|
||||
#endif
|
||||
REG_L " $a0, $sp, 0\n" /* argc (a0) was in the stack */
|
||||
LONG_ADDI " $a1, $sp, "SZREG"\n" /* argv (a1) = sp + SZREG */
|
||||
LONG_SLL " $a2, $a0, "LONGLOG"\n" /* envp (a2) = SZREG*argc ... */
|
||||
LONG_ADDI " $a2, $a2, "SZREG"\n" /* + SZREG (skip null) */
|
||||
LONG_ADD " $a2, $a2, $a1\n" /* + argv */
|
||||
|
||||
"move $a3, $a2\n" // iterate a3 over envp to find auxv (after NULL)
|
||||
"0:\n" // do {
|
||||
REG_L " $a4, $a3, 0\n" // a4 = *a3;
|
||||
LONG_ADDI " $a3, $a3, "SZREG"\n" // a3 += sizeof(void*);
|
||||
"bne $a4, $zero, 0b\n" // } while (a4);
|
||||
"la.pcrel $a4, _auxv\n" // a4 = &_auxv
|
||||
LONG_S " $a3, $a4, 0\n" // store a3 into _auxv
|
||||
"move $a3, $a2\n" /* iterate a3 over envp to find auxv (after NULL) */
|
||||
"0:\n" /* do { */
|
||||
REG_L " $a4, $a3, 0\n" /* a4 = *a3; */
|
||||
LONG_ADDI " $a3, $a3, "SZREG"\n" /* a3 += sizeof(void*); */
|
||||
"bne $a4, $zero, 0b\n" /* } while (a4); */
|
||||
"la.pcrel $a4, _auxv\n" /* a4 = &_auxv */
|
||||
LONG_S " $a3, $a4, 0\n" /* store a3 into _auxv */
|
||||
|
||||
"la.pcrel $a3, environ\n" // a3 = &environ
|
||||
LONG_S " $a2, $a3, 0\n" // store envp(a2) into environ
|
||||
LONG_BSTRINS " $sp, $zero, 3, 0\n" // sp must be 16-byte aligned
|
||||
"bl main\n" // main() returns the status code, we'll exit with it.
|
||||
"li.w $a7, 93\n" // NR_exit == 93
|
||||
"la.pcrel $a3, environ\n" /* a3 = &environ */
|
||||
LONG_S " $a2, $a3, 0\n" /* store envp(a2) into environ */
|
||||
LONG_BSTRINS " $sp, $zero, 3, 0\n" /* sp must be 16-byte aligned */
|
||||
"bl main\n" /* main() returns the status code, we'll exit with it. */
|
||||
"li.w $a7, 93\n" /* NR_exit == 93 */
|
||||
"syscall 0\n"
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#endif // _NOLIBC_ARCH_LOONGARCH_H
|
||||
#endif /* _NOLIBC_ARCH_LOONGARCH_H */
|
||||
|
@ -7,6 +7,8 @@
|
||||
#ifndef _NOLIBC_ARCH_MIPS_H
|
||||
#define _NOLIBC_ARCH_MIPS_H
|
||||
|
||||
#include "compiler.h"
|
||||
|
||||
/* The struct returned by the stat() syscall. 88 bytes are returned by the
|
||||
* syscall.
|
||||
*/
|
||||
@ -180,45 +182,49 @@ char **environ __attribute__((weak));
|
||||
const unsigned long *_auxv __attribute__((weak));
|
||||
|
||||
/* startup code, note that it's called __start on MIPS */
|
||||
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __start(void)
|
||||
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector __start(void)
|
||||
{
|
||||
__asm__ volatile (
|
||||
//".set nomips16\n"
|
||||
/*".set nomips16\n"*/
|
||||
".set push\n"
|
||||
".set noreorder\n"
|
||||
".option pic0\n"
|
||||
//".ent __start\n"
|
||||
//"__start:\n"
|
||||
"lw $a0,($sp)\n" // argc was in the stack
|
||||
"addiu $a1, $sp, 4\n" // argv = sp + 4
|
||||
"sll $a2, $a0, 2\n" // a2 = argc * 4
|
||||
"add $a2, $a2, $a1\n" // envp = argv + 4*argc ...
|
||||
"addiu $a2, $a2, 4\n" // ... + 4
|
||||
"lui $a3, %hi(environ)\n" // load environ into a3 (hi)
|
||||
"addiu $a3, %lo(environ)\n" // load environ into a3 (lo)
|
||||
"sw $a2,($a3)\n" // store envp(a2) into environ
|
||||
#ifdef _NOLIBC_STACKPROTECTOR
|
||||
"jal __stack_chk_init\n" /* initialize stack protector */
|
||||
"nop\n" /* delayed slot */
|
||||
#endif
|
||||
/*".ent __start\n"*/
|
||||
/*"__start:\n"*/
|
||||
"lw $a0,($sp)\n" /* argc was in the stack */
|
||||
"addiu $a1, $sp, 4\n" /* argv = sp + 4 */
|
||||
"sll $a2, $a0, 2\n" /* a2 = argc * 4 */
|
||||
"add $a2, $a2, $a1\n" /* envp = argv + 4*argc ... */
|
||||
"addiu $a2, $a2, 4\n" /* ... + 4 */
|
||||
"lui $a3, %hi(environ)\n" /* load environ into a3 (hi) */
|
||||
"addiu $a3, %lo(environ)\n" /* load environ into a3 (lo) */
|
||||
"sw $a2,($a3)\n" /* store envp(a2) into environ */
|
||||
|
||||
"move $t0, $a2\n" // iterate t0 over envp, look for NULL
|
||||
"0:" // do {
|
||||
"lw $a3, ($t0)\n" // a3=*(t0);
|
||||
"bne $a3, $0, 0b\n" // } while (a3);
|
||||
"addiu $t0, $t0, 4\n" // delayed slot: t0+=4;
|
||||
"lui $a3, %hi(_auxv)\n" // load _auxv into a3 (hi)
|
||||
"addiu $a3, %lo(_auxv)\n" // load _auxv into a3 (lo)
|
||||
"sw $t0, ($a3)\n" // store t0 into _auxv
|
||||
"move $t0, $a2\n" /* iterate t0 over envp, look for NULL */
|
||||
"0:" /* do { */
|
||||
"lw $a3, ($t0)\n" /* a3=*(t0); */
|
||||
"bne $a3, $0, 0b\n" /* } while (a3); */
|
||||
"addiu $t0, $t0, 4\n" /* delayed slot: t0+=4; */
|
||||
"lui $a3, %hi(_auxv)\n" /* load _auxv into a3 (hi) */
|
||||
"addiu $a3, %lo(_auxv)\n" /* load _auxv into a3 (lo) */
|
||||
"sw $t0, ($a3)\n" /* store t0 into _auxv */
|
||||
|
||||
"li $t0, -8\n"
|
||||
"and $sp, $sp, $t0\n" // sp must be 8-byte aligned
|
||||
"addiu $sp,$sp,-16\n" // the callee expects to save a0..a3 there!
|
||||
"jal main\n" // main() returns the status code, we'll exit with it.
|
||||
"nop\n" // delayed slot
|
||||
"move $a0, $v0\n" // retrieve 32-bit exit code from v0
|
||||
"li $v0, 4001\n" // NR_exit == 4001
|
||||
"and $sp, $sp, $t0\n" /* sp must be 8-byte aligned */
|
||||
"addiu $sp,$sp,-16\n" /* the callee expects to save a0..a3 there! */
|
||||
"jal main\n" /* main() returns the status code, we'll exit with it. */
|
||||
"nop\n" /* delayed slot */
|
||||
"move $a0, $v0\n" /* retrieve 32-bit exit code from v0 */
|
||||
"li $v0, 4001\n" /* NR_exit == 4001 */
|
||||
"syscall\n"
|
||||
//".end __start\n"
|
||||
/*".end __start\n"*/
|
||||
".set pop\n"
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#endif // _NOLIBC_ARCH_MIPS_H
|
||||
#endif /* _NOLIBC_ARCH_MIPS_H */
|
||||
|
@ -7,6 +7,8 @@
|
||||
#ifndef _NOLIBC_ARCH_RISCV_H
|
||||
#define _NOLIBC_ARCH_RISCV_H
|
||||
|
||||
#include "compiler.h"
|
||||
|
||||
struct sys_stat_struct {
|
||||
unsigned long st_dev; /* Device. */
|
||||
unsigned long st_ino; /* File serial number. */
|
||||
@ -33,9 +35,13 @@ struct sys_stat_struct {
|
||||
#if __riscv_xlen == 64
|
||||
#define PTRLOG "3"
|
||||
#define SZREG "8"
|
||||
#define REG_L "ld"
|
||||
#define REG_S "sd"
|
||||
#elif __riscv_xlen == 32
|
||||
#define PTRLOG "2"
|
||||
#define SZREG "4"
|
||||
#define REG_L "lw"
|
||||
#define REG_S "sw"
|
||||
#endif
|
||||
|
||||
/* Syscalls for RISCV :
|
||||
@ -174,35 +180,38 @@ char **environ __attribute__((weak));
|
||||
const unsigned long *_auxv __attribute__((weak));
|
||||
|
||||
/* startup code */
|
||||
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void)
|
||||
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
|
||||
{
|
||||
__asm__ volatile (
|
||||
".option push\n"
|
||||
".option norelax\n"
|
||||
"lla gp, __global_pointer$\n"
|
||||
".option pop\n"
|
||||
"lw a0, 0(sp)\n" // argc (a0) was in the stack
|
||||
"add a1, sp, "SZREG"\n" // argv (a1) = sp
|
||||
"slli a2, a0, "PTRLOG"\n" // envp (a2) = SZREG*argc ...
|
||||
"add a2, a2, "SZREG"\n" // + SZREG (skip null)
|
||||
"add a2,a2,a1\n" // + argv
|
||||
#ifdef _NOLIBC_STACKPROTECTOR
|
||||
"call __stack_chk_init\n" /* initialize stack protector */
|
||||
#endif
|
||||
REG_L" a0, 0(sp)\n" /* argc (a0) was in the stack */
|
||||
"add a1, sp, "SZREG"\n" /* argv (a1) = sp */
|
||||
"slli a2, a0, "PTRLOG"\n" /* envp (a2) = SZREG*argc ... */
|
||||
"add a2, a2, "SZREG"\n" /* + SZREG (skip null) */
|
||||
"add a2,a2,a1\n" /* + argv */
|
||||
|
||||
"add a3, a2, zero\n" // iterate a3 over envp to find auxv (after NULL)
|
||||
"0:\n" // do {
|
||||
"ld a4, 0(a3)\n" // a4 = *a3;
|
||||
"add a3, a3, "SZREG"\n" // a3 += sizeof(void*);
|
||||
"bne a4, zero, 0b\n" // } while (a4);
|
||||
"lui a4, %hi(_auxv)\n" // a4 = &_auxv (high bits)
|
||||
"sd a3, %lo(_auxv)(a4)\n" // store a3 into _auxv
|
||||
"add a3, a2, zero\n" /* iterate a3 over envp to find auxv (after NULL) */
|
||||
"0:\n" /* do { */
|
||||
REG_L" a4, 0(a3)\n" /* a4 = *a3; */
|
||||
"add a3, a3, "SZREG"\n" /* a3 += sizeof(void*); */
|
||||
"bne a4, zero, 0b\n" /* } while (a4); */
|
||||
"lui a4, %hi(_auxv)\n" /* a4 = &_auxv (high bits) */
|
||||
REG_S" a3, %lo(_auxv)(a4)\n" /* store a3 into _auxv */
|
||||
|
||||
"lui a3, %hi(environ)\n" // a3 = &environ (high bits)
|
||||
"sd a2,%lo(environ)(a3)\n" // store envp(a2) into environ
|
||||
"andi sp,a1,-16\n" // sp must be 16-byte aligned
|
||||
"call main\n" // main() returns the status code, we'll exit with it.
|
||||
"li a7, 93\n" // NR_exit == 93
|
||||
"lui a3, %hi(environ)\n" /* a3 = &environ (high bits) */
|
||||
REG_S" a2,%lo(environ)(a3)\n"/* store envp(a2) into environ */
|
||||
"andi sp,a1,-16\n" /* sp must be 16-byte aligned */
|
||||
"call main\n" /* main() returns the status code, we'll exit with it. */
|
||||
"li a7, 93\n" /* NR_exit == 93 */
|
||||
"ecall\n"
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#endif // _NOLIBC_ARCH_RISCV_H
|
||||
#endif /* _NOLIBC_ARCH_RISCV_H */
|
||||
|
@ -5,8 +5,11 @@
|
||||
|
||||
#ifndef _NOLIBC_ARCH_S390_H
|
||||
#define _NOLIBC_ARCH_S390_H
|
||||
#include <asm/signal.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
#include "compiler.h"
|
||||
|
||||
/* The struct returned by the stat() syscall, equivalent to stat64(). The
|
||||
* syscall returns 116 bytes and stops in the middle of __unused.
|
||||
*/
|
||||
@ -163,7 +166,7 @@ char **environ __attribute__((weak));
|
||||
const unsigned long *_auxv __attribute__((weak));
|
||||
|
||||
/* startup code */
|
||||
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void)
|
||||
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
|
||||
{
|
||||
__asm__ volatile (
|
||||
"lg %r2,0(%r15)\n" /* argument count */
|
||||
@ -223,4 +226,12 @@ void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd,
|
||||
return (void *)my_syscall1(__NR_mmap, &args);
|
||||
}
|
||||
#define sys_mmap sys_mmap
|
||||
#endif // _NOLIBC_ARCH_S390_H
|
||||
|
||||
static __attribute__((unused))
|
||||
pid_t sys_fork(void)
|
||||
{
|
||||
return my_syscall5(__NR_clone, 0, SIGCHLD, 0, 0, 0);
|
||||
}
|
||||
#define sys_fork sys_fork
|
||||
|
||||
#endif /* _NOLIBC_ARCH_S390_H */
|
||||
|
@ -7,6 +7,8 @@
|
||||
#ifndef _NOLIBC_ARCH_X86_64_H
|
||||
#define _NOLIBC_ARCH_X86_64_H
|
||||
|
||||
#include "compiler.h"
|
||||
|
||||
/* The struct returned by the stat() syscall, equivalent to stat64(). The
|
||||
* syscall returns 116 bytes and stops in the middle of __unused.
|
||||
*/
|
||||
@ -181,8 +183,6 @@ struct sys_stat_struct {
|
||||
char **environ __attribute__((weak));
|
||||
const unsigned long *_auxv __attribute__((weak));
|
||||
|
||||
#define __ARCH_SUPPORTS_STACK_PROTECTOR
|
||||
|
||||
/* startup code */
|
||||
/*
|
||||
* x86-64 System V ABI mandates:
|
||||
@ -190,31 +190,31 @@ const unsigned long *_auxv __attribute__((weak));
|
||||
* 2) The deepest stack frame should be zero (the %rbp).
|
||||
*
|
||||
*/
|
||||
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void)
|
||||
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
|
||||
{
|
||||
__asm__ volatile (
|
||||
#ifdef NOLIBC_STACKPROTECTOR
|
||||
"call __stack_chk_init\n" // initialize stack protector
|
||||
#ifdef _NOLIBC_STACKPROTECTOR
|
||||
"call __stack_chk_init\n" /* initialize stack protector */
|
||||
#endif
|
||||
"pop %rdi\n" // argc (first arg, %rdi)
|
||||
"mov %rsp, %rsi\n" // argv[] (second arg, %rsi)
|
||||
"lea 8(%rsi,%rdi,8),%rdx\n" // then a NULL then envp (third arg, %rdx)
|
||||
"mov %rdx, environ\n" // save environ
|
||||
"xor %ebp, %ebp\n" // zero the stack frame
|
||||
"mov %rdx, %rax\n" // search for auxv (follows NULL after last env)
|
||||
"pop %rdi\n" /* argc (first arg, %rdi) */
|
||||
"mov %rsp, %rsi\n" /* argv[] (second arg, %rsi) */
|
||||
"lea 8(%rsi,%rdi,8),%rdx\n" /* then a NULL then envp (third arg, %rdx) */
|
||||
"mov %rdx, environ\n" /* save environ */
|
||||
"xor %ebp, %ebp\n" /* zero the stack frame */
|
||||
"mov %rdx, %rax\n" /* search for auxv (follows NULL after last env) */
|
||||
"0:\n"
|
||||
"add $8, %rax\n" // search for auxv using rax, it follows the
|
||||
"cmp -8(%rax), %rbp\n" // ... NULL after last env (rbp is zero here)
|
||||
"add $8, %rax\n" /* search for auxv using rax, it follows the */
|
||||
"cmp -8(%rax), %rbp\n" /* ... NULL after last env (rbp is zero here) */
|
||||
"jnz 0b\n"
|
||||
"mov %rax, _auxv\n" // save it into _auxv
|
||||
"and $-16, %rsp\n" // x86 ABI : esp must be 16-byte aligned before call
|
||||
"call main\n" // main() returns the status code, we'll exit with it.
|
||||
"mov %eax, %edi\n" // retrieve exit code (32 bit)
|
||||
"mov $60, %eax\n" // NR_exit == 60
|
||||
"syscall\n" // really exit
|
||||
"hlt\n" // ensure it does not return
|
||||
"mov %rax, _auxv\n" /* save it into _auxv */
|
||||
"and $-16, %rsp\n" /* x86 ABI : esp must be 16-byte aligned before call */
|
||||
"call main\n" /* main() returns the status code, we'll exit with it. */
|
||||
"mov %eax, %edi\n" /* retrieve exit code (32 bit) */
|
||||
"mov $60, %eax\n" /* NR_exit == 60 */
|
||||
"syscall\n" /* really exit */
|
||||
"hlt\n" /* ensure it does not return */
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#endif // _NOLIBC_ARCH_X86_64_H
|
||||
#endif /* _NOLIBC_ARCH_X86_64_H */
|
||||
|
@ -7,7 +7,7 @@
|
||||
* 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 pint). So at the stack pointer we find argc.
|
||||
* 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.
|
||||
*/
|
||||
|
25
tools/include/nolibc/compiler.h
Normal file
25
tools/include/nolibc/compiler.h
Normal file
@ -0,0 +1,25 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
|
||||
/*
|
||||
* NOLIBC compiler support header
|
||||
* Copyright (C) 2023 Thomas Weißschuh <linux@weissschuh.net>
|
||||
*/
|
||||
#ifndef _NOLIBC_COMPILER_H
|
||||
#define _NOLIBC_COMPILER_H
|
||||
|
||||
#if defined(__SSP__) || defined(__SSP_STRONG__) || defined(__SSP_ALL__) || defined(__SSP_EXPLICIT__)
|
||||
|
||||
#define _NOLIBC_STACKPROTECTOR
|
||||
|
||||
#endif /* defined(__SSP__) ... */
|
||||
|
||||
#if defined(__has_attribute)
|
||||
# if __has_attribute(no_stack_protector)
|
||||
# define __no_stack_protector __attribute__((no_stack_protector))
|
||||
# else
|
||||
# define __no_stack_protector __attribute__((__optimize__("-fno-stack-protector")))
|
||||
# endif
|
||||
#else
|
||||
# define __no_stack_protector __attribute__((__optimize__("-fno-stack-protector")))
|
||||
#endif /* defined(__has_attribute) */
|
||||
|
||||
#endif /* _NOLIBC_COMPILER_H */
|
@ -99,11 +99,11 @@
|
||||
#include "sys.h"
|
||||
#include "ctype.h"
|
||||
#include "signal.h"
|
||||
#include "unistd.h"
|
||||
#include "stdio.h"
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
#include "time.h"
|
||||
#include "unistd.h"
|
||||
#include "stackprotector.h"
|
||||
|
||||
/* Used by programs to avoid std includes */
|
||||
|
@ -7,13 +7,9 @@
|
||||
#ifndef _NOLIBC_STACKPROTECTOR_H
|
||||
#define _NOLIBC_STACKPROTECTOR_H
|
||||
|
||||
#include "arch.h"
|
||||
#include "compiler.h"
|
||||
|
||||
#if defined(NOLIBC_STACKPROTECTOR)
|
||||
|
||||
#if !defined(__ARCH_SUPPORTS_STACK_PROTECTOR)
|
||||
#error "nolibc does not support stack protectors on this arch"
|
||||
#endif
|
||||
#if defined(_NOLIBC_STACKPROTECTOR)
|
||||
|
||||
#include "sys.h"
|
||||
#include "stdlib.h"
|
||||
@ -41,13 +37,14 @@ void __stack_chk_fail_local(void)
|
||||
__attribute__((weak,section(".data.nolibc_stack_chk")))
|
||||
uintptr_t __stack_chk_guard;
|
||||
|
||||
__attribute__((weak,no_stack_protector,section(".text.nolibc_stack_chk")))
|
||||
__attribute__((weak,section(".text.nolibc_stack_chk"))) __no_stack_protector
|
||||
void __stack_chk_init(void)
|
||||
{
|
||||
my_syscall3(__NR_getrandom, &__stack_chk_guard, sizeof(__stack_chk_guard), 0);
|
||||
/* a bit more randomness in case getrandom() fails */
|
||||
__stack_chk_guard ^= (uintptr_t) &__stack_chk_guard;
|
||||
/* a bit more randomness in case getrandom() fails, ensure the guard is never 0 */
|
||||
if (__stack_chk_guard != (uintptr_t) &__stack_chk_guard)
|
||||
__stack_chk_guard ^= (uintptr_t) &__stack_chk_guard;
|
||||
}
|
||||
#endif // defined(NOLIBC_STACKPROTECTOR)
|
||||
#endif /* defined(_NOLIBC_STACKPROTECTOR) */
|
||||
|
||||
#endif // _NOLIBC_STACKPROTECTOR_H
|
||||
#endif /* _NOLIBC_STACKPROTECTOR_H */
|
||||
|
@ -36,8 +36,8 @@ typedef ssize_t int_fast16_t;
|
||||
typedef size_t uint_fast16_t;
|
||||
typedef ssize_t int_fast32_t;
|
||||
typedef size_t uint_fast32_t;
|
||||
typedef ssize_t int_fast64_t;
|
||||
typedef size_t uint_fast64_t;
|
||||
typedef int64_t int_fast64_t;
|
||||
typedef uint64_t uint_fast64_t;
|
||||
|
||||
typedef int64_t intmax_t;
|
||||
typedef uint64_t uintmax_t;
|
||||
@ -84,16 +84,30 @@ typedef uint64_t uintmax_t;
|
||||
#define INT_FAST8_MIN INT8_MIN
|
||||
#define INT_FAST16_MIN INTPTR_MIN
|
||||
#define INT_FAST32_MIN INTPTR_MIN
|
||||
#define INT_FAST64_MIN INTPTR_MIN
|
||||
#define INT_FAST64_MIN INT64_MIN
|
||||
|
||||
#define INT_FAST8_MAX INT8_MAX
|
||||
#define INT_FAST16_MAX INTPTR_MAX
|
||||
#define INT_FAST32_MAX INTPTR_MAX
|
||||
#define INT_FAST64_MAX INTPTR_MAX
|
||||
#define INT_FAST64_MAX INT64_MAX
|
||||
|
||||
#define UINT_FAST8_MAX UINT8_MAX
|
||||
#define UINT_FAST16_MAX SIZE_MAX
|
||||
#define UINT_FAST32_MAX SIZE_MAX
|
||||
#define UINT_FAST64_MAX SIZE_MAX
|
||||
#define UINT_FAST64_MAX UINT64_MAX
|
||||
|
||||
#ifndef INT_MIN
|
||||
#define INT_MIN (-__INT_MAX__ - 1)
|
||||
#endif
|
||||
#ifndef INT_MAX
|
||||
#define INT_MAX __INT_MAX__
|
||||
#endif
|
||||
|
||||
#ifndef LONG_MIN
|
||||
#define LONG_MIN (-__LONG_MAX__ - 1)
|
||||
#endif
|
||||
#ifndef LONG_MAX
|
||||
#define LONG_MAX __LONG_MAX__
|
||||
#endif
|
||||
|
||||
#endif /* _NOLIBC_STDINT_H */
|
||||
|
@ -21,17 +21,75 @@
|
||||
#define EOF (-1)
|
||||
#endif
|
||||
|
||||
/* just define FILE as a non-empty type */
|
||||
/* just define FILE as a non-empty type. The value of the pointer gives
|
||||
* the FD: FILE=~fd for fd>=0 or NULL for fd<0. This way positive FILE
|
||||
* are immediately identified as abnormal entries (i.e. possible copies
|
||||
* of valid pointers to something else).
|
||||
*/
|
||||
typedef struct FILE {
|
||||
char dummy[1];
|
||||
} FILE;
|
||||
|
||||
/* We define the 3 common stdio files as constant invalid pointers that
|
||||
* are easily recognized.
|
||||
*/
|
||||
static __attribute__((unused)) FILE* const stdin = (FILE*)-3;
|
||||
static __attribute__((unused)) FILE* const stdout = (FILE*)-2;
|
||||
static __attribute__((unused)) FILE* const stderr = (FILE*)-1;
|
||||
static __attribute__((unused)) FILE* const stdin = (FILE*)(intptr_t)~STDIN_FILENO;
|
||||
static __attribute__((unused)) FILE* const stdout = (FILE*)(intptr_t)~STDOUT_FILENO;
|
||||
static __attribute__((unused)) FILE* const stderr = (FILE*)(intptr_t)~STDERR_FILENO;
|
||||
|
||||
/* provides a FILE* equivalent of fd. The mode is ignored. */
|
||||
static __attribute__((unused))
|
||||
FILE *fdopen(int fd, const char *mode __attribute__((unused)))
|
||||
{
|
||||
if (fd < 0) {
|
||||
SET_ERRNO(EBADF);
|
||||
return NULL;
|
||||
}
|
||||
return (FILE*)(intptr_t)~fd;
|
||||
}
|
||||
|
||||
/* provides the fd of stream. */
|
||||
static __attribute__((unused))
|
||||
int fileno(FILE *stream)
|
||||
{
|
||||
intptr_t i = (intptr_t)stream;
|
||||
|
||||
if (i >= 0) {
|
||||
SET_ERRNO(EBADF);
|
||||
return -1;
|
||||
}
|
||||
return ~i;
|
||||
}
|
||||
|
||||
/* flush a stream. */
|
||||
static __attribute__((unused))
|
||||
int fflush(FILE *stream)
|
||||
{
|
||||
intptr_t i = (intptr_t)stream;
|
||||
|
||||
/* NULL is valid here. */
|
||||
if (i > 0) {
|
||||
SET_ERRNO(EBADF);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Don't do anything, nolibc does not support buffering. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* flush a stream. */
|
||||
static __attribute__((unused))
|
||||
int fclose(FILE *stream)
|
||||
{
|
||||
intptr_t i = (intptr_t)stream;
|
||||
|
||||
if (i >= 0) {
|
||||
SET_ERRNO(EBADF);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (close(~i))
|
||||
return EOF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* getc(), fgetc(), getchar() */
|
||||
|
||||
@ -41,14 +99,8 @@ static __attribute__((unused))
|
||||
int fgetc(FILE* stream)
|
||||
{
|
||||
unsigned char ch;
|
||||
int fd;
|
||||
|
||||
if (stream < stdin || stream > stderr)
|
||||
return EOF;
|
||||
|
||||
fd = 3 + (long)stream;
|
||||
|
||||
if (read(fd, &ch, 1) <= 0)
|
||||
if (read(fileno(stream), &ch, 1) <= 0)
|
||||
return EOF;
|
||||
return ch;
|
||||
}
|
||||
@ -68,14 +120,8 @@ static __attribute__((unused))
|
||||
int fputc(int c, FILE* stream)
|
||||
{
|
||||
unsigned char ch = c;
|
||||
int fd;
|
||||
|
||||
if (stream < stdin || stream > stderr)
|
||||
return EOF;
|
||||
|
||||
fd = 3 + (long)stream;
|
||||
|
||||
if (write(fd, &ch, 1) <= 0)
|
||||
if (write(fileno(stream), &ch, 1) <= 0)
|
||||
return EOF;
|
||||
return ch;
|
||||
}
|
||||
@ -96,12 +142,7 @@ static __attribute__((unused))
|
||||
int _fwrite(const void *buf, size_t size, FILE *stream)
|
||||
{
|
||||
ssize_t ret;
|
||||
int fd;
|
||||
|
||||
if (stream < stdin || stream > stderr)
|
||||
return EOF;
|
||||
|
||||
fd = 3 + (long)stream;
|
||||
int fd = fileno(stream);
|
||||
|
||||
while (size) {
|
||||
ret = write(fd, buf, size);
|
||||
|
@ -102,7 +102,7 @@ char *_getenv(const char *name, char **environ)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline __attribute__((unused,always_inline))
|
||||
static __inline__ __attribute__((unused,always_inline))
|
||||
char *getenv(const char *name)
|
||||
{
|
||||
extern char **environ;
|
||||
@ -231,7 +231,7 @@ int utoh_r(unsigned long in, char *buffer)
|
||||
/* converts unsigned long <in> to an hex string using the static itoa_buffer
|
||||
* and returns the pointer to that string.
|
||||
*/
|
||||
static inline __attribute__((unused))
|
||||
static __inline__ __attribute__((unused))
|
||||
char *utoh(unsigned long in)
|
||||
{
|
||||
utoh_r(in, itoa_buffer);
|
||||
@ -293,7 +293,7 @@ int itoa_r(long in, char *buffer)
|
||||
/* for historical compatibility, same as above but returns the pointer to the
|
||||
* buffer.
|
||||
*/
|
||||
static inline __attribute__((unused))
|
||||
static __inline__ __attribute__((unused))
|
||||
char *ltoa_r(long in, char *buffer)
|
||||
{
|
||||
itoa_r(in, buffer);
|
||||
@ -303,7 +303,7 @@ char *ltoa_r(long in, char *buffer)
|
||||
/* converts long integer <in> to a string using the static itoa_buffer and
|
||||
* returns the pointer to that string.
|
||||
*/
|
||||
static inline __attribute__((unused))
|
||||
static __inline__ __attribute__((unused))
|
||||
char *itoa(long in)
|
||||
{
|
||||
itoa_r(in, itoa_buffer);
|
||||
@ -313,7 +313,7 @@ char *itoa(long in)
|
||||
/* converts long integer <in> to a string using the static itoa_buffer and
|
||||
* returns the pointer to that string. Same as above, for compatibility.
|
||||
*/
|
||||
static inline __attribute__((unused))
|
||||
static __inline__ __attribute__((unused))
|
||||
char *ltoa(long in)
|
||||
{
|
||||
itoa_r(in, itoa_buffer);
|
||||
@ -323,7 +323,7 @@ char *ltoa(long in)
|
||||
/* converts unsigned long integer <in> to a string using the static itoa_buffer
|
||||
* and returns the pointer to that string.
|
||||
*/
|
||||
static inline __attribute__((unused))
|
||||
static __inline__ __attribute__((unused))
|
||||
char *utoa(unsigned long in)
|
||||
{
|
||||
utoa_r(in, itoa_buffer);
|
||||
@ -367,7 +367,7 @@ int u64toh_r(uint64_t in, char *buffer)
|
||||
/* converts uint64_t <in> to an hex string using the static itoa_buffer and
|
||||
* returns the pointer to that string.
|
||||
*/
|
||||
static inline __attribute__((unused))
|
||||
static __inline__ __attribute__((unused))
|
||||
char *u64toh(uint64_t in)
|
||||
{
|
||||
u64toh_r(in, itoa_buffer);
|
||||
@ -429,7 +429,7 @@ int i64toa_r(int64_t in, char *buffer)
|
||||
/* converts int64_t <in> to a string using the static itoa_buffer and returns
|
||||
* the pointer to that string.
|
||||
*/
|
||||
static inline __attribute__((unused))
|
||||
static __inline__ __attribute__((unused))
|
||||
char *i64toa(int64_t in)
|
||||
{
|
||||
i64toa_r(in, itoa_buffer);
|
||||
@ -439,7 +439,7 @@ char *i64toa(int64_t in)
|
||||
/* converts uint64_t <in> to a string using the static itoa_buffer and returns
|
||||
* the pointer to that string.
|
||||
*/
|
||||
static inline __attribute__((unused))
|
||||
static __inline__ __attribute__((unused))
|
||||
char *u64toa(uint64_t in)
|
||||
{
|
||||
u64toa_r(in, itoa_buffer);
|
||||
|
@ -90,7 +90,7 @@ void *memset(void *dst, int b, size_t len)
|
||||
|
||||
while (len--) {
|
||||
/* prevent gcc from recognizing memset() here */
|
||||
asm volatile("");
|
||||
__asm__ volatile("");
|
||||
*(p++) = b;
|
||||
}
|
||||
return dst;
|
||||
@ -139,7 +139,7 @@ size_t strlen(const char *str)
|
||||
size_t len;
|
||||
|
||||
for (len = 0; str[len]; len++)
|
||||
asm("");
|
||||
__asm__("");
|
||||
return len;
|
||||
}
|
||||
|
||||
|
@ -12,15 +12,17 @@
|
||||
|
||||
/* system includes */
|
||||
#include <asm/unistd.h>
|
||||
#include <asm/signal.h> // for SIGCHLD
|
||||
#include <asm/signal.h> /* for SIGCHLD */
|
||||
#include <asm/ioctls.h>
|
||||
#include <asm/mman.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/loop.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/auxvec.h>
|
||||
#include <linux/fcntl.h> // for O_* and AT_*
|
||||
#include <linux/stat.h> // for statx()
|
||||
#include <linux/fcntl.h> /* for O_* and AT_* */
|
||||
#include <linux/stat.h> /* for statx() */
|
||||
#include <linux/reboot.h> /* for LINUX_REBOOT_* */
|
||||
#include <linux/prctl.h>
|
||||
|
||||
#include "arch.h"
|
||||
#include "errno.h"
|
||||
@ -322,7 +324,7 @@ static __attribute__((noreturn,unused))
|
||||
void sys_exit(int status)
|
||||
{
|
||||
my_syscall1(__NR_exit, status & 255);
|
||||
while(1); // shut the "noreturn" warnings.
|
||||
while(1); /* shut the "noreturn" warnings. */
|
||||
}
|
||||
|
||||
static __attribute__((noreturn,unused))
|
||||
@ -336,6 +338,7 @@ void exit(int status)
|
||||
* pid_t fork(void);
|
||||
*/
|
||||
|
||||
#ifndef sys_fork
|
||||
static __attribute__((unused))
|
||||
pid_t sys_fork(void)
|
||||
{
|
||||
@ -351,6 +354,7 @@ pid_t sys_fork(void)
|
||||
#error Neither __NR_clone nor __NR_fork defined, cannot implement sys_fork()
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static __attribute__((unused))
|
||||
pid_t fork(void)
|
||||
@ -858,7 +862,7 @@ int open(const char *path, int flags, ...)
|
||||
va_list args;
|
||||
|
||||
va_start(args, flags);
|
||||
mode = va_arg(args, mode_t);
|
||||
mode = va_arg(args, int);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
@ -872,6 +876,32 @@ int open(const char *path, int flags, ...)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* int prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||
* unsigned long arg4, unsigned long arg5);
|
||||
*/
|
||||
|
||||
static __attribute__((unused))
|
||||
int sys_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||
unsigned long arg4, unsigned long arg5)
|
||||
{
|
||||
return my_syscall5(__NR_prctl, option, arg2, arg3, arg4, arg5);
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
int prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||
unsigned long arg4, unsigned long arg5)
|
||||
{
|
||||
int ret = sys_prctl(option, arg2, arg3, arg4, arg5);
|
||||
|
||||
if (ret < 0) {
|
||||
SET_ERRNO(-ret);
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* int pivot_root(const char *new, const char *old);
|
||||
*/
|
||||
@ -909,7 +939,7 @@ int sys_poll(struct pollfd *fds, int nfds, int timeout)
|
||||
t.tv_sec = timeout / 1000;
|
||||
t.tv_nsec = (timeout % 1000) * 1000000;
|
||||
}
|
||||
return my_syscall4(__NR_ppoll, fds, nfds, (timeout >= 0) ? &t : NULL, NULL);
|
||||
return my_syscall5(__NR_ppoll, fds, nfds, (timeout >= 0) ? &t : NULL, NULL, 0);
|
||||
#elif defined(__NR_poll)
|
||||
return my_syscall3(__NR_poll, fds, nfds, timeout);
|
||||
#else
|
||||
@ -1131,23 +1161,26 @@ int sys_stat(const char *path, struct stat *buf)
|
||||
long ret;
|
||||
|
||||
ret = sys_statx(AT_FDCWD, path, AT_NO_AUTOMOUNT, STATX_BASIC_STATS, &statx);
|
||||
buf->st_dev = ((statx.stx_dev_minor & 0xff)
|
||||
| (statx.stx_dev_major << 8)
|
||||
| ((statx.stx_dev_minor & ~0xff) << 12));
|
||||
buf->st_ino = statx.stx_ino;
|
||||
buf->st_mode = statx.stx_mode;
|
||||
buf->st_nlink = statx.stx_nlink;
|
||||
buf->st_uid = statx.stx_uid;
|
||||
buf->st_gid = statx.stx_gid;
|
||||
buf->st_rdev = ((statx.stx_rdev_minor & 0xff)
|
||||
| (statx.stx_rdev_major << 8)
|
||||
| ((statx.stx_rdev_minor & ~0xff) << 12));
|
||||
buf->st_size = statx.stx_size;
|
||||
buf->st_blksize = statx.stx_blksize;
|
||||
buf->st_blocks = statx.stx_blocks;
|
||||
buf->st_atime = statx.stx_atime.tv_sec;
|
||||
buf->st_mtime = statx.stx_mtime.tv_sec;
|
||||
buf->st_ctime = statx.stx_ctime.tv_sec;
|
||||
buf->st_dev = ((statx.stx_dev_minor & 0xff)
|
||||
| (statx.stx_dev_major << 8)
|
||||
| ((statx.stx_dev_minor & ~0xff) << 12));
|
||||
buf->st_ino = statx.stx_ino;
|
||||
buf->st_mode = statx.stx_mode;
|
||||
buf->st_nlink = statx.stx_nlink;
|
||||
buf->st_uid = statx.stx_uid;
|
||||
buf->st_gid = statx.stx_gid;
|
||||
buf->st_rdev = ((statx.stx_rdev_minor & 0xff)
|
||||
| (statx.stx_rdev_major << 8)
|
||||
| ((statx.stx_rdev_minor & ~0xff) << 12));
|
||||
buf->st_size = statx.stx_size;
|
||||
buf->st_blksize = statx.stx_blksize;
|
||||
buf->st_blocks = statx.stx_blocks;
|
||||
buf->st_atim.tv_sec = statx.stx_atime.tv_sec;
|
||||
buf->st_atim.tv_nsec = statx.stx_atime.tv_nsec;
|
||||
buf->st_mtim.tv_sec = statx.stx_mtime.tv_sec;
|
||||
buf->st_mtim.tv_nsec = statx.stx_mtime.tv_nsec;
|
||||
buf->st_ctim.tv_sec = statx.stx_ctime.tv_sec;
|
||||
buf->st_ctim.tv_nsec = statx.stx_ctime.tv_nsec;
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
@ -1165,19 +1198,22 @@ int sys_stat(const char *path, struct stat *buf)
|
||||
#else
|
||||
#error Neither __NR_newfstatat nor __NR_stat defined, cannot implement sys_stat()
|
||||
#endif
|
||||
buf->st_dev = stat.st_dev;
|
||||
buf->st_ino = stat.st_ino;
|
||||
buf->st_mode = stat.st_mode;
|
||||
buf->st_nlink = stat.st_nlink;
|
||||
buf->st_uid = stat.st_uid;
|
||||
buf->st_gid = stat.st_gid;
|
||||
buf->st_rdev = stat.st_rdev;
|
||||
buf->st_size = stat.st_size;
|
||||
buf->st_blksize = stat.st_blksize;
|
||||
buf->st_blocks = stat.st_blocks;
|
||||
buf->st_atime = stat.st_atime;
|
||||
buf->st_mtime = stat.st_mtime;
|
||||
buf->st_ctime = stat.st_ctime;
|
||||
buf->st_dev = stat.st_dev;
|
||||
buf->st_ino = stat.st_ino;
|
||||
buf->st_mode = stat.st_mode;
|
||||
buf->st_nlink = stat.st_nlink;
|
||||
buf->st_uid = stat.st_uid;
|
||||
buf->st_gid = stat.st_gid;
|
||||
buf->st_rdev = stat.st_rdev;
|
||||
buf->st_size = stat.st_size;
|
||||
buf->st_blksize = stat.st_blksize;
|
||||
buf->st_blocks = stat.st_blocks;
|
||||
buf->st_atim.tv_sec = stat.st_atime;
|
||||
buf->st_atim.tv_nsec = stat.st_atime_nsec;
|
||||
buf->st_mtim.tv_sec = stat.st_mtime;
|
||||
buf->st_mtim.tv_nsec = stat.st_mtime_nsec;
|
||||
buf->st_ctim.tv_sec = stat.st_ctime;
|
||||
buf->st_ctim.tv_nsec = stat.st_ctime_nsec;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
@ -1365,6 +1401,29 @@ ssize_t write(int fd, const void *buf, size_t count)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* int memfd_create(const char *name, unsigned int flags);
|
||||
*/
|
||||
|
||||
static __attribute__((unused))
|
||||
int sys_memfd_create(const char *name, unsigned int flags)
|
||||
{
|
||||
return my_syscall2(__NR_memfd_create, name, flags);
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
int memfd_create(const char *name, unsigned int flags)
|
||||
{
|
||||
ssize_t ret = sys_memfd_create(name, flags);
|
||||
|
||||
if (ret < 0) {
|
||||
SET_ERRNO(-ret);
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* make sure to include all global symbols */
|
||||
#include "nolibc.h"
|
||||
|
||||
|
@ -86,14 +86,6 @@
|
||||
#define SEEK_CUR 1
|
||||
#define SEEK_END 2
|
||||
|
||||
/* cmd for reboot() */
|
||||
#define LINUX_REBOOT_MAGIC1 0xfee1dead
|
||||
#define LINUX_REBOOT_MAGIC2 0x28121969
|
||||
#define LINUX_REBOOT_CMD_HALT 0xcdef0123
|
||||
#define LINUX_REBOOT_CMD_POWER_OFF 0x4321fedc
|
||||
#define LINUX_REBOOT_CMD_RESTART 0x01234567
|
||||
#define LINUX_REBOOT_CMD_SW_SUSPEND 0xd000fce2
|
||||
|
||||
/* Macros used on waitpid()'s return status */
|
||||
#define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
|
||||
#define WIFEXITED(status) (((status) & 0x7f) == 0)
|
||||
@ -206,9 +198,9 @@ struct stat {
|
||||
off_t st_size; /* total size, in bytes */
|
||||
blksize_t st_blksize; /* blocksize for file system I/O */
|
||||
blkcnt_t st_blocks; /* number of 512B blocks allocated */
|
||||
time_t st_atime; /* time of last access */
|
||||
time_t st_mtime; /* time of last modification */
|
||||
time_t st_ctime; /* time of last status change */
|
||||
union { time_t st_atime; struct timespec st_atim; }; /* time of last access */
|
||||
union { time_t st_mtime; struct timespec st_mtim; }; /* time of last modification */
|
||||
union { time_t st_ctime; struct timespec st_ctim; }; /* time of last status change */
|
||||
};
|
||||
|
||||
/* WARNING, it only deals with the 4096 first majors and 256 first minors */
|
||||
|
@ -56,6 +56,21 @@ int tcsetpgrp(int fd, pid_t pid)
|
||||
return ioctl(fd, TIOCSPGRP, &pid);
|
||||
}
|
||||
|
||||
#define _syscall(N, ...) \
|
||||
({ \
|
||||
long _ret = my_syscall##N(__VA_ARGS__); \
|
||||
if (_ret < 0) { \
|
||||
SET_ERRNO(-_ret); \
|
||||
_ret = -1; \
|
||||
} \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define _syscall_narg(...) __syscall_narg(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0)
|
||||
#define __syscall_narg(_0, _1, _2, _3, _4, _5, _6, N, ...) N
|
||||
#define _syscall_n(N, ...) _syscall(N, __VA_ARGS__)
|
||||
#define syscall(...) _syscall_n(_syscall_narg(__VA_ARGS__), ##__VA_ARGS__)
|
||||
|
||||
/* make sure to include all global symbols */
|
||||
#include "nolibc.h"
|
||||
|
||||
|
1
tools/testing/selftests/nolibc/.gitignore
vendored
1
tools/testing/selftests/nolibc/.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
/initramfs/
|
||||
/libc-test
|
||||
/nolibc-test
|
||||
/run.out
|
||||
/sysroot/
|
||||
|
@ -64,7 +64,7 @@ QEMU_ARGS_mips = -M malta -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)"
|
||||
QEMU_ARGS_riscv = -M virt -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)"
|
||||
QEMU_ARGS_s390 = -M s390-ccw-virtio -m 1G -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)"
|
||||
QEMU_ARGS_loongarch = -M virt -append "console=ttyS0,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)"
|
||||
QEMU_ARGS = $(QEMU_ARGS_$(ARCH))
|
||||
QEMU_ARGS = $(QEMU_ARGS_$(ARCH)) $(QEMU_ARGS_EXTRA)
|
||||
|
||||
# OUTPUT is only set when run from the main makefile, otherwise
|
||||
# it defaults to this nolibc directory.
|
||||
@ -76,16 +76,12 @@ else
|
||||
Q=@
|
||||
endif
|
||||
|
||||
CFLAGS_STACKPROTECTOR = -DNOLIBC_STACKPROTECTOR \
|
||||
$(call cc-option,-mstack-protector-guard=global) \
|
||||
$(call cc-option,-fstack-protector-all)
|
||||
CFLAGS_STKP_i386 = $(CFLAGS_STACKPROTECTOR)
|
||||
CFLAGS_STKP_x86_64 = $(CFLAGS_STACKPROTECTOR)
|
||||
CFLAGS_STKP_x86 = $(CFLAGS_STACKPROTECTOR)
|
||||
CFLAGS_s390 = -m64
|
||||
CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables \
|
||||
CFLAGS_mips = -EL
|
||||
CFLAGS_STACKPROTECTOR ?= $(call cc-option,-mstack-protector-guard=global $(call cc-option,-fstack-protector-all))
|
||||
CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables -std=c89 \
|
||||
$(call cc-option,-fno-stack-protector) \
|
||||
$(CFLAGS_STKP_$(ARCH)) $(CFLAGS_$(ARCH))
|
||||
$(CFLAGS_$(ARCH)) $(CFLAGS_STACKPROTECTOR)
|
||||
LDFLAGS := -s
|
||||
|
||||
help:
|
||||
@ -94,6 +90,7 @@ help:
|
||||
@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 \$$ARCH, \$$TEST)"
|
||||
@echo " initramfs prepare the initramfs with nolibc-test"
|
||||
@echo " defconfig create a fresh new default config (uses \$$ARCH)"
|
||||
@ -128,10 +125,16 @@ nolibc-test: nolibc-test.c sysroot/$(ARCH)/include
|
||||
$(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ \
|
||||
-nostdlib -static -Isysroot/$(ARCH)/include $< -lgcc
|
||||
|
||||
libc-test: nolibc-test.c
|
||||
$(QUIET_CC)$(CC) -o $@ $<
|
||||
|
||||
# qemu user-land test
|
||||
run-user: nolibc-test
|
||||
$(Q)qemu-$(QEMU_ARCH) ./nolibc-test > "$(CURDIR)/run.out" || :
|
||||
$(Q)grep -w FAIL "$(CURDIR)/run.out" && echo "See all results in $(CURDIR)/run.out" || echo "$$(grep -c ^[0-9].*OK $(CURDIR)/run.out) test(s) passed."
|
||||
$(Q)awk '/\[OK\][\r]*$$/{p++} /\[FAIL\][\r]*$$/{f++} /\[SKIPPED\][\r]*$$/{s++} \
|
||||
END{ printf("%d test(s) passed, %d skipped, %d failed.", p, s, f); \
|
||||
if (s+f > 0) printf(" See all results in %s\n", ARGV[1]); else print; }' \
|
||||
$(CURDIR)/run.out
|
||||
|
||||
initramfs: nolibc-test
|
||||
$(QUIET_MKDIR)mkdir -p initramfs
|
||||
@ -147,18 +150,26 @@ kernel: 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"
|
||||
$(Q)grep -w FAIL "$(CURDIR)/run.out" && echo "See all results in $(CURDIR)/run.out" || echo "$$(grep -c ^[0-9].*OK $(CURDIR)/run.out) test(s) passed."
|
||||
$(Q)awk '/\[OK\][\r]*$$/{p++} /\[FAIL\][\r]*$$/{f++} /\[SKIPPED\][\r]*$$/{s++} \
|
||||
END{ printf("%d test(s) passed, %d skipped, %d failed.", p, s, f); \
|
||||
if (s+f > 0) printf(" See all results in %s\n", ARGV[1]); else print; }' \
|
||||
$(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)grep -w FAIL "$(CURDIR)/run.out" && echo "See all results in $(CURDIR)/run.out" || echo "$$(grep -c ^[0-9].*OK $(CURDIR)/run.out) test(s) passed."
|
||||
$(Q)awk '/\[OK\][\r]*$$/{p++} /\[FAIL\][\r]*$$/{f++} /\[SKIPPED\][\r]*$$/{s++} \
|
||||
END{ printf("%d test(s) passed, %d skipped, %d failed.", p, s, f); \
|
||||
if (s+f > 0) printf(" See all results in %s\n", ARGV[1]); else print; }' \
|
||||
$(CURDIR)/run.out
|
||||
|
||||
clean:
|
||||
$(call QUIET_CLEAN, sysroot)
|
||||
$(Q)rm -rf sysroot
|
||||
$(call QUIET_CLEAN, nolibc-test)
|
||||
$(Q)rm -f nolibc-test
|
||||
$(call QUIET_CLEAN, libc-test)
|
||||
$(Q)rm -f libc-test
|
||||
$(call QUIET_CLEAN, initramfs)
|
||||
$(Q)rm -rf initramfs
|
||||
$(call QUIET_CLEAN, run.out)
|
||||
|
@ -1,10 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
/* platform-specific include files coming from the compiler */
|
||||
#include <limits.h>
|
||||
|
||||
/* libc-specific include files
|
||||
* The program may be built in 3 ways:
|
||||
* $(CC) -nostdlib -include /path/to/nolibc.h => NOLIBC already defined
|
||||
@ -20,7 +17,9 @@
|
||||
#include <linux/reboot.h>
|
||||
#include <sys/io.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
@ -34,7 +33,10 @@
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -43,8 +45,8 @@ char **environ;
|
||||
|
||||
/* definition of a series of tests */
|
||||
struct test {
|
||||
const char *name; // test name
|
||||
int (*func)(int min, int max); // handler
|
||||
const char *name; /* test name */
|
||||
int (*func)(int min, int max); /* handler */
|
||||
};
|
||||
|
||||
#ifndef _NOLIBC_STDLIB_H
|
||||
@ -103,24 +105,32 @@ const char *errorname(int err)
|
||||
CASE_ERR(EDOM);
|
||||
CASE_ERR(ERANGE);
|
||||
CASE_ERR(ENOSYS);
|
||||
CASE_ERR(EOVERFLOW);
|
||||
default:
|
||||
return itoa(err);
|
||||
}
|
||||
}
|
||||
|
||||
static void putcharn(char c, size_t n)
|
||||
{
|
||||
char buf[64];
|
||||
|
||||
memset(buf, c, n);
|
||||
buf[n] = '\0';
|
||||
fputs(buf, stdout);
|
||||
}
|
||||
|
||||
static int pad_spc(int llen, int cnt, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int len;
|
||||
int ret;
|
||||
|
||||
for (len = 0; len < cnt - llen; len++)
|
||||
putchar(' ');
|
||||
putcharn(' ', cnt - llen);
|
||||
|
||||
va_start(args, fmt);
|
||||
ret = vfprintf(stdout, fmt, args);
|
||||
va_end(args);
|
||||
return ret < 0 ? ret : ret + len;
|
||||
return ret < 0 ? ret : ret + cnt - llen;
|
||||
}
|
||||
|
||||
/* The tests below are intended to be used by the macroes, which evaluate
|
||||
@ -162,7 +172,7 @@ static int expect_eq(uint64_t expr, int llen, uint64_t val)
|
||||
{
|
||||
int ret = !(expr == val);
|
||||
|
||||
llen += printf(" = %lld ", expr);
|
||||
llen += printf(" = %lld ", (long long)expr);
|
||||
pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n");
|
||||
return ret;
|
||||
}
|
||||
@ -290,18 +300,24 @@ static int expect_sysne(int expr, int llen, int val)
|
||||
}
|
||||
|
||||
|
||||
#define EXPECT_SYSER(cond, expr, expret, experr) \
|
||||
do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_syserr(expr, expret, experr, llen); } while (0)
|
||||
#define EXPECT_SYSER2(cond, expr, expret, experr1, experr2) \
|
||||
do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_syserr2(expr, expret, experr1, experr2, llen); } while (0)
|
||||
|
||||
static int expect_syserr(int expr, int expret, int experr, int llen)
|
||||
#define EXPECT_SYSER(cond, expr, expret, experr) \
|
||||
EXPECT_SYSER2(cond, expr, expret, experr, 0)
|
||||
|
||||
static int expect_syserr2(int expr, int expret, int experr1, int experr2, int llen)
|
||||
{
|
||||
int ret = 0;
|
||||
int _errno = errno;
|
||||
|
||||
llen += printf(" = %d %s ", expr, errorname(_errno));
|
||||
if (expr != expret || _errno != experr) {
|
||||
if (expr != expret || (_errno != experr1 && _errno != experr2)) {
|
||||
ret = 1;
|
||||
llen += printf(" != (%d %s) ", expret, errorname(experr));
|
||||
if (experr2 == 0)
|
||||
llen += printf(" != (%d %s) ", expret, errorname(experr1));
|
||||
else
|
||||
llen += printf(" != (%d %s %s) ", expret, errorname(experr1), errorname(experr2));
|
||||
llen += pad_spc(llen, 64, "[FAIL]\n");
|
||||
} else {
|
||||
llen += pad_spc(llen, 64, " [OK]\n");
|
||||
@ -471,11 +487,60 @@ static int test_getpagesize(void)
|
||||
return !c;
|
||||
}
|
||||
|
||||
static int test_fork(void)
|
||||
{
|
||||
int status;
|
||||
pid_t pid;
|
||||
|
||||
/* flush the printf buffer to avoid child flush it */
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
|
||||
pid = fork();
|
||||
|
||||
switch (pid) {
|
||||
case -1:
|
||||
return 1;
|
||||
|
||||
case 0:
|
||||
exit(123);
|
||||
|
||||
default:
|
||||
pid = waitpid(pid, &status, 0);
|
||||
|
||||
return pid == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 123;
|
||||
}
|
||||
}
|
||||
|
||||
static int test_stat_timestamps(void)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (sizeof(st.st_atim.tv_sec) != sizeof(st.st_atime))
|
||||
return 1;
|
||||
|
||||
if (stat("/proc/self/", &st))
|
||||
return 1;
|
||||
|
||||
if (st.st_atim.tv_sec != st.st_atime || st.st_atim.tv_nsec > 1000000000)
|
||||
return 1;
|
||||
|
||||
if (st.st_mtim.tv_sec != st.st_mtime || st.st_mtim.tv_nsec > 1000000000)
|
||||
return 1;
|
||||
|
||||
if (st.st_ctim.tv_sec != st.st_ctime || st.st_ctim.tv_nsec > 1000000000)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Run syscall tests between IDs <min> and <max>.
|
||||
* Return 0 on success, non-zero on failure.
|
||||
*/
|
||||
int run_syscall(int min, int max)
|
||||
{
|
||||
struct timeval tv;
|
||||
struct timezone tz;
|
||||
struct stat stat_buf;
|
||||
int euid0;
|
||||
int proc;
|
||||
@ -491,7 +556,7 @@ int run_syscall(int min, int max)
|
||||
euid0 = geteuid() == 0;
|
||||
|
||||
for (test = min; test >= 0 && test <= max; test++) {
|
||||
int llen = 0; // line length
|
||||
int llen = 0; /* line length */
|
||||
|
||||
/* avoid leaving empty lines below, this will insert holes into
|
||||
* test numbers.
|
||||
@ -527,14 +592,11 @@ 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(fork); EXPECT_SYSZR(1, test_fork()); 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;
|
||||
CASE_TEST(gettimeofday_null); EXPECT_SYSZR(1, gettimeofday(NULL, NULL)); break;
|
||||
#ifdef NOLIBC
|
||||
CASE_TEST(gettimeofday_bad1); EXPECT_SYSER(1, gettimeofday((void *)1, NULL), -1, EFAULT); break;
|
||||
CASE_TEST(gettimeofday_bad2); EXPECT_SYSER(1, gettimeofday(NULL, (void *)1), -1, EFAULT); break;
|
||||
CASE_TEST(gettimeofday_bad2); EXPECT_SYSER(1, gettimeofday(NULL, (void *)1), -1, EFAULT); break;
|
||||
#endif
|
||||
CASE_TEST(gettimeofday_tv); EXPECT_SYSZR(1, gettimeofday(&tv, NULL)); break;
|
||||
CASE_TEST(gettimeofday_tv_tz);EXPECT_SYSZR(1, gettimeofday(&tv, &tz)); break;
|
||||
CASE_TEST(getpagesize); EXPECT_SYSZR(1, test_getpagesize()); break;
|
||||
CASE_TEST(ioctl_tiocinq); EXPECT_SYSZR(1, ioctl(0, TIOCINQ, &tmp)); break;
|
||||
CASE_TEST(ioctl_tiocinq); EXPECT_SYSZR(1, ioctl(0, TIOCINQ, &tmp)); break;
|
||||
@ -550,6 +612,7 @@ int run_syscall(int min, int max)
|
||||
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(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(sched_yield); EXPECT_SYSZR(1, sched_yield()); break;
|
||||
CASE_TEST(select_null); EXPECT_SYSZR(1, ({ struct timeval tv = { 0 }; select(0, NULL, NULL, NULL, &tv); })); break;
|
||||
@ -557,6 +620,7 @@ int run_syscall(int min, int max)
|
||||
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(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;
|
||||
CASE_TEST(unlink_blah); EXPECT_SYSER(1, unlink("/proc/self/blah"), -1, ENOENT); break;
|
||||
@ -565,6 +629,8 @@ 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(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 __LINE__:
|
||||
return ret; /* must be last */
|
||||
/* note: do not set any defaults so as to permit holes above */
|
||||
@ -581,7 +647,7 @@ int run_stdlib(int min, int max)
|
||||
void *p1, *p2;
|
||||
|
||||
for (test = min; test >= 0 && test <= max; test++) {
|
||||
int llen = 0; // line length
|
||||
int llen = 0; /* line length */
|
||||
|
||||
/* avoid leaving empty lines below, this will insert holes into
|
||||
* test numbers.
|
||||
@ -639,9 +705,9 @@ int run_stdlib(int min, int max)
|
||||
CASE_TEST(limit_int_fast32_min); EXPECT_EQ(1, INT_FAST32_MIN, (int_fast32_t) INTPTR_MIN); break;
|
||||
CASE_TEST(limit_int_fast32_max); EXPECT_EQ(1, INT_FAST32_MAX, (int_fast32_t) INTPTR_MAX); break;
|
||||
CASE_TEST(limit_uint_fast32_max); EXPECT_EQ(1, UINT_FAST32_MAX, (uint_fast32_t) UINTPTR_MAX); break;
|
||||
CASE_TEST(limit_int_fast64_min); EXPECT_EQ(1, INT_FAST64_MIN, (int_fast64_t) INTPTR_MIN); break;
|
||||
CASE_TEST(limit_int_fast64_max); EXPECT_EQ(1, INT_FAST64_MAX, (int_fast64_t) INTPTR_MAX); break;
|
||||
CASE_TEST(limit_uint_fast64_max); EXPECT_EQ(1, UINT_FAST64_MAX, (uint_fast64_t) UINTPTR_MAX); break;
|
||||
CASE_TEST(limit_int_fast64_min); EXPECT_EQ(1, INT_FAST64_MIN, (int_fast64_t) INT64_MIN); break;
|
||||
CASE_TEST(limit_int_fast64_max); EXPECT_EQ(1, INT_FAST64_MAX, (int_fast64_t) INT64_MAX); break;
|
||||
CASE_TEST(limit_uint_fast64_max); EXPECT_EQ(1, UINT_FAST64_MAX, (uint_fast64_t) UINT64_MAX); break;
|
||||
#if __SIZEOF_LONG__ == 8
|
||||
CASE_TEST(limit_intptr_min); EXPECT_EQ(1, INTPTR_MIN, (intptr_t) 0x8000000000000000LL); break;
|
||||
CASE_TEST(limit_intptr_max); EXPECT_EQ(1, INTPTR_MAX, (intptr_t) 0x7fffffffffffffffLL); break;
|
||||
@ -667,17 +733,98 @@ int run_stdlib(int min, int max)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
__attribute__((optnone))
|
||||
#elif defined(__GNUC__)
|
||||
__attribute__((optimize("O0")))
|
||||
#endif
|
||||
#define EXPECT_VFPRINTF(c, expected, fmt, ...) \
|
||||
ret += expect_vfprintf(llen, c, expected, fmt, ##__VA_ARGS__)
|
||||
|
||||
static int expect_vfprintf(int llen, size_t c, const char *expected, const char *fmt, ...)
|
||||
{
|
||||
int ret, fd, w, r;
|
||||
char buf[100];
|
||||
FILE *memfile;
|
||||
va_list args;
|
||||
|
||||
fd = memfd_create("vfprintf", 0);
|
||||
if (fd == -1) {
|
||||
pad_spc(llen, 64, "[FAIL]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
memfile = fdopen(fd, "w+");
|
||||
if (!memfile) {
|
||||
pad_spc(llen, 64, "[FAIL]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
va_start(args, fmt);
|
||||
w = vfprintf(memfile, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
if (w != c) {
|
||||
llen += printf(" written(%d) != %d", w, (int) c);
|
||||
pad_spc(llen, 64, "[FAIL]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fflush(memfile);
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
|
||||
r = read(fd, buf, sizeof(buf) - 1);
|
||||
buf[r] = '\0';
|
||||
|
||||
fclose(memfile);
|
||||
|
||||
if (r != w) {
|
||||
llen += printf(" written(%d) != read(%d)", w, r);
|
||||
pad_spc(llen, 64, "[FAIL]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
llen += printf(" \"%s\" = \"%s\"", expected, buf);
|
||||
ret = strncmp(expected, buf, c);
|
||||
|
||||
pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int run_vfprintf(int min, int max)
|
||||
{
|
||||
int test;
|
||||
int tmp;
|
||||
int ret = 0;
|
||||
void *p1, *p2;
|
||||
|
||||
for (test = min; test >= 0 && test <= max; test++) {
|
||||
int llen = 0; /* line length */
|
||||
|
||||
/* avoid leaving empty lines below, this will insert holes into
|
||||
* test numbers.
|
||||
*/
|
||||
switch (test + __LINE__ + 1) {
|
||||
CASE_TEST(empty); EXPECT_VFPRINTF(0, "", ""); break;
|
||||
CASE_TEST(simple); EXPECT_VFPRINTF(3, "foo", "foo"); break;
|
||||
CASE_TEST(string); EXPECT_VFPRINTF(3, "foo", "%s", "foo"); break;
|
||||
CASE_TEST(number); EXPECT_VFPRINTF(4, "1234", "%d", 1234); break;
|
||||
CASE_TEST(negnumber); EXPECT_VFPRINTF(5, "-1234", "%d", -1234); break;
|
||||
CASE_TEST(unsigned); EXPECT_VFPRINTF(5, "12345", "%u", 12345); break;
|
||||
CASE_TEST(char); EXPECT_VFPRINTF(1, "c", "%c", 'c'); break;
|
||||
CASE_TEST(hex); EXPECT_VFPRINTF(1, "f", "%x", 0xf); break;
|
||||
CASE_TEST(pointer); EXPECT_VFPRINTF(3, "0x1", "%p", (void *) 0x1); break;
|
||||
case __LINE__:
|
||||
return ret; /* must be last */
|
||||
/* note: do not set any defaults so as to permit holes above */
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int smash_stack(void)
|
||||
{
|
||||
char buf[100];
|
||||
volatile char *ptr = buf;
|
||||
size_t i;
|
||||
|
||||
for (size_t i = 0; i < 200; i++)
|
||||
buf[i] = 'P';
|
||||
for (i = 0; i < 200; i++)
|
||||
ptr[i] = 'P';
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -689,12 +836,20 @@ static int run_protection(int min, int max)
|
||||
|
||||
llen += printf("0 -fstackprotector ");
|
||||
|
||||
#if !defined(NOLIBC_STACKPROTECTOR)
|
||||
#if !defined(_NOLIBC_STACKPROTECTOR)
|
||||
llen += printf("not supported");
|
||||
pad_spc(llen, 64, "[SKIPPED]\n");
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
#if defined(_NOLIBC_STACKPROTECTOR)
|
||||
if (!__stack_chk_guard) {
|
||||
llen += printf("__stack_chk_guard not initialized");
|
||||
pad_spc(llen, 64, "[FAIL]\n");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
pid = -1;
|
||||
pid = fork();
|
||||
|
||||
@ -708,6 +863,7 @@ static int run_protection(int min, int max)
|
||||
close(STDOUT_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
|
||||
prctl(PR_SET_DUMPABLE, 0, 0, 0, 0);
|
||||
smash_stack();
|
||||
return 1;
|
||||
|
||||
@ -778,6 +934,7 @@ static const struct test test_names[] = {
|
||||
/* add new tests here */
|
||||
{ .name = "syscall", .func = run_syscall },
|
||||
{ .name = "stdlib", .func = run_stdlib },
|
||||
{ .name = "vfprintf", .func = run_vfprintf },
|
||||
{ .name = "protection", .func = run_protection },
|
||||
{ 0 }
|
||||
};
|
||||
@ -785,7 +942,7 @@ static const struct test test_names[] = {
|
||||
int main(int argc, char **argv, char **envp)
|
||||
{
|
||||
int min = 0;
|
||||
int max = __INT_MAX__;
|
||||
int max = INT_MAX;
|
||||
int ret = 0;
|
||||
int err;
|
||||
int idx;
|
||||
@ -833,7 +990,7 @@ int main(int argc, char **argv, char **envp)
|
||||
* here, which defaults to the full range.
|
||||
*/
|
||||
do {
|
||||
min = 0; max = __INT_MAX__;
|
||||
min = 0; max = INT_MAX;
|
||||
value = colon;
|
||||
if (value && *value) {
|
||||
colon = strchr(value, ':');
|
||||
@ -899,7 +1056,7 @@ int main(int argc, char **argv, char **envp)
|
||||
#else
|
||||
else if (ioperm(0x501, 1, 1) == 0)
|
||||
#endif
|
||||
asm volatile ("outb %%al, %%dx" :: "d"(0x501), "a"(0));
|
||||
__asm__ volatile ("outb %%al, %%dx" :: "d"(0x501), "a"(0));
|
||||
/* if it does nothing, fall back to the regular panic */
|
||||
#endif
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user