In x86-64 linux, it's mandatory to supply a sa_restorer
and you haven't done so.
The relevant part of kernel source:
/* x86-64 should always use SA_RESTORER. */
if (ksig->ka.sa.sa_flags & SA_RESTORER) {
put_user_ex(ksig->ka.sa.sa_restorer, &frame->pretcode);
} else {
/* could use a vstub here */
err |= -EFAULT;
}
The C library wrapper does this for you:
kact.sa_flags = act->sa_flags | SA_RESTORER;
kact.sa_restorer = &restore_rt;
With the updated code you do indeed have a restorer, but you have two problems: it's broken and you pass it wrong. Looking at the above mentioned C library source you can find this comment:
/* The difference here is that the sigaction structure used in the
kernel is not the same as we use in the libc. Therefore we must
translate it here. */
Also, you can't have a C++ function as restorer due to the function prologue. Furthermore, calling printf
from a signal handler is not supported (but works here). Finally, as David Wohlferd pointed out, your clobbers are wrong. All in all, the following could be a reworked version:
#include<stdio.h>
#include<unistd.h>
#include<time.h>
void handler(int){
const char msg[] = "handler
";
write(0, msg, sizeof(msg));
}
extern "C" void restorer();
asm volatile("restorer:mov $15,%rax
syscall");
struct kernel_sigaction {
void (*k_sa_handler) (int);
unsigned long sa_flags;
void (*sa_restorer) (void);
unsigned long sa_mask;
};
struct kernel_sigaction act{handler};
timespec ts{10,0};
int main(){
act.sa_flags=0x04000000;
act.sa_restorer=&restorer;
asm volatile("
mov $13,%%rax
mov %0,%%rdi
mov %1,%%rsi
mov %2,%%rdx
mov $8,%%r10
syscall
"::"i"(7),"p"(&act),"p"(0):"rax","rcx", "rdi","rsi","rdx","r8", "r9", "r10", "r11");
nanosleep(&ts,0);
}
It's still hacky, and you shouldn't really be doing it this way, obviously.