今天查看了 iar 上面的启动文件,好奇堆栈指针到底是什么时候赋值的,所以就仔细的阅读了代码和相关手册,找到了答案。

首先,芯片启动后,会从ROM的首地址处进行执行,那么我们从 linker 里面找找具体是怎么安排的。

/* 起始地址标签 */
define symbol __ICFEDIT_intvec_start__ = 0x08000000;
/* iar 代码块绝对地址定位: intvec块 和 StartCode 块 */
place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec ,readonly section .StartCode};

再来看下启动代码:

/* NOROOT 表示如果没有被其他地方用到,就可以抛弃掉 */
/* 这边就是 intvec块 */
SECTION .intvec:CODE:NOROOT(2)
SECTION CSTACK:DATA:NOROOT(3)

/* Extern ... */
// Extern

/* DATA 模式 */
        DATA
__vector_table
        /* MSP 赋值 */
        DCD     sfe(CSTACK)
        /* pc 赋值 */
        DCD     Reset_Handler             ; Reset Handler

/* 后续指令解释为 thumb 执行模式的指令 */
        THUMB

        PUBLIC Reset_Handler
/* 这边就是 StartCode 块 */
        SECTION .StartCode:CODE:NOROOT(2)        
Reset_Handler
        LDR     R0, =__low_level_init
        BLX     R0
        LDR     R0, =__iar_program_start
        BX      R0

        END

从上面可以看出来,程序先读取了 sfe(CSTACK), 然后进入 Reset_Handler 中执行 low_level_init,最后执行 iar_program_start 进入 main 函数。 查了手册,sfe 表示 section end,是说 CSTACK 的结束地址的后一个地址。那么在到 linker 文件里面看看是怎么写的:

define symbol __ICFEDIT_region_RAM_start__ = 0x20000200;
/* cstack 大小 0x200 */
define symbol __ICFEDIT_size_cstack__ = 0x200;
define region RAM_region   = mem:[from __ICFEDIT_region_RAM_start__   to __ICFEDIT_region_RAM_end__];
define block CSTACK    with alignment = 8, size = __ICFEDIT_size_cstack__   { };
/* ram 中排列顺序: readwrite, cstack, heap */
place in RAM_region   { readwrite,
                        block CSTACK,block HEAP};

然后我们再编译一下程序,看看 readwrite 使用的大小: 6 903 bytes of readwrite data memory

经过测试发现,6903 这个数值已经包含了 cstack 的部分,所以我们计算一下: 那么 6903 +0x20000200 + 1 = 0x20001CF8。

然后模拟调试一下,看看 SP 的数值, 确实是 0x20001CF8。

标签: Assemble, ARM, STM32, C, Linker, startup

添加新评论