【问题标题】:Selecting specific registers for external calls为外部调用选择特定寄存器
【发布时间】:2016-06-04 14:36:22
【问题描述】:

我对组装非常陌生,并且正在努力学习自己。

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

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

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

连接到问题,我有两个问题:

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

系统: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) 是 2) 不是。见msdn
  • 这是调用约定的一部分,是实现定义的ABI(应用程序二进制接口)的一部分。
  • @Jester:非常感谢。这正是我想要的。

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


【解决方案1】:

对于 Windows,有一个 ABI 指定

  1. 如何传递参数
  2. 需要在调用中保留哪些寄存器

Msdn:microsoft calling conventions

为了像 C 函数一样调用,你应该遵守这些规则。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-02
    • 1970-01-01
    • 2011-02-03
    • 2011-07-14
    • 1970-01-01
    相关资源
    最近更新 更多