(五)ARM汇编 简单了解

汇编语言在最底层,只有电路的电信号,可以用电压表示电路状态,所以用0和1来代替高低电平。也就有了二进制。处理器处理二进制序列,有时候也成为机器码。
假设
有几个很长的二进制有不同的含义,前人总结了很多套形式,在使用,就需要助记符和缩写来记二进制组合,助记符一般是3个字符,也有一些多个字母的
我们就可以使用助记符来编写程序,也就是汇编语言的程序。汇编语言是程序的最底层语言

ARM汇编用在了什么地方?

我们身边有很多东西都是ARM架构,手机、路由器、遥控器、物联网IOT设备等等,都是ARM架构。

ARM汇编的指令集

  • 数据处理指令
  • 转义指令
  • 程序状态寄存器访问指令
  • 加载、存储指令
  • 异常产生指令
  • 伪指令
1. 数据处理(传送)指令

a=2 b=3 | a+b | a>b | true and false

分号后面可以写注释

1.1 数据传送指令

1----MOV

MOV R1,R0:把寄存器R0的值 或 立即数传递给R1寄存器

示例:

MOV R1,R0

MOV PC,R14     寄存器R14的值传给PC

MOV R1,R0,LSL#3   将寄存器R0的的值左移3位后(相当于十进制乘以8),传递给R1

2----MVN:数据取反传送指令

MVN R1,R0:把寄存器R0的立即数 按位取反 传递给R1寄存器

1.2 算数运算指令

1----ADD 加法

示例:(指令小写也可以)

ADD R0,R1,R2;   R0=R1+R2

ADD R0,R1,#256;  R0=R1+256

ADD R0,R1,R2,LSL#1  ;   R0=R1+(R2<<1)

2----ADC 带进位的加法指令
会将两个操作数相加,再加上CPSR中的C条件标位置的值,将加过放到 目的寄存器中

CPSR是什么?
叫做当前程序状态寄存器(ARM中一般有16个寄存器,0-15,第17个就是CPSR)
CPSR寄存器示意图如下:
(五)ARM汇编 简单了解_第1张图片

  • V:溢出标志
  • C:进位标志
  • Z:零标志
  • N:复数标志
  • T:状态位
  • M:模式位

3----ADDS:相加并影响标志位

4----SUB减法
SUB {条件} 目的寄存器R0,操作数1,操作数2
sub指令使用操作数1 减去 操作数2.并将结果放入操作数R0中

操作数1 一般都是寄存器
操作数2 可以是寄存器,也可以是立即数,也可以是被位移的寄存器

示例:

sub R0,R1,R2 ;  R0=R1-R2

sub  R0,R1,#256;  R0=R1-256

sub R0,R1,R2,LSL#1  ;   R0=R1-(R2<<1)

5----SBC 带借位的减法指令

1.3 比较指令

1----直接比较指令CMP
cmp指令用于把一个寄存器的内容和另一个寄存器的内容 或 立即数 进行比较,同时更新CPSR 中条件标示位。
这个执行,会做一次减法运算,不存储结果,只更改条件标志位。
标志位标示的是操作数1与操作数2的关系(大于、小于、等于)
CMP {条件} 操作数1,操作数2

示例:

cmp R0,R1   ;将寄存器R0 的值与R1的值进行相减,并根据结果设置CPSR的标志位

cmp R0,#50   ;将寄存器R0的值 与 立即数50 相减,并根据结果设置CPSR的标志位

2----CMN负数比较指令
cmn 操作数1,操作数2
cmn指令用于把一个寄存器的内容和另一个寄存器的内容 或立即数进行比较,同时更新 CPSR中条件标志位

示例:

cmn R1,R0   ;将R1寄存器和R0寄存器的值相加,并根据结果设置CPSR的标志位

cmn R1,#80   ;将寄存器R1的值 与 立即数 80 相加,并根据结果设置 CPSR 的标志位
1.4 逻辑运算指令

1----AND逻辑与
AND {条件}{S} 目的寄存器,操作数1,操作数2
AND指令用于操作数1与操作数2 进行逻辑运算,结果存入目的寄存器
操作数1 一般都是寄存器,操作数2 可以是寄存器,也可以是被位移的寄存器,也可以是立即数

AND R0,R1,R2  ;R1 && R2的值 给R0寄存器

2----ORR 逻辑或
3----EOR 逻辑异或
4----BIC 位清零

1.5 乘法

(1)MUL 乘法

mul {cond}{S} R0,R1,R2 ;R0=R1xR2

muls R0,R3,R7 ;R0=R3xR7 同时设置CPSR中的N位和Z位

(2)MLA 乘-累加
mla {cond}{S} 目的寄存器,操作数1,操作数2,操作数3 ;目的寄存器=操作数1 x 操作数2 + 操作数3
mla R0,R1,R2,#10 ;R0=R1 x R2 + 10

(3)UMULL 无符号,乘法(64位无符号乘)
umull R1,R0,R5,R8 ;将R5 R8做无符号相乘,结果 低32位R0中,高32位放到R1中

(4)UMLAL 无符号乘法-累加
(5)SMULL 有符号,乘法
(6)SMLAL 有符号乘法-累加

2. 汇编的转移(跳转)指令

用来实现程序流程的跳转,在RAM中,有两种跳转方式

  • 使用专门的跳转指令
  • 向程序计数器PC写入跳转地址的值

跳转指令向前或向后可以跳32MB的地址空间,写入跳转地址的值可以实现4GB跳转

ARM指令中,常用的指令有4条:

  • B:跳转指令
  • BL:带返回的跳转指令
  • BLX:带返回和状态切换的跳转指令
  • BX:带状态切换的跳转指令
2.1无条件跳转

1----B指令
语法:B label(标记label)

示例:

B  Label   ;无条件跳转到Label处执行
CMP R1,30

2----BX指令
语法:BX label

如果目标地址不是立即数

示例:

BX  Label   ;无条件跳转到Label处执行
CMP R1,30
2.2 有条件跳转

1----BL指令
语法:BL label

BL 跳转,在跳转之前,会在寄存器中 保留PC的当前内容。所以,我们可以将之前的内容重新加载到PC内,来返回到跳转指令 之后的 那个指令处执行

示例:

B  Label   ;无条件跳转到Label处执行
CMP R1,30

2----BLX指令
语法:BLX label

BLX 指令跳转到目标地址,并将处理器的工作状态用ARM状态切换到Thumb状态,并将当前内容保存到寄存器中。

当子程序使用Thumb指令(16位的),(Thumb指令是ARM指令集的子集)。本身使用ARM指令。子集的返回值可以通过

3-----其他指令
如:BEQ label 上面的cmp满足 等于,就跳到label处执行

  • BEQ:跳转到 等于的地方
  • BGT:跳转到大于的地方
  • BLT:跳转到小于的地方
  • BLE:跳转到小于等于的地方
  • BGE:跳转到大于等于的地方
3. 程序状态寄存器访问指令
3.1 MRS

语法:MRS {cond} 通用寄存器,程序状态寄存器(CPSR或SPSR)
MRS将程序状态寄存器的内容 传到 通用寄存器中,一般2种情况:
(1)需要改变当前程序状态寄存器的内容时,用MRS指令,将程序状态寄存器传递给通用寄存器,修改后再写回程序状态寄存器
(2)异常处理或者切换时,保存程序状态寄存器的值

例如:

MRS r0,CPSR    ;传送 CPSR的内容到r0

MRS r0,SPSR    ;传送 SPSR的内容到r0
3.2 MSR

语法:MSR {cond} 程序状态寄存器(CPSR或SPSR)的域,操作数

MSR指令将操作数的内容传递到 程序状态寄存器中 的 特定域中

域:用于设置程序状态寄存器,需要使用的操作位。32位状态寄存器分为4个域

位[7:0] 控制位 域,用c表示
位[15:8] 扩展位 域,用x表示
位[23:16] 状态位 域,用s表示
位[31:24] 条件标志位 域,用f表示

示例:

MSR  CPSR_c,r0   ;将r0的内容传送给CPSR,仅修改CPSR中的控制位域

MSR  CPSR,r0   ;将r0的内容传送给CPSR
4. 加载存储指令

ARM 处理器支持加载、存储指令,用于在寄存器和存储器之间传递数据
存储器在CPU外
寄存器(又称缓存),一般整合在CPU内
加载指令:将存储器中的数据传递到寄存器
存储指令:将寄存器中的数据 存储到存储器

4.1 LDR加载指令

语法:LDR{cond} 目的寄存器,<存储器地址>

示例:

