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 */
arch_elf_relocate(struct llext_loader * ldr,struct llext * ext,elf_rela_t * rel,const elf_shdr_t * shdr)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 */
arch_elf_relocate(struct llext_loader * ldr,struct llext * ext,elf_rela_t * rel,const elf_shdr_t * shdr)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
143