裸机 C 应用程序究竟是如何启动的?
how exactly do bare metal C applications start?
我正在尝试了解裸机 C 应用程序的工作原理。我编写了自己的调用 __libc_init_array
的启动程序集代码,我看到它遍历 preinit_array
部分并调用其中的所有函数。据我了解,gcc 添加了一些它自己的初始化例程的部分,这些例程需要在 main 之前 运行,但随后在 .init
部分中出现 _init()
函数。
gcc 是否生成该函数?它来自libc吗?还是必须自己提供?有哪些学习这些东西的好资源?
what does symbols have to do with platform? is init_() generated by
gcc on one platform and not on another?
是的,启动和尾声例程留给实现,实际上 gcc
不会生成它。
libc 提供了这些符号 - https://github.com/bminor/newlib/blob/e0f24404b3fcfa2c332ae14c3934546c91be3f42/newlib/libc/misc/init.c
根据您的目标硬件,初始化可能会以完全不同的方式完成。
STM32Fxxx 启动示例。
.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
如您所见,在此实现中调用了两个函数 - 一个 SystemInit
用于非常低级别的硬件初始化和 __libc_init_array
它是 newlib 库的内部初始化(现在最常用于裸机项目)
问题是如果您决定不使用标准库并且不想 link 任何标准库。有些 takechains 仅通过 return 语句提供弱函数,有些则没有。如果您遇到 linker 问题,只需在启动文件中注释此调用或自己提供一个空函数
我正在尝试了解裸机 C 应用程序的工作原理。我编写了自己的调用 __libc_init_array
的启动程序集代码,我看到它遍历 preinit_array
部分并调用其中的所有函数。据我了解,gcc 添加了一些它自己的初始化例程的部分,这些例程需要在 main 之前 运行,但随后在 .init
部分中出现 _init()
函数。
gcc 是否生成该函数?它来自libc吗?还是必须自己提供?有哪些学习这些东西的好资源?
what does symbols have to do with platform? is init_() generated by gcc on one platform and not on another?
是的,启动和尾声例程留给实现,实际上 gcc
不会生成它。
libc 提供了这些符号 - https://github.com/bminor/newlib/blob/e0f24404b3fcfa2c332ae14c3934546c91be3f42/newlib/libc/misc/init.c
根据您的目标硬件,初始化可能会以完全不同的方式完成。
STM32Fxxx 启动示例。
.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
如您所见,在此实现中调用了两个函数 - 一个 SystemInit
用于非常低级别的硬件初始化和 __libc_init_array
它是 newlib 库的内部初始化(现在最常用于裸机项目)
问题是如果您决定不使用标准库并且不想 link 任何标准库。有些 takechains 仅通过 return 语句提供弱函数,有些则没有。如果您遇到 linker 问题,只需在启动文件中注释此调用或自己提供一个空函数