资讯详情

java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol “__emutls_get_address“ refere...

最近遇到了一个奇怪的问题,有一个以前是静态链接的动态链接库STL(c _static),改为动态链接STL(c _shared)之后,在>=Android 11手机会报dlopen报找不到__emutls_get_address符号。

首先用nm查看动态链接库中的符号:

$ nm libxxx.so |grep __emutls_get_address          U __emutls_get_address

这个U表示不定义,即符号定义在其他库中。我们使用它ndk21b,到ndk的目录看下libc _shared.so里的符号:

$ cd toolchains/llvm/prebuilt/darwin-x86_64/sysroot/usr/lib/arm-linux-androideabi $ nm libc  _shared.so |grep __emutls_get_address                                                         00070364 t __emutls_get_address

小写t表示内部符号,不暴露给外部使用(如果暴露给外部,应该是大写T)。这有点奇怪。我们的动态库没有这个符号,然后依赖它libc _shared.so里面的符号不暴露在外面,肯定找不到。

最终发现的原因是:

当我们编译自己的动态链接库时,我们使用旧版本ndk里的ibc _shared.so,而打包进apk的,是ndk21b里的libc _shared.so。

这个老版本libc _shared.so会暴露这个__emutls_get_address符号。因为旧版本的库没有符号,所以不能使用nm但是我们可以使用命令查看readelf查看:

$ readelf -s libc  _shared.so | grep __emutls_get_address   2110: 000846a0   316 FUNC    GLOBAL DEFAULT   11 __emutls_get_address

可以发现这个符号的可见性是GLOBAL DEFAULT。

我们可以readelf再看下ndk21b的libc _shared.so里的符号:

$ readelf -s libc  _shared.so| grep __emutls_get_address                                  s  37081: 00070364   324 FUNC    LOCAL  HIDDEN    13 __emutls_get_address

发现区别没,这里的可见性是LOCAL HIDDEN,所以它不会暴露在外面。事实上,在这种情况下,链接器会自动帮助我们链接 libgcc_real.a,而libgcc_real.a这个符号包含在里面:

$ cd toolchains/llvm/prebuilt/darwin-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/armv7-a $ nm libgcc_real.a|grep __emutls_get_address 0000020c T __emutls_get_address

结论:

编译时用的stl版本必须打包apk里的stl保持版本一致,否则会出现一些莫名其妙的版本兼容性问题。

P.S. 如果不知道符号在哪个库中,可以lldb attach到app上,然后用image lookup --symbol 'xxx'搜索所有依赖库。

标签: 贴片电容cl21b103kacl21b223kb陶瓷电容cl21b331kb陶瓷电容cl21b392kb陶瓷电容

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台