我想跳转到存储在%rax中的地址,地址只能在运行时知道。这就是我尝试用自修改代码做的事情:
mov $0x0, %rax
jmp *%rax
操作数$ 0x0将在运行时更改为地址。但是运行代码我得到分段错误。我正在使用MacOS和gcc。以下是代码的完整版本:
.data
fmt_int:
.ascii "%ld\n\0"
fmt_hex:
.ascii "%#08x\n\0"
.global _main
.text
_main:
push %rbp
mov %rsp, %rbp
# allow us to write to section .text
lea _main(%rip), %rdi
mov %rdi, %rbx
call _getpagesize
mov %rax, %rsi
xor %rdx, %rdx
mov %rbx, %rax
div %rsi
sub %rdx, %rbx
lea _main(%rip), %rcx
lea _end(%rip), %rsi
sub %rcx, %rsi
add %rdx, %rsi
inc %rsi
mov %rbx, %rdi
mov $7, %rdx
call _mprotect
# change the mov statement at l0
lea l0(%rip), %rdi
lea l2(%rip), %rax
movl %eax, 3(%rdi)
mov $2, %rsi
l0:
mov $0x0, %rax
jmp *%rax
l1:
mov $0, %rsi
l2:
lea fmt_int(%rip), %rdi
call _printf
pop %rbp
ret
_end:
因此,# change the mov statement at l0
行下的代码会将mov $0x0, %rax
指令的操作数修改为mov $addr_l2, %rax
,其中addr_l2
是l2
的地址。因此,当它被执行时,它应该跳转到l2
。但是,代码在跳转时会出现分段错误。
我尝试了另一个不涉及自修改代码的代码:
.data
fmt_int:
.ascii "%ld\n\0"
fmt_hex:
.ascii "%#08x\n\0"
.global _main
.text
_main:
push %rbp
mov %rsp, %rbp
mov $2, %rsi
l0:
lea l2(%rip), %rax
jmp *%rax
l1:
mov $0, %rsi
l2:
lea fmt_int(%rip), %rdi
call _printf
pop %rbp
ret
_end:
此代码工作正常。但在这两种情况下,jmp
也会跳转到l2
的地址,所以我不知道为什么前一个不起作用而另一个起作用。
为什么自修改代码版本会失败,我该如何解决?