STM32 CM3/CM4 ------ startup.s 启动文件分析 ------ GCC RT-Thread Studio 版本
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
链接脚本把向量表放在内存首地址处,所以 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 版本一样都是死循环。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 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 } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
2018-06-10 串口、COM口、TTL、RS-232、RS-485区别详解