LDR r0,[r1]    ;将寄存器地址为r1的字数据 传递到 寄存器r0

LDR r0,[r1,#8]    ;将寄存器地址为r1+8的字数据 传递到 寄存器r0

LDR r0,[r1,r2]    ;将寄存器地址为r1+r2的字数据 传递到 寄存器r0

LDR r0,[r1],r2    ;先将寄存器地址为r1的值 给r0寄存器,后将r1+r2的值给r1

LDR r0,[r1,r2]!    ;将寄存器地址为r1+r2的字数据 传递到 寄存器r0,再将r1+r2的值给r1

LDR r0,[r1] r2,LSL#2    ;先将寄存器地址为 r1的值给r0,后将 r1+r2 x 4 的值给r1

LDR r0,[r1, r2,LSL#2 ]!   ;将寄存器地址为 r1+r2 x 4 的值给r0,再将新地址 r1+r2 x 4写入r1
4.2 LDRB

语法:LDRB{cond} 目的寄存器 <存储器地址>

LDRB 用于从存储器中将一个8位的字节数据传送到寄存器内,同时将高位24 位清零

示例:

LDRB r0,[r1]    ;将寄存器地址为r1的字数据 传递到 寄存器r0,r0的高24位清零

4.3 LDRH

语法:LDRH{cond} 目的寄存器 <存储器地址>

LDRB 用于从存储器中将一个16位的字节数据传送到寄存器内,同时将高位16 位清零

示例:

LDRH r0,[r1]    ;将寄存器地址为r1的字数据 传递到 寄存器r0,r0的高16位清零

4.4 STR存储指令

语法:STR{cond} 源寄存器 <存储器地址>

STR 用于从源存储器中将一个32位的字节数据传送到寄存器内

示例:

STR r0,[r1]    ;将r0寄存器的内容 存储到 地址为r1的存储器中

STR r0,[r1],#8    ;将r0寄存器的内容 存储到 地址为r1的存储器中,将新地址r1+8给r1

STR r0,[r1,#8]    ;将r0寄存器的内容 存储到 地址为r1+8的存储器中

4.5 STRB存储指令

语法:STRB{cond} 源寄存器 <存储器地址>

STRB 用于将寄存器中一个低16位的字节数据 传送到存储器内
示例:

STRB r0,[r1]    ;将r0寄存器的低16位的内容 存储到地址为r1的存储器中

STRB r0,[r1],#8    ;将r0寄存器低16位的内容 存储到 地址为r1的存储中
4.5 批量数据加载、存储指令

ARM支持在一片连续的存储单元和多个存储器之间进行数据传递
LDM批量加载指令
STM批量存储指令
语法:LDM {cond} 基址寄存器{!},寄存器列表{A}
{! }后缀,数据传送完毕后,将最后的地址写入基址寄存器,否则 基址寄存器内容不变

  • IA 每次传送 后 地址加1
  • IB 每次传送 前 地址加1
  • DA 每次传送 后 地址减1
  • DB 每次传送 前 地址减1
  • FD 满递减堆栈
  • ED 空递减堆栈
  • FA 满递增堆栈
  • EA 空递增堆栈

示例:

LDMFD  R13!,{R0,R4-R12,PC}     ;将 堆栈内容 读取到 寄存器(R0,R4-R12,LR)
5. 异常产生指令

异常指令 产生软件中断,使用用户程序能够调用系统进程

5.1 SWI

语法:SWI {cond} 24位的立即数
如:

swi  0x02    ;指令调用传统 操作 变量为02 的系统进程
5.2 BKPT

语法:BKPT {cond} 16位的立即数

BKPT 指令用于产生断点中断,用于调试

6. 汇编伪代码

(1)AREA
一个汇编程序至少包含一个段。当程序太长的时候,可以分为多个代码段和数据段
区分代码段的开头,我们使用AREA

语法格式:AREA 段名 属性1,属性2,…

CODE属性:用于定义代码段,默认是readonly
DATA属性:用来定义数据段,默认readwrite
readonly:只读
readwrite:可读可写
ALIGN:使用方式为align表达式,在ELF的代码段或数据段是按字对齐。0-31
COMMON:定义通用段,不包含代码和数据

示例:

AREA  Init,CODE,READONLY   ;这个伪指令定义一个名为Init,属性为只读的代码(code)段

(2)ALIGN
语法:ALIGN {表达式,{,偏移量}}

align 通过添加填充字节的方式,使当前位置满足对齐方式。2的n次方

示例:

AREA init,code,readonly,align=4   ;指定 后面的指令为16 字节对齐
...
指令序列
...
END

(3)CODE16, CODE32
CODE16 通知 编译器,后面的指令序列 都是16位Thumb 指令
CODE32 通知 编译器,后面的指令序列 都是32位ARM 指令
可以在同个代码段使用

示例:

AREA init,code,readonly
ENTRY  ;进入
code32    ;从这开始 为32位 ARM指令
LDR  R0,[R1]  ;存储[R1]的值,加载到寄存器R0
BX   R0   ;跳转到R0存的那个 地址,进行执行,且切换到Thumb 工作状态

code 16  ;从这里开始 是16位 Thumb指令
LDR R1,=0x2A
END   ;程序结束

(4)ENTRY
语法:entry

用来指定 汇编程序的 入口 。在一个完整的 汇编程序中 ,至少一个 entry ,可以有多个。但是在源文件中 ,只能有一个entry(或可以没有)

示例:

area  init , code, readonly
entry 
...
end

(5)END

(6)EQU
equ伪指令,定义的符号名必须是唯一的

用于将一个数值或寄存器名 赋值给一个指定的符号名

​ 程序结尾

代码实例

(1)有两个32位值a,b,存放在存储器地址为 0x80010,0x80014中,现在要实现 c=a+b,c存放在0x80018中。

;此段伪代码用来实现 c=a+b(寄存器的个数非常有限,不能浪费)

AREA  MYADD, CODE, READONLY   ;声明 名称 和属性
ENTRY                         ;入口
CODE32                        ;从此处开始 是 32 位的ARM
LDR  R0, =0x80010             ;变量a的地址 存入R0
LDR R1, [R0],#4               ;将存储器R0地址的值 给 寄存器 R1, 且R0更新为R0+4
LDR R2, [R0],#4               ;将存储器R0地址的值 给 寄存器 R2, 且R0更新为R0+4
ADD R1,R1,R2                  ;R1=R1+R2
STR R1,[R0]                   ;存储R1的值到R0,即存到0x80018的位置
END                           ;程序结束

(2)有一个32位的符号数x,存放在存储器地址为0x90010
实现:如x>0,y=0;x<0,y=5;将y保存到0x90010中。

		AREA  PANDUAN, CODE, READONLY   
		ENTRY      
		CODE32
START   LDR  R1, =0x90010
		LDR R2, [R1]
		CMP R2,#0
		BGT PLUS                      ;大于0则跳转到PLUS LABEL
		BLT MINUS
		END
PLUS	MOV R0,#10     ;将立即数10给R0
		STR R0,[R1]
		END
MINUS   MOV R0,#5    
		STR R0,[R1]
		END

(3)有一个32位带符号数x,存放在存储器地址为0x90010
实现:如x>0,y=1;x=0,y=0;x<0,y=-1;将y保存到0x90014中。

		AREA  PANDUAN, CODE, READONLY   
		ENTRY      
		CODE32
START	LDR  R1, =0x90010
		LDR R2, [R1],#4
		CMP R2,#0
		BGT PLUS 
		BEQ EQUAL
		MOV R0,#-1                   
		B FINISH
 PLUS   MOV R0,#1
 		B FINISH
 EQUAL  MOV R0,#0
 		B FINISH
FINISH 	STR R0,[R1]
 		END

(4)实现1+2+3+…+10

		AREA  MYLOOP, CODE, READONLY   
		ENTRY      
		CODE32
START	LDR R0,=0x90010
		MOV R1,#10                  ;最终加到10
		MOV R2,#1                   ;加数起始值为1
		MOV R3,#0                   ;起始和为0
LOOP	ADD R3,R3,R2                ;R3=R3+R2
		ADD R2,R2,#1                ;R2=R2+1
		CMP R2,R1                   ;判断是否加到最后一个数
		BGT FINISH                  ;大于就跳转到结束
		B LOOP                      ;如果不大于,就跳转回去重复执行
FINISH	STR R3,[R0]                 
		END

(5)实现1+2x3+3x4+…+10x11,存储结果到0x90010

		AREA  MYLOOP, CODE, READONLY   
		ENTRY      
		CODE32
START	LDR R0,=0x90010
		MOV R1,#10                  ;最终加到10
		MOV R2,#2                   ;加数起始值为2
		MOV R3,#0                   ;起始和为1
LOOP	ADD R4,R2,#1                ;R4=R2+1
		MLA R3,R2,R4,R3           ;R3=R2xR4+R3
		ADD R2,R2,#1 
		CMP R2,R1                   ;判断是否加到最后一个数
		BGT FINISH                  ;大于就跳转到结束
		B LOOP                      ;如果不大于,就跳转回去重复执行
FINISH  STR R3,[R0]               
		END

(6)求两个数组DATA1和DATA2对应数据的和,并将这个和放到新数组中。

		AREA DEFINEDATA,DATA,READWRITE   ;定义数据段,类型为data,可读可写
DATA1	DCD 1,2,-2,-1,4,5,6              ;数组data1
DATA2	DCD 1,2,3,-1,-2,-5,-6            ;数组data2
SUM	DCD 0,0,0,0,0,0,0                    ;数组sum
		
		AREA MYARRAY,CODE,READONLY       ;代码段
		ENTRY
		CODE32
START	LDR R1,=DATA1                    ;将数组data1的首地址加载到 R1
		LDR R2,=DATA2                    ;将数组data2的首地址加载到 R2
		LDR R3,=SUM                      ;将数组sum的首地址加载到 R3
		MOV R0,#0                        ;计数器R0 初始值为0
		  
LOOP	LDR R4,[R1],#04                  ;将R1地址的值,传给R4,然后修改R1的地址指针
		LDR R5,[R2],#04                  ;将R2地址的值,传给R5,然后修改R2的地址指针
		ADDS R4,R4,R5                    ;相加并影响标志位
		STR R4,[R3],#04                  ;将相加的值R4存到sum的首个地址中,然后修改R3的地址指针
		ADD R0,#1                        ;R0计数
		CMP R0,#6                        ;计数器R0和6比较
		BGT FINISH                       ;大于则跳转到FINISH
		B LOOP                           ;否则重复执行
FINISH	END

(7)数组a,b分别存放在 0x40000,0x50000为起始地址的区域内,完成

for(int i=1;i<7;i++){
	b[i]=a[i];
	if(b[i]==0){
		b[i]=-1;
	}
}
		AREA DEFINEDATA,DATA,READWRITE  
A1		EQU 0x40000
B1		EQU 0x50000
		
		AREA MYARRAY,CODE,READONLY        ;代码段
		ENTRY
		CODE32
START	LDR R1,=A1                        ;将数组A的首地址加载到 R1           
		LDR R2,=B1                        ;将数组B的首地址加载到 R2        
		MOV R0,#1                         ;定义i=1
		
LOOP	LDR R3,[R1],#4
		CMP R3,#0
		BEQ ZERO
		STR R3,[R2],#4
HALF	ADD R0,R0,#1
		CMP R0,#7
		BLT LOOP
		B FINISH
ZERO	MOV R3,#-1
		STR R3,[R2],#4
		B HALF	
FINISH	END
		
AREA 	MYARRAY,CODE,READONLY        ;代码段
A1		EQU 0x40000
B1		EQU 0x50000
NUM	EQU 7
		ENTRY
		CODE32
START	LDR R1,=A1
		LDR R2,=B1
		MOV R0,#1
LOOP	LDR R3,[R1],#4
CMP		R3,#0
		MVNEQ R3,#0   ;如果上面的判断为0,将-1给R3
		STR R3,[R2],#4
		ADD R0,R0,#1
		CMP R0,#NUM
		BLT LOOP
		END

(8)查询从存储器0x400000开始的100个数中,值为0的个数。将结果存到0x400200地址中。

		AREA ENN,CODE,READONLY
		ENTRY
		CODE32
START	LDR R1,=0x400000
		LDR R2,=0x400200
		MOV R0,#0      ;计数器1
		MOV R4,#1     ;计数器2
LOOP	LDR R3,[R1],#4
		CMP R3,#0
		BQE ZERO
HALF	ADD R4,R4,#1
		CMP R4,#100
		BGT FINISH
		B LOOP
ZERO	ADD R0,R0,#1
		B HALF
FINISH	STR R0,[R2]
		END
		
		

你可能感兴趣的:(Android逆向分析)