0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何在KEIL下阅读汇编

STM32嵌入式开发 来源:STM32嵌入式开发 作者:STM32嵌入式开发 2022-04-18 11:13 次阅读

不同的平台的汇编代码是不一样的,最早的汇编在50年代就发明了,比很多人的父母的年龄都大,老掉牙,不用学习怎么写汇编。一个公司有一个人知道怎么写汇编就够了。但要学习读汇编

为什么学习汇编?

性能

直接翻译为机器语言,性能最高。优秀的C语言效率只能达到汇编的80%左右。其他高级语言跟汇编一比差得更远。语言越高级性能越差。很多bootloader和BIOS用汇编写,汇编操作的是电脑手机刚刚上电时,硬件和初始化的那些命令,它们的性能的要求比较高,效率高开机速度更快。

分析问题

个人认为,编程人与机器对话,我们写C,写JAVA,但是电脑并不认识这些语言,电脑只认识0和1;所以需要一个人来翻译这些语言,这个翻译官就是编译器,但是编译器不能百分之百准确的表达程序员的意思,也就是所谓的翻译有反义。例如,编译器为了性能好一点,可能会优化变量和语句,这个过程可能好心办坏事,把有用的操作优化了。因此只有看懂一些汇编语句,才能分析程序真正执行的流程。在问题难以定位的情况下,汇编可能是分析问题的最后一根稻草。

帮助理解硬件

有些学校的单片机课程是以汇编进行教学的,主要原因就是汇编更贴近硬件。不过我不赞成这种做法,C语言能快速做出一点东西,有利于学生在放弃之前,增加成就感,好坚持下去。但是汇编确实更贴近硬件。

LDR指令

为了便于理解下文,先介绍下LDR指令,其格式如下:

LDR{条件}   目的寄存器     <存储器地址>

作用:将 存储器地址 所指地址处连续的4个字节(1个字)的数据传送到目的寄存器中。LDR指令的寻址方式比较灵活,实例如下:

