jdk无法在树莓派4b上运行

一个之前在海思平台运行正常的jdk版本,在32位树莓派的系统上面总是没法正常运行。运行java时报错

java: error while loading shared libraries: libjli.so: cannot open shared object file: No such file or directory

这个错误网上一堆说要设置 LD_LIBRARY_PATH 之类的。但是之前在海思平台上面也不需要设置,而且在树莓派上面设置了也还是报错。后来换了另外一个版本的jdk就可以运行了。但是之前的版本为什么不行呢?

这个so库位于 jdk1.7.0_60/lib/arm/jli 。使用ldd查看不行的版本

-bash-5.0# ldd libjli.so
        not a dynamic executable

而可以的版本

-bash-5.0# ldd libjli.so
        linux-vdso.so.1 (0xbedbe000)
        /usr/lib/arm-linux-gnueabihf/libarmmem-${PLATFORM}.so => /usr/lib/arm-linux-gnueabihf/libarmmem-v7l.so (0xb6f0d000)
        libdl.so.2 => /lib/arm-linux-gnueabihf/libdl.so.2 (0xb6efa000)
        libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0xb6dac000)
        libpthread.so.0 => /lib/arm-linux-gnueabihf/libpthread.so.0 (0xb6d82000)
        libgcc_s.so.1 => /lib/arm-linux-gnueabihf/libgcc_s.so.1 (0xb6d55000)
        /lib/ld-linux-armhf.so.3 (0xb6f40000)

ldd都分析不了这个动态库的依赖关系,之前在amd64系统ldd 32位i686库的时候遇到过。但是树莓派也都是arm32位系统,应该不存在32位 64位不匹配的问题啊?

PS:假如ldd不好使,还可以用 readelf -d xxx 来查看某个程序或者动态库的依赖

google搜索中,有人提到可以用strace分析java加载时为什么报错。于是试了一下。在漫长的结果中,有这么一段

openat(AT_FDCWD, "/usr/local/jdk1.7.0_60/bin/../lib/arm/jli/libjli.so", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0\330\27\0\0004\0\0\0"..., 512) = 512
_llseek(3, 79528, [79528], SEEK_SET)    = 0
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1200) = 1200
_llseek(3, 78572, [78572], SEEK_SET)    = 0
read(3, "A2\0\0\0aeabi\0\1(\0\0\0\5ARM10TDMI\0\6\3\10\1\t"..., 51) = 51
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/libjli.so", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/local/ffmpeg/lib/libjli.so", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = -1 ENOENT (No such file or directory)
...

很明显,java已经可以根据相对路径,找到 libjli.so了,但是在read aeabi一段后,就把它关闭了,继续从其他路径查找可用的 libjli.so。说明这个库的aeabi有不兼容的地方(aeabi是ARM Embedded Application Binary Interface的缩写)。继续google,发现readelf可以查看一个so的aeabi信息。

-bash-5.0# readelf -A libjli.so
Attribute Section: aeabi
File Attributes
  Tag_CPU_name: "ARM10TDMI"
  Tag_CPU_arch: v5T
  Tag_ARM_ISA_use: Yes
  Tag_THUMB_ISA_use: Thumb-1
  Tag_FP_arch: VFPv2
  Tag_ABI_PCS_wchar_t: 4
  Tag_ABI_FP_denormal: Needed
  Tag_ABI_FP_exceptions: Needed
  Tag_ABI_FP_number_model: IEEE 754
  Tag_ABI_align_needed: 8-byte
  Tag_ABI_enum_size: int
  Tag_ABI_HardFP_use: Deprecated
  Tag_ABI_optimization_goals: Aggressive Speed

而可以运行的那个版本

-bash-5.0# readelf -A libjli.so
Attribute Section: aeabi
File Attributes
  Tag_CPU_name: "6"
  Tag_CPU_arch: v6
  Tag_ARM_ISA_use: Yes
  Tag_THUMB_ISA_use: Thumb-1
  Tag_FP_arch: VFPv2
  Tag_ABI_PCS_wchar_t: 4
  Tag_ABI_FP_denormal: Needed
  Tag_ABI_FP_exceptions: Needed
  Tag_ABI_FP_number_model: IEEE 754
  Tag_ABI_align_needed: 8-byte
  Tag_ABI_align_preserved: 8-byte, except leaf SP
  Tag_ABI_enum_size: int
  Tag_ABI_HardFP_use: Deprecated
  Tag_ABI_VFP_args: VFP registers
  Tag_ABI_optimization_goals: Aggressive Speed
  Tag_CPU_unaligned_access: v6
  Tag_DIV_use: Not allowed

开始以为是Tag_CPU_name: "ARM10TDMI"这个导致了程序在树莓派上面不能正常执行。于是想办法编译一个相同Tag_CPU_name的执行程序来试验一下。apt search了一下,发现ubuntu自带的arm-linux gcc版本真多啊,从gcc 5到gcc 8,有multilib和非multilib版本之分,还有gnueabi和gnueabihf版本之分。先挑了一个低版本的
apt install gcc-5-arm-linux-gnueabi

结果发现,无论我怎么指定-mcpu,编译出来的Tag_CPU_name总是没变化。反而是指定-march=armv6或者armv7-a,Tag_CPU_name、Tag_CPU_arch都一起变了。后面又试了一下,用树莓派上面自己带的gcc,编译出来的aeabi信息为

