Адресация указателя инструкции сборки X86 - PullRequest
10 голосов
/ 27 июня 2011

Обычно я не трачу много времени на чтение ассемблера, поэтому следующий вывод компилятора меня немного смутил.

Допустим, я скомпилировал этот фрагмент кода C на моем Intel Core 2 Duo под управлением OSX 10.6:

while (var != 69) // var is a global variable
{
    printf("Looping!\n");
}

Сборка для сравнения "var! = 69" выглядит так:

cmpl    $69, _var(%rip)

Я понимаю, что это фактически означает сравнение значения "69" с содержимым глобальной переменной "var", но мне трудно разобраться в части "_var (% rip)". Обычно я ожидаю, что будет значение смещения, например, для ссылки на локальные переменные в стеке (например, -4 ($ ebp)). Однако я не совсем понимаю, как смещение указателя инструкций с помощью объявления «_var» даст мне содержимое глобальной переменной «var».

Что именно означает эта строка?

Спасибо.

1 Ответ

14 голосов
/ 27 июня 2011

Это работает почти так же, как адресация локальных переменных в стеке с offset(%ebp). В этом случае компоновщик установит в поле смещения этой инструкции значение разница между адресом var и значением, которое будет иметь %rip при выполнении этой инструкции. (Если я правильно помню, это значение является адресом инструкции next , потому что %rip всегда указывает на инструкцию после той, которая выполняется в настоящее время.) Таким образом, сложение дает адрес var.

Почему это так? Это отличительная черта позиционно-независимый код . Если компилятор сгенерировал

cmpl $69, _var

и компоновщик заполнил абсолютный адрес var, затем, когда вы запустили программу, исполняемый образ всегда должен быть загружен в память по одному конкретному адресу, чтобы все переменные имели абсолютные адреса, которые ожидает код. Делая это таким образом, единственное, что нужно исправить, это расстояние между кодом и данными; код плюс данные (то есть полный исполняемый образ) можно загрузить по любому адресу, и он все равно будет работать.

... Зачем беспокоиться? Почему плохо загружать исполняемый файл по одному конкретному адресу? Это не обязательно. Совместно используемые библиотеки должны быть независимыми от позиции, так как в противном случае у вас могут быть две библиотеки, которые нужно загружать по перекрывающимся адресам, и вы не сможете использовать обе из них в одной и той же программе. (Некоторые системы решают эту проблему, поддерживая глобальный реестр всех библиотек и места, которое им требуется, но, очевидно, это не масштабируется.) Создание исполняемых файлов независимым от позиции в значительной степени выполняется в качестве меры безопасности: это несколько Труднее использовать переполнение буфера, если вы не знаете, где находится код программы в памяти (это называется рандомизация размещения адресного пространства ).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...