我一直在尝试构建和执行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错误:程序使用了无法解析的外部函数'__ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1Emc'!
通过demangler运行符号,缺少的符号是:
_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源代码,看起来有两个错误的步骤:
-
考虑可能重载的C函数并将它们分解为LLVM IR的唯一名称
-
从LLVM IR中获取一个受损的名称,并添加任何特定于平台的怪癖,例如前导下划线
但是,这只是我的理论 . 有人可以解释一下在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)in generated-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)in generated-b4252a.o“std :: __ 1 :: basic_ios> :: rdbuf()const”,引用自:std :: __ 1 :: ostreambuf_iterator> :: ostreambuf_iterator(std :: _1 :: basic_ostream>&)in generated-b4252a.o“std :: __ 1 :: basic_ios> :: widen(char)const”,引用自:std :: __ 1 :: basic_ostream>&std :: __ 1 :: endl >(STD :: __ 1 :: b asic_ostream>&)in generated-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)in generated-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 )in generated-b4252a.o ld:找不到架构x86_64 clang-3.9的符号:错误:链接器命令失败,退出代码为1(使用-v查看调用)
1 回答
我不会怀疑名称错位问题 . C名称重整发生在前端(即
clang
),它是一个非常明确定义的/ -documented ABI standard的一部分 .此外,我认为没有虚假的下划线,因为这不会产生有效的
C++
名称,并且您提供的pastebin链接中的错位名称显示为:_ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1Emc
我不是在Mac OS上,而是在Linux上使用我的LLVM 3.8.1进行模拟(使用
--stdlib=libc++
),使用相同的源并逐行匹配IR,我得到以下符号:_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
给出的目录中,甚至可以使用readelf -d $(which lli)
检查工具链二进制文件的rpath条目 .如果有多个LLVM安装(例如,您自己从源代码编译的系统1和一个),您可能必须使用
clang
的-L
选项 . 指示ld
在其搜索列表中添加该路径 . 一个快速的替代方案(我不建议常规使用)是在命令行上执行此操作:LD_LIBRARY_PATH=$(llvm-config --libdir) clang generated.s