Я хочу перейти на адрес, сохраненный в% 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
, поэтому я не знаю, почему предыдущий не работает, а другой работает.
Почему происходит сбой самоизменяющейся версии кода и как ее исправить?