ELF(Executable and Linkable Format)是一种执行文件和可链接文件的格式。它是一种通用的二进制文件格式,用于在各种操作系统中存储可执行程序、共享库和内核模块。
Android 开发当中的 so 库本质上就是一种特殊类型的 ELF 文件,但在用途上它更专注于共享库的功能
so 库通常被设计为在程序运行时动态加载和链接,以提供代码、函数和数据等共享资源给其他程序使用。而可执行程序的 ELF 文件则是一个独立的程序,可以直接运行。因此,在使用方式和加载方式上有所不同,但它们都可以使用相同的 ELF 文件格式进行存储和组织。
readelf 是一个用于显示 ELF 文件的信息的工具,它可以显示 ELF 文件的各个部分的详细信息,例如头部信息、节(section)表、符号表、动态重定位表等。通过使用 readelf,开发者可以查看和分析 ELF 文件的结构和内容,以便了解和调试程序的执行过程。比如在进行 Native Hook 时,需要查看一个 so 库中的函数符号表,就可以使用这个工具进行查看。
在 Android 开发中,NDK 包中就已经包含了 readelf 工具了:
/AndroidSDK/ndk/21.0.6113669/toolchains/aarch64-linux-android-4.9/prebuilt/windows-x86_64/bin/aarch64-linux-android-readelf.exe
这是我电脑中 readelf 的路径,但我发现在 /toolchains/ 中有很多地方都有 readelf 文件且都能正常使用,把 readelf 配置一下环境变量就能正常使用了
使用命令来查看 so 库的节头表信息:
readelf -sW libxxx.so
libxxx.so 需要自行替换想要查看的 so库。但是把所有信息都输出到命令行实在是太多且难以查看,所以最好是输出到一个文件中方便我们来查找需要的信息:
readelf -sW libxxx.so > output.txt
这里我是把信息都输出到一个 txt 文件上了,然后在 txt 文件上直接搜索函数名就会出来对应的函数符号(因为函数符号是包含函数名的)
举个例子:
在 C++ 文件中创建一个函数 readelf_native_funtion:
通过一些列操作编译成 so 库(gradle 配置 + Cmake 配置 + mergeReleaseNativeLibs)
然后在 build/intermediates/merged_native_libs/ 找到自己编译好的 so 库,运行 readelf 后打开 txt 文件:
就可以查询到函数 readelf_native_funtion 对应的函数符号是 _Z22readelf_native_funtionv