OpenSSL1.0.0s aarch64交叉编译


时间轴

时间轴

2025-12-29

init

本文介绍了在x86_64主机上使用ARM交叉工具链编译OpenSSL 1.0.0s的aarch64共享库的完整流程,包括环境准备、Configure配置(需使用linux-aarch64 target并通过环境变量CROSS_COMPILE指定工具链前缀)、修改三个Makefile中的ARFLAGS和AR定义以解决瘦归档和参数顺序问题,以及编译、安装和常见问题排查方法。

目标:在 x86_64 主机上,使用aarch64-none-linux-gnu-交叉工具链, 编译出libssl.solibcrypto.so(ARM aarch64 共享库)。

1. 环境准备

1.1 源码

1
2
3
4
5
6
cd ~/repository

wget https://github.com/openssl/openssl/releases/download/OpenSSL_1_0_0s/openssl-1.0.0s.tar.gz

tar xvf openssl-1.0.0s.tar.gz # 如果尚未解压
cd openssl-1.0.0s

1.2 交叉工具链

本文使用 Arm GNU Toolchain 11.2-2022.02aarch64-none-linux-gnu-三元组)。

ARM目前总共发布了8种架构:ARMv1、ARMv2、ARMv3、ARMv4、ARMv5、ARMv6、ARMv7、ARMv8。

针对于支持ARMv8指令集的处理器可以使用-march=armv8-a参数编译代码,ARM GNU编译器可通过下面的链接下载

推荐使用ARM官网的编译器,它是Portable的,解压后即可使用。

本文使用的是11.2版本的交叉编译器

可以将其添加到环境变量

1
2
3
# ~/.bashrc或~/.bash_profile
emacs ~/.bashrc
export 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-none-linux-gnu-gcc
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指定工具链前缀。

1
2
3
4
5
6
7
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

期望输出:

1
2
3
CROSS_COMPILE= aarch64-none-linux-gnu-
CC= $(CROSS_COMPILE)gcc
AR= $(CROSS_COMPILE)ar $(ARFLAGS) r

如果CC= cc(没有前缀),说明交叉编译没生效,需要重新 Configure。

2.1 Configure 参数说明

./Configure的完整参数含义:

参数类型说明
linux-generic64target通用 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。

最简配置(不禁用任何算法)

如果你不想禁用任何算法,可以把这行:

1
2
3
4
5
./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

简化为:

1
2
3
./Configure linux-generic64 shared \
--prefix=$PWD/_install \
--openssldir=$PWD/_install/ssl

Configure 会自动尝试编译所有算法,遇到编译失败的会跳过。只有在你需要减小体积明确禁用某些算法时才加no-xxx


3. 修改 Makefile(关键修复)

Configure生成的Makefile里,ARFLAGS默认是空的,且AR的定义顺序有问题:

1
2
ARFLAGS=                  # ← 空
AR= $(CROSS_COMPILE)ar $(ARFLAGS) r

两个问题叠加导致构建失败

  1. 瘦归档问题:某些版本的交叉工具链(包括本文用的 Arm GNU Toolchain 11.2)的arARFLAGS为空时,默认创建瘦归档(thin archive)——归档里只存符号表,不内嵌.o文件内容。链接时ld读取成员会失败:
1
ld: libcrypto.a: member libcrypto.a(cryptlib.o) in archive is not an object
  1. AR 参数顺序问题ar的语法是ar [-]X[MOPTS] archive [members],操作符(r)必须紧挨着ar或放在MOPTS前面。错误的顺序ar rc r会让ar把最后的r当成归档文件名。

修复:把ARFLAGS改成c(create),并把AR定义里的rARFLAGS顺序互换。

⚠️ 重要:OpenSSL 1.0.0 有 3 个 Makefile 需要改(顶层、crypto/ssl/), 因为crypto/Makefilessl/Makefile各自有独立的AR定义, 且**硬编码了 **ar r(没有$(CROSS_COMPILE)前缀)。 顶层 Makefile 通过make -eAR环境变量,但子 Makefile 里的AR定义优先级更高。

1
2
3
4
5
6
7
8
9
# 顶层 Makefile
sed -i 's/^ARFLAGS= $/ARFLAGS=c/' Makefile
sed -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

期望输出:

1
2
3
4
Makefile:      ARFLAGS=c
Makefile: 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)会让arr当归档名。 正确写法是ar r$(ARFLAGS)ar rc


4. 编译(直接 make)

1
2
make depend   # 必须先跑,因为 ./Configure 改过算法开关
make # 不可以 make -j$(nproc)

编译完成后会得到:

1
2
3
4
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. 验证产物

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 文件类型
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.so
aarch64-none-linux-gnu-readelf -d libssl.so | grep NEEDED
# 期望:NEEDED Shared library: [libcrypto.so.1.0.0]

6. 安装

1
2
export INSTALLDIR=$HOME/repository/openssl-1.0.0s/_install
make install

最终目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
_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/同级目录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/usr/bin/env bash
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_COMPILE

cd "$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/' Makefile
sed -i 's/^AR= $(CROSS_COMPILE)ar $(ARFLAGS) r$/AR= $(CROSS_COMPILE)ar r$(ARFLAGS)/' Makefile
sed -i 's|^AR= ar r|AR= $(CROSS_COMPILE)ar r$(ARFLAGS)|' crypto/Makefile
sed -i 's|^AR= ar r|AR= $(CROSS_COMPILE)ar r$(ARFLAGS)|' ssl/Makefile

# 编译
make depend
make -j1 # 只能 make -j1 编译

# 安装
make install

echo "=== 构建完成 ==="
1
2
chmod +x build-openssl-aarch64.sh
./build-openssl-aarch64.sh

8. 常见问题排查

现象原因修复
Configure: target already definedCROSS_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 specifiedARFLAGS 包含了r(与 AR 定义里的r重复)ARFLAGS 应该只是c,不能是rc
ar: creating rar: r: No such fileAR 参数顺序错误(ar $(ARFLAGS) rsed -i 's/AR=...ar $(ARFLAGS) r$/AR=...ar r$(ARFLAGS)/' Makefile
改了顶层 Makefile 但归档还是瘦归档crypto/Makefilessl/Makefile有独立的 AR 定义同时改 3 个 Makefile
.so只有几 KB链接时缺--whole-archive(极少见,Makefile 内置了)检查 Makefile.shared 的ALLSYMSFLAGS
编译报openssl/idea.h: No such file没加no-ideaConfigure 时加no-idea no-mdc2 no-rc5
make cleanrm -f install/libinstall/目录已存在且非空手动rm -rf install或忽略该错误

9. 总结:四步出 .so

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 1. 配置
export PATH=/home/zhaohang/tools/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/bin:$PATH
export 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/' Makefile
sed -i 's/^AR= $(CROSS_COMPILE)ar $(ARFLAGS) r$/AR= $(CROSS_COMPILE)ar r$(ARFLAGS)/' Makefile
sed -i 's|^AR= ar r|AR= $(CROSS_COMPILE)ar r$(ARFLAGS)|' crypto/Makefile
sed -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