Skip to content

[FIPS 4.0 CHERRY-PICK #2977] Support GCC > v14 - #3223

Merged
justsmth merged 1 commit into
aws:fips-2025-09-12-ltsfrom
justsmth:fips-2025-09-12-gcc-15
May 7, 2026
Merged

justsmth merged 1 commit into
aws:fips-2025-09-12-ltsfrom
justsmth:fips-2025-09-12-gcc-15

Conversation

@justsmth

@justsmth justsmth commented May 7, 2026

Copy link
Copy Markdown
Contributor

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 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) 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.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.

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).

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.

Screenshot 2026-02-03 at 3 24 19β€―PM

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.

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.

…#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-commenter

Copy link
Copy Markdown

Codecov Report

βœ… All modified and coverable lines are covered by tests.
βœ… Project coverage is 78.75%. Comparing base (35bfa43) to head (1c1680b).

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.
πŸ“’ Have feedback on the report? Share it here.

πŸš€ New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@justsmth
justsmth merged commit d852313 into aws:fips-2025-09-12-lts May 7, 2026
157 of 190 checks passed
@justsmth
justsmth deleted the fips-2025-09-12-gcc-15 branch May 7, 2026 18:11

This branch was successfully deployed

No deployments
auto-approve β€” 1c1680be Deployed May 7, 2026 by justsmth via android-release-static #988
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants