x64汇编学习(4)-- For Loop

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

-- TOC --

本文通过示例代码,学习for loop循环被编译成汇编的样子。

测试用C代码如下:

#include <stdio.h>

int main(){
    for(int i=0; i<100; ++i){
        if(i%2 == 0)
            printf("%d\n", i);
    }
    return 0;
}

不开优化,汇编如下:

.LC0:
        .string "%d\n"
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        # i = 0
        mov     DWORD PTR [rbp-4], 0
        jmp     .L2
.L4:
        # 把i存入eax
        mov     eax, DWORD PTR [rbp-4]
        # i&=0x01
        and     eax, 1
        # i&i
        test    eax, eax
        # if i!=0, goto .L3
        jne     .L3
        # if i==0, prepare and call printf
        mov     eax, DWORD PTR [rbp-4]
        mov     esi, eax
        mov     edi, OFFSET FLAT:.LC0
        mov     eax, 0
        call    printf
.L3:
        # ++i
        add     DWORD PTR [rbp-4], 1
.L2:
        # i - 99
        cmp     DWORD PTR [rbp-4], 99
        # if i <= 99, goto .L4
        jle     .L4
        # for loop end
        mov     eax, 0
        leave
        ret

-O1

.LC0:
        .string "%d\n"
main:
        push    rbx
        # ebx = i = 0
        mov     ebx, 0
        jmp     .L3
.L2:
        # ++i
        add     ebx, 1
        # i-100
        cmp     ebx, 100
        # 如果cmp结果是0,goto .L6
        je      .L6
.L3:
        # 只对bl进行测试,bl&0x01
        test    bl, 1
        # 如果结果不为0,即不为偶数,goto .L2
        jne     .L2
        # 结果为0,call printf, goto .L2
        mov     esi, ebx
        mov     edi, OFFSET FLAT:.LC0
        mov     eax, 0
        call    printf
        jmp     .L2
.L6:
        # for loop end
        mov     eax, 0
        pop     rbx
        ret

-O2或-O3

.LC0:
        .string "%d\n"
main:
        push    rbx
        # 用xor清零
        xor     ebx, ebx
        jmp     .L3
.L2:
        add     ebx, 1
        cmp     ebx, 100
        je      .L7
.L3:
        test    bl, 1
        jne     .L2
        mov     esi, ebx
        mov     edi, OFFSET FLAT:.LC0
        # 用xor清零
        xor     eax, eax
        # ++i
        add     ebx, 1
        call    printf
        # (i-100)!=0, goto .L3
        cmp     ebx, 100
        jne     .L3
.L7:
        xor     eax, eax
        pop     rbx
        ret

O3代码的变化,感觉是某种inline,将判断是否继续循环的代码,放在循环内部,因此出现了两行相同的+1和cmp。

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

-- EOF --

-- MORE --