1 /******************************************************************************
2  * Copyright (c) 2004, 2011 IBM Corporation
3  * All rights reserved.
4  * This program and the accompanying materials
5  * are made available under the terms of the BSD License
6  * which accompanies this distribution, and is available at
7  * http://www.opensource.org/licenses/bsd-license.php
8  *
9  * Contributors:
10  *     IBM Corporation - initial implementation
11  *****************************************************************************/
12 
13 /*
14  * 64-bit ELF loader for PowerPC.
15  * See the "64-bit PowerPC ELF Application Binary Interface Supplement" and
16  * the "ELF-64 Object File Format" documentation for details.
17  */
18 
19 #include <string.h>
20 #include <stdio.h>
21 #include <libelf.h>
22 #include <byteorder.h>
23 
24 struct ehdr64
25 {
26 	uint32_t ei_ident;
27 	uint8_t ei_class;
28 	uint8_t ei_data;
29 	uint8_t ei_version;
30 	uint8_t ei_pad[9];
31 	uint16_t e_type;
32 	uint16_t e_machine;
33 	uint32_t e_version;
34 	uint64_t e_entry;
35 	uint64_t e_phoff;
36 	uint64_t e_shoff;
37 	uint32_t e_flags;
38 	uint16_t e_ehsize;
39 	uint16_t e_phentsize;
40 	uint16_t e_phnum;
41 	uint16_t e_shentsize;
42 	uint16_t e_shnum;
43 	uint16_t e_shstrndx;
44 };
45 
46 struct phdr64
47 {
48 	uint32_t p_type;
49 	uint32_t p_flags;
50 	uint64_t p_offset;
51 	uint64_t p_vaddr;
52 	uint64_t p_paddr;
53 	uint64_t p_filesz;
54 	uint64_t p_memsz;
55 	uint64_t p_align;
56 };
57 
58 struct shdr64
59 {
60 	uint32_t sh_name;	/* Section name */
61 	uint32_t sh_type;	/* Section type */
62 	uint64_t sh_flags; 	/* Section attributes */
63 	uint64_t sh_addr;	/* Virtual address in memory */
64 	uint64_t sh_offset;	/* Offset in file */
65 	uint64_t sh_size;	/* Size of section */
66 	uint32_t sh_link;	/* Link to other section */
67 	uint32_t sh_info;	/* Miscellaneous information */
68 	uint64_t sh_addralign;	/* Address alignment boundary */
69 	uint64_t sh_entsize;	/* Size of entries, if section has table */
70 };
71 
72 struct rela			/* RelA relocation table entry */
73 {
74 	uint64_t r_offset;	/* Address of reference */
75 	uint64_t r_info;	/* Symbol index and type of relocation */
76 	int64_t  r_addend;	/* Constant part of expression */
77 };
78 
79 struct sym64
80 {
81 	uint32_t st_name;	/* Symbol name */
82 	uint8_t st_info;	/* Type and Binding attributes */
83 	uint8_t st_other;	/* Reserved */
84 	uint16_t st_shndx;	/* Section table index */
85 	uint64_t st_value;	/* Symbol value */
86 	uint64_t st_size;	/* Size of object (e.g., common) */
87 };
88 
89 
90 /* For relocations */
91 #define	ELF_R_SYM(i)	((i)>>32)
92 #define	ELF_R_TYPE(i)	((uint32_t)(i) & 0xFFFFFFFF)
93 #define	ELF_R_INFO(s,t)	((((uint64_t) (s)) << 32) + (t))
94 
95 /*
96  * Relocation types for PowerPC64.
97  */
98 #define	R_PPC64_NONE			0
99 #define	R_PPC64_ADDR32			1
100 #define	R_PPC64_ADDR24			2
101 #define	R_PPC64_ADDR16			3
102 #define	R_PPC64_ADDR16_LO		4
103 #define	R_PPC64_ADDR16_HI		5
104 #define	R_PPC64_ADDR16_HA		6
105 #define	R_PPC64_ADDR14			7
106 #define	R_PPC64_ADDR14_BRTAKEN		8
107 #define	R_PPC64_ADDR14_BRNTAKEN		9
108 #define	R_PPC64_REL24			10
109 #define	R_PPC64_REL14			11
110 #define	R_PPC64_REL14_BRTAKEN		12
111 #define	R_PPC64_REL14_BRNTAKEN		13
112 #define	R_PPC64_GOT16			14
113 #define	R_PPC64_GOT16_LO		15
114 #define	R_PPC64_GOT16_HI		16
115 #define	R_PPC64_GOT16_HA		17
116 #define	R_PPC64_COPY			19
117 #define	R_PPC64_GLOB_DAT		20
118 #define	R_PPC64_JMP_SLOT		21
119 #define	R_PPC64_RELATIVE		22
120 #define	R_PPC64_UADDR32			24
121 #define	R_PPC64_UADDR16			25
122 #define	R_PPC64_REL32			26
123 #define	R_PPC64_PLT32			27
124 #define	R_PPC64_PLTREL32		28
125 #define	R_PPC64_PLT16_LO		29
126 #define	R_PPC64_PLT16_HI		30
127 #define	R_PPC64_PLT16_HA		31
128 #define	R_PPC64_SECTOFF			33
129 #define	R_PPC64_SECTOFF_LO		34
130 #define	R_PPC64_SECTOFF_HI		35
131 #define	R_PPC64_SECTOFF_HA		36
132 #define	R_PPC64_ADDR30			37
133 #define	R_PPC64_ADDR64			38
134 #define	R_PPC64_ADDR16_HIGHER		39
135 #define	R_PPC64_ADDR16_HIGHERA		40
136 #define	R_PPC64_ADDR16_HIGHEST		41
137 #define	R_PPC64_ADDR16_HIGHESTA		42
138 #define	R_PPC64_UADDR64			43
139 #define	R_PPC64_REL64			44
140 #define	R_PPC64_PLT64			45
141 #define	R_PPC64_PLTREL64		46
142 #define	R_PPC64_TOC16			47
143 #define	R_PPC64_TOC16_LO		48
144 #define	R_PPC64_TOC16_HI		49
145 #define	R_PPC64_TOC16_HA		50
146 #define	R_PPC64_TOC			51
147 #define	R_PPC64_PLTGOT16		52
148 #define	R_PPC64_PLTGOT16_LO		53
149 #define	R_PPC64_PLTGOT16_HI		54
150 #define	R_PPC64_PLTGOT16_HA		55
151 #define	R_PPC64_ADDR16_DS		56
152 #define	R_PPC64_ADDR16_LO_DS		57
153 #define	R_PPC64_GOT16_DS		58
154 #define	R_PPC64_GOT16_LO_DS		59
155 #define	R_PPC64_PLT16_LO_DS		60
156 #define	R_PPC64_SECTOFF_DS		61
157 #define	R_PPC64_SECTOFF_LO_DS		62
158 #define	R_PPC64_TOC16_DS		63
159 #define	R_PPC64_TOC16_LO_DS		64
160 #define	R_PPC64_PLTGOT16_DS		65
161 #define	R_PPC64_PLTGOT16_LO_DS		66
162 #define	R_PPC64_TLS			67
163 #define	R_PPC64_DTPMOD64		68
164 #define	R_PPC64_TPREL16			69
165 #define	R_PPC64_TPREL16_LO		60
166 #define	R_PPC64_TPREL16_HI		71
167 #define	R_PPC64_TPREL16_HA		72
168 #define	R_PPC64_TPREL64			73
169 #define	R_PPC64_DTPREL16		74
170 #define	R_PPC64_DTPREL16_LO		75
171 #define	R_PPC64_DTPREL16_HI		76
172 #define	R_PPC64_DTPREL16_HA		77
173 #define	R_PPC64_DTPREL64		78
174 #define	R_PPC64_GOT_TLSGD16		79
175 #define	R_PPC64_GOT_TLSGD16_LO		80
176 #define	R_PPC64_GOT_TLSGD16_HI		81
177 #define	R_PPC64_GOT_TLSGD16_HA		82
178 #define	R_PPC64_GOT_TLSLD16		83
179 #define	R_PPC64_GOT_TLSLD16_LO		84
180 #define	R_PPC64_GOT_TLSLD16_HI		85
181 #define	R_PPC64_GOT_TLSLD16_HA		86
182 #define	R_PPC64_GOT_TPREL16_DS		87
183 #define	R_PPC64_GOT_TPREL16_LO_	DS	88
184 #define	R_PPC64_GOT_TPREL16_HI		89
185 #define	R_PPC64_GOT_TPREL16_HA		90
186 #define	R_PPC64_GOT_DTPREL16_DS		91
187 #define	R_PPC64_GOT_DTPREL16_LO_DS	92
188 #define	R_PPC64_GOT_DTPREL16_HI		93
189 #define	R_PPC64_GOT_DTPREL16_HA		94
190 #define	R_PPC64_TPREL16_DS		95
191 #define	R_PPC64_TPREL16_LO_DS		96
192 #define	R_PPC64_TPREL16_HIGHER		97
193 #define	R_PPC64_TPREL16_HIGHERA		98
194 #define	R_PPC64_TPREL16_HIGHEST		99
195 #define	R_PPC64_TPREL16_HIGHESTA	100
196 #define	R_PPC64_DTPREL16_DS		101
197 #define	R_PPC64_DTPREL16_LO_DS		102
198 #define	R_PPC64_DTPREL16_HIGHER		103
199 #define	R_PPC64_DTPREL16_HIGHERA	104
200 #define	R_PPC64_DTPREL16_HIGHEST	105
201 #define	R_PPC64_DTPREL16_HIGHESTA	106
202 
203 
204 static struct phdr64*
get_phdr64(unsigned long * file_addr)205 get_phdr64(unsigned long *file_addr)
206 {
207 	return (struct phdr64 *) (((unsigned char *) file_addr)
208 		+ ((struct ehdr64 *)file_addr)->e_phoff);
209 }
210 
211 static void
load_segment64(unsigned long * file_addr,struct phdr64 * phdr,signed long offset,int (* pre_load)(void *,long),void (* post_load)(void *,long))212 load_segment64(unsigned long *file_addr, struct phdr64 *phdr, signed long offset,
213                int (*pre_load)(void*, long),
214                void (*post_load)(void*, long))
215 {
216 	unsigned long src = phdr->p_offset + (unsigned long) file_addr;
217 	unsigned long destaddr;
218 
219 	destaddr = phdr->p_paddr + offset;
220 
221 	/* check if we're allowed to copy */
222 	if (pre_load != NULL) {
223 		if (pre_load((void*)destaddr, phdr->p_memsz) != 0)
224 			return;
225 	}
226 
227 	/* copy into storage */
228 	memmove((void*)destaddr, (void*)src, phdr->p_filesz);
229 
230 	/* clear bss */
231 	memset((void*)(destaddr + phdr->p_filesz), 0,
232 	       phdr->p_memsz - phdr->p_filesz);
233 
234 	if (phdr->p_memsz && post_load != NULL) {
235 		post_load((void*)destaddr, phdr->p_memsz);
236 	}
237 }
238 
239 unsigned long
elf_load_segments64(void * file_addr,signed long offset,int (* pre_load)(void *,long),void (* post_load)(void *,long))240 elf_load_segments64(void *file_addr, signed long offset,
241                     int (*pre_load)(void*, long),
242                     void (*post_load)(void*, long))
243 {
244 	struct ehdr64 *ehdr = (struct ehdr64 *) file_addr;
245 	/* Calculate program header address */
246 	struct phdr64 *phdr = get_phdr64(file_addr);
247 	int i;
248 
249 	/* loop e_phnum times */
250 	for (i = 0; i <= ehdr->e_phnum; i++) {
251 		/* PT_LOAD ? */
252 		if (phdr->p_type == PT_LOAD) {
253 			if (phdr->p_paddr != phdr->p_vaddr) {
254 				printf("ELF64: VirtAddr(%lx) != PhysAddr(%lx) not supported, aborting\n",
255 					(long)phdr->p_vaddr, (long)phdr->p_paddr);
256 				return 0;
257 			}
258 
259 			/* copy segment */
260 			load_segment64(file_addr, phdr, offset, pre_load, post_load);
261 		}
262 		/* step to next header */
263 		phdr = (struct phdr64 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
264 	}
265 
266 	/* Entry point is always a virtual address, so translate it
267 	 * to physical before returning it */
268 	return ehdr->e_entry;
269 }
270 
271 /**
272  * Return the base address for loading (i.e. the address of the first PT_LOAD
273  * segment)
274  * @param  file_addr	pointer to the ELF file in memory
275  * @return		the base address
276  */
277 long
elf_get_base_addr64(void * file_addr)278 elf_get_base_addr64(void *file_addr)
279 {
280 	struct ehdr64 *ehdr = (struct ehdr64 *) file_addr;
281 	/* Calculate program header address */
282 	struct phdr64 *phdr = get_phdr64(file_addr);
283 	int i;
284 
285 	/* loop e_phnum times */
286 	for (i = 0; i <= ehdr->e_phnum; i++) {
287 		/* PT_LOAD ? */
288 		if (phdr->p_type == PT_LOAD) {
289 			/* Return base address */
290 			return phdr->p_paddr;
291 		}
292 		/* step to next header */
293 		phdr = (struct phdr64 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
294 	}
295 
296 	return 0;
297 }
298 
299 
300 /**
301  * Apply one relocation entry.
302  */
303 static void
elf_apply_rela64(void * file_addr,signed long offset,struct rela * relaentry,struct sym64 * symtabentry)304 elf_apply_rela64(void *file_addr, signed long offset, struct rela *relaentry,
305 		 struct sym64 *symtabentry)
306 {
307 	void *addr;
308 	unsigned long s_a;
309 	unsigned long base_addr;
310 
311 	base_addr = elf_get_base_addr64(file_addr);
312 
313 	/* Sanity check */
314 	if (relaentry->r_offset < base_addr) {
315 		printf("\nELF relocation out of bounds!\n");
316 		return;
317 	}
318 
319 	base_addr += offset;
320 
321 	/* Actual address where the relocation will be applied at. */
322 	addr = (void*)(relaentry->r_offset + offset);
323 
324 	/* Symbol value (S) + Addend (A) */
325 	s_a = symtabentry->st_value + offset + relaentry->r_addend;
326 
327 	switch (ELF_R_TYPE(relaentry->r_info)) {
328 	 case R_PPC64_ADDR32:		/* S + A */
329 		*(uint32_t *)addr = (uint32_t) s_a;
330 		break;
331 	 case R_PPC64_ADDR64:		/* S + A */
332 		*(uint64_t *)addr = (uint64_t) s_a;
333 		break;
334 	 case R_PPC64_TOC:		/* .TOC */
335 		*(uint64_t *)addr += offset;
336 		break;
337 	 case R_PPC64_ADDR16_HIGHEST:	/* #highest(S + A) */
338 		*(uint16_t *)addr = ((s_a >> 48) & 0xffff);
339 		break;
340 	 case R_PPC64_ADDR16_HIGHER:	/* #higher(S + A) */
341 		*(uint16_t *)addr = ((s_a >> 32) & 0xffff);
342 		break;
343 	 case R_PPC64_ADDR16_HI:	/* #hi(S + A) */
344 		*(uint16_t *)addr = ((s_a >> 16) & 0xffff);
345 		break;
346 	 case R_PPC64_ADDR16_LO:	/* #lo(S + A) */
347 		*(uint16_t *)addr = s_a & 0xffff;
348 		break;
349 	 case R_PPC64_ADDR16_LO_DS:
350 		*(uint16_t *)addr = (s_a & 0xfffc);
351 		break;
352 	 case R_PPC64_ADDR16_HA:	/* #ha(S + A) */
353 		*(uint16_t *)addr = (((s_a >> 16) + ((s_a & 0x8000) ? 1 : 0))
354 				     & 0xffff);
355 		break;
356 
357 	 case R_PPC64_TOC16:		/* half16* S + A - .TOC. */
358 	 case R_PPC64_TOC16_LO_DS:
359 	 case R_PPC64_TOC16_LO: 	/* #lo(S + A - .TOC.) */
360 	 case R_PPC64_TOC16_HI: 	/* #hi(S + A - .TOC.) */
361 	 case R_PPC64_TOC16_HA:
362 	 case R_PPC64_TOC16_DS: 	/* (S + A - .TOC) >> 2 */
363 	 case R_PPC64_REL14:
364 	 case R_PPC64_REL24:		/* (S + A - P) >> 2 */
365 	 case R_PPC64_REL32:		/* S + A - P */
366 	 case R_PPC64_REL64:		/* S + A - P */
367 	 case R_PPC64_GOT16_DS:
368 	 case R_PPC64_GOT16_LO_DS:
369 		// printf("\t\tignoring relocation type %i\n",
370 		//	  ELF_R_TYPE(relaentry->r_info));
371 		break;
372 	 default:
373 		printf("ERROR: Unhandled relocation (A) type %i\n",
374 			ELF_R_TYPE(relaentry->r_info));
375 	}
376 }
377 
378 
379 /**
380  * Step through all relocation entries and apply them one by one.
381  */
382 static void
elf_apply_all_rela64(void * file_addr,signed long offset,struct shdr64 * shdrs,int idx)383 elf_apply_all_rela64(void *file_addr, signed long offset, struct shdr64 *shdrs, int idx)
384 {
385 	struct shdr64 *rela_shdr = &shdrs[idx];
386 	struct shdr64 *dst_shdr = &shdrs[rela_shdr->sh_info];
387 	struct shdr64 *sym_shdr = &shdrs[rela_shdr->sh_link];
388 	struct rela *relaentry;
389 	struct sym64 *symtabentry;
390 	uint32_t symbolidx;
391 	int i;
392 
393 	/* If the referenced section has not been allocated, then it has
394 	 * not been loaded and thus does not need to be relocated. */
395 	if ((dst_shdr->sh_flags & SHF_ALLOC) != SHF_ALLOC)
396 		return;
397 
398 	for (i = 0; i < rela_shdr->sh_size; i += rela_shdr->sh_entsize) {
399 		relaentry = (struct rela *)(file_addr + rela_shdr->sh_offset + i);
400 
401 		symbolidx = ELF_R_SYM(relaentry->r_info);
402 		symtabentry = (struct sym64*)(file_addr + sym_shdr->sh_offset) + symbolidx;
403 
404 		elf_apply_rela64(file_addr, offset, relaentry, symtabentry);
405 	}
406 }
407 
408 
409 /**
410  * Apply ELF relocations
411  */
412 void
elf_relocate64(void * file_addr,signed long offset)413 elf_relocate64(void *file_addr, signed long offset)
414 {
415 	struct ehdr64 *ehdr = (struct ehdr64 *) file_addr;
416 	/* Calculate section header address */
417 	struct shdr64 *shdrs = (struct shdr64 *)
418 			(((unsigned char *) file_addr) + ehdr->e_shoff);
419 	int i;
420 
421 	/* loop over all segments */
422 	for (i = 0; i <= ehdr->e_shnum; i++) {
423 		/* Skip if it is not a relocation segment */
424 		if (shdrs[i].sh_type == SHT_RELA) {
425 			elf_apply_all_rela64(file_addr, offset, shdrs, i);
426 		}
427 	}
428 }
429 
430 void
elf_byteswap_header64(void * file_addr)431 elf_byteswap_header64(void *file_addr)
432 {
433 	struct ehdr64 *ehdr = (struct ehdr64 *) file_addr;
434 	struct phdr64 *phdr;
435 	int i;
436 
437 	bswap_16p(&ehdr->e_type);
438 	bswap_16p(&ehdr->e_machine);
439 	bswap_32p(&ehdr->e_version);
440 	bswap_64p(&ehdr->e_entry);
441 	bswap_64p(&ehdr->e_phoff);
442 	bswap_64p(&ehdr->e_shoff);
443 	bswap_32p(&ehdr->e_flags);
444 	bswap_16p(&ehdr->e_ehsize);
445 	bswap_16p(&ehdr->e_phentsize);
446 	bswap_16p(&ehdr->e_phnum);
447 	bswap_16p(&ehdr->e_shentsize);
448 	bswap_16p(&ehdr->e_shnum);
449 	bswap_16p(&ehdr->e_shstrndx);
450 
451 	phdr = get_phdr64(file_addr);
452 
453 	/* loop e_phnum times */
454 	for (i = 0; i <= ehdr->e_phnum; i++) {
455 		bswap_32p(&phdr->p_type);
456 		bswap_32p(&phdr->p_flags);
457 		bswap_64p(&phdr->p_offset);
458 		bswap_64p(&phdr->p_vaddr);
459 		bswap_64p(&phdr->p_paddr);
460 		bswap_64p(&phdr->p_filesz);
461 		bswap_64p(&phdr->p_memsz);
462 		bswap_64p(&phdr->p_align);
463 
464 		/* step to next header */
465 		phdr = (struct phdr64 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
466 	}
467 }
468 
elf_get_eflags_64(void * file_addr)469 uint32_t elf_get_eflags_64(void *file_addr)
470 {
471 	struct ehdr64 *ehdr = (struct ehdr64 *) file_addr;
472 
473 	return ehdr->e_flags;
474 }
475