原生Android - 即使先前加载的共享lib包含定义,也无法在加载共享库时找到未定义的方法

时间:2014-01-28 05:27:23

标签: android android-ndk shared-libraries native

我正在构建一个Android应用程序,它在运行时加载2个本机共享库:1使用未解析的符号构建,另一个解析并定义该符号。在Java中,我首先加载定义符号的共享库,然后加载具有声明为unresolved的符号的库,此时,运行时失败: "无法加载库:reloc_library []:33无法找到某些方法'

所以,这是一个独特的区别。带有未定义符号的共享库显然不了解共享库及其中符号的定义。

我只是假设如果我首先加载了带有方法定义的库,那么当我加载调用该方法的第二个库时,它就能找到它。我错了吗?在我的情况下,似乎在两个本地库之间编译了显式依赖关系,这意味着(我认为)使用未解析的符号制作.so是没用的。

我一直在寻找一个没有运气的类似问题。我认为我的问题是由于架构限制,我正在考虑以其他几种方式处理它,但我想知道它是否可以简单修复。

为了确保它本身并不复杂,我创建了两个非常简单的C文件:

fcn_defined.c:
int someMethod()
{
  return 1;
}

fcn_undefined.c:
extern int someMethod();
int someOtherMethod()
{
  someMethod();
}

然后构建两个共享对象,其中fcn_undefined.c代码创建一个.so,someMethod仍未定义,fcn_defined.c构建.so并定义了someMethod:

gcc -o libfcn_undefined.so fcn_undefined.c -shared -Wl,--export-dynamic
gcc -o libfcn_defined.so fcn_defined.c -shared -Wl,--export-dynamic

对这些产生一个nm:
libfcn_undefined.so:

0001f08 d _DYNAMIC
00001fe8 d _GLOBAL_OFFSET_TABLE_
00002004 A __bss_start
         U __cxa_atexit
         U __cxa_finalize
00002000 d __dso_handle
00000290 t __on_dlclose
00002004 A _edata
00002004 A _end
000002a0 t atexit
000002b4 T someOtherMethod
         U someMethod

和libfcn_defined.so:

00001f0c d _DYNAMIC
00001fec d _GLOBAL_OFFSET_TABLE_
00002004 A __bss_start
         U __cxa_atexit
         U __cxa_finalize
00002000 d __dso_handle
0000025c t __on_dlclose
00002004 A _edata
00002004 A _end
0000026c t atexit
00000280 T someMethod

所以你可以看到someMethod()在libfcn_defined.so中定义(它出现在read elf dynsym部分中)并且在另一个lib中未定义。

如果有人对readelf输出感兴趣,我也可以添加它。

在Java方面,我点击模拟器中有一个简单的按钮,它会创建一个包含以下内容的类:

static
{
        System.loadLibrary("fcn_defined");
        System.loadLibrary("fcn_undefined");
}

出于好奇,我添加了一个" -lfcn_defined"到fcn_undefined编译行,并比较nm和readelf输出。 nm的唯一区别在于" T someOtherMethod"进一步开始几个字节,readelf差异是" NEEDED" fcn_defined的行。这几乎与我的预期有关。 它并没有像这样崩溃。

这几乎是完整的解释。我确实找到了一些有关Android如何强制您在Java中以反向依赖顺序加载库的细节,因为它已经(而不是已经在API 18中修复)在LD_LIBRARY_PATH中没有引用应用程序的lib路径ENVVAR。不幸的是,我要求最低API lvl 10能够使用我的应用程序,因为市场渗透,其次我尝试了API 19,它仍然失败。

如果我不得不猜测,我相信如果您没有明确告诉它查看符号库X库,Android就不支持查找符号。换句话说,因为我没有构建具有对libfcn_defined.so的显式依赖的fcn_undefined库,所以Android无法解析它。有谁知道这是一个bug还是设计?这是正常的吗?如果是这种情况,似乎你没有选择创建带有未解析符号的.so,甚至更有趣的是,我用来构建它的Android NDK工具链默认启用此功能当你使用ld(它没有抱怨未解决的)时,我尝试关闭该功能,但似乎没有做任何事情,没有警告或错误生成库。

所以你可能会问我为什么不编译依赖于fcn_defined库的fcn_undefined库。好吧,这进入了一个更大的架构讨论。我使用的代码(本例中为fcn_undefined.c)是一个python扩展,使用ARM的交叉编译python工具链构建,我从NDK库调用此库,所以现在NDK库取决于python模块,它在Python中有一个未解析的方法,它在静态库中定义。将静态库链接到NDK共享库意味着我无法在Java中以正确的顺序加载本机共享库(由于前面提到的问题,它们已在API 18中修复)。我尝试使用现有系统,因为其他团队使用它,并且它用于构建许多平台。 叹息我显然还有其他的事情需要弄清楚,但我希望至少能将上面的那个钉在上面。

2 个答案:

答案 0 :(得分:1)

通过Unix / ELF设计,您需要libfnc_undefined.so中的NEEDED条目,该条目将libfnc_defines.so列为动态链接器的依赖关系,以查找缺少的符号。

即。您应该确保在生成libfcn_undefined.so的链接命令中出现-lfcn_defined(或/path/to/libfcn_defined.so)。

如果使用ndk-build生成两个库,只需将libfcn_defined.so列为libfcn_undefined.so的LOCAL_STATIC_LIBRARIES或LOCAL_SHARED_LIBRARIES条目。

如果您使用其他构建系统,请相应地进行调整。

答案 1 :(得分:1)

你如此精彩地展示的行为是设计(或缺乏,如果你愿意)。你是对的,crazy_linker确实解决了一些这样的问题(但不是全部)。有一个简单但丑陋的解决方法。构建一个虚拟libfcn_defined.so,其 nm 只有T someMethod。使用libfnc_undefined.so链接LD_LIBS。 NDK会显示警告,但没关系。在Java中加载真正的libfcn_defined.so