3.bss段 : 初始值为0 / 无初始值的全局静态变量
链接选项-Ttext 0 :
这个链接选项表示程序的代码段从0开始运行,数据段,bss段依次向后排列。
除了上面指定各个段存放位置的方法,还可以使用另外一种方法:使用链接脚本 -T leds.lds,这个链接脚本决定了各个段如何排列。
例如下面的脚本就是链接脚本的格式:
SECTIONS { . = 0x50000000; /*设置当前地址*/ .text : { /*代码段*/ start.o * (.text) } .data : { /*数据段*/ * (.data) } bss_start = .; /*bss段*/ .bss : { * (.bss) } bss_end = .; }引入bss_start,bss_end的原因是:编译出来的二进制文件led.bin是没有bss段( 初始值为0或未初始化的全局静态变量)的。用这两个变量来给bss段清0.
如何分析反汇编文件?
先给出例子:
00000000 <_start>: 0: e3a00207 mov r0, #1879048192 ; 0x70000000 4: e3800013 orr r0, r0, #19 8: ee0f0f92 mcr 15, 0, r0, cr15, cr2, {4} c: e59f0014 ldr r0, [pc, #20] ; 28 <halt+0x4> 10: e3a01000 mov r1, #0 14: e5801000 str r1, [r0] 18: e3a0db06 mov sp, #6144 ; 0x1800 1c: eb000047 bl 140 <clock_init> 20: eb000008 bl 48 <main>第一列:地址
1.当链接地址为0,变量i的地址为0x100。
2.当链接地址为0x50000000,变量i的地址为0x50000100。
所以说,当链接地址不一样的话,程序访问变量的地址是不一样的。(可以实验,将链接地址改为500000000的话,DDR还没有初始化,程序就会崩溃,使用openocd的现象是无法进行halt,因为跳转到了链接地址,而DDR没有初始化。)
实验代码:
#define CONFIG_PERIPORT_BASE 0x70000000 #define CONFIG_PERIPORT_SIZE 0x13 #define WTCON 0x7E004000 #define GPMCON 0x7F008820 #define GPMDAT 0x7F008824 .global _start _start: /*告诉CPU 外设的地址*/ ldr r0, =CONFIG_PERIPORT_BASE orr r0, r0, #CONFIG_PERIPORT_SIZE mcr p15,0,r0,c15,c2,4 /*关闭看门狗*/ ldr r0, =WTCON mov r1, #1 str r1,[r0] /*点灯nLED1 <==> GPM0*/ /*GPMCON 0x7F008820 **GPMDAT 0x7F008824 */ /*设置GPM0为输出引脚*/ ldr r0, =GPMCON mov r1, #0x1 str r1, [r0] bl test /* ldr pc, =test */ halt: b halt test: /*设置GPM0的电平输出为低,点亮*/ ldr r0, =GPMDAT mov r1, #0 str r1, [r0] mov pc, lrbl test的跳转:
如果设置的链接地址为0x50000000,那么这个程序运行的地址也“应该”是0x50000000.但是硬件决定了如果从nand启动的话,首先运行的地址还是片内内存,因为一上电,6410 CPU 会将nandflash中的前8K内容源源本本的拷贝到6410的片内内存上去运行。那么如果想要程序在链接地址50000000上取运行,那么拷贝到片内内存上的程序需要做重定位操作。
在重定位之前的代码可以运行的原因是使用了位置无关码。
位置无关码:
1.在跳转的时候使用相对跳转指令:b bl
2.不妨问全局变量,不访问静态变量