侧边栏壁纸
博主头像
noerror

虚灵不寐,众理具而万事出。

  • 累计撰写 239 篇文章
  • 累计创建 9 个标签
  • 累计收到 2 条评论
标签搜索

目 录CONTENT

文章目录

dlopen调试笔记

noerror
2022-09-17 / 0 评论 / 0 点赞 / 140 阅读 / 701 字 / 正在检测是否收录...

dlopen调试笔记

编译glibc

下载glibc源码:http://mirrors.aliyun.com/gnu/libc/

执行编译:

mkdir build
cd build
export CFLAGS="-g -ggdb -O1 -fno-omit-frame-pointer -Wno-maybe-uninitialized -Wno-format-overflow"
../configure --prefix=`pwd`/install
make -j
make install

编译测试程序

注意测试程序代码不能使用c写,会让程序链接libstdc.so,但没有基于自己编译的ld.so重新编译libstdc++.so,导致程序无法启动。

#include <stdio.h>
#include <sched.h>
#include <dlfcn.h>
#include <unistd.h>

void* OpenSo(const char *name, const char* info, int mode) {
    void* handle = dlopen(name, mode);
    if (handle == NULL) {
        printf("dlopen failed: %s", dlerror());
    }
    return handle;
}

int main(int, char**) {
    const char * soName = ("/home/tiny/Source/TestSo/build/libTestSo.so");
    OpenSo(soName, "in parent ", RTLD_LAZY | RTLD_LOCAL);
    pid_t pid = fork();
    if (pid == 0) {
        OpenSo(soName, "in child  ", RTLD_NOW | RTLD_GLOBAL);
    } else {
        OpenSo(soName, "in parent ", RTLD_NOW | RTLD_GLOBAL);
    }
}

修改程序链接选项,使用自己编译的glibc。注意ld.so需要修改linker,而不是直接链接它。

add_executable(TestDlopen main.c)
target_link_libraries(TestDlopen PUBLIC /home/tiny/Source/glibc-2.35/build/install/lib/libc.so.6 )
target_link_options(TestDlopen PUBLIC -Wl,-dynamic-linker=/home/tiny/Source/glibc-2.35/build/install/lib/ld-linux-x86-64.so.2)

gdb可视化调试glibc

在vscode中打开glibc的代码,调试时启动程序配置为测试程序TestDlopen

{
    // 使用 IntelliSense 了解相关属性。 
    // 悬停以查看现有属性的描述。
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(gdb) 启动",
            "type": "cppdbg",
            "request": "launch",
            "program": "/home/tiny/Source/TestDlopen/build/TestDlopen",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${fileDirname}",
            "environment": [{ "name": "LD_PRELOAD", "value": "/home/tiny/Source/glibc-2.35/build/install/lib/libc.so.6" }],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "为 gdb 启用整齐打印",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                },
                {
                    "description":  "将反汇编风格设置为 Intel",
                    "text": "-gdb-set disassembly-flavor intel",
                    "ignoreFailures": true
                }
            ]
        },
    ]
}

dlopen关键步骤

入口:

dlopen
___dlopen
dlopen_implementation
dlopen_doit
_dl_open
dl_open_worker

dl_open_worker中关键步骤

args->worker_continue = false;

__rtld_lock_lock_recursive (GL(dl_load_tls_lock));
dl_open_worker_begin
__rtld_lock_unlock_recursive (GL(dl_load_tls_lock));

if (!args->worker_continue) // 如果so已经加载过,就不会执行后面的流程
	return;
call_dl_init

dl_open_worker_begin中的关键步骤

_dl_map_object

/* It was already open.  */
if (__glibc_unlikely (new->l_searchlist.r_list != NULL))
{
  ...
  return;
}

_dl_map_object_deps

/* Only do lazy relocation if `LD_BIND_NOW' is not set.  */
int reloc_mode = mode & __RTLD_AUDIT;
if (GLRO(dl_lazy))
	reloc_mode |= mode & RTLD_LAZY;
	
_dl_relocate_object

args->worker_continue = true;

_dl_map_object中的关键步骤

{
	if (!_dl_name_match_p (name, l))
	{
		...
	}
	return l; // 已加载过就不再重复加载
}

_dl_map_object_from_fd
0

评论区