stm32f407启动代码分析

2023-11-03

官方资料

有关Cortex 内核的指令我们可以参考《CM3 权威指南 CnR2》第四章:指令集。剩下的 ARM 的汇编指令我们可以在 MDK->Help->Uvision Help 中搜索到,检索出来的结果会有很多,我们只需要看 Assembler User Guide 这部分即可。

指令名称 作用
EQU 给数字常量取一个符号名,相当于 C 语言中的 define
AREA 汇编一个新的代码段或者数据段
SPACE 分配内存空间
PRESERVE8 当前文件堆栈需按照 8 字节对齐
EXPORT 声明一个标号具有全局属性,可被外部的文件使用
DCD 以字为单位分配内存,要求 4 字节对齐,并要求初始化这些内存
PROC 定义子程序,与 ENDP 成对使用,表示子程序结束
WEAK 弱定义,如果外部文件声明了一个标号,则优先使用外部文件定义的标号
IMPORT 声明标号来自外部文件,跟 C 语言中的 EXTERN 关键字类似
B 跳转到一个标号
ALIGN 编译器对指令或者数据的存放地址进行对齐,一般需要跟一个立即数,缺省表示 4 字节对齐。
END 到达文件的末尾,文件结束
IF,ELSE,ENDIF 汇编条件分支语句,跟 C 语言的 if else 类似

Cortex-M3内核怎么开始执行一个程序

程序要执行得有栈用于局部变量,函数调用,函数形参等的开销,得有一个指针指向要执行的程序,所以Cortex-M3内核复位后做以下三件事:
1、从0x00000000读出栈顶(MSP)
2、从0x00000004读出程序计数器(PC)
3、跳转执行PC指向的代码

启动文件做什么

我们知道了Cortex-M3内核要读出栈顶和程序计数器,那么栈顶在哪,栈有多大,PC指针指向哪里,中断怎么处理,怎么开始执行C函数?这些就是启动文件里通过汇编语句要处理的事情

1、初始化堆栈大小

设置栈大小

Stack_Size		EQU     0x400

                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   Stack_Size
__initial_sp

EQU相当于#define
AREA用于定义一个新的数据段或者代码段,后面参数表示这个段名字为 STACK,NOINIT 即不初始化,可读可写,8(2^3)字节对齐。
SPACE指令用于分配一段连续的内存空间,Stack_Mem 是标签也是首地址,__initial_sp是末地址(即栈顶)
设置堆大小

Heap_Size      EQU     0x200

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem        SPACE   Heap_Size
__heap_limit

开辟堆的大小为 0X00000200(512 字节),名字为 HEAP,NOINIT 即不初始化,可读可写,8(2^3)字节对齐。__heap_base 表示对的起始地址,__heap_limit 表示堆的结束地址。堆是由低向高生长的,跟栈的生长方向相反。堆主要用来动态内存的分配,像 malloc()函数申请的内存就在堆上面。

2、初始化中断向量表

Cortex-M3内核拥有11个系统异常和最多240个外部中断,当有中断或异常发生,会返回一个编号给内核,内核通过编号查找中断向量表找到对应中断服务函数的地址去执行,所以中断向量表存放的就是中断服务函数的地址

3、初始化堆栈指针 SP=_initial_sp、PC 指针=Reset_Handler

; 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 detection                        
                DCD     TAMP_STAMP_IRQHandler             ; Tamper and TimeStamps through 
                ;为减小篇幅中间部分省略
                                             
__Vectors_End
__Vectors_Size  EQU  __Vectors_End - __Vectors

DCD指令表示在存储器上分配一片连续的字存储单元,并把 DCD 后面跟的值赋值到刚分配的存储单元内。因为是第一次使用DCD所以分配的地址从0开始,每次分配4字节所以0x00000000放__initial_sp,0x00000004放Reset_Handler,实现了初始化MSP地址和PC指向的地址

4、配置系统时钟

Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
        IMPORT  SystemInit
        IMPORT  __main

                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP

WEAK表示此声明是弱声明
EXPORT 是声明外部全局标签
IMPORT 引入外部全局标签
①“LDR R0, =SystemInit” 是将函数 SystemInit 的地址放到寄存器 R0中保存。
② “BLX R0” 是跳转到 R0 寄存器存储的地址处运行。B是直接跳转指令,B后加L表示保存PC的值到寄存器 R14,可以在执行完跳转全部指令后返回跳转前的位置。B后加X是表示根据跳转的地址改变当前的状态,地址的最低位 add[0] 若是1,则将存储器状态更改为 Thumb 状态,反之地址的最低位 add[0] 若是0,则将存储器状态更改为 ARM 状态。( 注意Cortex-M3内核不允许进入ARM 状态,否则将会产生一个硬件异常中断 HardFault_Handler )。

