libxxx.so- text relocations问题的终极解决方案

简介: 问题表现形式错误或警告日志当targetSdkVersion>=23且使用debug签名时,在6.0+的Android设备上运行App会输出以下错误Log:E/linker: /data/app/packagename/lib/arm/libxxx.

问题表现形式

错误或警告日志

当targetSdkVersion>=23且使用debug签名时,在6.0+的Android设备上运行App会输出以下错误Log:

E/linker: /data/app/packagename/lib/arm/libxxx.so: has text relocations 
W/System.err: java.lang.UnsatisfiedLinkError: dlopen failed: /data/app/packagename/lib/arm/libxxx.so: has text relocations

注意:当targetSdkVersion>=23,在低于6.0的设备上运行是正常的,至于原因,本文最后会谈到。

当targetSdkVersion<23且使用debug签名时,在6.0+的Android设备上虽然运行正常,但会输出以下警告Log:

W/linker: “/data/app/packagename/lib/arm/libxxx.so”: has W+E (writable and executable) load segments. This is a security risk shared libraries with W+E load segments will not be supported in a future Android release. Please fix the library.

W/linker: /data/app/packagename/lib/arm/libxxx.so has text relocations. This is wasting memory and prevents security hardening. Please fix.

App启动时弹出提醒对话框

当targetSdkVersion<23且使用debug签名的APK运行在高版本系统上(此处使用原生7.0测试),每次启动时会弹出一个对话框,其内容如下:

Detected problems with app native libraries (please consult log for detail) : libxxx.so: text relocations

上述各种表象可以发现是同一个问题所致,即libxxx.so: text relocations。

问题原因

“libxxx.so: text relocations”这个问题在Android 6.0官方的更新说明中有提及:

On previous versions of Android, if your app requested the system to load a shared library with text relocations, the system displayed a warning but still allowed the library to be loaded. Beginning in this release, the system rejects this library if your app’s target SDK version is 23 or higher. To help you detect if a library failed to load, your app should log the dlopen(3) failure, and include the problem description text that the dlerror(3) call returns. To learn more about handling text relocations, see this guide.

这个问题在6.0之前只会产生一个警告,系统还是可以正常加载包含text relocations的共享库的,但从6.0起,即SDK Version>=23时,系统将会拒绝加载包含text relocations的共享库,同时输出错误Log,也就是上文中看到的错误日志。

其实引起该问题的最根本原因,是so动态链接库的代码并非PIC(Position independent code),关于PIC的概念可以参考维基百科的介绍。在Android 6.0更新说明中,也只是简单提了一句处理方案:

To learn more about handling text relocations, see this guide.

该链接是一个解决text relocations (TEXTRELs)的指南。

解决方案

当你在网上搜索此问题时,会发现90%以上的搜索结果都告诉你把targetSdkVersion设为小于23。诚然,这样是可以回避掉上述问题,但只是治标不治本,并非终极方案。

如果App想使用6.0甚至7.0的新特性(前几天Android O开发者预览版已发布,此问题更是刻不容缓),就必须将targetSdkVersion提高至23或以上,所以这个问题必须彻底解决,决不能采用targetSdkVersion设为小于23的妥协方案。

真正的解决方案就是解决so动态链接库中的text relocations (TEXTRELs)问题。

修复源码中的text relocations

根据官方推荐的方案链接,会打开一个叫做“Hardened/Textrels Guide”的文档,这篇文档会指导大家解决text relocations问题。

我们大概看一下该文档的目录:

从文档目录可知我们可以先找到有text relocations问题的库,然后可以定位到源代码,从而修改源代码,彻底解决问题。

但是这篇指导文档学习成本较大,还需要安装特定工具,不太好操作。另外如果没有so动态库的源码,哪怕定位到了也无法修改。

编译时处理

在使用NDK编译so时配置Android.mk,增添PIC相关的配置项,这样编译出来的so文件将不再有text relocations的问题。具体配置如下:

LOCAL_LDFLAGS += -fPIC

PIC参数用于编译位置无关代码,生成可用于共享库的位置独立代码。若不添加-fPIC,则加载so文件的代码段时,代码段引用的数据对象需要重定位,重定位会修改代码段内容,这样就导致没使用这个so文件,代码段的进程在内核中就会生成这个文件的拷贝。

关于Android.mk的语法及配置,可参考官方文档。

实践建议

