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.
Rispondi
Avatar utente
Slack_Eater
Linux 1.x
Linux 1.x
Messaggi: 163
Iscritto il: gio 14 feb 2008, 21:29
Nome Cognome: Giuseppe Scalzi
Slackware: 13.37
Kernel: 2.6.38.2-smp
Desktop: KDE 4.7.0
Località: Svizzera
Contatta:

Errore inline Assembly in C

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

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: Errore inline Assembly in C

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

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: Errore inline Assembly in C

Messaggio 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

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

Re: Errore inline Assembly in C

Messaggio 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");

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

Re: Errore inline Assembly in C

Messaggio 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

Avatar utente
phobos3576
Staff
Staff
Messaggi: 2980
Iscritto il: dom 17 apr 2005, 0:00
Slackware: 13.1
Kernel: 2.6.37-smp
Desktop: KDE 4.5.3

Re: Errore inline Assembly in C

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

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: Errore inline Assembly in C

Messaggio 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

Rispondi