阿勒泰地区网站建设_网站建设公司_Java_seo优化
2026/1/9 18:46:30 网站建设 项目流程

1.系统库的准备

1.1 检查库

检查需要放入系统的系统库libxxx.so是否非TLS 64, 在命令行中输入:

/home/xxx/Android/Sdk/ndk/27.3.13750724/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-readelf -l libxxx.so | grep -A5 TLS

命令行输出:

TLS 0x12f0440 0x00000000012f1440 0x00000000012f1440 0x000000 0x000028 R 0x40 DYNAMIC 0x13777b8 0x00000000013787b8 0x00000000013787b8 0x0001c0 0x0001c0 RW 0x8 GNU_RELRO 0x12f1430 0x00000000012f2430 0x00000000012f2430 0x0a7280 0x0a7bd0 R 0x1 GNU_EH_FRAME 0x64b810 0x000000000064b810 0x000000000064b810 0x04526c 0x04526c R 0x4 GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x0 NOTE 0x0002a8 0x00000000000002a8 0x00000000000002a8 0x0000bc 0x0000bc R 0x4

可以看到第一行最后一列为: 0x40, 如果不为0x40, 则需要重新编译so。

另外一种方法是在将libxxx.so 库放到/system/lib64 目录下,然后运行如下命令:

adb shell ldd /system/lib64/libxxx.so # 检查依赖

如果输出如下:

linux-vdso.so.1 => [vdso] (0x7bc9149000) error: "linker64": executable's TLS segment is underaligned: alignment is 8, needs to be at least 64 for ARM64 Bionic Aborted

说明该库没有64位对齐, 需要重新编译so库

如果输出为:

linux-vdso.so.1 => [vdso] (0x78fca6c000) liblog.so => /system/lib64/liblog.so (0x78fb726000) libdl.so => /apex/com.android.runtime/lib64/bionic/libdl.so (0x78fa2a0000) libm.so => /apex/com.android.runtime/lib64/bionic/libm.so (0x78fb748000) libc.so => /apex/com.android.runtime/lib64/bionic/libc.so (0x78fa195000) libc++.so => /system/lib64/libc++.so (0x78fb786000)

则该库正常。

1.2 重新编译库

在libxxx.so 的任意C++文件中添加如下代码:注意只需要添加一次:

#if defined(__ANDROID__) && defined(__aarch64__) // 放在任意一个参与编译的 .cpp 文件中即可 extern "C" { __attribute__((visibility("default"))) __attribute__((aligned(64))) thread_local int _android_tls_alignment_fix = 0; } #endif

为了确保它能成功修复对齐问题,请注意以下几点:

1. 必须被链接进目标库

这个代码片段必须放在会被编译并链接进 librosa.so 的源文件中。你把它放在 rosa/RosaLinux.cc 是完美的,因为你的 CMakeLists.txt 中明确把这个文件编译进了 rosa 库。

2. 每个动态库(.so)只需要一个

链接器(linker)在生成 librosa.so 时,会扫描所有参与链接的 .o 文件(对象文件)。它会找到所有 thread_local 变量,并取其中最大的对齐值作为整个 PT_TLS 段的对齐属性。只要有一个地方定义了 alignas(64) 的 TLS 变量,整个库的 TLS 就会变成 64 字节对齐。不要在同一个库的多个源文件中放置同名的变量,否则会触发“重定义(multiple definition)”错误。

3. 不要放在 .h 头文件中

千万不要放在 .h 文件中(除非使用了 static 或 inline 修饰),原因有二:

如果头文件被多个 .cpp 包含,会导致重定义错误。如果头文件没被任何 .cpp 包含,代码就不会被编译,也就没法生效。

adb root adb remount # 确认是 lib64 还是 lib adb push librosa.so /system/lib64/ adb shell chmod 644 /system/lib64/libxxx.so # 恢复 SELinux 标签 adb shell restorecon /system/lib64/libxx.so adb reboot

4. 为什么这个代码能“隔空”生效?

你可能会奇怪:我只是在 RosaLinux.cc 里加了一个没被用到的变量,为什么能解决 spdlog 或其他代码里的错误?

物理结构决定:在一个 ELF 文件(.so)中,所有的线程本地变量(来自不同的 .cpp)最终都会被挤在同一个物理段(Segment)里,这个段叫 PT_TLS。

整体属性:PT_TLS 段作为一个整体,在文件头中只有一个“对齐(Alignment)”属性。链接器必须满足该段内要求最严格(对齐值最大)的那个变量。

木桶效应反转:这就像木桶效应的反面——只要有一块木板足够长,整个木桶的额定长度就会被标记为那个长度。

重新编译后,记得用 llvm-readelf -l librosa.so | grep TLS 确认最后那一列是否变成了 0x40。如果是,你的 adb shell ldd 报错就彻底解决了。

2. 将SO库设置为系统库

2.1 部署SO库

在命令行中依次输入如下命令:

adb root adb remount # 确认是 lib64 还是 lib adb push libxxx.so /system/lib64/ adb shell chmod 644 /system/lib64/libxxx.so # 恢复 SELinux 标签 adb shell restorecon /system/lib64/libxxx.so adb reboot

重启后,如果系统正常起来,说明设置成功。

2.2 如何正确测试库是否能加载?

如果你想验证这个库是否能被系统正确识别(且不再报 TLS 对齐错误),你应该使用 Android 链接器 来“追踪”加载过程,而不是直接运行它。

请在终端执行:

# 验证库的依赖和对齐是否通过 adb shell LD_TRACE_LOADED_OBJECTS=1 /system/bin/linker64 /system/lib64/libxxx.so

终端输出为:

Segmentation fault

3.公开系统库

通过 public.libraries.txt 公开(推荐系统开发者使用)

如果你希望这个库像 liblog.so 或 libc.so 一样,让所有 App 都能通过 System.loadLibrary 访问,确实需要在 public.libraries.txt 中添加它。

3.1 remount 系统

adb root adb remount

3.2 修改文件:

在 /system/etc/public.libraries.txt 的末尾添加一行

libxxx.so

注意(非常重要):

格式:只写库的文件名,不要写路径。

换行符:必须使用 Unix 格式的换行符(LF)。

末尾:确保最后一行后有一个换行符,且没有多余的空格或乱码。

3.3 SELinux 检查:

确保 /system/lib64/libxxx.so 的标签是正确的,否则 App 在加载时会报 Permission Denied:

adb shell restorecon /system/lib64/libxxx.so adb shell restorecon /system/etc/public.libraries.txt

3.4 重启系统:

adb reboot

修改该文件后必须重启,Android 的库管理服务才会重新加载配置。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询