Repository navigation
Conversation
|
GCC 13, Skylake |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #649 +/- ##
=======================================
Coverage 97.33% 97.33%
=======================================
Files 80 80
Lines 7739 7739
=======================================
Hits 7533 7533
Misses 206 206
Flags with carried forward coverage won't be shown. Click here to find out more. |
|
GCC 12, Haswell |
|
The savings are impressive, but the description is scary:
So ideally we could disable this, but enable is specifically at some places where risk is present? |
We need to consult this with some security experts. Originally, I wanted to disable this only for baseline interpreter, but the attribute does not work. Probably worth to report a bug. But we can also disable this per-file basis. It may have more sense to have this enabled for bytecode analysis. The risk is that if there is a bug in EVM someone will be able to take over the process the EVM is running in and e.g. steal some information or mess up how it behave in the p2p network. This seems unlikely though. The attacker will be still able to crash the node. Oh and the benchmarks are shaky. The improvements may come from smaller code size and code layout change. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #649 +/- ##
=======================================
Coverage 98.23% 98.23%
=======================================
Files 185 185
Lines 17131 17131
Branches 3912 3912
=======================================
Hits 16829 16829
Misses 233 233
Partials 69 69
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
🟡 Changes recommended
Multi-configuration builds can override explicit CET settings because the guard does not inspect all enabled configurations.
1 open issue
What changed in this PR
This PR reduces Baseline interpreter dispatch overhead by removing compiler-default Intel CET branch instrumentation while preserving default shadow-stack compatibility.
Changes:
- Detects whether the compiler enables CET branch and return protection.
- Selects
-fcf-protection=returnornonewhen branch protection is enabled by default. - Adds a guard intended to preserve explicit CET options in CMake flags.
| File | Description |
|---|---|
| lib/evmone/CMakeLists.txt | Adds CET detection and target-specific instrumentation options. |
Review effort: Balanced
The branch part of Intel CET (IBT), which e.g. Ubuntu's GCC enables by default, puts an ENDBR64 at every indirect branch target: in the Baseline interpreter at every instruction, executed on each dispatch. Linux does not enforce IBT in user space. Build evmone with only the shadow stack part, which costs no instructions and keeps the binary shadow-stack compatible. A -fcf-protection in the CMake flags of any configuration is kept.

The branch part of Intel CET (IBT), which e.g. Ubuntu's GCC enables by default (-fcf-protection=full), puts an ENDBR64 at every indirect branch target. In the Baseline interpreter these are the instruction labels of the computed-goto dispatch, so an ENDBR64 is executed on every instruction, while Linux does not enforce IBT in user space.
On Linux x86-64 evmone is now built with -fcf-protection=return: no ENDBR64, while the shadow stack marking stays. The shadow stack costs no instructions, and the linker marks a binary shadow-stack compatible only if all its objects are, so dropping it as well would disable it for every program linking evmone. A -fcf-protection in the CMake flags of any configuration is kept. Keeping a compiler default without the branch part is left as a TODO.
The nocf_check attribute cannot do this per function: it only controls the ENDBR64 at the function entry, and GCC instruments every label whose address is taken whenever the branch protection is on (checked again with GCC 15).
This only matters for GCC: Clang does not enable CET by default, so for Clang builds the change only adds the shadow stack marking. With GCC 15 it removes the ENDBR64 from every handler of the Baseline interpreter loop, one instruction less per executed EVM instruction. Measured with callgrind over 100 recent mainnet blocks in zvm1 (an evmone fork), that is 4.7% of the instructions executed in the interpreter loop and 0.7% of all the instructions of the EVM execution, host calls and precompiles included.