Hi, Thomas, David, Willy
Thanks very much for your kindly review.
This is the revision of v3 "tools/nolibc: add a new syscall helper" [1], this mainly applies the suggestion from David in this reply [2] and rebased everything on the dev.2023.06.14a branch of linux-rcu [3].
The old __sysret() doesn't support the syscalls with pointer return value, this revision now supports such syscalls. The left mmap() syscall is converted to use this new __sysret() with additional test cases.
Changes from v3 -> v4:
* tools/nolibc: sys.h: add a syscall return helper tools/nolibc: unistd.h: apply __sysret() helper tools/nolibc: sys.h: apply __sysret() helper
The original v3 series, no code change, except the Reviewed-by lines from Thomas.
* tools/nolibc: unistd.h: reorder the syscall macros
reorder the syscall macros in using order and align most of them.
* tools/nolibc: add missing my_syscall6() for mips
required by mmap() syscall, this is the last missing my_syscall6().
* tools/nolibc: __sysret: support syscalls who return a pointer
Apply suggestion from David.
Let __sysret() also supports syscalls with pointer return value, so, the return value is converted to unsigned long and the comparing of < 0 is converted to the comparing of [(unsigned long)-MAX_ERRNO, (unsigned long)-1].
This also allows return a huge value (not pointer) with highest bit as 1.
It is able to merge this one to the first one if necessary.
* tools/nolibc: clean up mmap() support
Apply new __sysret(), clean up #ifdef and some macros.
* selftests/nolibc: add EXPECT_PTREQ, EXPECT_PTRNE and EXPECT_PTRER selftests/nolibc: add sbrk_0 to test current brk getting selftests/nolibc: add mmap and munmap test cases
Add some mmap & munmap test cases and the corresponding helpers, to verify one of the new helpers, a sbrk_0 test case is also added.
Best regards, Zhangjin --- [1]: https://lore.kernel.org/linux-riscv/87e7a391-b97b-4001-b12a-76d20790563e@t-8... [2]: https://lore.kernel.org/linux-riscv/94dd5170929f454fbc0a10a2eb3b108d@AcuMS.a... [3]: https://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git/
Zhangjin Wu (10): tools/nolibc: sys.h: add a syscall return helper tools/nolibc: unistd.h: apply __sysret() helper tools/nolibc: sys.h: apply __sysret() helper tools/nolibc: unistd.h: reorder the syscall macros tools/nolibc: add missing my_syscall6() for mips tools/nolibc: __sysret: support syscalls who return a pointer tools/nolibc: clean up mmap() support selftests/nolibc: add EXPECT_PTREQ, EXPECT_PTRNE and EXPECT_PTRER selftests/nolibc: add sbrk_0 to test current brk getting selftests/nolibc: add mmap and munmap test cases
tools/include/nolibc/arch-mips.h | 26 ++ tools/include/nolibc/nolibc.h | 9 +- tools/include/nolibc/sys.h | 391 +++---------------- tools/include/nolibc/types.h | 11 + tools/include/nolibc/unistd.h | 13 +- tools/testing/selftests/nolibc/nolibc-test.c | 90 +++++ 6 files changed, 191 insertions(+), 349 deletions(-)
Most of the library routines share the same syscall return logic:
In general, a 0 return value indicates success. A -1 return value indicates an error, and an error number is stored in errno. [1]
Let's add a __sysret() helper for the above logic to simplify the coding and shrink the code lines too.
Thomas suggested to use inline function instead of macro for __sysret().
Willy suggested to make __sysret() be always inline.
[1]: https://man7.org/linux/man-pages/man2/syscall.2.html
Suggested-by: Willy Tarreau w@1wt.eu Link: https://lore.kernel.org/linux-riscv/ZH1+hkhiA2+ItSvX@1wt.eu/ Suggested-by: Thomas Weißschuh linux@weissschuh.net Link: https://lore.kernel.org/linux-riscv/ea4e7442-7223-4211-ba29-70821e907888@t-8... Reviewed-by: Thomas Weißschuh linux@weissschuh.net Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/include/nolibc/sys.h | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 856249a11890..150777207468 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -28,6 +28,16 @@ #include "errno.h" #include "types.h"
+/* Syscall return helper, set errno as -ret when ret < 0 */ +static __inline__ __attribute__((unused, always_inline)) +long __sysret(long ret) +{ + if (ret < 0) { + SET_ERRNO(-ret); + ret = -1; + } + return ret; +}
/* Functions in this file only describe syscalls. They're declared static so * that the compiler usually decides to inline them while still being allowed
Use __sysret() to shrink the whole _syscall() to oneline code.
Reviewed-by: Thomas Weißschuh linux@weissschuh.net Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/include/nolibc/unistd.h | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-)
diff --git a/tools/include/nolibc/unistd.h b/tools/include/nolibc/unistd.h index 0e832e10a0b2..fabc846f797b 100644 --- a/tools/include/nolibc/unistd.h +++ b/tools/include/nolibc/unistd.h @@ -56,16 +56,7 @@ int tcsetpgrp(int fd, pid_t pid) return ioctl(fd, TIOCSPGRP, &pid); }
-#define _syscall(N, ...) \ -({ \ - long _ret = my_syscall##N(__VA_ARGS__); \ - if (_ret < 0) { \ - SET_ERRNO(-_ret); \ - _ret = -1; \ - } \ - _ret; \ -}) - +#define _syscall(N, ...) __sysret(my_syscall##N(__VA_ARGS__)) #define _syscall_narg(...) __syscall_narg(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) #define __syscall_narg(_0, _1, _2, _3, _4, _5, _6, N, ...) N #define _syscall_n(N, ...) _syscall(N, __VA_ARGS__)
Use __sysret() to shrink most of the library routines to oneline code.
Removed 266 lines of duplicated code.
Reviewed-by: Thomas Weißschuh linux@weissschuh.net Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/include/nolibc/sys.h | 354 +++++-------------------------------- 1 file changed, 44 insertions(+), 310 deletions(-)
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 150777207468..4fbefe5adf93 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -76,13 +76,7 @@ void *sys_brk(void *addr) static __attribute__((unused)) int brk(void *addr) { - void *ret = sys_brk(addr); - - if (!ret) { - SET_ERRNO(ENOMEM); - return -1; - } - return 0; + return __sysret(sys_brk(addr) ? 0 : -ENOMEM); }
static __attribute__((unused)) @@ -112,13 +106,7 @@ int sys_chdir(const char *path) static __attribute__((unused)) int chdir(const char *path) { - int ret = sys_chdir(path); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_chdir(path)); }
@@ -141,13 +129,7 @@ int sys_chmod(const char *path, mode_t mode) static __attribute__((unused)) int chmod(const char *path, mode_t mode) { - int ret = sys_chmod(path, mode); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_chmod(path, mode)); }
@@ -170,13 +152,7 @@ int sys_chown(const char *path, uid_t owner, gid_t group) static __attribute__((unused)) int chown(const char *path, uid_t owner, gid_t group) { - int ret = sys_chown(path, owner, group); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_chown(path, owner, group)); }
@@ -193,13 +169,7 @@ int sys_chroot(const char *path) static __attribute__((unused)) int chroot(const char *path) { - int ret = sys_chroot(path); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_chroot(path)); }
@@ -216,13 +186,7 @@ int sys_close(int fd) static __attribute__((unused)) int close(int fd) { - int ret = sys_close(fd); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_close(fd)); }
@@ -239,13 +203,7 @@ int sys_dup(int fd) static __attribute__((unused)) int dup(int fd) { - int ret = sys_dup(fd); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_dup(fd)); }
@@ -268,13 +226,7 @@ int sys_dup2(int old, int new) static __attribute__((unused)) int dup2(int old, int new) { - int ret = sys_dup2(old, new); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_dup2(old, new)); }
@@ -292,13 +244,7 @@ int sys_dup3(int old, int new, int flags) static __attribute__((unused)) int dup3(int old, int new, int flags) { - int ret = sys_dup3(old, new, flags); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_dup3(old, new, flags)); } #endif
@@ -316,13 +262,7 @@ int sys_execve(const char *filename, char *const argv[], char *const envp[]) static __attribute__((unused)) int execve(const char *filename, char *const argv[], char *const envp[]) { - int ret = sys_execve(filename, argv, envp); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_execve(filename, argv, envp)); }
@@ -369,13 +309,7 @@ pid_t sys_fork(void) static __attribute__((unused)) pid_t fork(void) { - pid_t ret = sys_fork(); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_fork()); }
@@ -392,13 +326,7 @@ int sys_fsync(int fd) static __attribute__((unused)) int fsync(int fd) { - int ret = sys_fsync(fd); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_fsync(fd)); }
@@ -415,13 +343,7 @@ int sys_getdents64(int fd, struct linux_dirent64 *dirp, int count) static __attribute__((unused)) int getdents64(int fd, struct linux_dirent64 *dirp, int count) { - int ret = sys_getdents64(fd, dirp, count); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_getdents64(fd, dirp, count)); }
@@ -459,13 +381,7 @@ pid_t sys_getpgid(pid_t pid) static __attribute__((unused)) pid_t getpgid(pid_t pid) { - pid_t ret = sys_getpgid(pid); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_getpgid(pid)); }
@@ -545,15 +461,7 @@ static unsigned long getauxval(unsigned long key); static __attribute__((unused)) long getpagesize(void) { - long ret; - - ret = getauxval(AT_PAGESZ); - if (!ret) { - SET_ERRNO(ENOENT); - return -1; - } - - return ret; + return __sysret(getauxval(AT_PAGESZ) ?: -ENOENT); }
@@ -570,13 +478,7 @@ int sys_gettimeofday(struct timeval *tv, struct timezone *tz) static __attribute__((unused)) int gettimeofday(struct timeval *tv, struct timezone *tz) { - int ret = sys_gettimeofday(tv, tz); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_gettimeofday(tv, tz)); }
@@ -614,13 +516,7 @@ int sys_ioctl(int fd, unsigned long req, void *value) static __attribute__((unused)) int ioctl(int fd, unsigned long req, void *value) { - int ret = sys_ioctl(fd, req, value); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_ioctl(fd, req, value)); }
/* @@ -636,13 +532,7 @@ int sys_kill(pid_t pid, int signal) static __attribute__((unused)) int kill(pid_t pid, int signal) { - int ret = sys_kill(pid, signal); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_kill(pid, signal)); }
@@ -665,13 +555,7 @@ int sys_link(const char *old, const char *new) static __attribute__((unused)) int link(const char *old, const char *new) { - int ret = sys_link(old, new); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_link(old, new)); }
@@ -688,13 +572,7 @@ off_t sys_lseek(int fd, off_t offset, int whence) static __attribute__((unused)) off_t lseek(int fd, off_t offset, int whence) { - off_t ret = sys_lseek(fd, offset, whence); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_lseek(fd, offset, whence)); }
@@ -717,13 +595,7 @@ int sys_mkdir(const char *path, mode_t mode) static __attribute__((unused)) int mkdir(const char *path, mode_t mode) { - int ret = sys_mkdir(path, mode); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_mkdir(path, mode)); }
@@ -746,13 +618,7 @@ long sys_mknod(const char *path, mode_t mode, dev_t dev) static __attribute__((unused)) int mknod(const char *path, mode_t mode, dev_t dev) { - int ret = sys_mknod(path, mode, dev); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_mknod(path, mode, dev)); }
#ifndef MAP_SHARED @@ -810,13 +676,7 @@ int sys_munmap(void *addr, size_t length) static __attribute__((unused)) int munmap(void *addr, size_t length) { - int ret = sys_munmap(addr, length); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_munmap(addr, length)); }
/* @@ -836,13 +696,7 @@ int mount(const char *src, const char *tgt, const char *fst, unsigned long flags, const void *data) { - int ret = sys_mount(src, tgt, fst, flags, data); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_mount(src, tgt, fst, flags, data)); }
@@ -876,13 +730,7 @@ int open(const char *path, int flags, ...) va_end(args); }
- ret = sys_open(path, flags, mode); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_open(path, flags, mode)); }
@@ -902,13 +750,7 @@ static __attribute__((unused)) int prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) { - int ret = sys_prctl(option, arg2, arg3, arg4, arg5); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_prctl(option, arg2, arg3, arg4, arg5)); }
@@ -925,13 +767,7 @@ int sys_pivot_root(const char *new, const char *old) static __attribute__((unused)) int pivot_root(const char *new, const char *old) { - int ret = sys_pivot_root(new, old); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_pivot_root(new, old)); }
@@ -960,13 +796,7 @@ int sys_poll(struct pollfd *fds, int nfds, int timeout) static __attribute__((unused)) int poll(struct pollfd *fds, int nfds, int timeout) { - int ret = sys_poll(fds, nfds, timeout); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_poll(fds, nfds, timeout)); }
@@ -983,13 +813,7 @@ ssize_t sys_read(int fd, void *buf, size_t count) static __attribute__((unused)) ssize_t read(int fd, void *buf, size_t count) { - ssize_t ret = sys_read(fd, buf, count); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_read(fd, buf, count)); }
@@ -1007,13 +831,7 @@ ssize_t sys_reboot(int magic1, int magic2, int cmd, void *arg) static __attribute__((unused)) int reboot(int cmd) { - int ret = sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, 0); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, 0)); }
@@ -1030,13 +848,7 @@ int sys_sched_yield(void) static __attribute__((unused)) int sched_yield(void) { - int ret = sys_sched_yield(); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_sched_yield()); }
@@ -1076,13 +888,7 @@ int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeva static __attribute__((unused)) int select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout) { - int ret = sys_select(nfds, rfds, wfds, efds, timeout); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_select(nfds, rfds, wfds, efds, timeout)); }
@@ -1099,13 +905,7 @@ int sys_setpgid(pid_t pid, pid_t pgid) static __attribute__((unused)) int setpgid(pid_t pid, pid_t pgid) { - int ret = sys_setpgid(pid, pgid); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_setpgid(pid, pgid)); }
@@ -1122,13 +922,7 @@ pid_t sys_setsid(void) static __attribute__((unused)) pid_t setsid(void) { - pid_t ret = sys_setsid(); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_setsid()); }
#if defined(__NR_statx) @@ -1145,13 +939,7 @@ int sys_statx(int fd, const char *path, int flags, unsigned int mask, struct sta static __attribute__((unused)) int statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf) { - int ret = sys_statx(fd, path, flags, mask, buf); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_statx(fd, path, flags, mask, buf)); } #endif
@@ -1231,13 +1019,7 @@ int sys_stat(const char *path, struct stat *buf) static __attribute__((unused)) int stat(const char *path, struct stat *buf) { - int ret = sys_stat(path, buf); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_stat(path, buf)); }
@@ -1260,13 +1042,7 @@ int sys_symlink(const char *old, const char *new) static __attribute__((unused)) int symlink(const char *old, const char *new) { - int ret = sys_symlink(old, new); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_symlink(old, new)); }
@@ -1300,13 +1076,7 @@ int sys_umount2(const char *path, int flags) static __attribute__((unused)) int umount2(const char *path, int flags) { - int ret = sys_umount2(path, flags); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_umount2(path, flags)); }
@@ -1329,13 +1099,7 @@ int sys_unlink(const char *path) static __attribute__((unused)) int unlink(const char *path) { - int ret = sys_unlink(path); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_unlink(path)); }
@@ -1354,38 +1118,20 @@ pid_t sys_wait4(pid_t pid, int *status, int options, struct rusage *rusage) static __attribute__((unused)) pid_t wait(int *status) { - pid_t ret = sys_wait4(-1, status, 0, NULL); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_wait4(-1, status, 0, NULL)); }
static __attribute__((unused)) pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage) { - pid_t ret = sys_wait4(pid, status, options, rusage); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_wait4(pid, status, options, rusage)); }
static __attribute__((unused)) pid_t waitpid(pid_t pid, int *status, int options) { - pid_t ret = sys_wait4(pid, status, options, NULL); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_wait4(pid, status, options, NULL)); }
@@ -1402,13 +1148,7 @@ ssize_t sys_write(int fd, const void *buf, size_t count) static __attribute__((unused)) ssize_t write(int fd, const void *buf, size_t count) { - ssize_t ret = sys_write(fd, buf, count); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_write(fd, buf, count)); }
@@ -1425,13 +1165,7 @@ int sys_memfd_create(const char *name, unsigned int flags) static __attribute__((unused)) int memfd_create(const char *name, unsigned int flags) { - ssize_t ret = sys_memfd_create(name, flags); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_memfd_create(name, flags)); }
/* make sure to include all global symbols */
Tune the macros in the using order and align most of them.
Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/include/nolibc/unistd.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tools/include/nolibc/unistd.h b/tools/include/nolibc/unistd.h index fabc846f797b..e38f3660c051 100644 --- a/tools/include/nolibc/unistd.h +++ b/tools/include/nolibc/unistd.h @@ -56,9 +56,9 @@ int tcsetpgrp(int fd, pid_t pid) return ioctl(fd, TIOCSPGRP, &pid); }
-#define _syscall(N, ...) __sysret(my_syscall##N(__VA_ARGS__)) -#define _syscall_narg(...) __syscall_narg(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) #define __syscall_narg(_0, _1, _2, _3, _4, _5, _6, N, ...) N +#define _syscall_narg(...) __syscall_narg(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) +#define _syscall(N, ...) __sysret(my_syscall##N(__VA_ARGS__)) #define _syscall_n(N, ...) _syscall(N, __VA_ARGS__) #define syscall(...) _syscall_n(_syscall_narg(__VA_ARGS__), ##__VA_ARGS__)
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 | 26 ++++++++++++++++++++++++++ tools/include/nolibc/nolibc.h | 9 ++++----- 2 files changed, 30 insertions(+), 5 deletions(-)
diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h index db24e0837a39..48dd42b4abc3 100644 --- a/tools/include/nolibc/arch-mips.h +++ b/tools/include/nolibc/arch-mips.h @@ -178,6 +178,32 @@ 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) \ + : "memory", "cc", "at", "v1", "hi", "lo", \ + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + ); \ + _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()
To support syscalls (e.g. mmap()) who return a pointer and to allow the pointer as big as possible, we should convert the negated errno value to unsigned long (uintptr_t), otherwise, in signed long, a potential big pointer (whose highest bit is 1) will be treated as a failure.
tools/include/nolibc/errno.h defines the MAX_ERRNO, let's use it directly. after converting to unsigned long, the negative errno value from -1 to -MAX_ERRNO becomes something like '~1 + 1' (every bit is 1) to '~MAX_ERRNO + 1', '~1 + 1' is the biggest, '~MAX_ERRNO + 1' is the smallest, so, the check becomes:
if (ret <= (unsigned long)-1 && ret >= (unsigned long)-MAX_ERRNO) { ... }
Since (unsigned long)-1 is the biggest unsigned long value, it is always true if bigger than (unsigned long)-MAX_ERRNO, so, just reserve the following check is enough:
if (ret >= (unsigned long)-MAX_ERRNO) { ... }
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 | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 4fbefe5adf93..8a6e16472d54 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -28,13 +28,16 @@ #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 in [-MAX_ERRNO, -1] + */ 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; }
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
- Apply the new __sysret() to convert the calling of sys_map() to oneline code
Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/include/nolibc/sys.h | 24 +----------------------- tools/include/nolibc/types.h | 11 +++++++++++ 2 files changed, 12 insertions(+), 23 deletions(-)
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 8a6e16472d54..1c02cec3bcd9 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -624,26 +624,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) @@ -654,20 +639,13 @@ 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
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..f889d4e0ac7e 100644 --- a/tools/include/nolibc/types.h +++ b/tools/include/nolibc/types.h @@ -81,6 +81,17 @@ #define MAXPATHLEN (PATH_MAX) #endif
+/* flags for mmap */ +#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 + /* whence values for lseek() */ #define SEEK_SET 0 #define SEEK_CUR 1
On 2023-06-19 23:51:20+0800, Zhangjin Wu wrote:
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
Apply the new __sysret() to convert the calling of sys_map() to oneline code
Signed-off-by: Zhangjin Wu falcon@tinylab.org
tools/include/nolibc/sys.h | 24 +----------------------- tools/include/nolibc/types.h | 11 +++++++++++ 2 files changed, 12 insertions(+), 23 deletions(-)
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 8a6e16472d54..1c02cec3bcd9 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -624,26 +624,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)
This could return a plain integer type instead to save some casts. Not sure if API compatibility is guaranteed for the raw sys_ functions.
{ -#ifndef my_syscall6
- /* Function not implemented. */
- return (void *)-ENOSYS;
-#else
- int n;
#if defined(__NR_mmap2) @@ -654,20 +639,13 @@ 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 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..f889d4e0ac7e 100644 --- a/tools/include/nolibc/types.h +++ b/tools/include/nolibc/types.h @@ -81,6 +81,17 @@ #define MAXPATHLEN (PATH_MAX) #endif +/* flags for mmap */ +#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
/* whence values for lseek() */ #define SEEK_SET 0
#define SEEK_CUR 1
2.25.1
Hi, Thomas
On 2023-06-19 23:51:20+0800, Zhangjin Wu wrote:
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
Apply the new __sysret() to convert the calling of sys_map() to oneline code
Signed-off-by: Zhangjin Wu falcon@tinylab.org
tools/include/nolibc/sys.h | 24 +----------------------- tools/include/nolibc/types.h | 11 +++++++++++ 2 files changed, 12 insertions(+), 23 deletions(-)
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 8a6e16472d54..1c02cec3bcd9 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -624,26 +624,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)
This could return a plain integer type instead to save some casts. Not sure if API compatibility is guaranteed for the raw sys_ functions.
Seems musl simply not provide the sys_xxx() functions, but let the library routines call __syscall() directly. If we can treat these sys_xxx() as internal functions, perhaps we can simply let the return type of sys_xxx() as 'long' to.
$ grep "^void *sys_" -ur tools/include/nolibc/sys.h void *sys_brk(void *addr) void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd,
Thanks, Zhangjin
{ -#ifndef my_syscall6
- /* Function not implemented. */
- return (void *)-ENOSYS;
-#else
- int n;
#if defined(__NR_mmap2) @@ -654,20 +639,13 @@ 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 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..f889d4e0ac7e 100644 --- a/tools/include/nolibc/types.h +++ b/tools/include/nolibc/types.h @@ -81,6 +81,17 @@ #define MAXPATHLEN (PATH_MAX) #endif +/* flags for mmap */ +#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
/* whence values for lseek() */ #define SEEK_SET 0
#define SEEK_CUR 1
2.25.1
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 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 486334981e60..34af802dadfd 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -361,6 +361,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 brk, let's support such case.
EXPECT_PTRNE() is used to expect sbrk() always successfully getting the current brk.
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 34af802dadfd..80ab29e2887c 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -630,6 +630,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;
Three mmap/munmap related test cases are added:
- mmap(NULL, 0, PROT_READ, MAP_PRIVATE, 0, 0), MAP_FAILED, EINVAL)
The length argument must be greater than 0, otherwise, fail with -EINVAL.
- munmap((void *)-1, 4*1024), -1, EINVAL)
Invalid (void *)-1 address fail with -EINVAL.
- test_mmap_munmap(4*1024)
It finds a init file, mmap() it and then munmap().
Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/testing/selftests/nolibc/nolibc-test.c | 31 ++++++++++++++++++++ 1 file changed, 31 insertions(+)
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 80ab29e2887c..f7c0ca72cb28 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -592,6 +592,34 @@ static int test_stat_timestamps(void) return 0; }
+int test_mmap_munmap(int size) +{ + char init_files[5][20] = {"/init", "/sbin/init", "/etc/init", "/bin/init", "/bin/sh"}; + int ret, fd, i; + void *mem; + + for (i = 0; i < 5; i++) { + ret = fd = open(init_files[i], O_RDONLY); + if (ret < 0) + continue; + else + break; + } + if (ret < 0) + return ret; + + mem = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + return -1; + + ret = munmap(mem, size); + if (ret < 0) + return ret; + + return close(fd); +} + + /* Run syscall tests between IDs <min> and <max>. * Return 0 on success, non-zero on failure. */ @@ -666,6 +694,9 @@ 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(munmap_bad); EXPECT_SYSER(1, munmap((void *)-1, 0), -1, EINVAL); break; + CASE_TEST(mmap_good); EXPECT_SYSZR(1, test_mmap_munmap(4*1024)); 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;
Hi,
Three mmap/munmap related test cases are added:
mmap(NULL, 0, PROT_READ, MAP_PRIVATE, 0, 0), MAP_FAILED, EINVAL)
The length argument must be greater than 0, otherwise, fail with -EINVAL.
munmap((void *)-1, 4*1024), -1, EINVAL)
Sorry, this message doesn't match the code, will change it in new revison.
Invalid (void *)-1 address fail with -EINVAL.
test_mmap_munmap(4*1024)
It finds a init file, mmap() it and then munmap().
Signed-off-by: Zhangjin Wu falcon@tinylab.org
tools/testing/selftests/nolibc/nolibc-test.c | 31 ++++++++++++++++++++ 1 file changed, 31 insertions(+)
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 80ab29e2887c..f7c0ca72cb28 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -592,6 +592,34 @@ static int test_stat_timestamps(void) return 0; } +int test_mmap_munmap(int size) +{
- char init_files[5][20] = {"/init", "/sbin/init", "/etc/init", "/bin/init", "/bin/sh"};
- int ret, fd, i;
- void *mem;
- for (i = 0; i < 5; i++) {
ret = fd = open(init_files[i], O_RDONLY);
if (ret < 0)
continue;
else
break;
- }
- if (ret < 0)
return ret;
- mem = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
- if (mem == MAP_FAILED)
return -1;
And here need a close(fd):
if (mem == MAP_FAILED) { close(fd); return -1; }
- ret = munmap(mem, size);
- if (ret < 0)
return ret;
And here too:
if (ret < 0) { close(fd); return ret; }
- return close(fd);
close(fd); return 0;
Thanks, Zhangjin
+}
/* Run syscall tests between IDs <min> and <max>.
- Return 0 on success, non-zero on failure.
*/ @@ -666,6 +694,9 @@ 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(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;CASE_TEST(mmap_good); EXPECT_SYSZR(1, test_mmap_munmap(4*1024)); break;
-- 2.25.1
On 2023-06-19 23:55:41+0800, Zhangjin Wu wrote:
Three mmap/munmap related test cases are added:
mmap(NULL, 0, PROT_READ, MAP_PRIVATE, 0, 0), MAP_FAILED, EINVAL)
The length argument must be greater than 0, otherwise, fail with -EINVAL.
munmap((void *)-1, 4*1024), -1, EINVAL)
Invalid (void *)-1 address fail with -EINVAL.
test_mmap_munmap(4*1024)
It finds a init file, mmap() it and then munmap().
Signed-off-by: Zhangjin Wu falcon@tinylab.org
tools/testing/selftests/nolibc/nolibc-test.c | 31 ++++++++++++++++++++ 1 file changed, 31 insertions(+)
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 80ab29e2887c..f7c0ca72cb28 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -592,6 +592,34 @@ static int test_stat_timestamps(void) return 0; } +int test_mmap_munmap(int size) +{
- char init_files[5][20] = {"/init", "/sbin/init", "/etc/init", "/bin/init", "/bin/sh"};
Why not /proc/1/exe or even /proc/self/exe?
I know your other series tries to remove the procfs dependency, but we're not there yet :-).
Also does it make sense to pass a size parameter? Why not use either PAGE_SIZE or the real size of the binary from fstat().
- int ret, fd, i;
- void *mem;
- for (i = 0; i < 5; i++) {
ret = fd = open(init_files[i], O_RDONLY);
if (ret < 0)
continue;
else
break;
- }
- if (ret < 0)
return ret;
- mem = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
- if (mem == MAP_FAILED)
return -1;
- ret = munmap(mem, size);
- if (ret < 0)
return ret;
- return close(fd);
+}
/* Run syscall tests between IDs <min> and <max>.
- Return 0 on success, non-zero on failure.
*/ @@ -666,6 +694,9 @@ 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(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;CASE_TEST(mmap_good); EXPECT_SYSZR(1, test_mmap_munmap(4*1024)); break;
-- 2.25.1
Hi, Thomas
On 2023-06-19 23:55:41+0800, Zhangjin Wu wrote:
Three mmap/munmap related test cases are added:
mmap(NULL, 0, PROT_READ, MAP_PRIVATE, 0, 0), MAP_FAILED, EINVAL)
The length argument must be greater than 0, otherwise, fail with -EINVAL.
munmap((void *)-1, 4*1024), -1, EINVAL)
Invalid (void *)-1 address fail with -EINVAL.
test_mmap_munmap(4*1024)
It finds a init file, mmap() it and then munmap().
Signed-off-by: Zhangjin Wu falcon@tinylab.org
tools/testing/selftests/nolibc/nolibc-test.c | 31 ++++++++++++++++++++ 1 file changed, 31 insertions(+)
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 80ab29e2887c..f7c0ca72cb28 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -592,6 +592,34 @@ static int test_stat_timestamps(void) return 0; } +int test_mmap_munmap(int size) +{
- char init_files[5][20] = {"/init", "/sbin/init", "/etc/init", "/bin/init", "/bin/sh"};
Why not /proc/1/exe or even /proc/self/exe?
I know your other series tries to remove the procfs dependency, but we're not there yet :-).
Yeah, '/proc/self/exe' is a choice, if so, the 'has_proc' should be added ;-)
Also does it make sense to pass a size parameter? Why not use either PAGE_SIZE or the real size of the binary from fstat().
Ok, as the manpage of mmap shows:
For mmap(), offset must be a multiple of the underlying huge page size. The system automatically aligns length to be a multiple of the underlying huge page size.
For munmap(), addr, and length must both be a multiple of the underlying huge page size.
perhaps we should do further tests:
* the real size/length * even > the real size * the PAGE_SIZE * not aligned with PAGE_SIZE
If such tests are required, the 'size' and even 'offset' arguments could be provided to cover different combination or we do such tests internally, then, the arguments are not required.
Thanks, Zhangjin
- int ret, fd, i;
- void *mem;
- for (i = 0; i < 5; i++) {
ret = fd = open(init_files[i], O_RDONLY);
if (ret < 0)
continue;
else
break;
- }
- if (ret < 0)
return ret;
- mem = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
- if (mem == MAP_FAILED)
return -1;
- ret = munmap(mem, size);
- if (ret < 0)
return ret;
- return close(fd);
+}
/* Run syscall tests between IDs <min> and <max>.
- Return 0 on success, non-zero on failure.
*/ @@ -666,6 +694,9 @@ 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(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;CASE_TEST(mmap_good); EXPECT_SYSZR(1, test_mmap_munmap(4*1024)); break;
-- 2.25.1
Hi Zhangjin,
On 2023-06-23 03:32:49+0800, Zhangjin Wu wrote:
On 2023-06-19 23:55:41+0800, Zhangjin Wu wrote:
Three mmap/munmap related test cases are added:
mmap(NULL, 0, PROT_READ, MAP_PRIVATE, 0, 0), MAP_FAILED, EINVAL)
The length argument must be greater than 0, otherwise, fail with -EINVAL.
munmap((void *)-1, 4*1024), -1, EINVAL)
Invalid (void *)-1 address fail with -EINVAL.
test_mmap_munmap(4*1024)
It finds a init file, mmap() it and then munmap().
Signed-off-by: Zhangjin Wu falcon@tinylab.org
tools/testing/selftests/nolibc/nolibc-test.c | 31 ++++++++++++++++++++ 1 file changed, 31 insertions(+)
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 80ab29e2887c..f7c0ca72cb28 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -592,6 +592,34 @@ static int test_stat_timestamps(void) return 0; } +int test_mmap_munmap(int size) +{
- char init_files[5][20] = {"/init", "/sbin/init", "/etc/init", "/bin/init", "/bin/sh"};
Why not /proc/1/exe or even /proc/self/exe?
I know your other series tries to remove the procfs dependency, but we're not there yet :-).
Yeah, '/proc/self/exe' is a choice, if so, the 'has_proc' should be added ;-)
Currently procfs is a hard requirement. So I would leave 'has_proc' to the other series that may change this.
Also does it make sense to pass a size parameter? Why not use either PAGE_SIZE or the real size of the binary from fstat().
Ok, as the manpage of mmap shows:
For mmap(), offset must be a multiple of the underlying huge page size. The system automatically aligns length to be a multiple of the underlying huge page size. For munmap(), addr, and length must both be a multiple of the underlying huge page size.
perhaps we should do further tests:
- the real size/length
- even > the real size
- the PAGE_SIZE
- not aligned with PAGE_SIZE
If such tests are required, the 'size' and even 'offset' arguments could be provided to cover different combination or we do such tests internally, then, the arguments are not required.
I think task of nolibc-test is to test the code in nolibc itself. The custom mmap implementation is trivial and directly calls the syscall. These additionally proposed tests would effectively test the core kernels implementation of mmap() and not the code of nolibc.
Therefore I don't think they are necessary in nolibc-test and the functionality is hopefully already be tested in another testsuite.
Note:
Testing mmap is indeed useful to test the implementation of my_syscall6() by providing a bogus value in the 'offset' parameter. I think we do have such a testcase.
<snip>
Thomas
Hi, Thomas
Hi Zhangjin,
On 2023-06-23 03:32:49+0800, Zhangjin Wu wrote:
On 2023-06-19 23:55:41+0800, Zhangjin Wu wrote:
Three mmap/munmap related test cases are added:
(snipped)
+int test_mmap_munmap(int size) +{
- char init_files[5][20] = {"/init", "/sbin/init", "/etc/init", "/bin/init", "/bin/sh"};
Why not /proc/1/exe or even /proc/self/exe?
I know your other series tries to remove the procfs dependency, but we're not there yet :-).
Yeah, '/proc/self/exe' is a choice, if so, the 'has_proc' should be added ;-)
Currently procfs is a hard requirement. So I would leave 'has_proc' to the other series that may change this.
Yeah, but to be consistent with the already existing 'proc' condition check, 'proc' will be used at first ;-)
$ grep '(proc,' -ur tools/testing/selftests/nolibc/nolibc-test.c CASE_TEST(chmod_net); EXPECT_SYSZR(proc, chmod("/proc/self/net", 0555)); break; CASE_TEST(chmod_self); EXPECT_SYSER(proc, chmod("/proc/self", 0555), -1, EPERM); break; CASE_TEST(chown_self); EXPECT_SYSER(proc, chown("/proc/self", 0, 0), -1, EPERM); break; CASE_TEST(chroot_exe); EXPECT_SYSER(proc, chroot("/proc/self/exe"), -1, ENOTDIR); break; CASE_TEST(link_cross); EXPECT_SYSER(proc, link("/proc/self/net", "/blah"), -1, EXDEV); break;
Btw, for the /proc/self used in test_stat_timestamps, in the revision of the 'minimal' config support series, instead of using '/', a 'proc' should be added like above test cases.
Also does it make sense to pass a size parameter? Why not use either PAGE_SIZE or the real size of the binary from fstat().
Ok, as the manpage of mmap shows:
For mmap(), offset must be a multiple of the underlying huge page size. The system automatically aligns length to be a multiple of the underlying huge page size. For munmap(), addr, and length must both be a multiple of the underlying huge page size.
perhaps we should do further tests:
- the real size/length
- even > the real size
- the PAGE_SIZE
- not aligned with PAGE_SIZE
If such tests are required, the 'size' and even 'offset' arguments could be provided to cover different combination or we do such tests internally, then, the arguments are not required.
I think task of nolibc-test is to test the code in nolibc itself. The custom mmap implementation is trivial and directly calls the syscall. These additionally proposed tests would effectively test the core kernels implementation of mmap() and not the code of nolibc.
Therefore I don't think they are necessary in nolibc-test and the functionality is hopefully already be tested in another testsuite.
Ok, it is reasonable.
Note:
Testing mmap is indeed useful to test the implementation of my_syscall6() by providing a bogus value in the 'offset' parameter. I think we do have such a testcase.
Ok, we can pass a valid offset (n*PAGE_SIZE) to mmap() in test_mmap_munmap() or add a whole new mmap_offset test case with a PAGE_SIZE not aligned offset (such as 1).
Thanks, Zhangjin
<snip>
Thomas
Willy, Thomas
This is the revision of our 'tools/nolibc: add a new syscall helper' series [1].
It mainly applies the core part of suggestions from Thomas (Many thanks) and cleans up the multiple whitespaces issues reported by scripts/checkpatch.pl.
Changes from v4 --> v5:
* tools/nolibc: sys.h: add a syscall return helper tools/nolibc: unistd.h: apply __sysret() helper tools/nolibc: sys.h: apply __sysret() helper tools/nolibc: unistd.h: reorder the syscall macros tools/nolibc: __sysret: support syscalls who return a pointer selftests/nolibc: add EXPECT_PTREQ, EXPECT_PTRNE and EXPECT_PTRER selftests/nolibc: add sbrk_0 to test current brk getting
The same to original v4 series, no code change.
* tools/nolibc: string.h: clean up multiple whitespaces with tab tools/nolibc: arch-*.h: clean up multiple whitespaces tools/nolibc: arch-loongarch.h: shrink with SYSCALL_CLOBBERLIST tools/nolibc: arch-mips.h: shrink with SYSCALL_CLOBBERLIST
Clean up the multiple whitespaces issues reported by scripts/checkpatch.pl, prepare for the coming mips my_syscall6()
This cleanup is also required by another new arch shrink patchset.
In v4, we didn't touch multiple whitespaces, because the changes are huge, but it is really important to do this before being always 'complained' by scripts/checkpatch.pl in the future.
* tools/nolibc: add missing my_syscall6() for mips
Use tab instead of multiple whitespaces, let scripts/checkpatch.pl happy, also apply SYSCALL_CLOBBERLIST
* tools/nolibc: clean up mmap() support
Include <linux/mman.h> and remove more macros from nolibc side.
The return type of sys_mmap() is reserved as before, not changed currently.
* selftests/nolibc: add mmap and munmap test cases
Applies some suggestions from Thomas,
- Rebase length and offset on page_size and file_size
- make sure the last offset argument is not always zero to test my_syscall6()
- easier the for loop with NULL check
- use /proc/1/exe and /proc/self/exe for run, run-user and libc-test
but still reserve the old init files to align our another attempt to remove the unnecessary dependency on procfs (this is important to let developers happy to do all-architectures-test, the accumulated time cost and wait is really appreciable, it is really a pain for me to do repeated all-architectures-test for the new 'minimal' kernel config patchset [2], a v2 is ready for it).
Best regards, Zhangjin --- [1]: https://lore.kernel.org/lkml/cover.1687187451.git.falcon@tinylab.org/ [2]: https://lore.kernel.org/lkml/cover.1687706332.git.falcon@tinylab.org/
Zhangjin Wu (14): tools/nolibc: sys.h: add a syscall return helper tools/nolibc: unistd.h: apply __sysret() helper tools/nolibc: sys.h: apply __sysret() helper tools/nolibc: unistd.h: reorder the syscall macros tools/nolibc: string.h: clean up multiple whitespaces with tab tools/nolibc: arch-*.h: clean up multiple whitespaces tools/nolibc: arch-loongarch.h: shrink with SYSCALL_CLOBBERLIST tools/nolibc: arch-mips.h: shrink with SYSCALL_CLOBBERLIST tools/nolibc: add missing my_syscall6() for mips tools/nolibc: __sysret: support syscalls who return a pointer tools/nolibc: clean up mmap() support selftests/nolibc: add EXPECT_PTREQ, EXPECT_PTRNE and EXPECT_PTRER selftests/nolibc: add sbrk_0 to test current brk getting selftests/nolibc: add mmap and munmap test cases
tools/include/nolibc/arch-aarch64.h | 210 +++++----- tools/include/nolibc/arch-arm.h | 240 ++++++------ tools/include/nolibc/arch-i386.h | 226 +++++------ tools/include/nolibc/arch-loongarch.h | 219 +++++------ tools/include/nolibc/arch-mips.h | 241 ++++++------ tools/include/nolibc/arch-riscv.h | 208 +++++----- tools/include/nolibc/arch-s390.h | 202 +++++----- tools/include/nolibc/arch-x86_64.h | 222 +++++------ tools/include/nolibc/nolibc.h | 9 +- tools/include/nolibc/string.h | 8 +- tools/include/nolibc/sys.h | 391 +++---------------- tools/include/nolibc/types.h | 6 + tools/include/nolibc/unistd.h | 13 +- tools/testing/selftests/nolibc/nolibc-test.c | 115 ++++++ 14 files changed, 1083 insertions(+), 1227 deletions(-)
Most of the library routines share the same syscall return logic:
In general, a 0 return value indicates success. A -1 return value indicates an error, and an error number is stored in errno. [1]
Let's add a __sysret() helper for the above logic to simplify the coding and shrink the code lines too.
Thomas suggested to use inline function instead of macro for __sysret().
Willy suggested to make __sysret() be always inline.
[1]: https://man7.org/linux/man-pages/man2/syscall.2.html
Suggested-by: Willy Tarreau w@1wt.eu Link: https://lore.kernel.org/linux-riscv/ZH1+hkhiA2+ItSvX@1wt.eu/ Suggested-by: Thomas Weißschuh linux@weissschuh.net Link: https://lore.kernel.org/linux-riscv/ea4e7442-7223-4211-ba29-70821e907888@t-8... Reviewed-by: Thomas Weißschuh linux@weissschuh.net Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/include/nolibc/sys.h | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 5464f93e863e..097eef88cf7e 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -28,6 +28,16 @@ #include "errno.h" #include "types.h"
+/* Syscall return helper, set errno as -ret when ret < 0 */ +static __inline__ __attribute__((unused, always_inline)) +long __sysret(long ret) +{ + if (ret < 0) { + SET_ERRNO(-ret); + ret = -1; + } + return ret; +}
/* Functions in this file only describe syscalls. They're declared static so * that the compiler usually decides to inline them while still being allowed
Use __sysret() to shrink the whole _syscall() to oneline code.
Reviewed-by: Thomas Weißschuh linux@weissschuh.net Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/include/nolibc/unistd.h | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-)
diff --git a/tools/include/nolibc/unistd.h b/tools/include/nolibc/unistd.h index 0e832e10a0b2..fabc846f797b 100644 --- a/tools/include/nolibc/unistd.h +++ b/tools/include/nolibc/unistd.h @@ -56,16 +56,7 @@ int tcsetpgrp(int fd, pid_t pid) return ioctl(fd, TIOCSPGRP, &pid); }
-#define _syscall(N, ...) \ -({ \ - long _ret = my_syscall##N(__VA_ARGS__); \ - if (_ret < 0) { \ - SET_ERRNO(-_ret); \ - _ret = -1; \ - } \ - _ret; \ -}) - +#define _syscall(N, ...) __sysret(my_syscall##N(__VA_ARGS__)) #define _syscall_narg(...) __syscall_narg(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) #define __syscall_narg(_0, _1, _2, _3, _4, _5, _6, N, ...) N #define _syscall_n(N, ...) _syscall(N, __VA_ARGS__)
Use __sysret() to shrink most of the library routines to oneline code.
Removed 266 lines of duplicated code.
Reviewed-by: Thomas Weißschuh linux@weissschuh.net Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/include/nolibc/sys.h | 354 +++++-------------------------------- 1 file changed, 44 insertions(+), 310 deletions(-)
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 097eef88cf7e..53bc3ad6593e 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -76,13 +76,7 @@ void *sys_brk(void *addr) static __attribute__((unused)) int brk(void *addr) { - void *ret = sys_brk(addr); - - if (!ret) { - SET_ERRNO(ENOMEM); - return -1; - } - return 0; + return __sysret(sys_brk(addr) ? 0 : -ENOMEM); }
static __attribute__((unused)) @@ -112,13 +106,7 @@ int sys_chdir(const char *path) static __attribute__((unused)) int chdir(const char *path) { - int ret = sys_chdir(path); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_chdir(path)); }
@@ -141,13 +129,7 @@ int sys_chmod(const char *path, mode_t mode) static __attribute__((unused)) int chmod(const char *path, mode_t mode) { - int ret = sys_chmod(path, mode); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_chmod(path, mode)); }
@@ -170,13 +152,7 @@ int sys_chown(const char *path, uid_t owner, gid_t group) static __attribute__((unused)) int chown(const char *path, uid_t owner, gid_t group) { - int ret = sys_chown(path, owner, group); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_chown(path, owner, group)); }
@@ -193,13 +169,7 @@ int sys_chroot(const char *path) static __attribute__((unused)) int chroot(const char *path) { - int ret = sys_chroot(path); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_chroot(path)); }
@@ -216,13 +186,7 @@ int sys_close(int fd) static __attribute__((unused)) int close(int fd) { - int ret = sys_close(fd); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_close(fd)); }
@@ -239,13 +203,7 @@ int sys_dup(int fd) static __attribute__((unused)) int dup(int fd) { - int ret = sys_dup(fd); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_dup(fd)); }
@@ -268,13 +226,7 @@ int sys_dup2(int old, int new) static __attribute__((unused)) int dup2(int old, int new) { - int ret = sys_dup2(old, new); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_dup2(old, new)); }
@@ -292,13 +244,7 @@ int sys_dup3(int old, int new, int flags) static __attribute__((unused)) int dup3(int old, int new, int flags) { - int ret = sys_dup3(old, new, flags); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_dup3(old, new, flags)); } #endif
@@ -316,13 +262,7 @@ int sys_execve(const char *filename, char *const argv[], char *const envp[]) static __attribute__((unused)) int execve(const char *filename, char *const argv[], char *const envp[]) { - int ret = sys_execve(filename, argv, envp); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_execve(filename, argv, envp)); }
@@ -369,13 +309,7 @@ pid_t sys_fork(void) static __attribute__((unused)) pid_t fork(void) { - pid_t ret = sys_fork(); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_fork()); }
@@ -392,13 +326,7 @@ int sys_fsync(int fd) static __attribute__((unused)) int fsync(int fd) { - int ret = sys_fsync(fd); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_fsync(fd)); }
@@ -415,13 +343,7 @@ int sys_getdents64(int fd, struct linux_dirent64 *dirp, int count) static __attribute__((unused)) int getdents64(int fd, struct linux_dirent64 *dirp, int count) { - int ret = sys_getdents64(fd, dirp, count); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_getdents64(fd, dirp, count)); }
@@ -459,13 +381,7 @@ pid_t sys_getpgid(pid_t pid) static __attribute__((unused)) pid_t getpgid(pid_t pid) { - pid_t ret = sys_getpgid(pid); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_getpgid(pid)); }
@@ -545,15 +461,7 @@ static unsigned long getauxval(unsigned long key); static __attribute__((unused)) long getpagesize(void) { - long ret; - - ret = getauxval(AT_PAGESZ); - if (!ret) { - SET_ERRNO(ENOENT); - return -1; - } - - return ret; + return __sysret(getauxval(AT_PAGESZ) ?: -ENOENT); }
@@ -574,13 +482,7 @@ int sys_gettimeofday(struct timeval *tv, struct timezone *tz) static __attribute__((unused)) int gettimeofday(struct timeval *tv, struct timezone *tz) { - int ret = sys_gettimeofday(tv, tz); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_gettimeofday(tv, tz)); }
@@ -618,13 +520,7 @@ int sys_ioctl(int fd, unsigned long req, void *value) static __attribute__((unused)) int ioctl(int fd, unsigned long req, void *value) { - int ret = sys_ioctl(fd, req, value); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_ioctl(fd, req, value)); }
/* @@ -640,13 +536,7 @@ int sys_kill(pid_t pid, int signal) static __attribute__((unused)) int kill(pid_t pid, int signal) { - int ret = sys_kill(pid, signal); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_kill(pid, signal)); }
@@ -669,13 +559,7 @@ int sys_link(const char *old, const char *new) static __attribute__((unused)) int link(const char *old, const char *new) { - int ret = sys_link(old, new); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_link(old, new)); }
@@ -696,13 +580,7 @@ off_t sys_lseek(int fd, off_t offset, int whence) static __attribute__((unused)) off_t lseek(int fd, off_t offset, int whence) { - off_t ret = sys_lseek(fd, offset, whence); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_lseek(fd, offset, whence)); }
@@ -725,13 +603,7 @@ int sys_mkdir(const char *path, mode_t mode) static __attribute__((unused)) int mkdir(const char *path, mode_t mode) { - int ret = sys_mkdir(path, mode); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_mkdir(path, mode)); }
@@ -754,13 +626,7 @@ long sys_mknod(const char *path, mode_t mode, dev_t dev) static __attribute__((unused)) int mknod(const char *path, mode_t mode, dev_t dev) { - int ret = sys_mknod(path, mode, dev); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_mknod(path, mode, dev)); }
#ifndef MAP_SHARED @@ -818,13 +684,7 @@ int sys_munmap(void *addr, size_t length) static __attribute__((unused)) int munmap(void *addr, size_t length) { - int ret = sys_munmap(addr, length); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_munmap(addr, length)); }
/* @@ -844,13 +704,7 @@ int mount(const char *src, const char *tgt, const char *fst, unsigned long flags, const void *data) { - int ret = sys_mount(src, tgt, fst, flags, data); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_mount(src, tgt, fst, flags, data)); }
@@ -884,13 +738,7 @@ int open(const char *path, int flags, ...) va_end(args); }
- ret = sys_open(path, flags, mode); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_open(path, flags, mode)); }
@@ -910,13 +758,7 @@ static __attribute__((unused)) int prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) { - int ret = sys_prctl(option, arg2, arg3, arg4, arg5); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_prctl(option, arg2, arg3, arg4, arg5)); }
@@ -933,13 +775,7 @@ int sys_pivot_root(const char *new, const char *old) static __attribute__((unused)) int pivot_root(const char *new, const char *old) { - int ret = sys_pivot_root(new, old); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_pivot_root(new, old)); }
@@ -968,13 +804,7 @@ int sys_poll(struct pollfd *fds, int nfds, int timeout) static __attribute__((unused)) int poll(struct pollfd *fds, int nfds, int timeout) { - int ret = sys_poll(fds, nfds, timeout); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_poll(fds, nfds, timeout)); }
@@ -991,13 +821,7 @@ ssize_t sys_read(int fd, void *buf, size_t count) static __attribute__((unused)) ssize_t read(int fd, void *buf, size_t count) { - ssize_t ret = sys_read(fd, buf, count); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_read(fd, buf, count)); }
@@ -1015,13 +839,7 @@ ssize_t sys_reboot(int magic1, int magic2, int cmd, void *arg) static __attribute__((unused)) int reboot(int cmd) { - int ret = sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, 0); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, 0)); }
@@ -1038,13 +856,7 @@ int sys_sched_yield(void) static __attribute__((unused)) int sched_yield(void) { - int ret = sys_sched_yield(); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_sched_yield()); }
@@ -1084,13 +896,7 @@ int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeva static __attribute__((unused)) int select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout) { - int ret = sys_select(nfds, rfds, wfds, efds, timeout); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_select(nfds, rfds, wfds, efds, timeout)); }
@@ -1107,13 +913,7 @@ int sys_setpgid(pid_t pid, pid_t pgid) static __attribute__((unused)) int setpgid(pid_t pid, pid_t pgid) { - int ret = sys_setpgid(pid, pgid); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_setpgid(pid, pgid)); }
@@ -1130,13 +930,7 @@ pid_t sys_setsid(void) static __attribute__((unused)) pid_t setsid(void) { - pid_t ret = sys_setsid(); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_setsid()); }
#if defined(__NR_statx) @@ -1153,13 +947,7 @@ int sys_statx(int fd, const char *path, int flags, unsigned int mask, struct sta static __attribute__((unused)) int statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf) { - int ret = sys_statx(fd, path, flags, mask, buf); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_statx(fd, path, flags, mask, buf)); } #endif
@@ -1239,13 +1027,7 @@ int sys_stat(const char *path, struct stat *buf) static __attribute__((unused)) int stat(const char *path, struct stat *buf) { - int ret = sys_stat(path, buf); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_stat(path, buf)); }
@@ -1268,13 +1050,7 @@ int sys_symlink(const char *old, const char *new) static __attribute__((unused)) int symlink(const char *old, const char *new) { - int ret = sys_symlink(old, new); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_symlink(old, new)); }
@@ -1308,13 +1084,7 @@ int sys_umount2(const char *path, int flags) static __attribute__((unused)) int umount2(const char *path, int flags) { - int ret = sys_umount2(path, flags); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_umount2(path, flags)); }
@@ -1337,13 +1107,7 @@ int sys_unlink(const char *path) static __attribute__((unused)) int unlink(const char *path) { - int ret = sys_unlink(path); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_unlink(path)); }
@@ -1366,38 +1130,20 @@ pid_t sys_wait4(pid_t pid, int *status, int options, struct rusage *rusage) static __attribute__((unused)) pid_t wait(int *status) { - pid_t ret = sys_wait4(-1, status, 0, NULL); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_wait4(-1, status, 0, NULL)); }
static __attribute__((unused)) pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage) { - pid_t ret = sys_wait4(pid, status, options, rusage); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_wait4(pid, status, options, rusage)); }
static __attribute__((unused)) pid_t waitpid(pid_t pid, int *status, int options) { - pid_t ret = sys_wait4(pid, status, options, NULL); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_wait4(pid, status, options, NULL)); }
@@ -1414,13 +1160,7 @@ ssize_t sys_write(int fd, const void *buf, size_t count) static __attribute__((unused)) ssize_t write(int fd, const void *buf, size_t count) { - ssize_t ret = sys_write(fd, buf, count); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_write(fd, buf, count)); }
@@ -1437,13 +1177,7 @@ int sys_memfd_create(const char *name, unsigned int flags) static __attribute__((unused)) int memfd_create(const char *name, unsigned int flags) { - ssize_t ret = sys_memfd_create(name, flags); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_memfd_create(name, flags)); }
/* make sure to include all global symbols */
Tune the macros in the using order and align most of them.
Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/include/nolibc/unistd.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tools/include/nolibc/unistd.h b/tools/include/nolibc/unistd.h index fabc846f797b..e38f3660c051 100644 --- a/tools/include/nolibc/unistd.h +++ b/tools/include/nolibc/unistd.h @@ -56,9 +56,9 @@ int tcsetpgrp(int fd, pid_t pid) return ioctl(fd, TIOCSPGRP, &pid); }
-#define _syscall(N, ...) __sysret(my_syscall##N(__VA_ARGS__)) -#define _syscall_narg(...) __syscall_narg(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) #define __syscall_narg(_0, _1, _2, _3, _4, _5, _6, N, ...) N +#define _syscall_narg(...) __syscall_narg(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) +#define _syscall(N, ...) __sysret(my_syscall##N(__VA_ARGS__)) #define _syscall_n(N, ...) _syscall(N, __VA_ARGS__) #define syscall(...) _syscall_n(_syscall_narg(__VA_ARGS__), ##__VA_ARGS__)
To align with Linux code style and let scripts/checkpatch.pl happy, the multiple whitespaces in arch-<ARCH>.h files are cleaned up with tab.
It is detected by:
$ grep ' *\$' tools/include/nolibc/string.h
Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/include/nolibc/string.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/tools/include/nolibc/string.h b/tools/include/nolibc/string.h index 0c2e06c7c477..e8f471ce09f3 100644 --- a/tools/include/nolibc/string.h +++ b/tools/include/nolibc/string.h @@ -148,10 +148,10 @@ size_t strlen(const char *str) */ #if defined(__OPTIMIZE__) #define nolibc_strlen(x) strlen(x) -#define strlen(str) ({ \ - __builtin_constant_p((str)) ? \ - __builtin_strlen((str)) : \ - nolibc_strlen((str)); \ +#define strlen(str) ({ \ + __builtin_constant_p((str)) ? \ + __builtin_strlen((str)) : \ + nolibc_strlen((str)); \ }) #endif
To align with Linux code style and let scripts/checkpatch.pl happy, the multiple whitespaces in arch-<ARCH>.h files are cleaned up.
Most of them are modified by these commands automatically:
$ sed -i -e '/#define my_syscall/,/})/{s/ /\t/g}' tools/include/nolibc/arch-*.h $ sed -i -e '/#define my_syscall/,/})/{s/ *\$/\t\/g}' tools/include/nolibc/arch-*.h
And checked with:
$ grep ' *\$' tools/include/nolibc/arch-*.h
Besides, more multiple whitespaces are cleaned up:
- convert "__asm__ volatile" to "__asm__ volatile" - "foo _num bar" should be "foo _num bar"
Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/include/nolibc/arch-aarch64.h | 210 +++++++++++----------- tools/include/nolibc/arch-arm.h | 240 +++++++++++++------------- tools/include/nolibc/arch-i386.h | 226 ++++++++++++------------ tools/include/nolibc/arch-loongarch.h | 222 ++++++++++++------------ tools/include/nolibc/arch-mips.h | 218 +++++++++++------------ tools/include/nolibc/arch-riscv.h | 208 +++++++++++----------- tools/include/nolibc/arch-s390.h | 202 +++++++++++----------- tools/include/nolibc/arch-x86_64.h | 222 ++++++++++++------------ 8 files changed, 874 insertions(+), 874 deletions(-)
diff --git a/tools/include/nolibc/arch-aarch64.h b/tools/include/nolibc/arch-aarch64.h index 11f294a406b7..e30056f996db 100644 --- a/tools/include/nolibc/arch-aarch64.h +++ b/tools/include/nolibc/arch-aarch64.h @@ -52,123 +52,123 @@ struct sys_stat_struct { */ #define __ARCH_WANT_SYS_PSELECT6
-#define my_syscall0(num) \ -({ \ - register long _num __asm__ ("x8") = (num); \ - register long _arg1 __asm__ ("x0"); \ - \ - __asm__ volatile ( \ - "svc #0\n" \ - : "=r"(_arg1) \ - : "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ +#define my_syscall0(num) \ +({ \ + register long _num __asm__ ("x8") = (num); \ + register long _arg1 __asm__ ("x0"); \ + \ + __asm__ volatile ( \ + "svc #0\n" \ + : "=r"(_arg1) \ + : "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ })
-#define my_syscall1(num, arg1) \ -({ \ - register long _num __asm__ ("x8") = (num); \ - register long _arg1 __asm__ ("x0") = (long)(arg1); \ - \ - __asm__ volatile ( \ - "svc #0\n" \ - : "=r"(_arg1) \ - : "r"(_arg1), \ - "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ +#define my_syscall1(num, arg1) \ +({ \ + register long _num __asm__ ("x8") = (num); \ + register long _arg1 __asm__ ("x0") = (long)(arg1); \ + \ + __asm__ volatile ( \ + "svc #0\n" \ + : "=r"(_arg1) \ + : "r"(_arg1), \ + "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ })
-#define my_syscall2(num, arg1, arg2) \ -({ \ - 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) \ - : "r"(_arg1), "r"(_arg2), \ - "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ +#define my_syscall2(num, arg1, arg2) \ +({ \ + 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) \ + : "r"(_arg1), "r"(_arg2), \ + "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ })
-#define my_syscall3(num, arg1, arg2, arg3) \ -({ \ - register long _num __asm__ ("x8") = (num); \ - 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) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ - "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ +#define my_syscall3(num, arg1, arg2, arg3) \ +({ \ + register long _num __asm__ ("x8") = (num); \ + 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) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ + "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ })
-#define my_syscall4(num, arg1, arg2, arg3, arg4) \ -({ \ - register long _num __asm__ ("x8") = (num); \ - register long _arg1 __asm__ ("x0") = (long)(arg1); \ - 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) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ - "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ +#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +({ \ + register long _num __asm__ ("x8") = (num); \ + register long _arg1 __asm__ ("x0") = (long)(arg1); \ + 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) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ + "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ })
-#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ -({ \ - register long _num __asm__ ("x8") = (num); \ - register long _arg1 __asm__ ("x0") = (long)(arg1); \ - register long _arg2 __asm__ ("x1") = (long)(arg2); \ - 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) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ - "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ +#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +({ \ + register long _num __asm__ ("x8") = (num); \ + register long _arg1 __asm__ ("x0") = (long)(arg1); \ + register long _arg2 __asm__ ("x1") = (long)(arg2); \ + 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) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ + "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ })
-#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ -({ \ - register long _num __asm__ ("x8") = (num); \ - register long _arg1 __asm__ ("x0") = (long)(arg1); \ - register long _arg2 __asm__ ("x1") = (long)(arg2); \ - register long _arg3 __asm__ ("x2") = (long)(arg3); \ - 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) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ - "r"(_arg6), "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ +#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +({ \ + register long _num __asm__ ("x8") = (num); \ + register long _arg1 __asm__ ("x0") = (long)(arg1); \ + register long _arg2 __asm__ ("x1") = (long)(arg2); \ + register long _arg3 __asm__ ("x2") = (long)(arg3); \ + 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) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ + "r"(_arg6), "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ })
char **environ __attribute__((weak)); diff --git a/tools/include/nolibc/arch-arm.h b/tools/include/nolibc/arch-arm.h index ca4c66987497..7a64290fc518 100644 --- a/tools/include/nolibc/arch-arm.h +++ b/tools/include/nolibc/arch-arm.h @@ -86,138 +86,138 @@ struct sys_stat_struct {
#endif /* end THUMB */
-#define my_syscall0(num) \ -({ \ - register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ - register long _arg1 __asm__ ("r0"); \ - \ - __asm__ volatile ( \ - _NOLIBC_THUMB_SET_R7 \ - "svc #0\n" \ - _NOLIBC_THUMB_RESTORE_R7 \ - : "=r"(_arg1), "=r"(_num) \ - : "r"(_arg1), \ - "r"(_num) \ - : "memory", "cc", "lr" \ - ); \ - _arg1; \ +#define my_syscall0(num) \ +({ \ + register long _num __asm__ (_NOLIBC_SYSCALL_REG) = (num); \ + register long _arg1 __asm__ ("r0"); \ + \ + __asm__ volatile ( \ + _NOLIBC_THUMB_SET_R7 \ + "svc #0\n" \ + _NOLIBC_THUMB_RESTORE_R7 \ + : "=r"(_arg1), "=r"(_num) \ + : "r"(_arg1), \ + "r"(_num) \ + : "memory", "cc", "lr" \ + ); \ + _arg1; \ })
-#define my_syscall1(num, arg1) \ -({ \ - register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ - register long _arg1 __asm__ ("r0") = (long)(arg1); \ - \ - __asm__ volatile ( \ - _NOLIBC_THUMB_SET_R7 \ - "svc #0\n" \ - _NOLIBC_THUMB_RESTORE_R7 \ - : "=r"(_arg1), "=r" (_num) \ - : "r"(_arg1), \ - "r"(_num) \ - : "memory", "cc", "lr" \ - ); \ - _arg1; \ +#define my_syscall1(num, arg1) \ +({ \ + register long _num __asm__ (_NOLIBC_SYSCALL_REG) = (num); \ + register long _arg1 __asm__ ("r0") = (long)(arg1); \ + \ + __asm__ volatile ( \ + _NOLIBC_THUMB_SET_R7 \ + "svc #0\n" \ + _NOLIBC_THUMB_RESTORE_R7 \ + : "=r"(_arg1), "=r" (_num) \ + : "r"(_arg1), \ + "r"(_num) \ + : "memory", "cc", "lr" \ + ); \ + _arg1; \ })
-#define my_syscall2(num, arg1, arg2) \ -({ \ - 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" \ - _NOLIBC_THUMB_RESTORE_R7 \ - : "=r"(_arg1), "=r" (_num) \ - : "r"(_arg1), "r"(_arg2), \ - "r"(_num) \ - : "memory", "cc", "lr" \ - ); \ - _arg1; \ +#define my_syscall2(num, arg1, arg2) \ +({ \ + 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" \ + _NOLIBC_THUMB_RESTORE_R7 \ + : "=r"(_arg1), "=r" (_num) \ + : "r"(_arg1), "r"(_arg2), \ + "r"(_num) \ + : "memory", "cc", "lr" \ + ); \ + _arg1; \ })
-#define my_syscall3(num, arg1, arg2, arg3) \ -({ \ - register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ - register long _arg1 __asm__ ("r0") = (long)(arg1); \ - register long _arg2 __asm__ ("r1") = (long)(arg2); \ - register long _arg3 __asm__ ("r2") = (long)(arg3); \ - \ - __asm__ volatile ( \ - _NOLIBC_THUMB_SET_R7 \ - "svc #0\n" \ - _NOLIBC_THUMB_RESTORE_R7 \ - : "=r"(_arg1), "=r" (_num) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ - "r"(_num) \ - : "memory", "cc", "lr" \ - ); \ - _arg1; \ +#define my_syscall3(num, arg1, arg2, arg3) \ +({ \ + register long _num __asm__ (_NOLIBC_SYSCALL_REG) = (num); \ + register long _arg1 __asm__ ("r0") = (long)(arg1); \ + register long _arg2 __asm__ ("r1") = (long)(arg2); \ + register long _arg3 __asm__ ("r2") = (long)(arg3); \ + \ + __asm__ volatile ( \ + _NOLIBC_THUMB_SET_R7 \ + "svc #0\n" \ + _NOLIBC_THUMB_RESTORE_R7 \ + : "=r"(_arg1), "=r" (_num) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ + "r"(_num) \ + : "memory", "cc", "lr" \ + ); \ + _arg1; \ })
-#define my_syscall4(num, arg1, arg2, arg3, arg4) \ -({ \ - register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ - register long _arg1 __asm__ ("r0") = (long)(arg1); \ - register long _arg2 __asm__ ("r1") = (long)(arg2); \ - register long _arg3 __asm__ ("r2") = (long)(arg3); \ - register long _arg4 __asm__ ("r3") = (long)(arg4); \ - \ - __asm__ volatile ( \ - _NOLIBC_THUMB_SET_R7 \ - "svc #0\n" \ - _NOLIBC_THUMB_RESTORE_R7 \ - : "=r"(_arg1), "=r" (_num) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ - "r"(_num) \ - : "memory", "cc", "lr" \ - ); \ - _arg1; \ +#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +({ \ + register long _num __asm__ (_NOLIBC_SYSCALL_REG) = (num); \ + register long _arg1 __asm__ ("r0") = (long)(arg1); \ + register long _arg2 __asm__ ("r1") = (long)(arg2); \ + register long _arg3 __asm__ ("r2") = (long)(arg3); \ + register long _arg4 __asm__ ("r3") = (long)(arg4); \ + \ + __asm__ volatile ( \ + _NOLIBC_THUMB_SET_R7 \ + "svc #0\n" \ + _NOLIBC_THUMB_RESTORE_R7 \ + : "=r"(_arg1), "=r" (_num) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ + "r"(_num) \ + : "memory", "cc", "lr" \ + ); \ + _arg1; \ })
-#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ -({ \ - register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ - register long _arg1 __asm__ ("r0") = (long)(arg1); \ - register long _arg2 __asm__ ("r1") = (long)(arg2); \ - register long _arg3 __asm__ ("r2") = (long)(arg3); \ - register long _arg4 __asm__ ("r3") = (long)(arg4); \ - register long _arg5 __asm__ ("r4") = (long)(arg5); \ - \ - __asm__ volatile ( \ - _NOLIBC_THUMB_SET_R7 \ - "svc #0\n" \ - _NOLIBC_THUMB_RESTORE_R7 \ - : "=r"(_arg1), "=r" (_num) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ - "r"(_num) \ - : "memory", "cc", "lr" \ - ); \ - _arg1; \ +#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +({ \ + register long _num __asm__ (_NOLIBC_SYSCALL_REG) = (num); \ + register long _arg1 __asm__ ("r0") = (long)(arg1); \ + register long _arg2 __asm__ ("r1") = (long)(arg2); \ + register long _arg3 __asm__ ("r2") = (long)(arg3); \ + register long _arg4 __asm__ ("r3") = (long)(arg4); \ + register long _arg5 __asm__ ("r4") = (long)(arg5); \ + \ + __asm__ volatile ( \ + _NOLIBC_THUMB_SET_R7 \ + "svc #0\n" \ + _NOLIBC_THUMB_RESTORE_R7 \ + : "=r"(_arg1), "=r" (_num) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ + "r"(_num) \ + : "memory", "cc", "lr" \ + ); \ + _arg1; \ })
-#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ -({ \ - register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ - register long _arg1 __asm__ ("r0") = (long)(arg1); \ - register long _arg2 __asm__ ("r1") = (long)(arg2); \ - register long _arg3 __asm__ ("r2") = (long)(arg3); \ - register long _arg4 __asm__ ("r3") = (long)(arg4); \ - register long _arg5 __asm__ ("r4") = (long)(arg5); \ - register long _arg6 __asm__ ("r5") = (long)(arg6); \ - \ - __asm__ volatile ( \ - _NOLIBC_THUMB_SET_R7 \ - "svc #0\n" \ - _NOLIBC_THUMB_RESTORE_R7 \ - : "=r"(_arg1), "=r" (_num) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ - "r"(_arg6), "r"(_num) \ - : "memory", "cc", "lr" \ - ); \ - _arg1; \ +#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +({ \ + register long _num __asm__ (_NOLIBC_SYSCALL_REG) = (num); \ + register long _arg1 __asm__ ("r0") = (long)(arg1); \ + register long _arg2 __asm__ ("r1") = (long)(arg2); \ + register long _arg3 __asm__ ("r2") = (long)(arg3); \ + register long _arg4 __asm__ ("r3") = (long)(arg4); \ + register long _arg5 __asm__ ("r4") = (long)(arg5); \ + register long _arg6 __asm__ ("r5") = (long)(arg6); \ + \ + __asm__ volatile ( \ + _NOLIBC_THUMB_SET_R7 \ + "svc #0\n" \ + _NOLIBC_THUMB_RESTORE_R7 \ + : "=r"(_arg1), "=r" (_num) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ + "r"(_arg6), "r"(_num) \ + : "memory", "cc", "lr" \ + ); \ + _arg1; \ })
diff --git a/tools/include/nolibc/arch-i386.h b/tools/include/nolibc/arch-i386.h index 3d672d925e9e..c2e75ba91b6b 100644 --- a/tools/include/nolibc/arch-i386.h +++ b/tools/include/nolibc/arch-i386.h @@ -53,131 +53,131 @@ struct sys_stat_struct { */ #define __ARCH_WANT_SYS_OLD_SELECT
-#define my_syscall0(num) \ -({ \ - long _ret; \ - register long _num __asm__ ("eax") = (num); \ - \ - __asm__ volatile ( \ - "int $0x80\n" \ - : "=a" (_ret) \ - : "0"(_num) \ - : "memory", "cc" \ - ); \ - _ret; \ +#define my_syscall0(num) \ +({ \ + long _ret; \ + register long _num __asm__ ("eax") = (num); \ + \ + __asm__ volatile ( \ + "int $0x80\n" \ + : "=a" (_ret) \ + : "0"(_num) \ + : "memory", "cc" \ + ); \ + _ret; \ })
-#define my_syscall1(num, arg1) \ -({ \ - long _ret; \ - register long _num __asm__ ("eax") = (num); \ - register long _arg1 __asm__ ("ebx") = (long)(arg1); \ - \ - __asm__ volatile ( \ - "int $0x80\n" \ - : "=a" (_ret) \ - : "r"(_arg1), \ - "0"(_num) \ - : "memory", "cc" \ - ); \ - _ret; \ +#define my_syscall1(num, arg1) \ +({ \ + long _ret; \ + register long _num __asm__ ("eax") = (num); \ + register long _arg1 __asm__ ("ebx") = (long)(arg1); \ + \ + __asm__ volatile ( \ + "int $0x80\n" \ + : "=a" (_ret) \ + : "r"(_arg1), \ + "0"(_num) \ + : "memory", "cc" \ + ); \ + _ret; \ })
-#define my_syscall2(num, arg1, arg2) \ -({ \ - long _ret; \ - 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) \ - : "r"(_arg1), "r"(_arg2), \ - "0"(_num) \ - : "memory", "cc" \ - ); \ - _ret; \ +#define my_syscall2(num, arg1, arg2) \ +({ \ + long _ret; \ + 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) \ + : "r"(_arg1), "r"(_arg2), \ + "0"(_num) \ + : "memory", "cc" \ + ); \ + _ret; \ })
-#define my_syscall3(num, arg1, arg2, arg3) \ -({ \ - long _ret; \ - register long _num __asm__ ("eax") = (num); \ - 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) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ - "0"(_num) \ - : "memory", "cc" \ - ); \ - _ret; \ +#define my_syscall3(num, arg1, arg2, arg3) \ +({ \ + long _ret; \ + register long _num __asm__ ("eax") = (num); \ + 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) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ + "0"(_num) \ + : "memory", "cc" \ + ); \ + _ret; \ })
-#define my_syscall4(num, arg1, arg2, arg3, arg4) \ -({ \ - long _ret; \ - register long _num __asm__ ("eax") = (num); \ - register long _arg1 __asm__ ("ebx") = (long)(arg1); \ - 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) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ - "0"(_num) \ - : "memory", "cc" \ - ); \ - _ret; \ +#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +({ \ + long _ret; \ + register long _num __asm__ ("eax") = (num); \ + register long _arg1 __asm__ ("ebx") = (long)(arg1); \ + 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) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ + "0"(_num) \ + : "memory", "cc" \ + ); \ + _ret; \ })
-#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ -({ \ - long _ret; \ - register long _num __asm__ ("eax") = (num); \ - register long _arg1 __asm__ ("ebx") = (long)(arg1); \ - register long _arg2 __asm__ ("ecx") = (long)(arg2); \ - 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) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ - "0"(_num) \ - : "memory", "cc" \ - ); \ - _ret; \ +#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +({ \ + long _ret; \ + register long _num __asm__ ("eax") = (num); \ + register long _arg1 __asm__ ("ebx") = (long)(arg1); \ + register long _arg2 __asm__ ("ecx") = (long)(arg2); \ + 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) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ + "0"(_num) \ + : "memory", "cc" \ + ); \ + _ret; \ })
-#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ -({ \ - long _eax = (long)(num); \ - long _arg6 = (long)(arg6); /* Always in memory */ \ - __asm__ volatile ( \ - "pushl %[_arg6]\n\t" \ - "pushl %%ebp\n\t" \ - "movl 4(%%esp),%%ebp\n\t" \ - "int $0x80\n\t" \ - "popl %%ebp\n\t" \ - "addl $4,%%esp\n\t" \ - : "+a"(_eax) /* %eax */ \ - : "b"(arg1), /* %ebx */ \ - "c"(arg2), /* %ecx */ \ - "d"(arg3), /* %edx */ \ - "S"(arg4), /* %esi */ \ - "D"(arg5), /* %edi */ \ - [_arg6]"m"(_arg6) /* memory */ \ - : "memory", "cc" \ - ); \ - _eax; \ +#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +({ \ + long _eax = (long)(num); \ + long _arg6 = (long)(arg6); /* Always in memory */ \ + __asm__ volatile ( \ + "pushl %[_arg6]\n\t" \ + "pushl %%ebp\n\t" \ + "movl 4(%%esp),%%ebp\n\t" \ + "int $0x80\n\t" \ + "popl %%ebp\n\t" \ + "addl $4,%%esp\n\t" \ + : "+a"(_eax) /* %eax */ \ + : "b"(arg1), /* %ebx */ \ + "c"(arg2), /* %ecx */ \ + "d"(arg3), /* %edx */ \ + "S"(arg4), /* %esi */ \ + "D"(arg5), /* %edi */ \ + [_arg6]"m"(_arg6) /* memory */ \ + : "memory", "cc" \ + ); \ + _eax; \ })
char **environ __attribute__((weak)); diff --git a/tools/include/nolibc/arch-loongarch.h b/tools/include/nolibc/arch-loongarch.h index ad3f266e7093..292d6a58dc87 100644 --- a/tools/include/nolibc/arch-loongarch.h +++ b/tools/include/nolibc/arch-loongarch.h @@ -23,129 +23,129 @@ */ #define __ARCH_WANT_SYS_PSELECT6
-#define my_syscall0(num) \ -({ \ - register long _num __asm__ ("a7") = (num); \ - register long _arg1 __asm__ ("a0"); \ - \ - __asm__ volatile ( \ - "syscall 0\n" \ - : "=r"(_arg1) \ - : "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ - ); \ - _arg1; \ +#define my_syscall0(num) \ +({ \ + register long _num __asm__ ("a7") = (num); \ + register long _arg1 __asm__ ("a0"); \ + \ + __asm__ volatile ( \ + "syscall 0\n" \ + : "=r"(_arg1) \ + : "r"(_num) \ + : "memory", "$t0", "$t1", "$t2", "$t3", \ + "$t4", "$t5", "$t6", "$t7", "$t8" \ + ); \ + _arg1; \ })
-#define my_syscall1(num, arg1) \ -({ \ - register long _num __asm__ ("a7") = (num); \ - register long _arg1 __asm__ ("a0") = (long)(arg1); \ - \ - __asm__ volatile ( \ - "syscall 0\n" \ - : "+r"(_arg1) \ - : "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ - ); \ - _arg1; \ +#define my_syscall1(num, arg1) \ +({ \ + register long _num __asm__ ("a7") = (num); \ + register long _arg1 __asm__ ("a0") = (long)(arg1); \ + \ + __asm__ volatile ( \ + "syscall 0\n" \ + : "+r"(_arg1) \ + : "r"(_num) \ + : "memory", "$t0", "$t1", "$t2", "$t3", \ + "$t4", "$t5", "$t6", "$t7", "$t8" \ + ); \ + _arg1; \ })
-#define my_syscall2(num, arg1, arg2) \ -({ \ - register long _num __asm__ ("a7") = (num); \ - register long _arg1 __asm__ ("a0") = (long)(arg1); \ - register long _arg2 __asm__ ("a1") = (long)(arg2); \ - \ - __asm__ volatile ( \ - "syscall 0\n" \ - : "+r"(_arg1) \ - : "r"(_arg2), \ - "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ - ); \ - _arg1; \ +#define my_syscall2(num, arg1, arg2) \ +({ \ + register long _num __asm__ ("a7") = (num); \ + register long _arg1 __asm__ ("a0") = (long)(arg1); \ + register long _arg2 __asm__ ("a1") = (long)(arg2); \ + \ + __asm__ volatile ( \ + "syscall 0\n" \ + : "+r"(_arg1) \ + : "r"(_arg2), \ + "r"(_num) \ + : "memory", "$t0", "$t1", "$t2", "$t3", \ + "$t4", "$t5", "$t6", "$t7", "$t8" \ + ); \ + _arg1; \ })
-#define my_syscall3(num, arg1, arg2, arg3) \ -({ \ - register long _num __asm__ ("a7") = (num); \ - register long _arg1 __asm__ ("a0") = (long)(arg1); \ - register long _arg2 __asm__ ("a1") = (long)(arg2); \ - register long _arg3 __asm__ ("a2") = (long)(arg3); \ - \ - __asm__ volatile ( \ - "syscall 0\n" \ - : "+r"(_arg1) \ - : "r"(_arg2), "r"(_arg3), \ - "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ - ); \ - _arg1; \ +#define my_syscall3(num, arg1, arg2, arg3) \ +({ \ + register long _num __asm__ ("a7") = (num); \ + register long _arg1 __asm__ ("a0") = (long)(arg1); \ + register long _arg2 __asm__ ("a1") = (long)(arg2); \ + register long _arg3 __asm__ ("a2") = (long)(arg3); \ + \ + __asm__ volatile ( \ + "syscall 0\n" \ + : "+r"(_arg1) \ + : "r"(_arg2), "r"(_arg3), \ + "r"(_num) \ + : "memory", "$t0", "$t1", "$t2", "$t3", \ + "$t4", "$t5", "$t6", "$t7", "$t8" \ + ); \ + _arg1; \ })
-#define my_syscall4(num, arg1, arg2, arg3, arg4) \ -({ \ - register long _num __asm__ ("a7") = (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); \ - \ - __asm__ volatile ( \ - "syscall 0\n" \ - : "+r"(_arg1) \ - : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ - "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ - ); \ - _arg1; \ +#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +({ \ + register long _num __asm__ ("a7") = (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); \ + \ + __asm__ volatile ( \ + "syscall 0\n" \ + : "+r"(_arg1) \ + : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ + "r"(_num) \ + : "memory", "$t0", "$t1", "$t2", "$t3", \ + "$t4", "$t5", "$t6", "$t7", "$t8" \ + ); \ + _arg1; \ })
-#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ -({ \ - register long _num __asm__ ("a7") = (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 __asm__ ("a4") = (long)(arg5); \ - \ - __asm__ volatile ( \ - "syscall 0\n" \ - : "+r"(_arg1) \ - : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ - "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ - ); \ - _arg1; \ +#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +({ \ + register long _num __asm__ ("a7") = (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 __asm__ ("a4") = (long)(arg5); \ + \ + __asm__ volatile ( \ + "syscall 0\n" \ + : "+r"(_arg1) \ + : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ + "r"(_num) \ + : "memory", "$t0", "$t1", "$t2", "$t3", \ + "$t4", "$t5", "$t6", "$t7", "$t8" \ + ); \ + _arg1; \ })
-#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ -({ \ - register long _num __asm__ ("a7") = (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 __asm__ ("a4") = (long)(arg5); \ - register long _arg6 __asm__ ("a5") = (long)(arg6); \ - \ - __asm__ volatile ( \ - "syscall 0\n" \ - : "+r"(_arg1) \ - : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ - "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ - ); \ - _arg1; \ +#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +({ \ + register long _num __asm__ ("a7") = (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 __asm__ ("a4") = (long)(arg5); \ + register long _arg6 __asm__ ("a5") = (long)(arg6); \ + \ + __asm__ volatile ( \ + "syscall 0\n" \ + : "+r"(_arg1) \ + : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ + "r"(_num) \ + : "memory", "$t0", "$t1", "$t2", "$t3", \ + "$t4", "$t5", "$t6", "$t7", "$t8" \ + ); \ + _arg1; \ })
char **environ __attribute__((weak)); diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h index db24e0837a39..1fd1eedc12a6 100644 --- a/tools/include/nolibc/arch-mips.h +++ b/tools/include/nolibc/arch-mips.h @@ -57,125 +57,125 @@ struct sys_stat_struct { * don't have to experience issues with register constraints. */
-#define my_syscall0(num) \ -({ \ - register long _num __asm__ ("v0") = (num); \ - register long _arg4 __asm__ ("a3"); \ - \ - __asm__ volatile ( \ - "addiu $sp, $sp, -32\n" \ - "syscall\n" \ - "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" \ - ); \ - _arg4 ? -_num : _num; \ +#define my_syscall0(num) \ +({ \ + register long _num __asm__ ("v0") = (num); \ + register long _arg4 __asm__ ("a3"); \ + \ + __asm__ volatile ( \ + "addiu $sp, $sp, -32\n" \ + "syscall\n" \ + "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" \ + ); \ + _arg4 ? -_num : _num; \ })
-#define my_syscall1(num, arg1) \ -({ \ - 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" \ - "addiu $sp, $sp, 32\n" \ - : "=r"(_num), "=r"(_arg4) \ - : "0"(_num), \ - "r"(_arg1) \ - : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ - ); \ - _arg4 ? -_num : _num; \ +#define my_syscall1(num, arg1) \ +({ \ + 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" \ + "addiu $sp, $sp, 32\n" \ + : "=r"(_num), "=r"(_arg4) \ + : "0"(_num), \ + "r"(_arg1) \ + : "memory", "cc", "at", "v1", "hi", "lo", \ + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + ); \ + _arg4 ? -_num : _num; \ })
-#define my_syscall2(num, arg1, arg2) \ -({ \ - register long _num __asm__ ("v0") = (num); \ - 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" \ - "addiu $sp, $sp, 32\n" \ - : "=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" \ - ); \ - _arg4 ? -_num : _num; \ +#define my_syscall2(num, arg1, arg2) \ +({ \ + register long _num __asm__ ("v0") = (num); \ + 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" \ + "addiu $sp, $sp, 32\n" \ + : "=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" \ + ); \ + _arg4 ? -_num : _num; \ })
-#define my_syscall3(num, arg1, arg2, arg3) \ -({ \ - 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"); \ - \ - __asm__ volatile ( \ - "addiu $sp, $sp, -32\n" \ - "syscall\n" \ - "addiu $sp, $sp, 32\n" \ - : "=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" \ - ); \ - _arg4 ? -_num : _num; \ +#define my_syscall3(num, arg1, arg2, arg3) \ +({ \ + 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"); \ + \ + __asm__ volatile ( \ + "addiu $sp, $sp, -32\n" \ + "syscall\n" \ + "addiu $sp, $sp, 32\n" \ + : "=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" \ + ); \ + _arg4 ? -_num : _num; \ })
-#define my_syscall4(num, arg1, arg2, arg3, arg4) \ -({ \ - 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); \ - \ - __asm__ volatile ( \ - "addiu $sp, $sp, -32\n" \ - "syscall\n" \ - "addiu $sp, $sp, 32\n" \ - : "=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" \ - ); \ - _arg4 ? -_num : _num; \ +#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +({ \ + 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); \ + \ + __asm__ volatile ( \ + "addiu $sp, $sp, -32\n" \ + "syscall\n" \ + "addiu $sp, $sp, 32\n" \ + : "=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" \ + ); \ + _arg4 ? -_num : _num; \ })
-#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ -({ \ - 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); \ - \ - __asm__ volatile ( \ - "addiu $sp, $sp, -32\n" \ - "sw %7, 16($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) \ - : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ - ); \ - _arg4 ? -_num : _num; \ +#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +({ \ + 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); \ + \ + __asm__ volatile ( \ + "addiu $sp, $sp, -32\n" \ + "sw %7, 16($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) \ + : "memory", "cc", "at", "v1", "hi", "lo", \ + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + ); \ + _arg4 ? -_num : _num; \ })
char **environ __attribute__((weak)); diff --git a/tools/include/nolibc/arch-riscv.h b/tools/include/nolibc/arch-riscv.h index a2e8564e66d6..4f21e862b412 100644 --- a/tools/include/nolibc/arch-riscv.h +++ b/tools/include/nolibc/arch-riscv.h @@ -58,122 +58,122 @@ struct sys_stat_struct { */ #define __ARCH_WANT_SYS_PSELECT6
-#define my_syscall0(num) \ -({ \ - register long _num __asm__ ("a7") = (num); \ - register long _arg1 __asm__ ("a0"); \ - \ - __asm__ volatile ( \ - "ecall\n\t" \ - : "=r"(_arg1) \ - : "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ +#define my_syscall0(num) \ +({ \ + register long _num __asm__ ("a7") = (num); \ + register long _arg1 __asm__ ("a0"); \ + \ + __asm__ volatile ( \ + "ecall\n\t" \ + : "=r"(_arg1) \ + : "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ })
-#define my_syscall1(num, arg1) \ -({ \ - register long _num __asm__ ("a7") = (num); \ - register long _arg1 __asm__ ("a0") = (long)(arg1); \ - \ - __asm__ volatile ( \ - "ecall\n" \ - : "+r"(_arg1) \ - : "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ +#define my_syscall1(num, arg1) \ +({ \ + register long _num __asm__ ("a7") = (num); \ + register long _arg1 __asm__ ("a0") = (long)(arg1); \ + \ + __asm__ volatile ( \ + "ecall\n" \ + : "+r"(_arg1) \ + : "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ })
-#define my_syscall2(num, arg1, arg2) \ -({ \ - register long _num __asm__ ("a7") = (num); \ - register long _arg1 __asm__ ("a0") = (long)(arg1); \ - register long _arg2 __asm__ ("a1") = (long)(arg2); \ - \ - __asm__ volatile ( \ - "ecall\n" \ - : "+r"(_arg1) \ - : "r"(_arg2), \ - "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ +#define my_syscall2(num, arg1, arg2) \ +({ \ + register long _num __asm__ ("a7") = (num); \ + register long _arg1 __asm__ ("a0") = (long)(arg1); \ + register long _arg2 __asm__ ("a1") = (long)(arg2); \ + \ + __asm__ volatile ( \ + "ecall\n" \ + : "+r"(_arg1) \ + : "r"(_arg2), \ + "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ })
-#define my_syscall3(num, arg1, arg2, arg3) \ -({ \ - register long _num __asm__ ("a7") = (num); \ - register long _arg1 __asm__ ("a0") = (long)(arg1); \ - register long _arg2 __asm__ ("a1") = (long)(arg2); \ - register long _arg3 __asm__ ("a2") = (long)(arg3); \ - \ - __asm__ volatile ( \ - "ecall\n\t" \ - : "+r"(_arg1) \ - : "r"(_arg2), "r"(_arg3), \ - "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ +#define my_syscall3(num, arg1, arg2, arg3) \ +({ \ + register long _num __asm__ ("a7") = (num); \ + register long _arg1 __asm__ ("a0") = (long)(arg1); \ + register long _arg2 __asm__ ("a1") = (long)(arg2); \ + register long _arg3 __asm__ ("a2") = (long)(arg3); \ + \ + __asm__ volatile ( \ + "ecall\n\t" \ + : "+r"(_arg1) \ + : "r"(_arg2), "r"(_arg3), \ + "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ })
-#define my_syscall4(num, arg1, arg2, arg3, arg4) \ -({ \ - register long _num __asm__ ("a7") = (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); \ - \ - __asm__ volatile ( \ - "ecall\n" \ - : "+r"(_arg1) \ - : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ - "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ +#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +({ \ + register long _num __asm__ ("a7") = (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); \ + \ + __asm__ volatile ( \ + "ecall\n" \ + : "+r"(_arg1) \ + : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ + "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ })
-#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ -({ \ - register long _num __asm__ ("a7") = (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 __asm__ ("a4") = (long)(arg5); \ - \ - __asm__ volatile ( \ - "ecall\n" \ - : "+r"(_arg1) \ - : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ - "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ +#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +({ \ + register long _num __asm__ ("a7") = (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 __asm__ ("a4") = (long)(arg5); \ + \ + __asm__ volatile ( \ + "ecall\n" \ + : "+r"(_arg1) \ + : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ + "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ })
-#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ -({ \ - register long _num __asm__ ("a7") = (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 __asm__ ("a4") = (long)(arg5); \ - register long _arg6 __asm__ ("a5") = (long)(arg6); \ - \ - __asm__ volatile ( \ - "ecall\n" \ - : "+r"(_arg1) \ - : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ - "r"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ +#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +({ \ + register long _num __asm__ ("a7") = (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 __asm__ ("a4") = (long)(arg5); \ + register long _arg6 __asm__ ("a5") = (long)(arg6); \ + \ + __asm__ volatile ( \ + "ecall\n" \ + : "+r"(_arg1) \ + : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ + "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ })
char **environ __attribute__((weak)); diff --git a/tools/include/nolibc/arch-s390.h b/tools/include/nolibc/arch-s390.h index 516dff5bff8b..8cff5b05e841 100644 --- a/tools/include/nolibc/arch-s390.h +++ b/tools/include/nolibc/arch-s390.h @@ -47,119 +47,119 @@ struct sys_stat_struct { * */
-#define my_syscall0(num) \ -({ \ - register long _num __asm__ ("1") = (num); \ - register long _rc __asm__ ("2"); \ - \ - __asm__ volatile ( \ - "svc 0\n" \ - : "=d"(_rc) \ - : "d"(_num) \ - : "memory", "cc" \ - ); \ - _rc; \ +#define my_syscall0(num) \ +({ \ + register long _num __asm__ ("1") = (num); \ + register long _rc __asm__ ("2"); \ + \ + __asm__ volatile ( \ + "svc 0\n" \ + : "=d"(_rc) \ + : "d"(_num) \ + : "memory", "cc" \ + ); \ + _rc; \ })
-#define my_syscall1(num, arg1) \ -({ \ - register long _num __asm__ ("1") = (num); \ - register long _arg1 __asm__ ("2") = (long)(arg1); \ - \ - __asm__ volatile ( \ - "svc 0\n" \ - : "+d"(_arg1) \ - : "d"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ +#define my_syscall1(num, arg1) \ +({ \ + register long _num __asm__ ("1") = (num); \ + register long _arg1 __asm__ ("2") = (long)(arg1); \ + \ + __asm__ volatile ( \ + "svc 0\n" \ + : "+d"(_arg1) \ + : "d"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ })
-#define my_syscall2(num, arg1, arg2) \ -({ \ - register long _num __asm__ ("1") = (num); \ - register long _arg1 __asm__ ("2") = (long)(arg1); \ - register long _arg2 __asm__ ("3") = (long)(arg2); \ - \ - __asm__ volatile ( \ - "svc 0\n" \ - : "+d"(_arg1) \ - : "d"(_arg2), "d"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ +#define my_syscall2(num, arg1, arg2) \ +({ \ + register long _num __asm__ ("1") = (num); \ + register long _arg1 __asm__ ("2") = (long)(arg1); \ + register long _arg2 __asm__ ("3") = (long)(arg2); \ + \ + __asm__ volatile ( \ + "svc 0\n" \ + : "+d"(_arg1) \ + : "d"(_arg2), "d"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ })
-#define my_syscall3(num, arg1, arg2, arg3) \ -({ \ - register long _num __asm__ ("1") = (num); \ - register long _arg1 __asm__ ("2") = (long)(arg1); \ - register long _arg2 __asm__ ("3") = (long)(arg2); \ - register long _arg3 __asm__ ("4") = (long)(arg3); \ - \ - __asm__ volatile ( \ - "svc 0\n" \ - : "+d"(_arg1) \ - : "d"(_arg2), "d"(_arg3), "d"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ +#define my_syscall3(num, arg1, arg2, arg3) \ +({ \ + register long _num __asm__ ("1") = (num); \ + register long _arg1 __asm__ ("2") = (long)(arg1); \ + register long _arg2 __asm__ ("3") = (long)(arg2); \ + register long _arg3 __asm__ ("4") = (long)(arg3); \ + \ + __asm__ volatile ( \ + "svc 0\n" \ + : "+d"(_arg1) \ + : "d"(_arg2), "d"(_arg3), "d"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ })
-#define my_syscall4(num, arg1, arg2, arg3, arg4) \ -({ \ - register long _num __asm__ ("1") = (num); \ - register long _arg1 __asm__ ("2") = (long)(arg1); \ - register long _arg2 __asm__ ("3") = (long)(arg2); \ - register long _arg3 __asm__ ("4") = (long)(arg3); \ - register long _arg4 __asm__ ("5") = (long)(arg4); \ - \ - __asm__ volatile ( \ - "svc 0\n" \ - : "+d"(_arg1) \ - : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ +#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +({ \ + register long _num __asm__ ("1") = (num); \ + register long _arg1 __asm__ ("2") = (long)(arg1); \ + register long _arg2 __asm__ ("3") = (long)(arg2); \ + register long _arg3 __asm__ ("4") = (long)(arg3); \ + register long _arg4 __asm__ ("5") = (long)(arg4); \ + \ + __asm__ volatile ( \ + "svc 0\n" \ + : "+d"(_arg1) \ + : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ })
-#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ -({ \ - register long _num __asm__ ("1") = (num); \ - register long _arg1 __asm__ ("2") = (long)(arg1); \ - register long _arg2 __asm__ ("3") = (long)(arg2); \ - register long _arg3 __asm__ ("4") = (long)(arg3); \ - register long _arg4 __asm__ ("5") = (long)(arg4); \ - register long _arg5 __asm__ ("6") = (long)(arg5); \ - \ - __asm__ volatile ( \ - "svc 0\n" \ - : "+d"(_arg1) \ - : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5), \ - "d"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ +#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +({ \ + register long _num __asm__ ("1") = (num); \ + register long _arg1 __asm__ ("2") = (long)(arg1); \ + register long _arg2 __asm__ ("3") = (long)(arg2); \ + register long _arg3 __asm__ ("4") = (long)(arg3); \ + register long _arg4 __asm__ ("5") = (long)(arg4); \ + register long _arg5 __asm__ ("6") = (long)(arg5); \ + \ + __asm__ volatile ( \ + "svc 0\n" \ + : "+d"(_arg1) \ + : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5), \ + "d"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ })
-#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ -({ \ - register long _num __asm__ ("1") = (num); \ - register long _arg1 __asm__ ("2") = (long)(arg1); \ - register long _arg2 __asm__ ("3") = (long)(arg2); \ - register long _arg3 __asm__ ("4") = (long)(arg3); \ - register long _arg4 __asm__ ("5") = (long)(arg4); \ - register long _arg5 __asm__ ("6") = (long)(arg5); \ - register long _arg6 __asm__ ("7") = (long)(arg6); \ - \ - __asm__ volatile ( \ - "svc 0\n" \ - : "+d"(_arg1) \ - : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5), \ - "d"(_arg6), "d"(_num) \ - : "memory", "cc" \ - ); \ - _arg1; \ +#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +({ \ + register long _num __asm__ ("1") = (num); \ + register long _arg1 __asm__ ("2") = (long)(arg1); \ + register long _arg2 __asm__ ("3") = (long)(arg2); \ + register long _arg3 __asm__ ("4") = (long)(arg3); \ + register long _arg4 __asm__ ("5") = (long)(arg4); \ + register long _arg5 __asm__ ("6") = (long)(arg5); \ + register long _arg6 __asm__ ("7") = (long)(arg6); \ + \ + __asm__ volatile ( \ + "svc 0\n" \ + : "+d"(_arg1) \ + : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5), \ + "d"(_arg6), "d"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ })
char **environ __attribute__((weak)); diff --git a/tools/include/nolibc/arch-x86_64.h b/tools/include/nolibc/arch-x86_64.h index 6fc4d8392742..1dc8b60f5153 100644 --- a/tools/include/nolibc/arch-x86_64.h +++ b/tools/include/nolibc/arch-x86_64.h @@ -55,129 +55,129 @@ struct sys_stat_struct { * */
-#define my_syscall0(num) \ -({ \ - long _ret; \ - register long _num __asm__ ("rax") = (num); \ - \ - __asm__ volatile ( \ - "syscall\n" \ - : "=a"(_ret) \ - : "0"(_num) \ - : "rcx", "r11", "memory", "cc" \ - ); \ - _ret; \ +#define my_syscall0(num) \ +({ \ + long _ret; \ + register long _num __asm__ ("rax") = (num); \ + \ + __asm__ volatile ( \ + "syscall\n" \ + : "=a"(_ret) \ + : "0"(_num) \ + : "rcx", "r11", "memory", "cc" \ + ); \ + _ret; \ })
-#define my_syscall1(num, arg1) \ -({ \ - long _ret; \ - register long _num __asm__ ("rax") = (num); \ - register long _arg1 __asm__ ("rdi") = (long)(arg1); \ - \ - __asm__ volatile ( \ - "syscall\n" \ - : "=a"(_ret) \ - : "r"(_arg1), \ - "0"(_num) \ - : "rcx", "r11", "memory", "cc" \ - ); \ - _ret; \ +#define my_syscall1(num, arg1) \ +({ \ + long _ret; \ + register long _num __asm__ ("rax") = (num); \ + register long _arg1 __asm__ ("rdi") = (long)(arg1); \ + \ + __asm__ volatile ( \ + "syscall\n" \ + : "=a"(_ret) \ + : "r"(_arg1), \ + "0"(_num) \ + : "rcx", "r11", "memory", "cc" \ + ); \ + _ret; \ })
-#define my_syscall2(num, arg1, arg2) \ -({ \ - long _ret; \ - 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) \ - : "r"(_arg1), "r"(_arg2), \ - "0"(_num) \ - : "rcx", "r11", "memory", "cc" \ - ); \ - _ret; \ +#define my_syscall2(num, arg1, arg2) \ +({ \ + long _ret; \ + 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) \ + : "r"(_arg1), "r"(_arg2), \ + "0"(_num) \ + : "rcx", "r11", "memory", "cc" \ + ); \ + _ret; \ })
-#define my_syscall3(num, arg1, arg2, arg3) \ -({ \ - long _ret; \ - register long _num __asm__ ("rax") = (num); \ - 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) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ - "0"(_num) \ - : "rcx", "r11", "memory", "cc" \ - ); \ - _ret; \ +#define my_syscall3(num, arg1, arg2, arg3) \ +({ \ + long _ret; \ + register long _num __asm__ ("rax") = (num); \ + 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) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ + "0"(_num) \ + : "rcx", "r11", "memory", "cc" \ + ); \ + _ret; \ })
-#define my_syscall4(num, arg1, arg2, arg3, arg4) \ -({ \ - long _ret; \ - register long _num __asm__ ("rax") = (num); \ - register long _arg1 __asm__ ("rdi") = (long)(arg1); \ - 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) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ - "0"(_num) \ - : "rcx", "r11", "memory", "cc" \ - ); \ - _ret; \ +#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +({ \ + long _ret; \ + register long _num __asm__ ("rax") = (num); \ + register long _arg1 __asm__ ("rdi") = (long)(arg1); \ + 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) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ + "0"(_num) \ + : "rcx", "r11", "memory", "cc" \ + ); \ + _ret; \ })
-#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ -({ \ - long _ret; \ - register long _num __asm__ ("rax") = (num); \ - register long _arg1 __asm__ ("rdi") = (long)(arg1); \ - register long _arg2 __asm__ ("rsi") = (long)(arg2); \ - 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) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ - "0"(_num) \ - : "rcx", "r11", "memory", "cc" \ - ); \ - _ret; \ +#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +({ \ + long _ret; \ + register long _num __asm__ ("rax") = (num); \ + register long _arg1 __asm__ ("rdi") = (long)(arg1); \ + register long _arg2 __asm__ ("rsi") = (long)(arg2); \ + 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) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ + "0"(_num) \ + : "rcx", "r11", "memory", "cc" \ + ); \ + _ret; \ })
-#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ -({ \ - long _ret; \ - register long _num __asm__ ("rax") = (num); \ - register long _arg1 __asm__ ("rdi") = (long)(arg1); \ - register long _arg2 __asm__ ("rsi") = (long)(arg2); \ - register long _arg3 __asm__ ("rdx") = (long)(arg3); \ - 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) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ - "r"(_arg6), "0"(_num) \ - : "rcx", "r11", "memory", "cc" \ - ); \ - _ret; \ +#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +({ \ + long _ret; \ + register long _num __asm__ ("rax") = (num); \ + register long _arg1 __asm__ ("rdi") = (long)(arg1); \ + register long _arg2 __asm__ ("rsi") = (long)(arg2); \ + register long _arg3 __asm__ ("rdx") = (long)(arg3); \ + 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) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ + "r"(_arg6), "0"(_num) \ + : "rcx", "r11", "memory", "cc" \ + ); \ + _ret; \ })
char **environ __attribute__((weak));
Hi Zhangjin,
On Wed, Jun 28, 2023 at 09:19:33PM +0800, Zhangjin Wu wrote:
To align with Linux code style and let scripts/checkpatch.pl happy, the multiple whitespaces in arch-<ARCH>.h files are cleaned up.
Most of them are modified by these commands automatically:
$ sed -i -e '/#define my_syscall/,/})/{s/ /\t/g}' tools/include/nolibc/arch-*.h $ sed -i -e '/#define my_syscall/,/})/{s/ *\\$/\t\\/g}' tools/include/nolibc/arch-*.h
And checked with:
$ grep ' *\\$' tools/include/nolibc/arch-*.h
I'm surprised by this one, I never saw checkpatch complain here. For me, putting a tab after a non-tab is an error. It makes the code harder to edit and re-align, and diffs are harder to read on lines whose lengths varies by +/-1 around a multiple of 8 as it makes the post-tab stuff zigzag. You made me recheck the coding style file, and there's nothing about alignment there, only about indent (and indent uses tabs here). There are also other parts which use spaces for alignment (albeit not that many), so unless there is a solid reason for changing that, I'd rather not do it, as for me it's the exact opposite of a cleanup as it will cause me quite some discomfort.
Besides, more multiple whitespaces are cleaned up:
- convert "__asm__ volatile" to "__asm__ volatile"
I totally agree on this one, it's very likely the result of a mechanical change.
- "foo _num bar" should be "foo _num bar"
In theory yes, except that for those where it appears it was only to keep all declarations aligned given that this _num was shorter by one char than all other local names. Especially when it comes to enumerating register names, you definitely want to keep them aligned. It's sufficiently difficult to avoid mistakes there, any help for visual check counts.
Willy
Hi, Willy
Hi Zhangjin,
On Wed, Jun 28, 2023 at 09:19:33PM +0800, Zhangjin Wu wrote:
To align with Linux code style and let scripts/checkpatch.pl happy, the multiple whitespaces in arch-<ARCH>.h files are cleaned up.
Most of them are modified by these commands automatically:
$ sed -i -e '/#define my_syscall/,/})/{s/ /\t/g}' tools/include/nolibc/arch-*.h $ sed -i -e '/#define my_syscall/,/})/{s/ *\\$/\t\\/g}' tools/include/nolibc/arch-*.h
And checked with:
$ grep ' *\\$' tools/include/nolibc/arch-*.h
I'm surprised by this one, I never saw checkpatch complain here. For me, putting a tab after a non-tab is an error. It makes the code harder to edit and re-align, and diffs are harder to read on lines whose lengths varies by +/-1 around a multiple of 8 as it makes the post-tab stuff zigzag. You made me recheck the coding style file, and there's nothing about alignment there, only about indent (and indent uses tabs here). There are also other parts which use spaces for alignment (albeit not that many), so unless there is a solid reason for changing that, I'd rather not do it, as for me it's the exact opposite of a cleanup as it will cause me quite some discomfort.
Willy, it is not about alignment, just rechecked it, it is code indent related:
#32: FILE: tools/include/nolibc/arch-mips.h:160: +^I $
ERROR: code indent should use tabs where possible #44: FILE: tools/include/nolibc/arch-mips.h:172: +^I "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" $
The first one is here:
register long _arg6 = (long)(arg6); \ <-- whitespaces -->\ __asm__ volatile ( \
And the second one:
: "memory", "cc", "at", "v1", "hi", "lo", \ <-spaces->"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \
These two lines indent with "one tab + more than 8 whitespaces", the other lines also have whitespaces code indent, but not more than 8, so, not reported.
I have tried to replace whitespaces with tabs in the first one, but the first one can not align with the other lines, so, the current modify method is applied.
To only touch minimal lines, this may work (reserve the post-whitespaces):
$ sed -i -e '/^\t* /{s/ /\t/g}' tools/include/nolibc/arch-*.h
It will only fix up the lines the reported. The cleanup of the post-whitespaces is not necessary and it does touch too many lines.
Sorry to disturb you with such cleanups, since I have seen the similar reports when we added the arch-arm.h (for my_syscall6), because the code style aligns with the others, so, I did touch it, but again encounter the same issues with arch-mips.h and to avoid the future reports, I checked the whole arch-xxx.h, and found more such reports, so, we prepared such a patch.
To be honest, I do prefer post-tabs to whitespaces (less key press, less code size ;-)), but as you pointed out, post-tabs have more side-effects, we shouldn't touch them, Thanks.
Besides, more multiple whitespaces are cleaned up:
- convert "__asm__ volatile" to "__asm__ volatile"
I totally agree on this one, it's very likely the result of a mechanical change.
Ok, will split it to a standalone patch, one error report one patch.
- "foo _num bar" should be "foo _num bar"
In theory yes, except that for those where it appears it was only to keep all declarations aligned given that this _num was shorter by one char than all other local names. Especially when it comes to enumerating register names, you definitely want to keep them aligned. It's sufficiently difficult to avoid mistakes there, any help for visual check counts.
Agree, let's keep it as before.
Thanks, Zhangjin
Willy
my_syscall<N> share a same long clobber list, define a macro for them.
Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/include/nolibc/arch-loongarch.h | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-)
diff --git a/tools/include/nolibc/arch-loongarch.h b/tools/include/nolibc/arch-loongarch.h index 292d6a58dc87..fbb4844f7993 100644 --- a/tools/include/nolibc/arch-loongarch.h +++ b/tools/include/nolibc/arch-loongarch.h @@ -23,6 +23,10 @@ */ #define __ARCH_WANT_SYS_PSELECT6
+#define SYSCALL_CLOBBERLIST \ + "memory", "$t0", "$t1", "$t2", "$t3", \ + "$t4", "$t5", "$t6", "$t7", "$t8" + #define my_syscall0(num) \ ({ \ register long _num __asm__ ("a7") = (num); \ @@ -32,8 +36,7 @@ "syscall 0\n" \ : "=r"(_arg1) \ : "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) @@ -47,8 +50,7 @@ "syscall 0\n" \ : "+r"(_arg1) \ : "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) @@ -64,8 +66,7 @@ : "+r"(_arg1) \ : "r"(_arg2), \ "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) @@ -82,8 +83,7 @@ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), \ "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) @@ -101,8 +101,7 @@ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) @@ -121,8 +120,7 @@ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) @@ -142,8 +140,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" \ + : SYSCALL_CLOBBERLIST \ ); \ _arg1; \ })
On Wed, Jun 28, 2023 at 09:22:21PM +0800, Zhangjin Wu wrote:
my_syscall<N> share a same long clobber list, define a macro for them.
Signed-off-by: Zhangjin Wu falcon@tinylab.org
tools/include/nolibc/arch-loongarch.h | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-)
diff --git a/tools/include/nolibc/arch-loongarch.h b/tools/include/nolibc/arch-loongarch.h index 292d6a58dc87..fbb4844f7993 100644 --- a/tools/include/nolibc/arch-loongarch.h +++ b/tools/include/nolibc/arch-loongarch.h @@ -23,6 +23,10 @@ */ #define __ARCH_WANT_SYS_PSELECT6 +#define SYSCALL_CLOBBERLIST \
- "memory", "$t0", "$t1", "$t2", "$t3", \
- "$t4", "$t5", "$t6", "$t7", "$t8"
That's a good idea, but please be careful when adding macro definitions, we're in code that is used by user space we have no control on, and we're polluting the end user's macro namespace with plenty of names. While one could argue that it's unlikely that some program already defines and uses SYSCALL_CLOBBERLIST, actually with low-level code it's fairly possible.
Till now most of the definitions were for stuff that user-space really needs (e.g. STDIN_FILENO, various integer limits). If we start to declare random macros for internal use, at least we should probably prefix them with _NOLIBC_ or something like this to avoid the risk of collision.
Willy
On Wed, Jun 28, 2023 at 09:22:21PM +0800, Zhangjin Wu wrote:
my_syscall<N> share a same long clobber list, define a macro for them.
Signed-off-by: Zhangjin Wu falcon@tinylab.org
tools/include/nolibc/arch-loongarch.h | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-)
diff --git a/tools/include/nolibc/arch-loongarch.h b/tools/include/nolibc/arch-loongarch.h index 292d6a58dc87..fbb4844f7993 100644 --- a/tools/include/nolibc/arch-loongarch.h +++ b/tools/include/nolibc/arch-loongarch.h @@ -23,6 +23,10 @@ */ #define __ARCH_WANT_SYS_PSELECT6 +#define SYSCALL_CLOBBERLIST \
- "memory", "$t0", "$t1", "$t2", "$t3", \
- "$t4", "$t5", "$t6", "$t7", "$t8"
That's a good idea, but please be careful when adding macro definitions, we're in code that is used by user space we have no control on, and we're polluting the end user's macro namespace with plenty of names. While one could argue that it's unlikely that some program already defines and uses SYSCALL_CLOBBERLIST, actually with low-level code it's fairly possible.
Till now most of the definitions were for stuff that user-space really needs (e.g. STDIN_FILENO, various integer limits). If we start to declare random macros for internal use, at least we should probably prefix them with _NOLIBC_ or something like this to avoid the risk of collision.
Ok, _NOLIBC_ prefix will be applied, Thanks.
Best regards, Zhangjin
Willy
my_syscall<N> share a 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 1fd1eedc12a6..55a9f01825e0 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 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" \ + : 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" \ + : 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" \ + : 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" \ + : 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" \ + : 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" \ + : 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 | 25 +++++++++++++++++++++++++ tools/include/nolibc/nolibc.h | 9 ++++----- 2 files changed, 29 insertions(+), 5 deletions(-)
diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h index 55a9f01825e0..a8b33d6914a4 100644 --- a/tools/include/nolibc/arch-mips.h +++ b/tools/include/nolibc/arch-mips.h @@ -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) \ + : 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()
Hi Zhangjin,
On Wed, Jun 28, 2023 at 09:37:29PM +0800, Zhangjin Wu wrote:
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().
Very interesting, I didn't manage to make it work previously. Did you test it to confirm that it works ? I guess so but since you didn't mention, I preferred to ask.
Thanks! Willy
Hi, Willy
Hi Zhangjin,
On Wed, Jun 28, 2023 at 09:37:29PM +0800, Zhangjin Wu wrote:
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().
Very interesting, I didn't manage to make it work previously. Did you test it to confirm that it works ? I guess so but since you didn't mention, I preferred to ask.
Yes, I'm curious too ;-)
we did add the mmap test cases and run it for mips, as Thomas suggested, we pass a none-zero pa_offset to mmap() to make sure the 6th argument is used.
I just re-tested it for mips and printed something like this:
44 mmap_bad = <0xffffffff> EINVAL [OK] 45 munmap_bad = -1 EINVAL [OK] 46 mmap_munmap_good pa_offset: 8192 length: 1 file_size: 12287 = 0 [OK] 47 open_tty = 3 [OK] 48 open_blah = -1 ENOENT [OK]
And I also checked the mips support of musl, it evan provide a __syscall7, so, it should be ok ;-)
The only difference is, musl provide a different clobber list for '__mips_isa_rev >= 6', I didn't look into the details yet: https://elixir.bootlin.com/musl/latest/source/arch/mips/syscall_arch.h
Best regards, Zhangjin
Thanks! Willy
To support syscalls (e.g. mmap()) who return a pointer and to allow the pointer as big as possible, we should convert the negated errno value to unsigned long (uintptr_t), otherwise, in signed long, a potential big pointer (whose highest bit is 1) will be treated as a failure.
tools/include/nolibc/errno.h defines the MAX_ERRNO, let's use it directly. after converting to unsigned long, the negative errno value from -1 to -MAX_ERRNO becomes something like '~1 + 1' (every bit is 1) to '~MAX_ERRNO + 1', '~1 + 1' is the biggest, '~MAX_ERRNO + 1' is the smallest, so, the check becomes:
if (ret <= (unsigned long)-1 && ret >= (unsigned long)-MAX_ERRNO) { ... }
Since (unsigned long)-1 is the biggest unsigned long value, it is always true if bigger than (unsigned long)-MAX_ERRNO, so, just reserve the following check is enough:
if (ret >= (unsigned long)-MAX_ERRNO) { ... }
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 | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 53bc3ad6593e..b6125e600dc2 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -28,13 +28,16 @@ #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 in [-MAX_ERRNO, -1] + */ 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; }
On Wed, Jun 28, 2023 at 09:39:56PM +0800, Zhangjin Wu wrote:
To support syscalls (e.g. mmap()) who return a pointer and to allow the pointer as big as possible, we should convert the negated errno value to unsigned long (uintptr_t), otherwise, in signed long, a potential big pointer (whose highest bit is 1) will be treated as a failure.
tools/include/nolibc/errno.h defines the MAX_ERRNO, let's use it directly.
It might or might not work, it's an ABI change that, if validated, at least needs a much more detailed explanation. What matters is not what errno values we're willing to consider as an error, but what the *syscalls* themselves return as an error. If a syscall says "< 0 is an error equal to -errno", it means that we must treat it as an error, and extract its value to get errno. If that errno is larger than MAX_ERRNO it just means we don't know what the error is.
Syscalls that return pointer use that -MAX_ERRNO range to encode errors (such as mmap()). I just do not know if there is a convention saying that other ones also restrict themselves to that range or not. If you find some info which guarantees that it's the case for all of them, then by all means let's proceed like this, but in this case it should be mentioned in the comment why we think it's valid to do this. For now it's presented as an opportunity only.
Also, the rest of the commit message regarding uintptr_t (which we don't use), bit values and modular arithmetics is extremely confusing and not needed at all. What matters is only to know if we need to consider only values -MAX_ERRNO..-1 as error or all negative ones. If so, then it's obvious that ret >= (unsigned long)-MAX_ERRNO catches them all, as the current mmap() function already does with -4095UL.
I just don't know where to check if we can generalize that test. In the worst case we could have two __sys_ret(), the current one and a second one for pointers. But I would suspect we could generalize due to ptrace, as there it makes sense to be able to detect failures, even unknown ones. I just need something more convincing than an intuition for a commit message and to take such a change :-/
Thanks! Willy
Hi, Willy
On Wed, Jun 28, 2023 at 09:39:56PM +0800, Zhangjin Wu wrote:
To support syscalls (e.g. mmap()) who return a pointer and to allow the pointer as big as possible, we should convert the negated errno value to unsigned long (uintptr_t), otherwise, in signed long, a potential big pointer (whose highest bit is 1) will be treated as a failure.
tools/include/nolibc/errno.h defines the MAX_ERRNO, let's use it directly.
It might or might not work, it's an ABI change that, if validated, at least needs a much more detailed explanation. What matters is not what errno values we're willing to consider as an error, but what the *syscalls* themselves return as an error. If a syscall says "< 0 is an error equal to -errno", it means that we must treat it as an error, and extract its value to get errno. If that errno is larger than MAX_ERRNO it just means we don't know what the error is.
Yes, we do need to find a 'spec' or 'standard' to follow.
welcome suggestions from Arnd, Thomas and also David.
Syscalls that return pointer use that -MAX_ERRNO range to encode errors (such as mmap()). I just do not know if there is a convention saying that other ones also restrict themselves to that range or not. If you find some info which guarantees that it's the case for all of them, then by all means let's proceed like this, but in this case it should be mentioned in the comment why we think it's valid to do this. For now it's presented as an opportunity only.
Currently, I only found a prove-in-use case in musl:
https://elixir.bootlin.com/musl/latest/source/src/internal/syscall_ret.c:
#include <errno.h> #include "syscall.h"
long __syscall_ret(unsigned long r) { if (r > -4096UL) { errno = -r; return -1; } return r; }
Our new implementation (based on the one used by mmap()) is almostly the same as musl. Not sure if this is enough. I have tried to 'git blame' on __syscall_ret() of musl to find some clue, but failed, because the function has been added before importing into its git repo.
Also, the rest of the commit message regarding uintptr_t (which we don't use), bit values and modular arithmetics is extremely confusing and not needed at all. What matters is only to know if we need to consider only values -MAX_ERRNO..-1 as error or all negative ones. If so, then it's obvious that ret >= (unsigned long)-MAX_ERRNO catches them all, as the current mmap() function already does with -4095UL.
Yes, will clean up the commit message, but at first, let's continue get more information about which one is ok:
- -MAX_ERRNO..-1 as error, for sys_mmap (we know in nolibc) currently
- all negative ones, for others currently
I just don't know where to check if we can generalize that test. In the worst case we could have two __sys_ret(), the current one and a second one for pointers. But I would suspect we could generalize due to ptrace, as there it makes sense to be able to detect failures, even unknown ones. I just need something more convincing than an intuition for a commit message and to take such a change :-/
Of course, must be clear enough.
Best regards, Zhangjin
Thanks! Willy
On Mon, Jul 03, 2023 at 04:36:51PM +0800, Zhangjin Wu wrote:
Syscalls that return pointer use that -MAX_ERRNO range to encode errors (such as mmap()). I just do not know if there is a convention saying that other ones also restrict themselves to that range or not. If you find some info which guarantees that it's the case for all of them, then by all means let's proceed like this, but in this case it should be mentioned in the comment why we think it's valid to do this. For now it's presented as an opportunity only.
Currently, I only found a prove-in-use case in musl:
https://elixir.bootlin.com/musl/latest/source/src/internal/syscall_ret.c: #include <errno.h> #include "syscall.h" long __syscall_ret(unsigned long r) { if (r > -4096UL) { errno = -r; return -1; } return r; }
Our new implementation (based on the one used by mmap()) is almostly the same as musl. Not sure if this is enough. I have tried to 'git blame' on __syscall_ret() of musl to find some clue, but failed, because the function has been added before importing into its git repo.
OK, we already used the glibc-saved registers in the past to determine the official list of clobbered registers (and the ABI spec was even updated based on this). Here, musl is sufficiently deployed to consider this as valid. You can simply go that route and mention in the commit message that while you found no official reference stating that this is valid for int/long returns, you found at least one other implementation relying on this (i.e. if the kernel ever changes it will cause breakage).
Also, the rest of the commit message regarding uintptr_t (which we don't use), bit values and modular arithmetics is extremely confusing and not needed at all. What matters is only to know if we need to consider only values -MAX_ERRNO..-1 as error or all negative ones. If so, then it's obvious that ret >= (unsigned long)-MAX_ERRNO catches them all, as the current mmap() function already does with -4095UL.
Yes, will clean up the commit message, but at first, let's continue get more information about which one is ok:
-MAX_ERRNO..-1 as error, for sys_mmap (we know in nolibc) currently
all negative ones, for others currently
You can double-check in glibc for example, but I'm starting to guess you'll find the same test as above, i.e. errors are exclusively >-4096, regardless of the expected return type.
Thanks! Willy
Hi, Willy
On Mon, Jul 03, 2023 at 04:36:51PM +0800, Zhangjin Wu wrote:
Syscalls that return pointer use that -MAX_ERRNO range to encode errors (such as mmap()). I just do not know if there is a convention saying that other ones also restrict themselves to that range or not. If you find some info which guarantees that it's the case for all of them, then by all means let's proceed like this, but in this case it should be mentioned in the comment why we think it's valid to do this. For now it's presented as an opportunity only.
Currently, I only found a prove-in-use case in musl:
https://elixir.bootlin.com/musl/latest/source/src/internal/syscall_ret.c: #include <errno.h> #include "syscall.h" long __syscall_ret(unsigned long r) { if (r > -4096UL) { errno = -r; return -1; } return r; }
Our new implementation (based on the one used by mmap()) is almostly the same as musl. Not sure if this is enough. I have tried to 'git blame' on __syscall_ret() of musl to find some clue, but failed, because the function has been added before importing into its git repo.
OK, we already used the glibc-saved registers in the past to determine the official list of clobbered registers (and the ABI spec was even updated based on this). Here, musl is sufficiently deployed to consider this as valid. You can simply go that route and mention in the commit message that while you found no official reference stating that this is valid for int/long returns, you found at least one other implementation relying on this (i.e. if the kernel ever changes it will cause breakage).
ok.
Also, the rest of the commit message regarding uintptr_t (which we don't use), bit values and modular arithmetics is extremely confusing and not needed at all. What matters is only to know if we need to consider only values -MAX_ERRNO..-1 as error or all negative ones. If so, then it's obvious that ret >= (unsigned long)-MAX_ERRNO catches them all, as the current mmap() function already does with -4095UL.
Yes, will clean up the commit message, but at first, let's continue get more information about which one is ok:
-MAX_ERRNO..-1 as error, for sys_mmap (we know in nolibc) currently
all negative ones, for others currently
You can double-check in glibc for example, but I'm starting to guess you'll find the same test as above, i.e. errors are exclusively >-4096, regardless of the expected return type.
Your guest is definitely true ;-)
Glibc has the same logic in its INLINE_SYSCALL() macro:
https://elixir.bootlin.com/glibc/latest/source/sysdeps/unix/sysv/linux/sysde...
#undef INTERNAL_SYSCALL_ERROR_P #define INTERNAL_SYSCALL_ERROR_P(val) \ ((unsigned long int) (val) > -4096UL)
#ifndef SYSCALL_ERROR_LABEL # define SYSCALL_ERROR_LABEL(sc_err) \ ({ \ __set_errno (sc_err); \ -1L; \ }) #endif
/* Define a macro which expands into the inline wrapper code for a system call. It sets the errno and returns -1 on a failure, or the syscall return value otherwise. */ #undef INLINE_SYSCALL #define INLINE_SYSCALL(name, nr, args...) \ ({ \ long int sc_ret = INTERNAL_SYSCALL (name, nr, args); \ __glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (sc_ret)) \ ? SYSCALL_ERROR_LABEL (INTERNAL_SYSCALL_ERRNO (sc_ret)) \ : sc_ret; \ })
Nothing differs.
But 'git blame' has no clue to any 'spec' or 'standard' either.
- fcb78a55058fd, linux: Consolidate INLINE_SYSCALL
Moved all of the arch specific INTERNAL_SYSCALL_ERROR_P() to common header
- 369b849f1a382, sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h (INTERNAL_SYSCALL,...
Firstly defined this macro: INTERNAL_SYSCALL_ERROR_P()
$ git show 369b849f1a3 | grep "define.*INTERNAL_SYSCALL_ERROR_P" +#define INTERNAL_SYSCALL_ERROR_P(val) ((unsigned int) (val) >= 0xfffff001u) +#define INTERNAL_SYSCALL_ERROR_P(val) ((unsigned int) (val) >= 0xfffff001u) +#define INTERNAL_SYSCALL_ERROR_P(val) ((unsigned long) (val) >= -515L) +#define INTERNAL_SYSCALL_ERROR_P(val) ((unsigned long) (val) >= -4095L)
Willy, I plan to further use something like, is it ok for you?
tools/include/nolibc/errno.h:
-#define MAX_ERRNO 4095 +#define MAX_ERRNO 4095UL
tools/include/nolibc/sys.h:
/* Syscall return helper for library routines * set errno as -ret when ret in [-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(unsigned long ret) { if (ret >= -MAX_ERRNO) { SET_ERRNO(-(long)ret); return -1; } return ret; }
Or we also directly use 4096UL here.
static __inline__ __attribute__((unused, always_inline)) long __sysret(unsigned long ret) { if (ret > -4096UL) { SET_ERRNO(-(long)ret); return -1; } return ret; }
Best regards, Zhangjin
Thanks! Willy
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 __sysret() to convert the calling of sys_map() to oneline code
Signed-off-by: Zhangjin Wu falcon@tinylab.org --- tools/include/nolibc/sys.h | 24 +----------------------- tools/include/nolibc/types.h | 6 ++++++ 2 files changed, 7 insertions(+), 23 deletions(-)
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index b6125e600dc2..e0ac95a4bfa1 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -632,26 +632,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) @@ -662,20 +647,13 @@ 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
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..bed62da7877c 100644 --- a/tools/include/nolibc/types.h +++ b/tools/include/nolibc/types.h @@ -10,6 +10,7 @@ #include "std.h" #include <linux/time.h> #include <linux/stat.h> +#include <linux/mman.h>
/* Only the generic macros and types may be defined here. The arch-specific @@ -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
On Wed, Jun 28, 2023 at 09:41:13PM +0800, Zhangjin Wu wrote:
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));
}
One point regarding this one. By doing so, we're hard-coding the fact that we consider that MAP_FAILED is always -1. I'm not necessarily against it, but this implication can be confusing for those searching where it's being set. I would suggest putting a comment before the mmap() function saying:
/* 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. */
Since it's an assumed choice that theoretically could affect portability, it should be reflected in the commit message as well (and we all know it does not have any impact).
Thanks! Willy
On Wed, Jun 28, 2023 at 09:41:13PM +0800, Zhangjin Wu wrote:
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));
}
One point regarding this one. By doing so, we're hard-coding the fact that we consider that MAP_FAILED is always -1. I'm not necessarily against it, but this implication can be confusing for those searching where it's being set. I would suggest putting a comment before the mmap() function saying:
/* 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.
*/
Since it's an assumed choice that theoretically could affect portability, it should be reflected in the commit message as well (and we all know it does not have any impact).
Yeah, we do need such a comment and commit message note, thanks.
Best regards, Zhangjin
Thanks! Willy
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 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 486334981e60..34af802dadfd 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -361,6 +361,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 brk, let's support such case.
EXPECT_PTRNE() is used to expect sbrk() always successfully getting the current brk.
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 34af802dadfd..80ab29e2887c 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -630,6 +630,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;
Three mmap/munmap related test cases are added:
- mmap_bad: the length argument must be greater than 0, otherwise, fail with -EINVAL.
- munmap_bad: invalid (void *)-1 address fail with -EINVAL.
- mmap_munmap_good: mmap() a file with good offset and then munmap().
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:
- /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'
- the others, for kernel without procfs let it pass even with 'worst case' kernel configs
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 | 56 ++++++++++++++++++++ 1 file changed, 56 insertions(+)
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 80ab29e2887c..b178bfa29ad9 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -592,6 +592,59 @@ 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; + static const char * const files[] = { + "/proc/1/exe", "/proc/self/exe", + "/init", "/sbin/init", "/etc/init", "/bin/init", "/bin/sh", + 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 = 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. */ @@ -666,6 +719,9 @@ 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(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;
Hi Zhangjin,
On Wed, Jun 28, 2023 at 09:51:57PM +0800, Zhangjin Wu wrote:
Three mmap/munmap related test cases are added:
mmap_bad: the length argument must be greater than 0, otherwise, fail with -EINVAL.
munmap_bad: invalid (void *)-1 address fail with -EINVAL.
mmap_munmap_good: mmap() a file with good offset and then munmap().
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:
/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'
Strictly speaking, if your executable is not readable (e.g. chmod 111 due to a restrictive umask) it will also fail that one.
- the others, for kernel without procfs let it pass even with 'worst case' kernel configs
You should include /dev/zero, which is commonly used to allocate anonymous memory and is more likely present and readable than any of the other files. And another file of choice is obviously argv[0] ;-) In this case you don't need any of the other extra ones. Thus I could suggest that you try in this order:
/dev/zero, /proc/self/exe, /proc/1/exe, argv[0]
and be done with it. That doesn't prevent one from extending the list if really needed later, but I doubt it would be needed. Also, it's already arranged in a read-write, then read-only fallbacks mode, so if we later need to add more complex tests involving writes, the writable /dev/zero will have precedence.
Willy
Hi Zhangjin,
On Wed, Jun 28, 2023 at 09:51:57PM +0800, Zhangjin Wu wrote:
Three mmap/munmap related test cases are added:
mmap_bad: the length argument must be greater than 0, otherwise, fail with -EINVAL.
munmap_bad: invalid (void *)-1 address fail with -EINVAL.
mmap_munmap_good: mmap() a file with good offset and then munmap().
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:
/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'
Strictly speaking, if your executable is not readable (e.g. chmod 111 due to a restrictive umask) it will also fail that one.
ok.
- the others, for kernel without procfs let it pass even with 'worst case' kernel configs
You should include /dev/zero, which is commonly used to allocate anonymous memory and is more likely present and readable than any of the other files. And another file of choice is obviously argv[0] ;-) In this case you don't need any of the other extra ones. Thus I could suggest that you try in this order:
/dev/zero, /proc/self/exe, /proc/1/exe, argv[0]
and be done with it. That doesn't prevent one from extending the list if really needed later, but I doubt it would be needed. Also, it's already arranged in a read-write, then read-only fallbacks mode, so if we later need to add more complex tests involving writes, the writable /dev/zero will have precedence.
Cool, both /dev/zero and argv[0] are very good candidates ;-)
Just verified both of them, works perfectly.
- /dev/zero
we need to mknod it in prepare() and also, in test_mmap_munmap(), stat() return a zero size of /dev/zero, in this case, we should assign a non-zero file_size ourselves.
- file_size = stat_buf.st_size; + /* file size of the special /dev/zero is 0, let's assign one manually */ + if (i == 0) + file_size = 3*page_size - 1; + else + file_size = stat_buf.st_size;
- argv[0]
since nolibc has no realpath() currently, we can simply support the current path and the absolute path like this:
nolibc-test.c:
/* assigned as argv[0] in main(), will be used by some tests */ static char exe[PATH_MAX + 1];
main():
/* get absolute path of myself, nolibc has no realpath() currently */ #ifndef NOLIBC realpath(argv[0], exe); #else /* assume absolute path has no "./" */ if (strncmp(argv[0], "./", 2) != 0) strncat(exe, argv[0], strlen(argv[0]) + 1); else { pwd = getenv("PWD"); /* skip the ending '\0' */ strncat(exe, getenv("PWD"), strlen(pwd)); /* skip the first '.' */ strncat(exe, argv[0] + 1, strlen(argv[0])); } #endif
A full functional realpath() is a little complex, such as '../' support and even symlink support, let's delay its requirement at current stage ;-)
one or both of them may also help the other test cases:
- chroot_exe (used '/init' before)
CASE_TEST(chroot_exe); EXPECT_SYSER(1, chroot(proc ? "/proc/self/exe" : exe), -1, ENOTDIR); break;
- chmod_exe (replace the one: chmod_tmpdir in another patchset)
CASE_TEST(chmod_exe); EXPECT_SYSZR(1, chmod(proc ? "/proc/self/exe" : exe, 0555)); break;
It should be safe enough to only remove the writable attribute for the test program.
- stat_timestamps (used '/init' before)
if (stat("/proc/self/", &st) && stat(exe, &st) && stat("/dev/zero", &st) && stat("/", &st))
Will update the related patches with them.
Thanks, Zhangjin
Willy
On Mon, Jul 03, 2023 at 02:03:23PM +0800, Zhangjin Wu wrote:
- the others, for kernel without procfs let it pass even with 'worst case' kernel configs
You should include /dev/zero, which is commonly used to allocate anonymous memory and is more likely present and readable than any of the other files. And another file of choice is obviously argv[0] ;-) In this case you don't need any of the other extra ones. Thus I could suggest that you try in this order:
/dev/zero, /proc/self/exe, /proc/1/exe, argv[0]
and be done with it. That doesn't prevent one from extending the list if really needed later, but I doubt it would be needed. Also, it's already arranged in a read-write, then read-only fallbacks mode, so if we later need to add more complex tests involving writes, the writable /dev/zero will have precedence.
Cool, both /dev/zero and argv[0] are very good candidates ;-)
Just verified both of them, works perfectly.
/dev/zero
we need to mknod it in prepare()
Indeed.
and also, in test_mmap_munmap(), stat() return a zero size of /dev/zero, in this case, we should assign a non-zero file_size ourselves.
- file_size = stat_buf.st_size; + /* file size of the special /dev/zero is 0, let's assign one manually */ + if (i == 0) + file_size = 3*page_size - 1; + else + file_size = stat_buf.st_size;
OK but why this -1 ? That doesn't sound right, unless you explicitly want a file size that's not multiple of a page size for whatever reason ?
argv[0]
since nolibc has no realpath() currently, we can simply support the current path and the absolute path like this:
nolibc-test.c:
/* assigned as argv[0] in main(), will be used by some tests */ static char exe[PATH_MAX + 1];
main():
/* get absolute path of myself, nolibc has no realpath() currently */ #ifndef NOLIBC realpath(argv[0], exe); #else /* assume absolute path has no "./" */ if (strncmp(argv[0], "./", 2) != 0) strncat(exe, argv[0], strlen(argv[0]) + 1); else { pwd = getenv("PWD"); /* skip the ending '\0' */ strncat(exe, getenv("PWD"), strlen(pwd)); /* skip the first '.' */ strncat(exe, argv[0] + 1, strlen(argv[0])); } #endif
No, please, not like this. Just copy argv[0] (the pointer not the contents) and you're fine:
static const char *argv0;
int main(int argc, char **argv, char **envp) { argv0 = argv[0]; ... }
Nothing more, nothing less. Your program will always have its correct path when being called unless someone purposely forces it to something different, which is not our concern at all since this is a test program. And I'd rather call it "argv0" which exactly tells us what it contains than "exe" which can be misleading for that precise reason.
A full functional realpath() is a little complex, such as '../' support and even symlink support, let's delay its requirement at current stage ;-)
Please do not even engage into this, and keep in mind that the sole purpose of this test program is to help developers simply add tests to the set of existing ones. If the program becomes complex for doing stuff that is out of its scope, it will become much harder to extend and users will lose interest and motivation for updating it.
one or both of them may also help the other test cases:
chroot_exe (used '/init' before)
CASE_TEST(chroot_exe); EXPECT_SYSER(1, chroot(proc ? "/proc/self/exe" : exe), -1, ENOTDIR); break;
chmod_exe (replace the one: chmod_tmpdir in another patchset)
CASE_TEST(chmod_exe); EXPECT_SYSZR(1, chmod(proc ? "/proc/self/exe" : exe, 0555)); break;
It should be safe enough to only remove the writable attribute for the test program.
stat_timestamps (used '/init' before)
if (stat("/proc/self/", &st) && stat(exe, &st) && stat("/dev/zero", &st) && stat("/", &st))
Indeed, why not!
Will update the related patches with them.
OK thanks! Willy
Hi, Willy
On Mon, Jul 03, 2023 at 02:03:23PM +0800, Zhangjin Wu wrote:
- the others, for kernel without procfs let it pass even with 'worst case' kernel configs
You should include /dev/zero, which is commonly used to allocate anonymous memory and is more likely present and readable than any of the other files. And another file of choice is obviously argv[0] ;-) In this case you don't need any of the other extra ones. Thus I could suggest that you try in this order:
/dev/zero, /proc/self/exe, /proc/1/exe, argv[0]
and be done with it. That doesn't prevent one from extending the list if really needed later, but I doubt it would be needed. Also, it's already arranged in a read-write, then read-only fallbacks mode, so if we later need to add more complex tests involving writes, the writable /dev/zero will have precedence.
Cool, both /dev/zero and argv[0] are very good candidates ;-)
Just verified both of them, works perfectly.
/dev/zero
we need to mknod it in prepare()
Indeed.
and also, in test_mmap_munmap(), stat() return a zero size of /dev/zero, in this case, we should assign a non-zero file_size ourselves.
- file_size = stat_buf.st_size; + /* file size of the special /dev/zero is 0, let's assign one manually */ + if (i == 0) + file_size = 3*page_size - 1; + else + file_size = stat_buf.st_size;
OK but why this -1 ? That doesn't sound right, unless you explicitly want a file size that's not multiple of a page size for whatever reason ?
Just make sure the file size is a litle random, not just aligned with PAGE_SIZE, it is ok without '-1' ;-)
argv[0]
since nolibc has no realpath() currently, we can simply support the current path and the absolute path like this:
nolibc-test.c:
/* assigned as argv[0] in main(), will be used by some tests */ static char exe[PATH_MAX + 1];
main():
/* get absolute path of myself, nolibc has no realpath() currently */ #ifndef NOLIBC realpath(argv[0], exe); #else /* assume absolute path has no "./" */ if (strncmp(argv[0], "./", 2) != 0) strncat(exe, argv[0], strlen(argv[0]) + 1); else { pwd = getenv("PWD"); /* skip the ending '\0' */ strncat(exe, getenv("PWD"), strlen(pwd)); /* skip the first '.' */ strncat(exe, argv[0] + 1, strlen(argv[0])); } #endif
No, please, not like this. Just copy argv[0] (the pointer not the contents) and you're fine:
static const char *argv0; int main(int argc, char **argv, char **envp) { argv0 = argv[0]; ... }
Nothing more, nothing less. Your program will always have its correct path when being called unless someone purposely forces it to something different, which is not our concern at all since this is a test program. And I'd rather call it "argv0" which exactly tells us what it contains than "exe" which can be misleading for that precise reason.
Yeah, locally, I just used a global argv0 pointer directly, but chroot_exe("./nolibc-test") not work when run 'libc-test' in host system, that is why I tried to get an absolute path ;-)
CASE_TEST(chroot_exe); EXPECT_SYSER(1, chroot(exe), -1, ENOTDIR); break;
-->
19 chroot_exe = -1 ENOENT != (-1 ENOTDIR) [FAIL]
I removed the "proc ?" check manually to test if it also work with CONFIG_PROC_FS=n. it doesn't work, without absolute path, we need to add the ENOENT errno back to the errno check list.
I'm not sure if the other syscalls require an absolute path, so, the realpath() is called in this proposed method.
A full functional realpath() is a little complex, such as '../' support and even symlink support, let's delay its requirement at current stage ;-)
Please do not even engage into this, and keep in mind that the sole purpose of this test program is to help developers simply add tests to the set of existing ones. If the program becomes complex for doing stuff that is out of its scope, it will become much harder to extend and users will lose interest and motivation for updating it.
one or both of them may also help the other test cases:
chroot_exe (used '/init' before)
CASE_TEST(chroot_exe); EXPECT_SYSER(1, chroot(proc ? "/proc/self/exe" : exe), -1, ENOTDIR); break;
chmod_exe (replace the one: chmod_tmpdir in another patchset)
CASE_TEST(chmod_exe); EXPECT_SYSZR(1, chmod(proc ? "/proc/self/exe" : exe, 0555)); break;
It should be safe enough to only remove the writable attribute for the test program.
stat_timestamps (used '/init' before)
if (stat("/proc/self/", &st) && stat(exe, &st) && stat("/dev/zero", &st) && stat("/", &st))
Indeed, why not!
Ok, without absolute path, the chroot_exe() will be changed back to something like this:
CASE_TEST(chroot_exe); EXPECT_SYSER2(1, chroot(proc ? "/proc/self/exe" : argv0), -1, ENOTDIR, ENOENT); break;
Best regards, Zhangjin
Will update the related patches with them.
OK thanks! Willy
On 2023-07-03 16:06:47+0800, Zhangjin Wu wrote:
Hi, Willy
[..]
argv[0]
since nolibc has no realpath() currently, we can simply support the current path and the absolute path like this:
nolibc-test.c:
/* assigned as argv[0] in main(), will be used by some tests */ static char exe[PATH_MAX + 1];
main():
/* get absolute path of myself, nolibc has no realpath() currently */ #ifndef NOLIBC realpath(argv[0], exe); #else /* assume absolute path has no "./" */ if (strncmp(argv[0], "./", 2) != 0) strncat(exe, argv[0], strlen(argv[0]) + 1); else { pwd = getenv("PWD"); /* skip the ending '\0' */ strncat(exe, getenv("PWD"), strlen(pwd)); /* skip the first '.' */ strncat(exe, argv[0] + 1, strlen(argv[0])); } #endif
No, please, not like this. Just copy argv[0] (the pointer not the contents) and you're fine:
static const char *argv0; int main(int argc, char **argv, char **envp) { argv0 = argv[0]; ... }
Nothing more, nothing less. Your program will always have its correct path when being called unless someone purposely forces it to something different, which is not our concern at all since this is a test program. And I'd rather call it "argv0" which exactly tells us what it contains than "exe" which can be misleading for that precise reason.
Yeah, locally, I just used a global argv0 pointer directly, but chroot_exe("./nolibc-test") not work when run 'libc-test' in host system, that is why I tried to get an absolute path ;-)
CASE_TEST(chroot_exe); EXPECT_SYSER(1, chroot(exe), -1, ENOTDIR); break; --> 19 chroot_exe = -1 ENOENT != (-1 ENOTDIR) [FAIL]
I removed the "proc ?" check manually to test if it also work with CONFIG_PROC_FS=n. it doesn't work, without absolute path, we need to add the ENOENT errno back to the errno check list.
I'm not sure if the other syscalls require an absolute path, so, the realpath() is called in this proposed method.
A full functional realpath() is a little complex, such as '../' support and even symlink support, let's delay its requirement at current stage ;-)
Please do not even engage into this, and keep in mind that the sole purpose of this test program is to help developers simply add tests to the set of existing ones. If the program becomes complex for doing stuff that is out of its scope, it will become much harder to extend and users will lose interest and motivation for updating it.
one or both of them may also help the other test cases:
chroot_exe (used '/init' before)
CASE_TEST(chroot_exe); EXPECT_SYSER(1, chroot(proc ? "/proc/self/exe" : exe), -1, ENOTDIR); break;
chmod_exe (replace the one: chmod_tmpdir in another patchset)
CASE_TEST(chmod_exe); EXPECT_SYSZR(1, chmod(proc ? "/proc/self/exe" : exe, 0555)); break;
It should be safe enough to only remove the writable attribute for the test program.
stat_timestamps (used '/init' before)
if (stat("/proc/self/", &st) && stat(exe, &st) && stat("/dev/zero", &st) && stat("/", &st))
Indeed, why not!
Ok, without absolute path, the chroot_exe() will be changed back to something like this:
CASE_TEST(chroot_exe); EXPECT_SYSER2(1, chroot(proc ? "/proc/self/exe" : argv0), -1, ENOTDIR, ENOENT); break;
Are you sure the ENOENT is really correct? I played with this before and got ENOENT because before the chroot test we have a testcase that does chdir("/"). And therefore the relative name in argv[0] was not resolving correctly anymore against the changed working directory.
(You can also test this by executing *only* the chroot test and it should work)
In general chroot() should work just fine with relative paths.
This is really a lot of complexity and discussion only to avoid depending on procfs for the tests.
Thomas
Hi, Thomas
On 2023-07-03 16:06:47+0800, Zhangjin Wu wrote:
Hi, Willy
[..]
argv[0]
since nolibc has no realpath() currently, we can simply support the current path and the absolute path like this:
nolibc-test.c:
/* assigned as argv[0] in main(), will be used by some tests */ static char exe[PATH_MAX + 1];
main():
/* get absolute path of myself, nolibc has no realpath() currently */ #ifndef NOLIBC realpath(argv[0], exe); #else /* assume absolute path has no "./" */ if (strncmp(argv[0], "./", 2) != 0) strncat(exe, argv[0], strlen(argv[0]) + 1); else { pwd = getenv("PWD"); /* skip the ending '\0' */ strncat(exe, getenv("PWD"), strlen(pwd)); /* skip the first '.' */ strncat(exe, argv[0] + 1, strlen(argv[0])); } #endif
No, please, not like this. Just copy argv[0] (the pointer not the contents) and you're fine:
static const char *argv0; int main(int argc, char **argv, char **envp) { argv0 = argv[0]; ... }
Nothing more, nothing less. Your program will always have its correct path when being called unless someone purposely forces it to something different, which is not our concern at all since this is a test program. And I'd rather call it "argv0" which exactly tells us what it contains than "exe" which can be misleading for that precise reason.
Yeah, locally, I just used a global argv0 pointer directly, but chroot_exe("./nolibc-test") not work when run 'libc-test' in host system, that is why I tried to get an absolute path ;-)
CASE_TEST(chroot_exe); EXPECT_SYSER(1, chroot(exe), -1, ENOTDIR); break; --> 19 chroot_exe = -1 ENOENT != (-1 ENOTDIR) [FAIL]
I removed the "proc ?" check manually to test if it also work with CONFIG_PROC_FS=n. it doesn't work, without absolute path, we need to add the ENOENT errno back to the errno check list.
I'm not sure if the other syscalls require an absolute path, so, the realpath() is called in this proposed method.
A full functional realpath() is a little complex, such as '../' support and even symlink support, let's delay its requirement at current stage ;-)
Please do not even engage into this, and keep in mind that the sole purpose of this test program is to help developers simply add tests to the set of existing ones. If the program becomes complex for doing stuff that is out of its scope, it will become much harder to extend and users will lose interest and motivation for updating it.
one or both of them may also help the other test cases:
chroot_exe (used '/init' before)
CASE_TEST(chroot_exe); EXPECT_SYSER(1, chroot(proc ? "/proc/self/exe" : exe), -1, ENOTDIR); break;
chmod_exe (replace the one: chmod_tmpdir in another patchset)
CASE_TEST(chmod_exe); EXPECT_SYSZR(1, chmod(proc ? "/proc/self/exe" : exe, 0555)); break;
It should be safe enough to only remove the writable attribute for the test program.
stat_timestamps (used '/init' before)
if (stat("/proc/self/", &st) && stat(exe, &st) && stat("/dev/zero", &st) && stat("/", &st))
Indeed, why not!
Ok, without absolute path, the chroot_exe() will be changed back to something like this:
CASE_TEST(chroot_exe); EXPECT_SYSER2(1, chroot(proc ? "/proc/self/exe" : argv0), -1, ENOTDIR, ENOENT); break;
Are you sure the ENOENT is really correct? I played with this before and got ENOENT because before the chroot test we have a testcase that does chdir("/").
Yes, there are some chdir tests before chroot, it does answer why relative path not work and return ENOENT: no such file in the relative path changed by chdir(), it differs from the one in PWD environment variable.
And therefore the relative name in argv[0] was not resolving correctly anymore against the changed working directory.
(You can also test this by executing *only* the chroot test and it should work)
Yeah, If chdir() back to current path, it does work:
CASE_TEST(chroot_exe); chdir(getenv("PWD")); EXPECT_SYSER(1, chroot(exe), -1, ENOTDIR); break;
-->
11 chdir_root = 0 [OK] 12 chdir_dot = 0 [OK] 13 chdir_blah = -1 ENOENT [OK] 14 chmod_self = -1 EPERM [OK] 15 chmod_exe = 0 [OK] 16 chown_self = -1 EPERM [OK] 17 chroot_root [SKIPPED] 18 chroot_blah = -1 ENOENT [OK] 19 chroot_exe pwd: /home/ubuntu/Develop/src/examples/musl exe: ./nolibc-test = -1 ENOTDIR [OK]
In general chroot() should work just fine with relative paths.
it does work with relative path, to make sure argv0 always work as expected, an extra 'chdir()' may really required, or let's clean up the previous chdir() test cases to call chdir(getenv("PWD")) after every test.
CASE_TEST(chdir_root); EXPECT_SYSZR(1, chdir("/")); break; CASE_TEST(chdir_dot); EXPECT_SYSZR(1, chdir(".")); break; CASE_TEST(chdir_blah); EXPECT_SYSER(1, chdir("/blah"), -1, ENOENT); break;
perhaps only call 'chdir(getenv("PWD"))' after chdir_root() is enough, because the chdir(".") doesn't really change the directory:
CASE_TEST(chdir_root); EXPECT_SYSZR(1, chdir("/")); chdir(getenv("PWD")); break; CASE_TEST(chdir_dot); EXPECT_SYSZR(1, chdir(".")); break; CASE_TEST(chdir_blah); EXPECT_SYSER(1, chdir("/blah"), -1, ENOENT); break;
Which one do you prefer?
This is really a lot of complexity and discussion only to avoid depending on procfs for the tests.
Yes, one step further to find more interesting info, thanks a lot ;-)
Mixing chdir and relative path really need to be more careful.
Best regards, Zhangjin
Thomas
On Mon, Jul 03, 2023 at 04:06:47PM +0800, Zhangjin Wu wrote:
/* get absolute path of myself, nolibc has no realpath() currently */ #ifndef NOLIBC realpath(argv[0], exe); #else /* assume absolute path has no "./" */ if (strncmp(argv[0], "./", 2) != 0) strncat(exe, argv[0], strlen(argv[0]) + 1); else { pwd = getenv("PWD"); /* skip the ending '\0' */ strncat(exe, getenv("PWD"), strlen(pwd)); /* skip the first '.' */ strncat(exe, argv[0] + 1, strlen(argv[0])); } #endif
No, please, not like this. Just copy argv[0] (the pointer not the contents) and you're fine:
static const char *argv0; int main(int argc, char **argv, char **envp) { argv0 = argv[0]; ... }
Nothing more, nothing less. Your program will always have its correct path when being called unless someone purposely forces it to something different, which is not our concern at all since this is a test program. And I'd rather call it "argv0" which exactly tells us what it contains than "exe" which can be misleading for that precise reason.
Yeah, locally, I just used a global argv0 pointer directly, but chroot_exe("./nolibc-test") not work when run 'libc-test' in host system, that is why I tried to get an absolute path ;-)
CASE_TEST(chroot_exe); EXPECT_SYSER(1, chroot(exe), -1, ENOTDIR); break; --> 19 chroot_exe = -1 ENOENT != (-1 ENOTDIR) [FAIL]
Then we have a problem somewhere else and the test should be debugger instead. Are you sure there isn't a successful chdir() test before it for example, that would change the directory ? If so maybe we just need to save the current dir before calling it and restore it later.
I removed the "proc ?" check manually to test if it also work with CONFIG_PROC_FS=n. it doesn't work, without absolute path, we need to add the ENOENT errno back to the errno check list.
Same as above.
I'm not sure if the other syscalls require an absolute path, so, the realpath() is called in this proposed method.
No, please do not overengineer tests. That's only hiding the dust under the carpet and people adding more tests later that will randomly fail will have a very hard time trying to figure what's happening under the hood. If a test doesn't work as expected, we must not try to work around it, but arrange to fix it.
Thanks, Willy
On Mon, Jul 03, 2023 at 04:06:47PM +0800, Zhangjin Wu wrote:
/* get absolute path of myself, nolibc has no realpath() currently */ #ifndef NOLIBC realpath(argv[0], exe); #else /* assume absolute path has no "./" */ if (strncmp(argv[0], "./", 2) != 0) strncat(exe, argv[0], strlen(argv[0]) + 1); else { pwd = getenv("PWD"); /* skip the ending '\0' */ strncat(exe, getenv("PWD"), strlen(pwd)); /* skip the first '.' */ strncat(exe, argv[0] + 1, strlen(argv[0])); } #endif
No, please, not like this. Just copy argv[0] (the pointer not the contents) and you're fine:
static const char *argv0; int main(int argc, char **argv, char **envp) { argv0 = argv[0]; ... }
Nothing more, nothing less. Your program will always have its correct path when being called unless someone purposely forces it to something different, which is not our concern at all since this is a test program. And I'd rather call it "argv0" which exactly tells us what it contains than "exe" which can be misleading for that precise reason.
Yeah, locally, I just used a global argv0 pointer directly, but chroot_exe("./nolibc-test") not work when run 'libc-test' in host system, that is why I tried to get an absolute path ;-)
CASE_TEST(chroot_exe); EXPECT_SYSER(1, chroot(exe), -1, ENOTDIR); break; --> 19 chroot_exe = -1 ENOENT != (-1 ENOTDIR) [FAIL]
Then we have a problem somewhere else and the test should be debugger instead. Are you sure there isn't a successful chdir() test before it for example, that would change the directory ? If so maybe we just need to save the current dir before calling it and restore it later.
Yes, as Thomas pointed out, the chdir test cases changed current directory to "/" just before chroot_exe(), so, restore it with chdir(getenv("PWD")) solves the issue.
I removed the "proc ?" check manually to test if it also work with CONFIG_PROC_FS=n. it doesn't work, without absolute path, we need to add the ENOENT errno back to the errno check list.
Same as above.
I'm not sure if the other syscalls require an absolute path, so, the realpath() is called in this proposed method.
No, please do not overengineer tests. That's only hiding the dust under the carpet and people adding more tests later that will randomly fail will have a very hard time trying to figure what's happening under the hood. If a test doesn't work as expected, we must not try to work around it, but arrange to fix it.
That's right, thanks.
Best regards, Zhangjin
Thanks, Willy
On Wed, Jun 28, 2023 at 09:07:16PM +0800, Zhangjin Wu wrote:
Willy, Thomas
This is the revision of our 'tools/nolibc: add a new syscall helper' series [1].
(...)
just to let you know that I've read them all and am fine with the ones I didn't comment on.
Thanks Zhangjin! Willy
linux-kselftest-mirror@lists.linaro.org