汇编 64 位函数 a*b+c/d-(e-f)%(g+h)

Assembly 64 bits function a*b+c/d-(e-f)%(g+h)

我需要在汇编中解决这个函数,但我遇到了模数问题。我不知道为什么,但它给出了非常奇怪的结果。

C++代码

#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;
    
}

汇编代码

.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

不确定这是否是您想要的,但是当您必须在汇编中编写某些内容时,首先查看编译器生成的内容通常是个好主意。

我不确定为什么你有一个 __int64 return 类型,但你仍然将它分配给 int,但我会尊重你给定的函数原型。

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

我将使用的编译器是 Linux 中的 GCC,但是您的寄存器使用遵循 Windows ABI,因此我将按如下方式更改声明。

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

现在将您的一行代码放入主体中,并查看经过优化的输出 (-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

终于改得好看了,有点像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

另外,作为个人意见,不要盲目写

push rbp;
mov rbp, rsp;

在每个函数的入口处。在实际意义上需要这部分的情况很少见。