Dlaczego Asembler ???
Składnie Asemblerowe
Składnia Intel-a
Wykorzystywana w większości kompilatorów pod
systemy operacyjne DOS i Windows.
Składnia AT&T
Składnia opracowana przez AT&T przy okazji
tworzenia pierwszego procesora 32-bitowego
BELLMAC-32A (rok 1980 !!!). Zaczerpnięta z
asemblerów m68k. Głównie wykorzystywana przez
kompilatory Linux’owe.
Składnia Intel-a
(na przykładnie NASM)
Składnia AT&T
(na przykładzie GAS)
section .databeer
db "text„
db 0x0a
db "text2„
db 0x0a
db 0
main:
mov ecx, 100
_loop:
dec ecx
push ecx
push ecx
inc ecx
push ecx
push ecx
push beer
call printf
add esp,16
pop ecx
or ecx, ecx
jne _loop
xor eax,eax
ret
.section .rodata.beer:
.ascii “text".
asciz "text2 „
.text
.global main
main:
mov $100, %ecx
loop:
dec %ecx
push %ecx
push %ecx
inc %ecx
push %ecx
push %ecx
pushl $.beer
call printf
add $16,%esp
pop %ecx
or %ecx, %ecx
jne loop
xorl %eax,%eax
ret
Składnia Intel
TASM (Turbo assembler)
MASM (Macro assembler)
NASM (Netwide assembler)
FASM (Flat assembler)
HLA (High level assembly language)
TALC (Typed assembly language)
AS86
Składnia AT&T
GAS (GNU assembler)
GASP
YASM
Kompilacja
TASM
Kompilacja: tasm p1
powstaje p1.obj
Linkowanie: tlink p1.obj
powstaje p1.exe
MASM
Kompilacja: masm p1
powstaje p1.obj
Linkowanie: link p1.obj
powstaje p1.exe
GAS
Np..: gcc -s -o p1 p1.s
Deklaracja segmentu
segmencik SEGMENT ;
Deklaracja początku segmentu
; W tym miejscu OFFSET = 0
; Tutaj piszemy zawartość segmentu
; maksymalny OFFSET = FFFF h stąd maksymalny rozmiar segmentu to 64k
; w trybie DOS programy zwykle składają się z 3 segmentów:
; DANYCH
; STOSU
; PROGRAMU
; mają wówczas rozszerzenie EXE
;mogą również składać się z jednego segmentu wówczas mają rozszerzenie
COM
segmencik ENDS ; Deklaracja końca segmentu
Segment danych
dane SEGMENT
; sposób deklaracji:
;
nazwa_zmiennej typ wartość (wartości)
; rodzaje ‘zmiennych’ :
;
db bajt
;
dw słowo
;
dd podwójne słowo
zmienna1 db 0
;deklaracja 1 bajtu i zainicjalizowanie jego
wartoscią 1
zmienna2 db ?
;deklaracja bajtu bez inicjalizowania wartości
zmienna3 db ?,?,3
;deklaracja 3 komórek pamięci przy czym
wartość
;pierwszej i drugiej jest niezainicjaliwoana a trzeciej
;
zainicjalizowana wartością 3 adresy to kolejno:
zmienna3, zmienna3+1, zmienna3+2
zmienna4 db ‘A’
;deklaracja 1 bajtu zainicjalizowanego wartością 41
hex
; (znak ascii A)
zmienna4 db ‘A’
;deklaracja 1 bajtu
zainicjalizowanego wartością
; 41 hex (znak ascii
A)
zmienna5 db ‘A’,’B’,’C’ ; 3 komórki o wartościach ascii A,B i C, ale
również
; można to zadeklarować tak:
zmienna6 db ‘ABC’
; ale to się nie nadaje do wyświetlania na
ekranie !!!
zmienna7 db ‘ABC$’
; Teraz to się nadaje do wyświetlania jako
ciąg
; znaków - $ informuje funkcje wyświetlające
że jest
; to konieć stringa. Jak by to było napisane
tak:
zmienna8 db ‘ABC’
; jak by było tak to następna zmienna:
zmienna9 db ‘DEF$’
; wyświetliła by się również czyli się wys:
ABCDEF
zmienna 10 db 10,13,’$’
; zmiana linii
zmienna 11 dw 0
; zmienna 16-bit
zmienna 12 dd 0
; zmienna 32-bit
; na początek wystarczy
dane ENDS
Segment stosu
stosik SEGMENT stack
;stack od razu informuje kompilator że to jest segment stosu
db 256 dup(?) ;rozmiar stosu
stosik ENDS ;Aha nazwa nie może być stos bo jest taka instrukcja
Segment programu
program SEGMENT
ASSUME CS:program, DS:dane, SS:stosik
; przyporządkowanie nazw poszczególnych
; segmentów do rejestrów
start:
; przesunięcie adresowe w tym segmencie
MOV ax, SEG dane
; mov to instrukcja przesłania do AX zwartości
adresu segmentu
; danych
MOV ds., ax
; który następnie ładowany jest do DS-a. Wydaje się
oczywiste
MOV ah,4Ch
; Tu musimy zatrzymać się dłużej
INT 21h
program ENDS
END start
; Koniec programu
Tryby adresowania
Adresacja rejestrowa
000000010001011
1
000000000010001
1
000000000010001
1
000000000010001
1
MOV AX, BX
BX
AX
Adresowanie natychmiastowe
MOV AX, 20 ( MOV AX, 14h)
0000000000010000
00000000010100
AX
Adresowanie bezpośrednie
000000010001011
1
000000000010001
1
000000000010001
1
000000000010001
1
AX
Tablica
MOV AX, Tablica
Adresowanie pośrednie poprzez rejestr bazowy
MOV BX, offset Tablica (LEA BX, Tablica)
MOV AX, [BX]
MOV BX, offset Tablica (LEA BX, Tablica)
MOV DI, 1
MOV AX, [BX+DI]
Instrukcje warunkowe
Instrukcja CMP
cmp bx,ax
; OPERACJA ODEJMOWANA BEZ WYNIKU – ustawia jedynie
; słowo stanu
Rejestr znaczników (flag register)
Dopuszczalna postać instrukcji:
cmp rejestr,rejestr;
cmp rejestr,pamięć;
cmp pamięć,rejestr;
cmp rejestr,dana natychmiastowa
cmp pamięć,dana natychmiastowa
P – flaga parzystości
A – flaga przeniesienia pomocniczego
Z – flaga „zera”, przyjmuje 1 kiedy wynik
operacji jest 0
S – znak
O – znacznik przeniesienia warunkowego
C- carry – przepełnienie bez znaku
Instrukcje skoków warunkowych
opis słówny
liczby bez znaku
liczby ze znakiem
gdy X1 większy
ja (jnbe)
jg (jnle)
gdy X1 mniejszy
jb (jnae, jc)
jl (jnge)
gdy równe
je (jz)
je (jz)
gdy nierówne
jne (jnz)
jne (jnz)
gdy większy lub równy
jae (jnb, jnc)
jge (jnl)
gdy mniejszy lub równy
jbe (jna)
jle (jng)
Instrukcja skoku bezwarunkowego
JMP Etykieta
Pętle LOOP
mov cx,10 ; cx jest licznikiem petli
petla:
.
.
.
loop petla ; cx = cx -1, jesli cx nie jest 0, nastepuje skok do petla
LOOPE
ETYKIETA
LOOPZ
ETYKIETA
LOOPNE ETYKIETA
LOOPNZ ETYKIETA
Podstawowe Operacje
arytmetyczne
Mnożenie
mul cl ; AX := AL*CL
mul bx ; DX:AX := AX*BX
Dzielenie
div cl ; AL := (AX div CL), AH := (AX mod CL)
div bx ; AX := (DX:AX div BX), DX := (DX:AX mod
BX)
Dodawanie
Bez przeniesienia:
add al, bl ; AL=AL+BL
add dx, bx ; DX=BX+DX
z przeniesieniem:
adc al, bl ; AL=AL+BL+C
adc dx, bx ; DX=BX+DX+C
Zastosowanie przy długich dodawaniach:
add al, bl ; AL=AL+BL
adc ah, bh ; AH=AH+BH+C ; add ax,
bx
Odejmowanie
Bez pożyczki:
sub al, bl ; AL=AL-BL
sub dx, bx ; DX=BX-DX
z pożyczką:
sbb al, bl ; AL=AL-BL-C
sbb dx, bx ; DX=BX-DX-C
Zastosowanie przy długich odejmowaniach:
sub al, bl ; AL=AL-BL
sbb ah, bh ; AH=AH-BH-C ; sub ax,
bx
Inkrementacja i dekrementacja
Inkrementacja:
inc al ; AL=AL + 1
inc dx ; DX=DX + 1
Dekrementacja:
dec al ; AL=AL - 1
dec dx ; DX=DX - 1
Przesunięcia
Przesunięcia SHR i SHL
Wywołanie:
SHR AX, 1 ; przesunięcie rejestru
AX o ; jeden w prawo
SHL AX, 1 ; przesunięcie rejestru
AX o ; jeden w lewo
0 0 0 0 0 0 0 0
CY
0
0 0 0 0 0 0 0 0
CY
0
Przesunięcia RCL i RCL
Wywołanie:
RCR AX, 1 ; przesunięcie rejestru
AX o ; jeden w prawo
RCL AX, 1 ; przesunięcie rejestru
AX o ; jeden w lewo
0 0 0 0 0 0 0 0
CY
0 0 0 0 0 0 0 0
CY
Przesunięcia ROL i ROL
Wywołanie:
ROR AX, 1 ; przesunięcie rejestru
AX o ; jeden w prawo
ROL AX, 1 ; przesunięcie rejestru
AX o ; jeden w lewo
0 0 0 0 0 0 0 0
CY
0 0 0 0 0 0 0 0
CY
Operacje logiczne
Negacja Logiczna
Wywołanie:
NOT al
; 8 bit
NOT ax
; 16 bit
NOT 0 = 1
NOT 1 = 0
Iloczyn Logiczny
Wywołanie:
AND al, 0000 0001 b
; 8 bit
AND ax, 00FFh
; 16 bit
AND 0,0 =
0
AND 0,1 =
0
AND 1,0 =
0
AND 1,1 =
1
Suma Logiczna
Wywołanie:
OR al, 0000 0001 b
; 8
bit
OR ax, 00FFh
; 16 bit
OR 0,0 = 0
OR 0,1 = 1
OR 1,0 = 1
OR 1,1 = 1
Operacja eXclusiveOR (XOR)
Wywołanie:
XOR al, 0000 0001 b
; 8 bit
XOR ax, ax
; 16 bit
XOR 0,0 =
0
XOR 0,1 =
1
XOR 1,0 =
1
XOR 1,1 =
0
Koprocesor arytmetyczny
Operacje ładowania i wyciągania danych
FLD/FILD [mem] - załaduj liczbę
rzeczywistą/całkowitą z
pamięci. Dla liczby
rzeczywistej 32, 64 lub 80
bitów. Dla
całkowitej - 16, 32 lub 64 bity
FST [mem] - do pamięci idzie liczba ze st(0).
FSTP [mem] - "store & pop" - zapisz st(0) w
pamięci i zdejmij je ze stosu. Znaczy to tyle, że
st(1) o ile istnieje, staje się st(0) itd. każdy
rejestr cofa się
o 1.
FIST [mem] - ewentualnie obciętą do całkowitej
liczbę z
st(0) zapisz do pamięci.
FISTP [mem] - FIST ze zdjęciem ze stosu.
FXCH st(i) - zamień st(0) z st(i).
Operacje pobierania stałych
FLDZ - załaduj zero. st(0) = 0.0
FLD1 - załaduj 1. st(0) = 1.0
FLDPI - załaduj pi
FLDL2T - załaduj log2(10)
FLDL2E - załaduj log2(e)
FLDLG2 - załaduj log(2)=log10(2)
FLDLN2 - załaduj ln(2)
Operacje arytmetyczne
FADD [mem] st = st + [mem]
FADD st(0), st(i) st = st + st(i)
FADD st(i),st(0) st(i) = st(i) + st(0)
FADDP st(i), st(0) st(i) = st(i) + st(0) & pop
FADDP FADDP st(1),st(0)
FIADD [mem] st = st + [mem]
Dodawanie
Odejmowanie
FSUB [mem] st = st - [mem]
FSUB st(0), st(i) st = st - st(i)
FSUB st(i), st st(i) = st(i) - st
FSUBP st(i), st
st(i) = st(i) - st(0) & pop
FSUBP
FSUBP st(1), st(0)
FISUB [mem] st = st - [mem]
FSUBR [mem] st = [mem] - st(0)
Inne operacje odejmowania: FSUBRP st(i)_st ,
FSUBRP, FISUBRP [mem]
Mnożenie
FMUL [mem] st = st * [mem]
FMUL st(0), st(i) st = st * st(i)
FMUL st(i), st(0) st(i) = st(i) * st(0)
FMULP st(i), st(0)
st(i) = st(i) * st(0) & pop
FMULP
FMULP st(1),st(0)
FIMUL [mem] st = st * [mem]
Dzielenie
FDIV [mem] st = st / [mem]
FDIV st, st(i) st = st / st(i)
FDIV st(i), st st(i) = st(i) / st
FDIVP st(i), st
st(i) = st(i) / st & pop
FDIVP
FDIVP st(1), st
FIDIV [mem] st = st / [mem]
FDIVR [mem] st = [mem] / st
Inne operacje dzielenia: FDIVRP st(i)_st , FDIVRP,
FIDIVRP [mem]
Inne operacje arytmetyczne
FABS
st = abs(st)
FCHS st = -st
FSQRT
st = SQRT(st)
FPREM st = st mod st(1)
FRNDINT st = (int) st
FSIN, FCOS, FPTAN, FPATAN
podstawowe instrukcje
trygonometryczne
Operacje porównań
FCOM st(n)
- porównaj st(0) z st(n) (lub zmienną
w
pamięci) bez zdejmowania st(0) ze
stosu FPU
FCOMP st(n)
-porównaj st(0) z st(n) (lub zmienną
w
pamięci) i zdejmij st(0)
FCOMPP
- porównaj st(0) z st(1) i zdejmij oba
ze
stosu
FICOM [mem]
- porównaj st(0) ze zmienną
całkowitą 16-
lub 32-bitową w pamięci
FICOMP [mem]
- porównaj st(0) ze zmienną
całkowitą 16-
lub 32-bitową w pamięci,
zdejmij st(0)
FCOMI st(0), st(n)
- porównaj st(0) z st(n) i ustaw
flagi
procesora
FCOMIP st(0), st(n)
- porównaj st(0) z st(n) i ustaw
flagi
procesora, zdejmij st(0)
Operacje sterujące
FINIT/FNINIT - inicjalizacja FPU. Litera "N" oznacza, aby nie brać
pod
uwagę ew. niezałatwionych wyjątków.
FLDCW, FSTCW/FNSTCW - Load/Store control word - zapisuje 16
kontrolnych bitów do pamięci, gdzie można je zmieniać np. aby
zmienić sposób zaokrąglania liczb.
FSTSW/FNSTSW - zapisz do pamięci / rejestru AX słowo statusu
(FPU)
FCLEX/FNCLEX - wyczyść wyjątki
FLDENV, FSTENV/FNSTENV – wczytaj / zapisz środowisko (rejestry
stanu, kontroly i kilka innych, bez rejestrów danych).
Wymaga 14 albo 28 bajtów pamięci, w zależności od trybu
pracy procesora
(rzeczywisty/DOS lub chroniony -
Windows/Linux).
FRSTOR, FSAVE/FNSAVE - jw., tylko że z rejestrami danych.
Wymaga 94 lub 108 bajtów w pamięci, zależnie od trybu
procesora.
FINCSTP, FDECSTP - zwiększ/zmniejsz wskaźnik stosu - przesuń
st(0) na
st(7), st(1) na st(0) itd. oraz w drugą stronę,
odpowiednio.
FFREE - zwolnij podany rejestr danych
FNOP - no operation. Nic nie robi, ale zabiera czas.
WAIT/FWAIT - czekaj, aż FPU skończy pracę. Używane do
synchronizacji
z CPU.