在这篇“ 接口Linux信号”文章之后,我一直试图sys_rt_sigaction在 amd64中* 使用,但是在发送信号时总是会遇到 内存访问错误 。使用 C / C ++ 函数时, struct sigaction 有效。 *sigaction
sys_rt_sigaction
sigaction
sys_rt_sigaction通话有什么问题?
#include<signal.h> #include<stdio.h> #include<time.h> void handler(int){printf("handler\n");} void restorer(){asm volatile("mov $15,%%rax\nsyscall":::"rax");} struct sigaction act{handler}; timespec ts{10,0}; int main(){ act.sa_flags=0x04000000; act.sa_restorer=&restorer; //* asm volatile("\ mov $13,%%rax\n\ mov %0,%%rdi\n\ mov %1,%%rsi\n\ mov %2,%%rdx\n\ mov $8,%%r10\n\ syscall\n\ mov %%rax,%%rdi\n\ mov $60,%%rax\n\ #syscall\n\ "::"i"(7),"p"(&act),"p"(0):"rax","rdi","rsi","rdx","r10"); /**/ /* sigaction(7,&act,0); /**/ nanosleep(&ts,0); }
g++ -o bin -std=c++11 g++ -o bin -std=c++11 -no-pie
kill -7 `pidof bin`
在x86-64 linux中,必须提供a,sa_restorer而您尚未提供。
sa_restorer
内核源码的相关部分:
/* 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; }
在C库包装为您完成此:
kact.sa_flags = act->sa_flags | SA_RESTORER; kact.sa_restorer = &restore_rt;
使用更新的代码,您确实确实有一个还原器,但是您有两个问题:它已损坏并且您将其错误传递。查看上面提到的C库源代码,您可以找到以下注释:
/* 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. */
另外,由于函数序言,您不能将C ++函数用作恢复器。此外,printf不支持从信号处理程序进行调用(但可以在此处使用)。最后,正如大卫·沃尔弗德(David Wohlferd)所指出的那样,您的clo语是错误的。总而言之,以下内容可能是重新设计的版本:
printf
#include<stdio.h> #include<unistd.h> #include<time.h> void handler(int){ const char msg[] = "handler\n"; write(0, msg, sizeof(msg)); } extern "C" void restorer(); asm volatile("restorer:mov $15,%rax\nsyscall"); 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\n\ mov %0,%%rdi\n\ mov %1,%%rsi\n\ mov %2,%%rdx\n\ mov $8,%%r10\n\ syscall\n\ "::"i"(7),"p"(&act),"p"(0):"rax","rcx", "rdi","rsi","rdx","r8", "r9", "r10", "r11"); nanosleep(&ts,0); }
它仍然很hacky,显然,您不应该这样做。