用GDB跟踪观察共享库函数的地址翻译过程

2023-10-27

用GDB跟踪观察共享库函数的地址翻译过程

用GDB观察共享库函数的翻译过程

研究了一下共享库函数是怎样加载到当前进程中的.开始共享库函数地址放在GOT中,
第一次调用时,ld将其翻译成函数在程序空间的真实地址.用GDB跟踪了一下整个过程,
记录在下面.  

PLT (Procedure Linkage Table) 和 GOT (Global Offset Table)背景,google.  
-------------------------------------------------------------------------------
### 准备 ### ### 环境Ubuntu 11.04 amd64, ### 安装libc debug symbol.
?
sudo apt-get install libc-dbg
### 安装libc6 source,假设目录是~/codes/debsrc/eglibc-2.13
?
sudo apt-get install build-essential
sudo apt-get source libc6
### 使用实验源文件http://files.cnblogs.com/dyno/plt.zip,
?
mkdir whatever; cd whatever; make
main.c  <---- 主程序
test.c  <---- 共享库
test.h
Makefile
foo & foo2是两个共享库中的函数,
?
[dyno@ubuntu:plt]$ objdump --syms main.exe | grep -E "(foo|xyz)"
0000000000000000       F *UND*  0000000000000000              foo2 <---- 1
0000000000000000       F *UND*  0000000000000000              foo  <---- 2
0000000000601028 g     O .bss   0000000000000004              xyz
 
[dyno@ubuntu:plt]$ readelf --sections --wide main.exe | grep got
   [22] .got              PROGBITS        0000000000600fe0 000fe0 000008 08  WA  0   0  8
   [23] .got.plt          PROGBITS        0000000000600fe8 000fe8 000030 08  WA  0   0  8
-------------------------------------------------------------------------------
### 实验 ###
?
export LD_LIBRARY_PATH=$PWD
gdb main.exe
 
(gdb) break main
(gdb) run
Breakpoint 1, main () at main.c:4
4       xyz = 100;
### 加载ld的符号表,(/usr/lib/debug/lib/*是libc6-dbg安装的debug symbol。)
### 注意 add-symbol-file的第三个参数,地址是如何得到的。
?
(gdb) info sharedlibrary
From                To                  Syms Read   Shared Object Library
0x00007ffff7ddcaf0  0x00007ffff7df5a66  Yes (*)     /lib64/ld-linux-x86-64.so.2
0x00007ffff7bda500  0x00007ffff7bda628  Yes         /home/dyno/codes/plt/libtest.so
0x00007ffff7864c00  0x00007ffff79817ec  Yes         /lib/x86_64-linux-gnu/libc.so.6
 
(gdb) add-symbol-file /usr/lib/debug/lib/x86_64-linux-gnu/ld-2.13.so 0x00007ffff7ddcaf0
(gdb) directory ~/codes/debsrc/eglibc-2.13/elf
(gdb) set disassemble-next-line on
### foo() 现在是 <foo@plt>
?
(gdb) disassemble main
Dump of assembler code for function main:
    0x0000000000400674 <+0>: push   %rbp
    0x0000000000400675 <+1>: mov    %rsp,%rbp
    0x0000000000400678 <+4>: movl   $0x64,0x2009a6(%rip)        # 0x601028 <xyz>
    0x0000000000400682 <+14>:  mov    $0x0,%eax
    0x0000000000400687 <+19>:  callq  0x400578 <foo@plt> <----
    0x000000000040068c <+24>:  mov    $0x0,%eax
    0x0000000000400691 <+29>:  callq  0x400578 <foo@plt>
...
 
(gdb) disassemble 0x400578
Dump of assembler code for function foo@plt:
    0x0000000000400578 <+0>: jmpq   *0x200a92(%rip)        # 0x601010 <_GLOBAL_OFFSET_TABLE_+40>
    0x000000000040057e <+6>: pushq  $0x2            <----
    0x0000000000400583 <+11>:  jmpq   0x400548  <----
