Как удалить неиспользуемые символы C / C++ с помощью GCC и ld?
мне нужно оптимизировать размер моего исполняемого файла строго (ARM разработка) и
Я заметил, что в моей текущей схеме сборки (gcc + ld) неиспользуемые символы не удаляются.
использование arm-strip --strip-unneeded для результирующих исполняемых файлов / библиотек не изменяет выходной размер исполняемого файла (я понятия не имею, почему, может быть, это просто не может).
каким бы путем (если он существует) изменить мой дом конвейер, чтобы неиспользуемые символы были удалены из результирующего файла?
Я бы даже не подумал об этом, но моя текущая встроенная среда не очень "мощная" и
сохранение даже 500K из 2M результаты в очень хорошем повышении производительности загрузки.
обновление:
к сожалению, нынешние gcc версия, которую я использую, не имеет и -ffunction-sections... + --gc-sections на ld не дает никаких существенных разница в результате.
я в шоке, что это даже стало проблемой, потому что я был уверен, что gcc + ld должны автоматически удалять неиспользуемые символы (почему они даже должны их хранить?).
11 ответов:
для GCC это выполняется в два этапа:
сначала скомпилируйте данные, но попросите компилятор разделить код на отдельные разделы в блоке перевода. Это будет сделано для функций, классов и внешних переменных с помощью следующих двух флагов компилятора:
-fdata-sections -ffunction-sectionsсвяжите единицы перевода вместе с помощью флага оптимизации компоновщика (это приводит к тому, что компоновщик отбрасывает неиспользуемые разделы):
-Wl,--gc-sectionsТак что если у вас один файл называется Тест.cpp, в котором были объявлены две функции, но одна из них не использовалась, вы можете опустить неиспользуемую с помощью следующей команды gcc (g++):
gcc -Os -fdata-sections -ffunction-sections test.cpp -o test -Wl,--gc-sections(обратите внимание ,что-Os-это дополнительный флаг компилятора, который говорит GCC оптимизировать размер)
Если этой теме надо полагать, вам нужно поставить
-ffunction-sectionsи-fdata-sectionsв gcc, который поместит каждую функцию и объект данных в свой собственный раздел. Тогда вы даете и--gc-sectionsв GNU ld для удаления неиспользуемых разделов.
вы хотите проверить ваши документы для вашей версии gcc & ld:
однако для меня (OS X gcc 4.0.1) я нахожу их для ld
-dead_stripудалить функции и данные, недоступные для точки входа или экспортированных символов.
-dead_strip_dylibsудалите dylibs, которые недоступны для точки входа или экспортированных символов. То есть подавляет генерацию команд load command для dylibs, которые не предоставили никаких символов во время ссылки. Этот опция не должна использоваться при связывании с dylib, который требуется во время выполнения по какой-то косвенной причине, такой как dylib имеет важный инициализатор.
и этот полезный вариант
-why_live symbol_nameрегистрирует цепочку ссылок на symbol_name. Только с
-dead_strip. Это может помочь отладить, почему то, что вы думаете, должно быть мертвой полосы удалены не удаляется.есть также заметка в gcc / g++ man, что некоторые виды устранения мертвого кода выполняются только в том случае, если оптимизация включена при компиляции.
хотя эти параметры / условия могут не выполняться для вашего компилятора, я предлагаю вам искать что-то подобное в ваших документах.
привычки программирования тоже могут помочь; например, добавить
staticдля функций, которые не доступны за пределами конкретного файла; используйте более короткие имена для символов (может помочь немного, вероятно, не слишком много); используйтеconst char x[]там, где это возможно; ... этой статье, хотя он говорит о динамических общих объектах, может содержать предложения, которые, если следовать, могут помочь сделать ваш окончательный размер двоичного вывода меньше (если ваша цель-ELF).
ответ
-flto. Вы должны передать его на оба шага компиляции и ссылки, иначе он ничего не делает.Он действительно работает очень хорошо-уменьшил размер программы микроконтроллера, которую я написал, до менее чем 50% от ее предыдущего размера!
к сожалению, это действительно казалось немного глючным - у меня были случаи, когда вещи не были построены правильно. Возможно, это было связано с системой сборки, которую я использую (QBS; это очень новый), но в любом случае я бы рекомендовал вам только включить это для вашей окончательной сборки, если это возможно, и тщательно протестируйте эту сборку.
пока не строго о символах, если идете на размер-всегда компилируйте с
-Osи-sфлаги.-Osоптимизирует полученный код для минимального размера исполняемого файла и-sудаляет таблицу символов и информацию о перемещении из исполняемого файла.иногда - если требуется небольшой размер-игра с различными флагами оптимизации может иметь или не иметь значения. Например, переключение
-ffast-mathи/или-fomit-frame-pointerможет иногда спасти вас даже десятки байты.
мне кажется, что ответ Немо является правильным. Если эти инструкции не работают, проблема может быть связана с версией gcc/ld, которую вы используете, в качестве упражнения я скомпилировал пример программы с использованием подробных инструкций здесь
#include <stdio.h> void deadcode() { printf("This is d dead codez\n"); } int main(void) { printf("This is main\n"); return 0 ; }затем я скомпилировал код, используя все более агрессивные ключи удаления мертвого кода:
gcc -Os test.c -o test.elf gcc -Os -fdata-sections -ffunction-sections test.c -o test.elf -Wl,--gc-sections gcc -Os -fdata-sections -ffunction-sections test.c -o test.elf -Wl,--gc-sections -Wl,--strip-allэти параметры компиляции и компоновки создавали исполняемые файлы размером 8457, 8164 и 6160 байт, соответственно, самый существенный вклад, поступающий от декларации "strip-all". Если вы не можете произвести подобные сокращения на вашей платформе,то, возможно, ваша версия gcc не поддерживает эту функцию. Я использую gcc(4.5.2-8ubuntu4), ld(2.21.0.20110327) на Linux Mint 2.6.38-8-generic x86_64
strip --strip-unneededработает только с таблицей символов исполняемого файла. На самом деле он не удаляет исполняемый код.стандартные библиотеки достигают желаемого результата путем разделения всех их функций на отдельные объектные файлы, которые объединяются с помощью
ar. Если вы затем свяжете полученный архив как библиотеку (т. е. дать возможность-l your_libraryto ld) тогда ld будет включать только объектные файлы и, следовательно, символы, которые фактически используются.вы может также найти некоторые ответы на это аналогичный вопрос использования.
Я не знаю, поможет ли это с вашим текущим затруднительным положением, поскольку это недавняя функция, но вы можете указать видимость символов глобальным образом. Передает
-fvisibility=hidden -fvisibility-inlines-hiddenпри компиляции может помочь компоновщику в дальнейшем избавиться от ненужных символов. Если вы создаете исполняемый файл (в отличие от общей библиотеки), больше ничего не нужно делать.дополнительная информация (и мелкозернистый подход, например, для библиотек) доступна на GCC wiki.
из руководства GCC 4.2.1, раздел
-fwhole-program:предположим, что текущая единица компиляции представляет собой всю компилируемую программу. Все публичные функции и переменные, за исключением
mainи те, которые объединены по атрибутуexternally_visibleстать статические функции и влиять на получает более агрессивно оптимизирован межпроцедурное оптимизаторов. Хотя эта опция эквивалентна правильному использованиюstaticключевое слово для программ, состоящих из одного файла, в сочетании с опцией--combineэтот флаг можно использовать для компиляции большинства программ C меньшим масштабом, так как функции и переменные становятся локальными для всего объединенного блока компиляции, а не для одного исходного файла.