# EVM encapsulation format > Name suggestion: *EOF – EVM Object Format* > Or could go the GNU way: *EOF – EOF Object Format* ## Background on EVM changes A recurring theme in EVM change proposals is to have instructions with immediate arguments. Proposals looking for it include [EIP-615](https://eips.ethereum.org/EIPS/eip-615), [EIP-663](https://eips.ethereum.org/EIPS/eip-663), [EIP-2315](https://eips.ethereum.org/EIPS/eip-2315), and [EVM384](https://notes.ethereum.org/@poemm/evm384-update5#Cost-of-PUSH-Interface-v9). Introducing such instructions has been frowned up, because the risk of influencing [jumpdest analysis](https://ethereum-magicians.org/t/eip-663-unlimited-swap-and-dup-instructions/3346/10) and unwantendly changing behaviour of contracts before and after a fork. While this concern is [not 100% agreed upon](https://ethereum-magicians.org/t/eip-2315-simple-subroutines-for-the-evm/3941/40), the only option explored so far has been "[account versioning](https://ethereum-magicians.org/t/ethereum-account-versioning/3508)" to avoid this. Account versioning itself is a question [without consensus](https://ethereum-magicians.org/t/eip-663-unlimited-swap-and-dup-instructions/3346/13). There also have been three further proposals for immediates to consider: - require a preceding PUSH instruction (this puts strain on the interpreter marking these cases, but validation at deploy time could avoid that), - insert a PUSH byte between the instruction and the immediate as a guard (i.e. have the PUSH after the instruction), - and introduce a multi-byte opcode prefix. A different idea is to introduce validation rules for newly deployed contracts ([1](https://eips.ethereum.org/EIPS/eip-615#validation), [2](https://ethereum-magicians.org/t/eip-2348-validated-evm-contracts/3756/13)), and also run static analysis (or the validation) on the mainnet to ensure every contract passes it. If there are existing contracts not passing validation, it can be individually decided whether breaking them is good or not. A hard fork introducing validation would seal their fate. This idea was mostly just discussed, but so far not seriously considered. Validating at deploy-time (and storing the result) removes the need for jumpdest analysis at runtime. AFAIK currently clients perform this analysis for every execution, with the exception of silkworm which caches the analysis results (over what period?). The validation idea fails to cover at least two-cases: a) on-chain validators; b) contracts which are yet to be deployed, but are depended-on already (such as those of which only a create2 hash exists on chain). ## Motivation This write up is motivated by recent events: 1. The [resurgence of efforts](https://github.com/ethereum/pm/issues/250) to remove legacy or unwanted features from the EVM. 2. Discussions on EIP-2315 and the goal of statically defined subroutines. 3. The benefits of easily modifiable EVM code for layer-2 solutions (i.e. injecting guard code for on-chain validators, like in the case of Optimism). 4. And a [new twist](https://hackmd.io/@HWeNw8hNRimMm2m2GH56Cw/state_expiry_paths) on state expiry. All these pose breaking changes to the EVM. While the state expiry document is not defining it, discussions highlighted that it would be beneficial to consider extending the size of addresses from 160-bits to larger for security reasons. Additionally it should be further extended to include the epoch number. Contracts currently depend on addresses being 160-bits wide. The Solidity compiler as an example can remove masking of addresses in optimisation steps. (Not all mainnet contracts use the optimiser.) While this could be to our benefit given the contract won't truncate addresses, it would cause issues down the line. The widely used mapping construct (`mapping (address => uint) balance`) is translated into something similar to `keccak256(keccak256(<slot id>) || address)` internally. It is easy to see an expression like `balance[msg.sender]` or `balance[this]` would lead to widely different storage slots if addresses suddenly become larger than 160-bits. This suggest that in this state expiry model, epoch-0 (aka current mainnet) contracts need retain the EVM semantics of today. Any further epochs could benefit from an improved EVM, to introduce a new addressing format, new features for migrating data from older epochs and to have this opportunity for a large design cleanup/improvement. ## Encapsulation format I always wondered why are we mixing executable code and formatting. Many other systems encapsulate bytecode into a format consisting of various metadata aiding the execution, modification, or analysis of said bytecode. Examples include [ELF](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format) for Unix-like system, Mach-O for macOS, MZ and PE for Windows, or even WebAssembly itself. Very limited versions of syntatical separation were already proposed for the EVM: [version identifier](https://github.com/ethereum/EIPs/issues/154) and [BEGINDATA](https://eips.ethereum.org/EIPS/eip-2327). Encapsulation takes a larger step with the following goals: - Extensible future proof format - Remove runtime jumpdest analysis - Support data sections - Be efficient with block/transaction witnesses - Potential features: - Special section for account abstraction entry point? - Functions? - Debugging data? (To be removed prior to deployment.) - Relocation table? *Recall that jumpdest analysis is preformed to build an upfront offset table of valid locations containing a JUMPDEST opcode. Such values could be part of a PUSH data too, which must be be excluded.* In all approaches we start with an [EIP-154](https://github.com/ethereum/EIPs/issues/154)-style sequence, the `0xfe 0x65 0x76 0x6d` bytes. `0xfe` is the [invalid instruction](https://eips.ethereum.org/EIPS/eip-141) and the other three bytes is the string "EVM" in ASCII. A version is included following the magic. It would be possible to use one byte of the magic for versioning purposes. ### Simplistic approach The most simplistic approach is a format like this: | magic | 8-bits | |--------------|-----------------| | version | 8-bits | | code size | 16-bits | | ..code.. | variable length | | jumptable size | 16-bits | | ..jumptable.. | variable length | | metadata size | 16-bits | | ..metadata.. | variable length | Or with offsets upfront: | magic | 8-bits | |--------------|-----------------| | version | 8-bits | | jumptable offset | 16-bits | | metadata offset | 16-bits <small>(Could be made 8-bits and relative to jumptable.)</small> | ..code.. | variable length | | ..jumptable.. | variable length | | ..metadata.. | variable length | The reason we want to include a jumptable is that clients can avoid running the analysis every time the contract is encountered. While they certainly can create a cache of analysis data in their database, preparing for a (semi)-stateless future where proofs for accounts are submitted, having the jumptable present in the proof is beneficial. Since currently there is the requirement that jumps can only point to `JUMPDEST`s, at deploy time the correctness of the supplied jumptable should be verified by conducting jumpdest analysis and comparing the results. Potential ideas for a jumptable: - A bitmap of jumpdest validity. This however would be 3072 bytes long should there be a JUMPDEST at the very end of the codesize limit. - An array of 16-bit offsets to jumpdest locations. This has an upper bound of 49152 bytes if the code consists only of JUMPDESTs and is of the codesize limit. - Could consider some ideas for compression, like having a bitmap prefixed with offsets, RLE compressing the bitmap, etc. ### Structured approach The format starts with the header: | magic | 32-bits | |---------|---------| | version | 8-bits | Inspired by other formats, we have sections following the header. Each section is formatted as: | section id | 8-bits | |--------------|-----------------| | section size | 16-bits | | section data | variable length | We define three sections, which must appear in this order (S<sub>n+1</sub>.id >= S<sub>n</sub>.id): 1. Code (id = 0) 2. Jumptable (id = 1) 3. Data (id = 2) Restrictions: a single code and jumptable section must be present; zero or more data sections are allowed. *Q: Should clients drop unwanted sections at deploy time? I think they should just store whatever, it is the users' fault overspending with useless data.* ### Structured approach without dynamic jumps We could go further and apply changes to the EVM itself. This means we introduce a new version of the EVM and execution of the old one should remain as a separate path. For this case we consider the structured approach presented above, but the need for jumptable is removed. Remove `JUMPDEST` and `PC`. Change `JUMP` and `JUMPI` to take a signed immediate which means a relative jump offset. We could also consider introducing a new kind of jump with a jumptable (basically a switch statement). The reason for having `JUMPDEST`s in the first place was to section code for translation to machine code (see [evmjit](https://github.com/ethereum/evmjit)). Due to dynamic jumps, sectioning was not trivial. With having access to immediates, the code can be split into sections, should a VM wish to do so. The second reason `JUMPDEST` is useful is to avoid executing code-as-data, i.e. PUSH data. Therefore we assume code must be validated for well-formedness (every jump immediate points to an instruction, and not data) during deployment time. Of course we can make other changes to the EVM too. Additionally, since we remove jumpdest analysis, introducing multi-byte opcodes is not a problem anymore. ### Structured approach with functions We build on the previous section, a structured layout without dynamic jumps. We relax the limitation of a single code section, and now allow for multiple code sections. They must appear sequentially in the format, and represent function 0, 1, ..., n. Execution starts at function 0 (the first code section). We introduce a new instruction, `CALLF`, which takes a function index `n`, stores the callee's function index and PC, and starts executing function `n`. We also introduce a `RETF` instruction which returns to the callee. We could furthermore extend the function section to specify the number of stack items expected and returned, and have it enforced via the instructions. This is not too dissimilar to [EIP-615](https://eips.ethereum.org/EIPS/eip-615) with the exception of splitting up the EVM bytecode into sections. <small>As a remark, we may as well consider WebAssembly, which solved these problems :speak_no_evil: </small> ## Future work Consider account abstraction. Consider other sections useful for development (debugging data, relocation tables, etc.), which can be trimmed prior to deployment. While the encapsulation itself could be used by compilers and tools to work on compilation artifacts, the main benefit to the chain comes when improvements to the EVM are included. If the encapsulation as a direction is found to be useful, we should agree on goals of the format, and both VM/client, compiler and security teams should be engaged in clarifying the format and what EVM changes would be most beneficial. *Thanks to Paweł Bylica for a review.*