End of assembler dump.
</foo@plt></foo@plt></xyz>
### pushq是什么?翻译函数所需要的参数,这个是第一个参数reloc_index,是函数foo在GOT中的偏移量。
### $rip里存了下一条指令,所以实际上将要执行顺序下一条指令
?
(gdb) p/x 0x40057e + 0x200a92
$3 = 0x601010
### 这就是PLT的精妙之处,第一次执行,转到哪里去了呢?
?
(gdb) disassemble 0x400548
No function contains specified address.
(gdb) x/5i 0x400548
    0x400548:    pushq  0x200aa2(%rip)        # 0x600ff0 <_GLOBAL_OFFSET_TABLE_+8>  <----
    0x40054e:    jmpq   *0x200aa4(%rip)       # 0x600ff8 <_GLOBAL_OFFSET_TABLE_+16> <----
    0x400554:    nopl   0x0(%rax)
    0x400558 <__libc_start_main@plt>:  jmpq   *0x200aa2(%rip)        # 0x601000 <_GLOBAL_OFFSET_TABLE_+24>
    0x40055e <__libc_start_main@plt+6>:    pushq  $0x0
### 又一个pushq, link_map .got.plt,是翻译需要的第二个参数。
### 再次jumpq,where?where?
?
(gdb) x/a 0x600ff8
0x600ff8 <_GLOBAL_OFFSET_TABLE_+16>:  0x7ffff7df0760
(gdb) info symbol 0x7ffff7df0760
_dl_runtime_resolve in section .text of /usr/lib/debug/lib/x86_64-linux-gnu/ld-2.13.so
### 看看_dl_runtime_resolve是怎么工作的...
?
(gdb) break _dl_runtime_resolve
(gdb) info breakpoints
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000400678 in main at main.c:4
     breakpoint already hit 1 time
2       breakpoint     keep y   0x00007ffff7df0760 ../sysdeps/x86_64/dl-trampoline.S:30
 
(gdb) si
0x0000000000400548 in ?? ()
=> 0x0000000000400548:    ff 35 a2 0a 20 00  pushq  0x200aa2(%rip)        # 0x600ff0 <_GLOBAL_OFFSET_TABLE_+8>
### 上面提到的第二个参数
?
(gdb) x/x 0x600ff0
0x600ff0 <_GLOBAL_OFFSET_TABLE_+8>: 0x00007ffff7ffe2e8
 
(gdb) list _dl_runtime_resolve
...
29  _dl_runtime_resolve:
30  subq $56,%rsp
31  cfi_adjust_cfa_offset(72) # Incorporate PLT
32  movq %rax,(%rsp)    # Preserve registers otherwise clobbered.
...
(gdb) list +
...
39  movq 64(%rsp), %rsi # Copy args pushed by PLT in register.
40  movq 56(%rsp), %rdi # %rdi: link_map, %rsi: reloc_index  <----前面提到的两个参数
41  call _dl_fixup      # Call resolver.
42  movq %rax, %r11     # Save return value      <----真正的共享库里函数地址
43  movq 48(%rsp), %r9  # Get register content back.
...
### 设置断点,看地址在GOT表中的变化
?
(gdb) info line _dl_runtime_resolve
Line 30 of "../sysdeps/x86_64/dl-trampoline.S" starts at address 0x7ffff7df0760 <_dl_runtime_resolve>
    and ends at 0x7ffff7df0764 <_dl_runtime_resolve+4>.
(gdb) break ../sysdeps/x86_64/dl-trampoline.S:40
Breakpoint 3 at 0x7ffff7df078b: file ../sysdeps/x86_64/dl-trampoline.S, line 40.
 
(gdb) c
(gdb) x/a 0x601010
0x601010 <_GLOBAL_OFFSET_TABLE_+40>:  0x40057e <foo@plt+6>  <---- _dl_fixup 之前
(gdb) ni
42  movq %rax, %r11     # Save return value
=> 0x00007ffff7df0795 <_dl_runtime_resolve+53>:     49 89 c3   mov    %rax,%r11
(gdb) x/a 0x601010
0x601010 <_GLOBAL_OFFSET_TABLE_+40>:  0x7ffff7bda5cc <foo>  <---- _dl_fixup 之后
</foo></foo@plt+6>
### 以后再次调用foo就直接到这里了。
-------------------------------------------------------------------------------
### 延伸阅读 ###

[1] Reversing the ELF Stepping with GDB during PLT uses and .GOT fixup
    http://packetstormsecurity.org/files/view/25642/elf-runtime-fixup.txt
