2023-09-28 19:59:53 +08:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2023 Intel Corporation
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <zephyr/llext/elf.h>
|
|
|
|
#include <zephyr/llext/llext.h>
|
2024-09-25 20:00:18 +08:00
|
|
|
#include <zephyr/llext/llext_internal.h>
|
2023-12-02 02:04:49 +08:00
|
|
|
#include <zephyr/llext/loader.h>
|
2023-09-28 19:59:53 +08:00
|
|
|
#include <zephyr/logging/log.h>
|
|
|
|
|
|
|
|
LOG_MODULE_DECLARE(llext);
|
|
|
|
|
|
|
|
#define R_XTENSA_NONE 0
|
|
|
|
#define R_XTENSA_32 1
|
|
|
|
#define R_XTENSA_RTLD 2
|
|
|
|
#define R_XTENSA_GLOB_DAT 3
|
|
|
|
#define R_XTENSA_JMP_SLOT 4
|
|
|
|
#define R_XTENSA_RELATIVE 5
|
|
|
|
#define R_XTENSA_PLT 6
|
2024-09-25 20:00:18 +08:00
|
|
|
#define R_XTENSA_SLOT0_OP 20
|
2023-09-28 19:59:53 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Architecture specific function for relocating shared elf
|
|
|
|
*
|
|
|
|
* Elf files contain a series of relocations described in multiple sections.
|
|
|
|
* These relocation instructions are architecture specific and each architecture
|
|
|
|
* supporting modules must implement this.
|
|
|
|
*/
|
|
|
|
void arch_elf_relocate_local(struct llext_loader *ldr, struct llext *ext,
|
2024-03-27 21:43:31 +08:00
|
|
|
const elf_rela_t *rel, const elf_sym_t *sym, size_t got_offset)
|
2023-09-28 19:59:53 +08:00
|
|
|
{
|
|
|
|
uint8_t *text = ext->mem[LLEXT_MEM_TEXT];
|
|
|
|
int type = ELF32_R_TYPE(rel->r_info);
|
2024-03-27 21:43:31 +08:00
|
|
|
elf_word *got_entry = (elf_word *)(text + got_offset);
|
|
|
|
uintptr_t sh_addr;
|
2023-09-28 19:59:53 +08:00
|
|
|
|
2024-03-27 21:43:31 +08:00
|
|
|
if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) {
|
|
|
|
elf_shdr_t *shdr = llext_peek(ldr, ldr->hdr.e_shoff +
|
|
|
|
sym->st_shndx * ldr->hdr.e_shentsize);
|
2024-04-02 21:02:24 +08:00
|
|
|
sh_addr = shdr->sh_addr ? : (uintptr_t)llext_peek(ldr, shdr->sh_offset);
|
2024-03-27 21:43:31 +08:00
|
|
|
} else {
|
|
|
|
sh_addr = ldr->sects[LLEXT_MEM_TEXT].sh_addr;
|
|
|
|
}
|
2023-09-28 19:59:53 +08:00
|
|
|
|
2024-03-27 21:43:31 +08:00
|
|
|
switch (type) {
|
|
|
|
case R_XTENSA_RELATIVE:
|
2023-09-28 19:59:53 +08:00
|
|
|
/* Relocate a local symbol: Xtensa specific */
|
2024-03-27 21:43:31 +08:00
|
|
|
*got_entry += (uintptr_t)text - sh_addr;
|
|
|
|
break;
|
|
|
|
case R_XTENSA_32:
|
|
|
|
*got_entry += sh_addr;
|
2024-09-25 20:00:18 +08:00
|
|
|
break;
|
|
|
|
case R_XTENSA_SLOT0_OP:
|
|
|
|
;
|
|
|
|
uint8_t *opc = (uint8_t *)got_entry;
|
|
|
|
|
|
|
|
/* Check the opcode: is this an L32R? And does it have to be relocated? */
|
|
|
|
if ((opc[0] & 0xf) != 1 || opc[1] || opc[2])
|
|
|
|
break;
|
|
|
|
|
|
|
|
elf_sym_t rsym;
|
|
|
|
|
|
|
|
int ret = llext_seek(ldr, ldr->sects[LLEXT_MEM_SYMTAB].sh_offset +
|
|
|
|
ELF_R_SYM(rel->r_info) * sizeof(elf_sym_t));
|
|
|
|
if (!ret) {
|
|
|
|
ret = llext_read(ldr, &rsym, sizeof(elf_sym_t));
|
|
|
|
}
|
|
|
|
if (ret)
|
|
|
|
return;
|
|
|
|
|
|
|
|
uintptr_t link_addr = (uintptr_t)llext_loaded_sect_ptr(ldr, ext, rsym.st_shndx) +
|
|
|
|
rsym.st_value;
|
|
|
|
|
|
|
|
ssize_t value = (link_addr - (((uintptr_t)got_entry + 3) & ~3)) >> 2;
|
|
|
|
|
|
|
|
opc[1] = value & 0xff;
|
|
|
|
opc[2] = (value >> 8) & 0xff;
|
|
|
|
|
2024-03-27 21:43:31 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
LOG_DBG("unsupported relocation type %u", type);
|
|
|
|
|
|
|
|
return;
|
2023-09-28 19:59:53 +08:00
|
|
|
}
|
2024-03-27 21:43:31 +08:00
|
|
|
|
|
|
|
LOG_DBG("relocation to %#x type %u at %p", *got_entry, type, (void *)got_entry);
|
2023-09-28 19:59:53 +08:00
|
|
|
}
|