编译地址和运行地址的区别分析

ARM汇编概念(1): 什么是链接地址、运行地址、存储地址? 什么是位置无关码、位置有关码? ldr和adr的理解? ARM汇编概念(1): 什么是链接地址、运行地址、存储地址? 什么是位置无关码、位置有关码? ldr和adr的理解? 参考来源:http://blog.sina.com.cn/s/blog_93339c560102wjqm.html 链接地址: 在链接脚本里指定内存地址,编译时指定的代码运行时应该所处的内存地址。它是绝对地址(编译后的定值)。 运行地址: 当前代码运行时实际所处的地址。它是相对地址(相对于当前程序开始运行时的内存地址)。 存储地址: 代码烧写到ROM中的地址,比如NANDFLASH。 链接地 阅读详情

Ubuntu 16.04.2环境交叉编译   arm-linux3.4.5   arm架构的s3c2440芯片作为平台

       32位处理器中,每条指令都是4字节长度,以4个字节顺序存储。仅考虑顺序执行的情况下,处理器将按照指令顺序依次读出执行,但是如果考虑跳转执行的话,仅仅只有指令顺序存储这一条件的情况下,实现跳转执行唯一的方法即为跳转到“往后或者往前多少字节”的位置这样的约定。无疑这样的效率是很低的,而且计算也很麻烦

 

因此需要对指令进行编址,即对每个指令赋予地址。

这个操作在编译过程中完成,编译器以某个地址位初始地址,按照存储数据给每个字节赋予顺序的地址。

而这个地址即为编译地址。

运行地址位程序运行中实际的执行地址。


编译地址可以认为是程序编写者 “期望” 程序在运行时的地址,而实际上编译地址和运行地址有些差别。


首先需要知道的是程序源文件编译时可以使用交叉编译工具arm-linux-ld的-T参数对数据段的编译地址指定
如:
arm-linux-ld  -Ttext 0x30000000 start.O hello.O
即为将text(代码)段的编译地址设置以0x30000000为初始值,一般来说程序段的顺序为:
.text -> .rodata -> .data ->  .bss

.text为代码段,.rodata为只读数据段,.data为数据段(存放初始化过的全局变量或者静态变量),.bss段存放未初始化的全局变量

如果未给出-T参数的话,编译器将按照默认规则,以0地址作为初始地址依次编址

编译完成后生成的是.elf格式的文件,需要经过如下步骤:
arm-linux-objcopy -O binary -S xxx.elf xxx.bin
arm-linux-objdump -D xxx.elf > xxx.dis
才可以得到.bin格式文件用于烧写到芯片,第二个命令是用来生成反汇编代码的,通过反汇编代码可以直观的看到编译器对程序源码做出的转译、优化以及编址(编译地址)。


编译完成后得到的程序还要经过烧写到芯片的过程,而这里正是产生编译地址和运行地址的差别所在
假设程序一定是烧写在芯片的flash,也就是芯片的统一编址的0地址处。则:

1.如果arm-linux-ld的-Ttext 参数为0 或者不给出时,程序的编译地址为以0初始的编址,程序开始运行时都是从芯片                    编址的0地址开始,从而运行地址一定是从0地址开始(除非有特别指定),而编译地址也是从0开始,从这个角度来                          看,编译地址和运行地址并无区别

2.如果arm-linux-ld的-Ttext 参数给定为0x30000000,则编译地址为以0x30000000初始的编址,由1可知,程序上电开始运行还是从0地址 开始,所以运行地址为0,从这里编译地址和运行地址就不同了,但是程序依然会从0开始运行,而且还可以正常运行

 这里就需要提到一个位置无关码以及位置相关码的概念了,从名字可以看出来两者的区别在于代码执行时与代码所在位置是否有关系。
位置无关码通常使用相对跳转或者其他相对位置的指令进行跳转执行,与实际具体地址并无关系,所以称为位置无关码,类似于文件的相对路径。

位置相关码需要使用指令的绝对地址,也就是其编译地址进行跳转,也即跳转到指定的编译地址上,与指令实际所在地址有关,类似于文件的绝对路径。

