2016-05-09 3 views
1

Das ist also nur für meine eigene Neugier, ich wollte jede Speicheradresse von 0x000000 bis zur letzten Adresse meiner Festplatte gehen. Also schrieb ich diese C-Schnipsel:Was ist in der ersten Speicheradresse des Betriebssystems gespeichert? Warum kann ich den Inhalt nicht drucken?

#include <stdio.h> 

int main() { 
     void* ptr = 0x00000; 
     int x = 0; 
     while (x == 0) { 
       puts("hi"); 
       printf("%p\t%c\n",ptr,*(int*)ptr); 
       ptr++; 
     } 
} 

„hallo“ druckt nur einmal, bevor ich segfault. Was ist bei 0x000000 gespeichert und warum kann ich nicht darauf zugreifen?

+0

Welches Betriebssystem ist das? –

+0

Speicheradressen [sind nicht sequentiell] (https://en.wikipedia.org/wiki/Address_space_layout_randomization) auf den meisten modernen Betriebssystemen. – jordanm

+0

(1) Warum ist diese [Festplatte] markiert? (2) Warum holen Sie eine Ganzzahl ('* (int *) ptr') und versuchen, sie mit'% c' zu drucken? – Scott

Antwort

4

Da ist nichts da. Ein Nullzeiger zeigt auf nichts, weshalb er abstürzt. Sie tun *NULL. In der Tat wird NULL auf so ziemlich jeder derzeit verwendeten Plattform als 0 definiert (obwohl beachten Sie, dass dies nicht wirklich von den Standards garantiert wird und es möglicherweise eine obskure Plattform gibt, wo es anders ist).

Sie konnten sowieso nicht auf zufälligen Speicher zugreifen. Wohin würde es zeigen? Ihre Adresse ist entweder vollständig ungültig, in diesem Fall erhalten Sie einen segfault, oder sie zeigt in den Speicher eines anderen Programms, auf den Sie nicht zugreifen dürfen, und Sie erhalten immer noch einen segfault.

Auf modernen Systemen zeigen Sie nicht einmal direkt auf Speicher. Die Adressen sind virtuell. Wenn die Adresse Ihnen gehört und sinnvoll ist, übersetzt das Betriebssystem sie unter Verwendung der page table in die reale Adresse unter der Haube. Wenn die Adresse nicht deins ist, erhalten Sie einen segfault.

Wenn Sie ein wirklich altes System (denken Sie an ein 8-Bit-Mikro) oder einen einfachen Mikrocontroller haben, wo es keinen virtuellen Speicher oder Multitasking oder etwas ähnliches gibt, dann könnten Sie das tatsächlich tun. Aber auf einem modernen System können Sie nicht.

+0

Ich bin ziemlich sicher, dass Sie können Geben Sie Ring 0 ein und lesen Sie dann das erste Byte des RAM. – dbanet

+0

Ich stimme dem zweiten und vierten Absatz nicht zu (und stimme teilweise mit dem Kommentar von dbanet überein) - selbst im Benutzermodus können Sie auf Adresse0 zugreifen, wenn die Speicherzuordnung so eingerichtet ist, dass virtuelle Adresse0 einer vorhandenen physikalischen Adresse zugeordnet wird. – Scott

+0

Ihr erster Absatz sollte etwas darüber sagen, wie dies nur für * Standard C * gilt. Es gibt viele Plattformen, bei denen '* (int *) NULL' auf Speicher zugreifen kann. – immibis

1

Zunächst betrachten Sie nicht das OS; Sie betrachten den zugewiesenen Speicher Ihres eigenen Prozesses. Das meiste, was Sie mit diesem Ansatz sehen könnten, ist Ihr Prozess Bild (wahrscheinlich einschließlich aller Bibliotheken, die Sie verknüpft haben).

Zweitens, wenn Sie etwas ganz besonderes tun, verwenden Sie virtual memory, wie marinus says. Die virtuelle Adresse 0x001000 in Ihrem Prozess könnte auf die physische Adresse 0x; Die virtuelle Adresse 0x002000 könnte der physischen Adresse 0x42017000 entsprechen. Einige virtuelle Adressen möglicherweise nicht überall zuordnen - betrachten, auf einer 32-Bit-Maschine können Sie 2 Adressen haben. Das sind 4 GiB - nicht viele Computer haben sogar so viel physischen Speicher. (Und lassen Sie uns nicht einmal über 64-Bit-Maschinen denken!) Selbst wenn das System 4 GiB physischen Speicher hätte, würde es nicht alle in Ihrem virtuellen Adressraum zugeordnet werden, weil es andere Prozessspeicher (und ja, Kernel-Speicher).

Wie marinus erwähnt, ist ein Zeiger mit einem Wert von 0 ein Nullzeiger. Die C Programming Language Specification, Abschnitt 6.3.2.3 „Pointers“ Absatz 3, sagt:

eine ganzzahlige Konstante Ausdruck mit dem Wert 0, oder einem solchen Ausdruck void * Typ umgewandelt wird ein Null-Zeiger aufgerufen konstant. Wenn eine Null-Zeiger-Konstante in einen Zeigertyp konvertiert wird, der resultierende Zeiger, genannt Nullzeiger, wird garantiert ungleich zu einem Zeiger auf ein Objekt oder eine Funktion zu vergleichen.

Der zweite Satz bedeutet, dass es nichts an der Null-Zeiger-Adresse (die Adresse 0) sein kann, , denn wenn es etwas gibt, dann einen Zeiger auf dieses Objekt zu einem Null-Zeigern gleich sein würde, . C-Laufzeitumgebungen einrichten Daher eine virtuelle → physikalische Speicherkarte etwas wie folgt aus:

Virtual Memory Map

(Gebäude auf der einen in the Wikipedia page), wobei 0 virtuelle Adresse immer nicht so konfiguriert ist, auf alles abgebildet.


Die Sprache C hat dieses Verhalten nicht immer angegeben. Noch vor 25-30 Jahren, konnte ein Programm den virtuellen Speicherort 0 - vor allem auf 16-Bit-Systemen, und Maschinen zugreifen, deren Speicherverwaltungsarchitektur nicht ausgefeilt war, damit das System die Speicherseite 0 unzugänglich machen konnte , ohne einen großen Teil des virtuellen Adressraums zu opfern.

Verwandte Themen