MDK下的STM32启动程序相关:SP指到哪了?

2019-08-14 03:30发布

原子的开发板,原子的例程序“ALIENTEK MINISTM32 实验1 跑马灯”
是用SWD调试时发现R13也就是SP的值为 0x20000208,觉得奇怪不?stack的定位一般应该是RAM空间的最高位,因为STM32使用的是向下生长的满栈,所以根据RAM = 20KB SP可以定在0x20005000上。这样做的好处先不提,先看看MDK是怎样算出0x20000208的。
在启动程序里跟SP有关的当然就是__initial_sp这个标号了,也不知道内容是什么?反正进到__main里面就自动将SP改成0x20000208了,查找了下MDK的帮助文档,隐约有提到initial_sp的值是根据ZI的地址算出来的,ZI是什么我就不解释了,(RO,RW,ZI嘛),再来通过看编译后的程序确定下好了,详细信息都在.map文件里,这里面有IMAGE文件的详细说明。

XXX.map 文件里的一部分如下,XXX.map文件在工程文件夹里有的。 因为是复制粘贴过来的 所以要上下对齐了看。
====================================================================
Image component sizes
      Code (inc. data)   RO Data    RW Data    ZI Data      Debug   Object Name        160          8          0          4              0          0           delay.o
       128         18          0          0              0          0           led.o
        28          4        240          0            512          0           stm32f10x.o
       778         72          0          0              0          0           sys.o
        88         10          0          0              0          0           test.o     ----------------------------------------------------------------------
      1184        112        272          4           516          0   Object Totals
         0          0         32          0              0          0   (incl. Generated)
         2          0          0          0              4          0   (incl. Padding)     ----------------------------------------------------------------------       Code (inc. data)   RO Data    RW Data    ZI Data      Debug   Library Member Name          0          0          0          0          0          0   entry.o
         8          4          0          0          0          0   entry2.o
         4          0          0          0          0          0   entry5.o
         8          4          0          0          0          0   entry7.o
        30          0          0          0          0          0   handlers.o
        36          8          0          0          0          0   init.o     ----------------------------------------------------------------------
        88         16          0          0          0          0   Library Totals
         2          0          0          0          0          0   (incl. Padding)     ----------------------------------------------------------------------       Code (inc. data)   RO Data    RW Data    ZI Data      Debug   Library Name         86         16          0          0          0         68   mc_w.l     ----------------------------------------------------------------------
        88         16          0          0          0          0   Library Totals     ---------------------------------------------------------------------- ================================================================
      Code (inc. data)   RO Data    RW Data    ZI Data      Debug         1272        128        272          4        516       7504   Grand Totals
      1272        128        272          4        516       7504   ELF Image Totals
      1272        128        272          4          0          0   ROM Totals ===============================================================     Total RO  Size (Code + RO Data)                 1544 (   1.51kB)
    Total RW  Size (RW Data + ZI Data)               520 (   0.51kB)
    Total ROM Size (Code + RO Data + RW Data)       1548 (   1.51kB) ================================================================

注意到红线的地方,可以看到程序用到多少RW 和 ZI,启动stm32f10x.s里竟然有512个字节的ZI,这个不奇怪,就是因为
Stack_Size      EQU     0x00000200 的设定
所以再加上Padding的4个字节,ZI区共516个字节,看黄线部分,padding是干啥的我也不清楚,貌似是为了对齐用了添加的多余字节。
那么再加上RW区的4个字节,总共RW + ZI = 520个字节,所以SP就定在了 0x20000208 (0x208 = 520),那么现在真相看到了吧。

结论&吐槽:MDK能不用这么坑爹的设定么?把stack放到RW+ZI区的结束位置?并且Stack_Size      EQU     0x00000200 这个空间也算ZI?stack需要ZI?费力不讨好吧,你定个Stack_Size      EQU     0x00000200 有什么用呢?能防止程序深度调用时stack溢出?还要在创建ZI时多初始化512个字节,把stack定到RAM最高地址不好么?把RW+ZI区结束位置留给heap不好么?看着不爽吧,还不让人改,一个__main都搞完了,还直接跳到我的main,我只能干瞪眼。试过保留向量表,其他部分自己用汇编写吧,各种报错,各种库函数什么的找不到,我不用你的初始化库还不行吗?还真不行,不知道该哪的设置,搞了一晚上头都大了。

好吧我屈服了

在向量表的末尾加上红线部分
                .......
                DCD     EXTI15_10_IRQHandler      ; EXTI Line 15..10
                DCD     RTCAlarm_IRQHandler       ; RTC Alarm through EXTI Line
                DCD     USBWakeUp_IRQHandler      ; USB Wakeup from suspend
SP_ADDR   DCD  0X20005000
    EXPORT SP_ADDR
                AREA    |.text|, CODE, READONLY
                .......
然后在主程序里 加上红线部分 嵌入一个汇编函数来修改SP

__asm void set_sp(void)
{
 IMPORT SP_ADDR
 LDR  R13, SP_ADDR
 BX  LR // 返回主程序(不可省略)
 ALIGN
} int main(void)
{
 set_sp();               //终于我的SP是自己定义的了
  Stm32_Clock_Init(9); //系统时钟设置
 delay_init(72);      //延时初始化
    LED_Init();      //初始化与LED连接的硬件接口
 while(1)
 {
  LED0=0;
  LED1=1;
  delay_ms(300);
  LED0=1;
  LED1=0;
  delay_ms(300);
 } 
}

记得最后改 Stack_Size      EQU     0x00000000
这样就没了那512个字节的冤大头。

哎,这就是跟编译器卯了一晚上,得到的结果。



友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
5条回答
正点原子
1楼-- · 2019-08-14 07:15
 精彩回答 2  元偷偷看……
armmage
2楼-- · 2019-08-14 10:58
一个顶字让我情何以堪,来点心得分享下呗
shihantu
3楼-- · 2019-08-14 12:30
还需要修改溢出检查吧,不然出问题了还真不清楚,毕竟编译器自带的东西是自成一套体系的,改了这个要把其他的一套都要改了才好用,特别是它的RTX,没研究过会不会也有关系。
armmage
4楼-- · 2019-08-14 18:16
哎 过年玩了几天 今天来关注下

楼上的说溢出检查?我在MDK里没发现这个设置,话说堆栈这东西因为有中断程序的介入,调用深度是不可以预知的,所以编译器应该也没办法检查吧,只有在运行起来自己写程序检查SP是否溢出
qilima
5楼-- · 2019-08-14 22:21
楼主这么用了吗,长期使用下来有没有发现什么问题

一周热门 更多>