Skip to content

Instantly share code, notes, and snippets.

@loredanacirstea
Last active May 19, 2020 20:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save loredanacirstea/d8da062392b7c165976bbc25a183149e to your computer and use it in GitHub Desktop.
Save loredanacirstea/d8da062392b7c165976bbc25a183149e to your computer and use it in GitHub Desktop.
Yul -> ewasm with staticcall (staticcall not included in the bytecode); solc 0.6.8+commit.0bbfe453.Darwin.appleclang
======= initial Yul source =======
object "TestWasm9_2" {
code {
datacopy(0, dataoffset("Runtime"), datasize("Runtime"))
return(0, datasize("Runtime"))
}
object "Runtime" {
code {
let _calldata := 96
calldatacopy(_calldata, 0, calldatasize())
let addr := mslice(_calldata, 20)
let input_ptr := add(_calldata, 20)
// callStatic
let success := staticcall(gas(), addr, input_ptr, 4, 0, 0)
mstore(0, success)
return (0, 32)
function mslice(position, length) -> result {
if gt(length, 32) { revert(0, 0) }
result := div(mload(position), exp(2, sub(256, mul(length, 8))))
}
}
}
}
======= ./tests/contracts/c9_2.yul (Ewasm) =======
Pretty printed source:
object "TestWasm9_2" {
code {
{
let _1 := datasize("Runtime")
datacopy(0, dataoffset("Runtime"), _1)
return(0, _1)
}
}
object "Runtime" {
code {
{
calldatacopy(96, 0, calldatasize())
mstore(0, staticcall(gas(), div(mload(96), shl(96, 1)), 116, 4, 0, 0))
return(0, 32)
}
}
}
}
==========================
Translated source:
object "TestWasm9_2" {
code {
function main()
{
let _1 := datasize("Runtime")
let _2 := 0
let _3:i32 := u256_to_i32(_2, _2, _2, _1)
let _4:i32 := u256_to_i32(_2, _2, _2, dataoffset("Runtime"))
let p:i32 := u256_to_i32(_2, _2, _2, _2)
let r:i32 := i32.add(p, 64:i32)
if i32.lt_u(r, p) { unreachable() }
eth.codeCopy(r, _4, _3)
let _5:i32 := u256_to_i32(_2, _2, _2, _1)
let p_1:i32 := u256_to_i32(_2, _2, _2, _2)
let r_1:i32 := i32.add(p_1, 64:i32)
if i32.lt_u(r_1, p_1) { unreachable() }
eth.finish(r_1, _5)
}
function u256_to_i32(x1, x2, x3, x4) -> v:i32
{
if i64.ne(0, i64.or(i64.or(x1, x2), x3)) { unreachable() }
if i64.ne(0, i64.shr_u(x4, 32)) { unreachable() }
v := i32.wrap_i64(x4)
}
}
object "Runtime" {
code {
function main()
{
let _1 := i64.extend_i32_u(eth.getCallDataSize())
let _2 := 0
let _3:i32 := u256_to_i32(_2, _2, _2, _1)
let _4:i32 := u256_to_i32(_2, _2, _2, _2)
let _5 := 96
let p:i32 := u256_to_i32(_2, _2, _2, _5)
let r:i32 := i32.add(p, 64:i32)
if i32.lt_u(r, p) { unreachable() }
eth.callDataCopy(r, _4, _3)
let x4 := _5
let y1 := _2
let y2 := _2
let y3 := _2
let y4 := 1
let z1 := _2
let z2 := _2
let z3 := _2
let z4 := _2
let _6:i32 := i64.eqz(_2)
if i32.and(_6, _6)
{
if _6
{
if i64.lt_u(_5, 256)
{
if i64.ge_u(_5, 128)
{
y1 := _2
y2 := y4
y3 := _2
y4 := _2
x4 := i64.sub(_5, 128)
}
if i64.ge_u(x4, 64)
{
y1 := y2
y2 := y3
y3 := y4
y4 := _2
x4 := i64.sub(x4, 64)
}
let t, z4_1 := shl_single(y4, x4)
z4 := z4_1
let r_1, z3_1 := shl_single(y3, x4)
z3 := i64.or(z3_1, t)
let t_1, z2_1 := shl_single(y2, x4)
z2 := i64.or(z2_1, r_1)
let r_2, z1_1 := shl_single(y1, x4)
z1 := i64.or(z1_1, t_1)
}
}
}
let _7, _8, _9, _10 := mload(_2, _2, _2, _5)
let _11, _12, _13, _14 := div(_7, _8, _9, _10, z1, z2, z3, z4)
let _15, _16, _17, _18 := staticcall(_2, _2, _2, eth.getGasLeft(), _11, _12, _13, _14, _2, _2, _2, 116, _2, _2, _2, 4, _2, _2, _2, _2, _2, _2, _2, _2)
mstore(_2, _2, _2, _2, _15, _16, _17, _18)
return(_2, _2, _2, _2, _2, _2, _2, 32)
}
function add_carry(x, y, c) -> r, r_c
{
let t := i64.add(x, y)
r := i64.add(t, c)
r_c := i64.extend_i32_u(i32.or(i64.lt_u(t, x), i64.lt_u(r, t)))
}
function add(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4
{
let t := i64.add(x4, y4)
r4 := i64.add(t, 0)
let r3_1, carry := add_carry(x3, y3, i64.extend_i32_u(i32.or(i64.lt_u(t, x4), i64.lt_u(r4, t))))
r3 := r3_1
let r2_1, carry_1 := add_carry(x2, y2, carry)
r2 := r2_1
let r1_1, carry_2 := add_carry(x1, y1, carry_1)
r1 := r1_1
}
function sub(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4
{
let _1 := 0xffffffffffffffff
let t := i64.add(x4, i64.xor(y4, _1))
r4 := i64.add(t, 1)
let r3_1, carry := add_carry(x3, i64.xor(y3, _1), i64.extend_i32_u(i32.or(i64.lt_u(t, x4), i64.lt_u(r4, t))))
r3 := r3_1
let r2_1, carry_1 := add_carry(x2, i64.xor(y2, _1), carry)
r2 := r2_1
let r1_1, carry_2 := add_carry(x1, i64.xor(y1, _1), carry_1)
r1 := r1_1
}
function shl_internal(amount, x1, x2, x3, x4) -> r1, r2, r3, r4
{
let _1 := i64.sub(64, amount)
r1 := i64.add(i64.shl(x1, amount), i64.shr_u(x2, _1))
r2 := i64.add(i64.shl(x2, amount), i64.shr_u(x3, _1))
r3 := i64.add(i64.shl(x3, amount), i64.shr_u(x4, _1))
r4 := i64.shl(x4, amount)
}
function shr_internal(amount, x1, x2, x3, x4) -> r1, r2, r3, r4
{
let _1 := i64.sub(64, amount)
r4 := i64.add(i64.shr_u(x4, amount), i64.shl(x3, _1))
r3 := i64.add(i64.shr_u(x3, amount), i64.shl(x2, _1))
r2 := i64.add(i64.shr_u(x2, amount), i64.shl(x1, _1))
r1 := i64.shr_u(x1, amount)
}
function div(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4
{
if i64.eqz(i64.or(i64.or(y1, y2), i64.or(y3, y4))) { leave }
let m1 := 0
let m2 := m1
let m3 := m1
let m4 := 1
for { } true { }
{
if i32.or(i64.eqz(i64.clz(y1)), i32.eqz(lt_256x256_64(y1, y2, y3, y4, x1, x2, x3, x4))) { break }
let y1_1, y2_1, y3_1, y4_1 := shl_internal(1, y1, y2, y3, y4)
y1 := y1_1
y2 := y2_1
y3 := y3_1
y4 := y4_1
let m1_1, m2_1, m3_1, m4_1 := shl_internal(1, m1, m2, m3, m4)
m1 := m1_1
m2 := m2_1
m3 := m3_1
m4 := m4_1
}
for { }
i32.eqz(i64.eqz(i64.or(i64.or(m1, m2), i64.or(m3, m4))))
{ }
{
if i32.eqz(lt_256x256_64(x1, x2, x3, x4, y1, y2, y3, y4))
{
let x1_1, x2_1, x3_1, x4_1 := sub(x1, x2, x3, x4, y1, y2, y3, y4)
x1 := x1_1
x2 := x2_1
x3 := x3_1
x4 := x4_1
let r1_1, r2_1, r3_1, r4_1 := add(r1, r2, r3, r4, m1, m2, m3, m4)
r1 := r1_1
r2 := r2_1
r3 := r3_1
r4 := r4_1
}
let y1_2, y2_2, y3_2, y4_2 := shr_internal(1, y1, y2, y3, y4)
y1 := y1_2
y2 := y2_2
y3 := y3_2
y4 := y4_2
let m1_2, m2_2, m3_2, m4_2 := shr_internal(1, m1, m2, m3, m4)
m1 := m1_2
m2 := m2_2
m3 := m3_2
m4 := m4_2
}
}
function cmp(a, b) -> r:i32
{
switch i64.lt_u(a, b)
case 1:i32 { r := 0xffffffff:i32 }
default { r := i64.ne(a, b) }
}
function lt_256x256_64(x1, x2, x3, x4, y1, y2, y3, y4) -> z:i32
{
switch cmp(x1, y1)
case 0:i32 {
switch cmp(x2, y2)
case 0:i32 {
switch cmp(x3, y3)
case 0:i32 { z := i64.lt_u(x4, y4) }
case 1:i32 { z := 0:i32 }
default { z := 1:i32 }
}
case 1:i32 { z := 0:i32 }
default { z := 1:i32 }
}
case 1:i32 { z := 0:i32 }
default { z := 1:i32 }
}
function shl_single(a, amount) -> x, y
{
x := i64.shr_u(a, i64.sub(64, amount))
y := i64.shl(a, amount)
}
function u256_to_i32(x1, x2, x3, x4) -> v:i32
{
if i64.ne(0, i64.or(i64.or(x1, x2), x3)) { unreachable() }
if i64.ne(0, i64.shr_u(x4, 32)) { unreachable() }
v := i32.wrap_i64(x4)
}
function to_internal_i32ptr(x1, x2, x3, x4) -> r:i32
{
let p:i32 := u256_to_i32(x1, x2, x3, x4)
r := i32.add(p, 64:i32)
if i32.lt_u(r, p) { unreachable() }
}
function endian_swap_16(x) -> y
{
y := i64.or(i64.and(i64.shl(x, 8), 0xff00), i64.and(i64.shr_u(x, 8), 0xff))
}
function endian_swap_32(x) -> y
{
let hi := i64.shl(endian_swap_16(x), 16)
y := i64.or(hi, endian_swap_16(i64.shr_u(x, 16)))
}
function endian_swap(x) -> y
{
let hi := i64.shl(endian_swap_32(x), 32)
y := i64.or(hi, endian_swap_32(i64.shr_u(x, 32)))
}
function mload(x1, x2, x3, x4) -> z1, z2, z3, z4
{
let _1:i32 := to_internal_i32ptr(x1, x2, x3, x4)
let z1_1 := endian_swap(i64.load(_1))
let z2_1 := endian_swap(i64.load(i32.add(_1, 8:i32)))
let z3_1 := endian_swap(i64.load(i32.add(_1, 16:i32)))
let z4_1 := endian_swap(i64.load(i32.add(_1, 24:i32)))
z1 := z1_1
z2 := z2_1
z3 := z3_1
z4 := z4_1
}
function mstore(x1, x2, x3, x4, y1, y2, y3, y4)
{
mstore_internal(to_internal_i32ptr(x1, x2, x3, x4), y1, y2, y3, y4)
}
function mstore_internal(pos:i32, y1, y2, y3, y4)
{
i64.store(pos, endian_swap(y1))
i64.store(i32.add(pos, 8:i32), endian_swap(y2))
i64.store(i32.add(pos, 16:i32), endian_swap(y3))
i64.store(i32.add(pos, 24:i32), endian_swap(y4))
}
function staticcall(a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4, d1, d2, d3, d4, e1, e2, e3, e4, f1, f2, f3, f4) -> x1, x2, x3, x4
{
if i64.ne(0, b1) { unreachable() }
if i64.ne(0, i64.shr_u(b2, 32)) { unreachable() }
mstore_internal(0:i32, 0, b2, b3, b4)
let _1:i32 := u256_to_i32(d1, d2, d3, d4)
let _2:i32 := to_internal_i32ptr(c1, c2, c3, c4)
if i64.ne(0, i64.or(i64.or(a1, a2), a3)) { unreachable() }
x4 := i64.extend_i32_u(eth.callStatic(a4, 12:i32, _2, _1))
}
function return(x1, x2, x3, x4, y1, y2, y3, y4)
{
eth.finish(to_internal_i32ptr(x1, x2, x3, x4), u256_to_i32(y1, y2, y3, y4))
}
}
}
}
Binary representation:
0061736d0100000001170460000060047e7e7e7e017e60027f7f0060037f7f7f0002270208657468657265756d08636f6465436f7079000308657468657265756d0666696e697368000203030200010503010001060100071102066d656d6f72790200046d61696e000200f4120752756e74696d650061736d01000000017d0f6000006000017e6000017f60017e017e60027e7e017e60037e7e7e017e60047e7e7e7e017e60057e7e7e7e7e0060057e7e7e7e7e017e60087e7e7e7e7e7e7e7e0060087e7e7e7e7e7e7e7e017e60187e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e017e60047e7f7f7f017f60027f7f0060037f7f7f0002720508657468657265756d0f67657443616c6c4461746153697a65000208657468657265756d0a63616c6c537461746963000c08657468657265756d0a6765744761734c656674000108657468657265756d0666696e697368000d08657468657265756d0c63616c6c44617461436f7079000e03151400050a0a08080a040a0406060303030609070b0905030100010610037e0142000b7e0142000b7e0142000b071102066d656d6f72790200046d61696e00050aad1014ef0301257e1000ada7ad2100420021012001200120012000100f21022001200120012001100f210342e00021042001200120012004100f21052005a742c000a76aad21062006a72005a749ad4200520440000b2006a72003a72002a710042004210720012108200121092001210a4201210b2001210c2001210d2001210e2001210f200150ad21102010a72010a771ad420052044020104200520440200442800254ad420052044020044280015aad420052044020012108200b21092001210a2001210b20044280017d21070b200742c0005aad420052044020092108200a2109200b210a2001210b200742c0007d21070b0240200b2007100e2111230021120b2012210f0240200a2007100e2113230021140b2014201184210e024020092007100e2115230021160b2016201384210d024020082007100e2117230021180b2018201584210c0b0b0b02402001200120012004101421192300211a2301211b2302211c0b02402019201a201b201c200c200d200e200f100b211d2300211e2301211f230221200b02402001200120011002201d201e201f202020012001200142f400200120012001420420012001200120012001200120012001101721212300212223012123230221240b2001200120012001202120222023202410152001200120012001200120012001422010180b2c01037e200020017c2105200520027c21032005200054ada72003200554ada772ada7ad21042004240020030b6f010b7e200320077c210c200c42007c210b024020022006200c200354ada7200b200c54ada772ada7ad1006210d2300210e0b200d210a024020012005200e1006210f230021100b200f2109024020002004201010062111230021120b2011210820092400200a2401200b240220080b7f010c7e427f210c20032007200c857c210d200d42017c210b024020022006200c85200d200354ada7200b200d54ada772ada7ad1006210e2300210f0b200e210a024020012005200c85200f10062110230021110b20102109024020002004200c85201110062112230021130b2012210820092400200a2401200b240220080b4801057e42c00020007d2109200120008620022009887c2105200220008620032009887c2106200320008620042009887c21072004200086210820062400200724012008240220050b4801057e42c00020007d2109200420008820032009867c2108200320008820022009867c2107200220008820012009867c21062001200088210520062400200724012008240220050bbb0301207e200420058420062007848450ad42005204400f0b4200210c200c210d200c210e4201210f024003404201500d01024020047950ada720042005200620072000200120022003100da745ada772ad42005204400c030b024042012004200520062007100921102300211123012112230221130b2010210420112105201221062013210702404201200c200d200e200f100921142300211523012116230221170b2014210c2015210d2016210e2017210f0b0b0b02400340200c200d84200e200f848450ada745ad500d01024020002001200220032004200520062007100da745ad420052044002402000200120022003200420052006200710082118230021192301211a2302211b0b2018210020192101201a2102201b2103024020082009200a200b200c200d200e200f1007211c2300211d2301211e2302211f0b201c2108201d2109201e210a201f210b0b024042012004200520062007100a21202300212123012122230221230b2020210420212105202221062023210702404201200c200d200e200f100a21242300212523012126230221270b2024210c2025210d2026210e2027210f0b0b0b20092400200a2401200b240220080b2a01027e02402000200154ad21032003420151044042ffffffff0f2102052000200152ad21020b0b20020b7d01047e024020002004100c210920094200510440024020012005100c210a200a4200510440024020022006100c210b200b42005104402003200754ad210805200b42015104404200210805420121080b0b0b05200a42015104404200210805420121080b0b0b05200942015104404200210805420121080b0b0b20080b1c01027e200042c00020017d882102200020018621032003240020020b2f01017e4200200020018420028452ad4200520440000b4200200342208852ad4200520440000b2003a7ad210420040b2c01027e2000200120022003100f21052005a742c000a76aad21042004a72005a749ad4200520440000b20040b1c01017e20004208864280fe0383200042088842ff018384210120010b1b01027e20001011421086210220022000421088101184210120010b1b01027e20001012422086210220022000422088101284210120010b6801097e2000200120022003101021082008a7290300101321092008a74208a76aada72903001013210a2008a74210a76aada72903001013210b2008a74218a76aada72903001013210c20092104200a2105200b2106200c210720052400200624012007240220040b1801007e20002001200220031010200420052006200710160b3e01007e2000a7200110133703002000a74208a76aada7200210133703002000a74210a76aada7200310133703002000a74218a76aada7200410133703000b7801067e4200200452ad4200520440000b4200200542208852ad4200520440000b420042002005200620071016200c200d200e200f100f211c20082009200a200b1010211d4200200020018420028452ad4200520440000b2003420ca7201da7201ca71001ada7ad211b20192400201a2401201b240220180b1c01007e20002001200220031010a72004200520062007100fa710030b0ac40102910101097e42ec1221004200210120012001200120001003210220012001200142f500100321032001200120012001100321042004a742c000a76aad21052005a72004a749ad4200520440000b2005a72003a72002a710002001200120012000100321062001200120012001100321072007a742c000a76aad21082008a72007a749ad4200520440000b2008a72006a710010b2f01017e4200200020018420028452ad4200520440000b4200200342208852ad4200520440000b2003a7ad210420040b
Text representation:
(module
;; sub-module "Runtime" will be encoded as custom section in binary here, but is skipped in text mode.
(import "ethereum" "codeCopy" (func $eth.codeCopy (param i32 i32 i32)))
(import "ethereum" "finish" (func $eth.finish (param i32 i32)))
(memory $memory (export "memory") 1)
(export "main" (func $main))
(func $main
(local $_1 i64)
(local $_2 i64)
(local $_3 i64)
(local $_4 i64)
(local $p i64)
(local $r i64)
(local $_5 i64)
(local $p_1 i64)
(local $r_1 i64)
(local.set $_1 (datasize "Runtime"))
(local.set $_2 (i64.const 0))
(local.set $_3 (call $u256_to_i32 (local.get $_2) (local.get $_2) (local.get $_2) (local.get $_1)))
(local.set $_4 (call $u256_to_i32 (local.get $_2) (local.get $_2) (local.get $_2) (dataoffset "Runtime")))
(local.set $p (call $u256_to_i32 (local.get $_2) (local.get $_2) (local.get $_2) (local.get $_2)))
(local.set $r (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $p)) (i32.wrap_i64 (i64.const 64)))))
(if (i64.ne (i64.extend_i32_u (i32.lt_u (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (local.get $p)))) (i64.const 0)) (then
(unreachable)))
(call $eth.codeCopy (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (local.get $_4)) (i32.wrap_i64 (local.get $_3)))
(local.set $_5 (call $u256_to_i32 (local.get $_2) (local.get $_2) (local.get $_2) (local.get $_1)))
(local.set $p_1 (call $u256_to_i32 (local.get $_2) (local.get $_2) (local.get $_2) (local.get $_2)))
(local.set $r_1 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $p_1)) (i32.wrap_i64 (i64.const 64)))))
(if (i64.ne (i64.extend_i32_u (i32.lt_u (i32.wrap_i64 (local.get $r_1)) (i32.wrap_i64 (local.get $p_1)))) (i64.const 0)) (then
(unreachable)))
(call $eth.finish (i32.wrap_i64 (local.get $r_1)) (i32.wrap_i64 (local.get $_5)))
)
(func $u256_to_i32
(param $x1 i64)
(param $x2 i64)
(param $x3 i64)
(param $x4 i64)
(result i64)
(local $v i64)
(if (i64.ne (i64.extend_i32_u (i64.ne (i64.const 0) (i64.or (i64.or (local.get $x1) (local.get $x2)) (local.get $x3)))) (i64.const 0)) (then
(unreachable)))
(if (i64.ne (i64.extend_i32_u (i64.ne (i64.const 0) (i64.shr_u (local.get $x4) (i64.const 32)))) (i64.const 0)) (then
(unreachable)))
(local.set $v (i64.extend_i32_u (i32.wrap_i64 (local.get $x4))))
(local.get $v)
)
)
======== wasm2wat =======
(module
(type (;0;) (func))
(type (;1;) (func (param i64 i64 i64 i64) (result i64)))
(type (;2;) (func (param i32 i32)))
(type (;3;) (func (param i32 i32 i32)))
(import "ethereum" "codeCopy" (func (;0;) (type 3)))
(import "ethereum" "finish" (func (;1;) (type 2)))
(func (;2;) (type 0)
(local i64 i64 i64 i64 i64 i64 i64 i64 i64)
i64.const 2412
local.set 0
i64.const 0
local.set 1
local.get 1
local.get 1
local.get 1
local.get 0
call 3
local.set 2
local.get 1
local.get 1
local.get 1
i64.const 117
call 3
local.set 3
local.get 1
local.get 1
local.get 1
local.get 1
call 3
local.set 4
local.get 4
i32.wrap_i64
i64.const 64
i32.wrap_i64
i32.add
i64.extend_i32_u
local.set 5
local.get 5
i32.wrap_i64
local.get 4
i32.wrap_i64
i32.lt_u
i64.extend_i32_u
i64.const 0
i64.ne
if ;; label = @1
unreachable
end
local.get 5
i32.wrap_i64
local.get 3
i32.wrap_i64
local.get 2
i32.wrap_i64
call 0
local.get 1
local.get 1
local.get 1
local.get 0
call 3
local.set 6
local.get 1
local.get 1
local.get 1
local.get 1
call 3
local.set 7
local.get 7
i32.wrap_i64
i64.const 64
i32.wrap_i64
i32.add
i64.extend_i32_u
local.set 8
local.get 8
i32.wrap_i64
local.get 7
i32.wrap_i64
i32.lt_u
i64.extend_i32_u
i64.const 0
i64.ne
if ;; label = @1
unreachable
end
local.get 8
i32.wrap_i64
local.get 6
i32.wrap_i64
call 1)
(func (;3;) (type 1) (param i64 i64 i64 i64) (result i64)
(local i64)
i64.const 0
local.get 0
local.get 1
i64.or
local.get 2
i64.or
i64.ne
i64.extend_i32_u
i64.const 0
i64.ne
if ;; label = @1
unreachable
end
i64.const 0
local.get 3
i64.const 32
i64.shr_u
i64.ne
i64.extend_i32_u
i64.const 0
i64.ne
if ;; label = @1
unreachable
end
local.get 3
i32.wrap_i64
i64.extend_i32_u
local.set 4
local.get 4)
(memory (;0;) 1)
(export "memory" (memory 0))
(export "main" (func 2)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment