mov ax, 2
int 0x33;
}
==
==
h2. Transcrierea unor instructiuni C/PASCAL in asamblare
h3. IF cond THEN instr
Exemplu :
== code(cpp) |if (a==5) b=a; // a, b : integer
==
== code(cpp) |mov ax, a
cmp ax, 5
// ne intrebam daca !cond
jnz @skip_if
mov b, ax
@skip_if :
==
h3. IF cond THEN instr1 ELSE instr2
Exemplu:
== code(cpp) |if (a==b) a-=b; else b-=a;
==
Transcrierea in asamblare :
== code(cpp) |mov ax, a
mov bx, b
// compara ax cu bx si seteaza flag-urile
cmp ax, bx
je @if_then
// if (ax == bx) sari la @if_then
sub b, ax
jmp @end_if :
@if_then :
sub a, bx
@end_if :
==
h3. DO { inst } WHILE
Exemplu :
== code(cpp) |int i, a, n;
i = 0;
a = 0;
do
{
i++;
a+=i;
} while (i<=n);
==
Codul in asamblare :
== code(cpp) |// cx = 0, instructiunea xor cx, cx este
// mai rapida decat mov cx, 0
xor cx, cx
xor ax, ax
mov bx, n
@while :
inc cx
add ax, cx
cmp cx, bx
jne @while
mov a, ax
mov I, cx
==
Sau folosind instructiunea loop (pornim invers) :
== code(cpp) |mov cx, n
@while:
add ax, cx
loop @while
==
In codul de mai sus (prima varianta) puteti observa cateva mici optimizari : retinerea variabilelor in registri (accesul la registri este mult mai rapid decat la memorie), inlocuirea instructiunii {$mov reg, 0$ cu {$xor reg, reg$}. Varianta "xor" este mai rapida (desi $mov$ si $xor$ "teoretic" au tot atatea ceasuri de procesor) deoarece instructiunea $mov reg, 0$ transcrisa in cod masina este mai "lunga" (are cu $2-4$ bytes mai mult decat {$xor reg, reg$}). Aceeasi regula se aplica si in cazul "{$or reg, reg$}" in testarea daca valoarea unui registru este egala cu {$0$}, intrucat instructiunea "{$or$}" modifica flagurile procesorului ({$ZeroFlag$}). O alta optimizare este folosirea registrului $ax$ pentru calcule (in majoritatea cazurilor instructiunile care folosesc registrul $(e)ax$ sunt mai rapide).
h2. Program demonstrativ
Exemplu de functie in realizata in C/Asamblare (compilator folosit BC++ 3.1):
== code(cpp) |// BSort.CPP
#include <stdio.h>
#include <conio.h>
int a[20], n;
void bsort()
{
asm {
mov di,seg a
mov es,di
mov di,offset a
// es:[di] inceputul vectorului
// es - adresa segment
// di - adresa offset
};
do_while_not_ok :
asm {
// ok = 1;
mov dx, 1
// cx = n;
mov cx, n
// cx = n-1
dec cx
// ax = a[0]
mov ax, es:[di]
// punem di pe stiva
push di
}
inner_for :
asm {
// bx = a[i-1]
mov bx, ax
// ne mutam pe noua pozitie in vector
add di, 2
// ax = a[i]
mov ax, es:[di]
// comparam ax cu bx (a[i-1] cu a[i])
cmp bx, ax
// if (a[i-1] <= a[i]) don't swap
jbe if_not
// interschimbam a[i-1] cu a[i]
xchg bx, ax
// le scriem in memorie
mov es:[di], ax
mov es:[di-2], bx
// ok = 0
xor dx, dx
}
if_not :
asm {
// cx--;
dec cx
jnz inner_for
// daca cx != 0 atunci continuam for-ul
pop di
// compara dx cu 0
// (mai rapid decat cmp dx, 0)
or dx, dx
// if (ok) executam inca odata while-ul
jz do_while_not_ok
}
}
void citire()
{
printf("Numarul de elemente : ");
scanf("%d", &n);
for (int i=0; i<n; i++)
{
printf("a[%d] = ", i);
scanf("%d", &a[i]);
}
}
void afis()
{
for (int i=0; i<n; i++)
printf("%d ", a[i]);
}
int main()
{
citire();
bsort();
afis();
return 0;
}
==
Varianta Pascal + Asm (compilata cu BP 7.0):
== code(pas) |program b_sort;
const max_N = 1000;
n_tests = 100;
var N : Integer;
a, b : array [1..max_N] of Integer;
procedure citire;
var f : Text;
i : Integer;
begin
Assign(f, 'bsort.in'); Reset(f);
readln(f, N);
for i := 1 to N do
read(f, b[i]);
Close(f)
end;
procedure flip;
var i : Integer;
begin
for i:=1 to N do
a[i] := b[i];
end;
var p : pointer;
procedure bsort; assembler;
asm
{ les <=> es = seg(p), di = offset(p) }
les di, p
@do_while_not_ok :
mov dx, 1
mov cx, N
dec cx
mov ax, es:[di]
push di
@inner_for :
mov bx, ax
add di, 2
mov ax, es:[di]
cmp bx, ax
jbe @if_not
xchg bx, ax
mov es:[di], ax
mov es:[di-2], bx
xor dx, dx
@if_not :
dec cx
jnz @inner_for
pop di
or dx, dx
jz @do_while_not_ok
end;
procedure bsort2;
var ok : Boolean;
i, aux : Integer;
begin
repeat
ok := true;
for i := 1 to n-1 do
if (a[i] > a[i+1]) then
begin
aux := a[i];
a[i] := a[i+1];
a[i+1] := aux;
ok := false;
end;
until ok;
end;
var i : Integer;
starttick, endtick : LongInt;
time : Longint absolute $0000:$046C;
{ timer pentru masurarea timpului }
const tickspersecond = 18.206;
procedure starttimer;
begin
starttick := time;
end;
function elapsedtime : real;
begin
endtick := time;
elapsedtime := (endtick - starttick)*
(1 / tickspersecond);
end;
begin
citire;
p := @a;
starttimer;
for i:=1 to n_tests do
begin
flip;
bsort;
end;
writeln(n_tests, ' rulari ale bsort in asamblare
au rulat in : ', elapsedtime : 6:3, ' secunde');
starttimer;
for i:=1 to n_tests do
begin
flip;
bsort2;
end;
writeln(n_tests, ' rulari ale bsort obisnuit
au rulat in : ',elapsedtime : 6:3, ' secunde');
end.
==
Output program pascal (pe pc-ul meu: Duron $750$ Mhz):
$100$ rulari ale bsort in asamblare au rulat in : $1.263$ secunde
$100$ rulari ale bsort obisnuit au rulat in : $4.614$ secunde
De precizat este ca nu am optimizat programul aproape deloc (am transcris codul din pascal in asm). Cu optimizari "hardcore" se pot obtine timpi mult mai buni. Diferenta dintre varianta asm si varianta high level language este mai mica pe compilatoarele mai noi, cum ar fi GCC sau FreePascal deoarece acestea stiu genera un cod mai optimizat. Totusi, nici un compilator nu poate bate creierul uman.
h2. Linkuri
"Link #1":http://www.arl.wustl.edu/~lockwood/class/cs306/books/
"Link #2":http://artofasm/toc.html
Cartea "The Art of Assembly Language Programming". Este detaliata. Foarte buna atat pentru incepatori cat si pentru avansati.
"Link #3":http://www.goof.com/pcg/doc/pentopt.txt
Un tutorial bun pentru optimizarea programelor in asamblare pentru procesoarele din familia Pentium. Tutorialul este pentru avansati.
"Link #4":http://www.techtutorials.info/assembly.html
Mai multe tutoriale despre assembly language.
h2. Doua cuvinte conclusive...
Acest articol trateaza "bazele" programarii in asamblare, dupa cum ii zice numele este doar o introducere. Pentru a sti sa programezi in asm, trebuie invatate mult mai multe lucruri. Scopul articolului este de a starni interesul cititorilor si de a le oferi o imagine asupra acestui limbaj. Cei ce doresc sa invete mai multe despre assembly language sunt invitati sa citeasca cartile / tutorialele din sectiunea linkuri.