Skip to content

Commit 7bbe425

Browse files
laurenmurphyx64kartben
authored andcommitted
llext: basic x86 support
Adds basic x86 support for LLEXT. Signed-off-by: Lauren Murphy <[email protected]>
1 parent 9941902 commit 7bbe425

File tree

7 files changed

+189
-3
lines changed

7 files changed

+189
-3
lines changed

arch/x86/core/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ zephyr_library_sources_ifdef(CONFIG_X86_VERY_EARLY_CONSOLE early_serial.c)
2727

2828
zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE tls.c)
2929

30+
zephyr_library_sources_ifdef(CONFIG_LLEXT elf.c)
31+
3032
if(CONFIG_X86_64)
3133
include(intel64.cmake)
3234
else()

arch/x86/core/elf.c

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
/*
2+
* Copyright (c) 2025 Intel Corporation
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/llext/elf.h>
8+
#include <zephyr/llext/llext.h>
9+
#include <zephyr/llext/llext_internal.h>
10+
#include <zephyr/llext/loader.h>
11+
#include <zephyr/logging/log.h>
12+
13+
LOG_MODULE_REGISTER(elf, CONFIG_LLEXT_LOG_LEVEL);
14+
15+
#ifdef CONFIG_64BIT
16+
#define R_X86_64_64 1
17+
#define R_X86_64_PC32 2
18+
#define R_X86_64_PLT32 4
19+
#define R_X86_64_32 10
20+
#define R_X86_64_32S 11
21+
22+
/**
23+
* @brief Architecture specific function for relocating shared elf
24+
*
25+
* Elf files contain a series of relocations described in multiple sections.
26+
* These relocation instructions are architecture specific and each architecture
27+
* supporting modules must implement this.
28+
*
29+
* The relocation codes are well documented:
30+
*
31+
* https://refspecs.linuxfoundation.org/elf/x86_64-abi-0.95.pdf (intel64)
32+
*/
33+
int arch_elf_relocate(struct llext_loader *ldr, struct llext *ext, elf_rela_t *rel,
34+
const elf_shdr_t *shdr)
35+
{
36+
int ret = 0;
37+
const uintptr_t loc = llext_get_reloc_instruction_location(ldr, ext, shdr->sh_info, rel);
38+
elf_sym_t sym;
39+
uintptr_t sym_base_addr;
40+
const char *sym_name;
41+
42+
ret = llext_read_symbol(ldr, ext, rel, &sym);
43+
44+
if (ret != 0) {
45+
LOG_ERR("Could not read symbol from binary!");
46+
return ret;
47+
}
48+
49+
sym_name = llext_symbol_name(ldr, ext, &sym);
50+
51+
ret = llext_lookup_symbol(ldr, ext, &sym_base_addr, rel, &sym, sym_name, shdr);
52+
53+
if (ret != 0) {
54+
LOG_ERR("Could not find symbol %s!", sym_name);
55+
return ret;
56+
}
57+
58+
sym_base_addr += rel->r_addend;
59+
60+
int reloc_type = ELF32_R_TYPE(rel->r_info);
61+
62+
switch (reloc_type) {
63+
case R_X86_64_PC32:
64+
case R_X86_64_PLT32:
65+
*(uint32_t *)loc = sym_base_addr - loc;
66+
break;
67+
case R_X86_64_64:
68+
case R_X86_64_32:
69+
case R_X86_64_32S:
70+
*(uint32_t *)loc = sym_base_addr;
71+
break;
72+
default:
73+
LOG_ERR("unknown relocation: %u\n", reloc_type);
74+
ret = -ENOEXEC;
75+
break;
76+
}
77+
78+
return ret;
79+
}
80+
#else
81+
#define R_386_32 1
82+
#define R_286_PC32 2
83+
84+
/**
85+
* @brief Architecture specific function for relocating shared elf
86+
*
87+
* Elf files contain a series of relocations described in multiple sections.
88+
* These relocation instructions are architecture specific and each architecture
89+
* supporting modules must implement this.
90+
*
91+
* The relocation codes are well documented:
92+
*
93+
* https://docs.oracle.com/cd/E19683-01/817-3677/chapter6-26/index.html (ia32)
94+
*/
95+
int arch_elf_relocate(struct llext_loader *ldr, struct llext *ext, elf_rela_t *rel,
96+
const elf_shdr_t *shdr)
97+
{
98+
int ret = 0;
99+
const uintptr_t loc = llext_get_reloc_instruction_location(ldr, ext, shdr->sh_info, rel);
100+
elf_sym_t sym;
101+
uintptr_t sym_base_addr;
102+
const char *sym_name;
103+
104+
/* x86 uses elf_rel_t records with no addends */
105+
uintptr_t addend = *(uintptr_t *)loc;
106+
107+
ret = llext_read_symbol(ldr, ext, rel, &sym);
108+
109+
if (ret != 0) {
110+
LOG_ERR("Could not read symbol from binary!");
111+
return ret;
112+
}
113+
114+
sym_name = llext_symbol_name(ldr, ext, &sym);
115+
116+
ret = llext_lookup_symbol(ldr, ext, &sym_base_addr, rel, &sym, sym_name, shdr);
117+
118+
if (ret != 0) {
119+
LOG_ERR("Could not find symbol %s!", sym_name);
120+
return ret;
121+
}
122+
123+
sym_base_addr += addend;
124+
125+
int reloc_type = ELF32_R_TYPE(rel->r_info);
126+
127+
switch (reloc_type) {
128+
case R_386_32:
129+
*(uint32_t *)loc = sym_base_addr;
130+
break;
131+
case R_286_PC32:
132+
*(uint32_t *)loc = sym_base_addr - loc;
133+
break;
134+
default:
135+
LOG_ERR("unknown relocation: %u\n", reloc_type);
136+
ret = -ENOEXEC;
137+
break;
138+
}
139+
140+
return ret;
141+
}
142+
#endif

