什么是数据段初始值设定项?

问题描述 投票:0回答:2

我正在为在

STM32F3Discovery
板上运行的裸机应用程序构建链接器脚本。它使用位于
STM32Cube_FW_F3
包(确切地说是
stm32f303xc.s
文件)中的 CMSIS 驱动程序的启动代码。

上述文件(其片段粘贴在下面)引用了

_sidata

/* start address for the initialization values of the .data section.
defined in linker script */
.word   _sidata
/* start address for the .data section. defined in linker script */
.word   _sdata
/* end address for the .data section. defined in linker script */
.word   _edata
/* start address for the .bss section. defined in linker script */
.word   _sbss
/* end address for the .bss section. defined in linker script */
.word   _ebss

对数据和 bss 部分的开始和结束的引用是不言自明的,另一方面,我无法找到有关数据段初始值设定项的任何信息。复位后设置 SP 后直接使用。

stm32f303xc.s

    .section    .text.Reset_Handler
    .weak   Reset_Handler
    .type   Reset_Handler, %function
Reset_Handler:
  ldr   sp, =_estack    /* Atollic update: set stack pointer */

/* Copy the data segment initializers from flash to SRAM */
  movs  r1, #0
  b LoopCopyDataInit

CopyDataInit:
    ldr r3, =_sidata
    ldr r3, [r3, r1]
    str r3, [r0, r1]
    adds    r1, r1, #4

LoopCopyDataInit:
    ldr r0, =_sdata
    ldr r3, =_edata
    adds    r2, r0, r1
    cmp r2, r3
    bcc CopyDataInit
    ldr r2, =_sbss
    b   LoopFillZerobss
/* Zero fill the bss segment. */
FillZerobss:
    movs    r3, #0
    str r3, [r2], #4

LoopFillZerobss:
    ldr r3, = _ebss
    cmp r2, r3
    bcc FillZerobss

/* Call the clock system intitialization function.*/
    bl  SystemInit
/* Call static constructors */
    bl __libc_init_array
/* Call the application's entry point.*/
    bl  main

_sidata
应该指向哪个内存片段?它与数据段有何关系?

assembly arm linker-scripts
2个回答
3
投票

数据段将位于 RAM 中。由于 RAM 在断电时不会保存其内容,因此必须在启动时从闪存复制数据段的初始值。为此,

.data
段的初始内容的副本位于
_sidata
标签处;启动代码将其复制到实际数据段中。


3
投票

答案可以在 GNU 链接器手册的主题 VMALMA 下找到,它们分别代表“虚拟内存地址”和“加载内存地址”。对于初始化数据(非零),我们需要一个副本来初始化。这是通过具有以下节的链接描述文件放置在闪存中的,

 /* 启动时用来初始化数据 */
  _sidata = LOADADDR(.data);

  /* 将数据部分初始化到“RAM”Ram 类型存储器中 */
  。数据 :
  {
    。 =对齐(4); /* 不是对齐,这什么也不做。 */
    _sdata = .; /* 在数据开始处创建一个全局符号 */
    *(.data) /* .data 部分 */
    *(.data*) /* .data* 部分 */

    。 =对齐(4); /* 对齐(下一节)。 */
    _edata = .; /* 在数据端定义一个全局符号 */
    
  } >RAM AT> 闪存

“AT>FLASH”表示初始数据放置在FLASH部分,而

LOADADDR()
是获取该地址(LMA)的函数。该部分放置在
>RAM
中,以便对这些变量的所有代码引用都将被修复以使用“工作”地址(术语 VMA)。

_sidata_sdata_edata都是在链接器文件中声明的变量。它们可用作“C”或汇编代码中的地址。

另一方面,我无法找到有关数据段初始值设定项的任何信息

希望以上解释了这一点。同样,链接器文件的“RAM”版本包含这些变量,并将数据复制到自身。 所以,STM32的作者们似乎也很困惑。


这段代码非常可疑。让我们开始吧,

 .word   _sidata

这是为使用全局地址的数据腾出空间

_sidata
。它存在于链接器命令文件中。真正的用途应该是
.extern _sidata
,但这是默认的。该文件的整个前导部分没有任何作用?


/* Copy the data segment initializers from flash to SRAM */  
  movs  r1, #0         ; r1 is a counter up to size. 
  b  LoopCopyDataInit
CopyDataInit:
  ldr  r3, =_sidata    ; reload flash pointer
  ldr  r3, [r3, r1]    ; add count to flash pointer and get value
  str  r3, [r0, r1]    ; store value to RAM
  adds  r1, r1, #4     ; increment counter
    
LoopCopyDataInit:
  ldr  r0, =_sdata     ; (re)load destination
  ldr  r3, =_edata     ; (re)load end destination
  adds  r2, r0, r1     ; add count to start
  cmp  r2, r3          ; are we at end?
  bcc  CopyDataInit    ; loop.
 

这段代码效率很低而且很复杂;循环体有九个指令,并不断重新计算值。它有五个内存访问。 gnu 链接器手册给出了在“C”中执行此操作的公式,并且可以在 gnu 汇编器中轻松使用相同的符号。

.extern _sidata   /* Source of init data in flash. */
.extern _sdata    /* Target/start of init data in RAM. */
.extern _edata    /* End of init data in RAM. */

ldr r0, =_sidata
ldr r1, =_sdata
ldr r2, =_edata

/** Validate parameters. */
cmp   r1, r2       /* Zero size */
it    ne
cmpne r0, r1       /* Src is dest */
beq   2f           /* Skip it. */

1: /* init data copy loop */
ldr r3, [r0], #4  /* Load from flash and update source pointer. */
str r3, [r1], #4  /* Store to RAM and update dest pointer. */
cmp r1, r2
blo 1b
2:                /* exit */

很容易看出,一些填充和对齐将允许内部循环(四个指令和两个内存访问)展开和/或转换为

ldm
stm
。我用得越多,整个STM32代码集就显得像Mikey mouse。上面的替代代码将按照 gnu ld 手册使用编译器生成,但在数据对齐时使用 指针而不是 char。即,循环, uint32_t
一般主题是

ARM memcpy() 优化
。由于我们可以控制链接器脚本,因此可以通过链接器脚本强制保证源对齐和大小,以避免头/尾对齐问题。在我的链接器脚本中,此对齐方式是四个字节。

从手臂上的内存运行代码

© www.soinside.com 2019 - 2024. All rights reserved.