llext: Full ARM ELF relocation support
Adds support for all relocation type produced by GCC on ARM platform using partial linking (-r flag) or shared link (-fpic and -shared flag). Signed-off-by: Cedric Lescop <cedric.lescop@se.com>
This commit is contained in:
parent
00b46686b1
commit
7b1d9d6166
4 changed files with 366 additions and 58 deletions
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Intel Corporation
|
||||
* Copyright (c) 2024 Schneider Electric
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
@ -11,42 +12,266 @@
|
|||
|
||||
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)
|
||||
#define OPCODE2ARMMEM(x) ((uint32_t)(x))
|
||||
#define OPCODE2THM16MEM(x) ((uint16_t)(x))
|
||||
#define MEM2ARMOPCODE(x) OPCODE2ARMMEM(x)
|
||||
#define MEM2THM16OPCODE(x) OPCODE2THM16MEM(x)
|
||||
#define JUMP_UPPER_BOUNDARY ((int32_t)0xfe000000)
|
||||
#define JUMP_LOWER_BOUNDARY ((int32_t)0x2000000)
|
||||
#define PREL31_UPPER_BOUNDARY ((int32_t)0x40000000)
|
||||
#define PREL31_LOWER_BOUNDARY ((int32_t)-0x40000000)
|
||||
#define THM_JUMP_UPPER_BOUNDARY ((int32_t)0xff000000)
|
||||
#define THM_JUMP_LOWER_BOUNDARY ((int32_t)0x01000000)
|
||||
#define MASK_V4BX_RM_COND 0xf000000f
|
||||
#define MASK_V4BX_NOT_RM_COND 0x01a0f000
|
||||
#define MASK_BRANCH_COND GENMASK(31, 28)
|
||||
#define MASK_BRANCH_101 GENMASK(27, 25)
|
||||
#define MASK_BRANCH_L BIT(24)
|
||||
#define MASK_BRANCH_OFFSET GENMASK(23, 0)
|
||||
#define MASK_MOV_COND GENMASK(31, 28)
|
||||
#define MASK_MOV_00 GENMASK(27, 26)
|
||||
#define MASK_MOV_I BIT(25)
|
||||
#define MASK_MOV_OPCODE GENMASK(24, 21)
|
||||
#define MASK_MOV_S BIT(20)
|
||||
#define MASK_MOV_RN GENMASK(19, 16)
|
||||
#define MASK_MOV_RD GENMASK(15, 12)
|
||||
#define MASK_MOV_OPERAND2 GENMASK(11, 0)
|
||||
#define BIT_THM_BW_S 10
|
||||
#define MASK_THM_BW_11110 GENMASK(15, 11)
|
||||
#define MASK_THM_BW_S BIT(10)
|
||||
#define MASK_THM_BW_IMM10 GENMASK(9, 0)
|
||||
#define BIT_THM_BL_J1 13
|
||||
#define BIT_THM_BL_J2 11
|
||||
#define MASK_THM_BL_10 GENMASK(15, 14)
|
||||
#define MASK_THM_BL_J1 BIT(13)
|
||||
#define MASK_THM_BL_1 BIT(12)
|
||||
#define MASK_THM_BL_J2 BIT(11)
|
||||
#define MASK_THM_BL_IMM11 GENMASK(10, 0)
|
||||
#define MASK_THM_MOV_11110 GENMASK(15, 11)
|
||||
#define MASK_THM_MOV_I BIT(10)
|
||||
#define MASK_THM_MOV_100100 GENMASK(9, 4)
|
||||
#define MASK_THM_MOV_IMM4 GENMASK(3, 0)
|
||||
#define MASK_THM_MOV_0 BIT(15)
|
||||
#define MASK_THM_MOV_IMM3 GENMASK(14, 12)
|
||||
#define MASK_THM_MOV_RD GENMASK(11, 8)
|
||||
#define MASK_THM_MOV_IMM8 GENMASK(7, 0)
|
||||
#define SHIFT_PREL31_SIGN 30
|
||||
#define SHIFT_BRANCH_OFFSET 2
|
||||
#define SHIFT_JUMPS_SIGN 25
|
||||
#define SHIFT_MOV_RD 4
|
||||
#define SHIFT_MOV_RN 4
|
||||
#define SHIFT_MOVS_SIGN 15
|
||||
#define SHIFT_THM_JUMPS_SIGN 24
|
||||
#define SHIFT_THM_BW_IMM10 12
|
||||
#define SHIFT_THM_BL_J2 22
|
||||
#define SHIFT_THM_BL_J1 23
|
||||
#define SHIFT_THM_MOVS_SIGN 15
|
||||
#define SHIFT_THM_MOV_I 1
|
||||
#define SHIFT_THM_MOV_IMM3 4
|
||||
#define SHIFT_THM_MOV_IMM4 12
|
||||
|
||||
static int32_t arm_bl_blx_decode_addend(uintptr_t opaddr)
|
||||
static inline int prel31_decode(elf_word reloc_type, uint32_t loc,
|
||||
uint32_t sym_base_addr, const char *sym_name, int32_t *offset)
|
||||
{
|
||||
uint16_t upper = *((uint16_t *)opaddr);
|
||||
uint16_t lower = *(((uint16_t *)opaddr) + 1);
|
||||
int ret;
|
||||
|
||||
int32_t addend = upper & ARM_BL_BLX_UPPER_S_BIT ? UINT32_MAX : 0;
|
||||
*offset = sign_extend(*(int32_t *)loc, SHIFT_PREL31_SIGN);
|
||||
*offset += sym_base_addr - loc;
|
||||
if (*offset >= PREL31_UPPER_BOUNDARY || *offset < PREL31_LOWER_BOUNDARY) {
|
||||
LOG_ERR("sym '%s': relocation out of range (%#x -> %#x)\n",
|
||||
sym_name, loc, sym_base_addr);
|
||||
ret = -ENOEXEC;
|
||||
} else {
|
||||
ret = 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;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void arm_bl_blx_encode_addend(uintptr_t opaddr, int32_t addend)
|
||||
static inline void prel31_reloc(uint32_t loc, int32_t *offset)
|
||||
{
|
||||
uint16_t upper = *((uint16_t *)opaddr);
|
||||
uint16_t lower = *(((uint16_t *)opaddr) + 1);
|
||||
*(uint32_t *)loc &= BIT(31);
|
||||
*(uint32_t *)loc |= *offset & GENMASK(30, 0);
|
||||
}
|
||||
|
||||
addend = upper & ARM_BL_BLX_UPPER_S_BIT ? addend >> 1 : addend >> 2;
|
||||
static int prel31_handler(elf_word reloc_type, uint32_t loc,
|
||||
uint32_t sym_base_addr, const char *sym_name)
|
||||
{
|
||||
int ret;
|
||||
int32_t offset;
|
||||
|
||||
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;
|
||||
ret = prel31_decode(reloc_type, loc, sym_base_addr, sym_name, &offset);
|
||||
if (!ret) {
|
||||
prel31_reloc(loc, &offset);
|
||||
}
|
||||
|
||||
*((uint16_t *)opaddr) = upper;
|
||||
*(((uint16_t *)opaddr) + 1) = lower;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int jumps_decode(elf_word reloc_type, uint32_t loc,
|
||||
uint32_t sym_base_addr, const char *sym_name, int32_t *offset)
|
||||
{
|
||||
int ret;
|
||||
|
||||
*offset = MEM2ARMOPCODE(*(uint32_t *)loc);
|
||||
*offset = (*offset & MASK_BRANCH_OFFSET) << SHIFT_BRANCH_OFFSET;
|
||||
*offset = sign_extend(*offset, SHIFT_JUMPS_SIGN);
|
||||
*offset += sym_base_addr - loc;
|
||||
if (*offset >= JUMP_LOWER_BOUNDARY || *offset <= JUMP_UPPER_BOUNDARY) {
|
||||
LOG_ERR("sym '%s': relocation out of range (%#x -> %#x)\n",
|
||||
sym_name, loc, sym_base_addr);
|
||||
ret = -ENOEXEC;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void jumps_reloc(uint32_t loc, int32_t *offset)
|
||||
{
|
||||
*offset >>= SHIFT_BRANCH_OFFSET;
|
||||
*offset &= MASK_BRANCH_OFFSET;
|
||||
|
||||
*(uint32_t *)loc &= OPCODE2ARMMEM(MASK_BRANCH_COND|MASK_BRANCH_101|MASK_BRANCH_L);
|
||||
*(uint32_t *)loc |= OPCODE2ARMMEM(*offset);
|
||||
}
|
||||
|
||||
static int jumps_handler(elf_word reloc_type, uint32_t loc,
|
||||
uint32_t sym_base_addr, const char *sym_name)
|
||||
{
|
||||
int ret;
|
||||
int32_t offset;
|
||||
|
||||
ret = jumps_decode(reloc_type, loc, sym_base_addr, sym_name, &offset);
|
||||
if (!ret) {
|
||||
jumps_reloc(loc, &offset);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void movs_handler(elf_word reloc_type, uint32_t loc,
|
||||
uint32_t sym_base_addr, const char *sym_name)
|
||||
{
|
||||
int32_t offset;
|
||||
uint32_t tmp;
|
||||
|
||||
offset = tmp = MEM2ARMOPCODE(*(uint32_t *)loc);
|
||||
offset = ((offset & MASK_MOV_RN) >> SHIFT_MOV_RN) | (offset & MASK_MOV_OPERAND2);
|
||||
offset = sign_extend(offset, SHIFT_MOVS_SIGN);
|
||||
|
||||
offset += sym_base_addr;
|
||||
if (reloc_type == R_ARM_MOVT_PREL || reloc_type == R_ARM_MOVW_PREL_NC) {
|
||||
offset -= loc;
|
||||
}
|
||||
if (reloc_type == R_ARM_MOVT_ABS || reloc_type == R_ARM_MOVT_PREL) {
|
||||
offset >>= 16;
|
||||
}
|
||||
|
||||
tmp &= (MASK_MOV_COND | MASK_MOV_00 | MASK_MOV_I | MASK_MOV_OPCODE | MASK_MOV_RD);
|
||||
tmp |= ((offset & MASK_MOV_RD) << SHIFT_MOV_RD) | (offset & MASK_MOV_OPERAND2);
|
||||
|
||||
*(uint32_t *)loc = OPCODE2ARMMEM(tmp);
|
||||
}
|
||||
|
||||
static inline int thm_jumps_decode(elf_word reloc_type, uint32_t loc,
|
||||
uint32_t sym_base_addr, const char *sym_name, int32_t *offset,
|
||||
uint32_t *upper, uint32_t *lower)
|
||||
{
|
||||
int ret;
|
||||
uint32_t j_one, j_two, sign;
|
||||
|
||||
*upper = MEM2THM16OPCODE(*(uint16_t *)loc);
|
||||
*lower = MEM2THM16OPCODE(*(uint16_t *)(loc + 2));
|
||||
|
||||
/* sign is bit10 */
|
||||
sign = (*upper >> BIT_THM_BW_S) & 1;
|
||||
j_one = (*lower >> BIT_THM_BL_J1) & 1;
|
||||
j_two = (*lower >> BIT_THM_BL_J2) & 1;
|
||||
*offset = (sign << SHIFT_THM_JUMPS_SIGN) |
|
||||
((~(j_one ^ sign) & 1) << SHIFT_THM_BL_J1) |
|
||||
((~(j_two ^ sign) & 1) << SHIFT_THM_BL_J2) |
|
||||
((*upper & MASK_THM_BW_IMM10) << SHIFT_THM_BW_IMM10) |
|
||||
((*lower & MASK_THM_BL_IMM11) << 1);
|
||||
*offset = sign_extend(*offset, SHIFT_THM_JUMPS_SIGN);
|
||||
*offset += sym_base_addr - loc;
|
||||
|
||||
if (*offset >= THM_JUMP_LOWER_BOUNDARY || *offset <= THM_JUMP_UPPER_BOUNDARY) {
|
||||
LOG_ERR("sym '%s': relocation out of range (%#x -> %#x)\n",
|
||||
sym_name, loc, sym_base_addr);
|
||||
ret = -ENOEXEC;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void thm_jumps_reloc(uint32_t loc, int32_t *offset,
|
||||
uint32_t *upper, uint32_t *lower)
|
||||
{
|
||||
uint32_t j_one, j_two, sign;
|
||||
|
||||
sign = (*offset >> SHIFT_THM_JUMPS_SIGN) & 1;
|
||||
j_one = sign ^ (~(*offset >> SHIFT_THM_BL_J1) & 1);
|
||||
j_two = sign ^ (~(*offset >> SHIFT_THM_BL_J2) & 1);
|
||||
*upper = (uint16_t)((*upper & MASK_THM_BW_11110) | (sign << BIT_THM_BW_S) |
|
||||
((*offset >> SHIFT_THM_BW_IMM10) & MASK_THM_BW_IMM10));
|
||||
*lower = (uint16_t)((*lower & (MASK_THM_BL_10|MASK_THM_BL_1)) |
|
||||
(j_one << BIT_THM_BL_J1) | (j_two << BIT_THM_BL_J2) |
|
||||
((*offset >> 1) & MASK_THM_BL_IMM11));
|
||||
|
||||
*(uint16_t *)loc = OPCODE2THM16MEM(*upper);
|
||||
*(uint16_t *)(loc + 2) = OPCODE2THM16MEM(*lower);
|
||||
}
|
||||
|
||||
static int thm_jumps_handler(elf_word reloc_type, uint32_t loc,
|
||||
uint32_t sym_base_addr, const char *sym_name)
|
||||
{
|
||||
int ret;
|
||||
int32_t offset;
|
||||
uint32_t upper, lower;
|
||||
|
||||
ret = thm_jumps_decode(reloc_type, loc, sym_base_addr, sym_name, &offset, &upper, &lower);
|
||||
if (!ret) {
|
||||
thm_jumps_reloc(loc, &offset, &upper, &lower);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void thm_movs_handler(elf_word reloc_type, uint32_t loc,
|
||||
uint32_t sym_base_addr, const char *sym_name)
|
||||
{
|
||||
int32_t offset;
|
||||
uint32_t upper, lower;
|
||||
|
||||
upper = MEM2THM16OPCODE(*(uint16_t *)loc);
|
||||
lower = MEM2THM16OPCODE(*(uint16_t *)(loc + 2));
|
||||
|
||||
/* MOVT/MOVW instructions encoding in Thumb-2 */
|
||||
offset = ((upper & MASK_THM_MOV_IMM4) << SHIFT_THM_MOV_IMM4) |
|
||||
((upper & MASK_THM_MOV_I) << SHIFT_THM_MOV_I) |
|
||||
((lower & MASK_THM_MOV_IMM3) >> SHIFT_THM_MOV_IMM3) | (lower & MASK_THM_MOV_IMM8);
|
||||
offset = sign_extend(offset, SHIFT_THM_MOVS_SIGN);
|
||||
offset += sym_base_addr;
|
||||
|
||||
if (reloc_type == R_ARM_THM_MOVT_PREL || reloc_type == R_ARM_THM_MOVW_PREL_NC) {
|
||||
offset -= loc;
|
||||
}
|
||||
if (reloc_type == R_ARM_THM_MOVT_ABS || reloc_type == R_ARM_THM_MOVT_PREL) {
|
||||
offset >>= 16;
|
||||
}
|
||||
|
||||
upper = (uint16_t)((upper & (MASK_THM_MOV_11110|MASK_THM_MOV_100100)) |
|
||||
((offset & (MASK_THM_MOV_IMM4<<SHIFT_THM_MOV_IMM4)) >> SHIFT_THM_MOV_IMM4) |
|
||||
((offset & (MASK_THM_MOV_I<<SHIFT_THM_MOV_I)) >> SHIFT_THM_MOV_I));
|
||||
lower = (uint16_t)((lower & (MASK_THM_MOV_0|MASK_THM_MOV_RD)) |
|
||||
((offset & (MASK_THM_MOV_IMM3>>SHIFT_THM_MOV_IMM3)) << SHIFT_THM_MOV_IMM3) |
|
||||
(offset & MASK_THM_MOV_IMM8));
|
||||
*(uint16_t *)loc = OPCODE2THM16MEM(upper);
|
||||
*(uint16_t *)(loc + 2) = OPCODE2THM16MEM(lower);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,32 +283,81 @@ static void arm_bl_blx_encode_addend(uintptr_t opaddr, int32_t addend)
|
|||
*
|
||||
* The relocation codes for arm are well documented
|
||||
* https://github.com/ARM-software/abi-aa/blob/main/aaelf32/aaelf32.rst#relocation
|
||||
*
|
||||
* Handler functions prefixed by '_thm_' means that they are Thumb instructions specific.
|
||||
* Do NOT mix them with not 'Thumb instructions' in the below switch/case: they are not
|
||||
* intended to work together.
|
||||
*/
|
||||
void arch_elf_relocate(elf_rela_t *rel, uintptr_t opaddr, uintptr_t opval)
|
||||
int arch_elf_relocate(elf_rela_t *rel, uintptr_t loc, uintptr_t sym_base_addr,
|
||||
const char *sym_name, uintptr_t load_bias)
|
||||
{
|
||||
int ret = 0;
|
||||
elf_word reloc_type = ELF32_R_TYPE(rel->r_info);
|
||||
|
||||
LOG_DBG("%d %lx %lx %s", reloc_type, loc, sym_base_addr, sym_name);
|
||||
|
||||
switch (reloc_type) {
|
||||
case R_ARM_NONE:
|
||||
break;
|
||||
|
||||
case R_ARM_ABS32:
|
||||
/* Add the addend stored at opaddr to opval */
|
||||
opval += *((uint32_t *)opaddr);
|
||||
|
||||
/* Update the absolute address of a load/store instruction */
|
||||
*((uint32_t *)opaddr) = (uint32_t)opval;
|
||||
case R_ARM_TARGET1:
|
||||
*(uint32_t *)loc += sym_base_addr;
|
||||
break;
|
||||
|
||||
case R_ARM_PC24:
|
||||
case R_ARM_CALL:
|
||||
case R_ARM_JUMP24:
|
||||
ret = jumps_handler(reloc_type, loc, sym_base_addr, sym_name);
|
||||
break;
|
||||
|
||||
case R_ARM_V4BX:
|
||||
/* keep Rm and condition bits */
|
||||
*(uint32_t *)loc &= OPCODE2ARMMEM(MASK_V4BX_RM_COND);
|
||||
/* remove the rest */
|
||||
*(uint32_t *)loc |= OPCODE2ARMMEM(MASK_V4BX_NOT_RM_COND);
|
||||
break;
|
||||
|
||||
case R_ARM_PREL31:
|
||||
ret = prel31_handler(reloc_type, loc, sym_base_addr, sym_name);
|
||||
break;
|
||||
|
||||
case R_ARM_REL32:
|
||||
*(uint32_t *)loc += sym_base_addr - loc;
|
||||
break;
|
||||
|
||||
case R_ARM_MOVW_ABS_NC:
|
||||
case R_ARM_MOVT_ABS:
|
||||
case R_ARM_MOVW_PREL_NC:
|
||||
case R_ARM_MOVT_PREL:
|
||||
movs_handler(reloc_type, loc, sym_base_addr, sym_name);
|
||||
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);
|
||||
case R_ARM_THM_JUMP24:
|
||||
ret = thm_jumps_handler(reloc_type, loc, sym_base_addr, sym_name);
|
||||
break;
|
||||
|
||||
case R_ARM_THM_MOVW_ABS_NC:
|
||||
case R_ARM_THM_MOVT_ABS:
|
||||
case R_ARM_THM_MOVW_PREL_NC:
|
||||
case R_ARM_THM_MOVT_PREL:
|
||||
thm_movs_handler(reloc_type, loc, sym_base_addr, sym_name);
|
||||
break;
|
||||
|
||||
case R_ARM_RELATIVE:
|
||||
*(uint32_t *)loc += load_bias;
|
||||
break;
|
||||
|
||||
case R_ARM_GLOB_DAT:
|
||||
case R_ARM_JUMP_SLOT:
|
||||
*(uint32_t *)loc = sym_base_addr;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_DBG("Unsupported ARM elf relocation type %d at address %lx",
|
||||
reloc_type, opaddr);
|
||||
break;
|
||||
LOG_ERR("unknown relocation: %u\n", reloc_type);
|
||||
ret = -ENOEXEC;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Intel Corporation
|
||||
* Copyright (c) 2024 Schneider Electric
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
|
@ -370,10 +371,29 @@ struct elf64_rela {
|
|||
#define R_ARM_PC24 1
|
||||
#define R_ARM_ABS32 2
|
||||
#define R_ARM_REL32 3
|
||||
#define R_ARM_COPY 4
|
||||
#define R_ARM_THM_CALL 10
|
||||
#define R_ARM_COPY 20
|
||||
#define R_ARM_GLOB_DAT 21
|
||||
#define R_ARM_JUMP_SLOT 22
|
||||
#define R_ARM_RELATIVE 23
|
||||
#define R_ARM_CALL 28
|
||||
#define R_ARM_JUMP24 29
|
||||
#define R_ARM_TARGET1 38
|
||||
#define R_ARM_V4BX 40
|
||||
#define R_ARM_PREL31 42
|
||||
#define R_ARM_MOVW_ABS_NC 43
|
||||
#define R_ARM_MOVT_ABS 44
|
||||
#define R_ARM_MOVW_PREL_NC 45
|
||||
#define R_ARM_MOVT_PREL 46
|
||||
#define R_ARM_ALU_PC_G0_NC 57
|
||||
#define R_ARM_ALU_PC_G1_NC 59
|
||||
#define R_ARM_LDR_PC_G2 63
|
||||
|
||||
#define R_ARM_THM_CALL 10
|
||||
#define R_ARM_THM_JUMP24 30
|
||||
#define R_ARM_THM_MOVW_ABS_NC 47
|
||||
#define R_ARM_THM_MOVT_ABS 48
|
||||
#define R_ARM_THM_MOVW_PREL_NC 49
|
||||
#define R_ARM_THM_MOVT_PREL 50
|
||||
|
||||
#define R_XTENSA_NONE 0
|
||||
#define R_XTENSA_32 1
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Intel Corporation
|
||||
* Copyright (c) 2024 Schneider Electric
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
@ -202,11 +203,15 @@ int llext_add_domain(struct llext *ext, struct k_mem_domain *domain);
|
|||
* or object.
|
||||
*
|
||||
* @param[in] rel Relocation data provided by elf
|
||||
* @param[in] opaddr Address of operation to rewrite with relocation
|
||||
* @param[in] opval Value of looked up symbol to relocate
|
||||
* @param[in] loc Address of operation to rewrite with relocation
|
||||
* @param[in] sym_base_addr Symbol address
|
||||
* @param[in] sym_name Symbol name
|
||||
* @param[in] load_bias .text load address
|
||||
* @retval 0 success
|
||||
* @retval -ENOEXEC invalid relocation
|
||||
*/
|
||||
void arch_elf_relocate(elf_rela_t *rel, uintptr_t opaddr, uintptr_t opval);
|
||||
|
||||
int arch_elf_relocate(elf_rela_t *rel, uintptr_t loc,
|
||||
uintptr_t sym_base_addr, const char *sym_name, uintptr_t load_bias);
|
||||
/**
|
||||
* @brief Find an ELF section
|
||||
*
|
||||
|
|
|
@ -714,8 +714,10 @@ static void llext_link_plt(struct llext_loader *ldr, struct llext *ext,
|
|||
}
|
||||
}
|
||||
|
||||
__weak void arch_elf_relocate(elf_rela_t *rel, uintptr_t opaddr, uintptr_t opval)
|
||||
__weak int arch_elf_relocate(elf_rela_t *rel, uintptr_t loc,
|
||||
uintptr_t sym_base_addr, const char *sym_name, uintptr_t load_bias)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int llext_link(struct llext_loader *ldr, struct llext *ext, bool do_local)
|
||||
|
@ -773,6 +775,9 @@ static int llext_link(struct llext_loader *ldr, struct llext *ext, bool do_local
|
|||
if (tgt)
|
||||
llext_link_plt(ldr, ext, &shdr, do_local, tgt);
|
||||
continue;
|
||||
} else if (strcmp(name, ".rel.dyn") == 0) {
|
||||
/* we assume that first load segment starts at MEM_TEXT */
|
||||
loc = (uintptr_t)ext->mem[LLEXT_MEM_TEXT];
|
||||
}
|
||||
|
||||
LOG_DBG("relocation section %s (%d) linked to section %d has %zd relocations",
|
||||
|
@ -815,8 +820,11 @@ static int llext_link(struct llext_loader *ldr, struct llext *ext, bool do_local
|
|||
|
||||
op_loc = loc + rel.r_offset;
|
||||
|
||||
/* If symbol is undefined, then we need to look it up */
|
||||
if (sym.st_shndx == SHN_UNDEF) {
|
||||
if (ELF_R_SYM(rel.r_info) == 0) {
|
||||
/* no symbol ex: R_ARM_V4BX relocation, R_ARM_RELATIVE */
|
||||
link_addr = 0;
|
||||
} else if (sym.st_shndx == SHN_UNDEF) {
|
||||
/* If symbol is undefined, then we need to look it up */
|
||||
link_addr = (uintptr_t)llext_find_sym(NULL, name);
|
||||
|
||||
if (link_addr == 0) {
|
||||
|
@ -824,6 +832,8 @@ static int llext_link(struct llext_loader *ldr, struct llext *ext, bool do_local
|
|||
"symbol table %s, offset %zd, link section %d",
|
||||
name, (size_t)rel.r_offset, shdr.sh_link);
|
||||
return -ENODATA;
|
||||
} else {
|
||||
LOG_INF("found symbol %s at 0x%lx", name, link_addr);
|
||||
}
|
||||
} else if (ELF_ST_TYPE(sym.st_info) == STT_SECTION ||
|
||||
ELF_ST_TYPE(sym.st_info) == STT_FUNC ||
|
||||
|
@ -839,18 +849,17 @@ static int llext_link(struct llext_loader *ldr, struct llext *ext, bool do_local
|
|||
continue;
|
||||
}
|
||||
|
||||
LOG_INF("relocating (linking) symbol %s type %d binding %d ndx %d offset "
|
||||
"%zd link section %d",
|
||||
name, ELF_ST_TYPE(sym.st_info), ELF_ST_BIND(sym.st_info),
|
||||
sym.st_shndx, (size_t)rel.r_offset, shdr.sh_link);
|
||||
|
||||
LOG_INF("writing relocation symbol %s type %zd sym %zd at addr 0x%lx "
|
||||
"addr 0x%lx",
|
||||
name, (size_t)ELF_R_TYPE(rel.r_info), (size_t)ELF_R_SYM(rel.r_info),
|
||||
op_loc, link_addr);
|
||||
|
||||
/* relocation */
|
||||
arch_elf_relocate(&rel, op_loc, link_addr);
|
||||
ret = arch_elf_relocate(&rel, op_loc, link_addr, name,
|
||||
(uintptr_t)ext->mem[LLEXT_MEM_TEXT]);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue