zoukankan      html  css  js  c++  java
  • 内联汇编的使用

    基础知识:

    语法;
    内联编译语言也会像Solidity一样解析注释,字面量和标识符。所以你可以使用//和/**/的方式注释。内联编译的在Solidity中的语法是包裹在assembly { ... },下面是可用的语法,后续有更详细的内容。

    字面量。如0x123,42或abc(字符串最多是32个字符)
    操作码(指令的方式),如mload sload dup1 sstore,后面有可支持的指令列表
    函数风格的操作码,如add(1, mlod(0)
    标签,如name:
    变量定义,如let x := 7 或 let x := add(y, 3)
    标识符(标签或内联局部变量或外部),如jump(name),3 x add
    赋值(指令风格),如,3 =: x。
    函数风格的赋值,如x := add(y, 3)
    支持块级的局部变量,如{ let x := 3 { let y := add(x, 1) } }

    预定义操作符
    在语法中,操作码被表示为预先定义的标识符。

    操作码 栈 说明
    stop - stop execution, identical to return(0,0)
    add(x, y) x + y
    sub(x, y) x - y
    mul(x, y) x * y
    div(x, y) x / y
    sdiv(x, y) x / y, for signed numbers in two’s complement
    mod(x, y) x % y
    smod(x, y) x % y, for signed numbers in two’s complement
    exp(x, y) x to the power of y
    not(x) ~x, every bit of x is negated
    lt(x, y) 1 if x < y, 0 otherwise
    gt(x, y) 1 if x > y, 0 otherwise
    slt(x, y) 1 if x < y, 0 otherwise, for signed numbers in two’s complement
    sgt(x, y) 1 if x > y, 0 otherwise, for signed numbers in two’s complement
    eq(x, y) 1 if x == y, 0 otherwise
    iszero(x) 1 if x == 0, 0 otherwise
    and(x, y) bitwise and of x and y
    or(x, y) bitwise or of x and y
    xor(x, y) bitwise xor of x and y
    byte(n, x) nth byte of x, where the most significant byte is the 0th byte
    addmod(x, y, m) (x + y) % m with arbitrary precision arithmetics
    mulmod(x, y, m) (x * y) % m with arbitrary precision arithmetics
    signextend(i, x) sign extend from (i*8+7)th bit counting from least significant
    keccak256(p, n) keccak(mem[p...(p+n)))
    sha3(p, n) keccak(mem[p...(p+n)))
    jump(label) - jump to label / code position
    jumpi(label, cond) - jump to label if cond is nonzero
    pc current position in code
    pop(x) - remove the element pushed by x
    dup1 ... dup16 copy ith stack slot to the top (counting from top)
    swap1 ... swap16 * swap topmost and ith stack slot below it
    mload(p) mem[p..(p+32))
    mstore(p, v) - mem[p..(p+32)) := v
    mstore8(p, v) - mem[p] := v & 0xff - only modifies a single byte
    sload(p) storage[p]
    sstore(p, v) - storage[p] := v
    msize size of memory, i.e. largest accessed memory index
    gas gas still available to execution
    address address of the current contract / execution context
    balance(a) wei balance at address a
    caller call sender (excluding delegatecall)
    callvalue wei sent together with the current call
    calldataload(p) call data starting from position p (32 bytes)
    calldatasize size of call data in bytes
    calldatacopy(t, f, s) - copy s bytes from calldata at position f to mem at position t
    codesize size of the code of the current contract / execution context
    codecopy(t, f, s) - copy s bytes from code at position f to mem at position t
    extcodesize(a) size of the code at address a
    extcodecopy(a, t, f, s) - like codecopy(t, f, s) but take code at address a
    returndatasize size of the last returndata
    returndatacopy(t, f, s) - copy s bytes from returndata at position f to mem at position t
    create(v, p, s) create new contract with code mem[p..(p+s)) and send v wei and return the new address
    create2(v, n, p, s) create new contract with code mem[p..(p+s)) at address keccak256(
    . n . keccak256(mem[p..(p+s))) and send v wei and return the new address
    call(g, a, v, in, insize, out, outsize) call contract at address a with input mem[in..(in+insize)) providing g gas and v wei and output area mem[out..(out+outsize)) returning 0 on error (eg. out of gas) and 1 on success
    callcode(g, a, v, in, insize, out, outsize) identical to call but only use the code from a and stay in the context of the current contract otherwise
    delegatecall(g, a, in, insize, out, outsize) identical to callcode but also keep caller and callvalue
    staticcall(g, a, in, insize, out, outsize) identical to call(g, a, 0, in, insize, out, outsize) but do not allow state modifications
    return(p, s) - end execution, return data mem[p..(p+s))
    revert(p, s) - end execution, revert state changes, return data mem[p..(p+s))
    selfdestruct(a) - end execution, destroy current contract and send funds to a
    invalid - end execution with invalid instruction
    log0(p, s) - log without topics and data mem[p..(p+s))
    log1(p, s, t1) - log with topic t1 and data mem[p..(p+s))
    log2(p, s, t1, t2) - log with topics t1, t2 and data mem[p..(p+s))
    log3(p, s, t1, t2, t3) - log with topics t1, t2, t3 and data mem[p..(p+s))
    log4(p, s, t1, t2, t3, t4) - log with topics t1, t2, t3, t4 and data mem[p..(p+s))
    origin transaction sender
    gasprice gas price of the transaction
    blockhash(b) hash of block nr b - only for last 256 blocks excluding current
    coinbase current mining beneficiary
    timestamp timestamp of the current block in seconds since the epoch
    number current block number
    difficulty difficulty of the current block
    gaslimit block gas limit of the current block

    重点:
    mem [a ... b]表示从位置a开始到(不包括)位置b的存储器的字节,存储器[p]表示位置p处的存储内容。

    你可以在操作码后接着输入操作码,它们最终都会生成正确的字节码。比如:

    3 0x80 mload add 0x80 mstore
    下面将会添加3与memory中位置0x80的值。

    由于经常很难直观的看到某个操作码真正的参数,Solidity内联编译提供了一个函数风格的表达式,上面的代码与下述等同:

    mstore(0x80, add(mload(0x80), 3))

    表示的意思都是 将3添加到位置ox80 并保存 等同于storage

    举例子:
    pragma solidity ^0.4.0;

    library GetCode {
    function at(address _addr) returns (bytes o_code) {
    assembly {
    // 检索代码的大小,这需要汇编
    let size := extcodesize(_addr)
    // 分配输出字节数组 - 这也可以在没有汇编的情况下完成
    // by using o_code = new bytes(size)
    o_code := mload(0x40)
    // 新的“内存端”包括填充
    mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f))))
    // 存储长度在内存中
    mstore(o_code, size)
    // 实际上检索代码,这需要汇编
    extcodecopy(_addr, add(o_code, 0x20), 0, size)
    }
    }
    }

    pragma solidity ^0.4.12;

    library VectorSum {
    // 此功能效率较低,因为优化程序当前无法删除阵列访问中的边界检查。
    function sumSolidity(uint[] _data) returns (uint o_sum) {
    for (uint i = 0; i < _data.length; ++i)
    o_sum += _data[i];
    }

    // 我们知道我们只能在边界访问数组,所以我们可以避免检查。 0x20需要添加到数组,因为第一个插槽包含数组长度。
    function sumAsm(uint[] _data) returns (uint o_sum) {
        for (uint i = 0; i < _data.length; ++i) {
            assembly {
                o_sum := add(o_sum, mload(add(add(_data, 0x20), mul(i, 0x20))))
            }
        }
    }
    
    // 与上述相同,但在内联汇编中完成整个代码。
    function sumPureAsm(uint[] _data) returns (uint o_sum) {
        assembly {
           // 加载长度(前32个字节)
           let len := mload(_data)
    
           // 跳过长度字段。
           //
           // 保持临时变量,使其可以增加到位。
           //
           // 注意:增加_data将导致此程序集后不可用的_data变量
           let data := add(_data, 0x20)
    
           // 迭代,直到绑定不满足。
           for
               { let end := add(data, len) }
               lt(data, end)
               { data := add(data, 0x20) }
           {
               o_sum := add(o_sum, mload(data))
           }
        }
    }
    

    }

  • 相关阅读:
    忘记线上MySQL密码:
    Auth认证
    swoole定时
    hashMap,hashTable,concurrentHashmap的区别
    JSP中URL路径获取问题
    #Spring代理的简单例子#
    #动态代理#
    #类加载机制#
    #算法#二分查找和插入(start end交叉的地方)
    #tomcat#生成的jsp转换问题
  • 原文地址:https://www.cnblogs.com/xiaocongcong888/p/9636284.html
Copyright © 2011-2022 走看看