Я пытаюсь сделать относительный переход в сборке x86, но я не могу заставить его работать. Кажется, что по какой-то причине мой прыжок продолжает переписываться как абсолютный прыжок или что-то в этом роде.
Простая примерная программа для того, что я пытаюсь сделать, это следующее:
.global main
main:
jmp 0x4
ret
Так как команда jmp имеет длину 4 байта, а относительный скачок смещен от адреса прыжка + 1, это должно быть причудливым no-op. Однако компиляция и запуск этого кода вызовет ошибку сегментации.
Реальным головоломщиком для меня является то, что компиляция его на уровне объекта, а затем дизассемблирование объектного файла показывает, что похоже, что ассемблер правильно выполняет относительный переход, но после того, как файл компилируется, компоновщик меняет его на другой тип прыжка.
Например, если приведенный выше код был в файле asmtest.s:
$gcc -c asmtest.s
$objdump -D asmtest.o
... Some info from objdump
00000000 <main>:
0: e9 00 00 00 00 jmp 5 <main+0x5>
5: c3 ret
Похоже, что ассемблер правильно сделал относительный прыжок, хотя подозрительно, что команда jmp заполнена 0.
Затем я использовал gcc, чтобы связать его, затем разобрал его и получил следующее:
$gcc -o asmtest asmtest.o
$objdump -d asmtest
...Extra info and other disassembled functions
08048394 <main>:
8048394: e9 6b 7c fb f7 jmp 4 <_init-0x8048274>
8048399: c3 ret
Мне кажется, что компоновщик переписал оператор jmp или заменил 5 на другой адрес.
Итак, мой вопрос сводится к тому, что я делаю неправильно?
Я неправильно указываю смещение? Я не понимаю, как работают относительные прыжки? Gcc пытается убедиться, что я не делаю опасных вещей в своем коде?