Czy pliki binarne są przenośne w różnych architekturach procesorów?

16

Moim celem jest możliwość programowania dla wbudowanego systemu Linux. Mam doświadczenie w systemach wbudowanych typu bare-metal korzystających z ARM.

Mam kilka ogólnych pytań na temat programowania dla różnych celów procesora. Moje pytania są następujące:

  1. Jeśli mam aplikację skompilowaną do działania na systemie docelowym x86, linux OS w wersji xyz , czy mogę po prostu uruchomić ten sam skompilowany plik binarny w innym systemie „ docelowym ARM, linux OS w wersji xyz ”?

  2. Jeśli powyższe nie jest prawdą, jedynym sposobem jest uzyskanie kodu źródłowego aplikacji do przebudowania / ponownej kompilacji za pomocą odpowiedniego zestawu narzędzi „na przykład arm-linux-gnueabi”?

  3. Podobnie, jeśli mam ładowalny moduł jądra (sterownik urządzenia), który działa na systemie docelowym x86, Linux x OS w wersji xyz , czy mogę po prostu załadować / użyć tego samego skompilowanego pliku .ko w innym systemie docelowym ARM, Linux OS w wersji xyz ? ?

  4. Jeśli powyższe nie jest prawdą, jedynym sposobem jest uzyskanie kodu źródłowego sterownika w celu przebudowania / ponownej kompilacji za pomocą odpowiedniego zestawu narzędzi „na przykład arm-linux-gnueabi”?

foob
źródło
27
nie, tak, nie, tak.
hobbs
7
Pomaga uświadomić sobie, że nie mamy celu AMD i Intel, tylko jeden cel x86 dla obu. Jest tak, ponieważ Intel i AMD są wystarczająco kompatybilne. Wtedy staje się oczywiste, że cel ARM istnieje z konkretnego powodu, a mianowicie dlatego, że procesory ARM nie są kompatybilne z Intel / AMD / x86.
MSalters
1
Nie, chyba że jest to kod bajtowy przeznaczony do działania w przenośnym środowisku wykonawczym, takim jak Java Runtime. Jeśli piszesz kod do wbudowania, kod prawdopodobnie będzie polegał na niskopoziomowych optymalizacjach lub funkcjach specyficznych dla procesora i będzie bardzo trudny do przeniesienia, wymagając więcej niż tylko kompilacji dla platformy docelowej (np. Zmiany kodu asemblera, możliwe przepisanie kilka modułów lub cały program).
bwDraco
1
@MSalters: W rzeczywistości mamy cel AMD: amd64, który często jest oznaczony jako x86-64 (podczas gdy x86 to zwykle ponowne oznaczenie i386). Na szczęście Intel skopiował (a później rozszerzył) architekturę AMD, aby każdy 64-bitowy procesor x86 mógł uruchomić pliki binarne amd64.
slebetman

Odpowiedzi:

42

Nie. Pliki binarne muszą być (ponownie) skompilowane dla architektury docelowej, a Linux nie oferuje niczego takiego jak duże pliki binarne po wyjęciu z pudełka. Powodem jest to, że kod jest kompilowany do kodu maszynowego dla konkretnej architektury, a kod maszynowy jest bardzo różny w większości rodzin procesorów (na przykład ARM i x86 są bardzo różne).

EDYCJA: warto zauważyć, że niektóre architektury oferują poziomy kompatybilności wstecznej (a jeszcze rzadziej kompatybilności z innymi architekturami); w 64-bitowych procesorach powszechna jest kompatybilność wsteczna z wersjami 32-bitowymi (ale pamiętaj: biblioteki zależne również muszą być 32-bitowe, w tym biblioteka standardowa C, chyba że łączysz się statycznie ). Warto również wspomnieć o Itanium , gdzie można było uruchomić kod x86 (tylko 32-bit), choć bardzo wolno; niska prędkość wykonania kodu x86 była przynajmniej jednym z powodów, dla których nie odniósł on zbyt dużego sukcesu na rynku.

