【说明】
前面我们对链接的过程没有进行控制,我们在makefile中直接指定链接地址从0开始,这是因为6410如果是nand启动会把nand 前4页,每页2KB复制到片内内存中,片内内存地址从0开始,这里0指的是物理地址,所以我们的链接地址就会等于物理地址,程序就可以在片内内存正常运行,这一节我们学习一下利用所谓的链接脚本对链接进行控制,其实即使是默认的链接过程也是依赖于链接脚本的,只是那个链接脚本是系统自带的,里面的内容是一般ELF风格的链接方法。
【为什么要用链接脚本】
使用链接脚本的原因是我们要指定我们程序的内存映像,比如,我们必须把start.S的代码放在最前面,其他的放在后面,又如我们想让链接地址不从0开始。
linux内核中也使用了链接脚本来控制链接过程,因为它要严格控制链接所生成的映像文件的格式,比如中断向量表应该放哪个位置,比如什么程序要放在前面等
我们用链接脚本来链接裸机程序显得有点杀鸡用牛刀,但是学习链接脚本对于以后理解操作系统非常有帮助。
【例子讲解】
一个简单的链接脚本例子
- SECTIONS
- {
- . = 0x50000000; /* 当前地址 */
- .text : {
- start.o
- * (.text)
- }
- .data : {
- * (.data)
- }
- bss_start = .;
- .bss : {
- * (.bss)
- }
- bss_end = .;
- }
1).= 0x50000000 意思是当前链接地址设置为0x50000000 由于在这条前面没有其他数据或者指令了,所以这条也意味着程序链接地址从 0x50000000开始
2).text代码括号内的是代码段,下面的.data .bss 也一样
3)括号里面的东西意思是各个目标文件中名字一样的那个段的数据,比如 .text括号内意思就是先放start.o 然后放所有其他目标文件的 .text段
编译的时候会在目标文件内写明text段的位置,所以链接器可以找到,下面的data括号内也一样的意思。
4)所有东西的链接地址都是从最开始,也就是那个0X50000000递增的,"." 就是代表当前的链接地址
5)所以bss_start = . 意思就是标号bss_start 等于当前链接地址,而当前链接地址是多少呢,这由上边放了多少东西决定,递增的嘛!bss_end =.同理
【更详细介绍】
1】语句
链接脚本由命令语句和赋值语句组成。
1)语句使用分号“;”作为分隔符
2)可以使用类似C的表达式比如 +, -, * ,/ ,<<等等
3)用/**/注释
2】命令语句
其实SECTION 也是命令语句只是它比较复杂而已,里面包含很多东西,所以下面这些应该在SECTION的花括号外边
1)ENTRY(symbol) 指明程序入口地址
2)STARTUP(filename) 将文件filename作为链接过程中的第一个输入文件
3)SEARCH_DIR(path) 将路径path 加入到链接器的库查找目录
4)INPUT(file , file ....) 将指定文件作为链接过程的输入文件
5)INCLUDE filename 将指定文件包含进本链接脚本
6)PROVIDE (symbol) 在链接脚本中定义某个符号
【使用了链接脚本的Makefile】
- led.bin: start.o led.o
- arm-linux-ld -T leds.lds -o led.elf start.o led.o
- arm-linux-objcopy -O binary led.elf led.bin
- arm-linux-objdump -D led.elf > led.dis
- start.o : start.S
- arm-linux-gcc -o start.o start.S -c
- led.o : led.c
- arm-linux-gcc -o led.o led.c -c
- clean:
- rm *.o led.elf led.bin led.dis -f