CONNEXION
  • RetourJeux
    • Sorties
    • Hit Parade
    • Les + populaires
    • Les + attendus
    • Soluces
    • Tous les Jeux
    • Gaming
  • RetourActu Gaming
    • News
    • Astuces
    • Tests
    • Previews
    • Toute l'actu gaming
  • RetourBons plans
    • Bons plans
    • Bons plans Smartphone
    • Bons plans Hardware
    • Bons plans Image et Son
    • Bons plans Amazon
    • Bons plans Cdiscount
    • Bons plans Decathlon
    • Bons plans Fnac
    • Tous les Bons plans
  • RetourJVTech
    • Actus High-Tech
    • Intelligence Artificielle
    • Smartphones
    • Mobilité urbaine
    • Hardware
    • Image et son
    • Tutoriels
    • Tests produits High-Tech
    • Guides d'achat High-Tech
    • JVTech
  • RetourCulture
    • Actus Culture
    • Culture
  • RetourVidéos
    • A la une
    • Gaming Live
    • Vidéos Tests
    • Vidéos Previews
    • Gameplay
    • Trailers
    • Chroniques
    • Replay Web TV
    • Toutes les vidéos
  • RetourForums
    • Hardware PC
    • PS5
    • Switch 2
    • Xbox Series
    • Switch
    • Pokemon pocket
    • FC 25 Ultimate Team
    • League of Legends
    • Tous les Forums
  • PC
  • PS5
  • Xbox Series
  • Switch 2
  • PS4
  • One
  • Switch
  • iOS
  • Android
  • MMO
  • RPG
  • FPS
En ce moment Genshin Impact Valhalla Breath of the wild Animal Crossing GTA 5 Red dead 2
Liste des sujets

[Systeme, Archi] Format d'executable

saleGauss
saleGauss
Niveau 9
27 mars 2010 à 12:19:08

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 */
___________________________________________

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

chris_27
chris_27
Niveau 10
27 mars 2010 à 15:27:53

Question 1/
:d) non, la résolution de write ça se fait au chargement de ton fichier binaire. Essaie un :
$ ldd test_unix
pour avoir la liste de tous les fichiers objets qui seront chargés en même temps que ton binaire.

Si tu veux vraiment un binaire complet, tu dois le compiler avec l'option "-static" (note que tu ne verras pas de différence au niveau du .s).

Question 2/
:d) c'est plus subtile que ça.
Le fichier assembleur (.s) produit par gcc ne peut pas être traduit et linker directement par as + ld comme tu l'as fait.
J'avoue que je ne sais plus exactement comment il faut faire pour s'en sortir, et que je n'ai pas le courage de fouiller la page de man de gcc pour retrouver l'information.

Question 3/
:d) il y a trois formats gérés par Linux : a.out, coff et elf (elf32 ou elf64 suivant le système).

Mac OS X utilise le format Dwarf.

Et Windows utilise son propre format.

godrik
godrik
Niveau 30
27 mars 2010 à 18:14:11

nota bene: le noyau linux supporte le format a.out mais il n'est quasiment plus utilise et son support est souvent desactiver a la compilation dans les distributions.

saleGauss
saleGauss
Niveau 9
27 mars 2010 à 22:01:03

Tiens, c'est rigolo.
Voila ce que j'ai fais :

-depuis mon .s (obetenu avec gcc -S) j'ai fais :
as test_unix.s -o test_unix.o

-avec le .o ainsi obtenu, j'ai fais :
ld -o test_unix test_unix.o -static -lc

(si je ne met pas le "-lc" il me dit test_unix.c:(.text+0x14): undefined reference to `write')

J'obtiens donc mon executable test_unix
Et si je l'execute, j'obtiens :

hello
Erreur de segmentation

C'est étonnant quand même cet erreur de segmentation :D

bref, je vous tiendrais au courant.

Au fait, du coup, ça marche bien de s'arreter au .s avec gcc, puis de "as" et "ld" à la main.
Je sais, ça ne sert à rien, mais ça me permet d'apprendre quelques petits trucs et ça m'amuse :D

chris_27
chris_27
Niveau 10
27 mars 2010 à 22:31:50

Hoho…

D'un autre coté, chez moi, ce n'est pas suffisant de passer -lc à ld. Il faut en plus lui dire d'utiliser un fichier (dont j'ai oublié le nom :rouge: ) qui fournit le bout de code qui s'occupe d'initialiser le programme est de lancer la fonction main du programme C.

Sans ça, moi j'ai l'erreur suivante :
« cannot find entry symbol _start ».

Bon, j'ai trop honte d'avoir oublié, donc j'ai fait la recherche. La commande pour linker avec ld est :

ld /usr/lib/crt1.o /usr/lib/crti.o foo.o /usr/lib/crtn.o -lc -o foo

(et en fait il y a 3 fichiers).

saleGauss
saleGauss
Niveau 9
28 mars 2010 à 12:17:09

Merci Chris,

J'ai donc linké avec ta commande, en ajoutant les fichiers objets crt1, crti et crtn.

Et j'ai exactement la même erreur de segmentation.

Toi, si tu assembles le fichier .s mentionné dans mon premier post, et que tu linkes avec ta commande, tu obtiens un executable qui fait un segfault ou pas ?

Bref, si quelqu'un a une idée, je n'ai pas réussi à trouver...

Sous forums
  • Aide à l'achat Mac
  • Création de Jeux
  • Linux
  • Programmation
  • Création de sites web
  • Internet
  • Steam Deck
  • Macintosh
  • Hardware
La vidéo du moment