xref: /haiku/src/system/kernel/arch/sparc/arch_elf.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
1 /*
2  * Copyright 2019-2020, Adrien Destugues <pulkomandy@pulkomandy.tk>
3  * Copyright 2010, Ithamar R. Adema <ithamar.adema@team-embedded.nl>
4  * Copyright 2009, Johannes Wischert, johanneswi@gmail.com.
5  * Copyright 2005, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
6  * Copyright 2002, Travis Geiselbrecht. All rights reserved.
7  * Distributed under the terms of the MIT License.
8  */
9 
10 
11 #include <KernelExport.h>
12 
13 #include <elf_priv.h>
14 #include <boot/elf.h>
15 #include <arch/elf.h>
16 
17 
18 //#define TRACE_ARCH_ELF
19 #ifdef TRACE_ARCH_ELF
20 #	define TRACE(x) dprintf x
21 #	define CHATTY 1
22 #else
23 #	define TRACE(x) ;
24 #	define CHATTY 0
25 #endif
26 
27 
28 #ifndef _BOOT_MODE
29 static bool
30 is_in_image(struct elf_image_info *image, addr_t address)
31 {
32 	return (address >= image->text_region.start
33 			&& address < image->text_region.start + image->text_region.size)
34 		|| (address >= image->data_region.start
35 			&& address < image->data_region.start + image->data_region.size);
36 }
37 #endif	// !_BOOT_MODE
38 
39 
40 #ifdef _BOOT_MODE
41 status_t
42 boot_arch_elf_relocate_rel(struct preloaded_elf64_image *image, Elf64_Rel *rel,
43 	int rel_len)
44 #else
45 int
46 arch_elf_relocate_rel(struct elf_image_info *image,
47 	struct elf_image_info *resolve_image, Elf64_Rel *rel, int rel_len)
48 #endif
49 {
50 	// there are no rel entries in M68K elf
51 	return B_NO_ERROR;
52 }
53 
54 
55 static inline void
56 write_word32(addr_t P, Elf64_Word value)
57 {
58 	*(Elf64_Word*)P = value;
59 }
60 
61 
62 static inline void
63 write_word64(addr_t P, Elf64_Xword value)
64 {
65 	*(Elf64_Xword*)P = value;
66 }
67 
68 
69 static inline void
70 write_hi30(addr_t P, Elf64_Word value)
71 {
72 	*(Elf64_Word*)P |= value >> 2;
73 }
74 
75 
76 static inline void
77 write_hi22(addr_t P, Elf64_Word value)
78 {
79 	*(Elf64_Word*)P |= value >> 10;
80 }
81 
82 
83 static inline void
84 write_lo10(addr_t P, Elf64_Word value)
85 {
86 	*(Elf64_Word*)P |= value & 0x3ff;
87 }
88 
89 
90 static inline void
91 write_hh22(addr_t P, Elf64_Xword value)
92 {
93 	*(Elf64_Word*)P |= value >> 42;
94 }
95 
96 
97 static inline void
98 write_hm10(addr_t P, Elf64_Xword value)
99 {
100 	*(Elf64_Word*)P |= (value >> 32) & 0x3ff;
101 }
102 
103 
104 #ifdef _BOOT_MODE
105 status_t
106 boot_arch_elf_relocate_rela(struct preloaded_elf64_image *image,
107 	Elf64_Rela *rel, int rel_len)
108 #else
109 int
110 arch_elf_relocate_rela(struct elf_image_info *image,
111 	struct elf_image_info *resolve_image, Elf64_Rela *rel, int rel_len)
112 #endif
113 {
114 	int i;
115 	Elf64_Sym *sym;
116 	int vlErr;
117 
118 	Elf64_Addr S = 0;	// symbol address
119 	//addr_t R = 0;		// section relative symbol address
120 
121 	//addr_t G = 0;		// GOT address
122 	//addr_t L = 0;		// PLT address
123 
124 	#define P	((addr_t)(image->text_region.delta + rel[i].r_offset))
125 	#define A	((addr_t)rel[i].r_addend)
126 	#define B	(image->text_region.delta)
127 
128 	// TODO: Get the GOT address!
129 	#define REQUIRE_GOT	\
130 		if (G == 0) {	\
131 			dprintf("arch_elf_relocate_rela(): Failed to get GOT address!\n"); \
132 			return B_ERROR;	\
133 		}
134 
135 	// TODO: Get the PLT address!
136 	#define REQUIRE_PLT	\
137 		if (L == 0) {	\
138 			dprintf("arch_elf_relocate_rela(): Failed to get PLT address!\n"); \
139 			return B_ERROR;	\
140 		}
141 
142 	for (i = 0; i * (int)sizeof(Elf64_Rela) < rel_len; i++) {
143 #if CHATTY
144 		dprintf("looking at rel type %" PRIu64 ", offset 0x%lx, sym 0x%lx, "
145 			"addend 0x%lx\n", ELF64_R_TYPE(rel[i].r_info), rel[i].r_offset,
146 			ELF64_R_SYM(rel[i].r_info), rel[i].r_addend);
147 #endif
148 		// Relocation types and what to do with them are defined in Oracle docs
149 		// Documentation Home > Linker and Libraries Guide
150 		// 	> Chapter 7 Object File Format > File Format > Relocation Sections
151 		// 	> Relocation Types (Processor-Specific) > SPARC: Relocation Types
152 		// https://docs.oracle.com/cd/E19120-01/open.solaris/819-0690/chapter6-24/index.html
153 		// https://docs.oracle.com/cd/E19120-01/open.solaris/819-0690/chapter6-24-1/index.html
154 		switch (ELF64_R_TYPE(rel[i].r_info)) {
155 			case R_SPARC_WDISP30:
156 			case R_SPARC_HI22:
157 			case R_SPARC_LO10:
158 			case R_SPARC_HH22:
159 			case R_SPARC_LM22:
160 			case R_SPARC_HM10:
161 			case R_SPARC_GLOB_DAT:
162 			case R_SPARC_JMP_SLOT:
163 			case R_SPARC_64:
164 				sym = SYMBOL(image, ELF64_R_SYM(rel[i].r_info));
165 #ifdef _BOOT_MODE
166 				vlErr = boot_elf_resolve_symbol(image, sym, &S);
167 #else
168 				vlErr = elf_resolve_symbol(image, sym, resolve_image, &S);
169 #endif
170 				if (vlErr < 0) {
171 					dprintf("%s(): Failed to relocate "
172 						"entry index %d, rel type %" PRIu64 ", offset 0x%lx, "
173 						"sym 0x%lx, addend 0x%lx\n", __FUNCTION__, i,
174 						ELF64_R_TYPE(rel[i].r_info),
175 						rel[i].r_offset, ELF64_R_SYM(rel[i].r_info),
176 						rel[i].r_addend);
177 					return vlErr;
178 				}
179 				break;
180 		}
181 
182 		switch (ELF64_R_TYPE(rel[i].r_info)) {
183 			case R_SPARC_WDISP30:
184 			{
185 				write_hi30(P, S + A - P);
186 			}
187 			case R_SPARC_HI22:
188 			case R_SPARC_LM22:
189 			{
190 				write_hi22(P, S + A);
191 				break;
192 			}
193 			case R_SPARC_LO10:
194 			{
195 				write_lo10(P, S + A);
196 				break;
197 			}
198 			case R_SPARC_HH22:
199 			{
200 				write_hh22(P, S + A);
201 				break;
202 			}
203 			case R_SPARC_HM10:
204 			{
205 				write_hm10(P, S + A);
206 				break;
207 			}
208 			case R_SPARC_GLOB_DAT:
209 			{
210 				write_word64(P, S + A);
211 				break;
212 			}
213 			case R_SPARC_JMP_SLOT:
214 			{
215 				// Created by the link-editor for dynamic objects to provide
216 				// lazy binding. The relocation offset member gives the
217 				// location of a procedure linkage table entry. The runtime
218 				// linker modifies the procedure linkage table entry to
219 				// transfer control to the designated symbol address.
220 				addr_t jumpOffset = S - (P + 8);
221 				if ((jumpOffset & 0xc0000000) != 0
222 					&& (~jumpOffset & 0xc0000000) != 0) {
223 					// Offset > 30 bit.
224 					// TODO: Implement!
225 					// See https://docs.oracle.com/cd/E26502_01/html/E26507/chapter6-1235.html
226 					// examples .PLT102 and .PLT103
227 					dprintf("arch_elf_relocate_rela(): R_SPARC_JMP_SLOT: "
228 						"Offsets > 30 bit currently not supported!\n");
229 					dprintf("jumpOffset: %p\n", (void*)jumpOffset);
230 					return B_ERROR;
231 				} else {
232 					uint32* instructions = (uint32*)P;
233 					// We need to use a call instruction because it has a lot
234 					// of space for the destination (30 bits). However, it
235 					// erases o7, which we don't want.
236 					// We could avoid this with a JMPL if the displacement was
237 					// small enough, but it probably isn't.
238 					// So, we store o7 in g1 before the call, and restore it
239 					// in the branch delay slot. Crazy, but it works!
240 					instructions[0] = 0x01000000; // NOP to preserve the alignment?
241 					instructions[1] = 0x8210000f; // MOV %o7, %g1
242 					instructions[2] = 0x40000000 | ((jumpOffset >> 2) & 0x3fffffff);
243 					instructions[3] = 0x9e100001; // MOV %g1, %o7
244 				}
245 				break;
246 			}
247 			case R_SPARC_RELATIVE:
248 			{
249 				write_word32(P, B + A);
250 				break;
251 			}
252 			case R_SPARC_64:
253 			{
254 				write_word64(P, S + A);
255 				break;
256 			}
257 			default:
258 				dprintf("arch_elf_relocate_rela: unhandled relocation type %"
259 					PRIu64 "\n", ELF64_R_TYPE(rel[i].r_info));
260 				return B_ERROR;
261 		}
262 	}
263 	return B_OK;
264 }
265