MCU启动文件小解一下

GD32启动文件分析

  • 启动文件的一些指令
  • .s启动文件分析
    • 栈空间分配
    • 堆空间管理
    • 中断向量表定义
    • 堆空间定义
    • Reset_Handler复位程序
    • HardFault_Handler
    • _main文件分析
    • 用户堆栈初始化

GD32启动文件主要做了以下工作:
初始化SP=_initial_sp , PC=Reset_Handler指针,设置堆栈大小,初始化中断向量表,调用SystemInit,_main,最终调用到main函数。

启动文件的一些指令

指令名称作用
EQU给数字常量取一个符号名,相当于 C 语言中的 define
AREA汇编一个新的代码段或者数据段
ALIGN编译器对指令或者数据的存放地址进行对齐,一般需要跟一个立即数,缺省表示 4 字节对齐。要注意的是,这个不是 ARM 的指令,是编译器的,这里放到一起为了方便。
SPACE分配内存空间
PRESERVE8当前文件堆栈需要按照 8 字节对齐
THUMB表示后面指令兼容 THUMB 指令。在 ARM 以前的指令集中有 16 位的THUMBM 指令,现在 Cortex-M 系列使用的都是 THUMB-2 指令集,THUMB-2 是 32 位的,兼容 16 位和 32 位的指令,是 THUMB 的超级版。
EXPORT声明一个标号具有全局属性,可被外部的文件使用
DCD以字节为单位分配内存,要求 4 字节对齐,并要求初始化这些内存
PROC定义子程序,与 ENDP 成对使用,表示子程序结束
WEAK弱定义,如果外部文件声明了一个标号,则优先使用外部文件定义的标号,如果外部文件没有定义也不会出错。要注意的是,这个不是 ARM 的指令,是编译器的,这里放到一起为了方便。
IMPORT声明标号来自外部文件,跟 C 语言中的 extern 关键字类似
LDR从存储器中加载字到一个存储器中
BLX跳转到由寄存器给出的地址,并根据寄存器的 LSE 确定处理器的状态,还要把跳转前的下条指令地址保存到 LR
BX跳转到由寄存器/标号给出的地址,不用返回
B跳转到一个标号
IF,ELSE,ENDIF汇编条件分支语句,跟 C 语言的类似
END到达文件的末尾,文件结束

主要是一些arm指令,ARM指令还能够从keil的IDE ->help 里找到
在这里插入图片描述
在这里插入图片描述

.s启动文件分析

栈空间分配

在这里插入图片描述EQU:宏定义的伪指令,给数字常量取一个符号名,类似与 C 中的 define。定义栈大小为 0x00000400 字节,即 1024B(1KB),常量的符号是 Stack_Size。
AREA: 汇编一个新的代码段或者数据段。段名为 STACK,段名可以任意命名;
NOINIT 表示不初始化; READWRITE 表示可读可写;ALIGN=3,表示按照 2^3 对齐,
即 8 字节对齐。
SPACE 分配内存指令,分配大小为 Stack_Size 字节连续的存储单元给栈空间。
__initial_sp 紧挨着 SPACE 放置,表示栈的结束地址,栈是从高往低生长,所以结束地址就是栈顶地址。
通过map文件查看栈的initial_sp可以看到恰好栈由栈顶高地址到低地址是0x400
在这里插入图片描述

堆空间管理

在这里插入图片描述
开辟堆的大小
为 0x00000000(0 字节),段名为 HEAP,不初始化,可读可写,8 字节对齐。__heap_base表示堆的起始地址,__heap_limit 表示堆的结束地址。堆和栈的生长方向相反的,堆是由低向高生长,而栈是从高往低生长。
这里我这只为0,因为我用了freertos里heap的方式进行内存管理,就不用系统默认的堆了,因为malloc缺点比较多,容易造成较大的内存碎片。

堆可以用于动态内存分配,比如通过malloc()、calloc()和 realloc()等函数
malloc() 函数在堆上分配参数size字节大小的内存,并返回指向新分配内存起始位置处的指针,其所分配的内存未经初始化。
calloc() 函数用于给一组相同对象分配内存。参数mumitems指定分配对象的数量,size指定每个对象的大小与malloc()不同,calloc()会将已分配的内存初始化为0。
realloc() 函数用来调整(通常是增加)一块内存的大小
在这里插入图片描述
PRESERVE8:指示编译器按照 8 字节对齐。
THUMB:指示编译器之后的指令为 THUMB 指令。

