一、反汇编
简单代码分析
把以下代码生成的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
发表回复