Commit b19edac5 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull nolibc updates from Paul McKenney:

 - Add stackprotector support

 - Fix RISC-V load-store instruction syntax to support 32-bit binaries,
   plus fixes for generic 32-bit support

 - Fix use of s390 sys_fork()

 - Add my_syscall6() for ARM

 - Support different platforms having different errno definitions

 - Fix ppoll/ppoll_time64 arguments (add the fifth argument)

 - Force use of little endian on MIPS

 - Improved testing, for example, better handling of different compilers
   and compiler versions, comparing nolibc behavior to that of libc, and
   additional test cases

 - Improve syntax and header ordering

 - Use existing <linux/reboot.h> instead of redefining constants

 - Add syscall()

* tag 'nolibc.2023.06.22a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu: (53 commits)
  selftests/nolibc: make sure gcc always use little endian on MIPS
  selftests/nolibc: also count skipped and failed tests in output
  selftests/nolibc: add new gettimeofday test cases
  selftests/nolibc: remove gettimeofday_bad1/2 completely
  selftests/nolibc: support two errnos with EXPECT_SYSER2()
  tools/nolibc: open: fix up compile warning for arm
  tools/nolibc: arm: add missing my_syscall6
  selftests/nolibc: use INT_MAX instead of __INT_MAX__
  selftests/nolibc: not include limits.h for nolibc
  selftests/nolibc: fix up compile warning with glibc on x86_64
  selftests/nolibc: allow specify extra arguments for qemu
  selftests/nolibc: remove test gettimeofday_null
  tools/nolibc: ensure fast64 integer types have 64 bits
  selftests/nolibc: test_fork: fix up duplicated print
  tools/nolibc: ppoll/ppoll_time64: add a missing argument
  selftests/nolibc: remove the duplicated gettimeofday_bad2
  selftests/nolibc: print name instead of number for EOVERFLOW
  tools/nolibc: support nanoseconds in stat()
  selftests/nolibc: prevent coredumps during test execution
  tools/nolibc: add support for prctl()
  ...
parents af96134d dd58d666
Loading
Loading
Loading
Loading
+17 −2
Original line number Diff line number Diff line
@@ -25,8 +25,23 @@ endif

nolibc_arch := $(patsubst arm64,aarch64,$(ARCH))
arch_file := arch-$(nolibc_arch).h
all_files := ctype.h errno.h nolibc.h signal.h stackprotector.h std.h stdint.h \
             stdio.h stdlib.h string.h sys.h time.h types.h unistd.h
all_files := \
		compiler.h \
		ctype.h \
		errno.h \
		nolibc.h \
		signal.h \
		stackprotector.h \
		std.h \
		stdint.h \
		stdlib.h \
		string.h \
		sys.h \
		time.h \
		types.h \
		unistd.h \
		stdio.h \


# install all headers needed to support a bare-metal compiler
all: headers
+22 −17
Original line number Diff line number Diff line
@@ -7,6 +7,8 @@
#ifndef _NOLIBC_ARCH_AARCH64_H
#define _NOLIBC_ARCH_AARCH64_H

#include "compiler.h"

/* The struct returned by the newfstatat() syscall. Differs slightly from the
 * x86_64's stat one by field ordering, so be careful.
 */
@@ -173,27 +175,30 @@ char **environ __attribute__((weak));
const unsigned long *_auxv __attribute__((weak));

