I'm leanring low-level Solidity inline assembly, but confused by different output formats.
The ouptut option of Solidity compiler says:
--asm EVM assembly of the contracts.
--opcodes Opcodes of the contracts.
I tried both options to compile the contract below:
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
contract MyContract {
string bar = "Hello World";
function foo() public view returns(string memory) {
return bar;
}
}
The command solc -o output --asm contract.sol
generated MyContract.evm:
/* "contract.sol":70:208 contract MyContract {... */
mstore(0x40, 0x80)
/* "contract.sol":96:122 string bar = "Hello World" */
mload(0x40)
dup1
0x40
add
0x40
mstore
dup1
0x0b
dup2
mstore
0x20
add
0x7657399374655890603765000000000000000000000000000000000000000000
dup2
mstore
pop
0x00
swap1
dup1
mload
swap1
0x20
add
swap1
tag_1
swap3
swap2
swap1
tag_2
jump // in
tag_1:
pop
/* "contract.sol":70:208 contract MyContract {... */
callvalue
dup1
... (and a lot more code)
The command solc -o output --opcodes contract.sol
generated MyContract.opcode:
PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0xB DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x7657399374655890603765000000000000000000000000000000000000000000 DUP2 MSTORE POP PUSH1 0x0 SWAP1 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 PUSH2 0x4F SWAP3 SWAP2 SWAP1 PUSH2 0x62 JUMP JUMPDEST POP CALLVALUE DUP1 ISZERO PUSH2 0x5C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x166 JUMP JUMPDEST DUP3 DUP1 SLOAD PUSH2 0x6E SWAP1 PUSH2 0x105 JUMP JUMPDEST SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 PUSH1 0x1F ADD PUSH1 0x20 SWAP1 DIV DUP2 ADD SWAP3 DUP3 PUSH2 0x90 JUMPI PUSH1 0x0 DUP6 SSTORE PUSH2 0xD7 JUMP JUMPDEST DUP3 PUSH1 0x1F LT PUSH2 0xA9 JUMPI DUP1 MLOAD PUSH1 ... ...
They look pretty much similar, although not 100% matching each other...
Questions
--opcodes
just give a more compact form of assembly code compared to --asm
output?PUSH1 0x80 PUSH1 0x40 MSTORE
in --opcodes
format vs. mstore(0x40, 0x80)
in --asm
format. Are they doing the same thing? (I guess so but not 100% sure...)--opcodes
in a pretty format rather than in a single line?1. Does
--opcodes
just give a more compact form of assembly code compared to--asm
output?
That's somewhat correct. You could still translate the assembly to opcodes and get the same result.
Assembly represents a set of "low level-ish" instructions. Opcodes are the "real" binary instructions passed to the EVM. See for example this table that translates the opcodes to binary.
2.
PUSH1 0x80 PUSH1 0x40 MSTORE
in--opcodes
format vs.mstore(0x40, 0x80)
in--asm
format. Are they doing the same thing? (I guess so but not 100% sure...)
Yes, they are doing the same thing - see answer to 1. When you run this snippet in Solidity
assembly {
mstore(0x40, 0x80)
}
you get the same opcodes.
3. Is there a way to print
--opcodes
in a pretty format rather than in a single line?
You can use tr
on any other text-formatting unix cli command.
echo "PUSH1 0x80 PUSH1" | tr ' ' '\n'
PUSH1
0x80
PUSH1
See this forum post for more ways.
4. Are there any good resouces to learn Solidity inline assembly?
Apart from the documentation, I don't know any, so I'll let someone else give a better answer. But Solidity is still a pretty new technology, so my guess is that most people who specialize in Solidity assembly, learned by trial&error.