Commit f01d4c8a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nolibc.2023.02.06a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu

Pull nolibc updates from Paul McKenney:

 - Add s390 support

 - Add support for the ARM Thumb1 instruction set

 - Fix O_* flags definitions for open() and fcntl()

 - Make errno a weak symbol instead of a static variable

 - Export environ as a weak symbol

 - Export _auxv as a weak symbol for auxilliary vector retrieval

 - Implement getauxval() and getpagesize()

 - Further improve self tests, including permitting userland testing of
   the nolibc library

* tag 'nolibc.2023.02.06a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu: (28 commits)
  selftests/nolibc: Add a "run-user" target to test the program in user land
  selftests/nolibc: Support "x86_64" for arch name
  selftests/nolibc: Add `getpagesize(2)` selftest
  nolibc/sys: Implement `getpagesize(2)` function
  nolibc/stdlib: Implement `getauxval(3)` function
  tools/nolibc: add auxiliary vector retrieval for s390
  tools/nolibc: add auxiliary vector retrieval for mips
  tools/nolibc: add auxiliary vector retrieval for riscv
  tools/nolibc: add auxiliary vector retrieval for arm
  tools/nolibc: add auxiliary vector retrieval for arm64
  tools/nolibc: add auxiliary vector retrieval for x86_64
  tools/nolibc: add auxiliary vector retrieval for i386
  tools/nolibc: export environ as a weak symbol on s390
  tools/nolibc: export environ as a weak symbol on riscv
  tools/nolibc: export environ as a weak symbol on mips
  tools/nolibc: export environ as a weak symbol on arm
  tools/nolibc: export environ as a weak symbol on arm64
  tools/nolibc: export environ as a weak symbol on i386
  tools/nolibc: export environ as a weak symbol on x86_64
  tools/nolibc: make errno a weak symbol instead of a static one
  ...