/* startup code */
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void)
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
{
	__asm__ volatile (
		"ldr x0, [sp]\n"     // argc (x0) was in the stack
		"add x1, sp, 8\n"    // argv (x1) = sp
		"lsl x2, x0, 3\n"    // envp (x2) = 8*argc ...
		"add x2, x2, 8\n"    //           + 8 (skip null)
		"add x2, x2, x1\n"   //           + argv
		"adrp x3, environ\n"          // x3 = &environ (high bits)
		"str x2, [x3, #:lo12:environ]\n" // store envp into environ
		"mov x4, x2\n"       // search for auxv (follows NULL after last env)
#ifdef _NOLIBC_STACKPROTECTOR
		"bl __stack_chk_init\n"   /* initialize stack protector                     */
#endif
		"ldr x0, [sp]\n"     /* argc (x0) was in the stack                          */
		"add x1, sp, 8\n"    /* argv (x1) = sp                                      */
		"lsl x2, x0, 3\n"    /* envp (x2) = 8*argc ...                              */
		"add x2, x2, 8\n"    /*           + 8 (skip null)                           */
		"add x2, x2, x1\n"   /*           + argv                                    */
		"adrp x3, environ\n"          /* x3 = &environ (high bits)                  */
		"str x2, [x3, #:lo12:environ]\n" /* store envp into environ                 */
		"mov x4, x2\n"       /* search for auxv (follows NULL after last env)       */
		"0:\n"
		"ldr x5, [x4], 8\n"  // x5 = *x4; x4 += 8
		"cbnz x5, 0b\n"      // and stop at NULL after last env
		"adrp x3, _auxv\n"   // x3 = &_auxv (high bits)
		"str x4, [x3, #:lo12:_auxv]\n" // store x4 into _auxv
		"and sp, x1, -16\n"  // sp must be 16-byte aligned in the callee
		"bl main\n"          // main() returns the status code, we'll exit with it.
		"mov x8, 93\n"       // NR_exit == 93
		"ldr x5, [x4], 8\n"  /* x5 = *x4; x4 += 8                                   */
		"cbnz x5, 0b\n"      /* and stop at NULL after last env                     */
		"adrp x3, _auxv\n"   /* x3 = &_auxv (high bits)                             */
		"str x4, [x3, #:lo12:_auxv]\n" /* store x4 into _auxv                       */
		"and sp, x1, -16\n"  /* sp must be 16-byte aligned in the callee            */
		"bl main\n"          /* main() returns the status code, we'll exit with it. */
		"mov x8, 93\n"       /* NR_exit == 93                                       */
		"svc #0\n"
	);
	__builtin_unreachable();
}
#endif // _NOLIBC_ARCH_AARCH64_H
#endif /* _NOLIBC_ARCH_AARCH64_H */
+51 −23
Original line number Diff line number Diff line
@@ -7,6 +7,8 @@
#ifndef _NOLIBC_ARCH_ARM_H
#define _NOLIBC_ARCH_ARM_H

#include "compiler.h"

