什么是数据段初始值设定项?
What are data segment initializers?
我正在为 STM32F3Discovery
开发板上的裸机应用程序 运行 构建链接描述文件。它使用位于 STM32Cube_FW_F3
包中的 CMSIS 驱动程序的启动代码,准确地说是 stm32f303xc.s
文件。
上面的文件,其中的一个片段粘贴在下面,引用了_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后直接使用post-reset.
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
应该指向哪个内存片段,它与数据段有什么关系?
数据段将位于 RAM 中。由于 RAM 在断电时不保存其内容,因此数据段的初始值必须在启动时从闪存中复制。为此,.data
段的初始内容副本位于 _sidata
标签;启动代码将其复制到实际数据段中。
答案可在 GNU 链接器手册中的主题 VMA 和 LMA 下找到,它们代表 'virtual memory address' 和 'load memory address'。对于初始化数据 (non-zero),我们需要一个副本来初始化。这是通过带有以下节的链接器脚本放置在闪存中的,
/* Used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections into "RAM" Ram type memory */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
'AT> FLASH'表示初始数据放在FLASH段,LOADADDR()
是获取这个地址(LMA)的函数。该部分放置在 >RAM
中,以便所有对这些变量的代码引用都将固定为使用 'working' 地址(术语 VMA)。
这段代码很可疑。让我们开始,
.word _sidata
这是为使用全局地址 _sidata
的数据生成 space。它存在于链接器命令文件中。真正的使用应该是.extern _sidata
,但这是默认的。这个文件的整个前导部分什么都不做?
/* 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
此代码完全低效且复杂。 gnu linker manual 在 '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
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
很容易看出,一些填充和对齐将使内部循环展开 and/or 转换为 ldm
和 stm
。整个STM32代码集越用越像米老鼠
一般主题是 ARM memcpy() 优化。由于我们可以控制链接描述文件,因此可以通过链接描述文件强制执行有关源对齐和大小的保证,以避免 head/tail 对齐问题。在我的链接描述文件中,这个对齐是四个字节。
- Run code from ram on arm
- Last address of ARM image
- Relocation in ARM assembler
我正在为 STM32F3Discovery
开发板上的裸机应用程序 运行 构建链接描述文件。它使用位于 STM32Cube_FW_F3
包中的 CMSIS 驱动程序的启动代码,准确地说是 stm32f303xc.s
文件。
上面的文件,其中的一个片段粘贴在下面,引用了_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后直接使用post-reset.
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
应该指向哪个内存片段,它与数据段有什么关系?
数据段将位于 RAM 中。由于 RAM 在断电时不保存其内容,因此数据段的初始值必须在启动时从闪存中复制。为此,.data
段的初始内容副本位于 _sidata
标签;启动代码将其复制到实际数据段中。
答案可在 GNU 链接器手册中的主题 VMA 和 LMA 下找到,它们代表 'virtual memory address' 和 'load memory address'。对于初始化数据 (non-zero),我们需要一个副本来初始化。这是通过带有以下节的链接器脚本放置在闪存中的,
/* Used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections into "RAM" Ram type memory */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
'AT> FLASH'表示初始数据放在FLASH段,LOADADDR()
是获取这个地址(LMA)的函数。该部分放置在 >RAM
中,以便所有对这些变量的代码引用都将固定为使用 'working' 地址(术语 VMA)。
这段代码很可疑。让我们开始,
.word _sidata
这是为使用全局地址 _sidata
的数据生成 space。它存在于链接器命令文件中。真正的使用应该是.extern _sidata
,但这是默认的。这个文件的整个前导部分什么都不做?
/* 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
此代码完全低效且复杂。 gnu linker manual 在 '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
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
很容易看出,一些填充和对齐将使内部循环展开 and/or 转换为 ldm
和 stm
。整个STM32代码集越用越像米老鼠
一般主题是 ARM memcpy() 优化。由于我们可以控制链接描述文件,因此可以通过链接描述文件强制执行有关源对齐和大小的保证,以避免 head/tail 对齐问题。在我的链接描述文件中,这个对齐是四个字节。
- Run code from ram on arm
- Last address of ARM image
- Relocation in ARM assembler