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

时间:2012-03-13 06:32:40

标签: c++ c linker bootloader

我不是bootloader和系统SW的新手,但我不知道一般程序在0x8000开始的原因。我已经知道地址0x8000已被用作普通C / C ++程序中的起始地址。

一般程序的引导加载程序的最小大小是否占用0x8000?或者是应该分配给32KB引导加载程序的ROM的最小块大小?或者还有其他原因吗?

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


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

我基本同意R的意见,从物理内存地址的角度来看。

不说一个多样化的特定系统,例如linux(甚至在android),一般RTOS(核心,以及其他,特别是ARM链接器部分),它们都使用地址0x8000作为起始地址通用程序。 如此命名为crt_begin.o,crt.o等位于0x0的加载器存在于该区域。

因此,如果一般程序的引导加载程序的最小大小为32KB,则考虑到块大小,如果它在引导时位于BootROM中(冷启动)。

嗯,但我不确定......

4 个答案:

答案 0 :(得分:6)

这取决于系统,程序从不同的地址开始 不同的系统。在Unix下,它通常(或者甚至可能需要 Posix)使用地址0作为空指针,并且不映射 虚拟内存的第一页,以便取消引用空指针 导致段违规。我怀疑其他系统使用 地址0作为空指针的行为类似(但它们保留多少 可能会有所不同)。 (从历史上看,通常将第一页映射为已读 只有,并用零填充它,这样做一个空指针将表现得好像 它是一个空字符串,指向""的指针。那可以追溯到25岁左右 然而,年。)

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

答案 1 :(得分:3)

这有点武断,在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 :(得分:2)

我怀疑在很多情况下,第一个32K是为监视器代码/ ram使用保留的。在许多8051评估板中,对于所有应用程序默认为0x1000或0x2000并不常见,具体取决于驻留监视器(其中一些也用作调试器)。

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

答案 3 :(得分:2)

我相信答案与中断处理更相关。中断处理程序地址在硬件中设置。在Intel 8086中,有一个关于中断处理程序代码和相应中断处理例程的直接转换表。可能这是由一些组合电路完成的,因此,为了保持向前兼容性,将它们放在存储器的起始位置而不是最后位置以防止每次更改都更为明智。因此,执行起始地址将位于内存的另一端。此外,必须在该块中包含足够的代码以加载存储器段程序和跳转指令以切换以执行来自该代码地址的代码。