【万字长文&全网最全】STM32启动过程详解
STM32启动过程详解
STM32存储架构
首先来一张经典的存储器STM32映射表(STM32F103X):
对于这张图,我们在启动阶段只需要关注两段部分:
FLASH是什么?
FLASH(Flash Memory)即闪存,是一种非易失存储器,说白了,在芯片掉电后其中的内容可以被永久保存,类似电脑的硬盘。我们的代码编译成的可执行文件就放在这里。
SRAM是什么?
SRAM(Static Random-Access Memory)即静态随机存取存储器,只要保持通电,这里的数据就可以保存下来,一旦芯片掉电,数据也就不在了,类似电脑的内存。程序运行过程中的自动变量(在函数里声明的变量,保存在栈中,函数调用后被自动释放的变量)、全局变量就保存在这里。
我们编译好的程序如何正确的存放在FLASH段?程序运行中的变量又如何被暂存至SRAM段呢?这个可以查看Keil中的Options->Target段:
其中,存储区域(Memory Areas)被分为两部分:
0x8000000
是起始地址也就对应存储器映射表中的FLASH区域,大小为0x40000
也就是256KB,正好是我选用STM32F103RCT6
芯片的FLASH大小。(其实还有别的东西,这个后面再讲)启动文件startup_stm32f103xe.s
接下来我们分析一下启动文件,这个文件是MCU运行起来的核心,里面定义了堆、栈、中断向量表、启动代码。
汇编文件的结构
AREA
汇编文件由多个段组成,也可以叫做域(AREA
),通过以下方式定义,在其后需要定义一个自定义的任意的段名,后面再更上被编译器解释的参数。
什么是段呢?其实就是划分一段存储器空间用于存放段内的内容,有过一点编程基础的人都知道,程序中的代码、各种类型的变量都是存放在不同区域的,这里的不同区域就对应汇编中的不同段。我们定义了这些段以及这些段对应的属性,编译器就会帮我们把程序中不同的部分(代码部分、变量部分)链接到不同的内存地址。
AREA 段名 属性1,属性2,...
这个段需要被链接到哪个地址就通过后面的属性区分,常见的属性有:
CODE:标识这一段为代码段,用于存放只读的指令和代码。在STM32中,属性为CODE
的段一般会被放在FLASH中。
DATA:标识这一段为数据段,用来存放初始化的全局变量和静态变量,在STM32中,属性为DATA
的段一般会被放在SRAM中。【注意这里单指属性只有DATA一个标识的段】
NOINIT:标识这一段不初始化,经过我的测试,只有一个NOINIT
属性的段被存放在了SRAM中。
READONLY:标识这一段为只读,只读的段当然只能存放在FLASH(只读存储区)中了。
READWRITE:标识这一段为可读可写,可读写的段当然只能存放在SRAM中了。
ALIGN:指定对齐方式,如ALIGN=3
为2^3
对齐。
定义段名后,就可以在这个段里添加数据了,指令格式为:
[标号] [指令助记符] [操作数]
标号是给该指令所在的地址取一个名字,可以缺省。
启动文件分配空间用的指令助记符有:
AREA
后面的指令都会作用在这个段中,直到重新开启下一个段。
栗子
我们可以在startup_stm32f103xe.s
启动文件中定义一个自己的段,如:
AREA TESTAREA, DATA
Test_Mem SPACE 0x100
Test_Mem_End
这样就定义了一个名为TESTAREA的数据段,并直接在段中申请256字节的空间,用标号Test_Mem
代表这块空间的起始地址,后跟了一条只有标号的空指令,用标号Test_Mem_End
代表这块空间的结束地址。
为了不让编译器优化未被使用的段,需要在后面使用一下这个段,我把它的地址附在了中断向量表后:
; Vector Table Mapped to Address 0 at Reset
AREA RESET, DATA, READONLY
EXPORT __Vectors
EXPORT __Vectors_End
EXPORT __Vectors_Size
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
...
DCD DMA2_Channel3_IRQHandler ; DMA2 Channel3
DCD DMA2_Channel4_5_IRQHandler ; DMA2 Channel4 & Channel5
DCD Test_Mem
DCD Test_Mem_End
__Vectors_End
通过MAP文件就可以查到这个所段定义的地址了,如何使用MAP文件我们后面再说。
TESTAREA 0x20000014 Section 256 startup_stm32f103xe.o(TESTAREA)
Test_Mem 0x20000014 Data 256 startup_stm32f103xe.o(TESTAREA)
.bss 0x20000114 Section 72 usart.o(.bss)
Test_Mem_End 0x20000114 Data 0 startup_stm32f103xe.o(TESTAREA)
从这里可以看到Test_Mem
标号的地址是0x20000014
,Test_Mem_End标号的地址是0x20000114
,说明这个段被存放在了SRAM区,且占用了256字节。
特别的
有一个特殊的段名被编译器保留了:即RESET
段,程序中必须要存在一个RESET
段,指定程序的开端。如果删除这个段或者更名这个段,编译器就会报错:
Test1\Test1.sct(7): error: L6236E: No section matches selector - no section to be FIRST/LAST.
Not enough information to list image symbols.
Not enough information to list load addresses in the image map.
好,基础有了,我们来开始分析真正的启动文件。
栈区
在启动文件的最开头,是这样一个段。
Stack_Size EQU 0x400
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
这一段定义了STM32中的栈,我们逐行解释一下。
EQU
类似C中的#define
,这行代码定义了一个变量Stack_Size,它的值是0x400。AREA
表示定义一个区域,名称叫做STACK
(栈),不初始化,可读可写,8字节对齐。由于READWRITE
属性,这个段肯定会被放置在SRAM中。- 在这个段中申请
Stack_Size
,即1KB的空间,起始地址用Stack_Mem
标号代表。 - 用标号
__initial_sp
标识这段空间的结束地址。
栈的概念应该都不陌生吧,程序中的自动变量(局部变量)、形参就存放在这里,函数调用结束后自动释放,先进后出。
堆区
接下来定义了一个堆区。
Heap_Size EQU 0x200
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
- 定义了一个变量Heap_Size,它的值是0x200。
- 定义一个区域,名称叫做
HEAP
(堆),不初始化,可读可写,8字节对齐。由于READWRITE
属性,这个段肯定会被放置在SRAM中。 - 用标号
__heap_base
标识这段空间的起始地址。 - 在这个段中申请
Heap_Size
,即512字节的空间,起始地址用Heap_Mem
标号代表。 - 用标号
__heap_limit
标识这段空间的结束地址。
RESET区
接下来定义RESET
区,从前面的分析知道,这个区是程序的开端
; Vector Table Mapped to Address 0 at Reset
AREA RESET, DATA, READONLY
EXPORT __Vectors
EXPORT __Vectors_End
EXPORT __Vectors_Size
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD MemManage_Handler ; MPU Fault Handler
DCD BusFault_Handler ; Bus Fault Handler
DCD UsageFault_Handler ; Usage Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD DebugMon_Handler ; Debug Monitor Handler
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
; External Interrupts
DCD WWDG_IRQHandler ; Window Watchdog
DCD PVD_IRQHandler ; PVD through EXTI Line detect
DCD TAMPER_IRQHandler ; Tamper
DCD RTC_IRQHandler ; RTC
DCD FLASH_IRQHandler ; Flash
DCD RCC_IRQHandler ; RCC
DCD EXTI0_IRQHandler ; EXTI Line 0
DCD EXTI1_IRQHandler ; EXTI Line 1
DCD EXTI2_IRQHandler ; EXTI Line 2
DCD EXTI3_IRQHandler ; EXTI Line 3
DCD EXTI4_IRQHandler ; EXTI Line 4
DCD DMA1_Channel1_IRQHandler ; DMA1 Channel 1
DCD DMA1_Channel2_IRQHandler ; DMA1 Channel 2
DCD DMA1_Channel3_IRQHandler ; DMA1 Channel 3
DCD DMA1_Channel4_IRQHandler ; DMA1 Channel 4
DCD DMA1_Channel5_IRQHandler ; DMA1 Channel 5
DCD DMA1_Channel6_IRQHandler ; DMA1 Channel 6
DCD DMA1_Channel7_IRQHandler ; DMA1 Channel 7
DCD ADC1_2_IRQHandler ; ADC1 & ADC2
DCD USB_HP_CAN1_TX_IRQHandler ; USB High Priority or CAN1 TX
DCD USB_LP_CAN1_RX0_IRQHandler ; USB Low Priority or CAN1 RX0
DCD CAN1_RX1_IRQHandler ; CAN1 RX1
DCD CAN1_SCE_IRQHandler ; CAN1 SCE
DCD EXTI9_5_IRQHandler ; EXTI Line 9..5
DCD TIM1_BRK_IRQHandler ; TIM1 Break
DCD TIM1_UP_IRQHandler ; TIM1 Update
DCD TIM1_TRG_COM_IRQHandler ; TIM1 Trigger and Commutation
DCD TIM1_CC_IRQHandler ; TIM1 Capture Compare
DCD TIM2_IRQHandler ; TIM2
DCD TIM3_IRQHandler ; TIM3
DCD TIM4_IRQHandler ; TIM4
DCD I2C1_EV_IRQHandler ; I2C1 Event
DCD I2C1_ER_IRQHandler ; I2C1 Error
DCD I2C2_EV_IRQHandler ; I2C2 Event
DCD I2C2_ER_IRQHandler ; I2C2 Error
DCD SPI1_IRQHandler ; SPI1
DCD SPI2_IRQHandler ; SPI2
DCD USART1_IRQHandler ; USART1
DCD USART2_IRQHandler ; USART2
DCD USART3_IRQHandler ; USART3
DCD EXTI15_10_IRQHandler ; EXTI Line 15..10
DCD RTC_Alarm_IRQHandler ; RTC Alarm through EXTI Line
DCD USBWakeUp_IRQHandler ; USB Wakeup from suspend
DCD TIM8_BRK_IRQHandler ; TIM8 Break
DCD TIM8_UP_IRQHandler ; TIM8 Update
DCD TIM8_TRG_COM_IRQHandler ; TIM8 Trigger and Commutation
DCD TIM8_CC_IRQHandler ; TIM8 Capture Compare
DCD ADC3_IRQHandler ; ADC3
DCD FSMC_IRQHandler ; FSMC
DCD SDIO_IRQHandler ; SDIO
DCD TIM5_IRQHandler ; TIM5
DCD SPI3_IRQHandler ; SPI3
DCD UART4_IRQHandler ; UART4
DCD UART5_IRQHandler ; UART5
DCD TIM6_IRQHandler ; TIM6
DCD TIM7_IRQHandler ; TIM7
DCD DMA2_Channel1_IRQHandler ; DMA2 Channel1
DCD DMA2_Channel2_IRQHandler ; DMA2 Channel2
DCD DMA2_Channel3_IRQHandler ; DMA2 Channel3
DCD DMA2_Channel4_5_IRQHandler ; DMA2 Channel4 & Channel5
__Vectors_End
-
通过指定
DATA
、READONLY
两个属性,这个段肯定会被放置在FLASH中,又因为RESET
这个特殊的段名,编译器会把这个段放置在FLASH中最开头的位置,对于当前芯片,地址就是0x08000000
。当这个段只被RESET或者RESET和DATA限定时,它也会被放在FLASH中,但是不是最开头的地方。
但只需要被RESET和READONLY限定,它就会被正确的放在
0x08000000
位置。这个我还不太明白,不过不影响启动分析,有懂的大佬可以帮忙解答一下。
-
EXPORT表示声明了三个全局标识(全局变量)
__Vectors
、__Vectors_End
、__Vectors_Size
,可以在其他文件里,如你的main.c
中引用这个变量(用前要用extern
关键字声明)。 -
接下来开始划分空间,使用
__Vectors
标识代表起始地址,后面跟了一堆DCD表示一个字一个字地申请空间并赋初值。 -
第一个字的地址里放了
__initial_sp
,这个正是前面栈区空间的结束地址。由于STM32的栈是自高地址向低地址(自上向下)生长的,所以这个地址也就是栈顶地址。
-
接下来放置了一个标识符
Reset_Handler
,这个其实是一个函数名,往下翻就能找到它的定义,它存放在了CODE
段。; Reset handler Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT __main IMPORT SystemInit LDR R0, =SystemInit BLX R0 LDR R0, =__main BX R0 ENDP
-
接下来放置了一个标识符
NMI_Handler
,这个其实也是一个函数名,往下翻就能找到它的定义,它也存放在了CODE
段。NMI_Handler PROC EXPORT NMI_Handler [WEAK] B . ENDP
-
接下来放置了一个标识符
HardFault_Handler
,这个其实也是一个函数名,往下翻就能找到它的定义,它也存放在了CODE
段。HardFault_Handler\ PROC EXPORT HardFault_Handler [WEAK] B . ENDP
-
接下来…
等等,下面这些都是函数名,而且都可以在文件下面找到它们的定义,这是在干什么?这就需要查阅芯片的参考手册了,在参考手册的2.4小节,是这样说明的:
在从待机模式退出时,BOOT引脚的值将被被重新锁存;因此,在待机模式下BOOT引脚应保持
为需要的启动配置。在启动延迟之后,CPU从地址0x0000 0000获取堆栈顶的地址,并从启动
存储器的0x0000 0004指示的地址开始执行代码。
因为固定的存储器映像,代码区始终从地址0x0000 0000开始(通过ICode和DCode总线访问),
而数据区(SRAM)始终从地址0x2000 0000开始(通过系统总线访问)。 Cortex-M3的CPU始终从
ICode总线获取复位向量,即启动仅适合于从代码区开始(典型地从Flash启动)。 STM32F10xxx
微控制器实现了一个特殊的机制,系统可以不仅仅从Flash存储器或系统存储器启动,还可以从
内置SRAM启动。
根据选定的启动模式,主闪存存储器、系统存储器或SRAM可以按照以下方式访问:
● 从主闪存存储器启动:主闪存存储器被映射到启动空间(0x0000 0000),但仍然能够在它原
有的地址(0x0800 0000)访问它,即闪存存储器的内容可以在两个地址区域访问, 0x0000
0000或0x0800 0000。
● 从系统存储器启动:系统存储器被映射到启动空间(0x0000 0000),但仍然能够在它原有的
地址(互联型产品原有地址为0x1FFF B000,其它产品原有地址为0x1FFF F000)访问它。
● 从内置SRAM启动:只能在0x2000 0000开始的地址区访问SRAM
也就是说,CPU总是在地址0x00000000
获取栈顶地址(这个地址将被赋值给主堆栈指针寄存器MSP
),而后在地址0x00000004
处获取开始执行代码的地址(这个地址将被赋值给程序计数器PC
),这个是内核所规定的。而通过不同启动模式的映射,在主闪存存储器启动的模式下,FLASH的地址0x08000000
被映射到了0x00000000
,这个是芯片厂家,即ST公司所规定的。
因此,通过对RESET
区的定义,地址0x08000000
存放了栈区栈顶的地址,供CPU使用,同时地址0x08000004
存放了启动函数Reset_Handler
的地址,供CPU从这里开始执行。
至此,CPU就可以愉快的拿到这两个最重要的地址,开始程序的执行啦。
Reset_Handler
函数下面定义的那些函数又是作什么的呢?
其实,对于cortex-m3内核来说,从地址0x00000000
开始的这段空间也同时作为了中断向量表(这个表是硬件上的定义,当发生了表中对应的中断事件时,CPU会到对应地址处取地址,执行该地址上的程序),我们可以在参考手册里看到中断向量表的定义:
看它们的名字,正好与RESET
区中的函数名称一致。再看右侧的地址,这里的地址并不是偏移地址,而是内核的取指地址,可以看到,地址为0x00000000
的地方没有定义,实际上由上面的分析我们知道,这里放了一个特殊的地址:堆栈指针的地址。而紧跟着的一个中断则是Reset复位中断,地址为0x08000004
这也正好与上面从启动存储器的0x0000 0004指示的地址开始执行代码相对应,在CPU复位后,即执行Reset复位中断。按照这个表的要求,我们在RESET
区中定义了每个地址所对应的函数地址(中断服务函数)。
代码区
AREA |.text|, CODE, READONLY
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
IMPORT SystemInit
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
; Dummy Exception Handlers (infinite loops which can be modified)
NMI_Handler PROC
EXPORT NMI_Handler [WEAK]
B .
ENDP
HardFault_Handler\
PROC
EXPORT HardFault_Handler [WEAK]
B .
ENDP
MemManage_Handler\
PROC
EXPORT MemManage_Handler [WEAK]
B .
ENDP
BusFault_Handler\
PROC
EXPORT BusFault_Handler [WEAK]
B .
ENDP
UsageFault_Handler\
PROC
EXPORT UsageFault_Handler [WEAK]
B .
ENDP
SVC_Handler PROC
EXPORT SVC_Handler [WEAK]
B .
ENDP
DebugMon_Handler\
PROC
EXPORT DebugMon_Handler [WEAK]
B .
ENDP
PendSV_Handler PROC
EXPORT PendSV_Handler [WEAK]
B .
ENDP
SysTick_Handler PROC
EXPORT SysTick_Handler [WEAK]
B .
ENDP
Default_Handler PROC
EXPORT WWDG_IRQHandler [WEAK]
EXPORT PVD_IRQHandler [WEAK]
EXPORT TAMPER_IRQHandler [WEAK]
EXPORT RTC_IRQHandler [WEAK]
EXPORT FLASH_IRQHandler [WEAK]
EXPORT RCC_IRQHandler [WEAK]
EXPORT EXTI0_IRQHandler [WEAK]
EXPORT EXTI1_IRQHandler [WEAK]
EXPORT EXTI2_IRQHandler [WEAK]
EXPORT EXTI3_IRQHandler [WEAK]
EXPORT EXTI4_IRQHandler [WEAK]
EXPORT DMA1_Channel1_IRQHandler [WEAK]
EXPORT DMA1_Channel2_IRQHandler [WEAK]
EXPORT DMA1_Channel3_IRQHandler [WEAK]
EXPORT DMA1_Channel4_IRQHandler [WEAK]
EXPORT DMA1_Channel5_IRQHandler [WEAK]
EXPORT DMA1_Channel6_IRQHandler [WEAK]
EXPORT DMA1_Channel7_IRQHandler [WEAK]
EXPORT ADC1_2_IRQHandler [WEAK]
EXPORT USB_HP_CAN1_TX_IRQHandler [WEAK]
EXPORT USB_LP_CAN1_RX0_IRQHandler [WEAK]
EXPORT CAN1_RX1_IRQHandler [WEAK]
EXPORT CAN1_SCE_IRQHandler [WEAK]
EXPORT EXTI9_5_IRQHandler [WEAK]
EXPORT TIM1_BRK_IRQHandler [WEAK]
EXPORT TIM1_UP_IRQHandler [WEAK]
EXPORT TIM1_TRG_COM_IRQHandler [WEAK]
EXPORT TIM1_CC_IRQHandler [WEAK]
EXPORT TIM2_IRQHandler [WEAK]
EXPORT TIM3_IRQHandler [WEAK]
EXPORT TIM4_IRQHandler [WEAK]
EXPORT I2C1_EV_IRQHandler [WEAK]
EXPORT I2C1_ER_IRQHandler [WEAK]
EXPORT I2C2_EV_IRQHandler [WEAK]
EXPORT I2C2_ER_IRQHandler [WEAK]
EXPORT SPI1_IRQHandler [WEAK]
EXPORT SPI2_IRQHandler [WEAK]
EXPORT USART1_IRQHandler [WEAK]
EXPORT USART2_IRQHandler [WEAK]
EXPORT USART3_IRQHandler [WEAK]
EXPORT EXTI15_10_IRQHandler [WEAK]
EXPORT RTC_Alarm_IRQHandler [WEAK]
EXPORT USBWakeUp_IRQHandler [WEAK]
EXPORT TIM8_BRK_IRQHandler [WEAK]
EXPORT TIM8_UP_IRQHandler [WEAK]
EXPORT TIM8_TRG_COM_IRQHandler [WEAK]
EXPORT TIM8_CC_IRQHandler [WEAK]
EXPORT ADC3_IRQHandler [WEAK]
EXPORT FSMC_IRQHandler [WEAK]
EXPORT SDIO_IRQHandler [WEAK]
EXPORT TIM5_IRQHandler [WEAK]
EXPORT SPI3_IRQHandler [WEAK]
EXPORT UART4_IRQHandler [WEAK]
EXPORT UART5_IRQHandler [WEAK]
EXPORT TIM6_IRQHandler [WEAK]
EXPORT TIM7_IRQHandler [WEAK]
EXPORT DMA2_Channel1_IRQHandler [WEAK]
EXPORT DMA2_Channel2_IRQHandler [WEAK]
EXPORT DMA2_Channel3_IRQHandler [WEAK]
EXPORT DMA2_Channel4_5_IRQHandler [WEAK]
WWDG_IRQHandler
PVD_IRQHandler
TAMPER_IRQHandler
RTC_IRQHandler
FLASH_IRQHandler
RCC_IRQHandler
EXTI0_IRQHandler
EXTI1_IRQHandler
EXTI2_IRQHandler
EXTI3_IRQHandler
EXTI4_IRQHandler
DMA1_Channel1_IRQHandler
DMA1_Channel2_IRQHandler
DMA1_Channel3_IRQHandler
DMA1_Channel4_IRQHandler
DMA1_Channel5_IRQHandler
DMA1_Channel6_IRQHandler
DMA1_Channel7_IRQHandler
ADC1_2_IRQHandler
USB_HP_CAN1_TX_IRQHandler
USB_LP_CAN1_RX0_IRQHandler
CAN1_RX1_IRQHandler
CAN1_SCE_IRQHandler
EXTI9_5_IRQHandler
TIM1_BRK_IRQHandler
TIM1_UP_IRQHandler
TIM1_TRG_COM_IRQHandler
TIM1_CC_IRQHandler
TIM2_IRQHandler
TIM3_IRQHandler
TIM4_IRQHandler
I2C1_EV_IRQHandler
I2C1_ER_IRQHandler
I2C2_EV_IRQHandler
I2C2_ER_IRQHandler
SPI1_IRQHandler
SPI2_IRQHandler
USART1_IRQHandler
USART2_IRQHandler
USART3_IRQHandler
EXTI15_10_IRQHandler
RTC_Alarm_IRQHandler
USBWakeUp_IRQHandler
TIM8_BRK_IRQHandler
TIM8_UP_IRQHandler
TIM8_TRG_COM_IRQHandler
TIM8_CC_IRQHandler
ADC3_IRQHandler
FSMC_IRQHandler
SDIO_IRQHandler
TIM5_IRQHandler
SPI3_IRQHandler
UART4_IRQHandler
UART5_IRQHandler
TIM6_IRQHandler
TIM7_IRQHandler
DMA2_Channel1_IRQHandler
DMA2_Channel2_IRQHandler
DMA2_Channel3_IRQHandler
DMA2_Channel4_5_IRQHandler
B .
ENDP
ALIGN
;*******************************************************************************
; User Stack and Heap initialization
;*******************************************************************************
IF :DEF:__MICROLIB
EXPORT __initial_sp
EXPORT __heap_base
EXPORT __heap_limit
ELSE
IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap
LDR R0, = Heap_Mem
LDR R1, =(Stack_Mem + Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR
ALIGN
ENDIF
END
后面的这些代码都放在了段区。
-
定义一个区域,名称叫做
.text
,代码段,只读。由于READONLY
和CODE
属性,这个段肯定会被放置在FLASH中。 -
后面的内容其实就是定义了那些在中断向量表中出现的函数名,由
PROC
与ENDP
包围的内容就是函数体,[WEAK]
指令表示该函数在这里的定义为弱定义,可以在其他文件中重新定义该函数。另外还定义了一个__user_initial_stackheap
函数用于在不使用微库__MICROLIB
时负责初始化堆栈。 -
特别的,对于
Default_Handler
函数,定义函数地址后使用EXPORT
导出各个中断服务函数的符号,随后跟了一堆只有标号的空指令,使用标号定义如WWDG_IRQHandler
等中断服务函数的地址,这使得这些中断服务函数的地址都与Default_Handler
地址相同。因此,当程序产生未被外部重新定义的中断的时候,就会进入到Default_Handler这个函数中执行,在这个函数的最后是一条指令B.
,它表示无条件跳转到当前指令的位置,即进入死循环。 -
在汇编文件的最后,定义了堆栈初始化的代码,表示如果定义了微库
__MICROLIB
,则不调用下面的堆栈初始化函数__user_initial_stackheap
,由微库进行初始化。若未定义微库,则使用__user_initial_stackheap
函数初始化堆栈。
微库在这里勾选使用。
STM32内存管理与.map文件分析
堆、栈、代码、全局变量、局部变量都是放在哪里的呢?它们之间又怎么组织的呢?如何分析软件的代码占用和运行占用呢?
我们从.map
文件入手分析,.map
文件是编译器生成的一种映射文件,主要用于描述程序的内存布局和符号信息。
段参考信息(Section Cross References)
Section Cross References
startup_stm32f103xe.o(RESET) refers to startup_stm32f103xe.o(STACK) for __initial_sp
startup_stm32f103xe.o(RESET) refers to startup_stm32f103xe.o(.text) for Reset_Handler
startup_stm32f103xe.o(RESET) refers to stm32f1xx_it.o(i.NMI_Handler) for NMI_Handler
startup_stm32f103xe.o(RESET) refers to stm32f1xx_it.o(i.HardFault_Handler) for HardFault_Handler
startup_stm32f103xe.o(RESET) refers to stm32f1xx_it.o(i.MemManage_Handler) for MemManage_Handler
startup_stm32f103xe.o(RESET) refers to stm32f1xx_it.o(i.BusFault_Handler) for BusFault_Handler
startup_stm32f103xe.o(RESET) refers to stm32f1xx_it.o(i.UsageFault_Handler) for UsageFault_Handler
...
...
文件中的第一段Section Cross References
提供了程序段之间的引用关系的详细信息,从RESET
函数开始,分析各个符合的链接来源,如第一行:__initial_sp
是从同一个对象文件(startup_stm32f103xe.o
)的 STACK
区域中解析的。
段移除信息(Removing Unused input sections from the image.)
Removing Unused input sections from the image.
Removing main.o(.rev16_text), (4 bytes).
Removing main.o(.revsh_text), (4 bytes).
Removing main.o(.rrx_text), (6 bytes).
Removing gpio.o(.rev16_text), (4 bytes).
Removing gpio.o(.revsh_text), (4 bytes).
...
...
第二段显示了编译器优化代码,移除未使用的空间的详细信息,如前三行我们可以看到从main.o
文件中移除了两个四字节的空间占用和一个六字节的空间占用。
内存符号表(Image Symbol Table)
符号表,这个表里显示了程序中的一些本地符号和全局符号,如段名、变量名等,分为两大部分,Local Symbols
,和Global Symbols
。
Local Symbols
Local Symbols
Symbol Name Value Ov Type Size Object(Section)
../Core/Src/gpio.c 0x00000000 Number 0 gpio.o ABSOLUTE
../Core/Src/main.c 0x00000000 Number 0 main.o ABSOLUTE
../Core/Src/stm32f1xx_hal_msp.c 0x00000000 Number 0 stm32f1xx_hal_msp.o ABSOLUTE
../Core/Src/stm32f1xx_it.c 0x00000000 Number 0 stm32f1xx_it.o ABSOLUTE
../Core/Src/system_stm32f1xx.c 0x00000000 Number 0 system_stm32f1xx.o ABSOLUTE
../Core/Src/usart.c 0x00000000 Number 0 usart.o ABSOLUTE
../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c 0x00000000 Number 0 stm32f1xx_hal.o ABSOLUTE
../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_cortex.c 0x00000000 Number 0 stm32f1xx_hal_cortex.o ABSOLUTE
../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_dma.c 0x00000000 Number 0 stm32f1xx_hal_dma.o ABSOLUTE
../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_exti.c 0x00000000 Number 0 stm32f1xx_hal_exti.o ABSOLUTE
../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_flash.c 0x00000000 Number 0 stm32f1xx_hal_flash.o ABSOLUTE
../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_flash_ex.c 0x00000000 Number 0 stm32f1xx_hal_flash_ex.o ABSOLUTE
../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio.c 0x00000000 Number 0 stm32f1xx_hal_gpio.o ABSOLUTE
../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio_ex.c 0x00000000 Number 0 stm32f1xx_hal_gpio_ex.o ABSOLUTE
../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_pwr.c 0x00000000 Number 0 stm32f1xx_hal_pwr.o ABSOLUTE
../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc.c 0x00000000 Number 0 stm32f1xx_hal_rcc.o ABSOLUTE
../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc_ex.c 0x00000000 Number 0 stm32f1xx_hal_rcc_ex.o ABSOLUTE
../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim.c 0x00000000 Number 0 stm32f1xx_hal_tim.o ABSOLUTE
../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim_ex.c 0x00000000 Number 0 stm32f1xx_hal_tim_ex.o ABSOLUTE
../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_uart.c 0x00000000 Number 0 stm32f1xx_hal_uart.o ABSOLUTE
../clib/microlib/division.c 0x00000000 Number 0 uldiv.o ABSOLUTE
../clib/microlib/division.c 0x00000000 Number 0 uidiv.o ABSOLUTE
../clib/microlib/init/entry.s 0x00000000 Number 0 entry9b.o ABSOLUTE
../clib/microlib/init/entry.s 0x00000000 Number 0 entry9a.o ABSOLUTE
../clib/microlib/init/entry.s 0x00000000 Number 0 entry8b.o ABSOLUTE
../clib/microlib/init/entry.s 0x00000000 Number 0 entry8a.o ABSOLUTE
../clib/microlib/init/entry.s 0x00000000 Number 0 entry7a.o ABSOLUTE
../clib/microlib/init/entry.s 0x00000000 Number 0 entry11b.o ABSOLUTE
../clib/microlib/init/entry.s 0x00000000 Number 0 entry7b.o ABSOLUTE
../clib/microlib/init/entry.s 0x00000000 Number 0 entry5.o ABSOLUTE
../clib/microlib/init/entry.s 0x00000000 Number 0 entry2.o ABSOLUTE
../clib/microlib/init/entry.s 0x00000000 Number 0 entry11a.o ABSOLUTE
../clib/microlib/init/entry.s 0x00000000 Number 0 entry.o ABSOLUTE
../clib/microlib/init/entry.s 0x00000000 Number 0 entry10b.o ABSOLUTE
../clib/microlib/init/entry.s 0x00000000 Number 0 entry10a.o ABSOLUTE
../clib/microlib/longlong.c 0x00000000 Number 0 llushr.o ABSOLUTE
../clib/microlib/longlong.c 0x00000000 Number 0 llsshr.o ABSOLUTE
../clib/microlib/longlong.c 0x00000000 Number 0 llshl.o ABSOLUTE
../clib/microlib/printf/printf.c 0x00000000 Number 0 printf4.o ABSOLUTE
../clib/microlib/printf/printf.c 0x00000000 Number 0 printfb.o ABSOLUTE
../clib/microlib/printf/printf.c 0x00000000 Number 0 printf1.o ABSOLUTE
../clib/microlib/printf/printf.c 0x00000000 Number 0 printf3.o ABSOLUTE
../clib/microlib/printf/printf.c 0x00000000 Number 0 printf5.o ABSOLUTE
../clib/microlib/printf/printf.c 0x00000000 Number 0 printf6.o ABSOLUTE
../clib/microlib/printf/printf.c 0x00000000 Number 0 printfa.o ABSOLUTE
../clib/microlib/printf/printf.c 0x00000000 Number 0 printf8.o ABSOLUTE
../clib/microlib/printf/printf.c 0x00000000 Number 0 printf7.o ABSOLUTE
../clib/microlib/printf/printf.c 0x00000000 Number 0 printf0.o ABSOLUTE
../clib/microlib/printf/printf.c 0x00000000 Number 0 printf2.o ABSOLUTE
../clib/microlib/printf/stubs.s 0x00000000 Number 0 stubs.o ABSOLUTE
../clib/microlib/stdio/fputc.c 0x00000000 Number 0 fputc.o ABSOLUTE
../clib/microlib/stdio/semi.s 0x00000000 Number 0 semi.o ABSOLUTE
../clib/microlib/stdio/streams.c 0x00000000 Number 0 stdout.o ABSOLUTE
../clib/microlib/string/memset.c 0x00000000 Number 0 memseta.o ABSOLUTE
../clib/microlib/string/strlen.c 0x00000000 Number 0 strlen.o ABSOLUTE
../clib/microlib/stubs.s 0x00000000 Number 0 iusefp.o ABSOLUTE
../clib/microlib/stubs.s 0x00000000 Number 0 iusesemip.o ABSOLUTE
../fplib/microlib/fpadd.c 0x00000000 Number 0 dadd.o ABSOLUTE
../fplib/microlib/fpdiv.c 0x00000000 Number 0 ddiv.o ABSOLUTE
../fplib/microlib/fpepilogue.c 0x00000000 Number 0 depilogue.o ABSOLUTE
../fplib/microlib/fpfix.c 0x00000000 Number 0 dfixul.o ABSOLUTE
../fplib/microlib/fpmul.c 0x00000000 Number 0 dmul.o ABSOLUTE
..\Core\Src\gpio.c 0x00000000 Number 0 gpio.o ABSOLUTE
..\Core\Src\main.c 0x00000000 Number 0 main.o ABSOLUTE
..\Core\Src\stm32f1xx_hal_msp.c 0x00000000 Number 0 stm32f1xx_hal_msp.o ABSOLUTE
..\Core\Src\stm32f1xx_it.c 0x00000000 Number 0 stm32f1xx_it.o ABSOLUTE
..\Core\Src\system_stm32f1xx.c 0x00000000 Number 0 system_stm32f1xx.o ABSOLUTE
..\Core\Src\usart.c 0x00000000 Number 0 usart.o ABSOLUTE
..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal.c 0x00000000 Number 0 stm32f1xx_hal.o ABSOLUTE
..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_cortex.c 0x00000000 Number 0 stm32f1xx_hal_cortex.o ABSOLUTE
..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_dma.c 0x00000000 Number 0 stm32f1xx_hal_dma.o ABSOLUTE
..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_exti.c 0x00000000 Number 0 stm32f1xx_hal_exti.o ABSOLUTE
..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_flash.c 0x00000000 Number 0 stm32f1xx_hal_flash.o ABSOLUTE
..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_flash_ex.c 0x00000000 Number 0 stm32f1xx_hal_flash_ex.o ABSOLUTE
..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_gpio.c 0x00000000 Number 0 stm32f1xx_hal_gpio.o ABSOLUTE
..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_gpio_ex.c 0x00000000 Number 0 stm32f1xx_hal_gpio_ex.o ABSOLUTE
..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_pwr.c 0x00000000 Number 0 stm32f1xx_hal_pwr.o ABSOLUTE
..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_rcc.c 0x00000000 Number 0 stm32f1xx_hal_rcc.o ABSOLUTE
..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_rcc_ex.c 0x00000000 Number 0 stm32f1xx_hal_rcc_ex.o ABSOLUTE
..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_tim.c 0x00000000 Number 0 stm32f1xx_hal_tim.o ABSOLUTE
..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_tim_ex.c 0x00000000 Number 0 stm32f1xx_hal_tim_ex.o ABSOLUTE
..\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_uart.c 0x00000000 Number 0 stm32f1xx_hal_uart.o ABSOLUTE
cdrcmple.s 0x00000000 Number 0 cdrcmple.o ABSOLUTE
dc.s 0x00000000 Number 0 dc.o ABSOLUTE
handlers.s 0x00000000 Number 0 handlers.o ABSOLUTE
init.s 0x00000000 Number 0 init.o ABSOLUTE
startup_stm32f103xe.s 0x00000000 Number 0 startup_stm32f103xe.o ABSOLUTE
RESET 0x08000000 Section 304 startup_stm32f103xe.o(RESET)
.ARM.Collect$$$$00000000 0x08000130 Section 0 entry.o(.ARM.Collect$$$$00000000)
.ARM.Collect$$$$00000001 0x08000130 Section 4 entry2.o(.ARM.Collect$$$$00000001)
.ARM.Collect$$$$00000004 0x08000134 Section 4 entry5.o(.ARM.Collect$$$$00000004)
.ARM.Collect$$$$00000008 0x08000138 Section 0 entry7b.o(.ARM.Collect$$$$00000008)
.ARM.Collect$$$$0000000A 0x08000138 Section 0 entry8b.o(.ARM.Collect$$$$0000000A)
.ARM.Collect$$$$0000000B 0x08000138 Section 8 entry9a.o(.ARM.Collect$$$$0000000B)
.ARM.Collect$$$$0000000D 0x08000140 Section 0 entry10a.o(.ARM.Collect$$$$0000000D)
.ARM.Collect$$$$0000000F 0x08000140 Section 0 entry11a.o(.ARM.Collect$$$$0000000F)
.ARM.Collect$$$$00002712 0x08000140 Section 4 entry2.o(.ARM.Collect$$$$00002712)
__lit__00000000 0x08000140 Data 4 entry2.o(.ARM.Collect$$$$00002712)
.text 0x08000144 Section 36 startup_stm32f103xe.o(.text)
.text 0x08000168 Section 0 llushr.o(.text)
.text 0x08000188 Section 0 memseta.o(.text)
.text 0x080001ac Section 0 strlen.o(.text)
.text 0x080001ba Section 0 uldiv.o(.text)
.text 0x0800021c Section 36 init.o(.text)
.text 0x08000240 Section 0 llshl.o(.text)
i.BusFault_Handler 0x0800025e Section 0 stm32f1xx_it.o(i.BusFault_Handler)
i.DebugMon_Handler 0x08000260 Section 0 stm32f1xx_it.o(i.DebugMon_Handler)
i.Error_Handler 0x08000262 Section 0 main.o(i.Error_Handler)
i.HAL_DMA_Abort 0x08000266 Section 0 stm32f1xx_hal_dma.o(i.HAL_DMA_Abort)
i.HAL_DMA_Abort_IT 0x080002ac Section 0 stm32f1xx_hal_dma.o(i.HAL_DMA_Abort_IT)
i.HAL_GPIO_Init 0x080003dc Section 0 stm32f1xx_hal_gpio.o(i.HAL_GPIO_Init)
i.HAL_GetTick 0x080005d4 Section 0 stm32f1xx_hal.o(i.HAL_GetTick)
i.HAL_IncTick 0x080005e0 Section 0 stm32f1xx_hal.o(i.HAL_IncTick)
i.HAL_Init 0x080005f0 Section 0 stm32f1xx_hal.o(i.HAL_Init)
i.HAL_InitTick 0x08000614 Section 0 stm32f1xx_hal.o(i.HAL_InitTick)
i.HAL_MspInit 0x08000654 Section 0 stm32f1xx_hal_msp.o(i.HAL_MspInit)
i.HAL_NVIC_EnableIRQ 0x08000690 Section 0 stm32f1xx_hal_cortex.o(i.HAL_NVIC_EnableIRQ)
i.HAL_NVIC_SetPriority 0x080006ac Section 0 stm32f1xx_hal_cortex.o(i.HAL_NVIC_SetPriority)
i.HAL_NVIC_SetPriorityGrouping 0x080006ec Section 0 stm32f1xx_hal_cortex.o(i.HAL_NVIC_SetPriorityGrouping)
i.HAL_RCC_ClockConfig 0x08000710 Section 0 stm32f1xx_hal_rcc.o(i.HAL_RCC_ClockConfig)
i.HAL_RCC_GetPCLK1Freq 0x0800083c Section 0 stm32f1xx_hal_rcc.o(i.HAL_RCC_GetPCLK1Freq)
i.HAL_RCC_GetPCLK2Freq 0x0800085c Section 0 stm32f1xx_hal_rcc.o(i.HAL_RCC_GetPCLK2Freq)
i.HAL_RCC_GetSysClockFreq 0x0800087c Section 0 stm32f1xx_hal_rcc.o(i.HAL_RCC_GetSysClockFreq)
i.HAL_RCC_OscConfig 0x080008c8 Section 0 stm32f1xx_hal_rcc.o(i.HAL_RCC_OscConfig)
i.HAL_SYSTICK_Config 0x08000be8 Section 0 stm32f1xx_hal_cortex.o(i.HAL_SYSTICK_Config)
i.HAL_UARTEx_RxEventCallback 0x08000c10 Section 0 stm32f1xx_hal_uart.o(i.HAL_UARTEx_RxEventCallback)
i.HAL_UART_ErrorCallback 0x08000c12 Section 0 stm32f1xx_hal_uart.o(i.HAL_UART_ErrorCallback)
i.HAL_UART_IRQHandler 0x08000c14 Section 0 stm32f1xx_hal_uart.o(i.HAL_UART_IRQHandler)
i.HAL_UART_Init 0x08000e80 Section 0 stm32f1xx_hal_uart.o(i.HAL_UART_Init)
i.HAL_UART_MspInit 0x08000ee4 Section 0 usart.o(i.HAL_UART_MspInit)
i.HAL_UART_RxCpltCallback 0x08000f64 Section 0 stm32f1xx_hal_uart.o(i.HAL_UART_RxCpltCallback)
i.HAL_UART_Transmit 0x08000f66 Section 0 stm32f1xx_hal_uart.o(i.HAL_UART_Transmit)
i.HAL_UART_TxCpltCallback 0x08001006 Section 0 stm32f1xx_hal_uart.o(i.HAL_UART_TxCpltCallback)
i.HardFault_Handler 0x08001008 Section 0 stm32f1xx_it.o(i.HardFault_Handler)
i.MX_GPIO_Init 0x0800100c Section 0 gpio.o(i.MX_GPIO_Init)
i.MX_USART1_UART_Init 0x08001048 Section 0 usart.o(i.MX_USART1_UART_Init)
i.MemManage_Handler 0x08001080 Section 0 stm32f1xx_it.o(i.MemManage_Handler)
i.NMI_Handler 0x08001082 Section 0 stm32f1xx_it.o(i.NMI_Handler)
i.PendSV_Handler 0x08001084 Section 0 stm32f1xx_it.o(i.PendSV_Handler)
i.SVC_Handler 0x08001086 Section 0 stm32f1xx_it.o(i.SVC_Handler)
i.SysTick_Handler 0x08001088 Section 0 stm32f1xx_it.o(i.SysTick_Handler)
i.SystemClock_Config 0x0800108c Section 0 main.o(i.SystemClock_Config)
i.SystemInit 0x080010ea Section 0 system_stm32f1xx.o(i.SystemInit)
i.UART_DMAAbortOnError 0x080010ec Section 0 stm32f1xx_hal_uart.o(i.UART_DMAAbortOnError)
UART_DMAAbortOnError 0x080010ed Thumb Code 16 stm32f1xx_hal_uart.o(i.UART_DMAAbortOnError)
i.UART_EndRxTransfer 0x080010fc Section 0 stm32f1xx_hal_uart.o(i.UART_EndRxTransfer)
UART_EndRxTransfer 0x080010fd Thumb Code 78 stm32f1xx_hal_uart.o(i.UART_EndRxTransfer)
i.UART_Receive_IT 0x0800114a Section 0 stm32f1xx_hal_uart.o(i.UART_Receive_IT)
UART_Receive_IT 0x0800114b Thumb Code 194 stm32f1xx_hal_uart.o(i.UART_Receive_IT)
i.UART_SetConfig 0x0800120c Section 0 stm32f1xx_hal_uart.o(i.UART_SetConfig)
UART_SetConfig 0x0800120d Thumb Code 178 stm32f1xx_hal_uart.o(i.UART_SetConfig)
i.UART_WaitOnFlagUntilTimeout 0x080012c4 Section 0 stm32f1xx_hal_uart.o(i.UART_WaitOnFlagUntilTimeout)
UART_WaitOnFlagUntilTimeout 0x080012c5 Thumb Code 114 stm32f1xx_hal_uart.o(i.UART_WaitOnFlagUntilTimeout)
i.USART1_IRQHandler 0x08001338 Section 0 stm32f1xx_it.o(i.USART1_IRQHandler)
i.UsageFault_Handler 0x08001344 Section 0 stm32f1xx_it.o(i.UsageFault_Handler)
i.__0sprintf$8 0x08001348 Section 0 printf8.o(i.__0sprintf$8)
i.__NVIC_SetPriority 0x08001370 Section 0 stm32f1xx_hal_cortex.o(i.__NVIC_SetPriority)
__NVIC_SetPriority 0x08001371 Thumb Code 32 stm32f1xx_hal_cortex.o(i.__NVIC_SetPriority)
i.__scatterload_copy 0x08001390 Section 14 handlers.o(i.__scatterload_copy)
i.__scatterload_null 0x0800139e Section 2 handlers.o(i.__scatterload_null)
i.__scatterload_zeroinit 0x080013a0 Section 14 handlers.o(i.__scatterload_zeroinit)
i._printf_core 0x080013b0 Section 0 printf8.o(i._printf_core)
_printf_core 0x080013b1 Thumb Code 996 printf8.o(i._printf_core)
i._printf_post_padding 0x080017c0 Section 0 printf8.o(i._printf_post_padding)
_printf_post_padding 0x080017c1 Thumb Code 36 printf8.o(i._printf_post_padding)
i._printf_pre_padding 0x080017e4 Section 0 printf8.o(i._printf_pre_padding)
_printf_pre_padding 0x080017e5 Thumb Code 46 printf8.o(i._printf_pre_padding)
i._sputc 0x08001812 Section 0 printf8.o(i._sputc)
_sputc 0x08001813 Thumb Code 10 printf8.o(i._sputc)
i.main 0x0800181c Section 0 main.o(i.main)
.constdata 0x080018a8 Section 18 stm32f1xx_hal_rcc.o(.constdata)
aPredivFactorTable 0x080018a8 Data 2 stm32f1xx_hal_rcc.o(.constdata)
aPLLMULFactorTable 0x080018aa Data 16 stm32f1xx_hal_rcc.o(.constdata)
.constdata 0x080018ba Section 16 system_stm32f1xx.o(.constdata)
.constdata 0x080018ca Section 8 system_stm32f1xx.o(.constdata)
.data 0x20000000 Section 8 main.o(.data)
localVar 0x20000004 Data 4 main.o(.data)
.data 0x20000008 Section 12 stm32f1xx_hal.o(.data)
.data 0x20000014 Section 4 system_stm32f1xx.o(.data)
.bss 0x20000018 Section 72 usart.o(.bss)
HEAP 0x20000060 Section 512 startup_stm32f103xe.o(HEAP)
STACK 0x20000260 Section 1024 startup_stm32f103xe.o(STACK)
从这个例子里分析,每列依次代表:符号名、符号的值、类型、占用空间、对象(来源)。
其中,类型主要有以下几种
Number:代表这只是一个标志,比如文件名(这个其实是猜想,不太确定),Number类型的符号都不占用空间,所以一般无关紧要。
Section:代表这是一个段,这个和汇编文件中的段是一个意思,我们可以看到在.s
文件里定义的段名都在这里,比如HEAP
,STACK
。同时里面还有一些别的段,像.text
、i.Error_Handler
是它所对应的后面的C文件或者汇编文件中所定义的段。
Data:代表这是一个数据,其实这个就是C语言中我们所定义的本地静态变量,比如,我们在启动文件中加这样一行:
static uint32_t localVar[2];
就可以在表里看到
localVar 0x20000004 Data 8 main.o(.data)
这个变量出现了,地址放在了0x20000004
的位置(SRAM区),占用空间为8字节。烧写进MCU并使用串口打印这个变量的地址,可以看到这个变量的地址和.map
文件中的一致。
&localVar = 0x20000004 //这是串口打印的数据
.bss:特别的,.bss
也是一个段(类型为Selection),这个段里放置了在其他文件里未初始化的全局变量。
Global Symbols
Global Symbols
Symbol Name Value Ov Type Size Object(Section)
BuildAttributes$$THM_ISAv4$P$D$K$B$S$PE$A:L22UL41UL21$X:L11$S22US41US21$IEEE1$IW$USESV6$~STKCKD$USESV7$~SHL$OSPACE$ROPI$EBA8$MICROLIB$REQ8$PRES8$EABIv2 0x00000000 Number 0 anon$$obj.o ABSOLUTE
__ARM_use_no_argv 0x00000000 Number 0 main.o ABSOLUTE
_printf_a 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_c 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_charcount 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_d 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_e 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_f 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_flags 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_fp_dec 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_fp_hex 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_g 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_i 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_int_dec 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_l 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_lc 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_ll 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_lld 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_lli 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_llo 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_llu 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_llx 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_longlong_dec 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_longlong_hex 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_longlong_oct 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_ls 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_mbtowc 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_n 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_o 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_p 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_percent 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_pre_padding 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_return_value 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_s 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_sizespec 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_str 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_truncate_signed 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_truncate_unsigned 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_u 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_wc 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_wctomb 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_widthprec 0x00000000 Number 0 stubs.o ABSOLUTE
_printf_x 0x00000000 Number 0 stubs.o ABSOLUTE
__cpp_initialize__aeabi_ - Undefined Weak Reference
__cxa_finalize - Undefined Weak Reference
__decompress - Undefined Weak Reference
_clock_init - Undefined Weak Reference
_microlib_exit - Undefined Weak Reference
__Vectors_Size 0x00000130 Number 0 startup_stm32f103xe.o ABSOLUTE
__Vectors 0x08000000 Data 4 startup_stm32f103xe.o(RESET)
__Vectors_End 0x08000130 Data 0 startup_stm32f103xe.o(RESET)
__main 0x08000131 Thumb Code 0 entry.o(.ARM.Collect$$$$00000000)
_main_stk 0x08000131 Thumb Code 0 entry2.o(.ARM.Collect$$$$00000001)
_main_scatterload 0x08000135 Thumb Code 0 entry5.o(.ARM.Collect$$$$00000004)
__main_after_scatterload 0x08000139 Thumb Code 0 entry5.o(.ARM.Collect$$$$00000004)
_main_clock 0x08000139 Thumb Code 0 entry7b.o(.ARM.Collect$$$$00000008)
_main_cpp_init 0x08000139 Thumb Code 0 entry8b.o(.ARM.Collect$$$$0000000A)
_main_init 0x08000139 Thumb Code 0 entry9a.o(.ARM.Collect$$$$0000000B)
__rt_final_cpp 0x08000141 Thumb Code 0 entry10a.o(.ARM.Collect$$$$0000000D)
__rt_final_exit 0x08000141 Thumb Code 0 entry11a.o(.ARM.Collect$$$$0000000F)
Reset_Handler 0x08000145 Thumb Code 8 startup_stm32f103xe.o(.text)
ADC1_2_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
ADC3_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
CAN1_RX1_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
CAN1_SCE_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
DMA1_Channel1_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
DMA1_Channel2_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
DMA1_Channel3_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
DMA1_Channel4_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
DMA1_Channel5_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
DMA1_Channel6_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
DMA1_Channel7_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
DMA2_Channel1_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
DMA2_Channel2_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
DMA2_Channel3_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
DMA2_Channel4_5_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
EXTI0_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
EXTI15_10_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
EXTI1_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
EXTI2_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
EXTI3_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
EXTI4_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
EXTI9_5_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
FLASH_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
FSMC_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
I2C1_ER_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
I2C1_EV_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
I2C2_ER_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
I2C2_EV_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
PVD_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
RCC_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
RTC_Alarm_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
RTC_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
SDIO_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
SPI1_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
SPI2_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
SPI3_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
TAMPER_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
TIM1_BRK_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
TIM1_CC_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
TIM1_TRG_COM_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
TIM1_UP_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
TIM2_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
TIM3_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
TIM4_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
TIM5_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
TIM6_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
TIM7_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
TIM8_BRK_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
TIM8_CC_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
TIM8_TRG_COM_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
TIM8_UP_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
UART4_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
UART5_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
USART2_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
USART3_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
USBWakeUp_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
USB_HP_CAN1_TX_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
USB_LP_CAN1_RX0_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
WWDG_IRQHandler 0x0800015f Thumb Code 0 startup_stm32f103xe.o(.text)
__aeabi_llsr 0x08000169 Thumb Code 32 llushr.o(.text)
_ll_ushift_r 0x08000169 Thumb Code 0 llushr.o(.text)
__aeabi_memset 0x08000189 Thumb Code 14 memseta.o(.text)
__aeabi_memset4 0x08000189 Thumb Code 0 memseta.o(.text)
__aeabi_memset8 0x08000189 Thumb Code 0 memseta.o(.text)
__aeabi_memclr 0x08000197 Thumb Code 4 memseta.o(.text)
__aeabi_memclr4 0x08000197 Thumb Code 0 memseta.o(.text)
__aeabi_memclr8 0x08000197 Thumb Code 0 memseta.o(.text)
_memset$wrapper 0x0800019b Thumb Code 18 memseta.o(.text)
strlen 0x080001ad Thumb Code 14 strlen.o(.text)
__aeabi_uldivmod 0x080001bb Thumb Code 98 uldiv.o(.text)
__scatterload 0x0800021d Thumb Code 28 init.o(.text)
__scatterload_rt2 0x0800021d Thumb Code 0 init.o(.text)
__aeabi_llsl 0x08000241 Thumb Code 30 llshl.o(.text)
_ll_shift_l 0x08000241 Thumb Code 0 llshl.o(.text)
BusFault_Handler 0x0800025f Thumb Code 2 stm32f1xx_it.o(i.BusFault_Handler)
DebugMon_Handler 0x08000261 Thumb Code 2 stm32f1xx_it.o(i.DebugMon_Handler)
Error_Handler 0x08000263 Thumb Code 4 main.o(i.Error_Handler)
HAL_DMA_Abort 0x08000267 Thumb Code 70 stm32f1xx_hal_dma.o(i.HAL_DMA_Abort)
HAL_DMA_Abort_IT 0x080002ad Thumb Code 296 stm32f1xx_hal_dma.o(i.HAL_DMA_Abort_IT)
HAL_GPIO_Init 0x080003dd Thumb Code 462 stm32f1xx_hal_gpio.o(i.HAL_GPIO_Init)
HAL_GetTick 0x080005d5 Thumb Code 6 stm32f1xx_hal.o(i.HAL_GetTick)
HAL_IncTick 0x080005e1 Thumb Code 12 stm32f1xx_hal.o(i.HAL_IncTick)
HAL_Init 0x080005f1 Thumb Code 32 stm32f1xx_hal.o(i.HAL_Init)
HAL_InitTick 0x08000615 Thumb Code 54 stm32f1xx_hal.o(i.HAL_InitTick)
HAL_MspInit 0x08000655 Thumb Code 52 stm32f1xx_hal_msp.o(i.HAL_MspInit)
HAL_NVIC_EnableIRQ 0x08000691 Thumb Code 26 stm32f1xx_hal_cortex.o(i.HAL_NVIC_EnableIRQ)
HAL_NVIC_SetPriority 0x080006ad Thumb Code 60 stm32f1xx_hal_cortex.o(i.HAL_NVIC_SetPriority)
HAL_NVIC_SetPriorityGrouping 0x080006ed Thumb Code 26 stm32f1xx_hal_cortex.o(i.HAL_NVIC_SetPriorityGrouping)
HAL_RCC_ClockConfig 0x08000711 Thumb Code 280 stm32f1xx_hal_rcc.o(i.HAL_RCC_ClockConfig)
HAL_RCC_GetPCLK1Freq 0x0800083d Thumb Code 20 stm32f1xx_hal_rcc.o(i.HAL_RCC_GetPCLK1Freq)
HAL_RCC_GetPCLK2Freq 0x0800085d Thumb Code 20 stm32f1xx_hal_rcc.o(i.HAL_RCC_GetPCLK2Freq)
HAL_RCC_GetSysClockFreq 0x0800087d Thumb Code 58 stm32f1xx_hal_rcc.o(i.HAL_RCC_GetSysClockFreq)
HAL_RCC_OscConfig 0x080008c9 Thumb Code 778 stm32f1xx_hal_rcc.o(i.HAL_RCC_OscConfig)
HAL_SYSTICK_Config 0x08000be9 Thumb Code 40 stm32f1xx_hal_cortex.o(i.HAL_SYSTICK_Config)
HAL_UARTEx_RxEventCallback 0x08000c11 Thumb Code 2 stm32f1xx_hal_uart.o(i.HAL_UARTEx_RxEventCallback)
HAL_UART_ErrorCallback 0x08000c13 Thumb Code 2 stm32f1xx_hal_uart.o(i.HAL_UART_ErrorCallback)
HAL_UART_IRQHandler 0x08000c15 Thumb Code 616 stm32f1xx_hal_uart.o(i.HAL_UART_IRQHandler)
HAL_UART_Init 0x08000e81 Thumb Code 100 stm32f1xx_hal_uart.o(i.HAL_UART_Init)
HAL_UART_MspInit 0x08000ee5 Thumb Code 116 usart.o(i.HAL_UART_MspInit)
HAL_UART_RxCpltCallback 0x08000f65 Thumb Code 2 stm32f1xx_hal_uart.o(i.HAL_UART_RxCpltCallback)
HAL_UART_Transmit 0x08000f67 Thumb Code 160 stm32f1xx_hal_uart.o(i.HAL_UART_Transmit)
HAL_UART_TxCpltCallback 0x08001007 Thumb Code 2 stm32f1xx_hal_uart.o(i.HAL_UART_TxCpltCallback)
HardFault_Handler 0x08001009 Thumb Code 2 stm32f1xx_it.o(i.HardFault_Handler)
MX_GPIO_Init 0x0800100d Thumb Code 54 gpio.o(i.MX_GPIO_Init)
MX_USART1_UART_Init 0x08001049 Thumb Code 48 usart.o(i.MX_USART1_UART_Init)
MemManage_Handler 0x08001081 Thumb Code 2 stm32f1xx_it.o(i.MemManage_Handler)
NMI_Handler 0x08001083 Thumb Code 2 stm32f1xx_it.o(i.NMI_Handler)
PendSV_Handler 0x08001085 Thumb Code 2 stm32f1xx_it.o(i.PendSV_Handler)
SVC_Handler 0x08001087 Thumb Code 2 stm32f1xx_it.o(i.SVC_Handler)
SysTick_Handler 0x08001089 Thumb Code 4 stm32f1xx_it.o(i.SysTick_Handler)
SystemClock_Config 0x0800108d Thumb Code 94 main.o(i.SystemClock_Config)
SystemInit 0x080010eb Thumb Code 2 system_stm32f1xx.o(i.SystemInit)
USART1_IRQHandler 0x08001339 Thumb Code 6 stm32f1xx_it.o(i.USART1_IRQHandler)
UsageFault_Handler 0x08001345 Thumb Code 2 stm32f1xx_it.o(i.UsageFault_Handler)
__0sprintf$8 0x08001349 Thumb Code 34 printf8.o(i.__0sprintf$8)
__1sprintf$8 0x08001349 Thumb Code 0 printf8.o(i.__0sprintf$8)
__2sprintf 0x08001349 Thumb Code 0 printf8.o(i.__0sprintf$8)
__scatterload_copy 0x08001391 Thumb Code 14 handlers.o(i.__scatterload_copy)
__scatterload_null 0x0800139f Thumb Code 2 handlers.o(i.__scatterload_null)
__scatterload_zeroinit 0x080013a1 Thumb Code 14 handlers.o(i.__scatterload_zeroinit)
main 0x0800181d Thumb Code 78 main.o(i.main)
AHBPrescTable 0x08001892 Data 16 system_stm32f1xx.o(.constdata)
APBPrescTable 0x080018a2 Data 8 system_stm32f1xx.o(.constdata)
Region$$Table$$Base 0x08001908 Number 0 anon$$obj.o(Region$$Table)
Region$$Table$$Limit 0x08001928 Number 0 anon$$obj.o(Region$$Table)
globalVar 0x20000008 Data 8 main.o(.data)
uwTickFreq 0x20000010 Data 1 stm32f1xx_hal.o(.data)
uwTickPrio 0x20000014 Data 4 stm32f1xx_hal.o(.data)
uwTick 0x20000018 Data 4 stm32f1xx_hal.o(.data)
SystemCoreClock 0x2000001c Data 4 system_stm32f1xx.o(.data)
huart1 0x20000020 Data 72 usart.o(.bss)
gloablVarUsart 0x20000068 Data 40 usart.o(.bss)
Heap_Mem 0x20000090 Data 512 startup_stm32f103xe.o(HEAP)
__heap_base 0x20000090 Data 0 startup_stm32f103xe.o(HEAP)
__heap_limit 0x20000290 Data 0 startup_stm32f103xe.o(HEAP)
__initial_sp 0x20000690 Data 0 startup_stm32f103xe.o(STACK)
这里放置了一些全局符号,像startup_stm32f103xe.o
中使用EXPORT
导出的符号就会出现在这个表里,你可以尝试使用EXPORT HEAP
这样的汇编语句把Local Symbols里的符号声明为全局,那么它就会从本地符号的表中消失,再出现在全局符号的表里了。
像
entry.o
·entry2.o
这样的文件是由编译器生成的,用于初始化堆栈以及完成进入main
函数之前的一些必要操作,比如启动文件里的__main
函数就来自于entry.o
,可以在Section Cross References
表中看到它们的关系。startup_stm32f103xe.o(.text) refers to entry.o(.ARM.Collect$$$$00000000) for __main
内存映射表(Memory Map of the image)
**划重点,这部分最重要。**这个部分描述了程序镜像的加载和执行布局。这部分的前两行如下:
Image Entry point : 0x08000131
Load Region LR_IROM1 (Base: 0x08000000, Size: 0x00001964, Max: 0x00040000, ABSOLUTE)
第一行说明了程序的入点,也就是Reset_Handler
函数所在的地址。(编译器如何知道Reset_Handler
是入口呢?这个我没查到)
第二行写明了程序的加载域,域名称为LR_IROM1
,基地址为0x08000000
,实际占用大小为0x00001964
,即6472字节,最大大小为0x00040000
。ABSOLUTE
表示这个区域的地址是固定的,不能被动态调整。其中基地址和大小都是在Target
标签中设置的。
后面分为两个部分,详细描述了两个执行域内的内存分布结构,分别为:
Execution Region ER_IROM1 (Exec base: 0x08000000, Load base: 0x08000000, Size: 0x00001944, Max: 0x00040000, ABSOLUTE)
Execution Region RW_IRAM1 (Exec base: 0x20000000, Load base: 0x08001944, Size: 0x00000690, Max: 0x0000c000, ABSOLUTE)
区域一叫做ER_IROM1
,基地址0x08000000
,这个区域其实就是要存放在FLASH中的区域。
区域二叫做RW_IRAM1
,基地址0x20000000
,这个区域就是要存放在SRAM中的区域。
这几个区域是在哪里定义的呢,我们可以在输出文件夹里找到后缀为.sct
的分散加载文件,这个文件就是MDK根据Target标签下的地址所生成的文件。
在Linker标签下,只要勾选了Use Memory Layout from Target Dialog
,就会自动生成这个分散加载文件,取消勾选这个选项,可以自定义自己的分散加载文件。
这个文件的内容如下:
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x08000000 0x00040000 { ; load region size_region
ER_IROM1 0x08000000 0x00040000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x0000C000 { ; RW data
.ANY (+RW +ZI)
}
}
第一句定义了一个 加载域(Load Region),表示一段存储器区域的起始地址和大小。
第二句定义了一个执行域,叫做ER_IROM1
,表示程序运行时的代码和只读数据所在的存储器区域,在地址0x08000000
中存放,其中包括:
*.o (RESET, +First):+First
表示将 RESET 段(复位处理程序)放在区域的开头,并优先加载。(现在知道为什么必须要定义RESET
域了吧)
*(InRoot$$Sections):用于放置一些与启动相关的特殊段。
.ANY (+RO):分配任意的只读段(放置常量)。
随后定义了一个执行域,叫做RW_IRAM1
,即读写数据区域,在地址0x20000000
中存放,其中包括:
回到.map
文件,我们可以看到这两个域:ER_IROM1
和RW_IRAM1
的内存映像。
ER_IROM1域
Execution Region ER_IROM1 (Exec base: 0x08000000, Load base: 0x08000000, Size: 0x00001944, Max: 0x00040000, ABSOLUTE)
Exec Addr Load Addr Size Type Attr Idx E Section Name Object
0x08000000 0x08000000 0x00000130 Data RO 3 RESET startup_stm32f103xe.o
0x08000130 0x08000130 0x00000000 Code RO 1769 * .ARM.Collect$$$$00000000 mc_w.l(entry.o)
0x08000130 0x08000130 0x00000004 Code RO 2039 .ARM.Collect$$$$00000001 mc_w.l(entry2.o)
0x08000134 0x08000134 0x00000004 Code RO 2042 .ARM.Collect$$$$00000004 mc_w.l(entry5.o)
0x08000138 0x08000138 0x00000000 Code RO 2044 .ARM.Collect$$$$00000008 mc_w.l(entry7b.o)
0x08000138 0x08000138 0x00000000 Code RO 2046 .ARM.Collect$$$$0000000A mc_w.l(entry8b.o)
0x08000138 0x08000138 0x00000008 Code RO 2047 .ARM.Collect$$$$0000000B mc_w.l(entry9a.o)
0x08000140 0x08000140 0x00000000 Code RO 2049 .ARM.Collect$$$$0000000D mc_w.l(entry10a.o)
0x08000140 0x08000140 0x00000000 Code RO 2051 .ARM.Collect$$$$0000000F mc_w.l(entry11a.o)
0x08000140 0x08000140 0x00000004 Code RO 2040 .ARM.Collect$$$$00002712 mc_w.l(entry2.o)
0x08000144 0x08000144 0x00000024 Code RO 4 .text startup_stm32f103xe.o
0x08000168 0x08000168 0x00000020 Code RO 1772 .text mc_w.l(llushr.o)
0x08000188 0x08000188 0x00000024 Code RO 1774 .text mc_w.l(memseta.o)
0x080001ac 0x080001ac 0x0000000e Code RO 1776 .text mc_w.l(strlen.o)
0x080001ba 0x080001ba 0x00000062 Code RO 2058 .text mc_w.l(uldiv.o)
0x0800021c 0x0800021c 0x00000024 Code RO 2071 .text mc_w.l(init.o)
0x08000240 0x08000240 0x0000001e Code RO 2074 .text mc_w.l(llshl.o)
0x0800025e 0x0800025e 0x00000002 Code RO 216 i.BusFault_Handler stm32f1xx_it.o
0x08000260 0x08000260 0x00000002 Code RO 217 i.DebugMon_Handler stm32f1xx_it.o
0x08000262 0x08000262 0x00000004 Code RO 13 i.Error_Handler main.o
0x08000266 0x08000266 0x00000046 Code RO 1138 i.HAL_DMA_Abort stm32f1xx_hal_dma.o
0x080002ac 0x080002ac 0x00000130 Code RO 1139 i.HAL_DMA_Abort_IT stm32f1xx_hal_dma.o
0x080003dc 0x080003dc 0x000001f8 Code RO 1074 i.HAL_GPIO_Init stm32f1xx_hal_gpio.o
0x080005d4 0x080005d4 0x0000000c Code RO 768 i.HAL_GetTick stm32f1xx_hal.o
0x080005e0 0x080005e0 0x00000010 Code RO 774 i.HAL_IncTick stm32f1xx_hal.o
0x080005f0 0x080005f0 0x00000024 Code RO 775 i.HAL_Init stm32f1xx_hal.o
0x08000614 0x08000614 0x00000040 Code RO 776 i.HAL_InitTick stm32f1xx_hal.o
0x08000654 0x08000654 0x0000003c Code RO 298 i.HAL_MspInit stm32f1xx_hal_msp.o
0x08000690 0x08000690 0x0000001a Code RO 1234 i.HAL_NVIC_EnableIRQ stm32f1xx_hal_cortex.o
0x080006aa 0x080006aa 0x00000002 PAD
0x080006ac 0x080006ac 0x00000040 Code RO 1240 i.HAL_NVIC_SetPriority stm32f1xx_hal_cortex.o
0x080006ec 0x080006ec 0x00000024 Code RO 1241 i.HAL_NVIC_SetPriorityGrouping stm32f1xx_hal_cortex.o
0x08000710 0x08000710 0x0000012c Code RO 932 i.HAL_RCC_ClockConfig stm32f1xx_hal_rcc.o
0x0800083c 0x0800083c 0x00000020 Code RO 939 i.HAL_RCC_GetPCLK1Freq stm32f1xx_hal_rcc.o
0x0800085c 0x0800085c 0x00000020 Code RO 940 i.HAL_RCC_GetPCLK2Freq stm32f1xx_hal_rcc.o
0x0800087c 0x0800087c 0x0000004c Code RO 941 i.HAL_RCC_GetSysClockFreq stm32f1xx_hal_rcc.o
0x080008c8 0x080008c8 0x00000320 Code RO 944 i.HAL_RCC_OscConfig stm32f1xx_hal_rcc.o
0x08000be8 0x08000be8 0x00000028 Code RO 1245 i.HAL_SYSTICK_Config stm32f1xx_hal_cortex.o
0x08000c10 0x08000c10 0x00000002 Code RO 406 i.HAL_UARTEx_RxEventCallback stm32f1xx_hal_uart.o
0x08000c12 0x08000c12 0x00000002 Code RO 420 i.HAL_UART_ErrorCallback stm32f1xx_hal_uart.o
0x08000c14 0x08000c14 0x0000026c Code RO 423 i.HAL_UART_IRQHandler stm32f1xx_hal_uart.o
0x08000e80 0x08000e80 0x00000064 Code RO 424 i.HAL_UART_Init stm32f1xx_hal_uart.o
0x08000ee4 0x08000ee4 0x00000080 Code RO 174 i.HAL_UART_MspInit usart.o
0x08000f64 0x08000f64 0x00000002 Code RO 430 i.HAL_UART_RxCpltCallback stm32f1xx_hal_uart.o
0x08000f66 0x08000f66 0x000000a0 Code RO 432 i.HAL_UART_Transmit stm32f1xx_hal_uart.o
0x08001006 0x08001006 0x00000002 Code RO 435 i.HAL_UART_TxCpltCallback stm32f1xx_hal_uart.o
0x08001008 0x08001008 0x00000002 Code RO 218 i.HardFault_Handler stm32f1xx_it.o
0x0800100a 0x0800100a 0x00000002 PAD
0x0800100c 0x0800100c 0x0000003c Code RO 149 i.MX_GPIO_Init gpio.o
0x08001048 0x08001048 0x00000038 Code RO 175 i.MX_USART1_UART_Init usart.o
0x08001080 0x08001080 0x00000002 Code RO 219 i.MemManage_Handler stm32f1xx_it.o
0x08001082 0x08001082 0x00000002 Code RO 220 i.NMI_Handler stm32f1xx_it.o
0x08001084 0x08001084 0x00000002 Code RO 221 i.PendSV_Handler stm32f1xx_it.o
0x08001086 0x08001086 0x00000002 Code RO 222 i.SVC_Handler stm32f1xx_it.o
0x08001088 0x08001088 0x00000004 Code RO 223 i.SysTick_Handler stm32f1xx_it.o
0x0800108c 0x0800108c 0x0000005e Code RO 14 i.SystemClock_Config main.o
0x080010ea 0x080010ea 0x00000002 Code RO 1735 i.SystemInit system_stm32f1xx.o
0x080010ec 0x080010ec 0x00000010 Code RO 437 i.UART_DMAAbortOnError stm32f1xx_hal_uart.o
0x080010fc 0x080010fc 0x0000004e Code RO 447 i.UART_EndRxTransfer stm32f1xx_hal_uart.o
0x0800114a 0x0800114a 0x000000c2 Code RO 449 i.UART_Receive_IT stm32f1xx_hal_uart.o
0x0800120c 0x0800120c 0x000000b8 Code RO 450 i.UART_SetConfig stm32f1xx_hal_uart.o
0x080012c4 0x080012c4 0x00000072 Code RO 453 i.UART_WaitOnFlagUntilTimeout stm32f1xx_hal_uart.o
0x08001336 0x08001336 0x00000002 PAD
0x08001338 0x08001338 0x0000000c Code RO 224 i.USART1_IRQHandler stm32f1xx_it.o
0x08001344 0x08001344 0x00000002 Code RO 225 i.UsageFault_Handler stm32f1xx_it.o
0x08001346 0x08001346 0x00000002 PAD
0x08001348 0x08001348 0x00000028 Code RO 1987 i.__0sprintf$8 mc_w.l(printf8.o)
0x08001370 0x08001370 0x00000020 Code RO 1247 i.__NVIC_SetPriority stm32f1xx_hal_cortex.o
0x08001390 0x08001390 0x0000000e Code RO 2083 i.__scatterload_copy mc_w.l(handlers.o)
0x0800139e 0x0800139e 0x00000002 Code RO 2084 i.__scatterload_null mc_w.l(handlers.o)
0x080013a0 0x080013a0 0x0000000e Code RO 2085 i.__scatterload_zeroinit mc_w.l(handlers.o)
0x080013ae 0x080013ae 0x00000002 PAD
0x080013b0 0x080013b0 0x00000410 Code RO 1992 i._printf_core mc_w.l(printf8.o)
0x080017c0 0x080017c0 0x00000024 Code RO 1993 i._printf_post_padding mc_w.l(printf8.o)
0x080017e4 0x080017e4 0x0000002e Code RO 1994 i._printf_pre_padding mc_w.l(printf8.o)
0x08001812 0x08001812 0x0000000a Code RO 1996 i._sputc mc_w.l(printf8.o)
0x0800181c 0x0800181c 0x00000080 Code RO 15 i.main main.o
0x0800189c 0x0800189c 0x00000012 Data RO 945 .constdata stm32f1xx_hal_rcc.o
0x080018ae 0x080018ae 0x00000010 Data RO 1736 .constdata system_stm32f1xx.o
0x080018be 0x080018be 0x00000008 Data RO 1737 .constdata system_stm32f1xx.o
0x080018c6 0x080018c6 0x00000002 PAD
0x080018c8 0x080018c8 0x0000005a Data RO 16 .conststring main.o
0x08001922 0x08001922 0x00000002 PAD
0x08001924 0x08001924 0x00000020 Data RO 2081 Region$$Table anon$$obj.o
表中几列分别为:
Data
:有具体值的数据;Code
:代码;PAD
:占位符,用于内存对齐的空白部分;Zero
:表示在程序启动时,这段内存会被清零,而不是从闪存中加载任何值。RO
表示只读,RW
表示可读可写。.text
,在启动文件中定义的函数就在这个段里;.constdata
常量(const修饰的变量);RESET
段;HEAP
堆区;STACK
栈区;另外.bss
代表未初始化数据段,存放未初始化或初始化为零的全局和静态变量。总体概览下来,在这个从地址0x08000000
开始的ER_IROM1
域中,首先放置的就是RESET
段,中断向量表,随后是entry
文件里的启动文件相关的段,__main
函数就在这个段内,随后是startup_stm32f103xe.s
这个启动文件里的.text
段,再后是其他HAL库的C文件里的段,由于我勾选了使用微库并include
了stdio.h
、string.h
,所以还能看到print
函数相关的段,再后才是main.c
里的段。这些段中间为了对齐,还穿插了一些占位符。
再最后是一些数据段,主要存放了一些const
常量,从这里我们其实就可以看到,常量是存储在FLASH中的,并不会占用SRAM的空间。
RW_IRAM1域
Execution Region RW_IRAM1 (Exec base: 0x20000000, Load base: 0x08001944, Size: 0x00000690, Max: 0x0000c000, ABSOLUTE)
Exec Addr Load Addr Size Type Attr Idx E Section Name Object
0x20000000 0x08001944 0x00000010 Data RW 17 .data main.o
0x20000010 0x08001954 0x0000000c Data RW 782 .data stm32f1xx_hal.o
0x2000001c 0x08001960 0x00000004 Data RW 1738 .data system_stm32f1xx.o
0x20000020 - 0x00000048 Zero RW 176 .bss usart.o
0x20000068 - 0x00000028 Zero RW 177 .bss usart.o
0x20000090 - 0x00000200 Zero RW 2 HEAP startup_stm32f103xe.o
0x20000290 - 0x00000400 Zero RW 1 STACK startup_stm32f103xe.o
这个域首先是从地址0x08001944
中加载了0x00000010
的数据到0x20000000
,这其实就是在从FLASH中取出要初始化为非零值的全局和静态变量值,给到SRAM中。(段名为.data
)
可以看到,加载的地址刚好就是
EX_IROM
域的结束地址,即在加载域中,第一个执行域后还有一部分空间用于存放要初始化的全局或静态变量的初值。
随后又清零了一些空间,用于存放未初始化或初始化为零的全局和静态变量。(段名为.bss
)
最后划分出了堆和栈的空间。
综上,总结出FLASH中的内存分布图与SRAM中的内存分布图。
内存占用概况(Image component sizes)
在最后一部分,统计了程序各个不同属性数据的内存占用情况。
目标文件(用户文件)占用分析
Code (inc. data) RO Data RW Data ZI Data Debug Object Name
60 6 0 0 0 815 gpio.o
226 38 90 16 0 455793 main.o
36 8 304 0 1536 800 startup_stm32f103xe.o
128 24 0 12 0 5893 stm32f1xx_hal.o
198 14 0 0 0 28923 stm32f1xx_hal_cortex.o
374 8 0 0 0 1827 stm32f1xx_hal_dma.o
504 42 0 0 0 2272 stm32f1xx_hal_gpio.o
60 8 0 0 0 870 stm32f1xx_hal_msp.o
1240 84 18 0 0 5100 stm32f1xx_hal_rcc.o
1474 10 0 0 0 10064 stm32f1xx_hal_uart.o
32 6 0 0 0 4286 stm32f1xx_it.o
2 0 24 4 0 1107 system_stm32f1xx.o
184 20 0 0 112 1737 usart.o
----------------------------------------------------------------------
4526 268 472 32 1648 519487 Object Totals
0 0 32 0 0 0 (incl. Generated)
8 0 4 0 0 0 (incl. Padding)
----------------------------------------------------------------------
列名含义如下:
Code (inc. data):代码段的大小,包含函数的机器指令。
RO Data:只读数据大小,例如字符串常量和静态的只读变量。
RW Data:读写数据段的大小,指已初始化的全局或静态变量。
ZI Data:未初始化数据段(.bss 段)的大小,通常用于存储初始化为零的全局或静态变量。
Debug:与调试相关的符号表和调试信息的大小。
Object Name:对应的目标文件名称。
库文件占用分析
Code (inc. data) RO Data RW Data ZI Data Debug Library Member Name
0 0 0 0 0 0 entry.o
0 0 0 0 0 0 entry10a.o
0 0 0 0 0 0 entry11a.o
8 4 0 0 0 0 entry2.o
4 0 0 0 0 0 entry5.o
0 0 0 0 0 0 entry7b.o
0 0 0 0 0 0 entry8b.o
8 4 0 0 0 0 entry9a.o
30 0 0 0 0 0 handlers.o
36 8 0 0 0 68 init.o
30 0 0 0 0 68 llshl.o
32 0 0 0 0 68 llushr.o
36 0 0 0 0 108 memseta.o
1172 50 0 0 0 420 printf8.o
14 0 0 0 0 68 strlen.o
98 0 0 0 0 92 uldiv.o
----------------------------------------------------------------------
1470 66 0 0 0 892 Library Totals
2 0 0 0 0 0 (incl. Padding)
----------------------------------------------------------------------
Code (inc. data) RO Data RW Data ZI Data Debug Library Name
1468 66 0 0 0 892 mc_w.l
----------------------------------------------------------------------
1470 66 0 0 0 892 Library Totals
----------------------------------------------------------------------
总计大小
Code (inc. data) RO Data RW Data ZI Data Debug
5996 334 472 32 1648 517827 Grand Totals
5996 334 472 32 1648 517827 ELF Image Totals
5996 334 472 32 0 0 ROM Totals
ROM 的总使用情况
Total RO Size (Code + RO Data) 6468 ( 6.32kB)
Total RW Size (RW Data + ZI Data) 1680 ( 1.64kB)
Total ROM Size (Code + RO Data + RW Data) 6500 ( 6.35kB)
其中ROM的大小就是代码大小(Code)+常量数据大小(RO Data)+初始化不为零的全局和静态变量大小(RW Data)。
启动过程分析
根据以上分析,我们来梳理以下整个系统的启动过程,并补充一些启动细节。
- 从地址
0x00000000
中取得堆栈指针(这个位置由硬件映射到FLASH的0x08000000
),赋值给MSP
堆栈指针寄存器 - 从地址
0x00000004
中取得复位函数,赋值给PC
程序计数器。 - 开始运行
Reset_Handler
函数 - 运行
SystemInit
函数,这个函数用来初始化系统时钟等硬件相关设备。 - 运行
__main
函数,这个函数执行以下几个步骤:- 将
RW Data
(初始化不为零的全局和静态变量)从加载地址复制到运行地址中(FLASH中复制到SRAM中),像.map
文件中描述的那样。 - 初始化
ZI Data
(初始化为零或未初始化的全局和静态变量),像.map
文件中描述的那样。 - 运行
__rt_entry
函数
- 将
- 在
__rt_entry
函数中,执行以下一个步骤:- 调用
__user_setup_stackheap()
函数与__rt_stackheap_init()
函数,这两个函数按照分散加载文件(.sct
)所描述的各区域的绝对地址设置堆和栈。如果没有这一步,我们在.s
文件中设置的堆和栈的段就都白瞎了。 - 调用
__rt_lib_init()
函数,这个函数用于初始化所引用的库函数,如果需要,还可以为main()
设置argc
和argv
参数。 - 调用
main()
函数
- 调用
至此,整个系统就跑起来啦。
作者:LoneySmoke