Commit f01d4c8a authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+26 −26
Original line number Diff line number Diff line
@@ -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;                                                                \
})

char **environ __attribute__((weak));
const unsigned long *_auxv __attribute__((weak));

/* startup code */
__asm__ (".section .text\n"
    ".weak _start\n"
    "_start:\n"
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
+88 −50
Original line number Diff line number Diff line
@@ -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
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, %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)

		"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
+30 −30
Original line number Diff line number Diff line
@@ -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,13 +188,20 @@ struct sys_stat_struct {
 * 2) The deepest stack frame should be set to zero
 *
 */
__asm__ (".section .text\n"
    ".weak _start\n"
    "_start:\n"
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
@@ -214,6 +212,8 @@ __asm__ (".section .text\n"
		"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
+43 −36
Original line number Diff line number Diff line
@@ -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,20 +176,37 @@ 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"
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"
		//".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!
@@ -210,8 +215,10 @@ __asm__ (".section .text\n"
		"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
+33 −29
Original line number Diff line number Diff line
@@ -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,10 +170,13 @@ 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"
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void)
{
	__asm__ volatile (
		".option push\n"
		".option norelax\n"
		"lla   gp, __global_pointer$\n"
@@ -195,10 +186,23 @@ __asm__ (".section .text\n"
		"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
Loading