news 2026/7/5 13:47:04

linux x_86_64动态链接,gdb理解link_map参数

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
linux x_86_64动态链接,gdb理解link_map参数

接着前面的动态链接文章继续聊哈。源程序ex1.c没变(参见前一次的文章)

在前面的文章中,对rela_arg还是有了些了解,但对_dl_runtime_resolve的link_map参数还没搞清楚,查了好多资料,终于对下面几个概念有了了解

1、link_map在main函数执行前就已经确定还是没确定。

答:执行前就已经确定了。

2、link_map的第一个节点是啥,第二个节点又是啥,第三个节点再是啥。。。

答:就我目前的了解,第一个节点是elf文件本身的起始地址。

第二个节点是“linux-vsdo.so.1”,虽然还不知道这个有啥作用。

第三个节点是“/usr/lib/x86)64-linux-gnu/libc.so.6“,这是共享库

第四个节点应该是/lib64/ld-linux-x86-64.so.2。这是动态链接器

上面2,3,4个节点你用ldd ex1,就清楚的显示出来了,后面我用gdb方式来理解。

你去查,问,几乎没有回答准确的,只有gdb方式一步一步调试,就明白了。

3、link_map的结构大家知道一下(可能每个glibc的版本不一样link_map的结构不一样,我的是glibc2.42)

struct link_map

{

ElfW(Addr) l_addr;//是指向加载模块的起始地址,加载libc.so.6就是libc.so.6的起始地址,加载linux-vsdo.so.1,就是这个模块的地址。

char *l_name; /*这里放着指向模块的绝对路径的字符串的地址,比较绕,这是一个地址,指向模块的名字*/

ElfW(Dyn) *l_ld; /*这是指向动态节的地址.*/

struct link_map *l_next, *l_prev; /*这是指向下一个模块的结构体和前一个模块的结构体初始地址,切记是地址*/

};

============================================

正式开始:gdb调试(我的环境是mac x86_64下使用模拟器的kali-linux6.5,属于debian-linux,下面具体的地址可能随着各位的系统不一样,具体显示的地址不一样,但思路是一样的。我也在mac m系列机器上下载了kali-linux,反汇编显示的代码和这里的也大不一样,大家仅借鉴思路,如不同,欢迎大家一起探讨)

gdb ex1 开始调试

b main //设置断点到main函数

run //运行到main处

si //进入main函数 rip=0x0000555555555154

si //rip = 0x0000555555555157 ,汇编代码call 0x555555555030<puts@plt>

si //rip= 0x0000555555555030,汇编代码jmp *0x2fca(%rip)#0x555555558000<puts@got.plt>这个地址以后存放真实的puts地址,目前是下一条指令地址

si //rip=。。。5036(前面一样,后四位写一下),汇编push $0x0, 就是rela_arg压栈

si //rip= 5036 汇编jmp 。。。5020,跳转到5020处,执行_dl_runtime_resolve定位函数,找到puts的真实地址,写到0x555555558000处。

si //rip = 5020,汇编push 0x2fca(%rip) #0x555555557ff0,将这个地址的值压栈,就是link_map的地址。

si //rip = 5026,汇编jmp *0x2fcc(%rip) #0x555555557ff8,跳转到这个地址存储的地址,执行_dl_runtime_resolve。

x/a 0x555555557ff0 // 我们先看一下,0x555555557ff0处的值是0x7ffff7ffe2f0,这就是link_map的起始地址。

x/a 0x7ffff7ffe2f0//显示的0x555555554000,这就是载入内存后地址重载的elf进程的起始地址。所以link_map的第一个节点就是elf文件载入进程后的起始地址。

si //再走一步,就会执行/lib64/ld-lijux-x86-64.so.2的_dl_runtime_resolve函数了

x/16x 0x7ffff7ffe2f0 //会显示如下

55554000 00005555f7ffe8c8 00007fff

55557de0 00005555f7ffe8d0 00007fff

.....(后面有许多)

我们看红色的,结合上面的link_map结构,红色的是l_addr,是0000555555554000,要反过来看,就是elf载入进程的起始地址。

蓝颜色的就是指向l_name的地址。这里elf进程是没有名字的,是“ ”,可以用x/s 00007ffff7ffe8c8去看一下。

紫色的是指向dynamic的地址,我们可以看到是000055555557de0,我们在elf的节头表中可以看到偏移地址是3de0,在进程中加上前面的进程起始地址555555554000,就是555555557de0,验证正确。

关键是第四个黑色的00007ffff7ffe8d0,这个就是link_map结构中的下一个模块的结构体起始地址。

x/16x 0x7ffff7ffe8d0

又出现了类似上面的一些数据

00007ffff7fc500000007ffff7fc5371

00007ffff7fc53e000007ffff7fbf170

