Skip to content

Latest commit

 

History

8 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

glibc-adaptor

gnu libc adapte library

编译说明

git clone https://github.com/openfde/glibc-adapter.git
cd glibc-adapter/
cmake -B build/debug -DCMAKE_BUILD_TYPE=Debug -GNinja -DCMAKE_ANDROID_NDK=ndk-dir
cmake --build build/debug

CMAKE_ANDROID_NDK指定ndk路径,默认为"~/Android/Sdk/ndk/25.2.9519653",指定的ndk版本建议与默认版本一致

版本发布时,需将CMAKE_BUILD_TYPE改为Release。

动态库路径为build/debug/src/libglibc-adapter.so,库名不能修改,bionic linker64使用libglibc-adapter.so名加载该库,搜索路径为Android默认的搜索路径,如:/system/lib64/, /vendor/lib64/等,建议放在/vendor/lib64/路径下。

开发说明

主功能说明

定义了两类接口,一类为linker调用接口(src/glibc-adapter.h),一类为适配注册接口(src/adapter-register.h)

所有实现代码在src/glibc-adapter.c文件中,实现的功能有:

  • 根据符号查找适配接口函数,采用二分查找法搜索符号
  • 适配接口按类别注册,一般建议按照标准C的头文件分类,如:stdio.h中接口的适配,定义stdio类别,在该类别中实现功能。最多支持8192个适配接口
  • 定义了日志函数接口,采用Android log记录日志,级别为ANDROID_LOG_DEBUG,tag名为"glibc-adapter"

注意事项

  • 该实现代码中不能包含动态内存分配,以及涉及动态内存分配的libc函数
  • 不能包含运行前的初始化代码,即调用函数初始化全局变量,否则会报错,主要原因linker调用接口会在初始化该库前被调用。可以通过查看动态库ELF文件是否包含.init或.init_array分节来确认

适配接口开发说明

注册基础接口

struct glibc_adapter_t { const char* symbol; void* adapt_fun; };
int register_adapters(const char* classes, const struct glibc_adapter_t* adapters, size_t adapter_count);

注册封装接口

#define ADAPTERS_SIZE(adapters) (sizeof(adapters) / sizeof(adapters[0]))
#define REGISTER_ADAPTER_ARRAY(classes, adapters) register_adapters(classes, (adapters), ADAPTERS_SIZE((adapters)))
#define REGISTER_ADAPTERS_BY_CLASS(classes) REGISTER_ADAPTER_ARRAY(#classes, classes ## _adapters)

只需调用REGISTER_ADAPTERS_BY_CLASS(classes)注册即可,不需要再显示调用注册函数,"classes"表示类别

接口适配封装

#define ADAPT_DIRECT(symbol) {#symbol, (void *)symbol}
#define ADAPT_INDIRECT(symbol) {#symbol, (void *)adapt_##symbol}

ADAPT_DIRECT(symbol) 表示符号转发,即gnu glibc符号功能由bionic libc对应符号功能代替

ADAPT_INDIRECT(symbol) 表示符号适配,即bionic需要适配才能满足gnu libc符号功能,如:gnu libc符号在bionic中不存在;gnu libc接口参数与bionic对应接口不匹配等。

开发者需要实现适配函数,该函数的命名规则为"adapt_"接上gnu libc符号名。

日志记录接口

int adapter_log(const char* format, ...);

开发者如果想跟踪适配函数的调用,可使用adaper_log记录内容

新增适配类别

  1. 新增类别需创建一个c文件,建议命名规则为"classes-adapter.c","classes"表示类别名称。建议每个C头文件定义一个新类别
  2. 在src/CMakeLists.txt中的ADAPTER_FILES变量中增加该文件
  3. 编写适配函数代码,所有适配函数使用static修饰,函数的命名规则为"adapt_classes","classes"表示类别名称。
  4. 定义glibc_adapter_t数组,数组名的命名规则为"classes_adapters","classes"表示类别名称。
  5. 使用ADAPT_DIRECT或ADAPT_INDIRECT初始化数组元素
  6. 实现注册函数的封装功能,命名规则为"register_adapters_classes","classes"表示类别名称。该函数由主功能代码调用
  7. 在src/glibc-adapter.c中register_all_adapters函数末尾加上REGISTER_ADAPTERS_BY_CLASSES(classes); "classes"表示新增的适配接口类别。

适配函数的实现和定义可参照src/errno-adapter.c代码

新增适配接口

  1. 编写适配函数代码,所有适配函数使用static修饰,函数的命名规则为"adapt_classes","classes"表示类别名称。
  2. 在glibc_adapter_t数组末尾追加适配接口,也可以按照功能插入

函数名和变量名符号

libc中,有些函数名或变量名为宏定义,实际符号与宏名不一致,如:stdin, stdout, stderr,为宏名,定义变量分别为_IO_2_1_stdin_, IO_2_1_stdin, _IO_2_1_stderr_等,需要对定义变量进行适配,而非stdin, stdout, stderr名进行适配,可参考src/stdio-apdater.c中对stdin, stdout, stderr等的适配实现

使用以下命令,查看libc库导出的实际符号名

readelf -W --dyn-syms /lib/aarch64-linux-gnu/libc.so.6

约束:
  • 所有适配接口都以"adapt_"开头,再接上适配函数的名称
  • 所有适配函数都需用static修复,否则可能会产生符号污染问题
  • 代码必须使用标准C语言实现,不能使用C++,否则导致加载报错,此时libc++库未调用初始化过程
  • 必须静态定义glibc_adapter_t数组,不支持动态分配该数组,否则加载时出现段错误,这些数组在libc库初始化之前使用

注意事项

  • 最多支持8192个接口适配,包括:函数和全局变量,超过该数时,该类型适配接口不会生效,可使用logcat -s glibc-adapter查看日志确认,如:输出“No enough memory for %s adapters”。
  • 不能包含运行前的初始化代码,即调用函数初始化全局变量,否则会报错,主要原因linker调用接口会在初始化该库前被调用。可以通过查看动态库ELF文件是否包含.init或.init_array分节来确认

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages