在这个简单的例子中,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,由一些非常聪明和英俊的人发布几个月前:-)
一个简单的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,由一些非常聪明和英俊的人发布几个月前:-)