lib/arm/libVoAACEncoder.so has text relocations问题的解决方案

  • 前言

这几天维护新公司的项目, 拿到项目看了一眼.心中千万个草泥马奔腾....这尼玛我那时候还在高考呢.. targetSdkVersion还是停留在19.既然来上班了.心里放心那些纠结,开始改吧.(心里很不请愿,但是为了生活我就忍下来..)首先进行6.0的权限适配,没有任何难度的完成..  7.0的文件共享,也没有问题.升级项目中用到的jar包(旧项目开发环境是eclipse)  那么重点来了部分jar在Android Studio中不存在.存在错误提示,如下:

File error accessing recents directory (directory doesn't exist?).
/lib/arm/libVoAACEncoder.so" has text relocations 
(https://android.googlesource.com/platform/bionic/+/master/android-changes-for-ndk-developers.md#Text-Relocations-Enforced-for-API-level-23)

注意:当targetSdkVersion>=23,在低于6.0的设备上运行是正常的 ,编译运行到os库的时候程序会莫名地闪退. '

'总结:上述各种表象可以发现是同一个问题所致,即lib/arm/libVoAACEncoder.so" has text relocations .

  • 问题原因

lib/arm/libVoAACEncoder.so" has 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)的指南。

  • 这里提供三种解决方案(我选择的第三种)

 一丶妥协方案

当你在网上搜索此问题时,会发现很多的搜索结果都告诉你把targetSdkVersion设为小于23。诚然,这样是可以回避掉上述问题,但只是治标不治本.而且目前来说9.0都出来还不能解决6.0的遗留问题,所以这个问题必须彻底解决,决不能采用targetSdkVersion设为小于23的妥协方案。

二丶谷歌给出的解决方案--文本重定位(针对API级别> = 23强制执行)

翻译原文如下:

从API 23开始,共享对象不得包含文本重定位。也就是说,代码必须按原样加载,不得修改。这种方法减少了加载时间并提高了安全性。

文本重定位的通常原因是非位置独立的手写汇编程序。这并不常见。使用我们文档中描述的scanelf工具进行进一步诊断:

$ scanelf -qT libTextRel.so
  libTextRel.so :(内存/数据?)[0x15E0E2] in(优化出来:上一个simd_broken_op1)[0x15E0E0]
  libTextRel.so :(内存/数据?)[0x15E3B2] in(优化出来:上一个simd_broken_op2)[0x15E3B0]
  ...

如果您没有可用的scanelf工具,则可以使用readelf进行基本检查,查找TEXTREL条目或TEXTREL标志。单独就足够了。(对应于TEXTREL条目的值是无关紧要的,通常为0 ---只是TEXTREL条目的存在声明.so包含文本重定位)。这个例子有两个指标:

$ readelf --dynamic libTextRel.so | grep TEXTREL
 0x00000016(TEXTREL)0x0
 0x0000001e(FLAGS)符号TEXTREL BIND_NOW

注意:技术上可以使用TEXTREL条目/标志来创建共享对象,但不需要任何实际的文本重定位。NDK不会发生这种情况,但如果您自己生成ELF文件,请确保您没有生成声称具有文本重定位的ELF文件,因为Android动态链接器信任条目/标志。

潜在问题:重定位强制代码页可写,并浪费地增加内存中脏页的数量。自Android K(API 19)以来,动态链接器已发出有关文本重定位的警告,但在API 23及更高版本上,它拒绝使用文本重定位加载代码。

解决方案:将汇编程序重写为独立位置,以确保不需要进行文本重定位。在Gentoo的Textrels引导有固定文本重的指令,以及更详细的scanelf文档。

说白了就是让你通过工具找到源码的错误,然后修改在编译使用.难点在于需要去学习

"“Hardened/Textrels Guide"这篇文档.目录传送门如下 (需科学上网)

Contents

 [hide] 

  • 1 Introduction
  • 2 Finding broken object code
    • 2.1 "False" Positives
  • 3 Dissecting broken object code
    • 3.1 Dissect libsmpeg
    • 3.2 Dissect libdv
    • 3.3 Dissect libSDL
  • 4 Finding the broken source code
    • 4.1 libsmpeg source dive
    • 4.2 libSDL source dive
  • 5 How to write PIC (in theory)
    • 5.1 Rules of thumb
    • 5.2 PIC registers by architecture
  • 6 Cookie cutter PIC fixes
    • 6.1 Don't use the PIC register
    • 6.2 MMX/SSE masks
    • 6.3 Let gcc worry about it
    • 6.4 Thunk it in assembly
  • 7 How to fix broken PIC (in practice)
    • 7.1 Fix libsmpeg
    • 7.2 Fix libSDL
  • 8 External resources

 全英文文档 结合工具即可完美解决text relocations问题的库,但是这篇指导文档学习成本较大,还需要安装特定工具,不太好操作。另外如果没有so动态库的源码,哪怕定位到了也无法修改。算了 我们再来看看第三种解决办法把. 很适合初学者来解决出现text relocations问题的库.

三丶重新编译so源文件

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

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

  • 记录编译so文件中出现的问题

NDK编译源文件的时候失败,出现

Android NDK: The armeabi ABI is no longer supported. Use armeabi-v7a.    
Android NDK: NDK Application 'local' targets unknown ABI(s): armeabi  

 ndk 版本不能用最新的,本人测试android-ndk-r15c可以,ndk版本18.1.5063045 rc1不支持armeabi,否则编译会出现上面错误

解决办法如下:找到源码的Application.mk移除 armeabi,移除后如下

APP_ABI := armeabi-v7a 
  • 结尾:

  • 遇到问题不要着急, 多尝试使用搜索引擎,多多了解android的发源地.他会提供给我们很多疑难问题的解决办法.
  • --致正在努力挣扎的Android程序员.

你可能感兴趣的:(积少成多,文本重定向,so,android,ndk)