在点灯程序中,想看看超过地址空间的结果,于是做了个试验,修改Makefile中的连接地址为0xfffffffc,如下所示。
root@ubuntu:~/work/led_on_c# cat Makefile
all:
arm-linux-gcc -c -o led.o led.c
arm-linux-gcc -c -o start.o start.S
arm-linux-ld -Ttext 0xfffffffc start.o led.o -o led.elf
arm-linux-objcopy -O binary -S led.elf led.bin
arm-linux-objdump -D led.elf > led.dis
clean:
rm *.bin *.o *.elf *.dis
编译烧写到NAND中,复位后指示灯仍然能点亮。我认为超过地址空间了cpu就找不到程序执行的地址了,那它就不能正常工作啊,但是实验结果是它还能正常工作,感觉很奇怪,于是打开反汇编代码,如下所示:
fffffffc <_start>:
fffc: e3a0da01 mov sp, #4096 ; 0x1000
0: Address 0x0 is out of bounds.
Disassembly of section .comment:
00000000 <.comment>:
0: 43434700 cmpmi r3, #0 ; 0x0
4: 4728203a undefined
8: 2029554e eorcs r5, r9, lr, asr #10
c: 2e342e33 mrccs 14, 1, r2, cr4, cr3, {1}
10: Address 0x10 is out of bounds.
如上所示,反汇编有效代码只有2行,这是符合我的预期的。但是为什么还是能正常执行呢?通过查找资料,有一种说法我认为很有道理,记录下来。如下:
位置无关指令(比如这里用的 bl xxxx 就是位置无关指令)是将PC加上(或减去)绝对偏移值得到实际指令的地址,再跳到这个地址去执行,它不会管代码被连接后指令应该在的地址,也不管程序当前位置处于rom还是ram,它只会加上偏移值(如这里是PC+8后跳到main处执行)。而位置相关指令(如ldr指令)它是相对偏移,它会将连接地址赋给PC,PC再跳到连接地址处去执行。