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 *.dis

3、所以需要引入链接脚本 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 *.dis

4、引入的 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