前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >黑暗料理第一道菜

黑暗料理第一道菜

作者头像
用户1907613
发布2018-07-20 15:17:29
3390
发布2018-07-20 15:17:29
举报

何晓杰,鄙司著名歌手、律师、段子手,兼首席开发者,号称小精灵终结者、黑暗料理之王。

前几天有读者给我留言,想让我讲讲NDK开发中的一些黑科技,可我是堂堂Google大食堂厨师学校出来的,压根没学过这些黑暗料理。所以,只能有请鄙司黑科技掌握者,给大家带来一系列NDK黑科技料理——简称『黑暗料理』。

今天要讲的第一道菜——『获取JNI库里的版本号』

--------------黑暗来临--------------

为毛会有这么个奇葩的话题

其实起因很简单,因为我们有一个项目是在 JNI 库里面写了版本号的,而且该版本号将会影响编译过程。

具体说来,就是 JNI 库太大,为了在编译项目时节省时间,只有当版本号发生变化时才进行 JNI 的编译,否则就只编译 APK 了。

听起来挺靠谱的,但是到了真正写编译脚本的时候,就懵逼了,这个版本号写进去容易,但是怎么读出来呢... 最终的目的是要比对版本号嘛...

分析

再次重新审视现状,版本号是作为全局静态变量被写在.cpp文件内,而事后该.cpp被编译进.so文件,变得不可读。

而我们的判断是要判断.cpp内的版本号,和.so内的版本号,若是不一致才进行编译,这个问题就变为了如何从一个 JNI 库内读取一个指定的静态变量的值。

到了这里其实答案已经出来了,我们必须借助objdump,用它来对.so进行逆向,获取内部的数据。由此写下一个命令:

恩,直接悲剧了,程序报错,提示格式不对。你要问为毛,原因是这个 JNI 库是 ARM 指令集的,所以就必须找到跨平台工具,即作用于 ARM 的 objdump命令。

幸运的是,我们并不需要走太远,NDK 内已经提供了这一工具,就拿 Mac 版的 NDK 来说,这一工具位于:

只需要使用这一工具即可,于是有了以下脚本代码:

命令的执行需要比较长的时间,取决于这个 JNI 库有多复杂。完成后会打印出一大堆东西,当然大部分内容我们不需要关心。

直接找到Disassembly of section .data这个部分,你会发现几乎所有的全局变量都在此处列出(说『几乎』是因为还有部分全局变量会放在section .rodata,决定这个的是变量的类型)。

好了,往下稍微翻一下,就能找到我们定义的版本号了,此处是:

此处的000000f1转换成 10 进制就是我们要的版本号了,至此分析完毕。

解决问题

既然已经通过分析得到了想要的结果,那么解决问题就变得无比简单了,请出 CodeTyphon 写一段小程序搞定之,废话不多直接上代码:

随便编译一下就成了,接着就可以欢乐的玩耍啦,命令很简单:

执行命令后打印出 241,这就是 JNI 库的版本号。

设置BINUTIL_HOME这个环境变量是为了跨平台,每个平台下可能配置的命令路径都不一样,不能写死

如果觉得每次都 export 很麻烦,可以直接将BINUTIL_HOME写进 .bash_profile 内,以后就无需再输入了。

如果你使用 Ubuntu 或是它的衍生版本,可以直接 apt 安装binutils-arm-linux-gnueabihf,这样无需安装 NDK,也可以执行这个命令了。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2016-08-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 群英传 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云开发 CloudBase
云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档