Как уменьшить размер сгенерированных двоичных файлов?
Я знаю, что есть опция "-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, который использует декомпрессию во время выполнения.
Счастливое кодирование.
Ответ 3
Если вы хотите выжать все последние капли пространства из ваших двоичных файлов, вам, вероятно, придется изучить сборку. Для очень интересного (и интересного) вступления см. Эту ссылку:
Учебник Whirlwind по созданию действительно исполняемых файлов ELF для Linux
Ответ 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
, но это небезопасно, поэтому не забудьте понять, как они работают, прежде чем использовать их.