Programovanie v assembleri vo Windows x64 (x86-64): Rozdiel medzi revíziami

Smazaný obsah Přidaný obsah
Fabcde (diskusia | príspevky)
printf
d robot kozmetické zmeny
Riadok 8:
Skompilovaním zdrojového súboru príslušným kompilátorom (nasm resp. as) vznikne [[w:cs:Objektový kód|objektový súbor]], ktorý je následne pomocou [[w:cs:Linker|linkeru]] golink, resp. ld zlinkovaný do výsledného spustiteľného súboru. Kompilátor as (GNU Assembler) a linker ld sú súčasťou [[w:GNU_Compiler_Collection|gcc]]. Kvôli jednoduchšiemu rozlíšeniu majú tu uvedené [[w:Zdrojový_kód|zdrojové súbory]] programov určených pre NASM príponu .asm, objektové .obj, a pre GNU Assembler príponu .s, resp .o.
 
=== Volanie WinAPI ===
Programy bežiace v [[w:cs:Reálný režim|Reálnom móde]] (operačný systém MS-DOS) prípadne aj v móde (režime) [[w:cs:Virtual 8086 mode|Virtual 8086]] (operačný systém Windows) mohli využívať služby operačného systému MS-DOS prostredníctvom [[wikipedia:MS-DOS_API|MS-DOS API]]. Tieto sa volali pomocou [[w:cs:Přerušení#Softwarové přerušení|softvérového prerušenia]] inštrukciou INT, napríklad <code>INT 21h</code><ref>[http://www.cs.cmu.edu/~ralf/files.html Ralf Brown's Interrupt List]</ref>. Nakoľko 64-bitové verzie OS Windows režim Virtual 8086 nepodporujú, služby operačného systému je už možné zabezpečiť výlučne volaním funkcií [[w:cs:Windows API|Windows API]] (WinAPI).
 
Riadok 21:
 
=== Hello, World! ===
Náš prvý program vypíše v príkazovom riadku krátky text a skončí.
 
'''Výpis 1a''' HelloWorld.asm (Verzia pre NASM):<syntaxhighlight lang="nasm" line="1">
Riadok 27:
 
; kompilacia:
; nasm -f win64 HelloWorld.asm
; linkovanie:
; golink /console /ni /entry main HelloWorld.obj kernel32.dll
; alternativne linkovanie:
; ld -e main -s -o HelloWorld.exe HelloWorld.obj c:\windows\system32\kernel32.dll
 
 
Riadok 42:
 
section .bss use64 ; neinicializovana datova oblast
lpNumberOfBytesWritten: resd 1
 
 
section .text use64 ; Program code
message: db "Hello, World!",0xd,0xa
MESSAGE_LEN: equ $-message
 
main:
Riadok 84:
</syntaxhighlight>Ak kompilácia a linkovanie prebehli úspešne, môžme vyskúšať náš prvý 64-bitový program:<syntaxhighlight>
G:\>dir
15.07.2017 13:27 2 193 HelloWorld.asm
15.07.2017 13:27 1 536 HelloWorld.exe
15.07.2017 13:27 551 HelloWorld.obj
 
G:\>HelloWorld.exe
Riadok 135:
 
# kompilacia:
# as -o HelloWorld.o HelloWorld.s
# linkovanie:
# ld -e main -s -o HelloWorld.exe HelloWorld.o c:\windows\system32\kernel32.dll
# alternativna kompilacia+linkovanie:
# gcc -m64 -nostartfiles -Wl,-emain -o HelloWorld.exe HelloWorld.s c:\windows\system32\kernel32.dll
 
.global main
 
.section .bss
lpNumberOfBytesWritten: .space 4
 
.section .text
message: .ascii "Hello, World!\r\n"
MESSAGE_LEN = . - message
 
Riadok 185:
</syntaxhighlight>Výsledok:<syntaxhighlight>
G:\>dir
15.07.2017 15:32 2 200 HelloWorld.s
16.07.2017 12:48 584 HelloWorld.o
16.07.2017 12:48 1 536 HelloWorld.exe
 
G:\>HelloWorld.exe
Riadok 204:
MOV [RSP], RAX
</syntaxhighlight>Keďže architektúra x86/x86-64 používa na ukladanie viac-bajtových hodnôt usporiadanie [[w:Endianita|little-endian]], t.j. na nižšej adrese je uložený menej významný/nižší bajt, v zásobníku bude preto register RAX uložený:<syntaxhighlight>
| |
| |
+==============+
| 0. bajt | <- RSP = Vrchol zásobníka po (nižšia adresa)
+--------------+
| 1. bajt | ^
+--------------+ |
| 2. bajt | |
+--------------+ |
| 3. bajt | |
+--------------+ |
| 4. bajt | | RSP - 8
+--------------+ |
| 5. bajt | |
+--------------+ |
| 6. bajt | |
+--------------+ |
| 7. bajt | |
+==============+
| . | <- RSP = Vrchol zásobníka pred
+--------------+
| . |
+--------------+
| . |
+==============+ <- Dno zásobníka (vyššia adresa)
</syntaxhighlight>Z vrcholu zásobníka sa hodnoty vyberajú inštrukciou POP. Inštrukcia <code>POP RAX</code> z vrcholu zásobníka prečíta hodnotu, vloží ju do registra RAX, a následne uvoľní miesto v zásobníku, podobne ako:<syntaxhighlight lang="nasm">
MOV RAX, [RSP]
Riadok 258:
 
''Obsah zásobníka po zavolaní WinAPI funkcie :''<syntaxhighlight>
+---------------------+ (nižšia adresa)
| zarovnanie, | \
| lokálne premenné a | > volaná funkcia
| volatile registre | /
+=====================+
| návratová adresa | CALL \
| z podprogramu (RIP) | |
+---------------------+ |
| 32. bajtov (RCX) | \ |
| shadow space (RDX) | | |
| (R8) | | |
| (R9) | | |
+---------------------+ | |
| 5. argument | | > volajúca funkcia
+---------------------+ | |
| 6. argument | > zodpovednosť volajúceho |
+---------------------+ | za alokovanie a uvoľnenie |
| . | | |
| . | | |
+---------------------+ | |
| posledný argument | | |
+---------------------+ | |
| zarovnanie, | | |
| lokálne premenné a | | |
| volatile registre | / /
+=====================+ (vyššia adresa)
</syntaxhighlight>
 
=== Hello, World! v.2 ===
Program HelloWorld opravený v súlade s volacou konvenciou.
 
'''Výpis 2a''' HelloWorld.asm (Verzia pre NASM):<syntaxhighlight lang="nasm" line="1">
Riadok 292:
 
; kompilacia:
; nasm -f win64 HelloWorld.asm
; linkovanie:
; golink /console /ni /entry main HelloWorld.obj kernel32.dll
; alternativne linkovanie:
; ld -e main -s -o HelloWorld.exe HelloWorld.obj c:\windows\system32\kernel32.dll
 
 
Riadok 307:
 
section .bss use64 ; neinicializovana datova oblast
lpNumberOfBytesWritten: resd 1
 
 
section .text use64 ; Program code
message: db "Hello, World!",0xd,0xa
MESSAGE_LEN: equ $-message
 
main:
Riadok 358:
 
# kompilacia:
# as -o HelloWorld.o HelloWorld.s
# linkovanie:
# ld -e main -s -o HelloWorld.exe HelloWorld.o c:\windows\system32\kernel32.dll
# alternativna kompilacia+linkovanie:
# gcc -m64 -nostartfiles -Wl,-emain -o HelloWorld.exe HelloWorld.s c:\windows\system32\kernel32.dll
 
.global main
 
.section .bss
lpNumberOfBytesWritten: .space 4
 
.section .text
message: .ascii "Hello, World!\15\12"
MESSAGE_LEN = . - message
 
Riadok 420:
 
; kompilacia:
; nasm -f win64 HelloWorld.asm
; linkovanie:
; ld -e main -s -o HelloWorld.exe HelloWorld.obj C:\opt\mingw64\x86_64-w64-mingw32\lib\libmsvcrt.a
; alternativne linkovanie:
; gcc -nostartfiles -Wl,-emain,-s -o HelloWorld.exe HelloWorld.obj C:\opt\mingw64\x86_64-w64-mingw32\lib\libmsvcrt.a
 
 
global main
 
extern printf
 
 
section .text use64 ; Program code
message: db "Hello, World!",0xd,0xa,0
 
main:
Riadok 462:
 
; kompilacia:
; nasm -f win64 IntToStr.asm
; linkovanie:
; golink /console /ni /entry main IntToStr.obj kernel32.dll
; alternativne linkovanie:
; ld -e main -s -o IntToStr.exe IntToStr.obj c:\windows\system32\kernel32.dll
 
 
Riadok 477:
 
section .data use64 ; Program code
buffer: times 20 db " " ; Najvacsie 64-bitove cislo bez znamienka ma 20 cifier (2**64 - 1 = 18446744073709551615)
enter: db 0xd,0xa
lpNumberOfBytesWritten: dd 0
BUFFER_LEN: equ enter-buffer
NEWLINE_LEN: equ lpNumberOfBytesWritten-enter
 
 
Riadok 534:
 
# kompilacia:
# as -o IntToHex.o IntToHex.s
# linkovanie:
# ld -e main -s -o IntToHex.exe IntToHex.o c:\windows\system32\kernel32.dll
# alternativna kompilacia+linkovanie:
# gcc -m64 -nostartfiles -Wl,-emain -o IntToHex.exe IntToHex.s c:\windows\system32\kernel32.dll
 
.global main
 
.section .data
buffer: .ascii " " /* Najvacsie 64-bitove cislo bez znamienka ma v setnastkovej sustave 16 cifier (2**64 - 1 = ffffffffffffffff) */
enter: .ascii "h\r\n"
lpNumberOfBytesWritten: .long 0
BUFFER_LEN = enter - buffer
NEWLINE_LEN = lpNumberOfBytesWritten - enter
 
 
Riadok 614:
<references />
 
== Ďalšie zdroje ==
* http://cs.lmu.edu/~ray/notes/x86assembly/
* http://frdsa.fri.uniza.sk/~janosik/Kniha/ProgJSA.html