nolibc updates for v6.3
o Add s390 support. o Add support for the ARM Thumb1 instruction set. o Fix O_* flags definitions for open() and fcntl(). o Make errno a weak symbol instead of a static variable. o Export environ as a weak symbol. o Export _auxv as a weak symbol for auxilliary vector retrieval. o Implement getauxval() and getpagesize(). o Further improve self tests, including permitting userland testing of the nolibc library. -----BEGIN PGP SIGNATURE----- iQJHBAABCgAxFiEEbK7UrM+RBIrCoViJnr8S83LZ+4wFAmPh1DITHHBhdWxtY2tA a2VybmVsLm9yZwAKCRCevxLzctn7jJTqD/9FPv58m1ZJWP8j8EMF9p6Pd2GuYJ/F t0tSf8Qmv0tTLqtPzZtu5E5b5bTvsgxQkQJUGLtUBf5l0AsyQt5ve5EUlzGgBHAP 8opwLEzCPUMhjq6ZsHJrmLIPwrH1reVYiAV2uIdBxLHLjGF8QLdYgqIGtguRBIHT o9HS9RAyPxvMmV8OZqhp+NLjcEzKGloUBdcnDLURQ8Wy12vSQnALl9w1OKiN40rz dlmXcysn8TboRWZS/DJqr/Xsg5W8ZMIfxrlopgR+FwrqutwH2ZDKgnc5ixm9YxFF CJCM2QZO8d8UtAxllJRH3NApTCHJh6c257w4awEU97hgkHfhw0tHgRs6sOz6ho0g O5OeOTAv0NkNNt5jGHXI4s0iQwVU/Ek6m3N8RC2GGzuMXGDcKvbFzGB4T8m8AhYL MnyaQvuq8SWhE84c+gQgxagZ5cdm8r2hDgnSrlI7P19W5SCsQq7MNSo1WyHQ7uss sMyxomvCC3y4pMgHcJHWwxtjR/BKjN1wtgCHCvTFcE8k98ti/ycKS6X/zQbGie/1 j20AgP0Cli2MVq+vocInvn0Gf4Ce0xxu5kB0NM8RMX+uiYNB0cJR4lIyWxt0680U M2Ya6AnfO8Sn57BptTp+QaqZidx9IJJzrAY4QBsdzXIsyJ2kKTK8BVNIaWMQ96nB twKV/fU0HWWcJQ== =S+cL -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
commit
f01d4c8a22
|
@ -7,18 +7,6 @@
|
|||
#ifndef _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
|
||||
* x86_64's stat one by field ordering, so be careful.
|
||||
*/
|
||||
|
@ -181,19 +169,31 @@ struct sys_stat_struct {
|
|||
_arg1; \
|
||||
})
|
||||
|
||||
/* startup code */
|
||||
__asm__ (".section .text\n"
|
||||
".weak _start\n"
|
||||
"_start:\n"
|
||||
"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
|
||||
"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"
|
||||
"");
|
||||
char **environ __attribute__((weak));
|
||||
const unsigned long *_auxv __attribute__((weak));
|
||||
|
||||
/* startup code */
|
||||
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _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)
|
||||
"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
|
||||
"svc #0\n"
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
#endif // _NOLIBC_ARCH_AARCH64_H
|
||||
|
|
|
@ -7,18 +7,6 @@
|
|||
#ifndef _NOLIBC_ARCH_ARM_H
|
||||
#define _NOLIBC_ARCH_ARM_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 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.
|
||||
|
@ -70,20 +58,44 @@ struct sys_stat_struct {
|
|||
* don't have to experience issues with register constraints.
|
||||
* - the syscall number is always specified last in order to allow to force
|
||||
* some registers before (gcc refuses a %-register at the last position).
|
||||
* - in thumb mode without -fomit-frame-pointer, r7 is also used to store the
|
||||
* frame pointer, and we cannot directly assign it as a register variable,
|
||||
* nor can we clobber it. Instead we assign the r6 register and swap it
|
||||
* with r7 before calling svc, and r6 is marked as clobbered.
|
||||
* We're just using any regular register which we assign to r7 after saving
|
||||
* it.
|
||||
*
|
||||
* Also, ARM supports the old_select syscall if newselect is not available
|
||||
*/
|
||||
#define __ARCH_WANT_SYS_OLD_SELECT
|
||||
|
||||
#if (defined(__THUMBEB__) || defined(__THUMBEL__)) && \
|
||||
!defined(NOLIBC_OMIT_FRAME_POINTER)
|
||||
/* swap r6,r7 needed in Thumb mode since we can't use nor clobber r7 */
|
||||
#define _NOLIBC_SYSCALL_REG "r6"
|
||||
#define _NOLIBC_THUMB_SET_R7 "eor r7, r6\neor r6, r7\neor r7, r6\n"
|
||||
#define _NOLIBC_THUMB_RESTORE_R7 "mov r7, r6\n"
|
||||
|
||||
#else /* we're in ARM mode */
|
||||
/* in Arm mode we can directly use r7 */
|
||||
#define _NOLIBC_SYSCALL_REG "r7"
|
||||
#define _NOLIBC_THUMB_SET_R7 ""
|
||||
#define _NOLIBC_THUMB_RESTORE_R7 ""
|
||||
|
||||
#endif /* end THUMB */
|
||||
|
||||
#define my_syscall0(num) \
|
||||
({ \
|
||||
register long _num __asm__ ("r7") = (num); \
|
||||
register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
|
||||
register long _arg1 __asm__ ("r0"); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
_NOLIBC_THUMB_SET_R7 \
|
||||
"svc #0\n" \
|
||||
: "=r"(_arg1) \
|
||||
: "r"(_num) \
|
||||
_NOLIBC_THUMB_RESTORE_R7 \
|
||||
: "=r"(_arg1), "=r"(_num) \
|
||||
: "r"(_arg1), \
|
||||
"r"(_num) \
|
||||
: "memory", "cc", "lr" \
|
||||
); \
|
||||
_arg1; \
|
||||
|
@ -91,12 +103,14 @@ struct sys_stat_struct {
|
|||
|
||||
#define my_syscall1(num, arg1) \
|
||||
({ \
|
||||
register long _num __asm__ ("r7") = (num); \
|
||||
register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
|
||||
register long _arg1 __asm__ ("r0") = (long)(arg1); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
_NOLIBC_THUMB_SET_R7 \
|
||||
"svc #0\n" \
|
||||
: "=r"(_arg1) \
|
||||
_NOLIBC_THUMB_RESTORE_R7 \
|
||||
: "=r"(_arg1), "=r" (_num) \
|
||||
: "r"(_arg1), \
|
||||
"r"(_num) \
|
||||
: "memory", "cc", "lr" \
|
||||
|
@ -106,13 +120,15 @@ struct sys_stat_struct {
|
|||
|
||||
#define my_syscall2(num, arg1, arg2) \
|
||||
({ \
|
||||
register long _num __asm__ ("r7") = (num); \
|
||||
register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
|
||||
register long _arg1 __asm__ ("r0") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("r1") = (long)(arg2); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
_NOLIBC_THUMB_SET_R7 \
|
||||
"svc #0\n" \
|
||||
: "=r"(_arg1) \
|
||||
_NOLIBC_THUMB_RESTORE_R7 \
|
||||
: "=r"(_arg1), "=r" (_num) \
|
||||
: "r"(_arg1), "r"(_arg2), \
|
||||
"r"(_num) \
|
||||
: "memory", "cc", "lr" \
|
||||
|
@ -122,14 +138,16 @@ struct sys_stat_struct {
|
|||
|
||||
#define my_syscall3(num, arg1, arg2, arg3) \
|
||||
({ \
|
||||
register long _num __asm__ ("r7") = (num); \
|
||||
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); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
_NOLIBC_THUMB_SET_R7 \
|
||||
"svc #0\n" \
|
||||
: "=r"(_arg1) \
|
||||
_NOLIBC_THUMB_RESTORE_R7 \
|
||||
: "=r"(_arg1), "=r" (_num) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), \
|
||||
"r"(_num) \
|
||||
: "memory", "cc", "lr" \
|
||||
|
@ -139,15 +157,17 @@ struct sys_stat_struct {
|
|||
|
||||
#define my_syscall4(num, arg1, arg2, arg3, arg4) \
|
||||
({ \
|
||||
register long _num __asm__ ("r7") = (num); \
|
||||
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); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
_NOLIBC_THUMB_SET_R7 \
|
||||
"svc #0\n" \
|
||||
: "=r"(_arg1) \
|
||||
_NOLIBC_THUMB_RESTORE_R7 \
|
||||
: "=r"(_arg1), "=r" (_num) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
|
||||
"r"(_num) \
|
||||
: "memory", "cc", "lr" \
|
||||
|
@ -157,7 +177,7 @@ struct sys_stat_struct {
|
|||
|
||||
#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
|
||||
({ \
|
||||
register long _num __asm__ ("r7") = (num); \
|
||||
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); \
|
||||
|
@ -165,8 +185,10 @@ struct sys_stat_struct {
|
|||
register long _arg5 __asm__ ("r4") = (long)(arg5); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
_NOLIBC_THUMB_SET_R7 \
|
||||
"svc #0\n" \
|
||||
: "=r" (_arg1) \
|
||||
_NOLIBC_THUMB_RESTORE_R7 \
|
||||
: "=r"(_arg1), "=r" (_num) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
|
||||
"r"(_num) \
|
||||
: "memory", "cc", "lr" \
|
||||
|
@ -174,31 +196,47 @@ struct sys_stat_struct {
|
|||
_arg1; \
|
||||
})
|
||||
|
||||
char **environ __attribute__((weak));
|
||||
const unsigned long *_auxv __attribute__((weak));
|
||||
|
||||
/* startup code */
|
||||
__asm__ (".section .text\n"
|
||||
".weak _start\n"
|
||||
"_start:\n"
|
||||
#if defined(__THUMBEB__) || defined(__THUMBEL__)
|
||||
/* We enter here in 32-bit mode but if some previous functions were in
|
||||
* 16-bit mode, the assembler cannot know, so we need to tell it we're in
|
||||
* 32-bit now, then switch to 16-bit (is there a better way to do it than
|
||||
* adding 1 by hand ?) and tell the asm we're now in 16-bit mode so that
|
||||
* it generates correct instructions. Note that we do not support thumb1.
|
||||
*/
|
||||
".code 32\n"
|
||||
"add r0, pc, #1\n"
|
||||
"bx r0\n"
|
||||
".code 16\n"
|
||||
#endif
|
||||
"pop {%r0}\n" // argc was in the stack
|
||||
"mov %r1, %sp\n" // argv = sp
|
||||
"add %r2, %r1, %r0, lsl #2\n" // envp = argv + 4*argc ...
|
||||
"add %r2, %r2, $4\n" // ... + 4
|
||||
"and %r3, %r1, $-8\n" // AAPCS : sp must be 8-byte aligned in the
|
||||
"mov %sp, %r3\n" // callee, an bl doesn't push (lr=pc)
|
||||
"bl main\n" // main() returns the status code, we'll exit with it.
|
||||
"movs r7, $1\n" // NR_exit == 1
|
||||
"svc $0x00\n"
|
||||
"");
|
||||
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void)
|
||||
{
|
||||
__asm__ volatile (
|
||||
"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
|
||||
|
||||
"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
|
||||
"bne 0b\n"
|
||||
"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" //
|
||||
|
||||
"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
|
||||
"1:\n"
|
||||
".word environ\n"
|
||||
"2:\n"
|
||||
".word _auxv\n"
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#endif // _NOLIBC_ARCH_ARM_H
|
||||
|
|
|
@ -7,18 +7,6 @@
|
|||
#ifndef _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
|
||||
* exactly 56 bytes (stops before the unused array).
|
||||
*/
|
||||
|
@ -190,6 +178,9 @@ struct sys_stat_struct {
|
|||
_eax; \
|
||||
})
|
||||
|
||||
char **environ __attribute__((weak));
|
||||
const unsigned long *_auxv __attribute__((weak));
|
||||
|
||||
/* startup code */
|
||||
/*
|
||||
* i386 System V ABI mandates:
|
||||
|
@ -197,23 +188,32 @@ struct sys_stat_struct {
|
|||
* 2) The deepest stack frame should be set to zero
|
||||
*
|
||||
*/
|
||||
__asm__ (".section .text\n"
|
||||
".weak _start\n"
|
||||
"_start:\n"
|
||||
"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)
|
||||
"xor %ebp, %ebp\n" // zero the stack frame
|
||||
"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
|
||||
"");
|
||||
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void)
|
||||
{
|
||||
__asm__ volatile (
|
||||
"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)
|
||||
"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
|
||||
"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
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#endif // _NOLIBC_ARCH_I386_H
|
||||
|
|
|
@ -7,18 +7,6 @@
|
|||
#ifndef _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
|
||||
* syscall.
|
||||
*/
|
||||
|
@ -188,30 +176,49 @@ struct sys_stat_struct {
|
|||
_arg4 ? -_num : _num; \
|
||||
})
|
||||
|
||||
char **environ __attribute__((weak));
|
||||
const unsigned long *_auxv __attribute__((weak));
|
||||
|
||||
/* startup code, note that it's called __start on MIPS */
|
||||
__asm__ (".section .text\n"
|
||||
".weak __start\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
|
||||
"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
|
||||
"syscall\n"
|
||||
".end __start\n"
|
||||
".set pop\n"
|
||||
"");
|
||||
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __start(void)
|
||||
{
|
||||
__asm__ volatile (
|
||||
//".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
|
||||
|
||||
"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
|
||||
"syscall\n"
|
||||
//".end __start\n"
|
||||
".set pop\n"
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#endif // _NOLIBC_ARCH_MIPS_H
|
||||
|
|
|
@ -7,18 +7,6 @@
|
|||
#ifndef _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 {
|
||||
unsigned long st_dev; /* Device. */
|
||||
unsigned long st_ino; /* File serial number. */
|
||||
|
@ -182,23 +170,39 @@ struct sys_stat_struct {
|
|||
_arg1; \
|
||||
})
|
||||
|
||||
char **environ __attribute__((weak));
|
||||
const unsigned long *_auxv __attribute__((weak));
|
||||
|
||||
/* startup code */
|
||||
__asm__ (".section .text\n"
|
||||
".weak _start\n"
|
||||
"_start:\n"
|
||||
".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
|
||||
"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"
|
||||
"");
|
||||
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _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
|
||||
|
||||
"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
|
||||
"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
|
||||
|
|
|
@ -0,0 +1,226 @@
|
|||
/* 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 @@
|
|||
#ifndef _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
|
||||
* syscall returns 116 bytes and stops in the middle of __unused.
|
||||
*/
|
||||
|
@ -190,6 +178,9 @@ struct sys_stat_struct {
|
|||
_ret; \
|
||||
})
|
||||
|
||||
char **environ __attribute__((weak));
|
||||
const unsigned long *_auxv __attribute__((weak));
|
||||
|
||||
/* startup code */
|
||||
/*
|
||||
* x86-64 System V ABI mandates:
|
||||
|
@ -197,19 +188,28 @@ struct sys_stat_struct {
|
|||
* 2) The deepest stack frame should be zero (the %rbp).
|
||||
*
|
||||
*/
|
||||
__asm__ (".section .text\n"
|
||||
".weak _start\n"
|
||||
"_start:\n"
|
||||
"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)
|
||||
"xor %ebp, %ebp\n" // zero the stack frame
|
||||
"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
|
||||
"");
|
||||
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void)
|
||||
{
|
||||
__asm__ volatile (
|
||||
"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)
|
||||
"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
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#endif // _NOLIBC_ARCH_X86_64_H
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include "arch-mips.h"
|
||||
#elif defined(__riscv)
|
||||
#include "arch-riscv.h"
|
||||
#elif defined(__s390x__)
|
||||
#include "arch-s390.h"
|
||||
#endif
|
||||
|
||||
#endif /* _NOLIBC_ARCH_H */
|
||||
|
|
|
@ -9,11 +9,9 @@
|
|||
|
||||
#include <asm/errno.h>
|
||||
|
||||
/* this way it will be removed if unused */
|
||||
static int errno;
|
||||
|
||||
#ifndef NOLIBC_IGNORE_ERRNO
|
||||
#define SET_ERRNO(v) do { errno = (v); } while (0)
|
||||
int errno __attribute__((weak));
|
||||
#else
|
||||
#define SET_ERRNO(v) do { } while (0)
|
||||
#endif
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "types.h"
|
||||
#include "sys.h"
|
||||
#include "string.h"
|
||||
#include <linux/auxvec.h>
|
||||
|
||||
struct nolibc_heap {
|
||||
size_t len;
|
||||
|
@ -108,6 +109,32 @@ char *getenv(const char *name)
|
|||
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))
|
||||
void *malloc(size_t len)
|
||||
{
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "std.h"
|
||||
|
||||
/* system includes */
|
||||
#include <asm/fcntl.h> // for O_*
|
||||
#include <asm/unistd.h>
|
||||
#include <asm/signal.h> // for SIGCHLD
|
||||
#include <asm/ioctls.h>
|
||||
|
@ -18,6 +19,7 @@
|
|||
#include <linux/fs.h>
|
||||
#include <linux/loop.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/auxvec.h>
|
||||
|
||||
#include "arch.h"
|
||||
#include "errno.h"
|
||||
|
@ -498,6 +500,26 @@ pid_t gettid(void)
|
|||
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);
|
||||
|
@ -686,6 +708,7 @@ int mknod(const char *path, mode_t mode, dev_t dev)
|
|||
#define MAP_FAILED ((void *)-1)
|
||||
#endif
|
||||
|
||||
#ifndef sys_mmap
|
||||
static __attribute__((unused))
|
||||
void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd,
|
||||
off_t offset)
|
||||
|
@ -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);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static __attribute__((unused))
|
||||
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
|
||||
|
|
|
@ -14,21 +14,25 @@ endif
|
|||
|
||||
# kernel image names by architecture
|
||||
IMAGE_i386 = arch/x86/boot/bzImage
|
||||
IMAGE_x86_64 = arch/x86/boot/bzImage
|
||||
IMAGE_x86 = arch/x86/boot/bzImage
|
||||
IMAGE_arm64 = arch/arm64/boot/Image
|
||||
IMAGE_arm = arch/arm/boot/zImage
|
||||
IMAGE_mips = vmlinuz
|
||||
IMAGE_riscv = arch/riscv/boot/Image
|
||||
IMAGE_s390 = arch/s390/boot/bzImage
|
||||
IMAGE = $(IMAGE_$(ARCH))
|
||||
IMAGE_NAME = $(notdir $(IMAGE))
|
||||
|
||||
# default kernel configurations that appear to be usable
|
||||
DEFCONFIG_i386 = defconfig
|
||||
DEFCONFIG_x86_64 = defconfig
|
||||
DEFCONFIG_x86 = defconfig
|
||||
DEFCONFIG_arm64 = defconfig
|
||||
DEFCONFIG_arm = multi_v7_defconfig
|
||||
DEFCONFIG_mips = malta_defconfig
|
||||
DEFCONFIG_riscv = defconfig
|
||||
DEFCONFIG_s390 = defconfig
|
||||
DEFCONFIG = $(DEFCONFIG_$(ARCH))
|
||||
|
||||
# optional tests to run (default = all)
|
||||
|
@ -36,20 +40,24 @@ TEST =
|
|||
|
||||
# QEMU_ARCH: arch names used by qemu
|
||||
QEMU_ARCH_i386 = i386
|
||||
QEMU_ARCH_x86_64 = x86_64
|
||||
QEMU_ARCH_x86 = x86_64
|
||||
QEMU_ARCH_arm64 = aarch64
|
||||
QEMU_ARCH_arm = arm
|
||||
QEMU_ARCH_mips = mipsel # works with malta_defconfig
|
||||
QEMU_ARCH_riscv = riscv64
|
||||
QEMU_ARCH_s390 = s390x
|
||||
QEMU_ARCH = $(QEMU_ARCH_$(ARCH))
|
||||
|
||||
# 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_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_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_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 = $(QEMU_ARGS_$(ARCH))
|
||||
|
||||
# OUTPUT is only set when run from the main makefile, otherwise
|
||||
|
@ -62,7 +70,8 @@ else
|
|||
Q=@
|
||||
endif
|
||||
|
||||
CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables
|
||||
CFLAGS_s390 = -m64
|
||||
CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables $(CFLAGS_$(ARCH))
|
||||
LDFLAGS := -s
|
||||
|
||||
help:
|
||||
|
@ -71,6 +80,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 " 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)"
|
||||
@echo " kernel (re)build the kernel with the initramfs (uses \$$ARCH)"
|
||||
|
@ -104,6 +114,11 @@ nolibc-test: nolibc-test.c sysroot/$(ARCH)/include
|
|||
$(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ \
|
||||
-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
|
||||
$(QUIET_MKDIR)mkdir -p initramfs
|
||||
$(call QUIET_INSTALL, initramfs/init)
|
||||
|
|
|
@ -442,6 +442,35 @@ int test_getdents64(const char *dir)
|
|||
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>.
|
||||
* Return 0 on success, non-zero on failure.
|
||||
*/
|
||||
|
@ -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;
|
||||
#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(link_root1); EXPECT_SYSER(1, link("/", "/"), -1, EEXIST); break;
|
||||
|
|
|
@ -159,6 +159,9 @@ identify_boot_image () {
|
|||
qemu-system-aarch64)
|
||||
echo arch/arm64/boot/Image
|
||||
;;
|
||||
qemu-system-s390x)
|
||||
echo arch/s390/boot/bzImage
|
||||
;;
|
||||
*)
|
||||
echo vmlinux
|
||||
;;
|
||||
|
@ -184,6 +187,9 @@ identify_qemu () {
|
|||
elif echo $u | grep -q aarch64
|
||||
then
|
||||
echo qemu-system-aarch64
|
||||
elif echo $u | grep -q 'IBM S/390'
|
||||
then
|
||||
echo qemu-system-s390x
|
||||
elif uname -a | grep -q ppc64
|
||||
then
|
||||
echo qemu-system-ppc64
|
||||
|
|
|
@ -64,7 +64,7 @@ ___EOF___
|
|||
# build using nolibc on supported archs (smaller executable) and fall
|
||||
# back to regular glibc on other ones.
|
||||
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 - \
|
||||
| grep -q '^yes'; then
|
||||
# architecture supported by nolibc
|
||||
|
|
Loading…
Reference in New Issue