abclinuxu.cz AbcLinuxu.cz itbiz.cz ITBiz.cz HDmag.cz HDmag.cz abcprace.cz AbcPráce.cz
Inzerujte na AbcPráce.cz od 950 Kč
Rozšířené hledání
×
    dnes 18:11 | Nová verze

    Yocto Project byl vydán ve verzi 5.0. Její kódové jméno je Scarthgap. Yocto Project usnadňuje vývoj vestavěných (embedded) linuxových systémů na míru konkrétním zařízením. Cílem projektu je nabídnou vývojářům vše potřebné. Jedná se o projekt Linux Foundation.

    Ladislav Hagara | Komentářů: 0
    dnes 17:56 | Nová verze

    Operační systém 9front, fork operačního systému Plan 9, byl vydán v nové verzi "do not install" (pdf). Více o 9front v FQA.

    Ladislav Hagara | Komentářů: 0
    dnes 13:11 | Nová verze

    Svobodná webová platforma pro sdílení a přehrávání videí PeerTube (Wikipedie) byla vydána v nové verzi 6.1. Přehled novinek i s náhledy v oficiálním oznámení a na GitHubu. Řešeny jsou také 2 bezpečnostní chyby.

    Ladislav Hagara | Komentářů: 3
    dnes 12:33 | Zajímavý software

    Lennart Poettering na Mastodonu představil utilitu run0. Jedná se o alternativu k příkazu sudo založenou na systemd. Bude součástí systemd verze 256.

    Ladislav Hagara | Komentářů: 12
    včera 23:22 | Nová verze

    Hudební přehrávač Amarok byl vydán v nové major verzi 3.0 postavené na Qt5/KDE Frameworks 5. Předchozí verze 2.9.0 vyšla před 6 lety a byla postavená na Qt4. Portace Amaroku na Qt6/KDE Frameworks 6 by měla začít v následujících měsících.

    Ladislav Hagara | Komentářů: 11
    včera 21:44 | Komunita

    Ubuntu 24.10 bude Oracular Oriole (věštecká žluva).

    Ladislav Hagara | Komentářů: 11
    včera 20:22 | Nová verze

    Byla vydána nová verze 2.45.0 distribuovaného systému správy verzí Git. Přispělo 96 vývojářů, z toho 38 nových. Přehled novinek v příspěvku na blogu GitHubu a v poznámkách k vydání. Vypíchnout lze počáteční podporu repozitářů, ve kterých lze používat SHA-1 i SHA-256.

    Ladislav Hagara | Komentářů: 0
    včera 13:33 | IT novinky

    Před 25 lety, ve čtvrtek 29. dubna 1999, byla spuštěna služba "Úschovna".

    Ladislav Hagara | Komentářů: 0
    včera 01:00 | Nová verze

    Byla vydána nová verze 24.04.28 s kódovým názvem Time After Time svobodného multiplatformního video editoru Shotcut (Wikipedie) a nová verze 7.24.0 souvisejícího frameworku MLT Multimedia Framework. Nejnovější Shotcut je vedle zdrojových kódů k dispozici také ve formátech AppImage, Flatpak a Snap.

    Ladislav Hagara | Komentářů: 0
    28.4. 16:33 | Nová verze Ladislav Hagara | Komentářů: 0
    KDE Plasma 6
     (75%)
     (8%)
     (2%)
     (15%)
    Celkem 887 hlasů
     Komentářů: 4, poslední 6.4. 15:51
    Rozcestník

    Jaderné noviny – 17. 7. 2014: 32bitová systémová volání na x86

    5. 8. 2014 | Luboš Doležel | Jaderné noviny | 3167×

    Aktuální verze jádra: 3.16-rc5. Citáty týdne: Thomas Gleixner, Ted Ts'o, Grant Likely. Anatomie systémového volání, část druhá: Různé způsoby na x86 - shrnutí; Spuštění systémových volání pro x86_32 na x86_64; Složitější příklad: execve a kompatibilita s 32bitovými aplikacemi; ABI x32; Závěr.

    Obsah

    Aktuální verze jádra: 3.16-rc5

    link

    Aktuální vývojová verze jádra je 3.16-rc5 vydaná 13. července. Linus k němu řekl: Věci vypadají normálně a jako obvykle bych byl radši, kdyby tu byl menší šrumec, protože už jde o několikáté rc, ale po pravdě tam není nic, co by člověka zvedlo ze židle.

    Stabilní aktualizace: verze 3.15.5, 3.14.12, 3.10.48 a 3.4.98 vyšly 9. července. Aktualizace 3.14.13, 3.10.49 a 3.4.99 se aktuálně revidují; jejich vydání můžeme očekávat 17. července nebo později.

    Citáty týdne: Thomas Gleixner, Ted Ts'o, Grant Likely

    link

    Nejlákavějším nápadem bylo zatím svést se na vlně nejzábavnějšího crowdfundingového nesmyslu:

    https://www.kickstarter.com/projects/324283889/potato-salad

    Tudíž bychom mohli přetvořit RT na nesmyslný crowdfundovaný projekt, který slouží k účelu řízení stroje na výrobu bramborového salátu, abychom zajistili, že Zack Danger Brown může dodat všechen bramborový salát, na který lidé přispěli.

    -- Thomas Gleixner

    Člověk musí umět poznat, kdy přišel čas na to říct "Odval se domů checkpatchi, jseš opilej."

    -- Ted Ts'o

    Mám obavy, že celá tato debata vykazuje pohrdání jakoukoliv stabilitou platformy. Poprvé *v historii* (a možná by se dalo říci, že navzdory našemu úsilí) máme obří ekosystém ISV pro Linux. Ještě úžasnější je to, že je postaven okolo ARM, nikoliv x86! Hurá! Celé roky jsme doufali, že se toto stane. Takže se teď rozhodneme to všechno zahodit tím, že rozhodneme, že na starých binárkách nezáleží? Ostuda.

    -- Grant Likely

    Anatomie systémového volání, část druhá

    link

    V minulém článku jsme prozkoumávali jadernou implementaci systémových volání (syscallů) v nejčistší podobě: obyčejné systémové volání na nejběžnější architektuře: x86_64. Završujeme náš pohled na systémová volání variacemi na toto základní téma pohledem na jiné architektury x86 a ostatní mechanismy systémových volání. Začneme průzkumem různých 32bitových variant x86, pro které se může hodit mapa teritoria. Z mapy je možné se prokliknout přes názvy souborů a popisky šipek na zmiňovaný kód:

    Systémová volání na x86_32 přes SYSENTER

    Běžný způsob provedení systémového volání na 32bitovém systému x86_32 je blízce podobný mechanismu na systémech x86_64, který jsme popisovali minule. Tabulka arch/x86/syscalls/syscall_32.tbl má položku pro sys_read:

        3	i386	read			sys_read

    Tato položka značí, že read() pro x86_32 má systémové volání číslo 3 se vstupním bodem sys_read() a konvencí volání i386. Skript zpracovávající tabulky vytvoří makro __SYSCALL_I386(3, sys_read, sys_read), a to do souboru arch/x86/include/generated/asm/syscalls_32.h. Podle tohoto se pak zase sestavuje tabulka volání sys_call_table, stejně jako minule.

    Posuneme-li se dále, pak ke sys_call_table je přistupováno ze vstupního bodu ia32_sysenter_targetarch/x86/kernel/entry_32.S. Zde však makro SAVE_ALL vloží na zásobník jinou sadu registrů (EBX/ECX/EDX/ESI/EDI/EBP namísto RDI/RSI/RDX/R10/R8/R9), což odpovídá odlišnosti v ABI systémových volání na této platformě.

    Umístění vstupního bodu ia32_sysenter_target se zapisuje do registru specifického pro registr (Model-Specific Register; MSR) při spuštění CPU (v enable_sep_cpu()); v tomto případě se jedná o registr MSR_IA32_SYSENTER_EIP (0x176) používaný pro obsluhu instrukce SYSENTER.

    Toto nám ukazuje způsob vyvolání z uživatelského prostoru. Standardní moderní ABI pro vyvolávání systémových volání na x86_32 stanovuje, že číslo volání (3 pro read()) je umístěno do registru EAX, další parametry do konkrétních dalších registrů (EBX, ECX a EDX pro první tři) a pak je vyvolána instrukce SYSENTER.

    Tato instrukce způsobí, že se procesor přepne do ring 0 a spustí kód, na který ukazuje registr MSR_IA32_SYSENTER_EIP – konkrétně ia32_sysenter_target. Tento kód vloží registry na (jaderný) zásobník a zavolá ukazatel na funkci v položce dle čísla EAX z tabulky sys_call_table – konkrétně sys_read(), které je tenkým obalením pro skutečnou implementaci SYSC_read().

    Systémová volání na x86_32 přes INT 0x80

    K tabulce sys_call_table se přistupuje i přes arch/x86/kernel/entry_32.S ze vstupního bodu system_call. I zde se registry vkládají na zásobník, pak se použije EAX pro volbu příslušné položky v sys_call_table a zavolání. V tomto případě se umístění system_call používá v trap_init():

    #ifdef CONFIG_X86_32
    	set_system_trap_gate(SYSCALL_VECTOR, &system_call);
    	set_bit(SYSCALL_VECTOR, used_vectors);
    #endif
    

    Toto nastaví obsluhu SYSCALL_VECTOR na system_call; neboli stanoví jej příjemcem softwarového přerušení INT 0x80.

    Toto je původní způsob uskutečnění systémových volání, který se už nyní obecně nepoužívá, jelikož je na moderních procesorech pomalejší než instrukce speciálně navržené pro systémová volání (SYSCALL a SYSENTER).

    Programy používající toto starší ABI postupují v podstatě stejně jako programy používající SYSENTER. Číslo volání jde opět do EAX, první tři parametry pak do EBX, ECX a EDX.

    Různé způsoby na x86 – shrnutí

    link

    Pro shrnutí jsme doposud viděli tyto mechanismy spouštění systémových volání na x86:

    • 64bitové programy používají instrukci SYSCALL. S touto instrukcí původně přišlo AMD, ale následně byla implementována i na 64bitových procesorech Intel (x86), proto jde o nejlepší volbu pro přenositelnost.
    • Moderní 32bitové programy používají instrukci SYSENTER, která existuje už od uvedení architektury IA-32 (v procesorech Pentium II).
    • Staré 32bitové programy používají instrukci INT 0x80 pro vyvolání obsluhy softwarového přerušení, což je ale na moderních procesorech mnohem pomalejší než SYSENTER.

    Spuštění systémových volání pro x86_32 na x86_64

    link

    Teď tu máme jednu složitější situaci: co se stane spustíme-li 32bitovou binárku na našem x86_64 systému? Z pohledu uživatelského prostoru se nic neliší; po pravdě se ani nic lišit nemůže, protože spouštíme ten samý uživatelský kód.

    Pro SYSENTER 64bitové jádro zaregistruje jako obsluhu pro MSR_IA32_SYSENTER_EIP jinou funkci. Tato funkce má stejné jméno (ia32_sysenter_target) jako na x86_32, ale jinou definici (v arch/x86/ia32/ia32entry.S). Sice dává na zásobník ty samé registry, ale používá jinou tabulku ia32_sys_call_table. Tato tabulka je sestavena z 32bitové tabulky položek; například tedy bude mapovat na sys_read() položku 3 (jako je to na 32bitových systémech) namísto 0 (což odpovídá read() na 64bitových systémech).

    Pro INT 0x80 kód v trap_init() na x86_64 spouští:

    #ifdef CONFIG_IA32_EMULATION
    	set_system_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
    	set_bit(IA32_SYSCALL_VECTOR, used_vectors);
    #endif
    

    Toto mapuje IA32_SYSCALL_VECTOR (které je stále 0x80) na ia32_syscall. Vstupní bod v assembleru (v arch/x86/ia32/ia32entry.S používá místo 64bitové tabulky sys_call_table tabulku ia32_sys_call_table.

    Složitější příklad: execve a kompatibilita s 32bitovými aplikacemi

    link

    Podívejme se na systémové volání, které s sebou nese další komplikace: execve(). Pro přehled oblasti, kterou budeme prozkoumávat, je tu opět klikací mapa:

    Definice execve()fs/exec.c se podobá read(), ale hned po ní se v souboru nachází zajímavá dodatečná funkce (alespoň tehdy, když je definováno CONFIG_COMPAT):

    SYSCALL_DEFINE3(execve,
    		const char __user *, filename,
    			const char __user *const __user *, argv,
    			const char __user *const __user *, envp)
    {
    		return do_execve(getname(filename), argv, envp);
    }
    #ifdef CONFIG_COMPAT
    asmlinkage long compat_sys_execve(const char __user * filename,
    		const compat_uptr_t __user * argv,
    		const compat_uptr_t __user * envp)
    {
    		return compat_do_execve(getname(filename), argv, envp);
    }
    #endif
    

    Tyto dvě implementace se nakonec sejdou v do_execve_common(), kde je samotná implementace volání (sys_execve()do_execve()do_execve_common() versus compat_sys_execve()compat_do_execve()do_execve_common()), cestou vytváří struktury user_arg_ptr. Tyto struktury obsahují ty argumenty systémových volání, které jsou ukazatelem na ukazatel spolu s údajem, zda pocházejí z 32bitového ABI; pokud ano, pak je hodnota, na kterou se ukazuje, 32bitovou adresou v uživatelském prostoru, nikoliv 64bitová hodnota, a kód pro kopírování hodnot argumentů musí s tímto počítat.

    Na rozdíl od read(), kde implementace nemusela rozlišovat mezi 32bitovým a 64bitovým volajícím, protože argumenty byly ukazatelem na hodnoty, execve() toto rozlišovat musí, neboť má argumenty, které jsou ukazatelem na ukazatel. Toto je vcelku běžné – najdeme i další funkce compat_sys_name, které řeší argumenty s ukazatelem na ukazatel (nebo ukazatelem na strukturu obsahující ukazatel, například struct iovec nebo struct aiocb).

    ABI x32

    link

    Komplikace způsobené dvěma variantami implementace execve() se šíří od kódu až do tabulek volání. Pro x86_64 má 64bitová tabulka pro execve() hned dvě položky:

    59	64	execve			stub_execve
    ...
    520	x32	execve			stub_x32_execve
    

    Dodatečná položka s číslem 520 je určena pro programy používající x32 ABI, které běží na procesorech x86_64 v 64bitovém režimu, ale používají 32bitové ukazatele. Kvůli tomu pak máme pro execve() položky dvě.

    I když je toto naše první zmínka o x32 ABI, předchozí příklad s read() už kompatibilitu s x32 nenápadně obsahoval. Jelikož nebyl zapotřebí žádný překlad adres ukazatele na ukazatel, cesta spouštění systémového volání (stejně jako číslo volání) může být sdílena se 64bitovou verzí.

    stub_execve i stub_x32_execve jsou obě definovány v arch/x86/kernel/entry_64.S. Tyto vstupní body volají sys_execve a compat_sys_execve, ale také na jaderný zásobník ukládají dodatečné registry (R12-R15, RBX a RBP). Podobná obalení stub_* jsou v arch/x86/kernel/entry_64.S i pro ostatní volání (rt_sigreturn(), clone(), fork() a vfork()), kde může být potenciálně nutnost obnovit spouštění kódu v uživatelském prostoru na jiné adrese nebo s jiným zásobníkem než v době spuštění volání.

    Pro x86_32 má 32bitová tabulka položku pro execve v trochu jiném formátu než pro read():

    11	i386	execve			sys_execve			stub32_execve
    

    Z ní se dozvídáme, že execve() je na 32bitových systémech volání číslo 11, na rozdíl od 59 (nebo 520) na 64bitových systémech. Zajímavější ovšem je to, že se tam nachází dodatečné sloupeček, kde je vstupní bod stub32_execve pro kompatibilitu. Pro nativní 32bitové sestavení jádra je toto dodatečné pole ignorováno a sys_call_tablesys_execve() jako položku 11 – jako obvykle.

    Pro 64bitové sestavení jádra ale kód pro kompatibilitu s IA-32 vkládá stub32_execve() jako vstupní bod do tabulky ia32_sys_call_table. Tento bod je definován v arch/x86/ia32/ia32entry.S jako:

    PTREGSCALL stub32_execve, compat_sys_execve
    

    Makro PTREGSCALL připraví vstupní bod stub32_execve, který volá compat_sys_execve() a ukládá do jaderného zásobníku dodatečné registry (R12-R15, RBX a RBP), podobně jako stub_execve() výše.

    gettimeofday(): vDSO

    Některá systémová volání čtou z jádra jen malý objem informací a pro ně představuje plný přechod mezi ringy příliš velkou režii. Mechanismus vDSO (Virtual Dynamically-linked Shared Object; virtuální dynamicky linkovaný objekt) urychluje některá z těchto volání, která nedělají žádné změny, tím, že mapuje stránku se souvisejícími informacemi (spolu s kódem pro jejich čtení) do uživatelského prostoru (jen ke čtení). Stránka má formát sdílené knihovny ELF, tudíž je možné ji přímo linkovat do uživatelských programů.

    Pokud spustíme ldd na obyčejné binárce používající glibc, pak uvidíme vDSO jakožto závislost na linux-vdso.so.1 nebo linux-gate.so.1 (ke kterému ldd nedokáže najít příslušný soubor); je vidět i v mapě paměťového prostoru ([vdso]cat /proc/PID/maps).

    Dříve se používalo vsyscall, které dělalo cosi podobného, ale nyní je vsyscall zastaralé kvůli bezpečnostním obavám. Tento starší článek od Johana Peterssona podrobně rozebírá, jak se stránka příslušící k vsyscall objeví jako ELF objekt v uživatelském prostoru.

    Funkčnost vDSO popisuje tento článek na Linux Journalu (i když už není úplně aktuální), takže si tu popíšeme jen základy na příkladu se systémovým voláním gettimeofday().

    gettimeofday() v první řadě potřebuje přistupovat k datům. Aby to bylo možné, tak je příslušná struktura vsyscall_gtod_data exportována do speciální datové sekce .vvar_vsyscall_gtod_data. Povely pro linker se pak postarají o to, aby sekce .vvar_vsyscall_gtod_data byla slinkována do jádra do sekce __vvar_page a při spuštění jádra funkce setup_arch() zavolá map_vsyscall(), aby bylo pro __vvar_page připraveno fixní mapování.

    Kód poskytující implementaci gettimeofday() pro vDSO je v __vdso_gettimeofday(). Je označen jako notrace, aby kompilátory nikdy nepřidávaly profilování funkcí, a má také slabý alias na gettimeofday().

    Aby byla stránka s vDSO přístupná nově spuštěnému programu, kód v setup_additional_pages() nastaví umístění stránky s vDSO na náhodnou adresu zvolenou v vdso_addr() při spuštění procesu. Používání náhodné adresy potlačuje bezpečnostní problémy dřívější implementace vsyscall, ale znamená také to, že program potřebuje mít jak vDSO najít. Umístění je sděleno pomocí dodatečné hodnoty ELF (auxiliary value). Program pak může najít stránku pomocí funkce getauxval(), i když toto běžně řeší libc.

    Doplňme, že mechanismus vDSO je používán i pro jinou důležitou věc související se systémovými voláními ve 32bitových programech. Při bootu jádro zjistí, který z různých způsobů volání jádra je nejlepší a umístí příslušnou obalující funkci (pro SYSENTER, INT 0x80 nebo dokonce SYSCALL na 64bitových CPU AMD) do funkce __kernel_vsyscall. Uživatelské programy pak mohou spustit tuto obalující funkci a mají jistotu, že pro uskutečnění systémových volání používají ten nejrychlejší způsob.

    Závěr

    link

    Systémová volání jsou už desítky let standardním způsobem, jak uživatelské programy komunikují s unixovými jádry. Proto Linux obsahuje sadu nástrojů usnadňujících jejich definici a používání. Navzdory odlišnostem mezi různými architekturami jsou systémová volání stále velmi jednotným mechanismem – tato stabilita umožňuje všemožným nástrojům, od strace až po seccomp-bpf, pracovat obecným způsobem.

           

    Hodnocení: 100 %

            špatnédobré        

    Nástroje: Tisk bez diskuse

    Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

    Komentáře

    Vložit další komentář

    18.8.2014 22:37 zde
    Rozbalit Rozbalit vše Re: Jaderné noviny – 17. 7. 2014: 32bitová systémová volání na x86
    : Uživatelské programy pak mohou spustit tuto obalující funkci a mají jistotu, že pro uskutečnění systémových volání používají ten nejrychlejší způsob.

    Jo, obalující funkce jsou jako pruhy na adidasu.
    ISSN 1214-1267   www.czech-server.cz
    © 1999-2015 Nitemedia s. r. o. Všechna práva vyhrazena.