Pagina 1 di 1

Assembler inline

Inviato: ven 29 feb 2008, 18:52
da afterjames
Salve a tutti..Sono un neofita dell'assembler, ho provato a realizzare una semplice funzione che esegue una somma tra due interi senza segno..Purtroppo i risultati sono deludenti!Non capisco se è sbagliato il mio listato, o se c'è qualcosa che mi sfugge relativamente alla sintassi AT&T.Ho fatto così:

Codice: Seleziona tutto

#include<stdio.h>

unsigned int miaVar=56;
unsigned int miaVar2=299;
unsigned int somma;
int main(void){
	asm("movl miaVar,%ebx\n\t"
	       "movl miaVar2,%ecx\n\t"
	       "movl $0,%eax\n\t"
	       "pushl %ebx\n\t"
	       "pushl %ecx\n\t"
	       "call somma_r\n\t"
	       "addl $8,%esp\n\t"
	       "movl %eax,somma\n\t"      
       "somma_r:pushl %ebp\n\t"
	     	"movl %ebp,%esp\n\t"     	
             	"movl 12(%ebp),%eax\n\t"
	     	"addl 8(%ebp),%eax\n\t"
             	"movl %ebp,%esp\n\t"
	     	"popl %ebp\n\t"
	     	"ret\n\t");


printf("Valore %u \n",somma);
return 0; 		

} 

Ci sono alcune istruzioni inutili, tipo le movl su ebp ed esp, ma non credo siano quelli i problemi.La Call da problemi.Le label si inseriscono così?"<nome_label>:"

Re: Assembler inline

Inviato: ven 29 feb 2008, 20:46
da robbybby
Non conosco l'assembler AT&T, ma, a prima vista, mi sembra di notare una mancata pulizia dello stack dopo la chiamata: hai due push (ebx e ecx) ma nessun pop che li toglie dallo stack, ne' nel chimato, ne' nel chiamante.
Inoltre prima di "somma_r:" ci andrebbe un ret o un jump.
Ripeto: non conosco l'assembler in questione: le mie sono sono considerazioni generali.

Re: Assembler inline

Inviato: sab 1 mar 2008, 1:38
da afterjames
Ho trovato un'istruzione sbagliata sulla funzione.La versione giusta è:

"somma_r: pushl %ebp\n\t"
"movl %esp,%ebp\n\t"
"movl 12(%ebp),%eax\n\t"
"addl 8(%ebp),%eax\n\t"
"movl %ebp,%esp\n\t"
"popl %ebp\n\t"
"ret\n\t");
Però non funziona ugualmente!Riguardo la pulizia dello stack, non c'è bisogno di fare le pop, dopo la Call faccio un incremento di 8 byte pari proprio alla dimensione dei due parametri della funzione.La funzione dovrebbe essere giusta, ho provato a far generare l'assembler con gcc -S ed ho ottenuto praticamente quella che ho scritto..Grazie comunque

Re: Assembler inline

Inviato: dom 2 mar 2008, 11:04
da Blizzard
ciao,
ad occhio e croce ho visto che hai definito una funzione dentro il main.... non lo so se si può fare e soprattutto senza conseguenze impreviste....

Codice: Seleziona tutto

#include<stdio.h>

    unsigned int miaVar=56;
    unsigned int miaVar2=299;
    unsigned int somma;
    int main(void){
	    asm("movl miaVar,%ebx\n\t"
			    "movl miaVar2,%ecx\n\t"
			    "movl miaVar,%eax\n\t"
			    "addl %ecx,%eax\n\t"
			    "movl %eax,somma\n\t");


	    printf("Valore %u \n",somma);
	    return 0;       

    }

così funge tutto.... ma mi dirai "Grazie al" non era quello che volevo.... tuttavia hai provato a dichiarare, sempre inline la funzione separatamente???
oppure a scrivere quel codice totalmente asm?
a quanto vedo fai tutto con l'asm, non ho capito a cosa ti serve quella parte dichiarativa di C

ciao
Gio

Re: Assembler inline

Inviato: dom 2 mar 2008, 14:38
da afterjames
Grazie.Ho fatto così:

Codice: Seleziona tutto

#include<stdio.h>
unsigned int miaVar=56;
unsigned int miaVar2=29;
unsigned int somma=0;
void s(){
        asm("somma_r:pushl %ebp\n\t"
	     	   "movl %esp,%ebp\n\t"     	
             	   "movl 12(%ebp),%eax\n\t"
	     	    "addl 8(%ebp),%eax\n\t"
             	    "movl %ebp,%esp\n\t"
	     	    "popl %ebp\n\t"
	     	     "ret\n\t");

}
int main(void){
	asm("pusha\n\t"            // Salva: EAX, EBX, ECX, EDX, ESI, EDI, EBP
	    "movl miaVar,%ebx\n\t"
	    "movl miaVar2,%ecx\n\t"
	    "movl $0,%eax\n\t"
	    "pushl %ebx\n\t"
	    "pushl %ecx\n\t"
	    "call somma_r \n\t"
	    "addl $8,%esp\n\t"
	    "movl %eax,somma\n\t"
	    "popa\n\t");          // Salva: EAX, EBX, ECX, EDX, ESI, EDI, EBP


printf("Valore %u \n",somma);
return 0; 		
} 
+

