Redaktor:Fabcde/pieskovisko

z Wikipédie, slobodnej encyklopédie
Skočit na navigaci Skočit na vyhledávání

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čí:

 1 ; HelloWorld.asm
 2 
 3 ; kompilacia:
 4 ;   nasm -f win64 HelloWorld.asm
 5 ; linkovanie:
 6 ;   golink /console /ni /entry main HelloWorld.obj kernel32.dll
 7 ; alternativne linkovanie:
 8 ;   ld -e main -s HelloWorld.obj -o HelloWorld.exe c:\windows\system32\kernel32.dll
 9 
10 
11 global main
12 
13 extern GetStdHandle
14 extern WriteFile
15 extern ExitProcess
16 
17 
18         section .text use64            ; Program code
19 main:
20         ; rax = GetStdHandle(-11)
21         ; HANDLE hStdHandle = WINAPI GetStdHandle (_In_ DWORD nStdHandle)
22         ; nStdHandle: STD_INPUT_HANDLE=-10 , STD_OUTPUT_HANDLE=-11 , STD_ERROR_HANDLE=-12
23         mov ecx, dword -11             ; 1. param _In_ DWORD nStdHandle
24         call GetStdHandle
25 
26         ; rax = WriteFile(%rax, $message, $MESSAGE_LEN, %rsp-4, 0)
27         ; BOOL bErrorFlag = WINAPI WriteFile (_In_ HANDLE hFile, _In_ LPCVOID lpBuffer, _In_ DWORD nNumberOfBytesToWrite, _Out_opt_ LPDWORD lpNumberOfBytesWritten, _Inout_opt_ LPOVERLAPPED lpOverlapped)
28         ; WriteConsole(handle, &msg[0], 13, &written, 0)
29         mov rcx, rax                   ; 1. param _In_ HANDLE hFile
30         mov rdx, qword message         ; 2. param _In_ LPCVOID lpBuffer
31         mov r8d, dword MESSAGE_LEN     ; 3. param _In_ DWORD nNumberOfBytesToWrite
32         mov r9, lpNumberOfBytesWritten ; 4. param _Out_opt_ LPDWORD lpNumberOfBytesWritten
33         push qword 0                   ; 5. param _Inout_opt_ LPOVERLAPPED lpOverlapped
34         call WriteFile
35 
36         ; ExitProcess(0)
37         ; VOID WINAPI ExitProcess( _In_ UINT uExitCode)
38         xor ecx, ecx                   ; UINT je 32 bit aj v 64 bitovom prostredi
39         call ExitProcess
40 
41 message:                 db      "Hello, World!",0xd,0xa
42 MESSAGE_LEN:             equ     $-message
43 
44 
45         section .bss use64             ; neinicializovana datova oblast
46 
47 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:

 1 # HelloWorld.s
 2 
 3 # kompilacia:
 4 #   as HelloWorld.s -o HelloWorld.o
 5 # linkovanie:
 6 #   ld -e main -s HelloWorld.o -o HelloWorld.exe c:\windows\system32\kernel32.dll
 7 # alternativna kompilacia+linkovanie:
 8 #   gcc -m64 -nostartfiles -Wl,-emain -o HelloWorld.exe HelloWorld.s c:\windows\system32\kernel32.dll
 9 
10 .section .text
11 
12 .global main
13 
14 main:
15         /* rax = GetStdHandle(-11) */
16         /* HANDLE hStdHandle = WINAPI GetStdHandle (_In_ DWORD nStdHandle) */
17         /* nStdHandle: STD_INPUT_HANDLE=-10 , STD_OUTPUT_HANDLE=-11 , STD_ERROR_HANDLE=-12 */
18         mov $-11, %ecx            # 1. param _In_ DWORD nStdHandle
19         call GetStdHandle
20 
21         /* rax = WriteFile(%rax, $message, $MESSAGE_LEN, %rsp-4, 0) */
22         /* BOOL bErrorFlag = WINAPI WriteFile (_In_ HANDLE hFile, _In_ LPCVOID lpBuffer, _In_ DWORD nNumberOfBytesToWrite, _Out_opt_ LPDWORD lpNumberOfBytesWritten, _Inout_opt_ LPOVERLAPPED lpOverlapped) */
23         /* WriteConsole(handle, &msg[0], 13, &written, 0) */
24         mov %rax, %rcx            # 1. param _In_ HANDLE hFile
25         mov $message, %rdx        # 2. param _In_ LPCVOID lpBuffer
26         mov $MESSAGE_LEN, %r8d    # 3. param _In_ DWORD nNumberOfBytesToWrite
27         sub $4, %rsp              # rezervovanie miesta (4 bajty) v zasobniku pre 4. param
28         mov %rsp, %r9             # 4. param _Out_opt_ LPDWORD lpNumberOfBytesWritten
29         pushq $0                  # 5. param _Inout_opt_ LPOVERLAPPED lpOverlapped
30         call WriteFile
31 
32         /* ExitProcess(0) */
33         /* VOID WINAPI ExitProcess( _In_ UINT uExitCode) */
34         xor %ecx, %ecx            # 1. param _In_ UINT uExitCode UINT je 32 bit aj v 64 bitovom prostredi
35         call ExitProcess
36 
37 message:
38         .ascii  "Hello, World!\n"
39 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]