Binární utility
Nejen kompilátorem živ je člověk - během své práce jistě využijeme služeb alespoň některé z tzv. binárních utilit, zkráceně binutils. Tyto utility umožňují provádět další doplňkové činnosti s objektovými soubory, resp. s výsledným spustitelným souborem naší aplikace.
Stejně jako v případě kompilátoru budeme pro práci se spustitelným souborem pro naše cílové zařízení používat křížové verze binárních utilit, tj. křížové binární utility (cross-binutils). Pojďme si stručně představit ty nejdůležitější.
ld
Utilita ld neboli linker. Má za úkol vyřešit závislosti mezi objektovými soubory - dohledat všechny chybějící funkce a globální proměnné a přidělit jim místo v paměti. Této činnosti se říká symbol resolution. Vedle toho musí sloučit odpovídající si sekce v jednotlivých objektových souborech (vzniklých kompilací nebo uložených v knihovnách) do jednoho výsledného spustitelného souboru. Zároveň během slučování opravuje přidělené adresy v paměti. Tomuto postupu se říká relokace.
Je podstatné zdůraznit jednu důležitou konvenci, kterou jsme už zmínili dříve - linker se nevolá přímo, ale prostřednictvím kompilátoru. Pokud potřebujeme linkeru předat nějaké volby a parametry, tak k tomu slouží speciální volba kompilátoru -Wl, která řekne kompilátoru, že za čárkou budou následovat volby pro linker (oddělené čárkami bez mezer) až do první mezery. Viz příklad:
$ gcc -Wl,-rpath=/lib:/usr/lib:/usr/local/lib -march=armv5te
kde volba -rpath nastaví linkeru run-time cestu k dynamickým knihovnám na specifikované adresáře, zatímco volba -march je už volbou kompilátoru, protože následuje za první mezerou.
Zmíněnou konvenci je třeba mít na paměti především při použití utility make, protože při jejím použití se kompilační a linkovací fáze oddělují.
readelf
S pomocí utility readelf můžeme prozkoumávat spustitelné a objektové soubory ve formátu elfhttp://cs.wikipedia.org/wiki/Executable_and_Linkable_Format. Můžeme si například nechat vypsat informace uložené v hlavičce spustitelného souboru příkazem (výstup viz obrázek 1.7):
$ arm-none-linux-gnueabi-readelf -h ./helloarm
nebo informace specifické pro danou platformu:
$ arm-none-linux-gnueabi-readelf -A ./helloarm
a případně i seznam sekcí spustitelného souboru:
$ arm-none-linux-gnueabi-readelf -s ./helloarm
Snad jen krátkou poznámku k sekcím. Spustitelný soubor je rozdělený do několika tzv. sekcí, tedy částí, které uchovávájí určitý typ informací. Např. sekce .bss slouží pro uchování neinicializovaných globalních proměnných. Sekce .data zase pro uložení inicializovaných globálních proměnných. V sekci .rodata pak najdeme konstatní proměnné. A samotný kód je umístěn v sekci .text. Samozřejmě kromě uvedených základních sekcí najdeme v binárním spustitelném souboru celou řadu dalších sekcí (např. s ladícími informacemi), ale jejich výčet by přesáhl rámec tohoto textu.
objdump
Utilita objdump je zajímavá především kvůli tomu, že umí vypsat disasemblovaný strojový kód. Pokud navíc máme ve spustitelném souboru obsažené i ladící informace, tak se zobrazí i příslušný C kód. Na obrázku 1.8 je vidět zkrácený výpis ukázkové aplikace HelloArm, který získáme příkazem:
$ arm-none-linux-gnueabi-objdump -S ./helloarm
objcopy
S utilitou objcopy lze upravovat a konvertovat spustitelné soubory do/z různých formátů. Často se proto používá pro konverzi spustitelného souboru ve formátu elf do podoby binárního obrazu vhodného pro uložení do FLASH paměti. Také je používána pro konverzi do formátu S-record (Motorola) nebo HEX (Intel).
V souvislosti s pamětmi FLASH je vhodné přikázat utilitě objdump, aby případné mezery v binárním obrazu vyplnila jedničkami, což může urychlit nahrávání binárního obrazu do paměti (vymazané části FLASH paměti obsahují samé jedničky).
Příklad příkazu pro konverzi souboru ve formátu elf do binárního obrazu:
$ arm-none-linux-gnueabi-objcopy --gap-fill=0xff -O binary helloarm helloarm.bin
strip
Utilita strip odstraní ze spustitelného souboru symboly a ladící informace (debug info) a díky tomu zmenší velikost výsledného souboru. Tato skutečnost nám, programátorům aplikací pro embedded zařízení, hraje do not. Menší velikost binárního souboru totiž klade menší nároky na kapacitu paměti FLASH v cílovém zařízení. Kromě toho je rychlejší i samotné náhrávání binárního souboru do zařízení, což ocení zejména výroba a servis.
Míra zmenšení spustitelného souboru je někdy až překvapivá. Mnohdy se velikost spustitelného souboru sníží o více než 50% oproti velikosti původního souboru.
Schopnost utility strip zmenšovat binární soubory se využívá i při vzdáleném ladění aplikace. Původní nezmenšená verze spustitelného souboru se ponechá v hostitelském počítači, kde poběží křížový debugger, zatímco zmenšená verze (stripped) se nahraje do cílového zařízení. Debugger tak má k dispozici všechny potřebné ladící informace (zdrojový kód apod.), ale přitom není nutné řešit, kam v zařízení uloži původní nezmenšený binární soubor.
Kromě ladění je utilita strip používaná i při distribuci spustitelných souborů. Z původního spustitelného souboru se symboly a ladící informace vyjmou a uloží do zvláštního souboru (často s příponou .dbg nebo .debug). Standardně se pak distribuje pouze zmenšený binární souboru. A pokud někdo chce danou aplikaci ladit, tak si vyžádá soubor s ladícími informacemi.
nm
Utilita nm umí vypsat symboly (jména proměnných, funkcí atd.) ze souboru ve formátu elf. To je užitečné například tehdy, když hledáme proměnou nebo funkci, kterou nemůže linker při linková aplikace najít.
ldd
Ldd je skript, který se používá pro zjištění závislostí aplikací a dynamických knihoven na jiných dynamických knihovnách. Tato znalost se hodí při sestavování distribuce pro cílové zařízení, protože výsledný kořenový systém musí obsahovat všechny dynamické knihovny, které daná aplikace vyžaduje.
Příklad volání skriptu ldd s výsledkem:
$ ldd ./hello linux-gate.so.1 => (0xb7fc5000) libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb7e5c000) /lib/ld-linux.so.2 (0xb7fc6000)
Z výpisu je patrné, že aplikace hello tedy závisí na dynamické knihovně libc a dynamickém zavaděči/linkeru ld-linux.so. Bez těchto dvou komponent by se aplikace na cílovém zařízení nespustila. Objekt linux-gatehttp://www.trilithium.com/johan/2005/08/linux-gate/ je virtuální sdílený objekt jádra, jakási brána mezi uživatelským prostorem (user space) a prostorem jádra (kernel space).
I skript ldd musí být v křížové verzi, pokud jej chceme spouštět na hostitelském počítači, ale přitom s ním analyzovat aplikace zkompilované pro cílová zařízení. Některá vyvojová prostředí (např. SourceryG++) bohužel dodávají pouze nativní verzi, kterou je nutné spustit až na cílovém zařízení.