我试图减少原始问题(下面)中的混乱,但我担心这会让人难以理解。所以这里是原始来源以及IDA的反汇编。
我的问题仍然是:为什么getStruct()会弹出返回参数而只返回堆栈中的return参数? (它调用ret 4代替ret而不是参数,或者为所有三个参数调用12)。
#include <iostream>
struct SomeStruct {
char m_buff[0x1000];
};
SomeStruct getStruct(uint32_t someArg1, uint32_t someArg2)
{
return SomeStruct();
}
int main(int argc, const char * argv[])
{
SomeStruct myLocalStruct = getStruct(0x20,0x30);
return 0;
}
; _DWORD __stdcall getStruct(unsigned int, unsigned int)
public getStruct(unsigned int, unsigned int)
getStruct(unsigned int, unsigned int) proc near ; CODE XREF: _main+4Dp
var_8 = dword ptr -8
var_4 = dword ptr -4
arg_0 = dword ptr 8
arg_4 = dword ptr 0Ch
arg_8 = dword ptr 10h
push ebp
mov ebp, esp
sub esp, 18h
mov eax, [ebp+arg_8]
mov ecx, [ebp+arg_4]
mov edx, [ebp+arg_0]
mov [ebp+var_4], ecx
mov [ebp+var_8], eax
mov eax, esp
mov [eax], edx
mov dword ptr [eax+4], 1000h
call ___bzero
add esp, 18h
pop ebp
retn 4
getStruct(unsigned int, unsigned int) endp
; ---------------------------------------------------------------------------
align 10h
; =============== S U B R O U T I N E =======================================
; Attributes: bp-based frame
; int __cdecl main(int argc, const char **argv, const char **envp)
public _main
_main proc near
var_1020 = dword ptr -1020h
var_101C = dword ptr -101Ch
var_1018 = dword ptr -1018h
var_14 = dword ptr -14h
var_10 = dword ptr -10h
var_C = dword ptr -0Ch
argc = dword ptr 8
argv = dword ptr 0Ch
envp = dword ptr 10h
push ebp
mov ebp, esp
push edi
push esi
sub esp, 1030h
mov eax, [ebp+argv]
mov ecx, [ebp+argc]
lea edx, [ebp+var_1018]
mov esi, 20h
mov edi, 30h
mov [ebp+var_C], 0
mov [ebp+var_10], ecx
mov [ebp+var_14], eax
mov [esp], edx ; ptr to destination
mov dword ptr [esp+4], 20h ; unsigned int
mov dword ptr [esp+8], 30h
mov [ebp+var_101C], esi
mov [ebp+var_1020], edi
call getStruct(uint,uint)
sub esp, 4
mov eax, 0
add esp, 1030h
pop esi
pop edi
pop ebp
retn
_main endp
以下原始问题:
我有一些函数,声明如下:
SomeStruct getStruct(uint32_t someArg1, uint32_t someArg2);
正在调用getStruct:
myLocalStruct = getStruct(someArg1,someArg2);
在x86上使用clang编译时,调用代码看起来大致如下:
lea esi, [ebp-myLocalStructOffset]
mov [esp], esi
mov [esp+4], someArg1
mov [esp+8], someArg2
call getStruct;
sub esp, 4;
因此调用者在调用后恢复其堆栈指针。果然,getStruct的实现以ret 4结束,有效地弹出了结构指针。
这看起来部分是cdecl,调用者负责堆栈清理,并且部分stdcall与被调用者删除参数。我无法弄清楚这种方法的原因是什么。为什么不将所有清理工作留给来电者?这有什么好处吗?
答案 0 :(得分:2)
看起来好像忘记在引用的部分之上引用几行汇编程序。我假设有类似的东西:
sub esp,12
高于你引用的地方。调用约定看起来像纯stdcall
,并且返回值实际上是作为隐藏指针参数传递的,即代码实际上是编译,就像您声明了一样:
void __stdcall getStruct(SomeStruct *returnValue, uint32_t someArg1, uint32_t someArg2);