Home > Back-end >  Assembly 64 bits function a*b c/d-(e-f)%(g h)
Assembly 64 bits function a*b c/d-(e-f)%(g h)

Time:05-25

I need to solve this function in assembly but I have a problem with modulo. I have no idea why but it gives very strange results.

C code

#include <iostream>
extern "C" __int64 suma(int a, int b, int c, int d, int e, int f, int g, int h);
int main()
{
    int a = 1, b = 1, c = 1, d = 1, e = 1, f = 1, g = 1, h = 1;
    int wynik = suma(a, b, c, d, e, f, g, h);
    std::cout << wynik;
    
}

assembly code

.CODE
_DATA SEGMENT
_DATA ENDS
_TEXT SEGMENT
PUBLIC suma
suma PROC
    push rbp;
    mov rbp, rsp;
    imul rcx, rdx; // a * b
    mov rax, r8; // c
    xor rdx, rdx;
    div r9; // c/d
    mov r10, [rbp   6 * 8]; //e
    sub r10, [rbp   7 * 8]; // e-f
    mov r11, [rbp   8 * 8]; // g
    add r11, [rbp   9 * 8]; //g   h
    add rcx, rax; // a * b   c / d
    sub rcx, r10; // a * b   c / d - e - f
    mov rdx, 0;
    mov rax, rcx; 
    idiv r11;
    mov rax, rdx;
    pop rbp;
ret
suma ENDP
_TEXT ENDS
END

CodePudding user response:

Not sure if this is what you want, but when you have to write something in assembly, it is often a good idea to first have a look at what the compiler produces.

I'm not sure why you have an __int64 return type when you assign it anyway to an int, but I'll respect your given function prototype.

__int64 suma(int a, int b, int c, int d, int e, int f, int g, int h);

The compiler I'll use is GCC in Linux, but your register usage follows the Windows ABI, so I'll change the declaration as follows.

__attribute__((ms_abi))
long long suma(int a, int b, int c, int d, int e, int f, int g, int h);

Now put your one line of code in the body, and see the output with optimization (-O3).

{
    return a * b   c / d - (e - f) % (g   h);
}

suma:
        mov     eax, r8d
        imul    ecx, edx
        mov     r8d, DWORD PTR [rsp 64]
        add     r8d, DWORD PTR [rsp 56]
        cdq
        idiv    r9d
        add     ecx, eax
        mov     eax, DWORD PTR [rsp 40]
        sub     eax, DWORD PTR [rsp 48]
        cdq
        idiv    r8d
        sub     ecx, edx
        movsx   rax, ecx
        ret

Finally make it look better, a bit more like human-written.

suma:
        imul    ecx, edx
        mov     eax, r8d
        cdq
        idiv    r9d
        add     ecx, eax
        mov     eax, DWORD PTR [rsp   40]
        sub     eax, DWORD PTR [rsp   48]
        cdq
        mov     r8d, DWORD PTR [rsp   56]
        add     r8d, DWORD PTR [rsp   64]
        idiv    r8d
        sub     ecx, edx
        movsx   rax, ecx
        ret

Also, as a personal opinion, don't blindly write

push rbp;
mov rbp, rsp;

at the entry of every function. Cases where this part is necessary is rare in a practical sense.

  • Related