Programovanie v assembleri vo Windows x64 (x86-64): Rozdiel medzi revíziami
Smazaný obsah Přidaný obsah
dBez shrnutí editace |
|||
Riadok 1:
Toto sú poznámky k niekoľkým jednoduchým programom napísaných v jazyku [[w:Jazyk_symbolických_inštrukcií|symbolických adries]] (assembly language) určených pre [https://cs.wikipedia.org/wiki/Po%C4%8D%C3%ADta%C4%8Dov%C3%A1_platforma platformu] '''[[w:X86-64|x86-64]]''' – '''Windows x64'''. Väčšinou sú uvedené dve verzie programov, prvá pre [[w:Prekladač|prekladač]] (kompilátor) [[w:Netwide_Assembler|Netwide Assembler]] (NASM), druhá pre [https://cs.wikipedia.org/wiki/GNU_Assembler GNU Assembler] (GAS).
== Stručný prehľad ==
=== Syntax a kompilácia ===
NASM používa syntax Intelu, dominujúcu v prostredí MS-DOS a Windows, GNU Asembler používa syntax AT&T, prevládajúcu v Unixovom svete. Jedným z rozdielov týchto dvoch syntaxí je opačné poradie argumentov v niektorých inštrukciách.<ref>Ram Narayan (2007-10-17). [https://www.ibm.com/developerworks/library/l-gas-nasm/index.html "Linux assemblers: A comparison of GAS and NASM"]
</ref> Napríklad inštrukcia "vlož hodnotu nula do registra AX" sa v NASM zapisuje <code>MOV AX, 0</code>, v GAS <code>MOV $0, %AX</code>. Intelovská syntax (NASM) pripomína priraďovací príkaz vyšších programovacích jazykov <code>AX=0</code>, AT&T syntax (GAS) skôr niečo ako <code>0->AX</code>.
Řádek 7 ⟶ 9:
[https://cs.wikipedia.org/wiki/Objektov%C3%BD_k%C3%B3d Objektové súbory] sú zlinkované do spustiteľného exe súboru pomocou [https://cs.wikipedia.org/wiki/Linker linkeru] golink, alebo ld. Kompilátor as (GNU Assembler) a linker ld sú súčasťou [[w:GNU_Compiler_Collection|gcc]]. Kvôli jednoduchšiemu rozlíšeniu majú [[w:Zdrojový_kód|zdrojové súbory]] programov určených pre kompilátor NASM príponu .asm, objektové .obj, pre GNU Assembler .s, resp .o.
===
Programy bežiace v [https://cs.wikipedia.org/wiki/Re%C3%A1ln%C3%BD_re%C5%BEim Reálnom móde] (operačný systém MS-DOS) alebo v móde (režime) [https://cs.wikipedia.org/wiki/Virtual_8086_mode Virtual 8086] (operačný systém Windows) mohli využívať služby operačného systému MS-DOS (MS-DOS API). Tieto sa volali pomocou softvérového prerušenia inštrukciou INT, napríklad <code>INT 21h</code>. 64-bitové verzie OS Windows režim Virtual 8086 nepodporujú. Služby operačného systému je preto možné zabezpečiť jedine volaním funkcií Windows API (WinAPI). Funkcii (podprogramu) je zvyčajne potrebné nejakým spôsobom odovzdať argumenty a opačným smerom zase výsledok. V zásade nie sú žiadne obmedzenia týkajúce sa spôsobu odovzdávania údajov medzi volajúcim a volaným podprogramom. Je možné zvoliť akýkoľvek fungujúci spôsob, či už pomocou registrov, pamäti, zásobníka, atď, len treba o každej volanej funkcii (podprograme) vedieť, kde očakáva argumenty a kam ukladá výsledok ([https://cs.wikipedia.org/wiki/Volac%C3%AD_konvence volacia konvencia]).
Řádek 179 ⟶ 181:
Hello, World!
</syntaxhighlight>
== Volacia konvencia Microsoft x64 ==▼
=== Zásobník ===
Zásobník je možné používať ľubovoľne podľa potreby. Bežne sa používa na ukladanie lokálnych premenných a aj dočasných, pomocných hodnôt. Používa sa aj na odovzdávanie argumentov podprogramu. Inštrukcia CALL na vrchol zásobníka tiež ukladá návratovú adresu z podprogramu.
V architektúrach x86 a x86-64 sa ku zásobníku pristupuje pomocou inštrukcií PUSH a POP. Zásobník rastie (plní sa) smerom od vyššej adresy k nižšej. Na jeho vrchol ukazuje register RSP. (RSP obsahuje najnižšiu adresu, na ktorej je niečo uložené).
SUB RSP, 8
MOV [RSP], RAX
</syntaxhighlight>Keďže architektúra x86/x86-64 používa na ukladanie viac-bajtových hodnôt usporiadanie little-endian, t.j.
| |
+==============+
Řádek 213 ⟶ 214:
+--------------+
| . |
| . |
+==============+ <- Dno zásobníka
</syntaxhighlight>Z vrcholu zásobníka sa hodnoty vyberajú inštrukciou POP. Inštrukcia <code>POP RAX</code> z
</syntaxhighlight>K dátam uloženým v zásobníku je možné stále pristupovať aj priamo, ako ku hocijakým iným dátam uloženým kdekoľvek v pamäti, napríklad pomocou relatívneho odkazu na vrchol zásobníka <code>MOV EAX, [RSP+4]</code>.▼
▲Z vrcholu zásobníka sa hodnoty vyberajú inštrukciou POP. Inštrukcia <code>POP RAX</code> z vrchola zásobníka prečíta hodnotu, vloží ju do registra RAX, a následne uvoľní miesto, podobne ako<syntaxhighlight lang="nasm">
MOV RAX, [RSP]
ADD RSP, 8
▲</syntaxhighlight>
</syntaxhighlight>Pamäť zásobníka mimo rozsahu vymedzenom registrom RSP je nestála (volatile) a môže ju prepísať OS alebo debuger. Pri ukladaní údajov na vrchol zásobníka je preto nutné vždy najskôr alokovať potrebný priestor (napríklad <code>SUB RSP, n</code>) a až do takto alokovanej pamäte možno potom niečo bezpečne uložiť. Nepotrebné miesto na vrchole zásobníka uvoľní <code>ADD RSP, n</code>.▼
MOV EAX, [RSP+4]
▲</syntaxhighlight>Pamäť zásobníka mimo rozsahu vymedzenom registrom RSP je nestála (volatile) a môže ju prepísať OS alebo debuger.
SUB RSP, n
</syntaxhighlight>Nepotrebné miesto na vrchole zásobníka uvoľní:<syntaxhighlight lang="nasm">
ADD RSP, n
</syntaxhighlight>
▲=== Volacia konvencia Microsoft x64 ===
Volanie funkcie (podprogramu) sa realizuje
Volacia konvencia Microsoft x64 vyžaduje, aby v zásobníku bolo alokovaných ďalších 32 bajtov
Registre RAX, RCX, RDX, R8, R9, R10, R11 sú považované za nestále (volatile) a volaná funkcia ich môže kedykoľvek trvalo zmeniť. Volajúci ich samozrejme môže po návrate z funkcie obnoviť, ak si predtým uschoval ich hodnoty. Naopak, registre RBX, RBP, RDI, RSI, RSP, R12, R13, R14 a R15 sú považované za stále
| lokálne premenné a |
| volatile
+---------------------+▼
| volatile registre |▼
| návratová adresa | CALL▼
▲+-------------------+
▲| návratová adresa | CALL
+---------------------+ ▼
▲| z podprogramu (RIP) |
▲+-------------------+
| shadow
|
|
+---------------------+ |▼
▲| (R9) | |
▲+-------------------+ |
+---------------------+ |▼
|
▲+-------------------+ |
+---------------------+ |▼
▲| 6. argument | |
| . | |▼
▲+-------------------+ |
+---------------------+ |▼
▲| . | |
▲+-------------------+ |
+---------------------+ |▼
▲| posledný argument | /
| lokálne premenné a | |▼
▲+-------------------+
▲| volatile registre | /
▲| lokálne premenné |
+---------------------+
▲+-------------------+
</syntaxhighlight>
|