热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

深入解析MDK链接脚本的应用与优化技巧

本文深入探讨了MDK链接脚本的应用与优化技巧。首先,文章介绍了链接脚本的基本概念及其在嵌入式系统开发中的重要性。接着,通过具体实例详细分析了链接脚本的结构和功能,特别是在程序在FLASH中运行时,如何优化链接脚本以提高系统性能。此外,文章还讨论了无需将程序加载到SRAM中的技术细节,为开发者提供了实用的参考和指导。

文章目录

  • 序言
  • 一些基本概念的建立
  • 链接脚本的作用
  • 具体链接脚本分析


序言

我的上一篇文章程序是在FLASH中运行中介绍了单片机中的一种奇特现象:程序不需要加载到SRAM中,而是可以直接在FLASH中运行。在我们知道了这件事情之后,我们趁热打铁,继续探讨程序在FLASH中的静态布局与运行时动态布局。链接脚本文件对这两种布局有着重要影响。我们下面的主要探究对象就是这个链接脚本文件。

一些基本概念的建立
  • 段属性:代码是分段存储的,典型的分段规则是:代码段,数据段,堆栈段,BSS段
  • RO:READONLY,一种段属性,表示段里面的内容只读
  • RW:READWRITE,一种段属性,表示段里面的内容可读可写
  • ZI:ZEROINIT,一种段属性,表示段里面的数据都被初始化为0

链接脚本的作用

了解了上面的基本概念之后,我们知道,代码汇编完成之后会生成一系列段,链接脚本的作用主要是规定如何把输入文件内的section放入输出文件内,并控制输入文件内各部分在程序地址空间内的布局,这些事情都完成后,我们就得到了镜像文件(image),也就是最终要交给flashloader(bootloader)的文件,flashloader会将文件放到单片机对应的存储空间中。

如果我们将image文件烧录到ROM中,那么其必须包含有将RW段移动到RAM中以及将ZI段所在的地址清零的功能。这是保证烧录程序能运行起来的基本要求,这些功能也是由链接脚本提供。

具体链接脚本分析

在分析链接脚本之前,我们先来看一个汇编文件,分析一下里面有哪些东西(需要手边准备一些ARM汇编指令速查手册)。

;EQU指令的作用就是把0x00000400这个值定义一个标签Stack_Size,类似于C语言中的宏定义#define
Stack_Size EQU 0x00000400 ;AREA指令指示汇编器汇编新的代码节或数据节。节是不可分的已命名独立代码或数据块,由链接器处理。AREA STACK, NOINIT, READWRITE, ALIGN=3;SPACE 指令保留一个用零填充的内存块。
Stack_Mem SPACE Stack_Size
__initial_sp; <h> Heap Configuration
; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>Heap_Size EQU 0x00000200AREA HEAP, NOINIT, READWRITE, ALIGN&#61;3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit;PRESERVE8 指令指定当前文件保持堆栈八字节对齐PRESERVE8;THUMB 指令使用 UAL 语法&#xff0c;指示汇编器将后续指令解释为 Thumb 指令。THUMBAREA |.text|, CODE, READONLY; Reset handler
Reset_Handler PROCEXPORT Reset_Handler [WEAK]IMPORT __mainIMPORT SystemInitLDR R0, &#61;SystemInitBLX R0 LDR R0, &#61;__mainBX R0ENDP

找到上面代码中所有AREA行&#xff0c;AREA在ARM中是段标识指令&#xff08;具体的用法可以去查看指令手册&#xff09;&#xff0c;我们可以看到段被分成了几种&#xff1a;DATA段&#xff08;一般READWRITE就是DATA&#xff09;&#xff0c;CODE段。这些段的属性也都有标识出来。这些属性是我们链接脚本链接的依据。

下面是一个链接脚本&#xff0c;很短

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************LR_IROM1 0x00000000 0x00040000 { ; 定义一个加载时域&#xff0c;域基址&#xff1a;0x00000000&#xff0c;域大; 小为 0x00040000&#xff0c;对应实际 Flash 的大小ER_IROM1 0x00000000 0x00040000 { ; 定义一个运行时域&#xff0c;第一个运行时域必须和加载; 时域起始地址相同&#xff0c;否则库不能加载到该时域的; 错误&#xff0c;其域大小一般也和加载时域大小相同*.o (RESET, &#43;First) ; 将 RESET 段最先加载到本域的起始地址外&#xff0c;即; RESET 的起始地址为 0&#xff0c;RESET 存储的是向量表.ANY (&#43;RO) ; 加载所有匹配目标文件的只读属性数据&#xff0c;包含&#xff1a;; Code、RW-Code、RO-Data。}RW_IRAM1 0x10000000 0x00008000 { ; 定义一个运行时域&#xff0c;域基址&#xff1a;0x10000000&#xff0c;域大; 小为 0x00008000&#xff0c;对应实际 RAM 大小* (&#43;RW &#43;ZI) ; 加载所有区配目标文件的 RW-Data、ZI-Data; 这里也可以用.ANY 替代*}
}

上面的注释里面有两个词&#xff1a;加载时域、运行时域&#xff0c;注意断句要断好&#xff0c;加载时域就是代码被烧录后在存储空间中的状态&#xff08;至于为什么叫做加载时域&#xff0c;因为在嵌入式中程序是要被加载到内存的&#xff0c;只是在单片机这里有点特殊&#xff0c;加载域就是存储域&#xff09;&#xff0c;运行时域就是程序运行时代码在存储空间中的状态。
理解了上面两个域之后&#xff0c;我们再来看这个链接脚本&#xff0c;它定义了一个大的加载时域&#xff0c;也就是程序在运行前会被加载到什么地方&#xff08;在单片机中&#xff0c;它就在原地不动&#xff09;&#xff0c;加载时域下面有两个运行时域&#xff0c;也就是在运行的时候这两个域中的代码会被送到的地方。
到这里就差不多了&#xff0c;可以仔细看看代码&#xff0c;如果我有理解错误的地方&#xff0c;请在评论区留言&#xff0c;非常感谢。


