【发布时间】:2021-05-20 19:26:25
【问题描述】:
在我的previous question 中,我在程序集中发布了这段代码(x86-64 att),它替换了无效操作码的处理程序(或者如果what_to_do 函数返回 0,则可以调用前一个):
.globl my_ili_handler
.text
.align 4, 0x90
my_ili_handler:
movq (%rsp), %r8 # loading %rip from stack
movb (%r8), %dil # reading first byte in the invalid opcode
cmpb $0x0F, %dil
jne function_call
movb 1(%r8), %dil # else read the 2nd byte instead
addq $1, %r8
function_call:
addq $1, %r8
pushq %rbp # save old %rbp
movq %rsp, %rbp # move %rbp to top
# %rax, %rdi, %rsi, %rdx, %rcx, %r8, %r9, %r10, %r11 caller saved.
subq $8, %rsp
pushq %r8 # backup %r8
call what_to_do # unsigned int what_to_do(unsigned char magic)
popq %r8 # restore %r8
leave # push return address and jump
cmpl $0, %eax
je old_handler
mov %eax, %edi # zero the upper part of %rdi
addq $8, %rsp # pop old %rip from stack
pushq %r8
jmp end
old_handler:
jmp *old_ili_handler(%rip)
end:
iretq # go back to user space
你们中的许多人指出我没有遵循有关保存 r8 和 rdx 的指南,但我就是不明白为什么会这样?
但是:
-
那些寄存器是调用者保存的,我在调用
funciton_call之前保存它们并再次加载它们,那有什么问题? -
我不需要在调用 jmp 之前保存它们,这不是函数调用...
另外我应该如何在不破坏我的整个代码的情况下解决这个问题?
第一次编辑:
.globl my_ili_handler
.text
.align 4, 0x90
my_ili_handler:
movq (%rsp), %r8 # loading %rip from stack
movb (%r8), %dil # reading first byte in the invalid opcode
cmpb $0x0F, %dil
jne function_call
movb 1(%r8), %dil # else read the 2nd byte instead
addq $1, %r8
function_call:
addq $1, %r8
pushq %rbp # save old %rbp
movq %rsp, %rbp # move %rbp to top
# %rax, %rdi, %rsi, %rdx, %rcx, %r8, %r9, %r10, %r11 caller saved.
subq $72, %rsp
# backup all caller-saved registers
pushq %rax
pushq %rdi
pushq %rsi
pushq %rdx
pushq %rcx
pushq %r8
pushq %r9
pushq %r10
pushq %r11
call what_to_do # unsigned int what_to_do(unsigned char magic)
# restore all caller-saved registers
popq %r11
popq %r10
popq %r9
popq %r8
popq %rcx
popq %rdx
popq %rsi
popq %rdi
popq %rax
leave # (mov %rbp, %rsp) & (pop %rbp)
cmpl $0, %eax
je old_handler
mov %eax, %edi # zero the upper part of %rdi
addq $8, %rsp # pop old %rip from stack
pushq %r8
jmp end
old_handler:
jmp *old_ili_handler(%rip)
end:
iretq # go back to user space
【问题讨论】:
-
如果标签在单词“function”中没有拼写错误,您的代码会更容易阅读,特别是因为您现在在另一条指令中引用了标签名称:/
-
你正在编写一个异常处理程序,而不是一个普通的函数!将控制权转移给您的代码不会主动调用您,也不会期望 any 寄存器被修改。因此,您必须保留 所有 寄存器、标志和其他相关 CPU 状态,包括那些将在正常函数调用中“保存调用方”的状态。正常的调用约定不适用,因为“调用者”不与它们合作。
-
但这并没有回答我什么时候应该备份它们以及什么时候恢复它们,另外我应该备份所有其他寄存器吗? (我知道 cmp 会影响一个寄存器,我也应该备份它吗?)
-
您的编辑使问题中的代码变得荒谬(因为没有设置 R8),并使我的答案无效,因为您根本不再调用 C 函数。回滚。我看不出这种变化如何被描述为“修复”代码,因为它仍然修改了 R8 而不保存它。如果您尝试编写答案,请将其作为答案发布,而不是对问题的编辑。
标签: assembly x86-64 cpu-registers interrupt-handling