SECTIONS{
secname(段名) start(起始地址/运行地址/重定位地址): AT(lddr)(lddr加载地址)(不写时运行地址等于加载地址)
{
contents(内容)+
}
}
例子
SECTIONS{
.text 0:{*(.text)}//运行地址等于加载地址所以不需要重定位执行代码段代码段的顺序就是makefile中的顺序(用于存放可执行的代码)
.rodata : {*(.rodata)}//const全局变量(,存放c中的字符串和#define定义的常量)
.data 0x30000000 : AT(0x000)//加载地址等于0x800运行地址等于0x30000000 导致(*(.data)段处于0x800的地址,(用于存放初始化的全局变量)
{ // 程序运行运行时需要将在0x800段的代码放在0x30000000地方(重定位)只是将数据段放在SDRAM中
. = ALIGN(4) ;
data_load_addr=LOADADDR(.data);
data_start=. ;//等于当前位置
*(.data)
data_end=. ;
}
. = ALIGN(4) ;// 代码以4字节对齐)
bss_start=. ;
.bss :{*(.bss) *(.COMMON)} //.bss段紧跟着0x300000000后面放置,bin/elf文件都不存bss段(未初始化的全局变量和未设置的全局变量)(comment:表示注释)
//如何清除bss段程序运行时把bss段的对应空间清除
bss_end=. ;
}
在启动文件中
//重定位段data段
ldr r1,= data_load_addr
ldr r2,= data_start
ldr r3,= data_end
cpy:
ldr r4,[r1]
str r4,[r2]
add r1,r1,#4
add r2.r2,#4
cmp r2,r3
bne cpy
//清除bss段
ldr r1,=bss_start//伪代码
ldr r2,=bss_end
mov r3,#0
clean:
str r3 ,[r1]
add r1,r1,#4
cmp r1, r2
bne clean
#例子
//把所有的代码段,数据段,bss段 放在SDRAM中
SECTIONS{
.=0X30000000;
.-ALIGN(4);
.text 0:{*(.text)}
.-ALIGN(4);
.rodata : {*(.rodata)}
.-ALIGN(4);
.data : { *(.data) }
. = ALIGN(4) ;// 代码以4字节对齐)
bss_start=. ;
.bss :{*(.bss) *(.COMMON)}
bss_end=. ;
}
//重定位代码
mov r1,#0
ldr r2,=_start
ldr r3,=bss_start
cpy:
ldr r4 ,[r1]
str r4, [r2]
add r1,r1,#4
add r2,r2,#4
cmp r2,r3
ble cpy
#mov 指令ldr指令 和ldr伪指令的区别
MOV指令可以把立即数或者寄存器内容(注意:这里绝对不可以是内存!!)传递给一个寄存器。
mov 立即数就是数字嘛,表示数值的数字,
mov r1 ,#0x30000000//伪指令意思就是把0x30000000这个地址给了寄存器r1
mov r1,=0x30000000 //意思就是把0x30000000地址的内容放到r1这个寄存器中
LDR指令(有等号的ldr指令是伪汇编指令)
ldr指令既可以是大范围的地址读取伪指令,也可以内存访问指令。当它的第二个参数前面有“=”时,表示伪指令,否则表示内存访问指令
ldr r1,=0x70000000 //伪指令就是读取0x70000000这个地址给了寄存器r1
ldr r0, 0x12345678 //就是把0x12345678这个地址中的值存放到r0中。
#
global_start @ 给_start外部链接属性
.section .text@ 指定当前段为代码段
.ascii(定义字符) .byte(字节) .short(2个字节) .long(4个字节) .word(4个字节)
.quad(8个字节) .float .string@定义数据
.align 4 @ (2的4次方)以16字节对齐(内存地址对齐)
.balignl 16,0xabcdefgh@ 对齐+填充-16字节对齐填充
b表示位填充;
align表示要对齐;
l表示long,以4字节为单位填充;
16表示16字节对齐;
0xabcdefgh是用来填充的原料
.equ @类似于C中宏定义
在汇编程序中我们会使用cmp指令进行判断,类似于流程框图中的选择判断框(菱形框),其后面可以跟bne和beq两种指令,具体看下边例子:
(1)例一:cmp同bne搭配
cmp r1,r2 //这个cmp搭配下边的bne指令构成了如果r1≠r2则执行bne指令,跳转到copy_loop函数处执行。否则,就跳过下边
bne copy_loop//的bne指令向下执行。
(2)例二:cmp同beq搭配
cmp r0,r1//如果r0=r1,就执行beq,跳转到clean_bss函数处执行,否则跳过beq向下执行。
beq clean_bss
(3)
ble cpy
E是你之前一条指令的判断结果,表示相等意思是,如果上一条判断指令结果为相等,那么执行BL指令,调用子程序
(3)总结:其实上边两句都是跳转指令,跳转到相关函数处执行。区别在于执行跳转的条件不同。
#怎么写位置无关的程序
使用位置无关码,不使用绝对地址,最根本的办法是看汇编
1使用相对跳转命令B/BL
2 重定位之前,不可使用绝对地址,比如:不可访问全局变量和静态变量,不可访问初始值的数组,(因为初始值放在rodata里使用绝对地址来访问)
3 重定位之后,使用ldr pc,=xxx//跳转到运行地址及SDRAM上运行/绝对地址跳转到SDRAM中