STM32 CM3/CM4 ------ startup.s 启动文件分析 ------ GCC RT-Thread Studio 版本
2025-09-12 来源:cnblogs
startup.s 功能
startup.s 文件定义了向量表,包含栈初始值和各个中断服务函数指针。
芯片一上电,自动设置SP,PC,然后执行复位中断:
设置栈顶寄存器的值 --- 多余,芯片一上电自动设置了
data段的数据从 flash 拷贝到 SRAM
bss段位于SRAM,初始化为0
执行 SystemInit,初始化时钟,设置SCB->VTOR的值为向量表起始地址
跳转到 entry 函数,entry() 函数添加一些我们要在 main() 函数之前执行的代码,entry() 函数的最后调用 main()。
向量表
在 startup.s 内,定义了一个向量表,由链接脚本决定向量表存储在 flash 的起始地址 0x08000000,向量指向的位置就是对应的中断服务函数
MEMORY
{
ROM (rx) : ORIGIN = 0x08000000, LENGTH = 1024k /* 1024K flash */
RAM (rw) : ORIGIN = 0x20000000, LENGTH = 128k /* 128K sram */
}
SECTIONS
{
.text :
{
. = ALIGN(4);
_stext = .;
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
*(.text) /* remaining code */
*(.text.*) /* remaining code */
_etext = .;
} > ROM = 0
......
}
由上可知,变量 _stext 为空,不占用地址,所以首地址存的是向量表 isr_vector
向量表的内容按地址增长顺序如下:
主堆栈指针(MSP)的初始值
复位中断函数
NMI中断函数
硬 fault 服务函数
......
后两者(NMI 和硬 fault )也是必需的,因为有可能在引导过程中发生这两种异常。

链接脚本把向量表放在内存首地址处,所以 0x20000D84 就是主堆栈指针的初始值,0x08059545-1就是复位向量(最低为1,表示接下来使用的是Thumb指令),指向中断服务函数 Reset_Handler
可以看 rtthread.map 得到验证

startup.s 文件内容
以下是 GCC RT-Thread 版本的 startup.s
.section .text.Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
ldr sp, =_estack /* set stack pointer */
// STM32的data段需要从flash搬移到对应的sram,bss段对应的sram需要初始化为0
// data段的数据在flash中存有一份,由链接文件可知代码中使用位于data段的变量的地址都是sram地址,所以只要把数据搬移到对应的sram就可以了
// 代码中使用bss段的变量的地址都是sram地址,所以只需要把对应的sram初始化为0即可
// 由此可看出,对于BIN类型可执行文件,data段占其空间,bss段不占其空间
/* Copy the .data segment initializers from flash to SRAM */
movs r1, #0
b LoopCopyDataInit
CopyDataInit:
ldr r3, =_sidata
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyDataInit:
ldr r0, =_sdata
ldr r3, =_edata
adds r2, r0, r1
cmp r2, r3
bcc CopyDataInit
ldr r2, =_sbss
b LoopFillZerobss
/* Zero fill the bss segment. */
FillZerobss:
movs r3, #0
str r3, [r2], #4
LoopFillZerobss:
ldr r3, = _ebss
cmp r2, r3
bcc FillZerobss
/* Call the clock system intitialization function.*/
bl SystemInit
/* Call static constructors */
/* bl __libc_init_array */
/* Call the application's entry point.*/
bl entry
bx lr
.size Reset_Handler, .-Reset_Handler
/**
* @brief This is the code that gets called when the processor receives an
* unexpected interrupt. This simply enters an infinite loop, preserving
* the system state for examination by a debugger.
* @param None
* @retval None
*/
.section .text.Default_Handler,'ax',%progbits
Default_Handler:
Infinite_Loop:
b Infinite_Loop
.size Default_Handler, .-Default_Handler
/******************************************************************************
*
* The minimal vector table for a Cortex M3. Note that the proper constructs
* must be placed on this to ensure that it ends up at physical address
* 0x0000.0000.
*
*******************************************************************************/
.section .isr_vector,'a',%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
.word MemManage_Handler
.word BusFault_Handler
.word UsageFault_Handler
.word 0
.word 0
.word 0
.word 0
.word SVC_Handler
.word DebugMon_Handler
.word 0
.word PendSV_Handler
.word SysTick_Handler
/* External Interrupts */
.word WWDG_IRQHandler /* Window WatchDog */
.word PVD_IRQHandler /* PVD through EXTI Line detection */
.word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */
.word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */
.word FLASH_IRQHandler /* FLASH */
.word RCC_IRQHandler /* RCC */
.word EXTI0_IRQHandler /* EXTI Line0 */
.word EXTI1_IRQHandler /* EXTI Line1 */
.word EXTI2_IRQHandler /* EXTI Line2 */
.word EXTI3_IRQHandler /* EXTI Line3 */
......
/*******************************************************************************
*
* Provide weak aliases for each Exception handler to the Default_Handler.
* As they are weak aliases, any function with the same name will override
* this definition.
*
*******************************************************************************/
.weak NMI_Handler
.thumb_set NMI_Handler,Default_Handler
.weak HardFault_Handler
.thumb_set HardFault_Handler,Default_Handler
.weak MemManage_Handler
.thumb_set MemManage_Handler,Default_Handler
.weak BusFault_Handler
.thumb_set BusFault_Handler,Default_Handler
.weak UsageFault_Handler
.thumb_set UsageFault_Handler,Default_Handler
......
对于STM32,上电后固定从地址 0x0000 0004 取值赋值到 PC,该值是复位向量,所以上电从复位向量开始运行
下面两张图来自链接脚本,由 ENTRY(Reset_Handler) 可知程序从 Reset_Handler 开始运行,这个只是起到注释的作用,因为可执行文件用的是BIN文件,不是ELF。
Reset_Handler 第一条语句就是对 SP 进行初始化,初始化值是 _estack,这个也不需要,因为芯片上电自动设置了


