链接地址、运行地址、加载地址、存储地址

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

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

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

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

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


2、链接地址

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

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

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

总结:

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

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

例如上图所示,指令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、加载地址和存储地址区别

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

  • 42
    点赞
  • 170
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
Linux的加载地址链接地址是不同的概念。加载地址指的是程序在内存中的实际地址,也就是程序加载到内存后在内存中的位置。而链接地址指的是程序在编译和链接过程中使用的地址,它是相对于程序的编译和链接的环境而言的。 在Linux中,链接地址是由连接器(ld)根据连接脚本(.lds文件)中的指定来确定的。连接脚本中可以定义各个对象文件在内存中的存储位置和运行地址。通过连接脚本,可以将不同的模块链接到特定的地址上。 加载地址是指程序在运行时实际加载到内存的地址。如果程序是在flash中运行,那么加载地址链接地址是相同的,因为程序直接从flash中加载到内存中执行。如果程序是在ram中运行,但是存储在flash中,那么加载地址指向flash,而运行地址指向ram。在这种情况下,程序需要在运行前将相关代码从flash复制到ram中才能执行。 因此,Linux的加载地址链接地址是根据连接脚本和运行环境来确定的,并且在不同的运行环境下可能会有不同的配置。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [运行地址链接地址加载地址存储地址](https://blog.csdn.net/yeasang1104/article/details/90114493)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值