Fix parameters of signal handlers for linuxppc.
Linux passes the arguments in registers, but our compiler expects arguments on the stack. Signal handlers got garbage instead of the signal number. Some handlers, like the one in lang/m2/libm2/sigtrp.c, need the correct signal number. I write a "bridge" in PowerPC assembly that moves the arguments to the stack. I put the bridge in sigaction(), so I provide a signal() that calls sigaction(). I remove the *.c glob or wildcard from build.lua, so linuxppc only compiles its own signal.c, not the other signal.c for linux386 and linux68k. My bridge uses sigprocmask(), so I also add sigprocmask(). Because linux386 and linux68k use globs, they also get sigprocmask(). I sync the header files so all three Linux platforms declare execve(), sigprocmask(), and unlink(), but not remove(), because we have remove() in <stdio.h>. I am using sigaction.s to test some features that we recently added to our PowerPC assembler. These are the "hi16[...]" and "lo16[...]" syntax, and also the extended names like "beq", "cmpwi", "li", "subi".
This commit is contained in:
parent
5aa2ac2246
commit
a585ddf578
7
plat/linux/libsys/sigprocmask.c
Normal file
7
plat/linux/libsys/sigprocmask.c
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#include <signal.h>
|
||||||
|
#include "libsys.h"
|
||||||
|
|
||||||
|
int sigprocmask(int flags, const sigset_t *new, sigset_t *old)
|
||||||
|
{
|
||||||
|
return _syscall(__NR_sigprocmask, flags, (quad) new, (quad) old);
|
||||||
|
}
|
|
@ -56,7 +56,6 @@ extern int write(int fd, void* buffer, size_t count);
|
||||||
extern off_t lseek(int fildes, off_t offset, int whence);
|
extern off_t lseek(int fildes, off_t offset, int whence);
|
||||||
extern int fcntl(int fd, int op, ...);
|
extern int fcntl(int fd, int op, ...);
|
||||||
extern int unlink(const char* path);
|
extern int unlink(const char* path);
|
||||||
extern int remove(const char* path);
|
|
||||||
|
|
||||||
/* Special variables */
|
/* Special variables */
|
||||||
|
|
||||||
|
@ -117,8 +116,16 @@ typedef int sig_atomic_t;
|
||||||
|
|
||||||
#define _NSIG 32 /* Biggest signal number + 1
|
#define _NSIG 32 /* Biggest signal number + 1
|
||||||
(not including real-time signals). */
|
(not including real-time signals). */
|
||||||
|
|
||||||
|
/* sigprocmask */
|
||||||
|
#define SIG_BLOCK 0
|
||||||
|
#define SIG_UNBLOCK 1
|
||||||
|
#define SIG_SETMASK 2
|
||||||
|
typedef unsigned long sigset_t;
|
||||||
|
|
||||||
typedef void (*sighandler_t)(int);
|
typedef void (*sighandler_t)(int);
|
||||||
extern sighandler_t signal(int signum, sighandler_t handler);
|
extern sighandler_t signal(int signum, sighandler_t handler);
|
||||||
|
extern int sigprocmask(int, const sigset_t *, sigset_t *);
|
||||||
extern int raise(int signum);
|
extern int raise(int signum);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,7 @@ extern int read(int fd, void* buffer, size_t count);
|
||||||
extern int write(int fd, void* buffer, size_t count);
|
extern int write(int fd, void* buffer, size_t count);
|
||||||
extern off_t lseek(int fildes, off_t offset, int whence);
|
extern off_t lseek(int fildes, off_t offset, int whence);
|
||||||
extern int fcntl(int fd, int op, ...);
|
extern int fcntl(int fd, int op, ...);
|
||||||
|
extern int unlink(const char* path);
|
||||||
|
|
||||||
/* Special variables */
|
/* Special variables */
|
||||||
|
|
||||||
|
@ -67,6 +68,7 @@ extern pid_t getpid(void);
|
||||||
extern int brk(void* ptr);
|
extern int brk(void* ptr);
|
||||||
extern void* sbrk(int increment);
|
extern void* sbrk(int increment);
|
||||||
extern int isatty(int d);
|
extern int isatty(int d);
|
||||||
|
extern int execve(const char *path, char *const argv[], char *const envp[]);
|
||||||
|
|
||||||
/* Signal handling */
|
/* Signal handling */
|
||||||
|
|
||||||
|
@ -114,8 +116,16 @@ typedef int sig_atomic_t;
|
||||||
|
|
||||||
#define _NSIG 32 /* Biggest signal number + 1
|
#define _NSIG 32 /* Biggest signal number + 1
|
||||||
(not including real-time signals). */
|
(not including real-time signals). */
|
||||||
|
|
||||||
|
/* sigprocmask */
|
||||||
|
#define SIG_BLOCK 0
|
||||||
|
#define SIG_UNBLOCK 1
|
||||||
|
#define SIG_SETMASK 2
|
||||||
|
typedef unsigned long sigset_t;
|
||||||
|
|
||||||
typedef void (*sighandler_t)(int);
|
typedef void (*sighandler_t)(int);
|
||||||
extern sighandler_t signal(int signum, sighandler_t handler);
|
extern sighandler_t signal(int signum, sighandler_t handler);
|
||||||
|
extern int sigprocmask(int, const sigset_t *, sigset_t *);
|
||||||
extern int raise(int signum);
|
extern int raise(int signum);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,7 @@ extern int read(int fd, void* buffer, size_t count);
|
||||||
extern int write(int fd, void* buffer, size_t count);
|
extern int write(int fd, void* buffer, size_t count);
|
||||||
extern off_t lseek(int fildes, off_t offset, int whence);
|
extern off_t lseek(int fildes, off_t offset, int whence);
|
||||||
extern int fcntl(int fd, int op, ...);
|
extern int fcntl(int fd, int op, ...);
|
||||||
|
extern int unlink(const char* path);
|
||||||
|
|
||||||
/* Special variables */
|
/* Special variables */
|
||||||
|
|
||||||
|
@ -115,8 +116,34 @@ typedef int sig_atomic_t;
|
||||||
|
|
||||||
#define _NSIG 32 /* Biggest signal number + 1
|
#define _NSIG 32 /* Biggest signal number + 1
|
||||||
(not including real-time signals). */
|
(not including real-time signals). */
|
||||||
|
|
||||||
|
/* sigprocmask */
|
||||||
|
#define SIG_BLOCK 0
|
||||||
|
#define SIG_UNBLOCK 1
|
||||||
|
#define SIG_SETMASK 2
|
||||||
|
typedef unsigned long sigset_t;
|
||||||
|
|
||||||
|
/* sa_flags */
|
||||||
|
#define SA_NODEFER 0x40000000UL
|
||||||
|
#define SA_RESETHAND 0x80000000UL
|
||||||
|
|
||||||
|
struct __siginfo;
|
||||||
|
struct sigaction {
|
||||||
|
union {
|
||||||
|
void (*__sa_handler)(int);
|
||||||
|
void (*__sa_sigaction)(int, struct __siginfo *, void *);
|
||||||
|
} __sigaction_u;
|
||||||
|
sigset_t sa_mask;
|
||||||
|
unsigned long sa_flags;
|
||||||
|
void (*sa_restorer)(void);
|
||||||
|
};
|
||||||
|
#define sa_handler __sigaction_u.__sa_handler
|
||||||
|
#define sa_sigaction __sigaction_u.__sa_sigaction
|
||||||
|
|
||||||
typedef void (*sighandler_t)(int);
|
typedef void (*sighandler_t)(int);
|
||||||
|
extern int sigaction(int, const struct sigaction *, struct sigaction *);
|
||||||
extern sighandler_t signal(int signum, sighandler_t handler);
|
extern sighandler_t signal(int signum, sighandler_t handler);
|
||||||
|
extern int sigprocmask(int, const sigset_t *, sigset_t *);
|
||||||
extern int raise(int signum);
|
extern int raise(int signum);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,36 @@
|
||||||
acklibrary {
|
acklibrary {
|
||||||
name = "lib",
|
name = "lib",
|
||||||
srcs = {
|
srcs = {
|
||||||
"./*.s",
|
"./_syscall.s",
|
||||||
"plat/linux/libsys/*.c",
|
"./sigaction.s",
|
||||||
"plat/linux/libsys/*.s",
|
"./signal.c",
|
||||||
},
|
"./trap.s",
|
||||||
|
"plat/linux/libsys/_exit.c",
|
||||||
|
"plat/linux/libsys/_hol0.s",
|
||||||
|
"plat/linux/libsys/close.c",
|
||||||
|
"plat/linux/libsys/creat.c",
|
||||||
|
"plat/linux/libsys/errno.s",
|
||||||
|
"plat/linux/libsys/execve.c",
|
||||||
|
"plat/linux/libsys/getpid.c",
|
||||||
|
"plat/linux/libsys/gettimeofday.c",
|
||||||
|
"plat/linux/libsys/ioctl.c",
|
||||||
|
"plat/linux/libsys/isatty.c",
|
||||||
|
"plat/linux/libsys/kill.c",
|
||||||
|
"plat/linux/libsys/lseek.c",
|
||||||
|
"plat/linux/libsys/open.c",
|
||||||
|
"plat/linux/libsys/read.c",
|
||||||
|
"plat/linux/libsys/sbrk.c",
|
||||||
|
-- omit signal.c
|
||||||
|
"plat/linux/libsys/sigprocmask.c",
|
||||||
|
"plat/linux/libsys/unlink.c",
|
||||||
|
"plat/linux/libsys/write.c",
|
||||||
|
},
|
||||||
deps = {
|
deps = {
|
||||||
"lang/cem/libcc.ansi/headers+headers",
|
"lang/cem/libcc.ansi/headers+headers",
|
||||||
"plat/linuxppc/include+headers",
|
"plat/linuxppc/include+headers",
|
||||||
},
|
},
|
||||||
vars = {
|
vars = {
|
||||||
plat = "linuxppc"
|
plat = "linuxppc"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
156
plat/linuxppc/libsys/sigaction.s
Normal file
156
plat/linuxppc/libsys/sigaction.s
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
#define __NR_sigaction 67
|
||||||
|
#define SIG_BLOCK 0
|
||||||
|
#define SIG_SETMASK 2
|
||||||
|
#define MAXSIG 32
|
||||||
|
|
||||||
|
/* offsets into our stack frame */
|
||||||
|
#define mynew 16 /* new sigaction */
|
||||||
|
#define mynset 32 /* new signal set */
|
||||||
|
#define myoset 36 /* old signal set */
|
||||||
|
#define mysave 40
|
||||||
|
#define mysize 56
|
||||||
|
|
||||||
|
.sect .text; .sect .rodata; .sect .data; .sect .bss
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Linux calls signal handlers with arguments in registers, but the
|
||||||
|
* ACK expects arguments on the stack. This sigaction() uses a
|
||||||
|
* "bridge" to move the arguments.
|
||||||
|
*/
|
||||||
|
.sect .text
|
||||||
|
.define _sigaction
|
||||||
|
_sigaction:
|
||||||
|
mflr r0
|
||||||
|
subi r1, r1, mysize
|
||||||
|
stw r31, mysave+8(r1)
|
||||||
|
stw r30, mysave+4(r1)
|
||||||
|
stw r29, mysave(r1)
|
||||||
|
stw r0, mysave+12(r1)
|
||||||
|
li r3, 0
|
||||||
|
stw r3, mynset(r1) ! mynset = 0
|
||||||
|
lwz r29, mysize(r1) ! r29 = signal number
|
||||||
|
lwz r30, mysize+4(r1) ! r30 = new action
|
||||||
|
lwz r31, mysize+8(r1) ! r31 = old action
|
||||||
|
/*
|
||||||
|
* If the new action is non-NULL, the signal number is in
|
||||||
|
* range 1 to MAXSIG, and the new handler is not SIG_DFL 0
|
||||||
|
* or SIG_IGN 1, then we interpose our bridge.
|
||||||
|
*/
|
||||||
|
cmpwi cr0, r30, 0
|
||||||
|
subi r7, r29, 1 ! r7 = index in handlers
|
||||||
|
cmplwi cr7, r7, MAXSIG ! unsigned comparison
|
||||||
|
beq cr0, kernel
|
||||||
|
bge cr7, kernel
|
||||||
|
lwz r3, 0(r30) ! r3 = new handler
|
||||||
|
clrrwi. r3, r3, 1
|
||||||
|
beq cr0, kernel
|
||||||
|
/*
|
||||||
|
* Block the signal while we build the bridge. Prevents a
|
||||||
|
* race if a signal arrives after we change the bridge but
|
||||||
|
* before we change the action in the kernel.
|
||||||
|
*/
|
||||||
|
li r4, 1
|
||||||
|
slw r4, r4, r7
|
||||||
|
stw r4, mynset(r1) ! mynmask = 1 << (signal - 1)
|
||||||
|
li r3, SIG_BLOCK
|
||||||
|
la r4, mynset(r1)
|
||||||
|
la r5, myoset(r1)
|
||||||
|
stw r3, 0(r1)
|
||||||
|
stw r4, 4(r1)
|
||||||
|
stw r5, 8(r1)
|
||||||
|
bl _sigprocmask
|
||||||
|
/*
|
||||||
|
* Point our bridge to the new signal handler. Then copy the
|
||||||
|
* new sigaction but point it to our bridge.
|
||||||
|
*/
|
||||||
|
lis r6, hi16[handlers]
|
||||||
|
ori r6, r6, lo16[handlers]
|
||||||
|
subi r7, r29, 1
|
||||||
|
slwi r7, r7, 2
|
||||||
|
lwz r3, 0(r30) ! r3 = new handler
|
||||||
|
stwx r3, r6, r7 ! put it in array of handlers
|
||||||
|
lis r3, hi16[bridge]
|
||||||
|
ori r3, r3, lo16[bridge]
|
||||||
|
lwz r4, 4(r30)
|
||||||
|
lwz r5, 8(r30)
|
||||||
|
lwz r6, 12(r30)
|
||||||
|
stw r3, mynew(r1) ! sa_handler or sa_sigaction
|
||||||
|
stw r4, mynew+4(r1) ! sa_mask
|
||||||
|
stw r5, mynew+8(r1) ! sa_flags
|
||||||
|
stw r6, mynew+12(r1) ! sa_restorer
|
||||||
|
la r30, mynew(r1)
|
||||||
|
kernel:
|
||||||
|
li r3, __NR_sigaction
|
||||||
|
stw r3, 0(r1)
|
||||||
|
stw r29, 4(r1)
|
||||||
|
stw r30, 8(r1)
|
||||||
|
stw r31, 12(r1)
|
||||||
|
bl __syscall
|
||||||
|
/*
|
||||||
|
* If we blocked the signal, then restore the old signal mask.
|
||||||
|
*/
|
||||||
|
lwz r3, mynset(r1)
|
||||||
|
cmpwi cr0, r3, 0
|
||||||
|
beq cr0, fixold
|
||||||
|
li r3, SIG_SETMASK
|
||||||
|
la r4, myoset(r1)
|
||||||
|
li r5, 0
|
||||||
|
stw r3, 0(r1)
|
||||||
|
stw r4, 4(r1)
|
||||||
|
stw r5, 8(r1)
|
||||||
|
bl _sigprocmask
|
||||||
|
/*
|
||||||
|
* If the old sigaction is non-NULL and points to our bridge,
|
||||||
|
* then point it to the signal handler.
|
||||||
|
*/
|
||||||
|
fixold:
|
||||||
|
cmpwi cr0, r31, 0
|
||||||
|
beq cr0, leave
|
||||||
|
lis r3, hi16[bridge]
|
||||||
|
ori r3, r3, lo16[bridge]
|
||||||
|
lwz r4, 0(r31)
|
||||||
|
cmpw cr0, r3, r4
|
||||||
|
bne cr0, leave
|
||||||
|
lis r6, hi16[handlers]
|
||||||
|
ori r6, r6, lo16[handlers]
|
||||||
|
subi r7, r29, 1
|
||||||
|
slwi r7, r7, 2
|
||||||
|
lwzx r3, r6, r7 ! get it from array of handlers
|
||||||
|
stw r3, 0(r31) ! put it in old sigaction
|
||||||
|
leave:
|
||||||
|
lwz r0, mysave+12(r1)
|
||||||
|
lwz r29, mysave(r1)
|
||||||
|
lwz r30, mysave+4(r1)
|
||||||
|
lwz r31, mysave+8(r1)
|
||||||
|
addi r1, r1, mysize
|
||||||
|
mtlr r0
|
||||||
|
blr ! return from sigaction
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Linux calls bridge(signum) or bridge(signum, info, context) with
|
||||||
|
* arguments in registers r3, r4, r5.
|
||||||
|
*/
|
||||||
|
bridge:
|
||||||
|
mflr r0
|
||||||
|
subi r1, r1, 16
|
||||||
|
stw r0, 12(r1)
|
||||||
|
stw r3, 0(r1) ! signal number
|
||||||
|
stw r4, 4(r1) ! info
|
||||||
|
stw r5, 8(r1) ! context
|
||||||
|
|
||||||
|
lis r6, hi16[handlers]
|
||||||
|
ori r6, r6, lo16[handlers]
|
||||||
|
subi r7, r3, 1
|
||||||
|
slwi r7, r7, 2
|
||||||
|
lwzx r6, r6, r7
|
||||||
|
mtctr r6
|
||||||
|
bctrl ! call our signal handler
|
||||||
|
|
||||||
|
lwz r0, 12(r1)
|
||||||
|
addi r1, r1, 16
|
||||||
|
mtlr r0
|
||||||
|
blr ! return from bridge
|
||||||
|
|
||||||
|
.sect .bss
|
||||||
|
handlers:
|
||||||
|
.space 4 * MAXSIG ! array of signal handlers
|
19
plat/linuxppc/libsys/signal.c
Normal file
19
plat/linuxppc/libsys/signal.c
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Uses our bridge in sigaction.s when calling the signal handler.
|
||||||
|
* Mimics Linux __NR_signal by using SA_NODEFER | SA_RESETHAND.
|
||||||
|
*/
|
||||||
|
sighandler_t signal(int signum, sighandler_t handler) {
|
||||||
|
struct sigaction new, old;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
new.sa_handler = handler;
|
||||||
|
new.sa_mask = 0; /* empty set */
|
||||||
|
new.sa_flags = SA_NODEFER | SA_RESETHAND;
|
||||||
|
|
||||||
|
i = sigaction(signum, &new, &old);
|
||||||
|
if (i < 0)
|
||||||
|
return SIG_ERR;
|
||||||
|
return old.sa_handler;
|
||||||
|
}
|
Loading…
Reference in a new issue