PDA

View Full Version : Alcune domandine su Assembler! Datemi una mano Per Favore!!


luxorl
09-07-2004, 16:43
Allora vi spiego il mio dubbio:
lunedì ho un esamino sulle basi di assembler...
per studiare mi sto svlgendo tutti i vecchi appelli, adesso ho fatto un programmino che dati due vettori fa la somma di tutti gli elementi del primo e poi la somma di tutti gli elementi del secondo, e poi di questi due fa il prodotto.

andando a vedere le soluzioni dopo che l'ho svolto a modo mio ho trovato questa differenza...

Codice Soluzione:

loopsomma:
movl 8(%ebp),%ebx
movl (%ebx,%esi,4),%eax
add %eax,-4(%ebp)
incl %esi
loop loopsomma


questo è il ciclo per fare la somma di tutti gli elemeti del primo vettore, la differenza in quello che ho fatto io sta nel mettere fuori ciclo la riga:


movl 8(%ebp),%ebx


comando con cui sposto il vettore, che si trova ad 8(%ebp) in %ebx...

perchè secondo me metterlo nel ciclo è un passaggio inutile.. o ha una sua importanza? voi che dite?

poi non sapevo il comando per fare il prodotto, nelle soluzioni ho trovato queste righe:


movl $0, %edx
movl -8(%ebp),%eax
imull -4(%ebp)


non conosco questo comando imull.. me lo spiegate per favore? e mi spiegate come queste tre righe fanno il prodotto?

Come sempre vi ringrazio!!

ilsensine
09-07-2004, 16:52
Originariamente inviato da luxorl
questo è il ciclo per fare la somma di tutti gli elemeti del primo vettore, la differenza in quello che ho fatto io sta nel mettere fuori ciclo la riga:


movl 8(%ebp),%ebx


Hai fatto bene


poi non sapevo il comando per fare il prodotto, nelle soluzioni ho trovato queste righe:


movl $0, %edx
movl -8(%ebp),%eax
imull -4(%ebp)



imul <x> moltiplica eax per <x> e pone il risultato (a 64 bit) in edx:eax.
La prima mov che azzera edx per me è superflua.

luxorl
09-07-2004, 17:04
Grazie :)

questa scritta:

edx:eax

vuol dire che prima il risultato va in eax se poi nn ci entra va anche in edx?

cionci
09-07-2004, 18:56
Vuole dire che i 32 bit meno significativi vanno in eax ed i 32 bit più siginificativi vanno comunque (anche se il risultato entrerebbe in 32 bit) in edx...

imul (integer multiply)...la 'l' in fondo sta a significare la dimensione degli operandi, come al solito... I numeri vengono considerati come interi, quindi con segno...

Esiste anche mul che opera una moltiplicazione fra interi senza segno...

repne scasb
09-07-2004, 21:12

luxorl
09-07-2004, 21:41
Ingegneria elettronica.... è un esame di solo 3 crediti sulla base di assembler.. penso che tu stia confondendo/sbagliando qualcosa..

luxorl
09-07-2004, 21:41
per me il tuo codice è arabo.. MAI virso a corso!

luxorl
09-07-2004, 21:43
Esi lo incremento di uno perchè poi moltiplico per 4! :) forse è tardi e sei un po' stancuccia?

luxorl
09-07-2004, 21:45
-8(%EBP)
accede allo stack partendo dove ho "congelato" %EBP e salendo di 2 posti (8 perchè uso Long) posto dedicato ad una variabile d'ambiente che mi sono creato!

cionci
10-07-2004, 00:18
Originariamente inviato da repne scasb
1) Se usi ESI come indice nel loop lo devi incrementare non di 1 ma di 4 perche' stai sommando valori a 32 bit (32 bit=4 bytes)

Quella è la sintassi AT&T, la tua è quella Intel... Una grossa differenza sta appunto in questo...
E' giusta così, perchè il valore del registro indice (il secondo specificato) viene moltiplicato per lo scale factor che viene specificato successivamente...
Originariamente inviato da repne scasb
3) Se EBP e un puntatore allo stack, l'accesso ai valori sullo stack si ottieme EBP + "qualcosa" e non EBP - "qualcosa", lo stack scende e non sale.

Se si fa il prologo della PROC in questo modo:

