PDA

View Full Version : [ASM] Strano non è vero?


LOVE85
26-06-2006, 14:52
Ciao ragazzi ho consegnato online il materiale e il professore una volta controllato il codice ASM del mio elaborato dice:

Se imposta i dati di input secondo il caso di prova riportato dal
correttore, ossia

unsigned int Point = ( (-1000)<<16 | ((1000)&0xFFFF) );
unsigned int PointSet[]={
(0<<16) | (0)&0xFFFF,
(1000<<16) | (1000)&0xFFFF,
(-1000<<16) | (-1000)&0xFFFF,
((-999)<<16) | (999)&0xFFFF,
((-1000)<<16) | (200)&0xFFFF
};

noterà che il suo programma restituisce l'indice 1 (il punto 1000,1000),
mentre il punto più vicino è quello di indice 3 (999,-999).

Suggerisco di eseguire passo a passo con il debugger il programma in modo da
trovare l'errore.

ECCO IL MIO ELABORATO 2:

#include <stdio.h>


void main()
{

unsigned int Point = (5<<16) | (3)&0xFFFF; //il punto
unsigned int PointSet[] = { (10<<16) | (3)&0xFFFF, (4<<16) | (2)&0xFFFF, (5<<16) | (20)&0xFFFF}; //insieme
int n = sizeof(PointSet)/sizeof(PointSet[0]); // numero punti dell'insieme
int index; //risultato: indice del punto più vicino a Point
__asm
{
MOV ECX,n //Inizializza il registro ECX con il valore del numero dei punti n
MOV EDX,1 //Carica il valore 1 nel registro EDX per il confronto con il valore n
CMP EDX,ECX //Confronta 1 con il valore n
JE Fine //Salta a Fine se n=1 (si confronto un solo punto)
Ciclo1: MOV EAX,PointSet[ECX*4-4] // Inizia il ciclo che carica ogni elemento del vettore per confrontarlo con il punto dato in termini di distanza
PUSH EAX // Salvaguarda il contenuto di EAX (coordinate del punto corrente) nello stack per poter operare su EAX senza perdere il valore precedente
MOV EBX,Point[0] //Carica in EBX il punto dato verso il quale determinare la distanza
PUSH EBX //Salvaguarda il contenuto di EBX nello stack come sopra
AND EAX,0000FFFFh //Isola il valore di x del punto corrente dal suo valore y nel registro EAX

TEST AH,10000000b //Verifica se x del punto corrente è negativo
JNZ NegativoxVettore //Se x è negativo salta a NegativoxVettore dove provvede ad estendere il valore 1 in tutti i 16 bit più significativi


Coordinatay: AND EBX,0000FFFFh //Isola il valore di x del punto dato dal suo valore y nel registro EBX
TEST BH,10000000b //Verifica se x del punto dato è negativo
JNZ NegativoxPunto //Se x è negativo salta a NegativoxPunto dove provvede ad estendere a 1 tutti i 16 bit più significativi






Prosegui1: SUB EAX,EBX //Effettua la sottrazione tra le coordinate x del punto dato e del punto corrente
MUL EAX //Eleva al quadrato il riultato della sottrazione precedente facendo la moltiplicazione per se stesso
POP EBX //Estrae dallo stack e inserisce nel registro EBX nuovamente le coordinate del punto corrente
SHR EBX,16 //Sposta i primi 16 bit più significativi contenenti y del punto corrente nei 16 bit meno significativi
TEST BH,10000000b //Verifica se y del punto corrente è negativo
JNZ NegativoyVettore //Se y è negativo salta a NegativoyVettore dove provvede ad estendere a 1 tutti i 16 bit più significativi

Prosegui2: POP EDX //Estrae dallo stack e inserisce nel registro EDX nuovamente le coordinate del punto dato
SHR EDX,16 //Sposta i primi 16 bit più significativi contenenti y del punto dato nei 16 bit meno significativi
TEST DH,10000000b //Verifica se y del punto dato è negativo
JNZ NegativoyPunto //Se y è negativo salta a NegativoyPunto dove provvede ad estendere a 1 tutti i 16 bit più significativi


Prosegui3: SUB EDX,EBX //Effettua la sottrazione tra le coordinate y del punto dato e del punto corrente
MOV EBX,EAX //Salvaguarda il contenuto di EAX nel registro EBX
MOV EAX,EDX //Carica in EAX la differenza per predisporla alla moltiplicazione per se stessa
MUL EAX //Eleva al quadrato la differenza fra le y del punto corrente e del punto dato facendo la moltiplicazione per se stessa
ADD EAX,EBX //Somma i quadrati delle differenze tra le x e le y del punto dato e del punto corrente che rappresenta la distanza al quadrato
PUSH EAX //Salvaguarda nello stack la distanza al quadrato corrente da utilizzare per individuare quella minore
LOOP Ciclo1 //Gestione del Ciclo che ripete tutte le operazioni precedenti per ogni punto
JMP VersoFine //Salta a fine una volta terminato il ciclo e calcolati tutti i quadrati delle distanze salvaguardati nello stack

NegativoxVettore: OR EAX,11111111111111110000000000000000b //Imposta a 1 i 16 bit più significativi della componente x del punto corrente
JMP Coordinatay //Ritorna all'interno del Ciclo1
NegativoxPunto: OR EBX,11111111111111110000000000000000b //Imposta a 1 i 16 bit più significativi della componente x del punto dato
JMP Prosegui1 //Ritorna all'interno del Ciclo1
NegativoyVettore: OR EBX,11111111111111110000000000000000b //Imposta a 1 i 16 bit più significativi della componente y del punto corrente
JMP Prosegui2 //Ritorna all'interno del Ciclo1
NegativoyPunto: OR EDX,11111111111111110000000000000000b //Imposta a 1 i 16 bit più significativi della componente y del punto dato
JMP Prosegui3 //Ritorna all'interno del Ciclo1

VersoFine: MOV ECX,n //Carica nel registro ECX la dimensione n del vettore
DEC ECX //Decrementa di 1 il valore del registro ECX
MOV EDX,1 //Carica il valore 1 nel registro EDX (qui utilizzato per identificare l'indice della distanza al quadrato più piccolo)

POP EAX //Inizia l'estrazione delle distanza del quadrato per il loro conronto

Ciclo2: POP EBX //Inizio del ciclo di confronto

CMP EAX,EBX //Confronto tra le distanze corenti
JB Ritorno //Salta se la differenza delle distanze al quadrato è negativa
MOV EAX,EBX //Altrimenti scambia le due distanze in modo da mettere quella più piccola sempre in EAX

INC EDX //Calcola l'indice della distanza più piccola finora individuata e salvata in EAX


Ritorno: LOOP Ciclo2 //Ritorna al Ciclo2 per terminare i confronti delle distanze al quadrato
Fine: DEC EDX //Decrementa di 1 il valore del registro EDX per adeguarsi all'indice del vettore
MOV index,EDX //Carica l'indice trovato nella variabile index per stamparla a video
}
// Stampa su video

printf("Il punto piu' vicino a (%d,%d) e' (%d,%d) [indice=%d]\n",(short int)(Point&0xFFFF),(short int)(Point>>16),(short int)(PointSet[index]&0xFFFF),(short int)(PointSet[index]>>16),index);

}

