大家好,我是阿桃,一个想成为被点赞关注的程序员。
工控行业、物联网行业、机器人行业软件开发可联系我
很多人都知道程序是从main函数开始执行的,但在main之前执行了什么却不够了解,本文分别介绍Keil调用的ARMCC以及ARM-NONE-EABI-GCC两个编译器生成的在main之前的操作:
Keil MDK启动文件
总结一下MDK的启动流程:
1.系统初始化,包括中断向量表的重新映射
2.加载RW段(.data段初始化)
3.加载ZI段(.bss段初始化)
4.初始化用户堆栈
5.初始化Microlib
6.调用main函数
microlib 是缺省 C 库的备选库。 它旨在与需要装入到极少量内存中的深层嵌入式应用程序配合使用。 这些应用程序不在操作系统中运行。
microlib 进行了高度优化以使代码变得很小。 它的功能比缺省 C 库少,并且根本不具备某些 ISO C 特性。 某些库函数的运行速度也比较慢,例如,memcpy()。
下图是Keil调用ARMCC的加载到运行的变化视图:
稍微解释下这张图,从加载加载视图切换到执行视图时,代码存放在ROM中是不用变的,将pc指针指向程序的初始地址就可以依次执行指令,但是已经初始化的全局变量data段与未初始化的全局变量bss段需要从flash中加载到指定的内存地址中。
对于RO与RW段
Loadregion_nameBase表示region_name区域的装载地址
“Imageregion_nameBase”表示region_name区域的执行地址
“Imageregion_nameLength”表示region_name区域的长度(单位:字节)
对于ZI段
“Imageregion_nameZIBase”表示region_name区域的执行地址
“Imageregion_nameZILength”表示region_name区域的长度(单位:字节)
ARM-NONE-EABI-GCC的crt0启动流程
利用arm-none-eabi-gcc编译器生成ELF文件,将ELF文件通过objdump反汇编可以找出main之前的初始化函数_mainCRTStartup。
下图为ARM7V-M平台下_mainCRTStartup的大致流程:
下面看一下ELF文件中各段的分布:
由上图可知.text后直接跟.data段,但.data段的地址为RAM的实际地址。
小结:
arm-none-eabi-gcc不像armcc有将全局变量的值存储在flash中,所以没有像scatter_load函数这样从flash中加载全局变量到ram中,arm-none-eabi-gcc只能靠加载器将.data段直接加载到ram中。