Warum startet das allgemeine Programm normalerweise bei 0x8000?

Lesezeit: 7 Minuten

Benutzeravatar von OfusJK
OfusJK

Bootloader und System-SW sind mir nicht neu, aber ich kenne den Ursprung des Grundes, warum das allgemeine Programm startet, nicht 0x8000. Die Adresse kenne ich bereits 0x8000 wurde als Startadresse in einem normalen C/C++-Programm verwendet.

Nimmt die Mindestgröße des Bootloaders für ein allgemeines Programm zu 0x8000? Oder beträgt die Mindestblockgröße des ROM, die dem Bootloader zugewiesen werden sollte, 32 KB? Oder gibt es einen anderen Grund?

Ich würde gerne etwas darüber wissen, historisch oder logisch und aus Sicht der virtuellen Adresse.


Ich schätze alle, Ihre Zeit und Hilfe dabei. Um die Frage klarer zu machen, bezieht sich die Frage auf die virtuelle Adresse, nicht auf die physische.

Ich stimme grundsätzlich der Meinung von R aus Sicht der physischen Speicheradresse zu.

Ohne ein spezifisches System zu nennen, das unterschiedlich ist, zum Beispiel Linux (sogar in Android), allgemeines RTOS (Nucleus und die anderen, insbesondere ARM-Linker-Abschnitt), verwenden sie alle die Adresse 0x8000 als Startadresse des allgemeinen Programms. solche namens crt_begin.o, crt.o usw., die sich bei 0x0 mit Loader befinden, existieren in diesem Bereich.

Daher schätze ich, dass die Mindestgröße des Bootloaders für das allgemeine Programm 32 KB beträgt, wenn man die Blockgröße berücksichtigt, wenn sie sich beim Booten (Kaltstart) im BootROM befinden würde.

Ähm, aber ich bin mir nicht sicher…

  • Von welchem ​​System redest du hier?

    – Jerry Sarg

    13. März 2012 um 6:35 Uhr

  • Ich habe keine zuverlässige Quelle dafür, aber ich kann eine qualifizierte Vermutung anstellen. In der Vergangenheit hatten viele Prozessoren, insbesondere 8-Bit-Prozessoren, das genannte Feature null Seite was bedeutet, dass Speicherzellen an den Adressen 0x00–0xFF Befehlsunterstützung hatten, um schneller ausgeführt zu werden. Ich glaube, dies wurde damals von Motorola eingeführt, da sie speicherabgebildete E / A-Register auf den alten MCUs wie 6800 hatten. ->

    – Ludin

    13. März 2012 um 8:03 Uhr

  • Daher möchten Sie, dass dieser erste Speicherbereich von RAM-Zellen oder speziellen Registern belegt wird. Dann ist es sinnvoll, dass der Teil des Adressraums, der nach der Nullseite kommt, von der gleichen Art ist: RAM und/oder Register. Dies würde viel kb beanspruchen, vielleicht bis zu 0x6000 oder so. Ich gehe dann davon aus, dass es praktisch war, das ROM (Programmspeicher) an einer geraden Adresse zu platzieren, und 0x8000 war praktisch. Ich bin mir ziemlich sicher, dass die Antwort auf diese Frage in frühen Motorola-Prozessordesigns zu finden ist.

    – Ludin

    13. März 2012 um 8:04 Uhr

  • Das könnte relevant sein: en.wikipedia.org/wiki/ELF_binary. Vielleicht soll die Größe mit früheren Formaten kompatibel sein?

    – Lethargie

    30. Mai 2012 um 22:06 Uhr


Im Allgemeinen möchte der Plattform-ABI-Designer auf allen außer den kleinsten eingebetteten Systemen vermeiden, dass jemals die niedrigsten Adressen verwendet werden, damit Nullzeiger-Dereferenzen abgefangen werden können. Mehrere KB nie gültiger Adressen zu haben, gibt Ihnen zusätzliche Sicherheit, wenn der Nullzeiger mit einem Array- oder Strukturelement-Offset dereferenziert wird, wie in null_ptr->some_member.

  • Ich glaube nicht, dass dies der Grund ist, ich habe mit mehreren eingebetteten Systemen gearbeitet, bei denen die Adresse 0 ein gültiger und adressierbarer Speicher ist, während gleichzeitig der NVM bei 8000 beginnt.

    – Ludin

    13. März 2012 um 7:36 Uhr

  • …insbesondere, da die Adresse 0x8000 existierte, bevor die C-Sprache und NULL-Zeiger populär wurden. Vielleicht sogar bevor C erfunden wurde?

    – Ludin

    13. März 2012 um 8:05 Uhr

  • @MSalters malloc() gibt einen Nullzeiger zurück, wenn dies fehlschlägt. Es ist nicht erforderlich, dass ein Nullzeiger die Adresse 0 hat (nur dass eine ganzzahlige Konstante, die zu 0 ausgewertet wird, implizit in sie konvertiert wird, was auch immer es ist). Und wo das System Dinge wie Interrupt-Handler platziert, hängt von der Hardware ab – Intel hat sie immer ganz am Anfang platziert, aber andere Systeme waren unterschiedlich.

    – James Kanze

    13. März 2012 um 8:35 Uhr

  • @JamesKanze: Natürlich, aber die “eingebetteten Systeme”, bei denen “HW damit in Ordnung ist”, sind einfache Systeme ohne VM (wenn Sie eine VM haben, ordnen Sie sie einfach nicht zu (void*)NULL im Prozessraum). Auf diesen Systemen sind Sie so nah an dem Metall, das Sie wirklich wollen NULL bitweise 0 sein. Und ja, Interrupt-Handler sind ein Beispiel; andere CPUs hatten speicherabgebildete E/A-Register an Adresse 0.

    – MSalter

    13. März 2012 um 8:45 Uhr

  • @MSalters Bei VM besteht die einfachste Lösung darin, die Adresse 0 nicht zuzuordnen und 0 als Nullzeigerkonstante zu verwenden. Ohne VM haben Systeme alle möglichen Dinge verwendet, und es gab definitiv Systeme, bei denen der Nullzeiger nicht die Adresse 0 war.

    – James Kanze

    13. März 2012 um 10:44 Uhr

