Repository navigation
Restore ADX/AVX2 code paths under OPENSSL_SMALL via new MY_ASSEMBLER_IS_TOO_OLD_FOR_ADX_AVX2 flag - #3368
Conversation
โฆIS_TOO_OLD_FOR_512AVX MY_ASSEMBLER_IS_TOO_OLD_FOR_512AVX has always been documented and used as a combined switch: it disables ADX, AVX2, *and* AVX-512 code together, even though those are independent CPU/assembler feature sets (an assembler can know ADX/AVX2 while still predating AVX-512 -- the common case for anything from roughly Haswell through Cascade Lake). aws#3319 made OPENSSL_SMALL imply this combined flag to shed genuinely AVX-512-only code for size, but that silently disabled every ADX/AVX2 fast path too. Add MY_ASSEMBLER_IS_TOO_OLD_FOR_ADX_AVX2 to carry the ADX/AVX2/BMI2 half of that meaning on its own, so call sites can depend on exactly the assembler capability they need instead of the combined flag. Wire up the implication chain (MY_ASSEMBLER_IS_TOO_OLD_FOR_AVX implies MY_ASSEMBLER_IS_TOO_OLD_FOR_ADX_AVX2 implies MY_ASSEMBLER_IS_TOO_OLD_FOR_512AVX -- not the reverse) in both CMakeLists.txt and include/openssl/target.h, mirroring how the AVX/512AVX implication is already handled for CMake vs. non-CMake (aws-lc-sys CcBuilder) builds. MY_ASSEMBLER_IS_TOO_OLD_FOR_512AVX itself now guards only genuine AVX-512 (zmm/EVEX) code, matching its name. The new flag's option description and status message are scoped precisely to the specific call sites it moves (s2n-bignum, RSA/DH Montgomery, legacy P-256, SHA3 x4-batching) rather than implying it excludes every ADX/AVX2/BMI2 implementation in the tree: ChaCha20, RSAZ-1024, and SHA-1/256/512's AVX2 paths were never tied to the combined flag (they depend only on the stronger MY_ASSEMBLER_IS_TOO_OLD_FOR_AVX) and remain available regardless of this flag's setting. No call site is moved to the new flag yet; this commit only introduces it.
โฆO_OLD_FOR_512AVX Every one of these call sites uses ADX, AVX2, and/or BMI2 -- never genuine AVX-512 (zmm/EVEX) -- but was checking MY_ASSEMBLER_IS_TOO_OLD_FOR_512AVX, so OPENSSL_SMALL's implication of that flag (aws#3319) disabled them for size even though none of them cost anything AVX-512-sized: - s2n-bignum's x86_64 P-256/P-384/P-521/curve25519 implementations (crypto/fipsmodule/CMakeLists.txt build-file gate, ec_nistp.h, curve25519/internal.h, s2n-bignum_aws-lc.h comments). curve25519 is the one this regression was originally reported against (aws#3355): losing it forced X25519/Ed25519 down to the portable _nohw fallback under OPENSSL_SMALL, a ~2x slowdown observed by an aws-lc-rs consumer. - RSA/DH's ADX/BMI2 Montgomery multiplication (bn_mulx4x_mont / bn_sqr8x_mont in bn/internal.h, montgomery.c, bn_test.cc, and their perlasm source x86_64-mont.pl / x86_64-mont5.pl) -- the same root cause, previously unreported, hitting RSA and DH instead of curve25519. - The legacy P-256 ADX Montgomery ladder (ec/asm/p256-x86_64-asm.pl, guarded via ec_nistp.h's EC_NISTP_USE_S2N_BIGNUM path). This one is already unreachable under OPENSSL_SMALL for an unrelated reason (p256-nistz.c is compiled out entirely there), but stays consistent with every other ADX/AVX2 call site for non-OPENSSL_SMALL builds that set the assembler-capability flag directly. - SHA3's x4-batched Keccak (sha/internal.h's KECCAK1600_S2N_BIGNUM_ASM on x86_64, dispatched to sha3_keccak4_f1600_alt behind CRYPTO_is_AVX2_capable() in keccak1600.c). The scalar sha3_keccak_f1600 needs neither ADX/AVX2 nor AVX-512, but is bundled with the x4-batched file for build-file simplicity, same as the other categories above. Regenerated the affected generated-src/{linux,mac,win}-x86_64 files (pre-generated for DISABLE_PERL builds) to match the perlasm changes. Also drop the MY_ASSEMBLER_IS_TOO_OLD_FOR_512AVX check from ChaCha20's AVX2 dispatch (chacha.c, chacha_test.cc) entirely: chacha-x86_64.pl never gated ChaCha20_ctr32_avx2's *generation* on this macro (only on MY_ASSEMBLER_IS_TOO_OLD_FOR_AVX), so under OPENSSL_SMALL the routine was already being compiled into the binary -- the C dispatch just refused to call it. This was pure dead weight, not a real assembler-compatibility guard. Every remaining MY_ASSEMBLER_IS_TOO_OLD_FOR_512AVX call site (AES-GCM-AVX512, AES-XTS-AVX512, RSAZ-AVX512, and their perlasm sources) is untouched: each of those genuinely requires AVX-512, confirmed by grepping the underlying assembly for %zmm/EVEX instructions. Verified on native x86_64 (AMD EPYC, ADX/AVX2/BMI2 capable, no AVX-512) by cross-checking object sizes: with only MY_ASSEMBLER_IS_TOO_OLD_FOR_512AVX set, aesni-xts-avx512.S.o shrinks from 29936 to 888 bytes while x86_64-mont5.S.o is byte-for-byte unchanged; with MY_ASSEMBLER_IS_TOO_OLD_FOR_ADX_AVX2 set, x86_64-mont5.S.o additionally shrinks to 9680 bytes, and sha3_keccak_f1600/sha3_keccak4_f1600_alt disappear from the archive entirely. Full crypto_test suite passes (including SHA3Test/KeccakInternalTest/SHAKETest/SHAKETest_x4) under OPENSSL_SMALL, MY_ASSEMBLER_IS_TOO_OLD_FOR_ADX_AVX2, and MY_ASSEMBLER_IS_TOO_OLD_FOR_512AVX.
โฆsize expectations tests/ci/run_legacy_avx_tests.sh's legacy-toolchain matrix (.github/workflows/linux_x86_omnibus.yml) previously tested MY_ASSEMBLER_IS_TOO_OLD_FOR_AVX and MY_ASSEMBLER_IS_TOO_OLD_FOR_512AVX against real old compilers (CentOS 7/gcc-4, Ubuntu 16.04/gcc-5, Amazon Linux 2/gcc-7, CentOS 8/gcc-8, Ubuntu 18.04/clang-6). Since MY_ASSEMBLER_IS_TOO_OLD_FOR_512AVX no longer implies excluding ADX/AVX2, that coverage would otherwise be lost -- add an adx_avx2 leg so a genuinely ADX/AVX2-incapable assembler is still exercised against the same matrix. Update openssl-small.yml's two stale x86_64 comments: - The size-reduction job's matrix comment claimed OPENSSL_SMALL disables s2n-bignum entirely via MY_ASSEMBLER_IS_TOO_OLD_FOR_512AVX; it now only implies that flag (true AVX-512), so curve25519 s2n-bignum, RSA/DH's ADX/BMI2 Montgomery multiplication, and SHA3's x4-batched Keccak all remain in the build. Re-measured on native x86_64 Linux with the same clang -O2 methodology this job uses: 43.7% consumer-binary reduction, down from the previously-documented 55%. Lowered the threshold from 40% to 35% to preserve a comparable safety margin to the aarch64 leg. - The small-tests job's matrix comment made the same stale claim about x86_64 disabling s2n-bignum entirely; corrected it to describe what OPENSSL_SMALL actually removes on x86_64 now (genuine AVX-512, plus the P-256/P-384/P-521 s2n-bignum objects that are dead code there for an unrelated reason).
|
๐ Security Review โ View Report Please review before merging. |
The AVX-512-only files (aesni-gcm-avx512, aesni-xts-avx512, rsaz-2k/3k/4k-avx512) contain nothing but code wrapped in #ifndef MY_ASSEMBLER_IS_TOO_OLD_FOR_512AVX. When that flag is set (as OPENSSL_SMALL does on x86_64), they assemble to an empty translation unit. NASM (win64) errors on an object with no output (nasm.us bug 3392738), which breaks OPENSSL_SMALL builds on Windows -- reported via an aws-crt-python CI failure. Their symbols are only ever called from C that is itself gated on !MY_ASSEMBLER_IS_TOO_OLD_FOR_512AVX, so drop them from the build entirely instead of assembling dead objects. Verified on Linux: OPENSSL_SMALL now excludes all 5 objects from the build graph (previously present in the default build), and a shared libcrypto.so still links cleanly under OPENSSL_SMALL, confirming no dangling references. Also add a dedicated Windows leg to the OPENSSL_SMALL CI workflow (NASM + clang + Ninja), since the existing Linux legs use gas, which tolerates empty objects and so cannot catch this class of failure. Addresses aws#3355
| # for other reasons (e.g. OPENSSL_SMALL uses it to shed size on x86_64). It | ||
| # guards only genuine AVX-512 (zmm/EVEX) code; for ADX/AVX2/BMI2 code see | ||
| # MY_ASSEMBLER_IS_TOO_OLD_FOR_ADX_AVX2 above. | ||
| # Note: This flag name has "512AVX" instead of "AVX512" so that it doesn't |
Codecov Reportโ
All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3368 +/- ##
==========================================
- Coverage 78.20% 78.19% -0.01%
==========================================
Files 695 695
Lines 124172 124192 +20
Branches 17238 17244 +6
==========================================
+ Hits 97104 97112 +8
- Misses 26147 26159 +12
Partials 921 921 โ View full report in Codecov by Harness. ๐ New features to boost your workflow:
|
| # Windows/x86_64 assembles the generated .asm through NASM. OPENSSL_SMALL | ||
| # implies MY_ASSEMBLER_IS_TOO_OLD_FOR_512AVX, which compiles out the whole | ||
| # body of the AVX-512-only .asm files; NASM errors on an object with no | ||
| # output (bugzilla.nasm.us/show_bug.cgi?id=3392738). The Linux legs use |
There was a problem hiding this comment.
The NASM empty-object failure (nasm.us bug 3392738) that motivated this job is only reachable through the pre-generated sources: with DISABLE_PERL=ON, NASM itself evaluates the %ifndef MY_ASSEMBLER_IS_TOO_OLD_FOR_512AVX guards in generated-src/win-x86_64 and produces an object with no output. windows-latest ships Strawberry Perl, so as written the job only exercised the perlasm path, where the regenerated scripts emit non-empty ud2/ret stubs and the bug never triggers. Split the job into a two-leg matrix: perlasm (DISABLE_PERL=OFF) keeps the regeneration coverage, and pre-generated (DISABLE_PERL=ON) is the faithful repro of the original aws-crt-python failure. Go remains enabled in both legs, so the full run_tests target is used (DISABLE_PERL with full tests has precedent in run_posix_tests.sh). Also align the action versions with the rest of the workflows: actions/checkout v6 -> v7, with the named Checkout step to match windows-alt.yml style. Addresses aws#3355
What we checked
Suggestions
|
- Emit the .text directive outside the MY_ASSEMBLER_IS_TOO_OLD_FOR_512AVX guard in the five AVX-512-only perlasm scripts so the generated object is never empty (nasm.us bug 3392738), regardless of build system. This replaces the CMake-only REMOVE_ITEM workaround, which did not cover non-CMake consumers that set the flag via CFLAGS and assemble the pre-generated win-x86_64 sources with NASM. Regenerate generated-src. The Windows OPENSSL_SMALL CI legs now assemble these files again and validate the fix on an affected NASM. - Tighten the MY_ASSEMBLER_IS_TOO_OLD_FOR_ADX_AVX2 option docstring: the flag does not exclude all AVX2 code (ChaCha20, RSAZ-1024, SHA AVX2 paths remain gated on MY_ASSEMBLER_IS_TOO_OLD_FOR_AVX only). - Document in BUILDING.md that OPENSSL_SMALL keeps the ~370 KiB ADX/AVX2/BMI2 fast paths and that size-critical consumers can add -DMY_ASSEMBLER_IS_TOO_OLD_FOR_ADX_AVX2=1 to recover the previous minimum.
The generic OPENSSL_SMALL Linux/Windows legs run on whatever CPU the hosted runner lands on, so coverage of ADX+AVX2-without-AVX-512 (the fast paths restored by aws#3355) is only probabilistic. Add a dedicated small-sde-tests job that pins three CPU profiles with Intel SDE: - hsw (Haswell): AVX2/BMI2 without ADX - bdw (Broadwell): ADX+AVX2+BMI2 without AVX-512 - icl (Ice Lake): AVX-512-capable Runs both OPENSSL_SMALL and OPENSSL_SMALL + MY_ASSEMBLER_IS_TOO_OLD_FOR_ADX_AVX2 under each CPU. - util/all_tests.go: add a -sde-cpus flag to override the default 18-CPU SDE battery, which would be too slow to run per build config here. Empty value preserves existing behavior. - tests/ci/run_small_tests_with_sde.sh: new script building/testing both configs under the pinned CPU list. - .github/workflows/openssl-small.yml: new small-sde-tests job on the existing CodeBuild-hosted runner + aws-lc/ubuntu:22.04_sde image, mirroring the existing asan_sde_tests job.
|
Thanks for the thorough pass, Nevine -- especially the independent gate-by-gate audit. Replies to the suggestions below. Four are addressed in the latest revision; one I'd like to punt to a follow-up. Empty-object fix now covers non-CMake builds. Good catch that the Docstring tightened. Changed to "Exclude ADX/BMI2 code paths and the AVX2 code bundled with them (not all AVX2; see comment)" so Size escape hatch documented. Added a paragraph to the "Binary Size" section of Deterministic SDE coverage added. Added a OS-allowlist discrepancy -- deferring. Agreed this is worth fixing, but since it's pre-existing and orthogonal to the flag split, I'd rather not expand this PR's scope. I'll open a follow-up issue to reconcile |
Two things were inaccurate, both found while auditing the OPENSSL_SMALL build after aws#3319, aws#3320, aws#3350 and aws#3368. MY_ASSEMBLER_IS_TOO_OLD_FOR_ADX_AVX2 was documented as gating the "ADX/AVX2/BMI2" code paths, but it does not gate BMI1/BMI2 at all. A mnemonic census of the generated x86_64 assembly shows the real dividing line is adcx/adox: every file this flag gates emits them, and the files left in the AVX tier emit only mulx, rorx and andn. Concretely, chacha20_poly1305_x86_64.S has mulx=92 with adcx=adox=0, sha1-x86_64.S has rorx=320/andn=40, and aesni-sha256-x86_64.S has rorx=288/andn=48 -- all AVX-tier-gated -- while x86_64-mont.S (mulx=31, adcx=35, adox=29) and p256-x86_64-asm.S (mulx=100, adcx=86, adox=90) are gated here. So the existing gating is correct; only the comment was wrong. MY_ASSEMBLER_IS_TOO_OLD_FOR_AVX is not fully effective without Perl, which was undocumented. The ADX and AVX-512 tiers are also expressed as #ifndef guards inside the pre-generated assembly, so they still apply with DISABLE_PERL=ON; the AVX tier is not. Measured with -DDISABLE_PERL=ON -DMY_ASSEMBLER_IS_TOO_OLD_FOR_AVX=ON, the objects for chacha-x86_64, chacha20_poly1305_x86_64, ghash-x86_64, sha1-x86_64, aesni-sha256-x86_64, rsaz-avx2 and aes128gcmsiv-x86_64 are byte-identical to a build without the flag, with identical ymm counts. Emitting those guards is a larger change (nine scripts, win64 SEH .rva tables, and a full generated-src regeneration) and is left as follow-up; document the current contract and warn at configure time instead. Also note in run_legacy_avx_tests.sh that its DISABLE_PERL=ON leg cannot detect this, since it only checks that the build succeeds, and record that chacha-x86_64.pl's unreachable $avx>2 AVX-512 blocks would need a 512AVX gate if ever enabled. No functional change beyond the new configure-time warning.
aws-lc 5.5.0 Created-by: HarmonybrewBot Commit-by: HarmonybrewBot Merged-by: HarmonybrewBot Description: Created by `brew bump` --- Created with `brew bump-formula-pr`.<details> <summary>release notes</summary> <pre>## What's Changed * Restore ADX/AVX2 code paths under OPENSSL_SMALL via new MY_ASSEMBLER_IS_TOO_OLD_FOR_ADX_AVX2 flag by @justsmth in aws/aws-lc#3368 * Include <openssl/cipher.h> from <openssl/hmac.h> for OpenSSL compat by @justsmth in aws/aws-lc#3371 * ci: harden security-review.yml against script injection by @nebeid in aws/aws-lc#3365 * Fix flaky s_client cipher tests by using better ciphers by @justsmth in aws/aws-lc#3373 * chore: simplify the api docs workflow by @dougch in aws/aws-lc#3186 * Add tests for RSASSA-PSS with SHA-3 digest and MGF1 by @WillChilds-Klein in aws/aws-lc#3377 * Link header documentation from README by @WillChilds-Klein in aws/aws-lc#3378 * Rename autofix reasoning role to AwsLcGitHubActionsBedrockRole by @tianyiy-tim in aws/aws-lc#3376 * ci: pin openssh required job by @dougch in aws/aws-lc#3387 * delocate: Drop redundant `-dI` flag by @hanno-becker in aws/aws-lc#3384 * Add Neoverse-V3 (Graviton5) detection and dispatch by @nebeid in aws/aws-lc#3374 * Bump ring from 0.17.8 to 0.17.14 in /tests/ci/lambda by @dependabot[bot] in aws/aws-lc#3375 * Fix docker image dependencies and update octocrab initialization by @prasden in aws/aws-lc#3388 * Update FIPS.md by @justsmth in aws/aws-lc#3382 * Bump urllib3 from 2.6.3 to 2.7.0 in /tests/ci by @dependabot[bot] in aws/aws-lc#3372 * Add MinGW shared-library Windows CI coverage by @justsmth in aws/aws-lc#3398 * Update concurrency in `security-review` by @nhatnghiho in aws/aws-lc#3403 * Enable linker garbage collection for non-FIPS static builds by @justsmth in aws/aws-lc#3397 * Prepare 5.5.0 by @justsmth in aws/aws-lc#3401 ## New Contributors * @tianyiy-tim made their first contribution in aws/aws-lc#3376 **Full Changelog**: https://github.com/aws/aws-lc/compare/v5.4.0...v5.5.0</pre> <p>View the full release notes at <a href="https://github.com/aws/aws-lc/releases/tag/v5.5.0">https://github.com/aws/aws-lc/releases/tag/v5.5.0</a>.</p> </details> <hr> See merge request: Harmonybrew/homebrew-core!15934
Issues:
Addresses #3355
Description of changes:
MY_ASSEMBLER_IS_TOO_OLD_FOR_512AVXhas always been a combined switch: despite the name, it disables ADX, AVX2, and AVX-512 code together. When #3319 madeOPENSSL_SMALLimply it to shed the AVX-512-only assembly, that also silently dropped every ADX/AVX2/BMI2 fast path: X25519/Ed25519 fell back to the portable_nohwimplementations (the ~2x regression reported in #3355), and RSA/DH lost their ADX/BMI2 Montgomery multiplication.This PR splits the flag: a new
MY_ASSEMBLER_IS_TOO_OLD_FOR_ADX_AVX2carries the ADX/AVX2/BMI2 meaning, andMY_ASSEMBLER_IS_TOO_OLD_FOR_512AVXnow guards only genuine AVX-512 code, matching its name.OPENSSL_SMALLimplies only the latter, so the ADX/AVX2 fast paths stay available there.Call-outs:
use_s2n_bignum_alt(),bn_mulx_adx_capable(), etc.) only handles CPU capability at execution time, not whether the assembler can parse the mnemonics at build time. That's why these call sites moved to the new flag instead of dropping the guard entirely.generated-src/changes are the mechanical macro rename only; regenerating from the modified perlasm scripts produces identical output.Testing:
Full
crypto_testsuite passes on native x86_64 (ADX/AVX2/BMI2, no AVX-512) under default,OPENSSL_SMALL, and both assembler-flag configurations. Symbol and object-size checks confirm each flag strips exactly its own tier. Existing CI covers this going forward: the legacy-toolchain matrix now exercises all three flags, and theOPENSSL_SMALLworkflow runs the full suite plus the size check.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and the ISC license.