Android Toolchain与Bionic Libc

本文详细介绍了Android系统中使用的BionicLibc C库的特点、架构、系统调用、时间管理、线程实现及TLS特性,揭示了其与glibc的区别与优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

android所用的Toolchain(即交叉编译工具链)可从下面的网址下载:
http://android.kernel.org/pub/android-toolchain-20081019.tar.bz2。如果下载了完整的Android项目的源代码,则可以在“<your_android>/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin”目录下找到交叉编译工具,比如Android所用的arm-eabi-gcc-4.2.1。
Android并没有采用glibc作为C库,而是采用了Google自己开发的Bionic Libc,它的官方Toolchain也是基于Bionic Libc而并非glibc的。这使得使用或移植其他Toolchain来用于Android要比较麻烦:在Google公布用于Android的官方Toolchain之前,多数的Android爱好者使用的Toolchain是在http://www.codesourcery.com/gnu_toolchains/arm/download.html 下载的一个通用的Toolchain,它用来编译和移植Android 的Linux内核是可行的,因为内核并不需要C库,但是开发Android的应用程序时,直接采用或者移植其他的Toolchain都比较麻烦,其他Toolchain编译的应用程序只能采用静态编译的方式才能运行于Android模拟器中,这显然是实际开发中所不能接受的方式。目前尚没有看到说明成功移植其他交叉编译器来编译Android应用程序的资料。
与glibc相比,Bionic Libc有如下一些特点:

- 采用BSD License,而不是glibc的GPL License;
- 大小只有大约200k,比glibc差不多小一半,且比glibc更快;
- 实现了一个更小、更快的pthread;
- 提供了一些Android所需要的重要函数,如”getprop”, “LOGI”等;
- 不完全支持POSIX标准,比如C++ exceptions,wide chars等;
- 不提供libthread_db 和 libm的实现

另外,Android中所用的其他一些二进制工具也比较特殊:

- 加载动态库时使用的是/system/bin/linker而不是常用的/lib/ld.so;
- prelink工具不是常用的prelink而是apriori,其源代码位于” <your_android>/build/tools/apriori”

- strip工具也没有采用常用的strip,即“<your_android>/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin”目录下的arm-eabi-strip,而是位于<your_android>/out/host/linux-x86/bin/的soslim工具。



BionicC 库一览:
介绍:
核心体系

Bionic设计的核心思想是:尽量简单。
这意味这这个C库只围绕着内核提供轻量级的包装,我们让它尽量小,不去处理一些细枝末页的事情。

 

取Bionic这个名字,是因为它由部分BSD和部分linux组成:

 

 

它的代码由BSD C库和自定义的linux代码(用于处理线程,进程,信号,和其他事情)混合而成。

 

 

所有原始的BSD块,遵循BSD版权声明。特定的Bionic部分遵循Android open source project版权声明。一切发行版都遵循BSd版权。

 

 

 

架构:
Bionic 当前支持ARM andx86指令集。理论上可以支持更多,但是这需要做点工作(比如,
向SYSCALLS.TXT文件中添加系统调用IDS,如下面所述,或者修改动态链接器)。

 

ARM相关代码在arch-arm/下面,x86相关代码在arch-x86下面。

 

 

注意,x86版本只能运行在x86android设备上。我们并没有声明说,你能够在普通 x86 linux发布版上使用Bionic,(尽管这会很,因此欢迎大家做这样的补丁程序);

 

 

 

 

Syscall stub

 

 

每个系统调用函数都由一个小的汇编代码段实现(称为syscallstub),这是由tools/gensyscalls.py工具自动生成的,它从SYSCALL.TXT中取得输入参数。

 

 

SYSCALLS.TXT包含了一份要生成的系统调用块列表,和相应的系统调用数字标识符(ARM和X86不一样),以及它的签署。

 

 

如果你要修改这个文件,你可能要使用tools/checksyscalls.py工具,检查它里面是否包含官方linux核心头文件,如果有不合法的syscallids,它会报告错误。

 

 

有时,C库函数其实就是一个包装,它内部调用相应的syscall名称,例如,exit函数由C库提供,它调用了_exit()这个syscallstub.

 

 

详细内容请参考SYSCALLS.TXT文件。

 

 

 

 

time_t:

 

 

time_t在32位CPU内核上定义为32位,一个64位的版本需要避免Y2038bug,但是内核的维护者认为,此刻并不需要。相反,Bionic提供了一个<time64.h>头文件,定义了一个time64_t类型,和相关的函数,如mktime64(),localtime64(),等等。

 

 

 

 

时区管理:

 

 

当前时区的名字取决与TZ环境变量,如果TZ未定义,将会使用名为'persist.sys.timezone'的系统属性。

 

 

时区数据库和索引文件放在/system/usr/share/zoneinfo下面,而不是在posix兼容路径/usr/share/zoneinfo下面。

 

 

 

 