Es hängt vom System ab, und Programme starten auf verschiedenen Systemen an unterschiedlichen Adressen. Unter Unix ist es üblich (oder vielleicht sogar von Posix vorgeschrieben), die Adresse 0 als Nullzeiger zu verwenden und die erste Seite des virtuellen Speichers nicht zu mappen, so dass die Dereferenzierung eines Nullzeigers zu einer Segmentverletzung führt. Ich vermute, dass sich andere Systeme, die die Adresse 0 als Nullzeiger verwenden, ähnlich verhalten (aber wie viel sie reservieren, kann variieren). (In der Vergangenheit war es üblich, die erste Seite als schreibgeschützt abzubilden und mit Nullen zu füllen, damit sich ein Nullzeiger so verhält, als wäre er eine leere Zeichenfolge, ein Zeiger auf "". Das geht jedoch ungefähr 25 Jahre zurück.)

Ich würde erwarten, dass einige eingebettete Systeme das Programm auch heute noch ab der Adresse 0 laden.

Es ist etwas willkürlich und unter Linux zumindest vom Linker entschieden. Die allgemeine Idee ist, etwas Platz zu reservieren, um NULL-Zeiger-Ausnahmen abzufangen. Um zu verhindern, dass Kernel-Space-NULL-Zeiger-Dereferenzierungen beliebigen Benutzercode im Kernel-Modus ausführen, hindert Linux Sie daran, den untersten Teil des Speichers abzubilden. /proc/sys/vm/mmap_min_addr steuert die niedrigste Adresse, die Sie zuordnen können (Sie können sie auf 0 ändern und eine Seite bei 0 zuordnen, wenn Sie möchten).

Unter Linux können Sie sich die Speicherzuordnung ansehen, indem Sie hineinschauen /proc. Zum Beispiel,

genwitt ~> cat /proc/self/maps 
00400000-0040c000 r-xp 00000000 08:01 354804                             /bin/cat
0060b000-0060c000 r--p 0000b000 08:01 354804                             /bin/cat
0060c000-0060d000 rw-p 0000c000 08:01 354804                             /bin/cat
01dda000-01dfb000 rw-p 00000000 00:00 0                                  [heap]
7f5b25913000-7f5b25a97000 r-xp 00000000 08:01 435953                     /lib64/libc-2.14.1.so
7f5b25a97000-7f5b25c97000 ---p 00184000 08:01 435953                     /lib64/libc-2.14.1.so
7f5b25c97000-7f5b25c9b000 r--p 00184000 08:01 435953                     /lib64/libc-2.14.1.so
7f5b25c9b000-7f5b25c9c000 rw-p 00188000 08:01 435953                     /lib64/libc-2.14.1.so
7f5b25c9c000-7f5b25ca1000 rw-p 00000000 00:00 0 
7f5b25ca1000-7f5b25cc2000 r-xp 00000000 08:01 436061                     /lib64/ld-2.14.1.so
7f5b25cd2000-7f5b25e97000 r--p 00000000 08:01 126248                     /usr/lib64/locale/locale-archive
7f5b25e97000-7f5b25e9a000 rw-p 00000000 00:00 0 
7f5b25ec0000-7f5b25ec1000 rw-p 00000000 00:00 0 
7f5b25ec1000-7f5b25ec2000 r--p 00020000 08:01 436061                     /lib64/ld-2.14.1.so
7f5b25ec2000-7f5b25ec3000 rw-p 00021000 08:01 436061                     /lib64/ld-2.14.1.so
7f5b25ec3000-7f5b25ec4000 rw-p 00000000 00:00 0 
7fff18c37000-7fff18c58000 rw-p 00000000 00:00 0                          [stack]
7fff18d0c000-7fff18d0d000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

Ich würde vermuten, dass in vielen Fällen die ersten 32 KB für die Code-/RAM-Nutzung des Monitors reserviert waren. In vielen 8051-Evaluierungsboards war es nicht ungewöhnlich, je nach residentem Monitor für alle Apps standardmäßig 0x1000 oder 0x2000 zu verwenden (einige, die auch als Debugger funktionierten).

32 KB könnten Ihr Speicherplatz für U-Boot-/etc-Loader sein.

Ich glaube, die Antwort hängt eher mit der Interrupt-Behandlung zusammen. Die Interrupt-Handler-Adressen werden in Hardware gesetzt. In Intel 8086 gab es eine direkte Übersetzungstabelle für den Interrupt-Handler-Code und die entsprechende Interrupt-Handling-Routine. Wahrscheinlich wurde dies durch eine kombinatorische Schaltung durchgeführt, und daher wäre es zur Wahrung der Vorwärtskompatibilität sinnvoller gewesen, sie am Anfang des Speichers anstatt am Ende zu platzieren, um die Änderungen jedes Mal zu verhindern. Die Ausführungsstartadresse wäre also am anderen Ende des Speichers. Außerdem war es notwendig, dass in diesem Block genug Code enthalten war, um ein Speichersegmentprogramm und einen Sprungbefehl zu laden, um umzuschalten, um den Code von dieser Codeadresse auszuführen.

1401730cookie-checkWarum startet das allgemeine Programm normalerweise bei 0x8000?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy