GNU/Linux >> Linux Esercitazione >  >> Linux

Come funziona l'allocazione dello stack in Linux?

Sembra che il limite di memoria dello stack non sia allocato (comunque, non potrebbe con uno stack illimitato). https://www.kernel.org/doc/Documentation/vm/overcommit-accounting dice:

La crescita dello stack del linguaggio C esegue una mremap implicita. Se vuoi garanzie assolute e corri vicino al limite, DEVI mappare il tuo stack per la dimensione più grande di cui pensi di aver bisogno. Per l'utilizzo tipico dello stack questo non ha molta importanza, ma è un caso limite se ti interessa veramente

Tuttavia l'mmapping dello stack sarebbe l'obiettivo di un compilatore (se ha un'opzione per questo).

EDIT:Dopo alcuni test su una macchina Debian x84_64, ho scoperto che lo stack cresce senza alcuna chiamata di sistema (secondo strace ). Quindi, questo significa che il kernel lo fa crescere automaticamente (questo è ciò che significa "implicito" sopra), cioè senza mmap esplicito /mremap dal processo.

È stato piuttosto difficile trovare informazioni dettagliate che lo confermassero. Consiglio Understanding The Linux Virtual Memory Manager di Mel Gorman. Suppongo che la risposta sia nella Sezione 4.6.1 Gestione di un errore di pagina , con l'eccezione "Area non valida ma accanto a un'area espandibile come lo stack" e l'azione corrispondente "Espandi l'area e alloca una pagina". Vedi anche D.5.2 Espandere lo Stack .

Altri riferimenti sulla gestione della memoria di Linux (ma con quasi nulla sullo stack):

  • Domande frequenti sulla memoria
  • Quello che ogni programmatore dovrebbe sapere sulla memoria di Ulrich Drepper

EDIT 2:questa implementazione ha uno svantaggio:nei casi limite, una collisione stack-heap potrebbe non essere rilevata, anche nel caso in cui lo stack fosse maggiore del limite! Il motivo è che una scrittura in una variabile nello stack può finire nella memoria heap allocata, nel qual caso non si verifica alcun errore di pagina e il kernel non può sapere che lo stack deve essere esteso. Vedi il mio esempio nella discussione Collisione silenziosa stack-heap sotto GNU/Linux che ho iniziato nell'elenco gcc-help. Per evitarlo, il compilatore deve aggiungere del codice alla chiamata della funzione; questo può essere fatto con -fstack-check per GCC (vedere la risposta di Ian Lance Taylor e la pagina man di GCC per i dettagli).


Kernel Linux 4.2

  • mm/mmap.c#acct_stack_growth decide se eseguire il segfault o meno. Usa rlim[RLIMIT_STACK] che corrisponde al POSIX gerlimit(RLIMIT_STACK)
  • arch/x86/mm/fault.c#do_page_fault è il gestore di interrupt che avvia una catena che finisce per chiamare acct_stack_growth
  • arch/x86/entry/entry_64.S imposta il gestore degli errori di pagina. Devi conoscere un po' il paging per capire quella parte:come funziona il paging x86? | Overflow dello stack

Programma di test minimo

Possiamo quindi testarlo con un programma minimo NASM a 64 bit:

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

Assicurati di disattivare ASLR e di rimuovere le variabili di ambiente poiché andranno in pila e occuperanno spazio:

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

Il limite è da qualche parte leggermente al di sotto del mio ulimit -s (8MiB per me). Sembra che ciò sia dovuto a dati extra specificati da System V inizialmente messi nello stack oltre all'ambiente:Parametri della riga di comando di Linux 64 in Assembly | Overflow dello stack

Se sei serio su questo, TODO crea un'immagine initrd minima che inizia a scrivere dall'alto dello stack e scende, quindi eseguila con QEMU + GDB. Metti un dprintf sul ciclo stampando l'indirizzo dello stack e un punto di interruzione in acct_stack_growth . Sarà glorioso.

Correlati:

  • https://softwareengineering.stackexchange.com/questions/207386/how-are-the-size-of-the-stack-and-heap-limited-by-the-os
  • Da dove viene allocata la memoria dello stack per un processo Linux? | Overflow dello stack
  • Che cos'è lo stack Linux? | Overflow dello stack
  • Qual ​​è la massima profondità di ricorsione in Python e come aumentarla? su Stack Overflow

Per impostazione predefinita, la dimensione massima dello stack è configurata su 8 MB per processo,
ma può essere modificato usando ulimit :

Mostra l'impostazione predefinita in kB:

$ ulimit -s
8192

Imposta su illimitato:

ulimit -s unlimited

influenzando la shell e le subshell correnti e i loro processi figli.
(ulimit è un comando integrato della shell)

Puoi mostrare l'attuale intervallo di indirizzi dello stack in uso con:
cat /proc/$PID/maps | grep -F '[stack]'
su Linux.


Linux
  1. Cos'è NGINX? Come funziona?

  2. Come cancellare la cache di memoria in Linux

  3. Come funziona Awk '!a[$0]++'?

  4. Come funziona il bit appiccicoso?

  5. Linux:come funziona il carico medio con le moderne CPU?

Come disabilitare permanentemente lo scambio in Linux

Linux:come funziona il display di Linux?

Che cos'è il comando sorgente in Linux e come funziona?

Come funziona la memoria di scambio in Linux?

Come funziona una GUI Linux al livello più basso?

Come funziona il display di Linux?