中断向量表定义

在这里插入图片描述
定义一个数据段,名字为 RESET, READONLY 表示只读。EXPORT 表示声明一个标号
具有全局属性,可被外部的文件使用。这里是声明了__Vectors、__Vectors_End 和__Vectors_Size 三个标号具有全局性,可被外部的文件使用。
当内核响应了一个发生的异常后,对应的异常服务例程(ESR)就会执行。为了决定 ESR的入口地址, 内核使用了向量表查表机制。向量表其实是一个 WORD(32 位整数)数组。
每个下标对应一种异常,该下标元素的值则是该 ESR 的入口地址。
在复位后,该寄存器的值为 0。因此,在地址 0 (即 FLASH 地址 0) 处必须包含一张向量表,用于初始时的异常分配。
当然,我们如果说有bootloader的话,我们的起始地址将不会在0,这时候就需要通过 NVIC 中的一个重定位寄存器来指出向量表的地址。
在这里插入图片描述

转载自正点原子启动文件解析
举个例子,如果发生了异常 SVCall,则 NVIC 会计算出偏移移量是 11x4=0x2C,然后从那里取出服务例程的入口地址并跳入。要注意的是这里有个另类:地址 0x0000 0000 并不是什么入口地址,而是给出了复位后 MSP 的初值。
灰色部分是系统内核中断,后面就是用户的中断。

堆空间定义

接下来是定义只读代码段,定义一个段命为.text,只读的代码段,在 CODE 区。
在这里插入图片描述

Reset_Handler复位程序

在这里插入图片描述
PROC、ENDP 一对伪指令作为程序的起始和结束。
通过EXPORT 和 week 来声明其全局属性,同时将其声明为弱函数,外部可以定义覆盖。
IMPORT 表示SystemInit和__main来自外部文件。
LDR表示将Systeminit和_main存储到寄存器R0中。
BLX 表示跳转到由寄存器给出的地址,并根据寄存器的 LSE 确定处理器的状态,还要把跳转前的下条指令地址保存到 LR。
BX 表示跳转到由寄存器/标号给出的地址,不用返回。这里表示切换到__main地址,最终调用 main 函数,不返回,进入 C 的世界。

HardFault_Handler

在这里插入图片描述
若定义了HardFault_Handler,则执行我们自己的HardFault_Handler,若没有定义,则运行B . 这条汇编,进行原地跳转。
其他的中断也是如下。
在这里插入图片描述

_main文件分析

当看到__main 函数时,估计有不少人认为这个是 main 函数的别名或是编译之后的名字,
否则在启动代码中再也无法找到和 main 相关的字眼了。可事实是,_main 和 main 是两个完全不同的函数。_main 代码是编译器自动创建的,因此无法找到_main 代码。MDK 文档中有一句说明:it is automatically craated by the linker when it sees a definition of main() 。大体意
思可以理解为:当编译器发现定义了 main 函数,那么就会自动创建_main。
程序经过汇编启动代码,执行到__main()后,可以看出有两个大的函数:
__scatterload():负责把 RW/RO 输出段从装载域地址复制到运行域地址,并完成了 ZI运行域的初始化工作。
1._scatterload_null:判断r10和r11是否相等,不相等就跳到_scatterload_copy
2._scatterload_copy 复制好之后,在会到_scatterload_null判断是否相等,相等后进入__scatterload_zeroinit
3.__scatterload_zeroinit:对ZI段进行清零,最后跳回__scatterload
然后跳转到__rt_entry()

__rt_entry() :负责初始化堆栈,完成库函数的初始化,最后自动跳转向 main()函数。
先调用 __user_setup_stackheap 函数,然后调用__user_libspace进行一些微库的初始化,最后到__user_setup_stackheap初始化堆栈,调用__rt _entry_main最后回到main。
在这里插入图片描述

用户堆栈初始化

