-
Linux中汇编语言的学习(加法、乘法、除法、左移、右移、按位与等多种命令操作实例以及ARM的 N、Z、C、V 标志位的解释)
汇编概述
- 汇编需要学习的大致框架如下:
@ 汇编中的符号
@ 1.指令;能够北嘁肷梢惶?2bit机器码,并且能够被cpui识别和执行
@ 2.伪指令:本身不是指令,编译器可以将其替换成若干条指令
@ 3.伪操作:不会生成指令,只在编译阶段告诉编译器怎么编译
@ ARM指令集
@ 1.数据处理指令:进行数学运算、逻辑运算
@ 2.跳转指令:实现程序的眺转,本质就是修改PC寄存器
@ 3.Load/Score指令:访问(读写)内存
@ 4.状态寄存器传送指令:用于访问(读写)CPSR寄存器
@ 5.软中断指令:触发软中断
@ 6.协处理器指令:协处理器可以处理的指令
.text @表示当前为代码段
.global _start @将_start定义成全局符号
_start: @汇编入口
MOV R1,#1 @汇编指令
stop: @死循环,防止程序跑飞
B stop
.end @汇编的结束
汇编数据处理指令
- MOV指令的实例操作
@ 1.指令:能够编译生成一条32位的机器码,且能被cpu识别和执行
@ 1.1 数据处理指令:数学运算、逻辑运算
@ 数据搬移指令
@ MOV R1,#1
@ R1 = 1
@ MOV R2,R1
@ R2 = R1
@MVN R0,#0xFF
@ R0 = ~0xFF
@MOV R0,#0
@MOV R1,#0
@MOV R1,#1
@MVN R0,#0
@ 立即数:编译通过的是立即数,否则不是
@ 立即数的本质就是包含在指令当中的数,属于指令的一部分,变量则是单独占一个空间
@ 立即数的优点
@ 取值的时候就是可以将其读取到CPU,不用单独去内存读取,速度快
@ 立即数的缺点
@ 不能是任意的32的数字,有局限性
@ MOV R0,#0x12345678
@ 因为12345678太大了,所以编译报错,指令本身还有其他数而12345678本身就占了32位
@MOV R0, #0x12
@ MOV R0, #0xFFFFFFFF
@ 上述相当于伪指令,执行时替换成等价的CPU能认识的指令 - 数据运算指令格式操作实例(ADD、SUB等指令)
@ 数据运算指令的格式
@ 《操作吗》《目标寄存器》《第一操作寄存器》《第二操作数》
@ 操作码:表示执行哪种操作
@ 目标寄存器:用于存储运算的结果
@ 第一操作寄存器:存储第一个参与运算的数据(只能写寄存器)
@ 第二操作数:第二个参与运算的数据(可以是寄存器也可以是立即数)
@ 加法指令
@MOV R2,#5
@MOV R3,#3
@ADD R1,R2,R3
@ R1 = R2 + R3
@ADD R1,R2,#5
@ ADD R1,#5 R1这个形式的不行
@ ADD 不能计算两个值,例如:ADD R1,#2,#5,也不能是以下格式:ADD R1 #2,R2
@ 减法指令
@SUB R1,R2,R3
@ R1 = R2 - R3
@SUB R1,R2,#3
@ R1 = R2 - 3
@ 逆向减法指令,针对例如这种格式:R1 = #2 - R2
@RSB R1,R2,#3
@ R1 = 3 - R2
@ 乘法指令
@MUL R1,R2,R3
@ R1 = R2 * R3
@ 乘法必须是两个寄存器相乘
@ 按位与指令
@AND R1,R2,R3
@ R1 = R2 & R3
@ 按位与指令
@ORR R1,R2,R3
@ R1 = R2 | R3
@ 按位异或指令,相同为0,相异则1
@EOR R1,R2,R3
@ R1 = R2 ^ R3
@ 左移指令
@LSL R1,R2,R3
@ R1 = (R2 << R3)
@ 右移指令
@LSR R1,R2,R3
@ R1 = (R2 >> R3)
@ 位清零指令
MOV R2,#0xFF
BIC R1,R2,#0x0F
@ 第二操作数中的哪一位为1,则将第一操作寄存器中的哪一位清0,然后将结果放入目标寄存器
@ 数据运算指令的格式扩展
@MOV R1,R2,LSL #1
@ R1 = (R2 << 1)
@ 数据运算指令对条件位(N、Z、C、V)的影响
@ 默认情况下数据运算不会对条件位产生影响,当在指令后加后缀“s『罂梢杂跋毂
@ MOV R1,#3
@ SUBS R2,R1,#5
@ 两个64位的数据做加法运算
@ 第一个数的低32位放在R1
@ 第一个数的高32位放在R2
@ 第二个数的低32位放在R3
@ 第二个数的高32位放在R4
@ 第一个数
@ 0x00000001 FFFFFFFF
@ 第二个数
@ 0x00000002 00000005
@ MOV R1,#0xFFFFFFFF
@ MOV R2,#0x00000001
@ MOV R3,#0x00000005
@ MOV R4,#0x00000002
@ ADC带进位的加法,如果有进位的话C置为1,且ADC实际上为R2 + R4 + C(1)
@ ADDS R5,R1,R3
@ ADC R6,R2,R4
@ 第一个数
@ 0x00000002 00000001
@ 第二个数
@ 0x00000001 00000005
MOV R1,#0x00000001
MOV R2,#0x00000002
MOV R3,#0x00000005
MOV R4,#0x00000001
@ SBC本质上是:R2 - R4 -‘!C’,为什么减去取反的C,由于CPSR寄存器减法时,28位上置1
SUBS R5,R1,R3
SBC R6,R2,R4 - 跳转指令
@ 1.2 跳转指令:实现程序的眺转,本质就是修改了PC寄存器
@ 方式一:直接去修改PC寄存器的值(不建议使用,需要我们自己去计算绝对地址)
@ MAIN:
@ MOV R1,#1
@ MOV R2,#2
@ MOV R3,#3
@ MOV PC,#0x18
@ MOV R4,#4
@ MOV R5,#5
@ FUNC:
@ MOV R6,#6
@ MOV R7,#7
@ MOV R8,#8
@ 方式二:不带返回的跳转指令,本质就是将PC寄存器的值修改成跳转标号下第一条指令的地址,同时将跳转指令下一 条指令的地址存储到LR
MAIN:
MOV R1,#1
MOV R2,#2
MOV R3,#3
BL FUNC
MOV R4,#4
MOV R5,#5
FUNC:
@ 必须将LR地址给PC,然后程序就能返回了
MOV R6,#6
MOV R7,#7
MOV R8,#8
MOV PC,LR - ARM指令的条件码
@ 比较指令
@ CMP的本质是一条减法指令(SUBS),只是没有将运算的结果存入寄存器
MAIN:
MOV R1,#1
MOV R2,#2
CMP R1,R2
@ BEQ本质就是判断R1和R2是否相等,相等的话就跳转,否则就不跳转
@ BEQ FUNC
BNE FUNC @ if(NQ)(B FUNC)本质:if(z==0)(B FUNC)
MOV R3,#3
MOV R4,#4
MOV R5,#5
FUNC:
MOV R6,#6
MOV R7,#7
@ ARM指令集大多数都可以带条件码后缀如下:
@MOV R1,#1
@MOV R2,#2
@CMP R1,R2
@MOVGT R3,#3
条件码如下:
- 条件码的案例代码
@ 练习
@ int R1 = 9;
@ int R2 = 15;
@START:
@ if(R1 == R2)
@ STOP();
@ else(R1>R2)
@ {
@ R1 = R1-R2;
@ goto START;
@ }
@ else
@ {
@ R2 = R2 - R1;
@ goto START;
@ }
@ 汇编编写
MOV R1,#9
MOV R2,#15
START:
CMP R1,R2
BEQ STOP
SUBGT R1,R1,R2
SUBGT R2,R2,R1
B START
STOP:
B STOP - 内存读写案例代码:
@Load/Srore指令:访问(读写)内存
@ 写内存
@ MOV R1,#0xFF000000
@ MOV R2,#0x40000000
@ STR R1,[R2]
@将R1寄存器中的数据存储到R2指向的内存空间
@ 读内存
@ LDR R3,[R2]
@ 将内存中R2指向的内存空间的数据读取到R3寄存器
@ MOV R1,#0xFFFFFFFF
@ MOV R2,#0x40000000
@ STRB R1,[R2] @ B代表一个字节,往内存存取低一个字节的数据
@ STRH R1,[R2] @ H代表两个字节
@ STR R1,[R2] @ 默认为四个字节
@ LDR指令同样支持以上后缀 - ARM指令的寻址方式
@ 寻址方式就是CPU去寻找一个操作数的方式
@ 立即寻址
@ MOV R1,#1
@ ADD R1,R2,#1
@ 寄存器寻址
@ ADD R1,R2,R3
@ 寄存器移位寻址,寄存器先做移位然后再用寄存器
@ MOV R1,R2,LSL #1
@ 寄存器间接寻址,R2作为一个地址间接的去访问内存里面的内容
@ STR R1,[R2]
@。。。。
@ 基址加变址寻址
@MOV R1,#0xFFFFFFFF
@MOV R2,#0x40000000
@MOV R3,#4
@ STR R1,[R2,R3]
@ 将R1寄存器中的数据写入到R2+R3指向的内存空间
@ 将R1寄存器中的数据写入到R2+(R1<<1)指向的内存空间
@ STR R1,[R2,R3,LSL #1]
@ 基址加变址寻址的索引方式
@ 前索引
@ MOV R1,#0xFFFFFFFF
@ MOV R2,#0x40000000
@ STR R1,[R2,#8]
@ 将R1寄存器中的数据写入到R2+8指向的内存空间
@ 后索引
@ MOV R1,#0xFFFFFFFF
@ MOV R2,#0x40000000
@ STR R1,[R2],#8
@ 将R1寄存器中的数据写入到R2指向的内存空间,然后R2自增8
@ 自动索引
MOV R1,#0xFFFFFFFF
MOV R2,#0x40000000
STR R1,[R2,#8]!
@ 将R1寄存器中的数据写入到R2+8指向的内存空间,然后R2自增8
-
相关阅读:
openvswitch学习
spring 单元测试注解
x64dbg 2022 最新版编译方法
第三届经济、智慧金融与当代贸易国际学术会议(ESFCT2024)
Oracle数据库修改序列,Oracle中的主键值和序列中的值对应不上时的处理方式
Flink 状态管理
使用OKhttp3 与青云客AI聊天机器人交互 -Java
深度学习推荐系统(八)AFM模型及其在Criteo数据集上的应用
SPSS多元方差分析
洛谷P1607 Fair Shuttle G
-
原文地址:https://blog.csdn.net/weixin_58036810/article/details/136456209