PSk*_*cik 7 c linux assembly signals x86-64
我试图使用 a 的第三个参数SA_SIGINFO sigaction直接跳转到中断的上下文。
想到了这个:
void action(int Sig, siginfo_t *Info, void *Uctx) {
ucontext_t *uc = Uctx; setcontext(uc);
}
Run Code Online (Sandbox Code Playgroud)
将具有与以下相同的效果:
void action(int Sig, siginfo_t *Info, void *Uctx) {
return;
}
Run Code Online (Sandbox Code Playgroud)
但奇怪的是它接受三个信号(调用 setcontext 调用处理程序),然后出现段错误setcontext:
Dump of assembler code for function setcontext:
0x00007ffff7a34180 <+0>: push %rdi
0x00007ffff7a34181 <+1>: lea 0x128(%rdi),%rsi
0x00007ffff7a34188 <+8>: xor %edx,%edx
0x00007ffff7a3418a <+10>: mov $0x2,%edi
0x00007ffff7a3418f <+15>: mov $0x8,%r10d
0x00007ffff7a34195 <+21>: mov $0xe,%eax
0x00007ffff7a3419a <+26>: syscall
0x00007ffff7a3419c <+28>: pop %rdi
0x00007ffff7a3419d <+29>: cmp $0xfffffffffffff001,%rax
0x00007ffff7a341a3 <+35>: jae 0x7ffff7a34200 <setcontext+128>
0x00007ffff7a341a5 <+37>: mov 0xe0(%rdi),%rcx
--Type <RET> for more, q to quit, c to continue without paging--
0x00007ffff7a341ac <+44>: fldenv (%rcx)
=> 0x00007ffff7a341ae <+46>: ldmxcsr 0x1c0(%rdi)
0x00007ffff7a341b5 <+53>: mov 0xa0(%rdi),%rsp
0x00007ffff7a341bc <+60>: mov 0x80(%rdi),%rbx
Run Code Online (Sandbox Code Playgroud)
strace 显示的故障地址为 0(可捕获的 SIGSEGV)。
这是一个使用计时器发送三个信号的示例程序:
Dump of assembler code for function setcontext:
0x00007ffff7a34180 <+0>: push %rdi
0x00007ffff7a34181 <+1>: lea 0x128(%rdi),%rsi
0x00007ffff7a34188 <+8>: xor %edx,%edx
0x00007ffff7a3418a <+10>: mov $0x2,%edi
0x00007ffff7a3418f <+15>: mov $0x8,%r10d
0x00007ffff7a34195 <+21>: mov $0xe,%eax
0x00007ffff7a3419a <+26>: syscall
0x00007ffff7a3419c <+28>: pop %rdi
0x00007ffff7a3419d <+29>: cmp $0xfffffffffffff001,%rax
0x00007ffff7a341a3 <+35>: jae 0x7ffff7a34200 <setcontext+128>
0x00007ffff7a341a5 <+37>: mov 0xe0(%rdi),%rcx
--Type <RET> for more, q to quit, c to continue without paging--
0x00007ffff7a341ac <+44>: fldenv (%rcx)
=> 0x00007ffff7a341ae <+46>: ldmxcsr 0x1c0(%rdi)
0x00007ffff7a341b5 <+53>: mov 0xa0(%rdi),%rsp
0x00007ffff7a341bc <+60>: mov 0x80(%rdi),%rbx
Run Code Online (Sandbox Code Playgroud)
这种情况是怎么回事?
我认为这根本不起作用:您只能使用从orsetcontext获取的上下文进行调用,而不是将上下文传递给信号处理程序。getcontextmakecontext
手册页间接地暗示了这一点:
如果上下文是通过调用信号处理程序获得的,那么旧的标准文本会说“程序继续执行被信号中断的指令之后的程序指令”。不过这句话在SUSv2中被删除了,目前的判决是“结果未明”。
另外,glibc源码setcontext有一条评论:
此实现仅用于同步上下文切换。因此,它不必恢复 PRESERVED 状态以外的任何内容。
事实上,它不会尝试恢复任何浮点寄存器,并且它会归零rax(就像getcontext返回 0 一样)。对于尝试恢复不希望其寄存器自发更改的代码来说,这将是非常糟糕的。
用户空间中的抢占式多任务处理等功能需要异步上下文切换。我认为这个想法是,既然pthreads现在已经牢固地建立起来,人们应该不需要它,所以它不被支持。 getcontext/setcontext是从更早的时代开始的,事实上已经从 POSIX 规范中删除了,前提是应该使用 pthreads。
这种特殊的崩溃似乎是由于 的内核布局struct ucontext_t与 libc 的预期不匹配造成的。特别是,libc 期望浮点状态,包括 的保存值mxcsr,位于 内的特定偏移量处struct ucontext_t。然而,内核将浮点状态推送到堆栈上的单独位置(恰好与 libc 期望的位置重叠),并在struct ucontext_t. 因此 libcsetcontext尝试将一些垃圾值加载到 中mxcsr,其中设置了一些保留位 16-31,这会导致一般保护错误。
然而,如上所述,这种不匹配是最不重要的问题。