设为首页 收藏本站
查看: 1695|回复: 0

[经验分享] Mac系统下lipo, ar, nm等工具的使用简介

[复制链接]

尚未签到

发表于 2017-7-6 22:49:03 | 显示全部楼层 |阅读模式
引言
  开发第三方库时, 如果没有进行特殊处理, 很容易把其他第三方库的符号暴露出来, 导致链接时产生符号重复. 如下图所示
DSC0000.png

  如果用户链接了其他版本的libjpeg, 会因为入口地址不正确让程序直接崩溃
DSC0001.png

DSC0002.png

  本文就从这个问题入手, 简要介绍Mac OS X系统下几个常用二进制文件修改工具的使用
概述
  我们都知道, 代码到可执行文件需要经过编译(compile)和链接(link)两个主要步骤. 编译是把程序语言转换为机器指令, 这个不在本文的讨论范围.
  链接是把分块编译的对象文件(obj)合并成一个完整的程序, 主要解决函数入口重定向的问题. 其功能主要就是把所有的对象文件打个包, 生成一个导出符号表, 让其他程序可以知道本文件的结构.
  而对于苹果系统来说, 丰富的设备包含了多种架构平台, armv7, arm64, i386, x86_64是最常见的指令集, 一个程序库为了兼容各个平台, 常常要把不同平台编译的程序合并起来, 生成所谓的胖文件(Fat File), 这样子开发者就不需要专门准备一套真机版本库和模拟器版本库了(在早期, 很多第三方库确实是提供了不同版本的二进制文件来减少库文件大小).
  因此对于一个可执行文件, 其实包含了3层结构: Universal Fat File -> Single Architecture Binary File -> Mach-O Object.
  本文将要介绍的lipo, ar, nm, strip, ld等工具的功能就是对这三层结构进行转换和修改.
  本文以高德地图iOS SDK MAMapKit.framework 4.0.3为例, 演示如何从这个库文件里剔除暴露的png符号.
工具介绍
lipo
  lipo是管理Fat File的工具, 可以查看平台列表, 提取特定平台, 重新打包.
  首先运行 lipo -info MAMapKit
DSC0003.png

  可以看出这个文件包含了4个平台的代码. 接下来的所有操作都是要针对单一平台进行的, 因此先提取出来armv7平台,
  lipo -thin armv7 MAMapKit -output MAMapKit.armv7
DSC0004.png

  可以看出单平台的程序文件要小得多.
  接下来我们来查看一下这个文件的符号表
nm
  nm用来显示一个程序包的符号表, 默认会显示入口地址, 符号类型, 符号名.
nm -j MAMapKit.armv7  | grep png > symbols 可以获得所有的libpng导出符号, 存入到symbols文件, 为接下来的工作做准备. -j 选项控制只输出符号名.
strip
strip用来删除程序里的符号表. -R 用来指定一个要删除的符号列表, 使用上述生成的symbols文件. 添加 -S 选项来保留其他符号.
strip -S -R symbols MAMapKit.armv7 -o MAMapKit.armv7.strip
可以验证生成的新文件已经没有了png符号.
我们用这个方法应用到其他所有平台.
ar
我们用上述方法处理arm64时遇到了问题
DSC0005.png

这个文件里的一些符号用作了重定向入口, strip命令不允许删除, 这时就需要更强力的工具ld登场了. ld 其实苹果系统下的链接器, 可以更精确的控制符号表的导出.
ld的操作对象是obj, 因此我们需要先用到ar打包工具. ar可以查看一个程序包里的对象文件列表, 解压出其中的对象文件并重新打包.
ar -t MAMapKit.arm64
DSC0006.png

  可以看到整个包就包含了一个主对象文件.
  使用 -x 解压出来, 接下来就要轮到 ld 上场了.
ld
  本问题需要的ld功能和strip基本一致, 使用下述命令
ld -x -r -unexported_symbols_list symbols MAMapKit-arm64-master.o -o MAMapKit-arm64-master.o.strip
由此生成对象文件就剔除了png符号表
接下来要做的就是上述逆过程, 对象文件合并成程序文件
ar -r MAMapKit.arm64 MAMapKit-arm64-master.o.strip Pods-MAMapKit-dummy.o
最后是把各个平台的程序打包成Fat File即可.
  
终极大招
  2016-09-02 更新
  使用 Xcode 编译选项即可以完成上述任务!
  1. Perform Single-Object Prelink
  这个参数设置为 Yes
  这一步, 把所有的object文件合并成一个object文件, 相当于进行预编译
  这是最核心的操作, 因为该命令会触发Xcode调用 ld 命令
DSC0007.png

  2. Single-Object Prelink Flags
  这个参数设置 -unexported_symbols_list $(PROJECT_DIR)/symbol.txt
  这就相当于给 ld 命令传递参数, 正式我们上文提到的操作
  通过这两个选项的配置, 我们就在Xcode里设置好了符号删除的任务, 不用再在编译完成后手动删除.
  其他的一些参数, 比如 Strip Style, 可以根据需要手动决定, 因为删除后就不能再断点调试了!

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-391114-1-1.html 上篇帖子: mac地址、IP地址和端口号 下篇帖子: Mac 配置前端基本环境
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表