通过寄存器而不是堆栈传递参数

逆向工程 数据库 海湾合作委员会 争论
2021-06-13 16:51:09

我正在学习(并重新学习)C 和汇编,我发现我所教的内容与我的实际结果之间存在差异。

一些代码:

int test(int a, int b){
  return a + b;
}

int main(){
  test(1,2);
}

如您所见,这是一个非常简单的示例,我试图在其中了解值是如何围绕函数传递的。

我被教导要将变量传递给函数,必须以相反的顺序将值推送到堆栈,然后才能使用基指针访问,例如(简化编写):

-- main
...
mov   [esp+8] 0x02
mov   [esp] 0x01
call  0x...  <test>
...

然后您可以使用以下命令直接从堆栈中取回这些值:

-- test
...
mov   esi [esp+8]
add   esi [esp]
mov   eax esi
...

我对此完全没问题(虽然我可能没有完全理解),但令我感到奇怪的是我在 gdb 中使用它时得到的实际结果:

$ gcc -g stack.c
$ gdb a.out

(gdb) disass main
Dump of assembler code for function main:
   0x0000000100000f70 <+0>:     push   rbp
   0x0000000100000f71 <+1>:     mov    rbp,rsp
   0x0000000100000f74 <+4>:     sub    rsp,0x10
-> 0x0000000100000f78 <+8>:     mov    edi,0x1
-> 0x0000000100000f7d <+13>:    mov    esi,0x2
   0x0000000100000f82 <+18>:    call   0x100000f50 <test>
   0x0000000100000f87 <+23>:    xor    esi,esi
   0x0000000100000f89 <+25>:    mov    DWORD PTR [rbp-0x4],eax
   0x0000000100000f8c <+28>:    mov    eax,esi
   0x0000000100000f8e <+30>:    add    rsp,0x10
   0x0000000100000f92 <+34>:    pop    rbp
   0x0000000100000f93 <+35>:    ret
End of assembler dump.
(gdb) disass test
Dump of assembler code for function test:
   0x0000000100000f50 <+0>:     push   rbp
   0x0000000100000f51 <+1>:     mov    rbp,rsp
-> 0x0000000100000f54 <+4>:     mov    DWORD PTR [rbp-0x4],edi
-> 0x0000000100000f57 <+7>:     mov    DWORD PTR [rbp-0x8],esi
   0x0000000100000f5a <+10>:    mov    esi,DWORD PTR [rbp-0x4]
   0x0000000100000f5d <+13>:    add    esi,DWORD PTR [rbp-0x8]
   0x0000000100000f60 <+16>:    mov    eax,esi
   0x0000000100000f62 <+18>:    pop    rbp
   0x0000000100000f63 <+19>:    ret
End of assembler dump.

在这里,不是直接使用堆栈,而是将我传递给函数的两个值test存储在寄存器esiedi(用 标记的相应行->)中。

这是我的设置:

$ gcc -v
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin14.5.0
Thread model: posix


$ gdb --version
GNU gdb (GDB) 7.11.1
...
This GDB was configured as "x86_64-apple-darwin14.5.0".
...

我的两个问题是:

  • 这种行为与我的设置有关吗?
  • 它在任何地方都有记录吗?
1个回答

这种行为是完全正常的。处理函数的方式通常在所谓的ABI(应用程序二进制接口)中进行描述。它定义了调用约定,详细说明了如何在汇编代码中进行调用以及如何使用特定寄存器将参数传递给函数。我会推荐Agner Fog 的 C++ Optimization Manual它包含有关 Linux、Windows 和 MacOS ABI 的非常有用的信息。