The EVM Object Format (EOF) is an important upgrade for the Ethereum Virtual Machine, comprising a series of EIPs. It introduces an extensible and versioned container format for EVM bytecode with a once-off validation at deploy time, focusing on separating code and data, enhancing code validation, and improving overall efficiency.

Motivation

  • Code validation at deploy time

    Instead of having the interpreter validate instructions repeatedly at runtime, EVM bytecode is validated only once during contract creation, providing a faster, cheaper, and more secure execution.

  • Code-data separation

    EOF separates EVM bytecode from data, making it easier for static analysis tools, formal verification, and L2s to process executable code.

  • Removal of dynamic JUMPs

    EOF bytecode uses only static relative jumps, which is very desirable for tools involving static analysis, formal verification, compilation to native code, zero-knowledge circuits, as well as L2 EVMs.

  • Code and gas non-observability

    Lack of code and gas observability is a long-sought trait of the EVM allowing a more maintainable and upgradeable protocol.

  • Removal of JUMPDEST-analysis

    By obsoleting JUMPDEST-analysis done at contract runtime, EOF simplifies reasoning about EVM bytecode, as well as other changes, like EVMMAX, Verkle or bytecode size increase.

  • First-class support for EVM functions

    Functions in EOF are a subroutine mechanism not relying on dynamic jumps. It improves analysis opportunities by encoding the number of inputs and outputs for each given function, and isolating the stack of each function.

  • Code versioning

    Introducing versioning will make backwards-incompatible upgrades much easier. Backwards compatible changes can be done without bumping the EOF version, even if new instructions are introduced.

  • Addressing EVM pain points

    EOF proposals address many long-standing issues and quirks of the EVM, streamlining compiler development, providing new compiler optimization opportunities, and ultimately improving developer experience. An example of this are the new improved stack management instructions.

Implementation

EOF has been implemented in the following clients and projects.

3540367042004750545062067480706976207698663
Megaspec
EIP
Testing🚧🚧🚧
besu
erigon🚧🚧🚧🚧🚧🚧🚧🚧
ethereumjs🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧
evmone
geth🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧
nethermind
revm
solidity (experimental)N/AN/A

Learn More

Resources

eof.wtf: EOF Parser and Visualizer.

evm.codes: EVM Opcode Reference (Deprecated opcodes have yet to be removed).

EOF taxonomy infographic by Dragan Rakita.

Talks/Videos

EOF Explanation by Uttam Singh

EOF - History and Motivation by Danno Ferrin (Devcon 7)

EOF - Managing the bytecode chaos by Alex Murashkin (Devcon 7)

Zoom in on EOF stack validation by Andrei Maiboroda (Devcon 7)

The Future of EOF: Layer 1, Layer 2, and Beyond! by Danno Ferrin (Devcon 7)

FAQs - Frequently Asked Questions

Q: Is EOF a brand-new EVM replacing the old legacy EVM?

No, EOF updates only a small part of the EVM. EOF is first and foremost a container format for EVM code.

Most of the EVM — opcodes, operand stack, storage, accounts, memory, and more — stays the same. In that sense the “Legacy EVM” here only means the 16 opcodes not accessible to EOF code and the patterns they enable. Some new opcodes (like EXTCALL and EOFCREATE) reuse old logic, so the effective change is even smaller.

Q: Why does EOF seem so complex?

EOF is often perceived to be more complex than it is.

People think it’s complex because it involves many EIPs and opcodes. The large number of EIPs is because EOF’s parts were debated separately in the past, but now they are all part of one cohesive change. Because of that the total number of opcode changes is bigger than usual since EOF implements many features (static jumps, code and data separation, banning code introspection, etc.) in one step. Still, it only affects a small fraction of opcodes, and much of the logic within those opcodes is shared with the opcodes they are replacing.