/* The struct returned by the stat() syscall, 32-bit only, the syscall returns
 * exactly 56 bytes (stops before the unused array). In big endian, the format
 * differs as devices are returned as short only.
@@ -196,41 +198,67 @@ struct sys_stat_struct {
	_arg1;                                                                \
})

#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6)                  \
({                                                                            \
	register long _num  __asm__(_NOLIBC_SYSCALL_REG) = (num);             \
	register long _arg1 __asm__ ("r0") = (long)(arg1);                    \
	register long _arg2 __asm__ ("r1") = (long)(arg2);                    \
	register long _arg3 __asm__ ("r2") = (long)(arg3);                    \
	register long _arg4 __asm__ ("r3") = (long)(arg4);                    \
	register long _arg5 __asm__ ("r4") = (long)(arg5);                    \
	register long _arg6 __asm__ ("r5") = (long)(arg6);                    \
	                                                                      \
	__asm__  volatile (                                                   \
		_NOLIBC_THUMB_SET_R7                                          \
		"svc #0\n"                                                    \
		_NOLIBC_THUMB_RESTORE_R7                                      \
		: "=r"(_arg1), "=r" (_num)                                    \
		: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
		  "r"(_arg6), "r"(_num)                                       \
		: "memory", "cc", "lr"                                        \
	);                                                                    \
	_arg1;                                                                \
})


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

/* startup code */
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void)
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
{
	__asm__ volatile (
		"pop {%r0}\n"                 // argc was in the stack
		"mov %r1, %sp\n"              // argv = sp
#ifdef _NOLIBC_STACKPROTECTOR
		"bl __stack_chk_init\n"       /* initialize stack protector                          */
#endif
		"pop {%r0}\n"                 /* argc was in the stack                               */
		"mov %r1, %sp\n"              /* argv = sp                                           */

		"add %r2, %r0, $1\n"          // envp = (argc + 1) ...
		"lsl %r2, %r2, $2\n"          //        * 4        ...
		"add %r2, %r2, %r1\n"         //        + argv
		"ldr %r3, 1f\n"               // r3 = &environ (see below)
		"str %r2, [r3]\n"             // store envp into environ
		"add %r2, %r0, $1\n"          /* envp = (argc + 1) ...                               */
		"lsl %r2, %r2, $2\n"          /*        * 4        ...                               */
		"add %r2, %r2, %r1\n"         /*        + argv                                       */
		"ldr %r3, 1f\n"               /* r3 = &environ (see below)                           */
		"str %r2, [r3]\n"             /* store envp into environ                             */

		"mov r4, r2\n"                // search for auxv (follows NULL after last env)
		"mov r4, r2\n"                /* search for auxv (follows NULL after last env)       */
		"0:\n"
		"mov r5, r4\n"                // r5 = r4
		"add r4, r4, #4\n"            // r4 += 4
		"ldr r5,[r5]\n"               // r5 = *r5 = *(r4-4)
		"cmp r5, #0\n"                // and stop at NULL after last env
		"mov r5, r4\n"                /* r5 = r4                                             */
		"add r4, r4, #4\n"            /* r4 += 4                                             */
		"ldr r5,[r5]\n"               /* r5 = *r5 = *(r4-4)                                  */
		"cmp r5, #0\n"                /* and stop at NULL after last env                     */
		"bne 0b\n"
		"ldr %r3, 2f\n"               // r3 = &_auxv (low bits)
		"str r4, [r3]\n"              // store r4 into _auxv
		"ldr %r3, 2f\n"               /* r3 = &_auxv (low bits)                              */
		"str r4, [r3]\n"              /* store r4 into _auxv                                 */

		"mov %r3, $8\n"               // AAPCS : sp must be 8-byte aligned in the
		"neg %r3, %r3\n"              //         callee, and bl doesn't push (lr=pc)
		"and %r3, %r3, %r1\n"         // so we do sp = r1(=sp) & r3(=-8);
		"mov %sp, %r3\n"              //
		"mov %r3, $8\n"               /* AAPCS : sp must be 8-byte aligned in the            */
		"neg %r3, %r3\n"              /*         callee, and bl doesn't push (lr=pc)         */
		"and %r3, %r3, %r1\n"         /* so we do sp = r1(=sp) & r3(=-8);                    */
		"mov %sp, %r3\n"

		"bl main\n"                   // main() returns the status code, we'll exit with it.
		"movs r7, $1\n"               // NR_exit == 1
		"bl main\n"                   /* main() returns the status code, we'll exit with it. */
		"movs r7, $1\n"               /* NR_exit == 1                                        */
		"svc $0x00\n"
		".align 2\n"                  // below are the pointers to a few variables
		".align 2\n"                  /* below are the pointers to a few variables           */
		"1:\n"
		".word environ\n"
		"2:\n"
@@ -239,4 +267,4 @@ void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void)
	__builtin_unreachable();
}

#endif // _NOLIBC_ARCH_ARM_H
#endif /* _NOLIBC_ARCH_ARM_H */
+24 −24
Original line number Diff line number Diff line
@@ -7,6 +7,8 @@
#ifndef _NOLIBC_ARCH_I386_H
#define _NOLIBC_ARCH_I386_H

#include "compiler.h"

/* The struct returned by the stat() syscall, 32-bit only, the syscall returns
 * exactly 56 bytes (stops before the unused array).
 */
