嵌入式arm(二)涉及的汇编指令及相关知识

arm开发中需要掌握一些汇编语言的知识,如:指令的格式,作用和用法;但不是要求用汇编去编程,而是通过学习汇编来掌握:机器指令的格式,指令在内存中是如何存储的,指令的执行过程,寄存器的变化。

文章目录

一 汇编语言是什么

汇编语言由汇编指令组成,汇编指令是机器指令的便于记忆的文本书写格式,即机器指令的助记符,由编译器把汇编指令翻译为机器指令,由于不同架构的机器指令集并不相同,对应的汇编语言也各有区别,因此汇编语言可移植性差,只有相同架构的机器之间才能做汇编代码的移植;
一般提到指令集就是在说汇编指令集,由于不同CPU架构的指令集不同,所用到的编译器也不一样,为了能够在一个架构的系统上编译出不同架构的可执行文件,需要用特殊的编译器:交叉编译工具链;

二 汇编语言的基本语法

首先,我们不看啥啥啥寻址方式,放到最后再来看,正经人谁一上来就扯半天云里雾里的概念啊。

1 汇编语言的注释

用@注释符;

2 立即数

类似于C语言中的常量;在数字前加上#号,如#0x01,#88;

3 先了解程序状态寄存器

在这里插入图片描述
如图,在程序状态寄存器中,高5位为条件码标志,低8位为控制位;4-27位为保留位,程序不应该访问到保留位;
见名知意,在程序运行时,CPSR寄存器即随着变化。

3.1 条件码标志位

3.1.1 N位
当两个补码表示的带符号数进行运算,结果是负数则N=1;否则N=0;
3.1.2 Z位
当运算结果为0,Z=1;否则Z=0;
3.1.3 C位
加法运算(包括比较指令 CNM):C=1:运算结果产生了进位时(无符号数溢出)。C=0:运算结果没有进位
减法运算(包括比较指令 CMP):C=0:运算时产生了借位(无符号数溢出)。C=1:没有借位
对于包含移位操作的非加 / 减法运算指令,C 为移出值的最后一位
对于其他的非加 / 减法 运算指令,C 的值通常不变
3.1.4 V位
对于加 / 减法运算指令,当操作数和运算结果为二进制的补码表示的有符号数时,V=1 表示符号位溢出
对于其他的非加 / 减法 运算指令,V 的值通常不改变
3.1.5 Q位
在 ARM v5 及以上版本的 E 系列处理器中,用 Q 标志位指示增强的 DSP 运算指令是否发生了溢出。在其它版本的处理器中,Q 标志位无定义

3.2 控制位

低8位是控制位,当发生异常时,这些位将被改变,只有特权模式下程序可以修改这些位;
3.2.1 中断禁止位I、F
置1时,分别禁止IRQ中断和FIQ中断;
置0时,使能中断;
3.2.2 T标志位
反映处理器的运行状态;
T=1时,程序运行于THUMB状态;
T=0时,运行于ARM状态。
3.2.3 运行模式位M[4:0]:
这几位是模式位,这些位决定了处理器的运行模式。具体含义请查图片;

4 基本指令

4.1 指令基本格式

下图是keil4汇编代码调试的截图,汇编指令在汇编阶段翻译成机器指令,根据这条机器指令的内存地址能判断出其在内存的哪个段哪个位置;
在这里插入图片描述

4.1.1 汇编指令格式

放一条基本指令:mov r0,#1
再放一条:moveq r0,#1
再放一条:moveqS r0,#1
指令的格式为:
< opcode > {< cond >} {s} < rd >, {rn}, {< operand2 >} 其中:<>是必须要有的;{}可选的,
(1) Opcode:汇编指令,比如:mov
(2) Cond:条件码 ,如:moveq,详见4.1.2节;
(3) S:是否影响cpsr寄存器的nzcv位,如果写出S则影响,不写不影响;指令中使用"S"后缀时,指令执行后程序状态寄存器的条件标志位将被刷新;不使用"S"后缀时,指令执行后程序状态寄存器的条件标志将不会发生变化,指3.1中的条件标志位;
(4) Rd:目标寄存器
(5) Rn:第一操作数寄存器 mov没有
(6) Operand2:第二操作数,可以是寄存器,也可以是立即数
在有些连续地址访问的指令中,还有!后缀:
如果指令地址表达式中不含"!“后缀,则基址寄存器的地址值不会发生变化。指令中的地址表达式中含有”!"后缀时,指令执行后,基址寄存器中的地址值将发生变化,变化的结果如下:基址寄存器中的值(指令执行后) = 指令执行前的值 + 地址偏移量;更多请看4.7.2节。

