[英]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 源代碼,似乎有兩個修改步驟:
然而,這只是我的理論。 有人可以解釋一下 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)
我不會懷疑名稱修改問題。 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.