Cortex-M的启动流程与分散加载

263 阅读24分钟

引言

最近在研究IAP时需要弄清楚CM3单片机的启动流程,恰巧手边有一块野火的STM32F103开发板在吃灰,就拿它做了一些实验,并把实验结果分享出来,作为学习笔记。

一、第一条指令在哪里?

CPU需要找到第一条指令,才能够开始执行之后的程序。实际上,在离开复位状态(硬件时序)后,CM3做的第一件事就是读取下列两个32位整数的值:

  • 从地址0x0000,0000处取出MSP的初始值。

  • 从地址0x0000,0004处取出PC的初始值——这个值是复位向量,LSB必须是1。然后从这个值所对应的地址处取指。

image.png

请注意,这与传统的ARM架构不同——其实也和绝大多数的其它单片机不同。传统的ARM架构总是从0地址开始执行第一条指令。它们的0地址处总是一条跳转指令。在CM3中,在0地址处提供MSP的初始值,然后紧跟着就是向量表(向量表在以后还可以被移至其它位置)。向量表中的数值是32位的地址,而不是跳转指令。向量表的第一个条目指向复位后应执行的第一条指令。

对于STM32F10x,参考手册得知内部SRAM和Flash的存储器分布:

image.png

image.png 因为固定的存储器映像,代码区始终从地址0x00000000开始(通过ICode和DCode总线访问),而数据区(SRAM)始终从地址0x2000 0000开始(通过系统总线访问)。Cortex-M3的CPU始终从ICode总线获取复位向量,即启动仅适合于从代码区开始(典型地从Flash启动)。STM32F10xxx微控制器实现了一个特殊的机制,系统可以不仅仅从Flash存储器或系统存储器启动,还可以从内置SRAM启动。 根据选定的启动模式,主闪存存储器、系统存储器或SRAM可以按照以下方式访问:

  • 从主闪存存储器启动:主闪存存储器被映射到启动空间(0x00000000),但仍然能够在它原有的地址(0x08000000)访问它,即闪存存储器的内容可以在两个地址区域访问,0x00000000或0x08000000

  • 从系统存储器启动:系统存储器被映射到启动空间(0x00000000),但仍然能够在它原有的地址(互联型产品原有地址为0x1FFFB000,其它产品原有地址为0x1FFFF000)访问它。

  • 从内置SRAM启动:只能在0x20000000开始的地址区访问SRAM。

二、启动文件(startup_xx.s)

在每一个完整的stm32工程中都可以找到该启动文件,基本上所有的CM0,CM3,CM4等基于ARM核的单片机启动文件都差不多,熟悉ARM汇编同学们应该对此文件的阅读没有压力,下面为该文件每一条指令的进行注释解析。

;******************** (C) COPYRIGHT 2011 STMicroelectronics ********************
;* 文件名             : startup_stm32f10x_hd.s
;* 作者               : MCD Application Team
;* 版本               : V3.5.0
;* 日期               : 11-March-2011
;* 描述               : STM32F10x高密度设备中断向量表,使用MDK-ARM 工具链 
;*                      本模块将执行以下功能:
;*                      - 设置初始化SP寄存器
;*                      - 设置初始化PC寄存器=Reset_Handler
;*                      - 设置中断表中各个ISR的中断入口地址
;*                      - 设置系统时钟并且配置外挂在STM3210E-EVAL板上的SRAM作为数据内存(可选,如果用户使能)
;*                      - 跳转至__main(其最终会调用main)
;*                      复位之后Cortex-M3处理器处于线程模式,特权级访问,使用主堆栈 
;*******************************************************************************

; 评估你自己的应用程序需求来为栈分配内存(字节)
Stack_Size      EQU     0x00000400                        ;Stack_Size = 0x00000400

                AREA    STACK, NOINIT, READWRITE, ALIGN=3 ;声明STACK段,不初始化,RW,8字节对齐
Stack_Mem       SPACE   Stack_Size                        ;通过SPACE指令分配Stack_Size内存作为栈,Stack_Mem = 栈底地址
__initial_sp                                              ;__initial_sp = 栈顶地址
                                                  
Heap_Size       EQU     0x00000200                        ;Heap_Size = 0x00000400

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3  ;声明HEAP段,不初始化,RW,8字节对齐
__heap_base                                               
Heap_Mem        SPACE   Heap_Size                         ;通过SPACE指令分配Heap_Size内存作为堆,Heap_Mem = 堆底地址
__heap_limit                                              ;__heap_limit = 堆顶地址

                PRESERVE8                                 ;保留8字节对齐
                THUMB                                     ;切换到THUMB指令集

;复位时,向量表被映射到0地址处
                AREA    RESET, DATA, READONLY             ;声明RESET段,不初始化,RW
                EXPORT  __Vectors                         ;导出符号__Vectors,表示向量表基地址
                EXPORT  __Vectors_End                     ;导出符号__Vectors_End表示向量表尾地址
                EXPORT  __Vectors_Size                    ;导出符号__Vectors_Size表示向量表长度

                ;内核中断
__Vectors       DCD     __initial_sp                      ;栈顶(复位后取出该值给SP寄存器)
                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

                ;外设中断
                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     RTCAlarm_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

__Vectors_Size  EQU  __Vectors_End - __Vectors            ;向量表大小 = __Vectors_End - __Vectors

                AREA    |.text|, CODE, READONLY           ;声明以下属于|.text|段,只读
                
