GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Wie funktioniert die Stapelzuweisung unter Linux?

Es scheint, dass das Stack-Speicherlimit nicht zugewiesen ist (jedenfalls konnte es nicht mit unbegrenztem Stack). https://www.kernel.org/doc/Documentation/vm/overcommit-accounting sagt:

Das Wachstum des C-Sprachstapels führt eine implizite mremap durch. Wenn Sie absolute Garantien wollen und nahe am Rand laufen, MÜSSEN Sie Ihren Stapel auf die größte Größe abbilden, die Sie Ihrer Meinung nach benötigen. Für die typische Stack-Nutzung spielt dies keine große Rolle, aber es ist ein Grenzfall, wenn Sie sich wirklich wirklich darum kümmern

Das Mapping des Stacks wäre jedoch das Ziel eines Compilers (falls er eine Option dafür hat).

BEARBEITEN:Nach einigen Tests auf einem x84_64-Debian-Rechner habe ich festgestellt, dass der Stack ohne Systemaufruf wächst (gemäß strace ). Das bedeutet also, dass der Kernel es automatisch vergrößert (das bedeutet „implizit“ oben), d. h. ohne explizites mmap /mremap aus dem Prozess.

Es war ziemlich schwierig, detaillierte Informationen zu finden, die dies bestätigen. Ich empfehle Understanding The Linux Virtual Memory Manager von Mel Gorman. Ich nehme an, dass die Antwort in Abschnitt 4.6.1 Handhabung eines Seitenfehlers steht , mit der Ausnahme "Region nicht gültig, aber neben einer erweiterbaren Region wie dem Stack" und der entsprechenden Aktion "Region erweitern und Seite zuweisen". Siehe auch D.5.2 Stapel erweitern .

Andere Referenzen zur Linux-Speicherverwaltung (aber fast nichts über den Stack):

  • Speicher-FAQ
  • Was jeder Programmierer über Speicher wissen sollte von Ulrich Drepper

EDIT 2:Diese Implementierung hat einen Nachteil:In Eckfällen wird eine Stack-Heap-Kollision möglicherweise nicht erkannt, selbst wenn der Stack größer als das Limit wäre! Der Grund dafür ist, dass ein Schreibvorgang in eine Variable im Stack im zugewiesenen Heap-Speicher landen kann, in diesem Fall gibt es keinen Seitenfehler und der Kernel kann nicht wissen, dass der Stack erweitert werden musste. Siehe mein Beispiel in der Diskussion Silent Stack-Heap Collision unter GNU/Linux, die ich in der gcc-Hilfeliste gestartet habe. Um dies zu vermeiden, muss der Compiler beim Funktionsaufruf Code hinzufügen; Dies kann mit -fstack-check erfolgen für GCC (Einzelheiten finden Sie in der Antwort von Ian Lance Taylor und auf der GCC-Manpage).


Linux-Kernel 4.2

  • mm/mmap.c#acct_stack_growth entscheidet, ob es einen Segfault gibt oder nicht. Es verwendet rlim[RLIMIT_STACK] was dem POSIX gerlimit(RLIMIT_STACK) entspricht
  • arch/x86/mm/fault.c#do_page_fault ist der Interrupt-Handler, der eine Kette startet, die schließlich acct_stack_growth aufruft
  • arch/x86/entry/entry_64.S richtet den Seitenfehler-Handler ein. Sie müssen etwas über Paging wissen, um diesen Teil zu verstehen:Wie funktioniert x86-Paging? | Stapelüberlauf

Minimales Testprogramm

Wir können es dann mit einem minimalen NASM-64-Bit-Programm testen:

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

Stellen Sie sicher, dass Sie ASLR deaktivieren und Umgebungsvariablen entfernen, da diese auf den Stapel gehen und Platz beanspruchen:

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

Das Limit liegt etwas unter meinem ulimit -s (8 MiB für mich). Es sieht so aus, als ob dies an zusätzlichen System V-spezifischen Daten liegt, die ursprünglich zusätzlich zur Umgebung auf den Stapel gelegt wurden:Linux 64-Befehlszeilenparameter in Assembly | Stapelüberlauf

Wenn Sie es ernst meinen, erstellen Sie TODO ein minimales initrd-Image, das vom Stack-Top aus zu schreiben beginnt und herunterfährt, und führen Sie es dann mit QEMU + GDB aus. Geben Sie dprintf ein in der Schleife, die die Stapeladresse und einen Haltepunkt bei acct_stack_growth ausgibt . Es wird herrlich sein.

Verwandte:

  • https://softwareengineering.stackexchange.com/questions/207386/how-are-the-size-of-the-stack-and-heap-limited-by-the-os
  • Woher wird der Stapelspeicher für einen Linux-Prozess zugewiesen? | Stapelüberlauf
  • Was ist der Linux-Stack? | Stapelüberlauf
  • Was ist die maximale Rekursionstiefe in Python und wie kann sie erhöht werden? auf Stapelüberlauf

Standardmäßig ist die maximale Stapelgröße auf 8 MB pro Prozess konfiguriert.
kann aber mit ulimit geändert werden :

Anzeige der Vorgabe in kB:

$ ulimit -s
8192

Auf unbegrenzt setzen:

ulimit -s unlimited

Auswirkungen auf die aktuelle Shell und Subshells und ihre untergeordneten Prozesse.
(ulimit ist ein in die Shell eingebauter Befehl)

Sie können den tatsächlich verwendeten Stack-Adressbereich anzeigen mit:
cat /proc/$PID/maps | grep -F '[stack]'
unter Linux.


Linux
  1. Was ist NGINX? Wie funktioniert es?

  2. So löschen Sie den Speichercache in Linux

  3. Wie funktioniert Awk ‘!a[$0]++’?

  4. Ssh – Wie funktioniert TCP-Keepalive in Ssh?

  5. Ist die Speicherzuweisung in Linux nicht blockierend?

So deaktivieren Sie Swap dauerhaft unter Linux

Linux – Wie funktioniert die Anzeige von Linux?

Was ist Source Command in Linux und wie funktioniert es?

Wie funktioniert Swap-Speicher in Linux?

Wie funktioniert eine Linux-GUI auf der untersten Ebene?

Wie funktioniert die Anzeige von Linux?