Hauptmenü öffnen

Vu+ WIKI β

Änderungen

Cross Compiler

8.539 Bytes hinzugefügt, 18:06, 26. Feb. 2023
keine Bearbeitungszusammenfassung
Um Binaries für Mips-Boxen auf unseren ARM-Boxen zu erstellen, müssen alle drei Pakete installiert sein.
Nach dem Download der Pakete auf eine ARM-Box können die drei Pakete mit '''<code>opkg install <Paket.ipk>''' </code> wie jedes andere Paket auch installiert werden. Nach der Installation befinden sich unter '''<code>/usr/bin''' </code> diverse Programme mit dem Präfix '''<code>mipsel-oe-linux-''' </code> und unterhalb von '''<code>/usr/mipsel-oe-linux''' </code> das "Sysroot" mit Include-Dateien und Bibliotheken, um Mipsel-Binaries zu compilieren.
== Benutzung ==
=== Schritt 1: Sourcen besorgen ===
Die Sourcen für grep befinden sich auf dem GNU-FTP-Server unter https://ftp.gnu.org/gnu/grep/ - die momentan aktuelle Version ist grep-3.8. Die Sourcen werden von dort heruntergeladen und irgendwo auf der Festplatte der Box entpackt, z.B. unter /media/hdd/build. Ausgepackt wird in der Konsole (z.B. Putty) mit dem tar-Befehl: '''<code>tar xvf grep-3.8.tar.gz'''</code>
=== Schritt 2: Sourcen konfigurieren ===
Mit '''<code>cd grep-3.8''' </code> wird in den ausgpackten Source-Tree gewechselt. Die meisten der heute benutzten Software-Pakete werden mit einem '''<code>configure''' </code> konfiguriert; dieses schaut, ob alle benötigten Komponenten für ein erfolgreiches übersetzen vorhanden sind, und generiert die Makefiles, um das Programm anschließend zu übersetzen.
Um Makefiles benutzen zu können, benötigt man das '''<code>make'''</code>-Programm. Ein fertig übersetztes Programm befindet sich in der Database beim aktuellen GCC für die ARM-Boxen.
Ein erster Versuch, den Cross-Compiler zu benutzen, ist immer, den Aufruf von '''<code>configure''' </code> mit der '''<code>CC'''</code>-Variablen zu testen; es gibt eine Reihe von Umgebungsvariablen, die man auf diese Weise (nicht nur) an das configure-Script weiterreichen kann. Ein paar weitere sind: CXX (c++-Compiler), CFLAGS (Flags für den C-Compiler), CXXFLAGS (Flags für den C++-Compiler)
'''<code>CC=mipsel-oe-linux-gcc ./configure --prefix=/usr'''</code>
Das funktioniert bei '''<code>grep''' </code> nicht, die Fehlermeldung sagt, dass man den Compiler über den Switch '''<code>--host=mipsel-oe-linux''' </code> angeben soll. Das funktioniert. Also zweiter Versuch:
'''<code>./configure --host=mipsel-oe-linux --prefix=/usr'''</code>
Der Switch '''<code>--prefix=/usr''' </code> sagt der Umgebung, dass das fertig übersetzte Programm später nach '''<code>/usr''' </code> installiert werden soll; das bedeutet, dass das Binary unter '''<code>/usr/bin/grep''' </code> installiert wird. Ohne diesen Switch wird normalerweise '''<code>/usr/local''' </code> als Ziel benutzt, und das Binary findet sich später unter '''<code>/usr/local/bin/grep'''</code>.
=== Schritt 3: Compilieren ===
Als nächstes soll das Programm übersetzt werden; dazu wird '''<code>make''' </code> aufgerufen(ein "make" befindet sich im Paket aus dem Download "git-make.zip" in der [https://vuplus-support.org/wbb4/filebase/index.php?entry/1098-gcc-10-2-0-f%C3%BCr-boxen-mit-arm-prozessor-4k/ Database]):
'''<code>make'''</code>
Meistens dauert der Configure-Schritt genauso lange wie das eigentliche Übersetzen des Programms. Wenn beim Übersetzen keine Fehler passiert sind, kann das Programm installiert werden.
=== Schritt 4: Installation ===
Ich kontrolliere gerne vor dem installieren, was installiert werden soll. Fast alle Makefiles kennen das "Target" "install", viele können auch mit dem Target "install-strip" umgehen, und viele kennen auch eine Möglichkeit, das Programm in einem anderen Verzeichnis zu installieren. In der Regel wird das mit der Variablen '''<code>DESTDIR''' </code> erreicht. Wir führen also aus:
'''<code>make install-strip DESTDIR=/media/hdd/install'''</code>
Das installiert das übersetzte Programm unterhalb von '''<code>/media/hdd/install'''</code>, wo wir noch einmal schauen können, was wir mitnehmen möchten, und was nicht. Zusammengefasst:* <code>make install</code> installiert das fertig übersetzte Programm an seinen Bestimmungs-Ort.* <code>make install-strip</code> strippt Binaries vor der Installation und installiert sie dann an ihren Bestimmungs-Ort.* <code>make install DESTDIR=/media/hdd/install</code> installiert die Binaries in ein anderes Zielverzeichnis <code>/media/hdd/install</code> anstatt in das dafür vorgesehene Verzeichnis. Weitere nützliche Aufrufe von <code>make</code>* <code>make V=1</code> zeigt genauer an, was beim übersetzen wirklich ausgeführt wird; manchmal unterdrücken Makefiles wie das von grep die Ausgabe, wie genau der Compiler aufgerufen wird.* <code>make CC=mipsel-oe-linux-gcc</code> "überschreibt" den Eintrag für den Compiler im Makefile; das funktioniert bei allen Variablen im Makefile, die entsprechend deklariert wurden.
=== Schritt 5: Programm einpacken und testen ===
Der nächste Schritt ist bei mir immer, die Dateien als IPK einzupacken. Wie das gemacht werden kann, soll hier nicht gezeigt werden; dazu habe ich unter [[Paketmanager opkg]] schon einiges geschrieben.
Wir kontrollieren aber noch einmal, dass der Cross-Compiler ein Mipsel-Binary erstellt hat. Dazu wechseln wir in der Konsole mit "cd" nach '''<code>/media/hdd/install/usr/bin'''</code>. Ein '''<code>ls -l''' </code> zeigt hier drei Dateien an, '''<code>egrep'''</code>, '''<code>fgrep''' </code> und '''<code>grep'''</code>. egrep und fgrep sind Shell-Scripten, das eigentliche Binary ist '''<code>grep'''</code>. Wir können uns den Inhalt mit einigen Tools anschauen. Als erstes:
'''<code>file grep'''</code>: Ausgabe sollte sein: '''<code>grep: ELF 32-bit LSB executable, MIPS, MIPS-I version 1 (SYSV), dynamically linked, interpreter /lib/ld.so.1, for GNU/Linux 2.6.32, stripped'''</code>
Schauen wir etwas genauer in das Binary:
'''<code>mipsel-oe-linux-objdump -p grep'''</code>
Hier sehen wir alle interessanten Informationen, zum Beispiel welche Shared-Libraries das Programm in welcher Version auf der Mips-Maschine benötigt.
 
<div class="mw-collapsible mw-collapsed">
Ausgabe von <code>objdump grep</code>: bitte aufklappen.
<div class="mw-collapsible-content">
<pre>
 
grep: file format elf32-tradlittlemips
 
Program Header:
PHDR off 0x00000034 vaddr 0x00400034 paddr 0x00400034 align 2**2
filesz 0x00000140 memsz 0x00000140 flags r--
INTERP off 0x00000174 vaddr 0x00400174 paddr 0x00400174 align 2**0
filesz 0x0000000d memsz 0x0000000d flags r--
0x70000003 off 0x000001a8 vaddr 0x004001a8 paddr 0x004001a8 align 2**3
filesz 0x00000018 memsz 0x00000018 flags r--
0x70000000 off 0x000001c0 vaddr 0x004001c0 paddr 0x004001c0 align 2**2
filesz 0x00000018 memsz 0x00000018 flags r--
LOAD off 0x00000000 vaddr 0x00400000 paddr 0x00400000 align 2**16
filesz 0x00040280 memsz 0x00040280 flags r-x
LOAD off 0x00040280 vaddr 0x00450280 paddr 0x00450280 align 2**16
filesz 0x00000ab8 memsz 0x00011580 flags rw-
DYNAMIC off 0x000001d8 vaddr 0x004001d8 paddr 0x004001d8 align 2**2
filesz 0x00000118 memsz 0x00000118 flags r--
NOTE off 0x00000184 vaddr 0x00400184 paddr 0x00400184 align 2**2
filesz 0x00000020 memsz 0x00000020 flags r--
EH_FRAME off 0x00040240 vaddr 0x00440240 paddr 0x00440240 align 2**2
filesz 0x00000014 memsz 0x00000014 flags r--
NULL off 0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**2
filesz 0x00000000 memsz 0x00000000 flags ---
 
Dynamic Section:
NEEDED libc.so.6
INIT 0x00402cf4
FINI 0x0043ca60
INIT_ARRAY 0x00450280
INIT_ARRAYSZ 0x00000004
FINI_ARRAY 0x00450284
FINI_ARRAYSZ 0x00000004
HASH 0x004002f0
STRTAB 0x00401d6c
SYMTAB 0x00400b8c
STRSZ 0x00000c84
SYMENT 0x00000010
MIPS_RLD_MAP 0x004508b0
MIPS_RLD_MAP_REL 0x00050670
DEBUG 0x00000000
PLTGOT 0x004508c0
REL 0x00402c8c
RELSZ 0x00000068
RELENT 0x00000008
MIPS_RLD_VERSION 0x00000001
MIPS_FLAGS 0x00000002
MIPS_BASE_ADDRESS 0x00400000
MIPS_LOCAL_GOTNO 0x00000097
MIPS_SYMTABNO 0x0000011e
MIPS_UNREFEXTNO 0x00000029
MIPS_GOTSYM 0x00000098
VERNEED 0x00402c2c
VERNEEDNUM 0x00000001
VERSYM 0x004029f0
 
Version References:
required from libc.so.6:
0x0d696914 0x00 06 GLIBC_2.4
0x0d696915 0x00 05 GLIBC_2.5
0x0d696912 0x00 04 GLIBC_2.2
0x0d696910 0x00 03 GLIBC_2.0
0x0d696913 0x00 02 GLIBC_2.3
private flags = 1007: [abi=O32] [mips1] [not 32bitmode] [noreorder] [PIC] [CPIC]
 
MIPS ABI Flags Version: 0
 
ISA: MIPS1
GPR size: 32
CPR1 size: 32
CPR2 size: 0
FP ABI: Hard float (double precision)
ISA Extension: None
ASEs:
None
FLAGS 1: 00000000
FLAGS 2: 00000000
 
</pre>
</div>
</div>
Das Binary kann jetzt auf eine Mips-Box kopiert werden, um endgültig sicherzustellen, dass wir hier keinen Murks produziert haben.
 
== Nützliches zu objdump, ldd und Versionierung von Shared-Libraries ==
=== objdump ===
Das folgende ist eher allgemein gehalten und gilt für alle Architekturen. Damit man im Vorfeld schon weiß, ob die auf der Zielmaschine installierten Shared-Libraries neu genug sind, damit ein Programm läuft, gibt es ein paar Hilfsmittel. Eines haben wir vorhin schon kennen gelernt: <code>objdump</code>. Der interessante Teil befindet sich im Abschnitt "Version References:".
 
<pre>
Version References:
required from libc.so.6:
0x0d696914 0x00 06 GLIBC_2.4
0x0d696915 0x00 05 GLIBC_2.5
0x0d696912 0x00 04 GLIBC_2.2
0x0d696910 0x00 03 GLIBC_2.0
0x0d696913 0x00 02 GLIBC_2.3
</pre>
 
Hier erfahren wir, dass das Binary gegen eine Sharded-Library <code>libc.so.6</code> gelinkt wurde. Um nicht bei jedem Update der Libc die Versionsnummer "6" erhöhen zu müssen, werden neue Features oder geänderte Aufrufe in der Library selber versioniert. Hier sieht man, dass Features der GLIBC_2.0 bis GLIBC_2.5 benötigt werden. Ein wenig Recherche bringt zutage, dass diese Versionsnummern auch wirklich mit den Versionen der glibc übereinstimmen. Die auf unseren Boxen vorinstallierte glibc liegt in der Version 2.21 vor und benutzt deshalb für die neuen ab dieser Version integrierten Features die interne Version GLIBC_2.21. Aktuell ist übrigens die glibc-2.37. Da die glibc zweimal jährlich aktualisiert wird, liegen hier 8 Jahre (fehlende) Entwicklung dazwischen.
 
=== ldd ===
Ein anderes sehr nützliches Tool ist <code>ldd</code>. Ohne weitere Parameter werden hier einfach die benötigten Shared-Libraries angezeigt:
<pre>
root@vusolo4k:~# ldd /usr/bin/grep
libpcre.so.1 => /usr/lib/libpcre.so.1 (0xb6f20000)
libc.so.6 => /lib/libc.so.6 (0xb6db8000)
/lib/ld-linux-armhf.so.3 (0xb6f64000)
</pre>
 
Sehr nützlich ist der Aufruf mit Parameter "-v":
<pre>
root@vusolo4k:~# ldd -v /usr/bin/grep
libpcre.so.1 => /usr/lib/libpcre.so.1 (0xb6ec0000)
libc.so.6 => /lib/libc.so.6 (0xb6d58000)
/lib/ld-linux-armhf.so.3 (0xb6eff000)
 
Version information:
/usr/bin/grep:
libc.so.6 (GLIBC_2.26) => /lib/libc.so.6
libc.so.6 (GLIBC_2.5) => /lib/libc.so.6
libc.so.6 (GLIBC_2.34) => /lib/libc.so.6
libc.so.6 (GLIBC_2.4) => /lib/libc.so.6
/usr/lib/libpcre.so.1:
libc.so.6 (GLIBC_2.4) => /lib/libc.so.6
/lib/libc.so.6:
ld-linux-armhf.so.3 (GLIBC_2.4) => /lib/ld-linux-armhf.so.3
ld-linux-armhf.so.3 (GLIBC_PRIVATE) => /lib/ld-linux-armhf.so.3
</pre>
 
Ähnlich wie bei <code>objdump</code> werden auch hier die benötigten Versionen der Shared-Libraries angezeigt.
 
Weitere Bekannte Libraries, die versioniert sind, sind unter anderem folgende:
* libstdc++ - GLIBCXX_3.4.21 gehört z.B. zur libstdc++-6.0.21 (GCC-5.1), CXXABI_1.3.12 genauso wie GLIBCXX_3.4.26 zur libstdc++-6.26 (GCC-9.1). Die Versionen können der Dokumentation von gcc entnommen werden: https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html
* libssl und libcrypto von OpenSSL: die benötigten Versionen steht direkt in der Symboltabelle, z.B. als OPENSSL_1.0.2g
* zlib: die benötigten Versionen stehen ebenfalls direkt in der Symboltabelle der libz.so, z.B. ZLIB_1.2.12
 
=== c++filt ===
Ein letztes nützliches Tool in Zusammenhang mit Dumps und wenn man mehr über die Symbol-Tabelle eines Binaries erfahren möchte, ist <code>c++filt</code>. Mit diesem Tool können "gemanglte" Symbole wieder lesbar gemacht werden. Schauen wir z.B. in die Symbol-Tabelle von enigma2 mit <code>objdump -R /usr/bin/enigma2</code>, sehen wir viele c++-Symbolnamen, wie z.B. <code>_ZNSt3tr18__detail12__prime_listE@GLIBCXX_3.4.10</code>
 
<code>c++filt</code> kann uns das wieder lesbarer machen: <code>c++filt _ZNSt3tr18__detail12__prime_listE</code> spuckt dafür aus: <code>std::tr1::__detail::__prime_list</code>.
 
Oder:
 
<pre>root@vusolo4k:~# c++filt _ZNSt14basic_ifstreamIcSt11char_traitsIcEEC1EPKcSt13_Ios_Openmode
std::basic_ifstream<char, std::char_traits<char> >::basic_ifstream(char const*, std::_Ios_Openmode)
</pre>
<pre>root@vusolo4k:~# c++filt _ZN19CaProgramMapSectionC1EPK17ProgramMapSectionhhRKSt6vectorItSaItEE
CaProgramMapSection::CaProgramMapSection(ProgramMapSection const*, unsigned char, unsigned char, std::vector<unsigned short, std::allocator<unsigned short> > const&)
</pre>
75
Bearbeitungen