其中7ffff7fc5371(蓝色)就是下一个模块的名字指向的地址

x/s 0x00007ffff7fc5371,见证奇迹的时候到了,显示“linux-vdso.so.1”

这就是第二个模块(或叫共享库)的名字,和ldd ex1显示的对上了。

接着就好办了,粉色的00007ffff7fbf170就是接下来一个模块的地址了,link_map结构体是一个链表模式。

x/16x 0x00007ffff7fbf170

又出现了一堆数据,

00007ffff7daf00000007ffff7fbf140

00007ffff7f95940 00007ffff7ffdda0

我们不看别的,就看红色的数据。这是第三个模块的名字的地址。

x/s 0x00007ffff7fbf140 “/usr/lib/x86_64-linux-gnu/libc.so.6"再次印证了ldd,完全正确。

==================================================

明白了l_name和l_next,其他也基本明白了,这些无聊的地址变换最终要找到属于我们的数据,在其中_dl_runtime_resolve 通过这两个参数,找到puts字符串,找到libc.so.6的完全路径,再通过dysym函数定位到puts函数真正的执行地址,就能显示了,有了真正地址,写入got.plt所在的地址,下次再调用就不用去_dl_runtime_resolve了。这就是动态链接。

这两天又问自己0x555555558000这个地址是哪里来的呢,汇编代码是

jmp *0x2fca(%rip),是当前地址的下一条地址+0x2fca,为啥呢?

其实在Elf文件的.rela.plt里,puts函数的offset是4000,载入进程后,加上其实地址0x5555555555554000,就是0x5555555555558000了,要获取puts的真实地址的地址早已确定了(有点绕哈),那么要从8000这个地址取到puts的真实地址,必须要当前地址的下一条加上某个值,才能到8000处,那就只能加0x2fca了。

那么又问自己.rela.plt里的4000又是哪里来的呢?

是gcc编译过程中产生的,其实应该是ld链接器产生的(gcc只是一个壳而已,调用了预处理,编译,汇编,链接等过程,还没学会),ld链接时根据每个节产生的数据数量,一步步产生data,dynamic,got.plt等等等等,可以看节头表,当一步步累加字节到.rela.plt节时,正好是4000(估计每个elf根据代码大小,符号多少会有不同),那就在.rela.plt的第一个条目puts处的offset,就是4000,第二个条目如exit函数,就是4008(以上是看了资料后自己猜或理解的,没有通过学习编译链接原理实践得知的)

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/5 13:46:24

树形 DP 入门:递归返回值要先想清楚

树形 DP 入门&#xff1a;递归返回值要先想清楚 一、树题难在状态方向 树形 DP 常让人头疼&#xff0c;不是因为代码一定很长&#xff0c;而是因为状态方向容易乱。一个节点要从子节点拿什么信息&#xff1f;返回给父节点什么&#xff1f;答案是在子树里更新&#xff0c;还是…

作者头像 李华
网站建设 2026/7/5 13:45:39

新版 OpenClaw Windows 安装包,图形化操作一看就会

OpenClaw&#xff08;小龙虾&#xff09;Windows 一键部署实操手册&#xff5c;十分钟搭建专属本地数字员工 适配平台&#xff1a;Windows 10/11&#xff08;64 位&#xff09;&#xff5c;零基础友好&#xff5c;全可视化界面&#xff5c;无编程门槛 当下热度较高的开源 AI 智…

作者头像 李华
网站建设 2026/7/5 13:45:30

SpringBoot集成智能GUI测试:AI视觉与语义理解提升自动化测试稳定性

1. 项目概述&#xff1a;当SpringBoot遇上智能GUI自动化测试最近在跟几个做企业级应用交付的朋友聊天&#xff0c;大家普遍头疼一个问题&#xff1a;后端API测试覆盖率都挺高了&#xff0c;但一到前端界面&#xff0c;尤其是那些复杂业务流程的GUI&#xff08;图形用户界面&…

作者头像 李华
网站建设 2026/7/5 13:44:08

问题六问:从认知到行动的思维框架

人机协作&#xff0c;仅供参考面对任何复杂事务&#xff0c;我们常因急于求解而陷入盲动。若能回归本源&#xff0c;对“问题”本身提出六个基本追问&#xff0c;便能构建一条从认知到行动的完整路径。这六个问题——它是什么、从哪来、要干嘛、能做啥、给谁做、何时做——并非…

作者头像 李华
网站建设 2026/7/5 13:38:13

WSL2 官方无损迁移教程

全程使用管理员 PowerShell执行&#xff1b;路径不要带中文、空格。 一、前期准备 1.查看 WSL 发行版名称 wsl -l -v输出示例&#xff1a; NAME STATE VERSION * Ubuntu Running 2记下 NAME&#xff08;本例&#xff1a;Ubuntu&#xff0…

作者头像 李华