GCC поможет вам найти мертвый код в компиляции.Я был бы удивлен, если бы он мог найти мертвый код в нескольких единицах компиляции.Объявление на уровне файла функции или переменной в модуле компиляции означает, что какой-то другой модуль компиляции может ссылаться на него.Таким образом, все, что объявлено на верхнем уровне файла, GCC не может устранить, поскольку он, вероятно, видит только одну единицу компиляции за раз.
Проблема становится все труднее.Представьте, что модуль компиляции A объявляет функцию a, а модуль B компиляции имеет функцию b, которая вызывает a.Мертв?На первый взгляд, нет.Но на самом деле это зависит;если b мертв, и единственная ссылка на a находится в b, то a тоже мертв.Мы получаем ту же проблему, если b просто берет & a и помещает его в массив X. Теперь, чтобы решить, является ли a мертвым, нам нужен анализ точек по всей системе, чтобы увидеть, является ли этот указатель наa используется везде .
Чтобы получить точную «мертвую» информацию такого рода, вам необходимо глобальное представление всего набора единиц компиляции, а также вычисление анализа точек с последующим построением графа вызовов на основена что указывает на анализ.Функция a является мертвой только в том случае, если граф вызовов (как дерево, с основным в качестве корня) не ссылается на него где-либо(Некоторые предостережения необходимы: какой бы анализ ни был, с практической точки зрения он должен быть консервативным, поэтому даже полный анализ может не правильно определить функцию как мёртвую. Вам также нужно беспокоиться об использовании артефакта C извненабор функций C, например, вызов a из некоторого кода ассемблера).
Потоки усугубляют это;каждый поток имеет некоторую корневую функцию, которая, вероятно, находится на вершине вызова DAG.Поскольку начало работы потока не определяется компиляторами C, должно быть ясно, что для определения, имеет ли многопоточное приложение C мертвый код, необходимо как-то сообщить анализу корневые функции потока или узнать, как их обнаружитьищу примитивы инициализации потока.
Вы не получаете много ответов о том, как получить правильный ответ.Хотя он не является открытым исходным кодом, наш набор инструментов для реинжиниринга программного обеспечения DMS с C Front End имеет все необходимое для этого оборудование, включая синтаксические анализаторы C, control- и dataflow-анализ, локальный и глобальный точечный анализ и построение графа глобальных вызовов. DMS легко настраивается для включения дополнительной информации, такой как внешние вызовы из ассемблера, и / или список корней потоков или определенных шаблонов источников, которые являются потокамивызовы инициализации, и мы фактически (легко) сделали это для некоторых крупных встроенных контроллеров движков с миллионами строк кода.DMS была применена к системам размером до 26 миллионов строк кода (около 18 000 единиц компиляции) с целью построения таких графов вызовов.
[Интересное в стороне: при обработке отдельных модулей компиляции, DMS по причинам масштабированияфактически удаляет символы и связанный код, которые не используются в этом модуле компиляции.Примечательно, что это избавляет от примерно 95% кода по объему, если принять во внимание айсберг, обычно скрывающийся в гнезде включаемых файлов.Это говорит о том, что в программном обеспечении на Си плохо включены факторинговые файлы.Я подозреваю, что вы все это уже знаете.]
Такие инструменты, как GCC, удаляют мертвый код при компиляции .Это полезно, но мертвый код все еще лежит в вашем модуле компиляции исходный код , привлекая внимание разработчика (они должны выяснить, если он тоже мертв!).DMS в режиме программной трансформации может быть настроен по модулю некоторых проблем препроцессора, чтобы фактически удалить этот мертвый код из источника .В очень больших программных системах вы не хотите делать это вручную.