Assembler inline

Forum dedicato alla programmazione.

Moderatore: Staff

Regole del forum
1) Citare in modo preciso il linguaggio di programmazione usato.
2) Se possibile portare un esempio del risultato atteso.
3) Leggere attentamente le risposte ricevute.
4) Scrivere i messaggi con il colore di default, evitare altri colori.
5) Scrivere in Italiano o in Inglese, se possibile grammaticalmente corretto, evitate stili di scrittura poco chiari, quindi nessuna abbreviazione tipo telegramma o scrittura stile SMS o CHAT.
6) Appena registrati è consigliato presentarsi nel forum dedicato.

La non osservanza delle regole porta a provvedimenti di vari tipo da parte dello staff, in particolare la non osservanza della regola 5 porta alla cancellazione del post e alla segnalazione dell'utente. In caso di recidività l'utente rischia il ban temporaneo.
Rispondi
afterjames
Linux 0.x
Linux 0.x
Messaggi: 64
Iscritto il: lun 14 gen 2008, 14:14

Assembler inline

Messaggio 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>:"

Avatar utente
robbybby
Linux 4.x
Linux 4.x
Messaggi: 1223
Iscritto il: sab 16 dic 2006, 10:48
Slackware: 13.1 / 64 bit
Kernel: 3.3.x
Desktop: KDE 4.4.5
Località: Fra Trantor e Terminus

Re: Assembler inline

Messaggio 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.

afterjames
Linux 0.x
Linux 0.x
Messaggi: 64
Iscritto il: lun 14 gen 2008, 14:14

Re: Assembler inline

Messaggio 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

Avatar utente
Blizzard
Master
Master
Messaggi: 1509
Iscritto il: mar 2 gen 2007, 22:53
Nome Cognome: Giovanni Santostefano
Slackware: 12.2
Kernel: 2.6.27.7-smp
Desktop: Fluxbox
Contatta:

Re: Assembler inline

Messaggio 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

afterjames
Linux 0.x
Linux 0.x
Messaggi: 64
Iscritto il: lun 14 gen 2008, 14:14

Re: Assembler inline

Messaggio 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.

Avatar utente
Blizzard
Master
Master
Messaggi: 1509
Iscritto il: mar 2 gen 2007, 22:53
Nome Cognome: Giovanni Santostefano
Slackware: 12.2
Kernel: 2.6.27.7-smp
Desktop: Fluxbox
Contatta:

Re: Assembler inline

Messaggio 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

afterjames
Linux 0.x
Linux 0.x
Messaggi: 64
Iscritto il: lun 14 gen 2008, 14:14

Re: Assembler inline

Messaggio 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:

Avatar utente
414N
Iper Master
Iper Master
Messaggi: 2922
Iscritto il: mer 13 feb 2008, 16:19
Slackware: 15.0
Kernel: 5.15.19
Desktop: KDE5
Località: Bulagna
Contatta:

Re: Assembler inline

Messaggio 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.

Avatar utente
Calzo
Linux 1.x
Linux 1.x
Messaggi: 112
Iscritto il: sab 6 ott 2007, 22:21
Slackware: 10.2 | 13
Desktop: Fluxbox | KDE
Località: MN

Re: Assembler inline

Messaggio 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

Rispondi