SECTIONS { ... secname start BLOCK(align) (NOLOAD) : AT ( ldadr ) { contents } >region :phdr =fill ... } |
secname和contents是必须的,其他的都是可选的。下面挑几个常用的看看:
/* nand.lds */ SECTIONS { firtst 0x00000000 : { head.o init.o } second 0x30000000 : AT(4096) { main.o } } |
arm-linux-ld –Tnand.lds x.o y.o –o xy.o。也用-Ttext参数直接指定连接地址,如
arm-linux-ld –Ttext 0x30000000 x.o y.o –o xy.o。
relocate: /* 把U-Boot重新定位到RAM */ adr r0, _start /* r0是代码的当前位置 */ /* adr伪指令,汇编器自动通过当前PC的值算出 如果执行到_start时PC的值,放到r0中: 当此段在flash中执行时r0 = _start = 0;当此段在RAM中执行时_start = _TEXT_BASE(在board/smdk2410/config.mk中指定的值为0x33F80000,即u-boot在把代码拷贝到RAM中去执行的代码段的开始) */ ldr r1, _TEXT_BASE /* 测试判断是从Flash启动,还是RAM */ /* 此句执行的结果r1始终是0x33FF80000,因为此值是又编译器指定的(ads中设置,或-D设置编译器参数) */ cmp r0, r1 /* 比较r0和r1,调试的时候不要执行重定位 */ |
;指定输出可执行文件是elf格式,32位ARM指令,小端
OUTPUT_ARCH(arm)
;指定输出可执行文件的平台为ARM
ENTRY(_start)
;指定输出可执行文件的起始代码段为_start.
SECTIONS
{
. = 0x00000000 ; 从0x0位置开始
. = ALIGN(4) ; 代码以4字节对齐
.text : ;指定代码段
{
cpu/arm920t/start.o (.text) ; 代码的第一个代码部分
*(.text) ;其它代码部分
}
. = ALIGN(4)
.rodata : { *(.rodata) } ;指定只读数据段
. = ALIGN(4);
.data : { *(.data) } ;指定读/写数据段
. = ALIGN(4);
.got : { *(.got) } ;指定got段, got段式是uboot自定义的一个段, 非标准段
__u_boot_cmd_start = . ;把__u_boot_cmd_start赋值为当前位置, 即起始位置
.u_boot_cmd : { *(.u_boot_cmd) } ;指定u_boot_cmd段, uboot把所有的uboot命令放在该段.
__u_boot_cmd_end = .;把__u_boot_cmd_end赋值为当前位置,即结束位置
. = ALIGN(4);
__bss_start = .; 把__bss_start赋值为当前位置,即bss段的开始位置
.bss : { *(.bss) }; 指定bss段
_end = .; 把_end赋值为当前位置,即bss段的结束位置
}
88888888**********************************
r与adr的区别
转自:http://coon.blogbus.com/logs/2738861.html
ldr r0, _start
adr r0, _start
ldr r0, =_start
nop
mov pc, lr
_start:
nop
编译的时候设置 RO 为 0x0c008000
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
0c008000 <_start-0x14>:
c008000: e59f000c ldr r0, [pc, #12] ; c008014 <_start>
c008004: e28f0008 add r0, pc, #8 ; 0x8
c008008: e59f0008 ldr r0, [pc, #8] ; c008018 <_start+0x4>
c00800c: e1a00000 nop (mov r0,r0)
c008010: e1a0f00e mov pc, lr
0c008014 <_start>:
c008014: e1a00000 nop (mov r0,r0)
c008018: 0c008014 stceq 0, cr8, [r0], -#80
分析:
ldr r0, _start
从内存地址 _start 的地方把值读入。执行这个后,r0 = 0xe1a00000
adr r0, _start
取得 _start 的地址到 r0,但是请看反编译的结果,它是与位置无关的。其实取得的时相对的位置。例如这段代码在 0x0c008000 运行,那么 adr r0, _start 得到 r0 = 0x0c008014;如果在地址 0 运行,就是 0x00000014 了。
ldr r0, =_start
这个取得标号 _start 的绝对地址。这个绝对地址是在 link 的时候确定的。看上去这只是一个指令,但是它要占用 2 个 32bit 的空间,一条是指令,另一条是 _start 的数据(因为在编译的时候不能确定 _start 的值,而且也不能用 mov 指令来给 r0 赋一个 32bit 的常量,所以需要多出一个空间存放 _start 的真正数据,在这里就是 0x0c008014)。
因此可以看出,这个是绝对的寻址,不管这段代码在什么地方运行,它的结果都是 r0 = 0x0c008014