arm架构指令集中,位置无关码有相对跳转指令b,而位置相关码有ldr指令

通过b跳转的 如b main的实际跳转方式为PC + 偏移值 (PC值等于当前地址+8)
而通过ldr实现的跳转ldr pc,lab (此处lab为标号)则是将lab标号的编译地址直接赋值给PC,从而跳转到绝对地址

程序烧写从芯片统一编制的0地址开始,所以程序在内存中的存储是在0地址开始的,而运行也是从0地址开始,如果中间没有位置相关码,则程序在0地址处的程序执行是可行的,因为是程序存储位置,所以需要的指令和数据都能取到,但是此时运行地址和编译地址就不一样了。
如果程序在进行一定初始化后,使用ldr指令将pc指向到 “预期” 地址,也即编译地址,则编译地址和运行地址就可以达到相等(运行时的pc)。

再裸机程序中或者其他程序中经常编译地址和运行地址不一致,以裸机程序为例,使用s3c2440芯片,使用norflash作为存储的话,norflash为0地址开始处,而正如我们所知norflash类似于rom,能够正常读取数据,但是需要特殊的方式才能写入数据,这就导致我们烧入的程序中,一些全局变量或者保存在栈区的全局变量如果存储在norflash上的话将无法按照程序中所希望的那样可以进行赋值修改,所以需要将代码重定位到其他存储位置上,如我的板子的SDRAM上,所以造成了编译地址和运行地址的不一致。

需要注意的是将代码重定位到编译地址区域之前,需要初始化目标存储区,比如我使用的SDRAM,则我需要初始化SDRAM设置,还有需要将代码、数据等信息复制到目标区域,因为我们的代码存储在0地址区域而不是存储在重定位目标区域,所以目标区域在复制代码前是空的,直接绝对跳转的话会发生不可预料的事···
 

还有其他原因造成编译地址和运行地址不同的情况,以及需要进行代码重定位的原因,这里做了一些简单情况的讲述分析,在其他情况下,道理相似,可以举一反三,触类旁通。重定位的方式也有区分,日后抽空分析。


结论:
编译地址:编译过程中人为指定的代码编址地址,是程序员 "期望" 程序运行的位置

 

运行地址:实际运行中程序指针pc的值,和实际运行载体和代码存储位置有关。

 

欢迎交流、讨论或者指正!共同进步!

---------------------------------------------------------

2020重新回顾有了一些新的见解,可以移步至https://blog.youkuaiyun.com/G_METHOD/article/details/104508545。

运行地址,链接地址,加载地址,存储地址 位置无关码、位置有关码 搞ARM开发时,在连接目标代码会提到运行地址和加载地址。这两者有什么区别呢?其次,网上也有说链接地址和存储地址,那么这四个地址之间有什么区别? 1、运行地址链接地址:他们两个是等价的,只是两种不同的说法。 2、加载地址存储地址:他们两个是等价的,也是两种不同的说法。   运行地址:程序在SRAM、SDRAM中执行时的地址。就是执行这条指令时,PC应该等于这个地址,换句话说,PC等于这个地址 阅读详情

相关推荐

嵌入式linux中存储地址和运行地址(链接地址)

摘要:嵌入式Linux开发中,链接地址决定了代码的运行位置。与STM32不同,Linux需要手动指定链接地址(如0X87800000),通过交叉编译工具链将.o文件链接到该地址生成.elf文件,再转换为可烧写的.bin文件。链接地址需与硬件(如DDR)匹配,确保代码能正确加载运行。

qq_40170041的博客 554

编译地址与运行地址

比如在函数a中定义了函数b,当执行到函数b时要进行指令跳转,要跳转到b函数所对应的起始地址上去,编译时,编译器给每条指令都分配了编译地址,如果编译器已经给分配了地址就可以直接进行跳转,查找b函数跳转指令所对应的表,进行直接跳转,因为有个编译地址和指令对应的一个表,如果没有分配,编译器就查找不到这个跳转地址,要进行计算,非常麻烦。结果是不能跳转,编译后会产生跳转地址,如果实际地址和编译后产生的地址不相等,那么就不能跳转,所以都希望把编译地址和实际运行地址放在一起的。用来告诉编译器编译地址的起始地址。

