Страницы

Поиск по вопросам

воскресенье, 9 февраля 2020 г.

С (GCC). Как исключить из сборки неиспользуемые функции?

#c #gcc


В проекте есть пара .c / .h, в которой объявлены и определены несколько функций.
При этом некоторые из них не используются. Но после компиляции, заглянув в листинг
можно обнаружить там ассемблерный код этих самых неиспользуемых функций? Как исключить
их из сборки? В моем случае память очень ограничена и хотелось бы оптимально ее расходовать.
Да и вообще интересно. К тому же, не попадают же таким образом неиспользуемые ф-ии
из стандартной библиотеки.    


Ответы

Ответ 1



Итак давайте разбираться, на этапе компиляции понятное дело что функции вряд-ли куда денутся, все они окажутся в объектном файле, следовательно все дело в сборке (linking). Создадим пример: /* Файл func1.c */ int FuncA (void) { return 1; } /* ни где не используется */ int FuncB (void) { return 2; } /* ни где не используется */ /* Файл func2.c */ int FuncC (void) { return 0; } /* используется в main() */ /* Файл func1.h */ int FuncA (void); int FuncB (void); /* Файл func2.h */ int FuncC (void); /* Файл main.c */ #include "func1.h" #include "func2.h" int main(int argc, char **argv) { return FuncC(); } Теперь начинаем собирать: gcc -o a.out main.c func1.c func2.c Проверяем: nm a.out | grep Func[ABC] 080483c4 T FuncA 080483ce T FuncB 080483d8 T FuncC Ничего не получилось :-) Делаем еще одну попытку: gcc -c func1.c gcc -c func2.c gcc -o a.out main.c func1.o func2.o Проверяем: nm a.out | grep Func[ABC] 080483c4 T FuncA 080483ce T FuncB 080483d8 T FuncC Опять все функции попали в выходной файл. Применяем черную магию, а конкретно собираем библиотеку: gcc -c func1.c gcc -c func2.c ar rcs lib.a func1.o func2.o gcc -o main.c lib.a Проверяем: nm a.out | grep Func[ABC] 080483c4 T FuncC Итак у нас получилось. Отсюда вывод - разделяем исходняки на модули затем компилируем модули в объектные файлы, затем объектные файлы объединяем в библиотеку, а затем собираем основную программу с библиотеками подключатся только используемые модули UPDATE У gcc-шного линкера есть такая возможность как -gc-sections (garbage collect and discard unused sections), воспользоваться ею легко: gcc -fdata-sections -ffunction-sections -Wl,--gc-sections -o a.out \ main.c func1.c func2.c nm a.out | grep Func[ABC] 080483c0 T FuncC Но это не всегда приемлемо особенно когда это касается больших проектов. Пример

Ответ 2



Посмотрите вывод команды nm your.exe Код будет помечен метками T и t (t это "внутренний" (static) код). Часто несколько функций размещаются в одной единице компиляции (.c), которая (.o) линкуется с Вашим модулем либо непосредственно либо из библиотеки. Если Вы ссылаетесь на одну функцию из (.o), то остальные тоже прилинкуются. IMHO исключить их нельзя.

Ответ 3



Вот написал такой тестик #include __attribute__ ((noinline)) static int func_fff(int a) { puts ("OK"); return a*2; } int main() { printf ("%d\n", 4); #ifdef __COMP printf ("%d\n", func_fff (10)); #endif return 0; } Параметры компиляции и выводы программы nm : gcc test.c -c -o a.o nm a.o | grep func_fff t func_fff gcc test.c -c -o a.o -O nm a.o | grep func_fff gcc test.c -c -o a.o -O -D__COMP nm a.o | grep func_fff t func_fff Анализ ассемблерного кода также показывает, что во втором варианте никаких следов функции нет. Вывод: невключение невызываемой функции на этапе компиляции можно достичь, определяя ее как static и применяя оптимизацию компиляции (достаточно уровня О1). P.S. Чтобы статическая функция включалась всегда, нужно ее объявлять с аттрибутом __attribute__ ((used))

Ответ 4



Вероятно повысить уровень оптимизации в той среде разработки, в которой пишете. Сталкивался--помогало. Пробуйте =)

Ответ 5



Вы не путаетет компиляцию и линковку? На этапе компиляции обычно ничего не выбрасывается. А вот линковщик уже смотрим, что есть, а чего нет и просто не включает в результирующий файл. (Ну разве что включены всевозможные режимы для отладки, типа -ggdb). Что бы убедиться, что результат такой, как нужно, рекомендую смотреть дизассемблером и генерировать карту функций. Для этого добавьте такой параметр -Wl,-Map=a.map к gcc. Формат файла a.map не хитрый, и может быть понят. Там будут перечислены все функции, их адреса, размеры и другая интересная информация, которая позволит Вам найти, где можно ещё немного соптимизировать.

Ответ 6



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

Комментариев нет:

Отправить комментарий