PB173 - Binární programování Linux VIII. C bez libc Jiri Slabý Fakulta informatiky Masarykova univerzita 19. 11. 2015 Jiri Slabý (Fakulta informatiky, MU) PB173/05 19. 11. 2015 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* • Více vláken (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 19. 11. 2015 2/15 Komunikace s jádrem • Sdílená paměť • Jádro zapisuje, uživatel čte a naopak • V jednom z dalších cvičení • Systémová volání • Podobné jako zavolání funkce • Ale program a jádro běží v jiných kontextech • Přepnutí kontextu • Uložení a změna stavu procesoru • Relativně drahá operace • Uvidíme dnes dále Jiri Slabý (Fakulta informatiky, MU) PB173/05 19. 11. 2015 3/ 15 Systémová volání Volání funkce Instrukcí procesoru • Závislé na architektuře • Softwarové přerušení (x86_32: číslo 0x80) o Speciální instrukce (x86_32: sysenter, x86_64: syscall) • Demo: implementace syscall z glibc 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 19. 11. 2015 4/15 Úkol libc o úroveň níže O Zavolejte systémová volání • write s nějakým textem • exit O Proveďte ale pomocí funkce syscali z libc • Viz man 2 syscall • 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 19. 11. 2015 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 -nostdiib ... o gcc stále může vkládat volání memset apod. Jiri Slabý (Fakulta informatiky, MU) PB173/05 19. 11. 2015 6/15 Volací konvence Volací konvence Parametr Registry Systémová volání Uživatelský prostor Í386 x86_64 Í386 x86_64 1. EBX RDI EAX RDI 2. ECX RSI EDX RSI 3. EDX RDX Zásobník RDX 4. ESI R10 Zásobník RCX 5. EDI R8 Zásobník R8 6. EBP R9 Zásobník R9 7. Jen 6 parametrů Zásobník Zásobník 8. Zásobník Zásobník Návratová EAX RAX EAX RAX Pozn.: Í386 a -mregparm Jiri Slabý (Fakulta informatiky, MU) PB173/05 19. 11. 2015 7/15 Úkol Systémová volání bez libc O Otevřete a projděte si pbi73-bin/07/ O Zavolejte • fork o 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 19. 11. 2015 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) PB173/05 19. 11. 2015 9/ 15 Formát zásobníku 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 19. 11. 2015 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 19. 11. 2015 11/15 Úkol Zjištění názvu programu a platformy O 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 O Přeložte (bez libc) a spusťte Jiri Slabý (Fakulta informatiky, MU) PB173/05 19. 11. 2015 12/15 Virtuální systémová volání vsyscall • Jen na některých architekturách • Neprobíhá přepnutí kontextu • Speciální stránka(y) s kódem namapovaným jádrem • Podpora jen 3 funkcí • gettimeof day: 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) PB173/05 19. 11. 2015 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 19. 11. 2015 14/15 Virtuální dynamická knihovna vdso • Speciální knihovna přilinkovaná jádrem • Podpora také závislá na architektuře • Podobná vsyscali, ale více flexibilní • Navíc obsahuje ale jen clock.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: Documentation/vDSO/parse_vdso . c Úkol: domácí úkol Jiri Slabý (Fakulta informatiky, MU) PB173/05 19. 11. 2015 15/15