Hello à tous,
Bon, comme certains l'ont peut-être déjà remarqué, je m'interesse pas mal aux fonctionnement des systemes, parce que je n'y connais pas grand chose, et que je trouve cela vraiment essentiel.
J'en suis arrivé à me poser des questions au niveau des appels systemes, et de leur traduction en assembleur.
Je voulais voir la différence au niveau assembleur entre appels de fonctions de la bibliotheque standard, et primitives systeme.
Je me suis bettement demandé ce que devenait mon "write(1,buff,sizeof(buff))" une fois compilé.
J'ai donc naturellement écris :
/* test_unix.c */
___________________________________________
- include <unistd.h>
char buff[] = {'h','e','l','l','o', '\n'};
int main()
{
write(1, buff, sizeof(buff));
return(0);
}
_____________________________________________
Que j'ai compilé en m'arrétant à l'assembleur avec "gcc -S test_unix.c"
J'ai obtenu :
/* Fichier test_unix.s */
__________________________________________________
___
.file "test_unix.c"
.globl buff
.data
.type buff, @object
.size buff, 6
buff:
.byte 104
.byte 101
.byte 108
.byte 108
.byte 111
.byte 10
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
movl $6, %edx
movl $buff, %esi
movl $1, %edi
call write
movl $0, %eax
leave
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (SUSE Linux) 4.4.1 [gcc-4_4-branch revision 150839]"
.section .comment.SUSE.OPTs,"MS",@progbits,1
.string "ospwg"
.section .note.GNU-stack,"",@progbits
__________________________________________________
_______
Bon, je ne connais pas bcp l'assembleur x86, mais ayant fait un peu d'ARM, j'arrive à le déchiffrer un peu.
Au début, on trouve nos données.
Puis le point d'entrée du programme, qui globalement m'a l'air de préparer ses registres edx, eci, edi avec :
- Dans edx : La taille du buffer qu'il va devoir ecrire
- Dans eci : l'adresse du buffer qu'il va devoir ecrire
- Dans edi : Le descripteur de fichier qui lui stipule là où il va devoir écrire
Et il fait cela avant de se brancher sur "write" avec "call write"
Question 1/
--------------
J'imagine que la résolution de ce "write" qui n'est pas défini dans ma source se fera à l'édition des liens.
Ce "write" doit être défini dans la librairie unix. En gros j'imagine qu'il doit y avoir quelque par un code objet qui contient sa définition, et qui est prêt à être linké avec mon code objet (si je transforme ce fichier assembleur en fichier objet avec mon assmbleur gnu).
J'ai bon ?
En clair si je fais "as test_unix.s -o test_unix.o", je vais transformer mon fichier assembleur en fichier objet (code machine), mais le "write" n'est toujours pas défini.
Par contre, lorsque je ferais l'édition des liens avec :
ld -o output test_unix.o -ld
Il prendra mon .o, il prendra celui de la bibliothèque (dans un répertoire par defaut) qui contient la définition encore manquante de "write", et il produira un executable avec l'ensemble des deux.
J'en arrive à ma question 2 :
-----------------------------
Le format résultant, il devrait bien être exécutable normalement non ?
En faisant exactement ce que j'ai dis plus haut ("as" puis "ld"), il n'est pas exécutable.
J'obtiens cette erreur :
./output
bash: ./output: Aucun fichier ou dossier de ce type
Avez vous une idée de pourquoi ?
Si je fais
"file ./output"
Il me donne comme infos :
./output: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
Pouvez vous me dire pourquoi n'est-il pas executable normallement ? Est-ce parce que l'OS le jette parce qu'il ne correspond pas à un format que lon linux attend ?
Question 3 :
j'ai entendu parler du "format" .out et ELF.
Les deux sont-il sensé être supporté par linux ?
Je remercie ceux qui voudrons bien éclairé le programmeur Ocaml et Haskell que je suis, qui tente d'apprendre un peu d'archi et de système le week-end :D