推荐阅读
  • Python 程序转换为 EXE 文件:详细解析 .py 脚本打包成独立可执行文件的方法与技巧
    在开发了几个简单的爬虫 Python 程序后,我决定将其封装成独立的可执行文件以便于分发和使用。为了实现这一目标,首先需要解决的是如何将 Python 脚本转换为 EXE 文件。在这个过程中,我选择了 Qt 作为 GUI 框架,因为之前对此并不熟悉,希望通过这个项目进一步学习和掌握 Qt 的基本用法。本文将详细介绍从 .py 脚本到 EXE 文件的整个过程,包括所需工具、具体步骤以及常见问题的解决方案。 ... [详细]
  • [转]doc,ppt,xls文件格式转PDF格式http:blog.csdn.netlee353086articledetails7920355确实好用。需要注意的是#import ... [详细]
  • 字节流(InputStream和OutputStream),字节流读写文件,字节流的缓冲区,字节缓冲流
    字节流抽象类InputStream和OutputStream是字节流的顶级父类所有的字节输入流都继承自InputStream,所有的输出流都继承子OutputStreamInput ... [详细]
  • 本文介绍了如何利用ObjectMapper实现JSON与JavaBean之间的高效转换。ObjectMapper是Jackson库的核心组件,能够便捷地将Java对象序列化为JSON格式,并支持从JSON、XML以及文件等多种数据源反序列化为Java对象。此外,还探讨了在实际应用中如何优化转换性能,以提升系统整体效率。 ... [详细]
  • 本文介绍如何使用 Python 的 DOM 和 SAX 方法解析 XML 文件,并通过示例展示了如何动态创建数据库表和处理大量数据的实时插入。 ... [详细]
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • 基于Linux开源VOIP系统LinPhone[四]
    ****************************************************************************************** ... [详细]
  • 本文介绍了如何使用Python的Paramiko库批量更新多台服务器的登录密码。通过示例代码展示了具体实现方法,确保了操作的高效性和安全性。Paramiko库提供了强大的SSH2协议支持,使得远程服务器管理变得更加便捷。此外,文章还详细说明了代码的各个部分,帮助读者更好地理解和应用这一技术。 ... [详细]
  • 大类|电阻器_使用Requests、Etree、BeautifulSoup、Pandas和Path库进行数据抓取与处理 | 将指定区域内容保存为HTML和Excel格式
    大类|电阻器_使用Requests、Etree、BeautifulSoup、Pandas和Path库进行数据抓取与处理 | 将指定区域内容保存为HTML和Excel格式 ... [详细]
  • 本文介绍了如何使用 Node.js 和 Express(4.x 及以上版本)构建高效的文件上传功能。通过引入 `multer` 中间件,可以轻松实现文件上传。首先,需要通过 `npm install multer` 安装该中间件。接着,在 Express 应用中配置 `multer`,以处理多部分表单数据。本文详细讲解了 `multer` 的基本用法和高级配置,帮助开发者快速搭建稳定可靠的文件上传服务。 ... [详细]
  • 在尝试对 QQmlPropertyMap 类进行测试驱动开发时,发现其派生类中无法正常调用槽函数或 Q_INVOKABLE 方法。这可能是由于 QQmlPropertyMap 的内部实现机制导致的,需要进一步研究以找到解决方案。 ... [详细]
  • 在使用 Qt 进行 YUV420 图像渲染时,由于 Qt 本身不支持直接绘制 YUV 数据,因此需要借助 QOpenGLWidget 和 OpenGL 技术来实现。通过继承 QOpenGLWidget 类并重写其绘图方法,可以利用 GPU 的高效渲染能力,实现高质量的 YUV420 图像显示。此外,这种方法还能显著提高图像处理的性能和流畅性。 ... [详细]
  • 利用爬虫技术抓取数据,结合Fiddler与Postman在Chrome中的应用优化提交流程
    本文探讨了如何利用爬虫技术抓取目标网站的数据,并结合Fiddler和Postman工具在Chrome浏览器中的应用,优化数据提交流程。通过详细的抓包分析和模拟提交,有效提升了数据抓取的效率和准确性。此外,文章还介绍了如何使用这些工具进行调试和优化,为开发者提供了实用的操作指南。 ... [详细]
  • 本文介绍了如何利用 Delphi 中的 IdTCPServer 和 IdTCPClient 控件实现高效的文件传输。这些控件在默认情况下采用阻塞模式,并且服务器端已经集成了多线程处理,能够支持任意大小的文件传输,无需担心数据包大小的限制。与传统的 ClientSocket 相比,Indy 控件提供了更为简洁和可靠的解决方案,特别适用于开发高性能的网络文件传输应用程序。 ... [详细]
  • 深入解析 OpenSSL 生成 SM2 证书:非对称加密技术与数字证书、数字签名的关联分析
    本文深入探讨了 OpenSSL 在生成 SM2 证书过程中的技术细节,重点分析了非对称加密技术在数字证书和数字签名中的应用。非对称加密通过使用公钥和私钥对数据进行加解密,确保了信息传输的安全性。公钥可以公开分发,用于加密数据或验证签名,而私钥则需严格保密,用于解密数据或生成签名。文章详细介绍了 OpenSSL 如何利用这些原理生成 SM2 证书,并讨论了其在实际应用中的安全性和有效性。 ... [详细]
author-avatar
鲁毅-beyond_512
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有