However, EOF is admittedly a complex EVM change. Emphasis is being put on proper testing (with the modern testing machinery provided by EEST), fuzzing, and explicit specification clarity in order to carry it through. The EVM ecosystem is today mature enough to deliver on such a complex EVM upgrade, which has also itself matured over the years having been analyzed and investigated by many independent contributors.

Q: Couldn’t we split EOF into smaller changes?

No, breaking it into pieces makes it more complex long-term. Multiple updates would force clients to support multiple different EVM versions forever, which gets messy. EOF bundles all the breaking changes that would be done in multiple steps into one step.

Piecemeal changes can also clash. For example, an old versioning idea (EIP-1702) becomes more complicated with other peacemeal changes like EIP-7702, causing increasing complexity. One big update reduces these unexpected interactions and avoids risky in-between states.

Piecemeal changes were also tried in the past (see EIP-2315, EIP-1702, EIP-663, and EIP-615), but these changes were also rejected for not providing enough impact and not integrating well with other parts of the EVM. Feedback such as this led us to present EOF in one large change.

Q: Why not do [Feature X] by itself?

Each EOF feature needs a breaking change or relies on another feature to work safely. Here’s why some can’t stand alone:

  • Opcodes with Immediates (RJUMP/RJUMPI, DUPN/SWAPN): Need versioning to avoid breaking old code or adding complexity. Past tries (like earlier versions of EIP-663) failed without EOF’s structure.

  • Code Validation: Needs versioning and separating code and data, too. Without it, you’d track versions separately (tried and dropped in EIP-1702). New features like EIP-7702 make this harder. EOF puts versioning in the code itself and adds data sections naturally.

  • Removing Gas Introspection: Bundling this with EOFv1 avoids needing an EOFv2 later, keeping EVM versions low.

  • Removing Code Introspection: A halfway change that doesn’t include this adds more versions.

  • Subroutines: An earlier proposal (EIP-2315) was rejected as too weak. EOF’s approach has support from the Solidity team. The supported solution is also tightly integrated with the container format.

  • Address Space Expansion: Needs versioning to protect old contracts.

  • Removing Dynamic Jumps (e.g., JUMP/JUMPI): Alternative without immediates requires more complicated validation rules checked during every opcode evaluation.

Piecemeal changes mean more EVM versions, confusing rules, and harder upgrades. EOF keeps it to one new version.

Q: Why not drop codesize limits and use EIP-3860 metering?

EIP-3860 fixed missing gas charge for JUMPDEST analysis during contract deployment, but it doesn’t cover loading contracts during regular execution. JUMPDEST analysis still needs to happen every time a contract runs, or the results need to be cached. EOF’s advantage is that it validates code just once, when it’s added to the blockchain. After that, no extra checks are needed for execution or contract creation. This makes EOF simpler and faster in practice.

Q: Can’t we just remove the need for JUMPDESTs and jump analysis?

No, removing JUMPDESTs produces more problems that it solves. JUMPDESTs fix analysis issues with dynamic jumps, making compilation (like via LLVM) and static analysis a tractable problem. Without them, zkEVMs and control flow analysis get much harder. Plus, it risks running data as code, a security issue. This article explains more.

Q: Can't we fix Solidity's "stack too deep" without DUPN/SWAPN?

Compilers indeed can solve the “stack too deep” problem with register allocation but they cannot guarantee an optimal solution. Even when they do determine an optimal solution the use of stack/register spilling is very cost ineffective without reliable access to cheap memory. The EVM’s non-linear gas cost for memory makes access to larger variable pools more expensive and fragile than a paged memory model like one in typical silicon processors.

With this in mind, solving this problem on the compiler level is just a trade-off, rather than a direct improvement. Efficient and safe upgrade to EVM’s stack management is important, EIP-663 achieves that. Because it relies on immediate arguments to the opcode it requires the versioned container EOF provides.

Q: How much does EOF help the Solidity compiler?

The Solidity team has expressed multiple times that EOF is their preferred solution “by orders of magnitude,” and that it enables many Developer Experience (Devex) improvements. You can read about it in their own words.