Timeline
Timeline
2026-07-16
init
This article describes the complete process of cross-compiling OpenSSL 1.0.0s using Arm GNU Toolchain 11.2 on an x86_64 host to generate aarch64 shared libraries (.so). It first explains environment preparation, including source selection and cross-toolchain configuration, and points out that OpenSSL 1.0.0 has no dedicated aarch64 target, so a generic 64-bit target must be used and the toolchain prefix specified via environment variables. It then analyzes the Configure parameters in detail, including disabling the IDEA, MD2, MDC2, RC5 algorithms and SSL 2.0/3.0 protocols, and explains the related security considerations. The article focuses on solving a key build problem: because the cross-toolchain ar creates thin archives by default when ARFLAGS is empty, and the AR argument order is wrong, linking fails, so the ARFLAGS and AR definitions in the top-level Makefile, Makefile, and Makefile.shared must all be modified. Finally, it summarizes the compilation, verification, and installation steps, and provides a common problem troubleshooting table. This article is for the ARM64 platform
Objective: On an x86_64 host, useaarch64-none-linux-gnu-the cross-toolchain to compilelibssl.soandlibcrypto.so(ARM aarch64 shared libraries).
1. Environment Preparation
1.1 Source Code
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 # If not yet extractedcd openssl-1.0.0s |
If you don’t have to use OpenSSL 1.0.0, OpenSSL 1.1.1 is more recommended, as the code is more robust and compilation is simpler.
123 | ./Configure linux-aarch64 --cross-compile-prefix=aarch64-none-linux- --prefix=$PWD/_install sharedmake -j$(nproc) |
1.2 Cross Toolchain
This article uses Arm GNU Toolchain 11.2-2022.02(aarch64-none-linux-gnu-triplet).
ARM has released 8 architectures in total: ARMv1, ARMv2, ARMv3, ARMv4, ARMv5, ARMv6, ARMv7, ARMv8.
For processors supporting the ARMv8 instruction set, you can use-march=armv8-aCompile code with the appropriate parameters; the ARM GNU compiler can be downloaded from the link below.
It is recommended to use the compiler from ARM’s official website. It is portable and can be used after extraction.
This article uses the 11.2 version of the cross-compiler.
You can add it to the environment variables.
123 | # ~/.bashrc or ~/.bash_profileemacs ~/.bashrcexport PATH="$HOME/tools/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/bin:$PATH" |
Using version 11.2.1 ofaarch64-none-linux-gnu-gcc

