Почему общая программа обычно начинается с 0x8000? - PullRequest
43 голосов
/ 13 марта 2012

Я не новичок в загрузчике и системном ПО, но я не знаю причины, по которой общая программа запускается в 0x8000.Я уже знаю, что адрес 0x8000 использовался в качестве начального адреса в обычной программе C / C ++.

Минимальный размер загрузчика для обычной программы составляет до 0x8000?Или минимальный размер блока ПЗУ, который должен быть выделен для загрузчика 32 КБ?Или есть другая причина?

Я хотел бы знать об этом, исторически или логически, и с точки зрения виртуального адреса.


Я ценю все, ваше время ипомогите с этим.Чтобы прояснить вопрос, вопрос связан с виртуальным адресом, а не с физическим.

Я в основном согласен с мнением Р. с точки зрения адреса физической памяти.

Не говоря уже о конкретной системе, котораяРазнообразные, например, Linux (даже в Android), общая ОСРВ (ядро и другие, особенно раздел компоновщика ARM), все они используют адрес 0x8000 в качестве начальной программы общей программы.такие области, как crt_begin.o, crt.o и т. д., расположенные в 0x0 с загрузчиком, существуют в этой области.

Поэтому я предполагаю, что минимальный размер загрузчика для обычной программы составляет 32 КБ, учитывая размер блока, если он будет расположенв BootROM во время загрузки (холодная загрузка).

Ммм, но я не уверен ...

Ответы [ 5 ]

19 голосов
/ 13 марта 2012

Как правило, на всех встроенных системах, кроме самых маленьких, разработчик ABI платформы стремится избегать использования наименьших адресов, чтобы можно было отловить разыменование нулевого указателя.Наличие нескольких КБ недействительных адресов дает дополнительную безопасность, если нулевой указатель разыменовывается со смещением элемента массива или структуры, как в null_ptr->some_member.

6 голосов
/ 13 марта 2012

Это зависит от системы, и программы запускаются по разным адресам на разные системы. Под Unix это обычно (или, возможно, даже требуется Posix) использовать адрес 0 в качестве нулевого указателя и не отображать первая страница виртуальной памяти, так что разыменование нулевого указателя будет привести к нарушению сегмента. Я подозреваю, что другие системы используют адрес 0 как нулевой указатель ведет себя аналогично (но сколько они резервируют может различаться). (Исторически сложилось так, что первая страница отображалась как прочитанная. только, и заполните его нулями, чтобы нулевой указатель вел себя так, как если бы это была пустая строка, указатель на "". Это возвращается около 25 годы, однако.)

Я ожидаю, что даже сегодня некоторые встроенные системы загружают программа запускается по адресу 0.

3 голосов
/ 30 мая 2012

Это несколько произвольно, и в Linux, по крайней мере, решено компоновщиком.Общая идея состоит в том, чтобы зарезервировать некоторое пространство для перехвата исключений указателя NULL.Чтобы предотвратить использование произвольного пользовательского кода в режиме ядра разыменованием указателя NULL в пространстве ядра, linux не позволяет отображать самый нижний предел памяти./proc/sys/vm/mmap_min_addr контролирует наименьший адрес, который вы можете отобразить (вы можете изменить его на 0 и, если хотите, отобразить страницу на 0).

В linux вы можете посмотреть на отображение памяти, просмотрев /proc.Например,

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]
2 голосов
/ 30 мая 2012

Я думаю, что ответ больше связан с обработкой прерываний.Адреса обработчика прерываний устанавливаются аппаратно.В Intel 8086 существовала таблица прямого перевода кода обработчика прерываний и соответствующей процедуры обработки прерываний.Возможно, это было сделано какой-то комбинаторной схемой, и, следовательно, для сохранения прямой совместимости было бы более разумно размещать их в начале памяти, а не в конце, чтобы предотвратить изменения каждый раз.Таким образом, начальный адрес выполнения будет на другом конце памяти.Кроме того, было необходимо, чтобы в этом блоке содержалось достаточно кода для загрузки программы сегмента памяти и инструкции перехода для переключения для выполнения кода с этого адреса кода.

2 голосов
/ 30 мая 2012

Я подозреваю, что во многих случаях первые 32 КБ были зарезервированы для использования кода / оперативной памяти мониторов.На многих 8051 eval платах было не так уж редко по умолчанию 0x1000 или 0x2000 для всех приложений в зависимости от резидентного монитора (некоторые из которых также работали как отладчики).

32K может быть вашим u-boot /и т.д. пространство погрузчиков.

...