Skip to content

deps: enable OpenSSL asm support for riscv64#62606

Open
JamieMagee wants to merge 1 commit intonodejs:mainfrom
JamieMagee:riscv64-openssl-asm
Open

deps: enable OpenSSL asm support for riscv64#62606
JamieMagee wants to merge 1 commit intonodejs:mainfrom
JamieMagee:riscv64-openssl-asm

Conversation

@JamieMagee
Copy link
Copy Markdown
Contributor

When riscv64 was added to the OpenSSL config in 2021 (#40063), OpenSSL had no RISC-V assembly at all, so it went into NO_ASM_ARCHS. OpenSSL 3.5.x now has perlasm generators for AES, SHA-256/512, GHASH/GCM, ChaCha, SM3, SM4, and CPUID. All with runtime extension detection via riscvcap.c and the Linux hwprobe syscall, so there's no risk on hardware without the crypto extensions.

This moves linux64-riscv64 from NO_ASM_ARCHS to ASM_ARCHS in deps/openssl/config/Makefile, regenerates the config (adding asm/ and asm_avx2/ variants with 16 generated assembly files each), and adds riscv64 entries to the six gypi selector files.

Generated with nix shell nixpkgs#nasm -c make linux64-riscv64 in deps/openssl/config/.

Refs: nodejs/build#4099

@nodejs-github-bot
Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/security-wg

@nodejs-github-bot nodejs-github-bot added dependencies Pull requests that update a dependency file. needs-ci PRs that need a full CI run. openssl Issues and PRs related to the OpenSSL dependency. labels Apr 5, 2026
@sxa
Copy link
Copy Markdown
Member

sxa commented Apr 9, 2026

Have just spent a lot of today trying to unbreak my cross-compile environment but it's now working again. Will do some tests with this (natively and with the cross-compile) and see how it goes but this will be great if we can enable the assembly stuff now.

@kxxt
Copy link
Copy Markdown
Member

kxxt commented Apr 10, 2026

I encountered a strange OpenSSL compilation problem where it appears that the build system incorrectly fall-backs to x86_64 asm for a native riscv64 build: https://github.com/riscv-forks/node-riscv/actions/runs/24225505014/job/70735319923

I will give this PR a try in my new experimental CI system for riscv64: riscv-forks/node-riscv#1

@sxa
Copy link
Copy Markdown
Member

sxa commented Apr 10, 2026

I encountered a strange OpenSSL compilation problem where it appears that the build system incorrectly fall-backs to x86_64 asm for a native riscv64 build: https://github.com/riscv-forks/node-riscv/actions/runs/24225505014/job/70735319923

I will give this PR a try in my new experimental CI system for riscv64: riscv-forks/node-riscv#1

FYI I initially hit that as well when I hadn't included the --dest-cpu=riscv64 in the configure command when cross compiling (I typically run with CC and CXX set to clang with the appropriate --target and -march flags)

@kxxt
Copy link
Copy Markdown
Member

kxxt commented Apr 10, 2026

I encountered a strange OpenSSL compilation problem where it appears that the build system incorrectly fall-backs to x86_64 asm for a native riscv64 build: https://github.com/riscv-forks/node-riscv/actions/runs/24225505014/job/70735319923
I will give this PR a try in my new experimental CI system for riscv64: riscv-forks/node-riscv#1

FYI I initially hit that as well when I hadn't included the --dest-cpu=riscv64 in the configure command when cross compiling (I typically run with CC and CXX set to clang with the appropriate --target and -march flags)

Yeah, that might be expected in a cross-compilation setup. But I find it surprising because I am compiling natively on riscv64.

@panva
Copy link
Copy Markdown
Member

panva commented Apr 10, 2026

note: #62629 just landed with OpenSSL update to 3.5.6

@sxa
Copy link
Copy Markdown
Member

sxa commented Apr 10, 2026

Yeah, that might be expected in a cross-compilation setup. But I find it surprising because I am compiling natively on riscv64.

Interesting - my native build (clang21 with -march=rv64gc) seemed to go ok from this branch.

@JamieMagee JamieMagee force-pushed the riscv64-openssl-asm branch from 428839b to 3359202 Compare April 10, 2026 18:19
@JamieMagee
Copy link
Copy Markdown
Contributor Author

note: #62629 just landed with OpenSSL update to 3.5.6

Rebased on top of main and regenerated the riscv64 configs for 3.5.6.

@JamieMagee JamieMagee force-pushed the riscv64-openssl-asm branch from 3359202 to 9ad173a Compare April 21, 2026 06:18
Copy link
Copy Markdown
Member

@kxxt kxxt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also update the GN build recipe to add linux64-riscv64 ?

} else if (is_linux) {
if (current_cpu == "x86") {
config_path_name = "linux-elf"
} else if (current_cpu == "x64") {
config_path_name = "linux-x86_64"
} else if (current_cpu == "arm") {
config_path_name = "linux-armv4"
} else if (current_cpu == "arm64") {
config_path_name = "linux-aarch64"
}
} else if (is_apple) {

I am preparing patches to enable GN built Node.js for riscv64 and this would be necessary.

@JamieMagee JamieMagee force-pushed the riscv64-openssl-asm branch from 9ad173a to 5ea800d Compare April 21, 2026 15:29
@JamieMagee
Copy link
Copy Markdown
Contributor Author

@kxxt Done, added linux64-riscv64 to unofficial.gni. Thanks for the heads up.

@JamieMagee JamieMagee requested a review from kxxt April 21, 2026 15:31
Copy link
Copy Markdown
Member

@kxxt kxxt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we also need to update the following files?

#if defined(OPENSSL_LINUX) && defined(__i386__)
# include "./archs/linux-elf/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#elif defined(OPENSSL_LINUX) && defined(__ILP32__)
# include "./archs/linux-x32/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#elif defined(OPENSSL_LINUX) && defined(__x86_64__)
# include "./archs/linux-x86_64/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#elif defined(OPENSSL_LINUX) && defined(__arm__)
# include "./archs/linux-armv4/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#elif defined(OPENSSL_LINUX) && defined(__aarch64__)
# include "./archs/linux-aarch64/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#elif defined(__APPLE__) && defined(__MACH__) && defined(__i386__)
# include "./archs/darwin-i386-cc/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#elif defined(__APPLE__) && defined(__MACH__) && defined(__x86_64__)
# include "./archs/darwin64-x86_64-cc/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#elif defined(__APPLE__) && defined(__MACH__) && defined(__arm64__)
# include "./archs/darwin64-arm64-cc/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#elif defined(_WIN32) && defined(_M_IX86)
# include "./archs/VC-WIN32/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#elif defined(_WIN32) && defined(_M_X64)
# include "./archs/VC-WIN64A/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#elif (defined(__FreeBSD__) || defined(__OpenBSD__)) && defined(__i386__)
# include "./archs/BSD-x86/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#elif (defined(__FreeBSD__) || defined(__OpenBSD__)) && defined(__x86_64__)
# include "./archs/BSD-x86_64/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#elif defined(__sun) && defined(__i386__)
# include "./archs/solaris-x86-gcc/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#elif defined(__sun) && defined(__x86_64__)
# include "./archs/solaris64-x86_64-gcc/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#elif defined(OPENSSL_LINUX) && defined(__PPC64__) && defined(L_ENDIAN)
# include "./archs/linux-ppc64le/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#elif defined(_AIX) && defined(_ARCH_PPC64)
# include "./archs/aix64-gcc-as/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#elif defined(OPENSSL_LINUX) && defined(__s390x__)
# include "./archs/linux64-s390x/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#elif defined(OPENSSL_LINUX) && defined(__s390__)
# include "./archs/linux32-s390x/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#else
# include "./archs/linux-elf/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#endif

#if defined(OPENSSL_LINUX) && defined(__i386__)
# include "./archs/linux-elf/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#elif defined(OPENSSL_LINUX) && defined(__ILP32__)
# include "./archs/linux-x32/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#elif defined(OPENSSL_LINUX) && defined(__x86_64__)
# include "./archs/linux-x86_64/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#elif defined(OPENSSL_LINUX) && defined(__arm__)
# include "./archs/linux-armv4/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#elif defined(OPENSSL_LINUX) && defined(__aarch64__)
# include "./archs/linux-aarch64/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#elif defined(OPENSSL_LINUX) && defined(__loongarch64)
# include "./archs/linux64-loongarch64/%%-$asmdir-%%/include/%%-$incdir-%%/%%-$name-%%.h"
#elif defined(__APPLE__) && defined(__MACH__) && defined(__i386__)

Comment thread deps/openssl/config/Makefile
Comment thread deps/openssl/config/archs/linux64-riscv64/no-asm/configdata.pm Outdated
Copy link
Copy Markdown
Member

@sxa sxa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm I've built with this and if I've tested correctly it doesn't seem to show an improvement on the https tests (run without autocannon). I'd have hoped it would improve that a bit (as it does on x64).
I might also try and compare with a version using the system openssl on my boards to see if that shows any difference but do you have any tests where the results are noticeable?

Move linux64-riscv64 from NO_ASM_ARCHS to ASM_ARCHS in the OpenSSL
config Makefile and regenerate the configuration. This adds asm/ and
asm_avx2/ config variants alongside the existing no-asm/ variant.

When riscv64 was first added to the OpenSSL config in 2021 (nodejs#40063),
OpenSSL had no RISC-V assembly support. OpenSSL 3.5.x now ships 17
perlasm generators covering AES (zvkned, zvkb, zkn), SHA-256/512
(zvknha, zvknhb), GHASH/GCM (zvkg, zvbc), ChaCha (v, zbb), SM3
(zvksh), SM4 (zvksed), and CPUID detection. Runtime capability
detection via riscvcap.c and the Linux hwprobe syscall ensures safe
fallback to generic C code on hardware without these extensions.

Also add riscv64 entries to the six asm gypi selector files:
openssl_asm.gypi, openssl_asm_avx2.gypi, openssl-cl_asm.gypi,
openssl-cl_asm_avx2.gypi, openssl-fips_asm.gypi, and
openssl-fips_asm_avx2.gypi.

Refs: nodejs/build#4099
Signed-off-by: Jamie Magee <jamie.magee@gmail.com>
@JamieMagee JamieMagee force-pushed the riscv64-openssl-asm branch from 5ea800d to 77a251a Compare April 22, 2026 18:34
@JamieMagee
Copy link
Copy Markdown
Contributor Author

Do we also need to update the following files?

@kxxt Yes, they did need updating. Added __riscv && __riscv_xlen == 64 to both templates, then regenerated the headers with make gen-openssl.

Hmmm I've built with this and if I've tested correctly it doesn't seem to show an improvement on the https tests (run without autocannon). I'd have hoped it would improve that a bit (as it does on x64). I might also try and compare with a version using the system openssl on my boards to see if that shows any difference but do you have any tests where the results are noticeable?

@sxa The asm codepaths for riscv64 in OpenSSL 3.5 are mostly scalar optimizations and AES/SHA intrinsics. The gains are probably more modest than x86 where you get AVX/AES-NI. If you're seeing no difference on HTTPS benchmarks specifically, it might be worth checking openssl speed aes-256-gcm sha256 with and without the asm build to isolate whether the crypto layer itself is faster, separate from the HTTP overhead.

@JamieMagee JamieMagee requested review from kxxt, richardlau and sxa April 22, 2026 18:39
Copy link
Copy Markdown
Member

@kxxt kxxt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. But my approval doesn't count here, I think.

@sxa
Copy link
Copy Markdown
Member

sxa commented Apr 28, 2026

@sxa The asm codepaths for riscv64 in OpenSSL 3.5 are mostly scalar optimizations and AES/SHA intrinsics. The gains are probably more modest than x86 where you get AVX/AES-NI. If you're seeing no difference on HTTPS benchmarks specifically, it might be worth checking openssl speed aes-256-gcm sha256 with and without the asm build to isolate whether the crypto layer itself is faster, separate from the HTTP overhead.

Trying with openssl speed aes-256-cbc sha256 (aes-256-gcm doesn't exist for speed) shows that sha256 doesn't show any improvement but I get about 16% improvement for aes-256-cbc when asm is enabled.

@JamieMagee
Copy link
Copy Markdown
Contributor Author

@sxa Thanks for running this. I dug a little bit more into what OpenSSL 3.5.6 actually ships, and what the hardware requirements are.

3.5.6 has no scalar SHA asm for RISC-V at all. The only file is sha256-riscv64-zvkb-zvknha_or_zvknhb.pl, gated on V+Zvkb+(Zvknha|Zvknhb)+VLEN≥128. Without those, sha_riscv.c falls through to C and this PR does nothing for SHA. Julian Zhu's Zbb-scalar variant (openssl/openssl#27381) is master/3.6 only.

Same on the asymmetric side: no BN-mont, no ECDSA-P256 in 3.5.6. BN-mont (openssl/openssl#28012) and SM2 (openssl/openssl#25918) are both 3.6. So the TLS handshake is unaffected by this PR regardless of hardware.

What's actually live on rv64gc is the generic 4-table AES asm (your 16% on aes-256-cbc), plus the V+Zbb ChaCha20 path if your hardware exposes it. The Zvkned AES, fused AES-GCM, and vector SHA paths all need the vector crypto extensions, which I don't think any shipping silicon has.

So for TLS 1.3 on rv64gc with this PR: the bulk cipher gets the AES-CBC boost on its AES portion, GHASH stays in C (no Zbc on rv64gc), SHA stays in C, handshake stays in C. A full HTTPS run on this hardware is dominated by paths the PR can't reach in 3.5.6.

The next OpenSSL bump should change that. BN-mont alone usually moves RSA handshake numbers by 5–10% on similar work for other arches, and the Zbb scalar SHA-256 lands at the same time.

@sxa
Copy link
Copy Markdown
Member

sxa commented Apr 29, 2026

@sxa Thanks for running this. I dug a little bit more into what OpenSSL 3.5.6 actually ships, and what the hardware requirements are.

Thanks that makes sense - the board I was primarily testing on (SpacemiT-K1) has the V extension with a suitable length but not the crypto vector bits. I guess we'll see if we get boost with the next openssl bump.

I did try a quick test by building a standalone openssl 3.5 vs 3.6 and it only seemed to show a 2% boost for openssl speed sha256 on my system, although the same under qemu (which presumably defaulted to having all the extensions) gave around a a 75% boost for sha256 between 3.5 and 3.6.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file. needs-ci PRs that need a full CI run. openssl Issues and PRs related to the OpenSSL dependency.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants