stm32启动过程cortex-m3架构堆栈代码位置编译汇编链接分析
Posted GK小卜
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了stm32启动过程cortex-m3架构堆栈代码位置编译汇编链接分析相关的知识,希望对你有一定的参考价值。
分析
一、 寄存器、架构、工作流程
1.这里以stm32的架构:cortex-m3(也即ARMv7)的寄存器的作用、在指令取,指令的译码,指令的执行在其中的作用以及是如何配合实现代码的执行的
哈佛结构和冯诺依曼结构是如何体现的?
编译后的代码为什么分为code、堆、栈、bss、data、符号等部分,分别存储在哪些地方?
首先看寄存器
寄存器分为寄存器组,和外设寄存器
寄存器组对用户是不可见的(用户不能直接操作),它是CPU处理数据时需要调用的
外设寄存器对用户是可见的(用户可以通过地址的映射来对寄存器操作,从而控制相应的外设动作)
上面的是寄存器组,是在Cortex-M3中用来临时存放运算的数据或者指示程序运行的位置
1、 寄存器架构
参考官方Cortex-M3权威指南
二 、总线与各个部件之间的关系(主要是I-Code Bus、D-Code Bus、System Bus)
上图所示的指令总线与数据总线与CM3内部的数据总线和数据总线不一样,具体可以看下面Cortex-M3内部结构图,而且上图的两个总线共用一个总线矩阵,就导致取指令和访问数据不能同时访问flash(在CM3里,指令和数据都是存放在flash中,部分数据存放在SRAM中,具体可以看指令和数据在stm32中存放的结构那一节),
而CM3外部总线部分是有芯片产商来决定,所以stm32的指令和数据总线是由意法半导体来设计制造的,具体架构如下图所示,可以看到该架构,指令和数据总线并没有共用一个总线矩阵,数据总线和系统总线是共用总线矩阵,从Cortex-M3的地址映射关系(从存储器映射来看stm32架构(内存与外设)那一节和指令和数据在stm32中存放的结构那一节),可以知道数据总线是是访问flash中的程序编译好后生成的静态数据(初始化的全局变量、 ),系统总线是访问SRAM中程序运行过程中产生的动态数据(局部变量、)
因为静态数据和动态数据不会同时访问,所以不用设计成可以同时访问的,也就可以共用一个总线矩阵
而读取指令和访问数据是可以同时进行的,所以就没有共用一个总线矩阵,这里就体现了哈佛结构的特性,指令与数据可以同时访问
下面这个是32官方参考手册,才是我们真正使用stm32的MCU具备的系统结构
体系结构:哈佛结构与冯诺依曼结构的区别
上述I-code与D-code与flash的连接就体现了哈佛结构的特性:
CPU采用的是哈佛结构还是冯诺依曼结构?
复位有三种启动方式,从哪里开始启动、启动代码的所在的位置
复位后启动的位置都是从内存地址为0x00000000的位置开始,如下图:
但是根据boot引脚的硬件配置,有三种不同的硬件映射方式,将处于内存(Flash、system memery、SRAM)中不同地址(参考上面存储器映射)的启动代码,映射到0x00000000这个位置;
一般都是将位于Flash的启动代码映射到0地址的位置,这个时候,取指令是通过ICode总线,取数据靠的是DCode和System 总线,通过不同的总线和总线矩阵,以及流水线的实现,可以实现指令和数据的同时访问,这样就体现了哈佛结构;
三、从存储器映射来看stm32架构(内存与外设)
内存的映射就是数据和代码实际存放的地址
外设映射的地址其实是控制该外设的寄存器的地址
整个架构说的就是处理核心、内存与外设寄存器它们的关系,是怎么通过各种总线连接起来的
如果取指令和访问数据能同时进行,那么这种总线连接的关系,就可以称之为哈佛结构;
存储器地址映射如下:
以上三图都是在 Cortex-M3权威指南 中定义的,说明该架构的这些存储器映射是有arm定义好的,不是由芯片生产厂商来定义
下图为 stm32中文参考手册中定义的,这具体的就是有芯片生产厂家来定义的,主要介绍了code区、SRAM、片上外设(编程时主要就是用这里的地址来控制相应的模块)
由上四图可知,外设分为片上外设(USART、GPIO等模块)、片外外设(这个需要自己扩展)、片内外设(中断NVIC、路径跟踪TPIU等、调试接口SWJ,它并不是调试组件),这里的片内是相对于Cortex-M3,在它内部的外设叫片内外设;
下图的附加调试组件与再下一个图的外部私有外设总线相连
Cortex-M3内部还有一个核心CM3Core,它周围的外设叫片内外设(调试系统(调试组件)为片上外设); CM3Core和片内外设组成Cortex-M3;
Cortex-M3周围的外设叫片上外设;
Cortex-M3和片上外设组成stm32芯片;
在stm32外部自己在通过PCB添加外设组件叫片外外设; 如下图所示:
Cortex-M3模块结构图:
该图里并不包含调试组件,与外部私有外设总线相连的是调试组件
上述两张图第一张是CM3Core和片内外设(不包括调试组件),加上调试组件,主要由ARM设计;
第二张图除了CM3Core和片内外设组成的Cortex-M3,以及Trace controller(调试组件),其它的是芯片制造公司设计制造的
抽象图如下两张图所示:
四、从CM3内核架构来看CPU流水线–分析Cortex-M3内核架构
从上一节我们了解到Cortex-M3的内核CM3,它就相当于日常电脑的CPU,架构图如下:Processor Core System那部分
上图的Register Bank又可以分为以下:
ARM CPU的组成
ARM——Cortex系列体系结构
三级流水线
ARM Cortex-A8体系结构
流水线中出现的三个相关:
1、数据相关:是指令在流水bai线中du重叠执行时,当后继指令需要用到zhi前面的指令产生的结果dao时发生的。
2、控制相关:是当流水线遇到转移指令引起的。统计表明,转移指令约占总指令的四分之一左右,比起数据相关,它会使流水线丧失更多的功能。
3.结构相关:多条指令进入流水线后在同一机器周期内争用同一功能部件所发生的冲突。
使用五级指令流水的优点:
1.并行性更好
2.周期:机器周期可以设置地更短、时钟周期也更短、主频更高
具体为以下5级
从上面指令译码那个可以看到与下一节x86CPU组成不一样的在于,x86CPU还有一个操作控制器OC,而arm相当于是在译码器包含了这个
五、 stm32(ARM CPU)与x86 CPU架构组成的异同点
x86CPU组成:
CPU的内部架构和工作原理
cpu架构一
这里的AC累加器、缓冲寄存器和ARM里的通用寄存器R0、R1是一个作用
ARM
六、stm32中指令、汇编语言、机器码
根据操作数的地址是在寄存器还是在内存还是立即数,将这些数据传输类型分为以下几种:
1、Cortex-CM3中的数据传输类型
1)、两个寄存器间的传输数据。MOV
2)、寄存器与存储器间传输数据。LDR、STR
3)、寄存器与特殊功能寄存器间传输数据。
4)、把一个立即数加载到寄存器。MOV
STM32学习之路入门篇之指令集及cortex——m3的存储系统
可以通过命令行来汇编与反汇编
ARM-CPU原理,基于ARM的SOC讲解
看下面这个例子:
LED0=0这条C指令编译器把它转换成了3条汇编指令MOVS、LDR、STR,这三句汇编分别对应的机器码就是2000、490B、6008。
图中,0x08。。。是CODE地址,然后该地址开始的机器码,最后就是这个机器对应的汇编语句。
F04F0001是对应汇编的机器码,你不用关心它的长度,有兴趣的可以去查汇编指令表,其中有对应机器码的格式
上面的机器码对三种操作数的寻址:寄存器(R0这些)、内存(flash等)、立即数
对立即数寻址就是确定该立即数的大小,
详细参考如下文章:
ARM体系架构总结
首先我们分析下上面的例子:
490B LDR R1,[PC,#44]
490A LDR R1,[PC,#40]
这两的机器码为啥只差了1,而立即数差了4
这是因为立即数寻址是有8位图决定的,不是直接映射数值的
我们可以看到它是将机器码的0-4位乘以4得到最终的立即数
0xb=11,114=44
0xa=10,104=40
参考
ARM指令计算机器码,自己归纳整理的ARM THUMB指令机器码表
32位指令的寻址方式如下:
ARM立即寻址中有效立即数的计算
为什么要通过这种方式来寻址:
寄存器寻址可以直接控制寄存器,在机器码中所需的位数不多,够用
内存中寻址,如果是32位的那地址就有0-2的32次方,32位指令的话不够用,但这里就可以采用【】的方式间接寻址
而立即数就没有办法通过直接和间接来,32位指令中间除去操作码,剩下的位数根本覆盖不了0-2的32次方,所有采用了位图加循环右移的方式
详细如下:
ARM指令中如何判断一个立即数是有效立即数
七、指令和数据在stm32中存放的结构、堆栈大小及位置
这一节应该和**从存储器映射来看stm32架构(内存与外设)**这一节结合来看
上面的代码区(Block0)又细分为以下:
Flash=Code + RO-Data + RW-Data(.data);
SRAM= RW-data+ZI-data(.bss+heap+stack);
.bss:未初始化的全局变量
heap:申请的动态内存
stack:局部变量都是放在栈中
STM32内存管理以及堆和栈的理解
下面是附件代码生成的map图
==============================================================================
Memory Map of the image
Image Entry point : 0x08000131
Load Region LR_IROM1 (Base: 0x08000000, Size: 0x0000293c, Max: 0x00010000, ABSOLUTE)
Execution Region ER_IROM1 (Exec base: 0x08000000, Load base: 0x08000000, Size: 0x00002904, Max: 0x00010000, ABSOLUTE)
Exec Addr Load Addr Size Type Attr Idx E Section Name Object
0x08000000 0x08000000 0x00000130 Data RO 231 RESET startup_stm32f10x_hd.o
0x08000130 0x08000130 0x00000000 Code RO 3423 * .ARM.Collect$$$$00000000 mc_w.l(entry.o)
0x08000130 0x08000130 0x00000004 Code RO 3738 .ARM.Collect$$$$00000001 mc_w.l(entry2.o)
0x08000134 0x08000134 0x00000004 Code RO 3741 .ARM.Collect$$$$00000004 mc_w.l(entry5.o)
0x08000138 0x08000138 0x00000000 Code RO 3743 .ARM.Collect$$$$00000008 mc_w.l(entry7b.o)
0x08000138 0x08000138 0x00000000 Code RO 3745 .ARM.Collect$$$$0000000A mc_w.l(entry8b.o)
0x08000138 0x08000138 0x00000008 Code RO 3746 .ARM.Collect$$$$0000000B mc_w.l(entry9a.o)
0x08000140 0x08000140 0x00000000 Code RO 3748 .ARM.Collect$$$$0000000D mc_w.l(entry10a.o)
0x08000140 0x08000140 0x00000000 Code RO 3750 .ARM.Collect$$$$0000000F mc_w.l(entry11a.o)
0x08000140 0x08000140 0x00000004 Code RO 3739 .ARM.Collect$$$$00002712 mc_w.l(entry2.o)
0x08000144 0x08000144 0x00000024 Code RO 232 .text startup_stm32f10x_hd.o
0x08000168 0x08000168 0x00000062 Code RO 3426 .text mc_w.l(ldiv.o)
0x080001ca 0x080001ca 0x00000064 Code RO 3689 .text mf_w.l(fmul.o)
0x0800022e 0x0800022e 0x0000007c Code RO 3691 .text mf_w.l(fdiv.o)
0x080002aa 0x080002aa 0x0000014e Code RO 3693 .text mf_w.l(dadd.o)
0x080003f8 0x080003f8 0x000000e4 Code RO 3695 .text mf_w.l(dmul.o)
0x080004dc 0x080004dc 0x000000de Code RO 3697 .text mf_w.l(ddiv.o)
0x080005ba 0x080005ba 0x00000022 Code RO 3699 .text mf_w.l(dflti.o)
0x080005dc 0x080005dc 0x0000001a Code RO 3701 .text mf_w.l(dfltui.o)
0x080005f6 0x080005f6 0x00000028 Code RO 3703 .text mf_w.l(ffixui.o)
0x0800061e 0x0800061e 0x00000026 Code RO 3705 .text mf_w.l(f2d.o)
0x08000644 0x08000644 0x00000038 Code RO 3707 .text mf_w.l(d2f.o)
0x0800067c 0x0800067c 0x00000014 Code RO 3709 .text mf_w.l(cfrcmple.o)
0x08000690 0x08000690 0x00000062 Code RO 3755 .text mc_w.l(uldiv.o)
0x080006f2 0x080006f2 0x0000001e Code RO 3757 .text mc_w.l(llshl.o)
0x08000710 0x08000710 0x00000024 Code RO 3759 .text mc_w.l(llsshr.o)
0x08000734 0x08000734 0x00000000 Code RO 3768 .text mc_w.l(iusefp.o)
0x08000734 0x08000734 0x0000006e Code RO 3769 .text mf_w.l(fepilogue.o)
0x080007a2 0x080007a2 0x000000ba Code RO 3771 .text mf_w.l(depilogue.o)
0x0800085c 0x0800085c 0x0000002e Code RO 3773 .text mf_w.l(dscalb.o)
0x0800088a 0x0800088a 0x00000002 PAD
0x0800088c 0x0800088c 0x00000030 Code RO 3777 .text mf_w.l(cdrcmple.o)
0x080008bc 0x080008bc 0x00000024 Code RO 3779 .text mc_w.l(init.o)
0x080008e0 0x080008e0 0x00000020 Code RO 3781 .text mc_w.l(llushr.o)
0x08000900 0x08000900 0x000000a2 Code RO 3783 .text mf_w.l(dsqrt.o)
0x080009a2 0x080009a2 0x00000004 Code RO 144 i.BusFault_Handler stm32f10x_it.o
0x080009a6 0x080009a6 0x00000002 Code RO 145 i.DebugMon_Handler stm32f10x_it.o
0x080009a8 0x080009a8 0x00000116 Code RO 243 i.GPIO_Init stm32f10x_gpio.o
0x08000abe 0x08000abe 0x00000004 Code RO 251 i.GPIO_SetBits stm32f10x_gpio.o
0x08000ac2 0x08000ac2 0x00000004 Code RO 146 i.HardFault_Handler stm32f10x_it.o
0x08000ac6 0x08000ac6 0x00000002 PAD
0x08000ac8 0x08000ac8 0x00000038 Code RO 3164 i.IIC_Ack myiic.o
0x08000b00 0x08000b00 0x00000038 Code RO 3165 i.IIC_Init myiic.o
0x08000b38 0x08000b38 0x00000038 Code RO 3166 i.IIC_NAck myiic.o
0x08000b70 0x08000b70 0x00000058 Code RO 3167 i.IIC_Read_Byte myiic.o
0x08000bc8 0x08000bc8 0x00000060 Code RO 3168 i.IIC_Send_Byte myiic.o
0x08000c28 0x08000c28 0x00000038 Code RO 3169 i.IIC_Start myiic.o
0x08000c60 0x08000c60 0x00000034 Code RO 3170 i.IIC_Stop myiic.o
0x08000c94 0x08000c94 0x0000004c Code RO 3171 i.IIC_Wait_Ack myiic.o
0x08000ce0 0x08000ce0 0x00000050 Code RO 2906 i.LED_Init led.o
0x08000d30 0x08000d30 0x00000004 Code RO 147 i.MemManage_Handler stm32f10x_it.o
0x08000d34 0x08000d34 0x00000002 Code RO 148 i.NMI_Handler stm32f10x_it.o
0x08000d36 0x08000d36 0x00000002 PAD
0x08000d38 0x08000d38 0x00000070 Code RO 551 i.NVIC_Init misc.o
0x08000da8 0x08000da8 0x00000014 Code RO 552 i.NVIC_PriorityGroupConfig misc.o
0x08000dbc 0x08000dbc 0x00000002 Code RO 149 i.PendSV_Handler stm32f10x_it.o
0x08000dbe 0x08000dbe 0x00000002 PAD
0x08000dc0 0x08000dc0 0x00000020 Code RO 355 i.RCC_APB2PeriphClockCmd stm32f10x_rcc.o
0x08000de0 0x08000de0 0x000000d4 Code RO 363 i.RCC_GetClocksFreq stm32f10x_rcc.o
0x08000eb4 0x08000eb4 0x00000020 Code RO 3172 i.SDA_IN myiic.o
0x08000ed4 0x08000ed4 0x00000024 Code RO 3173 i.SDA_OUT myiic.o
0x08000ef8 0x08000ef8 0x00000002 Code RO 150 i.SVC_Handler stm32f10x_it.o
0x08000efa 0x08000efa 0x00000008 Code RO 2862 i.SetSysClock system_stm32f10x.o
0x08000f02 0x08000f02 0x00000002 PAD
0x08000f04 0x08000f04 0x000000e0 Code RO 2863 i.SetSysClockTo72 system_stm32f10x.o
0x08000fe4 0x08000fe4 0x00000028 Code RO 555 i.SysTick_CLKSourceConfig misc.o
0x0800100c 0x0800100c 0x00000002 Code RO 151 i.SysTick_Handler stm32f10x_it.o
0x0800100e 0x0800100e 0x00000002 PAD
0x08001010 0x08001010 0x0000003c Code RO 3320 i.SysTick_Init systick.o
0x0800104c 0x0800104c 0x00000060 Code RO 2865 i.SystemInit system_stm32f10x.o
0x080010ac 0x080010ac 0x0000003c Code RO 3349 i.USART1_IRQHandler usart.o
0x080010e8 0x080010e8 0x000000b0 Code RO 3350 i.USART1_Init usart.o
0x08001198 0x08001198 0x00000040 Code RO 3379 i.USART2_IRQHandler rs485.o
0x080011d8 0x080011d8 0x00000012 Code RO 1189 i.USART_ClearFlag stm32f10x_usart.o
0x080011ea 0x080011ea 0x00000018 Code RO 1193 i.USART_Cmd stm32f10x_usart.o
0x08001202 0x08001202 0x0000001a Code RO 1196 i.USART_GetFlagStatus stm32f10x_usart.o
0x0800121c 0x0800121c 0x00000054 Code RO 1197 i.USART_GetITStatus stm32f10x_usart.o
0x08001270 0x08001270 0x0000004a Code RO 1199 i.USART_ITConfig stm32f10x_usart.o
0x080012ba 0x080012ba 0x00000002 PAD
0x080012bc 0x080012bc 0x000000d8 Code RO 1200 i.USART_Init stm32f10x_usart.o
0x08001394 0x08001394 0x0000000a Code RO 1207 i.USART_ReceiveData stm32f10x_usart.o
0x0800139e 0x0800139e 0x00000008 Code RO 1210 i.USART_SendData stm32f10x_usart.o
0x080013a6 0x080013a6 0x00000004 Code RO 152 i.UsageFault_Handler stm32f10x_it.o
0x080013aa 0x080013aa 0x00000002 PAD
0x080013ac 0x080013ac 0x00000020 Code RO 3561 i.__0printf$5 mc_w.l(printf5.o)
0x080013cc 0x080013cc 0x00000028 Code RO 3725 i.__ARM_fpclassify m_ws.l(fpclassify.o)
0x080013f4 0x080013f4 0x000000aa Code RO 3727 i.__kernel_poly m_ws.l(poly.o)
0x0800149e 0x0800149e 0x00000002 PAD
0x080014a0 0x080014a0 0x00000010 Code RO 3711 i.__mathlib_dbl_divzero m_ws.l(dunder.o)
0x080014b0 0x080014b0 0x00000004 Code RO 3713 i.__mathlib_dbl_infnan2 m_ws.l(dunder.o)
0x080014b4 0x080014b4 0x0000000c Code RO 3714 i.__mathlib_dbl_invalid m_ws.l(dunder.o)
0x080014c0 0x080014c0 0x0000000e Code RO 3715 i.__mathlib_dbl_overflow m_ws.l(dunder.o)
0x080014ce 0x080014ce 0x00000002 PAD
0x080014d0 0x080014d0 0x00000010 Code RO 3717 i.__mathlib_dbl_underflow m_ws.l以上是关于stm32启动过程cortex-m3架构堆栈代码位置编译汇编链接分析的主要内容,如果未能解决你的问题,请参考以下文章
以stm32f407为例,学习cortex-m4通用寄存器的用法