u011029104的专栏 391

智能合约调用外部合约和继承接口合约的区别

在区块链开发中,智能合约是核心构件,用于实现分布式应用的逻辑。在开发智能合约时,开发者可能需要与其他合约进行交互,这可以通过调用外部合约或继承接口合约来实现。这两种方式有着显著的区别,各自适用于不同的场景。本文将详细探讨两者的不同点、优劣势以及适用场景。调用外部合约和继承接口合约是两种重要的智能合约交互方式,各有优劣。前者适用于动态性较强的场景,能够支持模块化开发和链上协作;后者更适合定义标准和静态实现,能够在编译时保证安全性和一致性。开发者在选择时应根据具体需求权衡两者的特点,以设计出最优的智能合约架构。

2201_75798391的博客 1013

编译地址与加载地址与运行地址

来自虚拟化课2 建立了一个临时页表,因为xen加载的地址可能与编译时指定的地址是不一致的,这种情况下我们会建立一个页表,对他们进行偏移映射,达到虚拟地址与编译地址是一致的效果,这样我们就不用做一些relocation的动作了,紧接着就是将MMU使能与打开,到这里就结束了一些简单的初始化 链接脚本中指定的就是各个符号的编译链接地址(我们就简称为编译地址来方便理解吧) 镜像加载到内存某个地址上,这个地址就是这个镜像加载后的起始运行地址,如果这个加载的起始运行地址 与 镜像中的起始编译地址

weixin_68665933的博客 479

深入程序编译链接和装载过程

目录 预编译 编译 汇编 链接 深入编译链接和运行 CPU、内存 与 I/O 32位4GLinux虚拟地址空间布局 指令和数据 分析二进制可重定位目标文件main.o 的组成 强符号与弱符号 符号表 链接过程分析 可执行文件分析 run可执行文件的组成格式分析 程序的运行——进程 VP与PP 在Linux下使用GCC来编译Hello World程序时,...

ZY-JIMMY 5356

大疆2025八月份校招硬件工程师笔试真题A卷题目分享

大疆2025年笔试真题解析

weixin_63651698的博客 1569

linux内核学习---内核编译

