初级会员

- 积分
- 109
- 金钱
- 109
- 注册时间
- 2016-4-30
- 在线时间
- 44 小时
|
本帖最后由 stayhungry 于 2016-9-18 23:14 编辑
大四狗等待秋招中,无聊之下就开始了学习M3的底层,现在分享一下,给予像我一样的新人一些帮助。
这次的研究的总结:划分“栈”这个动作是在编译器实现的,芯片刚复位上电时自己没有栈的概念(它甚至不知道自己的内存地址从哪里开始),所以也不会划分,编译器告诉它哪里是栈,哪里就是栈。(对于M3,是通过将栈顶地址放进0x00000000来通知芯片自己栈在哪里)。后来想起了之前度娘“栈和堆的区别”经典文章有提到过栈和编译器的关系更加验证了我的想法。好了,废话不说,入主题。
以下是用来验证想法的汇编程序,参考的是STM32的启动文件。
AREA USER_STACK, NOINIT, READWRITE ;定义一个段叫USER_STACK,用来当栈
SPACE 0X00000400 ;分配一段空间作为栈
MSP_TOP ;栈顶地址
AREA RESET, DATA, READONLY
DCD MSP_TOP ; ①
END
遇到的疑惑和一些猜想:
1、对于M3,怎么理解“编译器划分栈”这个概念?
答:
这里以keil5为例,先将环境配置成平时码F1程序的环境,然后工程文件用上面的汇编程序和一个干净的main函数.c文件。将Debug的Run to main()取消掉,编译之后运行软件仿真打开内存监视窗口
因为M3会把0x00000000映射到0x08000000,所以0x08000000内容就是0x00000000的内容,根据《M3权威指南》知道,刚上电之后在0x08000000的第一个数值就是栈的栈顶,也就是上述程序RESET段的MSP_TOP。所以这里的栈顶地址就是0x20000460,可以通过查看map文件
来证明MSP_TOP这个标号代表的地址是0x20000460。那么这个0x20000460是怎么来的呢?其实它是0x20000000+400h+60h,0x20000000就是栈开始划分的地址,是我们在Option->target->IRAM1设置的,这是我通过多次改变IRAM1的数值,对比观察仿真结果发现的。400h就是栈的大小,就是我们在汇编开头写的SPACE 0x00000400,如果你在SPACE指令之前写一个分配4字节内存的指令(DCD 0)会发现这里的400h会变成404h,通过查看map文件看到,
,USER_STACK这个段比之前多了4字节,这也就是为什么网上资料说更改这个SPACE后面的数值就是改变栈的大小,其实只要在USER_STACK段里面,分配了多少内存(必须小于Option->target->SIZE),栈就有多大。至于这个60h我也不清楚是什么,好像和静态变量初始化有关,想深究的可以看我之前的求助帖,里面有个网站说明。
所以对于M3,“编译器划分栈”的概念就是 IRAM1的数值+用户程序中需要的栈大小(必须小于Option->target->SIZE)+60h 从而得出一个栈顶地址。
2、“栈”和芯片内存的关系?
答:
上面汇编的①指令所处位置代表的意思就是告诉芯片:0x20000000~0x20000460这段内存我占用来做栈了。
编译结果: Program Size: Code=288 RO-data=20 RW-data=0 ZI-data=1120 占掉了RW+ZI= 0+1120 = 460h内存
如果把汇编①指令注释掉,就没人告诉芯片哪里是栈了。
编译结果: Program Size: Code=288 RO-data=20 RW-data=0 ZI-data=96 占掉了RW+ZI=0+96=60h内存
这里说明了,占不占用芯片内存是由向量表第一项来决定的,而不是编译器是否已经划分了栈决定的。当然这样不要栈的程序写进芯片是非法的,不过只是想验证我的一些猜想,所以也就没关系了。
以上就是我从启动文件得出的一些看法,不足或出错之处还望指出。
|
|