diff --git a/crates/polkavm-linker/src/program_from_elf.rs b/crates/polkavm-linker/src/program_from_elf.rs index 34f361f7..6efa0861 100644 --- a/crates/polkavm-linker/src/program_from_elf.rs +++ b/crates/polkavm-linker/src/program_from_elf.rs @@ -8487,6 +8487,18 @@ where InstExt::Basic(BasicInst::LoadAddress { dst, target }) } + Inst::RegImm { + kind: RegImmKind::Add64, + dst, + src: _, + imm: _, + } => { + let Some(dst) = cast_reg_non_zero(dst)? else { + return Err(ProgramFromElfError::other("R_RISCV_LO12_I with a zero destination register")); + }; + + InstExt::Basic(BasicInst::LoadAddress { dst, target }) + } Inst::Load { kind, dst, diff --git a/crates/polkavm/src/tests.rs b/crates/polkavm/src/tests.rs index 34f5bb94..94843e2c 100644 --- a/crates/polkavm/src/tests.rs +++ b/crates/polkavm/src/tests.rs @@ -2866,6 +2866,22 @@ fn test_asm_reloc_add_sub(config: Config, optimize: bool, _is_64_bit: bool) { assert_eq!(i.instance.read_u32(address).unwrap(), 0x03030303); } +fn test_asm_reloc_hi_lo(config: Config, optimize: bool, _is_64_bit: bool) { + const BLOB_64: &[u8] = include_bytes!("../../../guest-programs/asm-tests/output/reloc_hi_lo_64.elf"); + + let elf = BLOB_64; + let mut i = TestInstance::new(&config, elf, optimize); + + let address = i.call::<(u32,), u32>("get_string", (0,)).unwrap(); + assert_eq!(i.instance.read_u32(address).unwrap(), 0xA1010101); + + let address = i.call::<(u32,), u32>("get_string", (1,)).unwrap(); + assert_eq!(i.instance.read_u32(address).unwrap(), 0xB2020202); + + let address = i.call::<(u32,), u32>("get_string", (2,)).unwrap(); + assert_eq!(i.instance.read_u32(address).unwrap(), 0xC3030303); +} + fn basic_gas_metering(config: Config, gas_metering_kind: GasMeteringKind) { let _ = env_logger::try_init(); @@ -3664,6 +3680,7 @@ run_test_blob_tests! { test_blob_return_tuple_from_import test_blob_return_tuple_from_export test_asm_reloc_add_sub + test_asm_reloc_hi_lo } macro_rules! assert_impl { diff --git a/guest-programs/asm-tests/build-asm-tests.sh b/guest-programs/asm-tests/build-asm-tests.sh index f4981b7a..de59d21a 100755 --- a/guest-programs/asm-tests/build-asm-tests.sh +++ b/guest-programs/asm-tests/build-asm-tests.sh @@ -11,4 +11,5 @@ function build_asm_tests_64bit() { } build_asm_tests_64bit "reloc_add_sub_64" +build_asm_tests_64bit "reloc_hi_lo_64" diff --git a/guest-programs/asm-tests/output/reloc_hi_lo_64.elf b/guest-programs/asm-tests/output/reloc_hi_lo_64.elf new file mode 100644 index 00000000..879ad390 Binary files /dev/null and b/guest-programs/asm-tests/output/reloc_hi_lo_64.elf differ diff --git a/guest-programs/asm-tests/reloc_hi_lo_64.S b/guest-programs/asm-tests/reloc_hi_lo_64.S new file mode 100644 index 00000000..fd613f8d --- /dev/null +++ b/guest-programs/asm-tests/reloc_hi_lo_64.S @@ -0,0 +1,45 @@ +.global get_string + +get_string: + slli a0, a0, 2 + lui a1, %hi(magic_table) + addi a1, a1, %lo(magic_table) + mv a2, a1 + add a1, a1, a0 + lw a0, 0(a1) + add a0, a0, a2 + ret + +.pushsection .metadata,"",@progbits +_get_string_name: + .asciz "get_string" +_get_string_name_end: + +_metadata: + .byte 1 + .word 0 + .word _get_string_name_end - _get_string_name - 1 + .quad _get_string_name + .byte 1 + .byte 1 +.popsection + +.pushsection .polkavm_exports,"R",@note + .byte 1 + .quad _metadata + .quad get_string +.popsection + +.pushsection .rodata.secrets +magic0: .word 0xA1010101 +magic1: .word 0xB2020202 +magic2: .word 0xC3030303 +.popsection + +.pushsection .rodata.table +magic_table: + .word magic0 - magic_table + .word magic1 - magic_table + .word magic2 - magic_table +.popsection +