关于链接器的一点小小经验
本帖最后由 皮卡丘不会打乒乓球 于 2021-8-5 12:15 编辑链接器
昨天遇到了一点问题,关于嵌入的地址分配的问题。
一个项目片内设计有两个不同的主程序,放在不一样的位置上。一个用于从外下载数据更新应用程序,一个用在正常的应用程序状态下,两个程序之间可以通过重置PC指针到对方入口的办法调用。由于更换了MCU型号,内存部分内容被修改,导致这个跳转的部分失效,其余的功能都是正常的。
我把BUG反馈给了负责那个部分的工程师,他那边看了一下编译报告MAP文件,确认了跳转的标志位分配在两个新旧程序之间时不一致的,然后发了新的代码给我,测试确认了没有问题。
我查看了版本变化,具体的修改就是把原先变量绑定的段重新定义了几个子段,然后把原先变量一个个的绑定到对应的子段里面去。
趁这个机会聊几句链接器的事吧,我了解不是特别深入,有写地方可能不对,希望指正。
链接器本质的作用就是把编译产生的段文件(汇编代码片段),按照存储模型进行分配。对于这个过程需要一个指导文件,(ARM工程下为ld文件,TI工程下叫做CMD文件)。这个指导文件内容主要包括两个部分,存储模型(寻址空间)的描述和段的分配。
存储模型会分为很多个块,复杂一些的甚至会有页的概念。每一个块都会定义起始地址与长度,块可以预先填充。
段是编译产生的汇编产生的数据块与代码块,通过对应的标识,链接器就可以把这些东西分配到存储空间内。编译一共可以产生5种基本的段 其中.text,.data,.sect属于被初始化的段,而.bss与.unsect属于未初始化的部分及被初始化为0的全局变量与静态变量,
以上5种都属于静态分配,均会占据空间。局部变量会被放在堆栈(stack,heap)中。段可以创建子段,用于更加细致的分配(我的程序被修改的就是这一部分的定义)。
段内容使用有两种概念 加载与运行。
加载就是从原始存储地址读取,运行就是每次使用的时候读的位置。
有些程序比如本身存储于NVM中,但是实际上实在RAM中运行的。在使用前必须将对应的段搬运到对应RAM位置。未初始化的段由于在最开始没有实际的有意义的数据,所以需要且仅需要指定一个运行地址即可。
这个链接器部分是伪指令,有专门的关键字及语法。具体内容很复杂,暂时不去展开学习了。毕竟我不是专门弄编译器的,后面有机会再研究把。 小土表示依旧看不懂....
但还是能借用俺恩人的总结性发言:牛逼:lol 迷茫表示依旧看不懂....
但还是能借用土老板的总结性发言:屌 挺好,要常弄这些,对思路有加强作用 伪指令超级有用,而在C里,也有一些库是专门定义移植特征的,不包含这些头文件就没办法执行。
页:
[1]