s3c2440 bare - relocations (2 programming relocations)

Relocations (2 programming relocations)

1. incoming links script

Our last one describes why relocatable code, relocatable code then how to do?

We found that on an "arm-linux-ld -Ttext 0 -Tdata 0x30000000" compiled in such a way bin file has more than 800 M, which certainly does not work, you need to how to .data segment relocated to sdram it?

You can specify the storage location .data segment at compile time by AT parameters, we found that this is specified too inconvenient and unpleasant determine which position to put bin file. Here we must incoming links script that can help us solve this unnecessary trouble.

Link script format

FIG format:

Let's look at a concrete example:

SECTIONS
{
    . = 0x00000000; //表示当前地址为0

    . = ALIGN(4);  //设置当前位置让4字节对齐
    .text  :   
    {
      cpu/arm920t/start.o   (.text)
      board/lyb2440/boot_init.o (.text)
      *(.text)
    }   //表示.text段从0x4开始存放,其中可以手动调整代码段的位置,
        //比如让start.o,boot_init.o中的函数放在最前面,然后存放剩余的代码段

    . = ALIGN(4); //设置当前位置让4字节对齐
    .rodata : { *(.rodata) } //从该位置开始存放所有的.rodata段

    . = ALIGN(4); //设置当前位置让4字节对齐
    .data : 0x30000000 : AT(0x800) { *(.data) } //从该位置开始存放所有的.data段 设置运行

    __bss_start = .; //设置.bss段的起始位置
    .bss : { *(.bss) } //从该位置开始存放所有的.bss段
    _end = .;//设置.bss段的结束位置(也就是整个链接脚本的结束为止)
}

This is my cut from uboot over the link in the script, the script from the comments I've put a link to explain the structure of the same subject. Here .data section defines the program run (link) address base_addr sdram of (0x30000000) , by designated AT loaded (stored in the bin file) address 0x800 .

2. How relocatable code

Let's write a linker script as shown below:

SECTIONS {
   .text   0  : { *(.text) }
   .rodata  : { *(.rodata) }
   .data 0x30000000 : AT(0x800) { *(.data) }
   .bss  : { *(.bss) *(.COMMON) }
}

We can not be analyzed on a write global variables nor start, so now there are two relocation method:

  1. Re-positioning data segment only

    Process re-positioning data segment only by the following FIG more intuitive:

    Nor respect to the start, we can take nor directly from the instruction execution, can be performed only relocated data segment, we write a script relocate.lds link as follows:

     SECTIONS {
        .text   0  : { *(.text) }//所有文件的.text
        .rodata  : { *(.rodata) } //只读数据段
        .data 0x30000000 : AT(0x800) { *(.data) } //放在0x800,但运行时在0x3000000
        .bss  : { *(.bss) *(.COMMON) }//所有文件的bss段,所有文件的.COMMON段
     }

    Makefile as follows:

     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

    Compile sdram.bin, then modify start.s relocate .data segment. We will need the entire data segment 0x800 .data segment base address to the copy to 0x30000000, start.s modified as follows:

     .text
     .global _start
    
     _start:
    
         /* 关闭看门狗 */
         /* 初始化时钟 */
         /* 设置栈 */
         /*初始化sdram*/
     ...
         /* 重定位data段,把加载地址0x800(bin文件中在nor中)的数据段的内容重定位到sdram的baseaddr */
         mov r1, #0x800
         ldr r0, [r1]
         mov r1, #0x30000000
         str r0, [r1]
    
         bl main
    
     halt:
         b halt

    这里是用的相对跳转指令bl main,因为还没有重定位整个完整的代码,所以不能用ldr绝对跳转。前面的初始化时钟、sdram我就不写了,参考
    时钟编程(二、配置时钟寄存器)
    (三、UART编程实现)
    内存控制器(五、SDRAM编程实现)

    缺点:
    这里只是人为的对.data段写死了,那么当我有多个全局变量时,还要计算重定位的次数,而且我们也不知道有多少个全局变量,所以这重定位方式有缺陷。那么我们对这种重定位.data断的方法做一个改进,将链接脚本修改如下:

     SECTIONS
     {
        .text   0  : { *(.text) }
        .rodata  : { *(.rodata) }
        .data 0x30000000 : AT(0x800) 
        { 
           data_load_addr = LOADADDR(.data); /* data段在bin文件中的地址, 加载地址 */
           data_start = . ;          /* data段在重定位地址, 运行时的地址 */
           *(.data)              
           data_end = . ;            /* data段结束地址 */
        }
        .bss  : { *(.bss) *(.COMMON) }
     }

    上面的链接脚本用一个变量data_load_addr指定了加载地址(data段在bin文件中的地址,即0x800),用变量data_start指定了运行地址(即为0x30000000),那么用data_end - data_start就是我们数据段的总长度。

    对start.s做出如下修改:

         /* 重定位data段 */
         ldr r1, =data_load_addr  /* data段在bin文件中的地址, 加载地址 */
         ldr r2, =data_start      /* data段在重定位地址, 运行时的地址 */
         ldr r3, =data_end        /* data段结束地址 */
    
     cpy:
         ldrb r4, [r1]
         strb r4, [r2]
         add r1, r1, #1
         add r2, r2, #1
         cmp r2, r3
         ble cpy
    
         bl main
    
     halt:
         b halt

    注意,这里start.s中用到了链接脚本中的变量,r4作为临时变量,依次从data_load_addr读取出来后写入到data_start。

    优点:可以不用计算有多少个全局变量,链接脚本自动帮我们弄好了。
    缺点:由于我们的程序可能会大于SRAM或者nor的容量,那么就必须连代码段也一起进行重定位,
    下面这种重定位方式更好,在实际应用中也是用的下面这种方式去做的重定位。

  2. 重定位整个程序

    重定位整个程序的过程用下图更直观:

    我们修改链接脚本如下:

     SECTIONS
     {
         . = 0x30000000;
    
         . = ALIGN(4);
         .text      :
         {
           *(.text)
         }
    
         . = ALIGN(4);
         .rodata : { *(.rodata) }
    
         . = ALIGN(4);
         .data : { *(.data) }
    
         . = ALIGN(4);
         __bss_start = .;
         .bss : { *(.bss) *(.COMMON) }
         _end = .;
     }

    在这里我们将代码段的地址设置为0x3000_0004,然后紧接着放.rodata段,然后再紧接着放.data段。这样我们的bin文件就不再有“空洞”了。

    修改start.s如下:

     .text
     .global _start
    
     _start:
         ...
         ...
         /* 重定位text, rodata, data段整个程序 */
         mov r1, #0
         ldr r2, =_start         /* 第1条指令运行时的地址,也就是.text段的runtime addr,在这里是0x3000_0004*/
         ldr r3, =__bss_start    /* bss段的起始地址,也就是整个程序的结束地址  */
    
     cpy:
         ldrb r4, [r1]
         strb r4, [r2]
         add r1, r1, #1
         add r2, r2, #1
         cmp r2, r3
         ble cpy
    
         bl main     
     halt:
         b halt

    我们来分析下这段重定位:整个bin文件程序的长度(.text + .rodata + .data)为__bss_start - _start,那么我们是把bin文件从存储介质的0地址copy到程序的运行地址0x3000_0004,这样我们访问.data段时就是访问sdram中重定位后的数据段了。

Guess you like

Origin www.cnblogs.com/fuzidage/p/12043586.html