簡體   English   中英

LLVM 中的命名混淆

[英]Name mangling confusion in LLVM

我一直在嘗試構建和執行 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)

多余的_是可疑的,沒有前導下划線的函數似乎存在於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)

我不會懷疑名稱修改問題。 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

返回到:

std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::__init(unsigned long, char)

我想這在某種意義上幾乎是相同的構造。

所以,我相信您的鏈接器選擇了錯誤的libc++版本。

您可以檢查與您正在使用的 clang/LLVM 相關聯的libc++中可用的符號,在llvm-config --libdir給出的目錄中找到,甚至可以使用readelf -d $(which lli)檢查工具鏈二進制文件的 rpath 條目readelf -d $(which lli)

如果有多個 LLVM 安裝(例如,一個系統和一個您自己從源代碼編譯的系統),您可能需要使用clang-L選項,該選項指示ld在其搜索列表中添加該路徑。 一個快速的替代方法(我不建議經常使用)是在命令行上執行此操作:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM