MDK 链接脚本 sct测试

main函数调用前

程序启动时就是在片内的RAM上面跑。显然,片内RAM不可能很大。所以在这里就需要增加片外的SDRAM。说来就内存。
但是片外内存不可能一开始就能跑程序的。一没初始化,二没有设置时间参数,CPU怎么可能知道片外SDRAM的访问(s3c2440 nand启动,是因为集成了一个nand IP内核,小。但是通吃所有Nand)。再者系统启动时的代码地址和运行地址不见得是一样。因此就会产生代码重定位了。怎么解决了?

main函数调用前做好前面这些就ok了。

调用__main之前的过程

以rt1052初始化为例子

//startup_MIMXRT1052.s
Reset_Handler:
    ...
    LDR     R0, =SystemInit
    BLX     R0
    ...
    LDR     R0, =__main
    BX      R0
    ...

显然是调用__main函数之前调用了SystemInit
查看链接脚本以及*.map文件。反汇编文件

*.map文件
__main                                   0x60002401   Thumb Code     0  entry.o(.ARM.Collect$$$$00000000)
    _main_stk                                0x60002401   Thumb Code     0  entry4.o(.ARM.Collect$$$$00000003)
    _main_scatterload                        0x60002405   Thumb Code     0  entry5.o(.ARM.Collect$$$$00000004)
    ...
    __scatterload                            0x60002861   Thumb Code    28  init.o(.text)
    __scatterload_rt2                        0x60002861   Thumb Code     0  init.o(.text)
    ...
    __scatterload_copy                       0x60004dc1   Thumb Code    14  handlers.o(i.__scatterload_copy)
    __scatterload_null                       0x60004dcf   Thumb Code     2  handlers.o(i.__scatterload_null)
    __scatterload_zeroinit                   0x60004dd1   Thumb Code    14  handlers.o(i.__scatterload_zeroinit)
连接脚本
//MIMXRT1052xxxxx_nor_txt_sdram.scf
#define m_text_start                   0x60002400
#define m_text_size                    0x03FFDC00

#define m_data_start                   0x80000000
#define m_data_size                    0x01E00000

LR_m_text m_interrupts_start m_text_start+m_text_size-m_interrupts_size {   ; load region size_region
  ...
  ER_m_text m_text_start m_text_size { ; load address = execution address
    * (InRoot$$Sections)
    .ANY (+RO)
  }

 ...
}
汇编文件
** Section #4 'ER_m_text' (SHT_PROGBITS) [SHF_ALLOC + SHF_EXECINSTR]
    ...
    __main
    _main_stk
    0x60002400:    f8dfd00c    ....    LDR      sp,__lit__00000000 ; [0x60002410] = 0x20020000
    _main_scatterload
    0x60002404:    f000fa2c    ..,.    BL       __scatterload ; 0x60002860

可以看到 __main地址为0x60002400。置放在ER_m_text 节区的。然后在汇编文件中可以看,
_main_stk设置好SP指针。跳转到__scatterload

有关__scatterload详细内容。在这里看,不细说。
__scatterload 会将FLASH中的RW-data复制到RAM中。

  • __scatterload此时在ER_m_text节区。

怎么进行重定位的

__scatterload
        0x60002860:    4c06        .L      LDR      r4,[pc,#24] ; [0x6000287c] = 0x60005210
        0x60002862:    4d07        .M      LDR      r5,[pc,#28] ; [0x60002880] = 0x60005230
        ...
        0x60002866:    68e0        .h      LDR      r0,[r4,#0xc]
        0x60002868:    f0400301    @...    ORR      r3,r0,#1
        0x6000286c:    e8940007    ....    LDM      r4,{r0-r2}
        0x60002870:    4798        .G      BLX      r3
        0x60002872:    3410        .4      ADDS     r4,r4,#0x10
        ...
        0x60002876:    d3f6        ..      BCC      0x60002866 ; __scatterload + 6

        ...
        0x6000521c:    60004dc0    .M.`    DCD    1610632640
        ...
0x60002870:    4798        .G      BLX      r3 // r3 = r0 = LDR      r0,[r4,#0xc] = [0x60005210,0xc] = [0x6000521c] = 0x60004dc0    
        /*在这里 跳转到0x60004dc0 地址 ,恰好是 __scatterload_copy 的地址*/

在这调用了__scatterload_copy以及__scatterload_zeroinit。进行了代码的重定位以及清零操作。

SDRAM的初始化

既然前面已经进行讨论了数据的重定位。但是重定位的地址是在0x80000000(自己配置的)。就算是跳转过去了也不能读写的。所以在跳转之前就需要初始化外部SDRAM。

因此 再调用__main之前先调用Sdram_init_persion();记得使用位置无关码。以及将Sdram_init_persion的程序段和scatter_copy段放在一起。

参考资料

MDK的编译过程及文件类型全解 https://flash-rtd.readthedocs.io/zh_CN/latest/
STM32 _main 里做了什么  http://elmagnifico.me/2017/04/01/STM32-Startup-_main/
STM32启动过程--启动文件--分析 https://www.cnblogs.com/amanlikethis/p/3719529.html

相关推荐