Programovanie v assembleri vo Windows x64 (x86-64): Rozdiel medzi revíziami
Smazaný obsah Přidaný obsah
d zalamovanie Značka: editor wikitextu 2017 |
printf |
||
Riadok 31:
; golink /console /ni /entry main HelloWorld.obj kernel32.dll
; alternativne linkovanie:
; ld -e main -s
Riadok 131:
'''Výpis 1b''' HelloWorld.s (Verzia pre GAS):
<syntaxhighlight lang="
# HelloWorld.s
# kompilacia:
# as
# linkovanie:
# ld -e main -s
# alternativna kompilacia+linkovanie:
# gcc -m64 -nostartfiles -Wl,-emain -o HelloWorld.exe HelloWorld.s c:\windows\system32\kernel32.dll
Riadok 151:
main:
mov $-11, %ecx
call GetStdHandle
mov %rax, %rcx
mov $message, %rdx
mov $MESSAGE_LEN, %r8d
mov $lpNumberOfBytesWritten, %r9
pushq $0
call WriteFile
add $8, %rsp
mov $0, %ecx
call ExitProcess
Riadok 296:
; golink /console /ni /entry main HelloWorld.obj kernel32.dll
; alternativne linkovanie:
; ld -e main -s
Riadok 351:
xor ecx, ecx ; 1. param _In_ UINT uExitCode UINT je 32 bit aj v 64 bitovom prostredi
</syntaxhighlight>
Je to pokus o optimalizáciu kódu, kedže inštrukcia xor ecx,ecx tiež vynuluje obsah registra ECX, ale po preložení zaberá menej bajtov. Optimalizácia kódu je však dnes kvôli prúdovému spracovaniu inštrukcií ([[w:cs:Pipelining|pipelining]]),
'''Výpis 2b''' HelloWorld.s (Verzia pre GAS):
<syntaxhighlight lang="
# HelloWorld.s
# kompilacia:
# as
# linkovanie:
# ld -e main -s
# alternativna kompilacia+linkovanie:
# gcc -m64 -nostartfiles -Wl,-emain -o HelloWorld.exe HelloWorld.s c:\windows\system32\kernel32.dll
Riadok 374:
main:
sub $0x28, %rsp
mov $-11, %ecx
call GetStdHandle
mov %rax, %rcx
mov $message, %rdx
mov $MESSAGE_LEN, %r8d
mov $lpNumberOfBytesWritten, %r9
movq $0, 0x20(%rsp)
call WriteFile
xor %ecx, %ecx
call ExitProcess
add $0x28, %rsp
</syntaxhighlight>Za povšimnutie stojí zápis nepriamej adresácie (používanej napríklad pri indexovaní poľa). Kým v NASM to bolo: <code>mov qword [rsp + 20h], 0</code>, v GAS je "index" uvedený pred zátvorkou: <code>movq $0, 0x20(%rsp)</code>
Riadok 412:
GAS: <code>mov (%rbp, %rsi, 1), %eax</code>
=== Hello, World! v.3 ===
Posledná verzia programu Hello, World vypíše text pomocou funkcie printf štandardnej knižnce jazyka C.
'''Výpis 3a''' HelloWorld.asm:<syntaxhighlight lang="nasm" line="1">
; HelloWorld.asm
; 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:
sub rsp, 28h ; rezervovanie miesta v zasobniku pre shadow space a zarovnanie
; int printf(const char *format, ...)
; rax = printf(message)
mov rcx, qword message
call printf
add rsp, 28h ; uvolnenie rezervovaneho miesta
ret
</syntaxhighlight>Volanie funkcie printf v 64-bitovom windows tiež používa volaciu konvenciu Microsoft x64<ref>https://en.wikipedia.org/wiki/X86_calling_conventions#List_of_x86_calling_conventions</ref>.
== Rozširujeme ==
Řádek 422 ⟶ 458:
Napríklad vydelením čísla 321 : 10 dostaneme neúplný podiel 32, zvyšok je 1. Pokračujeme v delení s neúplným podielom 32 : 10 = 3, zvyšok 2, a nakoniec 3 : 10 = 0, zvyšok 3. Zvyšok postupne obsahoval jednotlivé cifry 1, 2, 3, ktoré musíme previesť na zodpovedajúci ASCII znak.
'''Výpis
; IntToStr.asm
Řádek 430 ⟶ 466:
; golink /console /ni /entry main IntToStr.obj kernel32.dll
; alternativne linkovanie:
; ld -e main -s
Řádek 494 ⟶ 530:
=== IntToHex ===
'''Výpis
# IntToHex.s
# kompilacia:
# as
# linkovanie:
# ld -e main -s
# alternativna kompilacia+linkovanie:
# gcc -m64 -nostartfiles -Wl,-emain -o IntToHex.exe IntToHex.s c:\windows\system32\kernel32.dll
Řádek 507 ⟶ 543:
.section .data
buffer: .ascii " "
enter: .ascii "h\r\n"
lpNumberOfBytesWritten: .long 0
Řádek 519 ⟶ 555:
IntToHex:
mov $1234567890, %rax
mov $16, %rbx
lea (buffer+BUFFER_LEN-1), %rdi
vydel:
xor %rdx, %rdx
div %rbx
cmp $10, %dl
jl doDesat
add $7, %dl
doDesat:
add $'0', %dl
mov %dl, (%rdi)
sub $1, %rdi
or %rax, %rax
jnz vydel
vypis:
sub $0x28, %rsp
mov $-11, %ecx
call GetStdHandle
mov %rax, %rcx
mov $buffer, %rdx
mov $BUFFER_LEN+NEWLINE_LEN, %r8d
mov $lpNumberOfBytesWritten, %r9
movq $0, 0x20(%rsp)
call WriteFile
xor %ecx, %ecx
call ExitProcess
add $0x28, %rsp
</syntaxhighlight>Ak chceme vypísať číslo v inej, napríklad šestnástkovej sústave, stačí deliť príslušným základom číselnej sústavy:<syntaxhighlight lang="gas" line="1" start="26">
mov $16, %rbx
</syntaxhighlight>Tiež je potrebné vysporiadať sa so znakmi ':', ';', '<', '=', '>', '?' a '@', nachádzajúcimi sa v ASCII medzi znakmi '9' a 'A':<syntaxhighlight lang="gas" line="1" start="34">
cmp $10, %dl
jl doDesat
add $7, %dl
doDesat:
add $'0', %dl
</syntaxhighlight>
|