代码重定位

Posted shwzh1990

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了代码重定位相关的知识,希望对你有一定的参考价值。

S2C2440当上电的时候会自动的把nor 或者nandflash的前4k字节拷贝到自己的ram中,可是如果当整个程序大于4k的时候怎么办?

 

代码重定义的方针就是把nor 或者是nandflash里面的代码通通的拷贝到SDRAM中去,然后所有的程序会从SDRAM里面去运行。

首先是写出脚本文件其格式如下:

SECTIONS
{
    . = 0x30000000;                         //表示重定位的地址是在SDRAM的最初地址

    __code_start = .;                      //把当前的地址给到__code_start 变量

    . = ALIGN(4);                          //四字节对齐
    .text      :                                //之后放置。text段
    {
      *(.text)
    }

    . = ALIGN(4);                          //四字节对齐
    .rodata : { *(.rodata) }            //放置只读数据段

    . = ALIGN(4);
    .data : { *(.data) }                //放置数据段

    . = ALIGN(4);
    __bss_start = .;                     //放置。bss数据段和common段
    .bss : { *(.bss) *(.COMMON) }
    _end = .;
}

 

这个脚本文件会指定分配和指定数据段的位置。然后这个脚本文件会在make里面被调用 其格式如下:

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-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
    
arm-linux-ld -T sdram.lds start.o led.o uart.o init.o main.o -o sdram.elf
其中这一行就是 arm 编译器会连接sdram.lds 分配各种数据段的位置。后面的文件顺序是有规定的,越靠近前面的越先被编译,有更大的几率会编译进前4k。

在start.S 中,我们需要用C语言把数据写入SDRAM 而且需要把.BSS 段清零。
 1     ldr r0, [r1] /* 读出原来的值备份 */
 2     str r1, [r1] /* 0->[0] */ 
 3     ldr r2, [r1] /* r2=[0] */
 4     cmp r1, r2   /* r1==r2? 如果相等表示是NAND启动 */
 5     ldr sp, =0x40000000+4096 /* 先假设是nor启动 */
 6     moveq sp, #4096  /* nand启动 */
 7     streq r0, [r1]   /* 恢复原来的值 */
 8 
 9     bl sdram_init
10     //bl sdram_init2     /* 用到有初始值的数组, 不是位置无关码 */
11 
12     /* 重定位text, rodata, data段整个程序 */
13     bl copy2sdram
14 
15     /* 清除BSS段 */
16     bl clean_bss
17 
18     //bl main  /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */
19     ldr pc, =main  /* 绝对跳转, 跳到SDRAM */

其中第十三行和第十6行分别是调用了两个函数用来重定位

text, rodata, data段整个程序 和 清除.bss 段。

这两个函数的代码如下:
 1 void copy2sdram(void)
 2 {
 3     /* 要从lds文件中获得 __code_start, __bss_start
 4      * 然后从0地址把数据复制到__code_start
 5      */
 6 
 7     extern int __code_start, __bss_start;
 8 
 9     volatile unsigned int *dest = (volatile unsigned int *)&__code_start;
10     volatile unsigned int *end = (volatile unsigned int *)&__bss_start;
11     volatile unsigned int *src = (volatile unsigned int *)0;
12 
13     while (dest < end)
14     {
15         *dest++ = *src++;
16     }
17 }
18 
19 
20 void clean_bss(void)
21 {
22     /* 要从lds文件中获得 __bss_start, _end
23      */
24     extern int _end, __bss_start;
25 
26     volatile unsigned int *start = (volatile unsigned int *)&__bss_start;
27     volatile unsigned int *end = (volatile unsigned int *)&_end;
28 
29 
30     while (start <= end)
31     {
32         *start++ = 0;
33     }
34 }

第九道十一行

 9     volatile unsigned int *dest = (volatile unsigned int *)&__code_start;
10     volatile unsigned int *end = (volatile unsigned int *)&__bss_start;
11     volatile unsigned int *src = (volatile unsigned int *)0;
后面的那几个变量都是从脚本文件获得而来,其中的思路就是我们确定了代码的初始地址和代码段的结束的地址,然后我们从0地址(就是norflash基地址 或者是nandflash自动拷贝4k到内存的基地址)拷贝所有的内容进入指定的内存的地址上面(就是SDRAM的基地址)

后面的26 到 33行决定了我们应该清楚.bss 段 把所有的变量都清零。 我们要注意只有elf文件是带有没有初始化的全局变量,而bin文件是不带这些变量的。


以上是关于代码重定位的主要内容,如果未能解决你的问题,请参考以下文章

代码重定位

CSS代码片段

CSS代码片段

代码重定位和位置无关码

代码重定位(韦东山)

代码重定位