Repository 32bit  Forum
Repository 64bit  Wiki

Errore inline Assembly in C

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.

Errore inline Assembly in C

Messaggioda Slack_Eater » mer ott 20, 2010 10:31

Ciao,

stavo facendo questo piccolo esercizio di Assembly per ritornare la lunghezza di una data stringa inserita:

Codice: Seleziona tutto
#include <stdio.h>
#include <stdlib.h>

#define MAXLEN 80

int main(int argc, char** argv) {

        unsigned char text[MAXLEN];
        unsigned long len = 0;

        scanf("%s", text);

        __asm (
                "movl $-1, %ecx;\n\t"
                "start_loop: inc %ecx;\n\t"
                "cmp 0, text(%ecx);\n\t"
                "jne start_loop;\n\t"
                "mov %ecx, len;\n\t"
        );

        printf("%d", len);

        return (EXIT_SUCCESS);
}
 

Quando lo compilo ho questo errore:

Codice: Seleziona tutto
ex1.c: Assembler messages:
ex1.c:22: Error: too many memory references for `cmp'


Premetto che a scuola il professore di questo corso usa windows per sviluppare questo genere di programmi e non
ha alcuna idea di come vengano scritte le istruzioni con un compilatore differente, per questo volevo chiedervi anche se la sintassi Assembly che ho usato è corretta.

Grazie :)
Avatar utente
Slack_Eater
Linux 2.0
Linux 2.0
 
Messaggi: 163
Iscritto il: gio feb 14, 2008 21:29
Località: Svizzera
Nome Cognome: Giuseppe Scalzi
Slackware: 13.37
Kernel: 2.6.38.2-smp
Desktop: KDE 4.7.0

Re: Errore inline Assembly in C

Messaggioda 414N » mer ott 20, 2010 13:02

È semplice: non puoi fare un confronto tra un valore immediato quale 0 e una cella di memoria, perché puoi puntare una sola cella alla volta durante un confronto.
Poni a 0 un registro e usa quello per il confronto.
Riguardo la sintassi, non sono molto dimestico di sintassi AT&T, ma sembra corretto quel che hai scritto.
EDIT: ho provato a far funzionare lo spezzone di codice che hai postato, ma sembra ci siano altri errori (va in segmentation fault appena dopo la scanf).
Ti consiglio di leggere questa pagina, soprattutto la parte Extended Asm, dato che quel che vuoi fare richiede l'uso di una variabile (len) dichiarata al di fuori del contesto asm.
EDIT2: gcc ti sparerà fuori un warning (se usi il flag -Wall) alla compilazione, per via del %d usato su di un "unsigned long". Usa "%lu".
Avatar utente
414N
Iper Master
Iper Master
 
Messaggi: 2877
Iscritto il: mer feb 13, 2008 16:19
Località: Bulagna
Slackware: 14.0 (x64)
Kernel: 3.2.29
Desktop: LXDE

Re: Errore inline Assembly in C

Messaggioda Calzo » mer ott 20, 2010 17:22

Ciao.
Io vedo due cose (una te l'ha già detta 414N):
1- il cmp non può comparare 2 indirizzi di memoria. Inoltre tu vuoi comparare proprio il valore 0 ('\0') quindi devi mettere $0 nell'istruzione cmp.
2- le variabili locali non puoi usarle in quel modo, ma devi metterle globali

Il codice che ho provato io è quindi questo:
Codice: Seleziona tutto
#include <stdio.h>
#include <stdlib.h>

#define MAXLEN 80
unsigned char text[MAXLEN];
unsigned long len = 0;

int main(int argc, char** argv) {
        scanf("%s", text);
        __asm (
                "movl $-1, %ecx;\n\t"
                "start_loop: inc %ecx;\n\t"
                "cmp $0, text(%ecx);\n\t"
                "jne start_loop;\n\t"
                "mov %ecx, len;\n\t"
        );

        printf("%d\n", len);

        return (EXIT_SUCCESS);
}
a me funziona.
bye
Avatar utente
Calzo
Linux 2.0
Linux 2.0
 
Messaggi: 112
Iscritto il: sab ott 06, 2007 21:21
Località: MN
Slackware: 10.2 | 13
Desktop: Fluxbox | KDE

Re: Errore inline Assembly in C

Messaggioda Slack_Eater » mer ott 20, 2010 19:24

Perfetto grazie, il codice che avete postato funziona.
Per curiosità ho chiesto anche sul forum di gentoo, ottenendo un altra possibile implementazione del codice che ho scritto, funzionante anche essa.

http://forums.gentoo.org/viewtopic-t-849368.html :D

Qui ho trovato qualcosa d'altro riguardante l'inline assembly => http://wiki.osdev.org/Inline_Assembly

Per esempio l'assegnazione di variabili:

Codice: Seleziona tutto
int some_obscure_name asm("param") = 5; // "param" will be accessible in inline Assembly.
 
void foo()
{
   asm("mov param, %%eax");
}

Ho anche visto che ce un interessante opzione per evitare di convertire codice con sintassi Intel in At&T:

Codice: Seleziona tutto
asm(".intel_syntax noprefix");
asm("mov eax, ebx");
Avatar utente
Slack_Eater
Linux 2.0
Linux 2.0
 
Messaggi: 163
Iscritto il: gio feb 14, 2008 21:29
Località: Svizzera
Nome Cognome: Giuseppe Scalzi
Slackware: 13.37
Kernel: 2.6.38.2-smp
Desktop: KDE 4.7.0

Re: Errore inline Assembly in C

Messaggioda Slack_Eater » mer ott 20, 2010 19:32

Ecco come sarebbe scritto con la sintassi Intel:

Codice: Seleziona tutto

#include <stdio.h>
#include <stdlib.h>

#define MAXLEN 80
unsigned char text[MAXLEN + 1];
unsigned long len;

int main(int argc, char** argv) {
        scanf("%s", &text);

        asm(".intel_syntax noprefix");
        asm("mov ecx, -1\n\t"
                        "start_loop:\n\t"
                        "inc ecx\n\t"
                        "cmpb text[ecx], 0\n\t"
                        "jne start_loop\n\t"
                        "mov len, ecx\n\t");

        asm(".att_syntax prefix");

        printf("%d", len);

        return (EXIT_SUCCESS);
}


Funziona anche questo
Avatar utente
Slack_Eater
Linux 2.0
Linux 2.0
 
Messaggi: 163
Iscritto il: gio feb 14, 2008 21:29
Località: Svizzera
Nome Cognome: Giuseppe Scalzi
Slackware: 13.37
Kernel: 2.6.38.2-smp
Desktop: KDE 4.7.0

Re: Errore inline Assembly in C

Messaggioda phobos3576 » mer ott 20, 2010 21:25

C'è da precisare comunque che in Assembly il trasferimento dati (o la comparazione) tra valore immediato e locazione di memoria è perfettamente lecito; il valore immediato, in quanto tale, viene codificato direttamente nel binario.
(il trasferimento inverso, da memoria a immediato, non avrebbe senso visto che il valore immediato non ha un indirizzo di memoria).

C'è però una importante differenza rispetto al trasferimento dati tra valore immediato e registro; ad esempio, con la sintassi NASM:

Trasferimento dati a 16 bit di un valore immediato nel registro AX:
Codice: Seleziona tutto
mov ax, 3


Trasferimento dati a 32 bit di un valore immediato nel registro EAX:
Codice: Seleziona tutto
mov eax, 3


Questa istruzione, invece, è lecita ma produce un errore:
Codice: Seleziona tutto
mov [myvar1], 3

L'Assembly non ha informazioni sulla dimensione in bit del trasferimento dati e così genera un messaggio di errore; non dimentichiamo, infatti, che il nome myvar1 rappresenta semplicemente l'indirizzo iniziale di una locazione di memoria.

Per risolvere il problema è necessario specificare l'informazione richiesta dall'Assembly; a tale proposito, NASM usa specificatori come byte, word, dword.
Quindi, ad esempio:

Trasferimento dati a 32 bit di un valore immediato in una locazione di memoria:
Codice: Seleziona tutto
mov dword [myvar1], 3


La sintassi AT&T prevede istruzioni come movl (Move Long - 32 bit), movw (Move Word - 16 bit), cmpb (Compare Byte - 8 bit), etc.
Avatar utente
phobos3576
Staff
Staff
 
Messaggi: 2980
Iscritto il: sab apr 16, 2005 23:00
Slackware: 13.1
Kernel: 2.6.37-smp
Desktop: KDE 4.5.3

Re: Errore inline Assembly in C

Messaggioda Calzo » gio ott 21, 2010 12:54

:shock:
Slack_Eater ha scritto:Ho anche visto che ce un interessante opzione per evitare di convertire codice con sintassi Intel in At&T:
asm(".intel_syntax noprefix");
asm("mov eax, ebx");

Ma grande!!
Questa mi mancava... e mi è piuttosto utile

grazie
bye
Avatar utente
Calzo
Linux 2.0
Linux 2.0
 
Messaggi: 112
Iscritto il: sab ott 06, 2007 21:21
Località: MN
Slackware: 10.2 | 13
Desktop: Fluxbox | KDE


Torna a Programmazione

Chi c’è in linea

Visitano il forum: TurnitinBot [Bot] e 2 ospiti