Ответ 1
Это работает почти так же, как обращение к локальным переменным в стеке с помощью offset(%ebp)
. В этом случае компоновщик установит поле смещения этой команды на разницу между адресом var
и значением, которое %rip
будет иметь при выполнении этой команды. (Если я правильно помню, это значение является адресом следующей команды, потому что %rip
всегда указывает на команду после исполняемого в настоящее время.) Таким образом, добавление дает адрес var
.
Почему так? Это признак независимого от позиции кода. Если компилятор сгенерировал
cmpl $69, _var
и компоновщик заполнил абсолютный адрес var
, тогда при запуске программы исполняемый образ всегда должен быть загружен в память по одному конкретному адресу, так что все переменные имели абсолютные адреса, код ожидает. Делая это таким образом, единственное, что должно быть исправлено, это расстояние между кодом и данными; код плюс данные (т.е. полное исполняемое изображение) могут быть загружены по любому адресу, и он все равно будет работать.
... Зачем беспокоиться? Почему плохо загружать исполняемый файл по одному конкретному адресу? Это не обязательно. Общие библиотеки должны быть независимы от позиции, потому что в противном случае у вас могут быть две библиотеки, которые хотят быть загружены на перекрывающиеся адреса, и вы не можете использовать их оба в одной программе. (Некоторые системы справились с этим, сохранив глобальный реестр всех библиотек и требуемое пространство, но, очевидно, это не масштабируется.) Создание исполняемых файлов, не зависящих от положения, в основном делается в качестве меры безопасности: несколько сложнее использовать переполнение буфера если вы не знаете, где находится программный код в памяти (это называется рандомизация размещения адресного пространства).