参数传递和返回值如何在程序集级别的 x86 上的 C/C++ 中工作?
How does argument passing and returning values work in C/C++ on x86 at the assembly level?
我试图找出在 C/C++ 中调用函数时如何将参数传递给函数以及如何在程序集级别返回函数的返回值。 我找到了这些答案:
程序集 x86 - 调用 C 函数
参数传递如何工作?
它表示堆栈用于在 C/C++ 中将参数传入和传出函数。 然而,当我编写一个简单的C++测试程序并在 radare2 中对其进行反汇编时,它似乎没有使用堆栈将参数传递给函数。 相反,参数在函数调用之前放在esi
和edi
中。
虽然这个网站上的答案会更直接地有帮助,但一个指向我可以了解更多信息的文档链接将不胜感激,即使适当的文档可能非常技术性,以至于超出了我的头脑。
测试C++程序:
void foo(int a, int b) {
return;
}
int main() {
int a=5;
foo(5,a);
return 0;
}
从雷达2拆卸的组件:
┌ (fcn) main 37
│ int main (int argc, char **argv, char **envp);
│ ; var int32_t var_4h @ rbp-0x4
│ ; DATA XREF from entry0 @ 0x50d
│ 0x00000607 55 push rbp
│ 0x00000608 4889e5 mov rbp, rsp
│ 0x0000060b 4883ec10 sub rsp, 0x10
│ 0x0000060f c745fc050000. mov dword [var_4h], 5
│ 0x00000616 8b45fc mov eax, dword [var_4h]
│ 0x00000619 89c6 mov esi, eax
│ 0x0000061b bf05000000 mov edi, 5
│ 0x00000620 e8d5ffffff call sym foo(int, int) ; sym.foo_int__int
│ 0x00000625 b800000000 mov eax, 0
│ 0x0000062a c9 leave
└ 0x0000062b c3 ret
引发这个问题的是以下我正在尝试解决的初学者破解程序的反汇编代码。
我不是在寻求帮助解决这个难题,只是帮助理解在下面的示例中如何传递函数参数以及将来可以去哪里查找。
下面这个来自crackme的例子显示了被调用的sym.imp.puts(以下两个例子是手工打字的,所以它们可能包含错误,尽管我确实尝试过校对(:
; CODE XREF from main @ 0x11f8
; 0x36915
; "Wrong key!"
lea rdi, str.Wrong_key
; int puts(const char *s)
call sym.imp.puts;[oo]
puts
似乎有地址str.Wrong_key
从rdi
传递给它。
另一方面,这个代码片段:
lea rax, [var_6ch]
mov rsi, rax
; const char *format
; "%d"
lea rdi, [0x000368ff]
mov eax, 0
; int scanf(const char *format)
call sym.imp.__isoc99_scanf;[ob]
mov eax, dword [var_6ch]
cmp eax, 1
je 0x1228
我无法理解此代码片段中发生了什么。 在此之前不使用var_6ch
。 大概scanf
是这样称呼的:scanf("%d", var_6ch);
但我看不出var_6ch
或%d
字符串是如何传递给scanf的。
前面的所有代码示例似乎都没有使用堆栈来传递参数,因此非常感谢任何和所有帮助。
在x86-64(这是你所在的体系结构(上,System V ABI 调用约定是最常用的,它定义了以下用于函数参数的寄存器(按声明顺序(:RDI、RSI、RDX、RCX、R8、R9、XMM0 到 XMM07。返回寄存器是 RAX。
另一方面,在x86 32位上,由于寄存器较少,因此通常在堆栈上传递参数。
当然,调用约定不仅定义了如何传递参数,要了解更多信息,您可以查看维基百科页面。
你在这段代码中看到的正是这样的:
lea rax, [var_6ch] ; get the address of some variable
mov rsi, rax ; rsi = second parameter
; loads the variable's address into rsi
lea rdi, [0x000368ff] ; rdi = first parameter
; loads the address of the format string into rdi
mov eax, 0 ; clear eax
call sym.imp.__isoc99_scanf;[ob] ; call scanf(rdi, rsi)
mov eax, dword [var_6ch]
cmp eax, 1
je 0x1228
- Linux的Cpp上的计时器
- 在VS代码中交叉编译Windows与Linux上的MinGW的SDL程序
- 物理键盘上的触发器按键
- 如何加载(或映射)文件部分的最大大小,但适合在Windows上的RAM
- SSL上的`curl_easy_send`和`curl_asy_recv`:如何处理`CURLE_AGAIN`
- 如果由不同的线程写入 8 字节,那么现代英特尔 x86 上的 8 字节读取是否保证理智?
- std::atomic::fetch_add是x86-64上的串行化操作
- 参数传递和返回值如何在程序集级别的 x86 上的 C/C++ 中工作?
- x86 上的指针大小和奇怪的字符输出
- 在 x86 32 位上的静态类实例中解决此问题
- X86-64上的C :何时通过结构/类在寄存器中返回
- C++Mac上使用Linux库(x86_64-Apple-Darwin上的elf64-x86-64)
- 使用OpenMP的x86上的Atomic Minimum
- x86 上的 Android NDK 和 STL 相关参考错误
- x86 体系结构上的内存排序限制
- “std::memory_order_aquire”的语义是否需要x86/x8_64上的处理器指令
- 检测x86 Linux上的异常浮点操作
- x86(_64) 上的原子计数器和自旋锁的成本
- vc++ 2012在x86 Windows Xp机器上的远程调试
- 为什么使用GCC的x86上的整数溢出会导致无限循环