salut,
Envoyé par
jamalkamal
On dit que l'instruction $0x80 est un appel au système
non. int est une instruction assembleur qui déclenche une interruption, et sous Linux l'interruption 0x80 (128 en décimal) est ce qu'on appelle la syscall gate (en français le portail à appel système)
je n'ai pas bien saisi comment cette instruction fonctionne, est ce que c'est elle qui est le responsable de l'affichage de mon message : "hello world" sur l'écran ? Si oui, comment peut-elle le faire ?
un appel système (syscall) est une fonction dans l'espace noyau (kernel-land), par exemple la fonction write() est disponible dans l'espace utilisateur (userland)
typiquement, en langage C on peut écrire un programme avec une ligne write(0, "hello world", 11) et - en gros, très schématique et pour simplifier - une fois le programme compilé on se retrouvera avec du code machine du genre :
1 2 3 4 5
| mov eax, syscall_write
mov ebx, 0
mov ecx, "hello world"
mov edx, 11
int 0x80 |
(note: c'est du pseudo-code, toujours pour simplifier la compréhension)
l'instruction int 0x80 va donc quand elle est exécutée récupérer les différentes valeurs dans les registres eax, ebx, ecx, edx etc. et effectuer le branchement adéquat dans le noyau, et au cas où ça ne serait toujours pas clair : l'interruption 0x80, ce petit bout de code qui effectue le bon branchement, est lui aussi dans le noyau, impossible de s'en passer, on est obligé de transiter par cette syscall gate pour absolument tout
le message contient 11 caractères, est ce que cette instruction ( je parle toujours de $0x80) marche comme une boucle pour lire le message caractère par caractère ?
(...)
l'instruction de la ligne 4 place juste le premier octet du message "hello world" dans le registre "ecx", je pense que nous avons besoin de faire une boucle pour lire tout le contenu du message "hello world"
non ! on ne met pas le premier octet de la chaine hello world dans ecx, on met l'adresse du premier octet de la chaine, ce qu'on appelle un pointeur en langage C
à partir de là on connait l'adresse du 1er octet, on connait le nombre d'octets à écrire, "y'a plus qu'à"
y'a plus qu'à... il faut comprendre que le code du noyau est lui aussi écrit en langage C, et en plus il est disponible sur le net, on peut donc aller voir comment est foutue la fonction sys_write(), à nos risques et périls (c'est du code noyau, ça pique forcément un peu)
607 ret = vfs_write(f.file, buf, count, &pos);
on est alors renvoyé successivement vers vfs_write(), puis __vfs_write(), puis un pointeur de fonction un peu obscur file->f_op->write pour finalement atterrir (non sans une certaine dose de magie) du coté de pty_write(), tty_insert_flip_string(), tty_insert_flip_string_fixed_flag() et finalement memcpy() qu'il convient de ne pas confondre avec son homologue en espace utilisateur mais dont le nom est suffisamment évocateur, et qui renvoie en gros sur __builtin_memcpy()
...reprend sa respiration...
cette dernière est une fonction optimisée pour le processeur et déléguée au compilateur, en gros "vas-y compilateur, donne moi la meilleure fonction memcpy() possible pour du x86", et le compilateur de générer un binaire (donc ici un noyau) avec une fonction pour copier de la mémoire en assembleur, en copiant (très probablement) la chaine non pas octet par octet (8bits) mais par coups de 4 octets (32 bits, x86 )
donc pour répondre à ta question initiale : non, la chaine n'est pas écrite "octet par octet" techniquement, elle est copiée d'un seul coup dans un buffer pour affichage
tout ça peut évidemment paraitre compliqué, mais ça l'est
savoir programmer en langage C aide beaucoup pour appréhender l'assembleur sous Linux, étant donné que les appels systèmes sont très largement documentés avec leurs prototypes et des exemples dans ce langage
Partager