【问题标题】:Does the return value always go into eax register after a method call?方法调用后返回值是否总是进入 eax 寄存器?
【发布时间】:2014-02-07 08:59:09
【问题描述】:

我编写了一个挂钩库,它检查 PE 可执行文件 dll 导入表,以创建一个能够更改参数和返回值的库。我有几个关于如何从函数传递返回值的问题。

我了解到函数的返回值保存在累加器寄存器中。总是这样吗?如果不是,编译器怎么知道去哪里寻找函数结果?

返回类型大小呢?一个整数很容易拟合,但是更大的结构呢?调用者是否保留堆栈空间,以便它调用的方法可以将结果写入堆栈?

【问题讨论】:

  • 为什么不编译几个例子自己看看呢?
  • 不,ARM7 处理器没有 EAX 寄存器。其他处理器也没有。
  • 很明显如果返回类型不适合eax,它就不可能在里面。请参阅您正在使用的任何调用约定的文档。
  • 底线:它完全取决于编译器及其使用的约定。 (我构建了一个在 EAX/EDX [有时] 中传递双浮点参数的编译器)。
  • 如果您的方法返回 void 并通过引用或指针传递值,则不会。

标签: c++ assembly compiler-construction x86


【解决方案1】:

这都是特定于调用约定的。

对于大多数调用约定,浮点数在 FPU 堆栈或 XMM 寄存器中返回。

调用返回结构的函数

    some_struct foo(int arg1, int arg2);
    some_struct s = foo(1, 2);

将被编译成一些等价的:

    some_struct* foo(some_struct* ret_val, int arg1, int arg2);
    some_struct s; // constructor isn't called
    foo(&s, 1, 2); // constructor will be called in foo

编辑:(添加信息)

澄清一下:即使sizeof(some_struct) <= 4,这也适用于所有结构和类。因此,如果您使用唯一的unsigned 字段和一些构造函数/转换器来定义像ip4_type 这样的小有用类unsignedin_addrchar*,与使用原始unigned 值相比,它将缺乏效率.

【讨论】:

  • 补充:64 位值 afaik 在 x86 上的 edx:eax 中返回
  • @MarcovandeVoort 是的,你是对的,尽管它仅适用于整数值。
  • 好吧,对于 COMP 以外的整数值 :-)
【解决方案2】:

您正在询问有关 ABI(应用程序二进制接口)的问题。这取决于操作系统。你应该查一下。你可以在http://en.wikipedia.org/wiki/X86_calling_conventions找到一些有用的信息和其他文档的链接

要回答你的问题,是的,据我所知,所有流行的操作系统都使用 A 寄存器来返回结果。

【讨论】:

  • MS Windows32 约定不在 EAX 中传递参数:标准 CDECL 调用堆栈中的推送参数; fastcall 的第一个参数在 ECX 中。哦,你的意思是流行的操作系统,不像Windows :-}
  • 为了完整起见:Windows 上的 Borland 编译器使用 eax 作为 __fastcall 的第一个参数;)
  • 我喜欢这个答案,因为它命名了上下文,提供了一个可搜索的词,以防有人想进一步定位自己。
【解决方案3】:

这实际上取决于使用的调用约定,但通常EAX 用于 32 位和更小的整数数据类型,浮点值倾向于使用 FPU 或 MMX 寄存器,而 64 位整数类型倾向于使用EAXEDX 的组合。然后是复杂类/结构类型的问题,在这种情况下,编译器可能会决定优化返回值并在调用堆栈上使用额外的输出参数通过引用将返回的对象传递给调用者。

【讨论】:

    【解决方案4】:

    如果函数被内联,结果不会保存在 eax 中,如果结果是通过引用/指针传递的,则不会使用该寄存器。

    看看返回双精度的函数会发生什么(在 32 位机器上)

    double func(){
        volatile double val=5.0;
        return val;
    }
    
    int main(){
        double val = func();
        return 0;
    }
    

    双打不在 eax 中。

    func():
        pushq   %rbp
        movq    %rsp, %rbp
        movabsq $4617315517961601024, %rax
        movq    %rax, -8(%rbp)
        movq    -8(%rbp), %rax
        movq    %rax, -24(%rbp)
        movsd   -24(%rbp), %xmm0
        popq    %rbp
        ret
    main:
        pushq   %rbp
        movq    %rsp, %rbp
        subq    $24, %rsp
        call    func()
        movsd   %xmm0, -24(%rbp)
        movq    -24(%rbp), %rax
        movq    %rax, -8(%rbp)
        movl    $0, %eax
        leave
        ret
    

    【讨论】:

    • 您的代码是 64 位,而不是 32 位。在 32 位 x86 上没有 rax、rbp、rsp...
    • 谁能帮我弄清楚为什么会发生这种情况:movq %rax, -8(%rbp) movq -8(%rbp), %rax movq %rax, -24(%rbp) movsd -24(%rbp), %xmm0func() 调用中(第 5 行到第 8 行)?
    猜你喜欢
    • 2013-08-14
    • 2013-02-11
    • 1970-01-01
    • 1970-01-01
    • 2017-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-13
    相关资源
    最近更新 更多