位置无关编码PIC:汇编源文件被编译后编码方式与位置(内存地址)无关(放在哪都可运行)
位置有关编码:汇编源文件被编译后 编码方式与位置(内存地址)有关
大部分编码都是位置有关代码,设计一个程序时会给程序指定一个运行地址
运行地址:实际上运行的地址-------链接地址:预先设定好的地址(位置有关码必须相同)
指定方式Makefile中用 -Ttext 0x0 指定链接的地址是0x0 或用链接脚本
实际我们运行在 0xd0020010(usb启动) 0xd0020000(sd启动)
datesheet中0xd0000 0000被映射到了 0x0000 0000
启动方式
UBOOT实际使用方式: Uboot大小随意
1.上电从IROM读取预先设置的代码(BL0,64k)(可直接读取运行)....读取第一部分启动代码(BL1,16K)到内部SRAM。
2.BL1运行时初始化DDR,将整个UBOOT搬运到DDR,长跳转指令从SRAM跳转到DDR中继续执行完全启动UBOOT
2.uboot启动后在uboot中启动OS
重定位作用:链接地址和运行地址没办法相同,还不能全部用PIC
Linux应用地址默认链接在0x0地址的,应用程序运行在OS的进程中,独享虚拟地址空间
210裸机程序运行地址由下载确定(CPU设计确定的)
链接脚本
代码编译过程:源代码
预编译:预编译器 处理宏 注释等东西
编译:编译器 将源码编成机器码.o文件
链接:链接器 将.o文件的各个函数(段)按照一定规则(链接脚本指定)累计在一起形成可执行文件
可选步骤:如strip 将可执行程序的符号信息去掉(由Debug版>Release版)
Objcopy:由可执行程序生成可烧录的bin文件
程序段:(与链接有关)程序的一部分:为了在链接脚本中用段名让段排序
代码段: .text段 文本段 函数编译后生成的
数据段: .data段 C语言中有初始化的(显式初始化为非0的)全局变量
BSS段: (ZI段 zero initial) 零初始化段 对应C语言初始化为0的全局变量
自定义段:
链接脚本:是链接器的规则文件,然后用规定规则处理.o文件的段 将 其链接成可执行程序
关键内容: 段名+地址(作为链接地址的内存地址)
代码:
SECTIONS
{
. = 0xd0024000;
.text : {
start.o
* (.text)
}
.data : {
* (.data)
}
bss_start = .;
.bss : {
* (.bss)
}
bss_end = .;
}
练习重定位:
长跳转:类似于b bl 跳转指令通过给pc(r15)赋值来完成跳转执行 长跳转指跳转到的地址和当前地址跳转范围较为宽广ldr pc,=main
adr和ldr伪指令的区别,ldr是长加载,adr是短加载
Adr加载符号地址时加载的是运行时地址
Ldr加载时加载的是链接地址
copy_loop:
ldr r3, [r0], #4 //源
str r3, [r1], #4 //目的
cmp r1, r2 //只要没到bss起始段就一直循环(都是链接地址)
bne copy_loop
其中#4是使4个字节放入r3地址在加4
只需重定位代码段和数据段 bss要手动清
写代码出现的问题:
- .global _start让_start符号成为可见的标识符,这样链接器就知道跳转到程序中的什么地方并开始执行程序。
- start.S: Assembler messages:
start.S:24: Error: internal_relocation (type: OFFSET_IMM) not fixed up
由于把ldr伪指令忘记加赋值符导致的
完整代码:start.s
//定义寄存器宏
#define WTCON 0XE2700000
#define SVC_STACK 0XD0037D80
.global _start
_start:
//关看门狗
ldr r0, =0x0
ldr r1, =WTCON
str r0, [r1]
//设置SVC栈
ldr sp, =SVC_STACK
//开关icache
mrc p15,0,r0,c1,c0,0//读cp15的c1到 r0
//bic r0, r0, #(1<<12)//置0关
orr r0, r0, #(1<<12)//置1开
mcr p15,0,r0,c1,c0,0//写回去
//重定位 本实验运行在0xd0020010,被链接在0xd0024000 将来运行位置有关码时 必须放在0xd0024000
adr r0, _start
ldr r1, =_start
ldr r2, =bss_start //加载bss段起始地址
cmp r0, r1 //比较运行地址和链接地址是否相等
beq clean_bss //相等则不进行重定位跳到clean_bss
copy_loop:
ldr r3, [r0], #4 //源
str r3, [r1], #4 //目的
cmp r1, r2 //(都是链接地址)只要没到bss起始段 就一直循环
bne copy_loop
clean_bss:
ldr r0, =bss_start
ldr r1, =bss_end
cmp r0,r1
beq run_on_dram //如果r0和r1相等,说明bss段为空 不需清空
clean_loop:
mov r2,#0
str r2, [r0],#4
cmp r0, r1
bne clean_loop
run_on_dram:
//重定位完成,长跳转到main
ldr pc, =main
//开始用C写程序 bl cfunction
//bl main //bl实现短跳转c语言函数
b . //死循环