时间轴
时间轴
2026-07-16
init
本文介绍了在x86_64主机上使用Arm GNU Toolchain 11.2交叉编译OpenSSL 1.0.0s,生成aarch64共享库(.so)的完整流程。文章首先说明了环境准备,包括源码选择与交叉工具链配置,并指出OpenSSL 1.0.0没有专门的aarch64 target,必须使用通用64位target并通过环境变量指定工具链前缀。随后详细解析了Configure参数,包括禁用IDEA、MD2、MDC2、RC5算法及SSL 2.0/3.0协议,并解释了相关安全考量。文章重点解决了构建中的关键问题:由于交叉工具链的ar在ARFLAGS为空时默认创建瘦归档,且AR参数顺序错误,导致链接失败,需同时修改顶层、Makefile和Makefile.shared三个Makefile中的ARFLAGS与AR定义。最后总结了编译、验证、安装步骤,并提供了常见问题排查表。本文为在ARM64平台
目标:在 x86_64 主机上,使用aarch64-none-linux-gnu-交叉工具链,编译出libssl.so和libcrypto.so(ARM aarch64 共享库)。
1. 环境准备
1.1 源码
123456 | cd ~/repositorywget https://github.com/openssl/openssl/releases/download/OpenSSL_1_0_0s/openssl-1.0.0s.tar.gztar xvf openssl-1.0.0s.tar.gz # 如果尚未解压cd openssl-1.0.0s |
如果不是必须要用 OpenSSL 1.0.0,OpenSSL 1.1.1 这个版本更推荐使用,不仅代码更健壮,编译也更简单。
123 | ./Configure linux-aarch64 --cross-compile-prefix=aarch64-none-linux- --prefix=$PWD/_install sharedmake -j$(nproc) |
1.2 交叉工具链
本文使用 Arm GNU Toolchain 11.2-2022.02(aarch64-none-linux-gnu-三元组)。
ARM目前总共发布了8种架构:ARMv1、ARMv2、ARMv3、ARMv4、ARMv5、ARMv6、ARMv7、ARMv8。
针对支持ARMv8指令集的处理器可以使用-march=armv8-a参数编译代码,ARM GNU编译器可通过下面的链接下载
推荐使用ARM官网的编译器,它是Portable的,解压后即可使用。
本文使用的是11.2版本的交叉编译器
可以将其添加到环境变量
123 | # ~/.bashrc或~/.bash_profileemacs ~/.bashrcexport PATH="$HOME/tools/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/bin:$PATH" |
使用11.2.1版本的aarch64-none-linux-gnu-gcc

