x64汇编学习(3)-- If Branch

Last Updated: 2023-10-02 14:19:01 Monday

-- TOC --

本文通过示例代码,学习if...else...结构被编译成汇编是什么样的。

测试用C代码如下:

#include <stdio.h>

int main(){
    int a = 1;
    int b = 2;
    int c = 3;
    int d = 4;
    if((a>b)&&(c>d)){
        printf("%d\n", a+c);
    } else {
        printf("%d\n", b+d);
    }
    int e = (a+b)/(c+d);
    return e;
}

不开优化,汇编如下:

.LC0:
        .string "%d\n"
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 32
        mov     DWORD PTR [rbp-4], 1
        mov     DWORD PTR [rbp-8], 2
        mov     DWORD PTR [rbp-12], 3
        mov     DWORD PTR [rbp-16], 4
        # 把a存入eax
        mov     eax, DWORD PTR [rbp-4]
        # a - b
        cmp     eax, DWORD PTR [rbp-8]
        # if a <= b, goto .L2
        # 后面的c>d就不判断了!
        jle     .L2
        # a > b, 把c存入eax
        mov     eax, DWORD PTR [rbp-12]
        # c - d
        cmp     eax, DWORD PTR [rbp-16]
        # if c <= d, goto .L2
        jle     .L2
        # if((a>b)&&(c>d)) is true
        mov     edx, DWORD PTR [rbp-4]
        mov     eax, DWORD PTR [rbp-12]
        # a+c的结果放入eax
        add     eax, edx
        # 准备call printf,两个参数
        mov     esi, eax
        mov     edi, OFFSET FLAT:.LC0
        mov     eax, 0
        call    printf
        # 离开if...else...结构
        jmp     .L3
.L2:
        # if((a>b)&&(c>d)) is false
        mov     edx, DWORD PTR [rbp-8]
        mov     eax, DWORD PTR [rbp-16]
        # b+d的结果放入eax
        add     eax, edx
        # 准备call printf, 两个参数
        mov     esi, eax
        mov     edi, OFFSET FLAT:.LC0
        mov     eax, 0
        call    printf
.L3:
        # 重新计算a+c和b+d
        mov     edx, DWORD PTR [rbp-4]
        mov     eax, DWORD PTR [rbp-8]
        # eax = a+c
        add     eax, edx
        mov     ecx, DWORD PTR [rbp-12]
        mov     edx, DWORD PTR [rbp-16]
        # ecx = b+d
        add     ecx, edx
        # 有符号扩展eax到edx,edx:eax是dividend
        cdq
        # ecx是divisor
        # quotient在eax,remainder在edx
        idiv    ecx
        mov     DWORD PTR [rbp-20], eax
        # quotient存入eax
        mov     eax, DWORD PTR [rbp-20]
        leave
        ret

如果开优化,只是-O1,整个if...else...结构就被优化没有了。

在汇编层面,jmp就像goto,jmp是必须的。我觉得,在C语言层面,只要不影响代码的可读性,还是可以看情况使用goto的。

汇编是面向寄存器编程,所有数据结构都在程序员心中,需要程序员自己编写实现调用栈。C是面向内存编程,看不见寄存器,调用栈自动就有。Python连内存都基本看不到了...

本文链接:https://cs.pynote.net/hd/asm/202302093/

-- EOF --

-- MORE --