Provate con altri punti anche quelli negativi e il programma funziona come deve. Mettendo il caso che dice il prof mi dà l'indice sbagliato. Perchè? :cry: :cry:

andbin
26-06-2006, 16:12
Scusa .... ma perché devi fare tutto 'sto macello per calcolare la distanza tra 2 punti???

Se devi fare una estensione di segno da 16 a 32 bit, ci sono già delle istruzioni apposite come la CWDE (che però fa solo AX --> EAX) oppure la più generica MOVSX.

EDIT:
Se programmi in assembly è meglio se tieni a portata di mano i manuali ufficiali della Intel che trovi <qui> (http://www.intel.com/design/pentium4/manuals/index_new.htm). Queste dovrebbero essere le tue bibbie. :read:

andbin
26-06-2006, 18:12
Aggiungo un'altra cosa importante (che mi è venuta in mente solo oggi :p ).

Il risultato delle sottrazioni x2-x1 e y2-y1 è un valore con segno (può essere, giustamente, anche negativo). In questa situazione NON devi usare la MUL ma devi usare la IMUL. Questo perché la MUL opera su valori senza segno. Quindi un valore di FFFFFC18h (-1000 in complemento due su 32 bit) verrebbe visto come 4294966296 e il risultato della moltiplicazione ... beh, prova ad immaginarlo! ;)
La IMUL invece opera su valori con segno.

LOVE85
27-06-2006, 09:51
Ciao Andrea ok grazie del consiglio.
Ci sentiamo oggi pomeriggio magari in chat che ho un sacco di domande da porti. Mi dici quando sei libero in chat? Grazie ancora a dopo! :D