为什么通用程序通常从0x8000开始?

我对bootloader和系统软件并不陌生,但是我不知道通用程序从0x8000开始的原因。 我已经知道在正常的C / C ++程序中地址0x8000已被用作起始地址。

一般程序的最小引导程序大小是否为0x8000 ? 还是应该分配给引导加载程序32KB的ROM的最小块大小? 还是有另一个原因?

我想从历史上或逻辑上以及从虚拟地址的angular度来了解这一点。


我感谢所有,你的时间和帮助。 为了使问题更清楚,问题与虚拟地址不是物理的相关。

我基本上同意R从物理内存地址的angular度来看待。

没有说具体的系统是多样的,例如linux(即使在android中),一般的RTOS(核心,其他的,特别是ARM链接器部分),它们都使用地址0x8000作为起始地址通用程序。 在这个区域中存在一个名为crt_begin.o,crt.o等位于0x0的加载器。

因此,如果在启动时(boot boot)时,启动加载程序位于BootROM中,则一般程序的启动加载程序的最小容量是32KB。

嗯,但我不确定…

一般来说,除了最小的embedded式系统之外,平台ABIdevise者都希望避免使用最低地址,以便可以捕获空指针解引用。 如果空指针与数组或结构成员偏移量一起取消引用(如null_ptr->some_member ,那么具有几KB的无效地址会给您一些额外的安全性。

这取决于系统,程序从不同系统的不同地址开始。 在Unix下,通常(甚至可能是Posix要求)使用地址0作为空指针,并且不映射虚拟内存的第一页,所以取消引用空指针会导致段违例。 我怀疑使用地址0作为空指针的其他系统的行为类似(但他们保留多less可能会有所不同)。 (从历史上看,通常把第一页映射为只读,并用零填充,做一个空指针的行为就好像是一个空string,指向"" ,这是大约25年,但是, 。)

我希望即使在今天,一些embedded式系统也会从地址0开始加载程序。

这有点武断,而在Linux上,至less由链接器决定。 总的想法是保留一些空间来捕获空指针exception。 为了防止内核空间在内核模式下执行任意用户代码的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 [堆]
 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] 

我怀疑在很多情况下,第一个32K是为监视器代码/ RAM使用而保留的。 在许多8051评估板中,根据驻留显示器(也可以用作debugging器),对于所有应用程序默认为0x1000或0x2000并不罕见。

32K可能是你的u-boot / etc加载器空间。

我相信答案更多地涉及到中断处理。 中断处理程序地址在硬件中设置。 在Intel 8086中,中断处理程序代码和相应的中断处理例程有一个直接转换表。 也许这是通过一些组合电路来完成的,因此,为了保持向前兼容性,将它们放置在内存的开始处而不是结束处以防止每次更改会更加明智。 所以,执行起始地址将在内存的另一端。 另外,需要在该块中包含足够的代码来加载内存段程序和跳转指令,以便从该代码地址执行代码。