GCC: пустая программа == 23202 байта? - PullRequest
14 голосов
/ 22 августа 2009
test.c:

int main()
{
    return 0;
}

Я не использовал никаких флагов (я новичок в gcc), просто команда:

gcc test.c

Я использовал последнюю TDM сборку GCC на win32. Итоговый исполняемый файл размером почти 23 КБ, слишком большой для пустой программы.

Как мне уменьшить размер исполняемого файла?

Ответы [ 10 ]

37 голосов
/ 22 августа 2009

Не следуйте его советам, но ради развлечения, прочитайте эту «историю» о создании наименьшего возможного двоичного файла ELF.

21 голосов
/ 22 августа 2009

Как я могу уменьшить его размер?

  • Не делай этого. Ты просто тратишь время.
  • Используйте флаг -s для удаления символов (gcc -s)
11 голосов
/ 22 августа 2009

Брось. В Linux x86 gcc 4.3.2 создает двоичный файл размером 5 КБ. Но ждать! Это с динамическим связыванием! Статически связанный двоичный файл занимает более половины мегабайта: 516K. Расслабься и научись жить с наворотом.

И они сказали, что Modula-3 никогда не пойдет никуда из-за двоичного файла 200K Hello World!


В случае, если вам интересно, что происходит, библиотека Gnu C структурирована таким образом, чтобы включать определенные функции, независимо от того, зависит ваша программа от них или нет. Эти функции включают в себя такие мелочи, как malloc и free, dlopen, некоторая обработка строк и целое bucketload материала, который, по-видимому, связан с локалями и интернационализацией, хотя я не могу найти соответствующие страницы руководства.

Создание небольших исполняемых файлов для программ, требующих минимального обслуживания, , а не цель разработки для glibc. Справедливости ради, это также было , а не целью разработки для каждой системы времени исполнения, с которой я когда-либо работал (около полдюжины).

11 голосов
/ 22 августа 2009

По умолчанию некоторые стандартные библиотеки (например, среда выполнения C) связаны с вашим исполняемым файлом. Проверьте ключи --nostdlib --nostartfiles --nodefaultlib для деталей. Параметры ссылок описаны здесь .

Для реальной программы второй вариант - попробовать опции оптимизации , например -О (оптимизировать по размеру).

7 голосов
/ 22 августа 2009

На самом деле, если ваш код ничего не делает, разве справедливо, что компилятор все еще создает исполняемый файл? ; -)

Что ж, в Windows любой исполняемый файл по-прежнему будет иметь размер, хотя он может быть достаточно маленьким. При использовании старой системы MS-DOS полное приложение, которое ничего не делает, будет занимать пару байтов. (Я думаю, четыре байта, чтобы использовать 21-часовое прерывание, чтобы закрыть программу.) С другой стороны, эти приложения были загружены прямо в память. Когда формат EXE стал более популярным, все немного изменилось. Теперь исполняемые файлы имели дополнительную информацию о самом процессе, например, перемещение кода и сегментов данных, а также некоторые контрольные суммы и информацию о версии. Внедрение Windows добавило еще один заголовок к формату, чтобы сообщить MS-DOS, что он не может выполнить исполняемый файл, так как он должен был работать под Windows. И Windows узнает это без проблем. Конечно, формат исполняемого файла также был расширен за счет информации о ресурсах, таких как растровые изображения, значки, диалоговые формы и многое, многое другое.

В настоящее время исполняемый файл без действия будет иметь размер от 4 до 8 килобайт, в зависимости от вашего компилятора и каждого метода, который вы использовали для уменьшения его размера. Это было бы в размере, где UPX фактически привел бы к большим исполняемым файлам! Дополнительные байты в вашем исполняемом файле могут быть добавлены, потому что вы добавили определенные библиотеки в свой код. Особенно библиотеки с инициализированными данными или ресурсами будут добавлять значительное количество байтов. Добавление отладочной информации также увеличивает размер исполняемого файла.

Но хотя все это является хорошим упражнением по уменьшению размера, вы можете задаться вопросом, целесообразно ли просто продолжать беспокоиться о раздутости приложений. Современные жесткие диски делят файлы на сегменты, а для действительно больших дисков разница будет очень мала. Тем не менее, количество проблем, которые потребуются для поддержания как можно меньшего размера, замедлит скорость разработки, если вы не являетесь опытным разработчиком, который привык к такой оптимизации. Подобные оптимизации не имеют тенденцию повышать производительность, и, учитывая среднее дисковое пространство большинства систем, я не понимаю, почему это было бы целесообразно. (Тем не менее, я оптимизирую свой собственный код подобными способами, но с другой стороны, у меня есть опыт этой оптимизации.)


