我有以下代码试图在 xv6 中运行:
void handle_signal(siginfo_t info)
{
printf(1, "Caught signal %d...\n", info.signum);
if (info.signum == SIGFPE)
printf(1, "TEST PASSED\n");
else
printf(1, "TEST FAILED: wrong signal sent.\n");
return;
}
int main(int argc, char *argv[])
{
int x = 5;
int y = 0;
//int z = 0;
signal(SIGFPE, handle_signal);
x = x / y;
//x = x / z;
printf(1, "TEST FAILED: no signal sent.\n");
return 0;
}
信号处理程序被推入堆栈,如下所示:
void handle_signal(int signo, struct trapframe *tf){
*((uint*)(tf->esp-4)) = tf->eip;
*((uint*)(tf->esp-8)) = proc->tf->eax;
*((uint*)(tf->esp-12)) = proc->tf->ecx;
*((uint*)(tf->esp-16)) = proc->tf->edx;
*((uint*)(tf->esp-20)) = signo;
*((uint*)(tf->esp-24)) =(uint)proc->pop;
tf->esp = tf->esp-24;
tf->eip = (uint)(proc->sigHandlers[signo]);
}
所以我将堆栈底部设置为旧指令指针,在这种情况下应该是指令
x = x / y;
然后我推送易失性寄存器,推送信号处理程序参数,推送将弹出寄存器的函数,最后将 eip(指令指针)设置为等于信号处理程序的地址。
这是我的弹出功能:
void popregs(void){
__asm__ (
"add $8, %esp;"
"pop %edx;"
"pop %ecx;"
"pop %eax;"
"ret");
}
通常,这段代码应该运行并陷入 SIGFPE 调用的无限循环,因为每次处理程序运行时我都将指令指针设置回 x = x/y 调用。但是,由于某种原因,它会向前跳过并完成程序,然后以非常不准确的 EIP 值出现分段错误。
真正让我困惑的是,如果我在下面添加另一条指令 x = x/z,它会完美运行。当我尝试打印出程序的 EIP 时,它正确指向 x = x/y,因此它甚至没有执行 x/z 部分。
有人可以帮我理解这一点吗?我正在努力理解堆栈中可能发生的事情