不同的平台的汇编代码是不一样的,最早的汇编在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 。
看光标,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)
汇编窗口往上翻,确实很多语句,先看这几行代码的汇编:
先说最常用的两句汇编:
LDR r0,[r1] r0 = *r1
STR r0,[r1] *r1 = r0
MOV r0,r1 r1->r0拷贝
从内存0x0800 017c的32位数据拷贝到r0:
r0 = * 0x0800 017c
我们看到的 1000 4002其实 就是0x4002 1000。这里边有个知识点叫做大小端模式,以下简单讲解,不能理解就记住。
这个数据是在地址是这么存放的:
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的操作。再分析下一句 :
前两句给r0分配空间,r0 = *0x4001 0c00
然后用BIC清除数据位,把4-7位清零,结果再赋值给r0。
*0x40010c00&=~(0xf0)
r1 = *0x4001 0c00
*0x40010c00&=~(0xf0)
剩下的不再详细分析,直接给答案 :
***0x40010c00|=0x20
0x4001 0c0c &= ~(0x02)*
最终,可以看到C语句被翻译成了意料之中的汇编语句,自己的意图被机器准确的理解了。
-
STM32
+关注
关注
2118文章
8697浏览量
341277 -
汇编
+关注
关注
2文章
203浏览量
25448 -
keil
+关注
关注
65文章
1105浏览量
163365 -
代码
+关注
关注
26文章
3187浏览量
64762
发布评论请先 登录
相关推荐
汇编学习入门之第一个汇编程序

如何在C语言程序集成汇编
如何用Keil uVision5实现C语言与汇编语言的混合编程
在stm32H743非中断模式下使用主堆栈指针下的汇编语句
如何在keil下创建工程并调试STM32汇编源程序
如何利用Keil完成汇编语言编写
汇编

keil软件是干嘛的?keil软件怎么用?

Keil下使用STlink重定向printf的配置

在Keil下完成一个汇编程序的编写
如何利用keil去新建一种汇编工程呢
Keil软件有哪些性能
如何使用汇编语言在Keil_v5和Proteus进行LED闪烁操作
介绍keil的使用
stm32在keil和IAR中的汇编启动代码不相同

Cortex-M系列:非中断、特权模式下的汇编语言

如何在keil ARM Compiler6.10.1 C++下stm32里使用printf?
在keil中创建C51的汇编工程
如何在keil中去查看stm32startup启动文件的汇编指令呢
keil教程之创建基础软件工程

Keil4中嵌入汇编语句

【汇编】AT89C52点亮一盏LED灯(汇编语言)

如何在Proteus 8x中进行汇编SRC设置
在Keil下完成一个汇编程序的编写
如何在keil中生成hex文件
C语言反汇编相关资料推荐
如何用Keil生成bin、汇编、C与汇编混合文件?

请问如何在COSMIC C文件中使用汇编语言?
如何使用KEIL C51和proteus实现C51汇编程序的设计实例

如何在Keil C环境下编译CY7C68013的大型固件代码?
keil工程中的一个h文件变成了汇编
如何阅读汇编代码?
如何在Keil ARM MDK中实现延迟功能
keil如何使用?图文教程告诉你keil怎么使用

手机PDF阅读器如何在PDF文件中查找某个词
Keil MDK5.12版本 C编程里面嵌入汇编指令的方法(STM32)
在keil中如何在一个工程下使用多个C文件?
求教汇编高手,汇编变量定义
keil中使用汇编编写stc12c5620ad系列单片机头文件
使用keil 汇编调用C无法实现
如何在keil 4中添加STC单片机型号
KEIL4设置 C代码嵌入汇编后无法设置断点,求拯救
【跟我学单片机C语言】无限制中英文版keil c51下载
如何在arm模式下读取cpsr寄存器的进位位值?
Linux中的汇编语言
Keil经典视频教程
如何在C程序中使用汇编
基于Keil的入门实例教程
Keil的调试命令、在线汇编与断点设置

keil c51 v8.12下载

评论