1、链接地址、运行地址、加载地址、存储地址关系

总的来说,他们之间的关系:链接地址 == 运行地址,加载地址 == 存储地址

链接地址:编译器编译时候,指定的a.out中第一条指令的地址

运行地址:a.out在内存中存储的第一条指令地址

补充说明:为了方便各位理解,我下面的例子都是直接在裸机上跑程序二进制机器码,中间省略了操作系统虚拟内存、MMU的知识,像编译阶段的链接地址,我是根据硬件平台的物理地址,直接将内存条的实际物理地址给到链接器(要和普通运行在系统上的程序编译区分开:系统运行的是直接按照4G内存空间给到的虚拟地址),在将程序拷贝到板子上后,加载到指定内存地址(运行地址)后,go运行的。


2、链接地址

在程序编译的时候,每个目标文件都是由源代码编译得到,最终多个目标文件链接生成一个最终的可执行文件,而链接地址就是指示链接器,各个目标文件的在可执行程序中的位置。比如,一个可执行程序a.out由a.o、b.o、c.o组成,那么最终的a.out中谁在前、谁在中间、谁在结尾,都可以通过制定链接地址来决定。

链接地址是静态的,在进行程序编译的时候指定的。

注意,对于CPU来说是不管你这个链接地址是物理地址还是虚拟地址。

总结:

          1、链接地址是给编译器用的,用来计算代码中相关地址偏移的

          2、只要和PC值相关的就是位置无关代码(相对偏移),和PC无关的就是位置相关代码(绝对值)

链接pyspark_加载

例如上图所示,指令ldr r0, =func就是一条位置相关指令,在编译的时候,编译器根据链接地址(链接地址入口是0x40008000)将其翻译成:ldr r0, [pc, #0x80],也就是将func标号等价于地址0x40008080,然后将0x40008080这个地址数值放在a.out文件中链接地址0x50008000的位置。当程序运行时,a.out会被加载到内存中运行,如果程序运行的地址和链接的地址都是0x40008000,那么程序运行时,没有任何问题,因为读取的func的地址是0x40008080,实际跳转的时候,跳转到0x40008080中存放的也是func对应的代码。但是如果运行的地址和链接地址不一样(运行地址是0x20008000),这时候,func的地址还是编译的时候计算的地址0x40008080,但是实际在内存中,func的地址是0x20008080,那么当你跳转执行func的时候,取出来的是0x40008080,跳转的地址也是0x40008080,而0x40008080中存放的是什么代码我们不确定,但是一定不是func的代码(func存放在0x20008080中)。这个就是位置相关的概念


3、运行地址

程序实际在内存中运行时候的地址,比如CPU要执行一条指令,那么必然要通过给PC赋值,从对应的地址空间中去取出来,那么这个地址就是实际的运行地址。

运行地址是动态的,如果你将程序加载到内存中时,改变存放在内存的地址,那么运行地址也就随之改变了。

注意,CPU同样不关心运行地址是虚拟地址还是物理地址。


4、加载地址

每一个程序一开始都是存放在flash中的,而运行是在内存中,这个时候就需要从flash中将指令读取到内存中(运行地址),flash的地址就是加载地址。

所以,加载地址指的是将代码从一个地址A搬移到地址B,这时候地址A就是加载地址


5、存储地址

指令在flash中存放的存储地址,就是存储地址。


6、链接地址和运行地址区别

首先要区分开两个概念:位置相关代码和位置有关代码。位置无关代码:mov、b或bl等指令,在跳转时,地址是PC+相对便宜量,这样的指令没有绝对地址,都是相对PC的偏移,这样,及时运行地址和链接地址不一样,也不影响实际代码的执行。位置相关代码:ldr r0, =标签,这里的标签实际就是链接地址,这条指令实质就是将标号的地址放到PC里实现跳转,但是如果实际运行的地址和链接的地址不一样,这样就会由于跳转的地址不是实际运行地址而出错,这就叫做位置相关代码

条件相关代码和条件无关代码之间的本质区别就是:指令中相关地址是运行地址还是链接地址,如果是运行地址那么就是位置无关代码,因为运行地址是变化的相对量;如果是加载地址,那么就是绝对量(链接时候指定了的),这就是位置相关代码了。

总结,当链接指定的地址和实际运行的地址一样的时候,链接地址==运行地址;当链接指定的地址和实际运行的地址不一样的时候,如果整个代码中的地址都是相对偏移量,那么整个程序仍然运行畅通无阻,否则,整个程序运行结果就会出错(因为指定运行地址和实际运行地址不符)。


7、加载地址和存储地址区别

本质上区别不大,都指的是程序存放的位置。