@@ -181,8 +183,6 @@ struct sys_stat_struct {
char **environ __attribute__((weak));
const unsigned long *_auxv __attribute__((weak));

#define __ARCH_SUPPORTS_STACK_PROTECTOR

/* startup code */
/*
 * i386 System V ABI mandates:
@@ -190,35 +190,35 @@ const unsigned long *_auxv __attribute__((weak));
 * 2) The deepest stack frame should be set to zero
 *
 */
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"),no_stack_protector)) _start(void)
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
{
	__asm__ volatile (
#ifdef NOLIBC_STACKPROTECTOR
		"call __stack_chk_init\n"   // initialize stack protector
#ifdef _NOLIBC_STACKPROTECTOR
		"call __stack_chk_init\n"   /* initialize stack protector                    */
#endif
		"pop %eax\n"                // argc   (first arg, %eax)
		"mov %esp, %ebx\n"          // argv[] (second arg, %ebx)
		"lea 4(%ebx,%eax,4),%ecx\n" // then a NULL then envp (third arg, %ecx)
		"mov %ecx, environ\n"       // save environ
		"xor %ebp, %ebp\n"          // zero the stack frame
		"mov %ecx, %edx\n"          // search for auxv (follows NULL after last env)
		"pop %eax\n"                /* argc   (first arg, %eax)                      */
		"mov %esp, %ebx\n"          /* argv[] (second arg, %ebx)                     */
		"lea 4(%ebx,%eax,4),%ecx\n" /* then a NULL then envp (third arg, %ecx)       */
		"mov %ecx, environ\n"       /* save environ                                  */
		"xor %ebp, %ebp\n"          /* zero the stack frame                          */
		"mov %ecx, %edx\n"          /* search for auxv (follows NULL after last env) */
		"0:\n"
		"add $4, %edx\n"            // search for auxv using edx, it follows the
		"cmp -4(%edx), %ebp\n"      // ... NULL after last env (ebp is zero here)
		"add $4, %edx\n"            /* search for auxv using edx, it follows the     */
		"cmp -4(%edx), %ebp\n"      /* ... NULL after last env (ebp is zero here)    */
		"jnz 0b\n"
		"mov %edx, _auxv\n"         // save it into _auxv
		"and $-16, %esp\n"          // x86 ABI : esp must be 16-byte aligned before
		"sub $4, %esp\n"            // the call instruction (args are aligned)
		"push %ecx\n"               // push all registers on the stack so that we
		"push %ebx\n"               // support both regparm and plain stack modes
		"mov %edx, _auxv\n"         /* save it into _auxv                            */
		"and $-16, %esp\n"          /* x86 ABI : esp must be 16-byte aligned before  */
		"sub $4, %esp\n"            /* the call instruction (args are aligned)       */
		"push %ecx\n"               /* push all registers on the stack so that we    */
		"push %ebx\n"               /* support both regparm and plain stack modes    */
		"push %eax\n"
		"call main\n"               // main() returns the status code in %eax
		"mov %eax, %ebx\n"          // retrieve exit code (32-bit int)
		"movl $1, %eax\n"           // NR_exit == 1
		"int $0x80\n"               // exit now
		"hlt\n"                     // ensure it does not
		"call main\n"               /* main() returns the status code in %eax        */
		"mov %eax, %ebx\n"          /* retrieve exit code (32-bit int)               */
		"movl $1, %eax\n"           /* NR_exit == 1                                  */
		"int $0x80\n"               /* exit now                                      */
		"hlt\n"                     /* ensure it does not                            */
	);
	__builtin_unreachable();
}

#endif // _NOLIBC_ARCH_I386_H
#endif /* _NOLIBC_ARCH_I386_H */
+27 −22
Original line number Diff line number Diff line
@@ -7,6 +7,8 @@
#ifndef _NOLIBC_ARCH_LOONGARCH_H
#define _NOLIBC_ARCH_LOONGARCH_H

#include "compiler.h"

/* Syscalls for LoongArch :
 *   - stack is 16-byte aligned
 *   - syscall number is passed in a7
@@ -158,7 +160,7 @@ const unsigned long *_auxv __attribute__((weak));
#define LONG_ADDI    "addi.w"
#define LONG_SLL     "slli.w"
#define LONG_BSTRINS "bstrins.w"
#else // __loongarch_grlen == 64
#else /* __loongarch_grlen == 64 */
#define LONGLOG      "3"
#define SZREG        "8"
#define REG_L        "ld.d"
@@ -170,31 +172,34 @@ const unsigned long *_auxv __attribute__((weak));
#endif

/* startup code */
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void)
void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
{
	__asm__ volatile (
		REG_L        " $a0, $sp, 0\n"         // argc (a0) was in the stack
		LONG_ADDI    " $a1, $sp, "SZREG"\n"   // argv (a1) = sp + SZREG
		LONG_SLL     " $a2, $a0, "LONGLOG"\n" // envp (a2) = SZREG*argc ...
		LONG_ADDI    " $a2, $a2, "SZREG"\n"   //             + SZREG (skip null)
		LONG_ADD     " $a2, $a2, $a1\n"       //             + argv

		"move          $a3, $a2\n"            // iterate a3 over envp to find auxv (after NULL)
		"0:\n"                                // do {
		REG_L        " $a4, $a3, 0\n"         //   a4 = *a3;
		LONG_ADDI    " $a3, $a3, "SZREG"\n"   //   a3 += sizeof(void*);
		"bne           $a4, $zero, 0b\n"      // } while (a4);
		"la.pcrel      $a4, _auxv\n"          // a4 = &_auxv
		LONG_S       " $a3, $a4, 0\n"         // store a3 into _auxv

		"la.pcrel      $a3, environ\n"        // a3 = &environ
		LONG_S       " $a2, $a3, 0\n"         // store envp(a2) into environ
		LONG_BSTRINS " $sp, $zero, 3, 0\n"    // sp must be 16-byte aligned
		"bl            main\n"                // main() returns the status code, we'll exit with it.
		"li.w          $a7, 93\n"             // NR_exit == 93
#ifdef _NOLIBC_STACKPROTECTOR
		"bl __stack_chk_init\n"               /* initialize stack protector                          */
#endif
		REG_L        " $a0, $sp, 0\n"         /* argc (a0) was in the stack                          */
		LONG_ADDI    " $a1, $sp, "SZREG"\n"   /* argv (a1) = sp + SZREG                              */
		LONG_SLL     " $a2, $a0, "LONGLOG"\n" /* envp (a2) = SZREG*argc ...                          */
		LONG_ADDI    " $a2, $a2, "SZREG"\n"   /*             + SZREG (skip null)                     */
		LONG_ADD     " $a2, $a2, $a1\n"       /*             + argv                                  */

		"move          $a3, $a2\n"            /* iterate a3 over envp to find auxv (after NULL)      */
		"0:\n"                                /* do {                                                */
		REG_L        " $a4, $a3, 0\n"         /*   a4 = *a3;                                         */
		LONG_ADDI    " $a3, $a3, "SZREG"\n"   /*   a3 += sizeof(void*);                              */
		"bne           $a4, $zero, 0b\n"      /* } while (a4);                                       */
		"la.pcrel      $a4, _auxv\n"          /* a4 = &_auxv                                         */
		LONG_S       " $a3, $a4, 0\n"         /* store a3 into _auxv                                 */

		"la.pcrel      $a3, environ\n"        /* a3 = &environ                                       */
		LONG_S       " $a2, $a3, 0\n"         /* store envp(a2) into environ                         */
		LONG_BSTRINS " $sp, $zero, 3, 0\n"    /* sp must be 16-byte aligned                          */
		"bl            main\n"                /* main() returns the status code, we'll exit with it. */
		"li.w          $a7, 93\n"             /* NR_exit == 93                                       */
		"syscall       0\n"
	);
	__builtin_unreachable();
}

#endif // _NOLIBC_ARCH_LOONGARCH_H
#endif /* _NOLIBC_ARCH_LOONGARCH_H */
Loading