打印
[STM32F1]

main函数之前究竟发生了什么?

[复制链接]
59|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
primojones|  楼主 | 2024-9-28 22:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

//=====================================================================
//TITLE:
//    main函数之前究竟发生了什么?
//AUTHOR:
//    norains
//DATE:
//    Friday  3-December-2010
//Environment:
//    MDK 4.1
//=====================================================================


     当使用MFC时,我们会认为入口函数是:: InitInstance;当使用WIN32 API时,我们会认为入口函数是WinMain;当我们写个纯粹的C++程序时,入口函数又变成了main;可当我们进入到嵌入式领域,却发现main函数之前还有一段启动代码!


     究竟在main函数之前,发生了什么?如果你觉得已经明白了这个过程,那么请试着回答这个问题:程序是存储到FLASH中的,运行时static变量地址是指向RAM,那么这些static变量的初始值是如何映射到RAM中的?


     我们以STM32F10x的启动代码为例,先看看其完整的源码:


[c-sharp]  view plain copy




  • ;/*****************************************************************************/
  • ;/* STM32F10x.s: Startup file for ST STM32F10x device series                  */
  • ;/*****************************************************************************/
  • ;/* <<< Use Configuration Wizard in Context Menu >>>                          */
  • ;/*****************************************************************************/
  • ;/* This file is part of the uVision/ARM development tools.                   */
  • ;/* Copyright (c) 2005-2007 Keil Software. All rights reserved.               */
  • ;/* This software may only be used under the terms of a valid, current,       */
  • ;/* end user licence from KEIL for a compatible version of KEIL software      */
  • ;/* development tools. Nothing else gives you the right to use this software. */
  • ;/*****************************************************************************/
  • ;// <h> Stack Configuration
  • ;//   <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
  • ;// </h>
  • Stack_Size      EQU     0x00000200
  •                 AREA    STACK, NOINIT, READWRITE, ALIGN=3
  • Stack_Mem       SPACE   Stack_Size
  • __initial_sp
  • ;// <h> Heap Configuration
  • ;//   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
  • ;// </h>
  • Heap_Size       EQU     0x00000000
  •                 AREA    HEAP, NOINIT, READWRITE, ALIGN=3
  • __heap_base
  • Heap_Mem        SPACE   Heap_Size
  • __heap_limit
  •                 PRESERVE8
  •                 THUMB
  • ; Vector Table Mapped to Address 0 at Reset
  •                 AREA    RESET, DATA, READONLY
  •                 EXPORT  __Vectors
  • __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     DMAChannel1_IRQHandler    ; DMA Channel 1
  •                 DCD     DMAChannel2_IRQHandler    ; DMA Channel 2
  •                 DCD     DMAChannel3_IRQHandler    ; DMA Channel 3
  •                 DCD     DMAChannel4_IRQHandler    ; DMA Channel 4
  •                 DCD     DMAChannel5_IRQHandler    ; DMA Channel 5
  •                 DCD     DMAChannel6_IRQHandler    ; DMA Channel 6
  •                 DCD     DMAChannel7_IRQHandler    ; DMA Channel 7
  •                 DCD     ADC_IRQHandler            ; ADC
  •                 DCD     USB_HP_CAN_TX_IRQHandler  ; USB High Priority or CAN TX
  •                 DCD     USB_LP_CAN_RX0_IRQHandler ; USB Low  Priority or CAN RX0
  •                 DCD     CAN_RX1_IRQHandler        ; CAN RX1
  •                 DCD     CAN_SCE_IRQHandler        ; CAN 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
  •                 AREA    |.text|, CODE, READONLY
  • ; Reset Handler
  • Reset_Handler   PROC
  •                 EXPORT  Reset_Handler             [WEAK]
  •                 IMPORT  __main
  •                 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  DMAChannel1_IRQHandler    [WEAK]
  •                 EXPORT  DMAChannel2_IRQHandler    [WEAK]
  •                 EXPORT  DMAChannel3_IRQHandler    [WEAK]
  •                 EXPORT  DMAChannel4_IRQHandler    [WEAK]
  •                 EXPORT  DMAChannel5_IRQHandler    [WEAK]
  •                 EXPORT  DMAChannel6_IRQHandler    [WEAK]
  •                 EXPORT  DMAChannel7_IRQHandler    [WEAK]
  •                 EXPORT  ADC_IRQHandler            [WEAK]
  •                 EXPORT  USB_HP_CAN_TX_IRQHandler  [WEAK]
  •                 EXPORT  USB_LP_CAN_RX0_IRQHandler [WEAK]
  •                 EXPORT  CAN_RX1_IRQHandler        [WEAK]
  •                 EXPORT  CAN_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]
  • WWDG_IRQHandler
  • PVD_IRQHandler
  • TAMPER_IRQHandler
  • RTC_IRQHandler
  • FLASH_IRQHandler
  • RCC_IRQHandler
  • EXTI0_IRQHandler
  • EXTI1_IRQHandler
  • EXTI2_IRQHandler
  • EXTI3_IRQHandler
  • EXTI4_IRQHandler
  • DMAChannel1_IRQHandler
  • DMAChannel2_IRQHandler
  • DMAChannel3_IRQHandler
  • DMAChannel4_IRQHandler
  • DMAChannel5_IRQHandler
  • DMAChannel6_IRQHandler
  • DMAChannel7_IRQHandler
  • ADC_IRQHandler
  • USB_HP_CAN_TX_IRQHandler
  • USB_LP_CAN_RX0_IRQHandler
  • CAN_RX1_IRQHandler
  • CAN_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
  •                 B       .
  •                 ENDP
  •                 ALIGN
  • ; User Initial Stack & Heap
  •                 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



     一些旁枝末节和本文的主题无关,我们先不要去理会,只需要知道这个启动代码是设置向量表,然后跳转到__main函数。跳转具体到代码段部分如下:

