Android 是否支持弱符号?

Does Android support weak symbols?

我一直在看这样的问题:

在我看来这可以用 weak symbols 来解决。也就是说,原生组件可以提供像 rand 这样的符号,但用 __attribute__((weak)) 来装饰它们。如果符号在另一个库中找到,比如标准运行时,那么弱链接符号将 not 被使用。另一方面,如果缺少该符号,则将使用本机组件的版本。

我无法找到有关 Android 的信息(搜索时有太多不相关的噪音)。

我打开了我的 Crypto++/JNI 示例项目之一,并将以下内容添加到 CPP 文件中。 AutoSeededRandomPool 只是一个 Crypto++ 随机数生成器对象(下面没有什么特别或棘手的)。

// CPP file

#ifdef __cplusplus
extern "C" {
#endif

int __attribute__((weak)) rand(void)
{
    int r;

    AutoSeededRandomPool& prng = GetPRNG();
    prng.GenerateBlock(&r, sizeof(r));

    return r;
}

#ifdef __cplusplus
}
#endif

尝试编译它会导致 redefinition of int rand()。我还尝试了以下方法:

// CPP file

#ifdef __cplusplus
extern "C" {
#endif

int rand(void) __attribute__((weak));

int random(void)
{
   ...
}

#ifdef __cplusplus
}
#endif

并将 int rand(void) __attribute__((weak)); 移动到 H 文件会产生相同的 redefinition of int rand()

而且我没有收到任何关于未知属性的错误或警告。

我还看到 __GXX_WEAK__ 在预处理器中被定义为 1,但是 SUPPORTS_WEAK 没有 定义,所以它的混合信号(可能是一个错误,类似于 Define GXX_WEAK to 0 when using -fno-weak)。

我不确定是我做错了什么,还是遇到了 const and weak attribute with c++ code 之类的事情,或者其他事情。

Android是否支持弱符号?如果是,如何使用它们。


这里有一个没有答案的类似 Stack Overflow 问题:


一些系统细节:

Android 不支持弱符号覆盖。

在最近的版本 android-5.0.2_r1 中, 请参阅 linker.cpp source code

中第 539 行的注释
/*
 *
 * Notes on weak symbols:
 * The ELF specs are ambigious about treatment of weak definitions in
 * dynamic linking.  Some systems return the first definition found
 * and some the first non-weak definition.   This is system dependent.
 * Here we return the first definition found for simplicity.
 */

此评论存在于版本 2.2_r1(在 linker.c 中)到最新版本 5.0.2_r1

tl;博士; Android 支持弱符号

请注意,这不是 android 特定的,它同样适用于 ld-linux。so/ld:

这需要澄清一下,因为有 2 种情况使用了弱符号:

  1. 静态libraries/object 个文件
  2. 动态libraries/executables

(1) 对于静态库和目标文件,可以定义多个弱符号,并在最终对象(.so 或可执行文件)的编译时链接期间选择正确的符号(最强或第一)。

(2) 对于动态库,弱符号的行为方式与默认符号相同,但有一个例外。这意味着共享库没有弱符号覆盖之类的东西。换句话说,在 relocation/dlsym() 期间,将返回第一个找到的 (GLOBAL) 符号:weak 或 default。

例如(这里我们假设none个对象是-Bsymbolic,这是另一个例外):

| main.executable <- foo()
的弱(弱)定义 | -> lib1.so <- foo()
的强(默认)定义 | -> lib2.so <- 使用 foo()

lib2.so 将使用 main.executalbe 的 foo() 实现,尽管 lib1.so 导出 DEFAULT foo() 的速度很快。

例外情况是 WEAK 符号在运行时链接过程中被允许保持未解析状态,并在大多数有用的情况下导致空引用...当未解析的 DEFAULT 符号运行时链接器失败时。