LDR R0,[R1]   ;将存储器地址为R1的字数据读入寄存器R0。LDR R0,[R1,R2]   ;将存储器地址为R1+R2的字数据读入寄存器R0。LDR R0,[R1,#8]    ;将存储器地址为R1+8的字数据读入寄存器R0。LDR R0,[R1],R2      ;将存储器地址为R1的字数据读入寄存器R0,并将R1+R2的值存入R1。LDR R0,[R1],#8      ;将存储器地址为R1的字数据读入寄存器R0,并将R1+8的值存入R1。LDR R0,[R1,R2]!    ;将存储器地址为R1+R2的字数据读入寄存器R0,并将R1+R2的值存入R1。LDR R0,[R1,LSL #3]     ;将存储器地址为R1*8的字数据读入寄存器R0。LDR R0,[R1,R2,LSL #2]   ;将存储器地址为R1+R2*4的字数据读入寄存器R0。LDR R0,[R1,R2,LSL #2]!;将存储器地址为R1+R2*4的字数据读入寄存器R0,并将R1+R2*4的值存入R1。LDR R0,[R1],R2,LSL #2     ;将存储器地址为R1的字数据读入寄存器R0,并将R1+R2*4的值存入R1。LDR R0,Label        ;Label为程序标号,Label必须是当前指令的-4~4KB范围内。

要注意的是:

LDR Rd,[Rn],#0x04   ;这里Rd不允许是R15。

另外LDRB 的指令格式与LDR相似,只不过它是将存储器地址中的8位(1个字节)读到目的寄存器中。LDRH的指令格式也与LDR相似,它是将内存中的16位(半字)读到目的寄存器中。

LDR R0,=0xff

这里的LDR不是arm指令,而是伪指令。这个时候与MOVE很相似,只不过MOV指令后的立即数是有限制的。这个立即数必须是0X00-OXFF范围内的数经过偶数次右移得到的数,所以MOV用起来比较麻烦,因为有些数不那么容易看出来是否合法。

如何在KEIL下阅读汇编

按d进入debug模式,在view下选择disassembly window 。

a6f3e324-beba-11ec-9e50-dac502259ad0.png

看光标,c文件下指向了main函数的第一行。

汇编窗口也指向了对应的语句。但是,在执行C语言的第一行之前,仍然有许多操作要做,比如变量放在哪?在哪里调用了main函数等,这些操作都被集成开发环境IDE给封装起来了。我们必须知道,在执行main函数之前,有许多事情要做,只不过,初学的时候不必理会。以下是C语言源码,功能是点亮LED

//main.c#include   
int main(void){    RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
    GPIOB->CRL &= ~(0xf<<(1*4));
    GPIOB->CRL |= 0x2<<(1*4);     
    GPIOB->ODR &= ~(1<<1);
return0;}
//main.h#defineRCC_APB2ENR(*(unsignedint*)0x40021018)#defineGPIOB_CRL(*(unsignedint*)0x40010c00)#define GPIOB_ODR (*(unsigned int *)0x40010c0c)

汇编窗口往上翻,确实很多语句,先看这几行代码的汇编:

a7094b2e-beba-11ec-9e50-dac502259ad0.jpg

先说最常用的两句汇编:

LDR r0,[r1]    r0 = *r1
STR  r0,[r1]    *r1 = r0
MOV r0,r1    r1->r0拷贝

a71c49d6-beba-11ec-9e50-dac502259ad0.jpg

从内存0x0800 017c的32位数据拷贝到r0:

r0 = * 0x0800 017c

我们看到的 1000 4002其实 就是0x4002 1000。这里边有个知识点叫做大小端模式,以下简单讲解,不能理解就记住。

a72b214a-beba-11ec-9e50-dac502259ad0.png

这个数据是在地址是这么存放的:

7C 7D 7E 7F

00 10 02 40

实际数据是0x4002 1000

* 0x0800 017c=0x4002 1000

然后r0的值+0x18也就是24 因为这个是第6号(第6号就是第7个的意思)元素

得到r0 = *0x4002 1018,r0的值由一个地址,变成了地址所存放的数据。

然后是或0x08操作,结果再复制给r0,*0x4002 1018 |=0x08

给r1分配地址,这个地址也是0x4002 1000, r1 = *0x4002 1000

把r0存放的值,(不是r0的地址,)存到r1+18的空间上

*(r1+0x18) = r0

*0x4002 1018 = (*0x4002 1018 |=0x08)

*0x4002 1018|=0x08

最终结果:地址4002 1018的数,执行了或0x08的操作。再分析下一句 :

a73a7528-beba-11ec-9e50-dac502259ad0.jpg

前两句给r0分配空间,r0 = *0x4001 0c00

然后用BIC清除数据位,把4-7位清零,结果再赋值给r0。

*0x40010c00&=~(0xf0)r1 = *0x4001 0c00 *0x40010c00&=~(0xf0)

剩下的不再详细分析,直接给答案 :

a74b8804-beba-11ec-9e50-dac502259ad0.jpg

***0x40010c00|=0x200x4001 0c0c &= ~(0x02)*

最终,可以看到C语句被翻译成了意料之中的汇编语句,自己的意图被机器准确的理解了。

原文标题:学习STM32时为什么要学习汇编?

文章出处:【微信公众号:STM32嵌入式开发】欢迎添加关注!文章转载请注明出处。

审核编辑:汤梓红
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • STM32
    +关注

    关注

    2239

    文章

    10670

    浏览量

    348711
  • 汇编
    +关注

    关注

    2

    文章

    214

    浏览量

    25733
  • keil
    +关注

    关注

    68

    文章

    1196

    浏览量

    165283
  • 代码
    +关注

    关注

    30

    文章

    4554

    浏览量

    66736

原文标题:学习STM32时为什么要学习汇编?

文章出处:【微信号:c-stm32,微信公众号:STM32嵌入式开发】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    如何用Keil生成bin、汇编、C与汇编混合文件?

    Keil生成bin、汇编、C与汇编混合文件
    发表于 04-08 06:17

    使用keil 汇编调用C无法实现

    汇编调用C,用keil debug一直在C程序里跑,而不是从汇编文件运行,但是用ADS里运行完全没问题;反过来用C 调用汇编,貌似也不行啊,但是ADS
    发表于 06-27 22:24

    何在keil中去查看stm32startup启动文件的汇编指令呢

    stm32startup启动文件的主要功能有哪些?如何在keil中去查看stm32startup启动文件的汇编指令呢?
    发表于 11-26 07:28

    何在Keil下去完成一个汇编程序的呢

    何在Keil下去完成一个汇编程序的呢?如何去新建基于MDK创建纯汇编语言的STM32工程呢?
    发表于 11-26 07:11

    何在Keil下完成一个汇编程序的编写呢

    stm32有哪三种BOOT模式?分别有何差异?如何在Keil下完成一个汇编程序的编写呢?
    发表于 11-29 07:12

    KeilSTM32的C与汇编语言混合编程

    KeilSTM32的C与汇编语言混合编程C语言调用汇编函数,以及汇编语言调用C语言的修改
    发表于 12-20 06:06

    如何使用Keil生成汇编文档

    如何使用Keil IDE环境中生成汇编文档使用Keil IDE环境中生成汇编文档
    发表于 10-19 07:31

    何在C程序中使用汇编

    怎样在C程序中使用汇编,如何在C程序中使用汇编:方法一:在每个汇编语句前加asm即可。如:void reset_data(void) { asm mov r0,#0dfh asm
    发表于 09-23 23:43 55次下载

    Keil的调试命令、在线汇编与断点设置

    Keil 的调试命令、在线汇编与断点设置上一讲中我们学习了如何建立工程、汇编、连接工程,并获得目标代码,但是做到这一步仅仅代表你的源
    发表于 01-18 09:38 1.1w次阅读
    <b class='flag-5'>Keil</b>的调试命令、在线<b class='flag-5'>汇编</b>与断点设置

    Keil软件“C语言”与“汇编”混编 —— 相关知识整理

    Keil软件“C语言”与“汇编”混编 —— 相关知识整理
    发表于 09-21 14:15 5次下载
    <b class='flag-5'>Keil</b>软件“C语言”与“<b class='flag-5'>汇编</b>”混编 —— 相关知识整理

    何在KEIL C中实现直接寻址和间接寻址

    本文档的主要内容详细介绍的是如何在KEIL C中实现直接寻址和间接寻址。
    发表于 07-02 17:42 0次下载
    如<b class='flag-5'>何在</b><b class='flag-5'>KEIL</b> C中实现直接寻址和间接寻址

    C51_keil汇编+proteus仿真(小白教程)

    C51_keil汇编+proteus仿真(小白教程)
    发表于 11-23 09:36 18次下载
    C51_<b class='flag-5'>keil</b><b class='flag-5'>汇编</b>+proteus仿真(小白教程)

    Keil4中嵌入汇编语句

    File 为灰色鄙人在keil4中开发51内核单片机时,因实际需求需要在C语言代码中利用#pragma ASM 和 #pragma ENDASM 嵌入部分汇编代码,格式如下:#pragma ASM MOV A, R7 ...#pragma ENDASM将上述有效的代码块
    发表于 11-23 16:20 10次下载
    <b class='flag-5'>Keil</b>4中嵌入<b class='flag-5'>汇编</b>语句

    何在KEIL C51 软件上创建一个工程

    何在KEIL C51 软件上创建一个工程
    发表于 11-23 17:06 1次下载
    如<b class='flag-5'>何在</b><b class='flag-5'>KEIL</b> C51 软件上创建一个工程

    KEIL中启动文件详解(汇编语言)

    KEIL中启动文件详解(汇编语言)
    发表于 12-04 12:06 8次下载
    <b class='flag-5'>KEIL</b>中启动文件详解(<b class='flag-5'>汇编</b>语言)