日常疑问-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 的写法
在这里插入图片描述

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

  • 16
    点赞
  • 63
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值