Ed ora funziona.Oltre a dover dichiarare la funzione fuori dal main, bisogna salvare all'inizio del main i registri utilizzati e poi ripristinarli.Uso ASM perchè ho maggiore flessibilità, e non ho bisogno di fare file separati da integrare poi in fase di linking.Mi sembra la soluzione più immediata.

Re: Assembler inline

Inviato: dom 2 mar 2008, 16:24
da Blizzard
ciao

senti... per fa na cosa più leggibile, perchè non scrivi tipo così?

Codice: Seleziona tutto

asm("movl miaVar,%ebx; \
		movl miaVar2,%ecx; \
		movl miaVar,%eax; \
		addl %ecx,%eax; \
		movl %eax,somma;");
	    
se non hai esigenze particolari, tutti sti \t\n non so troppo belli.... a me scritto così assembla lo stesso
Uso ASM perchè ho maggiore flessibilità, e non ho bisogno di fare file separati da integrare poi in fase di linking.Mi sembra la soluzione più immediata.
capito!

ciao
Gio

Re: Assembler inline

Inviato: dom 2 mar 2008, 16:28
da afterjames
ciao

senti... per fa na cosa più leggibile, perchè non scrivi tipo così?

Codice: Seleziona tutto

    asm("movl miaVar,%ebx; \
          movl miaVar2,%ecx; \
          movl miaVar,%eax; \
          addl %ecx,%eax; \
          movl %eax,somma;");
           
se non hai esigenze particolari, tutti sti \t\n non so troppo belli.... a me scritto così assembla lo stesso
Grazie! :thumbright:

Re: Assembler inline

Inviato: gio 6 mar 2008, 18:38
da 414N
Più che altro, dato che praticamente tutto il programma è scritto in assembly, non fai meglio a inglobarlo in una routine, schiaffarlo dentro un file assembly (.s) e richiamare la funzione somma dal programma C?
Certo, dovrai stare attento al passaggio degli argoment C<->ASM, ma una volta sistemato questo avrai reso il programma più guardabile e più riusabile.

Re: Assembler inline

Inviato: gio 17 apr 2008, 19:37
da Calzo
afterjames ha scritto:Oltre a dover dichiarare la funzione fuori dal main [...]
Bhè non è verissimo. Tu puoi mettere le funzioni praticamente dovunque ti pare (con l'asm tutto è possibile :badgrin:), anche se la soluzione a cui sei arrivato è sicuramente più chiara, IMHO; il vero problema è che nel listato originale tu fai queste operazioni:

Codice: Seleziona tutto

 [...]
       "call somma_r\n\t"
       "addl $8,%esp\n\t"
       "movl %eax,somma\n\t"
       "somma_r: pushl %ebp\n\t"
[...]
ma questo è sbagliato perchè tu fai una call dalla quale ritorni per poi proseguire, ma se prosegui linearmente vai ad eseguire ancora il codice puntato da somma_r il quale poi esegue delle operazioni sul base pointer e quando incontra RET esce dalla funzione main... e insomma succede un casino.
La soluzione è semplicemente nel mettere un jump incondizionato se vuoi mantenere la struttura del programma originale:

Codice: Seleziona tutto

asm("movl miaVar,%ebx\n\t"
       "movl miaVar2,%ecx\n\t"
       "movl $0,%eax\n\t"
       "pushl %ebx\n\t"
       "pushl %ecx\n\t"
       "call somma_r\n\t"
       "addl $8,%esp\n\t"
       "movl %eax,somma\n\t"
      "jmp salto_;\n\t"
       "somma_r: pushl %ebp\n\t"
       "movl %esp,%ebp\n\t"
       "movl 12(%ebp),%eax\n\t"
       "addl 8(%ebp),%eax\n\t"
       "movl %ebp,%esp\n\t"
       "popl %ebp\n\t"
       "ret\n\t"
      "salto_:");
afterjames ha scritto:bisogna salvare all'inizio del main i registri utilizzati e poi ripristinarli
neanche questo è strettamente necessario, anche se anche io preferisco metterlo ;)

Una cosa che forse ti può interessare: per "aumentare la visibilità" del codice puoi scrivere le funzioni così

Codice: Seleziona tutto

void funzione();
asm("funzione:\n\t"
        "pushl %ebp\n\t"
	"movl %esp,%ebp\n\t"     	
        [...]
        "ret\n\t");
Non so se lo sapevi già: io l'ho scoperto recentemente spulciando un kernel (Linux ovviamente :thumbright:). Questo ti permette anche di rilocare la funzione dove preferisci e di chiamarla come una funziona C. Inoltre aggiunge un piccolo livello di ottimizzazione in quanto elimini le istruzioni push %ebp, mov %ebp e il ret finale che la funzione s() che avevi definito aggiunge necessariamente (almeno a meno di ottimizzazioni del compilatore che non ho provato).

bye