为何isr_common_stub未调用isr_handler?x86_64 IDT实现是否正确?
问题分析:isr_common_stub未调用isr_handler的原因及调用方式正确性
调用方式的正确性
你的调用方式符合x86_64 System V ABI规范:
- 按照ABI要求,第一个参数通过
rdi寄存器传递,这里mov rdi, rsp将栈指针传给isr_handler,而栈上的布局正好对应registers_t结构体的定义,这种参数传递方式是正确的。 cld指令的使用也符合ABI要求(确保字符串操作指令的方向标志为0)。
可能导致未调用isr_handler的原因
1. save_registers实现与registers_t结构体不匹配
registers_t定义的寄存器顺序必须和save_registers压栈的顺序完全一致:
- 检查
save_registers是否按结构体顺序依次压入ds/es/fs/gs、通用寄存器(r15到rax)、int_no和err_code。如果顺序错位,栈布局会和结构体定义不符,导致isr_handler接收到的参数无效,甚至在调用时触发异常。 - 注意:部分中断会自动压入
err_code,如果你的中断服务程序(ISR)没有处理这一点,可能导致栈上多了或少了数据,破坏结构体布局。
2. 段寄存器加载错误
mov eax, 0x10加载内核数据段描述符后,如果0x10对应的GDT项无效(比如段限长错误、类型错误),后续访问内存(比如执行call isr_handler时取指令或访问栈)会触发段异常,导致流程跳转到异常处理函数,看起来像是isr_handler未被调用。
3. isr_handler函数签名错误
isr_handler的函数签名必须为:
void isr_handler(registers_t *regs);
如果写成void isr_handler(registers_t regs)(值传递),会导致函数尝试从栈上拷贝整个结构体,而栈布局不匹配,触发栈错误,函数无法正常执行。
4. IDT中断门配置错误
- 确保IDT中的中断门是64位中断门(属性字段需设置正确的位,比如类型为0xE),存在位(P位)置1。
- 中断门的代码段选择子必须是有效的内核代码段(通常是
0x08,对应GDT中内核代码段项),DPL设置为0(内核级),避免权限错误导致中断无法触发。
5. 栈指针或栈段错误
- 如果中断门配置了错误的栈段(比如指定用户栈而非内核栈),进入中断时栈切换失败,会导致后续指令执行异常,无法到达
call isr_handler。 - 检查
save_registers执行后,rsp是否指向有效的内核栈空间,栈溢出或栈地址无效都会导致调用失败。
6. 符号链接问题
- 在汇编代码中,需通过
extern isr_handler声明该C函数,确保链接器能正确解析符号。如果缺少声明,链接时可能出现未定义符号错误,或运行时无法找到函数地址,导致call指令执行失败。
7. add rsp, 16的合理性
检查add rsp, 16的作用:如果int_no和err_code是在save_registers之外压入栈的,那么这条指令是用来清理这两个值;但如果save_registers已经包含了这两个字段的压栈操作,这条指令会破坏栈平衡,导致restore_registers执行错误,甚至在call isr_handler前就出现栈问题。
内容的提问来源于stack exchange,提问作者baponkar
相关产品推荐
相关产品推荐

