2016-09-28 37 views
7

Mam skompilowany program Rust dla armv7-unknown-linux-gnueabihf, i chcę go uruchomić w systemie, który ma zainstalowany glibc 2.16. Niestety po uruchomieniu go otrzymuję ten błąd:Jak mogę skompilować program Rust, aby nie używać __cxa_thread_atexit_impl?

./foo: /lib/libc.so.6: version `GLIBC_2.18' not found (required by ./foo) 

Running objdump -T foo ujawnia, że ​​tylko symbol potrzebny od glibc 2.18 brzmi:

00000000 w DF *UND* 00000000 GLIBC_2.18 __cxa_thread_atexit_impl 

Rust makes __cxa_thread_atexit_impl a weak symbol (z punktu widzenia małego w flagą z objdump), jednak GCC jest najwyraźniej głupi i pomimo tego, że wszystkie znaki z GLIBC_2.18 są słabe, wciąż powoduje, że GLIBC_2.18 jest silnym wymaganiem. Widać, że z readelf:

$ readelf -V foo 
... 
Version needs section '.gnu.version_r' contains 5 entries: 
Addr: 0x0000000000001e4c Offset: 0x001e4c Link: 6 (.dynstr) 
    000000: Version: 1 File: ld-linux-armhf.so.3 Cnt: 1 
    0x0010: Name: GLIBC_2.4 Flags: none Version: 9 
    0x0020: Version: 1 File: librt.so.1 Cnt: 1 
    0x0030: Name: GLIBC_2.4 Flags: none Version: 5 
    0x0040: Version: 1 File: libgcc_s.so.1 Cnt: 4 
    0x0050: Name: GCC_4.3.0 Flags: none Version: 10 
    0x0060: Name: GCC_3.0 Flags: none Version: 7 
    0x0070: Name: GCC_3.5 Flags: none Version: 6 
    0x0080: Name: GCC_3.3.1 Flags: none Version: 4 
    0x0090: Version: 1 File: libc.so.6 Cnt: 2 
    0x00a0: Name: GLIBC_2.18 Flags: none Version: 8 
    0x00b0: Name: GLIBC_2.4 Flags: none Version: 3 
    0x00c0: Version: 1 File: libpthread.so.0 Cnt: 1 
    0x00d0: Name: GLIBC_2.4 Flags: none Version: 2 

Uwaga, GLIBC_2.18 mówi Flags: none. Należy powiedzieć: Flags: WEAK. Na szczęście znalazłem an amazing page where someone shows how to fix this. Niestety wymaga on edycji kodu binarnego !

Take przesunięcie tego .gnu.version_r tabeli (0x001e4c), dodać wpis offsetu dla GLIBC_2.18 (0x00a0), następnie dodać offset dla pola flagami struct pod tym adresem (0x04). To daje 0x001EF0. Pod tym adresem powinny znajdować się dwa zero bajtów: 0x0000. Zmień je na 0x0200.

Sprawdź u readelf:

Version needs section '.gnu.version_r' contains 5 entries: 
Addr: 0x0000000000001e4c Offset: 0x001e4c Link: 6 (.dynstr) 
    000000: Version: 1 File: ld-linux-armhf.so.3 Cnt: 1 
    0x0010: Name: GLIBC_2.4 Flags: none Version: 9 
    0x0020: Version: 1 File: librt.so.1 Cnt: 1 
    0x0030: Name: GLIBC_2.4 Flags: none Version: 5 
    0x0040: Version: 1 File: libgcc_s.so.1 Cnt: 4 
    0x0050: Name: GCC_4.3.0 Flags: none Version: 10 
    0x0060: Name: GCC_3.0 Flags: none Version: 7 
    0x0070: Name: GCC_3.5 Flags: none Version: 6 
    0x0080: Name: GCC_3.3.1 Flags: none Version: 4 
    0x0090: Version: 1 File: libc.so.6 Cnt: 2 
    0x00a0: Name: GLIBC_2.18 Flags: WEAK Version: 8 
    0x00b0: Name: GLIBC_2.4 Flags: none Version: 3 
    0x00c0: Version: 1 File: libpthread.so.0 Cnt: 1 
    0x00d0: Name: GLIBC_2.4 Flags: none Version: 2 

Sukces! Oprócz tego, że nadal nie działa:

./foo: /lib/libc.so.6: weak version `GLIBC_2.18' not found (required by ./foo) 
./foo: relocation error: ./foo: symbol __cxa_thread_atexit_impl, version GLIBC_2.18 not defined in file libc.so.6 with link time reference 

Jak jest nadal wymagana wersja słaby ?! Nie mogę się doczekać, aż glibc umrze.

Czy istnieje sposób, aby zmusić Rusta do zbudowania programu bez użycia tego symbolu?

+2

Akceptowanie, gdy rzeczy są straszne, to jedyny sposób [ulegają poprawie] (https://www.musl-libc.org/). Przepraszam, jeśli obraziłem twórców GNU. – Timmmm

+0

Celowo obraziłeś * bardzo * ludzi, którzy mogą odpowiedzieć na twoje pytanie. Wezmę na siebie @tumdum i zasugeruję, że usuniesz przeciwne do zamierzonych części. Jako częściową odpowiedź, istnieją * dobre powody, dla których GLIBC działa tak, jak robi. A jeśli uważasz, że Musl jest odpowiedzią, co dokładnie uniemożliwia ci korzystanie z niej? –

+0

'armv7-unknown-linux-muscl' niestety nie jest jeszcze dostępny jako cel. Również, jeśli * mogę * uzyskać to do pracy glibc 2.4 jest wystarczająco stary (2006), że wymaganie to nie jest nieuzasadnione i oszczędza miejsce w porównaniu do muscl. Jeśli nie ma sposobu, aby wymagać 2.18 (2013), to muscl jest zdecydowanie lepszym rozwiązaniem. – Timmmm

Odpowiedz

0

Potrzebujesz narzędzia Rust Toolchain, które zostało skompilowane dla glibc 2.16 lub wcześniejszego. glibc 2.17 prawdopodobnie działa również dlatego, że brakuje mu __cxa_thread_atexit_impl, więc nie będzie nosił wersji binarnej w postaci symbolu GLIBC_2.18.

Użycie słabego symbolu w kodzie Rusta nie jest szczególnie użyteczne, ponieważ wersja GNU wersji ELF nie ma słabych wersji symboli. Możemy to ostatecznie zmienić, ale teraz najlepszym sposobem na poradzenie sobie z tym jest kompilacja z dostatecznie starym łańcuchem narzędzi.

Inną opcją jest przypisanie symbolu do używanego glibc.To powinno być dość odosobniony backport, prawdopodobnie składający się z tych zatwierdzeń:

(ja nie próbowali się backportu do glibc 2.16, ale o ile takie rzeczy się zdarzają, nie wydaje się to szczególnie trudne.)

+0

Czy są jakieś przemyślenia, które mógłbyś podać dla wykorzystania glib przez toolchain, aby być może zrelaksować korzystanie z __cxa_thread_atexit_impl? Czy funkcja może być używana tylko przez jednoznaczne wywołanie z pakietu narzędziowego, czy też istnieje pośrednia ścieżka, która go pośrednio używa? – Digikata