如果工具链三元组是
aarch64-linux-gnu-(如 Ubuntu 的gcc-aarch64-linux-gnu包),把下面所有aarch64-none-linux-gnu-替换成aarch64-linux-gnu-即可。
2. 配置(Configure)
OpenSSL 1.0.0 没有linux-aarch64这个 target(即使命令行能选上,也会 fall back 到 host 的cc,产物是 x86_64)。
正确做法是使用通用 64-bit targetlinux-generic64,并通过环境变量CROSS_COMPILE指定工具链前缀。
1234567 | export CROSS_COMPILE=aarch64-none-linux-gnu-./Configure linux-generic64 shared \ --prefix=$PWD/_install \ --openssldir=$PWD/_install/ssl \ no-idea no-md2 no-mdc2 no-rc5 no-ssl2 no-ssl3 \ -DOPENSSL_NO_HEARTBEATS |
⚠️ 重要:
CROSS_COMPILE必须用 环境变量 传入。
如果写成./Configure ... CROSS_COMPILE=...命令行参数,
OpenSSL 1.0.0 的 Configure 脚本会报:target already defined - linux-generic64 (offending arg: CROSS_COMPILE=...)
配置完成后,检查Makefile确认交叉编译生效:
1 | grep -E '^(CC|CROSS_COMPILE|AR)=' Makefile |
期望输出:
123 | CROSS_COMPILE= aarch64-none-linux-gnu-CC= $(CROSS_COMPILE)gccAR= $(CROSS_COMPILE)ar $(ARFLAGS) r |
如果CC= cc(没有前缀),说明交叉编译没生效,需要重新 Configure。
2.1 Configure 参数说明
./Configure的完整参数含义:
| 参数 | 类型 | 说明 |
|---|---|---|
linux-generic64 | target | 通用 64-bit Linux 平台。OpenSSL 1.0.0 没有linux-aarch64目标,必须用这个 |
shared | 选项 | 同时构建共享库(.so)。不加的话只生成静态库(.a) |
--prefix=$PWD/_install | 路径 | make install时的安装根目录(头文件、库、证书等) |
--openssldir=$PWD/_install/ssl | 路径 | OpenSSL 运行时查找证书/配置文件的默认目录 |
no-idea | 禁用算法 | IDEA 对称加密。专利算法(专利已过期,但旧版 OpenSSL 默认不编译),不写会报idea.h: No such file |
no-md2 | 禁用算法 | MD2 哈希。已被证明极度不安全(1998 年即被碰撞),没必要保留 |
no-mdc2 | 禁用算法 | MDC2 哈希。老旧算法,极少使用 |
no-rc5 | 禁用算法 | RC5 对称加密。专利算法(已过期),默认不编译 |
no-ssl2 | 禁用协议 | SSL 2.0。已废弃且不安全(受 POODLE 等攻击,RFC 6176 废弃) |
no-ssl3 | 禁用协议 | SSL 3.0。已废弃且不安全(受 POODLE 攻击,RFC 7568 废弃) |
-DOPENSSL_NO_HEARTBEATS | 编译宏 | 禁用 TLS Heartbeat 扩展。Heartbleed 漏洞(CVE-2014-0160)的根源 |
关于no-xxx(禁用算法/协议)
OpenSSL 的./Configure接受no-<feature>在编译时剔除不需要的算法,作用:
- 减小体积:禁用的算法不会编译进
.so,库文件更小 - 规避专利:IDEA、RC5 曾是专利算法(已过期,但旧版本仍需显式启用)
- 消除安全风险:MD2/SSL2/SSL3 已被证明不安全,没必要保留
建议:如果不确定需要哪些算法,全加上是最安全的——能显著减小编译产物体积,并消除已知的安全风险算法。
如果你的项目确实需要某个算法(比如必须支持 SSL3 的 legacy 设备),去掉对应的
no-xxx即可。
关于-DOPENSSL_NO_HEARTBEATS(编译宏)
OpenSSL 1.0.0 本身不支持 Heartbeat(Heartbeat 是 1.0.1 引入的),所以这个宏在 1.0.0 上是冗余的。
但写上无害,且如果哪天换到 1.0.1+ 版本就能自动防 Heartbleed。
最简配置(不禁用任何算法)
如果你不想禁用任何算法,可以把这行:
12345 | ./Configure linux-generic64 shared \ --prefix=$PWD/_install \ --openssldir=$PWD/_install/ssl \ no-idea no-md2 no-mdc2 no-rc5 no-ssl2 no-ssl3 \ -DOPENSSL_NO_HEARTBEATS |
简化为:
123 | ./Configure linux-generic64 shared \ --prefix=$PWD/_install \ --openssldir=$PWD/_install/ssl |
Configure 会自动尝试编译所有算法,遇到编译失败的会跳过。只有在你需要减小体积或明确禁用某些算法时才加no-xxx。
3. 修改 Makefile(关键修复)
Configure生成的Makefile里,ARFLAGS默认是空的,且AR的定义顺序有问题:
12 | ARFLAGS= # ← 空AR= $(CROSS_COMPILE)ar $(ARFLAGS) r |
两个问题叠加导致构建失败:
- 瘦归档问题:某些版本的交叉工具链(包括本文用的 Arm GNU Toolchain 11.2)的
ar在ARFLAGS为空时,默认创建瘦归档(thin archive)——归档里只存符号表,不内嵌.o文件内容。链接时ld读取成员会失败:
1 | ld: libcrypto.a: member libcrypto.a(cryptlib.o) in archive is not an object |
- AR 参数顺序问题:
ar的语法是ar [-]X[MOPTS] archive [members],操作符(r)必须紧挨着ar或放在MOPTS前面。错误的顺序ar c r(ARFLAGS=c但顺序未修正时)会让ar把r当成归档文件名。
修复:把ARFLAGS改成c(create),并把AR定义里的r和ARFLAGS顺序互换。
⚠️ 重要:OpenSSL 1.0.0 有 3 个 Makefile 需要改(顶层、
crypto/、ssl/),因为crypto/Makefile和ssl/Makefile各自有独立的AR定义,且硬编码了ar r(没有$(CROSS_COMPILE)前缀)。顶层 Makefile 通过make -e传AR环境变量,但子 Makefile 里的AR定义优先级更高。
123456789 | # 顶层 Makefilesed -i 's/^ARFLAGS= $/ARFLAGS=c/' Makefilesed -i 's/^AR= $(CROSS_COMPILE)ar $(ARFLAGS) r$/AR= $(CROSS_COMPILE)ar r$(ARFLAGS)/' Makefile# crypto/Makefile(注意行首是 tab)sed -i 's|^AR= ar r|AR= $(CROSS_COMPILE)ar r$(ARFLAGS)|' crypto/Makefile# ssl/Makefile(注意行首是 tab)sed -i 's|^AR= ar r|AR= $(CROSS_COMPILE)ar r$(ARFLAGS)|' ssl/Makefile |
改完验证:
1 | grep -E '^ARFLAGS|^AR=' Makefile crypto/Makefile ssl/Makefile |
期望输出:
1234 | Makefile: ARFLAGS=cMakefile: AR= $(CROSS_COMPILE)ar r$(ARFLAGS)crypto/Makefile: AR= $(CROSS_COMPILE)ar r$(ARFLAGS)ssl/Makefile: AR= $(CROSS_COMPILE)ar r$(ARFLAGS) |
展开后实际调用:aarch64-none-linux-gnu-ar rc ../../libcrypto.a *.o—— 正确的胖归档格式。
原理
ar命令的 mode 字母含义:r:替换/插入成员(operation)c:创建归档(如果不存在)(modifier)s:写入符号索引(等同于单独跑ranlib)
GNU ar 的语法:
ar [-]X[MOPTS] archive [members]X = operation(r/d/m/p/q/t/x)
MOPTS = modifiers(c/v/w/…)
错误的ar $(ARFLAGS) r(当 ARFLAGS=c 时变成ar c r)会让ar把r当归档名。 正确写法是ar r$(ARFLAGS)→ar rc。
4. 编译(直接 make)
12 | make depend # 必须先跑,因为 ./Configure 改过算法开关make # 不可以 make -j$(nproc) |
编译完成后会得到:
1234 | libcrypto.so -> libcrypto.so.1.0.0 (符号链接)libcrypto.so.1.0.0 (2.1 MB, ELF aarch64)libssl.so -> libssl.so.1.0.0 (符号链接)libssl.so.1.0.0 (387 KB, ELF aarch64) |
5. 验证产物
123456789101112131415161718 | # 文件类型file libcrypto.so libssl.so# 期望:ELF 64-bit LSB shared object, ARM aarch64, ...# 大小(libcrypto ≈ 2.1 MB,libssl ≈ 387 KB)ls -lh libcrypto.so libssl.so# 导出符号aarch64-none-linux-gnu-nm -D libcrypto.so | grep -E 'SSLeay|RAND_bytes|AES_set_encrypt_key'aarch64-none-linux-gnu-nm -D libssl.so | grep -E 'SSL_library_init|TLSv1_method|DTLSv1_method'# ELF 头aarch64-none-linux-gnu-readelf -h libcrypto.so | grep -E 'Class|Machine|Type'# 期望:Class: ELF64 / Machine: AArch64 / Type: DYN (Shared object file)# libssl.so 应依赖 libcrypto.soaarch64-none-linux-gnu-readelf -d libssl.so | grep NEEDED# 期望:NEEDED Shared library: [libcrypto.so.1.0.0] |
6. 安装
12 | export INSTALLDIR=$HOME/repository/openssl-1.0.0s/_installmake install |
最终目录结构:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 | _install├── bin│ ├── c_rehash│ └── openssl├── include│ └── openssl│ ├── aes.h│ ├── asn1.h│ ├── asn1_mac.h│ ├── asn1t.h│ ├── bio.h│ ├── blowfish.h│ ├── bn.h│ ├── buffer.h│ ├── camellia.h│ ├── cast.h│ ├── cms.h│ ├── comp.h│ ├── conf.h│ ├── conf_api.h│ ├── crypto.h│ ├── des.h│ ├── des_old.h│ ├── dh.h│ ├── dsa.h│ ├── dso.h│ ├── dtls1.h│ ├── e_os2.h│ ├── ebcdic.h│ ├── ec.h│ ├── ecdh.h│ ├── ecdsa.h│ ├── engine.h│ ├── err.h│ ├── evp.h│ ├── hmac.h│ ├── krb5_asn.h│ ├── kssl.h│ ├── lhash.h│ ├── md4.h│ ├── md5.h│ ├── modes.h│ ├── obj_mac.h│ ├── objects.h│ ├── ocsp.h│ ├── opensslconf.h│ ├── opensslv.h│ ├── ossl_typ.h│ ├── pem.h│ ├── pem2.h│ ├── pkcs12.h│ ├── pkcs7.h│ ├── pqueue.h│ ├── rand.h│ ├── rc2.h│ ├── rc4.h│ ├── ripemd.h│ ├── rsa.h│ ├── safestack.h│ ├── seed.h│ ├── sha.h│ ├── ssl.h│ ├── ssl2.h│ ├── ssl23.h│ ├── ssl3.h│ ├── stack.h│ ├── symhacks.h│ ├── tls1.h│ ├── ts.h│ ├── txt_db.h│ ├── ui.h│ ├── ui_compat.h│ ├── whrlpool.h│ ├── x509.h│ ├── x509_vfy.h│ └── x509v3.h├── lib│ ├── engines│ │ ├── lib4758cca.so│ │ ├── libaep.so│ │ ├── libatalla.so│ │ ├── libcapi.so│ │ ├── libchil.so│ │ ├── libcswift.so│ │ ├── libgmp.so│ │ ├── libgost.so│ │ ├── libnuron.so│ │ ├── libpadlock.so│ │ ├── libsureware.so│ │ └── libubsec.so│ ├── libcrypto.a│ ├── libcrypto.so -> libcrypto.so.1.0.0│ ├── libcrypto.so.1.0.0│ ├── libssl.a│ ├── libssl.so -> libssl.so.1.0.0│ ├── libssl.so.1.0.0│ └── pkgconfig│ ├── libcrypto.pc│ ├── libssl.pc│ └── openssl.pc│............................... |
7. 一键脚本
把下面内容保存为build-openssl-aarch64.sh,放在openssl-1.0.0s/同级目录:
123456789101112131415161718192021222324252627282930313233343536373839 | set -euo pipefail# ============ 配置 ============# 工具链路径(按你的环境修改)CROSS=${CROSS:-/home/zhaohang/tools/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/bin}CROSS_COMPILE=${CROSS_COMPILE:-aarch64-none-linux-gnu-}# ==============================SRCDIR=$(cd "$(dirname "$0")/openssl-1.0.0s" && pwd)INSTALLDIR="$SRCDIR/_install"export PATH="$CROSS:$PATH"export CROSS_COMPILEcd "$SRCDIR"# 配置./Configure linux-generic64 shared \ --prefix="$INSTALLDIR" \ --openssldir="$INSTALLDIR/ssl" \ no-idea no-md2 no-mdc2 no-rc5 no-ssl2 no-ssl3 \ -DOPENSSL_NO_HEARTBEATS# ★ 关键修复:强制 ar 生成胖归档(修复瘦归档 + AR 参数顺序两个问题)# 需要改 3 个 Makefile:顶层、crypto/、ssl/sed -i 's/^ARFLAGS= $/ARFLAGS=c/' Makefilesed -i 's/^AR= $(CROSS_COMPILE)ar $(ARFLAGS) r$/AR= $(CROSS_COMPILE)ar r$(ARFLAGS)/' Makefilesed -i 's|^AR= ar r|AR= $(CROSS_COMPILE)ar r$(ARFLAGS)|' crypto/Makefilesed -i 's|^AR= ar r|AR= $(CROSS_COMPILE)ar r$(ARFLAGS)|' ssl/Makefile# 编译make dependmake -j1 # 只能 make -j1 编译# 安装make installecho "=== 构建完成 ===" |
12 | chmod +x build-openssl-aarch64.sh./build-openssl-aarch64.sh |
8. 常见问题排查
| 现象 | 原因 | 修复 |
|---|---|---|
Configure: target already defined | CROSS_COMPILE写成了命令行参数 | 改用export CROSS_COMPILE=...环境变量 |
CC= cc(无前缀) | 用了linux-aarch64等不存在的 target | 改用linux-generic64 |
ld: member ... in archive is not an object | 交叉 ar 生成瘦归档 | 改 3 个 Makefile 的 ARFLAGS/AR(见第 3 节) |
ar: two different operation options specified | ARFLAGS 包含了r(与 AR 定义里的r重复) | ARFLAGS 应该只是c,不能是rc |
ar: creating r或ar: r: No such file | AR 参数顺序错误(ar $(ARFLAGS) r) | sed -i 's/AR=...ar $(ARFLAGS) r$/AR=...ar r$(ARFLAGS)/' Makefile |
| 改了顶层 Makefile 但归档还是瘦归档 | crypto/Makefile和ssl/Makefile有独立的 AR 定义 | 同时改 3 个 Makefile |
.so只有几 KB | 链接时缺--whole-archive(极少见,Makefile 内置了) | 检查 Makefile.shared 的ALLSYMSFLAGS |
编译报openssl/idea.h: No such file | 没加no-idea | Configure 时加no-idea no-mdc2 no-rc5 |
make clean报rm -f install/lib | install/目录已存在且非空 | 手动rm -rf install或忽略该错误 |
9. 总结:四步出 .so
12345678910111213141516171819202122 | # 1. 配置export PATH=/home/zhaohang/tools/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/bin:$PATHexport CROSS_COMPILE=aarch64-none-linux-gnu-# 2. Configure./Configure linux-generic64 shared --prefix=$PWD/_install \ no-idea no-md2 no-mdc2 no-rc5 no-ssl2 no-ssl3 -DOPENSSL_NO_HEARTBEATS# 3. 改 3 个 Makefile 的 AR 定义(修复瘦归档 + AR 参数顺序)sed -i 's/^ARFLAGS= $/ARFLAGS=c/' Makefilesed -i 's/^AR= $(CROSS_COMPILE)ar $(ARFLAGS) r$/AR= $(CROSS_COMPILE)ar r$(ARFLAGS)/' Makefilesed -i 's|^AR= ar r|AR= $(CROSS_COMPILE)ar r$(ARFLAGS)|' crypto/Makefilesed -i 's|^AR= ar r|AR= $(CROSS_COMPILE)ar r$(ARFLAGS)|' ssl/Makefile# 4. 编译make depend && make -j1# 5. 安装make install# 6. 验证file libcrypto.so libssl.so |