3

I am just diving into EVM assembly and am a little confused about the following. I have the following simple contract:

pragma solidity >=0.8.1;

contract MyTest {}

When I compile it using Remix, I get the following assembly code:

.code
  PUSH 80           contract MyTest {\r\n   \r\n}
  PUSH 40           contract MyTest {\r\n   \r\n}
  MSTORE            contract MyTest {\r\n   \r\n}
  CALLVALUE             contract MyTest {\r\n   \r\n}
  DUP1          contract MyTest {\r\n   \r\n}
  ISZERO            contract MyTest {\r\n   \r\n}
  PUSH [tag] 1          contract MyTest {\r\n   \r\n}
  JUMPI             contract MyTest {\r\n   \r\n}
  PUSH 0            contract MyTest {\r\n   \r\n}
  DUP1          contract MyTest {\r\n   \r\n}
  REVERT            contract MyTest {\r\n   \r\n}
tag 1           contract MyTest {\r\n   \r\n}
  JUMPDEST          contract MyTest {\r\n   \r\n}
  POP           contract MyTest {\r\n   \r\n}
  PUSH #[$] 0000000000000000000000000000000000000000000000000000000000000000            contract MyTest {\r\n   \r\n}
  DUP1          contract MyTest {\r\n   \r\n}
  PUSH [$] 0000000000000000000000000000000000000000000000000000000000000000         contract MyTest {\r\n   \r\n}
  PUSH 0            contract MyTest {\r\n   \r\n}
  CODECOPY          contract MyTest {\r\n   \r\n}
  PUSH 0            contract MyTest {\r\n   \r\n}
  RETURN            contract MyTest {\r\n   \r\n}
.data
  0:
    .code
      PUSH 80           contract MyTest {\r\n   \r\n}
      PUSH 40           contract MyTest {\r\n   \r\n}
      MSTORE            contract MyTest {\r\n   \r\n}
      PUSH 0            contract MyTest {\r\n   \r\n}
      DUP1          contract MyTest {\r\n   \r\n}
      REVERT            contract MyTest {\r\n   \r\n}
    .data

When I use the solidity compiler to create assembly code from that contract (solc --asm), I get the following:

    /* "test.sol":26:49  contract MyTest {... */
  mstore(0x40, 0x80)
  callvalue
  dup1
  iszero
  tag_1
  jumpi
  0x00
  dup1
  revert
tag_1:
  pop
  dataSize(sub_0)
  dup1
  dataOffset(sub_0)
  0x00
  codecopy
  0x00
  return
stop

sub_0: assembly {
        /* "test.sol":26:49  contract MyTest {... */
      mstore(0x40, 0x80)
      0x00
      dup1
      revert

    auxdata: 0xa264697066735822122057b4abeab2d44c9d2cbb61c1302d88d50541a562fe3c17fb627482ec50f5651064736f6c63430008130033
}

It seems like the Remix assembly code is going deeper to core EVM as it is using the actual opcodes as described in the Yellow Paper, while the Solidity compiler assembly has a layer of abstraction which I assume is some Yul syntax. Does anyone have information on the latter one? Maybe some documentation or tutorials? Why does the assembly output differ and what is the preferred way if you want to code directly in assembly?

2 Answers 2

0

They dont produce the same output because Remix and solc have different goals. Remix aims to provide a comprehensive development environment for Solidity, including low-level debugging and inspection tools like the EVM assembly output, but the solc focuses on compiling Solidity code into efficient EVM bytecode, the Yul being an intermediate step.

So if you want to be precise and understand you should use Remix but if you want efficiency use solc. My guess is that you want to be with Yul so solc

here is some Yul documentation

Yul Documentation: Official documentation on Yul language, its features, and examples.

Yul Workshop: A repository containing examples and exercises to learn and practice Yul.

0

Remix is outputting the exact opcodes. We can get this using foundry by doing:

forge build --extra-output evm.bytecode.opcodes.

The opcodes are now in the output JSON artifact.

A oneliner to get the opcodes from your artifact could then be (requires jq):

$ jq -r '.opcodes' out/mytest.sol/MyTest.json  | tr ' ' '\n'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.