Dies gilt nicht für „fast alle Betriebssysteme“. Die Arten der dargestellten Speicherbereiche sind ziemlich typisch, aber es gibt keinen Grund, warum sie in einer bestimmten Reihenfolge sein sollten, und es kann mehr als ein Stück einer bestimmten Art geben.
Unter Linux können Sie sehen Adressraum ist ein Prozesses , mit cat /proc/$pid/maps
dem $pid
der Prozess - ID, zum Beispiel cat /proc/$$/maps
an der Schale schauen Sie laufen cat
von oder cat /proc/self/maps
zu Blick auf den cat
eigenen Mappings des Prozesses. Der Befehl pmap
erzeugt eine etwas schönere Ausgabe.
08048000-08054000 r-xp 00000000 08:01 828061 /bin/cat
08054000-08055000 r--p 0000b000 08:01 828061 /bin/cat
08055000-08056000 rw-p 0000c000 08:01 828061 /bin/cat
08c7f000-08ca0000 rw-p 00000000 00:00 0 [heap]
b755a000-b7599000 r--p 00000000 08:01 273200 /usr/lib/locale/en_US.utf8/LC_CTYPE
b7599000-b759a000 rw-p 00000000 00:00 0
b759a000-b76ed000 r-xp 00000000 08:01 269273 /lib/tls/i686/cmov/libc-2.11.1.so
b76ed000-b76ee000 ---p 00153000 08:01 269273 /lib/tls/i686/cmov/libc-2.11.1.so
b76ee000-b76f0000 r--p 00153000 08:01 269273 /lib/tls/i686/cmov/libc-2.11.1.so
b76f0000-b76f1000 rw-p 00155000 08:01 269273 /lib/tls/i686/cmov/libc-2.11.1.so
b76f1000-b76f4000 rw-p 00000000 00:00 0
b770b000-b7712000 r--s 00000000 08:01 271618 /usr/lib/gconv/gconv-modules.cache
b7712000-b7714000 rw-p 00000000 00:00 0
b7714000-b7715000 r-xp 00000000 00:00 0 [vdso]
b7715000-b7730000 r-xp 00000000 08:01 263049 /lib/ld-2.11.1.so
b7730000-b7731000 r--p 0001a000 08:01 263049 /lib/ld-2.11.1.so
b7731000-b7732000 rw-p 0001b000 08:01 263049 /lib/ld-2.11.1.so
bfbec000-bfc01000 rw-p 00000000 00:00 0 [stack]
Sie können den Code und die Lese- / Schreibdaten (Text und BSS) aus der ausführbaren Datei, dann dem Heap, dann einer Speicherzuordnungsdatei, dann etwas mehr Lese- / Schreibdaten, dann Code, Nur-Lese-Daten und Lese- sehen. Schreiben Sie Daten aus einer gemeinsam genutzten Bibliothek (wieder Text und BSS), mehr Lese- / Schreibdaten, eine andere gemeinsam genutzte Bibliothek (genauer gesagt den dynamischen Linker) und schließlich den Stapel des einzigen Threads.
Der Kernel-Code verwendet eigene Adressbereiche. Auf vielen Plattformen verwendet Linux den oberen Teil des Adressraums für den Kernel, häufig die oberen 1 GB. Im Idealfall würde dieser Speicherplatz ausreichen, um Kernelcode, Kerneldaten und den Systemspeicher (RAM) sowie jedes speicherabgebildete Gerät abzubilden. Auf typischen 32-Bit-PCs von heute ist dies nicht möglich, was Verzerrungen erfordert, die nur für Kernel-Hacker von Interesse sind.
Während der Kernelcode einen Systemaufruf verarbeitet, wird der Speicher des Prozesses idealerweise (wenn die oben genannten Verzerrungen nicht vorhanden sind) an denselben Adressen zugeordnet. Dadurch können Prozesse Daten an den Kernel übergeben und der Kernel kann direkt vom Zeiger lesen. Dies ist jedoch kein großer Gewinn, da die Zeiger ohnehin validiert werden müssen (damit der Prozess den Kernel nicht dazu verleiten kann, aus dem Speicher zu lesen, auf den der Prozess keinen Zugriff haben soll).
Die Speicherzonen im Linux-Kernel sind ziemlich komplex. Es gibt verschiedene Speicherpools, und bei den Hauptunterschieden geht es nicht darum, woher der Speicher stammt, sondern darum, mit wem er geteilt wird. Wenn Sie neugierig sind, beginnen Sie mit LDD3 .
where.c
unter Ubuntu 11.04gcc where.c -o where
; meldet "main at 0x80483c4". Versuchtreadelf -S where
, und es berichtet, sagen "[13] .text PROGBITS 08048310 ...", was ungefähr richtig aussieht? Obwohl ich auch "ac at 0xbfb035a0" und "local at 0xbfb0358c" bekomme, scheint dieser Adressbereich (0xbf ...) nicht von gemeldet zu werdenreadelf -S
.ac
und dieav
automatische Variablelocal
haben wahrscheinlich bei jedem Aufruf unterschiedliche Adressen. Die meisten modernen Linux-Kernel verfügen über "Address Space Layout Randomization", um das Ausnutzen von Pufferüberläufen zu erschweren.