我最近对 MCU 的链接描述文件和汇编编码感兴趣。我刚刚发现我们在reset_handler中做的第一件事是设置堆栈指针寄存器(sp)。
我的问题是:ST的所有教程和示例代码都显示RAM末尾的_estack变量,即0x20005000。然而,flash是从0x08000000开始的,而我编译的ELF文件的向量表是在flash的开头(0x08000000),但是我们将堆栈指针设置为_estack(0x20005000),这不是flash的开头。然而,代码是有效的。
如何让堆栈指针指向0x20005000,而指令从0x08000000(向量表)开始,并且仍然有效?
我的基本链接器:
_estack = 0x20005000;
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K
RAM (rxw) : ORIGIN = 0x20000000, LENGTH = 20K
}
我的程序集文件reset_handler(相关部分):
.type reset_handler, %function
reset_handler:
LDR r0, =_estack
MOV sp, r0
您需要阅读文档。
0
处的值。如果从 FLASH 启动,它将位于以下地址
0x08000000
。向量表中的下一个位置是 ResetHandler 地址,处理器从存储在那里的地址开始执行指令从0x08000000(向量表)开始,并且它 还有效吗?
不,说明不是从那里开始的。向量表只是处理程序的地址数组 - 第一个是初始堆栈指针,第二个是重置处理程序的地址。
_estack
只是符号,重置处理程序中的指令将其值加载到堆栈指针中。
堆栈通常(但并非总是)放置在 RAM 的末尾,并且它们向下增长。
STM32F103 有 20 KiB RAM,位于 [
0x20'000'000
, 0x20'004'fff
] 之间。
0x20'005'000
实际上不是一个有效的地址。在压入堆栈操作期间,硬件会先递减堆栈指针,然后再将压入的值放入 RAM。