From 765024eaf5aae843890ce2ad1ef320e45bd95ae7 Mon Sep 17 00:00:00 2001 From: xermicus Date: Thu, 13 Feb 2025 12:34:38 +0100 Subject: [PATCH 1/2] llvm-context: remove the linear memory pointer indirection Signed-off-by: xermicus --- CHANGELOG.md | 4 ++ crates/integration/contracts/MLoad.sol | 40 +++++++++++++++++++ crates/integration/src/tests.rs | 1 + crates/llvm-context/src/polkavm/const/mod.rs | 6 --- .../polkavm/context/function/runtime/entry.rs | 35 +++------------- .../llvm-context/src/polkavm/context/mod.rs | 27 +++++++------ crates/runtime-api/src/lib.rs | 2 +- crates/runtime-api/src/polkavm_imports.c | 10 ++--- crates/runtime-api/src/polkavm_imports.rs | 19 ++++----- 9 files changed, 75 insertions(+), 69 deletions(-) create mode 100644 crates/integration/contracts/MLoad.sol diff --git a/CHANGELOG.md b/CHANGELOG.md index e1c40b23..d6c4deff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ This is a development pre-release. Supported `polkadot-sdk` rev: `274a781e8ca1a9432c7ec87593bd93214abbff50` +### Fixed +- A bug causing incorrect loads from the emulated EVM linear memory. +- A missing integer truncate after switching to 64bit. + ## v0.1.0-dev.10 This is a development pre-release. diff --git a/crates/integration/contracts/MLoad.sol b/crates/integration/contracts/MLoad.sol new file mode 100644 index 00000000..74ee6722 --- /dev/null +++ b/crates/integration/contracts/MLoad.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.28; + +/* runner.json +{ + "differential": true, + "actions": [ + { + "Instantiate": { + "code": { + "Solidity": { + "contract": "MLoad" + } + } + } + }, + { + "Call": { + "dest": { + "Instantiated": 0 + }, + "data": "e2179b8e" + } + } + ] +} +*/ + +contract MLoad { + constructor() payable { + assert(g() == 0); + } + + function g() public payable returns (uint m) { + assembly { + m := mload(0) + } + } +} diff --git a/crates/integration/src/tests.rs b/crates/integration/src/tests.rs index ed874eab..3b1cac96 100644 --- a/crates/integration/src/tests.rs +++ b/crates/integration/src/tests.rs @@ -55,6 +55,7 @@ test_spec!(create2, "CreateB", "Create2.sol"); test_spec!(transfer, "Transfer", "Transfer.sol"); test_spec!(send, "Send", "Send.sol"); test_spec!(function_pointer, "FunctionPointer", "FunctionPointer.sol"); +test_spec!(mload, "MLoad", "MLoad.sol"); fn instantiate(path: &str, contract: &str) -> Vec { vec![Instantiate { diff --git a/crates/llvm-context/src/polkavm/const/mod.rs b/crates/llvm-context/src/polkavm/const/mod.rs index ce42a179..3285539e 100644 --- a/crates/llvm-context/src/polkavm/const/mod.rs +++ b/crates/llvm-context/src/polkavm/const/mod.rs @@ -6,15 +6,9 @@ pub const LLVM_VERSION: semver::Version = semver::Version::new(18, 1, 4); /// The pointer width sized type. pub static XLEN: usize = revive_common::BIT_LENGTH_X32; -/// The heap memory pointer pointer global variable name. -pub static GLOBAL_HEAP_MEMORY_POINTER: &str = "memory_pointer"; - /// The calldata size global variable name. pub static GLOBAL_CALLDATA_SIZE: &str = "calldatasize"; -/// The call flags global variable name. -pub static GLOBAL_CALL_FLAGS: &str = "call_flags"; - /// The deployer call header size that consists of: /// - bytecode hash (32 bytes) pub const DEPLOYER_CALL_HEADER_SIZE: usize = revive_common::BYTE_LENGTH_WORD; diff --git a/crates/llvm-context/src/polkavm/context/function/runtime/entry.rs b/crates/llvm-context/src/polkavm/context/function/runtime/entry.rs index 78d13caf..cb0f332a 100644 --- a/crates/llvm-context/src/polkavm/context/function/runtime/entry.rs +++ b/crates/llvm-context/src/polkavm/context/function/runtime/entry.rs @@ -24,22 +24,6 @@ impl Entry { where D: Dependency + Clone, { - context.set_global( - crate::polkavm::GLOBAL_HEAP_MEMORY_POINTER, - context.llvm().ptr_type(AddressSpace::Heap.into()), - AddressSpace::Stack, - context.xlen_type().get_undef(), - ); - context.build_store( - context - .get_global(crate::polkavm::GLOBAL_HEAP_MEMORY_POINTER)? - .into(), - context.build_sbrk( - context.xlen_type().const_zero(), - context.xlen_type().const_zero(), - )?, - )?; - context.set_global( crate::polkavm::GLOBAL_CALLDATA_SIZE, context.xlen_type(), @@ -47,13 +31,6 @@ impl Entry { context.xlen_type().get_undef(), ); - context.set_global( - crate::polkavm::GLOBAL_CALL_FLAGS, - context.word_type(), - AddressSpace::Stack, - context.word_const(0), - ); - Ok(()) } @@ -70,6 +47,11 @@ impl Entry { .build_runtime_call(revive_runtime_api::polkavm_imports::CALL_DATA_SIZE, &[]) .expect("the call_data_size syscall method should return a value") .into_int_value(); + let call_data_size_value = context.builder().build_int_truncate( + call_data_size_value, + context.xlen_type(), + "call_data_size_truncated", + )?; context .builder() .build_store(call_data_size_pointer, call_data_size_value)?; @@ -90,13 +72,6 @@ impl Entry { .borrow() .get_nth_param(Self::ARGUMENT_INDEX_CALL_FLAGS); - context.set_global( - crate::polkavm::GLOBAL_CALL_FLAGS, - is_deploy.get_type(), - AddressSpace::Stack, - is_deploy.into_int_value(), - ); - let deploy_code_call_block = context.append_basic_block("deploy_code_call_block"); let runtime_code_call_block = context.append_basic_block("runtime_code_call_block"); diff --git a/crates/llvm-context/src/polkavm/context/mod.rs b/crates/llvm-context/src/polkavm/context/mod.rs index 502371eb..94046d01 100644 --- a/crates/llvm-context/src/polkavm/context/mod.rs +++ b/crates/llvm-context/src/polkavm/context/mod.rs @@ -1209,17 +1209,17 @@ where /// Build a call to PolkaVM `msize` for querying the linear memory size. pub fn build_msize(&self) -> anyhow::Result> { - Ok(self - .builder() - .build_call( - self.runtime_api_method(revive_runtime_api::polkavm_imports::MEMORY_SIZE), - &[], - "call_msize", - )? - .try_as_basic_value() - .left() - .expect("sbrk returns an int") - .into_int_value()) + let memory_size_pointer = self + .module() + .get_global(revive_runtime_api::polkavm_imports::MEMORY_SIZE) + .expect("the memory size symbol should have been declared") + .as_pointer_value(); + let memory_size_value = self.builder().build_load( + self.xlen_type(), + memory_size_pointer, + "memory_size_value", + )?; + Ok(memory_size_value.into_int_value()) } /// Call PolkaVM `sbrk` for extending the heap by `offset` + `size`, @@ -1265,8 +1265,9 @@ where self.build_heap_alloc(offset, length)?; let heap_start = self - .get_global(crate::polkavm::GLOBAL_HEAP_MEMORY_POINTER)? - .value + .module() + .get_global(revive_runtime_api::polkavm_imports::MEMORY) + .expect("the memory symbol should have been declared") .as_pointer_value(); Ok(self.build_gep( Pointer::new(self.byte_type(), AddressSpace::Stack, heap_start), diff --git a/crates/runtime-api/src/lib.rs b/crates/runtime-api/src/lib.rs index b0e59876..cde5106c 100644 --- a/crates/runtime-api/src/lib.rs +++ b/crates/runtime-api/src/lib.rs @@ -1,6 +1,6 @@ //! This crate vendors the [PolkaVM][0] C API and provides a LLVM module for interacting //! with the `pallet-revive` runtime API. -//! At present, the contracts pallet requires blobs to export `call` and `deploy`, +//! At present, the revive pallet requires blobs to export `call` and `deploy`, //! and offers a bunch of [runtime API methods][1]. The provided [module] implements //! those exports and imports. //! [0]: [https://crates.io/crates/polkavm] diff --git a/crates/runtime-api/src/polkavm_imports.c b/crates/runtime-api/src/polkavm_imports.c index e101fb80..170ac7f1 100644 --- a/crates/runtime-api/src/polkavm_imports.c +++ b/crates/runtime-api/src/polkavm_imports.c @@ -8,10 +8,10 @@ #define EVM_WORD_SIZE 32 #define ALIGN(size) ((size + EVM_WORD_SIZE - 1) & ~(EVM_WORD_SIZE - 1)) #define MAX_MEMORY_SIZE (64 * 1024) -static char __memory[MAX_MEMORY_SIZE]; -static uint32_t __memory_size = 0; +char __memory[MAX_MEMORY_SIZE]; +uint32_t __memory_size = 0; -void * __sbrk_internal(uint32_t offset, uint32_t size) { +void * __sbrk_internal(uint32_t offset, uint32_t size) { if (offset >= MAX_MEMORY_SIZE || size > MAX_MEMORY_SIZE) { return NULL; } @@ -27,10 +27,6 @@ void * __sbrk_internal(uint32_t offset, uint32_t size) { return (void *)&__memory[__memory_size]; } -uint32_t __msize() { - return __memory_size; -} - void * memset(void *b, int c, size_t len) { uint8_t *dest = b; while (len-- > 0) *dest++ = c; diff --git a/crates/runtime-api/src/polkavm_imports.rs b/crates/runtime-api/src/polkavm_imports.rs index a14a12b9..4050bb8b 100644 --- a/crates/runtime-api/src/polkavm_imports.rs +++ b/crates/runtime-api/src/polkavm_imports.rs @@ -1,18 +1,14 @@ -//! This crate vendors the [PolkaVM][0] C API and provides a LLVM module for interacting -//! with the `pallet-revive` runtime API. -//! At present, the revive pallet requires blobs to export `call` and `deploy`, -//! and offers a bunch of [runtime API methods][1]. The provided [module] implements -//! those exports and imports. -//! [0]: [https://crates.io/crates/polkavm] -//! [1]: [https://docs.rs/pallet-contracts/26.0.0/pallet_contracts/api_doc/index.html] - use inkwell::{context::Context, memory_buffer::MemoryBuffer, module::Module, support::LLVMString}; include!(concat!(env!("OUT_DIR"), "/polkavm_imports.rs")); -pub static SBRK: &str = "__sbrk_internal"; +/// The emulated EVM heap memory global symbol. +pub static MEMORY: &str = "__memory"; -pub static MEMORY_SIZE: &str = "__msize"; +/// The emulated EVM heap memory size global symbol. +pub static MEMORY_SIZE: &str = "__memory_size"; + +pub static SBRK: &str = "__sbrk_internal"; pub static ADDRESS: &str = "address"; @@ -82,9 +78,8 @@ pub static WEIGHT_TO_FEE: &str = "weight_to_fee"; /// All imported runtime API symbols. /// Useful for configuring common attributes and linkage. -pub static IMPORTS: [&str; 35] = [ +pub static IMPORTS: [&str; 34] = [ SBRK, - MEMORY_SIZE, ADDRESS, BALANCE, BALANCE_OF, From f3a7c0c516dc7d0206c292bd8539255ed63e8662 Mon Sep 17 00:00:00 2001 From: xermicus Date: Thu, 13 Feb 2025 12:38:02 +0100 Subject: [PATCH 2/2] remove unrelated change Signed-off-by: xermicus --- crates/runtime-api/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/runtime-api/src/lib.rs b/crates/runtime-api/src/lib.rs index cde5106c..b0e59876 100644 --- a/crates/runtime-api/src/lib.rs +++ b/crates/runtime-api/src/lib.rs @@ -1,6 +1,6 @@ //! This crate vendors the [PolkaVM][0] C API and provides a LLVM module for interacting //! with the `pallet-revive` runtime API. -//! At present, the revive pallet requires blobs to export `call` and `deploy`, +//! At present, the contracts pallet requires blobs to export `call` and `deploy`, //! and offers a bunch of [runtime API methods][1]. The provided [module] implements //! those exports and imports. //! [0]: [https://crates.io/crates/polkavm]