2017-02-03 37 views
15

Próbowałem zbudować i wykonać moduły LLVM. Mój kod do generowania modułów jest dość długi, więc nie zamieszczę go tutaj. Zamiast tego moje pytanie dotyczy tego, w jaki sposób Clang i LLVM współpracują ze sobą, aby osiągnąć efekt mangerowania. Wyjaśnię moją konkretną kwestię, aby zmotywować to pytanie.Name mangling confusion in LLVM

Oto kod źródłowy jednego z moich modułów LLVM:

#include <iostream> 

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

Here is the generated LLVM IR; jest zbyt duży dla StackOverflow.

Kiedy próbuję wykonać mój moduł używając lli, pojawia się następujący błąd:

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

Running symbolu przez demangler, brakujący symbol:

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

Dodatkowy _ jest podejrzane, a funkcja bez wiodącego podkreślenia wydaje się istnieć w podczerwieni!

; 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 
} 

jestem na MacOS, więc wiodącym podkreślenia należy się spodziewać, ale myślę, że może być dodanie Clang to dwukrotnie.

Przeglądałem źródła LLVM/szczęk, i wydaje się, że istnieją dwa przekręcona etapy:

  1. Biorąc ewentualnie przeciążone funkcji C++ i przekręcona ich unikalne nazwy dla LLVM IR
  2. Oddana zniekształcone nazwa z LLVM IR i dodanie dowolnych specyficznych dla platformy dziwactw, takich jak wiodące podkreślenia:

Jednak to tylko moja teoria. Czy ktoś może wyjaśnić, jak działa proces mieszania w Clang i LLVM? Jak utworzyć obiekty llvm::DataLayout, aby uzyskać poprawne połączenie z moją platformą?


nm -gU /usr/lib/libc++.dylib i nm -gU /usr/lib/libc++abi.dylib nie zawierają __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorI‌​cEEEC1Emc


Kiedy próbuję skompilować IR, otrzymuję ten błąd:

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

Nie sądzę, że jest to nazwa-maglowania problem. Dopóki nie dotykasz nazwisk, powinieneś być w porządku. Jest to raczej problem łączący. lli nie łączy się w żadnej bibliotece, więc symbole STL nie mogą zostać rozwiązane. Jeśli skompilujesz i połączysz moduł, powinieneś być w porządku ... llc test.ll, clang ++ test.s (lub jakikolwiek inny kompilator). Daj mi znać, jeśli to pomoże i dodam ją jako odpowiedź. – Tobias

+0

... czy wygenerowałeś IR z kodem ++ -S -emit-llvm? edytował plik w jakikolwiek sposób? Czy chcesz, aby to działało, czy chcesz wiedzieć, w jaki sposób zamaskowane są nazwy b/c, które chcesz samemu wygenerować zniekształcone imię? – Tobias

+0

@Tobias Wygenerowałem LLVM przy użyciu fabryki 'clang :: CreateLLVMCodeGen' i' HandleTopLevelDecl' – sdgfsdh

Odpowiedz

2

nie będę podejrzewać problem z wymieszaniem nazwy. Wymazywanie nazw C++ ma miejsce w interfejsie użytkownika (tzn. clang) i jest częścią całkiem dobrze zdefiniowanego/udokumentowanego ABI standard.

Ponadto nie sądzę, jest nieprawdziwy podkreślenia, że ​​przyczyna nie produkują poprawną nazwę C++ plecy i zniekształcone nazwisko w linku Pastebin że podałeś pojawia się jako:

_ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1Emc

Nie jestem na Mac OS, ale symuluję z moim LLVM 3.8.1 Linux (stosując --stdlib=libc++), przy zastosowaniu tego samego źródła, a dopasowanie do linii IR po linii pojawia się następujący symbol:

_ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEmc

które demangles powrót do:

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

co, jak sądzę, ma w przybliżeniu taką samą konstrukcję.

Tak wierzę, że twój linker odbiera błędną wersję libc++.

Można sprawdzić symbole dostępne w libc++, który jest związany z brzękiem/LLVM, którego używasz, znajdujący się w katalogu określonym przez llvm-config --libdir lub nawet sprawdzanie wpis rpath twoich plików binarnych toolchain z readelf -d $(which lli).

Jeśli istnieje wiele instalacji LLVM (np system jeden i jeden, który został skompilowany ze źródeł siebie), może trzeba się bawić z opcją -L z clang która kieruje ld dodać tę ścieżkę na liście wyszukiwania. Szybka alternatywa (to nie polecam do regularnego stosowania) jest to zrobić w wierszu poleceń:

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