原本打算使用低版本的Linux内核进行实验,但是编译完成了几个3.X版本以后发现总是出现CPU死机或者无法开机情况,所以这里还是先用与原系统内核的版本相近的进行编译(占了近20G空间)。(好像是gcc编译器?linux c/c++后端开发 面试题、学习资料、教学视频,免费分享有需要的可以自行添加学习交流群739729163 领取。安装内核以后,会默认将新的内核信息更新到grub中,但是我们需要修改grub文件,使得我们可以进行开机选择进入的内核。设置线程数,可以提高编译速度!所以我们下面直接重启即可!

C/C++Linux、音视频、DPDK 304

FPGA实战:AXI BRAM Controller写时序避坑指南(附Vivado配置步骤)

本文深入探讨了FPGA开发中AXI BRAM Controller的写时序实战要点与常见陷阱。文章聚焦于写地址与写数据通道的握手机制,详细解析了AWREADY、WVALID等关键信号的处理,并提供了Vivado中流水线深度、ECC等关键参数的配置步骤与优化建议,旨在帮助开发者有效规避时序问题,提升系统性能。

weixin_32306683的博客 172

编译原理 - 变量的内存地址和符号地址

变量地址 引子 访问局部变量时,程序如何知道变量的内存地址?如下: int a; a = 10; 理解 保存在data,rodata等分区的变量,内存地址在编译期就能确定,通过变量名的访问可以由在编译期将变量名映射为变量的内存地址来实现;但是局部变量和指针变量不同,其内存地址是不断变化的,每次执行都不同。 事实上所有的变量的地址都是在编译阶段确定下来了的,包括局部变量和指针变量本身,编译期...

qazw9600的专栏 6659

ANSYS 2026 R1 Windows系统安装避坑指南:环境配置、模块部署与许可证实战

ANSYS作为主流CAE仿真平台,其安装部署已远超传统软件范畴,演变为涉及操作系统底层、GPU驱动兼容性、许可证微服务架构和统一缓存机制的系统工程。理解ANSYS安装原理,需从Windows 11 UEFI安全启动要求、DirectX 12 Ultimate图形栈依赖、gRPC架构的License Manager端口动态分配等核心机制切入;技术价值在于保障HFSS GPU加速、Fluent MPI并行稳定性及Workbench多模块协同可靠性;典型应用场景涵盖高校仿真实验室升级、工业设计院所平台重建及高性能

weixin_29251337的博客 1430

从零构建生产级K8s-v1.35.0集群:基于Containerd与Cilium的kubeadm实战指南

本文详细介绍了从零构建生产级K8s-v1.35.0集群的全过程,涵盖环境准备、Containerd配置、Kubernetes组件安装、集群初始化及Cilium网络部署等关键步骤。通过实战经验分享系统调优技巧和常见问题解决方案,帮助读者快速搭建稳定高效的Kubernetes集群。

weixin_28725553的博客 221

程序的编译、链接、安装与运行

​​链接地址(Link Address)​​是程序编译链接过程中使用的一个​​核心概念​​,指的是​​编译器(Compiler)和链接器(Linker)在生成可执行文件时,假定该程序未来将在内存中的某个特定地址运行​​。这个地址是程序内部所有​​绝对地址引用(如变量地址、函数入口地址、常量地址)的“基址”​​。就是在链接阶段,链接器 (ld) 并不知道程序最终会被加载到物理内存的哪个地址运行(可能是0x8000,也可能是0x87F00000,取决于硬件和启动方式)。所以需要​。

m0_59749585的博客 838

MimicKit 人形机器人强化学习全身模仿控制算法使用教程

本文介绍了MimicKit运动模仿算法框架的使用指南。主要内容包括:1)安装IsaacGym和依赖项;2)训练模型命令及参数说明;3)测试模型的方法;4)分布式训练配置;5)使用TensorBoard可视化日志;6)动作数据格式说明。该框架支持DeepMimic、AMP、ASE、ADD等算法,包含PPO、AWR等强化学习算法,适用于物理仿真角色动画控制研究。

机器人控制与仿真应用 1203

【指针和引用的区别】【汇编的角度分析】【典型场景】

本文对比了C++中指针和引用的底层实现差异。通过汇编代码分析发现:1)在内存操作和函数传参时,两者在汇编层面几乎相同,都是传递地址;2)关键区别在于指针可以重新绑定和为空,而引用则不能;3)引用由于不可重新绑定,编译器能进行更多优化,通常性能更优;4)指针适合需要灵活绑定的场景,引用更适合函数传参和对象别名。总结指出引用本质上是自动解引用的常量指针,但语言特性使其能生成更优化的代码。

qq_45592626的博客 255

大模型——CoPaw:阿里云通义推出的个人智能体工作台,让 AI 助理真正落地

阿里云通义实验室于2026年2月发布CoPaw个人智能助理,采用"本地+云端"双部署模式,支持多平台接入和技能扩展。该产品基于AgentScope多智能体生态构建,具备极简部署、长期记忆系统和灵活的技能插件体系三大核心特性。用户可通过简单命令快速安装,并通过记忆文件系统实现个性化交互体验。CoPaw还支持钉钉、飞书等主流平台接入,并开源了模块化架构,允许本地模型接入。技术架构采用多频道对话网关与可插拔Skills系统,为用户提供真正的AI助理服务体验。

2134

【ComfyUI 基础教程】ComfyUI 局部重绘工作流教程

本篇指南将带你了解 ComfyUI 中的局部重绘工作流,并带你完成一个局部重绘的示例,以及遮罩编辑器的使用等。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 303

C语言:编译和链接