; Reset handler异常处理函数
Reset_Handler   PROC                                      ;PROC表明函数开始
                EXPORT  Reset_Handler             [WEAK]  ;导出弱符号Reset_Handler
                IMPORT  __main                            ;导入符号__main
                IMPORT  SystemInit                        ;导入符号SystemInit
                LDR     R0, =SystemInit                   ;R0 = SystemInit
                BLX     R0                                ;跳转至SystemInit执行,并保存LR
                LDR     R0, =__main                       ;R0 =__main
                BX      R0                                ;无返回跳转__main
                ENDP                                      ;ENDP表明函数结束
                
; 空异常处理函数(可以被修改的无限循环)

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  RTCAlarm_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
RTCAlarm_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                                           ;填充字节使地址对齐

;*******************************************************************************
; 用户堆栈初始化
;*******************************************************************************
                 IF      :DEF:__MICROLIB                        ;如果用户使用了MircoLib
                
                 EXPORT  __initial_sp                           ;导出符号__initial_sp,表示栈顶地址
                 EXPORT  __heap_base                            ;导出符号__heap_base,表示堆底地址
                 EXPORT  __heap_limit                           ;导出符号__heap_limit,表示堆顶地址
                
                 ELSE                                           ;没定义__MICROLIB,则使用默认C库
                
                 IMPORT  __use_two_region_memory                ;用于指定存储器模式为双段模式,即一部分储存区用于栈空间,其他的存储区用于堆空间,
                                                                 堆区空间可以为0,但是,这样就不能调用malloc()内存分配函数;堆区空间也可以由存储
                                                                 器分配,也可以从执行环境中继承。在汇编代码中,通过 IMPORT __use_two_region_memory 
                                                                 表明使用双段模式;在C语言中,通过 #pragma import(__use_two_region_memory)语句表明使用双段模式。

                 EXPORT  __user_initial_stackheap                __user_initial_stackheap,外界通过该函数获取堆栈参数
                 
__user_initial_stackheap

                 LDR     R0, =  Heap_Mem                        ;R0 - 堆底
                 LDR     R1, =(Stack_Mem + Stack_Size)          ;R1 = 栈顶
                 LDR     R2, = (Heap_Mem +  Heap_Size)          ;R2 = 堆顶
                 LDR     R3, = Stack_Mem                        ;R3 = 栈底
                 BX      LR                                     ;返回

                 ALIGN                                          ;填充字节使地址对齐


                 ENDIF                                          ;结束IF

                 END                                            ;结束程序

;******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE*****

三、__main

3.1 重定位的作用

由启动文件可以看到,在用户main函数被正式调用前,实际上还有其它函数被调用了,分别是SystemInit()与__main。SystemInit()负责配置MCU的内部时钟,可根据用户需求将主频配置到预设时钟频率,之后重新设置向量表偏移到0x08000000。完成这些配置后进入__main。

此处以一个简单的用户main函数为例,简单说明__main函数中具体做了哪些事。

#include "stm32f10x.h"

volatile int g_a = 1;
volatile int g_b = 2;
volatile int g_c = 3;

int  main(void)
{
    g_a = 4;
    g_b = 5;
    g_c = 6;

	while(1);
    
    return 0;
}

该程序在编译好后的输出如下

Build started: Project: Project
*** Using Compiler 'V5.06 update 7 (build 960)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
Build target 'Target 1'
linking...
Program Size: Code=520 RO-data=336 RW-data=12 ZI-data=1028  

RW-data = 12 即g_a, g_c, g_c,ZI-data=1028 ,即为栈大小Stack_Size = 0x400,多出4字节为对齐。

image.png

image.png 问题在于,RW-data与ZI-data的执行地址(Exec Addr)应该位于RAM区0x20000000,而用户所编写的程序都被保存在Flash上,由谁来负责将RW与ZI中的数据从Flash搬运到RAM上,换句话说,谁来保证0x20000000处的g_a = 1,0x20000004处的g_b = 2?STACK既然被存放在ZI段,谁来负责上电后0x20000010 ~0x20000410这段内存的值为0?如果没有__main函数,直接进入main函数,这些内存中的内容是否还会按照程序员预想的方式存在? image.png

这里笔者做了一个实验,在启动文件中直接将__main改为main,并进入调试模式来查看内存中关于变量g_a,g_b,g_c的数值。

image.png 可以看到一开始g_a,g_b,g_c的值并不是我们给予的初始值,此处都是0是因为使用模拟器环境,在真实情况下应该为随机值。

3.2得到反汇编码

由于看不到__main函数的源代码,需要借助反汇编工具来查看__main为我们的程序做了什么。 通过powershell可以查看armcc工具链中的fromelf工具的使用帮助 image.png 其中-a选项可以打印数据的地址,-c选项可以得到反汇编代码,--output选项指明输出的文件名。 在如下的keil配置界面中输入

fromelf -a -c ./Objects/Template.axf --output ./Objects/Template.asm

