Colderleo's blog Colderleo's blog
首页
Linux
C++
Python
前端
工具软件
mysql
索引
关于
GitHub (opens new window)

Colder Leo

热爱代码的打工人
首页
Linux
C++
Python
前端
工具软件
mysql
索引
关于
GitHub (opens new window)
  • 常见程序性能开销cost、latency延迟耗时的经验值
  • 面试常见问题
  • 静态链接-动态链接-elf详解-elfloader
  • 动态库和静态库的依赖问题
  • glibc和ld的编译调试-为某程序单独设置ld
  • dl_iterate_phdr遍历linkmap头、获取so加载地址
  • shell、bash语法和脚本模板
  • so文件查找路径
  • 逻辑地址-线性地址or虚拟地址-物理地址
  • 通过ELF读取当前进程的符号表并获取符号的版本信息
  • 虚拟内存,cache,TLB,页表
  • 用户内存空间分布和mmap
  • numa网卡绑定
  • 隔核绑核、服务器优化
  • popen底层原理和仿照实现-execl
  • tmux用法
  • ASLR机制
  • 程序后台运行、恢复前台nohup
  • 大页内存huge_page
  • 用perf查看page-fault
  • Bash设置显示全部路径
  • 查看socket fd状态,设置nonblock
  • cout输出到屏幕的过程
  • 多进程写同一文件-write原子性-log日志
  • vim用法
  • epoll用法
  • signal信号、软中断、硬中断、alarm
  • 内核模块
  • 读写锁之pthread_rwlock和内核rwlock自旋读写锁
  • systemtap
  • xargs、awk用法
  • openssl libssl.so.10.so缺失问题
  • netstat用法
  • fork函数
  • tcp延迟确认ack
  • 90.centos7上一次std-string编译错误定位
  • docker用法
  • find用法
  • dmesg
  • gcc编译用法
  • avx-sse切换惩罚
  • Centos7防火墙
  • chmod用法
  • kernel-devel安装版本
  • Linux-Centos7系统安装、网络设置、常见报错
  • linux下g++编译c++文件
  • MegaCli 安装及使用
  • mysql
  • mysql忘记密码修改方法
  • set用法
  • crontab
  • ssh传文件scp
  • ssh连接
  • tcpdump、tshark、tcpreplay用法
  • ubantu root登录以及创建新用户
  • ubuntu安装g++和gdb
  • uClibc编译失败解决方法
  • win10安装WSL open-ssh
  • yum升级git
  • 比较so文件版本-md5sum
  • 查看磁盘信息
  • 合并两个硬盘,挂载到一个文件夹下
  • 软件安装目录usr-local-src
  • 下载centos历史版本
  • sh脚本转可执行文件、加密
  • Linux
gaoliu
2022-03-31

dliteratephdr遍历linkmap头、获取so加载地址

https://linux.die.net/man/3/dl_iterate_phdr (opens new window)

通过dl_iterate_phdr遍历so的linkmap,获取so加载地址

elf_utils.h

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <link.h>
#include <string.h>

/**
 * ref: 
 *    https://stackoverflow.com/questions/19451791/get-loaded-address-of-a-elf-binary-dlopen-is-not-working-as-expected
 *    https://linux.die.net/man/3/dl_iterate_phdr
 * 
**/

typedef struct CbData_t {
    char in_so_name[1024]; //input
    void *so_addr; //output
    size_t so_size; //output
}CbData;

extern "C" int __libc_csu_init(); //near 0x400920
extern "C" int __libc_start_main(); //__libc_start_main@GLIBC_2.2.5
extern "C" int _start(); //near 0x400610


// iterator all shared objects, or iterator unitl this callback return none 0
static int dl_iter_callback(struct dl_phdr_info *info, size_t size, void *data)
{
    CbData *cbdata = (CbData *)data;
    printf("======dl_iter_callback: %s @ %#lx\n", info->dlpi_name, (unsigned long)info->dlpi_addr);
    if(strstr(info->dlpi_name, cbdata->in_so_name)) {
        cbdata->so_addr = (char *)info->dlpi_addr;
    }

    int j;
    const char *main_addr = (const char *)&_start;
    const char *base = (const char *)info->dlpi_addr;
    const ElfW(Phdr) *first_load = NULL;

    for (j = 0; j < info->dlpi_phnum; j++) {
      const ElfW(Phdr) *phdr = &info->dlpi_phdr[j];

      if (phdr->p_type == PT_LOAD) {
        const char *begin = base + phdr->p_vaddr;
        const char *end = begin + phdr->p_memsz;

        printf("    in [%s] load %p->%p size=%ld\n", info->dlpi_name, begin, end, end-begin);

        if (first_load == NULL) first_load = phdr;
        if (begin <= main_addr && main_addr < end) {
          // Found PT_LOAD that "covers" callback().
          printf("    --main ELF header is at %p, image linked at 0x%zx, relocation: 0x%zx\n",
                base + first_load->p_vaddr, first_load->p_vaddr, info->dlpi_addr); 
                //elf_header=0x400000, image_link=0x400000, relocation: 0x0
          // return 0;
        }
      }
    }

    return 0;
}


// get so load addr. so_name should be smaller than 1024
__attribute__((visibility("default")))
void *get_so_addr(const char *so_name) {
    if(!so_name) return NULL;
    CbData cbdata;
    bzero(&cbdata, sizeof(CbData));
    strncpy(cbdata.in_so_name, so_name, sizeof(cbdata.so_addr));
    dl_iterate_phdr(&dl_iter_callback, &cbdata);
    if(cbdata.so_addr) {
        return cbdata.so_addr;
    }
    return nullptr;
}



int main(int argc, char *argv[])
{
    void *addr = get_so_addr("libc.so.6");
    printf("\nget addr of libc.so.6: %p\n", addr);

    addr = get_so_addr("libgcc");
    printf("\nget addr of libgcc: %p\n", addr);

    printf("main end\n");
    getchar();  //  cat /proc/`pgrep demo`/maps
    return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
编辑 (opens new window)
上次更新: 2022/05/03, 12:45:04
glibc和ld的编译调试-为某程序单独设置ld
shell、bash语法和脚本模板

← glibc和ld的编译调试-为某程序单独设置ld shell、bash语法和脚本模板→

最近更新
01
通过模板实现结构体成员拷贝-按成员名匹配
05-07
02
c++17通过模板获取类成员的个数
05-01
03
avx-sse切换惩罚
04-30
更多文章>
Theme by Vdoing | Copyright © 2019-2023 Colder Leo | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×