标签:
很多第三方库开发者工作敷衍, 技术不清(高德地图, 就是在说你), 不知道符号隐藏, 把一堆其他第三方库的符号暴露出来, 导致链接时产生符号重复. 如下图所示
一个地图库把整个libjepg的符号列表导出来了, 搞毛线. 更要命的是, 如果用户链接了其他版本的libjpeg, 会直接因为入口地址不正确让程序直接崩溃
这个问题找官方显然是无法解决的, 毕竟三个大版本了(2.4版本到4.0版本)完全没有改变的意思, 根本就不懂嘛. 求人不如求己, 本文就从这个问题入手, 简要介绍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是管理Fat File的工具, 可以查看平台列表, 提取特定平台, 重新打包.
首先运行 lipo -info MAMapKit
可以看出这个文件包含了4个平台的代码. 接下来的所有操作都是要针对单一平台进行的, 因此先提取出来armv7平台,
lipo -thin armv7 MAMapKit -output MAMapKit.armv7
可以看出单平台的程序文件要小得多.
接下来我们来查看一下这个文件的符号表
nm用来显示一个程序包的符号表, 默认会显示入口地址, 符号类型, 符号名.
nm -j MAMapKit.armv7 | grep png > symbols 可以获得所有的libpng导出符号, 存入到symbols文件, 为接下来的工作做准备. -j 选项控制只输出符号名.
strip用来删除程序里的符号表. -R 用来指定一个要删除的符号列表, 使用上述生成的symbols文件. 添加 -S 选项来保留其他符号.
strip -S -R symbols MAMapKit.armv7 -o MAMapKit.armv7.strip
可以验证生成的新文件已经没有了png符号.
我们用这个方法应用到其他所有平台.
我们用上述方法处理arm64时遇到了问题
这个文件里的一些符号用作了重定向入口, strip命令不允许删除, 这时就需要更强力的工具ld登场了. ld 其实苹果系统下的链接器, 可以更精确的控制符号表的导出.
ld的操作对象是obj, 因此我们需要先用到ar打包工具. ar可以查看一个程序包里的对象文件列表, 解压出其中的对象文件并重新打包.
ar -t MAMapKit.arm64
可以看到整个包就包含了一个主对象文件, 纳尼? 真是囫囵吞枣一把抓.
使用 -x 解压出来, 接下来就要轮到 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即可.
标签:
原文地址:http://www.cnblogs.com/dabaopku/p/5698186.html