Статья в Википедии о сборке x86 гласит, что "к IP-адресу нельзя напрямую обращаться программистом".
Прямо означает с помощью команд, таких как mov и add.
Почему бы и нет? В чем причина этого? Каковы технические ограничения?
Статья в Википедии о сборке x86 гласит, что "к IP-адресу нельзя напрямую обращаться программистом".
Прямо означает с помощью команд, таких как mov и add.
Почему бы и нет? В чем причина этого? Каковы технические ограничения?
Вы не можете получить к нему доступ напрямую, потому что нет законного варианта использования. Любое произвольное изменение команды eip
очень затруднит предсказание ветвления и, вероятно, откроет целый ряд проблем безопасности.
Вы можете редактировать eip
с помощью jmp
, call
или ret
. Вы просто не можете напрямую читать или писать на eip
с помощью обычных операций
Установка eip
в регистр так же просто, как jmp eax
. Вы также можете сделать push eax; ret
, который подталкивает значение eax
в стек, а затем возвращает (т.е. Всплывает и переходит). Третий вариант - call eax
, который выполняет вызов адреса в eax.
Чтение может быть выполнено следующим образом:
call get_eip
get_eip:
pop eax ; eax now contains the address of this instruction
Это был бы возможный дизайн для x86. ARM делает выставлять свой счетчик программ для чтения/записи как R15. Однако это необычно.
Он позволяет очень компактную функцию пролог/эпилог, наряду с возможностью нажатия или всплытия нескольких регистров с помощью одной команды: push {r5, lr}
при записи и pop {r5, pc}
для возврата. (Отображение сохраненного значения регистра ссылок в счетчик программ).
Тем не менее, он делает реализацию ARM с высоким приоритетом/невыполнением заказов менее удобным и был сброшен для AArch64.
Так что возможно, но использует один из регистров. 32-разрядная ARM имеет 16 целых регистров (включая ПК), поэтому номер регистра занимает 4 бита для кодирования в машинном коде ARM. Другой регистр почти всегда связан как указатель стека, поэтому ARM имеет 14 универсальных регистров общего назначения. (LR может быть сохранен в стеке, поэтому он может быть и используется как регистр общего назначения внутри тел функции).
Большинство современных x86 унаследовано от 8086. Оно было спроектировано с довольно компактной кодировкой команд переменной длины и всего 8 регистров, для которых требуется всего 3 бита для каждого регистра src и dst в машинный код.
В исходном 8086 они не были очень универсальными, а относительная адресация по SP не возможна в 16-битном режиме, поэтому по существу 2 регистра (SP и BP) привязаны к файлу стека. Это оставляет только 6 регистров общего назначения, и одним из них является ПК вместо общего назначения, это будет огромным сокращением доступных регистров, что значительно увеличит количество разливов/перезагрузки в типичном коде.
AMD64 добавлен r8-r15 и режим относительной адресации RIP. lea rsi, [rip+whatever]
и RIP-относительные режимы адресации для прямого доступа к статическим данным и константам - все, что вам нужно для эффективного независимого от позиции кода. Непрямые инструкции JMP вполне достаточны для записи в RIP.
На самом деле ничего не может быть сделано, если разрешить использование произвольных инструкций для чтения или записи ПК, так как вы всегда можете сделать то же самое с регистром целого числа и косвенным прыжком. Было бы почти чистым недостатком для x86-64 R15, чтобы быть тем же самым, что и RIP, особенно для архитектуры performace в качестве цели компилятора. (Рукописный материал ASM был уже очень необычной нишей к 2000 году, когда был разработан AMD64.)
Итак, AMD64 - это первый случай, когда x86 мог бы получить полностью открытый программный счетчик, такой как ARM, но было много серьезных причин не делать этого.
jmp
установит регистр EIP
.
этот код установит eip на 00401000:
mov eax, 00401000
jmp eax ;set Eip to 00401000
и для получения EIP
call GetEIP
.
.
GetEIP:
mov eax, [esp]
ret
Я думаю, что они имели в виду, что доступ к IP-адресу невозможен напрямую так же, как к другим регистрам. Программисты могут определенно писать на IP, например, выдавая инструкцию перехода.