韦东山一期视频学习笔记代码重定位学习

一、反汇编

简单代码分析

把以下代码生成的elf文件使用命令arm-linux-objdump -D led_on.elf > led_on.dis反汇编
原始文件

.text
.global _start
_start:
    ldr r0, =0x56000010
    mov r1, #0x00015400
    str r1, [r0]

    ldr r0, =0x56000014
    ldr r1, =0x00000040
    str r1, [r0]
halt:
    b halt

反汇编文件

led_on_elf:     file format elf32-littlearm

Disassembly of section .text:

00000000 <_start>:
   0:    e59f0014     ldr    r0, [pc, #20]    ; 1c <.text+0x1c>
   4:    e3a01b55     mov    r1, #87040    ; 0x15400
   8:    e5801000     str    r1, [r0]
   c:    e59f000c     ldr    r0, [pc, #12]    ; 20 <.text+0x20>
  10:    e3a01040     mov    r1, #64    ; 0x40
  14:    e5801000     str    r1, [r0]

00000018 <halt>:
  18:    eafffffe     b    18 <halt>
  1c:    56000010     undefined
  20:    56000014     undefined

sublime可以安装HexViewer查看bin二进制文件HexViewer的使用
二进制码

1400 9fe5 551b a0e3 0010 80e5 0c00 9fe5
4010 a0e3 0010 80e5 feff ffea 1000 0056
1400 0056 
  • ldr r0, [pc, #20] :表示PC的地址(当前地址也就是第一列值换算成十进制 + 十进制8)加上 #20(十进制20)地址0x1c上的数据0x56000010存入r0
  • 可以看出开头的1列0: 4: ..这些表示机器码所在的起始地址是第几个字节,一行指令是4字节32位,第二列表示的是储存在内存中实际的字节数据(机器码),第三列表示的是字节数据对应翻译成的汇编指令
  • 第一列最大值为0x20,0x20处存在4字节数据所以一直到0x23,所以bin程序一共有36字节(0x0~0x23)

一、代码段重定位

  • Norflash可以直接读但是无法直接写入
  • Norflash启动的栈设置与Nand启动不同
    mov r1, #0
    ldr r0, [r1] /* 读出原来的值备份 */
    str r1, [r1] /* 0->[0] */ 
    ldr r2, [r1] /* r2=[0] */
    cmp r1, r2   /* r1==r2? 如果相等表示是NAND启动 */
    ldr sp, =0x40000000+4096 /* 先假设是nor启动 */
    moveq sp, #4096  /* nand启动 */
    streq r0, [r1]   /* 恢复原来的值 */
  • arm-linux-ld -Ttext 0x00000000 $^ -o main.elf中加入-Tdata 位置可以简单指定.data段位置
  • 从Nor启动片内SRAM起始地址为0x4000_0000,从Nand启动片内SRAM起始地址为0x0
名称 中文名称 存放类型 保存位置
.text 代码段 存放代码部分 bin文件中
.data 数据段 存放全局变量 bin文件中
.rodata 只读数据段 存放const只读变量 bin文件中
.bss bss段 存放无初始值或初始值为0的全局变量 不在bin文件中
.comment 注释段 存放命令ascii码 不在bin文件中
关于指定.data段

因为如果data段存在于norflash中全局变量无法修改,所以我们需要把全局变量放入SDRAM中。
可以通过在Makefile中加入-Tdata 位置简单的指定data段位置但是会存在数据段和代码段之间有一个巨大的间隙空间最终导致bin文件可能非常的巨大,例如0~0x3000_000,可以通过两种办法解决

  1. 重定位.data段
  2. 重定位整个代码数据段
链接脚本lds文件
简单示例
SECTIONS {
    .text 0 : {*(.text)}
    .rodata : {*(.rodata)}
    .data 0x3000000 : AT(0x800) {*(.data)}
    .bss : {*(.bss) *(.COMMON)}
}
  • AT(0x800)指定data实际位置为0x800,声明位置为0x3000000,需要把值真正拷贝到0x3000000处CPU才可以访问到,因为CPU只会去0x3000000处找变量,所以要重定位把值拷贝到0x3000000吗,注意这里需要初始化sdram
mov r1, #0x800
ldr r0, [r1]
mov r1, #0x3000000
str r0, [r1]
通用智能动态重定位示例
SECTIONS {
    .text 0 : {*(.text)}
    .rodata : {*(.rodata)}
    .data 0x3000000 : AT(0x800) {
        data_load_addr = LOADADDR(.data)
        = .;
        *(.data)
        data_end = .;
    }
    .bss : {*(.bss) *(.COMMON)}
}
  • LOADADDR(.data):data段在bin文件的地址
  • data_start :CPU访问的开始地址
  • data_end:CPU访问的结束地址

重定位代码(低效率)

ldr r1, =data_load_addr
ldr r2, =data_start 
ldr r3, =data_end 
cpy:
  ldrb r4, [r1] #从data_load_addr拷贝1个字节 效率低
  strb r4, [r2]
  add r1, r1, #1
  add r2, r2, #1
  cmp r2, r3
  bne cpy #不等 继续copy

重定位代码(高效率)

ldr r1, =data_load_addr
ldr r2, =data_start 
ldr r3, =data_end 
cpy:
  ldr r4, [r1] #从data_load_addr拷贝1个字节 效率低
  str r4, [r2]
  add r1, r1, #4
  add r2, r2, #4
  cmp r2, r3
  ble cpy #不等 继续copy

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理