xv6 中的堆栈帧操作仅适用于 printf()?
Stack frame manipulation in xv6 only works correctly with a printf()?
我正在尝试为我的操作系统 class 扩展 xv6 内核,但我 运行 遇到了一个奇怪的错误,它占用了我 5 个小时的时间,但无济于事.我实现了一个信号处理系统,将信号处理函数和参数手动插入到指令指针中,现在我试图通过将易失性寄存器值推入用户堆栈来保存易失性寄存器值,然后在信号处理程序之后将它们弹出到原始寄存器中returns.
下面是我设置栈帧的方法:
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 , %esp;"
"pop %edx;"
"pop %ecx;"
"pop %eax;"
"ret");
}
这是我用来弹出寄存器的函数。真正奇怪的是,如果我在内联汇编之前有 sleep(5) 或 printf() 语句,我的程序将做正确的事情(正确保存寄存器的值),但如果我删除它,我得到我假设的 "out of bounds code" 语句是分段错误的 xv6 等价物。即使它确实正确地保存了寄存器的值,我也可以看出堆栈正在变得混乱,因为处理程序在以后的信号处理调用中失败。
我很难处理这个问题,因为我真的不知道如何很好地调试程序集 - 有人知道会发生什么吗?
当进入一个过程时(如popregs
),编译器通常通过修改esp来建立一个stackframe。所以 add ,%esp
是否正确,取决于编译器是否从 esp 中减去 8。如果删除 sleep(5),编译器可能不会生成修改 esp 的代码,因为该过程是叶过程,因此您需要一个 add ,%esp
。
我正在尝试为我的操作系统 class 扩展 xv6 内核,但我 运行 遇到了一个奇怪的错误,它占用了我 5 个小时的时间,但无济于事.我实现了一个信号处理系统,将信号处理函数和参数手动插入到指令指针中,现在我试图通过将易失性寄存器值推入用户堆栈来保存易失性寄存器值,然后在信号处理程序之后将它们弹出到原始寄存器中returns.
下面是我设置栈帧的方法:
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 , %esp;"
"pop %edx;"
"pop %ecx;"
"pop %eax;"
"ret");
}
这是我用来弹出寄存器的函数。真正奇怪的是,如果我在内联汇编之前有 sleep(5) 或 printf() 语句,我的程序将做正确的事情(正确保存寄存器的值),但如果我删除它,我得到我假设的 "out of bounds code" 语句是分段错误的 xv6 等价物。即使它确实正确地保存了寄存器的值,我也可以看出堆栈正在变得混乱,因为处理程序在以后的信号处理调用中失败。
我很难处理这个问题,因为我真的不知道如何很好地调试程序集 - 有人知道会发生什么吗?
当进入一个过程时(如popregs
),编译器通常通过修改esp来建立一个stackframe。所以 add ,%esp
是否正确,取决于编译器是否从 esp 中减去 8。如果删除 sleep(5),编译器可能不会生成修改 esp 的代码,因为该过程是叶过程,因此您需要一个 add ,%esp
。