X86和X64运行环境下C++调用汇编函数源码和解释

备注: 这里给出的代码是在Win10系统中VS2022开发环境下编译测试通过的。

X86环境下C++调用汇编函数

c++代码:

#include 

// 函数使用 C 风格命名规范、调用规则
extern "C" int CalcSum_(int a, int b, int c);

int main(int argc, unsigned short* argv[])
{
    int a = 17, b = 11, c = 14;
    int sum = CalcSum_(a, b, c);

    std::cout << "  a:   " << a << std::endl;
    std::cout << "  b:   " << b << std::endl;
    std::cout << "  c:   " << c << std::endl;
    std::cout << "  (x86)sum: " << sum << std::endl;
    return 0;
}

x86汇编代码:

    .model flat,c
    .code

; extern "C" int CalcSum_(int a, int b, int c)
;
; Description:  This function demonstrates passing arguments between
;               a C++ function and an assembly language function.
;
; Returns:      a + b + c

CalcSum_ proc

; x86处理器环境下, 参数由堆栈传入(依旧是从右向左入栈)
; Initialize a stack frame pointer
        push ebp
        mov ebp,esp

; Load the argument values
        mov eax,[ebp+8]                     ; eax = 'a'
        mov ecx,[ebp+12]                    ; ecx = 'b'
        mov edx,[ebp+16]                    ; edx = 'c'

; Calculate the sum
        add eax,ecx                         ; eax = 'a' + 'b'
        add eax,edx                         ; eax = 'a' + 'b' + 'c'

; Restore the caller's stack frame pointer
        pop ebp
        ret

CalcSum_ endp
        end

运行结果:

X86和X64运行环境下C++调用汇编函数源码和解释_第1张图片

X64环境下C++调用汇编函数

c++代码:

#include 

// 函数使用 C 风格命名规范、调用规则
extern "C" int CalcSum3_(int a, int b, int c);
extern "C" int CalcSum6_(int a, int b, int c, int d, int e, int f);
extern "C" int CalcSum7_(int a, int b, int c, int d, int e, int f, int g);

int main(int argc, unsigned short* argv[])
{
    int a = 17, b = 11, c = 14;
    int sum3 = CalcSum3_(a, b, c);

    std::cout << "  a:   " << a << std::endl;
    std::cout << "  b:   " << b << std::endl;
    std::cout << "  c:   " << c << std::endl;
    std::cout << "  (x64)sum3(a+b+c)        ,result: " << sum3 << std::endl;

    std::cout << "" << std::endl;

    a = 17, b = 11, c = 14;
    int d = 3, e = 9, f = 5, g = 6;
    int sum6 = CalcSum6_(a, b, c, d, e, f);
    int sum7 = CalcSum7_(a, b, c, d, e, f, g);

    std::cout << "  a:   " << a << std::endl;
    std::cout << "  b:   " << b << std::endl;
    std::cout << "  c:   " << c << std::endl;
    std::cout << "  d:   " << d << std::endl;
    std::cout << "  e:   " << e << std::endl;
    std::cout << "  f:   " << f << std::endl;
    std::cout << "  g:   " << g << std::endl;
    std::cout << "  (x64)sum6(a+b+c+d+e+f)  ,result: " << sum6 << std::endl;
    std::cout << "  (x64)sum7(a+b+c+d+e+f+g),result: " << sum7 << std::endl;
    return 0;
}

x64汇编代码:

; x64 新增 r8, r9, r10, r11, r12, r13, r14, r15 这8个通用寄存器
    .code

; extern "C" int CalcSum3_(int a, int b, int c)
;
; Description:  This function demonstrates passing arguments between
;               a C++ function and an assembly language function.
;
; Returns:      a + b + c

CalcSum3_ proc

; x64, 默认前四个参数由 rcx,rdx,r8,r9 四个寄存器传参
; Initialize a stack frame pointer
        push rbp
        mov rbp,rsp

; Load the argument values
        mov rax,rcx                          ; eax = 'a'

; Calculate the sum
        add rax,rdx                         ; eax = 'a' + 'b'
        add rax,r8                          ; eax = 'a' + 'b' + 'c'
                                            ; 返回值存放在rax中

; Restore the caller's stack frame pointer
        pop rbp
        ret

CalcSum3_ endp


; extern "C" int CalcSum6_(int a, int b, int c, int d, int e, int f)
;
; Description:  This function demonstrates passing arguments between
;               a C++ function and an assembly language function.
;
; Returns:      a + b + c + d + e + f

