xv6中的堆栈帧操作只能与printf()一起正常工作?

时间:2016-03-10 19:24:44

标签: c assembly stackframe xv6

我试图为我的操作系统类扩展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");
}

这是我用来弹出寄存器的功能。真正奇怪的是,如果我在内联汇编之前有睡眠(5)或printf()语句,我的程序将做正确的事情(正确保存寄存器的值),但如果我删除它,我得到一个"越界代码"我假设的陈述是xv6等效的分段错误。即使它确实正确地保存了寄存器的值,我也可以告诉堆栈搞砸了,因为处理程序在以后的信号处理调用中失败了。

我努力解决这个问题,因为我真的不知道如何调试装配 - 有没有人知道可能会发生什么?

1 个答案:

答案 0 :(得分:4)

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