在这个简单的例子中,call 汇编指令做了什么?

What does call assembly instruction do in this simple example?

一个简单的c函数。

void sum ()
{
    return ;
}

命令

gcc -c -m32 -o simple simpleProg.c -O0 && objdump -d simple -M intel

simple:     file format elf32-i386


Disassembly of section .text:

00000000 <sum>:
   0:   f3 0f 1e fb             endbr32 
   4:   55                      push   ebp
   5:   89 e5                   mov    ebp,esp
   7:   e8 fc ff ff ff          call   8 <sum+0x8> --->This
   c:   05 01 00 00 00          add    eax,0x1
  11:   90                      nop
  12:   5d                      pop    ebp
  13:   c3                      ret    

call 8 语句在这里做什么? void 也需要 return 作为 eax 中的 0x01 吗?

您实际上是在查看代码 ,然后再对其应用 修正(通常在 link 阶段完成)。如果你添加 -r 来查看重定位条目,你会看到这个(我没有得到 endbr32 但这可能是因为我是 运行 一个较旧的编译器):

00000000 <sum>:
   0:   55                      push   ebp
   1:   89 e5                   mov    ebp,esp
   3:   e8 fc ff ff ff          call   4 <sum+0x4>
                        4: R_386_PC32   __x86.get_pc_thunk.ax
   8:   05 01 00 00 00          add    eax,0x1
                        9: R_386_GOTPC  _GLOBAL_OFFSET_TABLE_
   d:   90                      nop
   e:   5d                      pop    ebp
   f:   c3                      ret

Disassembly of section .text.__x86.get_pc_thunk.ax:

00000000 <__x86.get_pc_thunk.ax>:
   0:   8b 04 24                mov    eax,DWORD PTR [esp]
   3:   c3                      ret

在修复时,第 3 行实际上将被修改为调用 __x86.get_pc_thunk.ax(使用相对地址,因为 e8 是相对调用)。此函数有效地使用 return 地址(从第 8 行开始的字节)加载 eax

第 8 行也已修复,因此它不是添加一个,而是添加全局偏移量 table (GOT) "relative to PC" 地址。所以,毕竟,eax 包含全局偏移量的绝对地址 table,所以你可以从那里调用任何你想要的函数。


所以,最重要的是,它不是实际调用它看起来正在调用的地址。那将开始 运行 在指令中间编写代码,除非您知道自己在做什么,否则通常是一件坏事 :-)

它也没有专门用 return 代码加载 eax。它正在做的是准备能够从函数访问 GOT,尽管事实上它不会真正使用它。

相反,它会丢弃所有信息并退出,留下 eax 保留一些任意值,因为 void 函数不关心。如果您实际 调用 函数,例如 puts("Hello"),您会看到它使用此值来定位 puts 函数的正确地址。

几乎可以肯定的是,如果您提高优化级别,很多此类(不必要的)代码将会消失。

有关 GOT 的更深入概述(以及程序 linkage table,或 PLT),请参阅 this answer,由一些非常聪明和英俊的人发布几个月前:-)