Pamiętaj, że nadal nie możesz używać plików binarnych skompilowanych z nowszymi instrukcjami na starszych procesorach, nawet w trybach zgodności (na przykład nie możesz używać AVX w 32-bitowym pliku binarnym na procesorach Nehalem x86 ; procesor po prostu go nie obsługuje.

Zauważ, że moduły jądra muszą zostać skompilowane dla odpowiedniej architektury; ponadto 32-bitowe moduły jądra nie będą działać na 64-bitowych jądrach i odwrotnie.

Aby uzyskać informacje na temat plików binarnych kompilujących się między sobą (abyś nie musiał mieć łańcucha narzędzi na docelowym urządzeniu ARM), zobacz wyczerpującą odpowiedź grochmal poniżej.

Elizafox
źródło
1
Warto wyjaśnić każdą kompatybilność (lub jej brak) między wersjami x86 i x64, biorąc pod uwagę, że niektóre pliki binarne x86 mogą działać na platformach x64. (Nie jestem pewien, czy tak jest w przypadku Linuksa, ale na przykład w systemie Windows.)
jpmc26
4
@ jpmc26 jest to możliwe w systemie Linux; ale może być konieczne najpierw zainstalowanie bibliotek zgodności. Obsługa x86 jest nie opcjonalną częścią instalacji Win64. W Linuksie jest opcjonalny; a ponieważ świat Linuksa jest znacznie dalej w tworzeniu 64-bitowych wersji wszystkiego, niektóre dystrybucje domyślnie nie mają zainstalowanych (wszystkich?) bibliotek 32-bitowych. (Nie jestem pewien, jak często to się zdarza; widziałem jednak kilka pytań na ten temat od osób prowadzących mainstreamowe dystrybucje.)
Dan jest Fiddling przez Firelight
@ jpmc26 Zaktualizowałem moją odpowiedź twoimi notatkami; Zastanawiałem się, czy o tym nie wspomnieć, ale nie chciałem komplikować odpowiedzi.
Elizafox,
16

Elizabeth Myers ma rację, każda architektura wymaga skompilowanego pliku binarnego dla danej architektury. Aby zbudować pliki binarne dla innej architektury niż system działa, potrzebujesz cross-compiler.


W większości przypadków musisz skompilować kompilator krzyżowy. Mam tylko doświadczenie z gcc(ale wierzę, że llvmi inne kompilatory mają podobne parametry). gccCross-kompilator uzyskuje się przez dodanie --targetdo skonfigurowania:

./configure --build=i686-arch-linux-gnu --target=arm-none-linux-gnueabi

Trzeba kompilować gcc, glibca binutilsz tych parametrów (i zapewniają nagłówki jądra jądra na komputerze docelowym).

W praktyce jest to znacznie bardziej skomplikowane i różne błędy kompilacji pojawiają się w różnych systemach.

Istnieje kilka przewodników na temat kompilowania zestawu narzędzi GNU, ale zalecę Linux From Scratch , który jest stale utrzymywany i wykonuje bardzo dobrą robotę wyjaśniając, co robią przedstawione polecenia.

Inną opcją jest kompilacja rozruchowa kompilatora krzyżowego. Dzięki walce o kompilację kompilatorów krzyżowych do różnych architektur na różnych architekturach crosstool-ng. Daje bootstrap nad łańcuchem narzędzi potrzebnym do zbudowania kompilatora krzyżowego.

crosstool-ngobsługuje kilka docelowych trojetów na różnych architekturach, w zasadzie jest to bootstrap, w którym ludzie poświęcają swój czas na rozwiązywanie problemów pojawiających się podczas kompilacji łańcucha narzędzi międzykompilatorowych.


Kilka dystrybucji udostępnia kompilatory krzyżowe jako pakiety:

Innymi słowy, sprawdź, co Twoja dystrybucja jest dostępna pod względem kompilatorów krzyżowych. Jeśli twoja dystrybucja nie ma kompilatora krzyżowego dla twoich potrzeb, zawsze możesz go skompilować samodzielnie.

Bibliografia:


Uwaga dotycząca modułów jądra

Jeśli kompilujesz cross-kompilator ręcznie, masz wszystko, czego potrzebujesz do kompilacji modułów jądra. Wynika to z faktu, że do skompilowania potrzebujesz nagłówków jądra glibc.

Ale jeśli używasz kompilatora krzyżowego dostarczonego przez twoją dystrybucję, będziesz potrzebować nagłówków jądra jądra, które działa na maszynie docelowej.

grochmal
źródło
FWIW Fedora obejmuje również kompilatory międzykompilatorowe.
mattdm
@mattdm - dzięki, odpowiedź poprawiona, myślę, że mam link do odpowiedniej strony wiki fedora.
grochmal
2
Łatwiejszym sposobem niż Linux From Scratch na uzyskanie Linuksa i zestawu narzędzi dla innej architektury jest crosstool-ng. Możesz dodać to do listy. Również ręczne konfigurowanie i kompilowanie krzyżowego łańcucha narzędzi GNU dla dowolnej architektury jest niezwykle zaangażowane i znacznie bardziej nużące niż same --targetflagi. Podejrzewam, że właśnie dlatego LLVM zyskuje na popularności; Jest zaprojektowany w taki sposób, że nie potrzebujesz przebudowy, aby celować w inną architekturę - zamiast tego możesz celować w wiele backendów przy użyciu tych samych bibliotek frontendu i bibliotek optymalizacyjnych.
Iwillnotexist Idonotexist
@IwillnotexistIdonotexist - dzięki, poprawiłem odpowiedź dalej. Nigdy wcześniej nie słyszałem o crosstool-ng i wygląda to bardzo przydatnie. Twój komentarz był dla mnie bardzo przydatny.
grochmal
9

Należy zauważyć, że w ostateczności (czyli gdy nie masz kodu źródłowego), można uruchomić pliki binarne na innej architekturze użyciu emulatorów jak qemu, dosboxlub exagear. Niektóre emulatory są przeznaczone do emulacji systemów innych niż Linux (np. Są przeznaczone do dosboxuruchamiania programów MS-DOS, a istnieje wiele emulatorów dla popularnych konsol do gier). Emulacja ma znaczny narzut wydajnościowy: emulowane programy działają 2-10 razy wolniej niż ich natywne odpowiedniki.

Jeśli musisz uruchomić moduły jądra na nienatywnym procesorze, będziesz musiał emulować cały system operacyjny, w tym jądro dla tej samej architektury. AFAIK nie można uruchomić obcego kodu w jądrze Linux.

Dmitrij Grigoriew
źródło
3
Kara za emulację jest często nawet wyższa niż 10x, ale jeśli ktoś próbuje uruchomić kod napisany dla maszyny 16MHz na maszynie 4GHz (różnica prędkości 250: 1), emulator, który ma karę prędkości 50: 1, może nadal uruchamiać kod znacznie szybciej niż na oryginalnej platformie.
supercat
7

Pliki binarne nie tylko nie są przenośne między x86 a ARM, istnieją również różne warianty ARM .

W praktyce możesz napotkać ARMv6 vs ARMv7. Raspberry Pi 1 to ARMv6, późniejsze wersje to ARMv7. Możliwe jest więc skompilowanie kodu na późniejszych, które nie działają na Pi 1.

Na szczęście jedną z zalet otwartego oprogramowania i wolnego oprogramowania jest posiadanie tego źródła, dzięki czemu można go odbudować na dowolnej architekturze. Chociaż może to wymagać trochę pracy.

(Wersje ARM są mylące, ale jeśli przed liczbą jest V, to mówi o architekturze zestawu instrukcji (ISA). Jeśli nie, to jest to numer modelu taki jak „Cortex M0” lub „ARM926EJS”. Numery modeli nie mają nic do zrobić z numerami ISA.)

pjc50
źródło
2
... a potem są nawet różne podmianki dla tego samego smaku ARM, a nawet różne ABI dla dokładnie tego samego sprzętu (myślę o całym bałaganie soft / softfp / hard zmiennoprzecinkowym ARM).
Matteo Italia
1
@MatteoItalia Ugh. Liczne ABI były snafu, lekarstwem na coś gorszego niż choroba. Niektóre ARM nie miały w ogóle rejestrów VFP lub NEON, niektóre miały 16, niektóre 32. Na Cortex-A8 i wcześniej silnik NEON pracował z tuzinem CC za resztą rdzenia, więc przeniesienie wyjścia wektorowego do GPR kosztowało los. ARM zajął się robieniem właściwych rzeczy - nakazując duży wspólny podzbiór funkcji.
Iwillnotexist Idonotexist 27.07.16
7

Zawsze musisz celować w platformę. W najprostszym przypadku docelowy procesor bezpośrednio uruchamia kod skompilowany w pliku binarnym (odpowiada to w przybliżeniu wykonywalnym plikom COM systemu MS DOS). Rozważmy dwie różne platformy, które właśnie wymyśliłem - Armistice i Intellio. W obu przypadkach będziemy mieli prosty program hello world, który wyświetla 42 na ekranie. Zakładam również, że używasz języka wieloplatformowego w sposób niezależny od platformy, więc kod źródłowy jest taki sam dla obu:

Print(42)

W Armistice masz prosty sterownik urządzenia, który zajmuje się drukowaniem liczb, więc wszystko, co musisz zrobić, to wyprowadzić dane do portu. W naszym przenośnym asemblerze odpowiada to mniej więcej tak:

out 1234h, 42

Jednak system Intellio nie ma czegoś takiego, więc musi przejść przez inne warstwy:

mov a, 10h
mov c, 42
int 13h

Ups, mamy już znaczącą różnicę między nimi, zanim jeszcze przejdziemy do kodu maszynowego! Odpowiadałoby to w przybliżeniu różnicy między Linuksem a MS DOS lub komputerem IBM i X-Boxem (nawet jeśli oba mogą korzystać z tego samego procesora).

Ale po to są systemy operacyjne. Załóżmy, że mamy warstwę HAL, która zapewnia, że ​​wszystkie różne konfiguracje sprzętu są obsługiwane w ten sam sposób na warstwie aplikacji - w zasadzie użyjemy podejścia Intellio nawet w zawieszeniu broni, a nasz kod „przenośnego zestawu” kończy się tak samo. Jest to wykorzystywane zarówno przez nowoczesne systemy uniksopodobne, jak i Windows, często nawet w scenariuszach osadzonych. Dobrze - teraz możemy mieć ten sam, naprawdę przenośny kod asemblacyjny zarówno w zawieszeniu broni, jak i Intellio. Ale co z plikami binarnymi?

Jak zakładaliśmy, procesor musi bezpośrednio wykonać plik binarny. Spójrzmy na pierwszą linię naszego kodu mov a, 10h, na Intellio:

20 10

O. Okazuje się, że mov a, constantjest tak popularny, że ma własną instrukcję, własny kod operacji. Jak radzi sobie z tym zawieszenie broni?

36 01 00 10

Hmm Istnieje kod operacji mov.reg.imm, więc potrzebujemy innego argumentu, aby wybrać rejestr, do którego przypisujemy. Stała jest zawsze 2-bajtowym słowem, w zapisie big-endian - tak właśnie zaprojektowano zawieszenie broni, w rzeczywistości wszystkie instrukcje w zawieszeniu mają długość 4 bajtów, bez wyjątków.

Teraz wyobraź sobie uruchamianie pliku binarnego z Intellio na Armistice: CPU rozpoczyna dekodowanie instrukcji, znajduje opcode 20h. W przypadku zawieszenia broni odpowiada to, powiedzmy, and.imm.reginstrukcji. Próbuje odczytać 2-bajtową stałą słowa (która odczytuje 10XX, już problem), a następnie numer rejestru (inny XX). Wykonujemy niewłaściwą instrukcję z niewłaściwymi argumentami. Co gorsza, następna instrukcja będzie kompletnie nieprawdziwa, ponieważ w rzeczywistości zjedliśmy inną instrukcję, myśląc, że to dane.

Aplikacja nie ma szans na działanie i najprawdopodobniej zawiesi się lub zawiesi niemal natychmiast.

To nie znaczy, że plik wykonywalny zawsze musi powiedzieć, że działa na Intellio lub zawieszeniu broni. Musisz tylko zdefiniować platformę niezależną od procesora (jak bashw systemie Unix) lub zarówno procesora, jak i systemu operacyjnego (np. Java lub .NET, a obecnie nawet JavaScript). W takim przypadku aplikacja może korzystać z jednego pliku wykonywalnego dla wszystkich różnych procesorów i systemów operacyjnych, podczas gdy w systemie docelowym jest aplikacja lub usługa (która bezpośrednio celuje na właściwy procesor i / lub system operacyjny), która tłumaczy kod niezależny od platformy na coś Procesor może się faktycznie wykonać. To może, ale nie musi, mieć wpływ na wydajność, koszty lub możliwości.

Procesory zwykle pochodzą z rodzin. Na przykład wszystkie procesory z rodziny x86 mają wspólny zestaw instrukcji, które są kodowane dokładnie w ten sam sposób, więc każdy procesor x86 może uruchomić każdy program x86, o ile nie próbuje używać żadnych rozszerzeń (na przykład operacje zmiennoprzecinkowe lub operacje wektorowe). Oczywiście na x86 najczęstszymi przykładami są Intel i AMD. Atmel jest znaną firmą projektującą procesory z rodziny ARM, dość popularną na urządzeniach wbudowanych. Apple ma również na przykład własne procesory ARM.

Ale ARM jest całkowicie niezgodny z x86 - mają one bardzo różne wymagania projektowe i mają bardzo mało wspólnego. Instrukcje mają zupełnie inne kody, są dekodowane w inny sposób, adresy pamięci są traktowane inaczej ... Może być możliwe utworzenie pliku binarnego działającego zarówno na procesorze x86, jak i na procesorze ARM, przy użyciu pewnych bezpiecznych operacji rozróżnij te dwa elementy i przejdź do dwóch zupełnie różnych zestawów instrukcji, ale nadal oznacza to, że masz osobne instrukcje dla obu wersji, a tylko bootstrapper, który wybiera właściwy zestaw w czasie wykonywania.

Luaan
źródło
3

Można ponownie rzucić to pytanie w środowisko, które może być bardziej znane. Przez analogię:

„Mam program Ruby, który chcę uruchomić, ale moja platforma ma tylko interpreter Pythona. Czy mogę użyć interpretera Python do uruchomienia mojego programu Ruby, czy też muszę przepisać mój program w Pythonie?”

Architektura zestawu instrukcji („cel”) to język - „język maszynowy” - a różne procesory implementują różne języki. Zatem poproszenie procesora ARM o uruchomienie pliku binarnego Intela jest bardzo podobne do próby uruchomienia programu Ruby przy użyciu interpretera Pythona.

Jander
źródło
2

gcc używa terminów „architektura” w znaczeniu „zestawu instrukcji” konkretnego procesora, a „cel” obejmuje kombinację procesora i architektury, a także inne zmienne, takie jak ABI, libc, endian-ness i więcej (ewentualnie włączając „goły metal”). Typowy kompilator ma ograniczony zestaw kombinacji docelowych (prawdopodobnie jeden ABI, jedna rodzina procesorów, ale prawdopodobnie zarówno 32-, jak i 64-bitowy). Kompilator krzyżowy zwykle oznacza albo kompilator z celem innym niż system, na którym działa, albo taki z wieloma celami lub ABI (patrz także to ).

Czy pliki binarne są przenośne w różnych architekturach procesorów?

Ogólnie nie. Plik binarny w tradycyjnym ujęciu jest rodzimym kodem obiektowym dla konkretnego procesora lub rodziny procesorów. Ale istnieje kilka przypadków, w których mogą one być średnio do bardzo przenośnych:

  • jedna architektura jest nadzbiorem innej (zwykle pliki binarne x86 są skierowane na i386 lub i686, a nie najnowsze i najlepsze x86, np. -march=core2)
  • jedna architektura zapewnia natywną emulację lub tłumaczenie innej (być może słyszałeś o Crusoe ) lub zapewnia kompatybilne koprocesory (np. PS2 )
  • system operacyjny i środowisko wykonawcze obsługują wiele ścieżek (np. możliwość uruchamiania 32-bitowych plików binarnych x86 na x86_64) lub płynną pracę VM / JIT (Android przy użyciu Dalvik lub ART )
  • istnieje obsługa „grubych” plików binarnych, które zasadniczo zawierają zduplikowany kod dla każdej obsługiwanej architektury

Jeśli uda ci się jakoś rozwiązać ten problem, pojawi się inny przenośny problem binarny niezliczonych wersji bibliotek (glibc patrzę na ciebie). (Większość systemów wbudowanych oszczędza przynajmniej od tego konkretnego problemu).

Jeśli jeszcze tego nie zrobiłeś, teraz jest dobry moment, aby biegać gcc -dumpspecsi gcc --target-helpzobaczyć, co masz przeciwko.

Pliki binarne tłuszczu mają różne wady , ale wciąż mają potencjalne zastosowania ( EFI ).

Istnieją dwie dalsze kwestie, których brakuje w pozostałych odpowiedziach: ELF i interpreter ELF oraz obsługa jądra Linux dla dowolnych formatów binarnych . Nie będę tutaj wchodził w szczegóły na temat plików binarnych lub kodu bajtowego dla nierealnych procesorów, chociaż można traktować je jako „natywne” i wykonywać pliki binarne kodu bajtowego Pythona w Javie lub skompilowanym , takie pliki binarne są niezależne od architektury sprzętowej (ale zależą w odpowiedniej wersji maszyny wirtualnej, która ostatecznie uruchamia natywny plik binarny).

Każdy współczesny system Linux będzie używał plików binarnych ELF (szczegóły techniczne w tym pliku PDF ), w przypadku dynamicznych plików binarnych ELF jądro jest odpowiedzialne za ładowanie obrazu do pamięci, ale jest to zadanie „interpretera” ustawionego w ELF nagłówki do ciężkiego podnoszenia. Zwykle wymaga to upewnienia się, że wszystkie zależne biblioteki dynamiczne są dostępne (za pomocą sekcji „Dynamiczna”, która zawiera listę bibliotek i niektórych innych struktur, które zawierają wymagane symbole) - ale jest to warstwa pośrednia o prawie ogólnym przeznaczeniu.

$ file /bin/ls
/bin/ls: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses \
shared libs), stripped
$ readelf -p .interp /bin/ls
    String dump of section '.interp':
      [     0]  /lib/ld-linux.so.2

