Это связано с выравниванием. Смотри readelf -eW <ELF_NAME>
. Интересный бит
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 0000000000401000 001000 00000c 00 AX 0 0 1
Обратите внимание на столбец Off
. Это смещение в файле, и раздел .text
начинается с 0x1000
, то есть 4K.
То же самое изображение, если вы посмотрите на заголовки программы . Пространство, заполненное нулями, находится между концом заголовка ELF и 0x1000.
Почему это?
Во-первых, потому что стандарт ELF диктует, что
Загружаемые сегменты процесса должны иметь совпадающие значения для p_vaddr и p_offset, по модулю размера страницы.
(см. man elf
). Размер страницы в вашей системе (моя тоже) составляет 4K. Это значение, которое вы видите в p_align
.
Во-вторых, виртуальный адрес, который компоновщик назначил началу «текстового» сегмента - так же, как и для раздела .text
здесь, потому что это все, что содержит этот сегмент - это 0x0000000000401000
. Поэтому шестнадцатеричное представление смещения сегмента «текст» в файле должно заканчиваться 000
. Но 0 уже занято сегментом только для чтения, содержащим заголовок ELF (самое начало файла). Второй выбор 0x1000
.
Почему компоновщик выбрал 0x401000 в качестве виртуального адреса для текстового раздела? Я не знаю. Я думаю, что если вы немного доработаете скрипт компоновщика, вы сможете получить исполняемый файл меньшего размера.
Как указал Питер и другой парень, выравнивание по размеру страницы можно отключить с помощью опции компоновщика -n
:
'-n'
'--nmagic'
Turn off page alignment of sections, and disable linking against
shared libraries[…]
Таким образом, я получаю
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 1] .text PROGBITS 0000000000400078 000078 00000c 00 AX 0 0 1
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000078 0x0000000000400078 0x0000000000400078 0x00000c 0x00000c R E 0x1
и размер исполняемого файла уменьшен до 664 байт (344 после strip
ping).
В GNU ld вы можете использовать сценарии компоновщика для точной настройки макета выходных файлов компоновщика. ld.bfd
(обычно также известный как просто ld
) интерпретирует скрипт компоновщика по умолчанию, если пользователь не указывает его. Его можно получить с ld --verbose
. Затем вы можете отредактировать его и указать вместо версии по умолчанию -T <your-script>
.
Я отредактировал первое вхождение
. = ALIGN(CONSTANT (MAXPAGESIZE));
(до .text
) и получил 720 (400 при strip
ped) байтов. Это отличается от результата использования опции -n
. Вы по-прежнему получаете 2 загружаемых сегмента, а их p_align
по-прежнему 0x1000
.
Существуют последствия для эффективности использования p_align
<<code>MAX_PAGE_SIZE, которые я не до конца понимаю. (Страницы не будут загружаться так быстро из-за более сложных вычислений адресов? Я думаю, что должно быть лучшее объяснение.) Не стесняйтесь редактировать ответ, если вы знаете больше об этом или где он объяснен.