Список внутренних ссылок в объектных файлах gcc или clang

Учитывая объектный файл, который предоставляет символ, как я могу определить, используется ли символ также для внутреннего использования?

Моя цель - обнаружение мертвых функций. У меня уже есть возможность (через readelf), чтобы найти, если он используется из другого объектного файла, но это не удается, если он используется только для внутреннего использования.

Если это имеет значение, я работаю с C++

1 ответ

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

Прежде всего, если вы оптимизируете, компилятор может встроить ваши функции, даже если они не помечены inline, На самом деле он будет стремиться сделать это, если функция помечена always_inline приписывать. В результате не будет никаких доказательств того, что функция f вызывает функцию g, даже если это действительно так. Обратите внимание, что если g сама является функцией, достижимой извне, компилятор может сгенерировать свой код дважды (или более), сначала под собственным именем для вызовов извне, а затем встроить в объектный код функции f (и других вызывающих функций).

Итак, избегайте оптимизации и как-то подавляйте always_inline, Вы даже можете явно указать -fno-inline для предотвращения встраивания.

Во-вторых, ваша целевая архитектура может иметь относительные инструкции вызова и ветвления. Компилятор может воспользоваться этим, если ваши f и g помещены в общий для них раздел кода. Это значение по умолчанию для не встроенных функций. В таком случае компилятор знает смещение между местом вызова и началом вызываемого абонента во время компиляции и может генерировать относительную команду вызова или перехода; дальнейшее перемещение не требуется. Некоторые компиляторы могут испускать перемещение 'no-op', но некоторые нет. Отсутствие перемещения означает, что на символ не ссылаются.

Итак, используйте -ffunction-sections (и для данных -fdata-sections). Каждая функция затем помещается в свой собственный раздел, и у компилятора не остается другого выбора, кроме как сгенерировать перемещение для исправления компоновщика (таким образом, делая ссылку на символ вызываемого).

Обратите внимание, что если вы используете -ffunction-sections а затем укажите --gc-sections при звонке ld, компилятор отбрасывает все разделы, на которые нет ссылок. Если вы добавите -M Вы получите получившуюся карту модуля. Отброшенные функции не будут отображаться на карте.

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

Другие вопросы по тегам