在SystemInit中完成时钟配置等的系统配置,__main() 函数执行C语言环境初始化的操作,包括堆栈、寄存器等的设置,初始化完成后,将会跳转到main()

5、初始化用户堆栈,从而最终调用 main 函数

                 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

首先判断是否定义了__MICROLIB (在 KEIL 里面配置),如果定义了这个宏则赋予标号__initial_sp(栈顶地址)、__heap_base(堆起始地址)、__heap_limit(堆结束地址)全局属性,可供外部文件调用,然后堆栈的初始化就由 C 库函数_main 来完成如果没有定 义 __MICROLIB ,需要编写一个初始化堆栈的函数,标签为 __user_initial_stackheap ,并将其声明为外部全局标签,以供 __main() 函数在初始化C语言环境时使用。
IF,ELSE,ENDIF:汇编的条件分支语句,跟 C 语言的 if ,else 类似
END:文件结束

参考博客: https://blog.csdn.net/qq_36300069/article/details/124319349

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

stm32f407启动代码分析 的相关文章

  • 如何修改内核DTB文件

    Summary 我目前正在为定制板编译 Linux 内核 内核 模块和 DTB 以及一些定制驱动程序 有时 我会编译内核并意识到 DTB 文件中的兼容性字符串不是自定义驱动程序正在寻找的内容 现在 我可以解决此问题的唯一方法是修改 DTS
  • 将结构体偏移属性赋予汇编器

    如何将 C 结构体的偏移量发送到汇编代码 例如 在我的 C 代码中 typedef struct unsigned int a unsigned int b CMyStruct 我向 ASM 函数发送一个 CMyStruct 结构的指针 假
  • 使用 gnueabihf 为 ARMv6 构建

    我尝试为 ARMv6 构建应用程序 但失败了 我猜问题是工具链支持硬浮点 但 ARMv6 不支持 好吧 首先我设置 march armv6 编译失败 opt gcc linaro arm linux gnueabihf 4 8 2014 0
  • 使用 ARM NEON 内在函数添加 alpha 和排列

    我正在开发一个 iOS 应用程序 需要相当快地将图像从 RGB gt BGRA 转换 如果可能的话 我想使用 NEON 内在函数 有没有比简单分配组件更快的方法 void neonPermuteRGBtoBGRA unsigned char
  • 哪些变量类型/大小在 STM32 微控制器上是原子的?

    以下是 STM32 微控制器上的数据类型 http www keil com support man docs armcc armcc chr1359125009502 htm http www keil com support man d
  • ARM架构中不同处理器模式下如何使用内核堆栈?

    据我了解 每个进程都有一个用户堆栈和内核堆栈 除此之外 ARM 架构中的每种模式都有一个堆栈 所以我想知道不同的堆栈和堆栈指针在 ARM 模式下如何工作 另外 何时会使用与进程关联的内核堆栈 何时会使用与进程关联的内核堆栈 当您进行系统调用
  • 将 GCC 内联汇编与采用立即值的指令结合使用

    问题 我正在为 ARM Cortex M3 处理器开发定制操作系统 为了与我的内核交互 用户线程必须生成 SuperVisor Call SVC 指令 以前称为 SWI 用于软件中断 该指令在ARM ARM中的定义是 这意味着该指令需要即时
  • 可以使用Visual Studio 2012构建ARM桌面程序吗?

    我正在使用 Visual Studio 2012 beta 我的桌面 win32 程序在 ARM 架构中编译得很好 升级到 Visual Studio 2012 RC 后 编译器无法工作并出现以下错误 不支持为 ARM 平台编译桌面应用程序
  • arm-thumb指令集的blx指令如何支持4MB范围

    读自https www keil com support man docs armasm armasm dom1361289866046 htm https www keil com support man docs armasm arma
  • 分析 Cortex-M7 (stm32f7) 上的 memcpy 性能

    简洁版本 从 GNU ARM 工具链中提取的 memcpy 的性能指标在 ARM Cortex M7 上对于不同的副本大小似乎差异很大 即使复制数据的代码始终保持不变 这可能是什么原因造成的 长版 我是使用 GNU Arm 工具链 11 2
  • 移动数组中的元素

    我需要一点帮助 我想将数组中的元素向上移动一个元素 以便新位置 1 包含位置 1 中的旧值 new 2 包含 old 1 依此类推 旧的最后一个值被丢弃 第一个位置的新值是我每秒给出的新值 我使用大小为 10 的数组 uint32 t TE
  • DS-5:什么是 FVP、RTSM、基础模型、AEM 模型、快速模型、CADI?

    DS 5 模拟器使用了很多术语 如 FVP RTSM 快速模型 基础模型 AEM 模型 CADI Arm的文档中提供的解释不是很清楚 这些术语的含义是什么 作为 DS 5 的最终用户我应该关心哪些术语 Model 软件模拟的行业术语 就 A
  • 使用 NEON 优化 Cortex-A8 颜色转换

    我目前正在执行颜色转换例程 以便从 YUY2 转换为 NV12 我有一个相当快的函数 但没有我预期的那么快 主要是由于缓存未命中 void convert hd uint8 t orig uint8 t result uint32 t wi
  • 了解 U-Boot 内存占用

    我不明白加载 U Boot 时 RAM 中发生了什么 我正在开发 Xilinx Zynq ZC702 评估套件 并尝试使用 U Boot 在其上加载 Linux 内核 于是我使用Xilinx工具Vivado和SDK生成了一个BOOT bin
  • 直接在 ARM 目标上调试单声道应用程序

    我最近在 BeagleBone 嵌入式 ARM 设备上安装了 Mono 希望通过 USB 连接 Kinnect 传感器并使用 C Mono 控制它 我想知道 Mono 我正在使用 MonoDevelop 但我想这个问题也适用于 VS 是否允
  • iPhone 3GS 上的 ARM 与 Thumb 性能比较,非浮点代码

    我想知道是否有人有关于 iPhone 3GS 上 ARM 与 Thumb 代码性能的硬性数据 特别是对于非浮点 VFP 或 NEON 代码 我知道 Thumb 模式下的浮点性能问题 更大的 ARM 指令的额外代码大小是否会在某个时刻成为性能
  • 什么是遗留中断?

    我正在开发一个项目 试图弄清楚 ARM 架构的全局中断控制器中如何处理中断 我正在使用 pl390 中断控制器 我看到有一条线被称为传统中断 它绕过了分配器逻辑 假设有 2 个中断可以被编程为传统中断 任何人都可以帮助解释一下什么是遗留中断
  • stm32l0: 执行MI命令失败。使用 vFlashErase 数据包擦除闪存时出错

    我正在使用 Nucleo STM32L031 和 AC6 STM32 工作台 eclipse 我编写应用程序并进入调试模式 一切正常 直到我在应用程序中添加另一个功能 我注意到当我删除 评论 新函数 软件可以再次进入调试模式 但是当我添加
  • 英特尔的最后分支记录功能是英特尔处理器独有的吗?

    最后分支记录是指存储与最近执行的分支相关的源地址和目标地址的寄存器对 MSR 的集合 它们受英特尔酷睿 2 英特尔至强和英特尔凌动处理器系列的支持 http css csail mit edu 6 858 2012 readings ia3
  • 哪些 GCC 优化标志对二进制大小影响最大?

    我正在使用 GCC 为 ARM 开发 C 我遇到了一个问题 我没有启用优化 我无法创建二进制文件 ELF https en wikipedia org wiki Executable and Linkable Format 对于我的代码 因