cmake/compiler/gcc/target_x86.cmake

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,28 @@ else()
1515
endif()
1616
endif()
1717

18+
# Flags not supported by llext linker
19+
# (regexps are supported and match whole word)
20+
set(LLEXT_REMOVE_FLAGS
21+
-fno-pic
22+
-fno-pie
23+
-ffunction-sections
24+
-fdata-sections
25+
-g.*
26+
-Os
27+
)
28+
29+
# Force compiler and linker match
30+
if(CONFIG_X86_64)
31+
set(LLEXT_APPEND_FLAGS
32+
-m64
33+
)
34+
else()
35+
set(LLEXT_APPEND_FLAGS
36+
-m32
37+
)
38+
endif()
39+
1840
# GNU Assembler, by default on non-Linux targets, treats slashes as
1941
# start of comments on i386.
2042
# (https://sourceware.org/binutils/docs-2.33.1/as/i386_002dChars.html#i386_002dChars)

subsys/llext/llext_link.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr
389389
int llext_link(struct llext_loader *ldr, struct llext *ext, const struct llext_load_param *ldr_parm)
390390
{
391391
uintptr_t sect_base = 0;
392-
elf_rela_t rel;
392+
elf_rela_t rel = {0};
393393
elf_word rel_cnt = 0;
394394
const char *name;
395395
int i, ret;

tests/subsys/llext/no_mem_protection.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ CONFIG_ARM_MPU=n
77
CONFIG_ARM_AARCH32_MMU=n
88
CONFIG_RISCV_PMP=n
99
CONFIG_ARC_MPU_ENABLE=n
10+
CONFIG_X86_MMU=n

tests/subsys/llext/src/syscalls_ext.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,25 @@
88
* This code demonstrates syscall support.
99
*/
1010

11+
/* This include directive must appear first in the file.
12+
*
13+
* On x86 platforms with demand paging on, Zephyr generates a
14+
* .pinned_text section containing syscalls. The LLEXT loader
15+
* requires .text-like sections to appear close to .text at the
16+
* start of the object file, before .rodata, so they can be
17+
* grouped into a contiguous text region.
18+
*
19+
* Including syscalls_ext.h first ensures the first instance of
20+
* data to be placed in .pinned_text appears before the first instance
21+
* of data for .rodata. As a result, .pinned_text will appear
22+
* before .rodata.
23+
*/
24+
#include "syscalls_ext.h"
25+
1126
#include <zephyr/llext/symbol.h>
1227
#include <zephyr/sys/printk.h>
1328
#include <zephyr/ztest_assert.h>
1429

15-
#include "syscalls_ext.h"
16-
1730
void test_entry(void)
1831
{
1932
int input = 41;

tests/subsys/llext/testcase.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ tests:
3939
- arm
4040
- riscv
4141
- arc
42+
- x86
4243
filter: not CONFIG_MPU and not CONFIG_MMU
4344
extra_conf_files: ['no_mem_protection.conf']
4445
extra_configs:
@@ -56,6 +57,7 @@ tests:
5657
- arm64
5758
- arm
5859
- riscv
60+
- x86
5961
filter: CONFIG_MMU or CONFIG_RISCV_PMP
6062
integration_platforms:
6163
- qemu_cortex_a53 # ARM Cortex-A53 (ARMv8-A ISA)
@@ -68,6 +70,7 @@ tests:
6870
- xtensa
6971
- riscv
7072
- arc
73+
- x86
7174
integration_platforms:
7275
- qemu_xtensa/dc233c # Xtensa ISA
7376
filter: not CONFIG_MPU and not CONFIG_MMU
@@ -80,6 +83,7 @@ tests:
8083
- xtensa
8184
- riscv
8285
- arc
86+
- x86
8387
platform_exclude:
8488
- qemu_arc/qemu_arc_hs5x # See #80949
8589
- nsim/nsim_hs5x # See #80949
@@ -101,6 +105,7 @@ tests:
101105
- xtensa
102106
- riscv
103107
- arc
108+
- x86
104109
integration_platforms:
105110
- qemu_xtensa/dc233c # Xtensa ISA
106111
filter: not CONFIG_MPU and not CONFIG_MMU
@@ -114,6 +119,7 @@ tests:
114119
- xtensa
115120
- riscv
116121
- arc
122+
- x86
117123
platform_exclude:
118124
- qemu_arc/qemu_arc_hs5x # See #80949
119125
- nsim/nsim_hs5x # See #80949

0 commit comments

Comments
 (0)