-bash-5.0# readelf -A a.out
Attribute Section: aeabi
File Attributes
  Tag_CPU_name: "6"
  Tag_CPU_arch: v6
  Tag_ARM_ISA_use: Yes
  Tag_THUMB_ISA_use: Thumb-1
  Tag_FP_arch: VFPv2
  Tag_ABI_PCS_wchar_t: 4
  Tag_ABI_FP_rounding: Needed
  Tag_ABI_FP_denormal: Needed
  Tag_ABI_FP_exceptions: Needed
  Tag_ABI_FP_number_model: IEEE 754
  Tag_ABI_align_needed: 8-byte
  Tag_ABI_align_preserved: 8-byte, except leaf SP
  Tag_ABI_enum_size: int
  Tag_ABI_VFP_args: VFP registers
  Tag_CPU_unaligned_access: v6

暂时搞不出来arm10tdmi的,就先不管吧。在台式机用 arm-linux-gnueabi-gcc-5 交叉编译出来的程序,加上-march=armv6,里面只包含一句printf,拿到树莓派上面,运行正常,但是使用ldd分析的时候会报错“not a dynamic executable”!交叉编译程序的aeabi和树莓派gcc编译出来的已经非常接近了!

-bash-5.0# readelf -A test
Attribute Section: aeabi
File Attributes
  Tag_CPU_name: "6"
  Tag_CPU_arch: v6
  Tag_ARM_ISA_use: Yes
  Tag_THUMB_ISA_use: Thumb-1
  Tag_ABI_PCS_wchar_t: 4
  Tag_ABI_FP_rounding: Needed
  Tag_ABI_FP_denormal: Needed
  Tag_ABI_FP_exceptions: Needed
  Tag_ABI_FP_number_model: IEEE 754
  Tag_ABI_align_needed: 8-byte
  Tag_ABI_align_preserved: 8-byte, except leaf SP
  Tag_ABI_enum_size: int
  Tag_CPU_unaligned_access: v6
-bash-5.0# ldd test
        not a dynamic executable
-bash-5.0# ./test
0

仔细一对比,差异之处只有 Tag_ABI_VFP_args: VFP registers。树莓派gcc编译出来的带有这个,而交叉编译的没有。google一下可以知道,这个代表着不同的浮点数函数传参规则。没有VFP registers的,使用的是软浮点,浮点数都是通过整形的通用寄存器进行传参的;而带有VFP registers的,使用的是硬浮点,浮点数直接使用浮点寄存器进行传参。
https://developer.toradex.com/knowledge-base/linux-floating-point-calling-convention-co-processor-engine

另外,使用软浮点EABI的称为armel,使用硬浮点的EABI被称为armhf
https://blogs.oracle.com/jtc/is-it-armhf-or-armel
https://www.cnblogs.com/hustdc/p/7224980.html

试一下在交叉编译的时候加上-mfloat-abi=hard,结果直接报错
/usr/lib/gcc-cross/arm-linux-gnueabi/5/../../../../arm-linux-gnueabi/bin/ld: error: /tmp/ccR9XYmB.o uses VFP register arguments, test does not
/usr/lib/gcc-cross/arm-linux-gnueabi/5/../../../../arm-linux-gnueabi/bin/ld: failed to merge target specific data of file /tmp/ccR9XYmB.o

回想起来ubuntu自带的gcc都是分gnueabi和gnueabihf的,之前装的是gnueabi,换成gnueabihf的
apt install gcc-5-arm-linux-gnueabihf

这个编译出来默认是硬浮点,而且arch已经是v7-a的了,也无法将arch改为armv6,会报错“ sorry, unimplemented: Thumb-1 hard-float VFP ABI”。不过现在普遍都是Cortex-A架构的cpu了,问题不大。这套gcc编译出来的程序在树莓派上面既可以正常运行,也可以被ldd识别。

不过之前的情况还是有些疑问,有些程序虽然在树莓派上面不能被ldd识别,但是是可以正确执行的。armel和armhf的兼容性情况到底是怎样的?写个带浮点运算的测试程序

#include <stdio.h>
#include <math.h>
int main()
{
        double i = 4.0f;
        printf("%f\n", sqrt(i));
        return 0;
}

用armel工具链编译出来的程序,居然也能运行!只不过输出是 4.000错误的结果!这就是一个巨坑了,可以执行,但是运行可能是错的。
反过来,在armel的平台上,armhf的程序是不能被执行的,直接报 not found,还好。

为了进一步模拟原来jdk那种so无法加载的情况,写了一个动态库

int add(int a, int b)
{
        return a+b;
}

编译成so: arm-hisiv400-linux-gcc -shared -o libtest.so 2.c

#include <stdio.h>
extern int add(int a, int b);
int main()
{
        int a=4, b=2;
        printf("%d\n", add(a, b));
        return 0;
}

编译执行程序:arm-hisiv400-linux-gcc -L./ -Wl,-rpath,./ 1.c -ltest -o test
在树莓派上面一执行,果然就报错了

./test: error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory

一开始这个add我是写成double类型的。但后来发现不需要浮点,只要浮点EABI不对,就不能加载so库。但是如果libtest.so是用armhf工具链编译的,执行程序用armel编译,还是能跑出正确的结果。

重要结论:armhf上面不会阻止armel执行程序的执行,但是会阻止armel动态库的加载。armel执行程序调用armhf的动态库,只要不涉及浮点传参,结果还是正常的。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容