参数传递和返回值如何在x/86上的C/C ++中的程序集级别工作? [英] How does argument passing and returning values work in C/C++ on x86 at the assembly level?

查看:75
本文介绍了参数传递和返回值如何在x/86上的C/C ++中的程序集级别工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图找出如何在C/C ++中调用函数时传递该函数的参数以及如何在汇编级别上返回该函数的返回值.我找到了这些答案:

I'm trying to find out how, when calling a function in C/C++ the arguments to the function are passed and how the return value from the function is given back at the assembly level. I found these answers:

组装x86-调用C函数

参数传递如何工作?

表示堆栈用于在C/C ++中的函数之间传递参数.但是,当我编写一个简单的C ++测试程序并在radare2中对其进行反汇编时,它似乎并未使用堆栈将参数传递给该函数.而是将参数放在函数调用之前的 esi edi 中.

which say that the stack is used to pass arguments to and from functions in C/C++. However when I wrote a simple C++ test program and disassembled it in radare2, it did not appear to be using the stack to pass arguments to the function. Instead, the arguments were put in esi and edi before the function call.

尽管此站点上的答案将立即对您有所帮助,但非常感谢您链接到我可以了解更多信息的文档,即使适当的文档可能太技术性了,我也无法理解.

While an answer on this site will be more immediately helpful, a link to documentation where I could learn more would be greatly appreciated, even though proper documentation will probably be so technical it goes over my head.

测试C ++程序:

void foo(int a, int b) {
    return;
}

int main() {
    int a=5;
    foo(5,a);
    return 0;
}

radare2的反汇编程序:

The disassembled assembly from radare2:

┌ (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

提示此问题的是我试图解决的以下来自初学者的反汇编代码.

What prompted this question was the following disassembled code from a beginner crackme I am trying to solve.

我并不是在寻求帮助来解决这一难题,而只是帮助理解下面的示例中如何传递函数自变量以及将来可以在哪里进行查找.

I am not asking for help solving this crackme, just help understanding how function arguments are passed in the below examples and where I could go to look this up in the future.

下面的示例显示了被调用的sym.imp.puts(以下两个示例是手工输入的,因此尽管我确实尝试过校对,但它们可能包含错误):

The following example from the crackme shows sym.imp.puts being called (the following two examples are hand typed so they may contain mistakes, although I did try to proofread):

; CODE XREF from main @ 0x11f8
; 0x36915
; "Wrong key!"
lea rdi, str.Wrong_key
; int puts(const char *s)
call sym.imp.puts;[oo]

puts 似乎具有从 rdi 传递给 str.Wrong_key 的地址.

puts appears to have the address to str.Wrong_key passed to it from 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.

I am unable to understand what is going on in this code snippet. var_6ch is not used before this. Presumably scanf is being called like this: scanf("%d", var_6ch); But I fail to see how var_6ch or the %d string are passed to scanf.

以前的所有代码示例似乎都没有使用堆栈来传递参数,因此我们将不胜感激.

All of the previous code samples do not appear to use the stack to pass arguments so any and all help is appreciated.

推荐答案

在x86-64(这是您使用的体系结构)上,System V ABI调用约定是最常用的,并定义了以下寄存器以用于函数参数(按声明顺序):RDI,RSI,RDX,RCX,R8,R9,XMM0至XMM07.返回寄存器是RAX.

On x86-64 (which is the architecture you're on), the System V ABI calling convention is the most commonly used, and defines the following registers to be used for function parameters (in order of declaration): RDI, RSI, RDX, RCX, R8, R9, XMM0 to XMM07. The return register is RAX.

另一方面,在x86 32位上,由于寄存器较少,因此参数通常在堆栈上传递.

On the other side, on x86 32bit, since there are fewer registers, parameters are usually passed on the stack.

当然,调用约定不仅定义了如何传递参数,要了解更多信息,您可以看看

Of course a calling convention does not only define how to pass parameters, to know more you can take a look at the wikipedia page.

您在该代码段中看到的正是这样:

What you're seeing in that snippet of code is exactly this:

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

这篇关于参数传递和返回值如何在x/86上的C/C ++中的程序集级别工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