ä»åã®è¨äºã¯Solidity Assemblyå
¥éã¨ããé£è¼è¨äºã®ç¬¬ï¼åç®ã§ãã
ãã®é£è¼ã§ã¯Solidityã®ã³ã¼ããã³ã³ãã¤ã«ããæã«çæãããopcodeã«ã¤ãã¦è§£èª¬ãã¦ããã¾ãã
ãã®é£è¼ã§ã¯Solidityã®ã³ã¼ãããããã°ããã®ã«å¿
è¦ãªç¥èãå¾ããããã¨ãç®çã¨ãã¦ãã¾ãã
ååã®è¨äºã¯ãã¡ãã
y-nakajo.hatenablog.com
第ï¼åç®ã®ä»åã¯ãSolidityï¼ã¨ãããEVMä¸ï¼ã§å©ç¨å¯è½ãªãã¼ã¿ã®è¨æ¶é åã«ã¤ãã¦èª¬æãã¾ãã
5ã¤ã®è¨æ¶é å
Solidityã®ã³ã¼ããå®è¡ããæã«EVMã§ã¯ä»¥ä¸ã®5ã¤ã®é åã使ã£ã¦ãã¼ã¿ã®ããã¨ããè¡ãã¾ãã
- stack
- memory
- storage
- calldata
- returndata
ä¸è¨ï¼ã¤ä»¥å¤ã«ãcodeé åã¨ããSmartContractã®æ¬ä½ã³ã¼ããæ ¼ç´ããé åãããã¾ããcodeé åã¯èªã¿åãå°ç¨ã®ãããè¨æ¶é åã¨ã¯ã¡ãã£ã¨éãã®ã§ä»åã®èª¬æã§ã¯é¤å¤ãã¾ãã
åºæ¬çã«SmartContractã®functionãå®è¡ããæã¯codeé åãé¤ããæ®ãã®5ã¤ã®é åã使ãã¾ããããããã®é åããã¤ä½¿ãããã®ãã説æãã¦ããããã¨æãã¾ãã
stacké å
pragma solidity ^0.4.24; contract SimpleContract { function getNum() public pure returns(uint){ uint a = 1; uint b = 2; return a + b; } }
ä¸è¨ã³ã¼ããå®è¡ããå ´ååºæ¬çã«stacké åã®ã¿ããå©ç¨ãã¾ãããstacké åãæä½ããåºæ¬ã®opcodeã¯ä»¥ä¸ã®ãã®ãããã¾ãã
- PUSH01ãPUSH32: 次ã«ç¶ã1ã32byteã®ãã¼ã¿ãstackã®å é ã«ç©ã¿ã¾ã
- DUP1ãDUP16: stackä¸ã®1ã16çªç®ã®å¤ãã³ãã¼ãã¦stackã®å é ã«ç©ã¿ã¾ã
- POP: stackã®å é ã®ãã¼ã¿ãåãé¤ãã¾ã
- SWAP1ãSWAP16: stackä¸ã®2ã17çªç®ã®ãã¼ã¿ã¨å é ã®ãã¼ã¿ãå ¥ãæ¿ãã¾ãã
- ADD, SUB, MOD, MUL, EXP, ADDMOD, MULMOD: ååæ¼ç®ç³»ã®opcode
ãã以å¤ã®opcodeãåºæ¬çã«stackä¸ã®å¤ã使ãã¾ãããªã®ã§stackã¯ä¸çªå©ç¨ãããé åã«ãªãã¾ãã
memoryé å
pragma solidity ^0.4.24; contract SimpleContract { struct Data { uint a; uint b; } function getNum() public pure returns(uint){ Data memory datas; datas.a = 1; datas.b = 2; return datas.a + datas.b; } }
ä¸è¨ã®ã³ã¼ããå®è¡ããã¨ãDataæ§é ä½ã«å¤ãæ ¼ç´ããããã«memoryé åãå©ç¨ãã¾ãã
*é
åã®ä¾ãèããã®ã§ãããé
åã ã¨çµæ§è¤éãªopcodeãçæããã¡ãã£ãã®ã§structã«ãã¾ãããããã
Remixã§ãããã¬ã¼ãèµ·åããã¨ãmemoryã®0x80ã«1ã0xa0ã«2ãããããæ ¼ç´ãã0x80ã¨0xa0ããå¤ãåãåºãã¦ADDããopcodeã確èªã§ããã¨æãã¾ããmemoryãæä½ããããã®åºæ¬ã®opcodeã¯ä»¥ä¸ã§ãã
- MSTORE(p, v); pãå é ã¢ãã¬ã¹ã¨ãã¦p+32ã®32byteé åã«vã®å¤ãæ ¼ç´ãã¾ãã
- MSTOREB(p, v); pã®ä½ç½®ã«v & 0xffã®1byteãã¼ã¿ãæ ¼ç´ãã¾ãã
- MLOAD(p): pãå é ã¢ãã¬ã¹ãã¦p+32ã¾ã§ã®32byteã®å¤ããã¼ããã¦stackã®å é ã«ç©ã¿ã¾ãã
ãã®æ§ã«åºæ¬çã«memoryã¸ã®å¤ã®in/outã¯32byteåä½ã§è¡ããã¾ããä»ã«ãsha3ãdelegatecallãªã©ã®å¤§ããªãã¼ã¿ãæ±ãopcodeã¯ã¡ã¢ãªã対象ã¨ãã¦åä½ãã¾ããã¾ããMSTOREãMLOADã§æ¸¡ãããp, vã¯ããããstackä¸ããèªã¿åãã¾ãããªã®ã§MSTOREãå®è¡ããã¨stackä¸ããï¼ã¤ã®å¤ãåãé¤ããã¾ããMLOADã®å ´åã¯1ã¤ã®å¤ãstackä¸ããåãé¤ãããæ°ããå¤ãç©ã¾ãã¾ãã
memoryé åã¯stackã«ã¤ãã§ï¼çªç®ã«ãã使ãããé åã§ãã
storageé å
pragma solidity ^0.4.24; contract SimpleContract { uint public a; uint public b; function setNum() public { a = 1; b = 2; } function getAdd() public view returns(uint) { return a + b; } }
ä¸è¨ã®setNum()ãå®è¡ããã¨ãaã®å¤ãstorageã®0x00ã®ä½ç½®ã«ãbã®å¤ãstorageã®0x01ã®ä½ç½®ã«æ ¼ç´ãã¾ãã
ãã®èª¬æã§ãããéããstorageå¤æ°ã¯compileããã¨ãã¹ã¦storageä¸ã®ã¢ãã¬ã¹ã¸ã¨å¤æããã¾ããã¢ãã¬ã¹ã®æ¯ãåãã¨ãã¦ã¯0x00ããéå§ããå¤æ°ãå®ç¾©ããé çªã«0x01ã0x02...ã¨æ¯ããã¦ããã¾ããï¼ã¤ã®storageã¢ãã¬ã¹ã«ã¯32byteã®ãã¼ã¿ãæ ¼ç´ããã¾ãã
ã¾ããgetAdd()ãå®è¡ããã¨ãstorageã®0x00ä½ç½®ã¨0x01ã®ä½ç½®ãããã¼ã¿ããã¼ããã¦å ç®ããçµæãè¿ãã¾ãã
storageãæä½ããopcodeã¯ä»¥ä¸ã®ï¼ã¤ã®ã¿ã§ãã
- SSTORE(p, v): storageã®pã®ä½ç½®ã«32byteã®vå¤ãæ ¼ç´ãã¾ãã
- SLOAD(p): storageã®pã®ä½ç½®ãã32byteã®å¤ããã¼ããstackã®å é ã«ç©ã¿ã¾ãã
storageã¯contractã®ç¶æ
ãä¿åããé åã§ããstorageã«ä¿åããå¤ã¯æ°¸ç¶åããã¾ãããã®ããstorageã®æä½ã«ã¯å¤§éã®gasãæ¶è²»ããã¾ããgasã®æ¶è²»éã«ã¤ãã¦ã¯ãã¡ããåç
§ãã ããã
y-nakajo.hatenablog.com
calldataé å
pragma solidity ^0.4.24; contract SimpleContract { function getNum(uint a, uint b) public pure returns(uint) { return a + b; } }
ä¸è¨ã³ã¼ããå®è¡ãããããã¬ã¼ãèµ·åãã¦program counter 086(optimize = falseã§compileããå ´å)ããå®è¡ãéå§ãããã¨ã§ãcalldatasize, calldataloadã®å¦çã確èªã§ãã¾ããããããããªãå ´åã¯ãããã¬ã¼ãèµ·åå¾ãããã°ã©ã ã«ã¦ã³ã¿ã®å
é ããstepå®è¡ãã¦ããã¨è¯ãã§ãã
ã³ã¼ãããã¿ã¦ãããéããcalldataã¯functionã®å¼æ°ãæ ¼ç´ããããã®é åã§ããcontextã®åãæ¿ãï¼call, delegatecallãå¼ã³åºãæã«åãæ¿ããã¾ãï¼ãè¡ãããæã«åè¨å®ããã¾ãããcontextãåãæ¿ãããªãéã¯å¤ã¯ä¿æããã¾ãã
calldataãæä½ããopcodeã¯ä»¥ä¸ã®ï¼ã¤ã§ãã
- calldatasize: calldataã«æ ¼ç´ããããã¼ã¿ãµã¤ãºãstackã®å é ã«ç©ã¿ã¾ãã
- calldataload(p): calldataã®pã®ä½ç½®ããp+32ã®ä½ç½®ã¾ã§ã®32byteã®ãã¼ã¿ãstackã®å é ã«ç©ã¿ã¾ãã
- calldatacopy(t, f, s): calldataé åã®fã®ä½ç½®ããsã§æå®ããããµã¤ãº(s bytes)ã®ãã¼ã¿ãmemory tã®ä½ç½®ã«ã³ãã¼ãã¾ããã¤ã¾ããã¡ã¢ãªã®tãt+sã¾ã§ã®éã«ã³ãã¼ãã¾ãã
calldataé åã使ãããã®ã¯ãtransactionãããªã¬ã¼ã¨ãã¦functionãcallãããæããcall, delegatecallã§å¥ã®contractãå¼ã³åºããæã ãã§ããåãContractå ã®ä»ã®functionãå¼ã³åºãæã¯stacké åã使ã£ã¦å¼æ°ã¯æ¸¡ããã¾ãã
returndataé å
pragma solidity ^0.4.24; contract SimpleContract { Callee callee; constructor(address _callee) public { callee = Callee(_callee); } function getNum() public view returns(uint) { uint[] memory res = callee.calcAdd(1,2); return res[0] + res[1]; } } contract Callee { function calcAdd(uint a, uint b) public pure returns(uint[]) { uint[] memory array = new uint[](2); array[0] = a; array[1] = b; return array; } }
ä¸è¨ã³ã¼ãã®SimpleContract#getNum()ãã³ã¼ã«ãããããã¬ã¼ãèµ·åããã¨returndatasizeãreturndatacopyã®åä½ã確èªã§ãã¾ãã
program counterã®299(optimize=falseã§compileããå ´å)以éãreturndataããå¤ãåå¾ããå¦çã«ãªãã¾ãã
ã³ã¼ããããããéããreturndataé åã¯ä»ã®Contractã®é¢æ°ãå¼ã³åºããã¨ãã®è¿å´ãã¼ã¿ã®æ ¼ç´å
ã§ããããã¯calldataã¨åæ§ã«callãdelegatecallã§Contractã®functionãå¼ã³åºãæ(=å¥ã®contextãããã¼ã¿ãreturnããæ)ã«å©ç¨ããã¾ãã
Contractå
ã®ä»ã®functionãå¼ã³åºãå ´åã¯stackã«return dataãç©ã¾ããã®ã§ãreturndataé åã¯ä½¿ããã¾ããã
returndataãæä½ããopcodeã¯Byzantiumããªãªã¼ã¹ãããæã«å®è£
ããã¾ããããã®ããæ¯è¼çæ°ããopcodeã§ãã
returndataé åãæä½ããopcodeã¯ä»¥ä¸ã®ï¼ã¤ã§ãã
- returndatasize: returndataã«æ ¼ç´ããã¦ãããã¼ã¿ã®ãµã¤ãºãstackã®å é ã«ç©ã¿ã¾ãã
- returndatacopy(t, f, s): returndataé åã®fã®ä½ç½®ããsã§æå®ããããµã¤ãº(s bytes)ã®ãã¼ã¿ãmemory tã®ä½ç½®ã«ã³ãã¼ãã¾ããã¤ã¾ããã¡ã¢ãªã®tãt+sã¾ã§ã®éã«ã³ãã¼ãã¾ãã
å®ã¯return dataã¯stackãmemory ä¸ã«ãæ®ã£ã¦ãã¾ã(context åãæ¿ãæã«ãmemoryã¨stackã¯å ±éãã¦ä½¿ããããã)ããã®ãããreturn dataãåºå®ãµã¤ãº(ä¾ãã°uintã®ã¿ã¨ã)ã®å ´åã¯returndataé åã使ããmemoryããsimpleã«ãã¼ãããæ§ãªopcodeã«å¤æããã¾ãã
ã¾ã¨ã
åºæ¬çã«Solidityãæ¸ãå ´åã«æèããã®ã¯memoryãstorageé åã®ã¿ã§ããcalldataãreturndataã¯ç´æ¥assemblyãæ¸ãæãããããæ示çã«ä½¿ããã¨ã¯ãªãã¨æãã¾ãã
ã§ããããããã¬ã¼ãåããã¦åé¡ã®ããã³ã¼ããç¹å®ãããæã¯ãããã®ï¼ã¤ã®ä¿åé åã¨ãããããæä½ããopcodeã¸ã®ç解ãããã°ããå¹ççã«åé¡ç¹ãè¦ã¤ãããã¨ãã§ãã¾ãã