Conclusion

Comparing C to machine language

  • 简单理解 cmpljl 如何判断大小

    • 有兴趣可以再去了解下这几个标志位,以及对于有无符号整数,是怎么利用这几个标志位来做大小、溢出比较的。

    • 关键标志位

      • cmpl 会设置以下标志位(用 result = dest - src 解释):

      • 标志位名称触发条件(何时为 1)用途
        ZF零标志result == 0(两数相等)判断是否相等
        SF符号标志result < 0(结果为负)判断有符号数的符号
        OF溢出标志结果溢出(有符号数的正负意外翻转)辅助判断有符号数的比较
        CF进位标志dest < src(无符号比较)判断无符号数的大小
    • 对比其他跳转指令

      • 指令含义判断条件比较类型
        jlJump if LessSF != OF有符号
        jgJump if GreaterZF=0 && SF=OF有符号
        jbJump if BelowCF=1无符号
        jaJump if AboveCF=0 && ZF=0无符号
    • 一句话总结

      • cmpl A, B:计算 B - A,设标志位。
      • jl:若 B < A(有符号数),则跳转。(实际是检查 SF != OF,涵盖溢出情况。)
  • ABI 参数传递规则

    • x86-64 System V ABI 的参数传递规则:
    • 整数/指针参数:前 6 个参数依次通过 %rdi, %rsi, %rdx, %rcx, %r8, %r9 传递。
    • 浮点参数:前 8 个参数通过 %xmm0 ~ %xmm7 传递。
    • 多余参数:从第 7 个参数开始,从右到左压栈(即最后一个参数先入栈)。
  • ABI 规则和编译器优化

    • 编译器在生成汇编时,并不严格按源码顺序填充寄存器;
    • 关键点:ABI 只要求函数调用时寄存器和栈中的参数值是正确的,不关心指令顺序。

Analysis

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>

int main(void) {
int x, y, z;
while (1) {
x = 0;
y = 1;
do {
printf("%d\n", x);
z = x + y;
x = y;
y = z;
} while (x < 255);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
Disassembly of section .text:
0000000000001140 <main>:
# set up
1140: 55 push %rbp
1141: 48 89 e5 mov %rsp,%rbp
1144: 48 83 ec 10 sub $0x10,%rsp
1148: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
# variable init
114f: c7 45 f8 00 00 00 00 movl $0x0,-0x8(%rbp) # x
1156: c7 45 f4 01 00 00 00 movl $0x1,-0xc(%rbp) # y
# printf
115d: 8b 75 f8 mov -0x8(%rbp),%esi # x
1160: 48 8d 3d 9d 0e 00 00 lea 0xe9d(%rip),%rdi # 2004 <_IO_stdin_used+0x4>
1167: b0 00 mov $0x0,%al
1169: e8 c2 fe ff ff call 1030 <printf@plt>
# z = x + y
116e: 8b 45 f8 mov -0x8(%rbp),%eax # x -> %eax
1171: 03 45 f4 add -0xc(%rbp),%eax # add y -> %eax
1174: 89 45 f0 mov %eax,-0x10(%rbp) # %eax -> z
# x = y
1177: 8b 45 f4 mov -0xc(%rbp),%eax
117a: 89 45 f8 mov %eax,-0x8(%rbp)
# y = z
117d: 8b 45 f0 mov -0x10(%rbp),%eax
1180: 89 45 f4 mov %eax,-0xc(%rbp)
# while condition
1183: 81 7d f8 ff 00 00 00 cmpl $0xff,-0x8(%rbp) # 255 ? x
118a: 0f 8c cd ff ff ff jl 115d <main+0x1d> # jump if less than -> # printf
1190: e9 ba ff ff ff jmp 114f <main+0xf> # jump -> # variable init

Disassembly of section .plt:
0000000000001030 <printf@plt>:
1030: ff 25 e2 2f 00 00 jmp *0x2fe2(%rip) # 4018 <printf@GLIBC_2.2.5>
1036: 68 00 00 00 00 push $0x0
103b: e9 e0 ff ff ff jmp 1020 <_init+0x20>

Disassembly of section .rodata:
0000000000002000 <_IO_stdin_used>:
2000: 01 00 add %eax,(%rax)
2002: 02 00 add (%rax),%al
2004: 25 .byte 0x25
2005: 64 0a 00 or %fs:(%rax),%al