לדלג לתוכן

7.2 דפוסים באסמבלי תרגול

תרגול - דפוסים באסמבלי

תרגיל 1 - זיהוי מבנה C מאסמבלי

לכל קטע אסמבלי, זהו מהו מבנה ה-C שהוא מייצג (if, for, while, switch) ושחזרו את הקוד ב-C:

קטע א:

        cmp     edi, 0
        jge     .L1
        neg     edi
.L1:
        mov     eax, edi
        ret

קטע ב:

        xor     eax, eax
        xor     ecx, ecx
.L1:
        add     eax, ecx
        inc     ecx
        cmp     ecx, esi
        jl      .L1
        ret

קטע ג:

        mov     eax, edi
.L1:
        test    eax, eax
        je      .L2
        mov     edx, eax
        shr     edx, 1
        add     eax, edx
        add     eax, 1
        jmp     .L1
.L2:
        ret

קטע ד:

        cmp     edi, 3
        ja      .default
        lea     rax, [rip + .jump_table]
        movsxd  rdx, dword [rax + rdi*4]
        add     rax, rdx
        jmp     rax


תרגיל 2 - חיזוי התנהגות

עבור כל קטע אסמבלי, עקבו ידנית אחרי הערכים באוגרים ונבאו מה ערך ההחזרה (rax/eax) עבור הקלט הנתון:

קטע א (קלט: edi = 5):

func:
        mov     eax, 1
        cmp     edi, 1
        jle     .end
.loop:
        imul    eax, edi
        dec     edi
        cmp     edi, 1
        jg      .loop
.end:
        ret

קטע ב (קלט: edi = 6):

func:
        xor     eax, eax
        test    edi, 1
        jnz     .odd
        mov     eax, 1
.odd:
        ret

קטע ג (קלט: edi = 10, esi = 3):

func:
        mov     eax, edi
        xor     edx, edx
        div     esi
        mov     eax, edx
        ret


תרגיל 3 - התאמת קוד C לדיסאסמבלי

להלן 4 פונקציות C ו-4 קטעי אסמבלי. התאימו כל פונקציה לקטע הנכון:

פונקציות C:

// פונקציה A
int func_a(int *arr, int n) {
    int max = arr[0];
    for (int i = 1; i < n; i++) {
        if (arr[i] > max)
            max = arr[i];
    }
    return max;
}

// פונקציה B
int func_b(int x) {
    int count = 0;
    while (x != 0) {
        count += x & 1;
        x >>= 1;
    }
    return count;
}

// פונקציה C
void func_c(int *arr, int n) {
    for (int i = 0; i < n; i++) {
        arr[i] = arr[i] * 2;
    }
    return;
}

// פונקציה D
int func_d(int a, int b) {
    if (a > b)
        return a - b;
    return b - a;
}

קטעי אסמבלי:

קטע 1:

        mov     eax, edi
        sub     eax, esi
        mov     ecx, esi
        sub     ecx, edi
        cmp     edi, esi
        cmovle  eax, ecx
        ret

קטע 2:

        xor     eax, eax
        test    edi, edi
        je      .end
.loop:
        mov     ecx, edi
        and     ecx, 1
        add     eax, ecx
        shr     edi, 1
        test    edi, edi
        jne     .loop
.end:
        ret

קטע 3:

        mov     eax, [rdi]
        mov     ecx, 1
.loop:
        cmp     ecx, esi
        jge     .end
        mov     edx, [rdi + rcx*4]
        cmp     edx, eax
        cmovg   eax, edx
        inc     ecx
        jmp     .loop
.end:
        ret

קטע 4:

        xor     ecx, ecx
.loop:
        cmp     ecx, esi
        jge     .end
        shl     dword [rdi + rcx*4], 1
        inc     ecx
        jmp     .loop
.end:
        ret


תרגיל 4 - זיהוי אופטימיזציות

עבור כל קטע אסמבלי, הסבירו מהי האופטימיזציה שהקומפיילר עשה וכתבו את קוד ה-C המקורי:

קטע א:

        lea     eax, [rdi + rdi*4]
        ret

קטע ב:

        mov     eax, edi
        shr     eax, 3
        ret

קטע ג:

        xor     eax, eax
        test    edi, edi
        setne   al
        ret

קטע ד:

        lea     eax, [rdi + rdi*2]
        shl     eax, 2
        ret

קטע ה:

        mov     eax, edi
        sar     eax, 31
        shr     eax, 30
        add     eax, edi
        sar     eax, 2
        ret


תרגיל 5 - שחזור פונקציה מלאה

להלן דיסאסמבלי של פונקציה. שחזרו את קוד ה-C שלה, כולל שמות משמעותיים למשתנים:

mystery:
        push    rbp
        mov     rbp, rsp
        push    rbx
        mov     rbx, rdi               ; שמירת ארגומנט ראשון (rdi)
        xor     eax, eax               ; eax = 0
        test    rbx, rbx               ; בדיקה אם rbx == NULL
        je      .end
        xor     eax, eax               ; eax = 0
.loop:
        cmp     byte [rbx + rax], 0    ; בדיקה אם הבית במיקום rax הוא 0
        je      .end
        inc     rax                    ; rax++
        jmp     .loop
.end:
        pop     rbx
        pop     rbp
        ret

רמזים:
- הפונקציה מקבלת ארגומנט אחד ב-rdi (כנראה מצביע)
- היא מחזירה ערך ב-rax
- חפשו דפוס של while loop
- מה עושה cmp byte [rbx + rax], 0?