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
29static bool
30is_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
41status_t
42boot_arch_elf_relocate_rel(struct preloaded_elf64_image *image, Elf64_Rel *rel,
43	int rel_len)
44#else
45int
46arch_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
55static inline void
56write_word32(addr_t P, Elf64_Word value)
57{
58	*(Elf64_Word*)P = value;
59}
60
61
62static inline void
63write_word64(addr_t P, Elf64_Xword value)
64{
65	*(Elf64_Xword*)P = value;
66}
67
68
69static inline void
70write_hi30(addr_t P, Elf64_Word value)
71{
72	*(Elf64_Word*)P |= value >> 2;
73}
74
75
76static inline void
77write_hi22(addr_t P, Elf64_Word value)
78{
79	*(Elf64_Word*)P |= value >> 10;
80}
81
82
83static inline void
84write_lo10(addr_t P, Elf64_Word value)
85{
86	*(Elf64_Word*)P |= value & 0x3ff;
87}
88
89
90static inline void
91write_hh22(addr_t P, Elf64_Xword value)
92{
93	*(Elf64_Word*)P |= value >> 42;
94}
95
96
97static inline void
98write_hm10(addr_t P, Elf64_Xword value)
99{
100	*(Elf64_Word*)P |= (value >> 32) & 0x3ff;
101}
102
103
104#ifdef _BOOT_MODE
105status_t
106boot_arch_elf_relocate_rela(struct preloaded_elf64_image *image,
107	Elf64_Rela *rel, int rel_len)
108#else
109int
110arch_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