diff --git a/docs/yul.rst b/docs/yul.rst index 473496e16..832153625 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -927,6 +927,30 @@ will store ``value`` at all points in memory that contain a call to ``loadimmutable("name")``. +linkersymbol +^^^^^^^^^^^^ + +The function ``linkersymbol("fq_library_name")`` is a placeholder for an address literal to be +substituted by the linker. Its first and only argument must be a string literal and represents the +fully qualified library name used with the ``--libraries`` option. + +For example this code + +.. code-block:: yul + + let a := linkersymbol("file.sol:Math") + +is equivalent to + +.. code-block:: yul + + let a := 0x1234567890123456789012345678901234567890 + +when the linker is invoked with ``--libraries "file.sol:Math:0x1234567890123456789012345678901234567890`` +option. + +See :ref:`Using the Commandline Compiler ` for details about the Solidity linker. + .. _yul-object: diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index 3c639f3d1..6cf006638 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -544,7 +544,7 @@ void AsmAnalyzer::expectType(YulString _expectedType, YulString _givenType, Sour bool AsmAnalyzer::warnOnInstructions(std::string const& _instructionIdentifier, langutil::SourceLocation const& _location) { auto const builtin = EVMDialect::strictAssemblyForEVM(EVMVersion{}).builtin(YulString(_instructionIdentifier)); - if (builtin) + if (builtin && builtin->instruction.has_value()) return warnOnInstructions(builtin->instruction.value(), _location); else return false; diff --git a/libyul/backends/evm/EVMDialect.cpp b/libyul/backends/evm/EVMDialect.cpp index 6875df234..b6a46043e 100644 --- a/libyul/backends/evm/EVMDialect.cpp +++ b/libyul/backends/evm/EVMDialect.cpp @@ -124,6 +124,17 @@ map createBuiltins(langutil::EVMVersion _evmVe ) builtins.emplace(createEVMFunction(instr.first, instr.second)); + builtins.emplace(createFunction("linkersymbol", 1, 1, SideEffects{}, {true}, []( + FunctionCall const& _call, + AbstractAssembly& _assembly, + BuiltinContext&, + function + ) { + yulAssert(_call.arguments.size() == 1, ""); + Expression const& arg = _call.arguments.front(); + _assembly.appendLinkerSymbol(std::get(arg).value.str()); + })); + if (_objectAccess) { builtins.emplace(createFunction("datasize", 1, 1, SideEffects{}, {true}, []( diff --git a/test/libyul/objectCompiler/linkersymbol.yul b/test/libyul/objectCompiler/linkersymbol.yul new file mode 100644 index 000000000..65bf004ef --- /dev/null +++ b/test/libyul/objectCompiler/linkersymbol.yul @@ -0,0 +1,42 @@ +object "a" { + code { + let addr := linkersymbol("contract/test.sol:L") + mstore(128, shl(227, 0x18530aaf)) + let success := call(gas(), addr, 0, 128, 4, 128, 0) + } +} +// ---- +// Assembly: +// linkerSymbol("f919ba91ac99f96129544b80b9516b27a80e376b9dc693819d0b18b7e0395612") +// /* "source":109:119 */ +// 0x18530aaf +// /* "source":104:107 */ +// 0xe3 +// /* "source":100:120 */ +// shl +// /* "source":95:98 */ +// 0x80 +// /* "source":88:121 */ +// mstore +// /* "source":179:180 */ +// 0x00 +// /* "source":174:177 */ +// 0x80 +// /* "source":171:172 */ +// 0x04 +// /* "source":166:169 */ +// 0x80 +// /* "source":163:164 */ +// 0x00 +// /* "source":157:161 */ +// dup6 +// /* "source":150:155 */ +// gas +// /* "source":145:181 */ +// call +// /* "source":22:187 */ +// pop +// pop +// Bytecode: 7300000000000000000000000000000000000000006318530aaf60e31b60805260006080600460806000855af15050 +// Opcodes: PUSH20 0x0 PUSH4 0x18530AAF PUSH1 0xE3 SHL PUSH1 0x80 MSTORE PUSH1 0x0 PUSH1 0x80 PUSH1 0x4 PUSH1 0x80 PUSH1 0x0 DUP6 GAS CALL POP POP +// SourceMappings: :::-:0;109:10:0;104:3;100:20;95:3;88:33;179:1;174:3;171:1;166:3;163:1;157:4;150:5;145:36;22:165; diff --git a/test/libyul/yulSyntaxTests/linkersymbol_evm.yul b/test/libyul/yulSyntaxTests/linkersymbol_evm.yul new file mode 100644 index 000000000..2bec7e49c --- /dev/null +++ b/test/libyul/yulSyntaxTests/linkersymbol_evm.yul @@ -0,0 +1,6 @@ +{ + let addr := linkersymbol("contract/library.sol:L") +} +// ==== +// dialect: evm +// ---- diff --git a/test/libyul/yulSyntaxTests/linkersymbol_evmtyped.yul b/test/libyul/yulSyntaxTests/linkersymbol_evmtyped.yul new file mode 100644 index 000000000..1cadcee0c --- /dev/null +++ b/test/libyul/yulSyntaxTests/linkersymbol_evmtyped.yul @@ -0,0 +1,6 @@ +{ + let addr:u256 := linkersymbol("contract/library.sol:L") +} +// ==== +// dialect: evmTyped +// ---- diff --git a/test/libyul/yulSyntaxTests/linkersymbol_ewasm.yul b/test/libyul/yulSyntaxTests/linkersymbol_ewasm.yul new file mode 100644 index 000000000..2b01045ce --- /dev/null +++ b/test/libyul/yulSyntaxTests/linkersymbol_ewasm.yul @@ -0,0 +1,7 @@ +{ + linkersymbol("contract/library.sol:L") +} +// ==== +// dialect: ewasm +// ---- +// DeclarationError 4619: (6-18): Function not found. diff --git a/test/libyul/yulSyntaxTests/linkersymbol_non_literal_args.yul b/test/libyul/yulSyntaxTests/linkersymbol_non_literal_args.yul new file mode 100644 index 000000000..e8b860a01 --- /dev/null +++ b/test/libyul/yulSyntaxTests/linkersymbol_non_literal_args.yul @@ -0,0 +1,8 @@ +{ + let library_name := "contract/library.sol:L" + let addr := linkersymbol(library_name) +} +// ==== +// dialect: evm +// ---- +// TypeError 9114: (67-79): Function expects direct literals as arguments. diff --git a/test/libyul/yulSyntaxTests/string_literal_too_long_linkersymbol.yul b/test/libyul/yulSyntaxTests/string_literal_too_long_linkersymbol.yul new file mode 100644 index 000000000..cf8ef95e1 --- /dev/null +++ b/test/libyul/yulSyntaxTests/string_literal_too_long_linkersymbol.yul @@ -0,0 +1,6 @@ +{ + let addr := linkersymbol("contract/long___name___that___definitely___exceeds___the___thirty___two___byte___limit.sol:L") +} +// ==== +// dialect: evm +// ----