2010-06-02 3 views
3

Est-il possible d'écrire un seul caractère à l'aide d'un appel système à partir d'un bloc d'assemblage en ligne? si c'est le cas, comment? il devrait ressembler à "quelque chose" comme ceci:syscall depuis l'assemblage en ligne GCC

__asm__ __volatile__ 
        (
        " movl $1, %%edx \n\t" 
        " movl $80, %%ecx \n\t" 
        " movl $0, %%ebx \n\t" 
        " movl $4, %%eax \n\t" 
        " int $0x80  \n\t" 
        ::: "%eax", "%ebx", "%ecx", "%edx" 
        ); 

80 $ est 'P' en ascii, mais qui ne renvoie rien.

toutes les suggestions très appréciées!

+0

Quel système d'exploitation? –

+0

@Paul_R: linux, x86 – guest

+0

OK - J'ai ajouté la balise 'linux' pour vous –

Répondre

1

Quelque chose comme


char p = 'P'; 

int main() 
{ 
__asm__ __volatile__ 
        (
        " movl $1, %%edx \n\t" 
        " leal p , %%ecx \n\t" 
        " movl $0, %%ebx \n\t" 
        " movl $4, %%eax \n\t" 
        " int $0x80  \n\t" 
        ::: "%eax", "%ebx", "%ecx", "%edx" 
        ); 
} 

Ajouter: Notez que je l'ai utilisé lea pour charger l'adresse effective du charbon dans ecx registre; pour la valeur de ebx J'ai essayé 0 $ et 1 $ et il semble fonctionner de toute façon ...

Évitez l'utilisation de charbon externe

int main() 
{ 
__asm__ __volatile__ 
        (
        " movl $1, %%edx \n\t" 
        " subl $4, %%esp \n\t" 
        " movl $80, (%%esp)\n\t" 
        " movl %%esp, %%ecx \n\t" 
        " movl $1, %%ebx \n\t" 
        " movl $4, %%eax \n\t" 
        " int $0x80  \n\t" 
        " addl $4, %%esp\n\t" 
        ::: "%eax", "%ebx", "%ecx", "%edx" 
        ); 
}

N.B. .: cela fonctionne en raison de la boutisme des processeurs intel! : D

+0

ah. Je ne suis pas très bon avec l'assemblage pour le moment, donc je n'ai pratiquement aucune idée de lea et autres .. aussi, 0 & 1 sont stderr, et stdout resp. iirc – guest

+0

bien sûr, vous pouvez utiliser la pile; le code généré par gcc utilise ebp, il l'a préparé avant; nous pouvons nous en tenir à utiliser juste pour le moment; J'ai modifié la réponse, voyez-la. – ShinTakezou

+0

génial !! peut-il aussi être fait avec un 'push' et le stackpointer? – guest

2

IIRC, deux choses sont fausses dans votre exemple. Premièrement, vous écrivez stdin avec mov $ 0,% ebx Ensuite, write prend un pointeur comme deuxième argument, donc pour écrire un seul caractère vous avez besoin que ce caractère soit stocké quelque part en mémoire, vous ne pouvez pas écrire la valeur directement à% ecx

ex:

.data 
char: .byte 80 
.text 
mov $char, %ecx 

Je n'ai fait asm pur sous Linux, en ligne ne jamais utiliser gcc, vous ne pouvez pas supprimer des données dans le milieu de l'assemblée, donc je ne suis pas sûr comment obtenir le pointeur en utilisant l'assemblage en ligne.

EDIT: Je pense que je viens de me rappeler comment le faire. vous pouvez pousser « p » sur la pile et l'utilisation% esp

pushw $80 
movl %%esp, %%ecx 
... int $0x80 ... 
addl $2, %%esp 
+0

en C je fais" pareil "avec' char * p = 'P'; write (1, &p, 1); ', donc stdout est 1 – guest

+0

char * p = 'P' devrait être char p = 'P' je suppose. – ShinTakezou

+0

'write()' prend 'const void * buf' comme deuxième argument – guest

4

Vous pouvez utiliser des contraintes spécifiques à l'architecture pour placer directement les arguments dans des registres spécifiques, sans avoir besoin des instructions movl dans votre assembly en ligne. De plus, vous pouvez alors utiliser l'opérateur & pour obtenir l'adresse du caractère:

#include <sys/syscall.h> 

void sys_putc(char c) { 
    // write(int fd, const void *buf, size_t count); 
    int ret; 
    asm volatile("int $0x80" : "=a"(ret): "a"(SYS_write), "b"(1), "c"(&c), "d"(1)); 
} 

int main(void) { 
    sys_putc('P'); 
    sys_putc('\n'); 
} 

(Dans ce cas, =a(ret) est nécessaire pour indiquer que le syscall aplatit EAX.)

$ cc -m32 sys_putc.c && ./a.out 
P 

Vous pouvez également renvoyer le nombre d'octets écrits que le syscall renvoie et utiliser "0" comme contrainte pour indiquer EAX à nouveau:

int sys_putc(char c) { 
    int ret; 
    asm volatile("int $0x80" : "=a"(ret) : "0"(SYS_write), "b"(1), "c"(&c), "d"(1)); 
    return ret; 
} 
+1

Dans le premier exemple, je considère que c'est un bug. Un problème est que 'int $ 0x80' modifie _EAX_ car il contient une valeur de retour. Vous devez vous assurer que vous avez une sorte de contrainte de sortie, sinon l'optimiseur peut simplement supposer que _EAX_ contient la valeur de SYS_write dans le modèle d'assemblage étendu. Votre deuxième exemple de code le fait correctement. –

+0

Excellent point, merci! Je suppose qu'il suffirait d'ajouter "% eax" dans la liste clobber de la première version? (Je voulais inclure une version sans sorties aussi.) – Dato

+0

Ne pense pas que _EAX_clobber fonctionnera parce que le compilateur peut supposer qu'il est en conflit avec la contrainte d'entrée seulement en utilisant '" a "'. Je soupçonne qu'une erreur quelconque serait soulevée. –

Questions connexes