4.1.2 条件码

在这里插入图片描述
还有1111,助记符后缀为NV,标志是任何,含义是不执行;

4.1.3 mov指令的机器指令格式:

汇编指令只是助记符,文本书写格式的机器指令,一句汇编指令最终还是会翻译为一条机器指令,机器指令可以简单理解为就是一个32位的数据;每个指令都有自己的指令格式,我们以mov指令为例来了解一下:
Mov指令的机器指令格式:
31-28 27 26 25 24-21 20 19-16 15-12 11-0
31-28:条件码
27、26:预留的为00
25:I 表示第二操作数是寄存器还是立即数 1 立即数 0 寄存器
24-21:具体的指令 mov 1101
20:1 影响cpsr的nzcv位 0不影响cpsr的nzcv位
19-16:第一操作数寄存器的编号
15-12:目标寄存器的编号
11-0:如果第二操作数是寄存器,0-3就是第二操作数寄存器的编号;
关键是0-11位
如果第二操作数是立即数,则:用0-7位的低字节表示一个32位数的低8位,用8-11位来表示位移量的一半,最后表示的数是将 低8位生成的的32位的数 循环右移 8-11位的数的两倍 的数量,右移后的数即是mov操作的立即数;
于是:
位移数只能是偶数,且最大为30;
基本数是0-255(但是生成32位的);
这11位能表示的最大数是0xff000000;
循环右移:就是按位右移,最右边移出的位往最左边补入;

可知,用mov指令最大能传输的立即数是0xff000000;超出这个范围则报错;而且,在这个范围内,如果不能通过0-255的值循环右移偶数位得到,也报错,怎么解决?请看4.2.2节;

4.2 数据传输指令mov
mov r0,#1  @r0=1,把立即数1放入寄存器r0中;
mov r0,r1  @r0=r1,把寄存器r1上的数据拿出来放到r0中;
mov r0,r0  @相当于空指令;
4.2.2 怎么解决mov中立即数的范围问题;

用ldr伪指令;可以将任意32位数传输给目标寄存器;详细见4.7节

ldr  r0,=0xffffffff  @立即数前是=,表示是ldr伪指令;

偷懒法:
如果立即数在0-255范围内,用mov,只要超出255,就用ldr伪指令

4.2.3 mov的扩展用法

mvn指令—数据取反指令,用于生成位掩码或者求反码和补码;

mvn r4,0x0  	   @将第二操作数取反之后赋值给目标寄存器
mov r6, r1, lsl#1  @将r1的值左移1位赋值给r6,lsl表示左移,后跟移位位数;
Mov r6, r1, lsr#1  @将r1的值右移1位赋值给r6,lsr表示右移,后跟移位位数;
4.3 算术指令

4.3.1 add指令

add r0,r1,r2  @r0 = r1+r2
add r0,r0,r1  @r0 = r0+r1-->add r0,r1
add r0,r1,r2,lsl #1   @r0 = r1 + (r2 << 1)
add r0,#1     @r0+=1
add r0,r1,#1     @r0=r1+1

类似的有:sub 减法;mul乘法;
4.3.2 adc指令
带进位的加法,指加的时候加上上一次运算的进位,与add指令联合使用。

@以下代码实现了两个128位的数相加,
@第一个数用r4,r5,r6,r7;
@第二个数用r8,r9,r10,r11;
@结果用r0,r1,r2,r3;
addS r0,r4,r8
adcS r1,r5,r9		@会加上进位
adcS r2,r6,r10		@会加上进位
adcS r3,r7,r11		@会加上进位

