Repository navigation
[FIPS 4.0 CHERRY-PICK #2977] Support GCC > v14 - #3223
Merged
Merged
Conversation
β¦#2977) Addresses: CryptoAlg-3376, AWS-LC-995 GCC 14 introduced changes to the Superword Level Parallelism (SLP) vectorizer which encourages the compiler to combine adjacent static function pointer stores into vector operations. This also induces the compiler to store some of these pointer values in the `.data.rel.ro.local`section in order to load them from memory rather than just computing them using `lea` instructions. This is problematic because the FIPS linker script (gcc_fips_shared.lds) discards these sections by design to ensure hashability of the FIPS module. This results in undefined reference errors at link time. This change disables the SLP vectorizer ([-fno-tree-slp-vectorize](https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#index-ftree-slp-vectorize)) for the bcm_library target on Linux x86_64 GCC 14+ builds. The problemative code which triggers this issue with the SLP vectorizer can be found [here](https://github.com/aws/aws-lc/blob/main/crypto/fipsmodule/hmac/hmac.c#L158-L168). As a macro, all invocations of this macro and the associated function pointers are liable to be stored in `.data.rel.ro.local` so we opt to apply this mitigation across the entire compilation unit. To illustrate, the below snippet consistently produces code which stores the _Init pointer in memory and computes the _Update pointer with lea. This results in a garbage pointer for the former and a working pointer for the latter if you use `ld.gold` as your linker which stubs undefined references with NULL pointers. ``` out->methods[idx].init = AWS_LC_TRAMPOLINE_##HASH_NAME##_Init; \ out->methods[idx].update = AWS_LC_TRAMPOLINE_##HASH_NAME##_Update; \ ``` Here is the disassembly with `tree-slp-vectorize` left on. This initializes two pointers within `AWSLC_hmac_in_place_methods_storage` by performing a single 64-bit load, lea/punpcklqdq operations, and a single 128-bit store. ```asm movq 0x0(%rip),%xmm0 # Load garbage address for SHA256_Init into xmm0 lea -0x1ff42(%rip),%rax # Compute the correct address for SHA256_Update movq %rax,%xmm2 # Store SHA256_Update into xmm2 punpcklqdq %xmm2,%xmm0 # Get both SHA256_Init (Garbage) and SHA256_Update into xmm0 movaps %xmm0,0x27b5eb(%rip) # Store xmm0 into AWSLC_hmac_in_place_methods_storage ``` Here is the dissassembly with `tree-slp-vectorize` disabled. The same two pointers are now initialized using an `lea` instruction and a single 64-bit store. The difference between these two is that the vectorized version is arguably worse performance wise (in this particular instance, can't generalize to all impacted code blocks). ```asm lea 0x26c56(%rip),%rax # Compute address of SHA256_Init mov %rax,0x27ab1f(%rip) # Store SHA256_Init lea -0x20178(%rip),%rax # Compute address of SHA256_Update mov %rax,0x27ab19(%rip) # Store SHA256_Update ``` Should we add a new dimension to our testing for SHARED builds? This would effectively double the entire test matrix if done blindly. Right now, this change is tightly scoped to the impacted shared library build. We have the option to expand this to the static library build which uses a different mitigation if we wanted to. That mitigation is likely more performant as it uses assembly re-writes to get the desired effect, but this could simplify the build. This impacts the compilation of the entire `bcm.c.o` unit, but notably not any of the assembly optimized cryptographic algorithm code. The performance impact, if any, would only be felt in the API layer. Using @torben-hansen's benchmarking framework I ran a couple tests of this flag against GCC13 (Since GCC14 wouldn't work and could not be controlled for). Given the results, I'm inclined to believe that disabling this optimization flag on the FIPS module has a negligible performance impact. `shared-fips-slp-on vs static-fips-slp-off` compares the shared build with the assembly re-write mitigation versus the static build with this PR's mitigation. We see negligible impact with the exception of -11% for RNG16. This could be merely a difference between shared/static. Reviewers, feel free to press on this. `static-noasm-slp-off vs static-noasm-slp-on` compares the NO_ASM build with and without the SLP vectorizer. Funny enough, it suggests a marginal performance improvement (Up to 2%) when disabling the SLP vectorizer. <img width="1491" height="540" alt="Screenshot 2026-02-03 at 3 24 19β―PM" src="https://github.com/user-attachments/assets/7dc6891c-8bee-4452-97ce-033ea9540966" /> How is this change tested (unit tests, fuzz tests, etc.)? Are there any testing steps to be verified by the reviewer? I setup an Ubuntu 24.04 container on an x86_64 host to test the compilation, run tests, and perform benchmarking. ``` CC=gcc-14 CXX=g++-14 cmake -GNinja -B build -DFIPS=1 -DBUILD_SHARED_LIBS=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo ninja ninja run_tests ``` 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.
Codecov Reportβ
All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## fips-2025-09-12-lts #3223 +/- ##
=======================================================
- Coverage 78.79% 78.75% -0.04%
=======================================================
Files 667 667
Lines 113338 113339 +1
Branches 16091 16080 -11
=======================================================
- Hits 89304 89263 -41
- Misses 23240 23282 +42
Partials 794 794 β View full report in Codecov by Sentry. π New features to boost your workflow:
|
WillChilds-Klein
approved these changes
May 7, 2026
samuel40791765
approved these changes
May 7, 2026
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Addresses: CryptoAlg-3376, AWS-LC-995
GCC 14 introduced changes to the Superword Level Parallelism (SLP) vectorizer which encourages the compiler to combine adjacent static function pointer stores into vector operations. This also induces the compiler to store some of these pointer values in the
.data.rel.ro.localsection in order to load them from memory rather than just computing them usingleainstructions. This is problematic because the FIPS linker script (gcc_fips_shared.lds) discards these sections by design to ensure hashability of the FIPS module. This results in undefined reference errors at link time. This change disables the SLP vectorizer(-fno-tree-slp-vectorize) for the bcm_library target on Linux x86_64 GCC 14+ builds.
The problemative code which triggers this issue with the SLP vectorizer can be found
here. As a macro, all invocations of this macro and the associated function pointers are liable to be stored in
.data.rel.ro.localso we opt to apply this mitigation across the entire compilation unit. To illustrate, the below snippet consistently produces code which stores the _Init pointer in memory and computes the _Update pointer with lea. This results in a garbage pointer for the former and a working pointer for the latter if you useld.goldas your linker which stubs undefined references with NULL pointers.Here is the disassembly with
tree-slp-vectorizeleft on. This initializes two pointers withinAWSLC_hmac_in_place_methods_storageby performing a single 64-bit load, lea/punpcklqdq operations, and a single 128-bit store.Here is the dissassembly with
tree-slp-vectorizedisabled. The same two pointers are now initialized using anleainstruction and a single 64-bit store. The difference between these two is that the vectorized version is arguably worse performance wise (in this particular instance, can't generalize to all impacted code blocks).Should we add a new dimension to our testing for SHARED builds? This would effectively double the entire test matrix if done blindly.
Right now, this change is tightly scoped to the impacted shared library build. We have the option to expand this to the static library build which uses a different mitigation if we wanted to. That mitigation is likely more performant as it uses assembly re-writes to get the desired effect, but this could simplify the build.
This impacts the compilation of the entire
bcm.c.ounit, but notably not any of the assembly optimized cryptographic algorithm code. The performance impact, if any, would only be felt in the API layer. Using @torben-hansen's benchmarking framework I ran a couple tests of this flag against GCC13 (Since GCC14 wouldn't work and could not be controlled for). Given the results, I'm inclined to believe that disabling this optimization flag on the FIPS module has a negligible performance impact.shared-fips-slp-on vs static-fips-slp-offcompares the shared build with the assembly re-write mitigation versus the static build with this PR's mitigation. We see negligible impact with the exception of -11% for RNG16. This could be merely a difference between shared/static. Reviewers, feel free to press on this.static-noasm-slp-off vs static-noasm-slp-oncompares the NO_ASM build with and without the SLP vectorizer. Funny enough, it suggests a marginal performance improvement (Up to 2%) when disabling the SLP vectorizer.How is this change tested (unit tests, fuzz tests, etc.)? Are there any testing steps to be verified by the reviewer?
I setup an Ubuntu 24.04 container on an x86_64 host to test the compilation, run tests, and perform benchmarking.
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.
Issues:
Resolves #ISSUE-NUMBER1
Addresses #ISSUE-NUMBER2
Description of changes:
Describe AWS-LCβs current behavior and how your code changes that behavior. If there are no issues this pr is resolving, explain why this change is necessary.
Call-outs:
Point out areas that need special attention or support during the review process. Discuss architecture or design changes.
Testing:
How is this change tested (unit tests, fuzz tests, etc.)? Are there any testing steps to be verified by the reviewer?
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.