IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 日常疑问-IAP、设置栈顶地址函数 -> 正文阅读

[嵌入式]日常疑问-IAP、设置栈顶地址函数

问题环境

IDE:Keil MDK
编程语言:C语言、汇编语言
硬件:STM32单片机

问题1描述

之前在写BootLoader的时候,参考了网上的设置栈顶地址函数,不是很理解这个函数,所以先记录下来,后面有时间在看看。

//设置栈顶地址
//addr:栈顶地址
__asm void MSR_MSP(uint32_t addr) 
{
    MSR MSP, r0 			//set Main Stack value
    BX r14
}

问题1分解回答

1、__asm 是什么?

答:__asm 是表示汇编的关键字,告诉编译器接下来的代码是汇编代码。

2、addr为什么在函数内部没有用,但实际的地址确成功设置了?

答:实际上 addr 的值会默认存储到 r0 中;
特意写一个函数测试,这个函数就是查看各个变量的存储位置
函数如下:

void test_input(uint8_t a,//第1个变量
                uint8_t b,//第2个变量
                uint8_t c,//第3个变量
                uint8_t d,//第4个变量
                uint8_t e,//第5个变量
                uint8_t f,//第6个变量
                uint8_t g,//第7个变量
                uint8_t h,//第8个变量
                uint8_t i,//第9个变量
                uint8_t j,//第10个变量
                uint8_t k,//第11个变量
                uint8_t l,//第12个变量
                uint8_t m,//第13个变量
                uint8_t n)//第14个变量
{
    uint8_t sum = 1;
    
    sum =a;
    sum =b;    
    sum =c;    
    sum =d;
    sum =e;
    sum =f;
    sum =g;
    sum =h;
    sum =i;
    sum =j;
    sum =k;  
    sum =l;
    sum =m;
    sum +=n;        
    
}

调用如下:

test_input(1,2,3,4,5,6,7,1,1,1,1,1,1,1);

编译后得到汇编指令如下:

   174: { 
0x080017B0 B5F0      PUSH     {r4-r7,lr}
0x080017B2 9D05      LDR      r5,[sp,#0x14]
0x080017B4 9C0D      LDR      r4,[sp,#0x34]
   175:     uint8_t sum = 1; 
   176:      
0x080017B6 2601      MOVS     r6,#0x01
   177:     sum =a; 
0x080017B8 4606      MOV      r6,r0
   178:     sum =b;     
0x080017BA 460E      MOV      r6,r1
   179:     sum =c;     
0x080017BC 4616      MOV      r6,r2
   180:     sum =d; 
0x080017BE 461E      MOV      r6,r3
   181:     sum =e; 
0x080017C0 462E      MOV      r6,r5
   182:     sum =f; 
0x080017C2 9E06      LDR      r6,[sp,#0x18]
   183:     sum =g; 
0x080017C4 9E07      LDR      r6,[sp,#0x1C]
   184:     sum =h; 
0x080017C6 9E08      LDR      r6,[sp,#0x20]
   185:     sum =i; 
0x080017C8 9E09      LDR      r6,[sp,#0x24]
   186:     sum =j; 
0x080017CA 9E0A      LDR      r6,[sp,#0x28]
   187:     sum =k;   
0x080017CC 9E0B      LDR      r6,[sp,#0x2C]
   188:     sum =l; 
0x080017CE 9E0C      LDR      r6,[sp,#0x30]
   189:     sum =m; 
0x080017D0 4626      MOV      r6,r4
   190:     sum +=n;         
   191:      
0x080017D2 9F0E      LDR      r7,[sp,#0x38]
0x080017D4 19F7      ADDS     r7,r6,r7
0x080017D6 B2FE      UXTB     r6,r7
   192: } 

在汇编中的175行中,可以看出 sum 的值是被保存在 r6 中

   175:     uint8_t sum = 1; 
   176:      
0x080017B6 2601      MOVS     r6,#0x01

在sum =a; 这条C语言的执行就是通过汇编中的MOV指令将r0 的值传给r6,由此可以判断出 addr 的值是存储在 r0 中

MOV命令是将数据移动到另一个地方,使用格式如下:
MOV 目标地址 源地址
目标地址:除CS、IP以外的寄存器或存储器;
源地址:寄存器、存储器、立即数;

   177:     sum =a; 
0x080017B8 4606      MOV      r6,r0

进一步拓展可以看到上面写的test_input 函数的第2个变量 b 是保存在 r1 中

   178:     sum =b;     
0x080017BA 460E      MOV      r6,r1

3、变量addr 和 r0 是什么关系?

答:变量 addr 的值保存在 r0 中。

4、MSR MSP, r0 这条汇编语句是什么作用?

答:MSR 的作用是将通用寄存器的值传给状态寄存器,也就是将 r0 的值传给 MSP,而MSP是主堆栈指针,也就是说,将 r0 存的值传给主堆栈指针,实现设置栈顶地址。

5、BX r14 这条汇编语句是什么作用?

答:R14称为子程序链接寄存器,将子程序或是函数调用执行完成后 ,通过BX r14返回到函数调用处

问题2描述

在分析问题1的过程中,发现还有另一种写法。

/**
  \brief   Set Main Stack Pointer
  \details Assigns the given value to the Main Stack Pointer (MSP).
  \param [in]    topOfMainStack  Main Stack Pointer value to set
 */
__STATIC_FORCEINLINE void __set_MSP(uint32_t topOfMainStack)
{
  __ASM volatile ("MSR msp, %0" : : "r" (topOfMainStack) : );
}

问题2分解回答

1、这种汇编语法是什么?

答:这种是属于AT&T 汇编语法,汇编在系统上分为Unix(主要是AT&T)和Windows(主要是Intel)两种派系格式,而问题2是Uinx系统的AT&T汇编的格式,而问题1是windows的Intel汇编格式。
具体可以参考这个大哥写这篇文章:
Intel汇编和AT&T汇编的简要区别,生成方法和判断技巧
或者看这篇
intel 汇编和at&t 汇编的区别

2、“MSR msp, %0” : : “r” (topOfMainStack) : 表示什么意思?

答:这个要从AT&T 汇编格式说起,不过这里可以简单说一下这个是一条汇编语句,这条语句是把变量 topOfMainStack 传进 MSP 实现设置栈顶地址。
具体详细说明可以看:AT&T_GCC_ASM.pdf 这个文档(百度一下有很多地方可以看的到)
百度文档:AT&T_GCC_ASM.pdf

问题拓展

问题1和问题2的函数都是同一个作用,但是不同的写法,就需要选择不同的编译器,
问题1对应的是keil-mdk 的编译器5 的写法
在这里插入图片描述
问题2对应的是keil-mdk 的编译器6 的写法
在这里插入图片描述

免责声明:本文内容含网络参考、作者编写等,内容版权归原作者所有,未经允许,禁止转载。如涉及作品版权问题,请与我们联系,我们将根据您提供的版权证明材料确认版权并支付稿酬或者删除内容。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-04-29 12:18:17  更:2022-04-29 12:19:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 2:39:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码