![]() |
| 图片由 Google Gemini 生成 |
因为老板想从「信创」分一杯羹,于是我们现在需要把一个 CentOS7 上面跑着的系统,移植到「银河麒麟」上去运行。
对于「国产」操作系统了解不多,不敢妄自确定方案。先去 下载 了银河麒麟的数个版本,主要都是服务器操作系统 V10,包括 SP2 的「CentOS 兼容版」,海光版,以及 SP3 2303 以及 2403 的海光版本。考虑到海光 CPU 也是 x86 架构,理论上应该可以跑在普通的 Intel / AMD CPU 的机器上,实际测试下来也是如此。
不得不说,我一开始对于情况设想得比现状要严峻一些。实在是没有想到银河麒麟 V10 对于 CentOS 抄得如此彻底,怪我太高看了国人的本领。无论是「CentOS 兼容版」还是海光版,我们在 CentOS7 上编译的东西,基本上拿上去就可以直接跑。
当然,从好处想,这样做的确提升了这些「国产」操作系统的兼容性,极大拓展了生态链。一定程度上也算是利国利民的好事情。除了钱以外的事情,我也就不吐槽了。
之所以说是「基本上」可以直接跑,是因为银河麒麟 V10 大概是从 CentOS8 开始「魔改」的,所以上面搭载的 OpenSSL 是 1.1.1 版本。有一些是 1.1.1c,有一些是 1.1.1f,总之不是 CentOS7 的 1.0.2。用 yum list 看了一下,源里面也只有 1.1.1 的版本可供安装。
我们的程序是在 CentOS7 上编译出来的,用了 so 版本的 OpenSSL
1.0.2,所以缺了这个东西还没法运行。尽管我们可以把自己的代码改成去链接 OpenSSL
1.1.1,或者索性静态链接进去,但还有些第三方厂商提供的库也是基于 OpenSSL
1.0.2 的,而且不算少。总之这个问题是绕不开的,只能迎头而上去解决它。
另外,我们发现那个「CentOS 兼容版」的默认安装会在 /lib64 下面形成 OpenSSL
1.0.2o 的库。yum list 里面还是没有,说明应该是某个软件包自行装上的。既然那个软件包可以这样做,我们也可以。把自己编译的 OpenSSL
1.0.2 的库放进系统里面去,然后 ldconfig 就好。
以上交代了背景,接下来就说说看具体怎么做,以及介绍一下踩过的坑。
编译 OpenSSL 很简单,从 OpenSSL官网 上下载 1.0.2u的tar.gz包(最后一个版本,1.0.2 已经停止维护了),解压以后编译:
wget https://openssl.org/source/old/1.0.2/openssl-1.0.2u.tar.gz tar -xvzf openssl-1.0.2u.tar.gz cd openssl-1.0.2u ./config --prefix=/usr/local/openssl-1.0.2u --openssldir=/usr/local/openssl-1.0.2u shared make make install
以上的操作,随处都可以搜到,AI 也能提供。不过编译出来的 openssl 动态链接库,有两个问题:
- 拿这两个编译出来的 so 库去用,会报「no version information available」。事实上 ldd 的时候就会报这个错。
- 编译出来的文件名是 libcrypto.so.1.0.0 和 libssl.so.1.0.0,而不是我想要的 libcrypto.so.1.0.2u 和 libssl.so.1.0.2u。
前者问题大一些,后者往小了说只是自己看着顺不顺眼的问题。一个一个解决吧。
问题1
拿着「no version information available」去搜,得到的信息不太具有参考价值。问 AI 也一样。
大多数的回答是说错用了别的操作系统编译的 OpenSSL 库,可能很多人遇到的情况也的确是这个,但显然我们遇到的情况并不是。
唯一找到 一篇相关文章,跟着评论找到了知乎上的 一篇文章。作者是想自己编译 1.0.2u 的库,替换掉 CentOS7 上的 1.0.2k 的版本。
顺带说一句:以前 CentOS7 还在维护,即使是 1.0.2k 的库,CentOS 也会补上安全漏洞。现在 CentOS7 不维护了,或许将有必要这样去做。但 1.0.2u 也已经是 2019 年发布的版本,换句话说,OpenSSL
1.0.2 在更早的时间就停止维护了。所以原文作者这样去做可能也没有什么意义。
该文作者的思路和实际操作都没有什么问题,尊重他人的劳动成果,我就不原样贴一遍了。需要的朋友可以根据上面的链接自己去看。虽然原文不知道为什么贴了 Markdown 的内容,在知乎上看不出样式,至少 PC
Web 版上看不出,但内容总归能看懂。
我遇到的坑是:按照该文操作的「1.4」步骤得到的函数名称中有「@库名」的内容,例如:
sk_find@libcrypto.so.10; sk_set@libcrypto.so.10; asn1_add_error@libcrypto.so.10; ……
对于 Version
Script,这是不可接受的写法。我的处理方法是把这里面的「@libcrypto.so.10」直接删掉了。原文假设所有的函数都是「@@」形式的默认导出,而不是「@」一个符号,这个假设是不对的。
这里是我从 CentOS7 中的 OpenSSL
1.0.2k 提取出来的 Version
Script,既然 CentOS7 和 OpenSSL 1.0.2u 都已经停止维护,那这个文件应该算是 Stable 了。可以 点此下载。
把下载得到的 version.map 放在解压生成的 openssl-1.0.2u 目录下。随后,./config 的时候换成下面这句:
./config --prefix=/usr/local/openssl-1.0.2 --openssldir=/usr/local/openssl-1.0.2 shared -Wl,--version-script=/root/openssl-1.0.2u/version.map -Wl,-Bsymbolic-functions zlib-dynamic
最重要的参数就是 -Wl,--version-script=version.map 这句。再编译生成的 so 库就不会被报「no version information available」了。而且这里似乎必须得写绝对路径。
问题2
直接改文件名是不行的。因为文件里面有 SONAME。做符号链接以及 ldconfig 的时候都会原形毕露。我们需要把文件内部的 SONAME 也一起改掉才行。
据说在编译前手动调整一些文件也可以解决这个问题。不过我是选择在编译之后用 patchelf 来解决这个问题的。为此当然首先要安装 patchelf:
yum -y install patchelf
然后就开始改文件了:
patchelf --set-soname libssl.so.1.0.2u libssl.so.1.0.0 patchelf --set-soname libcrypto.so.1.0.2u libcrypto.so.1.0.0 mv libssl.so.1.0.0 libssl.so.1.0.2u mv libcrypto.so.1.0.0 libcrypto.so.1.0.2u patchelf --replace-needed libcrypto.so.1.0.0 libcrypto.so.1.0.2u libssl.so.1.0.2u
最后一句也是必须的,因为 libssl.so 会引用 libcrypto.so。

没有评论:
发表评论