GNU/Linux >> Tutoriels Linux >  >> Linux

Comment fonctionne l'allocation de pile sous Linux ?

Il semble que la limite de mémoire de la pile ne soit pas allouée (de toute façon, elle ne le pourrait pas avec une pile illimitée). https://www.kernel.org/doc/Documentation/vm/overcommit-accounting dit :

La croissance de la pile du langage C effectue un mremap implicite. Si vous voulez des garanties absolues et que vous courez près du bord, vous DEVEZ mmapper votre pile pour la plus grande taille dont vous pensez avoir besoin. Pour une utilisation typique de la pile, cela n'a pas beaucoup d'importance, mais c'est un cas particulier si vous vous en souciez vraiment

Cependant, mmapper la pile serait l'objectif d'un compilateur (s'il a une option pour cela).

EDIT :Après quelques tests sur une machine Debian x84_64, j'ai constaté que la pile grandissait sans aucun appel système (selon strace ). Donc, cela signifie que le noyau le fait grandir automatiquement (c'est ce que signifie "implicite" ci-dessus), c'est-à-dire sans mmap explicite /mremap du processus.

Il était assez difficile de trouver des informations détaillées confirmant cela. Je recommande Understanding The Linux Virtual Memory Manager par Mel Gorman. Je suppose que la réponse se trouve dans la section 4.6.1 Gestion d'un défaut de page , à l'exception "Région non valide mais se trouve à côté d'une région extensible comme la pile" et l'action correspondante "Développer la région et allouer une page". Voir aussi D.5.2 Étendre la pile .

Autres références sur la gestion de la mémoire Linux (mais avec presque rien sur la pile) :

  • FAQ sur la mémoire
  • Ce que tout programmeur devrait savoir sur la mémoire par Ulrich Drepper

EDIT 2 :Cette implémentation a un inconvénient :dans les cas extrêmes, une collision pile-tas peut ne pas être détectée, même dans le cas où la pile serait plus grande que la limite ! La raison en est qu'une écriture dans une variable de la pile peut se retrouver dans la mémoire de tas allouée, auquel cas il n'y a pas de défaut de page et le noyau ne peut pas savoir que la pile devait être étendue. Voir mon exemple dans la discussion Silent stack-heap collision under GNU/Linux I started in the gcc-help list. Pour éviter cela, le compilateur doit ajouter du code à l'appel de la fonction ; cela peut être fait avec -fstack-check pour GCC (voir la réponse de Ian Lance Taylor et la page de manuel de GCC pour plus de détails).


Noyau Linux 4.2

  • mm/mmap.c#acct_stack_growth décide s'il y aura erreur de segmentation ou non. Il utilise rlim[RLIMIT_STACK] qui correspond au POSIX gerlimit(RLIMIT_STACK)
  • arch/x86/mm/fault.c#do_page_fault est le gestionnaire d'interruption qui démarre une chaîne qui finit par appeler acct_stack_growth
  • arch/x86/entry/entry_64.S configure le gestionnaire de défauts de page. Vous devez en savoir un peu plus sur la pagination pour comprendre cette partie :comment fonctionne la pagination x86 ? | Débordement de pile

Programme de test minimal

Nous pouvons ensuite le tester avec un programme NASM 64 bits minimal :

global _start
_start:
    sub rsp, 0x7FF000
    mov [rsp], rax
    mov rax, 60
    mov rdi, 0
    syscall

Assurez-vous de désactiver ASLR et de supprimer les variables d'environnement, car celles-ci iront sur la pile et prendront de la place :

echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
env -i ./main.out

La limite est quelque part légèrement en dessous de mon ulimit -s (8 Mo pour moi). Il semble que cela soit dû aux données supplémentaires spécifiées par System V initialement placées sur la pile en plus de l'environnement :Paramètres de ligne de commande Linux 64 dans Assembly | Débordement de pile

Si vous êtes sérieux à ce sujet, TODO créez une image initrd minimale qui commence à écrire à partir du haut de la pile et descend, puis exécutez-la avec QEMU + GDB. Mettez un dprintf sur la boucle imprimant l'adresse de la pile, et un point d'arrêt à acct_stack_growth . Ce sera glorieux.

Connexe :

  • https://softwareengineering.stackexchange.com/questions/207386/how-are-the-size-of-the-stack-and-heap-limited-by-the-os
  • D'où provient la mémoire de la pile allouée pour un processus Linux ? | Débordement de pile
  • Qu'est-ce que la pile Linux ? | Débordement de pile
  • Quelle est la profondeur de récursivité maximale en Python et comment l'augmenter ? sur débordement de pile

Par défaut, la taille maximale de la pile est configurée pour être de 8 Mo par processus,
mais il peut être modifié en utilisant ulimit :

Affichage de la valeur par défaut en Ko :

$ ulimit -s
8192

Définir sur illimité :

ulimit -s unlimited

affectant le shell et les sous-shells actuels et leurs processus enfants.
(ulimit est une commande intégrée du shell)

Vous pouvez afficher la plage d'adresses de pile réelle utilisée avec :
cat /proc/$PID/maps | grep -F '[stack]'
sous Linux.


Linux
  1. Comment effacer le cache mémoire sous Linux

  2. Comment fonctionne Awk '!a[$0]++' ?

  3. Comment fonctionne le Sticky Bit ?

  4. Ssh – Comment Tcp-keepalive fonctionne-t-il dans Ssh ?

  5. Comment fonctionne la commande 'ls' sous Linux/Unix ?

Comment désactiver définitivement Swap sous Linux

Linux - Comment fonctionne l'affichage de Linux ?

Qu'est-ce que la commande source sous Linux et comment ça marche ?

Comment fonctionne la mémoire d'échange sous Linux ?

Comment fonctionne une interface graphique Linux au niveau le plus bas ?

Comment fonctionne l'affichage de Linux ?