Numérisez à partir de stdin et imprimez sur stdout à l’aide d’un assemblage en ligne dans gcc

Comment lire depuis stdin et écrire sur stdout dans un assemblage en ligne gcc, comme nous le faisons dans NASM:

_start: mov ecx, buffer ;buffer is a data word initialised 0h in section .data mov edx, 03 mov eax, 03 ;read mov ebx, 00 ;stdin int 0x80 ;Output the number entered mov eax, 04 ;write mov ebx, 01 ;stdout int 0x80 

J’ai essayé de lire stdin dans l’assemblage en ligne, puis d’atsortingbuer l’entrée à x:

 #include int x; int main() { asm(" movl $5,  %%edx \n\t" " movl $0,  %%ebx \n\t" " movl $3,  %%eax \n\t" " int $0x80 \n\t " mov %%ecx,x" ::: "%eax", "%ebx", "%ecx", "%edx"); printf("%d",x); return 0; } 

Cependant, cela échoue.

appel système depuis un assemblage en ligne GCC

Ce lien contient un code capable d’imprimer un seul caractère sur la sortie standard.

Ce code est basé uniquement sur ma lecture des références Linux. Je ne suis pas sur Linux, donc je ne peux pas le tester, mais ça devrait être assez proche. Je voudrais le tester en utilisant la redirection: a.out

 #include  #define SYS_READ 3 int main() { char buff[10]; /* Declare a buff to hold the returned ssortingng. */ ssize_t charsread; /* The number of characters returned. */ /* Use constraints to move buffer size into edx, stdin handle number into ebx, address of buff into ecx. Also, "0" means this value goes into the same place as parameter 0 (charsread). So eax will hold SYS_READ (3) on input, and charsread on output. Lastly, you MUST use the "memory" clobber since you are changing the contents of buff without any of the constraints saying that you are. This is a much better approach than doing the "mov" statements inside the asm. For one thing, since gcc will be moving the values into the registers, it can RE-USE them if you make a second call to read more chars. */ asm volatile("int $0x80" /* Call the syscall interrupt. */ : "=a" (charsread) : "0" (SYS_READ), "b" (STDIN_FILENO), "c" (buff), "d" (sizeof(buff)) : "memory", "cc"); printf("%d: %s", (int)charsread, buff); return 0; } 

En réponse aux commentaires d’Aanchal Dalmia ci-dessous:

1) Comme Timothy le dit ci-dessous, même si vous n’utilisez pas la valeur de retour, vous devez informer gcc que le registre ax est en cours de modification. En d’autres termes, il n’est pas prudent de supprimer le “= a” (charsread), même si cela semble fonctionner.

2) Votre observation selon laquelle ce code ne fonctionnerait pas si le buff était global était très confuse. Maintenant que j’ai une installation linux pour jouer, j’ai pu reproduire l’erreur et je pense connaître le problème. Je parie que vous utilisez l’ int 0x80 sur un système x64. Ce n’est pas ainsi que vous êtes censé appeler le kernel en 64 bits.

Voici un autre code qui montre comment effectuer cet appel en x64. Notez que le numéro de fonction et les registres ont été modifiés par rapport à l’exemple ci-dessus (voir http://blog.rchapman.org/post/36801038863/linux-system-call-table-for-x86-64 ):

 #include  #define SYS_READ 0 #define STDIN_FILENO 0 int main() { char buff[10]; /* Declare a buff to hold the returned ssortingng. */ ssize_t charsread; /* The number of characters returned. */ /* Use constraints to move buffer size into rdx, stdin handle number into rdi, address of buff into rsi. Also, "0" means this value goes into the same place as parameter 0 (charsread). So eax will hold SYS_READ on input, and charsread on output. Lastly, I use the "memory" clobber since I am changing the contents of buff without any of the constraints saying that I am. This is a much better approach than doing the "mov" statements inside the asm. For one thing, since gcc will be moving the values into the registers, it can RE-USE them if you make a second call to read more chars. */ asm volatile("syscall" /* Make the syscall. */ : "=a" (charsread) : "0" (SYS_READ), "D" (STDIN_FILENO), "S" (buff), "d" (sizeof(buff)) : "rcx", "r11", "memory", "cc"); printf("%d: %s", (int)charsread, buff); return 0; } 

Cela demandera à un meilleur expert linux que moi d’expliquer pourquoi l’ int 0x80 sur x64 ne fonctionnerait pas avec les variables de stack. Mais utiliser syscall fonctionne, et syscall est plus rapide sur x64 que sur int.

Edit: Il m’a été signalé que les clobbers du kernel rcx et r11 pendant les appels système. Ne pas en tenir compte peut causer toutes sortes de problèmes, je les ai donc ajoutés à la liste des obstacles.