我正在为 ARM Thumb2(剥离)二进制文件开发反汇编程序。我已经可以恢复使用直接跳转的基本块 (BB) 的 CFG。我的下一个目标是处理间接跳转。我目前正在确定 switch 语句的目标,我将根据以下示例进行讨论:
int main(int argc, char** argv){
int i = 0;
switch (argc) {
case 0: i++; break;
case 1: i+=2; break;
case 3: i+=3; break;
case 6: i+=6; break;
case 5: i+=8; break;
case 7: i+=10; break;
default: i+=87; break;
}
return i;
}
使用以下方法编译上述示例时:
arm-linux-gnueabihf-gcc-4.8 -o3 -mthumb main.c -o main.out
反汇编main使用objdump显示开关表数据字开始于0x83d8如下所示:
83bc: b480 push {r7}
83be: b085 sub sp, #20
83c0: af00 add r7, sp, #0
83c2: 6078 str r0, [r7, #4]
83c4: 6039 str r1, [r7, #0]
83c6: 2300 movs r3, #0
83c8: 60fb str r3, [r7, #12]
83ca: 687b ldr r3, [r7, #4]
83cc: 2b07 cmp r3, #7
83ce: d82b bhi.n 8428 <main+0x6c>
83d0: a201 add r2, pc, #4 ; (adr r2, 83d8 <main+0x1c>)
83d2: f852 f023 ldr.w pc, [r2, r3, lsl #2]
83d6: bf00 nop
83d8: 000083f9 .word 0x000083f9
83dc: 00008401 .word 0x00008401
83e0: 00008429 .word 0x00008429
83e4: 00008409 .word 0x00008409
83e8: 00008429 .word 0x00008429
83ec: 00008419 .word 0x00008419
83f0: 00008411 .word 0x00008411
83f4: 00008421 .word 0x00008421
83f8: 68fb ldr r3, [r7, #12]
83fa: 3301 adds r3, #1
83fc: 60fb str r3, [r7, #12]
83fe: e017 b.n 8430 <main+0x74>
8400: 68fb ldr r3, [r7, #12]
8402: 3302 adds r3, #2
8404: 60fb str r3, [r7, #12]
8406: e013 b.n 8430 <main+0x74>
8408: 68fb ldr r3, [r7, #12]
840a: 3303 adds r3, #3
840c: 60fb str r3, [r7, #12]
840e: e00f b.n 8430 <main+0x74>
8410: 68fb ldr r3, [r7, #12]
8412: 3306 adds r3, #6
8414: 60fb str r3, [r7, #12]
8416: e00b b.n 8430 <main+0x74>
8418: 68fb ldr r3, [r7, #12]
841a: 3308 adds r3, #8
841c: 60fb str r3, [r7, #12]
841e: e007 b.n 8430 <main+0x74>
8420: 68fb ldr r3, [r7, #12]
8422: 330a adds r3, #10
8424: 60fb str r3, [r7, #12]
8426: e003 b.n 8430 <main+0x74>
8428: 68fb ldr r3, [r7, #12]
842a: 3357 adds r3, #87 ; 0x57
842c: 60fb str r3, [r7, #12]
842e: bf00 nop
8430: 68fb ldr r3, [r7, #12]
8432: 4618 mov r0, r3
8434: 3714 adds r7, #20
8436: 46bd mov sp, r7
8438: f85d 7b04 ldr.w r7, [sp], #4
843c: 4770 bx lr
843e: bf00 nop
观察:
- 数据字存储开关表的绝对目标地址而不是偏移量。
- 间接分支是使用
ldr.w pc, [base, index, lsl #2]其中 base(此处为 r2)存储数据字开头的地址和索引(此处为 r3)用于计算偏移量来实现的。
问题:
- 上述观察可以概括吗?换句话说,我可以假设这是(大多数)ARM 编译器实现 switch 语句的(事实上的)标准方式吗?
- 为什么存储在数据字中的地址是奇数?我在这里看不到 ARM/Thumb 之间的任何模式切换。例如,可以找到默认情况,
0x8428但相应的地址存储为0x00008429。