Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TO BE REBASED] disable FLIX commands #81145

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
141 changes: 103 additions & 38 deletions arch/xtensa/core/elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,80 +10,145 @@
#include <zephyr/llext/loader.h>
#include <zephyr/logging/log.h>

LOG_MODULE_DECLARE(llext);
LOG_MODULE_DECLARE(llext, CONFIG_LLEXT_LOG_LEVEL);

/*
* ELF relocation tables on Xtensa contain relocations of different types. They
* specify how the relocation should be performed. Which relocations are used
* depends on the type of the ELF object (e.g. shared or partially linked
* object), structure of the object (single or multiple source files), compiler
* flags used (e.g. -fPIC), etc. Also not all relocation table entries should be
* acted upon. Some of them describe relocations that have already been
* resolved by the linker. We have to distinguish them from actionable
* relocations and only need to handle the latter ones.
*/
#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
#define R_XTENSA_ASM_EXPAND 11
#define R_XTENSA_SLOT0_OP 20

/**
* @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,
const elf_rela_t *rel, const elf_sym_t *sym, size_t got_offset)
static void xtensa_elf_relocate(struct llext_loader *ldr, struct llext *ext,
const elf_rela_t *rel, uint8_t *text, uintptr_t addr,
uint8_t *loc, int type, uint32_t stb)
{

Check notice on line 38 in arch/xtensa/core/elf.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

arch/xtensa/core/elf.c:38 -#define R_XTENSA_ASM_EXPAND 11 +#define R_XTENSA_ASM_EXPAND 11 #define R_XTENSA_SLOT0_OP 20 -static void xtensa_elf_relocate(struct llext_loader *ldr, struct llext *ext, - const elf_rela_t *rel, uint8_t *text, uintptr_t addr, - uint8_t *loc, int type, uint32_t stb) +static void xtensa_elf_relocate(struct llext_loader *ldr, struct llext *ext, const elf_rela_t *rel, + uint8_t *text, uintptr_t addr, uint8_t *loc, int type, uint32_t stb)

Check notice on line 38 in arch/xtensa/core/elf.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

arch/xtensa/core/elf.c:38 -#define R_XTENSA_ASM_EXPAND 11 +#define R_XTENSA_ASM_EXPAND 11 #define R_XTENSA_SLOT0_OP 20 -static void xtensa_elf_relocate(struct llext_loader *ldr, struct llext *ext, - const elf_rela_t *rel, uint8_t *text, uintptr_t addr, - uint8_t *loc, int type, uint32_t stb) +static void xtensa_elf_relocate(struct llext_loader *ldr, struct llext *ext, const elf_rela_t *rel, + uint8_t *text, uintptr_t addr, uint8_t *loc, int type, uint32_t stb)
uint8_t *text = ext->mem[LLEXT_MEM_TEXT];
int type = ELF32_R_TYPE(rel->r_info);
elf_word *got_entry = (elf_word *)(text + got_offset);
uintptr_t sh_addr;

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);
sh_addr = shdr->sh_addr ? : (uintptr_t)llext_peek(ldr, shdr->sh_offset);
} else {
sh_addr = ldr->sects[LLEXT_MEM_TEXT].sh_addr;
}
elf_word *got_entry = (elf_word *)loc;

switch (type) {
case R_XTENSA_RELATIVE:
/* Relocate a local symbol: Xtensa specific */
*got_entry += (uintptr_t)text - sh_addr;
/* Relocate a local symbol: Xtensa specific. Seems to only be used with PIC */
*got_entry += (uintptr_t)text - addr;
break;
case R_XTENSA_GLOB_DAT:
case R_XTENSA_JMP_SLOT:
if (stb == STB_GLOBAL) {
*got_entry = addr;
}
break;
case R_XTENSA_32:
*got_entry += sh_addr;
/* Used for both LOCAL and GLOBAL bindings */
*got_entry += addr;
break;
case R_XTENSA_SLOT0_OP:
/* Apparently only actionable with LOCAL bindings */
;
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)
if (ret) {
LOG_ERR("Failed to read a symbol table entry, LLEXT linking might fail.");
return;
}

/*
* So far in all observed use-cases
* llext_loaded_sect_ptr(ldr, ext, rsym.st_shndx) was already
* available as the "addr" argument of this function, supplied
* by arch_elf_relocate_local() from its non-STT_SECTION branch.
*/
uintptr_t link_addr = (uintptr_t)llext_loaded_sect_ptr(ldr, ext, rsym.st_shndx) +
rsym.st_value + rel->r_addend;