( /lib/ld-linux.so.2jest również plikiem binarnym ELF, nie ma interpretera i jest rodzimym kodem binarnym).

Problem z ELF polega na tym, że nagłówek w pliku binarnym ( readelf -h /bin/ls) oznacza go dla konkretnej architektury, klasy (32- lub 64-bitowej), endianowości i ABI („uniwersalne” binarne pliki tłuszczu Apple używają alternatywnego formatu binarnego Mach-O zamiast tego, który rozwiązuje ten problem, pochodzi z NextSTEP). Oznacza to, że plik wykonywalny ELF musi pasować do systemu, w którym ma być uruchomiony. Jednym z nich jest interpreter, może to być dowolny plik wykonywalny (w tym taki, który wyodrębnia lub odwzorowuje specyficzne dla architektury podsekcje oryginalnie binarnego i je wywołuje), ale nadal jesteś ograniczony typami ELF, które twój system pozwoli na uruchomienie . (FreeBSD ma interesujący sposób obsługi plików ELF systemu Linux , brandelfmodyfikuje pole ELF ABI.)

Istnieje (przy użyciu binfmt_misc) wsparcie dla Mach-O na Linuksie , jest tam przykład, który pokazuje, jak utworzyć i uruchomić gruby (32- i 64-bitowy) plik binarny. Widelce zasobów / ADS , jak pierwotnie zrobiono na Macu, mogą być obejściem, ale żaden natywny system plików Linux nie obsługuje tego.

