[klibc] [PATCH 2/2] ia64: Fix sigaction struct layout and function implementation

James Clarke jrtc27 at jrtc27.com
Fri Feb 1 17:35:57 PST 2019


Commit 8418552 ("[klibc] ia64: Fix shared build") switched to the
function descriptor-less ABI. However, when passing a function pointer
to the kernel for signal handling, it always expects a descriptor, and
-mno-pic does not set any ELF flags that the kernel could detect. Thus
to fix this regression we must construct descriptors solely for passing
to/from the kernel.

Despite this, usr/dash/static/sh -c "usr/utils/static/true; exit" was
still seen to hang during the test suite. This is because sa_mask and
sa_flags were round the wrong way (matching the old sigaction syscall
rather than the newer rt_sigaction syscall, despite the former not
existing on ia64), causing the kernel to think SA_NOCLDWAIT was set.
This bug appears to have been present since the ia64 port was first
committed.
---
 usr/include/arch/ia64/klibc/archsignal.h |  3 ++-
 usr/klibc/sigaction.c                    | 45 +++++++++++++++++++++++++++++++-
 2 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/usr/include/arch/ia64/klibc/archsignal.h b/usr/include/arch/ia64/klibc/archsignal.h
index fbc961b..c52c41a 100644
--- a/usr/include/arch/ia64/klibc/archsignal.h
+++ b/usr/include/arch/ia64/klibc/archsignal.h
@@ -22,8 +22,9 @@ struct sigaction {
 		__sighandler_t _sa_handler;
 		void (*_sa_sigaction) (int, struct siginfo *, void *);
 	} _u;
-	sigset_t sa_mask;
 	int sa_flags;
+	int __pad0;
+	sigset_t sa_mask;
 };
 
 #define sa_handler      _u._sa_handler
diff --git a/usr/klibc/sigaction.c b/usr/klibc/sigaction.c
index 19a8a54..e4901ab 100644
--- a/usr/klibc/sigaction.c
+++ b/usr/klibc/sigaction.c
@@ -19,13 +19,30 @@ __extern int __rt_sigaction(int, const struct sigaction *, struct sigaction *,
 			    size_t);
 #endif
 
+#ifdef __ia64__
+/* We use -mno-pic so our function pointers are straight to the function entry
+   point, but the kernel always expects a descriptor. Thus we create a fake
+   descriptor for each possible signal, update it, and pass that to the kernel
+   instead (the descriptor must remain valid after returning from sigaction
+   until it is replaced). */
+struct {
+	uintptr_t entry;
+	uintptr_t gp;
+} signal_descriptors[_NSIG];
+#endif
+
 int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
 {
 	int rv;
 
-#if _KLIBC_NEEDS_SA_RESTORER
+#if _KLIBC_NEEDS_SA_RESTORER || defined(__ia64__)
 	struct sigaction sa;
+#endif
+#ifdef __ia64__
+	uintptr_t old_entry;
+#endif
 
+#if _KLIBC_NEEDS_SA_RESTORER
 	if (act && !(act->sa_flags & SA_RESTORER)) {
 		sa = *act;
 		act = &sa;
@@ -37,6 +54,26 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
 	}
 #endif
 
+#ifdef __ia64__
+	if (sig < 0 || sig >= _NSIG) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (oact) {
+		old_entry = signal_descriptors[sig].entry;
+	}
+
+	if (act && act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL) {
+		sa = *act;
+		act = &sa;
+
+		signal_descriptors[sig].entry = (uintptr_t)sa.sa_handler;
+
+		sa.sa_handler = (__sighandler_t)(uintptr_t)&signal_descriptors[sig];
+	}
+#endif
+
 #if _KLIBC_USE_RT_SIG
 # ifdef __sparc__
 	{
@@ -61,5 +98,11 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
 	}
 #endif
 
+#ifdef __ia64__
+	if (oact && oact->sa_handler != SIG_IGN && oact->sa_handler != SIG_DFL) {
+		oact->sa_handler = (__sighandler_t)old_entry;
+	}
+#endif
+
 	return rv;
 }
-- 
1.8.5.3



More information about the klibc mailing list