From aaa256a91830f09d0807cc318e9779c41f8c7ba0 Mon Sep 17 00:00:00 2001 From: Eric Ackermann Date: Thu, 19 Dec 2024 09:48:34 +0100 Subject: [PATCH] llext: Fix off-by-one in RISC-V truncation check The RISC-V architecture-specific relocations need to check whether each required relocation can fit into the modified instruction's immediate. All immediates in RISC-V are encoded as two's complement. The current truncation check has an off-by-one error for checking the maximum negative distance, as two's complement encoding can represent a negative value that is the maximum positive value plus one, causing LLEXT to refuse loading valid code. This commit adds an additional condition to the check that fixes the aforementioned issue. Signed-off-by: Eric Ackermann --- arch/riscv/core/elf.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/riscv/core/elf.c b/arch/riscv/core/elf.c index 4f981083b946b9..e0630876dd4c63 100644 --- a/arch/riscv/core/elf.c +++ b/arch/riscv/core/elf.c @@ -43,6 +43,13 @@ LOG_MODULE_REGISTER(elf, CONFIG_LLEXT_LOG_LEVEL); static inline int riscv_relocation_fits(long long jump_target, long long max_distance, elf_word reloc_type) { + /* + * two's complement encoding + * e.g., [-128=0b10000000, 127=0b01111111] encodable with 8 bits + */ + if (jump_target < 0) { + max_distance++; + } if (llabs(jump_target) > max_distance) { LOG_ERR("%lld byte relocation is not possible for type %" PRIu64 " (max %lld)!", jump_target, (uint64_t)reloc_type, max_distance);