Redaktor:Fabcde/pieskovisko
|
Toto je pieskovisko redaktora Fabcde. Pieskovisko je podstránkou stránky redaktora. Slúži na vytváranie článkov, testovanie a experimenty redaktora, nie je to encyklopedický článok. Ďalšie pieskoviská: Hlavné pieskovisko | Šablóny | Moduly |
Zdvojnásobovanie[upraviť | upraviť zdroj]
Zdvojnásobovanie je metóda (algoritmus) používaná k výpočtu súčinu dvoch činiteľov. Táto metóda umožňovala v dobe pred objavením základných aritmetických algoritmov nahradiť operáciu násobenia operáciami sčítavania.
Zdvojnásobovanie bolo v minulosti považované tiež za jednu zo základných matematických operácií.
Ukážka výpočtu[upraviť | upraviť zdroj]
Pre nájdenie súčinu rozložíme menší činiteľ na súčet mocnín čísla :
a opakovaným zdvojnásobovaním väčšieho činiteľa vypočítame jeho násobky mocnín čísla :
2n | 2n·639 | |
---|---|---|
0 | 1 | 639 |
1 | 2 | 1278 |
2 | 4 | 2556 |
3 | 8 | 5112 |
4 | 16 | 10224 |
5 | 32 | 20448 |
6 | 64 | 40896 |
Platí:
WikiKnihy
Assembler na platforme Windows 64-bit - x86-64
Úvod[upraviť | upraviť zdroj]
Toto sú poznámky k niekoľkým jednoduchým programom napísaných v jazyku symbolických adries (assembly language) pre operačný systém Windows 64-bit na procesore x86-64. Programy sú písané pre prekladač (kompilátor) Netwide Assembler (NASM), alebo pre GNU Assembler (GAS).
Kvôli jednoduchšiemu rozlíšeniu majú zdrojové súbory programov pre kompilátor NASM príponu .asm, objektové .obj, pre GNU Assembler .s, resp .o.
Objektové súbory sú zlinkované do výsledného exe súboru pomocou linkeru golink, alebo ld. Kompilátor as (GNU Assembler) a linker ld je súčasťou gcc.
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 aj opačné poradie argumentov v niektorých inštrukciách. Napríklad inštrukcia "vlož hodnotu nula do registra AX" sa v NASM zapisuje MOV AX, 0, v GAS MOV $0, %AX. Intelovská syntax (NASM) pripomína priraďovací príkaz vyšších programovacích jazykov AX=0, AT&T syntax (GAS) skôr niečo ako 0->AX.
Volacie konvencie[upraviť | upraviť zdroj]
Programy bežiace v Reálnom móde (operačný systém MS-DOS) alebo v móde (režime) 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 INT 21h. 64-bitové verzie OS Windows režim Virtual 8086 nepodporujú. Služby operačného systému je možné zabezpečiť jedine volaním funkcií Windows API (WinAPI). Podprogramu (funkcii) je potrebné väčšinou nejakým spôsobom odovzdať argumenty a opačným smerom zase výsledok. V princípe neexistujú žiadne obmedzenia, ako by si mali alebo nemali medzi sebou volaný a volajúci podprogram odovzdávať dáta. Je možné zvoliť akýkoľvek fungujúci spôsob, či už pomocou registrov, pamäti, zásobníka, len treba vedieť o každej jednej volanej funkcii/podprograme, kde očakáva argumenty a kam ukladá výsledok (volacia konvencia).
Toto sú niektoré (najbežnejšie) volacie konvencie (calling convention) vo svete Windows:
- cdecl - C declaration, pochádza z jazyka C, parametre sú ukladané na zásobník postupne z prava do ľava (kvôli podpore premenlivého počtu argumentov), výsledok je uložený buď v registry EAX (integer) alebo ST0 (float), zásobník čistí volajúca funkcia
- pascal - parametre sú ukladané na zásobník z ľava do prava, zásobník čistí volaná funkcia (napríklad inštrukciou RET n)
- stdcall - štandard pre Win32 API, parametre sú ukladané na zásobník z prava do ľava (ako cdecl), ale zásobník čistí volaná funkcia (ako pascal)
- Microsoft x64 - volania WinAPI v 64-bitových programoch pre MS Windows, prvé štyry parametre sú uložené v RCX/XMM0, RDX/XMM1, R8/XMM2, R9/XMM3 (integer/float), zvyšné v zásobníku z prava do ľava, výsledok je vrátený v registry RAX alebo XMM0, zásobník čistí volajúca funkcia
Hello, World![upraviť | upraviť zdroj]
Náš prvý NASM program vypíše v príkazovom riadku krátky text a skončí:
; HelloWorld.asm
; kompilacia:
; nasm -f win64 HelloWorld.asm
; linkovanie:
; golink /console /ni /entry main HelloWorld.obj kernel32.dll
; alternativne linkovanie:
; ld -e main -s HelloWorld.obj -o HelloWorld.exe c:\windows\system32\kernel32.dll
global main
extern GetStdHandle
extern WriteFile
extern ExitProcess
section .text use64 ; Program code
main:
; rax = GetStdHandle(-11)
; HANDLE hStdHandle = WINAPI GetStdHandle (_In_ DWORD nStdHandle)
; nStdHandle: STD_INPUT_HANDLE=-10 , STD_OUTPUT_HANDLE=-11 , STD_ERROR_HANDLE=-12
mov ecx, dword -11 ; 1. param _In_ DWORD nStdHandle
call GetStdHandle
; rax = WriteFile(%rax, $message, $MESSAGE_LEN, %rsp-4, 0)
; BOOL bErrorFlag = WINAPI WriteFile (_In_ HANDLE hFile, _In_ LPCVOID lpBuffer, _In_ DWORD nNumberOfBytesToWrite, _Out_opt_ LPDWORD lpNumberOfBytesWritten, _Inout_opt_ LPOVERLAPPED lpOverlapped)
; WriteConsole(handle, &msg[0], 13, &written, 0)
mov rcx, rax ; 1. param _In_ HANDLE hFile
mov rdx, qword message ; 2. param _In_ LPCVOID lpBuffer
mov r8d, dword MESSAGE_LEN ; 3. param _In_ DWORD nNumberOfBytesToWrite
mov r9, lpNumberOfBytesWritten ; 4. param _Out_opt_ LPDWORD lpNumberOfBytesWritten
push qword 0 ; 5. param _Inout_opt_ LPOVERLAPPED lpOverlapped
call WriteFile
; ExitProcess(0)
; VOID WINAPI ExitProcess( _In_ UINT uExitCode)
xor ecx, ecx ; UINT je 32 bit aj v 64 bitovom prostredi
call ExitProcess
message: db "Hello, World!",0xd,0xa
MESSAGE_LEN: equ $-message
section .bss use64 ; neinicializovana datova oblast
lpNumberOfBytesWritten: resd 1
Program síce nealokuje miesto v zásobníku, ako to vyžaduje volacia konvencia Microsoft x64 (podrobnosti v ďalšom texte), napriek tomu sa dal zostaviť aj spustiť: kompilácia:
G:\>nasm -f win64 HelloWorld.asm
linkovanie:
G:\>golink /console /ni /entry main HelloWorld.obj kernel32.dll
alebo:
G:\>ld -e main -s HelloWorld.obj -o HelloWorld.exe c:\windows\system32\kernel32.dll
Ak kompilácia a linkovanie prebehlo úspešne, môžme vyskúšať náš prvý 64-bitový program:
G:\>dir
po 10.07.2017 12:55 2 174 HelloWorld.asm
po 10.07.2017 12:56 1 536 HelloWorld.exe
po 10.07.2017 12:56 418 HelloWorld.obj
G:\>HelloWorld.exe
Hello, World!
Direktíva global main
deklaruje návestie main ako globálne a linker ho tak bude môcť použiť ako štartovaciu adresu programu.
Direktíva extern GetStdHandle
deklaruje symbol GetStdHandle ako externý, čiže nachádzajúci sa v niektorom z ďalších pripojených súboroch, v tomto prípade v dynamicky linkovanej knižnici kernel32.dll.
Direktíva section .text use64
uvádza nasledujúci segment ako programový (readonly).
Inštrukcie
mov ecx, dword -11
call GetStdHandle
naplnia register ECX hodnotou -11 (STD_OUTPUT_HANDLE) a zavolajú WinAPI funkciu GetStdHandle.
Funkcia vracia v registry RAX (v súlade s volacou konvenciou) handle zariadenia STDOUT.
Inštrukcie
mov rcx, rax ; 1. param _In_ HANDLE hFile
mov rdx, qword message ; 2. param _In_ LPCVOID lpBuffer
mov r8d, dword MESSAGE_LEN ; 3. param _In_ DWORD nNumberOfBytesToWrite
mov r9, lpNumberOfBytesWritten ; 4. param _Out_opt_ LPDWORD lpNumberOfBytesWritten
push qword 0 ; 5. param _Inout_opt_ LPOVERLAPPED lpOverlapped
call WriteFile
vložia prvé štyri argumenty funkcie WriteFile do príslušných registrov, piaty do zásobníka a zavolajú ju.
Nakoniec
xor ecx, ecx
call ExitProcess
vynuluje obsah registra ECX a ukončí program. Jediným argumentom funkcie ExitProcess (uložený v registry ECX) je exit code programu.
Nasleduje aj verzia pre GNU Assembler:
# HelloWorld.s
# kompilacia:
# as HelloWorld.s -o HelloWorld.o
# linkovanie:
# ld -e main -s HelloWorld.o -o HelloWorld.exe c:\windows\system32\kernel32.dll
# alternativna kompilacia+linkovanie:
# gcc -m64 -nostartfiles -Wl,-emain -o HelloWorld.exe HelloWorld.s c:\windows\system32\kernel32.dll
.section .text
.global main
main:
/* rax = GetStdHandle(-11) */
/* HANDLE hStdHandle = WINAPI GetStdHandle (_In_ DWORD nStdHandle) */
/* nStdHandle: STD_INPUT_HANDLE=-10 , STD_OUTPUT_HANDLE=-11 , STD_ERROR_HANDLE=-12 */
mov $-11, %ecx # 1. param _In_ DWORD nStdHandle
call GetStdHandle
/* rax = WriteFile(%rax, $message, $MESSAGE_LEN, %rsp-4, 0) */
/* BOOL bErrorFlag = WINAPI WriteFile (_In_ HANDLE hFile, _In_ LPCVOID lpBuffer, _In_ DWORD nNumberOfBytesToWrite, _Out_opt_ LPDWORD lpNumberOfBytesWritten, _Inout_opt_ LPOVERLAPPED lpOverlapped) */
/* WriteConsole(handle, &msg[0], 13, &written, 0) */
mov %rax, %rcx # 1. param _In_ HANDLE hFile
mov $message, %rdx # 2. param _In_ LPCVOID lpBuffer
mov $MESSAGE_LEN, %r8d # 3. param _In_ DWORD nNumberOfBytesToWrite
sub $4, %rsp # rezervovanie miesta (4 bajty) v zasobniku pre 4. param
mov %rsp, %r9 # 4. param _Out_opt_ LPDWORD lpNumberOfBytesWritten
pushq $0 # 5. param _Inout_opt_ LPOVERLAPPED lpOverlapped
call WriteFile
/* ExitProcess(0) */
/* VOID WINAPI ExitProcess( _In_ UINT uExitCode) */
xor %ecx, %ecx # 1. param _In_ UINT uExitCode UINT je 32 bit aj v 64 bitovom prostredi
call ExitProcess
message:
.ascii "Hello, World!\n"
MESSAGE_LEN = . - message
kompilacia:
G:\>as HelloWorld.s -o HelloWorld.o
linkovanie
G:\>ld -e main -s HelloWorld.o -o HelloWorld.exe c:\windows\system32\kernel32.dll
alebo
G:\>gcc -m64 -nostartfiles -Wl,-emain -o HelloWorld.exe HelloWorld.s c:\windows\system32\kernel32.dll
Pozn: golink si nerozumel s objektovým súborom kompilátora as
Referencie[upraviť | upraviť zdroj]
- AL CHVÁRIZMÍ. Aritmetický a algebraický traktát. [s.l.] : OPS, 2009. ISBN 978-80-87269-07-7.
[[Kategória:Algoritmy]]