parents 525445ef c54ba417
...@@ -7,18 +7,6 @@ ...@@ -7,18 +7,6 @@
#ifndef _NOLIBC_ARCH_AARCH64_H #ifndef _NOLIBC_ARCH_AARCH64_H
#define _NOLIBC_ARCH_AARCH64_H #define _NOLIBC_ARCH_AARCH64_H
/* O_* macros for fcntl/open are architecture-specific */
#define O_RDONLY 0
#define O_WRONLY 1
#define O_RDWR 2
#define O_CREAT 0x40
#define O_EXCL 0x80
#define O_NOCTTY 0x100
#define O_TRUNC 0x200
#define O_APPEND 0x400
#define O_NONBLOCK 0x800
#define O_DIRECTORY 0x4000
/* The struct returned by the newfstatat() syscall. Differs slightly from the /* The struct returned by the newfstatat() syscall. Differs slightly from the
* x86_64's stat one by field ordering, so be careful. * x86_64's stat one by field ordering, so be careful.
*/ */
...@@ -181,19 +169,31 @@ struct sys_stat_struct { ...@@ -181,19 +169,31 @@ struct sys_stat_struct {
_arg1; \ _arg1; \
}) })
char **environ __attribute__((weak));
const unsigned long *_auxv __attribute__((weak));
/* startup code */ /* startup code */
__asm__ (".section .text\n" void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void)
".weak _start\n" {
"_start:\n" __asm__ volatile (
"ldr x0, [sp]\n" // argc (x0) was in the stack "ldr x0, [sp]\n" // argc (x0) was in the stack
"add x1, sp, 8\n" // argv (x1) = sp "add x1, sp, 8\n" // argv (x1) = sp
"lsl x2, x0, 3\n" // envp (x2) = 8*argc ... "lsl x2, x0, 3\n" // envp (x2) = 8*argc ...
"add x2, x2, 8\n" // + 8 (skip null) "add x2, x2, 8\n" // + 8 (skip null)
"add x2, x2, x1\n" // + argv "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 "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. "bl main\n" // main() returns the status code, we'll exit with it.
"mov x8, 93\n" // NR_exit == 93 "mov x8, 93\n" // NR_exit == 93
"svc #0\n" "svc #0\n"
""); );
__builtin_unreachable();
}
#endif // _NOLIBC_ARCH_AARCH64_H #endif // _NOLIBC_ARCH_AARCH64_H
This diff is collapsed.
...@@ -7,18 +7,6 @@ ...@@ -7,18 +7,6 @@
#ifndef _NOLIBC_ARCH_I386_H #ifndef _NOLIBC_ARCH_I386_H
#define _NOLIBC_ARCH_I386_H #define _NOLIBC_ARCH_I386_H
/* O_* macros for fcntl/open are architecture-specific */
#define O_RDONLY 0
#define O_WRONLY 1
#define O_RDWR 2
#define O_CREAT 0x40
#define O_EXCL 0x80
#define O_NOCTTY 0x100
#define O_TRUNC 0x200
#define O_APPEND 0x400
#define O_NONBLOCK 0x800
#define O_DIRECTORY 0x10000
/* The struct returned by the stat() syscall, 32-bit only, the syscall returns /* The struct returned by the stat() syscall, 32-bit only, the syscall returns
* exactly 56 bytes (stops before the unused array). * exactly 56 bytes (stops before the unused array).
*/ */
...@@ -190,6 +178,9 @@ struct sys_stat_struct { ...@@ -190,6 +178,9 @@ struct sys_stat_struct {
_eax; \ _eax; \
}) })
char **environ __attribute__((weak));
const unsigned long *_auxv __attribute__((weak));
/* startup code */ /* startup code */
/* /*
* i386 System V ABI mandates: * i386 System V ABI mandates:
...@@ -197,13 +188,20 @@ struct sys_stat_struct { ...@@ -197,13 +188,20 @@ struct sys_stat_struct {
* 2) The deepest stack frame should be set to zero * 2) The deepest stack frame should be set to zero
* *
*/ */
__asm__ (".section .text\n" void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void)
".weak _start\n" {
"_start:\n" __asm__ volatile (
"pop %eax\n" // argc (first arg, %eax) "pop %eax\n" // argc (first arg, %eax)
"mov %esp, %ebx\n" // argv[] (second arg, %ebx) "mov %esp, %ebx\n" // argv[] (second arg, %ebx)
"lea 4(%ebx,%eax,4),%ecx\n" // then a NULL then envp (third arg, %ecx) "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 "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)
"jnz 0b\n"
"mov %edx, _auxv\n" // save it into _auxv
"and $-16, %esp\n" // x86 ABI : esp must be 16-byte aligned before "and $-16, %esp\n" // x86 ABI : esp must be 16-byte aligned before
"sub $4, %esp\n" // the call instruction (args are aligned) "sub $4, %esp\n" // the call instruction (args are aligned)
"push %ecx\n" // push all registers on the stack so that we "push %ecx\n" // push all registers on the stack so that we
...@@ -214,6 +212,8 @@ __asm__ (".section .text\n" ...@@ -214,6 +212,8 @@ __asm__ (".section .text\n"
"movl $1, %eax\n" // NR_exit == 1 "movl $1, %eax\n" // NR_exit == 1
"int $0x80\n" // exit now "int $0x80\n" // exit now
"hlt\n" // ensure it does not "hlt\n" // ensure it does not
""); );
__builtin_unreachable();
}
#endif // _NOLIBC_ARCH_I386_H #endif // _NOLIBC_ARCH_I386_H
...@@ -7,18 +7,6 @@ ...@@ -7,18 +7,6 @@
#ifndef _NOLIBC_ARCH_MIPS_H #ifndef _NOLIBC_ARCH_MIPS_H
#define _NOLIBC_ARCH_MIPS_H #define _NOLIBC_ARCH_MIPS_H
/* O_* macros for fcntl/open are architecture-specific */
#define O_RDONLY 0
#define O_WRONLY 1
#define O_RDWR 2
#define O_APPEND 0x0008
#define O_NONBLOCK 0x0080
#define O_CREAT 0x0100
#define O_TRUNC 0x0200
#define O_EXCL 0x0400
#define O_NOCTTY 0x0800
#define O_DIRECTORY 0x10000
/* The struct returned by the stat() syscall. 88 bytes are returned by the /* The struct returned by the stat() syscall. 88 bytes are returned by the
* syscall. * syscall.
*/ */
...@@ -188,20 +176,37 @@ struct sys_stat_struct { ...@@ -188,20 +176,37 @@ struct sys_stat_struct {
_arg4 ? -_num : _num; \ _arg4 ? -_num : _num; \
}) })
char **environ __attribute__((weak));
const unsigned long *_auxv __attribute__((weak));
/* startup code, note that it's called __start on MIPS */ /* startup code, note that it's called __start on MIPS */
__asm__ (".section .text\n" void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __start(void)
".weak __start\n" {
".set nomips16\n" __asm__ volatile (
//".set nomips16\n"
".set push\n" ".set push\n"
".set noreorder\n" ".set noreorder\n"
".option pic0\n" ".option pic0\n"
".ent __start\n" //".ent __start\n"
"__start:\n" //"__start:\n"
"lw $a0,($sp)\n" // argc was in the stack "lw $a0,($sp)\n" // argc was in the stack
"addiu $a1, $sp, 4\n" // argv = sp + 4 "addiu $a1, $sp, 4\n" // argv = sp + 4
"sll $a2, $a0, 2\n" // a2 = argc * 4 "sll $a2, $a0, 2\n" // a2 = argc * 4
"add $a2, $a2, $a1\n" // envp = argv + 4*argc ... "add $a2, $a2, $a1\n" // envp = argv + 4*argc ...
"addiu $a2, $a2, 4\n" // ... + 4 "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
"li $t0, -8\n" "li $t0, -8\n"
"and $sp, $sp, $t0\n" // sp must be 8-byte aligned "and $sp, $sp, $t0\n" // sp must be 8-byte aligned
"addiu $sp,$sp,-16\n" // the callee expects to save a0..a3 there! "addiu $sp,$sp,-16\n" // the callee expects to save a0..a3 there!
...@@ -210,8 +215,10 @@ __asm__ (".section .text\n" ...@@ -210,8 +215,10 @@ __asm__ (".section .text\n"
"move $a0, $v0\n" // retrieve 32-bit exit code from v0 "move $a0, $v0\n" // retrieve 32-bit exit code from v0
"li $v0, 4001\n" // NR_exit == 4001 "li $v0, 4001\n" // NR_exit == 4001
"syscall\n" "syscall\n"
".end __start\n" //".end __start\n"
".set pop\n" ".set pop\n"
""); );
__builtin_unreachable();
}
#endif // _NOLIBC_ARCH_MIPS_H #endif // _NOLIBC_ARCH_MIPS_H
...@@ -7,18 +7,6 @@ ...@@ -7,18 +7,6 @@
#ifndef _NOLIBC_ARCH_RISCV_H #ifndef _NOLIBC_ARCH_RISCV_H
#define _NOLIBC_ARCH_RISCV_H #define _NOLIBC_ARCH_RISCV_H
/* O_* macros for fcntl/open are architecture-specific */
#define O_RDONLY 0
#define O_WRONLY 1
#define O_RDWR 2
#define O_CREAT 0x40
#define O_EXCL 0x80
#define O_NOCTTY 0x100
#define O_TRUNC 0x200
#define O_APPEND 0x400
#define O_NONBLOCK 0x800
#define O_DIRECTORY 0x10000
struct sys_stat_struct { struct sys_stat_struct {
unsigned long st_dev; /* Device. */ unsigned long st_dev; /* Device. */
unsigned long st_ino; /* File serial number. */ unsigned long st_ino; /* File serial number. */
...@@ -182,10 +170,13 @@ struct sys_stat_struct { ...@@ -182,10 +170,13 @@ struct sys_stat_struct {
_arg1; \ _arg1; \
}) })
char **environ __attribute__((weak));
const unsigned long *_auxv __attribute__((weak));
/* startup code */ /* startup code */
__asm__ (".section .text\n" void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void)
".weak _start\n" {
"_start:\n" __asm__ volatile (
".option push\n" ".option push\n"
".option norelax\n" ".option norelax\n"
"lla gp, __global_pointer$\n" "lla gp, __global_pointer$\n"
...@@ -195,10 +186,23 @@ __asm__ (".section .text\n" ...@@ -195,10 +186,23 @@ __asm__ (".section .text\n"
"slli a2, a0, "PTRLOG"\n" // envp (a2) = SZREG*argc ... "slli a2, a0, "PTRLOG"\n" // envp (a2) = SZREG*argc ...
"add a2, a2, "SZREG"\n" // + SZREG (skip null) "add a2, a2, "SZREG"\n" // + SZREG (skip null)
"add a2,a2,a1\n" // + argv "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
"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 "andi sp,a1,-16\n" // sp must be 16-byte aligned
"call main\n" // main() returns the status code, we'll exit with it. "call main\n" // main() returns the status code, we'll exit with it.
"li a7, 93\n" // NR_exit == 93 "li a7, 93\n" // NR_exit == 93
"ecall\n" "ecall\n"
""); );
__builtin_unreachable();
}
#endif // _NOLIBC_ARCH_RISCV_H #endif // _NOLIBC_ARCH_RISCV_H
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* s390 specific definitions for NOLIBC
*/
#ifndef _NOLIBC_ARCH_S390_H
#define _NOLIBC_ARCH_S390_H
#include <asm/unistd.h>
/* The struct returned by the stat() syscall, equivalent to stat64(). The
* syscall returns 116 bytes and stops in the middle of __unused.
*/
struct sys_stat_struct {
unsigned long st_dev;
unsigned long st_ino;
unsigned long st_nlink;
unsigned int st_mode;
unsigned int st_uid;
unsigned int st_gid;
unsigned int __pad1;
unsigned long st_rdev;
unsigned long st_size;
unsigned long st_atime;
unsigned long st_atime_nsec;
unsigned long st_mtime;
unsigned long st_mtime_nsec;
unsigned long st_ctime;
unsigned long st_ctime_nsec;
unsigned long st_blksize;
long st_blocks;
unsigned long __unused[3];
};
/* Syscalls for s390:
* - registers are 64-bit
* - syscall number is passed in r1
* - arguments are in r2-r7
* - the system call is performed by calling the svc instruction
* - syscall return value is in r2
* - r1 and r2 are clobbered, others are preserved.
*
* Link s390 ABI: https://github.com/IBM/s390x-abi
*
*/
#define my_syscall0(num) \
({ \
register long _num __asm__ ("1") = (num); \
register long _rc __asm__ ("2"); \
\
__asm__ volatile ( \
"svc 0\n" \
: "=d"(_rc) \
: "d"(_num) \
: "memory", "cc" \
); \
_rc; \
})
#define my_syscall1(num, arg1) \
({ \
register long _num __asm__ ("1") = (num); \
register long _arg1 __asm__ ("2") = (long)(arg1); \
\
__asm__ volatile ( \
"svc 0\n" \
: "+d"(_arg1) \
: "d"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define my_syscall2(num, arg1, arg2) \
({ \
register long _num __asm__ ("1") = (num); \
register long _arg1 __asm__ ("2") = (long)(arg1); \
register long _arg2 __asm__ ("3") = (long)(arg2); \
\
__asm__ volatile ( \
"svc 0\n" \
: "+d"(_arg1) \
: "d"(_arg2), "d"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define my_syscall3(num, arg1, arg2, arg3) \
({ \
register long _num __asm__ ("1") = (num); \
register long _arg1 __asm__ ("2") = (long)(arg1); \
register long _arg2 __asm__ ("3") = (long)(arg2); \
register long _arg3 __asm__ ("4") = (long)(arg3); \
\
__asm__ volatile ( \
"svc 0\n" \
: "+d"(_arg1) \
: "d"(_arg2), "d"(_arg3), "d"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define my_syscall4(num, arg1, arg2, arg3, arg4) \
({ \
register long _num __asm__ ("1") = (num); \
register long _arg1 __asm__ ("2") = (long)(arg1); \
register long _arg2 __asm__ ("3") = (long)(arg2); \
register long _arg3 __asm__ ("4") = (long)(arg3); \
register long _arg4 __asm__ ("5") = (long)(arg4); \
\
__asm__ volatile ( \
"svc 0\n" \
: "+d"(_arg1) \
: "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
({ \
register long _num __asm__ ("1") = (num); \
register long _arg1 __asm__ ("2") = (long)(arg1); \
register long _arg2 __asm__ ("3") = (long)(arg2); \
register long _arg3 __asm__ ("4") = (long)(arg3); \
register long _arg4 __asm__ ("5") = (long)(arg4); \
register long _arg5 __asm__ ("6") = (long)(arg5); \
\
__asm__ volatile ( \
"svc 0\n" \
: "+d"(_arg1) \
: "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5), \
"d"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
register long _num __asm__ ("1") = (num); \
register long _arg1 __asm__ ("2") = (long)(arg1); \
register long _arg2 __asm__ ("3") = (long)(arg2); \
register long _arg3 __asm__ ("4") = (long)(arg3); \
register long _arg4 __asm__ ("5") = (long)(arg4); \
register long _arg5 __asm__ ("6") = (long)(arg5); \
register long _arg6 __asm__ ("7") = (long)(arg6); \
\
__asm__ volatile ( \
"svc 0\n" \
: "+d"(_arg1) \
: "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5), \
"d"(_arg6), "d"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
char **environ __attribute__((weak));
const unsigned long *_auxv __attribute__((weak));
/* startup code */
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void)
{
__asm__ volatile (
"lg %r2,0(%r15)\n" /* argument count */
"la %r3,8(%r15)\n" /* argument pointers */
"xgr %r0,%r0\n" /* r0 will be our NULL value */
/* search for envp */
"lgr %r4,%r3\n" /* start at argv */
"0:\n"
"clg %r0,0(%r4)\n" /* entry zero? */
"la %r4,8(%r4)\n" /* advance pointer */
"jnz 0b\n" /* no -> test next pointer */
/* yes -> r4 now contains start of envp */
"larl %r1,environ\n"
"stg %r4,0(%r1)\n"
/* search for auxv */
"lgr %r5,%r4\n" /* start at envp */
"1:\n"
"clg %r0,0(%r5)\n" /* entry zero? */
"la %r5,8(%r5)\n" /* advance pointer */
"jnz 1b\n" /* no -> test next pointer */
"larl %r1,_auxv\n" /* yes -> store value in _auxv */
"stg %r5,0(%r1)\n"
"aghi %r15,-160\n" /* allocate new stackframe */
"xc 0(8,%r15),0(%r15)\n" /* clear backchain */
"brasl %r14,main\n" /* ret value of main is arg to exit */
"lghi %r1,1\n" /* __NR_exit */
"svc 0\n"
);
__builtin_unreachable();
}
struct s390_mmap_arg_struct {
unsigned long addr;
unsigned long len;
unsigned long prot;
unsigned long flags;
unsigned long fd;
unsigned long offset;
};
static __attribute__((unused))
void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd,
off_t offset)
{
struct s390_mmap_arg_struct args = {
.addr = (unsigned long)addr,
.len = (unsigned long)length,
.prot = prot,
.flags = flags,
.fd = fd,
.offset = (unsigned long)offset
};
return (void *)my_syscall1(__NR_mmap, &args);
}
#define sys_mmap sys_mmap
#endif // _NOLIBC_ARCH_S390_H
...@@ -7,18 +7,6 @@ ...@@ -7,18 +7,6 @@
#ifndef _NOLIBC_ARCH_X86_64_H #ifndef _NOLIBC_ARCH_X86_64_H
#define _NOLIBC_ARCH_X86_64_H #define _NOLIBC_ARCH_X86_64_H
/* O_* macros for fcntl/open are architecture-specific */
#define O_RDONLY 0
#define O_WRONLY 1
#define O_RDWR 2
#define O_CREAT 0x40
#define O_EXCL 0x80
#define O_NOCTTY 0x100
#define O_TRUNC 0x200
#define O_APPEND 0x400
#define O_NONBLOCK 0x800
#define O_DIRECTORY 0x10000
/* The struct returned by the stat() syscall, equivalent to stat64(). The /* The struct returned by the stat() syscall, equivalent to stat64(). The
* syscall returns 116 bytes and stops in the middle of __unused. * syscall returns 116 bytes and stops in the middle of __unused.
*/ */
...@@ -190,6 +178,9 @@ struct sys_stat_struct { ...@@ -190,6 +178,9 @@ struct sys_stat_struct {
_ret; \ _ret; \
}) })
char **environ __attribute__((weak));
const unsigned long *_auxv __attribute__((weak));
/* startup code */ /* startup code */
/* /*
* x86-64 System V ABI mandates: * x86-64 System V ABI mandates:
...@@ -197,19 +188,28 @@ struct sys_stat_struct { ...@@ -197,19 +188,28 @@ struct sys_stat_struct {
* 2) The deepest stack frame should be zero (the %rbp). * 2) The deepest stack frame should be zero (the %rbp).
* *
*/ */
__asm__ (".section .text\n" void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void)
".weak _start\n" {
"_start:\n" __asm__ volatile (
"pop %rdi\n" // argc (first arg, %rdi) "pop %rdi\n" // argc (first arg, %rdi)
"mov %rsp, %rsi\n" // argv[] (second arg, %rsi) "mov %rsp, %rsi\n" // argv[] (second arg, %rsi)
"lea 8(%rsi,%rdi,8),%rdx\n" // then a NULL then envp (third arg, %rdx) "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 "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)
"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 "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. "call main\n" // main() returns the status code, we'll exit with it.
"mov %eax, %edi\n" // retrieve exit code (32 bit) "mov %eax, %edi\n" // retrieve exit code (32 bit)
"mov $60, %eax\n" // NR_exit == 60 "mov $60, %eax\n" // NR_exit == 60
"syscall\n" // really exit "syscall\n" // really exit
"hlt\n" // ensure it does not return "hlt\n" // ensure it does not return
""); );
__builtin_unreachable();
}
#endif // _NOLIBC_ARCH_X86_64_H #endif // _NOLIBC_ARCH_X86_64_H
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#include "arch-mips.h" #include "arch-mips.h"
#elif defined(__riscv) #elif defined(__riscv)
#include "arch-riscv.h" #include "arch-riscv.h"
#elif defined(__s390x__)
#include "arch-s390.h"
#endif #endif
#endif /* _NOLIBC_ARCH_H */ #endif /* _NOLIBC_ARCH_H */
...@@ -9,11 +9,9 @@ ...@@ -9,11 +9,9 @@
#include <asm/errno.h> #include <asm/errno.h>
/* this way it will be removed if unused */
static int errno;
#ifndef NOLIBC_IGNORE_ERRNO #ifndef NOLIBC_IGNORE_ERRNO
#define SET_ERRNO(v) do { errno = (v); } while (0) #define SET_ERRNO(v) do { errno = (v); } while (0)
int errno __attribute__((weak));
#else #else
#define SET_ERRNO(v) do { } while (0) #define SET_ERRNO(v) do { } while (0)
#endif #endif
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "types.h" #include "types.h"
#include "sys.h" #include "sys.h"
#include "string.h" #include "string.h"
#include <linux/auxvec.h>
struct nolibc_heap { struct nolibc_heap {
size_t len; size_t len;
...@@ -108,6 +109,32 @@ char *getenv(const char *name) ...@@ -108,6 +109,32 @@ char *getenv(const char *name)
return _getenv(name, environ); return _getenv(name, environ);
} }
static __attribute__((unused))
unsigned long getauxval(unsigned long type)
{
const unsigned long *auxv = _auxv;
unsigned long ret;
if (!auxv)
return 0;
while (1) {
if (!auxv[0] && !auxv[1]) {
ret = 0;
break;
}
if (auxv[0] == type) {
ret = auxv[1];
break;
}
auxv += 2;
}
return ret;
}
static __attribute__((unused)) static __attribute__((unused))
void *malloc(size_t len) void *malloc(size_t len)
{ {
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "std.h" #include "std.h"
/* system includes */ /* system includes */
#include <asm/fcntl.h> // for O_*
#include <asm/unistd.h> #include <asm/unistd.h>
#include <asm/signal.h> // for SIGCHLD #include <asm/signal.h> // for SIGCHLD
#include <asm/ioctls.h> #include <asm/ioctls.h>
...@@ -18,6 +19,7 @@ ...@@ -18,6 +19,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/loop.h> #include <linux/loop.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/auxvec.h>
#include "arch.h" #include "arch.h"
#include "errno.h" #include "errno.h"
...@@ -498,6 +500,26 @@ pid_t gettid(void) ...@@ -498,6 +500,26 @@ pid_t gettid(void)
return sys_gettid(); return sys_gettid();
} }
static unsigned long getauxval(unsigned long key);
/*
* long getpagesize(void);
*/
static __attribute__((unused))
long getpagesize(void)
{
long ret;
ret = getauxval(AT_PAGESZ);
if (!ret) {
SET_ERRNO(ENOENT);
return -1;
}
return ret;
}
/* /*
* int gettimeofday(struct timeval *tv, struct timezone *tz); * int gettimeofday(struct timeval *tv, struct timezone *tz);
...@@ -686,6 +708,7 @@ int mknod(const char *path, mode_t mode, dev_t dev) ...@@ -686,6 +708,7 @@ int mknod(const char *path, mode_t mode, dev_t dev)
#define MAP_FAILED ((void *)-1) #define MAP_FAILED ((void *)-1)
#endif #endif
#ifndef sys_mmap
static __attribute__((unused)) static __attribute__((unused))
void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd,
off_t offset) off_t offset)
...@@ -707,6 +730,7 @@ void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, ...@@ -707,6 +730,7 @@ void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd,
return (void *)my_syscall6(n, addr, length, prot, flags, fd, offset); return (void *)my_syscall6(n, addr, length, prot, flags, fd, offset);
#endif #endif
} }
#endif
static __attribute__((unused)) static __attribute__((unused))
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
......
...@@ -14,21 +14,25 @@ endif ...@@ -14,21 +14,25 @@ endif
# kernel image names by architecture # kernel image names by architecture
IMAGE_i386 = arch/x86/boot/bzImage IMAGE_i386 = arch/x86/boot/bzImage
IMAGE_x86_64 = arch/x86/boot/bzImage
IMAGE_x86 = arch/x86/boot/bzImage IMAGE_x86 = arch/x86/boot/bzImage
IMAGE_arm64 = arch/arm64/boot/Image IMAGE_arm64 = arch/arm64/boot/Image
IMAGE_arm = arch/arm/boot/zImage IMAGE_arm = arch/arm/boot/zImage
IMAGE_mips = vmlinuz IMAGE_mips = vmlinuz
IMAGE_riscv = arch/riscv/boot/Image IMAGE_riscv = arch/riscv/boot/Image
IMAGE_s390 = arch/s390/boot/bzImage
IMAGE = $(IMAGE_$(ARCH)) IMAGE = $(IMAGE_$(ARCH))
IMAGE_NAME = $(notdir $(IMAGE)) IMAGE_NAME = $(notdir $(IMAGE))
# default kernel configurations that appear to be usable # default kernel configurations that appear to be usable
DEFCONFIG_i386 = defconfig DEFCONFIG_i386 = defconfig
DEFCONFIG_x86_64 = defconfig
DEFCONFIG_x86 = defconfig DEFCONFIG_x86 = defconfig
DEFCONFIG_arm64 = defconfig DEFCONFIG_arm64 = defconfig
DEFCONFIG_arm = multi_v7_defconfig DEFCONFIG_arm = multi_v7_defconfig
DEFCONFIG_mips = malta_defconfig DEFCONFIG_mips = malta_defconfig
DEFCONFIG_riscv = defconfig DEFCONFIG_riscv = defconfig
DEFCONFIG_s390 = defconfig
DEFCONFIG = $(DEFCONFIG_$(ARCH)) DEFCONFIG = $(DEFCONFIG_$(ARCH))
# optional tests to run (default = all) # optional tests to run (default = all)
...@@ -36,20 +40,24 @@ TEST = ...@@ -36,20 +40,24 @@ TEST =
# QEMU_ARCH: arch names used by qemu # QEMU_ARCH: arch names used by qemu
QEMU_ARCH_i386 = i386 QEMU_ARCH_i386 = i386
QEMU_ARCH_x86_64 = x86_64
QEMU_ARCH_x86 = x86_64 QEMU_ARCH_x86 = x86_64
QEMU_ARCH_arm64 = aarch64 QEMU_ARCH_arm64 = aarch64
QEMU_ARCH_arm = arm QEMU_ARCH_arm = arm
QEMU_ARCH_mips = mipsel # works with malta_defconfig QEMU_ARCH_mips = mipsel # works with malta_defconfig
QEMU_ARCH_riscv = riscv64 QEMU_ARCH_riscv = riscv64
QEMU_ARCH_s390 = s390x
QEMU_ARCH = $(QEMU_ARCH_$(ARCH)) QEMU_ARCH = $(QEMU_ARCH_$(ARCH))
# QEMU_ARGS : some arch-specific args to pass to qemu # QEMU_ARGS : some arch-specific args to pass to qemu
QEMU_ARGS_i386 = -M pc -append "console=ttyS0,9600 i8042.noaux panic=-1 $(TEST:%=NOLIBC_TEST=%)" QEMU_ARGS_i386 = -M pc -append "console=ttyS0,9600 i8042.noaux panic=-1 $(TEST:%=NOLIBC_TEST=%)"
QEMU_ARGS_x86_64 = -M pc -append "console=ttyS0,9600 i8042.noaux panic=-1 $(TEST:%=NOLIBC_TEST=%)"
QEMU_ARGS_x86 = -M pc -append "console=ttyS0,9600 i8042.noaux panic=-1 $(TEST:%=NOLIBC_TEST=%)" QEMU_ARGS_x86 = -M pc -append "console=ttyS0,9600 i8042.noaux panic=-1 $(TEST:%=NOLIBC_TEST=%)"
QEMU_ARGS_arm64 = -M virt -cpu cortex-a53 -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)" QEMU_ARGS_arm64 = -M virt -cpu cortex-a53 -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)"
QEMU_ARGS_arm = -M virt -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)" QEMU_ARGS_arm = -M virt -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)"
QEMU_ARGS_mips = -M malta -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)" 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_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 = $(QEMU_ARGS_$(ARCH)) QEMU_ARGS = $(QEMU_ARGS_$(ARCH))
# OUTPUT is only set when run from the main makefile, otherwise # OUTPUT is only set when run from the main makefile, otherwise
...@@ -62,7 +70,8 @@ else ...@@ -62,7 +70,8 @@ else
Q=@ Q=@
endif endif
CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables CFLAGS_s390 = -m64
CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables $(CFLAGS_$(ARCH))
LDFLAGS := -s LDFLAGS := -s
help: help:
...@@ -71,6 +80,7 @@ help: ...@@ -71,6 +80,7 @@ help:
@echo " help this help" @echo " help this help"
@echo " sysroot create the nolibc sysroot here (uses \$$ARCH)" @echo " sysroot create the nolibc sysroot here (uses \$$ARCH)"
@echo " nolibc-test build the executable (uses \$$CC and \$$CROSS_COMPILE)" @echo " nolibc-test build the executable (uses \$$CC and \$$CROSS_COMPILE)"
@echo " run-user runs the executable under QEMU (uses \$$ARCH, \$$TEST)"
@echo " initramfs prepare the initramfs with nolibc-test" @echo " initramfs prepare the initramfs with nolibc-test"
@echo " defconfig create a fresh new default config (uses \$$ARCH)" @echo " defconfig create a fresh new default config (uses \$$ARCH)"
@echo " kernel (re)build the kernel with the initramfs (uses \$$ARCH)" @echo " kernel (re)build the kernel with the initramfs (uses \$$ARCH)"
...@@ -104,6 +114,11 @@ nolibc-test: nolibc-test.c sysroot/$(ARCH)/include ...@@ -104,6 +114,11 @@ nolibc-test: nolibc-test.c sysroot/$(ARCH)/include
$(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ \ $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ \
-nostdlib -static -Isysroot/$(ARCH)/include $< -lgcc -nostdlib -static -Isysroot/$(ARCH)/include $< -lgcc
# 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."
initramfs: nolibc-test initramfs: nolibc-test
$(QUIET_MKDIR)mkdir -p initramfs $(QUIET_MKDIR)mkdir -p initramfs
$(call QUIET_INSTALL, initramfs/init) $(call QUIET_INSTALL, initramfs/init)
......
...@@ -442,6 +442,35 @@ int test_getdents64(const char *dir) ...@@ -442,6 +442,35 @@ int test_getdents64(const char *dir)
return ret; return ret;
} }
static int test_getpagesize(void)
{
long x = getpagesize();
int c;
if (x < 0)
return x;
#if defined(__x86_64__) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__)
/*
* x86 family is always 4K page.
*/
c = (x == 4096);
#elif defined(__aarch64__)
/*
* Linux aarch64 supports three values of page size: 4K, 16K, and 64K
* which are selected at kernel compilation time.
*/
c = (x == 4096 || x == (16 * 1024) || x == (64 * 1024));
#else
/*
* Assuming other architectures must have at least 4K page.
*/
c = (x >= 4096);
#endif
return !c;
}
/* Run syscall tests between IDs <min> and <max>. /* Run syscall tests between IDs <min> and <max>.
* Return 0 on success, non-zero on failure. * Return 0 on success, non-zero on failure.
*/ */
...@@ -502,6 +531,7 @@ int run_syscall(int min, int max) ...@@ -502,6 +531,7 @@ int run_syscall(int min, int max)
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;
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 #endif
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;
CASE_TEST(ioctl_tiocinq); EXPECT_SYSZR(1, ioctl(0, TIOCINQ, &tmp)); break; CASE_TEST(ioctl_tiocinq); EXPECT_SYSZR(1, ioctl(0, TIOCINQ, &tmp)); break;
CASE_TEST(link_root1); EXPECT_SYSER(1, link("/", "/"), -1, EEXIST); break; CASE_TEST(link_root1); EXPECT_SYSER(1, link("/", "/"), -1, EEXIST); break;
......
...@@ -159,6 +159,9 @@ identify_boot_image () { ...@@ -159,6 +159,9 @@ identify_boot_image () {
qemu-system-aarch64) qemu-system-aarch64)
echo arch/arm64/boot/Image echo arch/arm64/boot/Image
;; ;;
qemu-system-s390x)
echo arch/s390/boot/bzImage
;;
*) *)
echo vmlinux echo vmlinux
;; ;;
...@@ -184,6 +187,9 @@ identify_qemu () { ...@@ -184,6 +187,9 @@ identify_qemu () {
elif echo $u | grep -q aarch64 elif echo $u | grep -q aarch64
then then
echo qemu-system-aarch64 echo qemu-system-aarch64
elif echo $u | grep -q 'IBM S/390'
then
echo qemu-system-s390x
elif uname -a | grep -q ppc64 elif uname -a | grep -q ppc64
then then
echo qemu-system-ppc64 echo qemu-system-ppc64
......
...@@ -64,7 +64,7 @@ ___EOF___ ...@@ -64,7 +64,7 @@ ___EOF___
# build using nolibc on supported archs (smaller executable) and fall # build using nolibc on supported archs (smaller executable) and fall
# back to regular glibc on other ones. # back to regular glibc on other ones.
if echo -e "#if __x86_64__||__i386__||__i486__||__i586__||__i686__" \ if echo -e "#if __x86_64__||__i386__||__i486__||__i586__||__i686__" \
"||__ARM_EABI__||__aarch64__\nyes\n#endif" \ "||__ARM_EABI__||__aarch64__||__s390x__\nyes\n#endif" \
| ${CROSS_COMPILE}gcc -E -nostdlib -xc - \ | ${CROSS_COMPILE}gcc -E -nostdlib -xc - \
| grep -q '^yes'; then | grep -q '^yes'; then
# architecture supported by nolibc # architecture supported by nolibc
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment