看linux内核启动流程需要的arm汇编指令学习笔记(二)

一、ldr

1.地址偏移模式

/* 读取0x80000地址的值到x0寄存器*/
ldr x0, [x1]

/* 读取0x80008地址的值*/
ldr x2, [x1, #8]

/* 读取x1+x3 地址的值*/
ldr x4, [x1, x3]

/* 读取(x1+ x3<<3) 地址的值*/
ldr x5, [x1, x3, lsl #3]

2.变基模式

/* 前变基模式:先更新偏移地址再访问内存 */
/* 先更新x1的值为X1+8,然后以新的X1值为地址,加载内存的值到x0 */
ldr x6, [x1, #8]!

/* 后变基模式:先访问内存地址再更新偏移地址  */
/* 以X1的值为地址,加载该内存地址的值到X0,然后再更新X1寄存器为X1+8*/
ldr x7, [x1], #8

3.标签

3.1 访问宏定义

#define my_label 0x30
ldr x0, =my_label  /*把宏的值加载到x0寄存器*/
ldr x1, my_label   /* PC值 + 宏的值,然后加载这个地址的值到x1寄存器*/

3.2 访问一个字符串

.globl string1
string1:
	.string "Boot at EL"
	
ldr x0, string1  /*加载string1的ASCII码的值到x0,加载8个字节的数据*/
ldr x1, =string1 /*加载string1的地址到x1寄存器。若读取地址的值,可以得到string1的ascii*/

3.3 访问一个data

.align 3
.globl my_data
my_data:
	.word 0x44
	
ldr x0, my_data  /*加载mydata的值到x0*/
ldr x1, =my_data  /*加载mydata的地址到x1*/

二、ldp和stp

1.双字节加载

//以X0的值为地址,加载此地址的值到x3寄存器,以x0+8为地址,加载此地址的值到X7寄存器
ldp x3,x7,[x0] 

2.双字节存储

//存储X1的值到地址为X4的内存中,然后存储x2的值到地址为X4+8的内存中。
STP X1,X2,[X4]

3.双字节存储的后变基模式

将寄存器 x1 的值存储到由 x0 指向的内存地址开始的位置。紧接着将寄存器 x2 的值存储到紧接着 x1 存储位置之后的内存地址。存储完成后,更新 x0 寄存器的值,使其增加 16 个字节。

stp x1, x2, [x0], #16

三、位操作

1. 移位

指令名字含义
lsl逻辑左移将寄存器中的每一位向左移动指定的位数,左边空出的位用 0 填充。
lsr逻辑右移将寄存器中的每一位向右移动指定的位数,右边空出的位用 0 填充。
asr算术右移将寄存器中的每一位向右移动,但会保留被移出的最高位(符号位),并用它来填充空出的位
ror循环右移将寄存器中的每一位向右移动,右边移出的数据用来回填最左边的空位

在这里插入图片描述

逻辑右移和算术右移的区别?

2. 按位操作

  1. AND: 执行逻辑与操作。
    and <destination>, <source1>, <source2>
    
  2. EOR (Exclusive OR): 执行逻辑异或操作。
    eor <destination>, <source1>, <source2>
    
  3. ORR (Bitwise OR): 执行逻辑或操作。
    orr <destination>, <source1>, <source2>
    
  4. BIC (Bit Clear): 执行逻辑非操作后与另一个操作数进行与操作,用于清除特定位。
    bic <destination>, <source1>, <source2>
    

3. 位段插入

   BFI Xd,Xn,#lsb,#width

BFI:位段插入指令。用Xn中的bit[0:width-1]替换Xd中从lsb开始的width位,Xd其他位不变。
例子:使用bfi指令把0x345中的低4位插入到x0寄存器的第八位开始的4位中

mov x1, 0x345
mov x0, 0
bfi x0, x1, 8, 4

4.位段提取

  UBFX Xd,Xn,#lsb,#width
  SBFX Xd,Xn,#lsb,#width

UBFX:无符号数的位段提取指令
SBFX:有符号数的位段提取指令
从Xn寄存器提取位段,位段从第lsb位开始,位宽为width,然后结果写入到Xd寄存器的最低比特位中。UBFX指令不做符号位的扩展,其他比特位是填充0;SBFX会对有符号位进行扩展,即当提取的位段中,最高位为1时,那么其他比特位会填充为1。
例子:

/*提取x2,从第4个bit开始,提取8bit。x3其他位都是0,最终:0xbc*/
ldr x2, =0x5678abcd
ubfx x3, x2, #4, #8

/*提取x2,从第4个bit开始,提取8bit。x4的其他比特位都是f, 最终:0xffffffffffffffbc*/
sbfx x4, x2, #4, #8

5.零计数指令

clz Xd,Xn

CLZ指令会扫描Xn寄存器中的位,从最高位开始计数,直到遇到第一个非零位。计数的结果(即零的数量)会被存储在Xd寄存器中。如果在最高位就遇到非零位,CLZ 指令会返回 0,因为没有任何零位。

例子:

ldr x1, =0x0fffffffffffffff
clz x2, x1

x2的结果为4

四、跳转指令

1. cmp比较两个数

/*相当于x1-x2*/
cmp x1,x2

2. cmn负向比较

/*相当于x1+x2*/
cmn x1,x2

然后查看NZCV位判断结果:

条件后缀含义标志条件码
EQ相等Z=10b0000
NE不相等Z=00b0001
CS/HS发生了无符号数溢出C=10b0010
CC/LO没有发生无符号数溢出C=00b0011
MI负数N=10b0100
PL正数或零N=00b0101
VS溢出V=10b0110
VC未溢出V=00b0111
HI无符号数大于(C=1)&&(Z=0)0b1000
LS无符号数小于或等于(C=0)||(Z=1)0b1001
GE带符号数大手或等于N=V0b1010
LT带符号数小于N!=V0b1011
GT带符号数大于(Z=0)&&(N=V)0b1100
LE带符号数小于或等千(Z=1)||(N!=V)0b1101
AL无条件执行-0b1110
NV无条件执行-0b1111

例子:

1:
	cmn x1, x2
	add x2, x2, 1
	/*查看NZCV操作后缀*/
	mrs x0, nzcv
	/*mi: 负数*/
	b.mi 1b

   /*测试CMP指令*/
   mov x2, 3
2:
	cmp x2, x1
	add x1, x1, 1
	/*查看NZCV操作后缀*/
	mrs x0, nzcv
	/*cs: 无符号数大于等于*/
	b.cs 2b

五、 条件选择指令

1. csel:条件选择指令

csel Xd,Xn,Xm,cond

如果cond为真,Xd=Xn,否则Xd=Xm。

2. cset:条件置位指令

cset Xd,cond

如果cond为真,Xd=1,否则Xd=0。

3. csinc:条件选择并增加指令

csinc Xd,Xn,Xm,cond

如果cond为真,Xd=Xn,否则Xd=(Xm+1)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小坚学Linux

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值