关于编译连接阶段指定连接地址的做用

首先,记住一句话:程序的连接地址必须等于运行地址!学习

在学习exynos 4412的启动过程时,发现本身对连接地址的做用不是很了解,因而上网查找了资料作了基本了解,在此作个总结。spa

上图是exynos 4412启动时iROM、BL1和BL2在iRAM中的分布状况。由图中能够看出,BL2会被加载到0x020_3400的起始地址处(由BL1加载),照理来讲,在BL2代码编译连接过程当中应该将连接地址指定到0x0202_3400才是正确的,可是在实际作led实验(此处BL2的代码功能便是按键控制led亮灭)过程当中发现,将连接地址指定为0x0202_0000也照常运行。如下为连接脚本的内容:blog

SECTIONS
{
. = 0x02020000;  #注:此处正确的连接地址应该为0x0202_3400
.text : { *(.text) }
.rodata ALIGN(4) : {*(.rodata*)}
.data ALIGN(4) : { *(.data*) }
.bss ALIGN(4) : { *(.bss) *(COMMON) }
}内存

要想明白缘由,就得理解连接地址的做用。编译

先看连接器的做用:遍历

  当连接器进行连接的时候,首先决定各个目标文件在最终可执行文件里的位置。而后访问全部目标文件的地址重定义表,对其中记录的地址进行重定向   (加上一个偏移量,即该编译单元在可执行文件上的起始地址)。而后遍历全部目标文件的未解决符号表,而且在全部的导出符号表里查找匹配的符号,   并在未解决符号表中所记录的位置上填写实现地址。最后把全部的目标文件的内容写在各自的位置上,再做一些另的工做,就生成一个可执行文件。程序

在上述连接脚本中指定的连接地址,便是告诉连接器将程序的起始地址设置为0x0202_0000,由此,连接器会根据这个设定的起始地址设定程序中位置相关代码的地址。假设连接地址是0x0202_0000,而程序的起始地址实际是在0x0202_3400,当运行位置无关代码时(即要跳转的运行地址为当前PC的值加上一个相对偏移量),CPU能够正确找到程序的存放位置,所以运行不会出错。可是若是存在位置相关代码(即连接时指定好的固定具体地址,非当前PC值加相对偏移量得到的相对地址),那么当CPU跳转到对应的运行地址处运行时,因为实际的代码存放地址运行地址(运行地址由连接时根据连接地址计算获得不一样,那么运行就会出错了。im

举个例子:假设当将连接地址指定为0x0202_0000,由今生成的可执行程序中有条位置相关代码是 goto 0x0202_1000 ,而实际可执行程序存放在0x0202_3400的起始地址处,那么实际 goto 0x0202_1000 对应的代码就不在0x0202_1000处了,而CPU经过执行 goto 0x0202_1000 跳转到0x0202_1000处,到那里去运行代码,却找不到对应的代码,所以程序运行就出错了。总结

若是连接地址与程序在内存中的实际存放起始地址不一样,当没有位置相关代码时程序运行不会出错,这就是前面说的led程序能够正常运行的缘由。可是若是程序中有位置相关代码,那么当运行到位置相关代码时,便会发生错误。脚本

所以,程序的连接地址必须等于运行地址。

相关文章
相关标签/搜索