pushl %ebp
movl %esp, %ebp
subl $k, %esp #si riservano k byte per le variabili locali alla proc

Allora è perfettamente lecito usare un displacement negativo rispetto a ebp... Si va infatti a lavorare sulel variabili locali alla proc...

L'epilogo della proc diventa questo:

movl %ebp, %esp
popl %ebp
ret

Si ristabiliscono le condizioni iniziali dello stack per permettere alla ret di prelevare l'indirizzo di ritorno...

Questo prologo ed epilogo sono quelli standard usati nella traduzione delle funzioni dal C e C++ in assembly dai compilatori GNU...

I parametri attuali della funzione sono accessibili da %ebp + un displacement non negativo... Lo spazio per le varibili locali deve essere riservato con la sottrazione sopra...e per accedervi si utilizza un displacement negativo...

repne scasb
10-07-2004, 09:21

cionci
10-07-2004, 09:59
Originariamente inviato da repne scasb
2) Dal 1989 i linguaggi di alto livello che necessitano di un "stack frame" (uno spazio per le variabili locali di una subroutine), "DEVONO" utilizzare le istruzione ENTER e LEAVE, che dispongono per loro natura la capacita' di generare un eccezione se lo spazio per lo stack "termina". Se utilizziamo lo spazio "sotto" lo stack senza dichiararlo chi ci assicura che lo stack non sia in overflow?
Formalmente hai ragione, ma questi linguaggi dichiarano le variabili locali per definizione nello stack... L'unico modo per evitare di fare N push è di fare la sottrazione....

Riguardo alla sintassi AT&T a me l'hanno fatta per imprare come un compilatore g++ traduce il codice C++ in assembly... Come prova pratica dovevamo tradurre alcune funzioni di una classe rispettando i formalismi del passaggio dei parametri e di nomeclatura delle varie funzioni...e poi linkado tutto insieme sorgente parziale C++ e sorgente ASM dovevamo ottenere un risultato coerente...
Per la LEAVE sono d'accordo con te...noi non la utilizzavamo perchè usavamo un compilatore chiamato DJGPP...che non è proprio il classico gcc... Il compialtore GNU invece la usa...

Tanto per farti un esempio:

int funzione(int i, int j)
{
int somma;
somma = i+j;
return somma;
}


int main()
{
int res = funzione(10, 5);
return 0;
}

Sorgente ASM generato dal compialtore:

.file "prova.c"
.text
.align 2
.globl __Z8funzioneii
.def __Z8funzioneii; .scl 2; .type 32; .endef
__Z8funzioneii:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl 12(%ebp), %eax
addl 8(%ebp), %eax
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
leave
ret
.def ___main; .scl 2; .type 32; .endef
.align 2
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
andl $-16, %esp
movl $0, %eax
movl %eax, -8(%ebp)
movl -8(%ebp), %eax
call __alloca
call ___main
movl $5, 4(%esp)
movl $10, (%esp)
call __Z8funzioneii
movl %eax, -4(%ebp)
movl $0, %eax
leave
ret

cionci
10-07-2004, 10:08
Ah...anche i compialtori M$ usano lo stesso metodo epr definire le variabili locali...
Questo non è un proprio vero sorgente ASM, ma il risultato del disassemblatore...

1: int funzione(int i, int j)
2: {
00401020 push ebp
00401021 mov ebp,esp
00401023 sub esp,44h
00401026 push ebx
00401027 push esi
00401028 push edi
00401029 lea edi,[ebp-44h]
0040102C mov ecx,11h
00401031 mov eax,0CCCCCCCCh
00401036 rep stos dword ptr [edi]
3: int somma;
4: somma = i+j;
00401038 mov eax,dword ptr [ebp+8]
0040103B add eax,dword ptr [ebp+0Ch]
0040103E mov dword ptr [ebp-4],eax
5: return somma;
00401041 mov eax,dword ptr [ebp-4]
6: }

Anche se sinceramente quel 44h non lo capisco...ma sembra una pratica standard per tutte le funzioni... Ogni chiamata riserve un minimo di 44h byte per le variabili locali... Secondo me è un enorme spreco, ma andiamo avanti...
Il sorgente del gcc (porting MinGW32) è molto più performante...perchè il Visual C++ inizializza sempre al valore 0xCCCCCCCCh la porzione di stack riservata alle variabili locali...

