通过前面的学习,我们知道,把可执行程序从一个位置复制到另一个位置的过程叫做重定位。

现在有两种方式,第一种是只重定位data段到内存(sdram),为什么需要重定位?因为有些flash的写操作,不是简单地内存访问,通常我们使用sdram这个介质作为程序运行的载体。但是只重定位data段这种方式存在弊端。第一,我们的调试工具通常不支持这种分体形式(比如我们的之前的代码在0地址开始存放text和rodata段,而在间隔很远处sdram 0x30000000存放data段,这就是分体的形式)的代码;第二,这种分体方式需要能够直接运行程序的flash比如nor flash才可以工作,但是有些板子根本连nor flash都没有,那么只能通过第二种方式进行开发了。

代码重定位和位置无关码——运行于nor flash

第二种方式是把整个程序都复制到内存(sdram),这种方式所有数据都是紧挨着的,以后我们都使用这种方式。

现在思考一个问题,关于第二种方式,我们的bin文件是由连接脚本指定了运行地址为sdram(0x30000000)的,但是这个bin文件我们烧写在nor flash,是从0地址开始运行的,那么在nor flash上的代码就需要把整个bin文件拷贝到sdram中去,这就是重定位,但这就要求我们必须做到,在重定位之前的代码必须是位置无关码。(连接脚本指定我们程序的运行地址为0x30000000,为什么我们的在nor flash上的代码从0地址开始运行也能工作?这就是建立在我们这部分代码必须是位置无关码的基础上的,0地址处运行和0x30000000处运行达到同样效果,需要我们保证,在重定位之前,也就是复制操作没有完成之前的代码,必须是位置无关的)。

现在修改我们之前的连接脚本和启动文件:

 

SECTIONS
{
    . = 0x30000000;

    . = ALIGN(4);
    .text      :
    {
      *(.text)
    }

    . = ALIGN(4);
    .rodata : { *(.rodata) }

    . = ALIGN(4);
    .data : { *(.data) }

    . = ALIGN(4);
    __bss_start = .;
    .bss : { *(.bss) *(.COMMON) }
    _end = .;
}

上面是连接脚本,我想此时应该都不需要备注了吧,基本语法。表示0x30000000处是我们的运行地址。

更改启动文件:

 

    /* 重定位text, rodata, data段整个程序 */
    mov r1, #0
    ldr r2, =_start         /* 第1条指令运行时的地址 */
    ldr r3, =__bss_start    /* bss段的起始地址 */

 

其中标号_start为启动文件的最开始处的标号,完整启动文件如下:

 1 .text
 2 .global _start
 3 
 4 _start:
 5 
 6     /* 关闭看门狗 */
 7     ldr r0, =0x53000000
 8     ldr r1, =0
 9     str r1, [r0]
10 
11     /* 设置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */
12     /* LOCKTIME(0x4C000000) = 0xFFFFFFFF */
13     ldr r0, =0x4C000000
14     ldr r1, =0xFFFFFFFF
15     str r1, [r0]
16 
17     /* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8  */
18     ldr r0, =0x4C000014
19     ldr r1, =0x5
20     str r1, [r0]
21 
22     /* 设置CPU工作于异步模式 */
23     mrc p15,0,r0,c1,c0,0
24     orr r0,r0,#0xc0000000   //R1_nF:OR:R1_iA
25     mcr p15,0,r0,c1,c0,0
26 
27     /* 设置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0) 
28      *  m = MDIV+8 = 92+8=100
29      *  p = PDIV+2 = 1+2 = 3
30      *  s = SDIV = 1
31      *  FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M
32      */
33     ldr r0, =0x4C000004
34     ldr r1, =(92<<12)|(1<<4)|(1<<0)
35     str r1, [r0]
36 
37     /* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定
38      * 然后CPU工作于新的频率FCLK
39      */
40     
41     
42 
43     /* 设置内存: sp 栈 */
44     /* 分辨是nor/nand启动
45      * 写0到0地址, 再读出来
46      * 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动
47      * 否则就是nor启动
48      */
49     mov r1, #0
50     ldr r0, [r1] /* 读出原来的值备份 */
51     str r1, [r1] /* 0->[0] */ 
52     ldr r2, [r1] /* r2=[0] */
53     cmp r1, r2   /* r1==r2? 如果相等表示是NAND启动 */
54     ldr sp, =0x40000000+4096 /* 先假设是nor启动 */
55     moveq sp, #4096  /* nand启动 */
56     streq r0, [r1]   /* 恢复原来的值 */
57 
58     bl sdram_init    
59 
60     # /* 重定位data段 */
61     # ldr r1, =data_load_add  /* data段在bin文件中的地址, 加载地址 */
62     # ldr r2, =data_start      /* data段在重定位地址, 运行时的地址 */
63     # ldr r3, =data_end          /* data段结束地址 */
64     /* 重定位text, rodata, data段整个程序 */
65     mov r1, #0
66     ldr r2, =_start         /* 第1条指令运行时的地址 */
67     ldr r3, =__bss_start    /* bss段的起始地址 */
68 cpy:
69     ldr r4, [r1]
70     str r4, [r2]
71     add r1, r1, #4
72     add r2, r2, #4
73     cmp r2, r3
74     bcc cpy
75 
76 
77     /* 清除BSS段 */
78     ldr r1, =__bss_start
79     ldr r2, =_end
80     mov r3, #0
81 clean:
82     str r3, [r1]
83     add r1, r1, #4
84     cmp r1, r2
85     bcc clean
86 
87     bl main
88 
89 halt:
90     b halt
91     
View Code

相关文章:

  • 2021-06-11
  • 2021-11-16
  • 2021-06-03
  • 2022-12-23
猜你喜欢
  • 2021-09-16
  • 2022-12-23
  • 2022-01-21
  • 2021-10-02
  • 2022-12-23
  • 2021-09-23
  • 2021-10-27
相关资源
相似解决方案