链接脚本(编译链接使用,改变数据运行地址)
1、nor flash为自读存储器,虽然可以在上面直接运行代码,但是变量由于自读,其值不可改变,需要将其搬运到SDRAM上运行。
2、在-Tdata段,0x30000000数据段变量的存储地址,但是这样做会使得生成的bin文件十分庞大,因为在代码段和数据段之间有很多空白区域。(data包含静态初始化的数据,所以有初值的全局变量和static变量在data区)
all:
arm-linux-gcc -c -o led.o led.c
arm-linux-gcc -c -o uart.o uart.c
arm-linux-gcc -c -o init.o init.c
arm-linux-gcc -c -o main.o main.c
arm-linux-gcc -c -o start.o start.S
arm-linux-ld -Ttext 0 -Tdata 0x30000000 start.o led.o uart.o init.o main.o -o sdram.elf
arm-linux-objcopy -O binary -S sdram.elf sdram.bin
arm-linux-objdump -D sdram.elf > sdram.dis
clean:
rm *.bin *.o *.elf *.dis3、所以需要引入链接脚本 sdram.lds,将数据地址重新定位,复制到SDRAM中,在SDRAM中才可进行数据修改。
all:
arm-linux-gcc -c -o led.o led.c
arm-linux-gcc -c -o uart.o uart.c
arm-linux-gcc -c -o init.o init.c
arm-linux-gcc -c -o main.o main.c
arm-linux-gcc -c -o start.o start.S
arm-linux-ld -T sdram.lds start.o led.o uart.o init.o main.o -o sdram.elf
arm-linux-objcopy -O binary -S sdram.elf sdram.bin
arm-linux-objdump -D sdram.elf > sdram.dis
clean:
rm *.bin *.o *.elf *.dis4、引入的 sdram.lds 即为链接脚本,其格式如下:
SECTIONS {
.text 0 : { *(.text) } ;代码段地址0
.rodata : { *(.rodata) } ;自读数据段,接着.text存放
.data 0x30000000 : AT(0x800) ;运行地址0x30000000, 数据加载地址0x800(在bin文件中的地址)
{
data_load_addr = LOADADDR(.data); ;赋值数据加载地址
data_start = . ;
*(.data)
data_end = . ;
}
bss_start = .;
.bss : { *(.bss) *(.COMMON) } ;bss段,接着.data 0x3xxxxxxx存放
bss_end = .;
}
未加AT()时,运行地址与数据加载地址相同;
5、 在start.S文件中写上重定位data段的代码
ldr r1, =data_load_addr /* data段在bin文件中的地址, 加载地址 */
ldr r2, =data_start /* data段在重定位地址, 运行时的地址 */
ldr r3, =data_end /* data段结束地址 */
cpy:
ldrb r4, [r1] /* 把bin文件中的数据放入r4 */
strb r4, [r2] /* 把r4的值放入data_start(sdram中运行地址)地址 */
add r1, r1, #1 /* 以下为循环执行拷贝,直到r2(data_start)=r3(data_end),停止拷贝 */
add r2, r2, #1
cmp r2, r3
bne cpy /* 不相等则循环cpy */6、bss段存放程序中未初始化的或者初始化为0的全局变量和静态变量的一块内存区域;在start.S文件中写上清除bss段数据的代码,不然该空间可能会有其他值;
/* 清除BSS段 */
ldr r1, =bss_start
ldr r2, =bss_end
mov r3, #0 /* 对应地址清零 */
clean:
strb r3, [r1]
add r1, r1, #1
cmp r1, r2
bne clean