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