* [RFC PATCH v1 1/8] nolibc/sys: Implement `sigaction(2)` function
2022-12-22 3:51 [RFC PATCH v1 0/8] nolibc signal handling support Ammar Faizi
@ 2022-12-22 3:51 ` Ammar Faizi
2022-12-22 3:51 ` [RFC PATCH v1 2/8] nolibc/sys: Implement `signal(2)` function Ammar Faizi
` (7 subsequent siblings)
8 siblings, 0 replies; 36+ messages in thread
From: Ammar Faizi @ 2022-12-22 3:51 UTC (permalink / raw)
To: Willy Tarreau, Shuah Khan, Paul E. McKenney
Cc: Ammar Faizi, Gilang Fachrezy, VNLX Kernel Department,
Alviro Iskandar Setiawan, Kanna Scarlet, Muhammad Rizki,
GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
From: Ammar Faizi <[email protected]>
This commit adds the initial implementation of nolibc `sigaction()`
function. Currently, this implementation is only available on the
x86-64 arch.
`sigaction()` needs an architecture-dependent "signal trampoline"
function that invokes the __rt_sigreturn syscall to resume the process
after a signal gets handled.
On Linux x86-64, the "signal trampoline" function has to be written in
inline Assembly to prevent the compiler from controlling the `%rsp`
(e.g., with `-fno-omit-frame-pointer`, every function has a `pushq
%rbp` that makes the `%rsp` no longer point to `struct rt_sigframe`).
The "signal trampoline" function is called `__arch_restore_rt` in this
implementation.
Signed-off-by: Ammar Faizi <[email protected]>
---
tools/include/nolibc/arch-x86_64.h | 12 +++++
tools/include/nolibc/sys.h | 80 ++++++++++++++++++++++++++++++
2 files changed, 92 insertions(+)
diff --git a/tools/include/nolibc/arch-x86_64.h b/tools/include/nolibc/arch-x86_64.h
index 0e1e9eb8545d..b6470943e836 100644
--- a/tools/include/nolibc/arch-x86_64.h
+++ b/tools/include/nolibc/arch-x86_64.h
@@ -212,4 +212,16 @@ __asm__ (".section .text\n"
"hlt\n" // ensure it does not return
"");
+void __arch_restore_rt(void);
+
+__asm__ (
+".section .text\n"
+"__arch_restore_rt:\n\t"
+ "movl $0xf, %eax\n\t" // __NR_rt_sigreturn == 0xf
+ "syscall\n\t" // %rsp must point to a valid struct rt_sigframe.
+ "int3"
+);
+
+#define __HAVE_ARCH_RESTORE_RT
+
#endif // _NOLIBC_ARCH_X86_64_H
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h
index 3db1dd8c74ee..91532a2fbe2c 100644
--- a/tools/include/nolibc/sys.h
+++ b/tools/include/nolibc/sys.h
@@ -1026,6 +1026,86 @@ pid_t setsid(void)
return ret;
}
+typedef void (*sighandler_t)(int sig);
+
+/*
+ * int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
+ */
+
+static __attribute__((unused))
+int sys_sigaction(int signum, const struct sigaction *act,
+ struct sigaction *oldact)
+{
+ return my_syscall4(__NR_rt_sigaction, signum, act, oldact,
+ sizeof(sigset_t));
+}
+
+static __attribute__((unused))
+int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
+{
+#ifdef __HAVE_ARCH_RESTORE_RT
+ struct sigaction act2 = *act;
+ int ret;
+
+ /*
+ * On Linux x86-64, libc's sigaction() always sets the
+ * @act->sa_restorer when the caller passes a NULL.
+ *
+ * @act->sa_restorer is an arch-specific function used
+ * as a "signal trampoline".
+ *
+ * @act->sa_handler is a signal handler provided by the
+ * user.
+ *
+ * When the handled signal is caught, the %rip jumps to
+ * @act->sa_handler with user stack already set by the
+ * kernel as below:
+ *
+ * |--------------------|
+ * %rsp -> | act->sa_restorer | (return address)
+ * |--------------------|
+ * | struct rt_sigframe | (process context info)
+ * | |
+ * | |
+ * ....................
+ *
+ * Once this signal handler executes the "ret" instruction,
+ * the %rip jumps to @act->sa_restorer. The sa_restorer
+ * function has to invoke the __rt_sigreturn syscall with
+ * %rsp pointing to the `struct rt_sigframe` that the kernel
+ * constructed previously to resume the process.
+ *
+ * The "signal trampoline" function has to be written in
+ * inline Assembly to prevent the compiler from controlling
+ * the %rsp (e.g., with -fno-omit-frame-pointer, every
+ * function has a `pushq %rbp` that makes the %rsp no longer
+ * point to `struct rt_sigframe`).
+ *
+ * `struct rt_sigframe` contains the registers' value before
+ * the signal is caught.
+ *
+ */
+ if (!act2.sa_restorer) {
+ act2.sa_flags |= SA_RESTORER;
+ act2.sa_restorer = __arch_restore_rt;
+ }
+
+ ret = sys_sigaction(signum, &act2, oldact);
+ if (ret < 0) {
+ SET_ERRNO(-ret);
+ ret = -1;
+ }
+ return ret;
+#else
+ /*
+ * TODO: Implement sa_restorer ("signal trampoline") for
+ * other architectures.
+ */
+ SET_ERRNO(ENOSYS);
+ return -1;
+#endif
+}
+
/*
* int stat(const char *path, struct stat *buf);
--
Ammar Faizi
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [RFC PATCH v1 2/8] nolibc/sys: Implement `signal(2)` function
2022-12-22 3:51 [RFC PATCH v1 0/8] nolibc signal handling support Ammar Faizi
2022-12-22 3:51 ` [RFC PATCH v1 1/8] nolibc/sys: Implement `sigaction(2)` function Ammar Faizi
@ 2022-12-22 3:51 ` Ammar Faizi
2022-12-22 3:51 ` [RFC PATCH v1 3/8] nolibc/sys: Implement `getpagesize(2)` function Ammar Faizi
` (6 subsequent siblings)
8 siblings, 0 replies; 36+ messages in thread
From: Ammar Faizi @ 2022-12-22 3:51 UTC (permalink / raw)
To: Willy Tarreau, Shuah Khan, Paul E. McKenney
Cc: Ammar Faizi, Gilang Fachrezy, VNLX Kernel Department,
Alviro Iskandar Setiawan, Kanna Scarlet, Muhammad Rizki,
GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
From: Ammar Faizi <[email protected]>
signal() function is the simpler version of sigaction(). Unlike
sigaction(), which fully controls the `struct sigaction`, the caller
only cares about the sa_handler when calling the signal() function.
signal() internally calls sigaction(). This implementation is
currently only available on the x86-64 arch.
Signed-off-by: Ammar Faizi <[email protected]>
---
tools/include/nolibc/sys.h | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h
index 91532a2fbe2c..ca348939eb50 100644
--- a/tools/include/nolibc/sys.h
+++ b/tools/include/nolibc/sys.h
@@ -1106,6 +1106,36 @@ int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
#endif
}
+/*
+ * sighandler_t signal(int signum, sighandler_t handler);
+ */
+
+static __attribute__((unused))
+sighandler_t signal(int signum, sighandler_t handler)
+{
+#ifdef __HAVE_ARCH_RESTORE_RT
+ const struct sigaction act = {
+ .sa_handler = handler,
+ .sa_flags = SA_RESTORER,
+ .sa_restorer = __arch_restore_rt
+ };
+ sighandler_t old_sah;
+ struct sigaction old;
+ int ret;
+
+ ret = sys_sigaction(signum, &act, &old);
+ if (ret < 0) {
+ SET_ERRNO(-ret);
+ old_sah = SIG_ERR;
+ } else {
+ old_sah = old.sa_handler;
+ }
+ return old_sah;
+#else
+ SET_ERRNO(ENOSYS);
+ return SIG_ERR;
+#endif
+}
/*
* int stat(const char *path, struct stat *buf);
--
Ammar Faizi
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [RFC PATCH v1 3/8] nolibc/sys: Implement `getpagesize(2)` function
2022-12-22 3:51 [RFC PATCH v1 0/8] nolibc signal handling support Ammar Faizi
2022-12-22 3:51 ` [RFC PATCH v1 1/8] nolibc/sys: Implement `sigaction(2)` function Ammar Faizi
2022-12-22 3:51 ` [RFC PATCH v1 2/8] nolibc/sys: Implement `signal(2)` function Ammar Faizi
@ 2022-12-22 3:51 ` Ammar Faizi
2022-12-22 3:51 ` [RFC PATCH v1 4/8] selftests/nolibc: Add `-Wall` and `-Wno-unsed-function` to the CFLAGS Ammar Faizi
` (5 subsequent siblings)
8 siblings, 0 replies; 36+ messages in thread
From: Ammar Faizi @ 2022-12-22 3:51 UTC (permalink / raw)
To: Willy Tarreau, Shuah Khan, Paul E. McKenney
Cc: Ammar Faizi, Gilang Fachrezy, VNLX Kernel Department,
Alviro Iskandar Setiawan, Kanna Scarlet, Muhammad Rizki,
GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
From: Ammar Faizi <[email protected]>
This commit adds getpagesize() function implementation.
The getpagesize() syscall doesn't always exist on the Linux syscall
table. Only specific architectures have this syscall.
Implementation detail:
Some architectures use a fixed page size, like x86. We can hard-code
the page size value on such architectures.
Some other architectures may use different page sizes. For example,
Linux aarch64 supports three values of page size: 4K, 16K, and 64K
which are selected at kernel compilation time. The kernel stores the
used page size in the auxiliary vector. The auxiliary vector can be
obtained from /proc/self/auxv at AT_PAGESZ key-value-pair.
/proc/self/auxv is available on all architectures.
Once we obtain the page size info, cache the value in a static
variable to avoid traversing the auxiliary vector again in the next
getpagesize() call. The page size should never change during kernel
uptime.
Link: https://lwn.net/Articles/519085
Link: https://github.com/torvalds/linux/blob/v6.1/fs/binfmt_elf.c#L260
Signed-off-by: Ammar Faizi <[email protected]>
---
tools/include/nolibc/sys.h | 114 +++++++++++++++++++++++++++++++++++++
1 file changed, 114 insertions(+)
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h
index ca348939eb50..e9e3640c36e1 100644
--- a/tools/include/nolibc/sys.h
+++ b/tools/include/nolibc/sys.h
@@ -18,6 +18,7 @@
#include <linux/fs.h>
#include <linux/loop.h>
#include <linux/time.h>
+#include <linux/auxvec.h>
#include "arch.h"
#include "errno.h"
@@ -407,6 +408,119 @@ int getdents64(int fd, struct linux_dirent64 *dirp, int count)
return ret;
}
+/*
+ * The getpagesize() syscall doesn't always exist on the Linux syscall
+ * table. Only specific architectures have this syscall.
+ *
+ * Implementation detail:
+ * Some architectures use a fixed page size, like x86. We can hard-code
+ * the page size value on such architectures.
+ *
+ * Some other architectures may use different page sizes. For example,
+ * Linux aarch64 supports three values of page size: 4K, 16K, and 64K
+ * which are selected at kernel compilation time. The kernel stores the
+ * used page size in the auxiliary vector. The auxiliary vector can be
+ * obtained from /proc/self/auxv at AT_PAGESZ key-val-pair.
+ * /proc/self/auxv is available on all architectures.
+ *
+ * Once we obtain the page size info, cache the value in a static
+ * variable to avoid traversing the auxiliary vector again in the next
+ * getpagesize() call. The page size should never change during kernel
+ * uptime.
+ *
+ * Link: https://lwn.net/Articles/519085
+ * Link: https://github.com/torvalds/linux/blob/v6.1/fs/binfmt_elf.c#L260
+ *
+ *
+ * long getpagesize(void);
+ *
+ */
+
+#if defined(__x86_64__) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__)
+__attribute__((unused))
+static inline long getpagesize(void)
+{
+ /*
+ * x86 family is always 4K page. Don't bother
+ * reading the auxiliary vector.
+ */
+ return 4096;
+}
+#else
+static int sys_open(const char *path, int flags, mode_t mode);
+static ssize_t sys_read(int fd, void *buf, size_t count);
+
+/*
+ * This function works for all architectures.
+ */
+static long sys_getpagesize(void)
+{
+ uint64_t buf[2] = {0, 0};
+ long ret;
+ int fd;
+
+
+ fd = sys_open("/proc/self/auxv", O_RDONLY, 0);
+ if (fd < 0)
+ return fd;
+
+ while (1) {
+ ssize_t x;
+
+ x = sys_read(fd, buf, sizeof(buf));
+ if (x < 0) {
+ ret = x;
+ break;
+ }
+
+ if (__builtin_expect(x == 0, 0)) {
+ /*
+ * We've reached the end of the auxiliary
+ * vector, but can't find the AT_PAGESZ
+ * entry.
+ */
+ ret = -ENOENT;
+ break;
+ }
+
+ /*
+ * buf[0] is the key.
+ * buf[1] is the value.
+ */
+ if (buf[0] == AT_PAGESZ) {
+ ret = buf[1];
+ break;
+ }
+ }
+
+ sys_close(fd);
+ return ret;
+}
+
+__attribute__((unused))
+static long getpagesize(void)
+{
+ static long cached;
+ long ret;
+
+ /*
+ * No need to read the auxv for the second
+ * getpagesize() call.
+ */
+ if (__builtin_expect(cached != 0, 1))
+ return cached;
+
+ ret = sys_getpagesize();
+ if (ret < 0) {
+ SET_ERRNO(-ret);
+ ret = -1;
+ } else {
+ cached = ret;
+ }
+ return ret;
+}
+#endif
+
/*
* pid_t getpgid(pid_t pid);
--
Ammar Faizi
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [RFC PATCH v1 4/8] selftests/nolibc: Add `-Wall` and `-Wno-unsed-function` to the CFLAGS
2022-12-22 3:51 [RFC PATCH v1 0/8] nolibc signal handling support Ammar Faizi
` (2 preceding siblings ...)
2022-12-22 3:51 ` [RFC PATCH v1 3/8] nolibc/sys: Implement `getpagesize(2)` function Ammar Faizi
@ 2022-12-22 3:51 ` Ammar Faizi
2022-12-22 3:51 ` [RFC PATCH v1 5/8] selftests/nolibc: Add `fork(2)` selftest Ammar Faizi
` (4 subsequent siblings)
8 siblings, 0 replies; 36+ messages in thread
From: Ammar Faizi @ 2022-12-22 3:51 UTC (permalink / raw)
To: Willy Tarreau, Shuah Khan, Paul E. McKenney
Cc: Ammar Faizi, Gilang Fachrezy, VNLX Kernel Department,
Alviro Iskandar Setiawan, Kanna Scarlet, Muhammad Rizki,
GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
From: Ammar Faizi <[email protected]>
Turn on more compiler warnings to help spot issues. Skip unused
function warning as it's inevitable in the nolibc test suite.
While adding these flags, remove unused variables in run_stdlib()
warned by the `-Wall` flag.
Signed-off-by: Ammar Faizi <[email protected]>
---
tools/testing/selftests/nolibc/Makefile | 2 +-
tools/testing/selftests/nolibc/nolibc-test.c | 2 --
2 files changed, 1 insertion(+), 3 deletions(-)
diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile
index 572fe72df68d..f6602a2c2bbd 100644
--- a/tools/testing/selftests/nolibc/Makefile
+++ b/tools/testing/selftests/nolibc/Makefile
@@ -66,7 +66,7 @@ else
Q=@
endif
-CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables
+CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables -Wall -Wno-unused-function
LDFLAGS := -s
help:
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index f14f5076fb6d..8d69f8a0f35a 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -542,9 +542,7 @@ int run_syscall(int min, int max)
int run_stdlib(int min, int max)
{
int test;
- int tmp;
int ret = 0;
- void *p1, *p2;
for (test = min; test >= 0 && test <= max; test++) {
int llen = 0; // line length
--
Ammar Faizi
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [RFC PATCH v1 5/8] selftests/nolibc: Add `fork(2)` selftest
2022-12-22 3:51 [RFC PATCH v1 0/8] nolibc signal handling support Ammar Faizi
` (3 preceding siblings ...)
2022-12-22 3:51 ` [RFC PATCH v1 4/8] selftests/nolibc: Add `-Wall` and `-Wno-unsed-function` to the CFLAGS Ammar Faizi
@ 2022-12-22 3:51 ` Ammar Faizi
2022-12-22 3:51 ` [RFC PATCH v1 6/8] selftests/nolibc: Add `sigaction(2)` selftest Ammar Faizi
` (3 subsequent siblings)
8 siblings, 0 replies; 36+ messages in thread
From: Ammar Faizi @ 2022-12-22 3:51 UTC (permalink / raw)
To: Willy Tarreau, Shuah Khan, Paul E. McKenney
Cc: Ammar Faizi, Gilang Fachrezy, VNLX Kernel Department,
Alviro Iskandar Setiawan, Kanna Scarlet, Muhammad Rizki,
GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
From: Ammar Faizi <[email protected]>
Ensure the fork() function can create a child process. Also, when the
child exits, the parent must be able to get the child's exit code
via waitpid().
Signed-off-by: Ammar Faizi <[email protected]>
---
tools/testing/selftests/nolibc/nolibc-test.c | 45 ++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index 8d69f8a0f35a..309cabbddeec 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -442,6 +442,50 @@ int test_getdents64(const char *dir)
return ret;
}
+/*
+ * Test fork().
+ * Make sure the exit code can be read from the parent process.
+ */
+static int test_fork_and_exit(int expected_code)
+{
+ int status;
+ int code;
+ pid_t ret;
+ pid_t p;
+
+ p = fork();
+ if (p < 0)
+ return p;
+
+ if (!p)
+ exit(expected_code);
+
+ do {
+ ret = waitpid(p, &status, 0);
+ if (ret < 0)
+ return ret;
+ } while (!WIFEXITED(status));
+
+ code = WEXITSTATUS(status);
+ if (code != expected_code) {
+ printf("test_fork_and_exit(): waitpid(): Invalid exit code: %d; expected = %d\n", code, expected_code);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int test_fork(void)
+{
+ int i;
+
+ for (i = 0; i < 255; i++) {
+ if (test_fork_and_exit(i))
+ return -1;
+ }
+ return 0;
+}
+
/* Run syscall tests between IDs <min> and <max>.
* Return 0 on success, non-zero on failure.
*/
@@ -494,6 +538,7 @@ int run_syscall(int min, int max)
CASE_TEST(dup3_0); tmp = dup3(0, 100, 0); EXPECT_SYSNE(1, tmp, -1); close(tmp); break;
CASE_TEST(dup3_m1); tmp = dup3(-1, 100, 0); EXPECT_SYSER(1, tmp, -1, EBADF); if (tmp != -1) close(tmp); break;
CASE_TEST(execve_root); EXPECT_SYSER(1, execve("/", (char*[]){ [0] = "/", [1] = NULL }, NULL), -1, EACCES); break;
+ CASE_TEST(fork); EXPECT_SYSZR(1, test_fork()); break;
CASE_TEST(getdents64_root); EXPECT_SYSNE(1, test_getdents64("/"), -1); break;
CASE_TEST(getdents64_null); EXPECT_SYSER(1, test_getdents64("/dev/null"), -1, ENOTDIR); break;
CASE_TEST(gettimeofday_null); EXPECT_SYSZR(1, gettimeofday(NULL, NULL)); break;
--
Ammar Faizi
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [RFC PATCH v1 6/8] selftests/nolibc: Add `sigaction(2)` selftest
2022-12-22 3:51 [RFC PATCH v1 0/8] nolibc signal handling support Ammar Faizi
` (4 preceding siblings ...)
2022-12-22 3:51 ` [RFC PATCH v1 5/8] selftests/nolibc: Add `fork(2)` selftest Ammar Faizi
@ 2022-12-22 3:51 ` Ammar Faizi
2022-12-22 3:51 ` [RFC PATCH v1 7/8] selftests/nolibc: Add `signal(2)` selftest Ammar Faizi
` (2 subsequent siblings)
8 siblings, 0 replies; 36+ messages in thread
From: Ammar Faizi @ 2022-12-22 3:51 UTC (permalink / raw)
To: Willy Tarreau, Shuah Khan, Paul E. McKenney
Cc: Ammar Faizi, Gilang Fachrezy, VNLX Kernel Department,
Alviro Iskandar Setiawan, Kanna Scarlet, Muhammad Rizki,
GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
From: Ammar Faizi <[email protected]>
Test the sigaction() function implementation. Test steps:
- Set a signal handler.
- Then send a signal to itself using the kill() syscall.
- The program has to survive and store the caught signal number in a
volatile global variable.
- Validate the volatile global variable value.
- Restore the original signal handler.
Only the x86-64 arch runs this test. Other architectures skip this test
for now.
Signed-off-by: Ammar Faizi <[email protected]>
---
tools/testing/selftests/nolibc/nolibc-test.c | 81 ++++++++++++++++++++
1 file changed, 81 insertions(+)
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index 309cabbddeec..562766e0f63c 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -486,6 +486,86 @@ static int test_fork(void)
return 0;
}
+static volatile int g_test_sig;
+
+static void test_sigaction_signal_handler(int sig)
+{
+ g_test_sig = sig;
+}
+
+static int test_sigaction_sig(int sig)
+{
+ const struct sigaction new = {
+ .sa_handler = test_sigaction_signal_handler
+ };
+ struct sigaction old;
+ int ret;
+
+ /*
+ * Set the signal handler.
+ */
+ ret = sigaction(sig, &new, &old);
+ if (ret) {
+ printf("test_sigaction_sig(%d): Failed to set a signal handler\n", sig);
+ return ret;
+ }
+
+ /*
+ * Test the signal handler.
+ */
+ g_test_sig = 0;
+ kill(getpid(), sig);
+
+ /*
+ * test_sigaction_signal_handler() must set @g_test_sig to @sig.
+ */
+ if (g_test_sig != sig) {
+ printf("test_sigaction_sig(%d): Invalid g_test_sig value (%d != %d)\n", sig, g_test_sig, sig);
+ return -1;
+ }
+
+ /*
+ * Restore the original signal handler.
+ */
+ ret = sigaction(sig, &old, NULL);
+ if (ret) {
+ printf("test_sigaction_sig(%d): Failed to restore the signal handler\n", sig);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int test_sigaction(void)
+{
+ static const int sig_to_test[] = {
+ SIGINT,
+ SIGHUP,
+ SIGTERM,
+ SIGQUIT,
+ SIGSEGV
+ };
+ size_t i;
+ int ret;
+
+ for (i = 0; i < (sizeof(sig_to_test) / sizeof(sig_to_test[0])); i++) {
+ ret = test_sigaction_sig(sig_to_test[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int should_test_sigaction(void)
+{
+#if defined(__x86_64__)
+ return 1;
+#else
+ return 0;
+#endif
+}
+
/* Run syscall tests between IDs <min> and <max>.
* Return 0 on success, non-zero on failure.
*/
@@ -566,6 +646,7 @@ int run_syscall(int min, int max)
CASE_TEST(select_null); EXPECT_SYSZR(1, ({ struct timeval tv = { 0 }; select(0, NULL, NULL, NULL, &tv); })); break;
CASE_TEST(select_stdout); EXPECT_SYSNE(1, ({ fd_set fds; FD_ZERO(&fds); FD_SET(1, &fds); select(2, NULL, &fds, NULL, NULL); }), -1); break;
CASE_TEST(select_fault); EXPECT_SYSER(1, select(1, (void *)1, NULL, NULL, 0), -1, EFAULT); break;
+ CASE_TEST(sigaction); EXPECT_SYSZR(should_test_sigaction(), test_sigaction()); break;
CASE_TEST(stat_blah); EXPECT_SYSER(1, stat("/proc/self/blah", &stat_buf), -1, ENOENT); break;
CASE_TEST(stat_fault); EXPECT_SYSER(1, stat(NULL, &stat_buf), -1, EFAULT); break;
CASE_TEST(symlink_root); EXPECT_SYSER(1, symlink("/", "/"), -1, EEXIST); break;
--
Ammar Faizi
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [RFC PATCH v1 7/8] selftests/nolibc: Add `signal(2)` selftest
2022-12-22 3:51 [RFC PATCH v1 0/8] nolibc signal handling support Ammar Faizi
` (5 preceding siblings ...)
2022-12-22 3:51 ` [RFC PATCH v1 6/8] selftests/nolibc: Add `sigaction(2)` selftest Ammar Faizi
@ 2022-12-22 3:51 ` Ammar Faizi
2022-12-22 3:51 ` [RFC PATCH v1 8/8] selftests/nolibc: Add `getpagesize(2)` selftest Ammar Faizi
2022-12-22 4:34 ` [RFC PATCH v1 0/8] nolibc signal handling support Willy Tarreau
8 siblings, 0 replies; 36+ messages in thread
From: Ammar Faizi @ 2022-12-22 3:51 UTC (permalink / raw)
To: Willy Tarreau, Shuah Khan, Paul E. McKenney
Cc: Ammar Faizi, Gilang Fachrezy, VNLX Kernel Department,
Alviro Iskandar Setiawan, Kanna Scarlet, Muhammad Rizki,
GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
From: Ammar Faizi <[email protected]>
Just like the sigaction() selftest, but for signal().
Signed-off-by: Ammar Faizi <[email protected]>
---
tools/testing/selftests/nolibc/nolibc-test.c | 84 +++++++++++++++++---
1 file changed, 72 insertions(+), 12 deletions(-)
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index 562766e0f63c..a65cc6b83779 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -488,7 +488,7 @@ static int test_fork(void)
static volatile int g_test_sig;
-static void test_sigaction_signal_handler(int sig)
+static void test_signal_handler(int sig)
{
g_test_sig = sig;
}
@@ -496,7 +496,7 @@ static void test_sigaction_signal_handler(int sig)
static int test_sigaction_sig(int sig)
{
const struct sigaction new = {
- .sa_handler = test_sigaction_signal_handler
+ .sa_handler = test_signal_handler
};
struct sigaction old;
int ret;
@@ -517,7 +517,7 @@ static int test_sigaction_sig(int sig)
kill(getpid(), sig);
/*
- * test_sigaction_signal_handler() must set @g_test_sig to @sig.
+ * test_signal_handler() must set @g_test_sig to @sig.
*/
if (g_test_sig != sig) {
printf("test_sigaction_sig(%d): Invalid g_test_sig value (%d != %d)\n", sig, g_test_sig, sig);
@@ -536,20 +536,74 @@ static int test_sigaction_sig(int sig)
return 0;
}
+static int test_signal_sig(int sig)
+{
+ sighandler_t old;
+
+ /*
+ * Set the signal handler.
+ */
+ old = signal(sig, test_signal_handler);
+ if (old == SIG_ERR) {
+ printf("test_signal_sig(%d): Failed to set a signal handler\n", sig);
+ return -1;
+ }
+
+ /*
+ * Test the signal handler.
+ */
+ g_test_sig = 0;
+ kill(getpid(), sig);
+
+ /*
+ * test_signal_handler() must set @g_test_sig to @sig.
+ */
+ if (g_test_sig != sig) {
+ printf("test_signal_sig(%d): Invalid g_test_sig value (%d != %d)\n", sig, g_test_sig, sig);
+ return -1;
+ }
+
+ /*
+ * Restore the original signal handler.
+ */
+ old = signal(sig, old);
+ if (old == SIG_ERR) {
+ printf("test_signal_sig(%d): Failed to restore the signal handler\n", sig);
+ return -1;
+ }
+
+ return 0;
+}
+
+static const int g_sig_to_test[] = {
+ SIGINT,
+ SIGHUP,
+ SIGTERM,
+ SIGQUIT,
+ SIGSEGV
+};
+
static int test_sigaction(void)
{
- static const int sig_to_test[] = {
- SIGINT,
- SIGHUP,
- SIGTERM,
- SIGQUIT,
- SIGSEGV
- };
size_t i;
int ret;
- for (i = 0; i < (sizeof(sig_to_test) / sizeof(sig_to_test[0])); i++) {
- ret = test_sigaction_sig(sig_to_test[i]);
+ for (i = 0; i < (sizeof(g_sig_to_test) / sizeof(g_sig_to_test[0])); i++) {
+ ret = test_sigaction_sig(g_sig_to_test[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int test_signal(void)
+{
+ size_t i;
+ int ret;
+
+ for (i = 0; i < (sizeof(g_sig_to_test) / sizeof(g_sig_to_test[0])); i++) {
+ ret = test_signal_sig(g_sig_to_test[i]);
if (ret)
return ret;
}
@@ -566,6 +620,11 @@ static int should_test_sigaction(void)
#endif
}
+static int should_test_signal(void)
+{
+ return should_test_sigaction();
+}
+
/* Run syscall tests between IDs <min> and <max>.
* Return 0 on success, non-zero on failure.
*/
@@ -647,6 +706,7 @@ int run_syscall(int min, int max)
CASE_TEST(select_stdout); EXPECT_SYSNE(1, ({ fd_set fds; FD_ZERO(&fds); FD_SET(1, &fds); select(2, NULL, &fds, NULL, NULL); }), -1); break;
CASE_TEST(select_fault); EXPECT_SYSER(1, select(1, (void *)1, NULL, NULL, 0), -1, EFAULT); break;
CASE_TEST(sigaction); EXPECT_SYSZR(should_test_sigaction(), test_sigaction()); break;
+ CASE_TEST(signal); EXPECT_SYSZR(should_test_signal(), test_signal()); break;
CASE_TEST(stat_blah); EXPECT_SYSER(1, stat("/proc/self/blah", &stat_buf), -1, ENOENT); break;
CASE_TEST(stat_fault); EXPECT_SYSER(1, stat(NULL, &stat_buf), -1, EFAULT); break;
CASE_TEST(symlink_root); EXPECT_SYSER(1, symlink("/", "/"), -1, EEXIST); break;
--
Ammar Faizi
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [RFC PATCH v1 8/8] selftests/nolibc: Add `getpagesize(2)` selftest
2022-12-22 3:51 [RFC PATCH v1 0/8] nolibc signal handling support Ammar Faizi
` (6 preceding siblings ...)
2022-12-22 3:51 ` [RFC PATCH v1 7/8] selftests/nolibc: Add `signal(2)` selftest Ammar Faizi
@ 2022-12-22 3:51 ` Ammar Faizi
2022-12-22 4:34 ` [RFC PATCH v1 0/8] nolibc signal handling support Willy Tarreau
8 siblings, 0 replies; 36+ messages in thread
From: Ammar Faizi @ 2022-12-22 3:51 UTC (permalink / raw)
To: Willy Tarreau, Shuah Khan, Paul E. McKenney
Cc: Ammar Faizi, Gilang Fachrezy, VNLX Kernel Department,
Alviro Iskandar Setiawan, Kanna Scarlet, Muhammad Rizki,
GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
From: Ammar Faizi <[email protected]>
Test the getpagesize() function. Make sure it returns the correct
value.
Signed-off-by: Ammar Faizi <[email protected]>
---
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 a65cc6b83779..19b3ed5f2356 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -625,6 +625,36 @@ static int should_test_signal(void)
return should_test_sigaction();
}
+static int test_getpagesize(void)
+{
+ long x = getpagesize();
+ int c;
+
+ if (x < 0)
+ return x;
+
+#if defined(__x86_64__) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__)
+ /*
+ * x86 family is always 4K page.
+ */
+ c = (x == 4096);
+#elif defined(__aarch64__)
+ /*
+ * Linux aarch64 supports three values of page size: 4K, 16K, and 64K
+ * which are selected at kernel compilation time.
+ */
+ c = (x == 4096 || x == (16 * 1024) || x == (64 * 1024));
+#else
+ /*
+ * Assuming other architectures must have at
+ * least 4K page.
+ */
+ c = (x >= 4096);
+#endif
+
+ return !c;
+}
+
/* Run syscall tests between IDs <min> and <max>.
* Return 0 on success, non-zero on failure.
*/
@@ -686,6 +716,7 @@ int run_syscall(int min, int max)
CASE_TEST(gettimeofday_bad2); EXPECT_SYSER(1, gettimeofday(NULL, (void *)1), -1, EFAULT); break;
CASE_TEST(gettimeofday_bad2); EXPECT_SYSER(1, gettimeofday(NULL, (void *)1), -1, EFAULT); break;
#endif
+ CASE_TEST(getpagesize); EXPECT_SYSZR(1, test_getpagesize()); break;
CASE_TEST(ioctl_tiocinq); EXPECT_SYSZR(1, ioctl(0, TIOCINQ, &tmp)); break;
CASE_TEST(ioctl_tiocinq); EXPECT_SYSZR(1, ioctl(0, TIOCINQ, &tmp)); break;
CASE_TEST(link_root1); EXPECT_SYSER(1, link("/", "/"), -1, EEXIST); break;
--
Ammar Faizi
^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: [RFC PATCH v1 0/8] nolibc signal handling support
2022-12-22 3:51 [RFC PATCH v1 0/8] nolibc signal handling support Ammar Faizi
` (7 preceding siblings ...)
2022-12-22 3:51 ` [RFC PATCH v1 8/8] selftests/nolibc: Add `getpagesize(2)` selftest Ammar Faizi
@ 2022-12-22 4:34 ` Willy Tarreau
2022-12-22 13:46 ` Ammar Faizi
8 siblings, 1 reply; 36+ messages in thread
From: Willy Tarreau @ 2022-12-22 4:34 UTC (permalink / raw)
To: Ammar Faizi
Cc: Shuah Khan, Paul E. McKenney, Gilang Fachrezy,
VNLX Kernel Department, Alviro Iskandar Setiawan, Kanna Scarlet,
Muhammad Rizki, GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
Hi Ammar,
On Thu, Dec 22, 2022 at 10:51:26AM +0700, Ammar Faizi wrote:
> From: Ammar Faizi <[email protected]>
>
> Hi,
>
> This series adds signal handling support to the nolibc subsystem.
(...)
Thank you! I'll have a look at this this week-end.
I noticed one thing that we'll need to discuss further:
> 3) Extra nolibc updates.
>
> Apart from the signal handling support. This series also contains
> nolibc updates, they are:
>
> - getpagesize() support.
This one relies on /proc/self/auxv, but we'll quickly run into a
chicken-and-egg situation given that nolibc is used by init programs
that mount /proc. Instead I think that we should modify the _start
code to retrieve the auxv at startup and store it somewhere. This
"somewhere" is not yet defined, but I'm thinking that it could
deserve reserving some room in the stack to store some nolibc-defined
information (possibly even a copy of a pointer to environ and/or errno)
and figure a reliable and simple way to access this. Note that one way
could also be to know that it's after the NULL that follows envp, and
to start from environ. In fact there are plenty of ways and we just
need to decide what's the least ugly. But once we have access to the
auxv from the process, then we could implement a getauxval() function
to retrieve the information you need for getpagesize().
More on this later.
Thanks!
Willy
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [RFC PATCH v1 0/8] nolibc signal handling support
2022-12-22 4:34 ` [RFC PATCH v1 0/8] nolibc signal handling support Willy Tarreau
@ 2022-12-22 13:46 ` Ammar Faizi
2022-12-22 14:55 ` Alviro Iskandar Setiawan
2022-12-27 6:26 ` Willy Tarreau
0 siblings, 2 replies; 36+ messages in thread
From: Ammar Faizi @ 2022-12-22 13:46 UTC (permalink / raw)
To: Willy Tarreau
Cc: Ammar Faizi, Shuah Khan, Paul E. McKenney, Gilang Fachrezy,
VNLX Kernel Department, Alviro Iskandar Setiawan, Kanna Scarlet,
Muhammad Rizki, GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
On Thu, 22 Dec 2022 05:34:52 +0100, Willy Tarreau wrote:
> This one relies on /proc/self/auxv, but we'll quickly run into a
> chicken-and-egg situation given that nolibc is used by init programs
> that mount /proc. Instead I think that we should modify the _start
> code to retrieve the auxv at startup and store it somewhere. This
> "somewhere" is not yet defined, but I'm thinking that it could
> deserve reserving some room in the stack to store some nolibc-defined
> information (possibly even a copy of a pointer to environ and/or errno)
> and figure a reliable and simple way to access this. Note that one way
> could also be to know that it's after the NULL that follows envp, and
> to start from environ. In fact there are plenty of ways and we just
> need to decide what's the least ugly. But once we have access to the
> auxv from the process, then we could implement a getauxval() function
> to retrieve the information you need for getpagesize().
Thanks for the great feedback!
I agree with following the @envp pointer to get the auxv. I was
trying to wire up a new function '__start' (with double underscores)
written in C that accepts @argc, @argv and @envp. Then it calls 'main'.
Then we call '__start' instead of 'main' from '_start'. This way, we
can arrange nolibc-defined data without touching Assembly much in
'__start' (before main).
But then I noticed that it wouldn't work because we may have users
who define the 'main' function differently, e.g.:
int main(void);
int main(int argc, char **argv);
int main(int argc, char **argv, char **envp);
So '__start' can't call main. We still need to call the main from the
inline Assembly (from '_start').
Just a quick dirty patch to get getauxval() works on x86-64 below.
This needs more work, but at least something like this for starting:
$ ./nolibc-test
Running test 'syscall'
AT_SYSINFO_EHDR = 140737354125312
AT_HWCAP = 3219913727
AT_PAGESZ = 4096
AT_CLKTCK = 100
AT_PHDR = 4194368
AT_PHENT = 56
AT_PHNUM = 9
AT_BASE = 0
AT_FLAGS = 0
AT_ENTRY = 4199128
AT_UID = 0
AT_EUID = 0
AT_GID = 0
AT_EGID = 0
AT_SECURE = 0
AT_RANDOM = 140737488349065
AT_EXECFN = 140737488351210
AT_PLATFORM = 140737488349081
I'll probably only spare more intensive time on this after the holiday
season ends. I still check in email, but the activity will be sparse.
Signed-off-by: [Do not commit]
---
base-commit: caf5c36025ec9395c8d7c78957b016a284812d23 ("srcu: Update comment after the index flip")
diff --git a/tools/include/nolibc/arch-x86_64.h b/tools/include/nolibc/arch-x86_64.h
index 0e1e9eb8545d..5ee945370ff5 100644
--- a/tools/include/nolibc/arch-x86_64.h
+++ b/tools/include/nolibc/arch-x86_64.h
@@ -199,17 +199,49 @@ struct sys_stat_struct {
*/
__asm__ (".section .text\n"
".weak _start\n"
"_start:\n"
"pop %rdi\n" // argc (first arg, %rdi)
"mov %rsp, %rsi\n" // argv[] (second arg, %rsi)
"lea 8(%rsi,%rdi,8),%rdx\n" // then a NULL then envp (third arg, %rdx)
"xor %ebp, %ebp\n" // zero the stack frame
"and $-16, %rsp\n" // x86 ABI : esp must be 16-byte aligned before call
+ "push %rdi\n" // Save argc
+ "push %rsi\n" // Save arg
+ "push %rdx\n" // Save envp.
+ "push %rcx\n" // Keep the 16-byte alignment
+ "call __start\n" // Save environ and auxv
+ "pop %rcx\n" // Restore alignment
+ "pop %rdx\n" // Restore envp
+ "pop %rsi\n" // Restore argv
+ "pop %rdi\n" // Restore argc
"call main\n" // main() returns the status code, we'll exit with it.
"mov %eax, %edi\n" // retrieve exit code (32 bit)
"mov $60, %eax\n" // NR_exit == 60
"syscall\n" // really exit
"hlt\n" // ensure it does not return
"");
+struct __nolibc_internal {
+ char **envp;
+ unsigned long *auxv;
+};
+
+static struct __nolibc_internal __nolibc_internal;
+
+/*
+ * Mark this __used__ to avoid being optimized away.
+ * Reason: Called from inline Assembly.
+ */
+static __attribute__((__used__))
+void __start(int argc, char **argv, char **envp)
+{
+ char **p = envp;
+
+ while (*p)
+ p++;
+
+ __nolibc_internal.auxv = (unsigned long *)++p;
+ __nolibc_internal.envp = envp;
+}
+
#endif // _NOLIBC_ARCH_X86_64_H
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h
index 3db1dd8c74ee..04bff724e056 100644
--- a/tools/include/nolibc/sys.h
+++ b/tools/include/nolibc/sys.h
@@ -12,18 +12,19 @@
/* system includes */
#include <asm/unistd.h>
#include <asm/signal.h> // for SIGCHLD
#include <asm/ioctls.h>
#include <asm/mman.h>
#include <linux/fs.h>
#include <linux/loop.h>
#include <linux/time.h>
+#include <linux/auxvec.h>
#include "arch.h"
#include "errno.h"
#include "types.h"
/* Functions in this file only describe syscalls. They're declared static so
* that the compiler usually decides to inline them while still being allowed
* to pass a pointer to one of their instances. Each syscall exists in two
@@ -379,18 +380,49 @@ int fsync(int fd)
if (ret < 0) {
SET_ERRNO(-ret);
ret = -1;
}
return ret;
}
+/*
+ * On success, getauxval() returns the value corresponding to type.
+ * If type is not found, 0 is returned.
+ *
+ * unsigned long getauxval(unsigned long type);
+ */
+
+static __attribute__((unused))
+unsigned long getauxval(unsigned long type)
+{
+ unsigned long *auxv = __nolibc_internal.auxv;
+
+ if (__builtin_expect(!auxv, 0))
+ return 0;
+
+ while (1) {
+ if (!auxv[0] && !auxv[1])
+ /*
+ * We've reached the end of auxv.
+ */
+ return 0;
+
+ if (auxv[0] == type)
+ return auxv[1];
+
+ auxv += 2;
+ }
+ __builtin_unreachable();
+}
+
+
/*
* int getdents64(int fd, struct linux_dirent64 *dirp, int count);
*/
static __attribute__((unused))
int sys_getdents64(int fd, struct linux_dirent64 *dirp, int count)
{
return my_syscall3(__NR_getdents64, fd, dirp, count);
}
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index f14f5076fb6d..bca29a952c69 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -436,30 +436,60 @@ int test_getdents64(const char *dir)
ret = getdents64(fd, (void *)buffer, sizeof(buffer));
err = errno;
close(fd);
errno = err;
return ret;
}
+static void test_getauxval(void)
+{
+ #define PRINT_AUXVAL(KEY) \
+ do { \
+ printf(#KEY " = %lu\n", getauxval(KEY)); \
+ } while (0)
+
+ PRINT_AUXVAL(AT_SYSINFO_EHDR);
+ PRINT_AUXVAL(AT_HWCAP);
+ PRINT_AUXVAL(AT_PAGESZ);
+ PRINT_AUXVAL(AT_CLKTCK);
+ PRINT_AUXVAL(AT_PHDR);
+ PRINT_AUXVAL(AT_PHENT);
+ PRINT_AUXVAL(AT_PHNUM);
+ PRINT_AUXVAL(AT_BASE);
+ PRINT_AUXVAL(AT_FLAGS);
+ PRINT_AUXVAL(AT_ENTRY);
+ PRINT_AUXVAL(AT_UID);
+ PRINT_AUXVAL(AT_EUID);
+ PRINT_AUXVAL(AT_GID);
+ PRINT_AUXVAL(AT_EGID);
+ PRINT_AUXVAL(AT_SECURE);
+ PRINT_AUXVAL(AT_RANDOM);
+ PRINT_AUXVAL(AT_EXECFN);
+ PRINT_AUXVAL(AT_PLATFORM);
+ exit(0);
+}
+
/* Run syscall tests between IDs <min> and <max>.
* Return 0 on success, non-zero on failure.
*/
int run_syscall(int min, int max)
{
struct stat stat_buf;
int proc;
int test;
int tmp;
int ret = 0;
void *p1, *p2;
+ test_getauxval();
+
/* <proc> indicates whether or not /proc is mounted */
proc = stat("/proc", &stat_buf) == 0;
for (test = min; test >= 0 && test <= max; test++) {
int llen = 0; // line length
/* avoid leaving empty lines below, this will insert holes into
* test numbers.
*/
--
Ammar Faizi
^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: [RFC PATCH v1 0/8] nolibc signal handling support
2022-12-22 13:46 ` Ammar Faizi
@ 2022-12-22 14:55 ` Alviro Iskandar Setiawan
2022-12-27 6:26 ` Willy Tarreau
1 sibling, 0 replies; 36+ messages in thread
From: Alviro Iskandar Setiawan @ 2022-12-22 14:55 UTC (permalink / raw)
To: Ammar Faizi
Cc: Gilang Fachrezy, Kanna Scarlet, Muhammad Rizki,
GNU/Weeb Mailing List
[ Off List ]
On Thu, Dec 22, 2022 at 8:46 PM Ammar Faizi <[email protected]> wrote:
> I'll probably only spare more intensive time on this after the holiday
> season ends. I still check in email, but the activity will be sparse.
bang liburan bang, jan ngoding teros
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [RFC PATCH v1 0/8] nolibc signal handling support
2022-12-22 13:46 ` Ammar Faizi
2022-12-22 14:55 ` Alviro Iskandar Setiawan
@ 2022-12-27 6:26 ` Willy Tarreau
2022-12-27 13:32 ` Ammar Faizi
1 sibling, 1 reply; 36+ messages in thread
From: Willy Tarreau @ 2022-12-27 6:26 UTC (permalink / raw)
To: Ammar Faizi
Cc: Shuah Khan, Paul E. McKenney, Gilang Fachrezy,
VNLX Kernel Department, Alviro Iskandar Setiawan, Kanna Scarlet,
Muhammad Rizki, GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
Hi Ammar,
On Thu, Dec 22, 2022 at 08:46:15PM +0700, Ammar Faizi wrote:
> I agree with following the @envp pointer to get the auxv. I was
> trying to wire up a new function '__start' (with double underscores)
> written in C that accepts @argc, @argv and @envp. Then it calls 'main'.
> Then we call '__start' instead of 'main' from '_start'. This way, we
> can arrange nolibc-defined data without touching Assembly much in
> '__start' (before main).
>
> But then I noticed that it wouldn't work because we may have users
> who define the 'main' function differently, e.g.:
>
> int main(void);
> int main(int argc, char **argv);
> int main(int argc, char **argv, char **envp);
>
> So '__start' can't call main. We still need to call the main from the
> inline Assembly (from '_start').
Yes, and quite frankly I prefer to make that the least complicated.
Doing just a simple loop in the _start code is trivial. The main
concern was to store the data. Till now we had an optional .bss
section, we didn't save environ and errno was optional. But let's
be honest, while it does allow for writing the smallest programs,
most programs will have at least one global variable and will get
this section anyway, so we don't save anything in practice. This
concern used to be valid when I was making tiny executables when
running on floppies where each byte mattered, but now that's pointless.
Thus what I'm proposing is to switch to weak symbol definitions for
errno, environ, and auxv. I did a quick test to make sure that the same
symbol was properly used when accessed from two units and that's OK, I'm
seeing the same instance for all of them (which is better than the current
situation where errno is static, hence per-unit).
My quick-and-dirty test looks like this:
diff --git a/arch-x86_64.h b/arch-x86_64.h
index e780fdf..73f7b5f 100644
--- a/arch-x86_64.h
+++ b/arch-x86_64.h
@@ -209,6 +209,9 @@ struct sys_stat_struct {
_ret; \
})
+char **environ __attribute__((weak,unused));
+long *auxv __attribute__((weak,unused));
+
/* startup code */
/*
* x86-64 System V ABI mandates:
@@ -218,11 +221,17 @@ struct sys_stat_struct {
*/
asm(".section .text\n"
".weak _start\n"
"_start:\n"
"pop %rdi\n" // argc (first arg, %rdi)
"mov %rsp, %rsi\n" // argv[] (second arg, %rsi)
"lea 8(%rsi,%rdi,8),%rdx\n" // then a NULL then envp (third arg, %rdx)
+ "mov %rdx, environ\n" // save environ
"xor %ebp, %ebp\n" // zero the stack frame
+ "mov %rdx, %rax\n" // search for auxv (follows NULL after last en>
+ "0: add $8, %rax\n"
+ " cmp -8(%rax), %rbp\n"
+ " jnz 0b\n"
+ "mov %rax, auxv\n" // save auxv
"and $-16, %rsp\n" // x86 ABI : esp must be 16-byte aligned befor>
"call main\n" // main() returns the status code, we'll exit >
"mov %eax, %edi\n" // retrieve exit code (32 bit)
diff --git a/errno.h b/errno.h
index df0e473..9781077 100644
--- a/errno.h
+++ b/errno.h
@@ -29,7 +29,8 @@
#include <asm/errno.h>
/* this way it will be removed if unused */
-static int errno;
+//static int errno;
+int errno __attribute__((weak));
#ifndef NOLIBC_IGNORE_ERRNO
#define SET_ERRNO(v) do { errno = (v); } while (0)
$ cat a.c
#include "nolibc.h"
extern void b(void);
int main(int argc, char **argv, char **envp)
{
//environ = envp;
errno = 1234;
printf("main(): errno=%d env(TERM)=%s auxv=%p auxv[0].t=0x%lx auxv[0].v=0x%lx\n",
errno, getenv("TERM"), auxv, auxv?auxv[0]:0, auxv?auxv[1]:0);
b();
return 0;
}
$ cat b.c
#include "nolibc.h"
void b(void)
{
long *v = auxv;
printf("b(): errno=%d env(TERM)=%s auxv=%p auxv[0].t=0x%lx auxv[0].v=0x%lx\n",
errno, getenv("TERM"), auxv, auxv?auxv[0]:0, auxv?auxv[1]:0);
printf("auxv:\n");
while (v && v[0]) {
printf(" 0x%lx: 0x%lx\n", v[0], v[1]);
v += 2;
}
}
$ gcc -Os -fno-asynchronous-unwind-tables -include /g/public/nolibc/nolibc.h -Wall -nostdlib -static -o ab a.c b.c
$ nm --size ab
0000000000000004 V errno
0000000000000008 V auxv
0000000000000008 V environ
0000000000000014 W memset
0000000000000018 W memcpy
0000000000000018 W raise
000000000000001b W abort
0000000000000030 W memmove
0000000000000053 t u64toa_r
0000000000000053 t u64toa_r
0000000000000082 T main
00000000000000a4 T b
0000000000000289 t printf
000000000000028c t printf.constprop.0
$ ./ab
main(): errno=1234 env(TERM)=xterm auxv=0x7ffdd0c31df8 auxv[0].t=0x21 auxv[0].v=0x7ffdd0d56000
b(): errno=1234 env(TERM)=xterm auxv=0x7ffdd0c31df8 auxv[0].t=0x21 auxv[0].v=0x7ffdd0d56000
auxv:
0x21: 0x7ffdd0d56000
0x10: 0xbfebfbff
0x6: 0x1000
0x11: 0x64
0x3: 0x400040
0x4: 0x38
0x5: 0x7
0x7: 0x0
0x8: 0x0
0x9: 0x401082
0xb: 0x1fd
0xc: 0x1fd
0xd: 0x64
0xe: 0x64
0x17: 0x0
0x19: 0x7ffdd0c31f39
0x1a: 0x2
0x1f: 0x7ffdd0c33ff3
0xf: 0x7ffdd0c31f49
Note that I could verify that some of the entries above are valid
(e.g. "x86_64" in 0xf = AT_PLATFORM).
Thus now my focus will be on storing these variables where relevant
for all archs, so that your getauxval() implementation works on top
of it. It will be much cleaner and will also improve programs' ease
of implementation and reliability.
Cheers,
Willy
PS: maybe we should trim the Cc list for future exchanges.
^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: [RFC PATCH v1 0/8] nolibc signal handling support
2022-12-27 6:26 ` Willy Tarreau
@ 2022-12-27 13:32 ` Ammar Faizi
2022-12-27 13:36 ` Ammar Faizi
2022-12-27 18:49 ` Willy Tarreau
0 siblings, 2 replies; 36+ messages in thread
From: Ammar Faizi @ 2022-12-27 13:32 UTC (permalink / raw)
To: Willy Tarreau
Cc: Shuah Khan, Paul E. McKenney, Gilang Fachrezy,
VNLX Kernel Department, Alviro Iskandar Setiawan, Kanna Scarlet,
Muhammad Rizki, GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
On 12/27/22 1:26 PM, Willy Tarreau wrote:
> Yes, and quite frankly I prefer to make that the least complicated.
> Doing just a simple loop in the _start code is trivial. The main
> concern was to store the data. Till now we had an optional .bss
> section, we didn't save environ and errno was optional. But let's
> be honest, while it does allow for writing the smallest programs,
> most programs will have at least one global variable and will get
> this section anyway, so we don't save anything in practice. This
> concern used to be valid when I was making tiny executables when
> running on floppies where each byte mattered, but now that's pointless.
>
> Thus what I'm proposing is to switch to weak symbol definitions for
> errno, environ, and auxv. I did a quick test to make sure that the same
> symbol was properly used when accessed from two units and that's OK, I'm
> seeing the same instance for all of them (which is better than the current
> situation where errno is static, hence per-unit).
Looks good to me.
> Thus now my focus will be on storing these variables where relevant
> for all archs, so that your getauxval() implementation works on top
> of it. It will be much cleaner and will also improve programs' ease
> of implementation and reliability.
Are you going to wire up a patchset for it?
If so, I'll wait for it. When it's already committed, I'll base this
series on top it.
Or I take your series locally then submit your patches and mine in a
single series.
What do you prefer?
--
Ammar Faizi
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [RFC PATCH v1 0/8] nolibc signal handling support
2022-12-27 13:32 ` Ammar Faizi
@ 2022-12-27 13:36 ` Ammar Faizi
2022-12-27 18:58 ` Willy Tarreau
2022-12-27 18:49 ` Willy Tarreau
1 sibling, 1 reply; 36+ messages in thread
From: Ammar Faizi @ 2022-12-27 13:36 UTC (permalink / raw)
To: Willy Tarreau
Cc: Shuah Khan, Paul E. McKenney, Gilang Fachrezy,
VNLX Kernel Department, Alviro Iskandar Setiawan, Kanna Scarlet,
Muhammad Rizki, GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
On 12/27/22 8:32 PM, Ammar Faizi wrote:
>> Thus now my focus will be on storing these variables where relevant
>> for all archs, so that your getauxval() implementation works on top
>> of it. It will be much cleaner and will also improve programs' ease
>> of implementation and reliability.
>
> Are you going to wire up a patchset for it?
>
> If so, I'll wait for it. When it's already committed, I'll base this
> series on top it.
>
> Or I take your series locally then submit your patches and mine in a
> single series.
>
> What do you prefer?
Side note:
I only know x86 Assembly. So unfortunately, I can't get them working
on all arch(s).
--
Ammar Faizi
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [RFC PATCH v1 0/8] nolibc signal handling support
2022-12-27 13:36 ` Ammar Faizi
@ 2022-12-27 18:58 ` Willy Tarreau
2022-12-28 12:23 ` Ammar Faizi
0 siblings, 1 reply; 36+ messages in thread
From: Willy Tarreau @ 2022-12-27 18:58 UTC (permalink / raw)
To: Ammar Faizi
Cc: Shuah Khan, Paul E. McKenney, Gilang Fachrezy,
VNLX Kernel Department, Alviro Iskandar Setiawan, Kanna Scarlet,
Muhammad Rizki, GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
On Tue, Dec 27, 2022 at 08:36:41PM +0700, Ammar Faizi wrote:
> On 12/27/22 8:32 PM, Ammar Faizi wrote:
> > > Thus now my focus will be on storing these variables where relevant
> > > for all archs, so that your getauxval() implementation works on top
> > > of it. It will be much cleaner and will also improve programs' ease
> > > of implementation and reliability.
> >
> > Are you going to wire up a patchset for it?
> >
> > If so, I'll wait for it. When it's already committed, I'll base this
> > series on top it.
> >
> > Or I take your series locally then submit your patches and mine in a
> > single series.
> >
> > What do you prefer?
>
> Side note:
> I only know x86 Assembly. So unfortunately, I can't get them working
> on all arch(s).
The nice thing about assembly is that once you know one, others are
easy to learn to permit you to write code that you can test. You can
have a look at MIPS for delayed slots, SPARC for register banks, ARM
for instructions that do multiple operations at once and you'll have
seen most of the basics that you'll ever need. Also all of these are
RISC based and cannot load a full-length register in a single instruction,
that's possibly the most confusing thing when you come from x86. And
it's also very interesting to see differences in constraints ;-)
Willy
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [RFC PATCH v1 0/8] nolibc signal handling support
2022-12-27 18:58 ` Willy Tarreau
@ 2022-12-28 12:23 ` Ammar Faizi
0 siblings, 0 replies; 36+ messages in thread
From: Ammar Faizi @ 2022-12-28 12:23 UTC (permalink / raw)
To: Willy Tarreau
Cc: Shuah Khan, Paul E. McKenney, Gilang Fachrezy,
VNLX Kernel Department, Alviro Iskandar Setiawan, Kanna Scarlet,
Muhammad Rizki, GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
On 12/28/22 1:58 AM, Willy Tarreau wrote:
> The nice thing about assembly is that once you know one, others are
> easy to learn to permit you to write code that you can test. You can
> have a look at MIPS for delayed slots, SPARC for register banks, ARM
> for instructions that do multiple operations at once and you'll have
> seen most of the basics that you'll ever need. Also all of these are
> RISC based and cannot load a full-length register in a single instruction,
> that's possibly the most confusing thing when you come from x86. And
> it's also very interesting to see differences in constraints ;-)
Sounds fun. I'll try to get involved with other arch(s). But before
that, I have to prepare the environment. At least virtualization
that emulates those arch(s).
--
Ammar Faizi
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [RFC PATCH v1 0/8] nolibc signal handling support
2022-12-27 13:32 ` Ammar Faizi
2022-12-27 13:36 ` Ammar Faizi
@ 2022-12-27 18:49 ` Willy Tarreau
2022-12-28 12:01 ` Ammar Faizi
1 sibling, 1 reply; 36+ messages in thread
From: Willy Tarreau @ 2022-12-27 18:49 UTC (permalink / raw)
To: Ammar Faizi
Cc: Shuah Khan, Paul E. McKenney, Gilang Fachrezy,
VNLX Kernel Department, Alviro Iskandar Setiawan, Kanna Scarlet,
Muhammad Rizki, GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
On Tue, Dec 27, 2022 at 08:32:57PM +0700, Ammar Faizi wrote:
> > Thus now my focus will be on storing these variables where relevant
> > for all archs, so that your getauxval() implementation works on top
> > of it. It will be much cleaner and will also improve programs' ease
> > of implementation and reliability.
>
> Are you going to wire up a patchset for it?
>
> If so, I'll wait for it. When it's already committed, I'll base this
> series on top it.
>
> Or I take your series locally then submit your patches and mine in a
> single series.
>
> What do you prefer?
I'll try to do it but do not want to make you wait too long in case it
gets delayed. In the worst case we should only postpone the getauxval()
patch and not the other ones.
BTW, do you think your arch-specific changes for sigaction() will be
easily portable to other architectures ? I feel a bit wary of starting
to have different features per architecture given the purpose of the
lib, so the more uniform the coverage the better.
I'll get back to you soon.
Thanks,
Willy
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [RFC PATCH v1 0/8] nolibc signal handling support
2022-12-27 18:49 ` Willy Tarreau
@ 2022-12-28 12:01 ` Ammar Faizi
2022-12-28 13:35 ` Willy Tarreau
0 siblings, 1 reply; 36+ messages in thread
From: Ammar Faizi @ 2022-12-28 12:01 UTC (permalink / raw)
To: Willy Tarreau
Cc: Shuah Khan, Paul E. McKenney, Gilang Fachrezy,
VNLX Kernel Department, Alviro Iskandar Setiawan, Kanna Scarlet,
Muhammad Rizki, GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
On 12/28/22 1:49 AM, Willy Tarreau wrote:
> I'll try to do it but do not want to make you wait too long in case it
> gets delayed. In the worst case we should only postpone the getauxval()
> patch and not the other ones.
I will split it into 2 patchset then.
> BTW, do you think your arch-specific changes for sigaction() will be
> easily portable to other architectures ? I feel a bit wary of starting
> to have different features per architecture given the purpose of the
> lib, so the more uniform the coverage the better.
The 'rt_sigaction()' itself doesn't seem to be an arch specific, but
the way it resumes the execution needs to call 'rt_sigreturn()' which
is arch specific. I took a look at the kernel source code, most
architectures read 'struct rt_sigframe' from the stack pointer.
https://github.com/torvalds/linux/blob/631aa744423173bf921191ba695bbc7c1aabd9e0/arch/x86/kernel/signal_32.c#L145
https://github.com/torvalds/linux/blob/631aa744423173bf921191ba695bbc7c1aabd9e0/arch/x86/kernel/signal_64.c#L243-L271
https://github.com/torvalds/linux/blob/a6b450573b912316ad36262bfc70e7c3870c56d1/arch/arm64/kernel/signal.c#L668-L699
https://github.com/torvalds/linux/blob/a6b450573b912316ad36262bfc70e7c3870c56d1/arch/arm64/kernel/signal32.c#L259
https://github.com/torvalds/linux/blob/eb67d239f3aa1711afb0a42eab50459d9f3d672e/arch/riscv/kernel/signal.c#L101
On the x86-64 arch, the implementation is just like this:
__arch_restore_rt:
#
# ((%rsp - sizeof(long)) must point to 'struct rt_sigframe')
#
# 'struct rt_sigframe' is automatically constructed by
# the kernel when a signal is caught.
#
movl $0xf, %eax // __NR_rt_sigreturn == 0xf
syscall
I believe aarch64 and RISCV don't behave differently, but different
registers.
Not sure what PowerPC does here, it seems a bit different:
https://github.com/torvalds/linux/blob/1612c382ffbdf1f673caec76502b1c00e6d35363/arch/powerpc/kernel/signal_64.c#L744
I haven't taken a look at other archs.
What do you think? Is it affordable for nolibc to implement all of
these?
--
Ammar Faizi
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [RFC PATCH v1 0/8] nolibc signal handling support
2022-12-28 12:01 ` Ammar Faizi
@ 2022-12-28 13:35 ` Willy Tarreau
2022-12-29 11:41 ` Ammar Faizi
0 siblings, 1 reply; 36+ messages in thread
From: Willy Tarreau @ 2022-12-28 13:35 UTC (permalink / raw)
To: Ammar Faizi
Cc: Shuah Khan, Paul E. McKenney, Gilang Fachrezy,
VNLX Kernel Department, Alviro Iskandar Setiawan, Kanna Scarlet,
Muhammad Rizki, GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
On Wed, Dec 28, 2022 at 07:01:36PM +0700, Ammar Faizi wrote:
> On 12/28/22 1:49 AM, Willy Tarreau wrote:
> > I'll try to do it but do not want to make you wait too long in case it
> > gets delayed. In the worst case we should only postpone the getauxval()
> > patch and not the other ones.
>
> I will split it into 2 patchset then.
OK thanks!
I've pushed for you an update which starts to do what I proposed. Errno
and environ are now marked weak for all archs, and _auxv is set for i386,
x86_64, arm64 and arm for now:
https://git.kernel.org/pub/scm/linux/kernel/git/wtarreau/nolibc.git/log/?h=20221227-nolibc-weak-2
You can already use it to implement getauxval(), it will normally work
for these archs.
> > BTW, do you think your arch-specific changes for sigaction() will be
> > easily portable to other architectures ? I feel a bit wary of starting
> > to have different features per architecture given the purpose of the
> > lib, so the more uniform the coverage the better.
>
> The 'rt_sigaction()' itself doesn't seem to be an arch specific, but
> the way it resumes the execution needs to call 'rt_sigreturn()' which
> is arch specific. I took a look at the kernel source code, most
> architectures read 'struct rt_sigframe' from the stack pointer.
>
> https://github.com/torvalds/linux/blob/631aa744423173bf921191ba695bbc7c1aabd9e0/arch/x86/kernel/signal_32.c#L145
> https://github.com/torvalds/linux/blob/631aa744423173bf921191ba695bbc7c1aabd9e0/arch/x86/kernel/signal_64.c#L243-L271
> https://github.com/torvalds/linux/blob/a6b450573b912316ad36262bfc70e7c3870c56d1/arch/arm64/kernel/signal.c#L668-L699
> https://github.com/torvalds/linux/blob/a6b450573b912316ad36262bfc70e7c3870c56d1/arch/arm64/kernel/signal32.c#L259
> https://github.com/torvalds/linux/blob/eb67d239f3aa1711afb0a42eab50459d9f3d672e/arch/riscv/kernel/signal.c#L101
>
> On the x86-64 arch, the implementation is just like this:
>
> __arch_restore_rt:
> #
> # ((%rsp - sizeof(long)) must point to 'struct rt_sigframe')
> #
> # 'struct rt_sigframe' is automatically constructed by
> # the kernel when a signal is caught.
> #
> movl $0xf, %eax // __NR_rt_sigreturn == 0xf
> syscall
I think we could avoid the asm specific stuff is we get rid of the frame
pointer. Please look below:
__attribute__((weak,unused,noreturn,optimize("omit-frame-pointer"),section(".text.nolibc_rt_sigreturn")))
void sys_rt_sigreturn()
{
my_syscall0(__NR_rt_sigreturn);
__builtin_unreachable();
}
It gives me the correct code for x86_64 and i586. I don't know if other
architectures will want to add a prologue. I tried with "naked" but it's
ignored by the compiler since the function is not purely asm. Not very
important but given that we already have everything to perform our calls
it would make sense to stay on this. By the way, for the sake of
consistency with other syscalls, I do think the function (or label if
we can't do otherwise) should be called "sys_rt_sigreturn" as it just
performs a syscall.
> I believe aarch64 and RISCV don't behave differently, but different
> registers.
>
> Not sure what PowerPC does here, it seems a bit different:
> https://github.com/torvalds/linux/blob/1612c382ffbdf1f673caec76502b1c00e6d35363/arch/powerpc/kernel/signal_64.c#L744
It looks similar to me, it's just that the kernel side differs but I
think it's the same.
> I haven't taken a look at other archs.
>
> What do you think? Is it affordable for nolibc to implement all of
> these?
Yes I think so. I suspect that we might need to have a few arch-specific
implementations, but we've already had this case a few times and we could
easily use a pair of #define/#ifdef to skip the generic version.
Best regards,
Willy
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [RFC PATCH v1 0/8] nolibc signal handling support
2022-12-28 13:35 ` Willy Tarreau
@ 2022-12-29 11:41 ` Ammar Faizi
2023-01-03 3:51 ` Alviro Iskandar Setiawan
0 siblings, 1 reply; 36+ messages in thread
From: Ammar Faizi @ 2022-12-29 11:41 UTC (permalink / raw)
To: Willy Tarreau
Cc: Paul E. McKenney, Shuah Khan, Gilang Fachrezy,
VNLX Kernel Department, Alviro Iskandar Setiawan, Kanna Scarlet,
Muhammad Rizki, GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
On 12/28/22 8:35 PM, Willy Tarreau wrote:
> OK thanks!
>
> I've pushed for you an update which starts to do what I proposed. Errno
> and environ are now marked weak for all archs, and _auxv is set for i386,
> x86_64, arm64 and arm for now:
>
> https://git.kernel.org/pub/scm/linux/kernel/git/wtarreau/nolibc.git/log/?h=20221227-nolibc-weak-2
>
> You can already use it to implement getauxval(), it will normally work
> for these archs.
Will do and be back with two patch series.
> I think we could avoid the asm specific stuff is we get rid of the frame
> pointer. Please look below:
>
> __attribute__((weak,unused,noreturn,optimize("omit-frame-pointer"),section(".text.nolibc_rt_sigreturn")))
> void sys_rt_sigreturn()
> {
> my_syscall0(__NR_rt_sigreturn);
> __builtin_unreachable();
> }
Wow! You just taught me that we can force optimize a function with
optimize("omit-frame-pointer") attribute. Nice to know this one!
I compile-tested it and it indeed gives the correct code on x86-64.
Hopefully this approach works for all archs.
> It gives me the correct code for x86_64 and i586. I don't know if other
> architectures will want to add a prologue. I tried with "naked" but it's
> ignored by the compiler since the function is not purely asm. Not very
> important but given that we already have everything to perform our calls
> it would make sense to stay on this. By the way, for the sake of
> consistency with other syscalls, I do think the function (or label if
> we can't do otherwise) should be called "sys_rt_sigreturn" as it just
> performs a syscall.
Will call that 'sys_rt_sigreturn' in the next series.
Thanks!
--
Ammar Faizi
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [RFC PATCH v1 0/8] nolibc signal handling support
2022-12-29 11:41 ` Ammar Faizi
@ 2023-01-03 3:51 ` Alviro Iskandar Setiawan
2023-01-03 3:54 ` Willy Tarreau
0 siblings, 1 reply; 36+ messages in thread
From: Alviro Iskandar Setiawan @ 2023-01-03 3:51 UTC (permalink / raw)
To: Ammar Faizi
Cc: Willy Tarreau, Paul E. McKenney, Shuah Khan, Gilang Fachrezy,
VNLX Kernel Department, Kanna Scarlet, Muhammad Rizki,
GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
On Thu, Dec 29, 2022 at 6:42 PM Ammar Faizi wrote:
> On 12/28/22 8:35 PM, Willy Tarreau wrote:
> > It gives me the correct code for x86_64 and i586. I don't know if other
> > architectures will want to add a prologue. I tried with "naked" but it's
> > ignored by the compiler since the function is not purely asm. Not very
> > important but given that we already have everything to perform our calls
> > it would make sense to stay on this. By the way, for the sake of
> > consistency with other syscalls, I do think the function (or label if
> > we can't do otherwise) should be called "sys_rt_sigreturn" as it just
> > performs a syscall.
>
> Will call that 'sys_rt_sigreturn' in the next series.
From glibc source code says:
GDB needs some intimate knowledge about it to recognize them as signal
trampolines, and make backtraces through signal handlers work right.
Important are both the names (__restore_rt) and the exact instruction
sequence.
link: https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/x86_64/sigaction.c;h=4e6d9cc32e1e18746726fa430d092de9a19ba6c6;hb=b4a5d26d8835d972995f0a0a2f805a8845bafa0b#l34
glibc does this:
" .type __" #name ",@function\n" \
"__" #name ":\n" \
" movq $" #syscall ", %rax\n" \
" syscall\n" \
where
#name = "restore_rt"
#syscall = __NR_rt_sigreturn
I think it should be called "__restore_rt" instead of "sys_rt_sigreturn"?
glibc also has unwind information, but we probably don't need to care
with that much
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [RFC PATCH v1 0/8] nolibc signal handling support
2023-01-03 3:51 ` Alviro Iskandar Setiawan
@ 2023-01-03 3:54 ` Willy Tarreau
2023-01-03 3:59 ` Ammar Faizi
0 siblings, 1 reply; 36+ messages in thread
From: Willy Tarreau @ 2023-01-03 3:54 UTC (permalink / raw)
To: Alviro Iskandar Setiawan
Cc: Ammar Faizi, Paul E. McKenney, Shuah Khan, Gilang Fachrezy,
VNLX Kernel Department, Kanna Scarlet, Muhammad Rizki,
GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
On Tue, Jan 03, 2023 at 10:51:35AM +0700, Alviro Iskandar Setiawan wrote:
> On Thu, Dec 29, 2022 at 6:42 PM Ammar Faizi wrote:
> > On 12/28/22 8:35 PM, Willy Tarreau wrote:
> > > It gives me the correct code for x86_64 and i586. I don't know if other
> > > architectures will want to add a prologue. I tried with "naked" but it's
> > > ignored by the compiler since the function is not purely asm. Not very
> > > important but given that we already have everything to perform our calls
> > > it would make sense to stay on this. By the way, for the sake of
> > > consistency with other syscalls, I do think the function (or label if
> > > we can't do otherwise) should be called "sys_rt_sigreturn" as it just
> > > performs a syscall.
> >
> > Will call that 'sys_rt_sigreturn' in the next series.
>
> >From glibc source code says:
> GDB needs some intimate knowledge about it to recognize them as signal
> trampolines, and make backtraces through signal handlers work right.
> Important are both the names (__restore_rt) and the exact instruction
> sequence.
>
> link: https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/x86_64/sigaction.c;h=4e6d9cc32e1e18746726fa430d092de9a19ba6c6;hb=b4a5d26d8835d972995f0a0a2f805a8845bafa0b#l34
>
> glibc does this:
>
> " .type __" #name ",@function\n" \
> "__" #name ":\n" \
> " movq $" #syscall ", %rax\n" \
> " syscall\n" \
>
> where
>
> #name = "restore_rt"
> #syscall = __NR_rt_sigreturn
>
> I think it should be called "__restore_rt" instead of "sys_rt_sigreturn"?
> glibc also has unwind information, but we probably don't need to care
> with that much
OK, I wasn't aware of this. Of course, if there are some strict rules
for this, let's follow them!
Thanks,
Willy
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [RFC PATCH v1 0/8] nolibc signal handling support
2023-01-03 3:54 ` Willy Tarreau
@ 2023-01-03 3:59 ` Ammar Faizi
2023-01-08 13:08 ` [PATCH v1 0/3] nolibc auxiliary vector retrieval support Ammar Faizi
2023-01-08 13:10 ` [PATCH v2 0/4] nolibc signal handling support Ammar Faizi
0 siblings, 2 replies; 36+ messages in thread
From: Ammar Faizi @ 2023-01-03 3:59 UTC (permalink / raw)
To: Willy Tarreau, Alviro Iskandar Setiawan
Cc: Paul E. McKenney, Shuah Khan, Gilang Fachrezy,
VNLX Kernel Department, Kanna Scarlet, Muhammad Rizki,
GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
On 1/3/23 10:54 AM, Willy Tarreau wrote:
> On Tue, Jan 03, 2023 at 10:51:35AM +0700, Alviro Iskandar Setiawan wrote:
>> GDB needs some intimate knowledge about it to recognize them as signal
>> trampolines, and make backtraces through signal handlers work right.
>> Important are both the names (__restore_rt) and the exact instruction
>> sequence.
Will follow it, thanks!
--
Ammar Faizi
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH v1 0/3] nolibc auxiliary vector retrieval support
2023-01-03 3:59 ` Ammar Faizi
@ 2023-01-08 13:08 ` Ammar Faizi
2023-01-08 13:08 ` [PATCH v1 1/3] nolibc/stdlib: Implement `getauxval(3)` function Ammar Faizi
` (2 more replies)
2023-01-08 13:10 ` [PATCH v2 0/4] nolibc signal handling support Ammar Faizi
1 sibling, 3 replies; 36+ messages in thread
From: Ammar Faizi @ 2023-01-08 13:08 UTC (permalink / raw)
To: Willy Tarreau
Cc: Ammar Faizi, Shuah Khan, Paul E. McKenney, Sven Schnelle,
Alviro Iskandar Setiawan, GNU/Weeb Mailing List,
Linux Kernel Mailing List, Linux Kselftest Mailing List
From: Ammar Faizi <[email protected]>
Hi Willy,
This series is a follow up of our previous discussion about getauxval()
and getpagesize() functions.
It will apply cleanly on top of your "20221227-nolibc-weak-4" branch.
Base commit: b6887ec8b0b0 ("tools/nolibc: add auxiliary vector
retrieval for mips").
I have added a selftest for the getpagesize() function, but I am not
sure how to assert the correctness of getauxval(). I think it is fine
not to add a selftest for getauxval(). If you think we should, please
give some advice on the test mechanism.
Thanks!
Signed-off-by: Ammar Faizi <[email protected]>
---
Ammar Faizi (3):
nolibc/stdlib: Implement `getauxval(3)` function
nolibc/sys: Implement `getpagesize(2)` function
selftests/nolibc: Add `getpagesize(2)` selftest
tools/include/nolibc/stdlib.h | 27 ++++++++++++++++++
tools/include/nolibc/sys.h | 21 ++++++++++++++
tools/testing/selftests/nolibc/nolibc-test.c | 30 ++++++++++++++++++++
3 files changed, 78 insertions(+)
base-commit: b6887ec8b0b0c78db414b78e329bf2ce234dedd5
--
Ammar Faizi
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH v1 1/3] nolibc/stdlib: Implement `getauxval(3)` function
2023-01-08 13:08 ` [PATCH v1 0/3] nolibc auxiliary vector retrieval support Ammar Faizi
@ 2023-01-08 13:08 ` Ammar Faizi
2023-01-08 13:08 ` [PATCH v1 2/3] nolibc/sys: Implement `getpagesize(2)` function Ammar Faizi
2023-01-08 13:08 ` [PATCH v1 3/3] selftests/nolibc: Add `getpagesize(2)` selftest Ammar Faizi
2 siblings, 0 replies; 36+ messages in thread
From: Ammar Faizi @ 2023-01-08 13:08 UTC (permalink / raw)
To: Willy Tarreau
Cc: Ammar Faizi, Shuah Khan, Paul E. McKenney, Sven Schnelle,
Alviro Iskandar Setiawan, GNU/Weeb Mailing List,
Linux Kernel Mailing List, Linux Kselftest Mailing List
From: Ammar Faizi <[email protected]>
Previous commits save the address of the auxiliary vector into a global
variable @_auxv. This commit creates a new function 'getauxval()' as a
helper function to get the auxv value based on the given key.
The behavior of this function is identic with the function documented
in 'man 3 getauxval'. This function is also needed to implement
'getpagesize()' function that we will wire up in the next patches.
Signed-off-by: Ammar Faizi <[email protected]>
---
tools/include/nolibc/stdlib.h | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h
index 92378c4b9660..cdca557c4013 100644
--- a/tools/include/nolibc/stdlib.h
+++ b/tools/include/nolibc/stdlib.h
@@ -12,6 +12,7 @@
#include "types.h"
#include "sys.h"
#include "string.h"
+#include <linux/auxvec.h>
struct nolibc_heap {
size_t len;
@@ -108,6 +109,32 @@ char *getenv(const char *name)
return _getenv(name, environ);
}
+static __attribute__((unused))
+unsigned long getauxval(unsigned long type)
+{
+ const unsigned long *auxv = _auxv;
+ unsigned long ret;
+
+ if (!auxv)
+ return 0;
+
+ while (1) {
+ if (!auxv[0] && !auxv[1]) {
+ ret = 0;
+ break;
+ }
+
+ if (auxv[0] == type) {
+ ret = auxv[1];
+ break;
+ }
+
+ auxv += 2;
+ }
+
+ return ret;
+}
+
static __attribute__((unused))
void *malloc(size_t len)
{
--
Ammar Faizi
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [PATCH v1 2/3] nolibc/sys: Implement `getpagesize(2)` function
2023-01-08 13:08 ` [PATCH v1 0/3] nolibc auxiliary vector retrieval support Ammar Faizi
2023-01-08 13:08 ` [PATCH v1 1/3] nolibc/stdlib: Implement `getauxval(3)` function Ammar Faizi
@ 2023-01-08 13:08 ` Ammar Faizi
2023-01-08 13:08 ` [PATCH v1 3/3] selftests/nolibc: Add `getpagesize(2)` selftest Ammar Faizi
2 siblings, 0 replies; 36+ messages in thread
From: Ammar Faizi @ 2023-01-08 13:08 UTC (permalink / raw)
To: Willy Tarreau
Cc: Ammar Faizi, Shuah Khan, Paul E. McKenney, Sven Schnelle,
Alviro Iskandar Setiawan, GNU/Weeb Mailing List,
Linux Kernel Mailing List, Linux Kselftest Mailing List
From: Ammar Faizi <[email protected]>
This function returns the page size used by the running kernel. The
page size value is taken from the auxiliary vector at 'AT_PAGESZ' key.
'getpagesize(2)' is assumed as a syscall becuase the manpage placement
of this function is in entry 2 ('man 2 getpagesize') despite there is
no real 'getpagesize(2)' syscall in the Linux syscall table. Define
this function in 'sys.h'.
Signed-off-by: Ammar Faizi <[email protected]>
---
Side note:
This function calls 'getauxval(3)' function that's defined in
'stdlib.h', but since most functions in 'stdlib.h' needs 'sys.h', the
'sys.h' is always included first. Therefore, we need a forward
declaration of 'getauxval(3)' in sys.h.
tools/include/nolibc/sys.h | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h
index 3db1dd8c74ee..acf7cf438010 100644
--- a/tools/include/nolibc/sys.h
+++ b/tools/include/nolibc/sys.h
@@ -18,6 +18,7 @@
#include <linux/fs.h>
#include <linux/loop.h>
#include <linux/time.h>
+#include <linux/auxvec.h>
#include "arch.h"
#include "errno.h"
@@ -498,6 +499,26 @@ pid_t gettid(void)
return sys_gettid();
}
+static unsigned long getauxval(unsigned long key);
+
+/*
+ * long getpagesize(void);
+ */
+
+static __attribute__((unused))
+long getpagesize(void)
+{
+ long ret;
+
+ ret = getauxval(AT_PAGESZ);
+ if (!ret) {
+ SET_ERRNO(ENOENT);
+ return -1;
+ }
+
+ return ret;
+}
+
/*
* int gettimeofday(struct timeval *tv, struct timezone *tz);
--
Ammar Faizi
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [PATCH v1 3/3] selftests/nolibc: Add `getpagesize(2)` selftest
2023-01-08 13:08 ` [PATCH v1 0/3] nolibc auxiliary vector retrieval support Ammar Faizi
2023-01-08 13:08 ` [PATCH v1 1/3] nolibc/stdlib: Implement `getauxval(3)` function Ammar Faizi
2023-01-08 13:08 ` [PATCH v1 2/3] nolibc/sys: Implement `getpagesize(2)` function Ammar Faizi
@ 2023-01-08 13:08 ` Ammar Faizi
2 siblings, 0 replies; 36+ messages in thread
From: Ammar Faizi @ 2023-01-08 13:08 UTC (permalink / raw)
To: Willy Tarreau
Cc: Ammar Faizi, Shuah Khan, Paul E. McKenney, Sven Schnelle,
Alviro Iskandar Setiawan, GNU/Weeb Mailing List,
Linux Kernel Mailing List, Linux Kselftest Mailing List
From: Ammar Faizi <[email protected]>
Test the getpagesize() function. Make sure it returns the correct
value.
Signed-off-by: Ammar Faizi <[email protected]>
---
tools/testing/selftests/nolibc/nolibc-test.c | 30 ++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index 6da17612251c..3a78399f4624 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -442,6 +442,35 @@ int test_getdents64(const char *dir)
return ret;
}
+static int test_getpagesize(void)
+{
+ long x = getpagesize();
+ int c;
+
+ if (x < 0)
+ return x;
+
+#if defined(__x86_64__) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__)
+ /*
+ * x86 family is always 4K page.
+ */
+ c = (x == 4096);
+#elif defined(__aarch64__)
+ /*
+ * Linux aarch64 supports three values of page size: 4K, 16K, and 64K
+ * which are selected at kernel compilation time.
+ */
+ c = (x == 4096 || x == (16 * 1024) || x == (64 * 1024));
+#else
+ /*
+ * Assuming other architectures must have at least 4K page.
+ */
+ c = (x >= 4096);
+#endif
+
+ return !c;
+}
+
/* Run syscall tests between IDs <min> and <max>.
* Return 0 on success, non-zero on failure.
*/
@@ -502,6 +531,7 @@ int run_syscall(int min, int max)
CASE_TEST(gettimeofday_bad2); EXPECT_SYSER(1, gettimeofday(NULL, (void *)1), -1, EFAULT); break;
CASE_TEST(gettimeofday_bad2); EXPECT_SYSER(1, gettimeofday(NULL, (void *)1), -1, EFAULT); break;
#endif
+ CASE_TEST(getpagesize); EXPECT_SYSZR(1, test_getpagesize()); break;
CASE_TEST(ioctl_tiocinq); EXPECT_SYSZR(1, ioctl(0, TIOCINQ, &tmp)); break;
CASE_TEST(ioctl_tiocinq); EXPECT_SYSZR(1, ioctl(0, TIOCINQ, &tmp)); break;
CASE_TEST(link_root1); EXPECT_SYSER(1, link("/", "/"), -1, EEXIST); break;
--
Ammar Faizi
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [PATCH v2 0/4] nolibc signal handling support
2023-01-03 3:59 ` Ammar Faizi
2023-01-08 13:08 ` [PATCH v1 0/3] nolibc auxiliary vector retrieval support Ammar Faizi
@ 2023-01-08 13:10 ` Ammar Faizi
2023-01-08 13:10 ` [PATCH v2 1/4] nolibc/sys: Implement `sigaction(2)` function Ammar Faizi
` (4 more replies)
1 sibling, 5 replies; 36+ messages in thread
From: Ammar Faizi @ 2023-01-08 13:10 UTC (permalink / raw)
To: Willy Tarreau
Cc: Ammar Faizi, Shuah Khan, Paul E. McKenney, Gilang Fachrezy,
Alviro Iskandar Setiawan, GNU/Weeb Mailing List,
Linux Kernel Mailing List, Linux Kselftest Mailing List
From: Ammar Faizi <[email protected]>
Hi Willy,
On top of the series titled "nolibc auxiliary vector retrieval support".
The prerequisite patches of this series are in that series.
This is v2 of nolibc signal handling support. It adds signal handling
support to the nolibc subsystem:
1) Initial implementation of nolibc sigaction(2) function.
`sigaction()` needs an architecture-dependent "signal trampoline"
function that invokes __rt_sigreturn syscall to resume the process
after a signal gets handled.
The "signal trampoline" function is called `__restore_rt` in this
implementation. The naming `__restore_rt` is important for GDB. It
also has to be given a special optimization attribute
"omit-frame-pointer" to prevent the compiler from creating a stack
frame that makes the `%rsp` value no longer points to the `struct
rt_sigframe` that the kernel constructed.
2) signal(2) function.
signal() function is the simpler version of sigaction(). Unlike
sigaction(), which fully controls the struct sigaction, the caller
only cares about the sa_handler when calling the signal() function.
signal() internally calls sigaction().
3) More selftests.
This series also adds selftests for:
- fork(2)
- sigaction(2)
- signal(2)
Side note for __restore_rt:
This has been tested on x86-64 arch and `__restore_rt` generates the
correct code. The `__restore_rt` codegen correctness on other
architectures need to be evaluated as well. If it can't generate the
correct code, it has to be written in inline Assembly.
The current codegen for __restore_rt looks like this (gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0):
00000000004038e3 <__restore_rt>:
4038e3: endbr64
4038e7: mov $0xf,%eax
4038ec: syscall
## Changes since RFC v1:
- Separate getpagesize() series.
- Write __restore_rt function in C instead of in inline Assembly.
Signed-off-by: Ammar Faizi <[email protected]>
---
Ammar Faizi (4):
nolibc/sys: Implement `sigaction(2)` function
nolibc/sys: Implement `signal(2)` function
selftests/nolibc: Add `fork(2)` selftest
selftests/nolibc: Add `sigaction(2)` selftest
tools/include/nolibc/sys.h | 97 +++++++++++
tools/testing/selftests/nolibc/nolibc-test.c | 172 +++++++++++++++++++
2 files changed, 269 insertions(+)
base-commit: b6887ec8b0b0c78db414b78e329bf2ce234dedd5
prerequisite-patch-id: 8dd0ca8ecee1732d8f5c0b233f8231dda6ab0d22
prerequisite-patch-id: ff4c08615ebbdc1a04ce39f39f99387ee46b2b31
prerequisite-patch-id: af837a829263849331eb6d73701afd7903146055
--
Ammar Faizi
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH v2 1/4] nolibc/sys: Implement `sigaction(2)` function
2023-01-08 13:10 ` [PATCH v2 0/4] nolibc signal handling support Ammar Faizi
@ 2023-01-08 13:10 ` Ammar Faizi
2023-01-08 13:10 ` [PATCH v2 2/4] nolibc/sys: Implement `signal(2)` function Ammar Faizi
` (3 subsequent siblings)
4 siblings, 0 replies; 36+ messages in thread
From: Ammar Faizi @ 2023-01-08 13:10 UTC (permalink / raw)
To: Willy Tarreau
Cc: Ammar Faizi, Shuah Khan, Paul E. McKenney, Gilang Fachrezy,
Alviro Iskandar Setiawan, GNU/Weeb Mailing List,
Linux Kernel Mailing List, Linux Kselftest Mailing List
From: Ammar Faizi <[email protected]>
This commit adds the initial implementation of nolibc `sigaction()`
function. Currently, this implementation is only available on the
x86-64 arch.
`sigaction()` needs an architecture-dependent "signal trampoline"
function that invokes __rt_sigreturn syscall to resume the process
after a signal gets handled.
The "signal trampoline" function is called `__restore_rt` in this
implementation. The naming `__restore_rt` is important for GDB. It also
has to be given a special optimization attribute "omit-frame-pointer"
to prevent the compiler from creating a stack frame that makes the
`%rsp` value no longer points to the `struct rt_sigframe` that the
kernel constructed.
Link: https://lore.kernel.org/lkml/[email protected]
Suggested-by: Willy Tarreau <[email protected]>
Signed-off-by: Ammar Faizi <[email protected]>
---
Side note:
This has been tested on x86-64 arch and `__restore_rt` generates the
correct code. The `__restore_rt` codegen correctness on other
architectures need to be evaluated as well. If it can't generate the
correct code, it has to be written in inline Assembly.
tools/include/nolibc/sys.h | 72 ++++++++++++++++++++++++++++++++++++++
1 file changed, 72 insertions(+)
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h
index acf7cf438010..7d594155e77f 100644
--- a/tools/include/nolibc/sys.h
+++ b/tools/include/nolibc/sys.h
@@ -1047,6 +1047,78 @@ pid_t setsid(void)
return ret;
}
+typedef void (*sighandler_t)(int sig);
+
+/*
+ * int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
+ */
+
+static __attribute__((unused))
+int sys_sigaction(int signum, const struct sigaction *act,
+ struct sigaction *oldact)
+{
+ return my_syscall4(__NR_rt_sigaction, signum, act, oldact,
+ sizeof(sigset_t));
+}
+
+__attribute__((weak,unused,noreturn,optimize("omit-frame-pointer"),section(".text.__restore_rt")))
+void __restore_rt(void)
+{
+ my_syscall0(__NR_rt_sigreturn);
+ __builtin_unreachable();
+}
+
+static __attribute__((unused))
+int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
+{
+ struct sigaction act2 = *act;
+ int ret;
+
+ /*
+ * On Linux x86-64, libc's sigaction() always sets the
+ * @act->sa_restorer when the caller passes a NULL.
+ *
+ * @act->sa_restorer is an arch-specific function used
+ * as a "signal trampoline".
+ *
+ * @act->sa_handler is a signal handler provided by the
+ * user.
+ *
+ * When the handled signal is caught, the %rip jumps to
+ * @act->sa_handler with user stack already set by the
+ * kernel as below:
+ *
+ * |--------------------|
+ * %rsp -> | act->sa_restorer | (return address)
+ * |--------------------|
+ * | struct rt_sigframe | (process context info)
+ * | |
+ * | |
+ * ....................
+ *
+ * Once this signal handler executes the "ret" instruction,
+ * the %rip jumps to @act->sa_restorer. The sa_restorer
+ * function has to invoke the __rt_sigreturn syscall with
+ * %rsp pointing to the `struct rt_sigframe` that the kernel
+ * constructed previously to resume the process.
+ *
+ * `struct rt_sigframe` contains the registers' value before
+ * the signal is caught.
+ *
+ */
+ if (!act2.sa_restorer) {
+ act2.sa_flags |= SA_RESTORER;
+ act2.sa_restorer = __restore_rt;
+ }
+
+ ret = sys_sigaction(signum, &act2, oldact);
+ if (ret < 0) {
+ SET_ERRNO(-ret);
+ ret = -1;
+ }
+ return ret;
+}
+
/*
* int stat(const char *path, struct stat *buf);
--
Ammar Faizi
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [PATCH v2 2/4] nolibc/sys: Implement `signal(2)` function
2023-01-08 13:10 ` [PATCH v2 0/4] nolibc signal handling support Ammar Faizi
2023-01-08 13:10 ` [PATCH v2 1/4] nolibc/sys: Implement `sigaction(2)` function Ammar Faizi
@ 2023-01-08 13:10 ` Ammar Faizi
2023-01-08 13:10 ` [PATCH v2 3/4] selftests/nolibc: Add `fork(2)` selftest Ammar Faizi
` (2 subsequent siblings)
4 siblings, 0 replies; 36+ messages in thread
From: Ammar Faizi @ 2023-01-08 13:10 UTC (permalink / raw)
To: Willy Tarreau
Cc: Ammar Faizi, Shuah Khan, Paul E. McKenney, Gilang Fachrezy,
Alviro Iskandar Setiawan, GNU/Weeb Mailing List,
Linux Kernel Mailing List, Linux Kselftest Mailing List
From: Ammar Faizi <[email protected]>
signal() function is the simpler version of sigaction(). Unlike
sigaction(), which fully controls the `struct sigaction`, the caller
only cares about the sa_handler when calling the signal() function.
signal() internally calls sigaction().
Signed-off-by: Ammar Faizi <[email protected]>
---
tools/include/nolibc/sys.h | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h
index 7d594155e77f..54e51f154b1f 100644
--- a/tools/include/nolibc/sys.h
+++ b/tools/include/nolibc/sys.h
@@ -1119,6 +1119,31 @@ int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
return ret;
}
+/*
+ * sighandler_t signal(int signum, sighandler_t handler);
+ */
+
+static __attribute__((unused))
+sighandler_t signal(int signum, sighandler_t handler)
+{
+ const struct sigaction act = {
+ .sa_handler = handler,
+ .sa_flags = SA_RESTORER,
+ .sa_restorer = __restore_rt
+ };
+ sighandler_t old_sah;
+ struct sigaction old;
+ int ret;
+
+ ret = sys_sigaction(signum, &act, &old);
+ if (ret < 0) {
+ SET_ERRNO(-ret);
+ old_sah = SIG_ERR;
+ } else {
+ old_sah = old.sa_handler;
+ }
+ return old_sah;
+}
/*
* int stat(const char *path, struct stat *buf);
--
Ammar Faizi
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [PATCH v2 3/4] selftests/nolibc: Add `fork(2)` selftest
2023-01-08 13:10 ` [PATCH v2 0/4] nolibc signal handling support Ammar Faizi
2023-01-08 13:10 ` [PATCH v2 1/4] nolibc/sys: Implement `sigaction(2)` function Ammar Faizi
2023-01-08 13:10 ` [PATCH v2 2/4] nolibc/sys: Implement `signal(2)` function Ammar Faizi
@ 2023-01-08 13:10 ` Ammar Faizi
2023-01-08 13:10 ` [PATCH v2 4/4] selftests/nolibc: Add `sigaction(2)` selftest Ammar Faizi
2023-01-08 13:28 ` [PATCH v2 0/4] nolibc signal handling support Alviro Iskandar Setiawan
4 siblings, 0 replies; 36+ messages in thread
From: Ammar Faizi @ 2023-01-08 13:10 UTC (permalink / raw)
To: Willy Tarreau
Cc: Ammar Faizi, Shuah Khan, Paul E. McKenney, Gilang Fachrezy,
Alviro Iskandar Setiawan, GNU/Weeb Mailing List,
Linux Kernel Mailing List, Linux Kselftest Mailing List
From: Ammar Faizi <[email protected]>
Ensure the fork() function can create a child process. Also, when the
child exits, the parent must be able to get the child's exit code
via waitpid().
Signed-off-by: Ammar Faizi <[email protected]>
---
tools/testing/selftests/nolibc/nolibc-test.c | 45 ++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index 3a78399f4624..cb6ec9f71aae 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -471,6 +471,50 @@ static int test_getpagesize(void)
return !c;
}
+/*
+ * Test fork().
+ * Make sure the exit code can be read from the parent process.
+ */
+static int test_fork_and_exit(int expected_code)
+{
+ int status;
+ int code;
+ pid_t ret;
+ pid_t p;
+
+ p = fork();
+ if (p < 0)
+ return p;
+
+ if (!p)
+ exit(expected_code);
+
+ do {
+ ret = waitpid(p, &status, 0);
+ if (ret < 0)
+ return ret;
+ } while (!WIFEXITED(status));
+
+ code = WEXITSTATUS(status);
+ if (code != expected_code) {
+ printf("test_fork_and_exit(): waitpid(): Invalid exit code: %d; expected = %d\n", code, expected_code);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int test_fork(void)
+{
+ int i;
+
+ for (i = 0; i < 255; i++) {
+ if (test_fork_and_exit(i))
+ return -1;
+ }
+ return 0;
+}
+
/* Run syscall tests between IDs <min> and <max>.
* Return 0 on success, non-zero on failure.
*/
@@ -523,6 +567,7 @@ int run_syscall(int min, int max)
CASE_TEST(dup3_0); tmp = dup3(0, 100, 0); EXPECT_SYSNE(1, tmp, -1); close(tmp); break;
CASE_TEST(dup3_m1); tmp = dup3(-1, 100, 0); EXPECT_SYSER(1, tmp, -1, EBADF); if (tmp != -1) close(tmp); break;
CASE_TEST(execve_root); EXPECT_SYSER(1, execve("/", (char*[]){ [0] = "/", [1] = NULL }, NULL), -1, EACCES); break;
+ CASE_TEST(fork); EXPECT_SYSZR(1, test_fork()); break;
CASE_TEST(getdents64_root); EXPECT_SYSNE(1, test_getdents64("/"), -1); break;
CASE_TEST(getdents64_null); EXPECT_SYSER(1, test_getdents64("/dev/null"), -1, ENOTDIR); break;
CASE_TEST(gettimeofday_null); EXPECT_SYSZR(1, gettimeofday(NULL, NULL)); break;
--
Ammar Faizi
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [PATCH v2 4/4] selftests/nolibc: Add `sigaction(2)` selftest
2023-01-08 13:10 ` [PATCH v2 0/4] nolibc signal handling support Ammar Faizi
` (2 preceding siblings ...)
2023-01-08 13:10 ` [PATCH v2 3/4] selftests/nolibc: Add `fork(2)` selftest Ammar Faizi
@ 2023-01-08 13:10 ` Ammar Faizi
2023-01-08 13:28 ` [PATCH v2 0/4] nolibc signal handling support Alviro Iskandar Setiawan
4 siblings, 0 replies; 36+ messages in thread
From: Ammar Faizi @ 2023-01-08 13:10 UTC (permalink / raw)
To: Willy Tarreau
Cc: Ammar Faizi, Shuah Khan, Paul E. McKenney, Gilang Fachrezy,
Alviro Iskandar Setiawan, GNU/Weeb Mailing List,
Linux Kernel Mailing List, Linux Kselftest Mailing List
From: Ammar Faizi <[email protected]>
Test the sigaction() function implementation. Test steps:
- Set a signal handler.
- Then send a signal to itself using the kill() syscall.
- The program has to survive and store the caught signal number in a
volatile global variable.
- Validate the volatile global variable value.
- Restore the original signal handler.
Signed-off-by: Ammar Faizi <[email protected]>
---
tools/testing/selftests/nolibc/nolibc-test.c | 127 +++++++++++++++++++
1 file changed, 127 insertions(+)
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index cb6ec9f71aae..946ed0132f93 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -515,6 +515,131 @@ static int test_fork(void)
return 0;
}
+static volatile int g_test_sig;
+
+static void test_signal_handler(int sig)
+{
+ g_test_sig = sig;
+}
+
+static int test_sigaction_sig(int sig)
+{
+ const struct sigaction new = {
+ .sa_handler = test_signal_handler
+ };
+ struct sigaction old;
+ int ret;
+
+ /*
+ * Set the signal handler.
+ */
+ ret = sigaction(sig, &new, &old);
+ if (ret) {
+ printf("test_sigaction_sig(%d): Failed to set a signal handler\n", sig);
+ return ret;
+ }
+
+ /*
+ * Test the signal handler.
+ */
+ g_test_sig = 0;
+ kill(getpid(), sig);
+
+ /*
+ * test_signal_handler() must set @g_test_sig to @sig.
+ */
+ if (g_test_sig != sig) {
+ printf("test_sigaction_sig(%d): Invalid g_test_sig value (%d != %d)\n", sig, g_test_sig, sig);
+ return -1;
+ }
+
+ /*
+ * Restore the original signal handler.
+ */
+ ret = sigaction(sig, &old, NULL);
+ if (ret) {
+ printf("test_sigaction_sig(%d): Failed to restore the signal handler\n", sig);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int test_signal_sig(int sig)
+{
+ sighandler_t old;
+
+ /*
+ * Set the signal handler.
+ */
+ old = signal(sig, test_signal_handler);
+ if (old == SIG_ERR) {
+ printf("test_signal_sig(%d): Failed to set a signal handler\n", sig);
+ return -1;
+ }
+
+ /*
+ * Test the signal handler.
+ */
+ g_test_sig = 0;
+ kill(getpid(), sig);
+
+ /*
+ * test_signal_handler() must set @g_test_sig to @sig.
+ */
+ if (g_test_sig != sig) {
+ printf("test_signal_sig(%d): Invalid g_test_sig value (%d != %d)\n", sig, g_test_sig, sig);
+ return -1;
+ }
+
+ /*
+ * Restore the original signal handler.
+ */
+ old = signal(sig, old);
+ if (old == SIG_ERR) {
+ printf("test_signal_sig(%d): Failed to restore the signal handler\n", sig);
+ return -1;
+ }
+
+ return 0;
+}
+
+static const int g_sig_to_test[] = {
+ SIGINT,
+ SIGHUP,
+ SIGTERM,
+ SIGQUIT,
+ SIGSEGV
+};
+
+static int test_sigaction(void)
+{
+ size_t i;
+ int ret;
+
+ for (i = 0; i < (sizeof(g_sig_to_test) / sizeof(g_sig_to_test[0])); i++) {
+ ret = test_sigaction_sig(g_sig_to_test[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int test_signal(void)
+{
+ size_t i;
+ int ret;
+
+ for (i = 0; i < (sizeof(g_sig_to_test) / sizeof(g_sig_to_test[0])); i++) {
+ ret = test_signal_sig(g_sig_to_test[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
/* Run syscall tests between IDs <min> and <max>.
* Return 0 on success, non-zero on failure.
*/
@@ -596,6 +721,8 @@ int run_syscall(int min, int max)
CASE_TEST(select_null); EXPECT_SYSZR(1, ({ struct timeval tv = { 0 }; select(0, NULL, NULL, NULL, &tv); })); break;
CASE_TEST(select_stdout); EXPECT_SYSNE(1, ({ fd_set fds; FD_ZERO(&fds); FD_SET(1, &fds); select(2, NULL, &fds, NULL, NULL); }), -1); break;
CASE_TEST(select_fault); EXPECT_SYSER(1, select(1, (void *)1, NULL, NULL, 0), -1, EFAULT); break;
+ CASE_TEST(sigaction); EXPECT_SYSZR(1, test_sigaction()); break;
+ CASE_TEST(signal); EXPECT_SYSZR(1, test_signal()); break;
CASE_TEST(stat_blah); EXPECT_SYSER(1, stat("/proc/self/blah", &stat_buf), -1, ENOENT); break;
CASE_TEST(stat_fault); EXPECT_SYSER(1, stat(NULL, &stat_buf), -1, EFAULT); break;
CASE_TEST(symlink_root); EXPECT_SYSER(1, symlink("/", "/"), -1, EEXIST); break;
--
Ammar Faizi
^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: [PATCH v2 0/4] nolibc signal handling support
2023-01-08 13:10 ` [PATCH v2 0/4] nolibc signal handling support Ammar Faizi
` (3 preceding siblings ...)
2023-01-08 13:10 ` [PATCH v2 4/4] selftests/nolibc: Add `sigaction(2)` selftest Ammar Faizi
@ 2023-01-08 13:28 ` Alviro Iskandar Setiawan
2023-01-08 13:31 ` Ammar Faizi
4 siblings, 1 reply; 36+ messages in thread
From: Alviro Iskandar Setiawan @ 2023-01-08 13:28 UTC (permalink / raw)
To: Ammar Faizi
Cc: Willy Tarreau, Shuah Khan, Paul E. McKenney, Gilang Fachrezy,
GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
On Sun, Jan 8, 2023 at 8:10 PM Ammar Faizi wrote:
> 3) More selftests.
>
> This series also adds selftests for:
> - fork(2)
> - sigaction(2)
> - signal(2)
[...]
> Ammar Faizi (4):
> nolibc/sys: Implement `sigaction(2)` function
> nolibc/sys: Implement `signal(2)` function
> selftests/nolibc: Add `fork(2)` selftest
> selftests/nolibc: Add `sigaction(2)` selftest
The signal() self test is missing?
btw, it's too crowded here, let's create a new thread for this if you
ever send another version
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v2 0/4] nolibc signal handling support
2023-01-08 13:28 ` [PATCH v2 0/4] nolibc signal handling support Alviro Iskandar Setiawan
@ 2023-01-08 13:31 ` Ammar Faizi
2023-01-08 13:39 ` Ammar Faizi
0 siblings, 1 reply; 36+ messages in thread
From: Ammar Faizi @ 2023-01-08 13:31 UTC (permalink / raw)
To: Alviro Iskandar Setiawan
Cc: Willy Tarreau, Shuah Khan, Paul E. McKenney, Gilang Fachrezy,
GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
On Sun, Jan 08, 2023 at 08:28:33PM +0700, Alviro Iskandar Setiawan wrote:
> The signal() self test is missing?
Ugh, yes. I didn't send the signal() selftest. Will do.
> btw, it's too crowded here, let's create a new thread for this if you
> ever send another version
I'll resend both series. Please ignore these versions...
--
Ammar Faizi
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v2 0/4] nolibc signal handling support
2023-01-08 13:31 ` Ammar Faizi
@ 2023-01-08 13:39 ` Ammar Faizi
0 siblings, 0 replies; 36+ messages in thread
From: Ammar Faizi @ 2023-01-08 13:39 UTC (permalink / raw)
To: Alviro Iskandar Setiawan
Cc: Willy Tarreau, Shuah Khan, Paul E. McKenney, Gilang Fachrezy,
GNU/Weeb Mailing List, Linux Kernel Mailing List,
Linux Kselftest Mailing List
On Sun, Jan 08, 2023 at 08:31:37PM +0700, Ammar Faizi wrote:
> On Sun, Jan 08, 2023 at 08:28:33PM +0700, Alviro Iskandar Setiawan wrote:
> > The signal() self test is missing?
>
> Ugh, yes. I didn't send the signal() selftest. Will do.
Bah, it turned out I squashed the signal() test into "selftests/nolibc:
Add `sigaction(2)` selftes" patch. It was unintentional. Will split it
properly in v3.
--
Ammar Faizi
^ permalink raw reply [flat|nested] 36+ messages in thread