【发布时间】:2017-02-03 17:25:47
【问题描述】:
我一直在尝试构建和执行 LLVM 模块。我生成模块的代码很长,所以我不会在这里发布。相反,我的问题是关于 Clang 和 LLVM 如何协同工作以实现名称修改。我将解释我的具体问题以激发问题。
这是我的 LLVM 模块之一的源代码:
#include <iostream>
int main() {
std::cout << "Hello, world. " << std::endl;
return 0;
}
Here is the generated LLVM IR;对于 StackOverflow 来说太大了。
当我尝试使用lli 执行我的模块时,我收到以下错误:
LLVM ERROR: Program used external function '__ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1Emc' which could not be resolved!
通过 demangler 运行符号,缺少的符号是:
_std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::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 源码,似乎有两个 mangling 步骤:
- 采用可能重载的 C++ 函数并将它们修改为 LLVM IR 的唯一名称
- 从 LLVM IR 中获取错误名称并添加任何特定于平台的怪癖,例如前导下划线
但是,这只是我的理论。有人可以解释一下 Clang 和 LLVM 中的重整过程是如何工作的吗?我应该如何创建我的 llvm::DataLayout 对象来为我的平台获得正确的修饰?
nm -gU /usr/lib/libc++.dylib` and `nm -gU /usr/lib/libc++abi.dylib` do not contain `__ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1Emc
当我尝试编译 IR 时,我得到这个错误:
llc generated.ll
clang++ generated.s
Undefined symbols for architecture x86_64:
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::data() const", referenced from:
std::__1::ostreambuf_iterator<char, std::__1::char_traits<char> > std::__1::__pad_and_output<char, std::__1::char_traits<char> >(std::__1::ostreambuf_iterator<char, std::__1::char_traits<char> >, char const*, char const*, char const*, std::__1::ios_base&, char) in generated-b4252a.o
"std::__1::basic_ostream<char, std::__1::char_traits<char> >::sentry::operator bool() const", referenced from:
std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::__put_character_sequence<char, std::__1::char_traits<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, char const*, unsigned long) in generated-b4252a.o
"std::__1::basic_ios<char, std::__1::char_traits<char> >::fill() const", referenced from:
std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::__put_character_sequence<char, std::__1::char_traits<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, char const*, unsigned long) in generated-b4252a.o
"std::__1::basic_ios<char, std::__1::char_traits<char> >::rdbuf() const", referenced from:
std::__1::ostreambuf_iterator<char, std::__1::char_traits<char> >::ostreambuf_iterator(std::__1::basic_ostream<char, std::__1::char_traits<char> >&) in generated-b4252a.o
"std::__1::basic_ios<char, std::__1::char_traits<char> >::widen(char) const", referenced from:
std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::endl<char, std::__1::char_traits<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&) in generated-b4252a.o
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::basic_string(unsigned long, char)", referenced from:
std::__1::ostreambuf_iterator<char, std::__1::char_traits<char> > std::__1::__pad_and_output<char, std::__1::char_traits<char> >(std::__1::ostreambuf_iterator<char, std::__1::char_traits<char> >, char const*, char const*, char const*, std::__1::ios_base&, char) in generated-b4252a.o
"std::__1::basic_ios<char, std::__1::char_traits<char> >::setstate(unsigned int)", referenced from:
std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::__put_character_sequence<char, std::__1::char_traits<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, char const*, unsigned long) in generated-b4252a.o
ld: symbol(s) not found for architecture x86_64
clang-3.9: error: linker command failed with exit code 1 (use -v to see invocation)
【问题讨论】:
-
我不认为这是一个名称修改问题。只要你不碰名字,你应该没问题。相反,这是一个链接问题。 lli 不链接任何库,因此无法解析 STL 符号。如果您编译并链接模块,您应该没问题... llc test.ll、clang++ test.s(或任何其他编译器)。让我知道这是否有帮助,我会将其添加为答案。
-
...您是否使用 clang++ -S -emit-llvm 生成了 IR?以任何方式编辑文件?您是希望它运行还是想知道名称是如何被修改的 b/c 您想自己生成一个修改后的名称?
-
@Tobias 我使用
clang::CreateLLVMCodeGen工厂和HandleTopLevelDecl生成了LLVM -
@Tobias 我不相信这是一个链接问题,因为
nm -gU /usr/lib/libc++.dylib和nm -gU /usr/lib/libc++abi.dylib不包含__ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1Emc。 -
@Tobias 我在使用
llc时遇到了类似的错误(请参阅上面的问题)。我的下一个最佳猜测是我的 LLVM IR 是针对错误的标准库生成的。