C语言 xv6 中的堆栈帧操作仅适用于 printf()



我正在尝试为我的操作系统类扩展 xv6 内核,但我遇到了一个奇怪的错误,它占用了我 5 个小时的时间无济于事。我实现了一个信号处理系统,该系统手动将信号处理函数和参数插入指令指针,现在我正在尝试通过将易失寄存器值推送到用户堆栈中来保存它们,然后在信号处理程序返回后将它们弹出到它们的原始寄存器中。

以下是我设置堆栈帧的方法:

  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]);
  }
因此,我将堆栈的底部设置为旧的指令指针,推送易失寄存器,推送信号处理程序

参数,推送将弹出寄存器的函数,然后最终将eip(指令指针)设置为等于信号处理程序的地址。

void
popregs(void){
    sleep(5);
    __asm__ (
    "add $16, %esp;"
    "pop %edx;"
    "pop %ecx;"
    "pop %eax;"
    "ret");
}

这是我用来弹出寄存器的函数。真正奇怪的是,如果我在内联程序集之前有 sleep(5) 或 printf() 语句,我的程序将做正确的事情(正确保存寄存器的值),但如果我删除它,我会得到一个"越界代码"语句,我假设它是 xv6 等效的分段错误。即使它确实正确保存了寄存器的值,我也可以说堆栈变得混乱,因为处理程序在以后的信号处理调用中失败。

我正在努力解决这个问题,因为我真的不知道如何很好地调试程序集 - 有人知道会发生什么吗?

当输入一个过程(如popregs)时,编译器通常通过修改esp来设置堆栈帧。因此,add $16,%esp是否正确,取决于事实,编译器是否从 esp 中减去 8。如果你删除 sleep(5), 编译器可能不会生成代码来修改 esp, 因为该过程是一个叶过程, 所以你需要一个add $8,%esp

最新更新