(32位)arm 汇编学习(2)
2016-10-28 15:30
225 查看
条件码
在指令中,有4位用来表示条件,也就是有16种条件。如果当前条件满足,则继续执行,否则这条指令将被忽略。结果标志主要是被数据操作指令设置和清除,这些指令只有在你强调其应该操作标志位的时候才会影响标志位,比如MOV不会影响标志位,但是MOVS(mov with set)就会设置标志位。
接下来我们就要看一些指令条件,是通过在指令后面加上2个字母的后缀来表明的。
AL(ALways)
这个指令即表示总是,也就是指令将总是会被执行,如果没有表明条件,这个条件将会是默认的。NV(NeVer)
所有的ARM条件指令都有相对应的相反的条件指令,AL就对应NV,NV就表示永不执行,可以用来占位或者消耗掉很小的一段时间。EQ(EQual)
这个条件在Z标志位为1的时候被认为是true(关于标志位可参见第一篇)。Z标志位主要是由比较指令和一些可能会使得目标为0的指令来产生。NE(Not Equal)
和EQ正好相反。VS(oVerflow Set)
这个条件在V(溢出标志)为1的时候被认为是true,加法减法和比较指令会影响这个标志位。VC (oVerflow Clear)
和VS相反MI (MInus)
这个条件在N(负数标志)为1的时候被认为是true。N标志在最后一个数据操作使得数据为负的时候被设置。PL(PLus)
和MI正好相反CS (Carry Set)
从本指令开始的4个指令常被用来比较2个无符号数。
CS指令的意思是当C(进位标志)是1的时候认为为true。C标志被算术操作,比如加法、减法、比较、移位等影响。用作比较的时候,可以被翻译为大于等于,所以也可以用HS(Higher or Same)来代替这个标志。
CC(Carry Clear)
为CS的相反情况,在比较的时候,也可以用来表示小于,所以也可以写作LO(LOwer than)HI(HIgher)
这个标志位在C标志为1且Z标志为0的时候被认为是true,在比较或者减法之后,这个组合可以被解释为左边的操作数大于右边的数(无符号数)。 (根据前几条命令,我们可以知道C表示大于等于,Z表示等于,大于等于且不等于,则为大于。)LS(Lower or Same)
和上一条条件相反,C为0Z为1时为true,即左边的数小于等于右边的数。GE(Greater than or Equal
从本指令开始的4条指令常被用来比较有符号数
本指令在N为0,V为0或者N为1V为1时为true。(大于等于)LT(Less Than)
为上一条指令的相反,N为1V为0或者N为0V为1。小于GT(Greater Than)
和GE类似,不过Z必须为0。 表示大于LE(Less than or Equal)
和LT类似,不过在Z为1的时候始终为true。 表示小于等于第一类-数据操作
这一类包含16个指令,指令语法较为相似,我们以ADD为例,然后其他指令说一下不同的部分。汇编典型格式
以add为例:ADD{cond}{S} <dest>, <lhs>, <rhs>
花括号里的是可选的。
cond:条件码,如果忽略则为AL
S:如果有S,则这条指令影响标志位。
dest:目的地,即存储结果的寄存器号,比如R0,R1等等。
lhs:永远是一个寄存器号,左边的操作数
rhs:右操作数比较复杂,再解释完移位操作再详细解释,其语法为
#<value>立即数,或者<reg>{,<shift type><reg>}或者<reg>{,<shift type> #<shift count>}
立即数
立即数用井号开始,后跟一个数字,比如#1表示立即数1。用&开头可以表示16进制,比如#&1000表示#65536
其内部立即数表示方式为12位。
那么如何表示超过12位的数呢? 于是arm对于立即数,将其12位分为了两个部分,高4位为pos,即位置,低8位为value,即值。值是8位的数字,表示256种组合,而位置用4位,来表示值在32位数字中位于哪个位置。pos从0到f,每一个表示值在32位中向右循环移位2位。
但是,作为用户,我们并不关心他是如何表示的,不过需要注意的是,如果这个数字不能被转换为这样的12进制表示,将会出现一个错误
移位操作
LSL #n(Logical Shift Left immediate)
逻辑左移n位,右边添0,左边超出的进入C标志位。ASL #n(Arithmetic Shift Left immediate)
算术左移n位,和LSL一样LSR #n(Logical Shift Right immediate)
逻辑右移n位,最右位进入C标志位,左边添0。ASR #n(Arithmetic Shift Right immediate)
算术右移n位,最右边进入C标志位,左边添最左一位。ROR #n(ROtate Right immediate)
循环右移n位,最右进入C标志位且左边添加最右一位。RXX(Rotate right one bit with extend)
循环右移1位,C标志位进入最左边,最右边进入C标志位。LSL rn(Logical Shift Left by a register)
逻辑左移寄存器指定的位数,以下几条指令与此类似,为之前指令的寄存器指定数字版本.不过需要注意的是只有寄存器最低一个字节会被计算。ASL rn
LSR rn
ASR rn
ROR rn
再谈<rhs>
现在有了移位操作,再让我们来看看rhs的几种语法:#<value>
立即数,就没有什么好说的了<reg>{,<shift type>#<shift count>}
这里的几个元素分别是寄存器,以及其移位方式,比如ASL LSR等等的移位方式,和移位的位数的0到32以内的立即数。也就是说,这个操作数是通过寄存器的值经过移位之后决定的
<reg>{,<shift type> <reg>}
这里除了<reg>其他和上一条一样,而这个元素即寄存器,也就是在移位当中解释的用于指明移动多少位的寄存器。
一个例子
ADD R0, R0, R0, LSL #1
这个即为R0 = R0 + R0逻辑左移一位,因为逻辑左移一位即×2,所以这个指令即为
R0 = R0 + R0 * 2 = R0 * 3
标志位影响
数据操作指令是会影响标志位的,主要遵循以下几个规律:一般情况,没有S的指令不影响标志位
N标志位:结果为负,即31位为1时为1,否则为0
Z标志位:结果为0时为1,否则为0
C标志位:如果RHS包含移位操作,则可能在这里被影响,否则不被影响
V标志位:不被影响
指令介绍
接下来介绍这一组的指令AND 逻辑与
比较简单,就是逻辑与BIC 清除特定位
即与非操作TST 检验位
进行与操作,不过不存储,只影响标志位,加不加S,都影响标志位ORR 逻辑或
EOR 逻辑异或
TEQ 检验相等性
进行逻辑异或,但是不存储结果,只影响标志位,且加不加S都影响标志位。MOV 移动值
类似于赋值操作,将rhs放入lhsMVN 移动逆反值
类似于赋值操作,不过要先进行逻辑非操作,即每一位取反再移动。ADD 加法
ADC 带进位加法
除了加lhs和rhs还要加上C标志位SBC 带借位减法
dest = lhs - rhs - NOT carryNOT即逻辑非,carry为C标志位
RSB 反转减法
倒过来减,dest = rhs - lhsRSC 带借位反转减法
同上不过多减一个C标志位取反CMP 比较
做减法,但是结果不存储,影响标志位CMN 比较负值
倒过来减,然后影响标志位,不存储结果另:在这一组操作中使用R15
如果lhs为R15 则0与1位无法被看到如果rhs为R15 则所有位都可以被看到
第一组A
有一些指令和第一组很像,但是不属于第一组,就是乘法指令,被归类为第一组A。这个组有两条指令
MUL {cond}{S}<dest>,<lhs>,<rhs> MLA {cond}{s}<dest>,<lhs>,<rhs>,<add>
注意:
这里没有移位操作。
所有的参数都为寄存器。
MUL将lhs乘上rhs然后将结果放入dest。
MLA类似,不过加上了寄存器add。
rhs和lhs不能为同一寄存器
R15不能作为dest
第二类-读取和存储
这一组只有两条基本的指令,LDR从一个地址读取值到寄存器,STR存储寄存器值。LDR和STR只在数据传输方向上不一样,所以我们以STR为核心介绍,LDR相应遵循规则即可。STR 存储一个字(word)或者一个字节
取值模式
在指明地址的时候,有两种取值模式可以用,分别为前索引和后索引。前索引:
STR {cond}<srce>,[<base>{,<offset>}]
后索引:
STR {cond}<srce>,[<base>],<offset>
前索引
srce是要存储的寄存器,base是包含需要的内存地址的基地址,offset是可选的,表示在存储前需要在地址上加上的偏移量,也就是说,存储位置为:srce数据存入base + offset为地址的内存
偏移量格式
偏移量可以通过两种方式表示:0到4095之间的立即数:如
STR R0,[R1,#20] ; STR R0,[R1,#-200]
经过移位的寄存器:如
STR R0,[R1,R2,LSL#2]会将R0的值存入R1+R2×4的地址的内存。
写回
只要内存地址被计算好之后,就更新存储基地址的寄存器的值会很方便,这样就可以在下一条指令中再使用。通过在指令后加上一个感叹号!,可以强制使得基寄存器从base+offset计算中被更新。比如:
STR R0,[R1,#-16]!
这条指令会将R0存入R1-16的位置,然后自动进行:
SUB R1, [R1,#16]
而这个额外的指令不需要额外的时间。
也就是说,在地址后面添加了感叹号,会使得保存基地址的寄存器在计算了基地址加offset之后,将这个基地址加offset的值直接存入保存基地址的寄存器,而这个过程是 “免费”的,不需要多余的时间。
字节和字操作
通过在STR指令后添加B,可以进行对字节的操作,否则一定是只能针对字也就是4个字节对齐来进行操作。后索引取址
这是第二种取址模式,再来回顾一下语法STR{cond} <srce>,[<base>],<offset>
这里和前索引的主要区别在于offset一直存在而不是可选的,且写回操作,虽然没有感叹号,可是都会被写回,也就是会自动写回,而不需要专门指明感叹号。
LDR 加载一个字或者一个字节
这里的取值模式等和STR是一样的,不过需要注意的是:矫正
会有一个特殊的矫正操作,比如地址在addr,那么addr & 3FFFFFFC的地址处的值会被加载,也就是说低两位会被置0,之后再加载。然后,寄存器循环右移(addr mod 4)×8位。举例说明:
假设&1000处的值为&76543210,加载如下左侧的地址,会得到右边的值
地址 | R0 |
---|---|
&1000 | &76543210 |
&1001 | &10765432 |
&1002 | &32107654 |
&1003 | &54321076 |
相对于PC的取址
LDR 有一种特殊的格式:LDR <dest>,<expression>
expression产生一个地址,在这种情况下,指令会用到R15作为基寄存器,然后计算立即数偏移,偏移范围在-4095到+4095
第三类 多重读取和存储
LDM和STM用来读取和存储多个值。关于栈
基本东西就不赘述了,网上有一大堆,不过注意这里的栈和数据结构的栈不完全等同,这里主要是指存储函数调用内容的栈。注意:
满/空栈:满栈full stack,即SP指向最后一个push进来的值,空栈empty stack,即SP指向下一个应该被放进来的空位置(下一个可用位置),这里主要是和数据结构的栈一样。
上升/下降栈:上升栈,即SP在push之后增加,pull之后减小。下降栈,相反,push之后减小,pull之后增加。
一般来说,我们使用的栈为满下降栈。
STM 存储多个寄存器
主要用于将多个值进栈,语法:STM<type> <base>{!},<registers>
我们忽略了条件码,但是一般来说是应该有条件码的。
type:两个字母,Full/Empty, Ascending/Descending,分别表示满F/空E,上升A/下降D。第一个字母F/E,第二个字母A/D。
base:栈指针,和LDR/STR一样,感叹号可以用来导致写回。
registers:我们想要push的寄存器列表,由大括号括起来的寄存器,可以每一个都写出来,也可以用Rx-Ry的形式。
举例:
STMED R13!,{R1,R2,R5}
这条指令将会把R1,R2和R5用R13作为SP存入,因为指明了需要写回,R13最终会被减少3×4。因为是空栈,所以压栈结束之后,最后一个字的地址为R13+4。(R13指向最后一个可用位置)
再提一句关于FD(满下降栈)等等
主要是F/E和A/D的一个关系,在处理的时候,A/D会导致加减offset不同,是相反的,这个比较好理解,然而F/E的一个主要区别除了SP指向的位置不一样以外,在执行指令的时候,顺序也会不同,因为F栈指向最后一个已经用了的元素,push的时候会先调整offset到下一个可用位置,然后再处理,E栈则是先处理再调整offset。存储方向
我们以FD栈为例,对于列表中的寄存器,存储的顺序将是低编号寄存器位于低地址,其他根据这个情况作相应变换。存储SP和PC
在需要写回且用作SP的寄存器同时也需要push的时候,先写回值还是先push呢?也就是说push的是哪一个值呢? 如果sp是列表中编号最低的,则先push,否则写回的值是存在栈中那一个,我们一般用R13作为SP,所以一般都是新值。LDM 读取多个寄存器
语法LDM<type> <base>{!},<registers>{^}
这里注意一下一个 ^ 符号,这个表示当R15也需要读取的时候,是否影响整个R15的值,换言之,有这个符号存在,将会影响标志位,否则标志位不变。
LDM SP和PC
当SP也被读取的时候,SP将永远时这个指令执行之后的值。如果R15也需要读取,由^来决定是否需要改变状态,即标志位。
可选标识符
E/F A/D 可以被更换为 I/D B/A对应关系:
STMFD:STMDB
LDMFD:LDMIA
STMFA:STMIB
LDMFA:LDMDA
STMED:STMDA
LDMED:LDMIB
STMEA:STMIA
LDMEA:LDMDB
第四类 跳转
语法:B{cond} <expression>
cond:条件码
expression:地址
偏移量和管道
(这一节对于逆向来讲似乎没有明显作用,掠过)带链接跳转
即BL指令,用来处理函数,R14用来存返回地址,如果还需要使用到R14,则存在栈上。第五类 软中断
主要用于和操作系统交互语法:
SWI{cond} <expression>
cond:条件码
expression:根据操作系统不同而不同
相关文章推荐
- (32位)arm 汇编学习(1)
- ARM汇编学习经验谈
- ARM汇编程序语言程序设计的学习小节_1
- 安装Skyeye学习ARM汇编
- 跟着锅子一步步学习32位汇编(6)---OFFSET ALIGN
- arm 汇编 LDMFD 语句有关 分类: 嵌入式开发学习 2011-04-17 21:55 2444人阅读 评论(0) 收藏
- 跟着锅子一步步学习32位汇编(3)---MOV和XCHG指令
- 跟着锅子一步步学习32位汇编(10)---TYPEDEF
- 嵌入式Linux中ARM gcc嵌套汇编学习-ARM GCC Inside Assembler
- 跟着锅子一步步学习32位汇编(7)---PTR
- uboot移植之arm汇编学习
- ARM汇编指令学习笔记(一)【为明天BOOTLOADER学习准备】
- 微机原理课程设计32位汇编学习之四(显示字符串之特殊字体)
- ARM汇编学习笔记
- windows下32位汇编语言学习笔记
- 微机原理课程设计32位汇编学习之三(显示字符串)
- ARM汇编学习之寄存器
- 跟着锅子一步步学习32位汇编(4)---EFLAGS及标志位操作指令
- 跟着锅子一步步学习32位汇编(5)---加减法 inc dec add sub neg
- ARM汇编语言学习笔记之一(ARM简介)