CalcSum6_ proc

; x64处理器环境下, 默认前四个参数由 rcx,rdx,r8,r9 四个寄存器传参,更多参数由堆栈传入(依旧是从右向左入栈)(第五个参数e也存放在rax中)
; Initialize a stack frame pointer
        push rbp
        mov rbp,rsp

; Load the argument values
        ;mov r10d, dword ptr [rbp + 8 * (5 + 1)]    ; 第5个参数, 即参数e
                                                    ; 这里的5(即: 5 * 8 = 40个字节) 表示 4 * 8 = 32 字节的影子空间(home area 为rcx,rdx,r8,r9准备的预留空间)和8字节调用此函数的返回地址(push rbp)
        mov r10d, [rbp + 8 * (5 + 1)]               ; 第5个参数, 即参数e
        mov r11d, [rbp + 8 * (5 + 2)]               ; 第6个参数, 即参数f
        mov rax,rcx                                 ; eax = 'a'

; Calculate the sum
        add rax,rdx                                 ; eax = 'a' + 'b'
        add rax,r8                                  ; eax = 'a' + 'b' + 'c'
        add rax,r9                                  ; eax = 'a' + 'b' + 'c' + 'd'
        add rax,r10                                 ; eax = 'a' + 'b' + 'c' + 'd' + 'e'
        add rax,r11                                 ; eax = 'a' + 'b' + 'c' + 'd' + 'e' + 'f'
                                                    ; 返回值存放在rax中

; Restore the caller's stack frame pointer
        pop rbp
        ret

CalcSum6_ endp


; extern "C" int CalcSum7_(int a, int b, int c, int d, int e, int f, int g)
;
; Description:  This function demonstrates passing arguments between
;               a C++ function and an assembly language function.
;
; Returns:      a + b + c + d + e + f + g


CalcSum7_ proc

; x64处理器环境下, 默认前四个参数由 rcx,rdx,r8,r9 四个寄存器传参,更多参数由堆栈传入(依旧是从右向左入栈)(第五个参数e也存放在rax中)

; Load the argument values
        ;mov r10d, dword ptr [rsp + 8 * (4 + 1)]    ; 第5个参数, 即参数e
                                                    ; 这里的4, 即: 4 * 8 = 32 字节的影子空间(home area 为rcx,rdx,r8,r9准备的预留空间)。注意,这里直接使用了rsp
        mov r10d, [rsp + 8 * (4 + 1)]               ; 第5个参数, 即参数e
        mov r11d, [rsp + 8 * (4 + 2)]               ; 第6个参数, 即参数f
        mov r12d, [rsp + 8 * (4 + 3)]               ; 第7个参数, 即参数g

        mov rax,rcx                                 ; eax = 'a'

; Calculate the sum
        add rax,rdx                                 ; eax = 'a' + 'b'
        add rax,r8                                  ; eax = 'a' + 'b' + 'c'
        add rax,r9                                  ; eax = 'a' + 'b' + 'c' + 'd'
        add rax,r10                                 ; eax = 'a' + 'b' + 'c' + 'd' + 'e'
        add rax,r11                                 ; eax = 'a' + 'b' + 'c' + 'd' + 'e' + 'f'
        add rax,r12                                 ; eax = 'a' + 'b' + 'c' + 'd' + 'e' + 'f' + 'g'
                                                    ; 返回值存放在rax中

; Return
        ret

CalcSum7_ endp
        end

运行结果:

X86和X64运行环境下C++调用汇编函数源码和解释_第2张图片

x64 环境下函数调用规则:

Caller/callee saved registers

The x64 ABI considers the registers RAX, RCX, RDX, R8, R9, R10, R11, and XMM0-XMM5 volatile. When present, the upper portions of YMM0-YMM15 and ZMM0-ZMM15 are also volatile. On AVX512VL, the ZMM, YMM, and XMM registers 16-31 are also volatile. Consider volatile registers destroyed on function calls unless otherwise safety-provable by analysis such as whole program optimization.

The x64 ABI considers registers RBX, RBP, RDI, RSI, RSP, R12, R13, R14, R15, and XMM6-XMM15 nonvolatile. They must be saved and restored by a function that uses them.

详见:

x64 calling convention | Microsoft Docs

可以看得出来,x64比x86环境下调用机制要复杂一些。所以x64环境下示例代码用了三个函数来演示说明。

你可能感兴趣的:(Assembly,系统,c++/c/asm,assembly,c++)