Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / lib / libelf / elf64.c
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*
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
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
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
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
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_REL64:            /* S + A - P */
366          case R_PPC64_GOT16_DS:
367          case R_PPC64_GOT16_LO_DS:
368                 // printf("\t\tignoring relocation type %i\n",
369                 //        ELF_R_TYPE(relaentry->r_info));
370                 break;
371          default:
372                 printf("ERROR: Unhandled relocation (A) type %i\n",
373                         ELF_R_TYPE(relaentry->r_info));
374         }
375 }
376
377
378 /**
379  * Step through all relocation entries and apply them one by one.
380  */
381 static void
382 elf_apply_all_rela64(void *file_addr, signed long offset, struct shdr64 *shdrs, int idx)
383 {
384         struct shdr64 *rela_shdr = &shdrs[idx];
385         struct shdr64 *dst_shdr = &shdrs[rela_shdr->sh_info];
386         struct shdr64 *sym_shdr = &shdrs[rela_shdr->sh_link];
387         struct rela *relaentry;
388         struct sym64 *symtabentry;
389         uint32_t symbolidx;
390         int i;
391
392         /* If the referenced section has not been allocated, then it has
393          * not been loaded and thus does not need to be relocated. */
394         if ((dst_shdr->sh_flags & SHF_ALLOC) != SHF_ALLOC)
395                 return;
396
397         for (i = 0; i < rela_shdr->sh_size; i += rela_shdr->sh_entsize) {
398                 relaentry = (struct rela *)(file_addr + rela_shdr->sh_offset + i);
399
400                 symbolidx = ELF_R_SYM(relaentry->r_info);
401                 symtabentry = (struct sym64*)(file_addr + sym_shdr->sh_offset) + symbolidx;
402
403                 elf_apply_rela64(file_addr, offset, relaentry, symtabentry);
404         }
405 }
406
407
408 /**
409  * Apply ELF relocations
410  */
411 void
412 elf_relocate64(void *file_addr, signed long offset)
413 {
414         struct ehdr64 *ehdr = (struct ehdr64 *) file_addr;
415         /* Calculate section header address */
416         struct shdr64 *shdrs = (struct shdr64 *)
417                         (((unsigned char *) file_addr) + ehdr->e_shoff);
418         int i;
419
420         /* loop over all segments */
421         for (i = 0; i <= ehdr->e_shnum; i++) {
422                 /* Skip if it is not a relocation segment */
423                 if (shdrs[i].sh_type == SHT_RELA) {
424                         elf_apply_all_rela64(file_addr, offset, shdrs, i);
425                 }
426         }
427 }
428
429 void
430 elf_byteswap_header64(void *file_addr)
431 {
432         struct ehdr64 *ehdr = (struct ehdr64 *) file_addr;
433         struct phdr64 *phdr;
434         int i;
435
436         bswap_16p(&ehdr->e_type);
437         bswap_16p(&ehdr->e_machine);
438         bswap_32p(&ehdr->e_version);
439         bswap_64p(&ehdr->e_entry);
440         bswap_64p(&ehdr->e_phoff);
441         bswap_64p(&ehdr->e_shoff);
442         bswap_32p(&ehdr->e_flags);
443         bswap_16p(&ehdr->e_ehsize);
444         bswap_16p(&ehdr->e_phentsize);
445         bswap_16p(&ehdr->e_phnum);
446         bswap_16p(&ehdr->e_shentsize);
447         bswap_16p(&ehdr->e_shnum);
448         bswap_16p(&ehdr->e_shstrndx);
449
450         phdr = get_phdr64(file_addr);
451
452         /* loop e_phnum times */
453         for (i = 0; i <= ehdr->e_phnum; i++) {
454                 bswap_32p(&phdr->p_type);
455                 bswap_32p(&phdr->p_flags);
456                 bswap_64p(&phdr->p_offset);
457                 bswap_64p(&phdr->p_vaddr);
458                 bswap_64p(&phdr->p_paddr);
459                 bswap_64p(&phdr->p_filesz);
460                 bswap_64p(&phdr->p_memsz);
461                 bswap_64p(&phdr->p_align);
462
463                 /* step to next header */
464                 phdr = (struct phdr64 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
465         }
466 }
467
468 uint32_t elf_get_eflags_64(void *file_addr)
469 {
470         struct ehdr64 *ehdr = (struct ehdr64 *) file_addr;
471
472         return ehdr->e_flags;
473 }