diff --git a/Cargo.lock b/Cargo.lock
index d091e46e9bf983cb85971c82fa2dfed9337bb74c..5bc51b7840ec1e670abb71d68b1402509fd36784 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6997,6 +6997,16 @@ dependencies = [
  "stable_deref_trait",
 ]
 
+[[package]]
+name = "gimli"
+version = "0.31.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
+dependencies = [
+ "fallible-iterator 0.3.0",
+ "stable_deref_trait",
+]
+
 [[package]]
 name = "glob"
 version = "0.3.1"
@@ -12520,7 +12530,6 @@ dependencies = [
  "parity-scale-codec",
  "paste",
  "polkavm 0.13.0",
- "polkavm-common 0.13.0",
  "pretty_assertions",
  "rlp 0.6.1",
  "scale-info",
@@ -12584,7 +12593,7 @@ dependencies = [
  "frame-system",
  "log",
  "parity-wasm",
- "polkavm-linker 0.13.0",
+ "polkavm-linker 0.14.0",
  "sp-core 28.0.0",
  "sp-io 30.0.0",
  "sp-runtime 31.0.1",
@@ -12644,7 +12653,7 @@ dependencies = [
  "bitflags 1.3.2",
  "parity-scale-codec",
  "paste",
- "polkavm-derive 0.13.0",
+ "polkavm-derive 0.14.0",
  "scale-info",
 ]
 
@@ -16405,11 +16414,16 @@ version = "0.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "084b4339aae7dfdaaa5aa7d634110afd95970e0737b6fb2a0cb10db8b56b753c"
 dependencies = [
- "blake3",
  "log",
  "polkavm-assembler 0.13.0",
 ]
 
+[[package]]
+name = "polkavm-common"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "711952a783e9c5ad407cdacb1ed147f36d37c5d43417c1091d86456d2999417b"
+
 [[package]]
 name = "polkavm-derive"
 version = "0.8.0"
@@ -16430,11 +16444,11 @@ dependencies = [
 
 [[package]]
 name = "polkavm-derive"
-version = "0.13.0"
+version = "0.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4456b9657b2abd04ac41a61c99e206b7410f93daf0e9b42b49089508d836c40"
+checksum = "b4832a0aebf6cefc988bb7b2d74ea8c86c983164672e2fc96300f356a1babfc1"
 dependencies = [
- "polkavm-derive-impl-macro 0.13.0",
+ "polkavm-derive-impl-macro 0.14.0",
 ]
 
 [[package]]
@@ -16463,11 +16477,11 @@ dependencies = [
 
 [[package]]
 name = "polkavm-derive-impl"
-version = "0.13.0"
+version = "0.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e4f2c19e7ccc53d8e21429e83b6589bd4139d15481e455a90ba4335a4decb5a"
+checksum = "e339fc7c11310fe5adf711d9342278ac44a75c9784947937cce12bd4f30842f2"
 dependencies = [
- "polkavm-common 0.13.0",
+ "polkavm-common 0.14.0",
  "proc-macro2 1.0.86",
  "quote 1.0.37",
  "syn 2.0.82",
@@ -16495,11 +16509,11 @@ dependencies = [
 
 [[package]]
 name = "polkavm-derive-impl-macro"
-version = "0.13.0"
+version = "0.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6f3ad876ca1855038c21d48cbe35164552208a54b21f8295a7d76bc33ef1e38"
+checksum = "b569754b15060d03000c09e3bf11509d527f60b75d79b4c30c3625b5071d9702"
 dependencies = [
- "polkavm-derive-impl 0.13.0",
+ "polkavm-derive-impl 0.14.0",
  "syn 2.0.82",
 ]
 
@@ -16520,15 +16534,15 @@ dependencies = [
 
 [[package]]
 name = "polkavm-linker"
-version = "0.13.0"
+version = "0.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4aa6e5a396abf195289d6d63d70182e59a7c27b9b06d0b7361317df05c07c8a8"
+checksum = "0959ac3b0f4fd5caf5c245c637705f19493efe83dba31a83bbba928b93b0116a"
 dependencies = [
- "gimli 0.28.0",
+ "gimli 0.31.1",
  "hashbrown 0.14.5",
  "log",
  "object 0.36.1",
- "polkavm-common 0.13.0",
+ "polkavm-common 0.14.0",
  "regalloc2 0.9.3",
  "rustc-demangle",
 ]
@@ -16986,8 +17000,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302"
 dependencies = [
  "bytes",
- "heck 0.4.1",
- "itertools 0.10.5",
+ "heck 0.5.0",
+ "itertools 0.12.1",
  "log",
  "multimap",
  "once_cell",
@@ -17020,7 +17034,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1"
 dependencies = [
  "anyhow",
- "itertools 0.10.5",
+ "itertools 0.12.1",
  "proc-macro2 1.0.86",
  "quote 1.0.37",
  "syn 2.0.82",
@@ -17033,7 +17047,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac"
 dependencies = [
  "anyhow",
- "itertools 0.10.5",
+ "itertools 0.12.1",
  "proc-macro2 1.0.86",
  "quote 1.0.37",
  "syn 2.0.82",
diff --git a/substrate/frame/revive/Cargo.toml b/substrate/frame/revive/Cargo.toml
index 8dbad5ffd8b6bde8bd5ddb17233489c90ec7bb20..c6e733477f3887fd5fe88262e63550c128e68da6 100644
--- a/substrate/frame/revive/Cargo.toml
+++ b/substrate/frame/revive/Cargo.toml
@@ -20,7 +20,6 @@ targets = ["x86_64-unknown-linux-gnu"]
 environmental = { workspace = true }
 paste = { workspace = true }
 polkavm = { version = "0.13.0", default-features = false }
-polkavm-common = { version = "0.13.0", default-features = false }
 bitflags = { workspace = true }
 codec = { features = ["derive", "max-encoded-len"], workspace = true }
 scale-info = { features = ["derive"], workspace = true }
@@ -100,7 +99,6 @@ std = [
 	"pallet-timestamp/std",
 	"pallet-transaction-payment/std",
 	"pallet-utility/std",
-	"polkavm-common/std",
 	"polkavm/std",
 	"rlp/std",
 	"scale-info/std",
diff --git a/substrate/frame/revive/fixtures/Cargo.toml b/substrate/frame/revive/fixtures/Cargo.toml
index 1d89db002b721d42a1ef52f1748b3067cc9fa020..1e6c950addfd367f93479768fbf5e30cb5612f3d 100644
--- a/substrate/frame/revive/fixtures/Cargo.toml
+++ b/substrate/frame/revive/fixtures/Cargo.toml
@@ -21,7 +21,7 @@ log = { workspace = true }
 parity-wasm = { workspace = true }
 tempfile = { workspace = true }
 toml = { workspace = true }
-polkavm-linker = { version = "0.13.0" }
+polkavm-linker = { version = "0.14.0" }
 anyhow = { workspace = true, default-features = true }
 
 [features]
diff --git a/substrate/frame/revive/fixtures/build.rs b/substrate/frame/revive/fixtures/build.rs
index ee7db4203cc95d1c91315a43db26894b398af313..38d63621677dc4fe5a62f14b85d7e99ee3aae017 100644
--- a/substrate/frame/revive/fixtures/build.rs
+++ b/substrate/frame/revive/fixtures/build.rs
@@ -32,6 +32,10 @@ mod build {
 		process::Command,
 	};
 
+	const OVERRIDE_RUSTUP_TOOLCHAIN_ENV_VAR: &str = "PALLET_REVIVE_FIXTURES_RUSTUP_TOOLCHAIN";
+	const OVERRIDE_STRIP_ENV_VAR: &str = "PALLET_REVIVE_FIXTURES_STRIP";
+	const OVERRIDE_OPTIMIZE_ENV_VAR: &str = "PALLET_REVIVE_FIXTURES_OPTIMIZE";
+
 	/// A contract entry.
 	struct Entry {
 		/// The path to the contract source file.
@@ -112,54 +116,50 @@ mod build {
 		fs::write(output_dir.join("Cargo.toml"), cargo_toml).map_err(Into::into)
 	}
 
-	fn invoke_build(current_dir: &Path) -> Result<()> {
-		let encoded_rustflags = [
-			"-Dwarnings",
-			"-Crelocation-model=pie",
-			"-Clink-arg=--emit-relocs",
-			"-Clink-arg=--export-dynamic-symbol=__polkavm_symbol_export_hack__*",
-		]
-		.join("\x1f");
+	fn invoke_build(target: &Path, current_dir: &Path) -> Result<()> {
+		let encoded_rustflags = ["-Dwarnings"].join("\x1f");
 
-		let build_res = Command::new(env::var("CARGO")?)
+		let mut build_command = Command::new(env::var("CARGO")?);
+		build_command
 			.current_dir(current_dir)
 			.env_clear()
 			.env("PATH", env::var("PATH").unwrap_or_default())
 			.env("CARGO_ENCODED_RUSTFLAGS", encoded_rustflags)
-			.env("RUSTUP_TOOLCHAIN", "rve-nightly")
 			.env("RUSTC_BOOTSTRAP", "1")
 			.env("RUSTUP_HOME", env::var("RUSTUP_HOME").unwrap_or_default())
 			.args([
 				"build",
 				"--release",
-				"--target=riscv32ema-unknown-none-elf",
 				"-Zbuild-std=core",
 				"-Zbuild-std-features=panic_immediate_abort",
 			])
-			.output()
-			.expect("failed to execute process");
+			.arg("--target")
+			.arg(target);
+
+		if let Ok(toolchain) = env::var(OVERRIDE_RUSTUP_TOOLCHAIN_ENV_VAR) {
+			build_command.env("RUSTUP_TOOLCHAIN", &toolchain);
+		}
+
+		let build_res = build_command.output().expect("failed to execute process");
 
 		if build_res.status.success() {
 			return Ok(())
 		}
 
 		let stderr = String::from_utf8_lossy(&build_res.stderr);
-
-		if stderr.contains("'rve-nightly' is not installed") {
-			eprintln!("RISC-V toolchain is not installed.\nDownload and install toolchain from https://github.com/paritytech/rustc-rv32e-toolchain.");
-			eprintln!("{}", stderr);
-		} else {
-			eprintln!("{}", stderr);
-		}
+		eprintln!("{}", stderr);
 
 		bail!("Failed to build contracts");
 	}
 
 	/// Post-process the compiled code.
 	fn post_process(input_path: &Path, output_path: &Path) -> Result<()> {
+		let strip = std::env::var(OVERRIDE_STRIP_ENV_VAR).map_or(false, |value| value == "1");
+		let optimize = std::env::var(OVERRIDE_OPTIMIZE_ENV_VAR).map_or(true, |value| value == "1");
+
 		let mut config = polkavm_linker::Config::default();
-		config.set_strip(false);
-		config.set_optimize(true);
+		config.set_strip(strip);
+		config.set_optimize(optimize);
 		let orig =
 			fs::read(input_path).with_context(|| format!("Failed to read {:?}", input_path))?;
 		let linked = polkavm_linker::program_from_elf(config, orig.as_ref())
@@ -171,7 +171,9 @@ mod build {
 	fn write_output(build_dir: &Path, out_dir: &Path, entries: Vec<Entry>) -> Result<()> {
 		for entry in entries {
 			post_process(
-				&build_dir.join("target/riscv32ema-unknown-none-elf/release").join(entry.name()),
+				&build_dir
+					.join("target/riscv32emac-unknown-none-polkavm/release")
+					.join(entry.name()),
 				&out_dir.join(entry.out_filename()),
 			)?;
 		}
@@ -183,6 +185,11 @@ mod build {
 		let fixtures_dir: PathBuf = env::var("CARGO_MANIFEST_DIR")?.into();
 		let contracts_dir = fixtures_dir.join("contracts");
 		let out_dir: PathBuf = env::var("OUT_DIR")?.into();
+		let target = fixtures_dir.join("riscv32emac-unknown-none-polkavm.json");
+
+		println!("cargo::rerun-if-env-changed={OVERRIDE_RUSTUP_TOOLCHAIN_ENV_VAR}");
+		println!("cargo::rerun-if-env-changed={OVERRIDE_STRIP_ENV_VAR}");
+		println!("cargo::rerun-if-env-changed={OVERRIDE_OPTIMIZE_ENV_VAR}");
 
 		// the fixtures have a dependency on the uapi crate
 		println!("cargo::rerun-if-changed={}", fixtures_dir.display());
@@ -200,7 +207,7 @@ mod build {
 		let tmp_dir_path = tmp_dir.path();
 
 		create_cargo_toml(&fixtures_dir, entries.iter(), tmp_dir.path())?;
-		invoke_build(tmp_dir_path)?;
+		invoke_build(&target, tmp_dir_path)?;
 
 		write_output(tmp_dir_path, &out_dir, entries)?;
 
diff --git a/substrate/frame/revive/fixtures/build/Cargo.toml b/substrate/frame/revive/fixtures/build/Cargo.toml
index c4aaf131148e929927e22697be034636d178dc2e..5d0e256e2e73c96f9e6e17fe30022171de544cf4 100644
--- a/substrate/frame/revive/fixtures/build/Cargo.toml
+++ b/substrate/frame/revive/fixtures/build/Cargo.toml
@@ -11,7 +11,7 @@ edition = "2021"
 [dependencies]
 uapi = { package = 'pallet-revive-uapi', path = "", default-features = false }
 common = { package = 'pallet-revive-fixtures-common', path = "" }
-polkavm-derive = { version = "0.13.0" }
+polkavm-derive = { version = "0.14.0" }
 
 [profile.release]
 opt-level = 3
diff --git a/substrate/frame/revive/fixtures/contracts/oom_rw_included.rs b/substrate/frame/revive/fixtures/contracts/oom_rw_included.rs
index 2cdcf7bafed1e533cf6dbec6028f14cfdfa45e17..123ee38a52004155585b9e135f8d4e8b78612b74 100644
--- a/substrate/frame/revive/fixtures/contracts/oom_rw_included.rs
+++ b/substrate/frame/revive/fixtures/contracts/oom_rw_included.rs
@@ -28,11 +28,16 @@ use uapi::{HostFn, HostFnImpl as api, ReturnFlags};
 
 static mut BUFFER: [u8; 513 * 1024] = [42; 513 * 1024];
 
+unsafe fn buffer() -> &'static [u8; 513 * 1024] {
+	let ptr = core::ptr::addr_of!(BUFFER);
+	&*ptr
+}
+
 #[no_mangle]
 #[polkavm_derive::polkavm_export]
 pub unsafe extern "C" fn call_never() {
 	// make sure the buffer is not optimized away
-	api::return_value(ReturnFlags::empty(), &BUFFER);
+	api::return_value(ReturnFlags::empty(), buffer());
 }
 
 #[no_mangle]
diff --git a/substrate/frame/revive/fixtures/contracts/oom_rw_trailing.rs b/substrate/frame/revive/fixtures/contracts/oom_rw_trailing.rs
index ddd4139db3ed6e13e05d9a2fb1ac4bc226012466..e127effca20c6d63a3437a3d6d62e66917aad73d 100644
--- a/substrate/frame/revive/fixtures/contracts/oom_rw_trailing.rs
+++ b/substrate/frame/revive/fixtures/contracts/oom_rw_trailing.rs
@@ -28,11 +28,16 @@ use uapi::{HostFn, HostFnImpl as api, ReturnFlags};
 
 static mut BUFFER: [u8; 2 * 1025 * 1024] = [0; 2 * 1025 * 1024];
 
+unsafe fn buffer() -> &'static [u8; 2 * 1025 * 1024] {
+	let ptr = core::ptr::addr_of!(BUFFER);
+	&*ptr
+}
+
 #[no_mangle]
 #[polkavm_derive::polkavm_export]
 pub unsafe extern "C" fn call_never() {
 	// make sure the buffer is not optimized away
-	api::return_value(ReturnFlags::empty(), &BUFFER);
+	api::return_value(ReturnFlags::empty(), buffer());
 }
 
 #[no_mangle]
diff --git a/substrate/frame/revive/fixtures/riscv32emac-unknown-none-polkavm.json b/substrate/frame/revive/fixtures/riscv32emac-unknown-none-polkavm.json
new file mode 100644
index 0000000000000000000000000000000000000000..bbd54cdefbac547021f606a0871b55edc4dca0cb
--- /dev/null
+++ b/substrate/frame/revive/fixtures/riscv32emac-unknown-none-polkavm.json
@@ -0,0 +1,26 @@
+{
+  "arch": "riscv32",
+  "cpu": "generic-rv32",
+  "crt-objects-fallback": "false",
+  "data-layout": "e-m:e-p:32:32-i64:64-n32-S32",
+  "eh-frame-header": false,
+  "emit-debug-gdb-scripts": false,
+  "features": "+e,+m,+a,+c,+lui-addi-fusion,+fast-unaligned-access,+xtheadcondmov",
+  "linker": "rust-lld",
+  "linker-flavor": "ld.lld",
+  "llvm-abiname": "ilp32e",
+  "llvm-target": "riscv32",
+  "max-atomic-width": 32,
+  "panic-strategy": "abort",
+  "relocation-model": "pie",
+  "target-pointer-width": "32",
+  "singlethread": true,
+  "pre-link-args": {
+    "ld": [
+      "--emit-relocs",
+      "--unique",
+      "--relocatable"
+    ]
+  },
+  "env": "polkavm"
+}
diff --git a/substrate/frame/revive/src/limits.rs b/substrate/frame/revive/src/limits.rs
index 0695590f537904a04582cad5f1b5ef163dc18bc7..64e66382b9ab26366cc594814b53501f45fc006e 100644
--- a/substrate/frame/revive/src/limits.rs
+++ b/substrate/frame/revive/src/limits.rs
@@ -132,7 +132,7 @@ pub mod code {
 		// This scans the whole program but we only do it once on code deployment.
 		// It is safe to do unchecked math in u32 because the size of the program
 		// was already checked above.
-		use polkavm_common::program::ISA32_V1_NoSbrk as ISA;
+		use polkavm::program::ISA32_V1_NoSbrk as ISA;
 		let mut num_instructions: u32 = 0;
 		let mut max_basic_block_size: u32 = 0;
 		let mut basic_block_size: u32 = 0;
diff --git a/substrate/frame/revive/uapi/Cargo.toml b/substrate/frame/revive/uapi/Cargo.toml
index 9eaa1b68ca8e3c1b4299a0f3740082def8d2a330..0c7461a35d691f259339a1076dca65a5b7670f12 100644
--- a/substrate/frame/revive/uapi/Cargo.toml
+++ b/substrate/frame/revive/uapi/Cargo.toml
@@ -21,7 +21,7 @@ codec = { features = [
 ], optional = true, workspace = true }
 
 [target.'cfg(target_arch = "riscv32")'.dependencies]
-polkavm-derive = { version = "0.13.0" }
+polkavm-derive = { version = "0.14.0" }
 
 [package.metadata.docs.rs]
 default-target = ["wasm32-unknown-unknown"]