Mniej więcej to samo dotyczy modułów jądra, .kopliki są również ELF (chociaż nie mają ustawionego interpretera). W tym przypadku jest dodatkowa warstwa, która używa wersji jądra ( uname -r) na ścieżce wyszukiwania, co można teoretycznie zrobić zamiast tego w ELF z wersjonowaniem, ale podejrzewam, że przy pewnym stopniu złożoności i niewielkim zysku.

Jak wspomniano w innym miejscu, Linux nie obsługuje natywnie plików binarnych typu fat, ale istnieje aktywny projekt binarny typu fat-fat: FatELF . Istnieje od lat , nigdy nie był zintegrowany ze standardowym jądrem, częściowo z powodu (wygasłych) obaw patentowych. W tej chwili wymaga to zarówno obsługi jądra, jak i zestawu narzędzi. Nie stosuje tego binfmt_miscpodejścia, ponieważ omija problemy z nagłówkiem ELF i pozwala również na moduły grubego jądra.

  1. Jeśli mam aplikację skompilowaną do działania na systemie docelowym x86, Linux xyz w wersji xyz, czy mogę po prostu uruchomić ten sam skompilowany plik binarny w innym systemie „docelowym ARM, Linux xyz”?

Nie z ELF, nie pozwoli ci to zrobić.

  1. Jeśli powyższe nie jest prawdą, jedynym sposobem jest uzyskanie kodu źródłowego aplikacji do przebudowania / ponownej kompilacji za pomocą odpowiedniego zestawu narzędzi „na przykład arm-linux-gnueabi”?

