Ответ 1
Нижняя строка: некоторые технические ограничения, которые amd64
использует при использовании больших адресов, предлагают выделить нижнее 2GiB
адресного пространства для кода и данных для повышения эффективности. Таким образом, стек был удален из этого диапазона.
В i386
ABI 1
- Стек
- находится перед кодом, растущим от чуть меньше
0x8048000
вниз. Что обеспечивает "чуть более 128 МБ для стека и около 2 ГБ для текста и данных "(стр. 3-22). - Динамические сегменты начинаются с
0x80000000
(2GiB), - а ядро занимает "зарезервированную область" наверху, которую спецификация допускает до
1GiB
, начиная не менее0xC0000000
(стр. 3-21) (что обычно делает). - Основной программе не требуется независимость от положения.
- Реализация не требуется для поиска нулевого указателя (стр. 3-21), но разумно ожидать, что для этого будет зарезервировано некоторое пространство стека выше
128MiB
(которое равно288KiB
).
amd64
(чей ABI сформулирован как поправка к i386
one (стр. 9)) имеет значительно большую (48-битное) адресное пространство, но большинство инструкций принимают только 32-битные непосредственные операнды (которые включают прямые адреса и смещения в инструкциях перехода), требующие большей работы и менее эффективного кода (особенно при учете взаимозависимости инструкций) для обработки больших значений. Меры по устранению этих ограничений обобщены авторами, введя несколько "кодовых моделей", которые они рекомендуют использовать, чтобы "позволить компилятору генерировать лучший код". (стр. 33)
- В частности, первая из них "Малая модель кода" предлагает использовать адреса "в диапазоне от 0 до 2 31 -2 24 -1 или от
0x00000000
до0x7effffff
", что позволяет использовать очень эффективные относительные ссылки и итерацию массива. Это1.98GiB
, что более чем достаточно для многих программ. - "Модель среднего кода" основана на предыдущем, разбивая данные на "быструю" часть под указанной границей и "более медленную" оставшуюся часть, для которой требуется специальная инструкция для доступа. Пока код остается под границей.
- И только "большая" модель не делает предположений о размерах, требуя от компилятора "использовать инструкцию
movabs
, как в среде модель кода, даже для работы с адресами внутри текстового раздела. Кроме того, непрямые ветки необходимы при ветвлении на адреса, чьи смещение от текущего указателя инструкции неизвестно ". Они продолжают предлагать разбиение базы кода на несколько разделяемых библиотек, поскольку эти меры не применяются для относительных ссылок с смещениями, которые, как известно, находятся в пределах границ (как указано в" Малозависимый код модель ").
Таким образом, стек перемещался в разделенное пространство библиотеки (0x80000000000
, 128GiB
), потому что его адреса никогда не являются непосредственными операндами, всегда ссылаются либо косвенно, либо с помощью lea
/mov
из другой ссылки, применяются относительные ограничения смещения.
Вышеприведенное объясняет, почему адрес загрузки был перенесен на более низкий адрес. Теперь, почему это было перенесено на 0x400000
(4MiB
)? Здесь я пришел пустым, поэтому, обобщая то, что я прочитал в спецификациях ABI, могу только догадываться, что он чувствовал себя "как раз":
- Он достаточно велик, чтобы уловить любое вероятное неправильное смещение структуры, что позволяет использовать более крупные единицы данных, которые
amd64
работает, но достаточно мала, чтобы не тратить значительную часть начального2GiB
адресного пространства. - Он равен наибольшему размеру практической страницы на сегодняшний день и является кратным всем другим размерам виртуальной памяти, о которых можно подумать.
1 Обратите внимание, что фактические x32 Linuxes отклоняются от этого макета больше и больше со временем. Но мы говорим о спецификации ABI здесь, поскольку форма amd64
формально основана на ней, а не на любом производном макете (см. Его параграф для цитирования).