keil mdk编译器学习笔记(2)
1、默认情况下,keil和iar都是认为char是unsigned char,可以通过设置去更改的。
2、赋初值的全局变量和静态变量,对于在程序中赋初值的全局变量和静态变量,程序编译后,MDK将这些初值放到Flash中,紧靠在可执行代码的后面。在程序进入main函数前,会运行一段库代码,将这部分数据拷贝至相应RAM位置。
后来看ARM的链接器,才知道ARM映象文件各组成部分在存储系统中的地址有两种:一种是在映象文件位于存储器中时(也就是该映象文件开始运行之前,通俗的说就是下载到Flash中的二进制代码)的地址,称为加载地址;一种是在映象文件运行时(通俗的说就是给板子上电,开始运行Flash中的程序了)的地址,称为运行时地址。赋初值的全局变量和静态变量在程序还没运行的时候,初值是被放在Flash中的,这个时候他们的地址称为加载地址,当程序运行后,这些初值会从Flash中拷贝到RAM中,这时候就是运行时地址了。
3、Stack分配到RAM的哪个地方? keil MDK中,我们只需要定义各个模式下的堆栈大小,编译器会自动在RAM的空闲区域选择一块合适的地方来分配给我们定义的堆栈,这个地方位于RAM的那个地方呢?通过查看编译列表文件,原来MDK将堆栈放到程序使用到的RAM空间的后面,比如你的RAM空间从0x4000 0000开始,你的程序用掉了0x200字节RAM,那么堆栈空间就从0x4000 0200处开始。具体的RAM分配,其实你可以从编译后生成的列表文件“工程名.map”文件中查看。
4、编译过程中,尽量不用高优化,高优化会吧很多代码会优化掉,如果禁止优化,使用volatile关键字,尤其是中断里面用到的全局变量,定义和生命都要加volatile 关键字,编译器是分文件编译,然后链接,文件A使用了文件B中定义的变量,在编译的时候,文件A是完全不知道文件B里面有什么东西的,只能通过文件B的接口文件(.h文件)来获得使用变量的属性。
不过目前使用新的编译器(我下载了keil mdk5.29),没有出现过类似bug,说明编译器越来越聪明了。
5、关于float类型,keil中,网上有文章说,如果不开启Optimize for time,则会占用8字节,开启Optimize for time编译选项,则占用4字节,具体没有测试过。
经过测试,上文说法已经不符合新版的keil了,相比keil4是这么特性,但是keil5.20我试过后,float只占4字节,与Optimize for time无关
6、.默认情况下,从按下复位到执行你编写的C代码main函数,keil mdk做了些什么?
之前开错rt-thread的启动代码,在main函数之前,就已经做了很多工作,其实在汇编文件startup_stm32f103xe.s中,已经做了很多工作。
复位后,已经调用了SystemInit函数,其实可以做更多,这里在另一篇文章中再详细展开。
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
IMPORT SystemInit
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
最后才进入main函数。