2017-02-03 23 views
15

Tôi đã cố gắng xây dựng và thực thi các mô-đun LLVM. Mã của tôi để tạo ra các mô-đun là khá dài, vì vậy tôi sẽ không đăng nó ở đây. Thay vào đó, câu hỏi của tôi là về cách Clang và LLVM làm việc cùng nhau để đạt được tên mangling. Tôi sẽ giải thích vấn đề cụ thể của tôi để thúc đẩy câu hỏi.Tên nhầm lẫn mangling trong LLVM

Đây là mã nguồn của một trong những module LLVM tôi:

#include <iostream> 

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

Here is the generated LLVM IR; nó quá lớn đối với StackOverflow.

Khi tôi cố gắng thực hiện mô-đun của tôi sử dụng lli, tôi nhận được lỗi sau:

LLVM ERROR: Program used external function '__ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1Emc' which could not be resolved!

Chạy biểu tượng thông qua một demangler, biểu tượng mất tích là:

_std::__1::basic_string, std::__1::allocator >::basic_string(unsigned long, char)

Các phụ _ là đáng ngờ, và chức năng không có dấu gạch dưới hàng đầu dường như tồn tại trong 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 
} 

Tôi đang trên hệ điều hành MacOS, do đó, một dấu gạch dưới hàng đầu là để được mong đợi, nhưng tôi nghĩ rằng Clang có thể thêm nó hai lần.

Tôi nhìn qua nguồn LLVM/Clang, và có vẻ như rằng có hai bước mangling:

  1. Lấy có thể bị quá tải chức năng C++ và mangling họ tên duy nhất cho LLVM IR
  2. Lấy một đọc sai tên từ IR LLVM và thêm bất kỳ quirks nền tảng cụ thể nào, chẳng hạn như dấu gạch dưới hàng đầu

Tuy nhiên, đây chỉ là lý thuyết của tôi. Ai đó có thể giải thích quá trình xâu chuỗi hoạt động như thế nào ở Clang và LLVM? Làm cách nào để tạo các đối tượng llvm::DataLayout của tôi để có được xâu xén chính xác cho nền tảng của tôi?


nm -gU /usr/lib/libc++.dylibnm -gU /usr/lib/libc++abi.dylib không chứa __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorI‌​cEEEC1Emc


Khi tôi cố gắng biên dịch IR, tôi nhận được lỗi này:

llc generated.ll 
clang++ generated.s 

Undefined symbols for architecture x86_64: "std::__1::basic_string, std::__1::allocator >::data() const", referenced from: 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", referenced from: 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 >::fill() const", referenced from: 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", referenced from: std::__1::ostreambuf_iterator >::ostreambuf_iterator(std::__1::basic_ostream >&) in generated-b4252a.o "std::__1::basic_ios >::widen(char) const", referenced from: std::__1::basic_ostream >& std::__1::endl >(std::__1::basic_ostream >&) in generated-b4252a.o "std::__1::basic_string, std::__1::allocator >::basic_string(unsigned long, char)", referenced from: 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)", referenced from: std::__1::basic_ostream >& std::__1::__put_character_sequence >(std::__1::basic_ostream >&, 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)

+1

Tôi không nghĩ rằng đây là một vấn đề tên mangling. Miễn là bạn không chạm vào tên, bạn sẽ ổn thôi. Thay vào đó, đây là một vấn đề liên kết. lli không liên kết trong bất kỳ thư viện nào, vì vậy các ký hiệu STL không thể được giải quyết. Nếu bạn biên dịch và liên kết các mô-đun bạn sẽ được tốt ... llc test.ll, clang ++ test.s (hoặc bất kỳ trình biên dịch khác). Hãy cho tôi biết nếu điều này giúp & tôi sẽ thêm nó làm câu trả lời. – Tobias

+0

... bạn đã tạo IR với clang ++ -S -emit-llvm chưa? đã chỉnh sửa tệp theo bất kỳ cách nào? Bạn có muốn nó chạy hay bạn muốn biết làm thế nào tên được băm nhỏ b/c bạn muốn tạo ra một tên bị xâu xé cho mình? – Tobias

+0

@Tobias Tôi đã tạo LLVM bằng cách sử dụng nhà máy 'clang :: CreateLLVMCodeGen' và' HandleTopLevelDecl' – sdgfsdh

Trả lời

2

Tôi sẽ không nghi ngờ một tên mangling vấn đề. Tên xén mang tên C++ xảy ra ở mặt trước (ví dụ: clang) và nó là một phần của một tài liệu được xác định rõ ràng/số ABI standard.

Hơn nữa, tôi không nghĩ rằng có một gạch giả mạo, nguyên nhân mà không tạo ra một C++ tên hợp lệ trở lại và tên đọc sai trong liên kết pastebin mà bạn cung cấp có vẻ như:

_ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1Emc

Tôi không phải trên Mac OS, nhưng mô phỏng với LLVM 3.8 của tôi.1 trên Linux (sử dụng --stdlib=libc++), sử dụng cùng một nguồn và phù hợp với dòng IR bởi dòng, tôi nhận được biểu tượng sau:

_ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEmc

mà demangles trở lại:

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

mà tôi đoán có khá nhiều công trình giống nhau.

Vì vậy, tôi tin rằng trình liên kết của bạn chọn sai phiên bản libc++.

Bạn có thể kiểm tra các ký hiệu có sẵn trong libc++ được gắn với clang/LLVM mà bạn đang sử dụng, được tìm thấy trong thư mục được cung cấp bởi llvm-config --libdir hoặc thậm chí kiểm tra mục nhập rpath của chuỗi nhị phân công cụ của bạn với readelf -d $(which lli).

Nếu có nhiều bản cài đặt LLVM (ví dụ: một hệ thống mà bạn đã tự biên soạn), bạn có thể phải chơi xung quanh với tùy chọn -Lclang chỉ đạo ld để thêm đường dẫn đó vào danh sách tìm kiếm. Một thay thế nhanh chóng (mà tôi sẽ không khuyên bạn nên sử dụng thường xuyên) là để làm điều này trên dòng lệnh:

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