Off_t:

 

 

出于相同的原因,off_t也是32位的,由于BSD的继承关系,我们定义loff_t型为64位变量,但是

 

 

可以使用typedef 定义off64_t类型,以便使得当前linux代码移植更简单。

 

 

 

 

Linux核心头文件:

 

 

Bionic带来一套自己的cleanLinux内核头文件,允许用户空间代码使用内核特有的声明(比如,

 

 

IOCTLs, structuredeclarations, constants,等等... ).他们位于:

 

 


./kernel/common,

 

 


./kernel/arch-arm

 

 


./kernel/arch-x86

 

 

这些头文件由一个工具(kernel/tools/update-all.py)产生,只包含原始Linux内核头文件中的公有定义。

 

 

如果你想知道为什么和怎么做,请参考kernel/README.TXT文件。

 

 



 

 

Pthread实现:

 

 

Bionic'sC库使用他自己的pthread程序包,与其他C库相比有如下不同点:

 

 

 

 

-放在一个外部库中(-lpthread

 

 

-开放含有少量符号的链接器入口用于动态链接

 

 

运行时特征支持(a.k.a. -lrt),也打包在C库中。基于futexes的实现,尽量提供很短小的代码实现通用操作,有以下几点显著的特征:

 

 

 

 


- pthread_mutex_t, pthread_cond_t
每各类型都只有4个字节.

 

 



-
支持Normal, recursive anderror-check互斥体,对Normalcase下的代码流程做了很细致的优化,通常大多数的时候都使用Normal。

 

 



-
进程共享互斥和条件变量不被支持,它们的实现很复杂,而且Android绝对用不到(android使用其他的进程内同步组件)。

 

 

注意,通过精心调整代码流程,他们可能会在未来添加进来,而且不会破坏ABI,(尽管这会使代码执行变得有点儿慢)。

 

 

-
当前没有读写锁,互斥体的优先权,和其他高级特征的支持。再说一句,在Android中根本不需要这些,但是在未来可能会被添加进来。

 

 

 

 

pthread_cancel():

 

 


pthread_cancel()
在Bionic中不被支持,因为这将使得C库变得庞大起来,就为了这点好处不值得。

 

 


基于一下几点考虑:

 

 


-
要正常实现,必须在C库的多个地方插入pthreadcancellation检测,这会使代码的统一调试变得非常困难。

 

 

-要正常实现,也必须清理资源,象释放内存,解锁互斥体,如果cancel恰好发生在complex函数里(比如在gethostbyname() or fprintf() +复杂格式化规则里面)。这会使许多函数的执行变慢。

 

 



- pthread cancellation
不能停止所有的线程:比如,对于无穷循环,它就无能为力。

 

 

- pthreadcancellation本身也有缺陷,不好移植。

 

 

(see http://advogato.org/person/slamb/diary.html?start=49 forexample).

 

 

所有这些都与Bionic的设计目标相反,如果你的代码依赖threadcancellation,请好好考虑下吧。

 

 

注意Bionic确实实现了pthread_cleanup_push()和pthread_cleanup_pop(),在线程通过pthread_exit()调用退出或者从它的主函数中返回的时候,它可作些清理工作,

 

 



 

 


NND
,不想支持就别支持嘛,非要编这么多理由来敷衍我们。

 

 

 

 

 

 

pthread_once():

 

 

不要在pthread_once()的回调函数中调用fork(),这么做的话,会在下次调用pthread_once()的时候,在子进程中导致死锁。

 

 

而且,你不能在回调函数中throw一个C++ Exception(参见下面的C++ Exception支持).

 

 

当前pthread_once()实现缺少必要的多核安全双重检查锁定(屏蔽读写操作)

 

 

 

 

线程本地数据:

 

 


线程本地存储区仅为每个进程提供了略小于64个pthread_key_t对象,在实现上,提供了64个实时slot, 而且自己使用了大约5个(实际数量依赖于实现)。(比如,两个slot由C库预先分配,以启动Android OpenGL子系统加速)。

 

 


注意,Posix要求至少128个slot,但是我们不打算与Posix兼容。

 

 

除了主线城,在堆栈顶部也存储了TLS区,详细资料请参考bionic/libc/bionic/pthread.c文件中的注释部分。

 

 

当前,使用__thread关键词来定义线程本地存储区,还不被Bionic C库和动态链接器支持。

 

 

<think>好的,用户现在遇到了一个问题,他在编译Android NDK项目时发现NDK里面没有crt1.o文件,而他的系统中有其他路径下存在这个文件。他想知道是否可以使用现有的这些文件。 首先,我需要回顾一下之前的对话。用户之前遇到了链接错误,提示找不到crt1.o等文件,虽然确认sysroot正确,但问题依然存在。现在通过find命令发现NDK目录下确实没有这些文件,而系统其他位置有。 接下来,我需要分析为什么NDK里没有这些文件。可能的原因包括NDK版本问题、安装不完整,或者用户配置的路径不正确。另外,用户可能混淆了不同工具链的文件,比如RV1126/RV1109的Linux工具链和Android NDK的工具链,这两者针对的平台不同,一个是Linux嵌入式系统,另一个是Android,所以库文件不兼容。 用户的问题核心在于是否可以使用系统中现有的crt1.o文件。这时候需要告诉他,直接使用非NDK提供的crt文件会导致兼容性问题,因为不同工具链的C运行时库针对的目标系统不同,混用可能导致链接错误或运行时崩溃。 然后,我需要给出解决方案。首先建议检查NDK安装是否正确,确保路径配置正确,特别是sysroot和--target参数是否正确指定了目标架构和API级别。如果确认配置正确,但NDK确实缺少这些文件,可能需要重新下载或验证NDK的完整性。 另外,用户提到使用的是NDK r18b,这个版本可能较旧,可以考虑升级到较新的NDK版本,因为新版本可能修复了此类问题,或者提供更好的工具链支持。同时,建议用户使用NDK提供的标准编译脚本或make_standalone_toolchain.py生成独立的工具链,避免手动配置路径带来的错误。 如果用户确实需要使用现有的非NDK提供的crt文件,需要指导他如何正确配置链接器的路径,但必须强调这可能带来的风险,并建议仅在明确知道兼容性的情况下使用。 最后,确认用户是否需要进一步的帮助,比如检查具体的编译命令,或者验证NDK安装的完整性,以及如何正确设置环境变量和编译参数。</think>根据您提供的搜索结果,这个问题的根源在于Android NDK工具本地系统工具链的架构不匹配。让我们逐步分析解决方案: 1. **架构差异分析**: - 您找到的crt1.o文件属于不同的工具链: - `/home/chang/rv1126...` 开头的路径:这是Rockchip RV1126/RV1109的**Linux嵌入式工具链** - `/usr/arm-linux-gnueabihf...`:这是Ubuntu系统的**ARM Linux桌面工具链** - Android NDK需要的是**Android Bionic C库**的启动文件,上述两者二进制不兼容 2. **NDK r18b正确路径验证**: 在标准NDK r18b中,crt文件应位于: ```bash # ARMv7架构示例 ${NDK}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/arm-linux-androideabi/21/crt1.o # 检查路径是否存在 ls /opt/android-ndk-r18b/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/arm-linux-androideabi ``` 3. **临时解决方案(不推荐长期使用)**: 如果必须使用现有文件,可以通过符号链接创建应急方案: ```bash sudo mkdir -p /opt/android-ndk-r18b/sysroot/usr/lib/arm-linux-androideabi/21/ sudo ln -s /usr/arm-linux-gnueabihf/lib/crt1.o /opt/android-ndk-r18b/sysroot/usr/lib/arm-linux-androideabi/21/ ``` ⚠️ 注意:这可能导致运行时崩溃,仅适用于编译测试 4. **推荐的标准修复方案**: ```bash # 清理旧配置 rm -rf /home/chang/dev/mpp/mpp_build # 重新配置时指定完整工具链参数 ./configure \ --cross-prefix=arm-linux-androideabi- \ --sysroot=/opt/android-ndk-r18b/sysroot \ --extra-cflags="-I/opt/android-ndk-r18b/sysroot/usr/include -march=armv7-a" \ --extra-ldflags="-L/opt/android-ndk-r18b/toolchains/llvm/prebuilt/linux-x86_64/lib/clang/9.0.9/lib/linux/arm/" ``` 5. **NDK版本升级建议**: ```bash # 下载新版NDK (示例使用r25b) wget https://dl.google.com/android/repository/android-ndk-r25b-linux.zip unzip android-ndk-r25b-linux.zip -d /opt/ # 验证新NDK路径 find /opt/android-ndk-r25b -name crt1.o # 预期输出类似: # /opt/android-ndk-r25b/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/26/crt1.o ``` 6. **交叉编译验证测试**: ```bash # 创建测试文件 test.c echo -e '#include <stdio.h>\nint main(){printf("NDK test\\n");return 0;}' > test.c # 使用NDK工具链编译 /opt/android-ndk-r18b/toolchains/llvm/prebuilt/linux-x86_64/bin/clang \ --target=armv7-none-linux-androideabi21 \ -pie -fPIE \ -o test test.c # 验证二进制格式 file test # 正确输出应包含:ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV) ``` 如果仍然存在问题,建议检查以下配置: ```bash # 查看环境变量污染 env | grep -E 'CROSS|TOOLCHAIN' # 确认库搜索路径 echo | clang -E -Wp,-v - 2>&1 | grep /usr/include ``` 最终建议优先考虑升级NDK版本,旧版r18b(2018年发布)对现代Android系统的兼容性支持已不足,新版NDK能更好地处理工具链路径问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值