Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'linux-kselftest-nolibc-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest

Pull nolibc updates from Shuah Khan:
"Nolibc:
- improved portability by removing build errors with -ENOSYS
- added syscall6() on MIPS to support pselect6() and mmap()
- added setvbuf(), rmdir(), pipe(), pipe2()
- add support for ppc/ppc64
- environ is no longer optional
- fixed frame pointer issues at -O0
- dropped sys_stat() in favor of sys_statx()
- centralized _start_c() to remove lots of asm code
- switched size_t to __SIZE_TYPE__

Selftests:
- improved status reporting (success/warning/failure counts, path to
log file)
- various code cleanups (indent, unused variables, ...)
- more consistent test numbering
- enabled compiler warnings
- dropped unreliable chmod_net test
- improved reliability (create /dev/zero & /tmp, rely less on /proc)
- new tests (brk/sbrk/mmap/munmap)
- improved compatibility with musl
- new run-nolibc-test target to build and run natively
- new run-libc-test target to build and run against native libc
- made the cmdline parser more reliable against boolean arguments
- dropped dependency on memfd for vfprintf() test
- nolibc-test is no longer stripped
- added support for extending ARCH via XARCH

Other:
- add Thomas as co-maintainer"

* tag 'linux-kselftest-nolibc-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest: (103 commits)
tools/nolibc: avoid undesired casts in the __sysret() macro
tools/nolibc: keep brk(), sbrk(), mmap() away from __sysret()
tools/nolibc: silence ppc64 compile warnings
selftests/nolibc: libc-test: use HOSTCC instead of CC
tools/nolibc: stackprotector.h: make __stack_chk_init static
selftests/nolibc: allow report with existing test log
selftests/nolibc: add test support for ppc64
selftests/nolibc: add test support for ppc64le
selftests/nolibc: add test support for ppc
selftests/nolibc: add XARCH and ARCH mapping support
tools/nolibc: add support for powerpc64
tools/nolibc: add support for powerpc
MAINTAINERS: nolibc: add myself as co-maintainer
selftests/nolibc: enable compiler warnings
selftests/nolibc: don't strip nolibc-test
selftests/nolibc: prevent out of bounds access in expect_vfprintf
selftests/nolibc: use correct return type for read() and write()
selftests/nolibc: avoid sign-compare warnings
selftests/nolibc: avoid unused parameter warnings
selftests/nolibc: make functions static if possible
...

