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