llext: basic x86 support

Adds basic x86 support for LLEXT.

Signed-off-by: Lauren Murphy <lauren.murphy@intel.com>
This commit is contained in:
Lauren Murphy 2025-05-16 14:15:45 -07:00 committed by Benjamin Cabé
parent 9941902e2c
commit 7bbe425fe4
7 changed files with 189 additions and 3 deletions

View File

@ -27,6 +27,8 @@ zephyr_library_sources_ifdef(CONFIG_X86_VERY_EARLY_CONSOLE early_serial.c)
zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE tls.c)
zephyr_library_sources_ifdef(CONFIG_LLEXT elf.c)
if(CONFIG_X86_64)
include(intel64.cmake)
else()

142
arch/x86/core/elf.c Normal file
View File

@ -0,0 +1,142 @@
/*
* Copyright (c) 2025 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/llext/elf.h>
#include <zephyr/llext/llext.h>
#include <zephyr/llext/llext_internal.h>
#include <zephyr/llext/loader.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(elf, CONFIG_LLEXT_LOG_LEVEL);
#ifdef CONFIG_64BIT
#define R_X86_64_64 1
#define R_X86_64_PC32 2
#define R_X86_64_PLT32 4
#define R_X86_64_32 10
#define R_X86_64_32S 11
/**
* @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.
*
* The relocation codes are well documented:
*
* https://refspecs.linuxfoundation.org/elf/x86_64-abi-0.95.pdf (intel64)
*/
int arch_elf_relocate(struct llext_loader *ldr, struct llext *ext, elf_rela_t *rel,
const elf_shdr_t *shdr)
{
int ret = 0;
const uintptr_t loc = llext_get_reloc_instruction_location(ldr, ext, shdr->sh_info, rel);
elf_sym_t sym;
uintptr_t sym_base_addr;
const char *sym_name;
ret = llext_read_symbol(ldr, ext, rel, &sym);
if (ret != 0) {
LOG_ERR("Could not read symbol from binary!");
return ret;
}
sym_name = llext_symbol_name(ldr, ext, &sym);
ret = llext_lookup_symbol(ldr, ext, &sym_base_addr, rel, &sym, sym_name, shdr);
if (ret != 0) {
LOG_ERR("Could not find symbol %s!", sym_name);
return ret;
}
sym_base_addr += rel->r_addend;
int reloc_type = ELF32_R_TYPE(rel->r_info);
switch (reloc_type) {
case R_X86_64_PC32:
case R_X86_64_PLT32:
*(uint32_t *)loc = sym_base_addr - loc;
break;
case R_X86_64_64:
case R_X86_64_32:
case R_X86_64_32S:
*(uint32_t *)loc = sym_base_addr;
break;
default:
LOG_ERR("unknown relocation: %u\n", reloc_type);
ret = -ENOEXEC;
break;
}
return ret;
}
#else
#define R_386_32 1
#define R_286_PC32 2
/**
* @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.
*
* The relocation codes are well documented:
*
* https://docs.oracle.com/cd/E19683-01/817-3677/chapter6-26/index.html (ia32)
*/
int arch_elf_relocate(struct llext_loader *ldr, struct llext *ext, elf_rela_t *rel,
const elf_shdr_t *shdr)
{
int ret = 0;
const uintptr_t loc = llext_get_reloc_instruction_location(ldr, ext, shdr->sh_info, rel);
elf_sym_t sym;
uintptr_t sym_base_addr;
const char *sym_name;
/* x86 uses elf_rel_t records with no addends */
uintptr_t addend = *(uintptr_t *)loc;
ret = llext_read_symbol(ldr, ext, rel, &sym);
if (ret != 0) {
LOG_ERR("Could not read symbol from binary!");
return ret;
}
sym_name = llext_symbol_name(ldr, ext, &sym);
ret = llext_lookup_symbol(ldr, ext, &sym_base_addr, rel, &sym, sym_name, shdr);
if (ret != 0) {
LOG_ERR("Could not find symbol %s!", sym_name);
return ret;
}
sym_base_addr += addend;
int reloc_type = ELF32_R_TYPE(rel->r_info);
switch (reloc_type) {
case R_386_32:
*(uint32_t *)loc = sym_base_addr;
break;
case R_286_PC32:
*(uint32_t *)loc = sym_base_addr - loc;
break;
default:
LOG_ERR("unknown relocation: %u\n", reloc_type);
ret = -ENOEXEC;
break;
}
return ret;
}
#endif

