llext: fix unaligned access for ARC

We hit some unaligned access faults running our internal tests.
Not every 32-bit instruction is 32-bit aligned; some are 16-bit aligned.
Make all reads and writes potentially unaligned to be on the safe side.

Signed-off-by: Ilya Tagunov <Ilya.Tagunov@synopsys.com>
This commit is contained in:
Ilya Tagunov 2024-11-19 13:23:20 +00:00 committed by Henrik Brix Andersen
parent d18f4256ee
commit 36c9777be8

View file

@ -8,6 +8,7 @@
#include <zephyr/llext/llext.h> #include <zephyr/llext/llext.h>
#include <zephyr/llext/loader.h> #include <zephyr/llext/loader.h>
#include <zephyr/logging/log.h> #include <zephyr/logging/log.h>
#include <zephyr/sys/util.h>
LOG_MODULE_REGISTER(elf, CONFIG_LLEXT_LOG_LEVEL); LOG_MODULE_REGISTER(elf, CONFIG_LLEXT_LOG_LEVEL);
@ -17,7 +18,7 @@ LOG_MODULE_REGISTER(elf, CONFIG_LLEXT_LOG_LEVEL);
#define R_ARC_32_ME 27 #define R_ARC_32_ME 27
/* ARCompact insns packed in memory have Middle Endian encoding */ /* ARCompact insns packed in memory have Middle Endian encoding */
#define ME(x) ((x & 0xffff0000) >> 16) | ((x & 0xffff) << 16); #define ME(x) (((x & 0xffff0000) >> 16) | ((x & 0xffff) << 16))
/** /**
* @brief Architecture specific function for relocating shared elf * @brief Architecture specific function for relocating shared elf
@ -34,7 +35,7 @@ int arch_elf_relocate(elf_rela_t *rel, uintptr_t loc, uintptr_t sym_base_addr, c
uintptr_t load_bias) uintptr_t load_bias)
{ {
int ret = 0; int ret = 0;
uint32_t insn = *(uint32_t *)loc; uint32_t insn = UNALIGNED_GET((uint32_t *)loc);
uint32_t value; uint32_t value;
sym_base_addr += rel->r_addend; sym_base_addr += rel->r_addend;
@ -44,7 +45,7 @@ int arch_elf_relocate(elf_rela_t *rel, uintptr_t loc, uintptr_t sym_base_addr, c
switch (reloc_type) { switch (reloc_type) {
case R_ARC_32: case R_ARC_32:
case R_ARC_B26: case R_ARC_B26:
*(uint32_t *)loc = sym_base_addr; UNALIGNED_PUT(sym_base_addr, (uint32_t *)loc);
break; break;
case R_ARC_S25W_PCREL: case R_ARC_S25W_PCREL:
/* ((S + A) - P) >> 2 /* ((S + A) - P) >> 2
@ -64,10 +65,10 @@ int arch_elf_relocate(elf_rela_t *rel, uintptr_t loc, uintptr_t sym_base_addr, c
insn = ME(insn); insn = ME(insn);
*(uint32_t *)loc = insn; UNALIGNED_PUT(insn, (uint32_t *)loc);
break; break;
case R_ARC_32_ME: case R_ARC_32_ME:
*(uint32_t *)loc = ME(sym_base_addr); UNALIGNED_PUT(ME(sym_base_addr), (uint32_t *)loc);
break; break;
default: default:
LOG_ERR("unknown relocation: %u\n", reloc_type); LOG_ERR("unknown relocation: %u\n", reloc_type);