我正在使用AMD 64位(我认为它不是什么重要的架构)在Linux上,也是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,则调用者为返回提供空间 value并将该存储的地址传递给%rdi,就像它是第一个一样 函数的参数。实际上,这个地址变成了“隐藏的”第一个 gument。此存储不得与被叫方可见的任何数据重叠 除此论点之外的其他名称。 返回时,%rax将包含已传入的地址 来自%rdi的来电者。
- 如果类是INTEGER,则序列%rax的下一个可用寄存器, 使用%rdx。
醇>
我希望更清楚我的意思。
PS:很抱歉我在评论中提出了混淆。谢谢你的提示。
答案 0 :(得分:2)
AMD64 calling conventions (System V ABI)指定寄存器RDX的双重用途:它可以用于传递第三个参数(如果有),并且可以用作第二个返回寄存器。 (请参阅第21页的图3.4)
根据功能签名的不同,这些角色既可以用作这些角色,也可以不使用。
那为什么要有2个返回寄存器(即RAX和RDX)?这样一来,函数可以在通用寄存器(例如__int128
或具有两个8字节字段的struct
)中返回最多128位的值。
因此,要从C调用站点访问RDX寄存器,您只需要调整函数的签名即可。这意味着代替
typedef long int Fixedpoint;
Fixedpoint _FixedMul(Fixedpoint v1, Fixedpoint v2);
声明为:
typedef long int Fixedpoint;
struct Fixedpoint_Pair { // when used as return value:
Fixedpoint fst; // - passed in RAX
Fixedpoint snd; // - passed in RDX
};
typedef struct Fixedpoint_Pair Fixedpoint_Pair;
Fixedpoint_Pair _FixedMul(Fixedpoint v1, Fixedpoint v2);
然后您可以在C代码中像这样访问RDX:
Fixedpoint_Pair r = _FixedMul(a, b);
printf("RDX: %ld\n", r.snd);
参考:
如果聚合的大小超过一个八字节,则将每个分类 分别。每个八字节初始化为类NO_CLASS。
如果该类是INTEGER,则序列%rax的下一个可用寄存器, 使用了%rdx。
答案 1 :(得分:1)
你的英语绝对没问题。
如何传递参数取决于已采用的调用约定 - 两个最常见的约定__stdcall
和__cdecl
,使用堆栈传递所有参数,但例如{{1约定将使用前两个args的寄存器,而在x64中,它仍然不同。有关完整列表,请参阅here。
实际返回值在__fastcall
中返回;但是,如果该函数收到一些指向"返回"更多的值,这些指针将作为普通参数传递 - 如前所述,通常在堆栈上。