mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #4992 from ethereum/docs-1190-inline-assembly
Docs: Improve sections of Inline assembly
This commit is contained in:
commit
7e749056e8
@ -4,22 +4,25 @@ Solidity Assembly
|
|||||||
|
|
||||||
.. index:: ! assembly, ! asm, ! evmasm
|
.. index:: ! assembly, ! asm, ! evmasm
|
||||||
|
|
||||||
Solidity defines an assembly language that can also be used without Solidity.
|
Solidity defines an assembly language that you can use without Solidity and also
|
||||||
This assembly language can also be used as "inline assembly" inside Solidity
|
as "inline assembly" inside Solidity source code. This guide starts with describing
|
||||||
source code. We start with describing how to use inline assembly and how it
|
how to use inline assembly, how it differs from standalone assembly, and
|
||||||
differs from standalone assembly and then specify assembly itself.
|
specifies assembly itself.
|
||||||
|
|
||||||
.. _inline-assembly:
|
.. _inline-assembly:
|
||||||
|
|
||||||
Inline Assembly
|
Inline Assembly
|
||||||
===============
|
===============
|
||||||
|
|
||||||
For more fine-grained control especially in order to enhance the language by writing libraries,
|
You can interleave Solidity statements with inline assembly in a language close
|
||||||
it is possible to interleave Solidity statements with inline assembly in a language close
|
to the one of the virtual machine. This gives you more fine-grained control,
|
||||||
to the one of the virtual machine. Due to the fact that the EVM is a stack machine, it is
|
especially when you are enhancing the language by writing libraries.
|
||||||
often hard to address the correct stack slot and provide arguments to opcodes at the correct
|
|
||||||
point on the stack. Solidity's inline assembly tries to facilitate that and other issues
|
As the EVM is a stack machine, it is often hard to address the correct stack slot
|
||||||
arising when writing manual assembly by the following features:
|
and provide arguments to opcodes at the correct point on the stack. Solidity's inline
|
||||||
|
assembly helps you do this, and with other issues that arise when writing manual assembly.
|
||||||
|
|
||||||
|
Inline assembly has the following features:
|
||||||
|
|
||||||
* functional-style opcodes: ``mul(1, add(2, 3))``
|
* functional-style opcodes: ``mul(1, add(2, 3))``
|
||||||
* assembly-local variables: ``let x := add(2, 3) let y := mload(0x40) x := add(x, y)``
|
* assembly-local variables: ``let x := add(2, 3) let y := mload(0x40) x := add(x, y)``
|
||||||
@ -29,24 +32,38 @@ arising when writing manual assembly by the following features:
|
|||||||
* switch statements: ``switch x case 0 { y := mul(x, 2) } default { y := 0 }``
|
* switch statements: ``switch x case 0 { y := mul(x, 2) } default { y := 0 }``
|
||||||
* function calls: ``function f(x) -> y { switch x case 0 { y := 1 } default { y := mul(x, f(sub(x, 1))) } }``
|
* function calls: ``function f(x) -> y { switch x case 0 { y := 1 } default { y := mul(x, f(sub(x, 1))) } }``
|
||||||
|
|
||||||
We now want to describe the inline assembly language in detail.
|
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
Inline assembly is a way to access the Ethereum Virtual Machine
|
Inline assembly is a way to access the Ethereum Virtual Machine
|
||||||
at a low level. This discards several important safety
|
at a low level. This bypasses several important safety
|
||||||
features of Solidity.
|
features and checks of Solidity. You should only use it for
|
||||||
|
tasks that need it, and only if you are confident with using it.
|
||||||
|
|
||||||
.. note::
|
Syntax
|
||||||
TODO: Write about how scoping rules of inline assembly are a bit different
|
------
|
||||||
and the complications that arise when for example using internal functions
|
|
||||||
of libraries. Furthermore, write about the symbols defined by the compiler.
|
Assembly parses comments, literals and identifiers in the same way as Solidity, so you can use the
|
||||||
|
usual ``//`` and ``/* */`` comments. Inline assembly is marked by ``assembly { ... }`` and inside
|
||||||
|
these curly braces, you can use the following (see the later sections for more details):
|
||||||
|
|
||||||
|
- literals, i.e. ``0x123``, ``42`` or ``"abc"`` (strings up to 32 characters)
|
||||||
|
- opcodes in functional style, e.g. ``add(1, mlod(0))``
|
||||||
|
- labels, e.g. ``name:``
|
||||||
|
- variable declarations, e.g. ``let x := 7``, ``let x := add(y, 3)`` or ``let x`` (initial value of empty (0) is assigned)
|
||||||
|
- identifiers (labels or assembly-local variables and externals if used as inline assembly), e.g. ``jump(name)``, ``3 x add``
|
||||||
|
- assignments (in "instruction style"), e.g. ``3 =: x``
|
||||||
|
- assignments in functional style, e.g. ``x := add(y, 3)``
|
||||||
|
- blocks where local variables are scoped inside, e.g. ``{ let x := 3 { let y := add(x, 1) } }``
|
||||||
|
|
||||||
|
At the end of the ``assembly { ... }`` block, the stack must be balanced,
|
||||||
|
unless you require it otherwise. If it is not balanced, the compiler generates
|
||||||
|
a warning.
|
||||||
|
|
||||||
Example
|
Example
|
||||||
-------
|
-------
|
||||||
|
|
||||||
The following example provides library code to access the code of another contract and
|
The following example provides library code to access the code of another contract and
|
||||||
load it into a ``bytes`` variable. This is not possible at all with "plain Solidity" and the
|
load it into a ``bytes`` variable. This is not possible with "plain Solidity" and the
|
||||||
idea is that assembly libraries will be used to enhance the language in such ways.
|
idea is that assembly libraries will be used to enhance the Solidity language.
|
||||||
|
|
||||||
.. code::
|
.. code::
|
||||||
|
|
||||||
@ -70,10 +87,8 @@ idea is that assembly libraries will be used to enhance the language in such way
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Inline assembly could also be beneficial in cases where the optimizer fails to produce
|
Inline assembly is also beneficial in cases where the optimizer fails to produce
|
||||||
efficient code. Please be aware that assembly is much more difficult to write because
|
efficient code, for example:
|
||||||
the compiler does not perform checks, so you should use it for complex things only if
|
|
||||||
you really know what you are doing.
|
|
||||||
|
|
||||||
.. code::
|
.. code::
|
||||||
|
|
||||||
@ -125,22 +140,6 @@ you really know what you are doing.
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Syntax
|
|
||||||
------
|
|
||||||
|
|
||||||
Assembly parses comments, literals and identifiers exactly as Solidity, so you can use the
|
|
||||||
usual ``//`` and ``/* */`` comments. Inline assembly is marked by ``assembly { ... }`` and inside
|
|
||||||
these curly braces, the following can be used (see the later sections for more details)
|
|
||||||
|
|
||||||
- literals, i.e. ``0x123``, ``42`` or ``"abc"`` (strings up to 32 characters)
|
|
||||||
- opcodes in functional style, e.g. ``add(1, mlod(0))``
|
|
||||||
- labels, e.g. ``name:``
|
|
||||||
- variable declarations, e.g. ``let x := 7``, ``let x := add(y, 3)`` or ``let x`` (initial value of empty (0) is assigned)
|
|
||||||
- identifiers (labels or assembly-local variables and externals if used as inline assembly), e.g. ``jump(name)``, ``3 x add``
|
|
||||||
- assignments (in "instruction style"), e.g. ``3 =: x``
|
|
||||||
- assignments in functional style, e.g. ``x := add(y, 3)``
|
|
||||||
- blocks where local variables are scoped inside, e.g. ``{ let x := 3 { let y := add(x, 1) } }``
|
|
||||||
|
|
||||||
.. _opcodes:
|
.. _opcodes:
|
||||||
|
|
||||||
Opcodes
|
Opcodes
|
||||||
@ -368,17 +367,17 @@ Note that the order of arguments is reversed in functional-style as opposed to t
|
|||||||
way. If you use functional-style, the first argument will end up on the stack top.
|
way. If you use functional-style, the first argument will end up on the stack top.
|
||||||
|
|
||||||
|
|
||||||
Access to External Variables and Functions
|
Access to External Variables, Functions and Libraries
|
||||||
------------------------------------------
|
-----------------------------------------------------
|
||||||
|
|
||||||
Solidity variables and other identifiers can be accessed by simply using their name.
|
You can access Solidity variables and other identifiers by using their name.
|
||||||
For memory variables, this will push the address and not the value onto the
|
For variables stored in the memory data location, this pushes the address, and not the value
|
||||||
stack. Storage variables are different: Values in storage might not occupy a
|
onto the stack. Variables stored in the storage data location are different, as they might not
|
||||||
full storage slot, so their "address" is composed of a slot and a byte-offset
|
occupy a full storage slot, so their "address" is composed of a slot and a byte-offset
|
||||||
inside that slot. To retrieve the slot pointed to by the variable ``x``, you
|
inside that slot. To retrieve the slot pointed to by the variable ``x``, you
|
||||||
used ``x_slot`` and to retrieve the byte-offset you used ``x_offset``.
|
use ``x_slot``, and to retrieve the byte-offset you use ``x_offset``.
|
||||||
|
|
||||||
In assignments (see below), we can even use local Solidity variables to assign to.
|
Local Solidity variables are available for assignments, for example:
|
||||||
|
|
||||||
.. code::
|
.. code::
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user