ssize_t value = (link_addr - (((uintptr_t)got_entry + 3) & ~3)) >> 2;

opc[1] = value & 0xff;
opc[2] = (value >> 8) & 0xff;
/* Check the opcode */
if ((loc[0] & 0xf) == 1 && !loc[1] && !loc[2]) {
/* L32R: low nibble is 1 */
loc[1] = value & 0xff;
loc[2] = (value >> 8) & 0xff;
} else if ((loc[0] & 0xf) == 5 && !(loc[0] & 0xc0) && !loc[1] && !loc[2]) {
/* CALLn: low nibble is 5 */
loc[0] = (loc[0] & 0x3f) | ((value << 6) & 0xc0);
loc[1] = (value >> 2) & 0xff;
loc[2] = (value >> 10) & 0xff;
} else {
LOG_DBG("%p: unhandled OPC or no relocation %02x%02x%02x inf %#x offs %#x",
(void *)loc, loc[2], loc[1], loc[0],
rel->r_info, rel->r_offset);
break;

Check notice on line 95 in arch/xtensa/core/elf.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

arch/xtensa/core/elf.c:95 - (void *)loc, loc[2], loc[1], loc[0], - rel->r_info, rel->r_offset); + (void *)loc, loc[2], loc[1], loc[0], rel->r_info, rel->r_offset);

Check notice on line 95 in arch/xtensa/core/elf.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

arch/xtensa/core/elf.c:95 - (void *)loc, loc[2], loc[1], loc[0], - rel->r_info, rel->r_offset); + (void *)loc, loc[2], loc[1], loc[0], rel->r_info, rel->r_offset);
}

break;
case R_XTENSA_ASM_EXPAND:
/* Nothing to do */
break;
default:
LOG_DBG("unsupported relocation type %u", type);
LOG_DBG("Unsupported relocation type %u", type);

return;
}

LOG_DBG("relocation to %#x type %u at %p", *got_entry, type, (void *)got_entry);
LOG_DBG("Applied relocation to %#x type %u at %p",
*(uint32_t *)((uintptr_t)got_entry & ~3), type, (void *)got_entry);
}

Check notice on line 110 in arch/xtensa/core/elf.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

arch/xtensa/core/elf.c:110 - LOG_DBG("Applied relocation to %#x type %u at %p", - *(uint32_t *)((uintptr_t)got_entry & ~3), type, (void *)got_entry); + LOG_DBG("Applied relocation to %#x type %u at %p", *(uint32_t *)((uintptr_t)got_entry & ~3), + type, (void *)got_entry);

Check notice on line 110 in arch/xtensa/core/elf.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

arch/xtensa/core/elf.c:110 - LOG_DBG("Applied relocation to %#x type %u at %p", - *(uint32_t *)((uintptr_t)got_entry & ~3), type, (void *)got_entry); + LOG_DBG("Applied relocation to %#x type %u at %p", *(uint32_t *)((uintptr_t)got_entry & ~3), + type, (void *)got_entry);

