llext: arm: Add R_ARM_ARM_THM_CALL reloc support
Add support for the relocation type R_ARM_ARM_THM_CALL which is produced for the ARM Thumb BL and BLX (branch immediate) instructions. These instructions are used for non-static functions like void test1(void) { } void main(void) { test1(); } Without support for this relocation, test1() has to be static. Signed-off-by: Bjarki Arge Andreasen <bjarki@arge-andreasen.me>
This commit is contained in:
parent
5cac834bb6
commit
9b583cc539
|
@ -7,9 +7,48 @@
|
|||
#include <zephyr/llext/elf.h>
|
||||
#include <zephyr/llext/llext.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
LOG_MODULE_REGISTER(elf, CONFIG_LLEXT_LOG_LEVEL);
|
||||
|
||||
#define ARM_BL_BLX_UPPER_S_BIT BIT(10)
|
||||
#define ARM_BL_BLX_ADDEND_OFFSET 0
|
||||
#define ARM_BL_BLX_ADDEND_SIZE 11
|
||||
#define ARM_BL_BLX_ADDEND_MASK 0x7FF
|
||||
#define ARM_BL_BLX_HDR_MASK 0xF800
|
||||
#define ARM_BL_BLX_LOWER_T1T2_BIT BIT(12)
|
||||
|
||||
static int32_t arm_bl_blx_decode_addend(uintptr_t opaddr)
|
||||
{
|
||||
uint16_t upper = *((uint16_t *)opaddr);
|
||||
uint16_t lower = *(((uint16_t *)opaddr) + 1);
|
||||
|
||||
int32_t addend = upper & ARM_BL_BLX_UPPER_S_BIT ? UINT32_MAX : 0;
|
||||
|
||||
addend <<= ARM_BL_BLX_ADDEND_SIZE;
|
||||
addend |= upper & ARM_BL_BLX_ADDEND_MASK;
|
||||
addend <<= ARM_BL_BLX_ADDEND_SIZE;
|
||||
addend |= lower & ARM_BL_BLX_ADDEND_MASK;
|
||||
|
||||
return lower & ARM_BL_BLX_LOWER_T1T2_BIT ? addend << 1 : addend << 2;
|
||||
}
|
||||
|
||||
static void arm_bl_blx_encode_addend(uintptr_t opaddr, int32_t addend)
|
||||
{
|
||||
uint16_t upper = *((uint16_t *)opaddr);
|
||||
uint16_t lower = *(((uint16_t *)opaddr) + 1);
|
||||
|
||||
addend = upper & ARM_BL_BLX_UPPER_S_BIT ? addend >> 1 : addend >> 2;
|
||||
|
||||
upper &= ARM_BL_BLX_HDR_MASK;
|
||||
lower &= ARM_BL_BLX_HDR_MASK;
|
||||
upper |= (addend >> ARM_BL_BLX_ADDEND_SIZE) & ARM_BL_BLX_ADDEND_MASK;
|
||||
lower |= addend & ARM_BL_BLX_ADDEND_MASK;
|
||||
|
||||
*((uint16_t *)opaddr) = upper;
|
||||
*(((uint16_t *)opaddr) + 1) = lower;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Architecture specific function for relocating partially linked (static) elf
|
||||
*
|
||||
|
@ -32,6 +71,16 @@ void arch_elf_relocate(elf_rela_t *rel, uintptr_t opaddr, uintptr_t opval)
|
|||
/* Update the absolute address of a load/store instruction */
|
||||
*((uint32_t *)opaddr) = (uint32_t)opval;
|
||||
break;
|
||||
case R_ARM_THM_CALL:
|
||||
/* Decode the initial addend */
|
||||
int32_t addend = arm_bl_blx_decode_addend(opaddr);
|
||||
|
||||
/* Calculate and add the branch offset (addend) */
|
||||
addend += ((int32_t)opval) - ((int32_t)opaddr);
|
||||
|
||||
/* Encode the addend */
|
||||
arm_bl_blx_encode_addend(opaddr, addend);
|
||||
break;
|
||||
default:
|
||||
LOG_DBG("Unsupported ARM elf relocation type %d at address %lx",
|
||||
reloc_type, opaddr);
|
||||
|
|
|
@ -371,6 +371,7 @@ struct elf64_rela {
|
|||
#define R_ARM_ABS32 2
|
||||
#define R_ARM_REL32 3
|
||||
#define R_ARM_COPY 4
|
||||
#define R_ARM_THM_CALL 10
|
||||
#define R_ARM_CALL 28
|
||||
#define R_ARM_V4BX 40
|
||||
|
||||
|
|
Loading…
Reference in a new issue