ARM64 SVE for Crypto: Ship One Binary, Test for the Oldest CPU
ARM64's Scalable Vector Extension can speed up crypto, but an SVE-only binary crashes on older CPUs. Use feature detection and a scalar fallback.
13 Aug 2026, 23:01 UTC

The crash you did not expect
You ship a new ARM64 build of your TLS termination service. It accelerates AES-256-GCM with wide vector instructions. On your development server it runs fine. On an older production node, the process dies with SIGILL before completing the first handshake.
The problem is usually not your cryptographic code. It is the CPU. ARM64's Scalable Vector Extension (SVE) lets a single binary use vector units of different widths, but only if the silicon actually implements it. Older ARMv8.2 nodes and many mobile SoCs do not. If you ship SVE instructions without a guard, they become illegal instructions on those hosts.
The practical takeaway: you can use SVE to accelerate vectorizable primitives such as AES, SHA-256, or ChaCha20, but you must detect SVE at runtime and keep a scalar fallback for nodes that lack it.
What SVE changes for vector code
SVE is a vector extension where the hardware vector length is not fixed at compile time. The same compiled code can run efficiently on 128-bit, 256-bit, 512-bit, or wider vector units. This is sometimes called "vector-length agnostic" code.
Instead of fixed-width registers, SVE uses scalable vector registers and predicate registers (p0 through p15) to mask lanes. A predicate register holds one bit per vector element, so the same instruction can process part of a vector without branching inside the loop. That is useful for crypto primitives that operate on fixed-size blocks but benefit from processing multiple blocks in parallel.
Unfamiliar terms: SIGILL is the signal sent when a CPU encounters an instruction it does not implement. Predicate register is a special register that controls which lanes of a vector operation are active.
Check the host before you build
Run this on each target host class, not just your laptop:
grep -m1 'sve' /proc/cpuinfo
Where: any shell on the target ARM64 host. Permissions: none required. Expected check: a line containing sve or sve2 in the Features block. Risk: no output means SVE is absent, and an SVE binary will crash there.
On the build host, compile with an explicit architecture flag so the compiler cannot silently fall back to scalar code:
gcc -O2 -march=armv8-a+simd+sve -o aes_sve aes_sve.c
Where: build host with GCC 12+ or Clang 14+. Permissions: write access to the output directory. Expected check: the command completes without architecture errors. Risk: the resulting binary runs only on SVE-capable CPUs.
Verify that SVE instructions were actually emitted:
objdump -d aes_sve | grep -i sve
Expected check: lines showing SVE mnemonics. If the output is empty, the compiler did not vectorize with SVE.
Worked example: a guarded crypto path
Structure your library so the hot function chooses an implementation at startup:
void encrypt(const uint8_t *key, const uint8_t *nonce,
const uint8_t *in, uint8_t *out, size_t len)
{
if (cpu_has_sve()) {
encrypt_sve(key, nonce, in, out, len);
} else {
encrypt_scalar(key, nonce, in, out, len);
}
}
cpu_has_sve() can be implemented by checking the operating system's hardware capability interface, such as parsing /proc/self/auxv or /proc/cpuinfo on Linux. Do not rely on a compile-time macro alone; a binary built with SVE can still start on a CPU that lacks it and fail later.
This keeps one deployable artifact while protecting older nodes. The SVE path can process multiple blocks per instruction using the available vector width; the scalar path handles everything else.
Trade-offs and limits
- Portability: SVE is optional on many ARM64 chips. A binary containing SVE instructions raises SIGILL on CPUs without the extension.
- Alignment and predicates: SVE code benefits from careful data alignment and correct use of predicate registers; mistakes can cause silent data hazards or crashes.
- Tooling:
objdumpandperfcan show SVE instructions and events, but source-level debugging of vector registers is more limited than for scalar code. - Kernel support: Older Linux kernels may not expose the full SVE state to user space, which can limit or block SVE usage even when the hardware supports it.
What to do before you deploy
- Inventory your oldest target node with
grep sve /proc/cpuinfo. - Build the SVE implementation with
-march=armv8-a+simd+sveand keep a scalar implementation in the same binary. - Add a runtime guard so the scalar path runs when
cpu_has_sve()is false. - Run
objdump -don the build artifact to confirm SVE instructions appear. - Smoke test the binary on a staging node matching your oldest production CPU. Watch for SIGILL in
dmesgor the process exit code.
If the staging node runs cleanly and objdump shows SVE mnemonics, you have a single binary that accelerates where possible and degrades safely where it cannot.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.