随机推荐

  • Alluxio介绍

    Alluxio介绍 Alluxio是什么 Alluxio是世界上第一个用于云分析和人工智能的开源数据编排技术 它弥合了数据驱动应用程序和存储系统之间的鸿沟 使存储层的数据更接近数据驱动应用程序 并使其易于访问 使应用程序能够通过一个通用接口
  • 2021美赛C题解题思考+参考文献+部分git开源代码

    解题思路 关于蜜蜂扩散的模型建立 标签方面 报告类型 数据集2021MCM ProblemC DataSet xlsx可以看出 在每次报告中Positive ID 有14 份 而 Negative ID 有 2069 份 Unverifie
  • 光纤收发器tx和rx是什么意思?二者有什么区别?

    现如今 在视频监控工程的高清视频图像传输中 一般都会使用光纤收发器 光纤收发器也被称之为光电转换器 Fiber Converter 可以将短距离的双绞线 网线 电信号和长距离的光信号 光纤 进行互换的以太网传输媒体转换设备 这样就能延长信号
  • 百度编辑器UEditor,怎样禁止用户粘贴??

    editor a addListener beforepaste myEditor paste function myEditor paste o html html html alert 只能录入不能粘贴
  • INFO BRAINPAN: 1

    INFO BRAINPAN 1 About Release Back to the Top Name Brainpan 1 Date release 20 Mar 2013 Author superkojiman Series Brainp
  • iOS应用添加第三方支付

    最简单明了的教程还是官方文档 以下是我给应用添加支付功能 记录下 1 微信支付 官方文档 https pay weixin qq com wiki doc api app php chapter 8 5 假设你的应用在微信开放平台已经创建
  • activeMQ的学习

    原来一直在使用activeMQ 没有对它进行整理 现在看到一个不错的activeMQ详细介绍 http www itpub net tree index 312 1
  • 遇到问题之-LNMP编译安装Redis构建高速Redis缓存

    LNMP编译安装Redis构建高速Redis缓存 前面已经讲过LNMP编译Memc和Srcache构建高速Memcached缓存 这次换另一种被广泛应用的缓存 Redis Redis实际上是一个高性能的key value数据库 他可以代替M
  • 如何使用java的String.split()方法分割话单,方便查看

    工作中 想要快速查到话单中某一列的值 可以使用String split 方法 但是如果直接使用就会变成如下图 那么怎么办呢 原因是 是转义字符 必须得加 如下图 是不是很明显就看出某一列的数值啦 代码片段 public static voi
  • mysql查询最近三个月数据方法

    select from t user where time gt DATE SUB CURDATE INTERVAL 1 WEEK 一周 select from t user where time gt DATE SUB CURDATE I
  • jQuery-两次基础了解总结-引入-选择器-选择集转移

    作者 芝士小熊饼干 系列专栏 数据结构 蓝桥杯 算法 坚持天数 17天
  • C++ 实现RSA加密

    背景 因项目需要 要做一个调用短信接口发送短信的功能 需要实现一个功能是 给定一个字符串 给定一个密钥对 实现RSA公钥加密 Base64加密 然后将加密后的字符串发给服务器 服务器返回通过私钥和Base64加密后的字符串 然后我这边要实现
  • 版本号大小比较算法

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 版本号大小比较算法 版本号之间比较大小 本质上是比较字符串之间的关系 这里给定两个版本号 你一定能迅速地区分出大小 0 0 2 0 0 3 想要让计算机程序分辨她们的关系
  • 云开发推送订阅消息报错 47003 rid ***

    小程序云开发推送订阅消息一直出现类似的问题 推送失败 errcode 47003 errmsg argument invalid data thing9 value is invalid rid 5f3a7906 0c594b15 6792
  • cisco VoIP软电话配置实验

    cisco VoIP软电话配置实验 2010 12 21 14 53 40 标签 语音通信 cisco 软电话 休闲 VoIP 职场 原创作品 允许转载 转载时请务必以超链接形式标明文章 原始出处 作者信息和本声明 否则将追究法律责任 ht
  • hdu 1022 简单的栈应用

    本题链接 点击打开链接 Train Problem I Time Limit 2000 1000 MS Java Others Memory Limit 65536 32768 K Java Others Total Submission
  • 基于Paddle Serving&百度智能边缘BIE的边缘AI解决方案

    Paddle Serving作为飞桨 PaddlePaddle 开源的服务化部署服务化方案 提供了C Serving和Python Pipeline两套框架 旨在帮助深度学习开发者和企业提供高性能 灵活易用的工业级在线推理服务 助力人工智能
  • unable to read project file....不能读取项目文件的解决方法

    我直接把整个解决方案和项目的源文件拷贝到另外的磁盘或者另外的文件夹和另外的电脑上 则有可能出现这个问题 解决方案 针对不同的问题可能有不同的解决方法 下面仅列举几种 删除解决方案中的 suo文件 这个与 sln一个目录下 一般为隐藏的 需要
  • 内存中有两个4字节以压缩的bcd_微机原理课后习题答案

    第1章 进制及码元 1 进制转换 129 81H 10000001B 201Q 298 12AH 100101010B 452Q 1000 3E8H 1111101000B 1750Q 5DH 1011101 B 135 Q 93 D 3E
  • stm32f407启动代码分析

    stm32f407启动代码分析 官方资料 Cortex M3内核怎么开始执行一个程序 启动文件做什么 1 初始化堆栈大小 2 初始化中断向量表 3 初始化堆栈指针 SP initial sp PC 指针 Reset Handler 4 配置