虽然有上述两种解决方案,但在实施中也有一些要注意的地方,下面结合自我实践来总结一下:

  • 定位哪个so文件有text relocations问题

    除了上述“Hardened/Textrels Guide”文档中提到的查找方法,在Linux上,可以使用readelf命令行查看。示例如下:

    readelf -a path/to/yourlib.so | grep TEXTREL
    • 1

    如果上边的shell命令输出类似下面的内容,则说明这该so文件不是PIC,是有text relocations问题的。

    0x00000016 (TEXTREL)                    0x0
    • 1

    TEXTREL表示代码段重定位表地址,PIC的共享对象不会包含任何代码段重定位表。因此如果上述命令无任何输出,则该表示so文件没有问题。

    一个App中通常会有多个so文件,有自己编写的,也有第三方的,可以使用上述方法来确定这些so文件是否有text relocations问题。

    另外还可以参考Android changes for NDK developers的“Text Relocations (Enforced since API 23)”章节。

  • 没有so源码的情况

    有时我们的App中使用的是第三方so,如地图定位库、音频解码库等。一旦这些so文件有问题,而我们没有源码,那将无法解决。此种情况下如果想将targetSdkVersion升级到23及以上,只能另寻替代方案或者割舍涉及到的功能。

    我们在实践中遇到的是一个第三方音频解码库有问题,解决方案是使用原生多媒体API来替代。

    同时也建议在使用第三方so文件时,先做一次检查,看有无text relocations的问题。

  • 修改编译参数无效的情况

    例如so中某个功能直接引用了.s的汇编文件(无源文件),而刚好text relocations问题出在.s文件上,此时再使用-fPIC参数编译是无效的,问题无法解决,只能另寻可替代的实现。

话外篇

本文一开始留了一个问题:当targetSdkVersion=23且使用debug签名时,在6.0+的Android设备上运行报错,而在低于6.0的系统上却正常运行,这是为什么呢?

这里不作解答了,顺便再提几个问题吧,留给大家思考:

compileSdkVersion、minSdkVersion、targetSdkVersion的各自含义及它们之间的关系是什么呢?

Android设备本身还有一个系统版本,那么最终影响App运行效果的又是什么呢?是compileSdkVersion?是targetSdkVersion?还是手机本身版本?或者其他?

目录
相关文章
|
安全 测试技术 数据库
安全测试的最佳实践
安全测试的最佳实践
600 0
|
存储 Shell Linux
八、Linux Shell 脚本:变量与字符串
Shell脚本里的变量就像一个个贴着标签的“箱子”。装东西(赋值)时,=两边千万不能有空格。用单引号''装进去的东西会原封不动,用双引号""则会让里面的$变量先“变身”再装箱。默认箱子只能在当前“房间”(Shell进程)用,想让隔壁房间(子进程)也能看到,就得给箱子盖个export的“出口”戳。此外,Shell还自带了$?(上条命令的成绩单)和$1(别人递进来的第一个包裹)等许多特殊箱子,非常有用。
1123 2
|
SQL 关系型数据库 MySQL
MySQL数据库连接过多(Too many connections)错误处理策略
综上所述,“Too many connections”错误处理策略涉及从具体参数配置到代码层面再到系统与架构设计全方位考量与改进。每项措施都需根据具体环境进行定制化调整,并且在执行任何变更前建议先行测试评估可能带来影响。
2009 11
|
编解码 算法 前端开发
《多端统一的终极答案:X5内核增强版的渲染优化全解析》
跨端应用需求激增,腾讯X5内核增强版通过多线程渲染、智能策略与资源优化,解决跨平台兼容和性能问题。它支持硬件加速图形处理,确保高清流畅体验;建立设备数据库,适配多系统版本,推动行业标准化。X5内核为用户提供一致体验,助力开发者高效构建跨端应用,引领行业技术革新。
520 11
|
Android开发 iOS开发 开发者
App备案-iOS云管理式证书 Distribution Managed 公钥及证书SHA-1指纹的获取方法
App备案-iOS云管理式证书 Distribution Managed 公钥及证书SHA-1指纹的获取方法
1981 0
|
JSON Go 数据库
Golang微服务框架居然可以开发单体应用?—— Kratos单体架构实践
微服务框架也是可以用于开发单体架构(monolith architecture)的应用。并且,单体应用也是最小的、最原始的、最初的项目状态,经过渐进式的开发演进,单体应用能够逐步的演变成微服务架构,并且不断的细分服务粒度。微服务框架开发的单体架构应用,既然是一个最小化的实施,那么它只需要使用到微服务框架最小的技术,也就意味着它只需要用到微服务框架最少的知识点,拿它来学习微服务框架是极佳的。
2054 0
|
数据安全/隐私保护
App逆向百例|10|某App x-zse-96分析
App逆向百例|10|某App x-zse-96分析
1277 0
|
前端开发 API 数据安全/隐私保护
开箱即用的 GoWind Admin|风行,企业级前后端一体中后台框架:前端权限控制
GoWind Admin(风行)是一款企业级前后端一体中后台框架,提供完善的前端权限控制体系。支持页面级与按钮级权限管控,涵盖后端动态路由、角色/权限码鉴权等核心功能,助力开发者快速构建安全、可扩展的管理系统。
819 0
|
机器学习/深度学习 人工智能 自然语言处理
深度学习之复杂推理与逻辑学习
基于深度学习的复杂推理与逻辑学习是当前人工智能领域中的一个前沿研究方向,旨在结合深度学习与传统逻辑推理的优势,使机器能够在处理复杂任务时具备更强的推理能力。
656 2
|
编译器 Linux C语言
ARM64上开启MTE
ARM64上开启MTE

热门文章

最新文章