【发布时间】:2021-11-13 04:29:09
【问题描述】:
我正在尝试使用SA_SIGINFO sigaction 的第三个参数直接跳转到中断的上下文。
这样想:
void action(int Sig, siginfo_t *Info, void *Uctx) {
ucontext_t *uc = Uctx; setcontext(uc);
}
和刚才的效果一样:
void action(int Sig, siginfo_t *Info, void *Uctx) {
return;
}
但奇怪的是它接受三个信号(调用 setcontext-calling 处理程序),然后它会出现段错误
在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
strace 显示的故障地址为 0(可捕获的 SIGSEGV)。
这是一个使用计时器发送三个信号的示例程序:
#include <unistd.h>
#include <sys/time.h>
#include <ucontext.h>
#include <signal.h>
void action(int Sig, siginfo_t *Info, void *Uctx) {
ucontext_t *uc = Uctx; setcontext(uc);
}
int main(void) {
char ch[100];
sigaction(SIGALRM, &(struct sigaction){.sa_sigaction = action, .sa_flags = SA_SIGINFO}, 0);
setitimer(ITIMER_REAL, &(struct itimerval){.it_interval.tv_sec = 1,.it_value.tv_sec = 1}, 0);
write(1, "enter\n", 6);
for (;;) {
write(1, "{\n", 2);
read(0, &ch[0], sizeof(ch));
write(1, "}\n", 2);
}
}
在这种情况下发生了什么?
【问题讨论】:
-
FWIW,我从像这样的信号处理程序返回的唯一成功是
sigsetjmp()和siglongjmp()这可能是相关的:stackoverflow.com/questions/20755260/… -
有趣。我可以在 Linux amd64 上重现这一点,但不能使用 -m32 或 arm64。段错误在
setcontext中,当它尝试ldmxcsr时使用可能无效的值。 -
如果我在循环中将循环体替换为
stmxcsr,则该值与处理程序在uc->__fpregs_mem.mxcsr中看到的不匹配,并在恢复上下文时更改。*uc结构中的mxcsr值似乎不正确,有时无效(设置了一些 16-31 位)。目前不确定它是否应该是正确的。 -
有点奇怪的是
uc->uc_mcontext.fpregs似乎指向正确填充的_libc_fpstate,包括mxcsr的正确值。但是setcontext不是从那里加载mxcsr,而是从uc->__fpregs_mem.mxcsr加载。.fpregs指向 within.__fpregs_mem,24 个字节。这看起来很奇怪。这不是getcontext的设置方式,我不认为。 -
是的,看起来 libc 认为 fpregs 包含在
struct ucontext_t本身中,而内核将它们作为单独的结构放在堆栈上,并在uc->uc_mcontext.fpregs中带有指向它的指针。目前还不清楚这种不匹配是否是一个错误,或者它们是否永远不会相同。
标签: c linux assembly signals x86-64