repne scasb
10-07-2004, 10:47

repne scasb
10-07-2004, 10:59

cionci
10-07-2004, 12:08
Rgiuardo all'ottimizzazione sembra che l'unico compilatore veramente ottimizzato sia quello Intel e solo per codice SSE e SSE2... Nell'uso della FPU invece sono equivalenti agli altri...

Luc@s
10-07-2004, 12:11
Originariamente inviato da cionci
Rgiuardo all'ottimizzazione sembra che l'unico compilatore veramente ottimizzato sia quello Intel e solo per codice SSE e SSE2... Nell'uso della FPU invece sono equivalenti agli altri...

Che caso :rolleyes:
Ma del compilatore intel........ne esiste una qualche vers gratisse ?

repne scasb
10-07-2004, 12:16

cionci
10-07-2004, 12:16
Non credo... C'è un trial di 30 gg...

Luc@s
10-07-2004, 12:19
Originariamente inviato da cionci
Non credo... C'è un trial di 30 gg...

Cerchero ;)
Cmq... ma oggi, con tutti i cmpilatori che ci sono, è il caso di stare a comparare l'asm disassemblato??
Non è meglio lasciare assemblare a un compilatore?
In fondo, la maggior parte dei programmi, nn deve avere prestazioni real time....li si che l'asm sarebbe molto utile.

IMHO ;)

cionci
10-07-2004, 12:59
Originariamente inviato da Luc@s
Non è meglio lasciare assemblare a un compilatore?
In fondo, la maggior parte dei programmi, nn deve avere prestazioni real time....li si che l'asm sarebbe molto utile.
Se cerchi le prestazioni migliori l'asm è la migliore strada...ma non l'intero programma, magari con l'asm inline...
Guarda anche il codice sopra generato da Visual C++ la differenza con il codice generato con MinGW32 è nettissima... E già in questo caso le prestazioni della routine di MinGW32 sono probabilmente più che doppie rispetto a quelle di Visual C++...

Luc@s
10-07-2004, 16:54
Originariamente inviato da cionci
Guarda anche il codice sopra generato da Visual C++ la differenza con il codice generato con MinGW32 è nettissima... E già in questo caso le prestazioni della routine di MinGW32 sono probabilmente più che doppie rispetto a quelle di Visual C++...

Con MinGW32 includi anche DevC++??
Mi dai qualche link a dati relativi alla comparazione tra i 2 compilatori, se li hai?

cionci
10-07-2004, 16:55
Non lì ho...mi dispiace...

Sì...include anche i vari IDE che fanno uso di MinGW32...

Luc@s
10-07-2004, 16:57
mi sapresti spiegare, in 2 parole, le differenze che rendono le prestazioni cosi diverse?

Tnk

cionci
10-07-2004, 17:09
C'è quell'inizializzazione della memoria dedicata alle variabili locali che prende molti cicli di clock (conta che bisogna accedere alla meoria)... Magari su una funzione più grande questa cosa conta poco...ma in questo caso si fa sentire...

Basta fare un confronto fra i due codici:

1: int funzione(int i, int j)
2: {
00401020 push ebp pushl %ebp
00401021 mov ebp,esp movl %esp, %ebp
00401023 sub esp,44h subl $4, %esp
00401026 push ebx
00401027 push esi
00401028 push edi
00401029 lea edi,[ebp-44h]
0040102C mov ecx,11h
00401031 mov eax,0CCCCCCCCh
00401036 rep stos dword ptr [edi]
3: int somma;
4: somma = i+j;
00401038 mov eax,dword ptr [ebp+8] movl 12(%ebp), %eax
0040103B add eax,dword ptr [ebp+0Ch] addl 8(%ebp), %eax
0040103E mov dword ptr [ebp-4],eax movl %eax, -4(%ebp)
5: return somma;
00401041 mov eax,dword ptr [ebp-4] movl -4(%ebp), %eax
6: }

Luc@s
10-07-2004, 17:12
ma perche tutta la roba che fa la M$ è imprecisa e piena di superficialita futili e il soft open è cosi ben definito, prestante e restio a inserimenti inutili e non richiesti?
Bah.......

Luc@s
25-08-2004, 22:14
up.......era una disc interessante ;)