Forum Linux.débutant probleme pour comprendre l'édition de lien

Posté par  . Licence CC By‑SA.
Étiquettes : aucune
1
20
jan.
2019

Bonjour à tous,

voici mon code :

#include <stdio.h>

void main(){
         fprintf(stdout, "bonjour");
         return 0;
}

Quand je compile mon programme avec : gcc mon_programme.c ,le compilateur va (furtivement) inclure des libs de la glibC car j'utilise la fonction fprintf(). Mais quand j'exécute mon programme : a.out, il faut également lancer dans la mémoire ram la fonction fprintf que j'ai besoin non ? comment ca marche ? quand je lance le programme, est ce qu'il y a un autre programme qui va regarder les fonctions des libs que j'utilise pour les mettres dans la RAM et leurs donner les bonnes adresses de pointage pour l'appelle de ces fonctions ?

Merci d'avance pour votre aide

  • # Dynamique vs statique

    Posté par  (site web personnel) . Évalué à 7. Dernière modification le 20 janvier 2019 à 20:34.

    $ cat bonjour.c 
    #include <stdio.h>
    
    int main(){
             fprintf(stdout, "bonjour");
             return 0;
    }
    
    $ gcc -o bonjour_dyn bonjour.c
    $ ldd bonjour_dyn 
        linux-vdso.so.1 (0x00007ffd071a9000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f33a5de3000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f33a5fdc000)
    $ ls -nhl bonjour_dyn
    -rwxr-xr-x 1 1000 1000 17K janv. 20 20:20 bonjour_dyn
    $ /sbin/ldconfig --help
    Usage : ldconfig [OPTION...]
    Configuration dynamique des éditions de liens lors de l'exécution.
    $ gcc -static -o bonjour_sta bonjour.c
    $ ldd bonjour_sta
        n'est pas un exécutable dynamique
    $ ls -nhl bonjour_sta
    -rwxr-xr-x 1 1000 1000 738K janv. 20 20:21 bonjour_sta

    Dans le premier cas, la fonction est fournie dynamiquement. Dans le second cas, elle est embarquée dans le binaire. Avec des conséquences sur la taille du binaire, la disponibilité de la bibliothèque à l'exécution, la possibilité de remplacer cette bibliothèque pour correction ou par malveillance, etc.

    Pour aller plus loin (mais ça devient plus technique), une discussion twitter récente #prod365 #fr Un peu de #linux #internals: quels sont les mécanismes du #kernel pour lire et executer un programme?

    • [^] # Re: Dynamique vs statique

      Posté par  . Évalué à 4.

      L'utilitaire "strace" est également bien utile pour voir le cheminement des appels lors du chargement des librairies dynamiques.

      strace ./bonjour_dyn 
      execve("./bonjour_dyn", ["./bonjour_dyn"], 0x7ffe7a1756c0 /* 60 vars */) = 0
      brk(NULL)                               = 0x1715000
      access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
      openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
      fstat(3, {st_mode=S_IFREG|0644, st_size=124549, ...}) = 0
      mmap(NULL, 124549, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fe9a3906000
      close(3)                                = 0
      openat(AT_FDCWD, "/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
      read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\21\2\0\0\0\0\0"..., 832) = 832
      fstat(3, {st_mode=S_IFREG|0755, st_size=2066504, ...}) = 0
      mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe9a3904000
      mmap(NULL, 3889792, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fe9a334b000
      mprotect(0x7fe9a34f8000, 2093056, PROT_NONE) = 0
      mmap(0x7fe9a36f7000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1ac000) = 0x7fe9a36f7000
      mmap(0x7fe9a36fd000, 14976, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fe9a36fd000
      close(3)                                = 0
      arch_prctl(ARCH_SET_FS, 0x7fe9a39054c0) = 0
      mprotect(0x7fe9a36f7000, 16384, PROT_READ) = 0
      mprotect(0x600000, 4096, PROT_READ)     = 0
      mprotect(0x7fe9a3925000, 4096, PROT_READ) = 0
      munmap(0x7fe9a3906000, 124549)          = 0
      fstat(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 2), ...}) = 0
      brk(NULL)                               = 0x1715000
      brk(0x1736000)                          = 0x1736000
      brk(NULL)                               = 0x1736000
      write(1, "bonjour", 7bonjour)                  = 7
      exit_group(0)                           = ?
      +++ exited with 0 +++
      

      On peut voir dans ce log, un premier accès au fichier "/etc/ld.so.cache", qui permet au système de retrouver la librairie libc, qu'il va ensuite ouvrir

      openat(AT_FDCWD, "/lib64/libc.so.6", O_RDONLY|O_CLOEXEC)

      Le système va ensuite faire un mmap de la fonction fprintf, qui appelle elle même d'autres fonctions (qui sont également mmapée), jusqu'à l'appel final qu'on peut voir vers la fin du log:

      write(1, "bonjour", 7bonjour)

  • # Le processus.

    Posté par  . Évalué à 3.

    En supposant que tu lances depuis une ligne de commande bash.

    • bash fork, il créer un clone de lui même.
      • Le noyau fait le fork,
        • il alloue la RAM nécessaire au clone de bash.
        • il crée un nouveau contexte d’exécution.
      • bash détermine qui est le fils et qui est le père.
    • bash.fils excecute execv qui va remplacer le processus actuel par l’exécutable en paramètre.
      • Le noyau charge le nouvel exécutable.
        • Lit le fichier exécutable
        • interprète les sections (code, donnée, etc.)
        • les installes en mémoires, initialise les données non initialisées à 0.
        • charge les bibliothèque dynamique s’il y en a.
        • fait l’édition de lien en RAM.
      • démarre l’exécution au point de start du programme.
      • Le programme s’initialise puis appelle la fonction main.
    • [^] # Re: Le processus.

      Posté par  . Évalué à 1.

      merci beaucoup pour vos réponses, vous avez répondu à mon probleme !

      Merci encore !

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.