前言:
我们先来思考几个问题
如:
1、 我们经常使用到的if else 流程语句代码 是怎么被机器读懂的
2、它背后的本质是什么
3、 从汇编的角度去看 if else 又是什么呢
4、 不同的汇编对if else 的解释 是相同的吗
本文分别从ARM和AT&T汇编去分析一段oc代码
源码
- (void)cycle {
int a = 6;
int b = 10;
if (a == b) {
NSLog(@"相等");
}else {
NSLog(@"不相等");
}
int c = 9;
}
ARM汇编
YangASM`-[ViewController asm_ifCycle]:
0x104b8df7c <+0>: sub sp, sp, #0x30 ; =0x30
0x104b8df80 <+4>: stp x29, x30, [sp, #0x20]
0x104b8df84 <+8>: add x29, sp, #0x20 ; =0x20
0x104b8df88 <+12>: stur x0, [x29, #-0x8]
0x104b8df8c <+16>: str x1, [sp, #0x10]
0x104b8df90 <+20>: mov w8, #0x6
0x104b8df94 <+24>: str w8, [sp, #0xc]
0x104b8df98 <+28>: mov w8, #0xa
0x104b8df9c <+32>: str w8, [sp, #0x8]
0x104b8dfa0 <+36>: ldr w8, [sp, #0xc]
0x104b8dfa4 <+40>: ldr w9, [sp, #0x8]
0x104b8dfa8 <+44>: subs w8, w8, w9
0x104b8dfac <+48>: b.ne 0x104b8dfc0 ; <+68> at ViewController.m
0x104b8dfb0 <+52>: adrp x0, 3
0x104b8dfb4 <+56>: add x0, x0, #0x8 ; =0x8
0x104b8dfb8 <+60>: bl 0x104b8e520 ; symbol stub for: NSLog
0x104b8dfbc <+64>: b 0x104b8dfcc ; <+80> at ViewController.m
0x104b8dfc0 <+68>: adrp x0, 3
0x104b8dfc4 <+72>: add x0, x0, #0x28 ; =0x28
0x104b8dfc8 <+76>: bl 0x104b8e520 ; symbol stub for: NSLog
0x104b8dfcc <+80>: mov w8, #0x9
-> 0x104b8dfd0 <+84>: str w8, [sp, #0x4]
0x104b8dfd4 <+88>: ldp x29, x30, [sp, #0x20]
0x104b8dfd8 <+92>: add sp, sp, #0x30 ; =0x30
0x104b8dfdc <+96>: ret
ARM汇编解析
我们重点看 if 语句 的汇编代码
// ne是 not equal缩写 代表条件 不相等
// b跳转指令
// b.ne 就是条件跳转指令 如果不相等跳转到0x104b8dfc0指令
// 0x104b8dfc0指令 就是 NSLog(@"不相等")对应的汇编地址 下面可以看到
0x104b8dfac <+48>: b.ne 0x104b8dfc0
// NSLog(@"相等")
0x104b8dfb0 <+52>: adrp x0, 3
0x104b8dfb4 <+56>: add x0, x0, #0x8 ; =0x8
0x104b8dfb8 <+60>: bl 0x104b8e520 ; symbol stub for: NSLog
// 无条件跳转到 0x104b8dfcc
// 跳过的3条指令 刚好是 NSLog(@"不相等"); 对应的汇编指令
0x104b8dfbc <+64>: b 0x104b8dfcc ; <+80> at ViewController.m
// NSLog(@"不相等");
0x104b8dfc0 <+68>: adrp x0, 3
0x104b8dfc4 <+72>: add x0, x0, #0x28 ; =0x28
0x104b8dfc8 <+76>: bl 0x104b8e520 ; symbol stub for: NSLog
// int c = 9
0x104b8dfcc <+80>: mov w8, #0x9
-> 0x104b8dfd0 <+84>: str w8, [sp, #0x4]
介绍3条跳转指令
bl 跳转指令 跳转会附带把下一条指令的地址 保存到寄存器lr(x30)中 之后 再去跳转
b 最单纯的跳转指令
b.ne 条件跳转指令 不相等就跳转
AT&T汇编
同样的代码 我们看下在AT&T 汇编下的生成
YangASM`-[ViewController asm_ifCycle]:
0x101c21eb0 <+0>: pushq %rbp
0x101c21eb1 <+1>: movq %rsp, %rbp
0x101c21eb4 <+4>: subq $0x20, %rsp
0x101c21eb8 <+8>: movq %rdi, -0x8(%rbp)
0x101c21ebc <+12>: movq %rsi, -0x10(%rbp)
0x101c21ec0 <+16>: movl $0x6, -0x14(%rbp)
0x101c21ec7 <+23>: movl $0xa, -0x18(%rbp)
0x101c21ece <+30>: movl -0x14(%rbp), %eax
0x101c21ed1 <+33>: cmpl -0x18(%rbp), %eax
0x101c21ed4 <+36>: jne 0x101c21ef0 ; <+64> at ViewController.m
0x101c21eda <+42>: leaq 0x2137(%rip), %rax ; @
0x101c21ee1 <+49>: movq %rax, %rdi
0x101c21ee4 <+52>: movb $0x0, %al
0x101c21ee6 <+54>: callq 0x101c22434 ; symbol stub for: NSLog
0x101c21eeb <+59>: jmp 0x101c21f01 ; <+81> at ViewController.m:29:9
0x101c21ef0 <+64>: leaq 0x2141(%rip), %rax ; @
0x101c21ef7 <+71>: movq %rax, %rdi
0x101c21efa <+74>: movb $0x0, %al
0x101c21efc <+76>: callq 0x101c22434 ; symbol stub for: NSLog
-> 0x101c21f01 <+81>: movl $0x9, -0x1c(%rbp)
0x101c21f08 <+88>: addq $0x20, %rsp
0x101c21f0c <+92>: popq %rbp
0x101c21f0d <+93>: retq
AT&T汇编解析
我们重点看其中的条件语句
// int a = 6 6存放到 -0x14(%rbp) 内存地址
0x101c21ec0 <+16>: movl $0x6, -0x14(%rbp)
// int b = 10 10 存放到 -0x18(%rbp) 内存地址
0x101c21ec7 <+23>: movl $0xa, -0x18(%rbp)
// 把-0x14(%rbp) 内存地址的值也就是6 赋给 eax 寄存器
0x101c21ece <+30>: movl -0x14(%rbp), %eax
// cmp 比较指令 加l变成 cmpl 就是比较的4个字节
// 我们的 a b 都是int类型 在内存占据4个字节
// 从-0x18(%rbp)地址 往下4个字节 里面存储的数据 也就是10 和 eax 里面的值 进行对比
// 也就是 6 和 10 对比 是否想等
0x101c21ed1 <+33>: cmpl -0x18(%rbp), %eax
// jne jump not equal 条件跳转指令 不相等就跳转
// 如果 a != b 那么就进行跳转 跳转到 0x101c21ef0 指令
// 0x101c21ef0指令 在下面可以找到 其实就是 NSLog(@"不相等"); 对应的指令
0x101c21ed4 <+36>: jne 0x101c21ef0 ; <+64> at ViewController.m
// leaq 我们后面再详细说 其实就是 强制拿一个地址 给 rax 而不是拿地址上的值给 rax
// NSLog(@"相等");
0x101c21eda <+42>: leaq 0x2137(%rip), %rax ; @
0x101c21ee1 <+49>: movq %rax, %rdi
0x101c21ee4 <+52>: movb $0x0, %al
0x101c21ee6 <+54>: callq 0x101c22434 ; symbol stub for: NSLog
// 输出完 NSLog(@"相等"); 之后跳转到 0x101c21f01 指令
0x101c21eeb <+59>: jmp 0x101c21f01 ; <+81> at ViewController.m:29:9
/// NSLog(@"不相等");
0x101c21ef0 <+64>: leaq 0x2141(%rip), %rax ; @
0x101c21ef7 <+71>: movq %rax, %rdi
0x101c21efa <+74>: movb $0x0, %al
0x101c21efc <+76>: callq 0x101c22434 ; symbol stub for: NSLog
/// int c = 9
-> 0x101c21f01 <+81>: movl $0x9, -0x1c(%rbp)
补充
1、ARM汇编和 AT&T汇编 条件跳转指令 分别是 b.ne jne
2、 jne 通常配合 cmd 使用