动态库连接器–动态库链接信息(Mach-O文件格式和程序从加载到执行过程)
section cmd | 说明 | 举例 |
---|---|---|
__text | 主程序代码 | |
__stubs | 用于动态库链接的桩 | |
__stub_helper | 用于动态库链接的桩 | |
__cstring | 常亮字符串符号表描述信息,通过该区信息,可以获得常亮字符串符号表地址 | |
__unwind_info | 这里字段不是太理解啥意思,希望大家指点下 |
动态库连接器–动态库链接信息
总结了mach-o文件的两个最重要的部分,那么动态库根据加载命令如何动态链接到内存中的呢?下面总结这个动态过程。
- 系统通过加载命令,获得动态加载器的地址/usr/lib/dyly(其解决的问题是,把代码段__TEXT中和动态库相关内容进行关联,比如代码中如何调用到哪个动态库的相关代码段的偏移地址)
(dyly是用户态进程,这个是开源的,不属于kern内核的部分)感兴趣可以看看这里
总结下:在加载命令中,和动态库和链接相关命令有如下几个:
- 段命令
- LC_DYLD_INFO_ONLY
- LC_LOAD_DYLIB
- LC_LOAD_DYLINKER
- LC_SYMTAB
- LC_DYSYMTAB
- 区命令
- __stubs
- __stubs_helper
在进行动态链接器工作前,要先解析相关工作环境参数
- LC_LOAD_DYLINKER 获得动态加载器地址
- LC_LOAD_DYLIB 二进制文件依赖动态库信息
可以使用otool工具,读取该部分信息
代码5.0
yingfang:mach-o文件结构-src fangying$ otool -L a.out
a.out:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1225.1.1)
- LC_DYLD_INFO_ONLY 动态库信息,根据该命令是真正动态库绑定,地址重定向重要的信息。
结合之前otool -l的信息中的command 4命令,下面struct就是该命令对应的数据结构:
代码5.1
struct dyld_info_command {
uint32_t cmd; /* LC_DYLD_INFO or LC_DYLD_INFO_ONLY */
uint32_t cmdsize; /* sizeof(struct dyld_info_command) */
uint32_t rebase_off;
uint32_t rebase_size;
uint32_t bind_off;
uint32_t bind_size;
uint32_t weak_bind_off;
uint32_t weak_bind_size;
uint32_t lazy_bind_off;
uint32_t lazy_bind_size;
uint32_t export_off;
uint32_t export_size;
};
根据该加载命令的字段偏移,系统可以得到压缩动态数据信息区(dymanic load info)。根据上述数据,dymanic load info数据区,主要包含了5种数据:
(下面的一些内容,我的理解可能不是太正确,希望和大家一起讨论)dyld_info_command具体定义地址
dymanic load info | 说明 | 举例 |
---|---|---|
重定向数据 rebase | demo中该段数据位 11 22 10 51 | 11: 高位0x10表示设置立即数类型,低位0x01表示立即数类型为指针 22: 表示REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB + 2 重定向到数据段2。结合上面的信息,就是重定向到数据段2,该段数据信息为一个指针 结合数据段2的数据,获得一个重定向符号指针[0x100001010 -> _printf] |
绑定数据 bind | 在demo中进行动态绑定依赖的dyld的函数 | U dyld_stub_binder |
弱绑定数据 weak bind | 用于弱绑定动态库,就像weak_framework一样 | |
懒绑定数据 lazy bind | 对于需要从动态库加载的函数符号 | demo中有两个: U _printf U _scanf |
export数据 | 用于对外开放的函数 | demo中只有两个 0000000100000000 T __mh_execute_header 0000000100000f50 T _main |
对于相关的绑定函数查找,可以使用nm命令
代码5.2
yingfang:mach-o文件结构-src fangying$ nm a.out
0000000100000000 T __mh_execute_header
0000000100000f50 T _main
U _printf
U dyld_stub_binder
>
标注:dymanic load info数据是以命令码(命令码就是一个字节码)的形式,传递具体内容。高四位表示真正命令名,低四位表示一个立即数。00表示该类型命令结束
可以使用dylyinfo获得这部分信息读取
代码5.3
yingfang:mach-o文件结构-src fangying$ xcrun dyldinfo -opcodes a.out
rebase opcodes:
0x0000 REBASE_OPCODE_SET_TYPE_IMM(1)
0x0001 REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(2, 0x00000010)
0x0003 REBASE_OPCODE_DO_REBASE_IMM_TIMES(1)
0x0004 REBASE_OPCODE_DONE()
binding opcodes:
0x0000 BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(1)
0x0001 BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x00, dyld_stub_binder)
0x0013 BIND_OPCODE_SET_TYPE_IMM(1)
0x0014 BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x02, 0x00000000)
0x0016 BIND_OPCODE_DO_BIND()
0x0017 BIND_OPCODE_DONE
no compressed weak binding info
lazy binding opcodes:
0x0000 BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x02, 0x00000010)
0x0002 BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(1)
0x0003 BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x00, _printf)
0x000C BIND_OPCODE_DO_BIND()
0x000D BIND_OPCODE_DONE
0x000E BIND_OPCODE_DONE
0x000F BIND_OPCODE_DONE
动态库链接器运行结果
上面总结,动态链接器相关信息(加载命令信息,加载命令偏移地址相关信息)。现在总结下动态链接器运行的结果是什么?如何使用相关动态链接信息,完成相关过程的?
从字面上,之前我理解,链接器就是把文本段原来动态库函数相关地址,用真实的动态库地址替换,生成一个真实的完整的可执行文本。比如demo中printf是其它动态库的,但是其真实地址对于可执行文件是不知道,只有这个执行文件运行时,通过动态链接器完善其原来文本段地址。
在总结之前两个问题前,先总结下__stubs(桩)的区概念:该区存放的是二进制文件中未定义符号的占位符,编译器生成代码时会创建对符号桩区的调用,链接器在运行时解决对桩的这些调用。链接器解决方案是在被调用的地址处,放置一条JMP指令。JMP指令将控制权转交给真实的函数体。
回顾下nm命令结果:U表示未定义的符号
yingfang:mach-o文件结构-src fangying$ nm a.out
0000000100000000 T __mh_execute_header
0000000100000f50 T _main
U _printf
U dyld_stub_binder
看下demo中main函数汇编代码:
- demo中真实的print函数调用,编译器,编译为callq 0x100000f84 ## symbol stub for: _printf
- 汇编代码中,callq 0x100000f84 . 注意0x100000f84,这个地址是 __TEXT段的__stubs区的地址。换句话说,就是JMP到__stubs(桩区)– 段1 section位__stubs的起始地址
- 0x100000f84地址,是一段汇编指令 0x100000f84: jmpq *0x86(%rip) # 0x100001010
- 0x100001010地址,是指向(代码7.2)数据段__la_symbol_ptr区,由于这个数据都符号指针,查看下该地址指向的数据区域(代码7.3)
- 0x100001010地址指针,指向地址为4294971292(数据段都在高位,所以相比__TEXT地址,这个地址是正常的)
- 4294971292地址,执行汇编代码请看(代码7.4) 0x100000fa1: jmpq 0x100000f8c。请注意 0x100000f8c就是__TEXT段section __stub_helper区的起始地址。该地址是执行汇编代码具体请看(代码7.5)0x100000f95: jmpq *0x65(%rip) # 0x100001000
- 0x100001000地址,恰好是__DATA段, __nl_symbol_ptr区的其实地址,该地址指向的数据值位为 0x100001000: 0x0000000000000000 0x0000000000000000 (代码7.6)
>
总结:
+ __stubs区和__stub_helper区是帮助动态链接器找到指定数据段__nl_symbol_ptr区,二进制文件用0x0000000000000000进行占位,在运行时,系统根据dynamic loader info信息,把占位符换为调用dylib的dyld_stub_binder函数的汇编指令。
+ 当第一次调用完动态库中的符号后,动态链接器会根据dynamic loader info信息,把数据段__la_symbol_ptr指向正在的符号地址,而不是指向_nl_symbol_ptr区
http://blog.csdn.net/bjtufang/article/details/50628310
动态库连接器–动态库链接信息(Mach-O文件格式和程序从加载到执行过程)的更多相关文章
- 动态符号链接的细节 与 linux程序的加载过程
转: http://hi.baidu.com/clivestudio/item/4341015363058d3d32e0a952 值得玩味的一篇分析程序链接.装载.动态链接细节的好文档 导读: by ...
- JS 动态加载脚本 执行回调
JS 动态加载脚本 执行回调 关于在javascript里面加载其它的js文件的问题可能很多人都遇到过,但很多朋友可能并不知道怎么判断我们要加载的js文件是否加载完成,如果没有加载完成我们就调用文件 ...
- 浏览器环境下JavaScript脚本加载与执行探析之动态脚本与Ajax脚本注入
在<浏览器环境下JavaScript脚本加载与执行探析之defer与async特性>中,我们研究了延迟脚本(defer)和异步脚本(async)的执行时机.浏览器支持情况.浏览器bug以及 ...
- JS 动态加载脚本 执行回调_转
关于在javascript里面加载其它的js文件的问题可能很多人都遇到过,但很多朋友可能并不知道怎么判断我们要加载的js文件是否加载完成,如果没有加载完成我们就调用文件里面的函数是不会成功的.本文讲解 ...
- ASM:《X86汇编语言-从实模式到保护模式》第13章:保护模式下内核的加载,程序的动态加载和执行
★PART1:32位保护模式下内核简易模型 1. 内核的结构,功能和加载 每个内核的主引导程序都会有所不同,因为内核都会有不同的结构.有时候主引导程序的一些段和内核段是可以共用的(事实上加载完内核以后 ...
- 动态加载并执行Win32可执行程序
本文所贴出的PoC代码将告诉你如何通过CreateProcess创建一个傀儡进程(称之为可执行程序A),并把dwCreationFlags设置为CREATE_SUSPENDED,然后把另一个可执行程序 ...
- 小程序web-view加载H5信息不全
满足小程序的web-view标签跳转网页形式 配置小程序后台的web-view(业务域名) 可打开关联的公众号的文章 通常实现逻辑 页面加载的时候赋值于一个data对象的值,然后赋值到web-view ...
- Linux 静态库与共享库的使用
申明: 正如题如示,本篇讲的是Linux下是静态库与共享库,而Window下的动态链接库详细情况可见这篇文章:windows动态链接库 DLL 浅析.虽然原理,思想差不多,但是细节却各有不同. 一.静 ...
- 【转】Linux 静态库与共享库的使用
原文网址:http://blog.csdn.net/heyabo/article/details/11688517 申明: 正如题如示,本篇讲的是Linux下是静态库与共享库,而Window下的动态链 ...
随机推荐
- IOS - 绘制文字 drawInRect: withFont: not working
在图形绘制中,我们经常会需要绘制文本,但我在给PDF上绘制Text时,始终绘制不上, 使用过: [str drawInRect:cubeRect withAttributes:attrs]; CGCo ...
- java实现QQ空间模拟登录
import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import j ...
- 题解 ZOJ3203 Light Bulb
也就是loj上的#10016灯泡了... 先上原图: 因为长度肯定是个开口向下的二次函数,所以先是确定用三分来找位置,然后想办法求出当前阴影长度 看到这条斜线,就想到了一次函数,所以就建了一个系,没想 ...
- eclipse 去掉Eclipse打开后定期弹出Usage Data Upload对话框
Eclipse 的 UDC 老定期蹦出来说要上传使用数据到 eclipse 官网服务器去除方法: 1.删除 eclipse/plugins 目录下以 org.eclipse.epp.usagedata ...
- Google Spanner (中文版)
温馨提示:本论文由厦门大学计算机系林子雨翻译自英文论文,转载请注明出处,仅用于学习交流,请勿用于商业用途. [本文翻译的原始出处:厦门大学计算机系数据库实验室网站林子雨老师的云数据库技术资料专区htt ...
- nodejs-Sream
Stream 是一个抽象接口,Node 中有很多对象实现了这个接口.例如,对http 服务器发起请求的request 对象就是一个 Stream,还有stdout(标准输出). Node.js,Str ...
- failed to sync branch You might need to open a shell and debug the state of this repo.
failed to sync branch You might need to open a shell and debug the state of this repo. i made some c ...
- Hadoop使用Java进行文件修改删除操作
Hadoop使用Java进行文件修改删除操作 学习了:http://blog.csdn.net/menghuannvxia/article/details/44651061 学习了:http://bl ...
- HDU 4268 Alice and Bob(贪心+Multiset的应用)
题意: Alice和Bob有n个长方形,有长度和宽度,一个矩形能够覆盖还有一个矩形的条件的是,本身长度大于等于还有一个矩形,且宽度大于等于还有一个矩形.矩形不可旋转.问你Alice最多能覆盖Bo ...
- 通达OA 小飞鱼工作流在线培训教程(一)HTML基础介绍
应一些刚接触工作流设计朋友的要求,这里开设一个系列教程,对通达OA工作流设计相关的内容做个介绍.方便解决一些日常经常出现的问题,希望对刚刚接触这部分工作的朋友能够有些帮助. 工作流设计须要多方面的知识 ...