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