如何返回复杂的返回值?

问题描述:

目前我正在编写一些汇编语言程序。正如一些约定所说的,当我想向调用者返回一些值时,比如说一个整数,我应该将它返回到EAX寄存器中。现在我想知道如果我想返回一个float,一个double,一个枚举或者一个复杂的结构。如何返回这些类型的值?如何返回复杂的返回值?

我可以考虑在EAX中返回一个指向内存中真实值的地址。但它是标准的方式吗?

非常感谢~~~

+2

如果你想知道“标准方式”,你需要指定你的平台。你使用什么硬件,操作系统和编译器? – 2010-09-13 19:04:00

+0

@StephenCanon当我发布这个问题时,我没有意识到这些是相关的。谢谢。 – smwikipedia 2016-09-20 05:36:26

如果调用者是您的代码,则完全取决于您。如果调用者不受您的控制,您必须遵循现有的惯例或共同制定您自己的惯例。

例如,在x86平台上,当FPU指令处理浮点运算时,函数的结果作为FPU寄存器堆栈中的最高值返回。 (如果你知道,x86 FPU寄存器被组织成各种类型的“循环堆栈”)。此时,它既不是float也不是double,它是一个以内部FPU精度存储的值(可能高于floatdouble),调用者有责任从FPU堆栈顶部检索该值并将其转换为任意值键入它的愿望。实际上,这就是典型的FPU指令的工作原理:它从FPU堆栈顶部获取参数,并将结果返回到FPU堆栈。通过以相同的方式实现你的功能,你基本上用你的功能模拟了一个“复杂的”FPU指令 - 这是一种非常自然的方式。

当通过SSE指令处理浮点运算时,您可以选择一些SSE寄存器用于相同目的(使用xmm0,就像整数使用EAX一样)。

对于复杂的结构(即大于寄存器或寄存器对的结构),调用者通常会将指针传递给函数的保留缓冲区。该函数会将结果放入缓冲区。换句话说,在底层,函数不会真的“返回”大对象,而是将它们构造在调用者提供的内存缓冲区中。

当然,您可以使用此“内存缓冲区”方法来返回任何类型的值,但使用较小的值(即标量类型值)时,使用寄存器比内存位置更有效。这也适用于小型结构。

枚举通常只是一些整数类型的概念包装。所以,返回一个枚举或一个整数没有区别。

通常,您将使用堆栈

+1

使用C ABI您使用堆栈。在C++中,它是未定义的,因此允许编译器制造商选择更有效的机制(如果他们想要的话)。 – 2010-09-13 16:15:06

如果你打算用C或其他高级语言接口,通常你会接受一个内存缓冲区的地址一个参数给你的函数,并通过填充该缓冲区来返回你的复杂值。如果这只是程序集,那么你可以使用你想要的任何寄存器来定义你自己的约定,但是如果你有特定的原因(例如性能),通常你只会这么做。

应将双精度值作为堆栈中的第一项返回。

这里是一个C++代码示例(X86):

double sqrt(double n) 
{ 
    _asm fld n 
    _asm fsqrt 
} 

如果希望手动管理堆栈(节省一些CPU周期):

double inline __declspec (naked) __fastcall sqrt(double n) 
{ 
    _asm fld qword ptr [esp+4] 
    _asm fsqrt 
    _asm ret 8 
} 

对于复杂类型,你应该通过一个指针,或返回一个指针。

+0

如果您说您还需要指定编译器(版本)和操作系统(使用版本),但您应该为编译器指定ABI文档。这是因为并非所有的C++编译器都这样做。所有的C编译器都会因为C ABI定义得很好。 – 2010-09-13 17:49:19

+0

对。它适用于Win32,VC++ 2008.但可能适用于所有VC版本。 – 2010-09-13 17:59:23

C99具有复杂的内置数据类型(_Complex)。所以,如果你有一个C99兼容的编译器,你可以编译一些函数来返回一个复合体并将其编译成汇编器(通常使用-S选项)。在那里你可以看到采取的惯例。

+0

也尝试'-save-temps'。 – 2010-09-14 04:06:34

当您对调用约定或汇编语言有任何疑问时,请用高级语言编写一个简单函数(在单独的文件中)。接下来,让您的编译器生成一个汇编语言列表或让您的调试器显示“交错组件”。

不仅列表会告诉您编译器如何实现代码,还会显示调用约定。比张贴到S.O更容易通常速度更快。 ;-)

这取决于ABI。例如,x86上的Linux使用Intel386 Architecture Processor Supplment, Fourth Edition中指定的Sys V ABI。

部分功能调用序列部分包含有关如何返回值的信息。简单地说,在这个API:

  • 函数返回标量或没有价值的使用%eax;
  • 返回浮点值的函数使用%st(0);
  • 对于返回structunion类型的函数,调用方为返回值提供空间并将其地址作为隐藏的第一个参数传递。被调用者在%eax中返回此地址。