image.png 再次编译即可在Objects文件目录中看到Template.asm文件。打开后找到程序的反汇编码如下。

    RESET
    __Vectors
        0x08000000:    20000410    ...     DCD    536871952
        0x08000004:    08000149    I...    DCD    134218057
        0x08000008:    0800019f    ....    DCD    134218143
        0x0800000c:    08000197    ....    DCD    134218135
        0x08000010:    0800019b    ....    DCD    134218139
        0x08000014:    08000191    ....    DCD    134218129
        0x08000018:    080002f1    ....    DCD    134218481
        0x0800001c:    00000000    ....    DCD    0
        0x08000020:    00000000    ....    DCD    0
        0x08000024:    00000000    ....    DCD    0
        0x08000028:    00000000    ....    DCD    0
        0x0800002c:    080001a3    ....    DCD    134218147
        0x08000030:    08000195    ....    DCD    134218133
        0x08000034:    00000000    ....    DCD    0
        0x08000038:    080001a1    ....    DCD    134218145
        0x0800003c:    0800028d    ....    DCD    134218381
        0x08000040:    08000163    c...    DCD    134218083
        0x08000044:    08000163    c...    DCD    134218083
        0x08000048:    08000163    c...    DCD    134218083
        0x0800004c:    08000163    c...    DCD    134218083
        0x08000050:    08000163    c...    DCD    134218083
        0x08000054:    08000163    c...    DCD    134218083
        0x08000058:    08000163    c...    DCD    134218083
        0x0800005c:    08000163    c...    DCD    134218083
        0x08000060:    08000163    c...    DCD    134218083
        0x08000064:    08000163    c...    DCD    134218083
        0x08000068:    08000163    c...    DCD    134218083
        0x0800006c:    08000163    c...    DCD    134218083
        0x08000070:    08000163    c...    DCD    134218083
        0x08000074:    08000163    c...    DCD    134218083
        0x08000078:    08000163    c...    DCD    134218083
        0x0800007c:    08000163    c...    DCD    134218083
        0x08000080:    08000163    c...    DCD    134218083
        0x08000084:    08000163    c...    DCD    134218083
        0x08000088:    08000163    c...    DCD    134218083
        0x0800008c:    08000163    c...    DCD    134218083
        0x08000090:    08000163    c...    DCD    134218083
        0x08000094:    08000163    c...    DCD    134218083
        0x08000098:    08000163    c...    DCD    134218083
        0x0800009c:    08000163    c...    DCD    134218083
        0x080000a0:    08000163    c...    DCD    134218083
        0x080000a4:    08000163    c...    DCD    134218083
        0x080000a8:    08000163    c...    DCD    134218083
        0x080000ac:    08000163    c...    DCD    134218083
        0x080000b0:    08000163    c...    DCD    134218083
        0x080000b4:    08000163    c...    DCD    134218083
        0x080000b8:    08000163    c...    DCD    134218083
        0x080000bc:    08000163    c...    DCD    134218083
        0x080000c0:    08000163    c...    DCD    134218083
        0x080000c4:    08000163    c...    DCD    134218083
        0x080000c8:    08000163    c...    DCD    134218083
        0x080000cc:    08000163    c...    DCD    134218083
        0x080000d0:    08000163    c...    DCD    134218083
        0x080000d4:    08000163    c...    DCD    134218083
        0x080000d8:    08000163    c...    DCD    134218083
        0x080000dc:    08000163    c...    DCD    134218083
        0x080000e0:    08000163    c...    DCD    134218083
        0x080000e4:    08000163    c...    DCD    134218083
        0x080000e8:    08000163    c...    DCD    134218083
        0x080000ec:    08000163    c...    DCD    134218083
        0x080000f0:    08000163    c...    DCD    134218083
        0x080000f4:    08000163    c...    DCD    134218083
        0x080000f8:    08000163    c...    DCD    134218083
        0x080000fc:    08000163    c...    DCD    134218083
        0x08000100:    08000163    c...    DCD    134218083
        0x08000104:    08000163    c...    DCD    134218083
        0x08000108:    08000163    c...    DCD    134218083
        0x0800010c:    08000163    c...    DCD    134218083
        0x08000110:    08000163    c...    DCD    134218083
        0x08000114:    08000163    c...    DCD    134218083
        0x08000118:    08000163    c...    DCD    134218083
        0x0800011c:    08000163    c...    DCD    134218083
        0x08000120:    08000163    c...    DCD    134218083
        0x08000124:    08000163    c...    DCD    134218083
        0x08000128:    08000163    c...    DCD    134218083
        0x0800012c:    08000163    c...    DCD    134218083
    $t
    .ARM.Collect$$$$00000000
    .ARM.Collect$$$$00000001
    __Vectors_End
    __main
    _main_stk
        0x08000130:    f8dfd010    ....    LDR      sp,__lit__00000000 ; [0x8000144] = 0x20000410
    .ARM.Collect$$$$00000004
    _main_scatterload
        0x08000134:    f000f81a    ....    BL       __scatterload ; 0x800016c
    .ARM.Collect$$$$00000008
    .ARM.Collect$$$$0000000A
    .ARM.Collect$$$$0000000B
    __main_after_scatterload
    _main_clock
    _main_cpp_init
    _main_init
        0x08000138:    4800        .H      LDR      r0,[pc,#0] ; [0x800013c] = 0x8000315
        0x0800013a:    4700        .G      BX       r0
    $d
        0x0800013c:    08000315    ....    DCD    134218517
    $t
    .ARM.Collect$$$$0000000E
    __rt_lib_shutdown_fini
        0x08000140:    f3af8000    ....    NOP.W    
    $d
    .ARM.Collect$$$$00002712
    __lit__00000000
    .ARM.Collect$$$$0000000F
    .ARM.Collect$$$$00000011
    __rt_final_cpp
    __rt_final_exit
        0x08000144:    20000410    ...     DCD    536871952
    $t
    .text
    Reset_Handler
        0x08000148:    4806        .H      LDR      r0,[pc,#24] ; [0x8000164] = 0x8000291
        0x0800014a:    4780        .G      BLX      r0
        0x0800014c:    4806        .H      LDR      r0,[pc,#24] ; [0x8000168] = 0x8000131
        0x0800014e:    4700        .G      BX       r0
        0x08000150:    e7fe        ..      B        0x8000150 ; Reset_Handler + 8
        0x08000152:    e7fe        ..      B        0x8000152 ; Reset_Handler + 10
        0x08000154:    e7fe        ..      B        0x8000154 ; Reset_Handler + 12
        0x08000156:    e7fe        ..      B        0x8000156 ; Reset_Handler + 14
        0x08000158:    e7fe        ..      B        0x8000158 ; Reset_Handler + 16
        0x0800015a:    e7fe        ..      B        0x800015a ; Reset_Handler + 18
        0x0800015c:    e7fe        ..      B        0x800015c ; Reset_Handler + 20
        0x0800015e:    e7fe        ..      B        0x800015e ; Reset_Handler + 22
        0x08000160:    e7fe        ..      B        0x8000160 ; Reset_Handler + 24
    ADC1_2_IRQHandler
    ADC3_IRQHandler
    CAN1_RX1_IRQHandler
    CAN1_SCE_IRQHandler
    DMA1_Channel1_IRQHandler
    DMA1_Channel2_IRQHandler
    DMA1_Channel3_IRQHandler
    DMA1_Channel4_IRQHandler
    DMA1_Channel5_IRQHandler
    DMA1_Channel6_IRQHandler
    DMA1_Channel7_IRQHandler
    DMA2_Channel1_IRQHandler
    DMA2_Channel2_IRQHandler
    DMA2_Channel3_IRQHandler
    DMA2_Channel4_5_IRQHandler
    EXTI0_IRQHandler
    EXTI15_10_IRQHandler
    EXTI1_IRQHandler
    EXTI2_IRQHandler
    EXTI3_IRQHandler
    EXTI4_IRQHandler
    EXTI9_5_IRQHandler
    FLASH_IRQHandler
    FSMC_IRQHandler
    I2C1_ER_IRQHandler
    I2C1_EV_IRQHandler
    I2C2_ER_IRQHandler
    I2C2_EV_IRQHandler
    PVD_IRQHandler
    RCC_IRQHandler
    RTCAlarm_IRQHandler
    RTC_IRQHandler
    SDIO_IRQHandler
    SPI1_IRQHandler
    SPI2_IRQHandler
    SPI3_IRQHandler
    TAMPER_IRQHandler
    TIM1_BRK_IRQHandler
    TIM1_CC_IRQHandler
    TIM1_TRG_COM_IRQHandler
    TIM1_UP_IRQHandler
    TIM2_IRQHandler
    TIM3_IRQHandler
    TIM4_IRQHandler
    TIM5_IRQHandler
    TIM6_IRQHandler
    TIM7_IRQHandler
    TIM8_BRK_IRQHandler
    TIM8_CC_IRQHandler
    TIM8_TRG_COM_IRQHandler
    TIM8_UP_IRQHandler
    UART4_IRQHandler
    UART5_IRQHandler
    USART1_IRQHandler
    USART2_IRQHandler
    USART3_IRQHandler
    USBWakeUp_IRQHandler
    USB_HP_CAN1_TX_IRQHandler
    USB_LP_CAN1_RX0_IRQHandler
    WWDG_IRQHandler
        0x08000162:    e7fe        ..      B        ADC1_2_IRQHandler ; 0x8000162
    $d
        0x08000164:    08000291    ....    DCD    134218385
        0x08000168:    08000131    1...    DCD    134218033
    $t
    .text
    __scatterload
    __scatterload_rt2
        0x0800016c:    4c06        .L      LDR      r4,[pc,#24] ; [0x8000188] = 0x8000338
        0x0800016e:    4d07        .M      LDR      r5,[pc,#28] ; [0x800018c] = 0x8000358
        0x08000170:    e006        ..      B        0x8000180 ; __scatterload + 20
        0x08000172:    68e0        .h      LDR      r0,[r4,#0xc]
        0x08000174:    f0400301    @...    ORR      r3,r0,#1
        0x08000178:    e8940007    ....    LDM      r4,{r0-r2}
        0x0800017c:    4798        .G      BLX      r3
        0x0800017e:    3410        .4      ADDS     r4,r4,#0x10
        0x08000180:    42ac        .B      CMP      r4,r5
        0x08000182:    d3f6        ..      BCC      0x8000172 ; __scatterload + 6
        0x08000184:    f7ffffd8    ....    BL       __main_after_scatterload ; 0x8000138
    $d
        0x08000188:    08000338    8...    DCD    134218552
        0x0800018c:    08000358    X...    DCD    134218584
    $t
    i.BusFault_Handler
    BusFault_Handler
        0x08000190:    bf00        ..      NOP      
        0x08000192:    e7fe        ..      B        0x8000192 ; BusFault_Handler + 2
    i.DebugMon_Handler
    DebugMon_Handler
        0x08000194:    4770        pG      BX       lr
    i.HardFault_Handler
    HardFault_Handler
        0x08000196:    bf00        ..      NOP      
        0x08000198:    e7fe        ..      B        0x8000198 ; HardFault_Handler + 2
    i.MemManage_Handler
    MemManage_Handler
        0x0800019a:    bf00        ..      NOP      
        0x0800019c:    e7fe        ..      B        0x800019c ; MemManage_Handler + 2
    i.NMI_Handler
    NMI_Handler
        0x0800019e:    4770        pG      BX       lr
    i.PendSV_Handler
    PendSV_Handler
        0x080001a0:    4770        pG      BX       lr
    i.SVC_Handler
    SVC_Handler
        0x080001a2:    4770        pG      BX       lr
    i.SetSysClock
    SetSysClock
        0x080001a4:    b510        ..      PUSH     {r4,lr}
        0x080001a6:    f000f801    ....    BL       SetSysClockTo72 ; 0x80001ac
        0x080001aa:    bd10        ..      POP      {r4,pc}
    i.SetSysClockTo72
    SetSysClockTo72
        0x080001ac:    b50c        ..      PUSH     {r2,r3,lr}
        0x080001ae:    2000        .       MOVS     r0,#0
        0x080001b0:    9001        ..      STR      r0,[sp,#4]
        0x080001b2:    9000        ..      STR      r0,[sp,#0]
        0x080001b4:    4833        3H      LDR      r0,[pc,#204] ; [0x8000284] = 0x40021000
        0x080001b6:    6800        .h      LDR      r0,[r0,#0]
        0x080001b8:    f4403080    @..0    ORR      r0,r0,#0x10000
        0x080001bc:    4931        1I      LDR      r1,[pc,#196] ; [0x8000284] = 0x40021000
        0x080001be:    6008        .`      STR      r0,[r1,#0]
        0x080001c0:    bf00        ..      NOP      
        0x080001c2:    4830        0H      LDR      r0,[pc,#192] ; [0x8000284] = 0x40021000
        0x080001c4:    6800        .h      LDR      r0,[r0,#0]
        0x080001c6:    f4003000    ...0    AND      r0,r0,#0x20000
        0x080001ca:    9000        ..      STR      r0,[sp,#0]
        0x080001cc:    9801        ..      LDR      r0,[sp,#4]
        0x080001ce:    1c40        @.      ADDS     r0,r0,#1
        0x080001d0:    9001        ..      STR      r0,[sp,#4]
        0x080001d2:    9800        ..      LDR      r0,[sp,#0]
        0x080001d4:    b918        ..      CBNZ     r0,0x80001de ; SetSysClockTo72 + 50
        0x080001d6:    9801        ..      LDR      r0,[sp,#4]
        0x080001d8:    f5b06fa0    ...o    CMP      r0,#0x500
        0x080001dc:    d1f1        ..      BNE      0x80001c2 ; SetSysClockTo72 + 22
        0x080001de:    4829        )H      LDR      r0,[pc,#164] ; [0x8000284] = 0x40021000
        0x080001e0:    6800        .h      LDR      r0,[r0,#0]
        0x080001e2:    f4003000    ...0    AND      r0,r0,#0x20000
        0x080001e6:    b110        ..      CBZ      r0,0x80001ee ; SetSysClockTo72 + 66
        0x080001e8:    2001        .       MOVS     r0,#1
        0x080001ea:    9000        ..      STR      r0,[sp,#0]
        0x080001ec:    e001        ..      B        0x80001f2 ; SetSysClockTo72 + 70
        0x080001ee:    2000        .       MOVS     r0,#0
        0x080001f0:    9000        ..      STR      r0,[sp,#0]
        0x080001f2:    9800        ..      LDR      r0,[sp,#0]
        0x080001f4:    2801        .(      CMP      r0,#1
        0x080001f6:    d143        C.      BNE      0x8000280 ; SetSysClockTo72 + 212
        0x080001f8:    4823        #H      LDR      r0,[pc,#140] ; [0x8000288] = 0x40022000
        0x080001fa:    6800        .h      LDR      r0,[r0,#0]
        0x080001fc:    f0400010    @...    ORR      r0,r0,#0x10
        0x08000200:    4921        !I      LDR      r1,[pc,#132] ; [0x8000288] = 0x40022000
        0x08000202:    6008        .`      STR      r0,[r1,#0]
        0x08000204:    4608        .F      MOV      r0,r1
        0x08000206:    6800        .h      LDR      r0,[r0,#0]
        0x08000208:    f0200003     ...    BIC      r0,r0,#3
        0x0800020c:    6008        .`      STR      r0,[r1,#0]
        0x0800020e:    4608        .F      MOV      r0,r1
        0x08000210:    6800        .h      LDR      r0,[r0,#0]
        0x08000212:    f0400002    @...    ORR      r0,r0,#2
        0x08000216:    6008        .`      STR      r0,[r1,#0]
        0x08000218:    481a        .H      LDR      r0,[pc,#104] ; [0x8000284] = 0x40021000
        0x0800021a:    6840        @h      LDR      r0,[r0,#4]
        0x0800021c:    4919        .I      LDR      r1,[pc,#100] ; [0x8000284] = 0x40021000
        0x0800021e:    6048        H`      STR      r0,[r1,#4]
        0x08000220:    4608        .F      MOV      r0,r1
        0x08000222:    6840        @h      LDR      r0,[r0,#4]
        0x08000224:    6048        H`      STR      r0,[r1,#4]
        0x08000226:    4608        .F      MOV      r0,r1
        0x08000228:    6840        @h      LDR      r0,[r0,#4]
        0x0800022a:    f4406080    @..`    ORR      r0,r0,#0x400
        0x0800022e:    6048        H`      STR      r0,[r1,#4]
        0x08000230:    4608        .F      MOV      r0,r1
        0x08000232:    6840        @h      LDR      r0,[r0,#4]
        0x08000234:    f420107c     .|.    BIC      r0,r0,#0x3f0000
        0x08000238:    6048        H`      STR      r0,[r1,#4]
        0x0800023a:    4608        .F      MOV      r0,r1
        0x0800023c:    6840        @h      LDR      r0,[r0,#4]
        0x0800023e:    f44010e8    @...    ORR      r0,r0,#0x1d0000
        0x08000242:    6048        H`      STR      r0,[r1,#4]
        0x08000244:    4608        .F      MOV      r0,r1
        0x08000246:    6800        .h      LDR      r0,[r0,#0]
        0x08000248:    f0407080    @..p    ORR      r0,r0,#0x1000000
        0x0800024c:    6008        .`      STR      r0,[r1,#0]
        0x0800024e:    bf00        ..      NOP      
        0x08000250:    480c        .H      LDR      r0,[pc,#48] ; [0x8000284] = 0x40021000
        0x08000252:    6800        .h      LDR      r0,[r0,#0]
        0x08000254:    f0007000    ...p    AND      r0,r0,#0x2000000
        0x08000258:    2800        .(      CMP      r0,#0
        0x0800025a:    d0f9        ..      BEQ      0x8000250 ; SetSysClockTo72 + 164
        0x0800025c:    4809        .H      LDR      r0,[pc,#36] ; [0x8000284] = 0x40021000
        0x0800025e:    6840        @h      LDR      r0,[r0,#4]
        0x08000260:    f0200003     ...    BIC      r0,r0,#3
        0x08000264:    4907        .I      LDR      r1,[pc,#28] ; [0x8000284] = 0x40021000
        0x08000266:    6048        H`      STR      r0,[r1,#4]
        0x08000268:    4608        .F      MOV      r0,r1
        0x0800026a:    6840        @h      LDR      r0,[r0,#4]
        0x0800026c:    f0400002    @...    ORR      r0,r0,#2
        0x08000270:    6048        H`      STR      r0,[r1,#4]
        0x08000272:    bf00        ..      NOP      
        0x08000274:    4803        .H      LDR      r0,[pc,#12] ; [0x8000284] = 0x40021000
        0x08000276:    6840        @h      LDR      r0,[r0,#4]
        0x08000278:    f000000c    ....    AND      r0,r0,#0xc
        0x0800027c:    2808        .(      CMP      r0,#8
        0x0800027e:    d1f9        ..      BNE      0x8000274 ; SetSysClockTo72 + 200
        0x08000280:    bd0c        ..      POP      {r2,r3,pc}
    $d
        0x08000282:    0000        ..      DCW    0
        0x08000284:    40021000    ...@    DCD    1073876992
        0x08000288:    40022000    . .@    DCD    1073881088
    $t
    i.SysTick_Handler
    SysTick_Handler
        0x0800028c:    4770        pG      BX       lr
        0x0800028e:    0000        ..      MOVS     r0,r0
    i.SystemInit
    SystemInit
        0x08000290:    b510        ..      PUSH     {r4,lr}
        0x08000292:    4813        .H      LDR      r0,[pc,#76] ; [0x80002e0] = 0x40021000
        0x08000294:    6800        .h      LDR      r0,[r0,#0]
        0x08000296:    f0400001    @...    ORR      r0,r0,#1
        0x0800029a:    4911        .I      LDR      r1,[pc,#68] ; [0x80002e0] = 0x40021000
        0x0800029c:    6008        .`      STR      r0,[r1,#0]
        0x0800029e:    4608        .F      MOV      r0,r1
        0x080002a0:    6840        @h      LDR      r0,[r0,#4]
        0x080002a2:    4910        .I      LDR      r1,[pc,#64] ; [0x80002e4] = 0xf8ff0000
        0x080002a4:    4008        .@      ANDS     r0,r0,r1
        0x080002a6:    490e        .I      LDR      r1,[pc,#56] ; [0x80002e0] = 0x40021000
        0x080002a8:    6048        H`      STR      r0,[r1,#4]
        0x080002aa:    4608        .F      MOV      r0,r1
        0x080002ac:    6800        .h      LDR      r0,[r0,#0]
        0x080002ae:    490e        .I      LDR      r1,[pc,#56] ; [0x80002e8] = 0xfef6ffff
        0x080002b0:    4008        .@      ANDS     r0,r0,r1
        0x080002b2:    490b        .I      LDR      r1,[pc,#44] ; [0x80002e0] = 0x40021000
        0x080002b4:    6008        .`      STR      r0,[r1,#0]
        0x080002b6:    4608        .F      MOV      r0,r1
        0x080002b8:    6800        .h      LDR      r0,[r0,#0]
        0x080002ba:    f4202080     ..     BIC      r0,r0,#0x40000
        0x080002be:    6008        .`      STR      r0,[r1,#0]
        0x080002c0:    4608        .F      MOV      r0,r1
        0x080002c2:    6840        @h      LDR      r0,[r0,#4]
        0x080002c4:    f42000fe     ...    BIC      r0,r0,#0x7f0000
        0x080002c8:    6048        H`      STR      r0,[r1,#4]
        0x080002ca:    f44f001f    O...    MOV      r0,#0x9f0000
        0x080002ce:    6088        .`      STR      r0,[r1,#8]
        0x080002d0:    f7ffff68    ..h.    BL       SetSysClock ; 0x80001a4
        0x080002d4:    f04f6000    O..`    MOV      r0,#0x8000000
        0x080002d8:    4904        .I      LDR      r1,[pc,#16] ; [0x80002ec] = 0xe000ed08
        0x080002da:    6008        .`      STR      r0,[r1,#0]
        0x080002dc:    bd10        ..      POP      {r4,pc}
    $d
        0x080002de:    0000        ..      DCW    0
        0x080002e0:    40021000    ...@    DCD    1073876992
        0x080002e4:    f8ff0000    ....    DCD    4177461248
        0x080002e8:    fef6ffff    ....    DCD    4277600255
        0x080002ec:    e000ed08    ....    DCD    3758157064
    $t
    i.UsageFault_Handler
    UsageFault_Handler
        0x080002f0:    bf00        ..      NOP      
        0x080002f2:    e7fe        ..      B        0x80002f2 ; UsageFault_Handler + 2
    i.__scatterload_copy
    __scatterload_copy
        0x080002f4:    e002        ..      B        0x80002fc ; __scatterload_copy + 8
        0x080002f6:    c808        ..      LDM      r0!,{r3}
        0x080002f8:    1f12        ..      SUBS     r2,r2,#4
        0x080002fa:    c108        ..      STM      r1!,{r3}
        0x080002fc:    2a00        .*      CMP      r2,#0
        0x080002fe:    d1fa        ..      BNE      0x80002f6 ; __scatterload_copy + 2
        0x08000300:    4770        pG      BX       lr
    i.__scatterload_null
    __scatterload_null
        0x08000302:    4770        pG      BX       lr
    i.__scatterload_zeroinit
    __scatterload_zeroinit
        0x08000304:    2000        .       MOVS     r0,#0
        0x08000306:    e001        ..      B        0x800030c ; __scatterload_zeroinit + 8
        0x08000308:    c101        ..      STM      r1!,{r0}
        0x0800030a:    1f12        ..      SUBS     r2,r2,#4
        0x0800030c:    2a00        .*      CMP      r2,#0
        0x0800030e:    d1fb        ..      BNE      0x8000308 ; __scatterload_zeroinit + 4
        0x08000310:    4770        pG      BX       lr
        0x08000312:    0000        ..      MOVS     r0,r0
    i.main
    main
        0x08000314:    2004        .       MOVS     r0,#4
        0x08000316:    4905        .I      LDR      r1,[pc,#20] ; [0x800032c] = 0x20000000
        0x08000318:    6008        .`      STR      r0,[r1,#0]
        0x0800031a:    2005        .       MOVS     r0,#5
        0x0800031c:    4904        .I      LDR      r1,[pc,#16] ; [0x8000330] = 0x20000004
        0x0800031e:    6008        .`      STR      r0,[r1,#0]
        0x08000320:    2006        .       MOVS     r0,#6
        0x08000322:    4904        .I      LDR      r1,[pc,#16] ; [0x8000334] = 0x20000008
        0x08000324:    6008        .`      STR      r0,[r1,#0]
        0x08000326:    bf00        ..      NOP      
        0x08000328:    e7fe        ..      B        0x8000328 ; main + 20
    $d
        0x0800032a:    0000        ..      DCW    0
        0x0800032c:    20000000    ...     DCD    536870912
        0x08000330:    20000004    ...     DCD    536870916
        0x08000334:    20000008    ...     DCD    536870920
    $d.realdata
    Region$$Table$$Base
        0x08000338:    08000358    X...    DCD    134218584
        0x0800033c:    20000000    ...     DCD    536870912
        0x08000340:    0000000c    ....    DCD    12
        0x08000344:    080002f4    ....    DCD    134218484
        0x08000348:    08000364    d...    DCD    134218596
        0x0800034c:    2000000c    ...     DCD    536870924
        0x08000350:    00000404    ....    DCD    1028
        0x08000354:    08000304    ....    DCD    134218500
    Region$$Table$$Limit

3.3通过反汇编分析__main

image.png 找到Reset_Handler段后,先从0x08000291进入SystemInit(),之后将0x000168地址处的内容加载到R0,跳转到R0所指向的地址处,即__main image.png

在0x0x8000130处,将0x0x000144地址处的内容设置到SP寄存器中,再次初始化栈。之后相对跳转至__scatterload。

image.png 在__scatterload开头处,将0x08000188地址里的内容与0x0800018c地址里的内容分别加载到R4与R5,为了搞清楚0x08000338和0x08000358这两个地址是什么含义,查看反汇编在0x08000338处对内存的定义即可知晓答案。

image.png 可以知道是一个名为Region$$Table的数组,观察数据内容可以知道其具体含义如下:

内容
RW段在FLASH的起始地址0x08000358
RW段在RAM的起始地址0x20000000
RW段长度0x0000000c
RW段拷贝函数地址0x080002F4
RW段在FLASH的结束地址0x08000364
ZI段在RAM的起始地址0x2000000C
ZI段长度0x00000404
ZI段初始化函数地址0x08000304

因此,LDR R4,[PC, #24]LDR R5,[PC, #28] 意在得到Region$$Table的起始长度与终止长度。回到刚才的地方接着往下分析__scatterload,PC指向0x08000180,比较R4与R5,若结果不等,跳转到0x08000172

image.png

此处将RW段拷贝函数地址存入R0,再往bit0写入1后存入R3,并将R0-R2处的内容设置为Region$$Table的前三项。这里介绍一下CM3下的一些细节。

1.ARM与THUMB指令集的表示:

CM3架构以bit0表示该指令为ARM指令集还是THUMB指令集。由于CM3架构只支持THUMB-2指令集,故BLX/BX指令的Bit0应该被事先置高。

2.AAPCS(Procedure Call Standard for the ARM Architecture):

详细可以参考STM32程序调用规则(AAPCS):最新的ARM子程序调用规则-CSDN博客

此处的{R0-R2}被用作函数参数进行传递,给到R3所指向的函数地址__scatterload_copy(0x080002F4)。

image.png 在__scatterload_copy中R2作为计数器,R0作为指向加载地址的指针,R2作为指向链接地址的指针,通过循环的方式将Flash上的RW内容搬运到RAM中。完成后通过LR返回。 image.png 如此一来还不够,由于返回后R4=R4+0x10仍然不等于R5,因此还会再次回到0x08000172,从Region$$Table中取出函数地址__scatterload_zeroinit(0x08000304)并跳转执行。

image.png 这段代码的作用即清空ZI段,R0 = 0,R1指向要清空的RAM地址,R2作为计数器,逐个清空指定RAM区的内容。 完成上述操作后即可进入下一阶段__main_after_scatterload。 image.png 在__main_after_scatterload中跳转进入0x08000314,正式进入main函数

image.png

四、scatter分散加载

4.1修改ZI段的链接地址

通过修改./Objects/xxx.sct可以为自己的程序指定各个段的链接地址,此处将原先RW_IRAM1中的.ANY(+ZI)段放到ZI_IRAM1,中,其起始地址变为从0x20000800开始。

image.png

编译程序,查看.map文件可以看到栈被链接至0x20000800地址处,合理猜测此时__scatterload_zeroinit会将0x20000800到0x20000c00处内容清空。

image.png

4.2多段下scatter的行为

使用__attribute__((at(x)))

此处通过__attribute__((at(x)))的编译器指令可以将变量定义到指定内存处。

image.png

定义完毕后编译程序,查看.map文件。

image.png

发现g_c,g_d,g_e的链接地址确实在0x20000500~0x20000508,此时通过反汇编分析scatter的行为是否发生变化:

image.png 似乎并没有发生什么变化,再来看看Region$$Table,RW-data的大小居然变成了0x050c! image.png

由此可见使用__attribute__((at(x)))的方法在RAM中任意地址定义变量时,如果定义变量的地址远离RW段的起始定义地址,一定会导致大片的空闲空间参与分散加载,不仅在加载时造成时间上的浪费,“小碎片”形式的变量定义更是会要命的占据Flash空间,从编译结果输出中便可以看出来。

Build started: Project: Project
*** Using Compiler 'V5.06 update 7 (build 960)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
Build target 'Target 1'
linking...
Program Size: Code=600 RO-data=336 RW-data=1292 ZI-data=1024  

这就是三个int变量引起的flash血案... 那么有没有一种更好的方式让这些变量参与分散加载,而不要去浪费宝贵的flash,同时也节约scatter的时间,答案是肯定的,我们只需要在xxx.sct文件中额外指定新的段。

使用__attribute__((at(x)))配合xxx.sct

image.png 如图指定新的执行域TEST_IRAM 0x20000500 0x100,并将所有.o文件中的TEST段链接到此处,再次编译查看.map文件。

image.png

可以看到工具链自动为我们把g_c,g_d,g_e并入了TEST段,此时的程序后的编译大小为

.\Objects\Template.sct(22): warning: L6314W: No section matches pattern *.o(TEST).
Program Size: Code=536 RO-data=352 RW-data=20 ZI-data=1024  
Finished: 0 information, 1 warning and 0 error messages.

回归正常,再看scatter的反汇编行为。

image.png

看似没有发生什么变化,再来看Region$$Table,发现Table整体长度从原先的0x20变为了0x30,多出的0x10是什么呢,仔细看看0x08000188地址处的定义

image.png

可以知道是一个名为Region$$Table的数组,观察数据内容可以知道其具体含义如下:

内容
RW段在FLASH的起始地址0x08000378
RW段在RAM的起始地址0x20000000
RW段长度0x00000008
RW段拷贝函数地址0x080002F4
RW段在FLASH的结束地址0x08000380
TEST段在RAM的起始地址0x20000500
TEST段数据长度0x0000000C
TEST段拷贝函数地址0x080002F4
TEST段在FLASH的起始地址0x08000380
ZI段在RAM的起始地址0x20000800
ZI段长度0x00000400
ZI段初始化函数地址0x08000304

可以在这种情况下scatter会去拷贝一个新的段,这样一来在既节省空间又节省时间的情况下完成了数据的分散加载,岂不美哉?

使用__attribute__((section("TEST")))配合xxx.sct

采用上述__attribute__((at(x)))配合xxx.sct的方式已经可以解决问题,但是却产生了其它几个名为.ARM.__AT_0x20000500,.ARM.__AT_0x20000504,.ARM.__AT_0x20000508的段,这会降低链接器的链接的效率,因此,最好的解决方法是使用 __attribute __((section("TEST")))。

image.png

如此一来,生成的.map文件也清爽很多。

image.png

五、Mircolib

实际上,上述代码是在用户勾选了“USE Mircolib”选项前提下得到的,而在取消使用mirco lib,使用默认arm lib时,__main函数的情况又有所不同,然而具体的分散加载方式却与使用“USE Mircolib”时基本一致,此处不再赘述。

image.png