Diferente pentru introducere-in-asamblare intre reviziile #25 si #26

Nu exista diferente intre titluri.

Diferente intre continut:

h1. Introducere in asamblare
(Categoria _Limbaje_, autor(i) _Botau Cristian_)
 
Acest articol prezinta un limbaj mai putin folosit : limbajul de asamblare. Este folosit de cele mai multe ori pentru marirea vitezei de rulare a programelor. In prima sectiune sunt prezentate cateva avantaje / dezavantaje in folosirea acestui limbaj, iar ulterior sunt definite notiunile elementare ce trebuie stiute inainte de a trece la tratarea limbajului propriu-zis. De asemenea, sunt prezentate cateva intructiuni si transcrieri ale unor structuri din C/Pascal in limbaj de asamblare. In final sunt comparati timpii de executie intre varianta pascal si varianta assembler ale unei proceduri de {$Bubble Sort$}.
h2. Limbajul de asamblare : avantaje si dezavantaje in folosirea lui
    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.
 

Nu exista diferente intre securitate.

Topicul de forum nu a fost schimbat.