当点击test.i的文件中,可以浏览到实际写的代码在1000行才开始执行,前面也有很多的代码信息,但是在实际编写的代码中,处理包含头文件以外并没有其他的代码增加,也就是说上面的信息都是来自于头文件的包含。来完成语义分析,即对表达式的语法层面分析,编译器所能做的分析是语义的静态分析,静态分析通常包括声明和类型的匹配,类型的转换,这个阶段会报告错误的语法信息。将源代码程序被输入扫描器,扫描器的任务就是简单的进行词法分析,把代码中的字符分割成一系列的记号(关键字、标识符、字面量、特殊字符等)

2403_86834518的博客 1174

图文教程本地部署开源扣子Coze Studio工作流并接入 Gemini 大模型(windows亲测) Coze Studio 本地部署、Gemini 模型接入、开源 AI 工具平台、大模型工作流搭建

本文介绍了在Windows系统本地部署开源AI工具平台Coze Studio并接入Google Gemini大模型的完整教程。主要内容包括:1) 环境准备要求(Docker等);2) 获取源码和配置Gemini模型(需API密钥);3) 通过Docker Compose部署服务;4) 浏览器访问验证。文章指出该平台适合私有化部署,支持智能体和工作流搭建,但也存在插件系统不完善等局限。最后提供了相关资源链接,为开发者实现本地AI解决方案提供了实用指南。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 2780

进程控制:地址空间、fork与进程异常结束

进程控制:地址空间、fork与进程异常结束

2302_80190394的博客 1049

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

动静态库(编译的基本原理)

编译器会识别源代码中的符号定义,如变量的声明、函数的定义等,并提取出符号的名称、类型、作用域等信息。

weixin_74128452的博客 1416

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

【踩坑记录】【C/C++】数组名与指针的关系;数组名取地址;数组名的解引用与取地址;

文章目录前序知识指针与数组名的区别验证一维数组二维数组参考 前序知识 获取变量类型的语句是:typeid(variable).name(); sizeof函数在编译阶段起作用。 指针与数组名的区别 C专家编程 中有讲到, 数组和指针在编译器处理时是不同的,在运行时的表示形式也是不一样的,并可能产生不同的代码。对编译器而言,一个数组就是一个地址,而一个指针就是一个地址的地址。 数组名是不可修改的左值,不能直接对其赋值(定义时除外)。但可以用memcpy,strcpy等来进行间接“赋值”。 讲

多丰富下自己呀 559

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

浅析可执行程序的编译过程

编译与链接、符号表、链接中的常见错误、

good good study, day day up! 1019

STM32CubeMX中I2C配置从机地址常见错误

本文深入剖析I2C通信协议中的从机地址机制,重点解析7位地址与8位传输字节的关系,揭示STM32在主机与从机模式下地址配置的常见误区,并结合CubeMX、HAL库和硬件寄存器说明正确配置方法。通过真实调试案例和标准化流程,帮助开发者避免NACK、通信失败等问题,提升嵌入式系统开发效率。

web99的专栏 868

对.lds连接脚本文件的分析

<br /> <br />    对于.lds文件,它定义了整个程序编译之后的连接过程,决定了一个可执行程序的各个段的存储位置。虽然现在我还没怎么用它,但感觉还是挺重要的,有必要了解一下。<br />先看一下GNU官方网站上对.lds文件形式的完整描述:<br />SECTIONS {<br />...<br />secname start BLOCK(align) (NOLOAD) : AT ( ldadr )<br />{ contents } >region :phdr =fill<br />...<

激情成就梦想--关注移动互联网 833

uboot 之uboot.lds分析

对于.lds文件,它定义了整个程序编译之后的连接过程,决定了一个可执行程序的各个段的存储位置,很有必要了解一下。先看一下GNU官方网站上对.lds文件形式的完整描述: SECTIONS { ... secname start BLOCK(align) (NOLOAD) : AT ( ldadr ) { contents } > region :phdr =fill ... }secname和

liuer2004_82的专栏 412
下一篇: Makefile:416: *** mixed implicit and normal rules: deprecated syntax
CryptonymAMS
博客等级 码龄10年 95粉丝 10原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值