Интересует заголовок EXE ? Это начинается с буквы MZ, для "Марк Zbikowski". Первая часть - это заголовок MS-DOS старого стиля для исполняемых файлов, который используется в качестве заглушки для MS-DOS, говоря, что программа , а не исполняемый файл MS-DOS. (В двоичном файле вы можете найти текст «Эта программа не может быть запущена в режиме DOS». Это в основном все, что он делает: отображение этого сообщения. Далее идет заголовок PE, который Windows распознает и использует вместо MS-DOS. заголовок. Он начинается с букв PE для Portable Executable . После этого второго заголовка будет сам исполняемый файл, разделенный на несколько блоков кода и данных. Заголовок содержит специальные таблицы перераспределения, которые сообщают ОС, куда загрузить определенный блок. И если вы можете ограничить его, конечный исполняемый файл может быть меньше 4 КБ, но тогда 90% будет информацией заголовка и не будет функционировать.
3 голосов
/ 22 августа 2009

Мне нравится, как часто задаваемые вопросы DJGPP обращались к этому много-много лет назад:

В целом, оценка размеров кода по размеру программ «Hello» не имеет смысла, поскольку такие программы состоят в основном из кода запуска. ... Большая часть всех этих функций тратится впустую в программах «Hello». Нет смысла запускать весь этот код только для того, чтобы вывести 15-байтовую строку и выйти.

2 голосов
/ 25 августа 2009

Что 'size a.out' говорит вам о размере кода, данных и bss-сегментов? Большая часть кода, вероятно, будет кодом запуска (классически crt0.o на машинах Unix), который вызывается операционными системами и настраивает работу (например, сортировку аргументов командной строки в argc, argv) перед вызовом main().

2 голосов
/ 22 августа 2009

Какова цель этого упражнения?

Даже при таком низком уровне языка, как C, все еще нужно выполнить много настроек, прежде чем можно будет вызывать main. Некоторые из этих настроек обрабатываются загрузчиком (который требует определенной информации), некоторые обрабатываются кодом, который вызывает main. А потом, вероятно, есть немного библиотечного кода, который должен быть у любой нормальной программы. По крайней мере, есть ссылки на стандартные библиотеки, если они в dll.

Изучение двоичного размера пустой программы само по себе бесполезно. Это ничего вам не говорит. Если вы хотите узнать что-то о размере кода, попробуйте написать непустые (и желательно нетривиальные) программы. Сравните программы, использующие стандартные библиотеки, с программами, которые все делают сами.

Если вы действительно хотите знать, что происходит в этом двоичном файле (и почему он такой большой), то найдите исполняемый формат, получите инструмент для двоичного дампа и разберите его на части.

1 голос
/ 24 августа 2009

Запустите полоску по двоичному файлу, чтобы избавиться от символов. С версией gcc 3.4.4 (специальный cygming) я понижаюсь с 10 КБ до 4 КБ.

Вы можете попробовать связать пользовательскую среду выполнения (часть, которая вызывает main) для настройки среды выполнения. Все программы используют одну и ту же программу для настройки среды выполнения, которая поставляется с gcc, но для вашего исполняемого файла вам не нужны данные или нулевая память. Это означает, что вы можете избавиться от неиспользуемых библиотечных функций, таких как memset / memcpy, и уменьшить размер CRT0. При поиске информации об этом посмотрите на GCC во встроенной среде. Разработчики встраиваемых систем, как правило, единственные люди, которые используют пользовательские среды выполнения.

Остальные накладные расходы для ОС, которая загружает исполняемый файл. Вы не собираетесь делать то же самое там, если не настроите это вручную?

0 голосов
/ 22 августа 2009

Используя GCC, скомпилируйте вашу программу, используя -Os, а не один из других флагов оптимизации (-O2 или -O3). Это говорит об оптимизации размера, а не скорости. Между прочим, иногда это может привести к тому, что программы будут работать быстрее, чем при оптимизации скорости, если какой-то критический сегмент окажется более подходящим. С другой стороны, -O3 может вызвать увеличение размера кода.

Также могут быть некоторые флаги компоновщика, указывающие, что он не должен использовать неиспользуемый код из окончательного двоичного файла.

...