Upload
idiftl
View
2.268
Download
0
Embed Size (px)
Citation preview
Úvod do x86 strojového kódu a assembleru
Nudný ale nevyhnutný
Na čo preBoha assembler?
● Znalosť vs. využívanie
● Kvalitná znalosť vyžaduje aspoň nejaké využívanie
● Využívanie neznamená len programovanie v ňom
● Využitie:
● Reverse engineering● Driver / system level programming● Copy protection● Machine code manipulation (compiler, packer, analyzer...)● ????● Profit
X86 milestones
● 8086 (16-bit)● 80286 (chránený mód)● 80386 (32-bitový chránený mód + množstvo
nových fičúr)● X86-64● Rozšírené inštrukčné sady: FPU (x87), MMX,
SSE, SSE2, SSE3, SSSE3, SSE4, SSE5, VMX, SMX, SVM, AVX, XOP, ...
“Chrbtica” x86
CPU Northbridge
RAM Video RAM ŔOM
Southbridge
Všetko ostatné
(nie naozaj)
Čo z toho pre nás vyplýva
● Procesor pristupuje k všetkým zariadeniam tým istým mechanizmom (ako k RAM), nepotrebuje zvláštne inštrukcie ● nie celkom pravda, ale pre náš účel užitočná
abstrakcia
● Nebudeme sa zaoberať “systémovými” a málo používanými inštrukciami (segmentácia, stránkovanie, task switching, stránkovanie, 16-bit a real mód)
● Stačí nám zvládnuť základné operácie a prácu s pamäťou
Inštrukcie
● Pokyny pre procesor (CPU) uložené v pamäti● CPU ich číta a vykonáva● Principiálne sa ničím nelíšia od bežných dát v
pamäti● DOS program na riešenie sudoku (62 bytov):
B4 3F 8B D5 CD 21 91 43 88 02 4E 78 F7 B8 31 40 80 3A 2E 75 F5 8B F9 4F 60 78 ED 38 03 75 11 97 D4 13 6B C0 0B 96 43 7B F7 33 C6 A9 C0 E0 7E 02 F6 E4 61 70 E2 C6 02 2E 3C 39 74 F6 EB D1
Zápisy inštrukcii
● Binárny:
00000001 11011000
● Hexadecimálny:
01 D8
0000-0001 1101-1000
● Osmičkový:
001 330
00-000-001 11-011-000
● Desiatkový:
fuj
● Assembler:
add eax, ebx
add %ebx, %eax (fuj)
0000 - 0
0001 - 1
0010 - 2
0011 - 3
0100 - 4
0101 - 5
0110 - 6
0111 - 7
1000 - 8
1001 - 9
1010 - A
1011 - B
1100 - C
1101 - D
1110 - E
1111 - F
“General purpose” registre
● Register = premenná procesoru
● CPU má množstvo registrov, 99.9% času sa ale pracuje s “general purpose” registrami (GPR)
● V bežnej (?) reči preto “Register” = “General Purpose Register”
● x86 má 8 GPR (až x86-64 rozšírilo počet na 16)
● 8086 mal 16-bitové GPR registre:
AX, BX, CX, DX, SP, BP, SI, DI
● Možnosť pristupovať k 8-bit častiam prvých 4 registrov:
AL (low), AH (high), BL, BH, CL, CH, DL, DH
● 386 rozšíril na 32-bitov:
EAX, EBX, ECX, EDX, ESP, EBP, ESI, EDI
Špecializované využitie “general purpose” registrov
0 = [E]AX = accumulator
1 = [E]CX = counter
2 = [E]DX = data
3 = [E]BX = base
4 = [E]SP = stack pointer
5 = [E]BP = base pointer
6 = [E]SI = source index
7 = [E]DI = destrination index
Formát x86 inštrukcie
● Prefix – voliteľný byte pred inštrukciou, menia jej funkčnosť
● Mnemonics – udáva základnú operáciu ktorá sa vykoná
● Operand – udáva register alebo pamäťovú premennp, nad ktorou sa vykoná operácia. Operandy môžu byť 0 až 3.● Operandy musia byť rovnakej veľkosti● Cieľový (destination) operand prvý● Niektoré inštrukcie majú implicitný operand
Presun / priradenie hodnoty GPR
MOV (move)mov eax, 31337
mov ecx, 123
mov esi, edx
mov bh, al
mov al, 500 (neplatná)
mov eax, sp (neplatná)
mov ah, ebx (neplatná)
Súčet / Rozdiel
ADD (addition)add ebx, eax
add esp, 1
INC (increment, jeden operand)inc eax
SUB (subtract)sub ebp, 20
sub eax, ebx
DEC (decrement, jeden operand)dec ecx
Bitové operácie
ANDand al, 11111100b
XORxor al, 101b
ORor al, 100b
NOT (jeden operand)not al
Negatívne čísla
● Čísla ktoré môžu nadobúdať aj zápornú hodnotu sa nazývajú znamienkové
● Existuje niekoľko možností ako ich reprezentovať v binárnej forme
● Najšikovnejší “two's complement”
● Tie isté operácie pre znamienkové aj neznamienkové čísla
● Horný bit udáva znamienko● Podtečenie: najmenšia hodnota – 1 = najväčšia
hodnota● Pretečenie: najväčšia hodnota +1 = najväčšia
hodnota
Two's complement
00000001 (1)
-00000001 (1)
00000000 (0)
00000010 (2)
-00000001 (1)
00000001 (1)
00000111 (7)
-00000010 (2)
00000101 (5)
00000000 (0)
-00000001 (1)
11111111 (255)
00000000 (0)
-00000010 (1)
11111110 (254)
00000011 (3)
+11111111 (255)
00000010 (2)
Negatívne čísla
add eax, ebx
sub ecx, 5
add al, -1
add al, 255
sub al, 1
sub cl, -5
sub cl, 251
add cl, 5
Negácia čísla
NEG (negation)neg eax
neg dx
neg cl
Bitwise spôsobnot eax
inc eax
Napr.:00000001 (1)
not
11111110 (-2)
+1
11111111 (-1)
Pamäť (z pohľadu CPU)
● Pole bytov● Adresovaná 32-bitovým číslom, toto udáva
pozíciu (index) bytu v “poli”.● Nieje možné pristupovať k dvom miestam v
pamäti vrámci jednej inštrukcie● Zápis operandu pre prístup k pamäti v
assembleri:
[adresa] (adresa v hranatých zátvorkách)
Priama adresácia pamäte
mov al, [1]
mov [2], al
add [0], eax
xor esp, [20]
mov [30], [29] - neexistuje
sub [0], [1] - neexistuje
Endianness
● Možnosť pristupovať k pamäti v rôznych veľkostiach
8-bit - byte
16-bit - word
32-bit - dword (double word)
64-bit - qword (quad word, X86-64 only)
● Poradie bytov vo väčších číslach od najmenej významného po najviac významný (tzv. “little endian”)
● byty 00h, 01h = word 100h = word 100000000b = 256● byty 11h, 22h, 33h, 44h = dword 44332211h
Priama adresácia pamäte
mov eax, [1234]
mov eax, dword [1234]
mov [31337], ecx
add [20], ebx
inc byte [0]
inc word [0]
neg dword [1]
Nepriama adresácia pamäte
● Ako adresa môže byť použitá aj hodnota v registri:
mov eax, dword [ebx]
mov al, byte [esi]
● K registru v adrese môže byť pripočítaná konštanta
mov edx, dword [ebx+4]
mov al, byte [esi-1]
Nepriama adresácia pamäte
● Úplná forma 32-bitovej adresácie:
[base + scale*index + displacement]
base - ľubovolný register
scale - konštanta 1, 2, 4, alebo 8
index - ľubovolný register
displacement - číselná 32-bit konštanta● Napríklad:
[ebx + 4*edi + 401224]
[eax + eax] = [2*eax]
[8*eax]
[3*ebx + 3] = [ebx + 2*ebx + 3]
Nepodmienený skok
● JMP (jump, nepodmienený skok)jmp 200
jmp dword [200]
jmp eax
jmp dword [eax]
● V assembleri číselné adresy nahrádzame symbolickými návestiami:
jmp koniec
…
koniec:
Príznaky
● CPU má register flags (korektne príznaky, hovorovo flagy)
● Každý z jeho bitov má samostatný význam● Nečítame ani nezapisujeme ho priamo● Nastavuje sa podľa výsledku (nielen)
aritmetických inštrukcii
Príznaky
● CF (carry flag)
● Nastaví sa ak operácia pretečie ako celočíselná● Inak využívaný inštrukciami ktoré “potrebujú nejaký
flag”● OF (overflow flag)
● Nastaví sa ak operácia pretečie ako znamienková● SF (sign flag)
● Nastaví sa ak je výsledkom operácie záporné číslo (horný bit výsledku je 1)
● ZF (zero flag)
● Nastaví sa ak výsledok operácie je nula.
Pretečenie
mov al, 0
sub al, 1 CF=1, OF=0, SF=1
mov al, 0
add al, 11111111b CF=0, OF=1, SF=1
mov al, 0
sub al, 11111111b CF=1, OF=1, SF=0
Podmienené skoky
● Skáču iba ak je splnená podmienka
JC (jump if carry) - CF=1
JNC (jump if not carry) - CF=0
JO (jump if overflow) - OF=1
JNO (jump if not overflow)- OF=0
JS (jump if signed) - SF=1
JNS (jump if not signed) - SF=0
JZ (jump if zero) - ZF=1
JNZ (jump if not zero) - ZF=0
Príklad:Nulovanie 16 bytov
mov ecx, 16 ;nuluj 16 bytov
mov edi, 5 ;od adresy 5
nuluj:
mov byte [edi], 0 ;vynuluj byte na adrese EDI
inc edi ;posun EDI na dalsi byte
dec ecx ;dalsi byte hotovy
jnz nuluj ;ak je ecx>0, opakuj cyklus
CMP
● CMP (compare)● Porovnáva dva operandy● Nastaví flagy pre špeciálne skoky● V skutočnosti SUB ktorý neprepíše cieľový register,
iba nastaví flagy podľa výsledku odpočítania.
● Príklady:cmp eax, ebx
cmp eax, dword [4]
cmp byte [eax], dl
cmp ecx, 30
CMP pre neznamienkové čísla
● Podmienené skoky:
JB – jump if 1st operand below 2nd
JBE – jump if 1st operand below or equal to 2nd
JE – jump if 1st operand equal to 2nd
JAE – jump if 1st operand above or equal to 2nd
JA – jump if 1st operand above 2nd
● Pre každý z nich možno obrátiť podmienku: JN (jump if not) namiesto J (jump if)
CMP pre znamienkové čísla
● Podmienené skoky:
JL – jump if 1st operand lower than 2nd
JLE – jump if 1st operand lower than or equal to 2nd
JE – jump if 1st operand equal to 2nd
JGE – jump if 1st operand greater than or equal to 2nd
JG – jump if 1st operand greater than 2nd
● Pre každý z nich možno obrátiť podmienku: JN (jump if not) namiesto J (jump if)
Príklad #2Nulovanie 16 bytov inak
mov ecx, 0
nuluj:
mov byte [ecx+5], 0 ;vynuluj ECX-ty byte od
;adresy 5
inc ecx ;dalsi byte hotovy
cmp ecx, 16 ;hotovych 16 bytov?
jne nuluj ;ak je ecx>0, opakuj cyklus
Príklad #3Porovnanie reťazcov
mov esi, retazec1 mov edi, retazec2
porovnaj:
mov al, byte [esi] ;nacitaj znak prveho
cmp byte [edi], al ;porovnaj so znakom
;druheho
ja druhy_vacsi ;znak druheho vacsi?
jb prvy_vacsi ;znak druheho mensi?
inc esi ;ak su rovnake, posun
inc edi ;na dalsi znak
jmp porovnaj ;a repete
Čo je “assembler”?
● Program, ktorý prekladá symbolický zápis inštrukcii na binárny strojový kód
● Syntax zápisu inštrukcii sa medzi rôznymi assemblermi viac či menej odlišuje
● Z toho prenesene “assembler” ako označenie niektorej konkrétnej syntaxe
● V širokom zmysle sa “assembler” používa aj ako označenie ľubovolnej syntaxe ktorá reprezentuje priamo strojový kód
Rozšírené assemblery
● MASM (Microsoft Macro Assembler)● MASM32 projekt
● gas (GNU Assembler)● NASM (Netwide Assembler)
● YASM (Yet-another Assembler, ...)
● FASM (Flat Assembler)● GoAsm, HLA (High Level Assembly), RosAsm
Zdroje pre štúdium
● Intel x86 CPU manuals
● http://developer.intel.com/products/processor/manuals/index.htm● AMD CPU manuals
● http://developer.amd.com/documentation/guides/pages/default.aspx#manuals● Art of assembly programming (Randall Hyde)
● http://webster.cs.ucr.edu/● Asm komunity:
● http://www.asmcommunity.net/board/ (General)● http://board.flatassembler.net (FASM)● http://www.masm32.com/board/ (MASM)● Newsgroups: alt.lang.asm, comp.lang.x86.asm
Nabudúce (?)
● Zásobník● Procedúry● Volacie štandardy (stdcall, ccall, fastcall,
vararg)● Ďalšie “prídavné” inštrukcie● Čo ma ešte napadne● Socializácia
vid (nie 'Vid')