How to set breakpoint on entry of dynamically opened shared library?

◇◆丶佛笑我妖孽 提交于 2020-06-29 04:58:25

问题


For some context, I'm inspecting a simple C++ program using the experimental transactional memory model, compiled with g++. I want to know exactly where register_tm_clones is called(you can see the fn by objdumping a simple program). This function will be called even in a program like int main() {}.

I want to know where in the whole scope of a general program where register_tm_clones is called. I set a breakpoint on it in GDB and I backtrace:

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 ?? ()

It's called when libgcc is opened by ld-linux at some point in the program. I make sure that we're linked with libgcc. Yup:

❯ 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)

But... How do I know when this is being called (It's definitely not in main)? I know _start is the true entry of the C++ program. and we run __libc_csu_init, and then there's some steps and we get to main. 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?


回答1:


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?

You already see that.

I think your confusion resides in not understanding what happens when a dynamically linked process runs. Roughly, the steps are:

  1. The kernel creates a new process "shell" and mmaps the executable into it.

  2. The kernel observes that the executable has PT_INTERP segment, and mmaps the file referenced there into the process as well. Here, the contents of PT_INTERP is /lib64/ld-linux-x86-64.so.2, aka dynamic loader, not to be confused with /usr/bin/ld (aka the static linker).

    Further, because there is a program interpreter, the kernel transfers control to it (instead of calling _start in the main executable), because the main executable is not ready to run yet.

  3. When ld-linux starts running, it first relocates itself, then mmaps all the libraries that the main executable directly linked against. You can see these libraries with readelf -d a.out | grep NEEDED.

    Note: since each of these libraries may itself direcly depend on other libraries, this process is repeated recursively.

  4. The libraries are initialized (by calling their constructor function, which is often called _init but can have different name as well) <== this is where libgcc_s.so.1 is initialized, and its register_tm_clones is called.

  5. Once all libraries are loaded and initialized, ld-linux finally calls _start in the main executable, which will eventually call main.



来源:https://stackoverflow.com/questions/61789860/how-to-set-breakpoint-on-entry-of-dynamically-opened-shared-library

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!