4.3.3 用于减法sub的是sbc指令
即带借位的减法

@两个64位数减法
@(r1,r0)-(r3,r2)=(r1,r0);
subS r0,r0,r2
sbcS r1,r1,r3	@高位相减时还要减去低位的借位;

4.3.4 rsb和带借位的rsc指令
rsb是逆向的减法,即用后面的寄存器来减前面的寄存器;

rsb r2,r0,#0xff		@r2=0xff-r0;
rsbS r2,r0,#0
rsc r3,r1,#0	@相减时带上借位;

4.3.5 单数据交换指令swp
用于交换

swp r1,r1,[r0]		@将r1和r0存地址上的数据进行交换
swp r1,r2,[r0]		@将r0地址上的数保存到r1中,再将r2中的数保存到r0存地址的空间上;
4.4 逻辑指令
and r0,r1,r2   @r0 = r1 & r2
orr r0,r1,r2   @r0 = r1 | r2
eor r0,r0,#0xf	@将r0的低4位取反
bic r0,#0x2   @将r0的第1位清0,后跟的立即数即是按位清0的控制数;即哪个位写1就清0哪个位;
4.5 比较指令
cmp r0,r1   @比较r0和r1的大小--》影响cpsr的nzcv位--》条件码
tst r0,#0x2   @测试r0的第1位是否为0
cmn r0,#0     @r0减去#0的相反数的结果
teq r0,r1		@两个异或的结果
注意:比较指令会自动更新cpsr的值,不需要加S

相当于:
cmp对应减法
cmn对应加法
tst对应与运算
teq对应异或运算
这四个指令都是用相应运算之后的结果来改变标志位;

4.6 跳转指令
4.6.1 什么是语句标号

标号(LABEL)是为一组机器指令所起名字,表示程序中的指令或者数据地址的符号。标号可有可无,只有当需要用符号地址来访问该语句时,才给此语句赋予标号。通过在目标地址的前面放上一个标号,可以在指令中使用标号来代替直接使用地址。标号是程序目标标志,总是和某地址相联系,供转移或循环指令控制转移使用。标号是编译程序使用的,也就是说程序中最后生成的代码中标号都换成了相应的数值。如果想不通,想想C语言中的goto语句;

4.6.2 b与bl

b 语句标号 @无条件跳转指令

b aa  @跳转到aa这个语句标号处
bl aa  @跳转到aa这个语句标号处,并且将bl aa这条指令的下一条指令的地址保存在lr寄存器中,bl指令实现了跳转,执行完函数代码后,把lr中的地址值mov给pc,就又跳回了之前的位置继续执行下一条指令,从而实现函数调用;
4.7 内存操作指令
4.7.1 单个内存空间ldr与str

ldr:将一个地址所指内存空间的内容拷贝到一个寄存器中;
str:将一个寄存器中的内容拷贝到一个地址指定的内存空间中;
简单来讲,ldr是拿回来,str是送出去;
(1) ldr指令:ldr r1,[r0]这条指令,r0上的数据被认为是地址,[ ]表示:不是取寄存器上的值,而是访问这个寄存器上存的地址所指的内存空间,那么这条指令就表示去拿r0存的地址上的值,放到r1中;相当于通过指针间接访问,然后直接赋值给目标寄存器;
(2) str指令:str r1,[r2]这条指令,是把r1上的数据取出来,放到r2存的地址所指的内存空间上面;
(3) 另外还有ldrb和strb,表示在操作数据时仅访问一个字节;ldrh和strh,表示访问2字节,halfword;

ldr r1,[r0]   @r1 = *r0
str r1,[r2]    @*r2 = r1
@以下两句都表示先访问内存的数据,然后对内存地址进行+1的操作,即会改变r0和r1上的地址;
ldrb r2,[r0],#1   @r2 = *r0,r0 = r0+1
strb r2,[r1],#1   @
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值