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