【发布时间】:2014-02-19 06:39:29
【问题描述】:
我正在构建一个 Android 应用程序,该应用程序在运行时加载到 2 个本机共享库中:1 个是使用其中未解析的符号构建的,另一个是解析并定义该符号的。在 Java 中,我首先加载定义符号的共享库,然后加载将符号声明为未解析的库,此时,运行时失败并显示: "无法加载库:reloc_library[]: 33 找不到 'someMethod'
所以这是一个独特的区别。具有未定义符号的共享库显然不知道其中包含符号定义的共享库。
我只是假设如果我首先加载带有方法定义的库,那么当我加载调用该方法的第二个库时,它将能够找到它。我错了吗?就我而言,似乎必须在两个本机库之间编译显式依赖项,这意味着(我认为)使用未解析的符号制作 .so 是没用的。
我一直在努力寻找类似的问题,但没有运气。我认为我的问题是由于架构限制,我正在考虑通过其他几种方式来解决它,但我想知道它是否可以简单地修复。
为了确保库本身不复杂,我创建了两个非常简单的 C 文件:
fcn_defined.c:
int someMethod()
{
return 1;
}
fcn_undefined.c:
extern int someMethod();
int someOtherMethod()
{
someMethod();
}
然后构建两个共享对象,其中 fcn_undefined.c 代码创建一个未定义 someMethod 的 .so,fcn_defined.c 构建一个定义了 someMethod 的 .so:
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");
}
出于好奇,我在 fcn_undefined 编译行中添加了“-lfcn_defined”,并比较了 nm 和 readelf 的输出。 nm 的唯一区别是“T someOtherMethod”开始更远几个字节,而 readelf 的区别是 fcn_defined 的“NEEDED”行。这和我的预期差不多。 而且它不会像这样崩溃。
这几乎是完整的解释。我确实找到了一些关于 Android 如何强制您在 Java 中以反向依赖顺序加载库的详细信息,因为它在 LD_LIBRARY_PATH envvar 中没有引用您的应用程序的库路径(而是已经在 API 18 中修复)。不幸的是,由于市场渗透,我需要最低 API lvl 10 才能使用我的应用程序,其次我还是尝试了 API 19,但仍然失败。
如果我不得不猜测,我相信如果您没有明确告诉它在库 X 中查找符号,Android 就不支持查找符号。换句话说,因为我没有构建库 fcn_undefined 并显式依赖 libfcn_defined.so,所以 Android 无法解决它。有谁知道这是一个错误还是设计使然?这是正常的吗?如果是这种情况,您似乎无法选择创建带有未解析符号的 .so ,甚至更有趣的是,当您使用 ld 时,我用来构建它的 Android NDK 工具链默认具有此功能(它不会抱怨未解决),我尝试关闭该功能但似乎没有做任何事情,没有警告或错误生成库。
所以你可能会问,为什么我不只是编译 fcn_undefined 库并依赖于 fcn_defined 库。好吧,这进入了更大的架构讨论。我正在使用的代码(本示例中为 fcn_undefined.c)是一个 python 扩展,它使用用于 ARM 的交叉编译 python 工具链构建,我从 NDK 库调用这个库,所以现在 NDK 库依赖于 python在 Python 中具有未解析方法的模块,该方法在静态库中定义。将静态库链接到 NDK 共享库意味着我无法在 Java 中以正确的顺序加载本机共享库(由于前面提到的问题,它们已在 API 18 中修复)。我正在尝试使用现有系统,因为其他团队使用它,并且它用于为许多平台构建。 叹息我显然还有其他事情要弄清楚,但我希望至少能确定上面的那个。
【问题讨论】:
标签: android android-ndk shared-libraries native