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

Wie kann man den Stack für den Systemaufruf clone() unter Linux zuordnen?

Sie möchten das MAP_ANONYMOUS-Flag für mmap. Und das MAP_GROWSDOWN, da Sie es als Stack verwenden möchten.

Etwas wie:

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

Weitere Informationen finden Sie auf der man-Seite von mmap. Und denken Sie daran, Klonen ist ein Low-Level-Konzept, das Sie nicht verwenden sollten, es sei denn, Sie brauchen wirklich, was es bietet. Und es bietet viel Kontrolle - wie das Setzen eines eigenen Stacks - nur für den Fall, dass Sie etwas Tricksen wollen (wie den Zugriff auf den Stack in allen verwandten Prozessen). Wenn Sie keinen guten Grund haben, Klonen zu verwenden, bleiben Sie bei Fork oder Pthreads.


Stacks sind in ihrem Wachstumsraum nicht unbegrenzt und können es niemals sein. Wie alles andere leben sie im virtuellen Adressraum des Prozesses, und die Menge, um die sie wachsen können, ist immer durch die Entfernung zum benachbarten abgebildeten Speicherbereich begrenzt.

Wenn Leute davon sprechen, dass der Stack dynamisch wächst, meinen sie möglicherweise eines von zwei Dingen:

  • Seiten des Stacks können Copy-on-Write-Nullseiten sein, von denen keine privaten Kopien erstellt werden, bis der erste Schreibvorgang durchgeführt wird.
  • Untere Teile des Stack-Bereichs sind möglicherweise noch nicht reserviert (und zählen daher nicht zur Commit-Gebühr des Prozesses, d. h. die Menge an physischem Speicher/Auslagerung, die der Kernel als für den Prozess reserviert berücksichtigt hat), bis eine Schutzseite erreicht wird , in diesem Fall schreibt der Kernel mehr und verschiebt die Schutzseite oder beendet den Prozess, wenn kein Speicher mehr zum Übergeben vorhanden ist.

Der Versuch, sich auf MAP_GROWSDOWN zu verlassen flag ist unzuverlässig und gefährlich weil es Sie nicht vor mmap schützen kann Erstellen Sie eine neue Zuordnung direkt neben Ihrem Stack, die dann geschlagen wird. (Siehe http://lwn.net/Articles/294001/) Für den Haupt-Thread reserviert der Kernel automatisch die Stapelgröße ulimit im Wert von Adressraum (nicht Speicher ) unterhalb des Stapels und verhindert mmap davon ab, es zuzuordnen. (Aber Vorsicht! Einige defekte, vom Hersteller gepatchte Kernel deaktivieren dieses Verhalten, was zu zufälliger Speicherbeschädigung führt!) Für andere Threads müssen Sie einfach müssen mmap den gesamten Bereich des Adressraums, den der Thread möglicherweise für den Stapel benötigt, wenn er ihn erstellt. Es geht nicht anders. Sie könnten Machen Sie das meiste davon anfänglich nicht beschreibbar/nicht lesbar und ändern Sie dies bei Fehlern, aber dann würden Sie Signalhandler benötigen, und diese Lösung ist in einer POSIX-Thread-Implementierung nicht akzeptabel, da sie die Signalhandler der Anwendung stören würde. (Beachten Sie, dass der Kernel als Erweiterung könnte Sonderangebot MAP_ Flags, um ein anderes Signal statt SIGSEGV zu liefern bei illegalem Zugriff auf die Zuordnung, und dann könnte die Thread-Implementierung dieses Signal abfangen und darauf reagieren. Aber Linux hat derzeit keine solche Funktion.)

Schließlich beachten Sie, dass clone syscall akzeptiert kein Stackpointer-Argument, da es dieses nicht benötigt. Der Systemaufruf muss vom Assemblercode ausgeführt werden, da der Userspace-Wrapper den Stack-Zeiger im "untergeordneten" Thread so ändern muss, dass er auf den gewünschten Stack zeigt, und vermeiden muss, etwas in den Stack des übergeordneten Threads zu schreiben.

Eigentlich clone nimmt ein Stapelzeiger-Argument, weil es unsicher ist, zu warten, bis der Stapelzeiger im "Kind" geändert wird, nachdem er zum Benutzerbereich zurückgekehrt ist. Wenn nicht alle Signale blockiert sind, könnte ein Signal-Handler sofort auf dem falschen Stack laufen, und auf einigen Architekturen muss der Stack-Zeiger gültig sein und jederzeit auf einen Bereich zeigen, in dem sicher geschrieben werden kann.

Es ist nicht nur unmöglich, den Stapelzeiger von C aus zu ändern, sondern Sie konnten auch die Möglichkeit nicht vermeiden, dass der Compiler den Stapel des Elternteils nach dem Syscall, aber bevor der Stapelzeiger geändert wurde, überschreiben würde.


Linux
  1. So verwenden Sie systemd-nspawn für die Linux-Systemwiederherstellung

  2. So ändern Sie die Identität eines Linux-Systems

  3. Linux:So finden Sie den für ein Gerät verwendeten Gerätetreiber

  4. Wie finde ich die Anwendung für einen Mime-Typ unter Linux?

  5. Linux-Systemaufruftabelle oder Cheatsheet für Assembly

So verwenden Sie den fd-Befehl auf einem Linux-System

So installieren Sie einen der besten Systemmonitore für den Linux-Desktop

Die 10 besten Comic-Viewer für Linux-Systeme

Die 10 besten Radio-Streaming-Software für Linux-Systeme

Die 15 besten Linux-Emulatoren für Windows-Systeme

Die 20 besten Bioinformatik-Tools für Linux-Systeme