Programowanie Systemów Wbudowanych OS Linux - Toolchain Iwona Kochańska Katedra Systemów Elektroniki Morskiej WETI PG
Co to jest toolchain? Toolchain - zestaw narzędzi do kompilacji kodu źródłowego do plików wykonywalnych na platformie docelowej: kompilator linker biblioteki współdzielone Za pomoca narzędzi toolchain można zbudować podstawowe elementy OS dla systemu wbudowanego: program rozruchowy (bootloader) jadro systemu (kernel) system plików (root filesystem) GUT Intel 2015/16 2/45
Co to jest toolchain? Toolchain powinien kompilować kod źródłowy w języku asemblera, C i C++ (w tych językach napisane sa kody źródłowe OS linux) Toolchain Linux składa się z elementów GNU project (http://www.gnu.org) Alternatywa - kompilator Clang i zwi azany z nim LLVM project (http://llvm.org) GUT Intel 2015/16 3/45
Elementy toolchain Binutils narzędzia binarne: assembler, linker, ld GCC kompilatory C i innych języków: C++, Objective-C, Objective- C++, Java, Fortran, Ada, i Go Biblioteka C ustandaryzowane API zgodne ze specyfikacja POSIX (podstawowe API jadra OS)... oraz kopia plików nagłówkowych jadra Linuxa. GUT Intel 2015/16 4/45
Toolchain Podstawowe definicje: build: platforma lokalna, na której realizowana jest kompilacja (na przykład PC z dystrybucja Debiana) target: platforma docelowa (na przykład Raspberry Pi) host: OS dostarczajacy wirtualnego środowiska guest: OS w środowisku wirtualnym GUT Intel 2015/16 5/45
Rodzaje toolchain-ów Natywny (np. w komputerach typu desktop) build machine host machine target machine arch. A arch. A arch. A Kompilacja skrośna (cross-compilation) build machine host machine target machine arch. A arch. A arch. B GUT Intel 2015/16 6/45
Rodzaje toolchain-ów Natywny skrośny (cross-native) build machine host machine target machine arch. A arch. B arch. B Canadian build machine host machine target machine arch. A arch. B arch. C GUT Intel 2015/16 7/45
Kompilacja skrośna Dwa podstawowe problemy kompilacji skrośnej: Wszystkie pliki nagłówkowe i biblioteki C/C++ dla platformy docelowej musza być dostępne na platformie kompilujacej (build). Kompilator powinien wygenerować kod właściwy dla platformy docelowej (target). GUT Intel 2015/16 8/45
Architektury CPU Toolchain powinien być dostosowany do właściwości CPU platformy docelowej (target): Architektury CPU: arm, mips, x86_64, itd. Big- lub little-endian: niektóre CPU moga pracować w obu trybach, ale kod maszynowy jest inny dla każdego z nich Wsparcie operacji na liczbach zmiennoprzecinkowych: sprzętowe lub programowe Application Binary Interface (ABI): konwencja przekazywania parametrów między wywołaniami funkcji GUT Intel 2015/16 9/45
Rodzaje ABI dla procesorów ARM OABI - Old Application Binary Interface (OABI) - nie kontynuowany po roku 2011 EABI - Extended Application Binary Interface (EABI) - rejestry ogólnego przeznaczenia (całkowitoliczbowe) EABIHF - Hard Float Extended Application Binary Interface - rejestry zmiennoprzecinkowe GUT Intel 2015/16 10/45
GNU prefix GNU prefix - złożony z trzech lub czterech elementów oddzielonych myślnikami: CPU: arm, mips, x86_64, el = little-endian, eb = big-endian; np. armeb = big-endian ARM Dostawca OS, np. poky Jadro, np. linux OS: nazwa przestrzeni użytkownika (gnu lub uclibc gnu). Może być dołaczony rodzaj ABI (gnueabi, gnueabihf, uclibcgnueabi, lub uclibcgnueabihf). $ gcc -dumpmachine x86_64-linux-gnu GUT Intel 2015/16 11/45
Instalacja toolchain-a dla ARM (RaspberryPi) Pobranie źródeł: $ cd ~ $ mkdir katalog $ cd katalog / $ git clone https :// github. com / raspberrypi / tools Dodanie ścieżki do kompilatora skrośnego do pliku ~/.bashrc: export PATH = $PATH : katalog / raspberrypi / tools /arm - bcm2708 /gcc - linaro -arm - linux - gnueabihf - raspbian / bin GUT Intel 2015/16 12/45
Biblioteka C Application C library Linux kernel Interfejs programistyczny do OS Unix zdefiniowany jest w języku C (standard POSIX) Bilbioteka C to implementacja tego interfejsu (do komunikacji programu z jadrem systemu) Biblioteka C używa wywołań systemowych w celu uzyskania dostępu do usługi jadra (przejście między przestrzenia użytkownika a przestrzenia jadra) GUT Intel 2015/16 13/45
Biblioteki C glibc - standardowa GNU C, najbardziej kompletna implementacja POSIX API eglibc - wbudowana GLIBC; łatki do glibc dodajace opcje konfiguracji i wsparcie dla architektur nie obsługiwanych przez glibc; właczona do glibc poczawszy od wersji2.20 uclibc - C dla mikrokontrolerów; zaprojektowana do współpracy z uclinux (Linux dla CPUs bez jednostki zarzadzania pamięcia), obecnie współpracuje z pełnym Linuxem musl libc - nowa biblioteka C dla systemów wbudowanych GUT Intel 2015/16 14/45
Crosstool-NG Crosstool-NG (2007) - buduje wersje stand-alone toolchain-a do kompilacji skrośnej ze źródeł SoC lub od dostawcy platformy Potrzebne pakiety: $ sudo apt - get install automake bison chrpath flex g ++ git gperf gawk libexpat1 - dev libncurses5 - dev libsdl1.2 - dev libtool python2.7 - dev texinfo Pobranie źródeł z http://crosstool-ng.org/download/crosstool-ng, a następnie: $ tar xf crosstool - ng -1.9.3. tar. bz2 $ cd crosstool - ng -1.9.3 $./ configure $ make $ make install GUT Intel 2015/16 15/45
Crosstool-NG Wejście do crosstool menu: $./ct -ng Lista przykładowych konfiguracji: $./ct -ng list - samples Wybór konfiguracji: $./ct -ng arm - cortex_a8 - linux - gnueabi Zmiany za pomoca menu konfiguracyjnego: $./ ct - ng menuconfig Konfiguracja zapisywana jest w pliku.config. Budowa toolchain-a: $./ct -ng build GUT Intel 2015/16 16/45
Crosstool-NG Ścieżka do toolchain-a: arm - cortex_a8 - linux - gnueabi / bin / Dodanie ścieżki do zmiennej PATH: $ PATH =/.../ arm - cortex_a8 - linux - gnueabihf / bin : $PATH Kompilacja helloworld.c: $ arm - cortex_a8 - linux - gnueabihf - gcc helloworld.c -o helloworld Sprawdzenie rodzaju pliku wykonywalnego: $ file helloworld helloworld : ELF 32 - bit LSB executable, ARM, version 1 ( SYSV ), dynamically linked ( uses shared libs ), for GNU / Linux 3.15.4, not stripped GUT Intel 2015/16 17/45
Crosstool-NG Sprawdzenie wersji kompilatora: $ arm - cortex_a8 - linux - gnueabi - gcc -- version Sprawdzenie konfiguracji kompilatora: $ arm - cortex_a8 - linux - gnueabi - gcc -v Lista opcji kompilatora zależnych od architektury maszyny docelowej: $ arm - cortex_a8 - linux - gnueabihf - gcc --target - help GUT Intel 2015/16 18/45
Crosstool-NG Toolchain sysroot - katalog z podkatalogami dla bibliotek, plików nagłówkowych i innych plików konfiguracyjnych ścieżka może być ustawiona podczas konfiguracji toolchain-a za pomoca: --with - sysroot = lub podczas jego wywołania za pomoca: -- sysroot = Sprawdzenie ścieżki domyślnej sysroot: $ arm - cortex_a8 - linux - gnueabi - gcc -print - sysroot GUT Intel 2015/16 19/45
Crosstool-NG Sysroot zawiera: lib: objekty współdzielone dla biblioteki C i dynamicznego linkera, ld-linux usr/lib: archiwym bibliotek statycznych usr/include: pliki nagłówkowe wszystkich bibliotek usr/bin: narzędzia uruchamiane na maszynie docelowej (np. komenda ldd) usr/share: pliki niezależne od maszyny docelowej sbin: zawiera narzędzie ldconfig do zarz adzania cache-owaniem bibliotek współdzielonych GUT Intel 2015/16 20/45
Narzędzia toolchain-a Polecenie addr2line ar as c++filt cpp elfedit g++ gcc gcov gdb gprof Opis tłumaczy adresy (pl. wykonywalny) na numery linii (kod źródło tworzy biblioteki statyczne GNU assembler przetwarza symbole C++ i Java C preprocessor edycja nagłówka pliku ELF front-end GNU C++ front-end GNU C narzędzie analizy pokrycia kodu (code coverage) GNU debugger narzędzie analizy wydajności programu GUT Intel 2015/16 21/45
Narzędzia toolchain-a Polecenie ld nm objcopy objdump ranlib readelf size strings strip Opis GNU linker wyświetla nazwy symboliczne z plików wynikowych kopiuje i tłumaczy pliki objektowe wyświetla informacje z plików obiektowych tworzy lub modyfikuje indeks bibliotek statycznych wyświetla inforamcje o plikach ELF lista rozmiarów sekcji i całkowity rozmiar wyświetla łańcuchy ( drukowalne ) z pliku usuwa symbole z plików wynikowych GUT Intel 2015/16 22/45
Narzędzia GNU Toolchain Narzędzia GNU Toolchain automatycznie: usprawniaja powtarzalne cykle kompilacji zapewniaja powtarzalność procesu kompilacji, eliminujac możliwość popełnienia błędu czynia proces kompilacji (budowy) programu możliwie najprostszym. GUT Intel 2015/16 23/45
GNU Compiler Collection GNU Compiler Collection (GNU C Compiler): 1987: Richard Stallman, założyciel GNU Project, postanowił opracować kompilator, który spełniałby wymagania wolnego oprogramowania (Free Software). kompilator GNU C szybko stał się popularny wśrod programistów wolnego oprogramowania ze względu na swoja przenośność. Dziś GCC obsługuje różne języki programowania: C i C++, Ada, Fortran, Objective C, Java. Jadra systemów Linux napisane sa w języku C i skompilowane za pomoca GCC. GCC współpracuje z procesorami o różnych architekturach: Intel IA32 ("x86"). AMD64, SPARC POWER/PowerPC oraz rosnac a liczba procesorów wyspecjalizowanych. If it s commercially available, GCC can probably compile code for it! GUT Intel 2015/16 24/45
Kompilacja pojedynczego pliku Proces budowy programu: compile assembly link Kompilator: tłumaczy kod programu na język maszynowy (specificzny dla danej rodziny procesorów) Assembler: tłumaczy skompilowane źródło na binarna reprezentację kodu maszynowego. nadaje każdej instrukcji maszynowej adres pamięci (ale nie bezwzględny, raczej symbolicznie lub jako przesunięcie). tworzy listę wszystkich nierozwiazanych referencji, które prawdopodobnie zdefiniowane sa w innych plikach programu Linker: ł aczy kod z plików wygenerowanych przez assembler (object code) w tzw. plik-kontener, który może być załadowany do pamięci i wykonany na danej platformie sprzętowej. GUT Intel 2015/16 25/45
Kompilacja pojedynczego pliku GCC nie potrafi zbudować wykonywalnego pliku programu, tłumaczy jedynie kod programu na język maszynowy. Domyślnie GCC wykonuje wszystkie kroki potrzebne do zbudowania wykonywalnego pliku binarnego, jednak sam dokonuje jedynie kompilacji. Assembler i Linker to osobne narzędzia GNU Toolchain, z którymi komunikuje się kompilator. Zwyczajowo plik wykonywalny dostaje nazwę a.out, chyba że użytkownik zdefiniuje ja inaczej za pomoca opcji -o kompilatora gcc. GUT Intel 2015/16 26/45
Kompilacja jednego źródła C Przykład "Hello World" kod źródłowy: /* Hello World */ # include <stdio.h> # include < stdlib.h> int main ( int argc, char ** argv ) { printf (" Hello, World!\n"); return (0); } kompilacja: $ gcc -o hello hello. c test: $./ hello Hello, World! GUT Intel 2015/16 27/45
Kompilacja wielu źródeł C GNU linker potrafi łaczyć ze soba kilka plików objektów.o w jeden plik wykonywalny. Przykład: message.c: # include <stdio.h> void goodbye_world ( void ) { printf (" Goodbye, World!\n"); Kompilacja message.c: $ gcc -c message. c Sterownik (driver) GCC woła swój wewnętrzny kompilator, przetwarza kod źródłowy na język maszynowy i przekazuje go na wejście zewnętrznego assemblera. Assembler tworzy plik z rozszerzeniem.o, który może być połaczony przez GNU linker z innymi plikami.o. GUT Intel 2015/16 28/45
Kompilacja wielu źródeł C goodbye.c: # include < stdlib.h> void goodbye_ world ( void ); int main ( int argc, char ** argv ) { goodbye_ world (); return (0) Kompilacja: $ gcc -c goodbye. c Linkowanie: $ gcc -o goodbye message. o goodbye. o Kompilacja i linkowanie w jednym poleceniu: $ gcc -o goodbye message. c goodbye. c Uruchomienie programu: $./ goodbye Goodbye, World! GUT Intel 2015/16 29/45
Biblioteka GLIBC Cztery główne części biblioteki implementuja składowe standardu POSIX: libc: główna biblioteka (implementacja printf, open, close, read, write) libm: funkcje matematyczne (cos, exp, log) libpthread: funkcje zwiazane z watkami (nazwy rozpoczynajace się od pthread_ ) librt: rozszerzenie czasu rzeczywistego (obsługa pamięci współdzielonej i asynchronicznego I/O) libc jest linkowana zawsze, pozostałe musza być dodane za pomoca opcji -l arm - cortex_a8 - linux - gnueabihf - gcc myprog.c -o myprog - lm GUT Intel 2015/16 30/45
Biblioteki, GLIBC Niemal każda aplikacja Linux używa biblioteki GLIBC (biblioteka GNU C) podstawowe operacje wejścia/wyjścia (np. zamknięcie programu) cienka wartwa między aplikacja a jadrem Linuxa GCC zakłada, że GLIBC jest domyślnie dodawana do programu podczas etapu linkowania. Mimo to do źródeł programu należy dodać pliki nagłówkowe standardowych bibliotek Przykład: # include <stdio.h> # include < stdlib.h> # include < math.h > // system math library int main ( int argc, char ** argv ) {... } Kompilacja i linkowanie: $ gcc -o trig - lm trig. c opcja -lm powoduje, że GCC przeszukuje bibliotekę GUT matematyczn Intel 2015/16 a libm 31/45
Biblioteki statyczne a współdzielone Biblioteki statyczne (static) - podczas kompilacji programu kod biblioteki statycznej jest umieszczany w wynikowym pliku binarnym; każda funkcja ma tyle kopii, ile jest programów, które z niej korzystaja. Biblioteki współdzielone (shared) - tylko jedna wersja każdej funkcji współdzielona między aplikacjami; jest to możliwe dzięki pamięci wirtualnej - kilka niezależnych aplikacji ma bezpieczny dostęp do tego samego obszaru pamięci. GUT Intel 2015/16 32/45
Biblioteki współdzielone Dołaczane do programu podczas jego wykonywania Istnieja dzięki wynalezieniu pamięci wirtualnej Pozwalaja efektywnie wykorzystać pamięć, ponieważ wystarcza tylko jedna kopia danej biblioteki w pamięci Łatwo je aktualizować Biblioteki współdzielone redukuja rozmiar pliku wynikowego Jeśli biblioteka jest współdzielona przez wiele różnych programów jednocześnie, pozostaje w pamięci i jest natychmiast dostępna. Biblioteka współdzielona powinna być zbudowana tak, by jej działanie było niezależne od miejsca w pamięci, do którego została załadowana: $ gcc - fpic -c message. c Flaga PIC informuje GCC, by w kodzie maszynowym programu nie umieszczał odwołań do adresów pamięci. GUT Intel 2015/16 33/45
Biblioteki współdzielone Utworzenie biblioteki współdzielonej: $ arm - cortex_a8 - linux - gnueabihf - gcc -fpic -c test1.c $ arm - cortex_a8 - linux - gnueabihf - gcc -fpic -c test2.c $ arm - cortex_a8 - linux - gnueabihf - gcc - shared -o libtest.so test1.o test2.o Dołaczenie libtest do programu helloworld: $ arm - cortex_a8 - linux - gnueabihf - gcc helloworld.c - ltest -L../ libs -I../ libs -o helloworld Linker będzie szukał libtest.so w domyślnej ścieżce /lib lub /usr/lib. Dołaczenie innych ścieżek bibliotek współdzielonych - w zmiennej LD_LIBRARY_PATH GUT Intel 2015/16 34/45
Nazwy bibliotek współdzielonych Nazwy bibliotek współdzielonych: libjpeg.a: biblioteka statyczna (archiwum) libjpeg.so -> libjpeg.so.8.0.2 : link symboliczny do dynamicznego linkowania libjpeg.so.8 -> libjpeg.so.8.0.2: link symboliczny do ładowania biblioteki podczas działania programu libjpeg.so.8.0.2: biblioteka współdzielona GUT Intel 2015/16 35/45
Biblioteki współdzielone Utworzenie biblioteki współdzielonej: (plik wyjściowy: libmessage.so): $ gcc - shared -o libmessage. so message. o Użycie biblioteki współdzielonej: $ gcc -o goodbye - lmessage -L. goodbye. o GCC informuje linkera, że ma połaczyć kod pliku main.o z biblioteka libmessage.so. flaga -L ustawia ścieżkę z plikami bibliotek. -L. oznacza, że biblioteki moga znajdować się w bieżacym katalogu. Własna biblioteka współdzielona może być używana tak jak dostarczana wraz z dystrybucja Linux, pod warnkiem, że znajduje się w odpowiednim katalogu (np. /usr/lib/) GUT Intel 2015/16 36/45
Biblioteki współdzielone ld-linux - dynamiczny linker; automatycznie uruchamiany, gdy uruchamiana jest aplikacja używajaca bibliotek współdzielonych. Poszukuje ich w katalogu /lib i /usr/lib (te domyślne ścieżki moga być zmienione w pliku konfiguracyjnym /etc/ld.so.conf. ldd - przeszukuje domyślne systemowe ścieżki bibliotek współdzielonych i wypisuje wersje tych bibliotek, używane przez program: $ ldd goodbye Przykładowy komunikat narzędzia ldd dla programu goodbye: linux - vdso.so.1 (0 x00007ffc8f2bb000 ) libmessage. so => not found libc.so.6 => / lib / x86_64 - linux - gnu / libc.so.6 (0 x00007fb6 / lib64 /ld - linux -x86-64. so.2 (0 x00007fb6d458e000 ) GUT Intel 2015/16 37/45
Biblioteki współdzielone Przy próbie uruchomienia programu pojawi się bład:./ goodbye./ goodbye : error while loading shared libraries : libmessage. so: cannot open shared object file : No such file Rozwiazanie: zmiana ustawień systemowych instalacja libmessage.so w katalogach standardowych ustawienie zmiennej środowiskowej LD_LIBRARY_PATH na dodatkowa ścieżkę bibliotek współdzielonych: export LD_ LIBRARY_ PATH =$( pwd ) po tej operacji ldd zwróci: linux - vdso.so.1 (0 x00007ffd78552000 ) libmessage.so => / opt / cpp_examples / libmessage.so (0 x0000 libc.so.6 => / lib / x86_64 - linux - gnu / libc.so.6 (0 x00007fc9 / lib64 /ld - linux -x86-64. so.2 (0 x00007fc909fd5000 ) GUT Intel 2015/16 38/45
Biblioteki współdzielone Jakie biblioteki zostały dołaczone? $ arm - cortex_a8 - linux - gnueabihf - readelf -a myprog grep " Shared library " 0 x00000001 ( NEEDED ) Shared library : [ libm. so.6] 0 x00000001 ( NEEDED ) Shared library : [ libc. so.6] Jaki linker jest wołany podczas działania programu? (run-time linker): $ arm - cortex_a8 - linux - gnueabihf - readelf -a myprog grep " program interpreter " [ Requesting program interpreter : / lib /ld - linux - armhf. so.3] GUT Intel 2015/16 39/45
Biblioteki statyczne Statyczne linkowanie jest przydatne: gdy budowany system jest mały i składa się tylko z elementów BusyBox gdy program jest uruchamiany bez dostępu do systemu plików z bibliotekami runtime Linkowanie tylko bibliotek statycznych: $ arm - cortex_a8 - linux - gnueabihf - gcc - static helloworld. c -o helloworld - static GUT Intel 2015/16 40/45
Biblioteki statyczne Tworzenie biblioteki statycznej: $ arm - cortex_a8 - linux - gnueabihf - gcc -c test1.c $ arm - cortex_a8 - linux - gnueabihf - gcc -c test2.c $ arm - cortex_a8 - linux - gnueabihf -ar rc libtest.a test1. o test2.o Linkowanie libtest do programu helloworld: $ arm - cortex_a8 - linux - gnueabihf - gcc helloworld.c - ltest -L../ libs -I../ libs -o helloworld GUT Intel 2015/16 41/45
GNU Binutils GNU Binutils - zbiór narzędzi do tworzenia i obróbki plików wykonywalnych. Składa się z: asemblera (GNU Assembler) linkera (GNU Linker) biblioteki obsługi różnych formatów plików z kodem narzędzi do obróbki plików z kodem (np. objdump) Binutils jest używany jako back-end przez GCC, ale też wiele innych programów operujacych na kodzie. GUT Intel 2015/16 42/45
GNU Assembler Przetwarza kod skompilowany do języka maszynowego w kod nadajacy się do wykonania przez konkretny procesor GNU as obsługuje wiele różnych rodzin mikroprocesorów GNU as w danym systemie Linux jest wstępnie skonfigurowany do pracy z procesorem, na którym pracuje ów system, jednak można ta konfigurację zmienić Język maszynowy programu Hello World: $ gcc -S hello. c Kompilacja źródła hello.s: $ as -o hello.o hello.s GUT Intel 2015/16 43/45
GNU Linker Aby kod programu był wykonywalny, musi on zostać sformatowany do postaci ELF (Executable and Linkable Format), zrozumiałej przez systemy UNIX. Format ten obowiazuje: pliki wykonywalne, pliki obiektowe, bibliotki współdzielone zrzuty pamięci Za formatowanie do ELF odpowiedziany jest linker. Linker jest również odpowiedzialny za sprawdzenie, czy kod uruchamiany podczas startu (plik crtbegin.o automatycznie dołaczany do aplikacji) oraz zamykania aplikacji (crtend.o) znajduje się w prawidłowym miejscu kodu wykonywalnego GUT Intel 2015/16 44/45
GNU Linker Przydatne narzędzie: objdump - zapisuje zawartość wykonywalnych plików binarnych w formacie tekstowym; wizualizuje zawartość plików wykonywalnych. Przykład: $ objdump -x -d -S hello GUT Intel 2015/16 45/45