17

我一直在尝试构建和执行 LLVM 模块。我生成模块的代码很长,所以我不会在这里发布。相反,我的问题是关于 Clang 和 LLVM 如何协同工作以实现名称修改。我将解释我的具体问题以激发问题。

这是我的 LLVM 模块之一的源代码:

#include <iostream>

int main() {
  std::cout << "Hello, world. " << std::endl;
  return 0;
}

这是生成的 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)

extra_可疑,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 源代码,似乎有两个修改步骤:

  1. 采用可能重载的 C++ 函数并将它们修改为 LLVM IR 的唯一名称
  2. 从 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_9allocatorI‌​cEEEC1Emc

当我尝试编译 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)
4

1 回答 1

4

我不会怀疑名称修改问题。C++ 名称修改发生在前端(即clang),它是一个非常明确/记录在案的ABI 标准的一部分。

此外,我认为没有虚假的下划线,因为它不会产生有效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

哪一个 demangles 回到:

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).

如果有多个 LLVM 安装(例如,您自己从源代码编译的一个系统和一个系统),您可能必须尝试使用​​哪个-L选项clang来指示ld在其搜索列表中添加该路径。一个快速的替代方法(我不建议经常使用)是在命令行上执行此操作:

LD_LIBRARY_PATH=$(llvm-config --libdir) clang generated.s

于 2017-04-19T19:57:21.463 回答