选择外部呼叫的特定寄存器

时间:2016-02-22 23:32:04

标签: c windows assembly x86-64 calling-convention

我很擅长集会,并试图自学。

到目前为止,我已经了解到,根据从调用者传递给被调用者的参数数量,如果只有少量参数可以传递,而不是推/弹操作,则只使用一些特定的寄存器

  • 例如,当将参数传递给交换函数void asm_swap(int *x, int *y)时,C编译器使用寄存器 rcx rdx 寄存器来传递地址变量(在这种情况下不需要返回值)。从 _cdecl 切换到 _fastcall 没有任何区别。

  • 对于另一个函数int asm_fact(int x),即计算x的阶乘,C编译器使用 rcx 传递x的值, rax 返回计算的阶乘。同样,从 _cdecl 切换到 _fastcall 没有任何区别。

关于这个问题,我有两个问题:

  1. 我可以推断出一个断言,每当我编译相同的代码时,调用者肯定会使用相同的寄存器来发送和接收数据吗?
  2. 有没有办法选择特定的寄存器作为传递变量的工具(比如,对于函数asm_fact,我更喜欢使用 rdx 来保存x的值,而不是 rcx
  3. 系统:Windows 10(64),VS-2013。

    示例代码: 文件“main.c”

    #include <stdlib.h>
    #include <stdio.h>
    
    extern void asm_swap();
    extern signed long long int asm_fact();
    
    typedef signed long long int sint64;
    
    sint64 fact_sint64(sint64 n) {
        sint64 ret = (sint64)1;
        if (n > (sint64)1) {
            while (n > (sint64)1) {
                ret *= n--;
            }
        }
        return (ret);
    }
    
    void swap_sint64(sint64 *a, sint64 *b) {
        sint64 t = *a;
        *a = *b;
        *b = t;
    }
    
    int main(void) {
        sint64 x, y;
        x = 8;
        y = 3;
        printf("(initial)     ->   x = %lli     y = %lli\n\n", x, y);
        swap_sint64(&x, &y);
        printf("(swap in c)   ->   x = %lli     y = %lli\n\n", x, y);
        asm_swap(&x, &y);
        printf("(swap in asm) ->   x = %lli     y = %lli\n\n", x, y);
        y = fact_sint64(x);
        printf("(fact in c)   ->   fact(%lli) = %lli\n\n", x, fact_sint64(x));
        y = asm_fact(x);
        printf("(fact in asm) ->   fact(%lli) = %lli\n\n", x, y);
        getchar();
        return (0);
    }
    

    文件“Assembly.asm64”

    .data
    
    .code
    asm_swap proc
        mov r8, [rcx]
        mov r9, [rdx]
        mov [rcx], r9
        mov [rdx], r8
        ret
    asm_swap endp
    
    asm_fact proc
        mov rax, 1
        cmp rcx, 1
        jle $exit@fact
    $loop@fact:
        imul rax, rcx
        dec rcx
        cmp rcx, 1
        jg $loop@fact
    $exit@fact:
        ret
    asm_fact endp
    end
    

1 个答案:

答案 0 :(得分:1)

对于Windows,有一个指定

的ABI
  1. 如何传递参数
  2. 需要在通话中保留哪些寄存器
  3. Msdn:microsoft calling conventions

    为了作为C函数调用,您应该遵守这些规则。

    您必须保留非易失性寄存器(保存并恢复它们)

相关问题