不同于 IAR 版本,这个版本除了中断服务函数 Reset_Handler 外,其他中断服务函数都是调用函数 Default_Handler,Default_Handler是一个死循环。功能上和 IAR 版本一样都是死循环。
void SystemInit(void)
{
/* FPU settings ------------------------------------------------------------*/
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
#endif
/* Reset the RCC clock configuration to the default reset state ------------*/
/* Set HSION bit */
RCC->CR |= (uint32_t)0x00000001;
/* Reset CFGR register */
RCC->CFGR = 0x00000000;
/* Reset HSEON, CSSON and PLLON bits */
RCC->CR &= (uint32_t)0xFEF6FFFF;
/* Reset PLLCFGR register */
RCC->PLLCFGR = 0x24003010;
/* Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF;
/* Disable all interrupts */
RCC->CIR = 0x00000000;
#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
SystemInit_ExtMemCtl();
#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
/* Configure the Vector Table location add offset address ------------------*/
#ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
#endif
}
- 意法半导体中国本地造STM32微控制器启动规模量产
- 意法半导体全新STM32C5系列,重新定义入门级微控制器性能与价值,赋能万千智能设备
- 使用 Keil Studio for Visual Studio Code开发 STM32 设备
- 基于机智云与STM32的智能拐杖安全监测系统在养老物联网中的应用
- 内置全栈安全,一站式满足CRA法案与IEC 62443标准——米尔STM32MP257核心板
- 如何用 STM32 FLASH 实现等效 100 万次擦写的 EEPROM 功能?
- 实战解析:通过一个小项目掌握STM32所有外设
- STM32学了两年半,却还是不会做项目
- 意法半导体推出最新STM32MP21微处理器,兼具高性价比、低功耗、高灵活性
- 基于STM32的矿井作业环境监测系统设计与实现
- 六大全新产品系列推出,MCX A微控制器家族迎来创新
- 意法半导体全新STM32C5系列,重新定义入门级微控制器性能与价值,赋能万千智能设备
- 从控制到系统:TI利用边缘AI重塑嵌入式MCU的边界
- 模组复用与整机重测在SRRC、CCC、CTA/NAL认证中的实践操作指南
- 有源晶振与无源晶振的六大区别详解
- 英飞凌持续巩固全球微控制器市场领导地位
- 使用 Keil Studio for Visual Studio Code开发 STM32 设备
- 蓝牙信道探测技术原理与开发套件实践
- LoRa、LoRaWAN、NB-IoT与4G DTU技术对比及工业无线方案选型分析
- Microchip 推出生产就绪型全栈边缘 AI 解决方案,赋能MCU和MPU实现 智能实时决策




