本文记录笔者学习对应汇编指令相关编码知识
ARM32
首先阅读基础概念:
ARM-instruction-set-encoding
A32
指令全部是32位且是4字节地址对齐.
位域如下
如何理解4字节地址对齐和指令长度?
0000139c <_start_main>:139c: e92d4800 push {fp, lr}13a0: e1a0b00d mov fp, sp13a4: e24dd010 sub sp, sp, #1613a8: e59f1030 ldr r1, [pc, #48] @ 13e0 <_start_main+0x44>13ac: e28d3004 add r3, sp, #413b0: e79f1001 ldr r1, [pc, r1]....
在上面展示是一个ELF中存储的函数片段。第一列是存储指令的地址(139c,13a0等),第二列为
指令编码(e92d4800
等)和最后一列对应的助记符。
地址对齐:
你会发现所有的地址139c到13b0所有地址都可以被4整除(由于4字节对齐,末尾两位位域必须为0)。
指令长度
所有A32
指令都是定长4字节编码。
指令位域解析
cond
cond 位域在[31,28]。 大多数ARM指令都支持条件执行.既根据APSR中N Z C V Q的条件位确定是否执行某一个指令。
APSR如下:
cond助记符和编码
举例:
0x02422010 subeq r2, r2, #0x10
0x12422010 subne r2, r2, #0x10
原本sub指令后面添加eq和ne后缀表示。
eq编码为0b0000 所以 subeq第一个编码为0x0
ne编码为0b0001 同理 subne第一个编码0x1
我们仔细研究subne编码如下:
当APSR的Z==0才会执行subne指令
op
官方 op分类表 Table 5.1
0x12422010 subne r2, r2, #0x10
我们以subne举例
op1=0b001 op=0b0 所以他属于Data-processing and miscellaneous instruction
.我们需要继续翻阅这个类别的文档,进一步分析格式
Data-processing and miscellaneous instruction
op = 1
op1 = 00100
op2 = 0001
从上表格可知需要查阅
Data-processing (immediate)
op = 00100
Rn = 0010
继续翻阅sub指令格式文档
sub(immediate,ARM)
SUB{S}<c> <Rd>, <Rn>, #<const>
标记位域结果:
cond = 0b0001
S = 0b0
Rn = 0b0010
RD = 0b0010
imm12 = 0b0000 0001 0000
在文档有介绍一些特殊情况如下:
#如果Rn等于 '1111' 且 S == ’0‘那么请参阅 ADR
if Rn == '1111' && S == '0' then SEE ADR;
# 略 类似上文
if Rn == '1101' then SEE SUB (SP minus immediate);
# 略 类似上文
if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;# 如果不是上面的特殊情况我们定义以下标志变量。d = UInt(Rd);
n = UInt(Rn);
setflags = (S == '1');
imm32 = ARMExpandImm(imm12);
Uint
函数和ARMExpandImm
是arm中定义伪代码函数,可参阅如下arm文档目录
pseudo-code 函数目录
ARMExpandImm
Uint文档
Uint
函数比较简单,我们详细看看ARMExpandImm
标记位域结果:
cond = 0b0000
a = 0
b = 0
c = 1
d = 0
e = 0
g = 0
h = 0
根据文档这个常量值将为0x10(cond为0的话直接根据顺序取值)
我们继续回带到sub指令中如下
d = 2
n = 2
setflags = false
imm32 = 0x10;
有这些具体变量数值后继续看sub的Operation伪代码
// ConditionPassed 根据cond和APSR判断是否能执行当前指令
if ConditionPassed() then//可以先忽略 排查一些未定义编码指令行为等EncodingSpecificOperations();//计算结果进位和溢出等。NOT(imm32), '1'相当于取反加1。也就是将立即数变为一个负数(result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1');//d表示写入pc寄存器if d == 15 thenALUWritePC(result); // setflags is always FALSE hereelse//结果写入目标寄存器R[d] = result;//根据条件更新APSRif setflags thenAPSR.N = result<31>;APSR.Z = IsZeroBit(result);APSR.C = carry;APSR.V = overflow;
// AddWithCarry()
// 比较简单可自行阅读
// ==============(bits(N), bit, bit) AddWithCarry(bits(N) x, bits(N) y, bit carry_in)unsigned_sum = UInt(x) + UInt(y) + UInt(carry_in);signed_sum = SInt(x) + SInt(y) + UInt(carry_in);result = unsigned_sum<N-1:0>; // same value as signed_sum<N-1:0>carry_out = if UInt(result) == unsigned_sum then '0' else '1';overflow = if SInt(result) == signed_sum then '0' else '1';return (result, carry_out, overflow);
Thumb&Thumb-2
Thumb-instruction-set-encoding
我们知道thumb指令
中有T1和T2两种类别,T1是16位,而T2是32位的。他们都是办字对齐(2字节对齐)
如果在Thumb
运行状态下如果指令是如下开头的那么证明为thumb-2指令
0b11101
0b11110
0b11111
地址对齐概念
下图是一个实际
0000141c <main>:141c: b580 push {r7, lr}141e: 466f mov r7, sp1420: f1a1 0110 sub.w r1, r1, #161424: 2200 movs r2, #01426: 9200 str r2, [sp, #0]1428: 9203 str r2, [sp, #12]142a: 9002 str r0, [sp, #8]142c: 9101 str r1, [sp, #4]142e: 9902 ldr r1, [sp, #8]1430: 4803 ldr r0, [pc, #12] @ (1440 <main+0x24>)1432: 4478 add r0, pc1434: f000 e82c blx 1490 <main+0x74>1438: 9800 ldr r0, [sp, #0]143a: b004 add sp, #16143c: bd80 pop {r7, pc}143e: bf00 nop1440: ffffef42 @ <UNDEFINED> instruction: 0xffffef42
第一列为地址,第二例为机器码,第三列为助记符(mnemonic)
因为thumb
指令都是半字节对齐(2字节),所以第一列所有地址都可以被2整除(地址末尾为0)。
thumb指令编码示例
# 注意thumb不支持条件执行比如subeq后面的eq就支持
0x84B0(大端为0xB084) sub sp, #16
0x5141(大端为0x4151) adcs r1,r2
16-bit-Thumb-instruction-encoding
另一个编码规则文档
我们以adcs举例说明
0x4151 adcs r1,r2
Opcode = 0b010000
通过查阅
Opcode表格得知属于数据指令,
Data-processing格式指令文档
Opcode=0b0101
Opcode表格查询得知
ADC指令格式
通过阅读得知编码格式如下:
ADC<c>
表示在IT block的指令(thumb不像arm单独对每个指令设置条件执行,只能依靠IT指令)
具体操作如下,这里就不在做讲解
d = UInt(Rdn); n = UInt(Rdn); m = UInt(Rm); setflags = !InITBlock();
(shift_t, shift_n) = (SRType_LSL, 0);if ConditionPassed() thenEncodingSpecificOperations();shifted = Shift(R[m], shift_t, shift_n, APSR.C);(result, carry, overflow) = AddWithCarry(R[n], shifted, APSR.C);if d == 15 then // Can only occur for ARM encodingALUWritePC(result); // setflags is always FALSE hereelseR[d] = result;if setflags thenAPSR.N = result<31>;APSR.Z = IsZeroBit(result);APSR.C = carry;APSR.V = overflow;
thumb2 指令编码示例
thumb2指令一般会带有.w
后缀如 sub.w r1, r1, #16
.
0xA1F11001 (大端0xF1A10110) sub.w r1, r1, #16
我们首先查阅文档可知前四位为0b11111
表示32位thumb2指令
32-bit-Thumb-instruction-encoding
op1 = 10
op2 = 0011010
op = 0
查阅文档进行下一步分析Data-processing(modified-immediate)
op = 0b1101
S = 0b0
Rn = 0b0001
Rd = 0b0001
查阅可知是一个sub指令
SUB (immediate, Thumb)
SUB指令位域如下
助记符格式:
SUB{S}<c>.W <Rd>, <Rn>, #<const>
一些变量计算和定义
if Rd == '1111' && S == '1' then SEE CMP (immediate);
if Rn == '1101' then SEE SUB (SP minus immediate);
d = UInt(Rd); n = UInt(Rn); setflags = (S == '1'); imm32 = ThumbExpandImm(i:imm3:imm8);
if d == 13 || (d == 15 && S == '0') || n == 15 then UNPREDICTABLE;
操作定义:
if ConditionPassed() thenEncodingSpecificOperations();(result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1');R[d] = result;if setflags thenAPSR.N = result<31>;APSR.Z = IsZeroBit(result);APSR.C = carry;APSR.V = overflow;
ARM64
aarch64编码
Arm® Architecture Reference Manual for A-profile architecture
一个示例汇编函数:
000000000000165c <main>:165c: d100c3ff sub sp, sp, #0x301660: a9027bfd stp x29, x30, [sp, #32]1664: 910083fd add x29, sp, #0x201668: 2a1f03e8 mov w8, wzr166c: b9000fe8 str w8, [sp, #12]1670: b81fc3bf stur wzr, [x29, #-4]1674: b81f83a0 stur w0, [x29, #-8]1678: f9000be1 str x1, [sp, #16]167c: b85f83a1 ldur w1, [x29, #-8]1680: f0ffffe0 adrp x0, 0 <note_android_ident-0x2c0>1684: 91142000 add x0, x0, #0x5081688: 94000016 bl 16e0 <printf@plt>168c: b9400fe0 ldr w0, [sp, #12]1690: a9427bfd ldp x29, x30, [sp, #32]1694: 9100c3ff add sp, sp, #0x301698: d65f03c0 ret
我们拿出下面指令说明
0x91142000 add x0, x0, #0x508
本例编码如下:
op1 = 1000
可见指令属于Data Processing --Emmediate
参阅Data Processing --Emmediate指令格式如下:
op0 = 010
查阅可知属于Add/substract(immediate)
。参照对应文档格式如下:
注:
sf:标准使用32位还是64
S: 是否更新标志寄存器
本例标记如下
sf = 1
op = 0
S = 0
根据上述变量属于Add(immediate) -64-bitr variant
。
继续翻阅对应文档位域视图:
ADD <Xd|SP>, <Xn|SP>, #<imm>{, <shift>}
具体操作类似ARM32就不在赘述。