一、反汇编
简单代码分析
把以下代码生成的 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,可以通过两种办法解决
- 重定位.data 段
- 重定位整个代码数据段
链接脚本 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