+1219 -1164
+1
MAINTAINERS
··· 15010 15010 15011 15011 NOLIBC HEADER FILE 15012 15012 M: Willy Tarreau <w@1wt.eu> 15013 + M: Thomas Weißschuh <linux@weissschuh.net> 15013 15014 S: Maintained 15014 15015 T: git git://git.kernel.org/pub/scm/linux/kernel/git/wtarreau/nolibc.git 15015 15016 F: tools/include/nolibc/
+1
tools/include/nolibc/Makefile
··· 27 27 arch_file := arch-$(nolibc_arch).h 28 28 all_files := \ 29 29 compiler.h \ 30 + crt.h \ 30 31 ctype.h \ 31 32 errno.h \ 32 33 nolibc.h \
+19 -66
tools/include/nolibc/arch-aarch64.h
··· 8 8 #define _NOLIBC_ARCH_AARCH64_H 9 9 10 10 #include "compiler.h" 11 - 12 - /* The struct returned by the newfstatat() syscall. Differs slightly from the 13 - * x86_64's stat one by field ordering, so be careful. 14 - */ 15 - struct sys_stat_struct { 16 - unsigned long st_dev; 17 - unsigned long st_ino; 18 - unsigned int st_mode; 19 - unsigned int st_nlink; 20 - unsigned int st_uid; 21 - unsigned int st_gid; 22 - 23 - unsigned long st_rdev; 24 - unsigned long __pad1; 25 - long st_size; 26 - int st_blksize; 27 - int __pad2; 28 - 29 - long st_blocks; 30 - long st_atime; 31 - unsigned long st_atime_nsec; 32 - long st_mtime; 33 - 34 - unsigned long st_mtime_nsec; 35 - long st_ctime; 36 - unsigned long st_ctime_nsec; 37 - unsigned int __unused[2]; 38 - }; 11 + #include "crt.h" 39 12 40 13 /* Syscalls for AARCH64 : 41 14 * - registers are 64-bit ··· 29 56 ({ \ 30 57 register long _num __asm__ ("x8") = (num); \ 31 58 register long _arg1 __asm__ ("x0"); \ 32 - \ 33 - __asm__ volatile ( \ 59 + \ 60 + __asm__ volatile ( \ 34 61 "svc #0\n" \ 35 62 : "=r"(_arg1) \ 36 63 : "r"(_num) \ ··· 43 70 ({ \ 44 71 register long _num __asm__ ("x8") = (num); \ 45 72 register long _arg1 __asm__ ("x0") = (long)(arg1); \ 46 - \ 47 - __asm__ volatile ( \ 73 + \ 74 + __asm__ volatile ( \ 48 75 "svc #0\n" \ 49 76 : "=r"(_arg1) \ 50 77 : "r"(_arg1), \ ··· 59 86 register long _num __asm__ ("x8") = (num); \ 60 87 register long _arg1 __asm__ ("x0") = (long)(arg1); \ 61 88 register long _arg2 __asm__ ("x1") = (long)(arg2); \ 62 - \ 63 - __asm__ volatile ( \ 89 + \ 90 + __asm__ volatile ( \ 64 91 "svc #0\n" \ 65 92 : "=r"(_arg1) \ 66 93 : "r"(_arg1), "r"(_arg2), \ ··· 76 103 register long _arg1 __asm__ ("x0") = (long)(arg1); \ 77 104 register long _arg2 __asm__ ("x1") = (long)(arg2); \ 78 105 register long _arg3 __asm__ ("x2") = (long)(arg3); \ 79 - \ 80 - __asm__ volatile ( \ 106 + \ 107 + __asm__ volatile ( \ 81 108 "svc #0\n" \ 82 109 : "=r"(_arg1) \ 83 110 : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ ··· 94 121 register long _arg2 __asm__ ("x1") = (long)(arg2); \ 95 122 register long _arg3 __asm__ ("x2") = (long)(arg3); \ 96 123 register long _arg4 __asm__ ("x3") = (long)(arg4); \ 97 - \ 98 - __asm__ volatile ( \ 124 + \ 125 + __asm__ volatile ( \ 99 126 "svc #0\n" \ 100 127 : "=r"(_arg1) \ 101 128 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ ··· 113 140 register long _arg3 __asm__ ("x2") = (long)(arg3); \ 114 141 register long _arg4 __asm__ ("x3") = (long)(arg4); \ 115 142 register long _arg5 __asm__ ("x4") = (long)(arg5); \ 116 - \ 117 - __asm__ volatile ( \ 143 + \ 144 + __asm__ volatile ( \ 118 145 "svc #0\n" \ 119 146 : "=r" (_arg1) \ 120 147 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ ··· 133 160 register long _arg4 __asm__ ("x3") = (long)(arg4); \ 134 161 register long _arg5 __asm__ ("x4") = (long)(arg5); \ 135 162 register long _arg6 __asm__ ("x5") = (long)(arg6); \ 136 - \ 137 - __asm__ volatile ( \ 163 + \ 164 + __asm__ volatile ( \ 138 165 "svc #0\n" \ 139 166 : "=r" (_arg1) \ 140 167 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ ··· 144 171 _arg1; \ 145 172 }) 146 173 147 - char **environ __attribute__((weak)); 148 - const unsigned long *_auxv __attribute__((weak)); 149 - 150 174 /* startup code */ 151 - void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void) 175 + void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) 152 176 { 153 177 __asm__ volatile ( 154 - #ifdef _NOLIBC_STACKPROTECTOR 155 - "bl __stack_chk_init\n" /* initialize stack protector */ 156 - #endif 157 - "ldr x0, [sp]\n" /* argc (x0) was in the stack */ 158 - "add x1, sp, 8\n" /* argv (x1) = sp */ 159 - "lsl x2, x0, 3\n" /* envp (x2) = 8*argc ... */ 160 - "add x2, x2, 8\n" /* + 8 (skip null) */ 161 - "add x2, x2, x1\n" /* + argv */ 162 - "adrp x3, environ\n" /* x3 = &environ (high bits) */ 163 - "str x2, [x3, #:lo12:environ]\n" /* store envp into environ */ 164 - "mov x4, x2\n" /* search for auxv (follows NULL after last env) */ 165 - "0:\n" 166 - "ldr x5, [x4], 8\n" /* x5 = *x4; x4 += 8 */ 167 - "cbnz x5, 0b\n" /* and stop at NULL after last env */ 168 - "adrp x3, _auxv\n" /* x3 = &_auxv (high bits) */ 169 - "str x4, [x3, #:lo12:_auxv]\n" /* store x4 into _auxv */ 170 - "and sp, x1, -16\n" /* sp must be 16-byte aligned in the callee */ 171 - "bl main\n" /* main() returns the status code, we'll exit with it. */ 172 - "mov x8, 93\n" /* NR_exit == 93 */ 173 - "svc #0\n" 178 + "mov x0, sp\n" /* save stack pointer to x0, as arg1 of _start_c */ 179 + "and sp, x0, -16\n" /* sp must be 16-byte aligned in the callee */ 180 + "bl _start_c\n" /* transfer to c runtime */ 174 181 ); 175 182 __builtin_unreachable(); 176 183 }
+20 -91
tools/include/nolibc/arch-arm.h
··· 8 8 #define _NOLIBC_ARCH_ARM_H 9 9 10 10 #include "compiler.h" 11 - 12 - /* The struct returned by the stat() syscall, 32-bit only, the syscall returns 13 - * exactly 56 bytes (stops before the unused array). In big endian, the format 14 - * differs as devices are returned as short only. 15 - */ 16 - struct sys_stat_struct { 17 - #if defined(__ARMEB__) 18 - unsigned short st_dev; 19 - unsigned short __pad1; 20 - #else 21 - unsigned long st_dev; 22 - #endif 23 - unsigned long st_ino; 24 - unsigned short st_mode; 25 - unsigned short st_nlink; 26 - unsigned short st_uid; 27 - unsigned short st_gid; 28 - 29 - #if defined(__ARMEB__) 30 - unsigned short st_rdev; 31 - unsigned short __pad2; 32 - #else 33 - unsigned long st_rdev; 34 - #endif 35 - unsigned long st_size; 36 - unsigned long st_blksize; 37 - unsigned long st_blocks; 38 - 39 - unsigned long st_atime; 40 - unsigned long st_atime_nsec; 41 - unsigned long st_mtime; 42 - unsigned long st_mtime_nsec; 43 - 44 - unsigned long st_ctime; 45 - unsigned long st_ctime_nsec; 46 - unsigned long __unused[2]; 47 - }; 11 + #include "crt.h" 48 12 49 13 /* Syscalls for ARM in ARM or Thumb modes : 50 14 * - registers are 32-bit ··· 54 90 ({ \ 55 91 register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ 56 92 register long _arg1 __asm__ ("r0"); \ 57 - \ 58 - __asm__ volatile ( \ 93 + \ 94 + __asm__ volatile ( \ 59 95 _NOLIBC_THUMB_SET_R7 \ 60 96 "svc #0\n" \ 61 97 _NOLIBC_THUMB_RESTORE_R7 \ ··· 71 107 ({ \ 72 108 register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ 73 109 register long _arg1 __asm__ ("r0") = (long)(arg1); \ 74 - \ 75 - __asm__ volatile ( \ 110 + \ 111 + __asm__ volatile ( \ 76 112 _NOLIBC_THUMB_SET_R7 \ 77 113 "svc #0\n" \ 78 114 _NOLIBC_THUMB_RESTORE_R7 \ ··· 89 125 register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ 90 126 register long _arg1 __asm__ ("r0") = (long)(arg1); \ 91 127 register long _arg2 __asm__ ("r1") = (long)(arg2); \ 92 - \ 93 - __asm__ volatile ( \ 128 + \ 129 + __asm__ volatile ( \ 94 130 _NOLIBC_THUMB_SET_R7 \ 95 131 "svc #0\n" \ 96 132 _NOLIBC_THUMB_RESTORE_R7 \ ··· 108 144 register long _arg1 __asm__ ("r0") = (long)(arg1); \ 109 145 register long _arg2 __asm__ ("r1") = (long)(arg2); \ 110 146 register long _arg3 __asm__ ("r2") = (long)(arg3); \ 111 - \ 112 - __asm__ volatile ( \ 147 + \ 148 + __asm__ volatile ( \ 113 149 _NOLIBC_THUMB_SET_R7 \ 114 150 "svc #0\n" \ 115 151 _NOLIBC_THUMB_RESTORE_R7 \ ··· 128 164 register long _arg2 __asm__ ("r1") = (long)(arg2); \ 129 165 register long _arg3 __asm__ ("r2") = (long)(arg3); \ 130 166 register long _arg4 __asm__ ("r3") = (long)(arg4); \ 131 - \ 132 - __asm__ volatile ( \ 167 + \ 168 + __asm__ volatile ( \ 133 169 _NOLIBC_THUMB_SET_R7 \ 134 170 "svc #0\n" \ 135 171 _NOLIBC_THUMB_RESTORE_R7 \ ··· 149 185 register long _arg3 __asm__ ("r2") = (long)(arg3); \ 150 186 register long _arg4 __asm__ ("r3") = (long)(arg4); \ 151 187 register long _arg5 __asm__ ("r4") = (long)(arg5); \ 152 - \ 153 - __asm__ volatile ( \ 188 + \ 189 + __asm__ volatile ( \ 154 190 _NOLIBC_THUMB_SET_R7 \ 155 191 "svc #0\n" \ 156 192 _NOLIBC_THUMB_RESTORE_R7 \ ··· 171 207 register long _arg4 __asm__ ("r3") = (long)(arg4); \ 172 208 register long _arg5 __asm__ ("r4") = (long)(arg5); \ 173 209 register long _arg6 __asm__ ("r5") = (long)(arg6); \ 174 - \ 175 - __asm__ volatile ( \ 210 + \ 211 + __asm__ volatile ( \ 176 212 _NOLIBC_THUMB_SET_R7 \ 177 213 "svc #0\n" \ 178 214 _NOLIBC_THUMB_RESTORE_R7 \ ··· 184 220 _arg1; \ 185 221 }) 186 222 187 - 188 - char **environ __attribute__((weak)); 189 - const unsigned long *_auxv __attribute__((weak)); 190 - 191 223 /* startup code */ 192 - void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void) 224 + void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) 193 225 { 194 226 __asm__ volatile ( 195 - #ifdef _NOLIBC_STACKPROTECTOR 196 - "bl __stack_chk_init\n" /* initialize stack protector */ 197 - #endif 198 - "pop {%r0}\n" /* argc was in the stack */ 199 - "mov %r1, %sp\n" /* argv = sp */ 200 - 201 - "add %r2, %r0, $1\n" /* envp = (argc + 1) ... */ 202 - "lsl %r2, %r2, $2\n" /* * 4 ... */ 203 - "add %r2, %r2, %r1\n" /* + argv */ 204 - "ldr %r3, 1f\n" /* r3 = &environ (see below) */ 205 - "str %r2, [r3]\n" /* store envp into environ */ 206 - 207 - "mov r4, r2\n" /* search for auxv (follows NULL after last env) */ 208 - "0:\n" 209 - "mov r5, r4\n" /* r5 = r4 */ 210 - "add r4, r4, #4\n" /* r4 += 4 */ 211 - "ldr r5,[r5]\n" /* r5 = *r5 = *(r4-4) */ 212 - "cmp r5, #0\n" /* and stop at NULL after last env */ 213 - "bne 0b\n" 214 - "ldr %r3, 2f\n" /* r3 = &_auxv (low bits) */ 215 - "str r4, [r3]\n" /* store r4 into _auxv */ 216 - 217 - "mov %r3, $8\n" /* AAPCS : sp must be 8-byte aligned in the */ 218 - "neg %r3, %r3\n" /* callee, and bl doesn't push (lr=pc) */ 219 - "and %r3, %r3, %r1\n" /* so we do sp = r1(=sp) & r3(=-8); */ 220 - "mov %sp, %r3\n" 221 - 222 - "bl main\n" /* main() returns the status code, we'll exit with it. */ 223 - "movs r7, $1\n" /* NR_exit == 1 */ 224 - "svc $0x00\n" 225 - ".align 2\n" /* below are the pointers to a few variables */ 226 - "1:\n" 227 - ".word environ\n" 228 - "2:\n" 229 - ".word _auxv\n" 227 + "mov %r0, sp\n" /* save stack pointer to %r0, as arg1 of _start_c */ 228 + "and ip, %r0, #-8\n" /* sp must be 8-byte aligned in the callee */ 229 + "mov sp, ip\n" 230 + "bl _start_c\n" /* transfer to c runtime */ 230 231 ); 231 232 __builtin_unreachable(); 232 233 }
+20 -66
tools/include/nolibc/arch-i386.h
··· 8 8 #define _NOLIBC_ARCH_I386_H 9 9 10 10 #include "compiler.h" 11 - 12 - /* The struct returned by the stat() syscall, 32-bit only, the syscall returns 13 - * exactly 56 bytes (stops before the unused array). 14 - */ 15 - struct sys_stat_struct { 16 - unsigned long st_dev; 17 - unsigned long st_ino; 18 - unsigned short st_mode; 19 - unsigned short st_nlink; 20 - unsigned short st_uid; 21 - unsigned short st_gid; 22 - 23 - unsigned long st_rdev; 24 - unsigned long st_size; 25 - unsigned long st_blksize; 26 - unsigned long st_blocks; 27 - 28 - unsigned long st_atime; 29 - unsigned long st_atime_nsec; 30 - unsigned long st_mtime; 31 - unsigned long st_mtime_nsec; 32 - 33 - unsigned long st_ctime; 34 - unsigned long st_ctime_nsec; 35 - unsigned long __unused[2]; 36 - }; 11 + #include "crt.h" 37 12 38 13 /* Syscalls for i386 : 39 14 * - mostly similar to x86_64 ··· 32 57 ({ \ 33 58 long _ret; \ 34 59 register long _num __asm__ ("eax") = (num); \ 35 - \ 36 - __asm__ volatile ( \ 60 + \ 61 + __asm__ volatile ( \ 37 62 "int $0x80\n" \ 38 63 : "=a" (_ret) \ 39 64 : "0"(_num) \ ··· 47 72 long _ret; \ 48 73 register long _num __asm__ ("eax") = (num); \ 49 74 register long _arg1 __asm__ ("ebx") = (long)(arg1); \ 50 - \ 51 - __asm__ volatile ( \ 75 + \ 76 + __asm__ volatile ( \ 52 77 "int $0x80\n" \ 53 78 : "=a" (_ret) \ 54 79 : "r"(_arg1), \ ··· 64 89 register long _num __asm__ ("eax") = (num); \ 65 90 register long _arg1 __asm__ ("ebx") = (long)(arg1); \ 66 91 register long _arg2 __asm__ ("ecx") = (long)(arg2); \ 67 - \ 68 - __asm__ volatile ( \ 92 + \ 93 + __asm__ volatile ( \ 69 94 "int $0x80\n" \ 70 95 : "=a" (_ret) \ 71 96 : "r"(_arg1), "r"(_arg2), \ ··· 82 107 register long _arg1 __asm__ ("ebx") = (long)(arg1); \ 83 108 register long _arg2 __asm__ ("ecx") = (long)(arg2); \ 84 109 register long _arg3 __asm__ ("edx") = (long)(arg3); \ 85 - \ 86 - __asm__ volatile ( \ 110 + \ 111 + __asm__ volatile ( \ 87 112 "int $0x80\n" \ 88 113 : "=a" (_ret) \ 89 114 : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ ··· 101 126 register long _arg2 __asm__ ("ecx") = (long)(arg2); \ 102 127 register long _arg3 __asm__ ("edx") = (long)(arg3); \ 103 128 register long _arg4 __asm__ ("esi") = (long)(arg4); \ 104 - \ 105 - __asm__ volatile ( \ 129 + \ 130 + __asm__ volatile ( \ 106 131 "int $0x80\n" \ 107 132 : "=a" (_ret) \ 108 133 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ ··· 121 146 register long _arg3 __asm__ ("edx") = (long)(arg3); \ 122 147 register long _arg4 __asm__ ("esi") = (long)(arg4); \ 123 148 register long _arg5 __asm__ ("edi") = (long)(arg5); \ 124 - \ 125 - __asm__ volatile ( \ 149 + \ 150 + __asm__ volatile ( \ 126 151 "int $0x80\n" \ 127 152 : "=a" (_ret) \ 128 153 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ ··· 155 180 _eax; \ 156 181 }) 157 182 158 - char **environ __attribute__((weak)); 159 - const unsigned long *_auxv __attribute__((weak)); 160 - 161 183 /* startup code */ 162 184 /* 163 185 * i386 System V ABI mandates: ··· 162 190 * 2) The deepest stack frame should be set to zero 163 191 * 164 192 */ 165 - void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void) 193 + void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) 166 194 { 167 195 __asm__ volatile ( 168 - #ifdef _NOLIBC_STACKPROTECTOR 169 - "call __stack_chk_init\n" /* initialize stack protector */ 170 - #endif 171 - "pop %eax\n" /* argc (first arg, %eax) */ 172 - "mov %esp, %ebx\n" /* argv[] (second arg, %ebx) */ 173 - "lea 4(%ebx,%eax,4),%ecx\n" /* then a NULL then envp (third arg, %ecx) */ 174 - "mov %ecx, environ\n" /* save environ */ 175 - "xor %ebp, %ebp\n" /* zero the stack frame */ 176 - "mov %ecx, %edx\n" /* search for auxv (follows NULL after last env) */ 177 - "0:\n" 178 - "add $4, %edx\n" /* search for auxv using edx, it follows the */ 179 - "cmp -4(%edx), %ebp\n" /* ... NULL after last env (ebp is zero here) */ 180 - "jnz 0b\n" 181 - "mov %edx, _auxv\n" /* save it into _auxv */ 182 - "and $-16, %esp\n" /* x86 ABI : esp must be 16-byte aligned before */ 183 - "sub $4, %esp\n" /* the call instruction (args are aligned) */ 184 - "push %ecx\n" /* push all registers on the stack so that we */ 185 - "push %ebx\n" /* support both regparm and plain stack modes */ 186 - "push %eax\n" 187 - "call main\n" /* main() returns the status code in %eax */ 188 - "mov %eax, %ebx\n" /* retrieve exit code (32-bit int) */ 189 - "movl $1, %eax\n" /* NR_exit == 1 */ 190 - "int $0x80\n" /* exit now */ 191 - "hlt\n" /* ensure it does not */ 196 + "xor %ebp, %ebp\n" /* zero the stack frame */ 197 + "mov %esp, %eax\n" /* save stack pointer to %eax, as arg1 of _start_c */ 198 + "and $-16, %esp\n" /* last pushed argument must be 16-byte aligned */ 199 + "push %eax\n" /* push arg1 on stack to support plain stack modes too */ 200 + "call _start_c\n" /* transfer to c runtime */ 201 + "hlt\n" /* ensure it does not return */ 192 202 ); 193 203 __builtin_unreachable(); 194 204 }
+21 -62
tools/include/nolibc/arch-loongarch.h
··· 8 8 #define _NOLIBC_ARCH_LOONGARCH_H 9 9 10 10 #include "compiler.h" 11 + #include "crt.h" 11 12 12 13 /* Syscalls for LoongArch : 13 14 * - stack is 16-byte aligned ··· 23 22 * On LoongArch, select() is not implemented so we have to use pselect6(). 24 23 */ 25 24 #define __ARCH_WANT_SYS_PSELECT6 25 + #define _NOLIBC_SYSCALL_CLOBBERLIST \ 26 + "memory", "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8" 26 27 27 28 #define my_syscall0(num) \ 28 29 ({ \ 29 30 register long _num __asm__ ("a7") = (num); \ 30 31 register long _arg1 __asm__ ("a0"); \ 31 32 \ 32 - __asm__ volatile ( \ 33 + __asm__ volatile ( \ 33 34 "syscall 0\n" \ 34 35 : "=r"(_arg1) \ 35 36 : "r"(_num) \ 36 - : "memory", "$t0", "$t1", "$t2", "$t3", \ 37 - "$t4", "$t5", "$t6", "$t7", "$t8" \ 37 + : _NOLIBC_SYSCALL_CLOBBERLIST \ 38 38 ); \ 39 39 _arg1; \ 40 40 }) ··· 45 43 register long _num __asm__ ("a7") = (num); \ 46 44 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 47 45 \ 48 - __asm__ volatile ( \ 46 + __asm__ volatile ( \ 49 47 "syscall 0\n" \ 50 48 : "+r"(_arg1) \ 51 49 : "r"(_num) \ 52 - : "memory", "$t0", "$t1", "$t2", "$t3", \ 53 - "$t4", "$t5", "$t6", "$t7", "$t8" \ 50 + : _NOLIBC_SYSCALL_CLOBBERLIST \ 54 51 ); \ 55 52 _arg1; \ 56 53 }) ··· 60 59 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 61 60 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 62 61 \ 63 - __asm__ volatile ( \ 62 + __asm__ volatile ( \ 64 63 "syscall 0\n" \ 65 64 : "+r"(_arg1) \ 66 65 : "r"(_arg2), \ 67 66 "r"(_num) \ 68 - : "memory", "$t0", "$t1", "$t2", "$t3", \ 69 - "$t4", "$t5", "$t6", "$t7", "$t8" \ 67 + : _NOLIBC_SYSCALL_CLOBBERLIST \ 70 68 ); \ 71 69 _arg1; \ 72 70 }) ··· 77 77 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 78 78 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 79 79 \ 80 - __asm__ volatile ( \ 80 + __asm__ volatile ( \ 81 81 "syscall 0\n" \ 82 82 : "+r"(_arg1) \ 83 83 : "r"(_arg2), "r"(_arg3), \ 84 84 "r"(_num) \ 85 - : "memory", "$t0", "$t1", "$t2", "$t3", \ 86 - "$t4", "$t5", "$t6", "$t7", "$t8" \ 85 + : _NOLIBC_SYSCALL_CLOBBERLIST \ 87 86 ); \ 88 87 _arg1; \ 89 88 }) ··· 95 96 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 96 97 register long _arg4 __asm__ ("a3") = (long)(arg4); \ 97 98 \ 98 - __asm__ volatile ( \ 99 + __asm__ volatile ( \ 99 100 "syscall 0\n" \ 100 101 : "+r"(_arg1) \ 101 102 : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ 102 103 "r"(_num) \ 103 - : "memory", "$t0", "$t1", "$t2", "$t3", \ 104 - "$t4", "$t5", "$t6", "$t7", "$t8" \ 104 + : _NOLIBC_SYSCALL_CLOBBERLIST \ 105 105 ); \ 106 106 _arg1; \ 107 107 }) ··· 114 116 register long _arg4 __asm__ ("a3") = (long)(arg4); \ 115 117 register long _arg5 __asm__ ("a4") = (long)(arg5); \ 116 118 \ 117 - __asm__ volatile ( \ 119 + __asm__ volatile ( \ 118 120 "syscall 0\n" \ 119 121 : "+r"(_arg1) \ 120 122 : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ 121 123 "r"(_num) \ 122 - : "memory", "$t0", "$t1", "$t2", "$t3", \ 123 - "$t4", "$t5", "$t6", "$t7", "$t8" \ 124 + : _NOLIBC_SYSCALL_CLOBBERLIST \ 124 125 ); \ 125 126 _arg1; \ 126 127 }) ··· 134 137 register long _arg5 __asm__ ("a4") = (long)(arg5); \ 135 138 register long _arg6 __asm__ ("a5") = (long)(arg6); \ 136 139 \ 137 - __asm__ volatile ( \ 140 + __asm__ volatile ( \ 138 141 "syscall 0\n" \ 139 142 : "+r"(_arg1) \ 140 143 : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ 141 144 "r"(_num) \ 142 - : "memory", "$t0", "$t1", "$t2", "$t3", \ 143 - "$t4", "$t5", "$t6", "$t7", "$t8" \ 145 + : _NOLIBC_SYSCALL_CLOBBERLIST \ 144 146 ); \ 145 147 _arg1; \ 146 148 }) 147 149 148 - char **environ __attribute__((weak)); 149 - const unsigned long *_auxv __attribute__((weak)); 150 - 151 150 #if __loongarch_grlen == 32 152 - #define LONGLOG "2" 153 - #define SZREG "4" 154 - #define REG_L "ld.w" 155 - #define LONG_S "st.w" 156 - #define LONG_ADD "add.w" 157 - #define LONG_ADDI "addi.w" 158 - #define LONG_SLL "slli.w" 159 151 #define LONG_BSTRINS "bstrins.w" 160 152 #else /* __loongarch_grlen == 64 */ 161 - #define LONGLOG "3" 162 - #define SZREG "8" 163 - #define REG_L "ld.d" 164 - #define LONG_S "st.d" 165 - #define LONG_ADD "add.d" 166 - #define LONG_ADDI "addi.d" 167 - #define LONG_SLL "slli.d" 168 153 #define LONG_BSTRINS "bstrins.d" 169 154 #endif 170 155 171 156 /* startup code */ 172 - void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void) 157 + void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) 173 158 { 174 159 __asm__ volatile ( 175 - #ifdef _NOLIBC_STACKPROTECTOR 176 - "bl __stack_chk_init\n" /* initialize stack protector */ 177 - #endif 178 - REG_L " $a0, $sp, 0\n" /* argc (a0) was in the stack */ 179 - LONG_ADDI " $a1, $sp, "SZREG"\n" /* argv (a1) = sp + SZREG */ 180 - LONG_SLL " $a2, $a0, "LONGLOG"\n" /* envp (a2) = SZREG*argc ... */ 181 - LONG_ADDI " $a2, $a2, "SZREG"\n" /* + SZREG (skip null) */ 182 - LONG_ADD " $a2, $a2, $a1\n" /* + argv */ 183 - 184 - "move $a3, $a2\n" /* iterate a3 over envp to find auxv (after NULL) */ 185 - "0:\n" /* do { */ 186 - REG_L " $a4, $a3, 0\n" /* a4 = *a3; */ 187 - LONG_ADDI " $a3, $a3, "SZREG"\n" /* a3 += sizeof(void*); */ 188 - "bne $a4, $zero, 0b\n" /* } while (a4); */ 189 - "la.pcrel $a4, _auxv\n" /* a4 = &_auxv */ 190 - LONG_S " $a3, $a4, 0\n" /* store a3 into _auxv */ 191 - 192 - "la.pcrel $a3, environ\n" /* a3 = &environ */ 193 - LONG_S " $a2, $a3, 0\n" /* store envp(a2) into environ */ 194 - LONG_BSTRINS " $sp, $zero, 3, 0\n" /* sp must be 16-byte aligned */ 195 - "bl main\n" /* main() returns the status code, we'll exit with it. */ 196 - "li.w $a7, 93\n" /* NR_exit == 93 */ 197 - "syscall 0\n" 160 + "move $a0, $sp\n" /* save stack pointer to $a0, as arg1 of _start_c */ 161 + LONG_BSTRINS " $sp, $zero, 3, 0\n" /* $sp must be 16-byte aligned */ 162 + "bl _start_c\n" /* transfer to c runtime */ 198 163 ); 199 164 __builtin_unreachable(); 200 165 }
+56 -91
tools/include/nolibc/arch-mips.h
··· 8 8 #define _NOLIBC_ARCH_MIPS_H 9 9 10 10 #include "compiler.h" 11 - 12 - /* The struct returned by the stat() syscall. 88 bytes are returned by the 13 - * syscall. 14 - */ 15 - struct sys_stat_struct { 16 - unsigned int st_dev; 17 - long st_pad1[3]; 18 - unsigned long st_ino; 19 - unsigned int st_mode; 20 - unsigned int st_nlink; 21 - unsigned int st_uid; 22 - unsigned int st_gid; 23 - unsigned int st_rdev; 24 - long st_pad2[2]; 25 - long st_size; 26 - long st_pad3; 27 - 28 - long st_atime; 29 - long st_atime_nsec; 30 - long st_mtime; 31 - long st_mtime_nsec; 32 - 33 - long st_ctime; 34 - long st_ctime_nsec; 35 - long st_blksize; 36 - long st_blocks; 37 - long st_pad4[14]; 38 - }; 11 + #include "crt.h" 39 12 40 13 /* Syscalls for MIPS ABI O32 : 41 14 * - WARNING! there's always a delayed slot! ··· 30 57 * don't have to experience issues with register constraints. 31 58 */ 32 59 60 + #define _NOLIBC_SYSCALL_CLOBBERLIST \ 61 + "memory", "cc", "at", "v1", "hi", "lo", \ 62 + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" 63 + 33 64 #define my_syscall0(num) \ 34 65 ({ \ 35 66 register long _num __asm__ ("v0") = (num); \ 36 67 register long _arg4 __asm__ ("a3"); \ 37 - \ 38 - __asm__ volatile ( \ 68 + \ 69 + __asm__ volatile ( \ 39 70 "addiu $sp, $sp, -32\n" \ 40 71 "syscall\n" \ 41 72 "addiu $sp, $sp, 32\n" \ 42 73 : "=r"(_num), "=r"(_arg4) \ 43 74 : "r"(_num) \ 44 - : "memory", "cc", "at", "v1", "hi", "lo", \ 45 - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ 75 + : _NOLIBC_SYSCALL_CLOBBERLIST \ 46 76 ); \ 47 77 _arg4 ? -_num : _num; \ 48 78 }) ··· 55 79 register long _num __asm__ ("v0") = (num); \ 56 80 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 57 81 register long _arg4 __asm__ ("a3"); \ 58 - \ 59 - __asm__ volatile ( \ 82 + \ 83 + __asm__ volatile ( \ 60 84 "addiu $sp, $sp, -32\n" \ 61 85 "syscall\n" \ 62 86 "addiu $sp, $sp, 32\n" \ 63 87 : "=r"(_num), "=r"(_arg4) \ 64 88 : "0"(_num), \ 65 89 "r"(_arg1) \ 66 - : "memory", "cc", "at", "v1", "hi", "lo", \ 67 - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ 90 + : _NOLIBC_SYSCALL_CLOBBERLIST \ 68 91 ); \ 69 92 _arg4 ? -_num : _num; \ 70 93 }) ··· 74 99 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 75 100 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 76 101 register long _arg4 __asm__ ("a3"); \ 77 - \ 78 - __asm__ volatile ( \ 102 + \ 103 + __asm__ volatile ( \ 79 104 "addiu $sp, $sp, -32\n" \ 80 105 "syscall\n" \ 81 106 "addiu $sp, $sp, 32\n" \ 82 107 : "=r"(_num), "=r"(_arg4) \ 83 108 : "0"(_num), \ 84 109 "r"(_arg1), "r"(_arg2) \ 85 - : "memory", "cc", "at", "v1", "hi", "lo", \ 86 - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ 110 + : _NOLIBC_SYSCALL_CLOBBERLIST \ 87 111 ); \ 88 112 _arg4 ? -_num : _num; \ 89 113 }) ··· 94 120 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 95 121 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 96 122 register long _arg4 __asm__ ("a3"); \ 97 - \ 98 - __asm__ volatile ( \ 123 + \ 124 + __asm__ volatile ( \ 99 125 "addiu $sp, $sp, -32\n" \ 100 126 "syscall\n" \ 101 127 "addiu $sp, $sp, 32\n" \ 102 128 : "=r"(_num), "=r"(_arg4) \ 103 129 : "0"(_num), \ 104 130 "r"(_arg1), "r"(_arg2), "r"(_arg3) \ 105 - : "memory", "cc", "at", "v1", "hi", "lo", \ 106 - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ 131 + : _NOLIBC_SYSCALL_CLOBBERLIST \ 107 132 ); \ 108 133 _arg4 ? -_num : _num; \ 109 134 }) ··· 114 141 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 115 142 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 116 143 register long _arg4 __asm__ ("a3") = (long)(arg4); \ 117 - \ 118 - __asm__ volatile ( \ 144 + \ 145 + __asm__ volatile ( \ 119 146 "addiu $sp, $sp, -32\n" \ 120 147 "syscall\n" \ 121 148 "addiu $sp, $sp, 32\n" \ 122 149 : "=r" (_num), "=r"(_arg4) \ 123 150 : "0"(_num), \ 124 151 "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4) \ 125 - : "memory", "cc", "at", "v1", "hi", "lo", \ 126 - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ 152 + : _NOLIBC_SYSCALL_CLOBBERLIST \ 127 153 ); \ 128 154 _arg4 ? -_num : _num; \ 129 155 }) ··· 135 163 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 136 164 register long _arg4 __asm__ ("a3") = (long)(arg4); \ 137 165 register long _arg5 = (long)(arg5); \ 138 - \ 139 - __asm__ volatile ( \ 166 + \ 167 + __asm__ volatile ( \ 140 168 "addiu $sp, $sp, -32\n" \ 141 169 "sw %7, 16($sp)\n" \ 142 - "syscall\n " \ 170 + "syscall\n" \ 143 171 "addiu $sp, $sp, 32\n" \ 144 172 : "=r" (_num), "=r"(_arg4) \ 145 173 : "0"(_num), \ 146 174 "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5) \ 147 - : "memory", "cc", "at", "v1", "hi", "lo", \ 148 - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ 175 + : _NOLIBC_SYSCALL_CLOBBERLIST \ 149 176 ); \ 150 177 _arg4 ? -_num : _num; \ 151 178 }) 152 179 153 - char **environ __attribute__((weak)); 154 - const unsigned long *_auxv __attribute__((weak)); 180 + #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ 181 + ({ \ 182 + register long _num __asm__ ("v0") = (num); \ 183 + register long _arg1 __asm__ ("a0") = (long)(arg1); \ 184 + register long _arg2 __asm__ ("a1") = (long)(arg2); \ 185 + register long _arg3 __asm__ ("a2") = (long)(arg3); \ 186 + register long _arg4 __asm__ ("a3") = (long)(arg4); \ 187 + register long _arg5 = (long)(arg5); \ 188 + register long _arg6 = (long)(arg6); \ 189 + \ 190 + __asm__ volatile ( \ 191 + "addiu $sp, $sp, -32\n" \ 192 + "sw %7, 16($sp)\n" \ 193 + "sw %8, 20($sp)\n" \ 194 + "syscall\n" \ 195 + "addiu $sp, $sp, 32\n" \ 196 + : "=r" (_num), "=r"(_arg4) \ 197 + : "0"(_num), \ 198 + "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ 199 + "r"(_arg6) \ 200 + : _NOLIBC_SYSCALL_CLOBBERLIST \ 201 + ); \ 202 + _arg4 ? -_num : _num; \ 203 + }) 155 204 156 205 /* startup code, note that it's called __start on MIPS */ 157 - void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector __start(void) 206 + void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector __start(void) 158 207 { 159 208 __asm__ volatile ( 160 - /*".set nomips16\n"*/ 161 209 ".set push\n" 162 - ".set noreorder\n" 210 + ".set noreorder\n" 163 211 ".option pic0\n" 164 - #ifdef _NOLIBC_STACKPROTECTOR 165 - "jal __stack_chk_init\n" /* initialize stack protector */ 166 - "nop\n" /* delayed slot */ 167 - #endif 168 - /*".ent __start\n"*/ 169 - /*"__start:\n"*/ 170 - "lw $a0,($sp)\n" /* argc was in the stack */ 171 - "addiu $a1, $sp, 4\n" /* argv = sp + 4 */ 172 - "sll $a2, $a0, 2\n" /* a2 = argc * 4 */ 173 - "add $a2, $a2, $a1\n" /* envp = argv + 4*argc ... */ 174 - "addiu $a2, $a2, 4\n" /* ... + 4 */ 175 - "lui $a3, %hi(environ)\n" /* load environ into a3 (hi) */ 176 - "addiu $a3, %lo(environ)\n" /* load environ into a3 (lo) */ 177 - "sw $a2,($a3)\n" /* store envp(a2) into environ */ 178 - 179 - "move $t0, $a2\n" /* iterate t0 over envp, look for NULL */ 180 - "0:" /* do { */ 181 - "lw $a3, ($t0)\n" /* a3=*(t0); */ 182 - "bne $a3, $0, 0b\n" /* } while (a3); */ 183 - "addiu $t0, $t0, 4\n" /* delayed slot: t0+=4; */ 184 - "lui $a3, %hi(_auxv)\n" /* load _auxv into a3 (hi) */ 185 - "addiu $a3, %lo(_auxv)\n" /* load _auxv into a3 (lo) */ 186 - "sw $t0, ($a3)\n" /* store t0 into _auxv */ 187 - 188 - "li $t0, -8\n" 189 - "and $sp, $sp, $t0\n" /* sp must be 8-byte aligned */ 190 - "addiu $sp,$sp,-16\n" /* the callee expects to save a0..a3 there! */ 191 - "jal main\n" /* main() returns the status code, we'll exit with it. */ 192 - "nop\n" /* delayed slot */ 193 - "move $a0, $v0\n" /* retrieve 32-bit exit code from v0 */ 194 - "li $v0, 4001\n" /* NR_exit == 4001 */ 195 - "syscall\n" 196 - /*".end __start\n"*/ 212 + "move $a0, $sp\n" /* save stack pointer to $a0, as arg1 of _start_c */ 213 + "li $t0, -8\n" 214 + "and $sp, $sp, $t0\n" /* $sp must be 8-byte aligned */ 215 + "addiu $sp, $sp, -16\n" /* the callee expects to save a0..a3 there */ 216 + "jal _start_c\n" /* transfer to c runtime */ 217 + " nop\n" /* delayed slot */ 197 218 ".set pop\n" 198 219 ); 199 220 __builtin_unreachable();
+221
tools/include/nolibc/arch-powerpc.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * PowerPC specific definitions for NOLIBC 4 + * Copyright (C) 2023 Zhangjin Wu <falcon@tinylab.org> 5 + */ 6 + 7 + #ifndef _NOLIBC_ARCH_POWERPC_H 8 + #define _NOLIBC_ARCH_POWERPC_H 9 + 10 + #include "compiler.h" 11 + #include "crt.h" 12 + 13 + /* Syscalls for PowerPC : 14 + * - stack is 16-byte aligned 15 + * - syscall number is passed in r0 16 + * - arguments are in r3, r4, r5, r6, r7, r8, r9 17 + * - the system call is performed by calling "sc" 18 + * - syscall return comes in r3, and the summary overflow bit is checked 19 + * to know if an error occurred, in which case errno is in r3. 20 + * - the arguments are cast to long and assigned into the target 21 + * registers which are then simply passed as registers to the asm code, 22 + * so that we don't have to experience issues with register constraints. 23 + */ 24 + 25 + #define _NOLIBC_SYSCALL_CLOBBERLIST \ 26 + "memory", "cr0", "r12", "r11", "r10", "r9" 27 + 28 + #define my_syscall0(num) \ 29 + ({ \ 30 + register long _ret __asm__ ("r3"); \ 31 + register long _num __asm__ ("r0") = (num); \ 32 + \ 33 + __asm__ volatile ( \ 34 + " sc\n" \ 35 + " bns+ 1f\n" \ 36 + " neg %0, %0\n" \ 37 + "1:\n" \ 38 + : "=r"(_ret), "+r"(_num) \ 39 + : \ 40 + : _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7", "r6", "r5", "r4" \ 41 + ); \ 42 + _ret; \ 43 + }) 44 + 45 + #define my_syscall1(num, arg1) \ 46 + ({ \ 47 + register long _ret __asm__ ("r3"); \ 48 + register long _num __asm__ ("r0") = (num); \ 49 + register long _arg1 __asm__ ("r3") = (long)(arg1); \ 50 + \ 51 + __asm__ volatile ( \ 52 + " sc\n" \ 53 + " bns+ 1f\n" \ 54 + " neg %0, %0\n" \ 55 + "1:\n" \ 56 + : "=r"(_ret), "+r"(_num) \ 57 + : "0"(_arg1) \ 58 + : _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7", "r6", "r5", "r4" \ 59 + ); \ 60 + _ret; \ 61 + }) 62 + 63 + 64 + #define my_syscall2(num, arg1, arg2) \ 65 + ({ \ 66 + register long _ret __asm__ ("r3"); \ 67 + register long _num __asm__ ("r0") = (num); \ 68 + register long _arg1 __asm__ ("r3") = (long)(arg1); \ 69 + register long _arg2 __asm__ ("r4") = (long)(arg2); \ 70 + \ 71 + __asm__ volatile ( \ 72 + " sc\n" \ 73 + " bns+ 1f\n" \ 74 + " neg %0, %0\n" \ 75 + "1:\n" \ 76 + : "=r"(_ret), "+r"(_num), "+r"(_arg2) \ 77 + : "0"(_arg1) \ 78 + : _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7", "r6", "r5" \ 79 + ); \ 80 + _ret; \ 81 + }) 82 + 83 + 84 + #define my_syscall3(num, arg1, arg2, arg3) \ 85 + ({ \ 86 + register long _ret __asm__ ("r3"); \ 87 + register long _num __asm__ ("r0") = (num); \ 88 + register long _arg1 __asm__ ("r3") = (long)(arg1); \ 89 + register long _arg2 __asm__ ("r4") = (long)(arg2); \ 90 + register long _arg3 __asm__ ("r5") = (long)(arg3); \ 91 + \ 92 + __asm__ volatile ( \ 93 + " sc\n" \ 94 + " bns+ 1f\n" \ 95 + " neg %0, %0\n" \ 96 + "1:\n" \ 97 + : "=r"(_ret), "+r"(_num), "+r"(_arg2), "+r"(_arg3) \ 98 + : "0"(_arg1) \ 99 + : _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7", "r6" \ 100 + ); \ 101 + _ret; \ 102 + }) 103 + 104 + 105 + #define my_syscall4(num, arg1, arg2, arg3, arg4) \ 106 + ({ \ 107 + register long _ret __asm__ ("r3"); \ 108 + register long _num __asm__ ("r0") = (num); \ 109 + register long _arg1 __asm__ ("r3") = (long)(arg1); \ 110 + register long _arg2 __asm__ ("r4") = (long)(arg2); \ 111 + register long _arg3 __asm__ ("r5") = (long)(arg3); \ 112 + register long _arg4 __asm__ ("r6") = (long)(arg4); \ 113 + \ 114 + __asm__ volatile ( \ 115 + " sc\n" \ 116 + " bns+ 1f\n" \ 117 + " neg %0, %0\n" \ 118 + "1:\n" \ 119 + : "=r"(_ret), "+r"(_num), "+r"(_arg2), "+r"(_arg3), \ 120 + "+r"(_arg4) \ 121 + : "0"(_arg1) \ 122 + : _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7" \ 123 + ); \ 124 + _ret; \ 125 + }) 126 + 127 + 128 + #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ 129 + ({ \ 130 + register long _ret __asm__ ("r3"); \ 131 + register long _num __asm__ ("r0") = (num); \ 132 + register long _arg1 __asm__ ("r3") = (long)(arg1); \ 133 + register long _arg2 __asm__ ("r4") = (long)(arg2); \ 134 + register long _arg3 __asm__ ("r5") = (long)(arg3); \ 135 + register long _arg4 __asm__ ("r6") = (long)(arg4); \ 136 + register long _arg5 __asm__ ("r7") = (long)(arg5); \ 137 + \ 138 + __asm__ volatile ( \ 139 + " sc\n" \ 140 + " bns+ 1f\n" \ 141 + " neg %0, %0\n" \ 142 + "1:\n" \ 143 + : "=r"(_ret), "+r"(_num), "+r"(_arg2), "+r"(_arg3), \ 144 + "+r"(_arg4), "+r"(_arg5) \ 145 + : "0"(_arg1) \ 146 + : _NOLIBC_SYSCALL_CLOBBERLIST, "r8" \ 147 + ); \ 148 + _ret; \ 149 + }) 150 + 151 + #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ 152 + ({ \ 153 + register long _ret __asm__ ("r3"); \ 154 + register long _num __asm__ ("r0") = (num); \ 155 + register long _arg1 __asm__ ("r3") = (long)(arg1); \ 156 + register long _arg2 __asm__ ("r4") = (long)(arg2); \ 157 + register long _arg3 __asm__ ("r5") = (long)(arg3); \ 158 + register long _arg4 __asm__ ("r6") = (long)(arg4); \ 159 + register long _arg5 __asm__ ("r7") = (long)(arg5); \ 160 + register long _arg6 __asm__ ("r8") = (long)(arg6); \ 161 + \ 162 + __asm__ volatile ( \ 163 + " sc\n" \ 164 + " bns+ 1f\n" \ 165 + " neg %0, %0\n" \ 166 + "1:\n" \ 167 + : "=r"(_ret), "+r"(_num), "+r"(_arg2), "+r"(_arg3), \ 168 + "+r"(_arg4), "+r"(_arg5), "+r"(_arg6) \ 169 + : "0"(_arg1) \ 170 + : _NOLIBC_SYSCALL_CLOBBERLIST \ 171 + ); \ 172 + _ret; \ 173 + }) 174 + 175 + #ifndef __powerpc64__ 176 + /* FIXME: For 32-bit PowerPC, with newer gcc compilers (e.g. gcc 13.1.0), 177 + * "omit-frame-pointer" fails with __attribute__((no_stack_protector)) but 178 + * works with __attribute__((__optimize__("-fno-stack-protector"))) 179 + */ 180 + #ifdef __no_stack_protector 181 + #undef __no_stack_protector 182 + #define __no_stack_protector __attribute__((__optimize__("-fno-stack-protector"))) 183 + #endif 184 + #endif /* !__powerpc64__ */ 185 + 186 + /* startup code */ 187 + void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) 188 + { 189 + #ifdef __powerpc64__ 190 + #if _CALL_ELF == 2 191 + /* with -mabi=elfv2, save TOC/GOT pointer to r2 192 + * r12 is global entry pointer, we use it to compute TOC from r12 193 + * https://www.llvm.org/devmtg/2014-04/PDFs/Talks/Euro-LLVM-2014-Weigand.pdf 194 + * https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.pdf 195 + */ 196 + __asm__ volatile ( 197 + "addis 2, 12, .TOC. - _start@ha\n" 198 + "addi 2, 2, .TOC. - _start@l\n" 199 + ); 200 + #endif /* _CALL_ELF == 2 */ 201 + 202 + __asm__ volatile ( 203 + "mr 3, 1\n" /* save stack pointer to r3, as arg1 of _start_c */ 204 + "clrrdi 1, 1, 4\n" /* align the stack to 16 bytes */ 205 + "li 0, 0\n" /* zero the frame pointer */ 206 + "stdu 1, -32(1)\n" /* the initial stack frame */ 207 + "bl _start_c\n" /* transfer to c runtime */ 208 + ); 209 + #else 210 + __asm__ volatile ( 211 + "mr 3, 1\n" /* save stack pointer to r3, as arg1 of _start_c */ 212 + "clrrwi 1, 1, 4\n" /* align the stack to 16 bytes */ 213 + "li 0, 0\n" /* zero the frame pointer */ 214 + "stwu 1, -16(1)\n" /* the initial stack frame */ 215 + "bl _start_c\n" /* transfer to c runtime */ 216 + ); 217 + #endif 218 + __builtin_unreachable(); 219 + } 220 + 221 + #endif /* _NOLIBC_ARCH_POWERPC_H */
+13 -70
tools/include/nolibc/arch-riscv.h
··· 8 8 #define _NOLIBC_ARCH_RISCV_H 9 9 10 10 #include "compiler.h" 11 - 12 - struct sys_stat_struct { 13 - unsigned long st_dev; /* Device. */ 14 - unsigned long st_ino; /* File serial number. */ 15 - unsigned int st_mode; /* File mode. */ 16 - unsigned int st_nlink; /* Link count. */ 17 - unsigned int st_uid; /* User ID of the file's owner. */ 18 - unsigned int st_gid; /* Group ID of the file's group. */ 19 - unsigned long st_rdev; /* Device number, if device. */ 20 - unsigned long __pad1; 21 - long st_size; /* Size of file, in bytes. */ 22 - int st_blksize; /* Optimal block size for I/O. */ 23 - int __pad2; 24 - long st_blocks; /* Number 512-byte blocks allocated. */ 25 - long st_atime; /* Time of last access. */ 26 - unsigned long st_atime_nsec; 27 - long st_mtime; /* Time of last modification. */ 28 - unsigned long st_mtime_nsec; 29 - long st_ctime; /* Time of last status change. */ 30 - unsigned long st_ctime_nsec; 31 - unsigned int __unused4; 32 - unsigned int __unused5; 33 - }; 34 - 35 - #if __riscv_xlen == 64 36 - #define PTRLOG "3" 37 - #define SZREG "8" 38 - #define REG_L "ld" 39 - #define REG_S "sd" 40 - #elif __riscv_xlen == 32 41 - #define PTRLOG "2" 42 - #define SZREG "4" 43 - #define REG_L "lw" 44 - #define REG_S "sw" 45 - #endif 11 + #include "crt.h" 46 12 47 13 /* Syscalls for RISCV : 48 14 * - stack is 16-byte aligned ··· 29 63 register long _num __asm__ ("a7") = (num); \ 30 64 register long _arg1 __asm__ ("a0"); \ 31 65 \ 32 - __asm__ volatile ( \ 66 + __asm__ volatile ( \ 33 67 "ecall\n\t" \ 34 68 : "=r"(_arg1) \ 35 69 : "r"(_num) \ ··· 43 77 register long _num __asm__ ("a7") = (num); \ 44 78 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 45 79 \ 46 - __asm__ volatile ( \ 80 + __asm__ volatile ( \ 47 81 "ecall\n" \ 48 82 : "+r"(_arg1) \ 49 83 : "r"(_num) \ ··· 58 92 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 59 93 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 60 94 \ 61 - __asm__ volatile ( \ 95 + __asm__ volatile ( \ 62 96 "ecall\n" \ 63 97 : "+r"(_arg1) \ 64 98 : "r"(_arg2), \ ··· 75 109 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 76 110 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 77 111 \ 78 - __asm__ volatile ( \ 112 + __asm__ volatile ( \ 79 113 "ecall\n\t" \ 80 114 : "+r"(_arg1) \ 81 115 : "r"(_arg2), "r"(_arg3), \ ··· 93 127 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 94 128 register long _arg4 __asm__ ("a3") = (long)(arg4); \ 95 129 \ 96 - __asm__ volatile ( \ 130 + __asm__ volatile ( \ 97 131 "ecall\n" \ 98 132 : "+r"(_arg1) \ 99 133 : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ ··· 112 146 register long _arg4 __asm__ ("a3") = (long)(arg4); \ 113 147 register long _arg5 __asm__ ("a4") = (long)(arg5); \ 114 148 \ 115 - __asm__ volatile ( \ 149 + __asm__ volatile ( \ 116 150 "ecall\n" \ 117 151 : "+r"(_arg1) \ 118 152 : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ ··· 132 166 register long _arg5 __asm__ ("a4") = (long)(arg5); \ 133 167 register long _arg6 __asm__ ("a5") = (long)(arg6); \ 134 168 \ 135 - __asm__ volatile ( \ 169 + __asm__ volatile ( \ 136 170 "ecall\n" \ 137 171 : "+r"(_arg1) \ 138 172 : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ ··· 142 176 _arg1; \ 143 177 }) 144 178 145 - char **environ __attribute__((weak)); 146 - const unsigned long *_auxv __attribute__((weak)); 147 - 148 179 /* startup code */ 149 - void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void) 180 + void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) 150 181 { 151 182 __asm__ volatile ( 152 183 ".option push\n" 153 184 ".option norelax\n" 154 - "lla gp, __global_pointer$\n" 185 + "lla gp, __global_pointer$\n" 155 186 ".option pop\n" 156 - #ifdef _NOLIBC_STACKPROTECTOR 157 - "call __stack_chk_init\n" /* initialize stack protector */ 158 - #endif 159 - REG_L" a0, 0(sp)\n" /* argc (a0) was in the stack */ 160 - "add a1, sp, "SZREG"\n" /* argv (a1) = sp */ 161 - "slli a2, a0, "PTRLOG"\n" /* envp (a2) = SZREG*argc ... */ 162 - "add a2, a2, "SZREG"\n" /* + SZREG (skip null) */ 163 - "add a2,a2,a1\n" /* + argv */ 164 - 165 - "add a3, a2, zero\n" /* iterate a3 over envp to find auxv (after NULL) */ 166 - "0:\n" /* do { */ 167 - REG_L" a4, 0(a3)\n" /* a4 = *a3; */ 168 - "add a3, a3, "SZREG"\n" /* a3 += sizeof(void*); */ 169 - "bne a4, zero, 0b\n" /* } while (a4); */ 170 - "lui a4, %hi(_auxv)\n" /* a4 = &_auxv (high bits) */ 171 - REG_S" a3, %lo(_auxv)(a4)\n" /* store a3 into _auxv */ 172 - 173 - "lui a3, %hi(environ)\n" /* a3 = &environ (high bits) */ 174 - REG_S" a2,%lo(environ)(a3)\n"/* store envp(a2) into environ */ 175 - "andi sp,a1,-16\n" /* sp must be 16-byte aligned */ 176 - "call main\n" /* main() returns the status code, we'll exit with it. */ 177 - "li a7, 93\n" /* NR_exit == 93 */ 178 - "ecall\n" 187 + "mv a0, sp\n" /* save stack pointer to a0, as arg1 of _start_c */ 188 + "andi sp, a0, -16\n" /* sp must be 16-byte aligned */ 189 + "call _start_c\n" /* transfer to c runtime */ 179 190 ); 180 191 __builtin_unreachable(); 181 192 }
+13 -64
tools/include/nolibc/arch-s390.h
··· 9 9 #include <asm/unistd.h> 10 10 11 11 #include "compiler.h" 12 - 13 - /* The struct returned by the stat() syscall, equivalent to stat64(). The 14 - * syscall returns 116 bytes and stops in the middle of __unused. 15 - */ 16 - 17 - struct sys_stat_struct { 18 - unsigned long st_dev; 19 - unsigned long st_ino; 20 - unsigned long st_nlink; 21 - unsigned int st_mode; 22 - unsigned int st_uid; 23 - unsigned int st_gid; 24 - unsigned int __pad1; 25 - unsigned long st_rdev; 26 - unsigned long st_size; 27 - unsigned long st_atime; 28 - unsigned long st_atime_nsec; 29 - unsigned long st_mtime; 30 - unsigned long st_mtime_nsec; 31 - unsigned long st_ctime; 32 - unsigned long st_ctime_nsec; 33 - unsigned long st_blksize; 34 - long st_blocks; 35 - unsigned long __unused[3]; 36 - }; 12 + #include "crt.h" 37 13 38 14 /* Syscalls for s390: 39 15 * - registers are 64-bit ··· 28 52 register long _num __asm__ ("1") = (num); \ 29 53 register long _rc __asm__ ("2"); \ 30 54 \ 31 - __asm__ volatile ( \ 55 + __asm__ volatile ( \ 32 56 "svc 0\n" \ 33 57 : "=d"(_rc) \ 34 58 : "d"(_num) \ ··· 42 66 register long _num __asm__ ("1") = (num); \ 43 67 register long _arg1 __asm__ ("2") = (long)(arg1); \ 44 68 \ 45 - __asm__ volatile ( \ 69 + __asm__ volatile ( \ 46 70 "svc 0\n" \ 47 71 : "+d"(_arg1) \ 48 72 : "d"(_num) \ ··· 57 81 register long _arg1 __asm__ ("2") = (long)(arg1); \ 58 82 register long _arg2 __asm__ ("3") = (long)(arg2); \ 59 83 \ 60 - __asm__ volatile ( \ 84 + __asm__ volatile ( \ 61 85 "svc 0\n" \ 62 86 : "+d"(_arg1) \ 63 87 : "d"(_arg2), "d"(_num) \ ··· 73 97 register long _arg2 __asm__ ("3") = (long)(arg2); \ 74 98 register long _arg3 __asm__ ("4") = (long)(arg3); \ 75 99 \ 76 - __asm__ volatile ( \ 100 + __asm__ volatile ( \ 77 101 "svc 0\n" \ 78 102 : "+d"(_arg1) \ 79 103 : "d"(_arg2), "d"(_arg3), "d"(_num) \ ··· 90 114 register long _arg3 __asm__ ("4") = (long)(arg3); \ 91 115 register long _arg4 __asm__ ("5") = (long)(arg4); \ 92 116 \ 93 - __asm__ volatile ( \ 117 + __asm__ volatile ( \ 94 118 "svc 0\n" \ 95 119 : "+d"(_arg1) \ 96 120 : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_num) \ ··· 108 132 register long _arg4 __asm__ ("5") = (long)(arg4); \ 109 133 register long _arg5 __asm__ ("6") = (long)(arg5); \ 110 134 \ 111 - __asm__ volatile ( \ 135 + __asm__ volatile ( \ 112 136 "svc 0\n" \ 113 137 : "+d"(_arg1) \ 114 138 : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5), \ ··· 128 152 register long _arg5 __asm__ ("6") = (long)(arg5); \ 129 153 register long _arg6 __asm__ ("7") = (long)(arg6); \ 130 154 \ 131 - __asm__ volatile ( \ 155 + __asm__ volatile ( \ 132 156 "svc 0\n" \ 133 157 : "+d"(_arg1) \ 134 158 : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5), \ ··· 138 162 _arg1; \ 139 163 }) 140 164 141 - char **environ __attribute__((weak)); 142 - const unsigned long *_auxv __attribute__((weak)); 143 - 144 165 /* startup code */ 145 - void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void) 166 + void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) 146 167 { 147 168 __asm__ volatile ( 148 - "lg %r2,0(%r15)\n" /* argument count */ 149 - "la %r3,8(%r15)\n" /* argument pointers */ 150 - 151 - "xgr %r0,%r0\n" /* r0 will be our NULL value */ 152 - /* search for envp */ 153 - "lgr %r4,%r3\n" /* start at argv */ 154 - "0:\n" 155 - "clg %r0,0(%r4)\n" /* entry zero? */ 156 - "la %r4,8(%r4)\n" /* advance pointer */ 157 - "jnz 0b\n" /* no -> test next pointer */ 158 - /* yes -> r4 now contains start of envp */ 159 - "larl %r1,environ\n" 160 - "stg %r4,0(%r1)\n" 161 - 162 - /* search for auxv */ 163 - "lgr %r5,%r4\n" /* start at envp */ 164 - "1:\n" 165 - "clg %r0,0(%r5)\n" /* entry zero? */ 166 - "la %r5,8(%r5)\n" /* advance pointer */ 167 - "jnz 1b\n" /* no -> test next pointer */ 168 - "larl %r1,_auxv\n" /* yes -> store value in _auxv */ 169 - "stg %r5,0(%r1)\n" 170 - 171 - "aghi %r15,-160\n" /* allocate new stackframe */ 172 - "xc 0(8,%r15),0(%r15)\n" /* clear backchain */ 173 - "brasl %r14,main\n" /* ret value of main is arg to exit */ 174 - "lghi %r1,1\n" /* __NR_exit */ 175 - "svc 0\n" 169 + "lgr %r2, %r15\n" /* save stack pointer to %r2, as arg1 of _start_c */ 170 + "aghi %r15, -160\n" /* allocate new stackframe */ 171 + "xc 0(8,%r15), 0(%r15)\n" /* clear backchain */ 172 + "brasl %r14, _start_c\n" /* transfer to c runtime */ 176 173 ); 177 174 __builtin_unreachable(); 178 175 }
+21 -65
tools/include/nolibc/arch-x86_64.h
··· 8 8 #define _NOLIBC_ARCH_X86_64_H 9 9 10 10 #include "compiler.h" 11 - 12 - /* The struct returned by the stat() syscall, equivalent to stat64(). The 13 - * syscall returns 116 bytes and stops in the middle of __unused. 14 - */ 15 - struct sys_stat_struct { 16 - unsigned long st_dev; 17 - unsigned long st_ino; 18 - unsigned long st_nlink; 19 - unsigned int st_mode; 20 - unsigned int st_uid; 21 - 22 - unsigned int st_gid; 23 - unsigned int __pad0; 24 - unsigned long st_rdev; 25 - long st_size; 26 - long st_blksize; 27 - 28 - long st_blocks; 29 - unsigned long st_atime; 30 - unsigned long st_atime_nsec; 31 - unsigned long st_mtime; 32 - 33 - unsigned long st_mtime_nsec; 34 - unsigned long st_ctime; 35 - unsigned long st_ctime_nsec; 36 - long __unused[3]; 37 - }; 11 + #include "crt.h" 38 12 39 13 /* Syscalls for x86_64 : 40 14 * - registers are 64-bit ··· 33 59 ({ \ 34 60 long _ret; \ 35 61 register long _num __asm__ ("rax") = (num); \ 36 - \ 37 - __asm__ volatile ( \ 62 + \ 63 + __asm__ volatile ( \ 38 64 "syscall\n" \ 39 65 : "=a"(_ret) \ 40 66 : "0"(_num) \ ··· 48 74 long _ret; \ 49 75 register long _num __asm__ ("rax") = (num); \ 50 76 register long _arg1 __asm__ ("rdi") = (long)(arg1); \ 51 - \ 52 - __asm__ volatile ( \ 77 + \ 78 + __asm__ volatile ( \ 53 79 "syscall\n" \ 54 80 : "=a"(_ret) \ 55 81 : "r"(_arg1), \ ··· 65 91 register long _num __asm__ ("rax") = (num); \ 66 92 register long _arg1 __asm__ ("rdi") = (long)(arg1); \ 67 93 register long _arg2 __asm__ ("rsi") = (long)(arg2); \ 68 - \ 69 - __asm__ volatile ( \ 94 + \ 95 + __asm__ volatile ( \ 70 96 "syscall\n" \ 71 97 : "=a"(_ret) \ 72 98 : "r"(_arg1), "r"(_arg2), \ ··· 83 109 register long _arg1 __asm__ ("rdi") = (long)(arg1); \ 84 110 register long _arg2 __asm__ ("rsi") = (long)(arg2); \ 85 111 register long _arg3 __asm__ ("rdx") = (long)(arg3); \ 86 - \ 87 - __asm__ volatile ( \ 112 + \ 113 + __asm__ volatile ( \ 88 114 "syscall\n" \ 89 115 : "=a"(_ret) \ 90 116 : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ ··· 102 128 register long _arg2 __asm__ ("rsi") = (long)(arg2); \ 103 129 register long _arg3 __asm__ ("rdx") = (long)(arg3); \ 104 130 register long _arg4 __asm__ ("r10") = (long)(arg4); \ 105 - \ 106 - __asm__ volatile ( \ 131 + \ 132 + __asm__ volatile ( \ 107 133 "syscall\n" \ 108 134 : "=a"(_ret) \ 109 135 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ ··· 122 148 register long _arg3 __asm__ ("rdx") = (long)(arg3); \ 123 149 register long _arg4 __asm__ ("r10") = (long)(arg4); \ 124 150 register long _arg5 __asm__ ("r8") = (long)(arg5); \ 125 - \ 126 - __asm__ volatile ( \ 151 + \ 152 + __asm__ volatile ( \ 127 153 "syscall\n" \ 128 154 : "=a"(_ret) \ 129 155 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ ··· 143 169 register long _arg4 __asm__ ("r10") = (long)(arg4); \ 144 170 register long _arg5 __asm__ ("r8") = (long)(arg5); \ 145 171 register long _arg6 __asm__ ("r9") = (long)(arg6); \ 146 - \ 147 - __asm__ volatile ( \ 172 + \ 173 + __asm__ volatile ( \ 148 174 "syscall\n" \ 149 175 : "=a"(_ret) \ 150 176 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ ··· 154 180 _ret; \ 155 181 }) 156 182 157 - char **environ __attribute__((weak)); 158 - const unsigned long *_auxv __attribute__((weak)); 159 - 160 183 /* startup code */ 161 184 /* 162 185 * x86-64 System V ABI mandates: ··· 161 190 * 2) The deepest stack frame should be zero (the %rbp). 162 191 * 163 192 */ 164 - void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void) 193 + void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) 165 194 { 166 195 __asm__ volatile ( 167 - #ifdef _NOLIBC_STACKPROTECTOR 168 - "call __stack_chk_init\n" /* initialize stack protector */ 169 - #endif 170 - "pop %rdi\n" /* argc (first arg, %rdi) */ 171 - "mov %rsp, %rsi\n" /* argv[] (second arg, %rsi) */ 172 - "lea 8(%rsi,%rdi,8),%rdx\n" /* then a NULL then envp (third arg, %rdx) */ 173 - "mov %rdx, environ\n" /* save environ */ 174 - "xor %ebp, %ebp\n" /* zero the stack frame */ 175 - "mov %rdx, %rax\n" /* search for auxv (follows NULL after last env) */ 176 - "0:\n" 177 - "add $8, %rax\n" /* search for auxv using rax, it follows the */ 178 - "cmp -8(%rax), %rbp\n" /* ... NULL after last env (rbp is zero here) */ 179 - "jnz 0b\n" 180 - "mov %rax, _auxv\n" /* save it into _auxv */ 181 - "and $-16, %rsp\n" /* x86 ABI : esp must be 16-byte aligned before call */ 182 - "call main\n" /* main() returns the status code, we'll exit with it. */ 183 - "mov %eax, %edi\n" /* retrieve exit code (32 bit) */ 184 - "mov $60, %eax\n" /* NR_exit == 60 */ 185 - "syscall\n" /* really exit */ 186 - "hlt\n" /* ensure it does not return */ 196 + "xor %ebp, %ebp\n" /* zero the stack frame */ 197 + "mov %rsp, %rdi\n" /* save stack pointer to %rdi, as arg1 of _start_c */ 198 + "and $-16, %rsp\n" /* %rsp must be 16-byte aligned before call */ 199 + "call _start_c\n" /* transfer to c runtime */ 200 + "hlt\n" /* ensure it does not return */ 187 201 ); 188 202 __builtin_unreachable(); 189 203 }
+2
tools/include/nolibc/arch.h
··· 25 25 #include "arch-aarch64.h" 26 26 #elif defined(__mips__) && defined(_ABIO32) 27 27 #include "arch-mips.h" 28 + #elif defined(__powerpc__) 29 + #include "arch-powerpc.h" 28 30 #elif defined(__riscv) 29 31 #include "arch-riscv.h" 30 32 #elif defined(__s390x__)
+61
tools/include/nolibc/crt.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * C Run Time support for NOLIBC 4 + * Copyright (C) 2023 Zhangjin Wu <falcon@tinylab.org> 5 + */ 6 + 7 + #ifndef _NOLIBC_CRT_H 8 + #define _NOLIBC_CRT_H 9 + 10 + char **environ __attribute__((weak)); 11 + const unsigned long *_auxv __attribute__((weak)); 12 + 13 + static void __stack_chk_init(void); 14 + static void exit(int); 15 + 16 + void _start_c(long *sp) 17 + { 18 + long argc; 19 + char **argv; 20 + char **envp; 21 + const unsigned long *auxv; 22 + /* silence potential warning: conflicting types for 'main' */ 23 + int _nolibc_main(int, char **, char **) __asm__ ("main"); 24 + 25 + /* initialize stack protector */ 26 + __stack_chk_init(); 27 + 28 + /* 29 + * sp : argc <-- argument count, required by main() 30 + * argv: argv[0] <-- argument vector, required by main() 31 + * argv[1] 32 + * ... 33 + * argv[argc-1] 34 + * null 35 + * environ: environ[0] <-- environment variables, required by main() and getenv() 36 + * environ[1] 37 + * ... 38 + * null 39 + * _auxv: _auxv[0] <-- auxiliary vector, required by getauxval() 40 + * _auxv[1] 41 + * ... 42 + * null 43 + */ 44 + 45 + /* assign argc and argv */ 46 + argc = *sp; 47 + argv = (void *)(sp + 1); 48 + 49 + /* find environ */ 50 + environ = envp = argv + argc + 1; 51 + 52 + /* find _auxv */ 53 + for (auxv = (void *)envp; *auxv++;) 54 + ; 55 + _auxv = auxv; 56 + 57 + /* go to application */ 58 + exit(_nolibc_main(argc, argv, envp)); 59 + } 60 + 61 + #endif /* _NOLIBC_CRT_H */
+4 -5
tools/include/nolibc/nolibc.h
··· 13 13 * Syscalls are split into 3 levels: 14 14 * - The lower level is the arch-specific syscall() definition, consisting in 15 15 * assembly code in compound expressions. These are called my_syscall0() to 16 - * my_syscall6() depending on the number of arguments. The MIPS 17 - * implementation is limited to 5 arguments. All input arguments are cast 18 - * to a long stored in a register. These expressions always return the 19 - * syscall's return value as a signed long value which is often either a 20 - * pointer or the negated errno value. 16 + * my_syscall6() depending on the number of arguments. All input arguments 17 + * are castto a long stored in a register. These expressions always return 18 + * the syscall's return value as a signed long value which is often either 19 + * a pointer or the negated errno value. 21 20 * 22 21 * - The second level is mostly architecture-independent. It is made of 23 22 * static functions called sys_<name>() which rely on my_syscallN()
+3 -2
tools/include/nolibc/stackprotector.h
··· 37 37 __attribute__((weak,section(".data.nolibc_stack_chk"))) 38 38 uintptr_t __stack_chk_guard; 39 39 40 - __attribute__((weak,section(".text.nolibc_stack_chk"))) __no_stack_protector 41 - void __stack_chk_init(void) 40 + static __no_stack_protector void __stack_chk_init(void) 42 41 { 43 42 my_syscall3(__NR_getrandom, &__stack_chk_guard, sizeof(__stack_chk_guard), 0); 44 43 /* a bit more randomness in case getrandom() fails, ensure the guard is never 0 */ 45 44 if (__stack_chk_guard != (uintptr_t) &__stack_chk_guard) 46 45 __stack_chk_guard ^= (uintptr_t) &__stack_chk_guard; 47 46 } 47 + #else /* !defined(_NOLIBC_STACKPROTECTOR) */ 48 + static void __stack_chk_init(void) {} 48 49 #endif /* defined(_NOLIBC_STACKPROTECTOR) */ 49 50 50 51 #endif /* _NOLIBC_STACKPROTECTOR_H */
+1 -1
tools/include/nolibc/stdint.h
··· 15 15 typedef signed int int32_t; 16 16 typedef unsigned long long uint64_t; 17 17 typedef signed long long int64_t; 18 - typedef unsigned long size_t; 18 + typedef __SIZE_TYPE__ size_t; 19 19 typedef signed long ssize_t; 20 20 typedef unsigned long uintptr_t; 21 21 typedef signed long intptr_t;
+27
tools/include/nolibc/stdio.h
··· 21 21 #define EOF (-1) 22 22 #endif 23 23 24 + /* Buffering mode used by setvbuf. */ 25 + #define _IOFBF 0 /* Fully buffered. */ 26 + #define _IOLBF 1 /* Line buffered. */ 27 + #define _IONBF 2 /* No buffering. */ 28 + 24 29 /* just define FILE as a non-empty type. The value of the pointer gives 25 30 * the FD: FILE=~fd for fd>=0 or NULL for fd<0. This way positive FILE 26 31 * are immediately identified as abnormal entries (i.e. possible copies ··· 353 348 void perror(const char *msg) 354 349 { 355 350 fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno); 351 + } 352 + 353 + static __attribute__((unused)) 354 + int setvbuf(FILE *stream __attribute__((unused)), 355 + char *buf __attribute__((unused)), 356 + int mode, 357 + size_t size __attribute__((unused))) 358 + { 359 + /* 360 + * nolibc does not support buffering so this is a nop. Just check mode 361 + * is valid as required by the spec. 362 + */ 363 + switch (mode) { 364 + case _IOFBF: 365 + case _IOLBF: 366 + case _IONBF: 367 + break; 368 + default: 369 + return EOF; 370 + } 371 + 372 + return 0; 356 373 } 357 374 358 375 /* make sure to include all global symbols */
+2 -10
tools/include/nolibc/stdlib.h
··· 83 83 * declared as a char **, and must be terminated by a NULL (it is recommended 84 84 * to set this variable to the "envp" argument of main()). If the requested 85 85 * environment variable exists its value is returned otherwise NULL is 86 - * returned. getenv() is forcefully inlined so that the reference to "environ" 87 - * will be dropped if unused, even at -O0. 86 + * returned. 88 87 */ 89 88 static __attribute__((unused)) 90 - char *_getenv(const char *name, char **environ) 89 + char *getenv(const char *name) 91 90 { 92 91 int idx, i; 93 92 ··· 99 100 } 100 101 } 101 102 return NULL; 102 - } 103 - 104 - static __inline__ __attribute__((unused,always_inline)) 105 - char *getenv(const char *name) 106 - { 107 - extern char **environ; 108 - return _getenv(name, environ); 109 103 } 110 104 111 105 static __attribute__((unused))
+147 -387
tools/include/nolibc/sys.h
··· 21 21 #include <linux/auxvec.h> 22 22 #include <linux/fcntl.h> /* for O_* and AT_* */ 23 23 #include <linux/stat.h> /* for statx() */ 24 - #include <linux/reboot.h> /* for LINUX_REBOOT_* */ 25 24 #include <linux/prctl.h> 26 25 27 26 #include "arch.h" 28 27 #include "errno.h" 29 28 #include "types.h" 29 + 30 + 31 + /* Syscall return helper: takes the syscall value in argument and checks for an 32 + * error in it. This may only be used with signed returns (int or long), but 33 + * not with pointers. An error is any value < 0. When an error is encountered, 34 + * -ret is set into errno and -1 is returned. Otherwise the returned value is 35 + * passed as-is with its type preserved. 36 + */ 37 + 38 + #define __sysret(arg) \ 39 + ({ \ 40 + __typeof__(arg) __sysret_arg = (arg); \ 41 + (__sysret_arg < 0) /* error ? */ \ 42 + ? (({ SET_ERRNO(-__sysret_arg); }), -1) /* ret -1 with errno = -arg */ \ 43 + : __sysret_arg; /* return original value */ \ 44 + }) 30 45 31 46 32 47 /* Functions in this file only describe syscalls. They're declared static so ··· 93 78 static __attribute__((unused)) 94 79 void *sbrk(intptr_t inc) 95 80 { 96 - void *ret; 97 - 98 81 /* first call to find current end */ 99 - if ((ret = sys_brk(0)) && (sys_brk(ret + inc) == ret + inc)) 82 + void *ret = sys_brk(0); 83 + 84 + if (ret && sys_brk(ret + inc) == ret + inc) 100 85 return ret + inc; 101 86 102 87 SET_ERRNO(ENOMEM); ··· 117 102 static __attribute__((unused)) 118 103 int chdir(const char *path) 119 104 { 120 - int ret = sys_chdir(path); 121 - 122 - if (ret < 0) { 123 - SET_ERRNO(-ret); 124 - ret = -1; 125 - } 126 - return ret; 105 + return __sysret(sys_chdir(path)); 127 106 } 128 107 129 108 ··· 133 124 #elif defined(__NR_chmod) 134 125 return my_syscall2(__NR_chmod, path, mode); 135 126 #else 136 - #error Neither __NR_fchmodat nor __NR_chmod defined, cannot implement sys_chmod() 127 + return -ENOSYS; 137 128 #endif 138 129 } 139 130 140 131 static __attribute__((unused)) 141 132 int chmod(const char *path, mode_t mode) 142 133 { 143 - int ret = sys_chmod(path, mode); 144 - 145 - if (ret < 0) { 146 - SET_ERRNO(-ret); 147 - ret = -1; 148 - } 149 - return ret; 134 + return __sysret(sys_chmod(path, mode)); 150 135 } 151 136 152 137 ··· 156 153 #elif defined(__NR_chown) 157 154 return my_syscall3(__NR_chown, path, owner, group); 158 155 #else 159 - #error Neither __NR_fchownat nor __NR_chown defined, cannot implement sys_chown() 156 + return -ENOSYS; 160 157 #endif 161 158 } 162 159 163 160 static __attribute__((unused)) 164 161 int chown(const char *path, uid_t owner, gid_t group) 165 162 { 166 - int ret = sys_chown(path, owner, group); 167 - 168 - if (ret < 0) { 169 - SET_ERRNO(-ret); 170 - ret = -1; 171 - } 172 - return ret; 163 + return __sysret(sys_chown(path, owner, group)); 173 164 } 174 165 175 166 ··· 180 183 static __attribute__((unused)) 181 184 int chroot(const char *path) 182 185 { 183 - int ret = sys_chroot(path); 184 - 185 - if (ret < 0) { 186 - SET_ERRNO(-ret); 187 - ret = -1; 188 - } 189 - return ret; 186 + return __sysret(sys_chroot(path)); 190 187 } 191 188 192 189 ··· 197 206 static __attribute__((unused)) 198 207 int close(int fd) 199 208 { 200 - int ret = sys_close(fd); 201 - 202 - if (ret < 0) { 203 - SET_ERRNO(-ret); 204 - ret = -1; 205 - } 206 - return ret; 209 + return __sysret(sys_close(fd)); 207 210 } 208 211 209 212 ··· 214 229 static __attribute__((unused)) 215 230 int dup(int fd) 216 231 { 217 - int ret = sys_dup(fd); 218 - 219 - if (ret < 0) { 220 - SET_ERRNO(-ret); 221 - ret = -1; 222 - } 223 - return ret; 232 + return __sysret(sys_dup(fd)); 224 233 } 225 234 226 235 ··· 230 251 #elif defined(__NR_dup2) 231 252 return my_syscall2(__NR_dup2, old, new); 232 253 #else 233 - #error Neither __NR_dup3 nor __NR_dup2 defined, cannot implement sys_dup2() 254 + return -ENOSYS; 234 255 #endif 235 256 } 236 257 237 258 static __attribute__((unused)) 238 259 int dup2(int old, int new) 239 260 { 240 - int ret = sys_dup2(old, new); 241 - 242 - if (ret < 0) { 243 - SET_ERRNO(-ret); 244 - ret = -1; 245 - } 246 - return ret; 261 + return __sysret(sys_dup2(old, new)); 247 262 } 248 263 249 264 ··· 255 282 static __attribute__((unused)) 256 283 int dup3(int old, int new, int flags) 257 284 { 258 - int ret = sys_dup3(old, new, flags); 259 - 260 - if (ret < 0) { 261 - SET_ERRNO(-ret); 262 - ret = -1; 263 - } 264 - return ret; 285 + return __sysret(sys_dup3(old, new, flags)); 265 286 } 266 287 #endif 267 288 ··· 273 306 static __attribute__((unused)) 274 307 int execve(const char *filename, char *const argv[], char *const envp[]) 275 308 { 276 - int ret = sys_execve(filename, argv, envp); 277 - 278 - if (ret < 0) { 279 - SET_ERRNO(-ret); 280 - ret = -1; 281 - } 282 - return ret; 309 + return __sysret(sys_execve(filename, argv, envp)); 283 310 } 284 311 285 312 ··· 312 351 #elif defined(__NR_fork) 313 352 return my_syscall0(__NR_fork); 314 353 #else 315 - #error Neither __NR_clone nor __NR_fork defined, cannot implement sys_fork() 354 + return -ENOSYS; 316 355 #endif 317 356 } 318 357 #endif ··· 320 359 static __attribute__((unused)) 321 360 pid_t fork(void) 322 361 { 323 - pid_t ret = sys_fork(); 324 - 325 - if (ret < 0) { 326 - SET_ERRNO(-ret); 327 - ret = -1; 328 - } 329 - return ret; 362 + return __sysret(sys_fork()); 330 363 } 331 364 332 365 ··· 337 382 static __attribute__((unused)) 338 383 int fsync(int fd) 339 384 { 340 - int ret = sys_fsync(fd); 341 - 342 - if (ret < 0) { 343 - SET_ERRNO(-ret); 344 - ret = -1; 345 - } 346 - return ret; 385 + return __sysret(sys_fsync(fd)); 347 386 } 348 387 349 388 ··· 354 405 static __attribute__((unused)) 355 406 int getdents64(int fd, struct linux_dirent64 *dirp, int count) 356 407 { 357 - int ret = sys_getdents64(fd, dirp, count); 358 - 359 - if (ret < 0) { 360 - SET_ERRNO(-ret); 361 - ret = -1; 362 - } 363 - return ret; 408 + return __sysret(sys_getdents64(fd, dirp, count)); 364 409 } 365 410 366 411 ··· 392 449 static __attribute__((unused)) 393 450 pid_t getpgid(pid_t pid) 394 451 { 395 - pid_t ret = sys_getpgid(pid); 396 - 397 - if (ret < 0) { 398 - SET_ERRNO(-ret); 399 - ret = -1; 400 - } 401 - return ret; 452 + return __sysret(sys_getpgid(pid)); 402 453 } 403 454 404 455 ··· 466 529 static unsigned long getauxval(unsigned long key); 467 530 468 531 /* 469 - * long getpagesize(void); 532 + * int getpagesize(void); 470 533 */ 471 534 472 535 static __attribute__((unused)) 473 - long getpagesize(void) 536 + int getpagesize(void) 474 537 { 475 - long ret; 476 - 477 - ret = getauxval(AT_PAGESZ); 478 - if (!ret) { 479 - SET_ERRNO(ENOENT); 480 - return -1; 481 - } 482 - 483 - return ret; 538 + return __sysret((int)getauxval(AT_PAGESZ) ?: -ENOENT); 484 539 } 485 540 486 541 ··· 483 554 static __attribute__((unused)) 484 555 int sys_gettimeofday(struct timeval *tv, struct timezone *tz) 485 556 { 557 + #ifdef __NR_gettimeofday 486 558 return my_syscall2(__NR_gettimeofday, tv, tz); 559 + #else 560 + return -ENOSYS; 561 + #endif 487 562 } 488 563 489 564 static __attribute__((unused)) 490 565 int gettimeofday(struct timeval *tv, struct timezone *tz) 491 566 { 492 - int ret = sys_gettimeofday(tv, tz); 493 - 494 - if (ret < 0) { 495 - SET_ERRNO(-ret); 496 - ret = -1; 497 - } 498 - return ret; 567 + return __sysret(sys_gettimeofday(tv, tz)); 499 568 } 500 569 501 570 ··· 531 604 static __attribute__((unused)) 532 605 int ioctl(int fd, unsigned long req, void *value) 533 606 { 534 - int ret = sys_ioctl(fd, req, value); 535 - 536 - if (ret < 0) { 537 - SET_ERRNO(-ret); 538 - ret = -1; 539 - } 540 - return ret; 607 + return __sysret(sys_ioctl(fd, req, value)); 541 608 } 542 609 543 610 /* ··· 547 626 static __attribute__((unused)) 548 627 int kill(pid_t pid, int signal) 549 628 { 550 - int ret = sys_kill(pid, signal); 551 - 552 - if (ret < 0) { 553 - SET_ERRNO(-ret); 554 - ret = -1; 555 - } 556 - return ret; 629 + return __sysret(sys_kill(pid, signal)); 557 630 } 558 631 559 632 ··· 563 648 #elif defined(__NR_link) 564 649 return my_syscall2(__NR_link, old, new); 565 650 #else 566 - #error Neither __NR_linkat nor __NR_link defined, cannot implement sys_link() 651 + return -ENOSYS; 567 652 #endif 568 653 } 569 654 570 655 static __attribute__((unused)) 571 656 int link(const char *old, const char *new) 572 657 { 573 - int ret = sys_link(old, new); 574 - 575 - if (ret < 0) { 576 - SET_ERRNO(-ret); 577 - ret = -1; 578 - } 579 - return ret; 658 + return __sysret(sys_link(old, new)); 580 659 } 581 660 582 661 ··· 581 672 static __attribute__((unused)) 582 673 off_t sys_lseek(int fd, off_t offset, int whence) 583 674 { 675 + #ifdef __NR_lseek 584 676 return my_syscall3(__NR_lseek, fd, offset, whence); 677 + #else 678 + return -ENOSYS; 679 + #endif 585 680 } 586 681 587 682 static __attribute__((unused)) 588 683 off_t lseek(int fd, off_t offset, int whence) 589 684 { 590 - off_t ret = sys_lseek(fd, offset, whence); 591 - 592 - if (ret < 0) { 593 - SET_ERRNO(-ret); 594 - ret = -1; 595 - } 596 - return ret; 685 + return __sysret(sys_lseek(fd, offset, whence)); 597 686 } 598 687 599 688 ··· 607 700 #elif defined(__NR_mkdir) 608 701 return my_syscall2(__NR_mkdir, path, mode); 609 702 #else 610 - #error Neither __NR_mkdirat nor __NR_mkdir defined, cannot implement sys_mkdir() 703 + return -ENOSYS; 611 704 #endif 612 705 } 613 706 614 707 static __attribute__((unused)) 615 708 int mkdir(const char *path, mode_t mode) 616 709 { 617 - int ret = sys_mkdir(path, mode); 710 + return __sysret(sys_mkdir(path, mode)); 711 + } 618 712 619 - if (ret < 0) { 620 - SET_ERRNO(-ret); 621 - ret = -1; 622 - } 623 - return ret; 713 + /* 714 + * int rmdir(const char *path); 715 + */ 716 + 717 + static __attribute__((unused)) 718 + int sys_rmdir(const char *path) 719 + { 720 + #ifdef __NR_rmdir 721 + return my_syscall1(__NR_rmdir, path); 722 + #elif defined(__NR_unlinkat) 723 + return my_syscall3(__NR_unlinkat, AT_FDCWD, path, AT_REMOVEDIR); 724 + #else 725 + return -ENOSYS; 726 + #endif 727 + } 728 + 729 + static __attribute__((unused)) 730 + int rmdir(const char *path) 731 + { 732 + return __sysret(sys_rmdir(path)); 624 733 } 625 734 626 735 ··· 652 729 #elif defined(__NR_mknod) 653 730 return my_syscall3(__NR_mknod, path, mode, dev); 654 731 #else 655 - #error Neither __NR_mknodat nor __NR_mknod defined, cannot implement sys_mknod() 732 + return -ENOSYS; 656 733 #endif 657 734 } 658 735 659 736 static __attribute__((unused)) 660 737 int mknod(const char *path, mode_t mode, dev_t dev) 661 738 { 662 - int ret = sys_mknod(path, mode, dev); 663 - 664 - if (ret < 0) { 665 - SET_ERRNO(-ret); 666 - ret = -1; 667 - } 668 - return ret; 739 + return __sysret(sys_mknod(path, mode, dev)); 669 740 } 670 - 671 - #ifndef MAP_SHARED 672 - #define MAP_SHARED 0x01 /* Share changes */ 673 - #define MAP_PRIVATE 0x02 /* Changes are private */ 674 - #define MAP_SHARED_VALIDATE 0x03 /* share + validate extension flags */ 675 - #endif 676 - 677 - #ifndef MAP_FAILED 678 - #define MAP_FAILED ((void *)-1) 679 - #endif 680 741 681 742 #ifndef sys_mmap 682 743 static __attribute__((unused)) 683 744 void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, 684 745 off_t offset) 685 746 { 686 - #ifndef my_syscall6 687 - /* Function not implemented. */ 688 - return (void *)-ENOSYS; 689 - #else 690 - 691 747 int n; 692 748 693 749 #if defined(__NR_mmap2) ··· 677 775 #endif 678 776 679 777 return (void *)my_syscall6(n, addr, length, prot, flags, fd, offset); 680 - #endif 681 778 } 682 779 #endif 780 + 781 + /* Note that on Linux, MAP_FAILED is -1 so we can use the generic __sysret() 782 + * which returns -1 upon error and still satisfy user land that checks for 783 + * MAP_FAILED. 784 + */ 683 785 684 786 static __attribute__((unused)) 685 787 void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) ··· 706 800 static __attribute__((unused)) 707 801 int munmap(void *addr, size_t length) 708 802 { 709 - int ret = sys_munmap(addr, length); 710 - 711 - if (ret < 0) { 712 - SET_ERRNO(-ret); 713 - ret = -1; 714 - } 715 - return ret; 803 + return __sysret(sys_munmap(addr, length)); 716 804 } 717 805 718 806 /* ··· 726 826 const char *fst, unsigned long flags, 727 827 const void *data) 728 828 { 729 - int ret = sys_mount(src, tgt, fst, flags, data); 730 - 731 - if (ret < 0) { 732 - SET_ERRNO(-ret); 733 - ret = -1; 734 - } 735 - return ret; 829 + return __sysret(sys_mount(src, tgt, fst, flags, data)); 736 830 } 737 831 738 832 ··· 742 848 #elif defined(__NR_open) 743 849 return my_syscall3(__NR_open, path, flags, mode); 744 850 #else 745 - #error Neither __NR_openat nor __NR_open defined, cannot implement sys_open() 851 + return -ENOSYS; 746 852 #endif 747 853 } 748 854 ··· 750 856 int open(const char *path, int flags, ...) 751 857 { 752 858 mode_t mode = 0; 753 - int ret; 754 859 755 860 if (flags & O_CREAT) { 756 861 va_list args; ··· 759 866 va_end(args); 760 867 } 761 868 762 - ret = sys_open(path, flags, mode); 869 + return __sysret(sys_open(path, flags, mode)); 870 + } 763 871 764 - if (ret < 0) { 765 - SET_ERRNO(-ret); 766 - ret = -1; 767 - } 768 - return ret; 872 + 873 + /* 874 + * int pipe2(int pipefd[2], int flags); 875 + * int pipe(int pipefd[2]); 876 + */ 877 + 878 + static __attribute__((unused)) 879 + int sys_pipe2(int pipefd[2], int flags) 880 + { 881 + return my_syscall2(__NR_pipe2, pipefd, flags); 882 + } 883 + 884 + static __attribute__((unused)) 885 + int pipe2(int pipefd[2], int flags) 886 + { 887 + return __sysret(sys_pipe2(pipefd, flags)); 888 + } 889 + 890 + static __attribute__((unused)) 891 + int pipe(int pipefd[2]) 892 + { 893 + return pipe2(pipefd, 0); 769 894 } 770 895 771 896 ··· 803 892 int prctl(int option, unsigned long arg2, unsigned long arg3, 804 893 unsigned long arg4, unsigned long arg5) 805 894 { 806 - int ret = sys_prctl(option, arg2, arg3, arg4, arg5); 807 - 808 - if (ret < 0) { 809 - SET_ERRNO(-ret); 810 - ret = -1; 811 - } 812 - return ret; 895 + return __sysret(sys_prctl(option, arg2, arg3, arg4, arg5)); 813 896 } 814 897 815 898 ··· 820 915 static __attribute__((unused)) 821 916 int pivot_root(const char *new, const char *old) 822 917 { 823 - int ret = sys_pivot_root(new, old); 824 - 825 - if (ret < 0) { 826 - SET_ERRNO(-ret); 827 - ret = -1; 828 - } 829 - return ret; 918 + return __sysret(sys_pivot_root(new, old)); 830 919 } 831 920 832 921 ··· 842 943 #elif defined(__NR_poll) 843 944 return my_syscall3(__NR_poll, fds, nfds, timeout); 844 945 #else 845 - #error Neither __NR_ppoll nor __NR_poll defined, cannot implement sys_poll() 946 + return -ENOSYS; 846 947 #endif 847 948 } 848 949 849 950 static __attribute__((unused)) 850 951 int poll(struct pollfd *fds, int nfds, int timeout) 851 952 { 852 - int ret = sys_poll(fds, nfds, timeout); 853 - 854 - if (ret < 0) { 855 - SET_ERRNO(-ret); 856 - ret = -1; 857 - } 858 - return ret; 953 + return __sysret(sys_poll(fds, nfds, timeout)); 859 954 } 860 955 861 956 ··· 866 973 static __attribute__((unused)) 867 974 ssize_t read(int fd, void *buf, size_t count) 868 975 { 869 - ssize_t ret = sys_read(fd, buf, count); 870 - 871 - if (ret < 0) { 872 - SET_ERRNO(-ret); 873 - ret = -1; 874 - } 875 - return ret; 976 + return __sysret(sys_read(fd, buf, count)); 876 977 } 877 978 878 979 ··· 884 997 static __attribute__((unused)) 885 998 int reboot(int cmd) 886 999 { 887 - int ret = sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, 0); 888 - 889 - if (ret < 0) { 890 - SET_ERRNO(-ret); 891 - ret = -1; 892 - } 893 - return ret; 1000 + return __sysret(sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, 0)); 894 1001 } 895 1002 896 1003 ··· 901 1020 static __attribute__((unused)) 902 1021 int sched_yield(void) 903 1022 { 904 - int ret = sys_sched_yield(); 905 - 906 - if (ret < 0) { 907 - SET_ERRNO(-ret); 908 - ret = -1; 909 - } 910 - return ret; 1023 + return __sysret(sys_sched_yield()); 911 1024 } 912 1025 913 1026 ··· 934 1059 #endif 935 1060 return my_syscall5(__NR__newselect, nfds, rfds, wfds, efds, timeout); 936 1061 #else 937 - #error None of __NR_select, __NR_pselect6, nor __NR__newselect defined, cannot implement sys_select() 1062 + return -ENOSYS; 938 1063 #endif 939 1064 } 940 1065 941 1066 static __attribute__((unused)) 942 1067 int select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout) 943 1068 { 944 - int ret = sys_select(nfds, rfds, wfds, efds, timeout); 945 - 946 - if (ret < 0) { 947 - SET_ERRNO(-ret); 948 - ret = -1; 949 - } 950 - return ret; 1069 + return __sysret(sys_select(nfds, rfds, wfds, efds, timeout)); 951 1070 } 952 1071 953 1072 ··· 958 1089 static __attribute__((unused)) 959 1090 int setpgid(pid_t pid, pid_t pgid) 960 1091 { 961 - int ret = sys_setpgid(pid, pgid); 962 - 963 - if (ret < 0) { 964 - SET_ERRNO(-ret); 965 - ret = -1; 966 - } 967 - return ret; 1092 + return __sysret(sys_setpgid(pid, pgid)); 968 1093 } 969 1094 970 1095 ··· 975 1112 static __attribute__((unused)) 976 1113 pid_t setsid(void) 977 1114 { 978 - pid_t ret = sys_setsid(); 979 - 980 - if (ret < 0) { 981 - SET_ERRNO(-ret); 982 - ret = -1; 983 - } 984 - return ret; 1115 + return __sysret(sys_setsid()); 985 1116 } 986 1117 987 - #if defined(__NR_statx) 988 1118 /* 989 1119 * int statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf); 1120 + * int stat(const char *path, struct stat *buf); 990 1121 */ 991 1122 992 1123 static __attribute__((unused)) 993 1124 int sys_statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf) 994 1125 { 1126 + #ifdef __NR_statx 995 1127 return my_syscall5(__NR_statx, fd, path, flags, mask, buf); 1128 + #else 1129 + return -ENOSYS; 1130 + #endif 996 1131 } 997 1132 998 1133 static __attribute__((unused)) 999 1134 int statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf) 1000 1135 { 1001 - int ret = sys_statx(fd, path, flags, mask, buf); 1002 - 1003 - if (ret < 0) { 1004 - SET_ERRNO(-ret); 1005 - ret = -1; 1006 - } 1007 - return ret; 1136 + return __sysret(sys_statx(fd, path, flags, mask, buf)); 1008 1137 } 1009 - #endif 1010 1138 1011 - /* 1012 - * int stat(const char *path, struct stat *buf); 1013 - * Warning: the struct stat's layout is arch-dependent. 1014 - */ 1015 1139 1016 - #if defined(__NR_statx) && !defined(__NR_newfstatat) && !defined(__NR_stat) 1017 - /* 1018 - * Maybe we can just use statx() when available for all architectures? 1019 - */ 1020 1140 static __attribute__((unused)) 1021 - int sys_stat(const char *path, struct stat *buf) 1141 + int stat(const char *path, struct stat *buf) 1022 1142 { 1023 1143 struct statx statx; 1024 1144 long ret; 1025 1145 1026 - ret = sys_statx(AT_FDCWD, path, AT_NO_AUTOMOUNT, STATX_BASIC_STATS, &statx); 1146 + ret = __sysret(sys_statx(AT_FDCWD, path, AT_NO_AUTOMOUNT, STATX_BASIC_STATS, &statx)); 1147 + if (ret == -1) 1148 + return ret; 1149 + 1027 1150 buf->st_dev = ((statx.stx_dev_minor & 0xff) 1028 1151 | (statx.stx_dev_major << 8) 1029 1152 | ((statx.stx_dev_minor & ~0xff) << 12)); ··· 1030 1181 buf->st_mtim.tv_nsec = statx.stx_mtime.tv_nsec; 1031 1182 buf->st_ctim.tv_sec = statx.stx_ctime.tv_sec; 1032 1183 buf->st_ctim.tv_nsec = statx.stx_ctime.tv_nsec; 1033 - return ret; 1034 - } 1035 - #else 1036 - static __attribute__((unused)) 1037 - int sys_stat(const char *path, struct stat *buf) 1038 - { 1039 - struct sys_stat_struct stat; 1040 - long ret; 1041 1184 1042 - #ifdef __NR_newfstatat 1043 - /* only solution for arm64 */ 1044 - ret = my_syscall4(__NR_newfstatat, AT_FDCWD, path, &stat, 0); 1045 - #elif defined(__NR_stat) 1046 - ret = my_syscall2(__NR_stat, path, &stat); 1047 - #else 1048 - #error Neither __NR_newfstatat nor __NR_stat defined, cannot implement sys_stat() 1049 - #endif 1050 - buf->st_dev = stat.st_dev; 1051 - buf->st_ino = stat.st_ino; 1052 - buf->st_mode = stat.st_mode; 1053 - buf->st_nlink = stat.st_nlink; 1054 - buf->st_uid = stat.st_uid; 1055 - buf->st_gid = stat.st_gid; 1056 - buf->st_rdev = stat.st_rdev; 1057 - buf->st_size = stat.st_size; 1058 - buf->st_blksize = stat.st_blksize; 1059 - buf->st_blocks = stat.st_blocks; 1060 - buf->st_atim.tv_sec = stat.st_atime; 1061 - buf->st_atim.tv_nsec = stat.st_atime_nsec; 1062 - buf->st_mtim.tv_sec = stat.st_mtime; 1063 - buf->st_mtim.tv_nsec = stat.st_mtime_nsec; 1064 - buf->st_ctim.tv_sec = stat.st_ctime; 1065 - buf->st_ctim.tv_nsec = stat.st_ctime_nsec; 1066 - return ret; 1067 - } 1068 - #endif 1069 - 1070 - static __attribute__((unused)) 1071 - int stat(const char *path, struct stat *buf) 1072 - { 1073 - int ret = sys_stat(path, buf); 1074 - 1075 - if (ret < 0) { 1076 - SET_ERRNO(-ret); 1077 - ret = -1; 1078 - } 1079 - return ret; 1185 + return 0; 1080 1186 } 1081 1187 1082 1188 ··· 1047 1243 #elif defined(__NR_symlink) 1048 1244 return my_syscall2(__NR_symlink, old, new); 1049 1245 #else 1050 - #error Neither __NR_symlinkat nor __NR_symlink defined, cannot implement sys_symlink() 1246 + return -ENOSYS; 1051 1247 #endif 1052 1248 } 1053 1249 1054 1250 static __attribute__((unused)) 1055 1251 int symlink(const char *old, const char *new) 1056 1252 { 1057 - int ret = sys_symlink(old, new); 1058 - 1059 - if (ret < 0) { 1060 - SET_ERRNO(-ret); 1061 - ret = -1; 1062 - } 1063 - return ret; 1253 + return __sysret(sys_symlink(old, new)); 1064 1254 } 1065 1255 1066 1256 ··· 1088 1290 static __attribute__((unused)) 1089 1291 int umount2(const char *path, int flags) 1090 1292 { 1091 - int ret = sys_umount2(path, flags); 1092 - 1093 - if (ret < 0) { 1094 - SET_ERRNO(-ret); 1095 - ret = -1; 1096 - } 1097 - return ret; 1293 + return __sysret(sys_umount2(path, flags)); 1098 1294 } 1099 1295 1100 1296 ··· 1104 1312 #elif defined(__NR_unlink) 1105 1313 return my_syscall1(__NR_unlink, path); 1106 1314 #else 1107 - #error Neither __NR_unlinkat nor __NR_unlink defined, cannot implement sys_unlink() 1315 + return -ENOSYS; 1108 1316 #endif 1109 1317 } 1110 1318 1111 1319 static __attribute__((unused)) 1112 1320 int unlink(const char *path) 1113 1321 { 1114 - int ret = sys_unlink(path); 1115 - 1116 - if (ret < 0) { 1117 - SET_ERRNO(-ret); 1118 - ret = -1; 1119 - } 1120 - return ret; 1322 + return __sysret(sys_unlink(path)); 1121 1323 } 1122 1324 1123 1325 ··· 1124 1338 static __attribute__((unused)) 1125 1339 pid_t sys_wait4(pid_t pid, int *status, int options, struct rusage *rusage) 1126 1340 { 1341 + #ifdef __NR_wait4 1127 1342 return my_syscall4(__NR_wait4, pid, status, options, rusage); 1343 + #else 1344 + return -ENOSYS; 1345 + #endif 1128 1346 } 1129 1347 1130 1348 static __attribute__((unused)) 1131 1349 pid_t wait(int *status) 1132 1350 { 1133 - pid_t ret = sys_wait4(-1, status, 0, NULL); 1134 - 1135 - if (ret < 0) { 1136 - SET_ERRNO(-ret); 1137 - ret = -1; 1138 - } 1139 - return ret; 1351 + return __sysret(sys_wait4(-1, status, 0, NULL)); 1140 1352 } 1141 1353 1142 1354 static __attribute__((unused)) 1143 1355 pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage) 1144 1356 { 1145 - pid_t ret = sys_wait4(pid, status, options, rusage); 1146 - 1147 - if (ret < 0) { 1148 - SET_ERRNO(-ret); 1149 - ret = -1; 1150 - } 1151 - return ret; 1357 + return __sysret(sys_wait4(pid, status, options, rusage)); 1152 1358 } 1153 1359 1154 1360 1155 1361 static __attribute__((unused)) 1156 1362 pid_t waitpid(pid_t pid, int *status, int options) 1157 1363 { 1158 - pid_t ret = sys_wait4(pid, status, options, NULL); 1159 - 1160 - if (ret < 0) { 1161 - SET_ERRNO(-ret); 1162 - ret = -1; 1163 - } 1164 - return ret; 1364 + return __sysret(sys_wait4(pid, status, options, NULL)); 1165 1365 } 1166 1366 1167 1367 ··· 1164 1392 static __attribute__((unused)) 1165 1393 ssize_t write(int fd, const void *buf, size_t count) 1166 1394 { 1167 - ssize_t ret = sys_write(fd, buf, count); 1168 - 1169 - if (ret < 0) { 1170 - SET_ERRNO(-ret); 1171 - ret = -1; 1172 - } 1173 - return ret; 1395 + return __sysret(sys_write(fd, buf, count)); 1174 1396 } 1175 1397 1176 1398 ··· 1181 1415 static __attribute__((unused)) 1182 1416 int memfd_create(const char *name, unsigned int flags) 1183 1417 { 1184 - ssize_t ret = sys_memfd_create(name, flags); 1185 - 1186 - if (ret < 0) { 1187 - SET_ERRNO(-ret); 1188 - ret = -1; 1189 - } 1190 - return ret; 1418 + return __sysret(sys_memfd_create(name, flags)); 1191 1419 } 1192 1420 1193 1421 /* make sure to include all global symbols */
+19 -3
tools/include/nolibc/types.h
··· 8 8 #define _NOLIBC_TYPES_H 9 9 10 10 #include "std.h" 11 - #include <linux/time.h> 11 + #include <linux/mman.h> 12 + #include <linux/reboot.h> /* for LINUX_REBOOT_* */ 12 13 #include <linux/stat.h> 14 + #include <linux/time.h> 13 15 14 16 15 17 /* Only the generic macros and types may be defined here. The arch-specific 16 - * ones such as the O_RDONLY and related macros used by fcntl() and open(), or 17 - * the layout of sys_stat_struct must not be defined here. 18 + * ones such as the O_RDONLY and related macros used by fcntl() and open() 19 + * must not be defined here. 18 20 */ 19 21 20 22 /* stat flags (WARNING, octal here). We need to check for an existing ··· 83 81 #define MAXPATHLEN (PATH_MAX) 84 82 #endif 85 83 84 + /* flags for mmap */ 85 + #ifndef MAP_FAILED 86 + #define MAP_FAILED ((void *)-1) 87 + #endif 88 + 86 89 /* whence values for lseek() */ 87 90 #define SEEK_SET 0 88 91 #define SEEK_CUR 1 89 92 #define SEEK_END 2 93 + 94 + /* flags for reboot */ 95 + #define RB_AUTOBOOT LINUX_REBOOT_CMD_RESTART 96 + #define RB_HALT_SYSTEM LINUX_REBOOT_CMD_HALT 97 + #define RB_ENABLE_CAD LINUX_REBOOT_CMD_CAD_ON 98 + #define RB_DISABLE_CAD LINUX_REBOOT_CMD_CAD_OFF 99 + #define RB_POWER_OFF LINUX_REBOOT_CMD_POWER_OFF 100 + #define RB_SW_SUSPEND LINUX_REBOOT_CMD_SW_SUSPEND 101 + #define RB_KEXEC LINUX_REBOOT_CMD_KEXEC 90 102 91 103 /* Macros used on waitpid()'s return status */ 92 104 #define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
+2 -11
tools/include/nolibc/unistd.h
··· 56 56 return ioctl(fd, TIOCSPGRP, &pid); 57 57 } 58 58 59 - #define _syscall(N, ...) \ 60 - ({ \ 61 - long _ret = my_syscall##N(__VA_ARGS__); \ 62 - if (_ret < 0) { \ 63 - SET_ERRNO(-_ret); \ 64 - _ret = -1; \ 65 - } \ 66 - _ret; \ 67 - }) 68 - 69 - #define _syscall_narg(...) __syscall_narg(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) 70 59 #define __syscall_narg(_0, _1, _2, _3, _4, _5, _6, N, ...) N 60 + #define _syscall_narg(...) __syscall_narg(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) 61 + #define _syscall(N, ...) __sysret(my_syscall##N(__VA_ARGS__)) 71 62 #define _syscall_n(N, ...) _syscall(N, __VA_ARGS__) 72 63 #define syscall(...) _syscall_n(_syscall_narg(__VA_ARGS__), ##__VA_ARGS__) 73 64
+84 -27
tools/testing/selftests/nolibc/Makefile
··· 14 14 ARCH = $(SUBARCH) 15 15 endif 16 16 17 + # XARCH extends the kernel's ARCH with a few variants of the same 18 + # architecture that only differ by the configuration, the toolchain 19 + # and the Qemu program used. It is copied as-is into ARCH except for 20 + # a few specific values which are mapped like this: 21 + # 22 + # XARCH | ARCH | config 23 + # -------------|-----------|------------------------- 24 + # ppc | powerpc | 32 bits 25 + # ppc64 | powerpc | 64 bits big endian 26 + # ppc64le | powerpc | 64 bits little endian 27 + # 28 + # It is recommended to only use XARCH, though it does not harm if 29 + # ARCH is already set. For simplicity, ARCH is sufficient for all 30 + # architectures where both are equal. 31 + 32 + # configure default variants for target kernel supported architectures 33 + XARCH_powerpc = ppc 34 + XARCH = $(or $(XARCH_$(ARCH)),$(ARCH)) 35 + 36 + # map from user input variants to their kernel supported architectures 37 + ARCH_ppc = powerpc 38 + ARCH_ppc64 = powerpc 39 + ARCH_ppc64le = powerpc 40 + ARCH := $(or $(ARCH_$(XARCH)),$(XARCH)) 41 + 17 42 # kernel image names by architecture 18 43 IMAGE_i386 = arch/x86/boot/bzImage 19 44 IMAGE_x86_64 = arch/x86/boot/bzImage ··· 46 21 IMAGE_arm64 = arch/arm64/boot/Image 47 22 IMAGE_arm = arch/arm/boot/zImage 48 23 IMAGE_mips = vmlinuz 24 + IMAGE_ppc = vmlinux 25 + IMAGE_ppc64 = vmlinux 26 + IMAGE_ppc64le = arch/powerpc/boot/zImage 49 27 IMAGE_riscv = arch/riscv/boot/Image 50 28 IMAGE_s390 = arch/s390/boot/bzImage 51 29 IMAGE_loongarch = arch/loongarch/boot/vmlinuz.efi 52 - IMAGE = $(IMAGE_$(ARCH)) 30 + IMAGE = $(IMAGE_$(XARCH)) 53 31 IMAGE_NAME = $(notdir $(IMAGE)) 54 32 55 33 # default kernel configurations that appear to be usable ··· 62 34 DEFCONFIG_arm64 = defconfig 63 35 DEFCONFIG_arm = multi_v7_defconfig 64 36 DEFCONFIG_mips = malta_defconfig 37 + DEFCONFIG_ppc = pmac32_defconfig 38 + DEFCONFIG_ppc64 = powernv_be_defconfig 39 + DEFCONFIG_ppc64le = powernv_defconfig 65 40 DEFCONFIG_riscv = defconfig 66 41 DEFCONFIG_s390 = defconfig 67 42 DEFCONFIG_loongarch = defconfig 68 - DEFCONFIG = $(DEFCONFIG_$(ARCH)) 43 + DEFCONFIG = $(DEFCONFIG_$(XARCH)) 69 44 70 45 # optional tests to run (default = all) 71 46 TEST = ··· 80 49 QEMU_ARCH_arm64 = aarch64 81 50 QEMU_ARCH_arm = arm 82 51 QEMU_ARCH_mips = mipsel # works with malta_defconfig 52 + QEMU_ARCH_ppc = ppc 53 + QEMU_ARCH_ppc64 = ppc64 54 + QEMU_ARCH_ppc64le = ppc64le 83 55 QEMU_ARCH_riscv = riscv64 84 56 QEMU_ARCH_s390 = s390x 85 57 QEMU_ARCH_loongarch = loongarch64 86 - QEMU_ARCH = $(QEMU_ARCH_$(ARCH)) 58 + QEMU_ARCH = $(QEMU_ARCH_$(XARCH)) 87 59 88 60 # QEMU_ARGS : some arch-specific args to pass to qemu 89 61 QEMU_ARGS_i386 = -M pc -append "console=ttyS0,9600 i8042.noaux panic=-1 $(TEST:%=NOLIBC_TEST=%)" ··· 95 61 QEMU_ARGS_arm64 = -M virt -cpu cortex-a53 -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)" 96 62 QEMU_ARGS_arm = -M virt -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)" 97 63 QEMU_ARGS_mips = -M malta -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)" 64 + QEMU_ARGS_ppc = -M g3beige -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)" 65 + QEMU_ARGS_ppc64 = -M powernv -append "console=hvc0 panic=-1 $(TEST:%=NOLIBC_TEST=%)" 66 + QEMU_ARGS_ppc64le = -M powernv -append "console=hvc0 panic=-1 $(TEST:%=NOLIBC_TEST=%)" 98 67 QEMU_ARGS_riscv = -M virt -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)" 99 68 QEMU_ARGS_s390 = -M s390-ccw-virtio -m 1G -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)" 100 69 QEMU_ARGS_loongarch = -M virt -append "console=ttyS0,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)" 101 - QEMU_ARGS = $(QEMU_ARGS_$(ARCH)) $(QEMU_ARGS_EXTRA) 70 + QEMU_ARGS = $(QEMU_ARGS_$(XARCH)) $(QEMU_ARGS_EXTRA) 102 71 103 72 # OUTPUT is only set when run from the main makefile, otherwise 104 73 # it defaults to this nolibc directory. ··· 113 76 Q=@ 114 77 endif 115 78 79 + CFLAGS_ppc = -m32 -mbig-endian -mno-vsx $(call cc-option,-mmultiple) 80 + CFLAGS_ppc64 = -m64 -mbig-endian -mno-vsx $(call cc-option,-mmultiple) 81 + CFLAGS_ppc64le = -m64 -mlittle-endian -mno-vsx $(call cc-option,-mabi=elfv2) 116 82 CFLAGS_s390 = -m64 117 83 CFLAGS_mips = -EL 118 84 CFLAGS_STACKPROTECTOR ?= $(call cc-option,-mstack-protector-guard=global $(call cc-option,-fstack-protector-all)) 119 - CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables -std=c89 \ 85 + CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables -std=c89 -W -Wall -Wextra \ 120 86 $(call cc-option,-fno-stack-protector) \ 121 - $(CFLAGS_$(ARCH)) $(CFLAGS_STACKPROTECTOR) 122 - LDFLAGS := -s 87 + $(CFLAGS_$(XARCH)) $(CFLAGS_STACKPROTECTOR) 88 + LDFLAGS := 89 + 90 + REPORT ?= awk '/\[OK\][\r]*$$/{p++} /\[FAIL\][\r]*$$/{if (!f) printf("\n"); f++; print;} /\[SKIPPED\][\r]*$$/{s++} \ 91 + END{ printf("\n%3d test(s): %3d passed, %3d skipped, %3d failed => status: ", p+s+f, p, s, f); \ 92 + if (f) printf("failure\n"); else if (s) printf("warning\n"); else printf("success\n");; \ 93 + printf("\nSee all results in %s\n", ARGV[1]); }' 123 94 124 95 help: 125 96 @echo "Supported targets under selftests/nolibc:" ··· 136 91 @echo " sysroot create the nolibc sysroot here (uses \$$ARCH)" 137 92 @echo " nolibc-test build the executable (uses \$$CC and \$$CROSS_COMPILE)" 138 93 @echo " libc-test build an executable using the compiler's default libc instead" 139 - @echo " run-user runs the executable under QEMU (uses \$$ARCH, \$$TEST)" 94 + @echo " run-user runs the executable under QEMU (uses \$$XARCH, \$$TEST)" 140 95 @echo " initramfs prepare the initramfs with nolibc-test" 141 - @echo " defconfig create a fresh new default config (uses \$$ARCH)" 142 - @echo " kernel (re)build the kernel with the initramfs (uses \$$ARCH)" 143 - @echo " run runs the kernel in QEMU after building it (uses \$$ARCH, \$$TEST)" 144 - @echo " rerun runs a previously prebuilt kernel in QEMU (uses \$$ARCH, \$$TEST)" 96 + @echo " defconfig create a fresh new default config (uses \$$XARCH)" 97 + @echo " kernel (re)build the kernel with the initramfs (uses \$$XARCH)" 98 + @echo " run runs the kernel in QEMU after building it (uses \$$XARCH, \$$TEST)" 99 + @echo " rerun runs a previously prebuilt kernel in QEMU (uses \$$XARCH, \$$TEST)" 145 100 @echo " clean clean the sysroot, initramfs, build and output files" 146 101 @echo "" 147 102 @echo "The output file is \"run.out\". Test ranges may be passed using \$$TEST." 148 103 @echo "" 149 104 @echo "Currently using the following variables:" 150 105 @echo " ARCH = $(ARCH)" 106 + @echo " XARCH = $(XARCH)" 151 107 @echo " CROSS_COMPILE = $(CROSS_COMPILE)" 152 108 @echo " CC = $(CC)" 153 109 @echo " OUTPUT = $(OUTPUT)" 154 110 @echo " TEST = $(TEST)" 155 - @echo " QEMU_ARCH = $(if $(QEMU_ARCH),$(QEMU_ARCH),UNKNOWN_ARCH) [determined from \$$ARCH]" 156 - @echo " IMAGE_NAME = $(if $(IMAGE_NAME),$(IMAGE_NAME),UNKNOWN_ARCH) [determined from \$$ARCH]" 111 + @echo " QEMU_ARCH = $(if $(QEMU_ARCH),$(QEMU_ARCH),UNKNOWN_ARCH) [determined from \$$XARCH]" 112 + @echo " IMAGE_NAME = $(if $(IMAGE_NAME),$(IMAGE_NAME),UNKNOWN_ARCH) [determined from \$$XARCH]" 157 113 @echo "" 158 114 159 115 all: run ··· 167 121 $(Q)$(MAKE) -C ../../../include/nolibc ARCH=$(ARCH) OUTPUT=$(CURDIR)/sysroot/ headers_standalone 168 122 $(Q)mv sysroot/sysroot sysroot/$(ARCH) 169 123 124 + ifneq ($(NOLIBC_SYSROOT),0) 170 125 nolibc-test: nolibc-test.c sysroot/$(ARCH)/include 171 126 $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ \ 172 127 -nostdlib -static -Isysroot/$(ARCH)/include $< -lgcc 128 + else 129 + nolibc-test: nolibc-test.c 130 + $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ \ 131 + -nostdlib -static -include ../../../include/nolibc/nolibc.h $< -lgcc 132 + endif 173 133 174 134 libc-test: nolibc-test.c 175 - $(QUIET_CC)$(CC) -o $@ $< 135 + $(QUIET_CC)$(HOSTCC) -o $@ $< 136 + 137 + # local libc-test 138 + run-libc-test: libc-test 139 + $(Q)./libc-test > "$(CURDIR)/run.out" || : 140 + $(Q)$(REPORT) $(CURDIR)/run.out 141 + 142 + # local nolibc-test 143 + run-nolibc-test: nolibc-test 144 + $(Q)./nolibc-test > "$(CURDIR)/run.out" || : 145 + $(Q)$(REPORT) $(CURDIR)/run.out 176 146 177 147 # qemu user-land test 178 148 run-user: nolibc-test 179 149 $(Q)qemu-$(QEMU_ARCH) ./nolibc-test > "$(CURDIR)/run.out" || : 180 - $(Q)awk '/\[OK\][\r]*$$/{p++} /\[FAIL\][\r]*$$/{f++} /\[SKIPPED\][\r]*$$/{s++} \ 181 - END{ printf("%d test(s) passed, %d skipped, %d failed.", p, s, f); \ 182 - if (s+f > 0) printf(" See all results in %s\n", ARGV[1]); else print; }' \ 183 - $(CURDIR)/run.out 150 + $(Q)$(REPORT) $(CURDIR)/run.out 184 151 185 152 initramfs: nolibc-test 186 153 $(QUIET_MKDIR)mkdir -p initramfs ··· 209 150 # run the tests after building the kernel 210 151 run: kernel 211 152 $(Q)qemu-system-$(QEMU_ARCH) -display none -no-reboot -kernel "$(srctree)/$(IMAGE)" -serial stdio $(QEMU_ARGS) > "$(CURDIR)/run.out" 212 - $(Q)awk '/\[OK\][\r]*$$/{p++} /\[FAIL\][\r]*$$/{f++} /\[SKIPPED\][\r]*$$/{s++} \ 213 - END{ printf("%d test(s) passed, %d skipped, %d failed.", p, s, f); \ 214 - if (s+f > 0) printf(" See all results in %s\n", ARGV[1]); else print; }' \ 215 - $(CURDIR)/run.out 153 + $(Q)$(REPORT) $(CURDIR)/run.out 216 154 217 155 # re-run the tests from an existing kernel 218 156 rerun: 219 157 $(Q)qemu-system-$(QEMU_ARCH) -display none -no-reboot -kernel "$(srctree)/$(IMAGE)" -serial stdio $(QEMU_ARGS) > "$(CURDIR)/run.out" 220 - $(Q)awk '/\[OK\][\r]*$$/{p++} /\[FAIL\][\r]*$$/{f++} /\[SKIPPED\][\r]*$$/{s++} \ 221 - END{ printf("%d test(s) passed, %d skipped, %d failed.", p, s, f); \ 222 - if (s+f > 0) printf(" See all results in %s\n", ARGV[1]); else print; }' \ 223 - $(CURDIR)/run.out 158 + $(Q)$(REPORT) $(CURDIR)/run.out 159 + 160 + # report with existing test log 161 + report: 162 + $(Q)$(REPORT) $(CURDIR)/run.out 224 163 225 164 clean: 226 165 $(call QUIET_CLEAN, sysroot)
+461 -143
tools/testing/selftests/nolibc/nolibc-test.c
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 */ 2 2 3 3 #define _GNU_SOURCE 4 + #define _LARGEFILE64_SOURCE 4 5 5 6 /* libc-specific include files 6 7 * The program may be built in 3 ways: ··· 15 14 #include <string.h> 16 15 #ifndef _NOLIBC_STDIO_H 17 16 /* standard libcs need more includes */ 18 - #include <linux/reboot.h> 17 + #include <sys/auxv.h> 19 18 #include <sys/io.h> 20 19 #include <sys/ioctl.h> 21 20 #include <sys/mman.h> ··· 41 40 #endif 42 41 #endif 43 42 44 - /* will be used by nolibc by getenv() */ 45 - char **environ; 43 + /* for the type of int_fast16_t and int_fast32_t, musl differs from glibc and nolibc */ 44 + #define SINT_MAX_OF_TYPE(type) (((type)1 << (sizeof(type) * 8 - 2)) - (type)1 + ((type)1 << (sizeof(type) * 8 - 2))) 45 + #define SINT_MIN_OF_TYPE(type) (-SINT_MAX_OF_TYPE(type) - 1) 46 + 47 + /* will be used to test initialization of environ */ 48 + static char **test_envp; 49 + 50 + /* will be used to test initialization of argv */ 51 + static char **test_argv; 52 + 53 + /* will be used to test initialization of argc */ 54 + static int test_argc; 55 + 56 + /* will be used by some test cases as readable file, please don't write it */ 57 + static const char *argv0; 46 58 47 59 /* definition of a series of tests */ 48 60 struct test { ··· 80 66 /* returns the error name (e.g. "ENOENT") for common errors, "SUCCESS" for 0, 81 67 * or the decimal value for less common ones. 82 68 */ 83 - const char *errorname(int err) 69 + static const char *errorname(int err) 84 70 { 85 71 switch (err) { 86 72 case 0: return "SUCCESS"; ··· 134 120 fputs(buf, stdout); 135 121 } 136 122 137 - static int pad_spc(int llen, int cnt, const char *fmt, ...) 123 + enum RESULT { 124 + OK, 125 + FAIL, 126 + SKIPPED, 127 + }; 128 + 129 + static void result(int llen, enum RESULT r) 138 130 { 139 - va_list args; 140 - int ret; 131 + const char *msg; 141 132 142 - putcharn(' ', cnt - llen); 133 + if (r == OK) 134 + msg = " [OK]"; 135 + else if (r == SKIPPED) 136 + msg = "[SKIPPED]"; 137 + else 138 + msg = "[FAIL]"; 143 139 144 - va_start(args, fmt); 145 - ret = vfprintf(stdout, fmt, args); 146 - va_end(args); 147 - return ret < 0 ? ret : ret + cnt - llen; 140 + if (llen < 64) 141 + putcharn(' ', 64 - llen); 142 + puts(msg); 148 143 } 149 144 150 145 /* The tests below are intended to be used by the macroes, which evaluate ··· 163 140 */ 164 141 165 142 #define EXPECT_ZR(cond, expr) \ 166 - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_zr(expr, llen); } while (0) 143 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_zr(expr, llen); } while (0) 167 144 168 - static int expect_zr(int expr, int llen) 145 + static __attribute__((unused)) 146 + int expect_zr(int expr, int llen) 169 147 { 170 148 int ret = !(expr == 0); 171 149 172 150 llen += printf(" = %d ", expr); 173 - pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n"); 151 + result(llen, ret ? FAIL : OK); 174 152 return ret; 175 153 } 176 154 177 155 178 156 #define EXPECT_NZ(cond, expr, val) \ 179 - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_nz(expr, llen; } while (0) 157 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_nz(expr, llen; } while (0) 180 158 181 - static int expect_nz(int expr, int llen) 159 + static __attribute__((unused)) 160 + int expect_nz(int expr, int llen) 182 161 { 183 162 int ret = !(expr != 0); 184 163 185 164 llen += printf(" = %d ", expr); 186 - pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n"); 165 + result(llen, ret ? FAIL : OK); 187 166 return ret; 188 167 } 189 168 190 169 191 170 #define EXPECT_EQ(cond, expr, val) \ 192 - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_eq(expr, llen, val); } while (0) 171 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_eq(expr, llen, val); } while (0) 193 172 194 - static int expect_eq(uint64_t expr, int llen, uint64_t val) 173 + static __attribute__((unused)) 174 + int expect_eq(uint64_t expr, int llen, uint64_t val) 195 175 { 196 176 int ret = !(expr == val); 197 177 198 178 llen += printf(" = %lld ", (long long)expr); 199 - pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n"); 179 + result(llen, ret ? FAIL : OK); 200 180 return ret; 201 181 } 202 182 203 183 204 184 #define EXPECT_NE(cond, expr, val) \ 205 - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_ne(expr, llen, val); } while (0) 185 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ne(expr, llen, val); } while (0) 206 186 207 - static int expect_ne(int expr, int llen, int val) 187 + static __attribute__((unused)) 188 + int expect_ne(int expr, int llen, int val) 208 189 { 209 190 int ret = !(expr != val); 210 191 211 192 llen += printf(" = %d ", expr); 212 - pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n"); 193 + result(llen, ret ? FAIL : OK); 213 194 return ret; 214 195 } 215 196 216 197 217 198 #define EXPECT_GE(cond, expr, val) \ 218 - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_ge(expr, llen, val); } while (0) 199 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ge(expr, llen, val); } while (0) 219 200 220 - static int expect_ge(int expr, int llen, int val) 201 + static __attribute__((unused)) 202 + int expect_ge(int expr, int llen, int val) 221 203 { 222 204 int ret = !(expr >= val); 223 205 224 206 llen += printf(" = %d ", expr); 225 - pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n"); 207 + result(llen, ret ? FAIL : OK); 226 208 return ret; 227 209 } 228 210 229 211 230 212 #define EXPECT_GT(cond, expr, val) \ 231 - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_gt(expr, llen, val); } while (0) 213 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_gt(expr, llen, val); } while (0) 232 214 233 - static int expect_gt(int expr, int llen, int val) 215 + static __attribute__((unused)) 216 + int expect_gt(int expr, int llen, int val) 234 217 { 235 218 int ret = !(expr > val); 236 219 237 220 llen += printf(" = %d ", expr); 238 - pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n"); 221 + result(llen, ret ? FAIL : OK); 239 222 return ret; 240 223 } 241 224 242 225 243 226 #define EXPECT_LE(cond, expr, val) \ 244 - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_le(expr, llen, val); } while (0) 227 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_le(expr, llen, val); } while (0) 245 228 246 - static int expect_le(int expr, int llen, int val) 229 + static __attribute__((unused)) 230 + int expect_le(int expr, int llen, int val) 247 231 { 248 232 int ret = !(expr <= val); 249 233 250 234 llen += printf(" = %d ", expr); 251 - pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n"); 235 + result(llen, ret ? FAIL : OK); 252 236 return ret; 253 237 } 254 238 255 239 256 240 #define EXPECT_LT(cond, expr, val) \ 257 - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_lt(expr, llen, val); } while (0) 241 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_lt(expr, llen, val); } while (0) 258 242 259 - static int expect_lt(int expr, int llen, int val) 243 + static __attribute__((unused)) 244 + int expect_lt(int expr, int llen, int val) 260 245 { 261 246 int ret = !(expr < val); 262 247 263 248 llen += printf(" = %d ", expr); 264 - pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n"); 249 + result(llen, ret ? FAIL : OK); 265 250 return ret; 266 251 } 267 252 268 253 269 254 #define EXPECT_SYSZR(cond, expr) \ 270 - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_syszr(expr, llen); } while (0) 255 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_syszr(expr, llen); } while (0) 271 256 272 - static int expect_syszr(int expr, int llen) 257 + static __attribute__((unused)) 258 + int expect_syszr(int expr, int llen) 273 259 { 274 260 int ret = 0; 275 261 276 262 if (expr) { 277 263 ret = 1; 278 264 llen += printf(" = %d %s ", expr, errorname(errno)); 279 - llen += pad_spc(llen, 64, "[FAIL]\n"); 265 + result(llen, FAIL); 280 266 } else { 281 267 llen += printf(" = %d ", expr); 282 - llen += pad_spc(llen, 64, " [OK]\n"); 268 + result(llen, OK); 283 269 } 284 270 return ret; 285 271 } 286 272 287 273 288 274 #define EXPECT_SYSEQ(cond, expr, val) \ 289 - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_syseq(expr, llen, val); } while (0) 275 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_syseq(expr, llen, val); } while (0) 290 276 291 - static int expect_syseq(int expr, int llen, int val) 277 + static __attribute__((unused)) 278 + int expect_syseq(int expr, int llen, int val) 292 279 { 293 280 int ret = 0; 294 281 295 282 if (expr != val) { 296 283 ret = 1; 297 284 llen += printf(" = %d %s ", expr, errorname(errno)); 298 - llen += pad_spc(llen, 64, "[FAIL]\n"); 285 + result(llen, FAIL); 299 286 } else { 300 287 llen += printf(" = %d ", expr); 301 - llen += pad_spc(llen, 64, " [OK]\n"); 288 + result(llen, OK); 302 289 } 303 290 return ret; 304 291 } 305 292 306 293 307 294 #define EXPECT_SYSNE(cond, expr, val) \ 308 - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_sysne(expr, llen, val); } while (0) 295 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_sysne(expr, llen, val); } while (0) 309 296 310 - static int expect_sysne(int expr, int llen, int val) 297 + static __attribute__((unused)) 298 + int expect_sysne(int expr, int llen, int val) 311 299 { 312 300 int ret = 0; 313 301 314 302 if (expr == val) { 315 303 ret = 1; 316 304 llen += printf(" = %d %s ", expr, errorname(errno)); 317 - llen += pad_spc(llen, 64, "[FAIL]\n"); 305 + result(llen, FAIL); 318 306 } else { 319 307 llen += printf(" = %d ", expr); 320 - llen += pad_spc(llen, 64, " [OK]\n"); 308 + result(llen, OK); 321 309 } 322 310 return ret; 323 311 } 324 312 325 313 326 314 #define EXPECT_SYSER2(cond, expr, expret, experr1, experr2) \ 327 - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_syserr2(expr, expret, experr1, experr2, llen); } while (0) 315 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_syserr2(expr, expret, experr1, experr2, llen); } while (0) 328 316 329 317 #define EXPECT_SYSER(cond, expr, expret, experr) \ 330 318 EXPECT_SYSER2(cond, expr, expret, experr, 0) 331 319 332 - static int expect_syserr2(int expr, int expret, int experr1, int experr2, int llen) 320 + static __attribute__((unused)) 321 + int expect_syserr2(int expr, int expret, int experr1, int experr2, int llen) 333 322 { 334 323 int ret = 0; 335 324 int _errno = errno; ··· 353 318 llen += printf(" != (%d %s) ", expret, errorname(experr1)); 354 319 else 355 320 llen += printf(" != (%d %s %s) ", expret, errorname(experr1), errorname(experr2)); 356 - llen += pad_spc(llen, 64, "[FAIL]\n"); 321 + result(llen, FAIL); 357 322 } else { 358 - llen += pad_spc(llen, 64, " [OK]\n"); 323 + result(llen, OK); 359 324 } 360 325 return ret; 361 326 } 362 327 363 328 364 329 #define EXPECT_PTRZR(cond, expr) \ 365 - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_ptrzr(expr, llen); } while (0) 330 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ptrzr(expr, llen); } while (0) 366 331 367 - static int expect_ptrzr(const void *expr, int llen) 332 + static __attribute__((unused)) 333 + int expect_ptrzr(const void *expr, int llen) 368 334 { 369 335 int ret = 0; 370 336 371 337 llen += printf(" = <%p> ", expr); 372 338 if (expr) { 373 339 ret = 1; 374 - llen += pad_spc(llen, 64, "[FAIL]\n"); 340 + result(llen, FAIL); 375 341 } else { 376 - llen += pad_spc(llen, 64, " [OK]\n"); 342 + result(llen, OK); 377 343 } 378 344 return ret; 379 345 } 380 346 381 347 382 348 #define EXPECT_PTRNZ(cond, expr) \ 383 - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_ptrnz(expr, llen); } while (0) 349 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ptrnz(expr, llen); } while (0) 384 350 385 - static int expect_ptrnz(const void *expr, int llen) 351 + static __attribute__((unused)) 352 + int expect_ptrnz(const void *expr, int llen) 386 353 { 387 354 int ret = 0; 388 355 389 356 llen += printf(" = <%p> ", expr); 390 357 if (!expr) { 391 358 ret = 1; 392 - llen += pad_spc(llen, 64, "[FAIL]\n"); 359 + result(llen, FAIL); 393 360 } else { 394 - llen += pad_spc(llen, 64, " [OK]\n"); 361 + result(llen, OK); 395 362 } 396 363 return ret; 397 364 } 398 365 366 + #define EXPECT_PTREQ(cond, expr, cmp) \ 367 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ptreq(expr, llen, cmp); } while (0) 368 + 369 + static __attribute__((unused)) 370 + int expect_ptreq(const void *expr, int llen, const void *cmp) 371 + { 372 + int ret = 0; 373 + 374 + llen += printf(" = <%p> ", expr); 375 + if (expr != cmp) { 376 + ret = 1; 377 + result(llen, FAIL); 378 + } else { 379 + result(llen, OK); 380 + } 381 + return ret; 382 + } 383 + 384 + #define EXPECT_PTRNE(cond, expr, cmp) \ 385 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ptrne(expr, llen, cmp); } while (0) 386 + 387 + static __attribute__((unused)) 388 + int expect_ptrne(const void *expr, int llen, const void *cmp) 389 + { 390 + int ret = 0; 391 + 392 + llen += printf(" = <%p> ", expr); 393 + if (expr == cmp) { 394 + ret = 1; 395 + result(llen, FAIL); 396 + } else { 397 + result(llen, OK); 398 + } 399 + return ret; 400 + } 401 + 402 + #define EXPECT_PTRGE(cond, expr, cmp) \ 403 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ptrge(expr, llen, cmp); } while (0) 404 + 405 + static __attribute__((unused)) 406 + int expect_ptrge(const void *expr, int llen, const void *cmp) 407 + { 408 + int ret = !(expr >= cmp); 409 + 410 + llen += printf(" = <%p> ", expr); 411 + result(llen, ret ? FAIL : OK); 412 + return ret; 413 + } 414 + 415 + #define EXPECT_PTRGT(cond, expr, cmp) \ 416 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ptrgt(expr, llen, cmp); } while (0) 417 + 418 + static __attribute__((unused)) 419 + int expect_ptrgt(const void *expr, int llen, const void *cmp) 420 + { 421 + int ret = !(expr > cmp); 422 + 423 + llen += printf(" = <%p> ", expr); 424 + result(llen, ret ? FAIL : OK); 425 + return ret; 426 + } 427 + 428 + 429 + #define EXPECT_PTRLE(cond, expr, cmp) \ 430 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ptrle(expr, llen, cmp); } while (0) 431 + 432 + static __attribute__((unused)) 433 + int expect_ptrle(const void *expr, int llen, const void *cmp) 434 + { 435 + int ret = !(expr <= cmp); 436 + 437 + llen += printf(" = <%p> ", expr); 438 + result(llen, ret ? FAIL : OK); 439 + return ret; 440 + } 441 + 442 + 443 + #define EXPECT_PTRLT(cond, expr, cmp) \ 444 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ptrlt(expr, llen, cmp); } while (0) 445 + 446 + static __attribute__((unused)) 447 + int expect_ptrlt(const void *expr, int llen, const void *cmp) 448 + { 449 + int ret = !(expr < cmp); 450 + 451 + llen += printf(" = <%p> ", expr); 452 + result(llen, ret ? FAIL : OK); 453 + return ret; 454 + } 455 + 456 + #define EXPECT_PTRER2(cond, expr, expret, experr1, experr2) \ 457 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ptrerr2(expr, expret, experr1, experr2, llen); } while (0) 458 + 459 + #define EXPECT_PTRER(cond, expr, expret, experr) \ 460 + EXPECT_PTRER2(cond, expr, expret, experr, 0) 461 + 462 + static __attribute__((unused)) 463 + int expect_ptrerr2(const void *expr, const void *expret, int experr1, int experr2, int llen) 464 + { 465 + int ret = 0; 466 + int _errno = errno; 467 + 468 + llen += printf(" = <%p> %s ", expr, errorname(_errno)); 469 + if (expr != expret || (_errno != experr1 && _errno != experr2)) { 470 + ret = 1; 471 + if (experr2 == 0) 472 + llen += printf(" != (<%p> %s) ", expret, errorname(experr1)); 473 + else 474 + llen += printf(" != (<%p> %s %s) ", expret, errorname(experr1), errorname(experr2)); 475 + result(llen, FAIL); 476 + } else { 477 + result(llen, OK); 478 + } 479 + return ret; 480 + } 399 481 400 482 #define EXPECT_STRZR(cond, expr) \ 401 - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_strzr(expr, llen); } while (0) 483 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_strzr(expr, llen); } while (0) 402 484 403 - static int expect_strzr(const char *expr, int llen) 485 + static __attribute__((unused)) 486 + int expect_strzr(const char *expr, int llen) 404 487 { 405 488 int ret = 0; 406 489 407 490 llen += printf(" = <%s> ", expr); 408 491 if (expr) { 409 492 ret = 1; 410 - llen += pad_spc(llen, 64, "[FAIL]\n"); 493 + result(llen, FAIL); 411 494 } else { 412 - llen += pad_spc(llen, 64, " [OK]\n"); 495 + result(llen, OK); 413 496 } 414 497 return ret; 415 498 } 416 499 417 500 418 501 #define EXPECT_STRNZ(cond, expr) \ 419 - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_strnz(expr, llen); } while (0) 502 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_strnz(expr, llen); } while (0) 420 503 421 - static int expect_strnz(const char *expr, int llen) 504 + static __attribute__((unused)) 505 + int expect_strnz(const char *expr, int llen) 422 506 { 423 507 int ret = 0; 424 508 425 509 llen += printf(" = <%s> ", expr); 426 510 if (!expr) { 427 511 ret = 1; 428 - llen += pad_spc(llen, 64, "[FAIL]\n"); 512 + result(llen, FAIL); 429 513 } else { 430 - llen += pad_spc(llen, 64, " [OK]\n"); 514 + result(llen, OK); 431 515 } 432 516 return ret; 433 517 } 434 518 435 519 436 520 #define EXPECT_STREQ(cond, expr, cmp) \ 437 - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_streq(expr, llen, cmp); } while (0) 521 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_streq(expr, llen, cmp); } while (0) 438 522 439 - static int expect_streq(const char *expr, int llen, const char *cmp) 523 + static __attribute__((unused)) 524 + int expect_streq(const char *expr, int llen, const char *cmp) 440 525 { 441 526 int ret = 0; 442 527 443 528 llen += printf(" = <%s> ", expr); 444 529 if (strcmp(expr, cmp) != 0) { 445 530 ret = 1; 446 - llen += pad_spc(llen, 64, "[FAIL]\n"); 531 + result(llen, FAIL); 447 532 } else { 448 - llen += pad_spc(llen, 64, " [OK]\n"); 533 + result(llen, OK); 449 534 } 450 535 return ret; 451 536 } 452 537 453 538 454 539 #define EXPECT_STRNE(cond, expr, cmp) \ 455 - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_strne(expr, llen, cmp); } while (0) 540 + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_strne(expr, llen, cmp); } while (0) 456 541 457 - static int expect_strne(const char *expr, int llen, const char *cmp) 542 + static __attribute__((unused)) 543 + int expect_strne(const char *expr, int llen, const char *cmp) 458 544 { 459 545 int ret = 0; 460 546 461 547 llen += printf(" = <%s> ", expr); 462 548 if (strcmp(expr, cmp) == 0) { 463 549 ret = 1; 464 - llen += pad_spc(llen, 64, "[FAIL]\n"); 550 + result(llen, FAIL); 465 551 } else { 466 - llen += pad_spc(llen, 64, " [OK]\n"); 552 + result(llen, OK); 467 553 } 468 554 return ret; 469 555 } ··· 593 437 /* declare tests based on line numbers. There must be exactly one test per line. */ 594 438 #define CASE_TEST(name) \ 595 439 case __LINE__: llen += printf("%d %s", test, #name); 440 + 441 + int run_startup(int min, int max) 442 + { 443 + int test; 444 + int ret = 0; 445 + /* kernel at least passes HOME and TERM, shell passes more */ 446 + int env_total = 2; 447 + /* checking NULL for argv/argv0, environ and _auxv is not enough, let's compare with sbrk(0) or &end */ 448 + extern char end; 449 + char *brk = sbrk(0) != (void *)-1 ? sbrk(0) : &end; 450 + /* differ from nolibc, both glibc and musl have no global _auxv */ 451 + const unsigned long *test_auxv = (void *)-1; 452 + #ifdef NOLIBC 453 + test_auxv = _auxv; 454 + #endif 455 + 456 + for (test = min; test >= 0 && test <= max; test++) { 457 + int llen = 0; /* line length */ 458 + 459 + /* avoid leaving empty lines below, this will insert holes into 460 + * test numbers. 461 + */ 462 + switch (test + __LINE__ + 1) { 463 + CASE_TEST(argc); EXPECT_GE(1, test_argc, 1); break; 464 + CASE_TEST(argv_addr); EXPECT_PTRGT(1, test_argv, brk); break; 465 + CASE_TEST(argv_environ); EXPECT_PTRLT(1, test_argv, environ); break; 466 + CASE_TEST(argv_total); EXPECT_EQ(1, environ - test_argv - 1, test_argc ?: 1); break; 467 + CASE_TEST(argv0_addr); EXPECT_PTRGT(1, argv0, brk); break; 468 + CASE_TEST(argv0_str); EXPECT_STRNZ(1, argv0 > brk ? argv0 : NULL); break; 469 + CASE_TEST(argv0_len); EXPECT_GE(1, argv0 > brk ? strlen(argv0) : 0, 1); break; 470 + CASE_TEST(environ_addr); EXPECT_PTRGT(1, environ, brk); break; 471 + CASE_TEST(environ_envp); EXPECT_PTREQ(1, environ, test_envp); break; 472 + CASE_TEST(environ_auxv); EXPECT_PTRLT(test_auxv != (void *)-1, environ, test_auxv); break; 473 + CASE_TEST(environ_total); EXPECT_GE(test_auxv != (void *)-1, (void *)test_auxv - (void *)environ - 1, env_total); break; 474 + CASE_TEST(environ_HOME); EXPECT_PTRNZ(1, getenv("HOME")); break; 475 + CASE_TEST(auxv_addr); EXPECT_PTRGT(test_auxv != (void *)-1, test_auxv, brk); break; 476 + CASE_TEST(auxv_AT_UID); EXPECT_EQ(1, getauxval(AT_UID), getuid()); break; 477 + CASE_TEST(auxv_AT_PAGESZ); EXPECT_GE(1, getauxval(AT_PAGESZ), 4096); break; 478 + case __LINE__: 479 + return ret; /* must be last */ 480 + /* note: do not set any defaults so as to permit holes above */ 481 + } 482 + } 483 + return ret; 484 + } 596 485 597 486 598 487 /* used by some syscall tests below */ ··· 659 458 return ret; 660 459 } 661 460 662 - static int test_getpagesize(void) 461 + int test_getpagesize(void) 663 462 { 664 - long x = getpagesize(); 463 + int x = getpagesize(); 665 464 int c; 666 465 667 466 if (x < 0) ··· 688 487 return !c; 689 488 } 690 489 691 - static int test_fork(void) 490 + int test_fork(void) 692 491 { 693 492 int status; 694 493 pid_t pid; ··· 713 512 } 714 513 } 715 514 716 - static int test_stat_timestamps(void) 515 + int test_stat_timestamps(void) 717 516 { 718 517 struct stat st; 719 518 720 519 if (sizeof(st.st_atim.tv_sec) != sizeof(st.st_atime)) 721 520 return 1; 722 521 723 - if (stat("/proc/self/", &st)) 522 + if (stat("/proc/self/", &st) && stat(argv0, &st) && stat("/", &st)) 724 523 return 1; 725 524 726 525 if (st.st_atim.tv_sec != st.st_atime || st.st_atim.tv_nsec > 1000000000) ··· 734 533 735 534 return 0; 736 535 } 536 + 537 + int test_mmap_munmap(void) 538 + { 539 + int ret, fd, i, page_size; 540 + void *mem; 541 + size_t file_size, length; 542 + off_t offset, pa_offset; 543 + struct stat stat_buf; 544 + const char * const files[] = { 545 + "/dev/zero", 546 + "/proc/1/exe", "/proc/self/exe", 547 + argv0, 548 + NULL 549 + }; 550 + 551 + page_size = getpagesize(); 552 + if (page_size < 0) 553 + return 1; 554 + 555 + /* find a right file to mmap, existed and accessible */ 556 + for (i = 0; files[i] != NULL; i++) { 557 + ret = fd = open(files[i], O_RDONLY); 558 + if (ret == -1) 559 + continue; 560 + else 561 + break; 562 + } 563 + if (ret == -1) 564 + return 1; 565 + 566 + ret = stat(files[i], &stat_buf); 567 + if (ret == -1) 568 + goto end; 569 + 570 + /* file size of the special /dev/zero is 0, let's assign one manually */ 571 + if (i == 0) 572 + file_size = 3*page_size; 573 + else 574 + file_size = stat_buf.st_size; 575 + 576 + offset = file_size - 1; 577 + if (offset < 0) 578 + offset = 0; 579 + length = file_size - offset; 580 + pa_offset = offset & ~(page_size - 1); 581 + 582 + mem = mmap(NULL, length + offset - pa_offset, PROT_READ, MAP_SHARED, fd, pa_offset); 583 + if (mem == MAP_FAILED) { 584 + ret = 1; 585 + goto end; 586 + } 587 + 588 + ret = munmap(mem, length + offset - pa_offset); 589 + 590 + end: 591 + close(fd); 592 + return !!ret; 593 + } 594 + 595 + int test_pipe(void) 596 + { 597 + const char *const msg = "hello, nolibc"; 598 + int pipefd[2]; 599 + char buf[32]; 600 + size_t len; 601 + 602 + if (pipe(pipefd) == -1) 603 + return 1; 604 + 605 + write(pipefd[1], msg, strlen(msg)); 606 + close(pipefd[1]); 607 + len = read(pipefd[0], buf, sizeof(buf)); 608 + close(pipefd[0]); 609 + 610 + if (len != strlen(msg)) 611 + return 1; 612 + 613 + return !!memcmp(buf, msg, len); 614 + } 615 + 737 616 738 617 /* Run syscall tests between IDs <min> and <max>. 739 618 * Return 0 on success, non-zero on failure. ··· 829 548 int tmp; 830 549 int ret = 0; 831 550 void *p1, *p2; 551 + int has_gettid = 1; 832 552 833 553 /* <proc> indicates whether or not /proc is mounted */ 834 554 proc = stat("/proc", &stat_buf) == 0; 835 555 836 556 /* this will be used to skip certain tests that can't be run unprivileged */ 837 557 euid0 = geteuid() == 0; 558 + 559 + /* from 2.30, glibc provides gettid() */ 560 + #if defined(__GLIBC_MINOR__) && defined(__GLIBC__) 561 + has_gettid = __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 30); 562 + #endif 838 563 839 564 for (test = min; test >= 0 && test <= max; test++) { 840 565 int llen = 0; /* line length */ ··· 851 564 switch (test + __LINE__ + 1) { 852 565 CASE_TEST(getpid); EXPECT_SYSNE(1, getpid(), -1); break; 853 566 CASE_TEST(getppid); EXPECT_SYSNE(1, getppid(), -1); break; 854 - #ifdef NOLIBC 855 - CASE_TEST(gettid); EXPECT_SYSNE(1, gettid(), -1); break; 856 - #endif 567 + CASE_TEST(gettid); EXPECT_SYSNE(has_gettid, gettid(), -1); break; 857 568 CASE_TEST(getpgid_self); EXPECT_SYSNE(1, getpgid(0), -1); break; 858 569 CASE_TEST(getpgid_bad); EXPECT_SYSER(1, getpgid(-1), -1, ESRCH); break; 859 570 CASE_TEST(kill_0); EXPECT_SYSZR(1, kill(getpid(), 0)); break; 860 571 CASE_TEST(kill_CONT); EXPECT_SYSZR(1, kill(getpid(), 0)); break; 861 572 CASE_TEST(kill_BADPID); EXPECT_SYSER(1, kill(INT_MAX, 0), -1, ESRCH); break; 573 + CASE_TEST(sbrk_0); EXPECT_PTRNE(1, sbrk(0), (void *)-1); break; 862 574 CASE_TEST(sbrk); if ((p1 = p2 = sbrk(4096)) != (void *)-1) p2 = sbrk(-4096); EXPECT_SYSZR(1, (p2 == (void *)-1) || p2 == p1); break; 863 575 CASE_TEST(brk); EXPECT_SYSZR(1, brk(sbrk(0))); break; 864 - CASE_TEST(chdir_root); EXPECT_SYSZR(1, chdir("/")); break; 576 + CASE_TEST(chdir_root); EXPECT_SYSZR(1, chdir("/")); chdir(getenv("PWD")); break; 865 577 CASE_TEST(chdir_dot); EXPECT_SYSZR(1, chdir(".")); break; 866 578 CASE_TEST(chdir_blah); EXPECT_SYSER(1, chdir("/blah"), -1, ENOENT); break; 579 + CASE_TEST(chmod_argv0); EXPECT_SYSZR(1, chmod(argv0, 0555)); break; 867 580 CASE_TEST(chmod_self); EXPECT_SYSER(proc, chmod("/proc/self", 0555), -1, EPERM); break; 868 581 CASE_TEST(chown_self); EXPECT_SYSER(proc, chown("/proc/self", 0, 0), -1, EPERM); break; 869 582 CASE_TEST(chroot_root); EXPECT_SYSZR(euid0, chroot("/")); break; 870 583 CASE_TEST(chroot_blah); EXPECT_SYSER(1, chroot("/proc/self/blah"), -1, ENOENT); break; 871 - CASE_TEST(chroot_exe); EXPECT_SYSER(proc, chroot("/proc/self/exe"), -1, ENOTDIR); break; 584 + CASE_TEST(chroot_exe); EXPECT_SYSER(1, chroot(argv0), -1, ENOTDIR); break; 872 585 CASE_TEST(close_m1); EXPECT_SYSER(1, close(-1), -1, EBADF); break; 873 586 CASE_TEST(close_dup); EXPECT_SYSZR(1, close(dup(0))); break; 874 587 CASE_TEST(dup_0); tmp = dup(0); EXPECT_SYSNE(1, tmp, -1); close(tmp); break; ··· 889 602 CASE_TEST(link_root1); EXPECT_SYSER(1, link("/", "/"), -1, EEXIST); break; 890 603 CASE_TEST(link_blah); EXPECT_SYSER(1, link("/proc/self/blah", "/blah"), -1, ENOENT); break; 891 604 CASE_TEST(link_dir); EXPECT_SYSER(euid0, link("/", "/blah"), -1, EPERM); break; 892 - CASE_TEST(link_cross); EXPECT_SYSER(proc, link("/proc/self/net", "/blah"), -1, EXDEV); break; 605 + CASE_TEST(link_cross); EXPECT_SYSER(proc, link("/proc/self/cmdline", "/blah"), -1, EXDEV); break; 893 606 CASE_TEST(lseek_m1); EXPECT_SYSER(1, lseek(-1, 0, SEEK_SET), -1, EBADF); break; 894 607 CASE_TEST(lseek_0); EXPECT_SYSER(1, lseek(0, 0, SEEK_SET), -1, ESPIPE); break; 895 608 CASE_TEST(mkdir_root); EXPECT_SYSER(1, mkdir("/", 0755), -1, EEXIST); break; 609 + CASE_TEST(mmap_bad); EXPECT_PTRER(1, mmap(NULL, 0, PROT_READ, MAP_PRIVATE, 0, 0), MAP_FAILED, EINVAL); break; 610 + CASE_TEST(munmap_bad); EXPECT_SYSER(1, munmap((void *)1, 0), -1, EINVAL); break; 611 + CASE_TEST(mmap_munmap_good); EXPECT_SYSZR(1, test_mmap_munmap()); break; 896 612 CASE_TEST(open_tty); EXPECT_SYSNE(1, tmp = open("/dev/null", 0), -1); if (tmp != -1) close(tmp); break; 897 613 CASE_TEST(open_blah); EXPECT_SYSER(1, tmp = open("/proc/self/blah", 0), -1, ENOENT); if (tmp != -1) close(tmp); break; 614 + CASE_TEST(pipe); EXPECT_SYSZR(1, test_pipe()); break; 898 615 CASE_TEST(poll_null); EXPECT_SYSZR(1, poll(NULL, 0, 0)); break; 899 616 CASE_TEST(poll_stdout); EXPECT_SYSNE(1, ({ struct pollfd fds = { 1, POLLOUT, 0}; poll(&fds, 1, 0); }), -1); break; 900 617 CASE_TEST(poll_fault); EXPECT_SYSER(1, poll((void *)1, 1, 0), -1, EFAULT); break; 901 618 CASE_TEST(prctl); EXPECT_SYSER(1, prctl(PR_SET_NAME, (unsigned long)NULL, 0, 0, 0), -1, EFAULT); break; 902 619 CASE_TEST(read_badf); EXPECT_SYSER(1, read(-1, &tmp, 1), -1, EBADF); break; 620 + CASE_TEST(rmdir_blah); EXPECT_SYSER(1, rmdir("/blah"), -1, ENOENT); break; 903 621 CASE_TEST(sched_yield); EXPECT_SYSZR(1, sched_yield()); break; 904 622 CASE_TEST(select_null); EXPECT_SYSZR(1, ({ struct timeval tv = { 0 }; select(0, NULL, NULL, NULL, &tv); })); break; 905 623 CASE_TEST(select_stdout); EXPECT_SYSNE(1, ({ fd_set fds; FD_ZERO(&fds); FD_SET(1, &fds); select(2, NULL, &fds, NULL, NULL); }), -1); break; 906 624 CASE_TEST(select_fault); EXPECT_SYSER(1, select(1, (void *)1, NULL, NULL, 0), -1, EFAULT); break; 907 625 CASE_TEST(stat_blah); EXPECT_SYSER(1, stat("/proc/self/blah", &stat_buf), -1, ENOENT); break; 908 - CASE_TEST(stat_fault); EXPECT_SYSER(1, stat(NULL, &stat_buf), -1, EFAULT); break; 626 + CASE_TEST(stat_fault); EXPECT_SYSER(1, stat((void *)1, &stat_buf), -1, EFAULT); break; 909 627 CASE_TEST(stat_timestamps); EXPECT_SYSZR(1, test_stat_timestamps()); break; 910 628 CASE_TEST(symlink_root); EXPECT_SYSER(1, symlink("/", "/"), -1, EEXIST); break; 911 629 CASE_TEST(unlink_root); EXPECT_SYSER(1, unlink("/"), -1, EISDIR); break; ··· 933 641 int run_stdlib(int min, int max) 934 642 { 935 643 int test; 936 - int tmp; 937 644 int ret = 0; 938 - void *p1, *p2; 939 645 940 646 for (test = min; test >= 0 && test <= max; test++) { 941 647 int llen = 0; /* line length */ ··· 988 698 CASE_TEST(limit_int_fast8_max); EXPECT_EQ(1, INT_FAST8_MAX, (int_fast8_t) 0x7f); break; 989 699 CASE_TEST(limit_int_fast8_min); EXPECT_EQ(1, INT_FAST8_MIN, (int_fast8_t) 0x80); break; 990 700 CASE_TEST(limit_uint_fast8_max); EXPECT_EQ(1, UINT_FAST8_MAX, (uint_fast8_t) 0xff); break; 991 - CASE_TEST(limit_int_fast16_min); EXPECT_EQ(1, INT_FAST16_MIN, (int_fast16_t) INTPTR_MIN); break; 992 - CASE_TEST(limit_int_fast16_max); EXPECT_EQ(1, INT_FAST16_MAX, (int_fast16_t) INTPTR_MAX); break; 701 + CASE_TEST(limit_int_fast16_min); EXPECT_EQ(1, INT_FAST16_MIN, (int_fast16_t) SINT_MIN_OF_TYPE(int_fast16_t)); break; 702 + CASE_TEST(limit_int_fast16_max); EXPECT_EQ(1, INT_FAST16_MAX, (int_fast16_t) SINT_MAX_OF_TYPE(int_fast16_t)); break; 993 703 CASE_TEST(limit_uint_fast16_max); EXPECT_EQ(1, UINT_FAST16_MAX, (uint_fast16_t) UINTPTR_MAX); break; 994 - CASE_TEST(limit_int_fast32_min); EXPECT_EQ(1, INT_FAST32_MIN, (int_fast32_t) INTPTR_MIN); break; 995 - CASE_TEST(limit_int_fast32_max); EXPECT_EQ(1, INT_FAST32_MAX, (int_fast32_t) INTPTR_MAX); break; 704 + CASE_TEST(limit_int_fast32_min); EXPECT_EQ(1, INT_FAST32_MIN, (int_fast32_t) SINT_MIN_OF_TYPE(int_fast32_t)); break; 705 + CASE_TEST(limit_int_fast32_max); EXPECT_EQ(1, INT_FAST32_MAX, (int_fast32_t) SINT_MAX_OF_TYPE(int_fast32_t)); break; 996 706 CASE_TEST(limit_uint_fast32_max); EXPECT_EQ(1, UINT_FAST32_MAX, (uint_fast32_t) UINTPTR_MAX); break; 997 707 CASE_TEST(limit_int_fast64_min); EXPECT_EQ(1, INT_FAST64_MIN, (int_fast64_t) INT64_MIN); break; 998 708 CASE_TEST(limit_int_fast64_max); EXPECT_EQ(1, INT_FAST64_MAX, (int_fast64_t) INT64_MAX); break; 999 709 CASE_TEST(limit_uint_fast64_max); EXPECT_EQ(1, UINT_FAST64_MAX, (uint_fast64_t) UINT64_MAX); break; 1000 - #if __SIZEOF_LONG__ == 8 1001 - CASE_TEST(limit_intptr_min); EXPECT_EQ(1, INTPTR_MIN, (intptr_t) 0x8000000000000000LL); break; 1002 - CASE_TEST(limit_intptr_max); EXPECT_EQ(1, INTPTR_MAX, (intptr_t) 0x7fffffffffffffffLL); break; 1003 - CASE_TEST(limit_uintptr_max); EXPECT_EQ(1, UINTPTR_MAX, (uintptr_t) 0xffffffffffffffffULL); break; 1004 - CASE_TEST(limit_ptrdiff_min); EXPECT_EQ(1, PTRDIFF_MIN, (ptrdiff_t) 0x8000000000000000LL); break; 1005 - CASE_TEST(limit_ptrdiff_max); EXPECT_EQ(1, PTRDIFF_MAX, (ptrdiff_t) 0x7fffffffffffffffLL); break; 1006 - CASE_TEST(limit_size_max); EXPECT_EQ(1, SIZE_MAX, (size_t) 0xffffffffffffffffULL); break; 1007 - #elif __SIZEOF_LONG__ == 4 1008 - CASE_TEST(limit_intptr_min); EXPECT_EQ(1, INTPTR_MIN, (intptr_t) 0x80000000); break; 1009 - CASE_TEST(limit_intptr_max); EXPECT_EQ(1, INTPTR_MAX, (intptr_t) 0x7fffffff); break; 1010 - CASE_TEST(limit_uintptr_max); EXPECT_EQ(1, UINTPTR_MAX, (uintptr_t) 0xffffffffU); break; 1011 - CASE_TEST(limit_ptrdiff_min); EXPECT_EQ(1, PTRDIFF_MIN, (ptrdiff_t) 0x80000000); break; 1012 - CASE_TEST(limit_ptrdiff_max); EXPECT_EQ(1, PTRDIFF_MAX, (ptrdiff_t) 0x7fffffff); break; 1013 - CASE_TEST(limit_size_max); EXPECT_EQ(1, SIZE_MAX, (size_t) 0xffffffffU); break; 1014 - #else 1015 - # warning "__SIZEOF_LONG__ is undefined" 1016 - #endif /* __SIZEOF_LONG__ */ 710 + CASE_TEST(sizeof_long_sane); EXPECT_EQ(1, sizeof(long) == 8 || sizeof(long) == 4, 1); break; 711 + CASE_TEST(limit_intptr_min); EXPECT_EQ(1, INTPTR_MIN, sizeof(long) == 8 ? (intptr_t) 0x8000000000000000LL : (intptr_t) 0x80000000); break; 712 + CASE_TEST(limit_intptr_max); EXPECT_EQ(1, INTPTR_MAX, sizeof(long) == 8 ? (intptr_t) 0x7fffffffffffffffLL : (intptr_t) 0x7fffffff); break; 713 + CASE_TEST(limit_uintptr_max); EXPECT_EQ(1, UINTPTR_MAX, sizeof(long) == 8 ? (uintptr_t) 0xffffffffffffffffULL : (uintptr_t) 0xffffffffU); break; 714 + CASE_TEST(limit_ptrdiff_min); EXPECT_EQ(1, PTRDIFF_MIN, sizeof(long) == 8 ? (ptrdiff_t) 0x8000000000000000LL : (ptrdiff_t) 0x80000000); break; 715 + CASE_TEST(limit_ptrdiff_max); EXPECT_EQ(1, PTRDIFF_MAX, sizeof(long) == 8 ? (ptrdiff_t) 0x7fffffffffffffffLL : (ptrdiff_t) 0x7fffffff); break; 716 + CASE_TEST(limit_size_max); EXPECT_EQ(1, SIZE_MAX, sizeof(long) == 8 ? (size_t) 0xffffffffffffffffULL : (size_t) 0xffffffffU); break; 717 + 1017 718 case __LINE__: 1018 719 return ret; /* must be last */ 1019 720 /* note: do not set any defaults so as to permit holes above */ ··· 1016 735 #define EXPECT_VFPRINTF(c, expected, fmt, ...) \ 1017 736 ret += expect_vfprintf(llen, c, expected, fmt, ##__VA_ARGS__) 1018 737 1019 - static int expect_vfprintf(int llen, size_t c, const char *expected, const char *fmt, ...) 738 + static int expect_vfprintf(int llen, int c, const char *expected, const char *fmt, ...) 1020 739 { 1021 - int ret, fd, w, r; 740 + int ret, fd; 741 + ssize_t w, r; 1022 742 char buf[100]; 1023 743 FILE *memfile; 1024 744 va_list args; 1025 745 1026 - fd = memfd_create("vfprintf", 0); 746 + fd = open("/tmp", O_TMPFILE | O_EXCL | O_RDWR, 0600); 1027 747 if (fd == -1) { 1028 - pad_spc(llen, 64, "[FAIL]\n"); 1029 - return 1; 748 + result(llen, SKIPPED); 749 + return 0; 1030 750 } 1031 751 1032 752 memfile = fdopen(fd, "w+"); 1033 753 if (!memfile) { 1034 - pad_spc(llen, 64, "[FAIL]\n"); 754 + result(llen, FAIL); 1035 755 return 1; 1036 756 } 1037 757 ··· 1041 759 va_end(args); 1042 760 1043 761 if (w != c) { 1044 - llen += printf(" written(%d) != %d", w, (int) c); 1045 - pad_spc(llen, 64, "[FAIL]\n"); 762 + llen += printf(" written(%d) != %d", (int)w, c); 763 + result(llen, FAIL); 1046 764 return 1; 1047 765 } 1048 766 ··· 1050 768 lseek(fd, 0, SEEK_SET); 1051 769 1052 770 r = read(fd, buf, sizeof(buf) - 1); 1053 - buf[r] = '\0'; 1054 771 1055 772 fclose(memfile); 1056 773 1057 774 if (r != w) { 1058 - llen += printf(" written(%d) != read(%d)", w, r); 1059 - pad_spc(llen, 64, "[FAIL]\n"); 775 + llen += printf(" written(%d) != read(%d)", (int)w, (int)r); 776 + result(llen, FAIL); 1060 777 return 1; 1061 778 } 1062 779 780 + buf[r] = '\0'; 1063 781 llen += printf(" \"%s\" = \"%s\"", expected, buf); 1064 782 ret = strncmp(expected, buf, c); 1065 783 1066 - pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n"); 784 + result(llen, ret ? FAIL : OK); 1067 785 return ret; 1068 786 } 1069 787 1070 788 static int run_vfprintf(int min, int max) 1071 789 { 1072 790 int test; 1073 - int tmp; 1074 791 int ret = 0; 1075 - void *p1, *p2; 1076 792 1077 793 for (test = min; test >= 0 && test <= max; test++) { 1078 794 int llen = 0; /* line length */ ··· 1108 828 return 1; 1109 829 } 1110 830 1111 - static int run_protection(int min, int max) 831 + static int run_protection(int min __attribute__((unused)), 832 + int max __attribute__((unused))) 1112 833 { 1113 834 pid_t pid; 1114 835 int llen = 0, status; ··· 1118 837 1119 838 #if !defined(_NOLIBC_STACKPROTECTOR) 1120 839 llen += printf("not supported"); 1121 - pad_spc(llen, 64, "[SKIPPED]\n"); 840 + result(llen, SKIPPED); 1122 841 return 0; 1123 842 #endif 1124 843 1125 844 #if defined(_NOLIBC_STACKPROTECTOR) 1126 845 if (!__stack_chk_guard) { 1127 846 llen += printf("__stack_chk_guard not initialized"); 1128 - pad_spc(llen, 64, "[FAIL]\n"); 847 + result(llen, FAIL); 1129 848 return 1; 1130 849 } 1131 850 #endif ··· 1136 855 switch (pid) { 1137 856 case -1: 1138 857 llen += printf("fork()"); 1139 - pad_spc(llen, 64, "[FAIL]\n"); 858 + result(llen, FAIL); 1140 859 return 1; 1141 860 1142 861 case 0: ··· 1152 871 1153 872 if (pid == -1 || !WIFSIGNALED(status) || WTERMSIG(status) != SIGABRT) { 1154 873 llen += printf("waitpid()"); 1155 - pad_spc(llen, 64, "[FAIL]\n"); 874 + result(llen, FAIL); 1156 875 return 1; 1157 876 } 1158 - pad_spc(llen, 64, " [OK]\n"); 877 + result(llen, OK); 1159 878 return 0; 1160 879 } 1161 880 } ··· 1171 890 */ 1172 891 if (stat("/dev/.", &stat_buf) == 0 || mkdir("/dev", 0755) == 0) { 1173 892 if (stat("/dev/console", &stat_buf) != 0 || 1174 - stat("/dev/null", &stat_buf) != 0) { 893 + stat("/dev/null", &stat_buf) != 0 || 894 + stat("/dev/zero", &stat_buf) != 0) { 1175 895 /* try devtmpfs first, otherwise fall back to manual creation */ 1176 896 if (mount("/dev", "/dev", "devtmpfs", 0, 0) != 0) { 1177 897 mknod("/dev/console", 0600 | S_IFCHR, makedev(5, 1)); 1178 898 mknod("/dev/null", 0666 | S_IFCHR, makedev(1, 3)); 899 + mknod("/dev/zero", 0666 | S_IFCHR, makedev(1, 5)); 1179 900 } 1180 901 } 1181 902 } ··· 1204 921 1205 922 /* try to mount /proc if not mounted. Silently fail otherwise */ 1206 923 if (stat("/proc/.", &stat_buf) == 0 || mkdir("/proc", 0755) == 0) { 1207 - if (stat("/proc/self", &stat_buf) != 0) 1208 - mount("/proc", "/proc", "proc", 0, 0); 924 + if (stat("/proc/self", &stat_buf) != 0) { 925 + /* If not mountable, remove /proc completely to avoid misuse */ 926 + if (mount("none", "/proc", "proc", 0, 0) != 0) 927 + rmdir("/proc"); 928 + } 1209 929 } 930 + 931 + /* some tests rely on a writable /tmp */ 932 + mkdir("/tmp", 0755); 1210 933 1211 934 return 0; 1212 935 } ··· 1220 931 /* This is the definition of known test names, with their functions */ 1221 932 static const struct test test_names[] = { 1222 933 /* add new tests here */ 934 + { .name = "startup", .func = run_startup }, 1223 935 { .name = "syscall", .func = run_syscall }, 1224 936 { .name = "stdlib", .func = run_stdlib }, 1225 937 { .name = "vfprintf", .func = run_vfprintf }, 1226 938 { .name = "protection", .func = run_protection }, 1227 939 { 0 } 1228 940 }; 941 + 942 + static int is_setting_valid(char *test) 943 + { 944 + int idx, len, test_len, valid = 0; 945 + char delimiter; 946 + 947 + if (!test) 948 + return valid; 949 + 950 + test_len = strlen(test); 951 + 952 + for (idx = 0; test_names[idx].name; idx++) { 953 + len = strlen(test_names[idx].name); 954 + if (test_len < len) 955 + continue; 956 + 957 + if (strncmp(test, test_names[idx].name, len) != 0) 958 + continue; 959 + 960 + delimiter = test[len]; 961 + if (delimiter != ':' && delimiter != ',' && delimiter != '\0') 962 + continue; 963 + 964 + valid = 1; 965 + break; 966 + } 967 + 968 + return valid; 969 + } 1229 970 1230 971 int main(int argc, char **argv, char **envp) 1231 972 { ··· 1266 947 int idx; 1267 948 char *test; 1268 949 1269 - environ = envp; 950 + argv0 = argv[0]; 951 + test_argc = argc; 952 + test_argv = argv; 953 + test_envp = envp; 1270 954 1271 955 /* when called as init, it's possible that no console was opened, for 1272 956 * example if no /dev file system was provided. We'll check that fd#1 ··· 1285 963 * syscall:5-15[:.*],stdlib:8-10 1286 964 */ 1287 965 test = argv[1]; 1288 - if (!test) 966 + if (!is_setting_valid(test)) 1289 967 test = getenv("NOLIBC_TEST"); 1290 968 1291 - if (test) { 969 + if (is_setting_valid(test)) { 1292 970 char *comma, *colon, *dash, *value; 1293 971 1294 972 do { ··· 1366 1044 */ 1367 1045 printf("Leaving init with final status: %d\n", !!ret); 1368 1046 if (ret == 0) 1369 - reboot(LINUX_REBOOT_CMD_POWER_OFF); 1047 + reboot(RB_POWER_OFF); 1370 1048 #if defined(__x86_64__) 1371 1049 /* QEMU started with "-device isa-debug-exit -no-reboot" will 1372 1050 * exit with status code 2N+1 when N is written to 0x501. We 1373 1051 * hard-code the syscall here as it's arch-dependent. 1374 1052 */ 1375 - #if defined(_NOLIBC_SYS_H) 1376 - else if (my_syscall3(__NR_ioperm, 0x501, 1, 1) == 0) 1377 - #else 1378 - else if (ioperm(0x501, 1, 1) == 0) 1379 - #endif 1053 + else if (syscall(__NR_ioperm, 0x501, 1, 1) == 0) 1380 1054 __asm__ volatile ("outb %%al, %%dx" :: "d"(0x501), "a"(0)); 1381 1055 /* if it does nothing, fall back to the regular panic */ 1382 1056 #endif