Я пытался построить и выполнить модули LLVM. Мой код для генерации модулей довольно длинный, поэтому я не буду публиковать его здесь. Вместо этого мой вопрос о том, как Clang и LLVM работают вместе, чтобы добиться искажения имен. Я объясню свою конкретную проблему, чтобы мотивировать вопрос.
Вот исходный код одного из моих модулей LLVM:
#include <iostream>
int main() {
std::cout << "Hello, world. " << std::endl;
return 0;
}
Вот сгенерированный LLVM IR; он слишком велик для StackOverflow.
Когда я пытаюсь выполнить мой модуль, используя lli
Я получаю следующую ошибку:
ОШИБКА LLVM: Программа использовала внешнюю функцию ‘__ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1Emc’, которая не может быть разрешена!
При прохождении символа через деманглера, отсутствующий символ:
_std :: __ 1 :: basic_string, std :: __ 1 :: allocator> :: basic_string (unsigned long, char)
Экстра _
подозрительно, и функция без начального подчеркивания, кажется, существует в IR!
; Function Attrs: alwaysinline ssp uwtable
define available_externally hidden void @_ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1Emc(%"class.std::__1::basic_string"*, i64, i8 signext) unnamed_addr #2 align 2 {
%4 = alloca %"class.std::__1::basic_string"*, align 8
%5 = alloca i64, align 8
%6 = alloca i8, align 1
store %"class.std::__1::basic_string"* %0, %"class.std::__1::basic_string"** %4, align 8
store i64 %1, i64* %5, align 8
store i8 %2, i8* %6, align 1
%7 = load %"class.std::__1::basic_string"*, %"class.std::__1::basic_string"** %4, align 8
%8 = load i64, i64* %5, align 8
%9 = load i8, i8* %6, align 1
call void @_ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC2Emc(%"class.std::__1::basic_string"* %7, i64 %8, i8 signext %9)
ret void
}
Я нахожусь на macOS, поэтому стоит ожидать подчеркивания, но я думаю, что Clang может добавить его дважды.
Я просмотрел источник LLVM / Clang, и кажется, что есть два шага искажения:
Впрочем, это всего лишь моя теория. Может кто-нибудь объяснить, как процесс искажения работает в Clang и LLVM? Как мне создать свой llvm::DataLayout
объекты, чтобы получить правильное искажение для моей платформы?
nm -gU /usr/lib/libc++.dylib
а также nm -gU /usr/lib/libc++abi.dylib
не содержат __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1Emc
Когда я пытаюсь скомпилировать IR, я получаю эту ошибку:
llc generated.ll
clang++ generated.s
Неопределенные символы для архитектуры x86_64:
«std :: __ 1 :: basic_string, std :: __ 1 :: allocator> :: data () const», на который ссылаются из:
std :: __ 1 :: ostreambuf_iterator> std :: __ 1 :: __ pad_and_output> (std :: __ 1 :: ostreambuf_iterator>, char const *, char const *, char const *, std :: __ 1 :: ios_base&, char) в генерируемом b4252a.o
«std :: __ 1 :: basic_ostream> :: sentry :: operator bool () const», на который ссылаются из:
std :: __ 1 :: basic_ostream>& std :: __ 1 :: __ put_character_sequence> (std :: __ 1 :: basic_ostream>&, char const *, unsigned long) в генерируемом b4252a.o
«std :: __ 1 :: basic_ios> :: fill () const», на который ссылаются из:
std :: __ 1 :: basic_ostream>& std :: __ 1 :: __ put_character_sequence> (std :: __ 1 :: basic_ostream>&, char const *, unsigned long) в генерируемом-b4252a.o
«std :: __ 1 :: basic_ios> :: rdbuf () const», на который ссылаются из:
std :: __ 1 :: ostreambuf_iterator> :: ostreambuf_iterator (std :: __ 1 :: basic_ostream>&) в созданном b4252a.o
«std :: __ 1 :: basic_ios> :: widen (char) const», на который ссылаются из:
std :: __ 1 :: basic_ostream>& std :: __ 1 :: endl> (std :: __ 1 :: basic_ostream>&) в созданном b4252a.o
«std :: __ 1 :: basic_string, std :: __ 1 :: allocator> :: basic_string (unsigned long, char)», на который ссылаются из:
std :: __ 1 :: ostreambuf_iterator> std :: __ 1 :: __ pad_and_output> (std :: __ 1 :: ostreambuf_iterator>, char const *, char const *, char const *, std :: __ 1 :: ios_base&, char) в генерируемом b4252a.o
«std :: __ 1 :: basic_ios> :: setstate (unsigned int)», на который ссылаются из:
std :: __ 1 :: basic_ostream>& std :: __ 1 :: __ put_character_sequence> (std :: __ 1 :: basic_ostream>&, char const *, unsigned long) в генерируемом-b4252a.o
ld: символы не найдены для архитектуры x86_64
clang-3.9: ошибка: сбой команды компоновщика с кодом выхода 1 (используйте -v для просмотра вызова)
Я бы не заподозрил проблему искажения имени. Искажение имени в C ++ происходит на внешнем интерфейсе (т.е. clang
) и это часть довольно четкого / документально Стандарт ABI.
Кроме того, я не думаю, что есть ложное подчеркивание, причина, которая не дает действительного C++
name back и искаженное имя в предоставленной вами ссылке на pastebin выглядит следующим образом:
_ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1Emc
Я не на Mac OS, но симулирую с моим LLVM 3.8.1 на Linux (используя --stdlib=libc++
), используя тот же источник и сопоставляя ИК построчно,
Я получаю следующий символ:
_ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEmc
который восстанавливает обратно к:
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::__init(unsigned long, char)
который, я думаю, делает в значительной степени ту же самую конструкцию некоторого вида
Итак, я считаю, что ваш компоновщик подхватывает неправильно libc++
версия.
Вы можете проверить символы, доступные в libc++
это связано с Clang / LLVM, который вы используете, находится в каталоге, заданном llvm-config --libdir
или даже проверяя запись rpath ваших бинарных файлов с помощью readelf -d $(which lli)
,
Если имеется несколько установок LLVM (например, система, одна из которых вы сами скомпилировали из источников), вам, возможно, придется поиграться с -L
вариант clang
который направляет ld
чтобы добавить этот путь в свой список поиска.
Быстрая альтернатива (которую я бы не рекомендовал для регулярного использования) — сделать это в командной строке:
LD_LIBRARY_PATH=$(llvm-config --libdir) clang generated.s
Других решений пока нет …