x86-64内核无效Opcode中断处理:跳转原处理器时保留GPR的问题
无效Opcode中断处理程序跳转问题解决
问题场景
课程要求实现自定义无效Opcode中断处理程序,当处理流程中调用的某函数返回0时,需将控制权交还给原处理程序,原处理程序地址已保存至全局变量void *old_ili_handler。
当前处理程序序言会压入所有通用寄存器以保护现场:
my_ili_handler: push %rax push %rbx ; ... 依次压入其余通用寄存器 ... push %r15
在尝试跳转原处理程序时,若先弹出所有寄存器恢复原始状态,再执行movq old_ili_handler(%rip), %r8 + jmp *%r8,会覆盖R8寄存器的原始值,破坏中断发生前的CPU状态,不符合要求。
问题根源
恢复通用寄存器后,再使用任意通用寄存器暂存原处理程序地址,必然会修改该寄存器的原始值,导致现场状态被破坏。
可行解决方案
最优方案:使用RIP相对间接跳转
64位模式下,直接通过RIP相对寻址完成间接跳转,无需借助任何通用寄存器,完全不会破坏已恢复的现场状态:
; 依次弹出所有通用寄存器恢复现场 pop %r15 pop %r14 ; ... 弹出其余通用寄存器 ... pop %rax ; 直接通过RIP相对寻址获取原处理程序地址并跳转,不修改任何寄存器 jmp *old_ili_handler(%rip)
备选方案:利用栈暂存地址(兼容特殊场景)
若因环境限制无法使用RIP相对寻址,可在恢复寄存器前将原处理程序地址压入栈,恢复完成后通过栈地址跳转:
; 先将原处理程序地址压入栈顶 movq old_ili_handler(%rip), %rax push %rax ; 依次弹出所有通用寄存器恢复现场 pop %r15 pop %r14 ; ... 弹出其余通用寄存器 ... pop %rbx pop %rax ; 跳转至栈顶存储的原处理程序地址 jmp *(%rsp) ; 跳转后原处理程序会自行处理栈帧,无需额外清理
内容的提问来源于stack exchange,提问作者FalleN
相关产品推荐
相关产品推荐

