Мусор из других ссылок - PullRequest
       31

Мусор из других ссылок

4 голосов
/ 27 января 2011

Я задавал себе следующий вопрос, когда обсуждал эту тему.

Существуют ли случаи, когда какой-то неиспользуемый код из модулей перевода будет ссылаться на конечный исполняемый код (в режиме выпускаконечно) для популярных компиляторов, таких как GCC и VC ++?

Например, предположим, у нас есть 2 модуля компиляции:

//A.hpp
//Here are declarations of some classes, functions, extern variables etc.

и исходный файл

//A.cpp
//defination of A.hpp declarations

И, наконец, основной

//main.cpp
//including A.hpp library
#include "A.hpp"
//here we will use some stuff from A.hpp library, but not everything

Мой вопрос.Что если в main.cpp используется не весь материал из A.hpp?Удалит ли компоновщик весь неиспользуемый код, или в некоторых случаях неиспользуемый код может связываться с исполняемым файлом?

Редактировать: Мне интересны компоновщики G ++ и VC ++.

Редактировать:Конечно, я имею в виду в режиме релиза.

Редактировать: я начинаю щедрость за этот вопрос, чтобы получить хороший и полный ответ.Я ожидаю ответа, который объяснит, в каких случаях линкеры g ++ и VC ++ связывают ненужные файлы и какой код они могут удалить из исполняемого файла (ненужные функции, ненужные глобальные переменные, ненужные определения классов и т. Д.) Ипочему они не могут удалить ненужные вещи.

Ответы [ 4 ]

4 голосов
/ 10 марта 2011

Как указали другие авторы, компоновщик обычно не удаляет мертвый код перед сборкой окончательного исполняемого файла. Однако часто есть параметры оптимизации, которые вы можете использовать, чтобы заставить компоновщика приложить дополнительные усилия.

Для GCC это выполняется в два этапа:

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

    -fdata-секции -функция-секции

  2. Соедините блоки перевода вместе, используя флаг оптимизации компоновщика (это заставляет компоновщик отбрасывать несвязанные разделы):

    -Wl, - ГЦ-секции

Итак, если у вас был один файл с именем test.cpp, в котором были объявлены две функции, но одна из них не использовалась, вы можете опустить неиспользуемый файл с помощью следующей команды для gcc (g ++):

gcc -Os -fdata-sections -ffunction-sections test.cpp -o test.o -Wl,--gc-sections

(Обратите внимание, что -Os - это дополнительный флаг компоновщика, который указывает GCC оптимизировать размер)

Я также где-то читал, что связывание статических библиотек отличается. Этот GCC автоматически пропускает неиспользуемые символы в этом случае. Возможно, другой плакат может подтвердить / опровергнуть это.

Что касается MSVC, как уже упоминалось, связывание на уровне функций выполняет то же самое. Я считаю, что флаг компилятора для этого (для сортировки вещей по разделам):

/Gy

А затем флаг компоновщика (для удаления неиспользуемых разделов):

/OPT:REF

РЕДАКТИРОВАТЬ: После дальнейших исследований, я думаю, что бит о GCC автоматически делает это для статических библиотек является ложным.

1 голос
/ 10 марта 2011

Как правило, компоновщики включают все из объектных файлов, явно переданных в командной строке, но извлекают только те объектные файлы из статической библиотеки, которая содержит символы, необходимые для разрешения внешних ссылок из уже связанных объектных файлов.

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

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

Я бы также ожидал, что любые символы, определенные с глобальной видимостью, которые могут быть найдены с помощью dlsym (в отличие от «скрытых» символов, которые видны только в в исполняемом файле), будут присутствовать вфинальный исполняемый файл.Однако это скорее ожидание, чем то, что я подтвердил, протестировав или прочитав документы.

1 голос
/ 27 января 2011

Компоновщик не удалит код.

Вы по-прежнему можете получить к нему динамический доступ через dlsym в вашем коде.

0 голосов
/ 14 марта 2011

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

...