程序重定位

先复习一下段的概念: 一个程序由代码段、只读数据段、可读可写的数据段、BSS段等组成。

char g_Char = 'A';           // 可读可写,不能放在ROM上,应该放在RAM里
const char g_Char2 = 'B';    // 只读变量,可以放在ROM上
int g_A = 0;   // 初始值为0,干嘛浪费空间保存在ROM上?没必要
int g_B;       // 没有初始化,干嘛浪费空间保存在ROM上?没必要
  • 代码段(RO-CODE):就是程序执行的指令,不能被修改

  • 可读可写的数据段(RW-DATA):有初始值的全局变量、静态变量,需要从ROM上复制到内存

  • 只读的数据段(RO-DATA):可以放在ROM上,不需要复制到内存

  • BSS段或ZI段:

    • 初始值为0的全局变量或静态变量,没必要放在ROM上,使用之前清零就可以

    • 未初始化的全局变量或静态变量,没必要放在ROM上,使用之前清零就可以

  • 局部变量:保存在栈中,运行时生成

  • 堆:一块空闲空间,使用malloc函数来管理它,malloc函数可以自己写

为什么要重定位?

当程序的加载地址 != 链接地址时,需要重定位。

加载地址和链接地址:

程序运行时,应该位于它的链接地址处,因为:

  • 使用函数地址时用的是"函数的链接地址",所以代码段应该位于链接地址处

  • 去访问全局变量、静态变量时,用的是"变量的链接地址",所以数据段应该位于链接地址处

但是: 程序一开始时可能并没有位于它的"链接地址":

  • 比如对于STM32F103,程序被烧录器烧写在Flash上,这个地址称为"加载地址"

  • 比如对于IMX6ULL/STM32MP157,片内ROM根据头部信息把程序读入内存,这个地址称为“加载地址”

程序重定位

  • 代码段:如果它不在链接地址上,就需要重定位

  • 只读数据段:如果它不在链接地址上,就需要重定位

  • 可读可写的数据段:如果它不在链接地址上,就需要重定位

  • BSS段:不需要重定位,因为程序里根本不保存BSS段,使用前把BSS段对应的空间清零即可

谁来做重定位的操作?

1.CPU内部

2. 程序开头通过使用“位置无关码”编写的重定位代码,实现程序自己重定位

  • 什么叫位置无关码:这段代码扔在任何位置都可以运行,跟它所在的位置无关

  • 怎么写出位置无关码:

    • 跳转:使用相对跳转指令,不能使用绝对跳转指令

      • 只能使用branch指令(比如bl main),不能给PC直接复制,比如ldr pc, =main

    • 不要访问全局变量、静态变量

    • 不使用字符串

3. 怎么做重定位和清除BSS段?

  • 核心:复制

  • 复制的三要素:源、目的、长度

    • 怎么知道代码段/数据段保存在哪?(加载地址)

    • 怎么知道代码段/数据段要被复制到哪?(链接地址)

    • 怎么知道代码段/数据段的长度?

  • 怎么知道BSS段的地址范围:起始地址、长度?

  • 这一切

    • 在keil中使用散列文件(Scatter File)来描述

    • 在GCC中使用链接脚本(Link Script)来描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值