链接脚本(Linker Script)应用实例(一)使用copy table将函数载入到RAM中运行
将函数载入到RAM中运行需要以下三个步骤:
(1)用编译器命令#pragma section "<section name>" <user functions> #pragma section 将想要载入RAM运行的函数存储为自定义段名的程序段,其中ax是#pragma section命令中的可选设置——<flags>,a表示allocatable,x表示executable,具体
#pragma section ".flash_driver" ax void PFlashProgram( uint32 flash, uint32 addr, uint32 word_l, uint32 word_u ) { uint32 load_cnt; uint16 endinitSfty_pw = IfxScuWdt_getSafetyWatchdogPasswordInline(); IfxFlash_enterPageMode(addr); /* wait until unbusy */ IfxFlash_waitUnbusy(flash, IfxFlash_FlashType_P0); /* write 32 bytes (8 doublewords) into assembly buffer */ for (load_cnt = 0; load_cnt < 4; load_cnt++) { IfxFlash_loadPage2X32(addr, word_l, word_u); } /* write page */ IfxScuWdt_clearSafetyEndinitInline(endinitSfty_pw); IfxFlash_writePage(addr); IfxScuWdt_setSafetyEndinitInline(endinitSfty_pw); /* wait until unbusy */ IfxFlash_waitUnbusy(flash, IfxFlash_FlashType_P0); } #pragma section
(2)在链接脚本中,以自定义的程序段为输入,定义输出段output section:
/* user defined output section, used to allocate ram space(VMA) for code running in ram, */ /* and also allocate rom space(LMA) to store it */ .code2ram : { *(.flash_driver) *(.flash_driver.*) . = ALIGN(8); } > psram_local AT> pfls0 =0
(3)将该输出段.code2ram的LMA、VMA和SIZE等信息加入到copy table中,以使CPU启动时将该段(函数)从ROM拷贝到RAM中(从而正常运行)。这里贴出相关的上下文以便于读者的整体理解
(注:这里有一个VMA和LMA概念的问题,会在之前的博文——链接脚本(linker script)用法解析(一)中讲解)
/* user defined output section, used to allocate ram space(VMA) for code running in ram, */ /* and also allocate rom space(LMA) to store it */ .code2ram : { *(.flash_driver) *(.flash_driver.*) . = ALIGN(8); } > psram_local AT> pfls0 =0 .rodata : FLAGS(arl) { *(.rodata) *(.rodata.*) *(.gnu.linkonce.r.*) /* * Create the clear and copy tables that tell the startup code * which memory areas to clear and to copy, respectively. */ . = ALIGN(16) ; PROVIDE(__clear_table = .) ; LONG(0 + ADDR(.CPU2.zbss)); LONG(SIZEOF(.CPU2.zbss)); LONG(0 + ADDR(.CPU2.bss)); LONG(SIZEOF(.CPU2.bss)); LONG(0 + ADDR(.CPU1.zbss)); LONG(SIZEOF(.CPU1.zbss)); LONG(0 + ADDR(.CPU1.bss)); LONG(SIZEOF(.CPU1.bss)); LONG(0 + ADDR(.CPU0.zbss)); LONG(SIZEOF(.CPU0.zbss)); LONG(0 + ADDR(.CPU0.bss)); LONG(SIZEOF(.CPU0.bss)); LONG(0 + ADDR(.zbss)); LONG(SIZEOF(.zbss)); LONG(0 + ADDR(.sbss)); LONG(SIZEOF(.sbss)); LONG(0 + ADDR(.bss)); LONG(SIZEOF(.bss)); LONG(0 + ADDR(.sbss4)); LONG(SIZEOF(.sbss4)); LONG(-1); LONG(-1); PROVIDE(__copy_table = .) ; LONG(LOADADDR(.CPU2.zdata)); LONG(0 + ADDR(.CPU2.zdata)); LONG(SIZEOF(.CPU2.zdata)); LONG(LOADADDR(.CPU2.data)); LONG(0 + ADDR(.CPU2.data)); LONG(SIZEOF(.CPU2.data)); LONG(LOADADDR(.CPU1.zdata)); LONG(0 + ADDR(.CPU1.zdata)); LONG(SIZEOF(.CPU1.zdata)); LONG(LOADADDR(.CPU1.data)); LONG(0 + ADDR(.CPU1.data)); LONG(SIZEOF(.CPU1.data)); LONG(LOADADDR(.CPU0.zdata)); LONG(0 + ADDR(.CPU0.zdata)); LONG(SIZEOF(.CPU0.zdata)); LONG(LOADADDR(.CPU0.data)); LONG(0 + ADDR(.CPU0.data)); LONG(SIZEOF(.CPU0.data)); LONG(LOADADDR(.zdata)); LONG(0 + ADDR(.zdata)); LONG(SIZEOF(.zdata)); LONG(LOADADDR(.sdata)); LONG(0 + ADDR(.sdata)); LONG(SIZEOF(.sdata)); LONG(LOADADDR(.data)); LONG(0 + ADDR(.data)); LONG(SIZEOF(.data)); LONG(LOADADDR(.sdata4)); LONG(0 + ADDR(.sdata4)); LONG(SIZEOF(.sdata4)); LONG(LOADADDR(.code2ram)); LONG(0 + ADDR(.code2ram)); LONG(SIZEOF(.code2ram)); LONG(-1); LONG(-1); LONG(-1); . = ALIGN(16); } > pfls0 .text : FLAGS(axl) { *(.text) *(.text.*) *(.gnu.linkonce.t.*) *(.gnu.warning) /* .gnu.warning sections are handled specially by elf32.em. */ . = ALIGN(16); } > pfls0
以上的示例来源于TC297的Flash驱动测试程序。