[2] AMD64 Application Binary Interface (v 0.99)
    http://www.x86-64.org/documentation/abi.pdf
[3] PLT and GOT - the key to code sharing and dynamic libraries
    http://www.technovelty.org/linux/pltgot.html
[4] examining PLT/GOT structures
    http://althing.cs.dartmouth.edu/secref/resources/plt-got.txt
[5] Debugging with GDB
    http://sourceware.org/gdb/current/onlinedocs/gdb/
[6] 共享库函数调用原理
    http://blog.csdn.net/absurd/article/details/3169860
[7] How main() is executed on Linux 
    http://linuxgazette.net/issue84/hawk.html
[8] Gentle Introduction to x86-64 Assembly
    http://www.x86-64.org/documentation/assembly.html
标签:  gdbdebuggccLinuxpltgot
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

用GDB跟踪观察共享库函数的地址翻译过程 的相关文章

  • 浏览器网页被劫持

    你是否遇到过网页被劫持 正常打开却发现 这种情况能容忍吗 能忍但是没必要 首先打开浏览器网页被劫持不要慌 浏览器右键打开属性 你会发现目标 后面 这里多了一个网址 把它干掉你会发现 大无语事件发生了 好家伙 想直接干掉这个还没权限 右键属性
  • 桌面图标有蓝色阴影终极解决方法

    桌面图标有蓝色阴影 桌面图标背景出现蓝色阴影是怎么回事呢 通常情况下桌面图标变成蓝色背景是由于一些错误的设置而导致的 虽然它不影响系统的正常运行 但是看起来总是不舒服的 网上也有很多处理桌面图标背景出现蓝色阴影的方法 但大都不太全面 引起这
  • Android 手机影音 开发过程记录(四)

    前一篇已经将视频播放页面的布局弄好了 这一篇主要来处理播放页面的各种逻辑 播放 暂停 上 下一个视频 音量 进度 逻辑比较多 一点一点贴代码 顶部布局的逻辑 显示系统时间 时间是一秒一秒更新的 所以可以通过循环发消息的方法来更新系统时间 相
  • 离散对数密码学原理

    一 简介 离散对数被誉为当代密码学领域的三大基础之一 1976年 Diffifie和Hellman提出了一种密钥协商协议 产生了首个离散对数系统模型 8年后 ElGamal提出了基于离散对数系统的公钥加密和签名方法 并奠定了离散对数密码学基

