Probleme asm pe “release”
Problema de fata apare in versiunele 2005+ ale Visual Studio in modul de compilare "Release". Sa luam exemplul urmator:
-
int functie(int)
-
{
-
_asm
-
{
-
mov eax,[ebp+8]
-
}
-
}
-
-
-
int main()
-
{
-
int a=10,b;
-
b=functie(a);
-
printf("%d ",b);
-
return 0;
-
}
In mod normal, functia returneaza valoarea primita ca parametru . Prin urmare, b=functie(a) va lua valoarea lui a, adica 10. Pana acum toate bune si frumoase. Sa compilam acum pe "Release mode" . De data aceasta, b va lua valoarea ...0
. Ciudat ? Nicidecum. Daca vom modifica antetul functiei main in felul urmator:
-
int main(int)
b va lua valoarea ... 1
... acum sa rulam programul cu 5 parametri ... si da, intr-adevar , b va lua valoarea 5 ... hmmm...Situatia nu e atat de hazlie pe cat pare. Sa zicem ca avem o functie care primeste ca parametru adresa unei variabile ... daca in loc de adresa noi primim 0, 1 sau alte tampenii, cu siguranta ca programul nostru va functiona razna iar noi ne vom pune nervii la incercare pentru mult timp, cu debugger-ul etc., negasind eroarea.
Eroarea provine din cauza optimizarilor de cod pe care le efectueaza Visual Studio . Sa luam acelasi caz de mai sus. Ce inseamna optimizare ? Compilatorul "vede" ca functia de mai sus nu mai apeleaza alte functii si este apelata doar din main . Asa ca , literal, ia tot codul functiei si il pune in locul apelului din functia main . Ceea ce echivaleaza perfect cu :
-
int main()
-
{
-
int a=10,b;
-
_asm
-
{
-
mov eax,[ebp+8]
-
mov b,eax
-
}
-
printf("%d ",b);
-
return 0;
-
}
Astfel, nu se mai face saltul la codul functiei, codul e "performant", dar intelesul sau deja se schimba...
In mod logic, problema se rezolva in 2 moduri :
1. Spunem compilatorului sa nu mai optimizeze nimic ( foarte usor : Project Properties -> Configuration Properties -> C/C++ -> Optimization -> Optimization -> Disabled .
2. Spunem compilatorului sa nu optimizeze functia noastra ... va urma
Visual Studio 2008 … interesant
Hmm .. eram obisnuit sa setez release, si dau f5 , sa astept sa termina de incarcat aberatiile respective si sa am executabilul ... vremuri bune . Pe Visual Studio mai vechi poti face acest lucru pentru un program de tip console application. Se pare ca, mai nou, acest lucru nu mai este disponibil direct in Visual Studio 2008 . Daca dati simplu release si dati altcuiva programul, sunt sanse mari ca acesta sa nu-i mearga ( logica spune asa : daca eu sunt singurul tampit care foloseste Visual Studio 2008 cu .net 3.5, iar ceilalti folosesc altceva, e clar ca nu va merge ) . Problema se rezolva foarte simplu. Mergeti la Properties->Configurations Properties-> C/C++ ->Code Generation->Runtime Library-> Multi-threaded (/MT)... atata tot ... acum dati prietenilor programul vostru si virusati-i![]()
Naiv Sort - C++/ASM
Ah ... 2008 ... un nou an ... Dupa sampanie si cozonac ( meniu special de revelion ) , dupa artificii ( pe faleza Dunarii ) ...
Ma bucur cel putin ca acum folosesc un soft de anu asta ( Visual Studio 2008 ) , sunt trist ca in curand vin examenele, sunt bucuros ca in scurta vacanta de Craciun am reusit sa invat ASM ( un limbaj imposibil pentru mine la inceput - cu ocazia asta, tin sa-i multumesc lui AndreiASM .. de la el am invatat o buna parte a limbajului dar si profului ... printre cei mai de treaba de la FII ) ...
Si ca sa incep anul cu dreptul, m-am gandit in seara asta sa schimb algoritmul de anul trecut ( bubble sort ) , cu unul de "anul asta" ( naiv sort ) ... am implementat atat in C++ cat si in ASM ...
-
#include <stdio.h>
-
-
int v[5];
-
/*
-
void interschimba(int &a,int &b)
-
{
-
int c;
-
c=a;
-
a=b;
-
b=c;
-
}
-
void Naiv_Sort(int v[],int n)
-
{
-
int i,poz,min,j;
-
for(i=0;i<n;i++)
-
{
-
min=v[i];
-
poz=i;
-
-
for(j=i+1;j<n;j++)
-
if(v[j]<min)
-
{
-
min=v[j];
-
poz=j;
-
}
-
interschimba(v[i],v[poz]);
-
}
-
}*/
-
-
void Naiv_Sort(int*,int)
-
{
-
_asm
-
{
-
mov ebx,0
-
for_mare:
-
mov ecx,[ebp+12]
-
dec ecx
-
cmp ebx,ecx
-
je gata
-
mov esi,[ebp+8]
-
//ajungem pe pozitia curenta
-
mov eax,ebx
-
shl eax,2
-
add esi,eax
-
//in esi avem pozitia curenta
-
//in eax avem minimul, in edx avem pozitia minimului
-
mov eax,[esi]
-
mov edx,ebx
-
//ecx va fi contorul celui de-al doilea for
-
mov ecx,ebx
-
inc ecx
-
add esi,4
-
for_mic:
-
cmp ecx,[ebp+12]
-
je stop
-
mov edi,[esi]
-
cmp edi,eax
-
jb schimba
-
jmp continua
-
schimba:
-
mov eax,[esi]
-
mov edx,ecx
-
jmp continua
-
continua:
-
add esi,4
-
inc ecx
-
jmp for_mic
-
stop:
-
mov esi,[ebp+8]
-
mov eax,ebx
-
shl eax,2
-
add esi,eax
-
mov edi,[ebp+8]
-
mov eax,edx
-
shl eax,2
-
add edi,eax
-
//in esi si edi am cele 2 adrese ale elementelor ce trebuie schimbate
-
-
push dword ptr [esi]
-
push dword ptr [edi]
-
pop dword ptr [esi]
-
pop dword ptr [edi]
-
-
inc ebx
-
jmp for_mare
-
gata:
-
-
}
-
}
-
-
-
int main()
-
{
-
int n,i;
-
n=5;
-
v[0]=10;v[1]=2;v[2]=1;v[3]=5;v[4]=6;
-
Naiv_Sort(v,n);
-
for(i=0;i<n;i++) printf("%d ",v[i]);
-
getchar();
-
return 0;
-
}
Sa utilizam bubble sort …
M-am gandit sa ma mai joc putin cu bubble sort-ul, sa-l folosesc in cadrul unei anumite probleme. Problema care mi-a venit in minte este urmatoarea : Sa se scrie o functie care primeste ca parametru un numar natural si care returneaza cel mai mare numar care se poate forma cu cifrele sale . Algoritmul banal cu care se rezolva aceasta problema este urmatorul:
-retinem cifrele numarului intr-un vector
-le ordonam
-compunem noul numar
Am implementat totul in ASM desigur. Pentru a nu mai recurge la fel de fel de artificii, am organizat vectorul in felul urmator:
v[0] - numarul de cifre
v[1] ... v[v[0] - cifrele numarului
Bineinteles, am modificat usor bubble-sort-ul ( cel scris de mine avea nevoie de 2 variabile , un pointer catre primul element al vectorului, v[0] , si numarul de elemente ... cateva modificari minore si a fost gata. O alta problema care mi-a atras atentia la bubble sort a fost urmatoarea : ce se intampla daca exista un singur element in vector ? Am vrut sa merg la f**** masa si sa-l las asa, dar atunci cand compara v[i] cu v[i+1], sare la o adresa la care nu se gaseste nimic ... eroare
... am prevazut acest caz in functia maxim() . Este cel mai lung programel scris de mine in ASM ( vreo 90 linii de cod ) ... Sper sa nu mai am placerea sa scriu programe atat de lungi in ASM, e foarte dificil sa caut erori, chiar si cu ajutorul debugger-ului ... Iata codul...
-
#include <iostream>
-
using namespace std;
-
-
void bubble_sort(int*)
-
{
-
_asm
-
{
-
bucla_mare:
-
mov ecx,0
-
mov eax,[ebp+8]
-
mov ebx,[eax]
-
add eax,4
-
bucla_mica:
-
mov edx,eax
-
add edx,4
-
mov esi,[eax]
-
cmp esi,[edx]
-
ja interschimbare
-
jmp continua
-
interschimbare:
-
push dword ptr [edx]
-
push dword ptr [eax]
-
pop dword ptr [edx]
-
pop dword ptr [eax]
-
mov ecx,1
-
jmp continua
-
continua:
-
add eax,4
-
dec ebx
-
cmp ebx,1
-
jne bucla_mica
-
cmp ecx,1
-
je bucla_mare
-
}
-
}
-
-
int maxim(int)
-
{
-
int v[12];
-
_asm
-
{
-
mov eax,[ebp+8]
-
cmp eax,10
-
jb exceptie
-
jmp continua
-
exceptie:
-
mov ecx,eax
-
jmp stop2
-
continua:
-
mov ebx,10
-
mov ecx,0
-
lea esi,v
-
add esi,4
-
bucla1:
-
mov edx,0
-
cmp eax,0
-
je stop1
-
div ebx
-
inc ecx
-
mov [esi],edx
-
add esi,4
-
jmp bucla1
-
stop1:
-
lea eax,v
-
mov [eax],ecx
-
push eax
-
call bubble_sort
-
add esp,4
-
-
mov ecx,0
-
mov eax,1
-
lea esi,v
-
mov ebx,[esi]
-
add esi,4
-
bucla2:
-
cmp ebx,0
-
je stop2
-
push ecx
-
mov ecx,[esi]
-
mov edx,0
-
push eax
-
mov edi,eax
-
mov eax,1
-
mul edi
-
mul ecx
-
pop edx
-
pop ecx
-
push edx
-
add ecx,eax
-
pop eax
-
mov edi,10
-
mul edi
-
dec ebx
-
add esi,4
-
jmp bucla2
-
stop2:
-
mov eax,ecx
-
}
-
}
-
-
int main()
-
{
-
int x;
-
cin>>x;
-
cout<<maxim(x)<<endl;
-
system("pause");
-
return 0;
-
}
O mica problema in ASM … de Craciun
Pentru ca tot era Craciunul si nu aveam ce face, m-am apucat de o mica problema in ASM ... am apelat la un coleg de facultate,Alex D., care mi-a dat urmatoarea problema : Sa se ordoneze un vector de numere naturale dupa numarul de biti necesari pentru a le scrie in baza 2 ... aveam deja bubble sort-ul implementat in asm ... Am procedat in felul urmator: stiam ca bubble sort compara, la un moment dat cate 2 elemente si verifica daca unul e mai mare ca celalalt. In loc de aceasta condiitie, eu trebuia sa aflu daca numarul de biti al primului e mai mare ca numarul de biti al celui de-al doilea... ca sa evit o seara "plina", am scris o alta functie, tot in asm , care imi returneaza numarul de biti pentru un numar. De aici totul a fost simplu ... ba nu ! Am stat o ora intreaga, uitandu-ma dupa pop-uri, push-uri, unele adrese se pierdeau, o adevarata dezordine... noroc cu prietenul meu AndreiASM ( numele spune tot
), care m-a ajutat cu diverse chestii tehnice pe care nu aveam de unde sa le cunosc ( apelarea unei functii cu parametri, etc. ) . In cele din urma, a rezultat codul de mai jos, care "merge", dar nu am absolut niciun chef sa ma mai bag pe el in caz ca gasesc vreo eroare...
-
#include <stdio.h>
-
#include <iostream>
-
using namespace std;
-
-
-
int nr_biti(int)
-
{
-
_asm
-
{
-
mov eax,[ebp+8]
-
cmp eax,0
-
je final
-
mov ebx,0
-
bucla:
-
cmp eax,0
-
je stop
-
inc ebx
-
shr eax,1
-
jmp bucla
-
stop:
-
mov eax,ebx
-
jmp stop2
-
final:
-
mov ebx,1
-
jmp stop
-
stop2:
-
-
}
-
}
-
-
void bubble_sort(int*,int)
-
{
-
_asm
-
{
-
bucla_mare:
-
mov ecx,0
-
mov eax,[ebp+8]
-
mov ebx,[ebp+12]
-
bucla_mica:
-
mov edx,eax
-
add edx,4
-
-
push dword ptr[eax]
-
push dword ptr[edx]
-
-
push eax
-
-
mov edi,eax
-
-
push dword ptr[edx]
-
call nr_biti
-
mov [edx],eax
-
add esp,4
-
-
push dword ptr[edi]
-
call nr_biti
-
mov [edi],eax
-
add esp,4
-
-
pop eax
-
push ecx
-
mov ecx,[edi]
-
mov [eax],ecx
-
pop ecx
-
mov esi,[eax]
-
cmp esi,[edx]
-
ja interschimbare
-
cmp esi,[edx]
-
jle nu_e
-
-
interschimbare:
-
pop dword ptr[edx]
-
pop dword ptr[eax]
-
push dword ptr [edx]
-
push dword ptr [eax]
-
pop dword ptr [edx]
-
pop dword ptr [eax]
-
mov ecx,1
-
jmp continua
-
nu_e: pop dword ptr[edx]
-
pop dword ptr[eax]
-
jmp continua
-
-
continua:
-
-
add eax,4
-
dec ebx
-
cmp ebx,1
-
jne bucla_mica
-
cmp ecx,1
-
je bucla_mare
-
}
-
}
-
-
int main()
-
{
-
int v[100],n,i;
-
cin>>n;
-
for(i=0;i<n;i++) cin>>v[i];
-
bubble_sort(v,n);
-
for(i=0;i<n;i++) cout<<v[i]<<' ';
-
system("pause");
-
return 0;
-
}
Use the stack , Luke !
Lucrez de foarte putin timp timp in ASM si , cum imi sta mie mai bine, imi place sa ma complic al naibii de tare cand rezolv o problema... de exemplu, azi m-am gandit la urmatoarea problema in ASM : se da un vector de numere intregi. Sa se scrie o functie in ASM care inverseaza elementele vectorului .
Ok . Bag in registrul eax adresa elementului curent, calculez cati bytes trebuie sa sar ca sa ajung la ultimul element, fac o bucla, sar la elementul al doilea, calculez cati bytes am nevoie sa sar la penultimul ... etc., nervi, pana la urma adaug un sub edx,ecx ... minune, merge. De ce? Nu ma mai intereseaza... Merge si atat. Iata minunatul cod:
-
void inversare(int*,int)
-
{
-
_asm
-
{
-
mov ecx,0
-
mov ebx,[ebp+12]
-
shr ebx,1
-
dec ebx
-
bucla:
-
mov eax,[ebp+8]
-
-
push ecx
-
shl ecx,2
-
add eax,ecx
-
pop ecx
-
-
mov edx,[ebp+12]
-
dec edx
-
sub edx,ecx
-
sub edx,ecx
-
shl edx,2
-
-
push eax
-
add eax,edx
-
mov edx,eax
-
pop eax
-
-
push dword ptr [eax]
-
push dword ptr [edx]
-
pop dword ptr [eax]
-
pop dword ptr [edx]
-
-
cmp ecx,ebx
-
jne continua
-
cmp ecx,ebx
-
je stop
-
continua:
-
inc ecx
-
jmp bucla
-
stop:
-
}
-
}
Ok... , ma minunam si eu de cat de frumos e codul asta ... ma simteam mandru... USE THE STACK LUKE... mi-am adus aminte de Star Wars ... si de o mica chestie numite STIVA... care avea interesenta proprietate ca ultimul intrat era primul iesit . Sa vezi si sa nu crezi ... exact ce-mi trebuia mie .
Mi-am tras o palma peste cap, am pornit alt proiect, am scris repede codul, a rezultat cel de mai jos. Elegant, simplu, fara shiftari de biti sau alte magarii ...
-
void inverseaza2(int*,int)
-
{
-
_asm
-
{
-
mov eax,[ebp+8]
-
mov ecx,[ebp+12]
-
mov edx,0
-
bucla:
-
cmp edx,ecx
-
je final
-
push dword ptr [eax]
-
add eax,4
-
inc edx
-
jmp bucla
-
final:
-
mov eax,[ebp+8]
-
mov edx,0
-
bucla2:
-
cmp edx,ecx
-
je final2
-
pop dword ptr [eax]
-
add eax,4
-
inc edx
-
jmp bucla2
-
final2:
-
}
-
}
De acum incolo voi folosi stiva !
De acum incolo voi folosi stiva !
De acum incolo voi folosi stiva !
De acum incolo voi folosi stiva !
De acum incolo voi folosi stiva !
De acum incolo voi folosi stiva !
Bubble Sort - ASM
Astazi am reusit , cu ajutor ce-i drept ( din partea prof. meu de arhitectura ), sa implementez ultra-performantul, ultra-schimbistul si nemaipomenitul Bubble Sort . Il pun aici, in speranta ca mai exista cineva care este interesat de ASM ...
-
void bubble_sort(int*,int)
-
{
-
_asm
-
{
-
bucla_mare:
-
mov ecx,0
-
mov eax,[ebp+8]
-
mov ebx,[ebp+12]
-
bucla_mica:
-
mov edx,eax
-
add edx,4
-
mov esi,[eax]
-
cmp esi,[edx]
-
ja interschimbare
-
jmp continua
-
interschimbare:
-
push dword ptr [edx]
-
push dword ptr [eax]
-
pop dword ptr [edx]
-
pop dword ptr [eax]
-
mov ecx,1
-
jmp continua
-
continua:
-
add eax,4
-
dec ebx
-
cmp ebx,1
-
jne bucla_mica