2016-09-25 1 views
27

В this документ на с. 27 говорится, что текстовый сегмент начинается с 0x400000. Почему именно этот адрес был выбран? Есть ли причина ? Тот же адрес выбирается в GNU ld на Linux:Почему адрес 0x400000 выбран как начало текстового сегмента в x86_64 ABI?

$ ld -verbose | grep -i text-segment 
    PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS; 

Это удивительно, потому что этот адрес находится в 32-разрядных x86 исполняемых файлов больше:

$ ld -verbose | grep -i text-segment 
    PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x08048000)); . = SEGMENT_START("text-segment", 0x08048000) + SIZEOF_HEADERS; 

Я прочитал this question, который обсуждает, почему был выбран 0x080xxxxx адрес для i386, но это не объясняет изменения в x86_64. Трудно найти любое объяснение в этом отношении. Кто-нибудь знает?

+0

https://www.uclibc.org/docs/psABI-x86_64.pdf - это последняя версия (0.99.7), [согласно WDD OSDev] (http://wiki.osdev.org/System_V_ABI# Документы). –

+0

0x400000 - это 4MiB, поэтому это может иметь какое-то отношение к огромной поддержке страниц. В разделе 3.3.3 разрешен только размер страницы до 64 килобайт. –

+0

@ivan_pozdeev: https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI имеет ссылки на PDF-файлы, созданные из версии Git HEAD источника LaTeX. Таблицы страниц x86-64 могут использовать огромные страницы размером 2 МБ (и даже 1GiB), а Linux делает это прозрачно/оппортунистически для анонимной памяти, но не для файлового резервного копирования. Я предполагаю, что 4MB достаточно далеко от 0, что индексированный NULL-указатель deref обычно не будет индексироваться на допустимые страницы. Хе-хе, я вижу, ты сказал то же самое в своем ответе. –

ответ

28

Итог: некоторые технические ограничения, которые amd64 имеет при использовании больших адресов, предлагают выделить нижнее 2GiB адресного пространства для кода и данных для повышения эффективности. Таким образом, стек был перемещен из этого диапазона.


В i386 ABI

  • стека находится перед кодом, растет с чуть менее 0x8048000 вниз. Что обеспечивает «чуть более 128 МБ для стека и около 2 ГБ для текста и данных» (стр. 3-22).
  • Динамические сегменты начинаются в 0x80000000 (2GiB),
  • и ядро ​​занимает «зарезервированной области» на вершине которой спецификация позволяет достигать 1GiB, начиная по меньшей мере 0xC0000000 (стр. 3-21) (which is what it typically does).
  • Основная программа не обязательно должна быть независимой от положения.
  • Реализация не требуется для доступа к нулевому указателю (стр. 3-21), но разумно ожидать, что для этого будет зарезервировано некоторое пространство стека выше 128MiB (которое равно 288KiB).

amd64 (whose ABI формулируется в виде поправки к i386 один (стр. 9)) имеет значительно больший (48-бит) адресное пространство, но большинство команд принимают только 32-разрядные непосредственные операнды (которые включают в себя прямые адреса и смещения в инструкциях перехода), требуя большей работы и менее эффективного кода (особенно при учете взаимозависимости инструкций) для обработки больших значений. Меры по устранению этих ограничений обобщены авторами, введя несколько «кодовых моделей», которые они рекомендуют использовать для «разрешить компилятору генерировать лучший код». (стр. 33)

  • В частности, первый из них, "Малый кода модель", предлагает использовать адрес «в диапазоне от 0 до 2 -2 -1 или от 0x00000000 до 0x7effffff ", который позволяет использовать очень эффективные относительные ссылки и итерацию массива.Это 1.98GiB, что более чем достаточно для многих программ.
  • «Средняя модель кода» основана на предыдущем, разделяет данные в «быструю» часть под указанной границей и «более медленную» оставшуюся часть, для которой требуется специальная инструкция для доступа. Пока код остается под границей.
  • И только «большая» модель не делает предположений о размерах, требуя компилятора «использовать инструкцию movabs, как в модели кода , даже для обработки адресов внутри текстового раздела. необходим при ветвлении на адреса, чья смещение от текущего указателя инструкции неизвестно. " Они продолжают предлагать разбиение базы кода на несколько разделяемых библиотек, поскольку эти меры не применяются для относительных ссылок с смещениями, которые, как известно, находятся в пределах границ (как указано в «Модели с независимым кодом с малой позицией»).

Таким образом, стек был перенесен под общей библиотекой пространства (0x80000000000, 128GiB), потому что его адрес никогда не Непосредственные операндов, всегда ссылаются либо косвенно или с lea/mov из другой ссылки, таким образом, только относительное смещение ограничения.


Приведенное выше объясняет, почему адрес загрузки был перенесен на нижний адрес. Теперь, почему он был перенесен точно в 0x400000 (4MiB)? Вот, я пришел пустой так, подводя итоги того, что я прочитал в спецификации ABI, я могу только догадываться, что он чувствовал себя «впору»:

  • Это достаточно большой, чтобы поймать любую вероятную неправильную структуру смещения, что позволяет больше данных, которые amd64 работает, но достаточно мал, чтобы не тратить большую часть ценных сообщений 2GiB адресного пространства.
  • Он равен самому большому практическому размеру страницы на сегодняшний день и является кратным всем другим размерам виртуальной памяти, о которых можно думать.

Обратите внимание, что фактические x32 версии Linux были отклонения от этой схемы more и more как время идет. Но мы говорим о спецификации ABI здесь, так как форма amd64 формально основана на ней, а не на любом производном макете (см. Его пункт для цитирования).

Смежные вопросы