2016-09-18 8 views
0

Я протестировал два успешных выхода из минимальных программ, сначала использует libc, второй не использует libc.почему компоновщик не разделяет основную рутину с исполняемого файла?

Первое:

segment .text 
    global main 
main: 
    xor eax, eax 
    ret 

Сложение и проверьте размер:

yasm -f elf64 main.s; clang -o main main.o; stat ./main 
... 
Size: 8552 
... 

Второе:

segment .text 
    global _start 
_start: 
    mov eax, 60 
    xor edi, edi 
    syscall 

Сложение и проверьте размер:

yasm -f elf64 main.s; ld -o main main.o; stat ./main 
... 
Size: 704 
--- 

Очевидно, что программа с использованием основных больше по размеру. Почему линкеры не разделяют main рутина из двоичных файлов для оптимизации размера? Я имею в виду линкеры, которые получают объектные файлы после компиляции программы C.

+0

Что вы имеете в виду? Я спрашивал о возможности «вырезать» код из основного и вставить его в _start, так что main не будет вызываться. –

+0

Это было предназначено как шутка. Sry, за то, что пропустил «;-)». – alk

+0

Я не вижу никакого кода С. Вы проверили ** содержимое **? Заключение по размеру двоичного кода, что происходит внутри, - очень плохой подход. В вашем коде Ассемблера нет функции/«подпрограммы»! Просто метка, которая генерирует символ. – Olaf

ответ

1

почему компоновщик не разделяет основную рутину с исполняемого файла?

Поскольку сшивающие агенты вообще не раздеваться никаких подпрограмм из объектных файлов они приведены. Они просто не в этом бизнесе.

Контакторы не работают в режимах, они работают на секциях. Некоторые линкеры могут выполнять ограниченное удаление без ссылок. GNU BFD ld и Gold имеют флаг --gc-sections, но в вашем примере нет разделов без ссылок, поэтому в любом случае ничего не будет GC'd.

Теперь разница между вашими двумя программами является то, что один с main звеньев в запуске C во время выполнения (обычно crt0.o), и устанавливает argc и argv аргументы так, как main определяется их ожидать.

Ваш main не заботится об этом, но для его вывода потребуется действительно умный компоновщик. Кроме того, ваш mainделает заботиться о вызове sys_exit после возвращения, поэтому на самом деле ему необходимо crt0.o для правильного выключения.

Является ли это процессом создания argc/argv, который занимает несколько килобайт?

Если вы используете GNU Л.Д., вы можете попросить линкер сказать вам точно, что, используя сколько пространства с линкера --print-map аргументом.

На платформах ELF вы также можете использовать nm main, чтобы увидеть, какие символы занимают место в финальном двоичном формате, и используйте ld -y <symbol> ..., чтобы увидеть, с чего связаны эти символы.

+0

Является ли это argc/argv, который занимает несколько килобайт? –

+0

@ BulatM.Я обновил ответ. –