/**
* @brief Architecture specific function for STB_LOCAL ELF relocations
*/
void arch_elf_relocate_local(struct llext_loader *ldr, struct llext *ext, const elf_rela_t *rel,
const elf_sym_t *sym, size_t got_offset,
const struct llext_load_param *ldr_parm)
{
uint8_t *text = ext->mem[LLEXT_MEM_TEXT];
uint8_t *loc = text + got_offset;
int type = ELF32_R_TYPE(rel->r_info);
uintptr_t sh_addr;

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);
sh_addr = shdr->sh_addr &&
(!ldr_parm->section_detached || !ldr_parm->section_detached(shdr)) ?
shdr->sh_addr : (uintptr_t)llext_peek(ldr, shdr->sh_offset);
} else {

Check notice on line 130 in arch/xtensa/core/elf.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

arch/xtensa/core/elf.c:130 - elf_shdr_t *shdr = llext_peek(ldr, ldr->hdr.e_shoff + - sym->st_shndx * ldr->hdr.e_shentsize); - sh_addr = shdr->sh_addr && - (!ldr_parm->section_detached || !ldr_parm->section_detached(shdr)) ? - shdr->sh_addr : (uintptr_t)llext_peek(ldr, shdr->sh_offset); + elf_shdr_t *shdr = + llext_peek(ldr, ldr->hdr.e_shoff + sym->st_shndx * ldr->hdr.e_shentsize); + sh_addr = shdr->sh_addr && (!ldr_parm->section_detached || + !ldr_parm->section_detached(shdr)) + ? shdr->sh_addr + : (uintptr_t)llext_peek(ldr, shdr->sh_offset);

Check notice on line 130 in arch/xtensa/core/elf.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

arch/xtensa/core/elf.c:130 - elf_shdr_t *shdr = llext_peek(ldr, ldr->hdr.e_shoff + - sym->st_shndx * ldr->hdr.e_shentsize); - sh_addr = shdr->sh_addr && - (!ldr_parm->section_detached || !ldr_parm->section_detached(shdr)) ? - shdr->sh_addr : (uintptr_t)llext_peek(ldr, shdr->sh_offset); + elf_shdr_t *shdr = + llext_peek(ldr, ldr->hdr.e_shoff + sym->st_shndx * ldr->hdr.e_shentsize); + sh_addr = shdr->sh_addr && (!ldr_parm->section_detached || + !ldr_parm->section_detached(shdr)) + ? shdr->sh_addr + : (uintptr_t)llext_peek(ldr, shdr->sh_offset);
sh_addr = ldr->sects[LLEXT_MEM_TEXT].sh_addr;
}

xtensa_elf_relocate(ldr, ext, rel, text, sh_addr, loc, type, ELF_ST_BIND(sym->st_info));
}