Prostą odpowiedzią jest tak. (Skomplikowane odpowiedzi obejmują emulację, reprezentacje pośrednie, translatory i JIT; z wyjątkiem przypadku „obniżenia” wersji binarnej i686 do używania tylko kodów i386, prawdopodobnie nie są one tutaj interesujące, a poprawki ABI są potencjalnie tak trudne jak tłumaczenie kodu natywnego. )

  1. Podobnie, jeśli mam ładowalny moduł jądra (sterownik urządzenia), który działa na systemie docelowym x86, Linux x OS w wersji xyz, czy mogę po prostu załadować / użyć tego samego skompilowanego pliku .ko w innym systemie docelowym ARM, Linux OS w wersji xyz? ?

Nie, ELF nie pozwoli ci tego zrobić.

  1. Jeśli powyższe nie jest prawdą, jedynym sposobem jest uzyskanie kodu źródłowego sterownika w celu przebudowania / ponownej kompilacji za pomocą odpowiedniego zestawu narzędzi „na przykład arm-linux-gnueabi”?

Prostą odpowiedzią jest tak. Wierzę, że FatELF pozwala ci zbudować .kowielowątkową architekturę, ale w pewnym momencie trzeba utworzyć wersję binarną dla każdej obsługiwanej architektury. Rzeczy wymagające modułów jądra często pochodzą ze źródła i są budowane zgodnie z wymaganiami, np. Robi to VirtualBox.

