1 问题背景解读
编译环境一致,代码一致,环境变量一致,编译器版本一致,但是最终2个一致的环境编译出来的ELF文件,也就是XXX.so库正常应该一致。然而不一致。。。针对这2个ELF文件,通过readelf查看,仅build-id不同,但是其他的都是一样的,使用bcompare进行对比如下:
非常有趣的是 代码一致,编译时环境变量一致,编译器的版本,链接器的版本也一致,这么搞辖区都没有什么能查的了,但是问题要解决阿,毕竟交付合同要求MD5值必须一致。而且着急。
经过不断的探索和查资料,最后推断出应该是环境上有细微差别导致的,uname -a 查看下系统的版本如下:
#环境1
$uname -a
6.8.0-47-generic #47~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Wed Oct 4 16:16:55 UTC 2 x86_64 x86_64 x86_64 GNU/Linux
#环境2
$uname -a
6.8.0-48-generic #48~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Wed Oct 4 17:24:13 UTC 2 x86_64 x86_64 x86_64 GNU/Linux
这个问题直接解决似乎是不太可能了,毕竟重装系统,再重新安装各种软件和调试,代价过大。但是针对交付体系来说这个字段的变化会导致MD5值发生变化,进而影响商业的交付。
于是我们就想到,能否直接将这个build-id删除掉以保证MD5值一致呢?查了下资料发现是可行的,原理上很简单,就是在链接的时候添加"-Wl,--build-id=none" 这个链接选项禁止build-id的生成。
但是我们还是要对这个原理和是否满足交付需求。探讨之前我们先对build-id 标识进行解读:
ELF 文件中的 build-id 是一个在编译过程中生成的唯一标识符。build-id 是一个在 ELF 文件中存储的唯一的构建标识符,通常由编译器在编译过程中生成。它有点类似于文件的哈希值,用于标识特定的编译实例。build-id 的值被保存在 ELF 文件的 .note.gnu.build-id 段中,这是一个特殊的 ELF 段,用于存储构建相关的信息。
同时build-id 的设计目的主要有:
- 版本控制:build-id 可以用来判断两个 ELF 文件是否是同一版本的源码编译得到的,有助于版本控制和二进制文件的一致性检查。
- 调试和符号解析:在调试过程中,build-id 可以帮助调试器或符号服务器准确地识别出具体的二进制文件版本,尤其是在使用预编译的二进制或共享库时。
- 安全性:build-id 可以用于安全目的,比如在动态链接库中,确保加载的库是预期的版本,防止恶意替换。
由于版本控制内部有其他的字段便于查找,调试版本本身不做约束,安全性上有MD5做保障,可以考虑将build-id去掉。作出决定后,接下来看具体的修改方案。
2 build-id禁止生成的修改方案解读
2.1 Linux系统上的修改
一般针对linux系统的编译,主要使用如下方式,如果cmake的版本在3.13以下在CMakeList.txt中添加:
add_library(X SHARED source_file.cpp)
set_target_properties(${module} PROPERTIES LINK_FLAGS "-Wl,--build-id=none")
如果cmake版本在3.13以上,则在CMakeList.txt中添加:
target_link_options(myTarget PRIVATE "-Wl,--build-id=none")
2.2 Android系统上的修改
针对android系统,将 -DCMAKE_SHARED_LINKER_FLAGS
用于设置共享库的链接器标志。需要修改build.gradle即可,修改方式如下:
android {
...
defaultConfig {
...
externalNativeBuild {
cmake {
cppFlags ""
arguments "-DCMAKE_SHARED_LINKER_FLAGS=-Wl,--build-id=none"
}
}
}
}
3 效果呈现
使用readelf工具再次查看下build-id是否还存在。对比如下:
未做处理,lib库编译调整前,如下所示:
$readelf -n lib/arm64-v8a/XXX.so
Displaying notes found in: .note.android.ident
所有者 Data size Description
Android 0x00000084 NT_VERSION (版本)
description data: 1a 00 00 00 72 32 36 2d 63 61 6e 61 72 79 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Displaying notes found in: .note.gnu.build-id
所有者 Data size Description
GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring)
Build ID: 907f0648f3759fd2970655c1d5cbff119c17f196
做处理,lib库编译调整后,如下所示:
$readelf -n lib/arm64-v8a/XXX.so
Displaying notes found in: .note.android.ident
所有者 Data size Description
Android 0x00000084 NT_VERSION (版本)
description data: 1a 00 00 00 72 32 36 2d 63 61 6e 61 72 79 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
因为做了这样的处理,所以最终2个ELF的文件MD5值就变得一致了。