【发布时间】:2015-05-23 12:27:58
【问题描述】:
我在 Linux 上使用 AMD 64 位(我认为确切的架构并不重要),也是 64 位。用gcc编译到elf64。
我从 C ABI 中看到整数参数通过通用寄存器传递给函数,并且我可以在我的代码(被调用者)的汇编端找到值。当我需要将结果从被调用者检索到调用者时,就会出现问题。
据我所知,RAX 获取第一个整数返回值,我可以轻松找到并使用那个值。第二个整数 返回 值通过 RDX 传递。这就是让我困惑的地方。
我还可以从 C ABI 中看到,RDX 是用于将第三个整数函数参数从调用者传递给被调用者的寄存器,但我的函数不使用第三个参数。
如何从我的函数中取出 RDX?我是否必须在函数中伪造一个参数才能在调用方引用它?
定点乘法 16.16:
从 C 调用看起来像:
typedef long int Fixedpoint;
Fixedpoint _FixedMul(Fixedpoint v1, Fixedpoint v2);
这是函数本身:
_FixedMul:
push bp
mov bp, sp
; entering the function EDI contains v1, ESI contains v2. So:
mov eax, edi ; eax = v1
imul dword esi ; eax = v1 * v2
; at this point EDX contains the higher part of the
; imul moltiplication, EAX the lower one.
add eax, 8000h ; round by adding 2^(-17)
adc edx, 0 ; whole part of result is in DX
shr eax, 16 ; put the fractional part in AX
pop bp
ret
来自System V Application Binary Interface AMD64 Architecture Processor Supplement
返回值算法:
值的返回按照如下方式进行
- 使用分类算法对返回类型进行分类。
- 如果该类型具有类 MEMORY,则调用者为返回提供空间 值并在 %rdi 中传递此存储的地址,就好像它是第一个一样 函数的参数。实际上,这个地址变成了“隐藏”的第一个地址 牙龈。此存储不得与被调用方可见的任何数据重叠 此参数以外的其他名称。 返回时 %rax 将包含由 %rdi 中的调用者。
- 如果类是 INTEGER,则序列 %rax 的下一个可用寄存器, 使用了 %rdx。
我希望我的意思更清楚。
PS:对于我在 cmets 中造成的混乱,我深表歉意。感谢您的提示。
【问题讨论】:
-
只能返回 1 个结果,根据类型在
rax或xmm0或内存中。 -
你的英语绝对没问题。参数的传递方式取决于所采用的调用约定。实际返回值在
(E/R)AX中返回;但是,如果函数接收到一些指向“返回”更多值的指针,这些指针将作为普通参数传递(通常在堆栈上,在最常见的__stdcall和__cdecl中)。 -
我想我需要从x86-64.org/documentation/abi.pdf过去一个sn-p:
-
由于您正在尝试优化速度,请记住,在“普通”(Intel/AMD)x86 CPU 上,定点数学需要更多指令,足以使其比仅使用强大的硬件浮点。此外,在 amd64 上,您需要推送/弹出
rbp,而不仅仅是低 16 位!如果您没有将任何局部变量溢出到堆栈上的内存中,甚至不必通过保存rsp来创建堆栈帧。 -
另外,如果要进行 64 位乘法运算,请使用 64 位寄存器。那么你就不需要 add-with-cary 了。也许将您的其他函数分成两部分携带定点数据会更好。
标签: c assembly x86-64 calling-convention