Pagina 1 di 1

Errore inline Assembly in C

Inviato: mer 20 ott 2010, 11:31
da Slack_Eater
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 :)

Re: Errore inline Assembly in C

Inviato: mer 20 ott 2010, 14:02
da 414N
È 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".

Re: Errore inline Assembly in C

Inviato: mer 20 ott 2010, 18:22
da Calzo
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

Re: Errore inline Assembly in C

Inviato: mer 20 ott 2010, 20:24
da Slack_Eater
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");

Re: Errore inline Assembly in C

Inviato: mer 20 ott 2010, 20:32
da Slack_Eater
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

Re: Errore inline Assembly in C

Inviato: mer 20 ott 2010, 22:25
da phobos3576
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.

Re: Errore inline Assembly in C

Inviato: gio 21 ott 2010, 13:54
da Calzo
: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