helloworld
并使用objdump
进行了拆卸。开始时有
_init
:0000000000400600 <_init>:
400600: 48 83 ec 08 sub rsp,0x8
400604: 48 8b 05 ed 09 20 00 mov rax,QWORD PTR [rip+0x2009ed] # 600ff8 <_DYNAMIC+0x1e0>
40060b: 48 85 c0 test rax,rax
40060e: 74 05 je 400615 <_init+0x15>
400610: e8 1b 00 00 00 call 400630 <__gmon_start__@plt>
400615: 48 83 c4 08 add rsp,0x8
400619: c3 ret
是什么
_DYNAMIC
?使用
-x
我可以看到部分详细信息:Dynamic Section:
NEEDED libstdc++.so.6
NEEDED libc.so.6
INIT 0x0000000000400600
FINI 0x0000000000400864
INIT_ARRAY 0x0000000000600df8
INIT_ARRAYSZ 0x0000000000000010
FINI_ARRAY 0x0000000000600e08
FINI_ARRAYSZ 0x0000000000000008
GNU_HASH 0x0000000000400298
STRTAB 0x00000000004003c8
SYMTAB 0x00000000004002c0
STRSZ 0x000000000000011c
SYMENT 0x0000000000000018
DEBUG 0x0000000000000000
PLTGOT 0x0000000000601000
PLTRELSZ 0x0000000000000090
PLTREL 0x0000000000000007
JMPREL 0x0000000000400570
RELA 0x0000000000400540
RELASZ 0x0000000000000030
RELAENT 0x0000000000000018
VERNEED 0x0000000000400500
VERNEEDNUM 0x0000000000000002
VERSYM 0x00000000004004e4
但是,我不确定
rip+0x2009ed
指的是哪个条目。考虑下一行是对
gmon
的调用,它与GPROF
挂钩有关系吗?#1 楼
初始化代码使用此技巧来支持对其进行编译时的监视,并在不进行编译时将其忽略。当我使用
gcc -pg
编译小型测试程序时,然后调用objdump -Mintel -d
在它上面,我得到:00000000004004c0 <_init>:
4004c0: 48 83 ec 08 sub rsp,0x8
4004c4: 48 8d 05 c5 00 00 00 lea rax,[rip+0xc5] # 400590 <__gmon_start__>
4004cb: 48 85 c0 test rax,rax
4004ce: 74 05 je 4004d5 <_init+0x15>
4004d0: e8 bb 00 00 00 call 400590 <__gmon_start__>
4004d5: 48 83 c4 08 add rsp,0x8
4004d9: c3 ret
如果在编译时省略了
-pg
,它将变为:0000000000400418 <_init>:
400418: 48 83 ec 08 sub rsp,0x8
40041c: 48 8b 05 d5 0b 20 00 mov rax,QWORD PTR [rip+0x200bd5] # 600ff8 <_DYNAMIC+0x1d0>
400423: 48 85 c0 test rax,rax
400426: 74 05 je 40042d <_init+0x15>
400428: e8 43 00 00 00 call 400470 <__gmon_start__@plt>
40042d: 48 83 c4 08 add rsp,0x8
400431: c3 ret
因此,您看到在启用监视的情况下,代码在调用函数之前检查
__gmon_start__
是否不为null。在禁用监视的情况下,它将检查一些变量,如果该变量为0,则会跳过对__gmon_start__
的调用。但是请稍候。为什么在第一种情况下有一个
lea
,在第二种情况下有一个mov
?以及为什么名称以@plt
结尾?因为,即使您的程序没有编译性能分析,也许您的某些动态库也可以,并且您正在针对启用了性能分析的C版本运行图书馆。因此,C库可以提供
__gmon_start__
的动态版本,并提供标记来标记它是否这样做。此功能和标志在GOT和GOTPLT部分中定义。确实,如果您注意到所使用的地址
600FF8
,并从部分详细信息中向下滚动objdump -x
输出,您将请参见: 21 .got 00000008 0000000000600ff8 0000000000600ff8 00000ff8 2**3
CONTENTS, ALLOC, LOAD, DATA
22 .got.plt 00000038 0000000000601000 0000000000601000 00001000 2**3
CONTENTS, ALLOC, LOAD, DATA
您将看到代码访问GOT表条目(对于小型测试程序,该条目是GOT中唯一的条目,该条目这就是为什么GOT只有8个字节的大小。)