View File

@ -15,6 +15,28 @@ else()
endif()
endif()
# 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.*
-Os
)
# Force compiler and linker match
if(CONFIG_X86_64)
set(LLEXT_APPEND_FLAGS
-m64
)
else()
set(LLEXT_APPEND_FLAGS
-m32
)
endif()
# GNU Assembler, by default on non-Linux targets, treats slashes as
# start of comments on i386.
# (https://sourceware.org/binutils/docs-2.33.1/as/i386_002dChars.html#i386_002dChars)

View File

@ -389,7 +389,7 @@ static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr
int llext_link(struct llext_loader *ldr, struct llext *ext, const struct llext_load_param *ldr_parm)
{
uintptr_t sect_base = 0;
elf_rela_t rel;
elf_rela_t rel = {0};
elf_word rel_cnt = 0;
const char *name;
int i, ret;

View File

@ -7,3 +7,4 @@ CONFIG_ARM_MPU=n
CONFIG_ARM_AARCH32_MMU=n
CONFIG_RISCV_PMP=n
CONFIG_ARC_MPU_ENABLE=n
CONFIG_X86_MMU=n

View File

@ -8,12 +8,25 @@
* This code demonstrates syscall support.
*/
/* This include directive must appear first in the file.
*
* On x86 platforms with demand paging on, Zephyr generates a
* .pinned_text section containing syscalls. The LLEXT loader
* requires .text-like sections to appear close to .text at the
* start of the object file, before .rodata, so they can be
* grouped into a contiguous text region.
*
* Including syscalls_ext.h first ensures the first instance of
* data to be placed in .pinned_text appears before the first instance
* of data for .rodata. As a result, .pinned_text will appear
* before .rodata.
*/
#include "syscalls_ext.h"
#include <zephyr/llext/symbol.h>
#include <zephyr/sys/printk.h>
#include <zephyr/ztest_assert.h>
#include "syscalls_ext.h"
void test_entry(void)
{
int input = 41;

View File

@ -39,6 +39,7 @@ tests:
- arm
- riscv
- arc
- x86
filter: not CONFIG_MPU and not CONFIG_MMU
extra_conf_files: ['no_mem_protection.conf']
extra_configs:
@ -56,6 +57,7 @@ tests:
- arm64
- arm
- riscv
- x86
filter: CONFIG_MMU or CONFIG_RISCV_PMP
integration_platforms:
- qemu_cortex_a53 # ARM Cortex-A53 (ARMv8-A ISA)
@ -68,6 +70,7 @@ tests:
- xtensa
- riscv
- arc
- x86
integration_platforms:
- qemu_xtensa/dc233c # Xtensa ISA
filter: not CONFIG_MPU and not CONFIG_MMU
@ -80,6 +83,7 @@ tests:
- xtensa
- riscv
- arc
- x86
platform_exclude:
- qemu_arc/qemu_arc_hs5x # See #80949
- nsim/nsim_hs5x # See #80949
@ -101,6 +105,7 @@ tests:
- xtensa
- riscv
- arc
- x86
integration_platforms:
- qemu_xtensa/dc233c # Xtensa ISA
filter: not CONFIG_MPU and not CONFIG_MMU
@ -114,6 +119,7 @@ tests:
- xtensa
- riscv
- arc
- x86
platform_exclude:
- qemu_arc/qemu_arc_hs5x # See #80949
- nsim/nsim_hs5x # See #80949