上位机图像处理和嵌入式模块部署(f103 mcu中main入口函数误解)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

学习stm32代码的时候,关于汇编文件,大家一般都会参考官方给出的汇编文件。通常情况下,不会自己去写汇编文件。特别是汇编文件的最后一行,大家都会把__main看成是直接进入main函数。后面通过反汇编,发现情况并不是这样的。我们编写代码,除了keil工程中的内容,还有MicroLib库,这一点常常被我们忽视。

1、之前的汇编代码

; Reset handler
Reset_Handler   PROC
                EXPORT  Reset_Handler             [WEAK]
                IMPORT  __main
                IMPORT  SystemInit
                LDR     R0, =SystemInit
                BLX     R0               
                LDR     R0, =__main
                BX      R0
                ENDP

汇编代码这部分呢,大家一般都不会陌生,我们也通常都认为是__main直接跳转到了自定义的main函数。但是实际情况,我们可以通过反汇编来确认。

2、如何生成反汇编文件

在项目的User tab配置中,添加这样的命令,就可以在project下面生成dis文件,

fromelf --text -a -c --output=Fire_F103VE.dis ../Output/Fire_F103VE.axf

这样在最后的axf生成的同时,也能生成dis文件。如果需要生成bin文件,也是类似的做法。

fromelf --bin --output Fire_F103VE.bin ../Output/Fire_F103VE.axf

3、找到Reset_Handler位置

首先我们找到Reset_Handler位置,

    __Vectors
        0x08000000:    20000410    ...     DCD    536871952
        0x08000004:    08000145    E...    DCD    134218053
        0x08000008:    08000d81    ....    DCD    134221185

一般向量的第二个选项就是reset入口,不过mcu很奇怪,入口地址都要减去1才是正确的地址。也就是说,这里的Reset_Handler其实是08000144,

    Reset_Handler
        0x08000144:    4806        .H      LDR      r0,[pc,#24] ; [0x8000160] = 0x8000e17
        0x08000146:    4780        .G      BLX      r0
        0x08000148:    4806        .H      LDR      r0,[pc,#24] ; [0x8000164] = 0x8000131
        0x0800014a:    4700        .G      BX       r0

我们发现了,这边pc最后跳转的地址是8000131,因为需要减去1,那就是8000130,

    _main_stk
        0x08000130:    f8dfd00c    ....    LDR      sp,__lit__00000000 ; [0x8000140] = 0x20000410
    .ARM.Collect$$$$00000004
    _main_scatterload
        0x08000134:    f000f82a    ..*.    BL       __scatterload ; 0x800018c

这边执行不久,就跳转到了__scatterload,

    __scatterload
    __scatterload_rt2
        0x0800018c:    4c06        .L      LDR      r4,[pc,#24] ; [0x80001a8] = 0x8000ec4
        0x0800018e:    4d07        .M      LDR      r5,[pc,#28] ; [0x80001ac] = 0x8000ee4
        0x08000190:    e006        ..      B        0x80001a0 ; __scatterload + 20
        0x08000192:    68e0        .h      LDR      r0,[r4,#0xc]
        0x08000194:    f0400301    @...    ORR      r3,r0,#1
        0x08000198:    e8940007    ....    LDM      r4,{r0-r2}
        0x0800019c:    4798        .G      BLX      r3
        0x0800019e:    3410        .4      ADDS     r4,r4,#0x10
        0x080001a0:    42ac        .B      CMP      r4,r5
        0x080001a2:    d3f6        ..      BCC      0x8000192 ; __scatterload + 6
        0x080001a4:    f7ffffc8    ....    BL       __main_after_scatterload ; 0x8000138

快结束的时候,又跳转到了__main_after_scatterload,

    __main_after_scatterload
    _main_clock
    _main_cpp_init
    _main_init
        0x08000138:    4800        .H      LDR      r0,[pc,#0] ; [0x800013c] = 0x8000e75
        0x0800013a:    4700        .G      BX       r0

这边貌似要回到main函数了,看这里的地址是8000e75,那就是8000e74,

    i.main
    main
        0x08000e74:    bf00        ..      NOP      
        0x08000e76:    f7ffff9e    ....    BL       SystemClock_Config ; 0x8000db6
        0x08000e7a:    f7ffff2b    ..+.    BL       LED_GPIO_Config ; 0x8000cd4
        0x08000e7e:    e012        ..      B        0x8000ea6 ; main + 50
        0x08000e80:    2200        ."      MOVS     r2,#0
        0x08000e82:    f44f5100    O..Q    MOV      r1,#0x2000
        0x08000e86:    4808        .H      LDR      r0,[pc,#32] ; [0x8000ea8] = 0x40011000
        0x08000e88:    f7fffb4a    ..J.    BL       HAL_GPIO_WritePin ; 0x8000520
        0x08000e8c:    f44f707a    O.zp    MOV      r0,#0x3e8
        0x08000e90:    f7fff992    ....    BL       HAL_Delay ; 0x80001b8
        0x08000e94:    2201        ."      MOVS     r2,#1
        0x08000e96:    0351        Q.      LSLS     r1,r2,#13
        0x08000e98:    4803        .H      LDR      r0,[pc,#12] ; [0x8000ea8] = 0x40011000
        0x08000e9a:    f7fffb41    ..A.    BL       HAL_GPIO_WritePin ; 0x8000520
        0x08000e9e:    f44f707a    O.zp    MOV      r0,#0x3e8
        0x08000ea2:    f7fff989    ....    BL       HAL_Delay ; 0x80001b8
        0x08000ea6:    e7eb        ..      B        0x8000e80 ; main + 12

看到上面的代码,大约可以验证到我们的猜测了。

4、总结

**之前在做linux soc芯片汇编文件编写的时候,中断初始化、bss初始化、sp初始化、已初始化全局变量copy、main函数跳转,这些都是基本的内容。**后面自己看mcu代码的时候,却没有发现这部分内容,当时觉得很诧异,直到后来自己看了axf文件的反汇编内容之后,才晓得ide和背后的编译器帮我们做了很多事情。刚才说的这一切,都在main函数调用之前准备好了。但恰恰这一点,对于我们debug调试、分析和boot 加载研究很有帮助。

相关推荐
zy张起灵5 分钟前
48v72v-100v转12v 10A大功率转换电源方案CSM3100SK
经验分享·嵌入式硬件·硬件工程
lantiandianzi7 小时前
基于单片机的多功能跑步机控制系统
单片机·嵌入式硬件
哔哥哔特商务网7 小时前
高集成的MCU方案已成电机应用趋势?
单片机·嵌入式硬件
跟着杰哥学嵌入式7 小时前
单片机进阶硬件部分_day2_项目实践
单片机·嵌入式硬件
电子科技圈8 小时前
IAR与鸿轩科技共同推进汽车未来
科技·嵌入式硬件·mcu·汽车
东芝、铠侠总代136100683939 小时前
浅谈TLP184小型平面光耦
单片机·嵌入式硬件·物联网·平面
lantiandianzi9 小时前
基于单片机中医药柜管理系统的设计
单片机·嵌入式硬件
嵌入式知识大讲堂9 小时前
HDMI数据传输三种使用场景
单片机
黑客呀10 小时前
[系统安全]Rootkit基础
stm32·单片机·系统安全
小A15910 小时前
STM32完全学习——使用SysTick精确延时(阻塞式)
stm32·嵌入式硬件·学习