Как уменьшить размер сгенерированных двоичных файлов?

Я знаю, что есть опция "-O" для "Оптимизация для размера", но она мало влияет или даже увеличивает размер в некотором случае:(

strip (или "-s" ) удаляет таблицу символов отладки, которая работает нормально; но это может только уменьшить лишь небольшую прописку размера.

Есть ли другой способ пойти дальше?

Ответ 1

Помимо очевидного (-Os -s), выравнивание функций до наименьшего возможного значения, которое не будет аварийно (я не знаю требований к выравниванию ARM), может выжать несколько байтов на каждую функцию. -Os должен уже отключить функции выравнивания, но по умолчанию это может быть значение равно 4 или 8. Если выравнивание, например, до 1 возможно с ARM, который может сэкономить несколько байтов.

-ffast-math (или менее абразивный -fno-math-errno) не будет устанавливать errno и избежать некоторых проверок, что уменьшает размер кода. Если, как и большинство людей, вы все равно не читаете errno, это опция.

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

Включение LTO может помочь, и если это невозможно, скомпилируйте все исходные файлы в двоичный файл за один раз (gcc foo.c bar.c baz.c -o program вместо компиляции foo.c, bar.c и baz.c) в объектные файлы, а затем ссылка) будет иметь аналогичный эффект. Он делает все видимым для оптимизатора за один раз, возможно, позволяя ему работать лучше.

-fdelete-null-pointer-checks может быть вариантом (обратите внимание, что это нормально с любым "O", но не по встроенным целям).

Полагая статические глобальные переменные (у вас, надеюсь, не так много, но все же) в структуру, можно выделить много служебных ресурсов, инициализирующих их. Я узнал, что при написании моего первого загрузчика OpenGL. Наличие всех указателей функций в структуре и инициализация структуры с помощью = {} генерирует один вызов memset, тогда как при инициализации указателей "обычный путь" генерирует сто килобайт кода только для того, чтобы каждый из них был равен нулю.

Избегайте статических локальных переменных нетривиального-конструктора, таких как дьявол (типы POD не являются проблемой). Gcc инициализирует статические локаторы нетривиального-конструктора threadsafe, если вы не компилируете с помощью -fno-threadsafe-statics, который связывается с большим количеством дополнительного кода (даже если вы вообще не используете потоки).

Использование чего-то вроде libowfat вместо обычного crt может значительно уменьшить ваш двоичный размер.

Ответ 2

Предполагая, что еще один инструмент разрешен; -)

Затем рассмотрим UPX: Ultimate Packer for Binaries, который использует декомпрессию во время выполнения.

Счастливое кодирование.

Ответ 4

Вы также можете использовать -nostartfiles и/или -nodefaultlibs или комбо обоих -nostdlib. Если вам не нужен стандартный стартовый файл, вы должны написать свою собственную функцию _start. См. Также этот поток на ompf:

(цитируя Перрина)

# man syscalls
# cat phat.cc
extern "C" void _start() {
        asm("int $0x80" :: "a"(1), "b"(42));
}
# g++ -fno-exceptions -Os -c phat.cc
# objdump -d phat.o

phat.o:     file format elf64-x86-64

Disassembly of section .text:

0000000000000000 <_start>:
   0:   53                      push   %rbx
   1:   b8 01 00 00 00          mov    $0x1,%eax
   6:   bb 2a 00 00 00          mov    $0x2a,%ebx
   b:   cd 80                   int    $0x80
   d:   5b                      pop    %rbx
   e:   c3                      retq
# ld -nostdlib -nostartfiles phat.o -o phat
# sstrip phat
# ls -l phat
-rwxr-xr-x 1 tbp src 294 2007-04-11 22:47 phat
# ./phat; echo $?
42

Сводка: выше фрагмента дал двоичный файл 294 байта, каждый байт 8 бит.

Ответ 5

Это также зависит от используемой архитектуры.

На руке у вас есть набор инструкций Thumb, который здесь, чтобы уменьшить сгенерированный размер кода.

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

Ответ 6

При использовании полосы (1) вы хотите убедиться, что используете все соответствующие параметры. По какой-то причине --strip-all не всегда разделяет все. Может оказаться полезным удаление ненужных разделов.

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

Ответ 7

Вы можете попробовать играть с -fdata-sections, -ffunction-sections и -Wl,--gc-sections, но это небезопасно, поэтому не забудьте понять, как они работают, прежде чем использовать их.