Почему вы не можете установить указатель инструкции напрямую?

В статье в Википедии о сборке x86 говорится, что "регистр IP не может быть доступен программисту напрямую".

Прямо означает с инструкциями, как MOV и добавить.

Почему бы и нет? В чем причина этого? Каковы технические ограничения?

4 ответа

Решение

Вы не можете получить к нему доступ напрямую, потому что нет законного варианта использования. Любое произвольное изменение инструкции 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 целочисленных регистров (включая ПК), поэтому для кодирования номера в машинном коде ARM требуется 4 бита. Другой регистр почти всегда связан как указатель стека, поэтому 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.

На самом деле ничего нельзя получить, разрешив использовать произвольные инструкции для чтения или записи на ПК, поскольку вы всегда можете сделать то же самое с целочисленным регистром и косвенным переходом. Было бы почти чистым недостатком R15 для x86-64 быть тем же, что и RIP, особенно для производительности архитектуры в качестве цели компилятора. (Рукописные asm странные вещи были уже очень редкой нишей к 2000 году, когда был разработан AMD64.)

Таким образом, AMD64 - это действительно первый случай, когда x86, возможно, получил полноценный счетчик программ, такой как ARM, но было много веских причин не делать этого.

Я думаю, что они имели в виду, что IP-регистр не может быть доступен напрямую так же, как другие регистры. Программисты могут точно писать в IP, например, с помощью инструкции перехода.

jmp установит EIP регистр.

этот код установит eip на 00401000:

mov eax, 00401000
jmp eax ;set Eip to 00401000

и для получения EIP

call GetEIP
.
.
GetEIP:
mov eax, [esp]
ret
Другие вопросы по тегам