在这里插入图片描述
ALIGN 表示对指令或者数据的存放地址进行对齐,一般需要跟一个立即数,缺省表示4 字节对齐。
首先判断是否定义了__MICROLIB。关于__MICROLIB 这个宏定义,我们是在 KEIL里面配置。
在这里插入图片描述
如果定义__MICROLIB,声明__initial_sp、__heap_base 和__heap_limit
这三个标号具有全局属性,可被外部的文件使用。__initial_sp 表示栈顶地址,__heap_base表示堆起始地址,__heap_limit 表示堆结束地址。
没有定义__MICROLIB,实际的情况就是我们没有定义__MICROLIB,所以使用默认的 C 库运行。堆栈的初始化由 C 库函数__main 来完成。
IMPORT 声明__use_two_region_memory 标号来自外部文件。
EXPORT 声明__user_initial_stackheap 具有全局属性,可被外部的文件使用。
标号__user_initial_stackheap,表示用户堆栈初始化程序入口。
接下来进行堆栈空间初始化,堆是从低到高生长,栈是从高到低生长,是两个互相独立的数据段,并且不能交叉使用。
保存堆起始地址。
保存栈大小。
保存堆大小。
保存栈顶指针。
跳转到 LR 标号给出的地址,不用返回。
END 表示到达文件的末尾,文件结束。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/353206.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux下安装openresty

Linux下安装openresty 十一、Linux下安装openresty11.1.概述11.2.下载OpenResty并安装相关依赖:11.3.使用wget下载:11.4.解压缩:11.5.进入OpenResty目录:11.6.编译和安装11.7.进入OpenResty的目录,找到nginx:11.8.在conf目录下的nginx.conf添…

React一学就会(3): 强化练习一

前言 兄弟们点个关注点点赞,有什么建议在评论里留言说一下,一定要和我多多互动啊,这样我才有动力创作出更有品质的文章。 这节课我们用前两节课的知识做一个实践,在实战中巩固我们所学。本来我想借用官方的示例翻译一下&#xf…

Redis3-秒杀活动

秒杀 准备工作 我是参照下面这位大佬的i骄傲成下载的 csdn友情链接 Jmeter模拟多线程的压力测试工具 秒杀代码: package com.aaa.controller;import io.netty.util.internal.StringUtil; import org.apache.commons.lang.StringUtils; import org.springfram…

HarmonyOS鸿蒙ArkTS,封装http网络请求

HarmonyOS鸿蒙ArkTS,封装http网络请求 前提: 要想使用http请求,系统必须要具备ohos.permission.INTERNET权限,在model.json5文件中的module模块下添加如下请求权限: 在module.json5文件中 配置 "requestPermi…

1949-2022年交通运输设备行业数据

1949-2022年交通运输设备行业数据 1、时间1949-2021年 2、指标:民用驳船保有量(艘)_AmoCivBar、民用机动船保有量(艘)_AmoCivMotBoat、民用运输机保有量(架)_AmoPlaTra、民用其他汽车保有量(万辆)_AmoOthAutCiv、私人其他汽车保有量(万辆)_AmoOthAutPri、新注册民…

k8s 进阶实战笔记 | Scheduler 调度策略总结

文章目录 Scheduler 调度策略总结调度原理和过程调度策略nodeSelect亲和性和反亲和性NodeAffinify亲和验证PodAffinity 亲和验证PodAntiAffinity 反亲和验证污点与容忍跳过 Scheduler 调度策略 调度策略场景总结 Scheduler 调度策略总结 调度原理和过程 Scheduler 一直监听着…

Linux使用二进制包安装MySQL

目录 一、软件包下载 二、上传软件包到Linux根目录 1、使用xftp将软件包上传到根目录 2、解压缩 三、准备工作 四、初始化软件 五、设置MySQL的配置文件 六、配置启动脚本 一、软件包下载 官网下载:MySQL :: Download MySQL Community Server 二、上传软件…

【leetcode题解C++】144. 94. 145.二叉树前序、中序、后序遍历 and 102.二叉树的层序遍历

144. 二叉树前序遍历 给出一个根节点,返回前中后序遍历的结果的。 示例 1: 输入:root [1,null,2,3] 输出:[1,2,3]示例 2: 输入:root [] 输出:[]示例 3: 输入:root…

vue项目如何打包,java项目如何打包

目录 vue项目如何打包 java项目如何打jar包 使用Maven打包为JAR(方式一)视图: 先双击clean再双击package即可打包 使用Maven打包为JAR(方式二)命令: 1、确保你已经安装了Maven,并且配置了相应…

关机恶搞小程序

