PB173 - Binární programování Linux VIII. C bez libc Jiri Slabý Fakulta informatiky Masarykova univerzita 8. 11. 2016 Jiri Slabý (Fakulta informatiky, MU) PB173/05 8. 11. 2016 1/15 C a libc • libc se stará o komunikaci s OS (jádrem) • Jádro poskytuje pouze „základní" funkcionalitu • libc poskytuje spoustu nadstaveb • Soubory: f open, f read, fwrite, f close, ... • Síť: getaddrinfo, ntoh*, hton* • Vlákna (libpthread): pthread_* (včetně zamykání) • A spoustu dalšího (celý POSIX), ... Bez libc nic z toho nemáme Jak teď ale např. otevřu soubor? Jiri Slabý (Fakulta informatiky, MU) PB173/05 8. 11. 2016 2/15 Komunikace s jádrem Sdílená paměť 9 Jádro zapisuje, uživatel čte a naopak • Systémová volání Podobné jako zavolání funkce Ale program a jádro běží v jiných kontextech • Přepnutí kontextu o Uložení a změna stavu procesoru • Relativně drahá operace • Uvidíme dnes dále Jiri Slabý (Fakulta informatiky, MU) PB173/05 8.11.2016 3/15 Systémová volání • Volání funkce • Instrukcí procesoru • Závislé na architektuře • Softwarové přerušení (x86_32: číslo 0x80) • Speciální instrukce (x86_32: sysenter, x86_64: syscall) • Demo: implementace syscall z glibc o Systémová volání jsou očíslovaná • Do jednoho registru číslo • Čísla __nr_* definovaná jádrem (pro každou architekturu) • sys/syscall.h • Např. (x86_64): __nr_write (1), __nr_exit (60) Jiri Slabý (Fakulta informatiky, MU) PB173/05 8.11.2016 4/15 Úkol libc o úroveň níže O Zavolejte systémová volání • write s nějakým textem • exit Q Proveďte ale pomocí funkce syscali z libc • Tedy nepište přímo write (...), exit (...) • Viz man 2 syscall 9 První argument: číslo systémového volání Další argumenty: odpovídají už danému volání • Např. syscall (__NR_kill, -1, SIGKILL) O Přeložte a vyzkoušejte Jiri Slabý (Fakulta informatiky, MU) PB173/05 8.11.2016 5/15 C bez libc • Žádné hlavičkové soubory z libc, ani jeho funkce • Jen tO, CO poskytuje jádro (/usr/include/linux/) • Při překladu: gcc -nostdinc ... • Při linkování: gcc -nostdlib ... • gcc stále může vkládat volání memset apod. Jiri Slabý (Fakulta informatiky, MU) PB173/05 8. 11. 2016 6/15 Volací konvence Parametr Registry Uživatelský prostor Systémová volání x86_32 x86_64 x86_32 x86_64 1. EAX RDI EBX RDI 2. EDX RSI ECX RSI 3. Zásobník RDX EDX RDX 4. Zásobník RCX ESI R10 5. Zásobník R8 EDI R8 6. Zásobník R9 EBP R9 7. Zásobník Zásobník Jen 6 parametrů 8. Zásobník Zásobník Návratová EAX RAX EAX RAX Pozn.: x86_32 a -mregparm Jiri Slabý (Fakulta informatiky, MU) PB173/05 8. 11. 2016 7/15 Úkol Systémová volání bez libc O Otevřete a projděte si pbl73-bin/08/ Q Zavolejte • fork Z potomka: write na standardní výstup Z rodiče: read 16 bytů a jejich write na standardní výstup • Z obou potom: exit O Přeložte a spusťte • gcc -nostdlib ... Jiri Slabý (Fakulta informatiky, MU) PB173/05 8. 11. 2016 8/15 Data z jádra Jádro předává Parametry programu • Proměnné prostředí • Rozšiřující vektor Vše na zásobníku • Formát zásobníku je pevně daný Jiri Slabý (Fakulta informatiky MU) PB 173/05 8.11.2016 9/15 Formát zásobníku Počet parametrů long 1. parametr char * ... char * m-tý parametr char * Konec parametrů OUL 1. proměnná prostředí char * ... char * n-tá proměnná prostředí char * Konec proměnných prostředí OUL Rozšiřující vektor 1 struct { long type, val; } ... struct { long type, val; } Rozšiřující vektor o struct { long type, val; } Konec rozšiřujících vektorů {AT.NULL, ? } Jiri Slabý (Fakulta informatiky, MU) PB173/05 8.11.2016 10/15 Rozšiřující vektor Typ záznamů struct { long type; long value; }; Typy: at.null, at.entry, at.random, Pole struktur zakončuje typ at.null Jiri Slabý (Fakulta informatiky MU) PB173/05 8. 11. 2016 11/15 Úkol Zjištění názvu programu a platformy O Pište do programu pbl73-bin/08/nostd.c Q Vypište první parametr programu • Tj. název samotného programu O Dále iterujte přes zásobník až k rozšiřujícímu vektoru O Tam najděte typ at.platform O Vypište hodnotu jako řetězec • Použijte write O Přeložte (bez libc) a spusťte Jiri Slabý (Fakulta informatiky MU) PB173/05 8. 11. 2016 12/15 Virtuální systémová volání vsyscall o Jen na některých architekturách • A konfiguracích jádra • Neprobíhá přepnutí kontextu • Speciální stránka(y) s kódem namapovaným jádrem • Podpora jen 3 funkcí gettimeofday: aktuální Čas (Oxffffffffff 600000) • time: čas v sekundách od Epochy (Oxffffffffff 600400) • getcpu: číslo CPU a NUMA uzlu (Oxffffffffff 600800) • Demo: /proc/self/maps Jiri Slabý (Fakulta informatiky MU) PB 173/05 8.11.2016 13/15 Úkol Volání time Z vsyscall O Zavolejte adresu s time O Vypište hodnotu jako řetězec O Přeložte a spusťte několikrát Jiri Slabý (Fakulta informatiky MU) PB173/05 8. 11. 2016 14/15 Virtuální dynamická knihovna vdso • Speciální knihovna pňlinkovaná jádrem • Podpora také závislá na architektuře • Podobná vsyscali, ale více flexibilní • Navíc obsahuje ale jen ciock_gettime • Demo: ldd a readelf • Knihovna v ELF formátu • Adresa začátku v auxv: getauxval (at_sysinfo_ehdr) • Dále se přečte ELF pomocí libelf • Ukázkový kód: tools/testing/self tests/vDSO/parse_vdso. c Úkol: domácí úkol Jiri Slabý (Fakulta informatiky, MU) PB173/05 8.11.2016 15/15