[c-sharp]  view plain copy




  • Reset_Handler   PROC
  •                 EXPORT  Reset_Handler             [WEAK]
  •                 IMPORT  __main
  •                 LDR     R0, =__main
  •                 BX      R0
  •                 ENDP



     当大家看到__main函数时,估计应该有不少人认为这个是main函数的别名或是编译之后的名字,否则在启动代码中再也无法找到和main相关的字眼了。可事实是,__main和main是完全两个不同的函数!如果这还不足以让你诧异,那么再告诉你另一个事实:你无法找到__main代码,因为这个是编译器自动创建的!


     如果你对此还半信半疑,可以查看MDK的文档,会发现有这么一句说明:It is automatically created by the linker when it sees a definition of main()。简单点来说,当编译器发现定义了main函数,那么就会自动创建__main。


     __main函数的出身我们基本搞清楚了,那么现在的问题是,它和main又有什么关系呢?其实__main主要做这么两件事:初始化C/C++所需的资源,调用main函数。初始化先暂时不说,但“调用main函数”这个功能能够让我们解决为什么之前的启动代码调用的是__main,最后却能转到main函数的疑惑。


     初始化C/C++所需的资源,如果脱离了具体情况,实在很难解释清楚,还是先看看编译出来的汇编代码片段:


     凡是以__rt开头的,都是用来初始化C/C++运行库的;而以__scatterload开头,则是根据离散文件的定义,将代码中的变量映射到相应的内存位置。而回答本文开头的问题,关键就在于__scatterload_copy函数!


     我们在STM32F10x平台举个简单的例子,首先要明白一点是,该平台的的flash地址以0x08000000为起始,主要是存储代码;而SRAM是以0x20000000为起始,也就是内存。然后C/C++有这么一行代码:

[cpp]  view plain copy




  • static int g_iVal = 12;



     当我们程序开始跑起来的时候,通过IDE发现,g_iVal被映射到内存地址0x20000000,数值为一个随机数0xFFFFBE00,而不是代码中设置的12,如图:


     我们让程序继续往下执行,当执行完毕__scatterload_copy之后,我们发现g_iVal这时候已经变成我们所需要的初始值了:


     接下来就是C/C++库的初始化,最后就是进入到main函数,而此时已经是万事俱备。



使用特权

评论回复
沙发
烟雨蒙蒙520| | 2024-9-29 01:25 | 只看该作者
当微控制器上电或复位时,处理器会从特定的地址(通常是地址0x00000000)开始执行指令。这个地址通常存放的是中断向量表,包括复位处理程序的地址。复位处理程序负责初始化系统,然后跳转到__main函数。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

41

主题

1239

帖子

0

粉丝