GNU/Linux >> Linux Esercitazione >  >> Linux

Come eseguire il mmap dello stack per la chiamata di sistema clone() su Linux?

Vorresti il ​​flag MAP_ANONYMOUS per mmap. E il MAP_GROWSDOWN dato che vuoi usarlo come pila.

Qualcosa come:

void *stack = mmap(NULL,initial_stacksize,PROT_WRITE|PROT_READ,MAP_PRIVATE|MAP_GROWSDOWN|MAP_ANONYMOUS,-1,0);

Vedi la pagina man di mmap per maggiori informazioni. E ricorda, il clone è un concetto di basso livello, che non dovresti usare a meno che tu non abbia davvero bisogno di ciò che offre. E offre molto controllo, come l'impostazione del proprio stack, nel caso in cui si desideri fare qualche trucco (come avere lo stack accessibile in tutti i processi correlati). A meno che tu non abbia una buona ragione per usare clone, usa fork o pthreads.


Gli stack non sono, e non potranno mai essere, illimitati nel loro spazio di crescita. Come ogni altra cosa, vivono nello spazio degli indirizzi virtuali del processo e la quantità di cui possono crescere è sempre limitata dalla distanza dalla regione di memoria mappata adiacente.

Quando le persone parlano della crescita dinamica dello stack, ciò che potrebbero intendere è una di queste due cose:

  • Le pagine dello stack potrebbero essere zero pagine copy-on-write, che non ottengono copie private fino a quando non viene eseguita la prima scrittura.
  • Le parti inferiori della regione dello stack potrebbero non essere ancora riservate (e quindi non essere conteggiate per l'addebito di commit del processo, ovvero la quantità di memoria fisica/swap che il kernel ha considerato come riservata per il processo) fino a quando non viene raggiunta una pagina di guardia , nel qual caso il kernel si impegna di più e sposta la pagina di guardia, o termina il processo se non c'è più memoria per il commit.

Cercando di fare affidamento sullo MAP_GROWSDOWN flag è inaffidabile e pericoloso perché non può proteggerti da mmap creando una nuova mappatura appena adiacente al tuo stack, che verrà quindi bloccato. (Vedi http://lwn.net/Articles/294001/) Per il thread principale, il kernel riserva automaticamente la dimensione dello stack ulimit valore di spazio indirizzo (non memoria ) sotto lo stack e impedisce mmap dall'attribuirlo. (Ma attenzione! Alcuni kernel non funzionanti con patch del fornitore disabilitano questo comportamento portando a un danneggiamento casuale della memoria!) Per altri thread, semplicemente devi mmap l'intero intervallo di spazio degli indirizzi di cui il thread potrebbe aver bisogno per lo stack durante la sua creazione. Non c'è altro modo. Potresti rendere la maggior parte di esso inizialmente non scrivibile/non leggibile e modificarlo in caso di errori, ma in tal caso avresti bisogno di gestori di segnale e questa soluzione non è accettabile in un'implementazione di thread POSIX perché interferirebbe con i gestori di segnale dell'applicazione. (Notare che, come estensione, il kernel potrebbe offerta speciale MAP_ flag per fornire un segnale diverso invece di SIGSEGV sull'accesso illegale alla mappatura, e quindi l'implementazione dei thread potrebbe catturare e agire su questo segnale. Ma Linux al momento non ha questa caratteristica.)

Infine, nota che il clone syscall non accetta un argomento del puntatore dello stack perché non ne ha bisogno. La chiamata di sistema deve essere eseguita dal codice assembly, poiché il wrapper dello spazio utente è necessario per modificare il puntatore dello stack nel thread "figlio" in modo che punti allo stack desiderato ed eviti di scrivere qualsiasi cosa nello stack del genitore.

In realtà, clone prende un argomento del puntatore dello stack, perché non è sicuro aspettare di cambiare il puntatore dello stack nel "figlio" dopo essere tornato allo spazio utente. A meno che i segnali non siano tutti bloccati, un gestore di segnale potrebbe essere eseguito immediatamente sullo stack sbagliato e su alcune architetture il puntatore dello stack deve essere valido e puntare sempre a un'area sicura in cui scrivere.

Non solo è impossibile modificare il puntatore dello stack da C, ma non puoi nemmeno evitare la possibilità che il compilatore blocchi lo stack del genitore dopo la chiamata di sistema ma prima che il puntatore dello stack venga modificato.


Linux
  1. Come utilizzare systemd-nspawn per il ripristino del sistema Linux

  2. Come controllare la versione del sistema operativo e di Linux

  3. Come cambiare l'identità di un sistema Linux

  4. Linux:come disabilitare il segnale acustico di sistema per utenti non privilegiati?

  5. Tabella delle chiamate di sistema Linux o cheatsheet per Assembly

Come utilizzare il comando fd sul sistema Linux

Come installare uno dei migliori monitor di sistema per il desktop Linux

I 10 migliori visualizzatori di fumetti per sistemi Linux

I 10 migliori software di streaming radio per sistemi Linux

I 15 migliori emulatori Linux per sistemi Windows

I 20 migliori strumenti di bioinformatica per il sistema Linux