/**
* @brief Architecture specific function for STB_GLOBAL ELF relocations
*/
void arch_elf_relocate_global(struct llext_loader *ldr, struct llext *ext, const elf_rela_t *rel,
const elf_sym_t *sym, size_t got_offset, const void *link_addr)
{
uint8_t *text = ext->mem[LLEXT_MEM_TEXT];
elf_word *got_entry = (elf_word *)(text + got_offset);
int type = ELF32_R_TYPE(rel->r_info);

/* For global relocations we expect the initial value for R_XTENSA_RELATIVE to be zero */
if (type == R_XTENSA_RELATIVE && *got_entry) {
LOG_WRN("global: non-zero relative value %#x", *got_entry);
}

xtensa_elf_relocate(ldr, ext, rel, text, (uintptr_t)link_addr, (uint8_t *)got_entry, type,
ELF_ST_BIND(sym->st_info));
}
17 changes: 14 additions & 3 deletions cmake/compiler/gcc/target_xtensa.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
# Flags not supported by llext linker
# (regexps are supported and match whole word)
set(LLEXT_REMOVE_FLAGS
-fno-pic
-fno-pie
-ffunction-sections
-fdata-sections
-g.*
Expand All @@ -14,7 +12,20 @@ set(LLEXT_REMOVE_FLAGS

# Flags to be added to llext code compilation
set(LLEXT_APPEND_FLAGS
-fPIC
-nostdlib
-nodefaultlibs
)

if(CONFIG_LLEXT_BUILD_PIC)
set(LLEXT_REMOVE_FLAGS ${LLEXT_REMOVE_FLAGS}
-fno-pic
-fno-pie
)
set(LLEXT_APPEND_FLAGS ${LLEXT_APPEND_FLAGS}
-fPIC
)
else()
set(LLEXT_APPEND_FLAGS ${LLEXT_APPEND_FLAGS}
-ffreestanding
)
endif()
18 changes: 15 additions & 3 deletions cmake/compiler/xt-clang/target.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ include(${ZEPHYR_BASE}/cmake/compiler/xcc/target.cmake)
# Flags not supported by llext linker
# (regexps are supported and match whole word)
set(LLEXT_REMOVE_FLAGS
-fno-pic
-fno-pie
-ffunction-sections
-fdata-sections
-g.*
Expand All @@ -16,7 +14,21 @@ set(LLEXT_REMOVE_FLAGS

# Flags to be added to llext code compilation
set(LLEXT_APPEND_FLAGS
-fPIC
-nostdlib
-nodefaultlibs
)

if(CONFIG_LLEXT_BUILD_PIC)
set(LLEXT_REMOVE_FLAGS ${LLEXT_REMOVE_FLAGS}
-fno-pic
-fno-pie
)
set(LLEXT_APPEND_FLAGS ${LLEXT_APPEND_FLAGS}
-fPIC
)
else()
set(LLEXT_APPEND_FLAGS ${LLEXT_APPEND_FLAGS}
-ffreestanding
-mno-generate-flix
)
endif()
55 changes: 51 additions & 4 deletions include/zephyr/llext/llext.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,24 @@ struct llext {

/** Array of extensions, whose symbols this extension accesses */
struct llext *dependency[LLEXT_MAX_DEPENDENCIES];

/** @cond ignore */
unsigned int sect_cnt;
elf_shdr_t *sect_hdrs;
bool sect_hdrs_on_heap;
/** @endcond */
};

static inline const elf_shdr_t *llext_section_headers(const struct llext *ext)
{
return ext->sect_hdrs;
}

static inline unsigned int llext_section_count(const struct llext *ext)
{
return ext->sect_cnt;
}

/**
* @brief Advanced llext_load parameters
*
Expand Down Expand Up @@ -336,16 +352,47 @@ int arch_elf_relocate(elf_rela_t *rel, uintptr_t loc,
ssize_t llext_find_section(struct llext_loader *loader, const char *search_name);

/**
* @brief Architecture specific function for updating addresses via relocation table
* @brief Extract ELF section header by name.
*
* Searches for a section by name in the ELF file and retrieves its full header.
*
* @param[in] loader Extension loader data and context
* @param[in] ext Extension to be searched
* @param[in] search_name Section name to search for
* @param[out] shdr Buffer for the section header
* @retval 0 Success
* @retval -ENOTSUP "peek" method not supported
* @retval -ENOENT section not found
*/
int llext_get_section_header(struct llext_loader *loader, struct llext *ext,
const char *search_name, elf_shdr_t *shdr);

/**
* @brief Architecture specific function for local binding relocations
*
* @param[in] loader Extension loader data and context
* @param[in] ext Extension to call function in
* @param[in] rel Relocation data provided by elf
* @param[in] sym Corresponding symbol table entry
* @param[in] got_offset Offset within a relocation table or in the code
* @param[in] ldr_parm Loader parameters
*/
void arch_elf_relocate_local(struct llext_loader *loader, struct llext *ext, const elf_rela_t *rel,
const elf_sym_t *sym, size_t got_offset,
const struct llext_load_param *ldr_parm);

/**
* @brief Architecture specific function for global binding relocations
*
* @param[in] loader Extension loader data and context
* @param[in] ext Extension to call function in
* @param[in] rel Relocation data provided by elf
* @param[in] sym Corresponding symbol table entry
* @param[in] got_offset Offset within a relocation table
* @param[in] got_offset Offset within a relocation table or in the code
* @param[in] link_addr target address for table-based relocations
*/
void arch_elf_relocate_local(struct llext_loader *loader, struct llext *ext,
const elf_rela_t *rel, const elf_sym_t *sym, size_t got_offset);
void arch_elf_relocate_global(struct llext_loader *loader, struct llext *ext, const elf_rela_t *rel,
const elf_sym_t *sym, size_t got_offset, const void *link_addr);

/**
* @}
Expand Down
3 changes: 0 additions & 3 deletions include/zephyr/llext/loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,7 @@ struct llext_loader {
/** @cond ignore */
elf_ehdr_t hdr;
elf_shdr_t sects[LLEXT_MEM_COUNT];
elf_shdr_t *sect_hdrs;
bool sect_hdrs_on_heap;
struct llext_elf_sect_map *sect_map;
uint32_t sect_cnt;
/** @endcond */
};

Expand Down
10 changes: 10 additions & 0 deletions subsys/llext/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ config LLEXT_HEAP_SIZE
help
Heap size in kilobytes available to llext for dynamic allocation

config LLEXT_BUILD_PIC
bool "Use -fPIC when building LLEXT"
depends on XTENSA
default y if LLEXT_TYPE_ELF_SHAREDLIB
help
By default LLEXT compilation is performed with -fno-pic -fno-pie compiler
flags. Some platforms can benefit from using -fPIC instead, in which case
most internal linking is performed by the linker at build time. Select "y"
to make use of that advantage.

config LLEXT_SHELL
bool "llext shell commands"
depends on SHELL
Expand Down
Loading
Loading