If the toolchain triplet is
aarch64-linux-gnu-(e.g., Ubuntu’sgcc-aarch64-linux-gnupackage), replace all the followingaarch64-none-linux-gnu-withaarch64-linux-gnu-That’s all.
2. Configuration (Configure)
OpenSSL 1.0.0 does notlinux-aarch64This target (even if it can be selected on the command line, it will fall back to the host’scc, and the output is x86_64).
The correct approach is to use the generic 64-bit targetlinux-generic64, andEnvironment variablesCROSS_COMPILEspecify the toolchain prefix.
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 |
⚠️ Important:
CROSS_COMPILEmust use Environment variables pass in.
If written as./Configure ... CROSS_COMPILE=...command-line argument,
the OpenSSL 1.0.0 Configure script will report:target already defined - linux-generic64 (offending arg: CROSS_COMPILE=...)
After configuration, checkMakefileto confirm cross-compilation is effective:
1 | grep -E '^(CC|CROSS_COMPILE|AR)=' Makefile |
Expected output:
123 | CROSS_COMPILE= aarch64-none-linux-gnu-CC= $(CROSS_COMPILE)gccAR= $(CROSS_COMPILE)ar $(ARFLAGS) r |
ifCC= cc(no prefix), indicating that cross-compilation did not take effect; you need to run Configure again.
2.1 Description of Configure parameters
./ConfigureThe full meanings of the parameters are:
| Parameters | Type | Description |
|---|---|---|
linux-generic64 | target | Generic 64-bit Linux platform. OpenSSL 1.0.0 does not havelinux-aarch64target, so you must use this one |
shared | Options | Also build shared libraries (.so). If not added, only static libraries are generated (.a) |
--prefix=$PWD/_install | path | make installthe installation root directory when specified (headers, libraries, certificates, etc.) |
--openssldir=$PWD/_install/ssl | path | The default directory where OpenSSL looks for certificates/config files at runtime |
no-idea | Disable algorithm | IDEA symmetric encryption.patented algorithm(patent has expired, but old versions of OpenSSL do not compile it by default); if not specified, it will reportidea.h: No such file |
no-md2 | Disable algorithm | MD2 hash. It has been provenextremely insecure(collision was found as early as 1998), so there is no need to keep it |
no-mdc2 | Disable algorithm | MDC2 hash. An old algorithm, rarely used. |
no-rc5 | Disable algorithm | RC5 symmetric encryption.patented algorithm(has expired), not compiled by default |
no-ssl2 | Disabled protocols | SSL 2.0。Deprecated and insecure(Deprecated by RFC 6176 due to attacks such as POODLE) |
no-ssl3 | Disabled protocols | SSL 3.0。Deprecated and insecure(Deprecated by RFC 7568 due to the POODLE attack) |
-DOPENSSL_NO_HEARTBEATS | Compile-time macro | Disable the TLS Heartbeat extension.Heartbleed vulnerabilitythe root cause of (CVE-2014-0160) |
Aboutno-xxx(Disabled algorithms/protocols)
OpenSSL’s./Configureacceptanceno-<feature>Beforecompile-time removalof unneeded algorithms, effect:
- Reduce size: disabled algorithms will not be compiled into
.so, the library file is smaller - Avoid patents: IDEA and RC5 were once patented algorithms (patents have expired, but older versions still require explicit enabling)
- Eliminate security risks: MD2/SSL2/SSL3 have been proven insecure, no need to keep them
Recommendation: If you are not sure which algorithms are needed,adding all of them is the safest— can significantly reduce the compiled output size and eliminate known security-risk algorithms.
If your project really needs a certain algorithm (for example, legacy devices that must support SSL3), remove the corresponding
no-xxxThat’s all.
About-DOPENSSL_NO_HEARTBEATS(compile macro)
OpenSSL 1.0.0 itself does not support Heartbeat(Heartbeat was introduced in 1.0.1), so this macro on 1.0.0 isredundant.
But including it is harmless, and if you ever switch to 1.0.1+ it will automatically protect against Heartbleed.
Minimal configuration (without disabling any algorithms)
If you don’t want to disable any algorithms, you can take this line:
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 |
simplify it to:
123 | ./Configure linux-generic64 shared \ --prefix=$PWD/_install \ --openssldir=$PWD/_install/ssl |
Configure will automatically try to compile all algorithms and skip any that fail to compile. Only when youneed to reduce the sizeorexplicitly disable certain algorithmsshould you add itno-xxx。
3. Modify the Makefile (critical fix)
ConfigureThe generatedMakefilein,ARFLAGSis empty by default, andARthe definition order has a problem:
12 | ARFLAGS= # ← emptyAR= $(CROSS_COMPILE)ar $(ARFLAGS) r |
The two problems together cause the build to fail:
- Thin archive problem: of some versions of the cross toolchain (including the Arm GNU Toolchain 11.2 used in this article)
arBeforeARFLAGSWhen empty, create by default.thin archive(thin archive) — the archive only stores the symbol table, without embedding.ofile contents. When linking,ldreading members will fail:
1 | ld: libcrypto.a: member libcrypto.a(cryptlib.o) in archive is not an object |
- AR argument order issue:
arthe syntax isar [-]X[MOPTS] archive [members], the operator (r) must be immediately adjacent toaror placed beforeMOPTSin front. Incorrect orderar c r(ARFLAGS=cbut when the order is not corrected) will causearholdrbe treated as the archive filename.
Fix: changeARFLAGStoc(create), andARin the definitionrandARFLAGSswap the order.
⚠️ Important: OpenSSL 1.0.0 has 3 Makefiles need to be changed (top-level,
crypto/、ssl/), becausecrypto/Makefileandssl/Makefileeach has its own independentARdefinition, and hardcodedar r(no$(CROSS_COMPILE)prefix). The top-level Makefile passesmake -ebiographyARenvironment variables, but in the sub-MakefileARthe definition has higher priority.
123456789 | # top-level Makefilesed -i 's/^ARFLAGS= $/ARFLAGS=c/' Makefilesed -i 's/^AR= $(CROSS_COMPILE)ar $(ARFLAGS) r$/AR= $(CROSS_COMPILE)ar r$(ARFLAGS)/' Makefile# crypto/Makefile (note the line starts with a tab)sed -i 's|^AR= ar r|AR= $(CROSS_COMPILE)ar r$(ARFLAGS)|' crypto/Makefile# ssl/Makefile (note the line starts with a tab)sed -i 's|^AR= ar r|AR= $(CROSS_COMPILE)ar r$(ARFLAGS)|' ssl/Makefile |
After making changes, verify:
1 | grep -E '^ARFLAGS|^AR=' Makefile crypto/Makefile ssl/Makefile |
Expected output:
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) |
Actual call after expansion:aarch64-none-linux-gnu-ar rc ../../libcrypto.a *.o— the correct fat archive format.
Principle
arMeaning of the mode letters in the command:r: replace/insert member (operation)c: create archive (if it does not exist) (modifier)s: write symbol index (equivalent to runningranlib)
GNU ar syntax:
ar [-]X[MOPTS] archive [members]X = operation(r/d/m/p/q/t/x)
MOPTS = modifiers(c/v/w/…)
Incorrectar $(ARFLAGS) r(when ARFLAGS=c it becomesar c r) will makearholdras the archive name. The correct way isar r$(ARFLAGS)→ar rc。
4. Compile (directly make)
12 | make depend # Must run first, because ./Configure changed the algorithm switchesmake # Cannot make -j$(nproc) |
After compilation completes, you will get:
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. Verify the artifacts
123456789101112131415161718 | # File typefile libcrypto.so libssl.so# Expected: ELF 64-bit LSB shared object, ARM aarch64, ...# Size (libcrypto ≈ 2.1 MB, libssl ≈ 387 KB)ls -lh libcrypto.so libssl.so# Exported symbolsaarch64-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 headeraarch64-none-linux-gnu-readelf -h libcrypto.so | grep -E 'Class|Machine|Type'# Expected: Class: ELF64 / Machine: AArch64 / Type: DYN (Shared object file)# libssl.so should depend on libcrypto.soaarch64-none-linux-gnu-readelf -d libssl.so | grep NEEDED# Expected: NEEDED Shared library: [libcrypto.so.1.0.0] |
6. Installation
12 | export INSTALLDIR=$HOME/repository/openssl-1.0.0s/_installmake install |
Final directory structure:
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. One-click script
Save the following content asbuild-openssl-aarch64.sh, and place it inopenssl-1.0.0s/the same directory as:
123456789101112131415161718192021222324252627282930313233343536373839 | set -euo pipefail# ============ Configuration ============# Toolchain path (modify according to your environment)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"# Configuration./Configure linux-generic64 shared \ --prefix="$INSTALLDIR" \ --openssldir="$INSTALLDIR/ssl" \ no-idea no-md2 no-mdc2 no-rc5 no-ssl2 no-ssl3 \ -DOPENSSL_NO_HEARTBEATS# ★ Key fix: force ar to generate a fat archive (fixes two issues: thin archive + AR argument order)# Need to modify 3 Makefiles: top-level, 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# Compilationmake dependmake -j1 # Can only compile with make -j1# Installmake installecho "=== 构建完成 ===" |
12 | chmod +x build-openssl-aarch64.sh./build-openssl-aarch64.sh |
8. Troubleshooting common issues
| Symptom | Reason | Fix |
|---|---|---|
Configure: target already defined | CROSS_COMPILEWritten as command-line arguments | Use insteadexport CROSS_COMPILE=...Environment variables |
CC= cc(no prefix) | usedlinux-aarch64nonexistent targets, etc. | Use insteadlinux-generic64 |
ld: member ... in archive is not an object | cross ar to generate thin archives | Modify ARFLAGS/AR in the 3 Makefiles (see Section 3) |
ar: two different operation options specified | ARFLAGS containsr(with the one in the AR definitionrduplicate) | ARFLAGS should only bec, cannot berc |
ar: creating rorar: r: No such file | AR argument order error (ar $(ARFLAGS) r) | sed -i 's/AR=...ar $(ARFLAGS) r$/AR=...ar r$(ARFLAGS)/' Makefile |
| Changed the top-level Makefile but the archive is still thin | crypto/Makefileandssl/Makefilehas a separate AR definition | Modify the 3 Makefiles simultaneously |
.soonly a few KB | missing at link time--whole-archive(very rare, built into the Makefile) | Check Makefile.shared’sALLSYMSFLAGS |
compilation reportsopenssl/idea.h: No such file | did not addno-idea | add during Configureno-idea no-mdc2 no-rc5 |
make cleanreportsrm -f install/lib | install/directory already exists and is non-empty | manuallyrm -rf installor ignore this error |
9. Summary: Four steps to produce .so
12345678910111213141516171819202122 | # 1. Configurationexport 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. Modify AR definitions in 3 Makefiles (fix thin archive + AR argument order)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. Compilemake depend && make -j1# 5. Installmake install# 6. Verifyfile libcrypto.so libssl.so |