To już długa, kłótliwa odpowiedź, jest tylko jeden objazd. Jądro ma już wbudowaną maszynę wirtualną, choć dedykowaną: maszynę wirtualną BPF, która służy do dopasowywania pakietów. Czytelny dla człowieka filtr „host foo, a nie port 22”) jest kompilowany do kodu bajtowego i filtr pakietów jądra go wykonuje . Nowy eBPF jest nie tylko dla pakietów, teoretycznie, że kod VM jest przenośny w dowolnym współczesnym Linuksie i lvvm obsługuje go, ale ze względów bezpieczeństwa prawdopodobnie nie będzie on odpowiedni do niczego innego niż reguły administracyjne.


Teraz, w zależności od tego, jak hojna jesteś z definicją binarnego pliku wykonywalnego, możesz (ab) użyć binfmt_miscdo implementacji obsługi grubego binarnego skryptu powłoki i plików ZIP jako formatu kontenera:

#!/bin/bash

name=$1
prog=${1/*\//}      # basename
prog=${prog/.woz/}  # remove extension
root=/mnt/tmpfs
root=$(TMPDIR= mktemp -d -p ${root} woz.XXXXXX)
shift               # drop argv[0], keep other args

arch=$(uname -m)                  # i686
uname_s=$(uname -s)               # Linux
glibc=$(getconf GNU_LIBC_VERSION) # glibc 2.17
glibc=${glibc// /-}               # s/ /-/g

# test that "foo.woz" can unzip, and test "foo" is executable
unzip -tqq "$1" && {
  unzip -q -o -j -d ${root} "$1"  "${arch}/${uname_s}/${glibc}/*" 
  test -x ${root}/$prog && ( 
    export LD_LIBRARY_PATH="${root}:${LD_LIBRARY_PATH}"
    #readlink -f "${root}/${prog}"   # for the curious
    exec -a "${name}" "${root}/${prog}" "$@" 
  )
  rc=$?
  #rm -rf -- "${root}/${prog}"       # for the brave
  exit $rc
}

Nazwij to „wozbin” i skonfiguruj go za pomocą czegoś takiego:

mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
printf ":%s:%s:%s:%s:%s:%s:%s" \
  "woz" "E" "" "woz" "" "/path/to/wozbin" ""  > /proc/sys/fs/binfmt_misc/register

Rejestruje .wozpliki w jądrze, wozbinzamiast tego wywoływany jest skrypt z pierwszym argumentem ustawionym na ścieżkę wywoływanego .wozpliku.

Aby uzyskać przenośny (gruby) .woz plik, po prostu utwórz test.wozplik ZIP z hierarchią katalogów, aby:

i686/ 
    \- Linux/
            \- glibc-2.12/
armv6l/
    \- Linux/
            \- glibc-2.17/

W każdym katalogu arch / OS / libc (dowolny wybór) umieść specyficzne dla architektury pliki testbinarne i komponenty, takie jak .sopliki. Po wywołaniu wymagany podkatalog jest rozpakowywany do systemu plików w pamięci tmpfs ( /mnt/tmpfstutaj) i wywoływany.

pan. spuratic
źródło
0

boot jagód, rozwiąż niektóre z twoich problemów .. ale to nie rozwiązuje problemu jak uruchomić na arm hf, normall / regullAr linux distro dla x86-32 / 64bit.

Myślę, że powinien on być wbudowany w isolinux (linux loaderloader na USB) w jakiś konwerter na żywo, który mógłby rozpoznać regullar distro oraz w ride / live konwersję do hf.

Dlaczego? Ponieważ jeśli każdy linux może zostać przekonwertowany przez bootowanie jagód do pracy na Arm-HF, może być w stanie wbudować mechanizm rozruchowy Bery, aby wyodrębnić to, co uruchamiamy za pomocą exache Eacher lub wbudowanego dysku startowego kreacji Ubuntu.

fdf
źródło