如何在动态打开的共享库入口设置断点?
How to set breakpoint on entry of dynamically opened shared library?
在某些情况下,我正在使用实验性事务内存模型检查一个简单的 C++ 程序,该模型是用 g++ 编译的。我想确切地知道 register_tm_clones
在哪里被调用(您可以通过 objdumping 一个简单的程序来查看 fn)。即使在 int main() {}
.
这样的程序中也会调用此函数
我想知道调用 register_tm_clones
的一般程序的整个范围内的哪个位置。 我在 GDB 中设置了一个断点,然后回溯:
Breakpoint 1, 0x00007ffff7c5e6e0 in register_tm_clones () from /usr/lib/libgcc_s.so.1
(gdb) bt
#0 0x00007ffff7c5e6e0 in register_tm_clones () from /usr/lib/libgcc_s.so.1
#1 0x00007ffff7fe209a in call_init.part () from /lib64/ld-linux-x86-64.so.2
#2 0x00007ffff7fe21a1 in _dl_init () from /lib64/ld-linux-x86-64.so.2
#3 0x00007ffff7fd313a in _dl_start_user () from /lib64/ld-linux-x86-64.so.2
#4 0x0000000000000001 in ?? ()
#5 0x00007fffffffe390 in ?? ()
#6 0x0000000000000000 in ?? ()
当 libgcc
在程序的某个时刻被 ld-linux
打开时调用。我确保我们链接到 libgcc
。是的:
❯ ldd main
linux-vdso.so.1 (0x00007fff985e4000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f7eb82dc000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007f7eb8196000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007f7eb817c000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f7eb7fb6000)
/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007f7eb84ec000)
但是...我怎么知道什么时候调用它(肯定不在 main
中)?我知道_start
才是C++程序的真正入口。然后我们 运行 __libc_csu_init
,然后有一些步骤,我们进入主要。如何设置断点以查看 ld
何时决定打开 libgcc
,以及因此调用 register_tm_clones
的位置?
How can I set breakpoints to see in the grand picture to see when ld decided to open libgcc, and consequently where register_tm_clones is called?
你已经看到了。
我认为您的困惑在于不了解动态链接进程 运行 时会发生什么。大致步骤是:
内核创建一个新进程“shell”并将可执行文件mmap
放入其中。
内核观察到可执行文件有 PT_INTERP
段,并且 mmap
将那里引用的文件也添加到进程中。这里,PT_INTERP
的内容是 /lib64/ld-linux-x86-64.so.2
,又名动态加载器,不要与 /usr/bin/ld
(又名静态链接器)混淆。
更进一步,因为有程序解释器,内核将控制权交给了它(而不是在主可执行文件中调用_start
),因为主可执行文件是还没有准备好 运行。
当ld-linux
启动运行ning时,它首先重新定位自己,然后mmap
s all直接链接的主要可执行文件。您可以使用 readelf -d a.out | grep NEEDED
.
查看这些库
注意:由于这些库中的每一个本身都可能直接依赖于其他库,因此递归地重复此过程。
库被初始化(通过调用它们的构造函数,通常称为 _init
但也可以有不同的名称)<== 这是 libgcc_s.so.1
的位置初始化,它的 register_tm_clones
被调用。
加载并初始化所有库后,ld-linux
最终在主可执行文件中调用 _start
,最终将调用 main
.
在某些情况下,我正在使用实验性事务内存模型检查一个简单的 C++ 程序,该模型是用 g++ 编译的。我想确切地知道 register_tm_clones
在哪里被调用(您可以通过 objdumping 一个简单的程序来查看 fn)。即使在 int main() {}
.
我想知道调用 register_tm_clones
的一般程序的整个范围内的哪个位置。 我在 GDB 中设置了一个断点,然后回溯:
Breakpoint 1, 0x00007ffff7c5e6e0 in register_tm_clones () from /usr/lib/libgcc_s.so.1
(gdb) bt
#0 0x00007ffff7c5e6e0 in register_tm_clones () from /usr/lib/libgcc_s.so.1
#1 0x00007ffff7fe209a in call_init.part () from /lib64/ld-linux-x86-64.so.2
#2 0x00007ffff7fe21a1 in _dl_init () from /lib64/ld-linux-x86-64.so.2
#3 0x00007ffff7fd313a in _dl_start_user () from /lib64/ld-linux-x86-64.so.2
#4 0x0000000000000001 in ?? ()
#5 0x00007fffffffe390 in ?? ()
#6 0x0000000000000000 in ?? ()
当 libgcc
在程序的某个时刻被 ld-linux
打开时调用。我确保我们链接到 libgcc
。是的:
❯ ldd main
linux-vdso.so.1 (0x00007fff985e4000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f7eb82dc000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007f7eb8196000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007f7eb817c000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f7eb7fb6000)
/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007f7eb84ec000)
但是...我怎么知道什么时候调用它(肯定不在 main
中)?我知道_start
才是C++程序的真正入口。然后我们 运行 __libc_csu_init
,然后有一些步骤,我们进入主要。如何设置断点以查看 ld
何时决定打开 libgcc
,以及因此调用 register_tm_clones
的位置?
How can I set breakpoints to see in the grand picture to see when ld decided to open libgcc, and consequently where register_tm_clones is called?
你已经看到了。
我认为您的困惑在于不了解动态链接进程 运行 时会发生什么。大致步骤是:
内核创建一个新进程“shell”并将可执行文件
mmap
放入其中。内核观察到可执行文件有
PT_INTERP
段,并且mmap
将那里引用的文件也添加到进程中。这里,PT_INTERP
的内容是/lib64/ld-linux-x86-64.so.2
,又名动态加载器,不要与/usr/bin/ld
(又名静态链接器)混淆。更进一步,因为有程序解释器,内核将控制权交给了它(而不是在主可执行文件中调用
_start
),因为主可执行文件是还没有准备好 运行。当
查看这些库ld-linux
启动运行ning时,它首先重新定位自己,然后mmap
s all直接链接的主要可执行文件。您可以使用readelf -d a.out | grep NEEDED
.注意:由于这些库中的每一个本身都可能直接依赖于其他库,因此递归地重复此过程。
库被初始化(通过调用它们的构造函数,通常称为
_init
但也可以有不同的名称)<== 这是libgcc_s.so.1
的位置初始化,它的register_tm_clones
被调用。加载并初始化所有库后,
ld-linux
最终在主可执行文件中调用_start
,最终将调用main
.