最近折腾了一下Exyson 4412的裸机编程,Exyson 4412的iRAM只有256K,裸机程序本来也不大,之前一直使用的iRAM,也每初始化内存。现在编写裸机LCD驱动,由于需要显存的大小至少要2MB以上,因此必须初始化内存,反正也要初始化内存了,就想着将裸机程序直接重定位到DRAM中运行。介绍重定位的文章很多,其中(ARM之重定位和链接脚本)介绍的比较详细。先在iRAM做小范围的重定位,于是将重定位代码加上,修改连接描述文件的链接地址,修改中断向量偏移地址,编译,没有问题,烧写到SD卡运行,居然没有反应。之前程序都是正常的啊,查找了很久也没有找到原因。在网上查看了很多帖子,最后才发现是因为我的程序中添加了中断处理,初始化中断向量表的代码着这样写的:
ldr pc, =reset
ldr pc, =undefine_instruction
ldr pc, =software_interrupt
ldr pc, =prefetch_abort
ldr pc, =data_abort
ldr pc, =not_used
ldr pc, =irq_handle
ldr pc, =fiq_handle
关键就在这个ldr,这个使用的是绝对地址,也就是链接地址,而这个时候重定位的链接的地址还没有把代码拷贝过去,所以自然没有能够执行的指令了,因此复位时应使用相对寻址,也就是b reset。把ldr pc, =reset,改成b reset就一切正常了。其实在重定位的代码中,通过adr和ldr获取de _start地址是不同的,也是相对地址和绝对地址的差别。这些道理早在学习ARM寻址方式时就已经知道,但每和实际联系上,在实际应用中会产生什么效果也没有区深入研究,所以才造成的这次问题。