随机推荐

  • 解决Visual Studio 2017启动后不显示窗体

    今晚启动VS等了很久都没有显示窗体 电脑也没有卡死的迹象 只是在任务栏里显示了图标 试了很多常规操作 检查兼容性的时候发现一个叫devenv exe的程序似乎是导致这个问题的原因 有趣的是我在Windows上看到了有人提交了这个问题 有的人
  • apache配置双向ssl认证(笔记)

    一 CA自签 Linux下先安装openssl 安装路径于 usr local openssl 1 修改openssl配置文件 etc pki tls openssl cnf 设置好 dir usr local openssl ssl mi
  • 随笔之---基于信号量实现,生产者与消费者模型

    Class BoundedBuffer mutex new Semaphore 1 hasBuffer new Semaphore n 有n个空buffer 用来装数据 hasData new Semaphore 0 记录有数据的buffe
  • Java导出压缩包zip文件

    需要导出一些图片和一个文本 一起放到zip压缩包中 GetMapping downloadZip public void downloadZip HttpServletResponse response throws IOException
  • 解决ffmpeg视频转码后视频清晰度下降的问题

    清晰度 Chrome不支持非h264编码的mp4视频播放 可通过ffmpeg将视频转码成h264编码 ffmpeg i input mp4 vcodec h264 b v 0 output mp4 注 如果不加参数 b v 0 会有精度损失
  • Flutter Text控件在不同手机上不居中的问题

    在最近flutter页面改造过程中 发现通过Contail包裹Text控件设置上下padding时 在华为魅族和vivo等手机上并没有居中展示 所以通过查看控件属性 得以解决此类问题 可以看到上面的在华为手机上明显偏下了 使用 Contai
  • 找出一批正整数中的最大偶数_c语言求一批正整数的奇数和-求奇数和输入一批正整数c语言程序-找出一批正整数中最大的偶数c语言...

    include stdio h int main int a 10 i j k printf 输入10个整数 n for i k 0 i lt 10 i scanf d a k for j 0 j if a k a j k k printf
  • [疯狂Java]面向对象:单例模式

    1 单例模式的应用 1 单例类就是指该类最多只能创建一个对象 不能创建超过一个的对象 2 这样做的原因 要么就是为了降低系统开销 要么这种类型的对象创建了多个没有任何意义 最多只需要一个就行 例如窗口管理器 假脱机打印设备 数据库引擎访问结
  • TCP传输过程详解——三次握手、四次挥手

    TCP 3 1 三次握手 重点 3 2 四次挥手 重点 3 3 通过序列号与确认应答提高可靠性 3 4 重发超时的确定 3 5 以段为单位发送数据 3 6 利用窗口控制提高速度 3 7 滑动窗口控制 3 8 窗口控制中的重发控制 TCP T
  • ICCV19 (Oral)

    点击上方 小白学视觉 选择加 星标 或 置顶 重磅干货 第一时间送达 本文作者 洪晓鹏 https zhuanlan zhihu com p 127956794 本文已由原作者授权 不得擅自二次转载 Zhiheng Ma Xing Wei
  • 苹果发布iOS16正式版,各机型升级建议

    文章目录 前言 升级注意事项 iOS 16增加了哪些功能 1 锁屏界面大改动 2 全新专注模式 3 查看Wi Fi密码 4面容ID横屏解锁 5 电量百分比 6 支持任天堂Switch手柄 7 键盘输入震动 8 隐藏相册支持加密 9 清理重复
  • Linux 信号(三) —— 强大的sigaction

    在Linux中 对于信号的收发有着两组函数 1 入门版 发送函数 int kill pid t pid int sig 接收函数 sighandler t signal int signum sighandler t handler 这组函
  • MyBatis进阶版

    本文有点难 目录 1 一些区分 1 1参数占位符 和 1 1 1SQL注入 1 1 2like查询 1 2resultType和resultMap 2 映射查询 2 1一对一表映射 2 2一对多表映射 3 动态SQL 3 1标签 3 2标签
  • esp32使用fft算法显示音乐频谱

    演示参考下方视频 源码链接在视频末尾获取 点击查看视频 介绍 本项目使用esp32s3 ifd4 2 声音传感器以及tft显示屏构成 使用快速傅里叶变换算法处理采集到的音频数据 fft处理后的数据使用lvgl显示在tft屏幕上 电路图 源码
  • SpringBoot MongoDB批量删除指定日期前的文件

    SpringBoot MongoDB批量删除指定日期前的文件 Query query new Query LocalDateTime localDateTime LocalDateTime of 2021 6 1 0 0 0 query a
  • 《动手学深度学习 Pytorch版》 2.1 数据操作

    2 1 1 数据操作 注意此处 import 的不是 pytorch 而是 torch Torch 是采用 lua 语言实现的 从某种程度上说 PyTorch 是 Torch 的 Python 版本 当然还是有部分差别的 import to
  • python学生分布_python统计函数库scipy.stats的用法解析

    背景 总结统计工作中几个常用用法在python统计函数库scipy stats的使用范例 正态分布 以正态分布的常见需求为例了解scipy stats的基本使用方法 1 生成服从指定分布的随机数 norm rvs通过loc和scale参数可
  • CDUA 图形学 Texture Reference 实验

    下面是对Texture Reference的实验 代码改自 CUDA C PROGRAMMING GUIDE PG 02829 001 v10 0 October 2018 p54 因为这里比较贴近计算机图形学 故移到图形学中去 版权所有
  • Java基础面试题一:请说说抽象类和接口的区别?

    1 抽象类实例 abstract class person public String name 可以有普通成员变量 public static String sex 可以有静态成员变量 public static void eat 可以有
  • 用GDB跟踪观察共享库函数的地址翻译过程

    用GDB跟踪观察共享库函数的地址翻译过程 用GDB观察共享库函数的翻译过程 研究了一下共享库函数是怎样加载到当前进程中的 开始共享库函数地址放在GOT中 第一次调用时 ld将其翻译成函数在程序空间的真实地址 用GDB跟踪了一下整个过程 记录