1. system("shutdown")的介绍 当system函数的参数是"shutdown"时,它将会执行系统的关机命令。 具体来说,system("shutdown")的功能是向操作系统发送一个关机信号,请求关闭计算机。这将触发操作系统执行一系列…

uniapp实现页面左滑右滑切换内容

uniapp uview&#xff1a;使用uniapp的swiper和uview的tabs标签组合实现 Tabs 标签 | uview-plus 3.0 - 全面兼容nvue的uni-app生态框架 - uni-app UI框架 vue <template> <view class"main"> <view class""> …

ElasticSearch7.7.1集群搭建

前言 Elasticsearch&#xff08;ES&#xff09;是一个基于Apache Lucene的分布式、高扩展、近实时的搜索引擎&#xff0c;主要用于海量数据快速存储、实时检索、高效分析的场景。通过简单易用的RESTful API&#xff0c;Elasticsearch隐藏了Lucene的复杂性&#xff0c;使得全文搜…

elasticsearch8.x版本docker部署说明

前提&#xff0c;当前部署没有涉及证书和https访问 1、环境说明,我采用三个节点&#xff0c;每个节点启动两个es&#xff0c;用端口区分 主机角色ip和端口服务器Amaster192.168.2.223:9200服务器Adata192.168.2.223:9201服务器Bdata,master192.168.2.224:9200服务器Bdata192.1…

打开 IOS开发者模式

前言 需要 1、辅助设备&#xff1a;苹果电脑&#xff1b; 2、辅助应用&#xff1a;Xcode&#xff1b; 3、准备工作&#xff1a;苹果手机 使用数据线连接 苹果电脑&#xff1b; 当前系统版本 IOS 17.3 通过Xcode激活 两指同时点击 Xcode 显示选择&#xff0c;Open Develop…

眼底增强型疾病感知蒸馏模型 FDDM:无需配对,fundus 指导 OCT 分类

眼底增强型疾病感知蒸馏模型 FDDM&#xff1a;fundus 指导 OCT 分类 核心思想设计思路训练和推理 效果总结子问题: 疾病特定特征的提取与蒸馏子问题: 类间关系的理解与建模 核心思想 论文&#xff1a;https://arxiv.org/pdf/2308.00291.pdf 代码&#xff1a;https://github.c…

k8s学习-DaemonSet和Job

1.1DaemonSet是什么 Deployment部署的副本Pod会分布在各个Node上&#xff0c;每个Node都可能运行好几个副本。DaemonSet的不同之处在于&#xff1a;每个Node上最多只能运行⼀个副本。DaemonSet的典型应用场景有&#xff1a; &#xff08;1&#xff09;在集群的每个节点上运⾏存…

工业空调转IEC104协议转换网关BE108

随着电力系统信息化建设和数字化转型的进程不断加速&#xff0c;对电力能源的智能化需求也日趋增强。健全稳定的智慧电力系统能够为工业生产、基础设施建设以及国防建设提供稳定的能源支持。在此背景下&#xff0c;高性能的工业电力数据传输解决方案——协议转换网关应运而生&a…

CodeGPT--(Visual )

GitCode - 开发者的代码家园 gitcode.com/ inscode.csdn.net/liujiaping/java_1706242128563/edit?openFileMain.java&editTypelite marketplace.visualstudio.com/items?itemNameCSDN.csdn-codegpt&spm1018.2226.3001.9836&extra%5Butm_source%5Dvip_chatgpt_c…

面向Java开发者的ChatGPT提示词工程(11)扩写

什么是扩写&#xff1f; 扩写是指将较短的文本交给GPT生成更长的文本。比如&#xff1a;根据一组基本指令&#xff0c;写出一封完整的电子邮件&#xff1b;或者根据一系列主题&#xff0c;创作出一篇包含这些主题的文章。 这样的技术&#xff0c;有着广阔的应用场景&#xff…

FPGA 通过 UDP 以太网传输 JPEG 压缩图片

FPGA 通过 UDP 以太网传输 JPEG 压缩图片 简介 在 FPGA 上实现了 JPEG 压缩和 UDP 以太网传输。从摄像机的输入中获取单个灰度帧&#xff0c;使用 JPEG 标准对其进行压缩&#xff0c;然后通过UDP以太网将其传输到另一个设备&#xff08;例如计算机&#xff09;&#xff0c;所有…