Hi, Willy
Here is the v6 of the __sysret series [1], applies your suggestions. additionally, the sbrk() also uses the __sysret helper.
These patches are tested (together with the coming v4 selftests/nolibc patches) for all of the supported architectures:
arch/board | result ------------|------------ arm/vexpress-a9 | 142 test(s) passed, 1 skipped, 0 failed. arm/virt | 142 test(s) passed, 1 skipped, 0 failed. aarch64/virt | 142 test(s) passed, 1 skipped, 0 failed. ppc/g3beige | not supported ppc/ppce500 | not supported i386/pc | 142 test(s) passed, 1 skipped, 0 failed. x86_64/pc | 142 test(s) passed, 1 skipped, 0 failed. mipsel/malta | 142 test(s) passed, 1 skipped, 0 failed. loongarch64/virt | 142 test(s) passed, 1 skipped, 0 failed. riscv64/virt | 142 test(s) passed, 1 skipped, 0 failed. riscv32/virt | 0 test(s) passed, 0 skipped, 0 failed. s390x/s390-ccw-virtio | 142 test(s) passed, 1 skipped, 0 failed.
Changes from v5 --> v6:
* tools/nolibc: arch-*.h: fix up code indent errors toolc/nolibc: arch-*.h: clean up whitespaces after __asm__
Fix up the code indent errors and whitespaces between __asm__ and volatile.
The post-whitespaces are reserved as before.
* tools/nolibc: arch-loongarch.h: shrink with _NOLIBC_SYSCALL_CLOBBERLIST tools/nolibc: arch-mips.h: shrink with _NOLIBC_SYSCALL_CLOBBERLIST
Add _NOLIBC_ prefix for SYSCALL_CLOBBERLIST.
* tools/nolibc: add missing my_syscall6() for mips
Use post-whitespaces instead of post-tab.
The above 4 patches are preparation for this one.
* tools/nolibc: __sysret: support syscalls who return a pointer
Add comments about the new errno range [-MAX_ERRNOR, -1], add ref to the musl and glibc.
* tools/nolibc: clean up mmap() routine
Comment the MAP_FAILED return info.
* tools/nolibc: clean up sbrk() routine
New patch, applies __sysret() helper too and also fixes up an error reported by scripts/checkpatch.pl.
* selftests/nolibc: export argv0 for some tests selftests/nolibc: prepare: create /dev/zero
Prepare /dev/zero and argv0 for mmap test cases.
* selftests/nolibc: add EXPECT_PTREQ, EXPECT_PTRNE and EXPECT_PTRER selftests/nolibc: add sbrk_0 to test current brk getting
No change.
* selftests/nolibc: add mmap_bad test case selftests/nolibc: add munmap_bad test case selftests/nolibc: add mmap_munmap_good test case
Split the first two out to standalone patches.
Add /dev/zero and argv0 to the file list and assigns a file_size manually for /dev/zero.
Best regards, Zhangjin --- [1]: https://lore.kernel.org/lkml/cover.1687957589.git.falcon@tinylab.org/
Zhangjin Wu (15): tools/nolibc: arch-*.h: fix up code indent errors toolc/nolibc: arch-*.h: clean up whitespaces after __asm__ tools/nolibc: arch-loongarch.h: shrink with _NOLIBC_SYSCALL_CLOBBERLIST tools/nolibc: arch-mips.h: shrink with _NOLIBC_SYSCALL_CLOBBERLIST tools/nolibc: add missing my_syscall6() for mips tools/nolibc: __sysret: support syscalls who return a pointer tools/nolibc: clean up mmap() routine tools/nolibc: clean up sbrk() routine selftests/nolibc: export argv0 for some tests selftests/nolibc: prepare: create /dev/zero selftests/nolibc: add EXPECT_PTREQ, EXPECT_PTRNE and EXPECT_PTRER selftests/nolibc: add sbrk_0 to test current brk getting selftests/nolibc: add mmap_bad test case selftests/nolibc: add munmap_bad test case selftests/nolibc: add mmap_munmap_good test case
tools/include/nolibc/arch-aarch64.h | 28 ++-- tools/include/nolibc/arch-arm.h | 28 ++-- tools/include/nolibc/arch-i386.h | 24 ++-- tools/include/nolibc/arch-loongarch.h | 37 +++--- tools/include/nolibc/arch-mips.h | 73 +++++++---- tools/include/nolibc/arch-riscv.h | 14 +- tools/include/nolibc/arch-s390.h | 14 +- tools/include/nolibc/arch-x86_64.h | 28 ++-- tools/include/nolibc/nolibc.h | 9 +- tools/include/nolibc/sys.h | 55 ++++---- tools/include/nolibc/types.h | 6 + tools/testing/selftests/nolibc/nolibc-test.c | 129 ++++++++++++++++++- 12 files changed, 292 insertions(+), 153 deletions(-)
-- 2.25.1
More than 8 whitespaces of the code indent are replaced with "tab + whitespaces" to fix up such errors reported by scripts/checkpatch.pl:
ERROR: code indent should use tabs where possible #64: FILE: tools/include/nolibc/arch-mips.h:64: +^I $
ERROR: code indent should use tabs where possible #72: FILE: tools/include/nolibc/arch-mips.h:72: +^I "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" $
This command is used:
$ sed -i -e '/^\t* /{s/ /\t/g}' tools/include/nolibc/arch-*.h
Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/include/nolibc/arch-aarch64.h | 14 +++++++------- tools/include/nolibc/arch-arm.h | 14 +++++++------- tools/include/nolibc/arch-i386.h | 12 ++++++------ tools/include/nolibc/arch-mips.h | 24 ++++++++++++------------ tools/include/nolibc/arch-x86_64.h | 14 +++++++------- 5 files changed, 39 insertions(+), 39 deletions(-)
diff --git a/tools/include/nolibc/arch-aarch64.h b/tools/include/nolibc/arch-aarch64.h index 11f294a406b7..c911f61365d1 100644 --- a/tools/include/nolibc/arch-aarch64.h +++ b/tools/include/nolibc/arch-aarch64.h @@ -56,7 +56,7 @@ struct sys_stat_struct { ({ \ register long _num __asm__ ("x8") = (num); \ register long _arg1 __asm__ ("x0"); \ - \ + \ __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ @@ -70,7 +70,7 @@ struct sys_stat_struct { ({ \ register long _num __asm__ ("x8") = (num); \ register long _arg1 __asm__ ("x0") = (long)(arg1); \ - \ + \ __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ @@ -86,7 +86,7 @@ struct sys_stat_struct { register long _num __asm__ ("x8") = (num); \ register long _arg1 __asm__ ("x0") = (long)(arg1); \ register long _arg2 __asm__ ("x1") = (long)(arg2); \ - \ + \ __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ @@ -103,7 +103,7 @@ struct sys_stat_struct { register long _arg1 __asm__ ("x0") = (long)(arg1); \ register long _arg2 __asm__ ("x1") = (long)(arg2); \ register long _arg3 __asm__ ("x2") = (long)(arg3); \ - \ + \ __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ @@ -121,7 +121,7 @@ struct sys_stat_struct { register long _arg2 __asm__ ("x1") = (long)(arg2); \ register long _arg3 __asm__ ("x2") = (long)(arg3); \ register long _arg4 __asm__ ("x3") = (long)(arg4); \ - \ + \ __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ @@ -140,7 +140,7 @@ struct sys_stat_struct { register long _arg3 __asm__ ("x2") = (long)(arg3); \ register long _arg4 __asm__ ("x3") = (long)(arg4); \ register long _arg5 __asm__ ("x4") = (long)(arg5); \ - \ + \ __asm__ volatile ( \ "svc #0\n" \ : "=r" (_arg1) \ @@ -160,7 +160,7 @@ struct sys_stat_struct { register long _arg4 __asm__ ("x3") = (long)(arg4); \ register long _arg5 __asm__ ("x4") = (long)(arg5); \ register long _arg6 __asm__ ("x5") = (long)(arg6); \ - \ + \ __asm__ volatile ( \ "svc #0\n" \ : "=r" (_arg1) \ diff --git a/tools/include/nolibc/arch-arm.h b/tools/include/nolibc/arch-arm.h index ca4c66987497..d5887fd9bc5f 100644 --- a/tools/include/nolibc/arch-arm.h +++ b/tools/include/nolibc/arch-arm.h @@ -90,7 +90,7 @@ struct sys_stat_struct { ({ \ register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ register long _arg1 __asm__ ("r0"); \ - \ + \ __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ @@ -107,7 +107,7 @@ struct sys_stat_struct { ({ \ register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ register long _arg1 __asm__ ("r0") = (long)(arg1); \ - \ + \ __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ @@ -125,7 +125,7 @@ struct sys_stat_struct { register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ register long _arg1 __asm__ ("r0") = (long)(arg1); \ register long _arg2 __asm__ ("r1") = (long)(arg2); \ - \ + \ __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ @@ -144,7 +144,7 @@ struct sys_stat_struct { register long _arg1 __asm__ ("r0") = (long)(arg1); \ register long _arg2 __asm__ ("r1") = (long)(arg2); \ register long _arg3 __asm__ ("r2") = (long)(arg3); \ - \ + \ __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ @@ -164,7 +164,7 @@ struct sys_stat_struct { register long _arg2 __asm__ ("r1") = (long)(arg2); \ register long _arg3 __asm__ ("r2") = (long)(arg3); \ register long _arg4 __asm__ ("r3") = (long)(arg4); \ - \ + \ __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ @@ -185,7 +185,7 @@ struct sys_stat_struct { register long _arg3 __asm__ ("r2") = (long)(arg3); \ register long _arg4 __asm__ ("r3") = (long)(arg4); \ register long _arg5 __asm__ ("r4") = (long)(arg5); \ - \ + \ __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ @@ -207,7 +207,7 @@ struct sys_stat_struct { register long _arg4 __asm__ ("r3") = (long)(arg4); \ register long _arg5 __asm__ ("r4") = (long)(arg5); \ register long _arg6 __asm__ ("r5") = (long)(arg6); \ - \ + \ __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ diff --git a/tools/include/nolibc/arch-i386.h b/tools/include/nolibc/arch-i386.h index 3d672d925e9e..c11a53acf159 100644 --- a/tools/include/nolibc/arch-i386.h +++ b/tools/include/nolibc/arch-i386.h @@ -57,7 +57,7 @@ struct sys_stat_struct { ({ \ long _ret; \ register long _num __asm__ ("eax") = (num); \ - \ + \ __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ @@ -72,7 +72,7 @@ struct sys_stat_struct { long _ret; \ register long _num __asm__ ("eax") = (num); \ register long _arg1 __asm__ ("ebx") = (long)(arg1); \ - \ + \ __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ @@ -89,7 +89,7 @@ struct sys_stat_struct { register long _num __asm__ ("eax") = (num); \ register long _arg1 __asm__ ("ebx") = (long)(arg1); \ register long _arg2 __asm__ ("ecx") = (long)(arg2); \ - \ + \ __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ @@ -107,7 +107,7 @@ struct sys_stat_struct { register long _arg1 __asm__ ("ebx") = (long)(arg1); \ register long _arg2 __asm__ ("ecx") = (long)(arg2); \ register long _arg3 __asm__ ("edx") = (long)(arg3); \ - \ + \ __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ @@ -126,7 +126,7 @@ struct sys_stat_struct { register long _arg2 __asm__ ("ecx") = (long)(arg2); \ register long _arg3 __asm__ ("edx") = (long)(arg3); \ register long _arg4 __asm__ ("esi") = (long)(arg4); \ - \ + \ __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ @@ -146,7 +146,7 @@ struct sys_stat_struct { register long _arg3 __asm__ ("edx") = (long)(arg3); \ register long _arg4 __asm__ ("esi") = (long)(arg4); \ register long _arg5 __asm__ ("edi") = (long)(arg5); \ - \ + \ __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h index db24e0837a39..55cd376a98e2 100644 --- a/tools/include/nolibc/arch-mips.h +++ b/tools/include/nolibc/arch-mips.h @@ -61,7 +61,7 @@ struct sys_stat_struct { ({ \ register long _num __asm__ ("v0") = (num); \ register long _arg4 __asm__ ("a3"); \ - \ + \ __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "syscall\n" \ @@ -69,7 +69,7 @@ struct sys_stat_struct { : "=r"(_num), "=r"(_arg4) \ : "r"(_num) \ : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ ); \ _arg4 ? -_num : _num; \ }) @@ -79,7 +79,7 @@ struct sys_stat_struct { register long _num __asm__ ("v0") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ register long _arg4 __asm__ ("a3"); \ - \ + \ __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "syscall\n" \ @@ -88,7 +88,7 @@ struct sys_stat_struct { : "0"(_num), \ "r"(_arg1) \ : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ ); \ _arg4 ? -_num : _num; \ }) @@ -99,7 +99,7 @@ struct sys_stat_struct { register long _arg1 __asm__ ("a0") = (long)(arg1); \ register long _arg2 __asm__ ("a1") = (long)(arg2); \ register long _arg4 __asm__ ("a3"); \ - \ + \ __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "syscall\n" \ @@ -108,7 +108,7 @@ struct sys_stat_struct { : "0"(_num), \ "r"(_arg1), "r"(_arg2) \ : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ ); \ _arg4 ? -_num : _num; \ }) @@ -120,7 +120,7 @@ struct sys_stat_struct { register long _arg2 __asm__ ("a1") = (long)(arg2); \ register long _arg3 __asm__ ("a2") = (long)(arg3); \ register long _arg4 __asm__ ("a3"); \ - \ + \ __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "syscall\n" \ @@ -129,7 +129,7 @@ struct sys_stat_struct { : "0"(_num), \ "r"(_arg1), "r"(_arg2), "r"(_arg3) \ : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ ); \ _arg4 ? -_num : _num; \ }) @@ -141,7 +141,7 @@ struct sys_stat_struct { register long _arg2 __asm__ ("a1") = (long)(arg2); \ register long _arg3 __asm__ ("a2") = (long)(arg3); \ register long _arg4 __asm__ ("a3") = (long)(arg4); \ - \ + \ __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "syscall\n" \ @@ -150,7 +150,7 @@ struct sys_stat_struct { : "0"(_num), \ "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4) \ : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ ); \ _arg4 ? -_num : _num; \ }) @@ -163,7 +163,7 @@ struct sys_stat_struct { register long _arg3 __asm__ ("a2") = (long)(arg3); \ register long _arg4 __asm__ ("a3") = (long)(arg4); \ register long _arg5 = (long)(arg5); \ - \ + \ __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "sw %7, 16($sp)\n" \ @@ -173,7 +173,7 @@ struct sys_stat_struct { : "0"(_num), \ "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5) \ : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ ); \ _arg4 ? -_num : _num; \ }) diff --git a/tools/include/nolibc/arch-x86_64.h b/tools/include/nolibc/arch-x86_64.h index 6fc4d8392742..1ae73d83aad1 100644 --- a/tools/include/nolibc/arch-x86_64.h +++ b/tools/include/nolibc/arch-x86_64.h @@ -59,7 +59,7 @@ struct sys_stat_struct { ({ \ long _ret; \ register long _num __asm__ ("rax") = (num); \ - \ + \ __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ @@ -74,7 +74,7 @@ struct sys_stat_struct { long _ret; \ register long _num __asm__ ("rax") = (num); \ register long _arg1 __asm__ ("rdi") = (long)(arg1); \ - \ + \ __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ @@ -91,7 +91,7 @@ struct sys_stat_struct { register long _num __asm__ ("rax") = (num); \ register long _arg1 __asm__ ("rdi") = (long)(arg1); \ register long _arg2 __asm__ ("rsi") = (long)(arg2); \ - \ + \ __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ @@ -109,7 +109,7 @@ struct sys_stat_struct { register long _arg1 __asm__ ("rdi") = (long)(arg1); \ register long _arg2 __asm__ ("rsi") = (long)(arg2); \ register long _arg3 __asm__ ("rdx") = (long)(arg3); \ - \ + \ __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ @@ -128,7 +128,7 @@ struct sys_stat_struct { register long _arg2 __asm__ ("rsi") = (long)(arg2); \ register long _arg3 __asm__ ("rdx") = (long)(arg3); \ register long _arg4 __asm__ ("r10") = (long)(arg4); \ - \ + \ __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ @@ -148,7 +148,7 @@ struct sys_stat_struct { register long _arg3 __asm__ ("rdx") = (long)(arg3); \ register long _arg4 __asm__ ("r10") = (long)(arg4); \ register long _arg5 __asm__ ("r8") = (long)(arg5); \ - \ + \ __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ @@ -169,7 +169,7 @@ struct sys_stat_struct { register long _arg4 __asm__ ("r10") = (long)(arg4); \ register long _arg5 __asm__ ("r8") = (long)(arg5); \ register long _arg6 __asm__ ("r9") = (long)(arg6); \ - \ + \ __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \
On Fri, Jul 07, 2023 at 10:50:34PM +0800, Zhangjin Wu wrote:
More than 8 whitespaces of the code indent are replaced with "tab + whitespaces" to fix up such errors reported by scripts/checkpatch.pl:
ERROR: code indent should use tabs where possible #64: FILE: tools/include/nolibc/arch-mips.h:64: +^I \$ ERROR: code indent should use tabs where possible #72: FILE: tools/include/nolibc/arch-mips.h:72: +^I "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \$
Another option we could have had would have been to just delete these lines since there were in fact empty lines containing only an aligned backslash. But that's fine, I've queued it as-is, thanks!
Willy
replace "__asm__ volatile" with "__asm__ volatile" and insert necessary whitespace before "" to make sure the lines are aligned.
$ sed -i -e 's/__asm__ volatile ( /__asm__ volatile ( /g' tools/include/nolibc/*.h
Note, arch-s390.h uses post-tab instead of post-whitespaces, must avoid insert whitespace just before the tabs:
$ sed -i -e 's/__asm__ volatile (\t/__asm__ volatile (\t/g' tools/include/nolibc/arch-*.h
Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/include/nolibc/arch-aarch64.h | 14 +++++++------- tools/include/nolibc/arch-arm.h | 14 +++++++------- tools/include/nolibc/arch-i386.h | 12 ++++++------ tools/include/nolibc/arch-loongarch.h | 14 +++++++------- tools/include/nolibc/arch-mips.h | 12 ++++++------ tools/include/nolibc/arch-riscv.h | 14 +++++++------- tools/include/nolibc/arch-s390.h | 14 +++++++------- tools/include/nolibc/arch-x86_64.h | 14 +++++++------- 8 files changed, 54 insertions(+), 54 deletions(-)
diff --git a/tools/include/nolibc/arch-aarch64.h b/tools/include/nolibc/arch-aarch64.h index c911f61365d1..6227b77a4a09 100644 --- a/tools/include/nolibc/arch-aarch64.h +++ b/tools/include/nolibc/arch-aarch64.h @@ -57,7 +57,7 @@ struct sys_stat_struct { register long _num __asm__ ("x8") = (num); \ register long _arg1 __asm__ ("x0"); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ : "r"(_num) \ @@ -71,7 +71,7 @@ struct sys_stat_struct { register long _num __asm__ ("x8") = (num); \ register long _arg1 __asm__ ("x0") = (long)(arg1); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ : "r"(_arg1), \ @@ -87,7 +87,7 @@ struct sys_stat_struct { register long _arg1 __asm__ ("x0") = (long)(arg1); \ register long _arg2 __asm__ ("x1") = (long)(arg2); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ : "r"(_arg1), "r"(_arg2), \ @@ -104,7 +104,7 @@ struct sys_stat_struct { register long _arg2 __asm__ ("x1") = (long)(arg2); \ register long _arg3 __asm__ ("x2") = (long)(arg3); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ @@ -122,7 +122,7 @@ struct sys_stat_struct { register long _arg3 __asm__ ("x2") = (long)(arg3); \ register long _arg4 __asm__ ("x3") = (long)(arg4); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ @@ -141,7 +141,7 @@ struct sys_stat_struct { register long _arg4 __asm__ ("x3") = (long)(arg4); \ register long _arg5 __asm__ ("x4") = (long)(arg5); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc #0\n" \ : "=r" (_arg1) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ @@ -161,7 +161,7 @@ struct sys_stat_struct { register long _arg5 __asm__ ("x4") = (long)(arg5); \ register long _arg6 __asm__ ("x5") = (long)(arg6); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc #0\n" \ : "=r" (_arg1) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ diff --git a/tools/include/nolibc/arch-arm.h b/tools/include/nolibc/arch-arm.h index d5887fd9bc5f..4d4887a5f04b 100644 --- a/tools/include/nolibc/arch-arm.h +++ b/tools/include/nolibc/arch-arm.h @@ -91,7 +91,7 @@ struct sys_stat_struct { register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ register long _arg1 __asm__ ("r0"); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ _NOLIBC_THUMB_RESTORE_R7 \ @@ -108,7 +108,7 @@ struct sys_stat_struct { register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ register long _arg1 __asm__ ("r0") = (long)(arg1); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ _NOLIBC_THUMB_RESTORE_R7 \ @@ -126,7 +126,7 @@ struct sys_stat_struct { register long _arg1 __asm__ ("r0") = (long)(arg1); \ register long _arg2 __asm__ ("r1") = (long)(arg2); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ _NOLIBC_THUMB_RESTORE_R7 \ @@ -145,7 +145,7 @@ struct sys_stat_struct { register long _arg2 __asm__ ("r1") = (long)(arg2); \ register long _arg3 __asm__ ("r2") = (long)(arg3); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ _NOLIBC_THUMB_RESTORE_R7 \ @@ -165,7 +165,7 @@ struct sys_stat_struct { register long _arg3 __asm__ ("r2") = (long)(arg3); \ register long _arg4 __asm__ ("r3") = (long)(arg4); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ _NOLIBC_THUMB_RESTORE_R7 \ @@ -186,7 +186,7 @@ struct sys_stat_struct { register long _arg4 __asm__ ("r3") = (long)(arg4); \ register long _arg5 __asm__ ("r4") = (long)(arg5); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ _NOLIBC_THUMB_RESTORE_R7 \ @@ -208,7 +208,7 @@ struct sys_stat_struct { register long _arg5 __asm__ ("r4") = (long)(arg5); \ register long _arg6 __asm__ ("r5") = (long)(arg6); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ _NOLIBC_THUMB_RESTORE_R7 \ diff --git a/tools/include/nolibc/arch-i386.h b/tools/include/nolibc/arch-i386.h index c11a53acf159..4c6b7c04e2e7 100644 --- a/tools/include/nolibc/arch-i386.h +++ b/tools/include/nolibc/arch-i386.h @@ -58,7 +58,7 @@ struct sys_stat_struct { long _ret; \ register long _num __asm__ ("eax") = (num); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ : "0"(_num) \ @@ -73,7 +73,7 @@ struct sys_stat_struct { register long _num __asm__ ("eax") = (num); \ register long _arg1 __asm__ ("ebx") = (long)(arg1); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ : "r"(_arg1), \ @@ -90,7 +90,7 @@ struct sys_stat_struct { register long _arg1 __asm__ ("ebx") = (long)(arg1); \ register long _arg2 __asm__ ("ecx") = (long)(arg2); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ : "r"(_arg1), "r"(_arg2), \ @@ -108,7 +108,7 @@ struct sys_stat_struct { register long _arg2 __asm__ ("ecx") = (long)(arg2); \ register long _arg3 __asm__ ("edx") = (long)(arg3); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ @@ -127,7 +127,7 @@ struct sys_stat_struct { register long _arg3 __asm__ ("edx") = (long)(arg3); \ register long _arg4 __asm__ ("esi") = (long)(arg4); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ @@ -147,7 +147,7 @@ struct sys_stat_struct { register long _arg4 __asm__ ("esi") = (long)(arg4); \ register long _arg5 __asm__ ("edi") = (long)(arg5); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ diff --git a/tools/include/nolibc/arch-loongarch.h b/tools/include/nolibc/arch-loongarch.h index ad3f266e7093..8df42268e578 100644 --- a/tools/include/nolibc/arch-loongarch.h +++ b/tools/include/nolibc/arch-loongarch.h @@ -28,7 +28,7 @@ register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0"); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall 0\n" \ : "=r"(_arg1) \ : "r"(_num) \ @@ -43,7 +43,7 @@ register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall 0\n" \ : "+r"(_arg1) \ : "r"(_num) \ @@ -59,7 +59,7 @@ register long _arg1 __asm__ ("a0") = (long)(arg1); \ register long _arg2 __asm__ ("a1") = (long)(arg2); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall 0\n" \ : "+r"(_arg1) \ : "r"(_arg2), \ @@ -77,7 +77,7 @@ register long _arg2 __asm__ ("a1") = (long)(arg2); \ register long _arg3 __asm__ ("a2") = (long)(arg3); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall 0\n" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), \ @@ -96,7 +96,7 @@ register long _arg3 __asm__ ("a2") = (long)(arg3); \ register long _arg4 __asm__ ("a3") = (long)(arg4); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall 0\n" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ @@ -116,7 +116,7 @@ register long _arg4 __asm__ ("a3") = (long)(arg4); \ register long _arg5 __asm__ ("a4") = (long)(arg5); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall 0\n" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ @@ -137,7 +137,7 @@ register long _arg5 __asm__ ("a4") = (long)(arg5); \ register long _arg6 __asm__ ("a5") = (long)(arg6); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall 0\n" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h index 55cd376a98e2..22aacc07b1fc 100644 --- a/tools/include/nolibc/arch-mips.h +++ b/tools/include/nolibc/arch-mips.h @@ -62,7 +62,7 @@ struct sys_stat_struct { register long _num __asm__ ("v0") = (num); \ register long _arg4 __asm__ ("a3"); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "syscall\n" \ "addiu $sp, $sp, 32\n" \ @@ -80,7 +80,7 @@ struct sys_stat_struct { register long _arg1 __asm__ ("a0") = (long)(arg1); \ register long _arg4 __asm__ ("a3"); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "syscall\n" \ "addiu $sp, $sp, 32\n" \ @@ -100,7 +100,7 @@ struct sys_stat_struct { register long _arg2 __asm__ ("a1") = (long)(arg2); \ register long _arg4 __asm__ ("a3"); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "syscall\n" \ "addiu $sp, $sp, 32\n" \ @@ -121,7 +121,7 @@ struct sys_stat_struct { register long _arg3 __asm__ ("a2") = (long)(arg3); \ register long _arg4 __asm__ ("a3"); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "syscall\n" \ "addiu $sp, $sp, 32\n" \ @@ -142,7 +142,7 @@ struct sys_stat_struct { register long _arg3 __asm__ ("a2") = (long)(arg3); \ register long _arg4 __asm__ ("a3") = (long)(arg4); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "syscall\n" \ "addiu $sp, $sp, 32\n" \ @@ -164,7 +164,7 @@ struct sys_stat_struct { register long _arg4 __asm__ ("a3") = (long)(arg4); \ register long _arg5 = (long)(arg5); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "sw %7, 16($sp)\n" \ "syscall\n " \ diff --git a/tools/include/nolibc/arch-riscv.h b/tools/include/nolibc/arch-riscv.h index a2e8564e66d6..cd958b2f4b1b 100644 --- a/tools/include/nolibc/arch-riscv.h +++ b/tools/include/nolibc/arch-riscv.h @@ -63,7 +63,7 @@ struct sys_stat_struct { register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0"); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "ecall\n\t" \ : "=r"(_arg1) \ : "r"(_num) \ @@ -77,7 +77,7 @@ struct sys_stat_struct { register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "ecall\n" \ : "+r"(_arg1) \ : "r"(_num) \ @@ -92,7 +92,7 @@ struct sys_stat_struct { register long _arg1 __asm__ ("a0") = (long)(arg1); \ register long _arg2 __asm__ ("a1") = (long)(arg2); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "ecall\n" \ : "+r"(_arg1) \ : "r"(_arg2), \ @@ -109,7 +109,7 @@ struct sys_stat_struct { register long _arg2 __asm__ ("a1") = (long)(arg2); \ register long _arg3 __asm__ ("a2") = (long)(arg3); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "ecall\n\t" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), \ @@ -127,7 +127,7 @@ struct sys_stat_struct { register long _arg3 __asm__ ("a2") = (long)(arg3); \ register long _arg4 __asm__ ("a3") = (long)(arg4); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "ecall\n" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ @@ -146,7 +146,7 @@ struct sys_stat_struct { register long _arg4 __asm__ ("a3") = (long)(arg4); \ register long _arg5 __asm__ ("a4") = (long)(arg5); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "ecall\n" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ @@ -166,7 +166,7 @@ struct sys_stat_struct { register long _arg5 __asm__ ("a4") = (long)(arg5); \ register long _arg6 __asm__ ("a5") = (long)(arg6); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "ecall\n" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ diff --git a/tools/include/nolibc/arch-s390.h b/tools/include/nolibc/arch-s390.h index 516dff5bff8b..a644ecd361c0 100644 --- a/tools/include/nolibc/arch-s390.h +++ b/tools/include/nolibc/arch-s390.h @@ -52,7 +52,7 @@ struct sys_stat_struct { register long _num __asm__ ("1") = (num); \ register long _rc __asm__ ("2"); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc 0\n" \ : "=d"(_rc) \ : "d"(_num) \ @@ -66,7 +66,7 @@ struct sys_stat_struct { register long _num __asm__ ("1") = (num); \ register long _arg1 __asm__ ("2") = (long)(arg1); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc 0\n" \ : "+d"(_arg1) \ : "d"(_num) \ @@ -81,7 +81,7 @@ struct sys_stat_struct { register long _arg1 __asm__ ("2") = (long)(arg1); \ register long _arg2 __asm__ ("3") = (long)(arg2); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc 0\n" \ : "+d"(_arg1) \ : "d"(_arg2), "d"(_num) \ @@ -97,7 +97,7 @@ struct sys_stat_struct { register long _arg2 __asm__ ("3") = (long)(arg2); \ register long _arg3 __asm__ ("4") = (long)(arg3); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc 0\n" \ : "+d"(_arg1) \ : "d"(_arg2), "d"(_arg3), "d"(_num) \ @@ -114,7 +114,7 @@ struct sys_stat_struct { register long _arg3 __asm__ ("4") = (long)(arg3); \ register long _arg4 __asm__ ("5") = (long)(arg4); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc 0\n" \ : "+d"(_arg1) \ : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_num) \ @@ -132,7 +132,7 @@ struct sys_stat_struct { register long _arg4 __asm__ ("5") = (long)(arg4); \ register long _arg5 __asm__ ("6") = (long)(arg5); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc 0\n" \ : "+d"(_arg1) \ : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5), \ @@ -152,7 +152,7 @@ struct sys_stat_struct { register long _arg5 __asm__ ("6") = (long)(arg5); \ register long _arg6 __asm__ ("7") = (long)(arg6); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc 0\n" \ : "+d"(_arg1) \ : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5), \ diff --git a/tools/include/nolibc/arch-x86_64.h b/tools/include/nolibc/arch-x86_64.h index 1ae73d83aad1..e69113742a99 100644 --- a/tools/include/nolibc/arch-x86_64.h +++ b/tools/include/nolibc/arch-x86_64.h @@ -60,7 +60,7 @@ struct sys_stat_struct { long _ret; \ register long _num __asm__ ("rax") = (num); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ : "0"(_num) \ @@ -75,7 +75,7 @@ struct sys_stat_struct { register long _num __asm__ ("rax") = (num); \ register long _arg1 __asm__ ("rdi") = (long)(arg1); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ : "r"(_arg1), \ @@ -92,7 +92,7 @@ struct sys_stat_struct { register long _arg1 __asm__ ("rdi") = (long)(arg1); \ register long _arg2 __asm__ ("rsi") = (long)(arg2); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ : "r"(_arg1), "r"(_arg2), \ @@ -110,7 +110,7 @@ struct sys_stat_struct { register long _arg2 __asm__ ("rsi") = (long)(arg2); \ register long _arg3 __asm__ ("rdx") = (long)(arg3); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ @@ -129,7 +129,7 @@ struct sys_stat_struct { register long _arg3 __asm__ ("rdx") = (long)(arg3); \ register long _arg4 __asm__ ("r10") = (long)(arg4); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ @@ -149,7 +149,7 @@ struct sys_stat_struct { register long _arg4 __asm__ ("r10") = (long)(arg4); \ register long _arg5 __asm__ ("r8") = (long)(arg5); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ @@ -170,7 +170,7 @@ struct sys_stat_struct { register long _arg5 __asm__ ("r8") = (long)(arg5); \ register long _arg6 __asm__ ("r9") = (long)(arg6); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
my_syscall<N> share the same long clobber list, define a macro for them.
Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/include/nolibc/arch-loongarch.h | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-)
diff --git a/tools/include/nolibc/arch-loongarch.h b/tools/include/nolibc/arch-loongarch.h index 8df42268e578..8aa7724fe38e 100644 --- a/tools/include/nolibc/arch-loongarch.h +++ b/tools/include/nolibc/arch-loongarch.h @@ -22,6 +22,8 @@ * On LoongArch, select() is not implemented so we have to use pselect6(). */ #define __ARCH_WANT_SYS_PSELECT6 +#define _NOLIBC_SYSCALL_CLOBBERLIST \ + "memory", "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8"
#define my_syscall0(num) \ ({ \ @@ -32,8 +34,7 @@ "syscall 0\n" \ : "=r"(_arg1) \ : "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) @@ -47,8 +48,7 @@ "syscall 0\n" \ : "+r"(_arg1) \ : "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) @@ -64,8 +64,7 @@ : "+r"(_arg1) \ : "r"(_arg2), \ "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) @@ -82,8 +81,7 @@ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), \ "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) @@ -101,8 +99,7 @@ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) @@ -121,8 +118,7 @@ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) @@ -142,8 +138,7 @@ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg1; \ })
my_syscall<N> share the same long clobber list, define a macro for them.
Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/include/nolibc/arch-mips.h | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-)
diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h index 22aacc07b1fc..1848f57777c4 100644 --- a/tools/include/nolibc/arch-mips.h +++ b/tools/include/nolibc/arch-mips.h @@ -57,6 +57,10 @@ struct sys_stat_struct { * don't have to experience issues with register constraints. */
+#define _NOLIBC_SYSCALL_CLOBBERLIST \ + "memory", "cc", "at", "v1", "hi", "lo", \ + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" + #define my_syscall0(num) \ ({ \ register long _num __asm__ ("v0") = (num); \ @@ -68,8 +72,7 @@ struct sys_stat_struct { "addiu $sp, $sp, 32\n" \ : "=r"(_num), "=r"(_arg4) \ : "r"(_num) \ - : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg4 ? -_num : _num; \ }) @@ -87,8 +90,7 @@ struct sys_stat_struct { : "=r"(_num), "=r"(_arg4) \ : "0"(_num), \ "r"(_arg1) \ - : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg4 ? -_num : _num; \ }) @@ -107,8 +109,7 @@ struct sys_stat_struct { : "=r"(_num), "=r"(_arg4) \ : "0"(_num), \ "r"(_arg1), "r"(_arg2) \ - : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg4 ? -_num : _num; \ }) @@ -128,8 +129,7 @@ struct sys_stat_struct { : "=r"(_num), "=r"(_arg4) \ : "0"(_num), \ "r"(_arg1), "r"(_arg2), "r"(_arg3) \ - : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg4 ? -_num : _num; \ }) @@ -149,8 +149,7 @@ struct sys_stat_struct { : "=r" (_num), "=r"(_arg4) \ : "0"(_num), \ "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4) \ - : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg4 ? -_num : _num; \ }) @@ -172,8 +171,7 @@ struct sys_stat_struct { : "=r" (_num), "=r"(_arg4) \ : "0"(_num), \ "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5) \ - : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg4 ? -_num : _num; \ })
It is able to pass the 6th argument like the 5th argument via the stack for mips, let's add a new my_syscall6() now, see [1] for details:
The mips/o32 system call convention passes arguments 5 through 8 on the user stack.
Both mmap() and pselect6() require my_syscall6().
[1]: https://man7.org/linux/man-pages/man2/syscall.2.html
Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/include/nolibc/arch-mips.h | 27 ++++++++++++++++++++++++++- tools/include/nolibc/nolibc.h | 9 ++++----- 2 files changed, 30 insertions(+), 6 deletions(-)
diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h index 1848f57777c4..a2bfdf57b957 100644 --- a/tools/include/nolibc/arch-mips.h +++ b/tools/include/nolibc/arch-mips.h @@ -166,7 +166,7 @@ struct sys_stat_struct { __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "sw %7, 16($sp)\n" \ - "syscall\n " \ + "syscall\n" \ "addiu $sp, $sp, 32\n" \ : "=r" (_num), "=r"(_arg4) \ : "0"(_num), \ @@ -176,6 +176,31 @@ struct sys_stat_struct { _arg4 ? -_num : _num; \ })
+#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +({ \ + register long _num __asm__ ("v0") = (num); \ + register long _arg1 __asm__ ("a0") = (long)(arg1); \ + register long _arg2 __asm__ ("a1") = (long)(arg2); \ + register long _arg3 __asm__ ("a2") = (long)(arg3); \ + register long _arg4 __asm__ ("a3") = (long)(arg4); \ + register long _arg5 = (long)(arg5); \ + register long _arg6 = (long)(arg6); \ + \ + __asm__ volatile ( \ + "addiu $sp, $sp, -32\n" \ + "sw %7, 16($sp)\n" \ + "sw %8, 20($sp)\n" \ + "syscall\n" \ + "addiu $sp, $sp, 32\n" \ + : "=r" (_num), "=r"(_arg4) \ + : "0"(_num), \ + "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ + "r"(_arg6) \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _arg4 ? -_num : _num; \ +}) + char **environ __attribute__((weak)); const unsigned long *_auxv __attribute__((weak));
diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 05a228a6ee78..1f8d821000ac 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -13,11 +13,10 @@ * Syscalls are split into 3 levels: * - The lower level is the arch-specific syscall() definition, consisting in * assembly code in compound expressions. These are called my_syscall0() to - * my_syscall6() depending on the number of arguments. The MIPS - * implementation is limited to 5 arguments. All input arguments are cast - * to a long stored in a register. These expressions always return the - * syscall's return value as a signed long value which is often either a - * pointer or the negated errno value. + * my_syscall6() depending on the number of arguments. All input arguments + * are castto a long stored in a register. These expressions always return + * the syscall's return value as a signed long value which is often either + * a pointer or the negated errno value. * * - The second level is mostly architecture-independent. It is made of * static functions called sys_<name>() which rely on my_syscallN()
No official reference states the errno range, here aligns with musl and glibc and uses [-MAX_ERRNO, -1] instead of all negative ones.
- musl: src/internal/syscall_ret.c - glibc: sysdeps/unix/sysv/linux/sysdep.h
The MAX_ERRNO used by musl and glibc is 4095, just like the one nolibc defined in tools/include/nolibc/errno.h.
Suggested-by: Willy Tarreau w@1wt.eu Link: https://lore.kernel.org/lkml/ZKKdD%2Fp4UkEavru6@1wt.eu/ Suggested-by: David Laight David.Laight@ACULAB.COM Link: https://lore.kernel.org/linux-riscv/94dd5170929f454fbc0a10a2eb3b108d@AcuMS.a... Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/include/nolibc/sys.h | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 53bc3ad6593e..3479f54d7957 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -28,13 +28,20 @@ #include "errno.h" #include "types.h"
-/* Syscall return helper, set errno as -ret when ret < 0 */ + +/* Syscall return helper for library routines, set errno as -ret when ret is in + * range of [-MAX_ERRNO, -1] + * + * Note, No official reference states the errno range here aligns with musl + * (src/internal/syscall_ret.c) and glibc (sysdeps/unix/sysv/linux/sysdep.h) + */ + static __inline__ __attribute__((unused, always_inline)) -long __sysret(long ret) +long __sysret(unsigned long ret) { - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; + if (ret >= (unsigned long)-MAX_ERRNO) { + SET_ERRNO(-(long)ret); + return -1; } return ret; }
Hi Zhangjin,
On Fri, Jul 07, 2023 at 10:56:59PM +0800, Zhangjin Wu wrote:
No official reference states the errno range, here aligns with musl and glibc and uses [-MAX_ERRNO, -1] instead of all negative ones.
- musl: src/internal/syscall_ret.c
- glibc: sysdeps/unix/sysv/linux/sysdep.h
The MAX_ERRNO used by musl and glibc is 4095, just like the one nolibc defined in tools/include/nolibc/errno.h.
Suggested-by: Willy Tarreau w@1wt.eu Link: https://lore.kernel.org/lkml/ZKKdD%2Fp4UkEavru6@1wt.eu/ Suggested-by: David Laight David.Laight@ACULAB.COM Link: https://lore.kernel.org/linux-riscv/94dd5170929f454fbc0a10a2eb3b108d@AcuMS.a... Signed-off-by: Zhangjin Wu falcon@tinylab.org
tools/include/nolibc/sys.h | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 53bc3ad6593e..3479f54d7957 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -28,13 +28,20 @@ #include "errno.h" #include "types.h" -/* Syscall return helper, set errno as -ret when ret < 0 */
+/* Syscall return helper for library routines, set errno as -ret when ret is in
- range of [-MAX_ERRNO, -1]
- Note, No official reference states the errno range here aligns with musl
- (src/internal/syscall_ret.c) and glibc (sysdeps/unix/sysv/linux/sysdep.h)
- */
static __inline__ __attribute__((unused, always_inline)) -long __sysret(long ret) +long __sysret(unsigned long ret) {
- if (ret < 0) {
SET_ERRNO(-ret);
ret = -1;
- if (ret >= (unsigned long)-MAX_ERRNO) {
SET_ERRNO(-(long)ret);
} return ret;return -1;
}
While running some regression tests, I found that my programs increased in size by 3-4% overall, which was solely attributed to this helper that significantly increased the size of many syscalls (particularly those returning ints). Let's consider this simple function:
void unlink_exit(const char *name) { int ret = unlink(name); exit(ret < 0 ? errno : 0); }
Before: $ nm --size unlink.o | grep unli 0000000000000030 T unlink_exit
$ objdump -d -j .text --disassemble=unlink_exit unlink.o 000000000000003b <unlink_exit>: 3b: 48 89 fe mov %rdi,%rsi 3e: b8 07 01 00 00 mov $0x107,%eax 43: 31 d2 xor %edx,%edx 45: 48 c7 c7 9c ff ff ff mov $0xffffffffffffff9c,%rdi 4c: 0f 05 syscall 4e: 31 ff xor %edi,%edi 50: 85 c0 test %eax,%eax 52: 79 0a jns 5e <unlink_exit+0x23> 54: 89 c7 mov %eax,%edi 56: f7 df neg %edi 58: 89 3d 00 00 00 00 mov %edi,0x0(%rip) # 5e <unlink_exit+0x23> 5e: b8 3c 00 00 00 mov $0x3c,%eax 63: 40 0f b6 ff movzbl %dil,%edi 67: 0f 05 syscall 69: eb fe jmp 69 <unlink_exit+0x2e>
After: $ nm --size unlink.o | grep unli 0000000000000042 T unlink_exit
$ objdump -d -j .text --disassemble=unlink_exit unlink.o 0000000000000051 <unlink_exit>: 51: 48 89 fe mov %rdi,%rsi 54: b8 07 01 00 00 mov $0x107,%eax 59: 31 d2 xor %edx,%edx 5b: 48 c7 c7 9c ff ff ff mov $0xffffffffffffff9c,%rdi 62: 0f 05 syscall 64: 48 63 d0 movslq %eax,%rdx 67: 48 81 fa 00 f0 ff ff cmp $0xfffffffffffff000,%rdx 6e: 76 0a jbe 7a <unlink_exit+0x29> 70: f7 da neg %edx 72: 89 15 00 00 00 00 mov %edx,0x0(%rip) # 78 <unlink_exit+0x27> 78: eb 06 jmp 80 <unlink_exit+0x2f> 7a: 31 ff xor %edi,%edi 7c: 85 c0 test %eax,%eax 7e: 79 06 jns 86 <unlink_exit+0x35> 80: 8b 3d 00 00 00 00 mov 0x0(%rip),%edi # 86 <unlink_exit+0x35> 86: b8 3c 00 00 00 mov $0x3c,%eax 8b: 40 0f b6 ff movzbl %dil,%edi 8f: 0f 05 syscall 91: eb fe jmp 91 <unlink_exit+0x40>
=> that's 18 bytes added to retrieve the result of a syscall.
There are several reasons involved: - the "unsigned long" argument to __sysret() forces a sign extension from all sys_* functions that used to return int (the movslq above).
- the comparison with the error range now has to be performed on a long instead of an int
- the return value from __sysret() is a long (note, a signed long) which then has to be turned back to an int before being returned by the caller to satisfy the caller's prototype.
I could recover a part of it by replacing the __sysret() function with a macro that preserves the input type and avoids these useless conversions:
#define __sysret(arg) ({ \ typeof(arg) __sysret_arg = (arg); \ if ((unsigned long)__sysret_arg >= (unsigned long)-MAX_ERRNO) { \ SET_ERRNO(-(int)__sysret_arg); \ __sysret_arg = -1L; \ } \ __sysret_arg; \ })
But the remaining part is the comparison to -MAX_ERRNO inflicted on all integer returns where we could previously keep a simple sign comparison:
51: 48 89 fe mov %rdi,%rsi 54: b8 07 01 00 00 mov $0x107,%eax 59: 31 d2 xor %edx,%edx 5b: 48 c7 c7 9c ff ff ff mov $0xffffffffffffff9c,%rdi 62: 0f 05 syscall 64: 3d 00 f0 ff ff cmp $0xfffff000,%eax 69: 76 0a jbe 75 <unlink_exit+0x24> 6b: f7 d8 neg %eax 6d: 89 05 00 00 00 00 mov %eax,0x0(%rip) # 73 <unlink_exit+0x22> 73: eb 06 jmp 7b <unlink_exit+0x2a> 75: 31 ff xor %edi,%edi 77: 85 c0 test %eax,%eax 79: 79 06 jns 81 <unlink_exit+0x30> 7b: 8b 3d 00 00 00 00 mov 0x0(%rip),%edi # 81 <unlink_exit+0x30> 81: b8 3c 00 00 00 mov $0x3c,%eax 86: 40 0f b6 ff movzbl %dil,%edi 8a: 0f 05 syscall 8c: eb fe jmp 8c <unlink_exit+0x3b>
And given that the vast majority of the syscalls return integers, I think we should specialize these sysret functions so that we don't add needless complexity for all those for which we know they're returning ints (it's written in the caller's prototype anyway). I.e. we can have __sysret_int() that is the low-overhead version and keep __sysret() the expensive one doing the comparison (and possibly through the macro like above if needed in order to avoid multiple casts).
I'm not going to change all that now, that's too late, but I'm a bit sad to see my binaries inflate just because of this, so I hope we can get back to this later after the current queue is flushed.
Regards, Willy
Hi Zhangjin,
On Fri, Jul 07, 2023 at 10:56:59PM +0800, Zhangjin Wu wrote:
No official reference states the errno range, here aligns with musl and glibc and uses [-MAX_ERRNO, -1] instead of all negative ones.
- musl: src/internal/syscall_ret.c
- glibc: sysdeps/unix/sysv/linux/sysdep.h
The MAX_ERRNO used by musl and glibc is 4095, just like the one nolibc defined in tools/include/nolibc/errno.h.
Suggested-by: Willy Tarreau w@1wt.eu Link: https://lore.kernel.org/lkml/ZKKdD%2Fp4UkEavru6@1wt.eu/ Suggested-by: David Laight David.Laight@ACULAB.COM Link: https://lore.kernel.org/linux-riscv/94dd5170929f454fbc0a10a2eb3b108d@AcuMS.a... Signed-off-by: Zhangjin Wu falcon@tinylab.org
tools/include/nolibc/sys.h | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 53bc3ad6593e..3479f54d7957 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -28,13 +28,20 @@ #include "errno.h" #include "types.h" -/* Syscall return helper, set errno as -ret when ret < 0 */
+/* Syscall return helper for library routines, set errno as -ret when ret is in
- range of [-MAX_ERRNO, -1]
- Note, No official reference states the errno range here aligns with musl
- (src/internal/syscall_ret.c) and glibc (sysdeps/unix/sysv/linux/sysdep.h)
- */
static __inline__ __attribute__((unused, always_inline)) -long __sysret(long ret) +long __sysret(unsigned long ret) {
- if (ret < 0) {
SET_ERRNO(-ret);
ret = -1;
- if (ret >= (unsigned long)-MAX_ERRNO) {
SET_ERRNO(-(long)ret);
} return ret;return -1;
}
While running some regression tests, I found that my programs increased in size by 3-4% overall, which was solely attributed to this helper that significantly increased the size of many syscalls (particularly those returning ints). Let's consider this simple function:
I'm very sad to learn this, so sorry, but we do need a test suite for the coverage on different toolchains, on O0/1/2/3/s, on generated size ...
void unlink_exit(const char *name) { int ret = unlink(name); exit(ret < 0 ? errno : 0); }
Before: $ nm --size unlink.o | grep unli 0000000000000030 T unlink_exit
$ objdump -d -j .text --disassemble=unlink_exit unlink.o 000000000000003b <unlink_exit>: 3b: 48 89 fe mov %rdi,%rsi 3e: b8 07 01 00 00 mov $0x107,%eax 43: 31 d2 xor %edx,%edx 45: 48 c7 c7 9c ff ff ff mov $0xffffffffffffff9c,%rdi 4c: 0f 05 syscall 4e: 31 ff xor %edi,%edi 50: 85 c0 test %eax,%eax 52: 79 0a jns 5e <unlink_exit+0x23> 54: 89 c7 mov %eax,%edi 56: f7 df neg %edi 58: 89 3d 00 00 00 00 mov %edi,0x0(%rip) # 5e <unlink_exit+0x23> 5e: b8 3c 00 00 00 mov $0x3c,%eax 63: 40 0f b6 ff movzbl %dil,%edi 67: 0f 05 syscall 69: eb fe jmp 69 <unlink_exit+0x2e>
After: $ nm --size unlink.o | grep unli 0000000000000042 T unlink_exit
$ objdump -d -j .text --disassemble=unlink_exit unlink.o 0000000000000051 <unlink_exit>: 51: 48 89 fe mov %rdi,%rsi 54: b8 07 01 00 00 mov $0x107,%eax 59: 31 d2 xor %edx,%edx 5b: 48 c7 c7 9c ff ff ff mov $0xffffffffffffff9c,%rdi 62: 0f 05 syscall 64: 48 63 d0 movslq %eax,%rdx 67: 48 81 fa 00 f0 ff ff cmp $0xfffffffffffff000,%rdx 6e: 76 0a jbe 7a <unlink_exit+0x29> 70: f7 da neg %edx 72: 89 15 00 00 00 00 mov %edx,0x0(%rip) # 78 <unlink_exit+0x27> 78: eb 06 jmp 80 <unlink_exit+0x2f> 7a: 31 ff xor %edi,%edi 7c: 85 c0 test %eax,%eax 7e: 79 06 jns 86 <unlink_exit+0x35> 80: 8b 3d 00 00 00 00 mov 0x0(%rip),%edi # 86 <unlink_exit+0x35> 86: b8 3c 00 00 00 mov $0x3c,%eax 8b: 40 0f b6 ff movzbl %dil,%edi 8f: 0f 05 syscall 91: eb fe jmp 91 <unlink_exit+0x40>
=> that's 18 bytes added to retrieve the result of a syscall.
There are several reasons involved:
the "unsigned long" argument to __sysret() forces a sign extension from all sys_* functions that used to return int (the movslq above).
the comparison with the error range now has to be performed on a long instead of an int
the return value from __sysret() is a long (note, a signed long) which then has to be turned back to an int before being returned by the caller to satisfy the caller's prototype.
I could recover a part of it by replacing the __sysret() function with a macro that preserves the input type and avoids these useless conversions:
#define __sysret(arg) ({ \ typeof(arg) __sysret_arg = (arg); \ if ((unsigned long)__sysret_arg >= (unsigned long)-MAX_ERRNO) { \ SET_ERRNO(-(int)__sysret_arg); \ __sysret_arg = -1L; \ } \ __sysret_arg; \ })
But the remaining part is the comparison to -MAX_ERRNO inflicted on all integer returns where we could previously keep a simple sign comparison:
51: 48 89 fe mov %rdi,%rsi 54: b8 07 01 00 00 mov $0x107,%eax 59: 31 d2 xor %edx,%edx 5b: 48 c7 c7 9c ff ff ff mov $0xffffffffffffff9c,%rdi 62: 0f 05 syscall 64: 3d 00 f0 ff ff cmp $0xfffff000,%eax 69: 76 0a jbe 75 <unlink_exit+0x24> 6b: f7 d8 neg %eax 6d: 89 05 00 00 00 00 mov %eax,0x0(%rip) # 73 <unlink_exit+0x22> 73: eb 06 jmp 7b <unlink_exit+0x2a> 75: 31 ff xor %edi,%edi 77: 85 c0 test %eax,%eax 79: 79 06 jns 81 <unlink_exit+0x30> 7b: 8b 3d 00 00 00 00 mov 0x0(%rip),%edi # 81 <unlink_exit+0x30> 81: b8 3c 00 00 00 mov $0x3c,%eax 86: 40 0f b6 ff movzbl %dil,%edi 8a: 0f 05 syscall 8c: eb fe jmp 8c <unlink_exit+0x3b>
And given that the vast majority of the syscalls return integers, I think we should specialize these sysret functions so that we don't add needless complexity for all those for which we know they're returning ints (it's written in the caller's prototype anyway). I.e. we can have __sysret_int() that is the low-overhead version and keep __sysret() the expensive one doing the comparison (and possibly through the macro like above if needed in order to avoid multiple casts).
Based on your macro version, I tried to use the is_signed_type() from kernel, it seems works.
A simple test shows, before:
// ppc64 $ size nolibc-test text data bss dec hex filename 27308 1880 80 29268 7254 nolibc-test
// mips $ size nolibc-test text data bss dec hex filename 23276 64 64 23404 5b6c nolibc-test
After:
// ppc64 $ size nolibc-test text data bss dec hex filename 27136 1880 80 29096 71a8 nolibc-test
// mips $ size nolibc-test text data bss dec hex filename 23036 64 64 23164 5a7c nolibc-test
I'm not going to change all that now, that's too late, but I'm a bit sad to see my binaries inflate just because of this, so I hope we can get back to this later after the current queue is flushed.
Ok, will send a patch with is_signed_type() for more discuss soon.
Thanks, Willy
Regards, Willy
From: Zhangjin Wu
Sent: 06 August 2023 13:34
...
Based on your macro version, I tried to use the is_signed_type() from kernel, it seems works.
You'll find that (void *)0 isn't 'constant enough' for is_constexpr() - so is_constexpr((type)0) can be used to detect pointer types. Probably requires an 'is_pointer_type()' define. This also rather means that is_signed_type() needs to be wrapped in is_constexpr() - probably generating header file inclusion hell.
I'm going to add a comment on v3 of the patch...
David
- Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
Do several cleanups together:
- Since all supported architectures have my_syscall6() now, remove the #ifdef check.
- Move the mmap() related macros to tools/include/nolibc/types.h and reuse most of them from <linux/mman.h>
- Apply the new generic __sysret() to convert the calling of sys_map() to oneline code
Note, since MAP_FAILED is -1 on Linux, so we can use the generic __sysret() which returns -1 upon error and still satisfy user land that checks for MAP_FAILED.
Suggested-by: Willy Tarreau w@1wt.eu Link: https://lore.kernel.org/lkml/20230702192347.GJ16233@1wt.eu/ Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/include/nolibc/sys.h | 29 ++++++----------------------- tools/include/nolibc/types.h | 6 ++++++ 2 files changed, 12 insertions(+), 23 deletions(-)
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 3479f54d7957..3d01a24e6f7a 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -636,26 +636,11 @@ int mknod(const char *path, mode_t mode, dev_t dev) return __sysret(sys_mknod(path, mode, dev)); }
-#ifndef MAP_SHARED -#define MAP_SHARED 0x01 /* Share changes */ -#define MAP_PRIVATE 0x02 /* Changes are private */ -#define MAP_SHARED_VALIDATE 0x03 /* share + validate extension flags */ -#endif - -#ifndef MAP_FAILED -#define MAP_FAILED ((void *)-1) -#endif - #ifndef sys_mmap static __attribute__((unused)) void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { -#ifndef my_syscall6 - /* Function not implemented. */ - return (void *)-ENOSYS; -#else - int n;
#if defined(__NR_mmap2) @@ -666,20 +651,18 @@ void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, #endif
return (void *)my_syscall6(n, addr, length, prot, flags, fd, offset); -#endif } #endif
+/* Note that on Linux, MAP_FAILED is -1 so we can use the generic __sysret() + * which returns -1 upon error and still satisfy user land that checks for + * MAP_FAILED. + */ + static __attribute__((unused)) void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { - void *ret = sys_mmap(addr, length, prot, flags, fd, offset); - - if ((unsigned long)ret >= -4095UL) { - SET_ERRNO(-(long)ret); - ret = MAP_FAILED; - } - return ret; + return (void *)__sysret((unsigned long)sys_mmap(addr, length, prot, flags, fd, offset)); }
static __attribute__((unused)) diff --git a/tools/include/nolibc/types.h b/tools/include/nolibc/types.h index f96e28bff4ba..5e1bac8509ec 100644 --- a/tools/include/nolibc/types.h +++ b/tools/include/nolibc/types.h @@ -8,6 +8,7 @@ #define _NOLIBC_TYPES_H
#include "std.h" +#include <linux/mman.h> #include <linux/time.h> #include <linux/stat.h>
@@ -81,6 +82,11 @@ #define MAXPATHLEN (PATH_MAX) #endif
+/* flags for mmap */ +#ifndef MAP_FAILED +#define MAP_FAILED ((void *)-1) +#endif + /* whence values for lseek() */ #define SEEK_SET 0 #define SEEK_CUR 1
Fix up the error reported by scripts/checkpatch.pl:
ERROR: do not use assignment in if condition #95: FILE: tools/include/nolibc/sys.h:95: + if ((ret = sys_brk(0)) && (sys_brk(ret + inc) == ret + inc))
Apply the new generic __sysret() to merge the SET_ERRNO() and return lines.
Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/include/nolibc/sys.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 3d01a24e6f7a..61a3204b00d7 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -89,14 +89,13 @@ int brk(void *addr) static __attribute__((unused)) void *sbrk(intptr_t inc) { - void *ret; - /* first call to find current end */ - if ((ret = sys_brk(0)) && (sys_brk(ret + inc) == ret + inc)) + void *ret = sys_brk(0); + + if (ret && sys_brk(ret + inc) == ret + inc) return ret + inc;
- SET_ERRNO(ENOMEM); - return (void *)-1; + return (void *)__sysret(-ENOMEM); }
argv0 is the path to nolibc-test program itself, which is a very good always existing readable file for some tests, let's export it.
Note, the path may be absolute or relative, please make sure the tests work with both of them. If it is relative, we must make sure the current path is the one specified by the PWD environment variable.
Suggested-by: Willy Tarreau w@1wt.eu Link: https://lore.kernel.org/lkml/ZKKbS3cwKcHgnGwu@1wt.eu/ Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/testing/selftests/nolibc/nolibc-test.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 486334981e60..88b840f86f52 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -43,6 +43,9 @@ /* will be used by nolibc by getenv() */ char **environ;
+/* will be used by some test cases as readable file, please don't write it */ +static const char *argv0; + /* definition of a series of tests */ struct test { const char *name; /* test name */ @@ -948,6 +951,7 @@ int main(int argc, char **argv, char **envp) int idx; char *test;
+ argv0 = argv[0]; environ = envp;
/* when called as init, it's possible that no console was opened, for
/dev/zero is commonly used to allocate anonymous memory, it is a very good file for tests, let's prepare it.
Suggested-by: Willy Tarreau w@1wt.eu Link: https://lore.kernel.org/lkml/20230702193306.GK16233@1wt.eu/ Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/testing/selftests/nolibc/nolibc-test.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 88b840f86f52..b759fb25d375 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -894,11 +894,13 @@ int prepare(void) */ if (stat("/dev/.", &stat_buf) == 0 || mkdir("/dev", 0755) == 0) { if (stat("/dev/console", &stat_buf) != 0 || - stat("/dev/null", &stat_buf) != 0) { + stat("/dev/null", &stat_buf) != 0 || + stat("/dev/zero", &stat_buf) != 0) { /* try devtmpfs first, otherwise fall back to manual creation */ if (mount("/dev", "/dev", "devtmpfs", 0, 0) != 0) { mknod("/dev/console", 0600 | S_IFCHR, makedev(5, 1)); mknod("/dev/null", 0666 | S_IFCHR, makedev(1, 3)); + mknod("/dev/zero", 0666 | S_IFCHR, makedev(1, 5)); } } }
The syscalls like sbrk() and mmap() return pointers, to test them, more pointer compare test macros are required, add them:
- EXPECT_PTREQ() expects two equal pointers. - EXPECT_PTRNE() expects two non-equal pointers. - EXPECT_PTRER() expects failure with a specified errno. - EXPECT_PTRER2() expects failure with one of two specified errnos.
Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/testing/selftests/nolibc/nolibc-test.c | 58 ++++++++++++++++++++ 1 file changed, 58 insertions(+)
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index b759fb25d375..8be675debf28 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -364,6 +364,64 @@ static int expect_ptrnz(const void *expr, int llen) return ret; }
+#define EXPECT_PTREQ(cond, expr, cmp) \ + do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_ptreq(expr, llen, cmp); } while (0) + +static int expect_ptreq(const void *expr, int llen, const void *cmp) +{ + int ret = 0; + + llen += printf(" = <%p> ", expr); + if (expr != cmp) { + ret = 1; + llen += pad_spc(llen, 64, "[FAIL]\n"); + } else { + llen += pad_spc(llen, 64, " [OK]\n"); + } + return ret; +} + +#define EXPECT_PTRNE(cond, expr, cmp) \ + do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_ptrne(expr, llen, cmp); } while (0) + +static int expect_ptrne(const void *expr, int llen, const void *cmp) +{ + int ret = 0; + + llen += printf(" = <%p> ", expr); + if (expr == cmp) { + ret = 1; + llen += pad_spc(llen, 64, "[FAIL]\n"); + } else { + llen += pad_spc(llen, 64, " [OK]\n"); + } + return ret; +} + +#define EXPECT_PTRER2(cond, expr, expret, experr1, experr2) \ + do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_ptrerr2(expr, expret, experr1, experr2, llen); } while (0) + +#define EXPECT_PTRER(cond, expr, expret, experr) \ + EXPECT_PTRER2(cond, expr, expret, experr, 0) + +static int expect_ptrerr2(const void *expr, const void *expret, int experr1, int experr2, int llen) +{ + int ret = 0; + int _errno = errno; + + llen += printf(" = <%p> %s ", expr, errorname(_errno)); + if (expr != expret || (_errno != experr1 && _errno != experr2)) { + ret = 1; + if (experr2 == 0) + llen += printf(" != (<%p> %s) ", expret, errorname(experr1)); + else + llen += printf(" != (<%p> %s %s) ", expret, errorname(experr1), errorname(experr2)); + llen += pad_spc(llen, 64, "[FAIL]\n"); + } else { + llen += pad_spc(llen, 64, " [OK]\n"); + } + return ret; +}
#define EXPECT_STRZR(cond, expr) \ do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_strzr(expr, llen); } while (0)
From musl 0.9.14 (to the latest version 1.2.3), both sbrk() and brk() have almost been disabled for they conflict with malloc, only sbrk(0) is still permitted as a way to get the current location of the program break, let's support such case.
EXPECT_PTRNE() is used to expect sbrk() always successfully getting the current break.
Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/testing/selftests/nolibc/nolibc-test.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 8be675debf28..fde1b3c51a4a 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -633,6 +633,7 @@ int run_syscall(int min, int max) CASE_TEST(kill_0); EXPECT_SYSZR(1, kill(getpid(), 0)); break; CASE_TEST(kill_CONT); EXPECT_SYSZR(1, kill(getpid(), 0)); break; CASE_TEST(kill_BADPID); EXPECT_SYSER(1, kill(INT_MAX, 0), -1, ESRCH); break; + CASE_TEST(sbrk_0); EXPECT_PTRNE(1, sbrk(0), (void *)-1); break; CASE_TEST(sbrk); if ((p1 = p2 = sbrk(4096)) != (void *)-1) p2 = sbrk(-4096); EXPECT_SYSZR(1, (p2 == (void *)-1) || p2 == p1); break; CASE_TEST(brk); EXPECT_SYSZR(1, brk(sbrk(0))); break; CASE_TEST(chdir_root); EXPECT_SYSZR(1, chdir("/")); break;
The length argument of mmap() must be greater than 0, passing a zero length argument expects failure with -EINVAL.
Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/testing/selftests/nolibc/nolibc-test.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index fde1b3c51a4a..4026772ed4c5 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -669,6 +669,7 @@ int run_syscall(int min, int max) CASE_TEST(lseek_m1); EXPECT_SYSER(1, lseek(-1, 0, SEEK_SET), -1, EBADF); break; CASE_TEST(lseek_0); EXPECT_SYSER(1, lseek(0, 0, SEEK_SET), -1, ESPIPE); break; CASE_TEST(mkdir_root); EXPECT_SYSER(1, mkdir("/", 0755), -1, EEXIST); break; + CASE_TEST(mmap_bad); EXPECT_PTRER(1, mmap(NULL, 0, PROT_READ, MAP_PRIVATE, 0, 0), MAP_FAILED, EINVAL); break; CASE_TEST(open_tty); EXPECT_SYSNE(1, tmp = open("/dev/null", 0), -1); if (tmp != -1) close(tmp); break; CASE_TEST(open_blah); EXPECT_SYSER(1, tmp = open("/proc/self/blah", 0), -1, ENOENT); if (tmp != -1) close(tmp); break; CASE_TEST(poll_null); EXPECT_SYSZR(1, poll(NULL, 0, 0)); break;
On Fri, Jul 07, 2023 at 11:05:49PM +0800, Zhangjin Wu wrote:
The length argument of mmap() must be greater than 0, passing a zero length argument expects failure with -EINVAL.
This one doesn't work for me on x86_64 kernel 5.15.112, qemu userland:
46 mmap_bad = <0x0> EEXIST != (<0xffffffffffffffff> EINVAL) [FAIL]
This EEXIST actually is the errno from the previous test. If I run the test natively it's OK:
$ ./nolibc-test syscall:46 Running test 'syscall' 46 mmap_bad = <0xffffffffffffffff> EINVAL [OK] Errors during this test: 0
I'll queue it anyway for now but it would be nice that we figure what's happening (even if we need to adjust or drop the test if it's a false positive) so that we don't get used to "ah this is a normal error".
Willy
Hi, Willy
On Fri, Jul 07, 2023 at 11:05:49PM +0800, Zhangjin Wu wrote:
The length argument of mmap() must be greater than 0, passing a zero length argument expects failure with -EINVAL.
This one doesn't work for me on x86_64 kernel 5.15.112, qemu userland:
46 mmap_bad = <0x0> EEXIST != (<0xffffffffffffffff> EINVAL) [FAIL]
Just rerun 'run-user' on x86_64 with kernel 5.11.0-41-generic, it is ok.
The failure is very interesting, and also rechecked the kernel mmap code:
unsigned long do_mmap(struct file *file, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long pgoff, unsigned long *populate, struct list_head *uf) { ... if (!len) return -EINVAL; ... }
$ git blame -L 1202,1202 mm/mmap.c e37609bb36f70 (Piotr Kwapulinski 2015-06-24 16:58:39 -0700 1202) if (!len)
$ git show e37609bb36f706c954e82e580e2e790e9d5caef8:Makefile VERSION = 4 PATCHLEVEL = 1 SUBLEVEL = 0 EXTRAVERSION =
So, the kernel side should be ok from v4.1?
For qemu-user, I have rechecked the following version:
$ qemu-x86_64 --version qemu-x86_64 version 4.2.1 (Debian 1:4.2-3ubuntu6.18)
$ qemu-x86_64 --version qemu-x86_64 version 7.0.0 (Debian 1:7.0+dfsg-7ubuntu2.6~backport20.04.202306190332~ubuntu20.04.1)
$ build/x86_64/pc/qemu/v8.0.2/qemu-x86_64 --version qemu-x86_64 version 8.0.2 (v8.0.2-dirty)
all of them work well, as a comparison, what's your qemu-user version?
This EEXIST actually is the errno from the previous test. If I run the test natively it's OK:
$ ./nolibc-test syscall:46 Running test 'syscall' 46 mmap_bad = <0xffffffffffffffff> EINVAL [OK] Errors during this test: 0
I'll queue it anyway for now but it would be nice that we figure what's happening (even if we need to adjust or drop the test if it's a false positive) so that we don't get used to "ah this is a normal error".
Yes, if there is a failure, we should figure out why. It is ok for me to remove this one or let's find another errno condition before we find the root cause of the reported failure.
Thanks, Zhangjin
Willy
Hi Zhangjin,
On Mon, Jul 10, 2023 at 02:33:22AM +0800, Zhangjin Wu wrote:
For qemu-user, I have rechecked the following version:
$ qemu-x86_64 --version qemu-x86_64 version 4.2.1 (Debian 1:4.2-3ubuntu6.18) $ qemu-x86_64 --version qemu-x86_64 version 7.0.0 (Debian 1:7.0+dfsg-7ubuntu2.6~backport20.04.202306190332~ubuntu20.04.1) $ build/x86_64/pc/qemu/v8.0.2/qemu-x86_64 --version qemu-x86_64 version 8.0.2 (v8.0.2-dirty)
all of them work well, as a comparison, what's your qemu-user version?
Spot on! I ran it remotely and had a different qemu in my default path:
$ qemu-x86_64 --version qemu-x86_64 version 2.7.0, Copyright (c) 2003-2016 Fabrice Bellard and the QEMU Project developers
I didn't notice but it yells at me during the test:
qemu: Unsupported syscall: 332
Locally with this version it's much cleaner:
$ qemu-x86_64 --version qemu-x86_64 version 6.2.0 Copyright (c) 2003-2021 Fabrice Bellard and the QEMU Project developers $ make run-user | grep status: 143 test(s): 141 passed, 2 skipped, 0 failed => status: warning
So we can keep it and blame my environment for that failure.
Thanks for checking, Willy
The addr argument of munmap() must be a multiple of the page size, passing invalid (void *)1 addr expects failure with -EINVAL.
Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/testing/selftests/nolibc/nolibc-test.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 4026772ed4c5..8644e415cb66 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -670,6 +670,7 @@ int run_syscall(int min, int max) CASE_TEST(lseek_0); EXPECT_SYSER(1, lseek(0, 0, SEEK_SET), -1, ESPIPE); break; CASE_TEST(mkdir_root); EXPECT_SYSER(1, mkdir("/", 0755), -1, EEXIST); break; CASE_TEST(mmap_bad); EXPECT_PTRER(1, mmap(NULL, 0, PROT_READ, MAP_PRIVATE, 0, 0), MAP_FAILED, EINVAL); break; + CASE_TEST(munmap_bad); EXPECT_SYSER(1, munmap((void *)1, 0), -1, EINVAL); break; CASE_TEST(open_tty); EXPECT_SYSNE(1, tmp = open("/dev/null", 0), -1); if (tmp != -1) close(tmp); break; CASE_TEST(open_blah); EXPECT_SYSER(1, tmp = open("/proc/self/blah", 0), -1, ENOENT); if (tmp != -1) close(tmp); break; CASE_TEST(poll_null); EXPECT_SYSZR(1, poll(NULL, 0, 0)); break;
mmap() a file with a good offset and then munmap() it. a non-zero offset is passed to test the 6th argument of my_syscall6().
Note, it is not easy to find a unique file for mmap() in different scenes, so, a file list is used to search the right one:
- /dev/zero: is commonly used to allocate anonymous memory and is likely present and readable
- /proc/1/exe: for 'run' and 'run-user' target, 'run-user' can not find '/proc/self/exe'
- /proc/self/exe: for 'libc-test' target, normal program 'libc-test' has no permission to access '/proc/1/exe'
- argv0: the path of the program itself, let it pass even with worst case scene: no procfs and no /dev/zero
Suggested-by: Willy Tarreau w@1wt.eu Link: https://lore.kernel.org/lkml/20230702193306.GK16233@1wt.eu/ Suggested-by: Thomas Weißschuh linux@weissschuh.net Link: https://lore.kernel.org/lkml/bff82ea6-610b-4471-a28b-6c76c28604a6@t-8ch.de/ Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/testing/selftests/nolibc/nolibc-test.c | 60 ++++++++++++++++++++ 1 file changed, 60 insertions(+)
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 8644e415cb66..a7191b637b85 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -595,6 +595,65 @@ static int test_stat_timestamps(void) return 0; }
+int test_mmap_munmap(void) +{ + int ret, fd, i; + void *mem; + size_t page_size, file_size, length; + off_t offset, pa_offset; + struct stat stat_buf; + const char * const files[] = { + "/dev/zero", + "/proc/1/exe", "/proc/self/exe", + argv0, + NULL + }; + + page_size = getpagesize(); + if (page_size < 0) + return -1; + + /* find a right file to mmap, existed and accessible */ + for (i = 0; files[i] != NULL; i++) { + ret = fd = open(files[i], O_RDONLY); + if (ret == -1) + continue; + else + break; + } + if (ret == -1) + return ret; + + ret = stat(files[i], &stat_buf); + if (ret == -1) + goto end; + + /* file size of the special /dev/zero is 0, let's assign one manually */ + if (i == 0) + file_size = 3*page_size; + else + file_size = stat_buf.st_size; + + offset = file_size - 1; + if (offset < 0) + offset = 0; + length = file_size - offset; + pa_offset = offset & ~(page_size - 1); + + mem = mmap(NULL, length + offset - pa_offset, PROT_READ, MAP_SHARED, fd, pa_offset); + if (mem == MAP_FAILED) { + ret = -1; + goto end; + } + + ret = munmap(mem, length + offset - pa_offset); + +end: + close(fd); + return ret; +} + + /* Run syscall tests between IDs <min> and <max>. * Return 0 on success, non-zero on failure. */ @@ -671,6 +730,7 @@ int run_syscall(int min, int max) CASE_TEST(mkdir_root); EXPECT_SYSER(1, mkdir("/", 0755), -1, EEXIST); break; CASE_TEST(mmap_bad); EXPECT_PTRER(1, mmap(NULL, 0, PROT_READ, MAP_PRIVATE, 0, 0), MAP_FAILED, EINVAL); break; CASE_TEST(munmap_bad); EXPECT_SYSER(1, munmap((void *)1, 0), -1, EINVAL); break; + CASE_TEST(mmap_munmap_good); EXPECT_SYSZR(1, test_mmap_munmap()); break; CASE_TEST(open_tty); EXPECT_SYSNE(1, tmp = open("/dev/null", 0), -1); if (tmp != -1) close(tmp); break; CASE_TEST(open_blah); EXPECT_SYSER(1, tmp = open("/proc/self/blah", 0), -1, ENOENT); if (tmp != -1) close(tmp); break; CASE_TEST(poll_null); EXPECT_SYSZR(1, poll(NULL, 0, 0)); break;
linux-kselftest-mirror@lists.linaro.org