Удалите мертвый код перед связыванием

В проекте, состоящем из нескольких статически связанных объектных файлов, я заменяю один из них отдельной реализацией. Я хотел бы протестировать свой код еще до того, как я реализовал каждый символ, предоставленный замененным объектным файлом, поэтому я использую -Wl,--unresolved-symbols=ignore-all, чтобы компоновщик не жаловался на отсутствующие символы.

Но когда я тестирую код, он просто падает при попытке использовать один из неопределенных символов. Поэтому я ищу способ сказать компоновщику: «Пожалуйста, удалите весь код без ссылок перед компоновкой, а затем сообщите мне, если в коде, доступном из точки входа, все еще есть символы без ссылок». Это возможно?


person Joachim Breitner    schedule 29.03.2017    source источник
comment
Объектные файлы создаются из сгенерированного LLVM IR (а не кода C), если это имеет значение.   -  person Joachim Breitner    schedule 29.03.2017
comment
Достаточно ли передать ИК через opt? Звучит как тупиковая полоса, а затем связывание в обычном режиме поможет.   -  person Jon Chesterfield    schedule 31.03.2017
comment
Нет, я не думаю, что opt поможет, так как opt просматривает один модуль за раз, верно?   -  person Joachim Breitner    schedule 31.03.2017
comment
Я подумываю использовать llvm-link для объединения различных IR, а затем выбрать (особенно -dce, -globaldce) их удаление. Преобразование IR в объектный код. Затем компоновщик получает один файл и по-прежнему будет предупреждать о том, какие символы были фактически доступны.   -  person Jon Chesterfield    schedule 31.03.2017
comment
Хм, это может сработать, но его сложно интегрировать в существующую систему сборки (которая компилирует каждый .ll в .o файлов, прежде чем в конечном итоге связать их).   -  person Joachim Breitner    schedule 31.03.2017
comment
С другой стороны, если вы сохраните файлы .ll (или .bc), а затем свяжете их с помощью llvm, вы получите возможность кросс-модульной оптимизации, а также удаление мертвых файлов. Но да, потенциально сложно подключить к системе сборки.   -  person Jon Chesterfield    schedule 01.04.2017


Ответы (1)


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

int do_things(void);

int application_main(void)
{
  return do_things();
}

int test_main(void)
{
  return 42;
}

int main(void)
{
  return test_main();
}

Макет примерно отражает мой вариант использования. У данного блока IR может быть две точки входа: одна для запуска модульных тестов, а другая для выполнения всего, для чего используется код. Для модульных тестов требуется подмножество символов, необходимых всему модулю. Преимущество заключается в том, что вы можете построить часть модульного теста без создания всего остального.

Мертвая зачистка — это определенное улучшение по сравнению с моим предыдущим методом -Wl,--unresolved-symbols=ignore-all

clang demo.c     # undefined reference to `do_things'
clang -O3 demo.c # undefined reference to `do_things'
clang demo.c -c -emit-llvm -o demo.bc # OK

llvm-nm demo.bc 
---------------- T application_main
                 U do_things
---------------- T main
---------------- T test_main
clang demo.bc    # undefined reference to `do_things'

opt -o stripped.bc -internalize -internalize-public-api-list=main -globaldce demo.bc
llvm-nm stripped.bc 
---------------- T main
---------------- t test_main
clang stripped.bc # OK

Список общедоступных символов может быть получен из ir-файлов (по крайней мере, в моем случае), поэтому вызов opt на самом деле

 opt -internalize -internalize-public-api-list=`llvm-nm -extern-only -defined-only -just-symbol-name some-file.bc` -globaldce -O2
person Jon Chesterfield    schedule 01.04.2017