Initialize Tizen 2.3
[external/prelink.git] / src / arch-ppc64.c
1 /* Copyright (C) 2002, 2003, 2004, 2009 Red Hat, Inc.
2    Written by Jakub Jelinek <jakub@redhat.com>, 2002.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software Foundation,
16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 #include <config.h>
19 #include <assert.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <locale.h>
25 #include <error.h>
26 #include <argp.h>
27 #include <stdlib.h>
28
29 #include "prelink.h"
30 #include "layout.h"
31
32 struct opd_rec
33 {
34   GElf_Addr fn, toc, chain;
35 };
36
37 struct opd_lib
38 {
39   GElf_Addr start, size;
40   GElf_Addr table[1];
41 };
42
43 static int
44 ppc64_adjust_section (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
45 {
46   if (dso->shdr[n].sh_type == SHT_PROGBITS
47       && ! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
48                            dso->shdr[n].sh_name), ".got"))
49     {
50       Elf64_Addr data;
51
52       /* .got[0]-0x8000 points to .got, it needs to be adjusted.  */
53       data = read_ube64 (dso, dso->shdr[n].sh_addr);
54       if (addr_to_sec (dso, data - 0x8000) == n
55           && data - 0x8000 == dso->shdr[n].sh_addr)
56         write_be64 (dso, dso->shdr[n].sh_addr, data + adjust);
57     }
58   return 0;
59 }
60
61 static int
62 ppc64_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
63                   GElf_Addr adjust)
64 {
65   if (dyn->d_tag == DT_PPC64_GLINK && dyn->d_un.d_ptr >= start)
66     {
67       dyn->d_un.d_ptr += adjust;
68       return 1;
69     }
70
71   return 0;
72 }
73
74 static int
75 ppc64_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
76                   GElf_Addr adjust)
77 {
78   error (0, 0, "%s: PowerPC64 doesn't support REL relocs", dso->filename);
79   return 1;
80 }
81
82 static int
83 ppc64_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
84                    GElf_Addr adjust)
85 {
86   if (GELF_R_TYPE (rela->r_info) == R_PPC64_RELATIVE
87       || GELF_R_TYPE (rela->r_info) == R_PPC64_IRELATIVE)
88     {
89       GElf_Addr val = read_ube64 (dso, rela->r_offset);
90
91       if (val == rela->r_addend && val >= start)
92         write_be64 (dso, rela->r_offset, val + adjust);
93       if (rela->r_addend >= start)
94         rela->r_addend += adjust;
95     }
96   else if (GELF_R_TYPE (rela->r_info) == R_PPC64_JMP_IREL)
97     {
98       if (rela->r_addend >= start)
99         rela->r_addend += adjust;
100     }
101   return 0;
102 }
103
104 static int
105 ppc64_prelink_rel (struct prelink_info *info, GElf_Rel *rel,
106                    GElf_Addr reladdr)
107 {
108   error (0, 0, "%s: PowerPC64 doesn't support REL relocs", info->dso->filename);
109   return 1;
110 }
111
112 static int
113 ppc64_fixup_plt (struct prelink_info *info, GElf_Rela *rela, GElf_Addr value)
114 {
115   DSO *dso = info->dso;
116   int sec, i;
117   size_t n;
118   struct opd_rec rec;
119
120   if (value == 0)
121     {
122       rec.fn = 0;
123       rec.toc = 0;
124       rec.chain = 0;
125     }
126   else if ((sec = addr_to_sec (dso, value)) != -1)
127     {
128       rec.fn = read_ube64 (dso, value);
129       rec.toc = read_ube64 (dso, value + 8);
130       rec.chain = read_ube64 (dso, value + 16);
131     }
132   else
133     {
134       for (i = 0; i < info->ent->ndepends; ++i)
135         if (info->ent->depends[i]->opd
136             && info->ent->depends[i]->opd->start <= value
137             && (info->ent->depends[i]->opd->start
138                 + info->ent->depends[i]->opd->size) > value)
139         break;
140
141       if (i == info->ent->ndepends)
142         {
143           error (0, 0, "%s: R_PPC64_JMP_SLOT doesn't resolve to an .opd address",
144                  dso->filename);
145           return 1;
146         }
147       if ((value - info->ent->depends[i]->opd->start) % 8)
148         {
149           error (0, 0, "%s: R_PPC64_JMP_SLOT doesn't resolve to valid .opd section location",
150                  dso->filename);
151           return 1;
152         }
153       n = (value - info->ent->depends[i]->opd->start) / 8;
154       rec.fn = info->ent->depends[i]->opd->table[n];
155       rec.toc = info->ent->depends[i]->opd->table[n + 1];
156       rec.chain = info->ent->depends[i]->opd->table[n + 2];
157     }
158   write_be64 (dso, rela->r_offset, rec.fn);
159   write_be64 (dso, rela->r_offset + 8, rec.toc);
160   write_be64 (dso, rela->r_offset + 16, rec.chain);
161   return 0;
162 }
163
164 static int
165 ppc64_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
166                     GElf_Addr relaaddr)
167 {
168   DSO *dso = info->dso;
169   GElf_Addr value;
170
171   if (GELF_R_TYPE (rela->r_info) == R_PPC64_NONE
172       || GELF_R_TYPE (rela->r_info) == R_PPC64_IRELATIVE
173       || GELF_R_TYPE (rela->r_info) == R_PPC64_JMP_IREL)
174     return 0;
175   else if (GELF_R_TYPE (rela->r_info) == R_PPC64_RELATIVE)
176     {
177       write_be64 (dso, rela->r_offset, rela->r_addend);
178       return 0;
179     }
180   value = info->resolve (info, GELF_R_SYM (rela->r_info),
181                          GELF_R_TYPE (rela->r_info));
182   value += rela->r_addend;
183   switch (GELF_R_TYPE (rela->r_info))
184     {
185     case R_PPC64_GLOB_DAT:
186     case R_PPC64_ADDR64:
187     case R_PPC64_UADDR64:
188       write_be64 (dso, rela->r_offset, value);
189       break;
190     case R_PPC64_DTPREL64:
191       write_be64 (dso, rela->r_offset, value - 0x8000);
192       break;
193     case R_PPC64_ADDR32:
194     case R_PPC64_UADDR32:
195       write_be32 (dso, rela->r_offset, value);
196       break;
197     case R_PPC64_JMP_SLOT:
198       return ppc64_fixup_plt (info, rela, value);
199     case R_PPC64_ADDR16:
200     case R_PPC64_UADDR16:
201     case R_PPC64_ADDR16_LO:
202       write_be16 (dso, rela->r_offset, value);
203       break;
204     case R_PPC64_DTPREL16:
205     case R_PPC64_DTPREL16_LO:
206       write_be16 (dso, rela->r_offset, value - 0x8000);
207       break;
208     case R_PPC64_ADDR16_HI:
209     case R_PPC64_DTPREL16_HA:
210       write_be16 (dso, rela->r_offset, value >> 16);
211       break;
212     case R_PPC64_DTPREL16_HI:
213       write_be16 (dso, rela->r_offset, (value - 0x8000) >> 16);
214       break;
215     case R_PPC64_ADDR16_HA:
216       write_be16 (dso, rela->r_offset, (value + 0x8000) >> 16);
217       break;
218     case R_PPC64_ADDR16_HIGHER:
219       write_be16 (dso, rela->r_offset, value >> 32);
220       break;
221     case R_PPC64_ADDR16_HIGHERA:
222       write_be16 (dso, rela->r_offset, (value + 0x8000) >> 32);
223       break;
224     case R_PPC64_ADDR16_HIGHEST:
225       write_be16 (dso, rela->r_offset, value >> 48);
226       break;
227     case R_PPC64_ADDR16_HIGHESTA:
228       write_be16 (dso, rela->r_offset, (value + 0x8000) >> 48);
229       break;
230     case R_PPC64_ADDR16_LO_DS:
231     case R_PPC64_ADDR16_DS:
232       write_be16 (dso, rela->r_offset,
233                   (value & 0xfffc) | read_ube16 (dso, rela->r_offset & 3));
234       break;
235     case R_PPC64_ADDR24:
236       write_be32 (dso, rela->r_offset,
237                   (value & 0x03fffffc)
238                   | (read_ube32 (dso, rela->r_offset) & 0xfc000003));
239       break;
240     case R_PPC64_ADDR14:
241       write_be32 (dso, rela->r_offset,
242                   (value & 0xfffc)
243                   | (read_ube32 (dso, rela->r_offset) & 0xffff0003));
244       break;
245     case R_PPC64_ADDR14_BRTAKEN:
246     case R_PPC64_ADDR14_BRNTAKEN:
247       write_be32 (dso, rela->r_offset,
248                   (value & 0xfffc)
249                   | (read_ube32 (dso, rela->r_offset) & 0xffdf0003)
250                   | ((((GELF_R_TYPE (rela->r_info) == R_PPC64_ADDR14_BRTAKEN)
251                        << 21)
252                       ^ (value >> 42)) & 0x00200000));
253       break;
254     case R_PPC64_REL24:
255       write_be32 (dso, rela->r_offset,
256                   ((value - rela->r_offset) & 0x03fffffc)
257                   | (read_ube32 (dso, rela->r_offset) & 0xfc000003));
258       break;
259     case R_PPC64_REL32:
260       write_be32 (dso, rela->r_offset, value - rela->r_offset);
261       break;
262     case R_PPC64_REL64:
263       write_be64 (dso, rela->r_offset, value - rela->r_offset);
264       break;
265     /* DTPMOD64 and TPREL* is impossible to predict in shared libraries
266        unless prelink sets the rules.  */
267     case R_PPC64_DTPMOD64:
268       if (dso->ehdr.e_type == ET_EXEC)
269         {
270           error (0, 0, "%s: R_PPC64_DTPMOD64 reloc in executable?",
271                  dso->filename);
272           return 1;
273         }
274       break;
275     case R_PPC64_TPREL64:
276     case R_PPC64_TPREL16:
277     case R_PPC64_TPREL16_LO:
278     case R_PPC64_TPREL16_HI:
279     case R_PPC64_TPREL16_HA:
280       if (dso->ehdr.e_type == ET_EXEC && info->resolvetls)
281         {
282           value += info->resolvetls->offset - 0x7000;
283           switch (GELF_R_TYPE (rela->r_info))
284             {
285             case R_PPC64_TPREL64:
286               write_be64 (dso, rela->r_offset, value);
287               break;
288             case R_PPC64_TPREL16:
289             case R_PPC64_TPREL16_LO:
290               write_be16 (dso, rela->r_offset, value);
291               break;
292             case R_PPC64_TPREL16_HI:
293               write_be16 (dso, rela->r_offset, value >> 16);
294               break;
295             case R_PPC64_TPREL16_HA:
296               write_be16 (dso, rela->r_offset, (value + 0x8000) >> 16);
297               break;
298             }
299         }
300       break;
301     case R_PPC64_COPY:
302       if (dso->ehdr.e_type == ET_EXEC)
303         /* COPY relocs are handled specially in generic code.  */
304         return 0;
305       error (0, 0, "%s: R_PPC64_COPY reloc in shared library?", dso->filename);
306       return 1;
307     default:
308       error (0, 0, "%s: Unknown ppc relocation type %d", dso->filename,
309              (int) GELF_R_TYPE (rela->r_info));
310       return 1;
311     }
312   return 0;
313 }
314
315 static int
316 ppc64_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
317                            char *buf, GElf_Addr dest_addr)
318 {
319   GElf_Rela *ret;
320   switch (GELF_R_TYPE (rela->r_info))
321     {
322     case R_PPC64_ADDR64:
323     case R_PPC64_UADDR64:
324       buf_write_be64 (buf, rela->r_addend);
325       break;
326     case R_PPC64_ADDR32:
327     case R_PPC64_UADDR32:
328       buf_write_be32 (buf, rela->r_addend);
329       break;
330     case R_PPC64_ADDR16:
331     case R_PPC64_UADDR16:
332       buf_write_be16 (buf, rela->r_addend);
333       break;
334     case R_PPC64_IRELATIVE:
335       if (dest_addr == 0)
336         return 5;
337       ret = prelink_conflict_add_rela (info);
338       if (ret == NULL)
339         return 1;
340       ret->r_offset = dest_addr;
341       ret->r_info = GELF_R_INFO (0, R_PPC64_IRELATIVE);
342       ret->r_addend = rela->r_addend;
343       break;
344     default:
345       abort ();
346     }
347   return 0;
348 }
349
350 static int
351 ppc64_apply_rel (struct prelink_info *info, GElf_Rel *rel, char *buf)
352 {
353   error (0, 0, "%s: PowerPC64 doesn't support REL relocs", info->dso->filename);
354   return 1;
355 }
356
357 static int
358 ppc64_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
359 {
360   GElf_Addr value;
361
362   value = info->resolve (info, GELF_R_SYM (rela->r_info),
363                          GELF_R_TYPE (rela->r_info));
364   value += rela->r_addend;
365   switch (GELF_R_TYPE (rela->r_info))
366     {
367     case R_PPC64_NONE:
368       break;
369     case R_PPC64_GLOB_DAT:
370     case R_PPC64_ADDR64:
371     case R_PPC64_UADDR64:
372       buf_write_be64 (buf, value);
373       break;
374     case R_PPC64_ADDR32:
375     case R_PPC64_UADDR32:
376       buf_write_be32 (buf, value);
377       break;
378     case R_PPC64_ADDR16_HA:
379       value += 0x8000;
380       /* FALLTHROUGH  */
381     case R_PPC64_ADDR16_HI:
382       value = value >> 16;
383       /* FALLTHROUGH  */
384     case R_PPC64_ADDR16:
385     case R_PPC64_UADDR16:
386     case R_PPC64_ADDR16_LO:
387       buf_write_be16 (buf, value);
388       break;
389     case R_PPC64_ADDR16_HIGHERA:
390       value += 0x8000;
391       /* FALLTHROUGH  */
392     case R_PPC64_ADDR16_HIGHER:
393       buf_write_be16 (buf, value >> 32);
394       break;
395     case R_PPC64_ADDR16_HIGHESTA:
396       value += 0x8000;
397       /* FALLTHROUGH  */
398     case R_PPC64_ADDR16_HIGHEST:
399       buf_write_be16 (buf, value >> 48);
400       break;
401     case R_PPC64_ADDR16_LO_DS:
402     case R_PPC64_ADDR16_DS:
403       buf_write_be16 (buf, (value & 0xfffc)
404                            | (buf_read_ube16 (buf) & 3));
405       break;
406     case R_PPC64_ADDR24:
407       buf_write_be32 (buf, (value & 0x03fffffc)
408                            | (buf_read_ube32 (buf) & 0xfc000003));
409       break;
410     case R_PPC64_ADDR14:
411       buf_write_be32 (buf, (value & 0xfffc)
412                            | (buf_read_ube32 (buf) & 0xffff0003));
413       break;
414     case R_PPC64_ADDR14_BRTAKEN:
415     case R_PPC64_ADDR14_BRNTAKEN:
416       buf_write_be32 (buf, (value & 0xfffc)
417                            | (buf_read_ube32 (buf) & 0xffdf0003)
418                            | ((((GELF_R_TYPE (rela->r_info)
419                                  == R_PPC64_ADDR14_BRTAKEN) << 21)
420                                ^ (value >> 42)) & 0x00200000));
421       break;
422     case R_PPC64_REL24:
423       buf_write_be32 (buf, ((value - rela->r_offset) & 0x03fffffc)
424                            | (buf_read_ube32 (buf) & 0xfc000003));
425       break;
426     case R_PPC64_REL32:
427       buf_write_be32 (buf, value - rela->r_offset);
428       break;
429     case R_PPC64_REL64:
430       buf_write_be64 (buf, value - rela->r_offset);
431       break;
432     case R_PPC64_RELATIVE:
433       error (0, 0, "%s: R_PPC64_RELATIVE in ET_EXEC object?",
434              info->dso->filename);
435       return 1;
436     default:
437       return 1;
438     }
439   return 0;
440 }
441
442 static int
443 ppc64_prelink_conflict_rel (DSO *dso, struct prelink_info *info,
444                             GElf_Rel *rel, GElf_Addr reladdr)
445 {
446   error (0, 0, "%s: PowerPC64 doesn't support REL relocs", dso->filename);
447   return 1;
448 }
449
450 static int
451 ppc64_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
452                              GElf_Rela *rela, GElf_Addr relaaddr)
453 {
454   GElf_Addr value;
455   struct prelink_conflict *conflict;
456   struct prelink_tls *tls;
457   GElf_Rela *ret;
458   int r_type;
459
460   if (GELF_R_TYPE (rela->r_info) == R_PPC64_RELATIVE
461       || GELF_R_TYPE (rela->r_info) == R_PPC64_NONE)
462     /* Fast path: nothing to do.  */
463     return 0;
464   conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
465                                GELF_R_TYPE (rela->r_info));
466   if (conflict == NULL)
467     {
468       switch (GELF_R_TYPE (rela->r_info))
469         {
470         /* Even local DTPMOD and TPREL relocs need conflicts.  */
471         case R_PPC64_DTPMOD64:
472         case R_PPC64_TPREL64:
473         case R_PPC64_TPREL16:
474         case R_PPC64_TPREL16_LO:
475         case R_PPC64_TPREL16_HI:
476         case R_PPC64_TPREL16_HA:
477           if (info->curtls == NULL || info->dso == dso)
478             return 0;
479           break;
480         /* Similarly IRELATIVE relocations always need conflicts.  */
481         case R_PPC64_IRELATIVE:
482         case R_PPC64_JMP_IREL:
483           break;
484         default:
485           return 0;
486         }
487       value = 0;
488     }
489   else if (info->dso == dso && !conflict->ifunc)
490     return 0;
491   else
492     {
493       /* DTPREL wants to see only real conflicts, not lookups
494          with reloc_class RTYPE_CLASS_TLS.  */
495       if (conflict->lookup.tls == conflict->conflict.tls
496           && conflict->lookupval == conflict->conflictval)
497         switch (GELF_R_TYPE (rela->r_info))
498           {
499           case R_PPC64_DTPREL64:
500           case R_PPC64_DTPREL16:
501           case R_PPC64_DTPREL16_LO:
502           case R_PPC64_DTPREL16_HI:
503           case R_PPC64_DTPREL16_HA:
504             return 0;
505           }
506
507       value = conflict_lookup_value (conflict);
508     }
509   ret = prelink_conflict_add_rela (info);
510   if (ret == NULL)
511     return 1;
512   ret->r_offset = rela->r_offset;
513   value += rela->r_addend;
514   r_type = GELF_R_TYPE (rela->r_info);
515   switch (r_type)
516     {
517     case R_PPC64_GLOB_DAT:
518       r_type = R_PPC64_ADDR64;
519     case R_PPC64_ADDR64:
520     case R_PPC64_UADDR64:
521       if (conflict != NULL && conflict->ifunc)
522         r_type = R_PPC64_IRELATIVE;
523       break;
524     case R_PPC64_IRELATIVE:
525     case R_PPC64_JMP_IREL:
526       break;
527     case R_PPC64_JMP_SLOT:
528       if (conflict != NULL && conflict->ifunc)
529         r_type = R_PPC64_JMP_IREL;
530       break;
531     case R_PPC64_ADDR32:
532     case R_PPC64_UADDR32:
533       value = (Elf32_Sword) value;
534       break;
535     case R_PPC64_ADDR16_HA:
536       value += 0x8000;
537       /* FALLTHROUGH  */
538     case R_PPC64_ADDR16_HI:
539       value = value >> 16;
540       /* FALLTHROUGH  */
541     case R_PPC64_ADDR16:
542     case R_PPC64_UADDR16:
543     case R_PPC64_ADDR16_LO:
544       if (r_type != R_PPC64_UADDR16)
545         r_type = R_PPC64_ADDR16;
546       value = ((value & 0xffff) ^ 0x8000) - 0x8000;
547       break;
548     case R_PPC64_ADDR16_HIGHERA:
549       value += 0x8000;
550       /* FALLTHROUGH  */
551     case R_PPC64_ADDR16_HIGHER:
552       r_type = R_PPC64_ADDR16;
553       value = (((value >> 32) & 0xffff) ^ 0x8000) - 0x8000;
554       break;
555     case R_PPC64_ADDR16_HIGHESTA:
556       value += 0x8000;
557       /* FALLTHROUGH  */
558     case R_PPC64_ADDR16_HIGHEST:
559       r_type = R_PPC64_ADDR16;
560       value = ((Elf64_Sxword) value) >> 48;
561       break;
562     case R_PPC64_ADDR16_LO_DS:
563     case R_PPC64_ADDR16_DS:
564       r_type = R_PPC64_ADDR16;
565       value = ((value & 0xffff) ^ 0x8000) - 0x8000;
566       value |= read_ube16 (dso, rela->r_offset) & 3;
567       break;
568     case R_PPC64_ADDR24:
569       r_type = R_PPC64_ADDR32;
570       value = (value & 0x03fffffc)
571               | (read_ube32 (dso, rela->r_offset) & 0xfc000003);
572       value = (Elf32_Sword) value;
573       break;
574     case R_PPC64_ADDR14:
575       r_type = R_PPC64_ADDR32;
576       value = (value & 0xfffc)
577               | (read_ube32 (dso, rela->r_offset) & 0xffff0003);
578       value = (Elf32_Sword) value;
579       break;
580     case R_PPC64_ADDR14_BRTAKEN:
581     case R_PPC64_ADDR14_BRNTAKEN:
582       r_type = R_PPC64_ADDR32;
583       value = (value & 0xfffc)
584               | (read_ube32 (dso, rela->r_offset) & 0xffdf0003)
585               | ((((r_type == R_PPC64_ADDR14_BRTAKEN) << 21)
586                   ^ (value >> 42)) & 0x00200000);
587       value = (Elf32_Sword) value;
588       break;
589     case R_PPC64_REL24:
590       r_type = R_PPC64_ADDR32;
591       value = ((value - rela->r_offset) & 0x03fffffc)
592               | (read_ube32 (dso, rela->r_offset) & 0xfc000003);
593       value = (Elf32_Sword) value;
594       break;
595     case R_PPC64_REL32:
596       r_type = R_PPC64_ADDR32;
597       value -= rela->r_offset;
598       value = (Elf32_Sword) value;
599       break;
600     case R_PPC64_REL64:
601       r_type = R_PPC64_ADDR64;
602       value -= rela->r_offset;
603       break;
604     case R_PPC64_DTPMOD64:
605     case R_PPC64_DTPREL64:
606     case R_PPC64_DTPREL16:
607     case R_PPC64_DTPREL16_LO:
608     case R_PPC64_DTPREL16_HI:
609     case R_PPC64_DTPREL16_HA:
610     case R_PPC64_TPREL64:
611     case R_PPC64_TPREL16:
612     case R_PPC64_TPREL16_LO:
613     case R_PPC64_TPREL16_HI:
614     case R_PPC64_TPREL16_HA:
615       if (conflict != NULL
616           && (conflict->reloc_class != RTYPE_CLASS_TLS
617               || conflict->lookup.tls == NULL))
618         {
619           error (0, 0, "%s: TLS reloc not resolving to STT_TLS symbol",
620                  dso->filename);
621           return 1;
622         }
623       tls = conflict ? conflict->lookup.tls : info->curtls;
624       r_type = R_PPC64_ADDR16;
625       switch (GELF_R_TYPE (rela->r_info))
626         {
627         case R_PPC64_DTPMOD64:
628           r_type = R_PPC64_ADDR64;
629           value = tls->modid;
630           break;
631         case R_PPC64_DTPREL64:
632           r_type = R_PPC64_ADDR64;
633           value -= 0x8000;
634           break;
635         case R_PPC64_DTPREL16:
636         case R_PPC64_DTPREL16_LO:
637           value -= 0x8000;
638           break;
639         case R_PPC64_DTPREL16_HI:
640           value = (value - 0x8000) >> 16;
641           break;
642         case R_PPC64_DTPREL16_HA:
643           value >>= 16;
644           break;
645         case R_PPC64_TPREL64:
646           r_type = R_PPC64_ADDR64;
647           value += tls->offset - 0x7000;
648           break;
649         case R_PPC64_TPREL16:
650         case R_PPC64_TPREL16_LO:
651           value += tls->offset - 0x7000;
652           break;
653         case R_PPC64_TPREL16_HI:
654           value = (value + tls->offset - 0x7000) >> 16;
655           break;
656         case R_PPC64_TPREL16_HA:
657           value = (value + tls->offset - 0x7000 + 0x8000) >> 16;
658           break;
659         }
660       if (r_type == R_PPC64_ADDR16)
661         value = ((value & 0xffff) ^ 0x8000) - 0x8000;
662       break;
663     default:
664       error (0, 0, "%s: Unknown PowerPC64 relocation type %d", dso->filename,
665              r_type);
666       return 1;
667     }
668   if (conflict != NULL && conflict->ifunc
669       && r_type != R_PPC64_IRELATIVE && r_type != R_PPC64_JMP_IREL)
670     {
671       error (0, 0, "%s: relocation %d against IFUNC symbol", dso->filename,
672              (int) GELF_R_TYPE (rela->r_info));
673       return 1;
674     }
675   ret->r_info = GELF_R_INFO (0, r_type);
676   ret->r_addend = value;
677   return 0;
678 }
679
680 static int
681 ppc64_rel_to_rela (DSO *dso, GElf_Rel *rel, GElf_Rela *rela)
682 {
683   error (0, 0, "%s: PowerPC64 doesn't support REL relocs", dso->filename);
684   return 1;
685 }
686
687 static int
688 ppc64_need_rel_to_rela (DSO *dso, int first, int last)
689 {
690   return 0;
691 }
692
693 static int
694 ppc64_undo_prelink_rela (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr)
695 {
696   switch (GELF_R_TYPE (rela->r_info))
697     {
698     case R_PPC64_NONE:
699       return 0;
700     case R_PPC64_JMP_SLOT:
701       /* .plt section will become SHT_NOBITS.  */
702       return 0;
703     case R_PPC64_JMP_IREL:
704       /* .iplt section will become SHT_NOBITS.  */
705       return 0;
706     case R_PPC64_RELATIVE:
707     case R_PPC64_ADDR64:
708     case R_PPC64_IRELATIVE:
709       write_be64 (dso, rela->r_offset, rela->r_addend);
710       break;
711     case R_PPC64_GLOB_DAT:
712     case R_PPC64_UADDR64:
713     case R_PPC64_DTPREL64:
714     case R_PPC64_TPREL64:
715     case R_PPC64_DTPMOD64:
716     case R_PPC64_REL64:
717       write_be64 (dso, rela->r_offset, 0);
718       break;
719     case R_PPC64_ADDR32:
720     case R_PPC64_UADDR32:
721     case R_PPC64_REL32:
722       write_be32 (dso, rela->r_offset, 0);
723       break;
724     case R_PPC64_ADDR16_HA:
725     case R_PPC64_DTPREL16_HA:
726     case R_PPC64_TPREL16_HA:
727     case R_PPC64_ADDR16_HI:
728     case R_PPC64_DTPREL16_HI:
729     case R_PPC64_TPREL16_HI:
730     case R_PPC64_ADDR16:
731     case R_PPC64_UADDR16:
732     case R_PPC64_ADDR16_LO:
733     case R_PPC64_DTPREL16:
734     case R_PPC64_TPREL16:
735     case R_PPC64_DTPREL16_LO:
736     case R_PPC64_TPREL16_LO:
737     case R_PPC64_ADDR16_HIGHERA:
738     case R_PPC64_ADDR16_HIGHER:
739     case R_PPC64_ADDR16_HIGHESTA:
740     case R_PPC64_ADDR16_HIGHEST:
741     case R_PPC64_ADDR16_LO_DS:
742     case R_PPC64_ADDR16_DS:
743       write_be16 (dso, rela->r_offset, 0);
744       break;
745     case R_PPC64_ADDR24:
746     case R_PPC64_REL24:
747       write_be32 (dso, rela->r_offset,
748                   read_ube32 (dso, rela->r_offset) & 0xfc000003);
749       break;
750     case R_PPC64_ADDR14:
751       write_be32 (dso, rela->r_offset,
752                   read_ube32 (dso, rela->r_offset) & 0xffff0003);
753       break;
754     case R_PPC64_ADDR14_BRTAKEN:
755     case R_PPC64_ADDR14_BRNTAKEN:
756       write_be32 (dso, rela->r_offset,
757                   read_ube32 (dso, rela->r_offset) & 0xffdf0003);
758       break;
759     case R_PPC64_COPY:
760       if (dso->ehdr.e_type == ET_EXEC)
761         /* COPY relocs are handled specially in generic code.  */
762         return 0;
763       error (0, 0, "%s: R_PPC64_COPY reloc in shared library?", dso->filename);
764       return 1;
765     default:
766       error (0, 0, "%s: Unknown ppc relocation type %d", dso->filename,
767              (int) GELF_R_TYPE (rela->r_info));
768       return 1;
769     }
770   return 0;
771 }
772
773 static int
774 ppc64_reloc_size (int reloc_type)
775 {
776   switch (reloc_type)
777     {
778     case R_PPC64_ADDR16:
779     case R_PPC64_UADDR16:
780     case R_PPC64_ADDR16_LO:
781     case R_PPC64_ADDR16_HA:
782     case R_PPC64_ADDR16_HI:
783     case R_PPC64_ADDR16_LO_DS:
784     case R_PPC64_ADDR16_DS:
785     case R_PPC64_ADDR16_HIGHER:
786     case R_PPC64_ADDR16_HIGHERA:
787     case R_PPC64_ADDR16_HIGHEST:
788     case R_PPC64_ADDR16_HIGHESTA:
789     case R_PPC64_DTPREL16:
790     case R_PPC64_DTPREL16_LO:
791     case R_PPC64_DTPREL16_HI:
792     case R_PPC64_DTPREL16_HA:
793     case R_PPC64_TPREL16:
794     case R_PPC64_TPREL16_LO:
795     case R_PPC64_TPREL16_HI:
796     case R_PPC64_TPREL16_HA:
797       return 2;
798     case R_PPC64_GLOB_DAT:
799     case R_PPC64_ADDR64:
800     case R_PPC64_UADDR64:
801     case R_PPC64_REL64:
802     case R_PPC64_DTPMOD64:
803     case R_PPC64_DTPREL64:
804     case R_PPC64_TPREL64:
805     case R_PPC64_IRELATIVE:
806       return 8;
807     default:
808       break;
809     }
810   return 4;
811 }
812
813 static int
814 ppc64_reloc_class (int reloc_type)
815 {
816   switch (reloc_type)
817     {
818     case R_PPC64_COPY: return RTYPE_CLASS_COPY | RTYPE_CLASS_PLT;
819     default:
820       if (reloc_type >= R_PPC64_DTPMOD64
821           && reloc_type <= R_PPC64_TPREL16_HIGHESTA)
822         return RTYPE_CLASS_TLS;
823       return RTYPE_CLASS_PLT;
824     }
825 }
826
827 static int
828 ppc64_read_opd (DSO *dso, struct prelink_entry *ent)
829 {
830   int opd;
831   GElf_Addr n, s;
832
833   free (ent->opd);
834   ent->opd = NULL;
835   for (opd = 1; opd < dso->ehdr.e_shnum; ++opd)
836     if (dso->shdr[opd].sh_type == SHT_PROGBITS
837         && ! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
838                              dso->shdr[opd].sh_name), ".opd"))
839       break;
840   if (opd == dso->ehdr.e_shnum)
841     return 0;
842   ent->opd = malloc (sizeof (struct opd_lib) + dso->shdr[opd].sh_size);
843   /* The error will happen only when we'll need the opd.  */
844   if (ent->opd == NULL)
845     return 0;
846   s = dso->shdr[opd].sh_addr;
847   for (n = 0; n < dso->shdr[opd].sh_size / 8; ++n, s += 8)
848     ent->opd->table[n] = read_ube64 (dso, s);
849   ent->opd->start = dso->shdr[opd].sh_addr;
850   ent->opd->size = dso->shdr[opd].sh_size;
851   return 0;
852 }
853
854 static int
855 ppc64_free_opd (struct prelink_entry *ent)
856 {
857   free (ent->opd);
858   ent->opd = NULL;
859   return 0;
860 }
861
862 PL_ARCH = {
863   .name = "PowerPC",
864   .class = ELFCLASS64,
865   .machine = EM_PPC64,
866   .alternate_machine = { EM_NONE },
867   .R_JMP_SLOT = R_PPC64_JMP_SLOT,
868   .R_COPY = R_PPC64_COPY,
869   .R_RELATIVE = R_PPC64_RELATIVE,
870   .rtype_class_valid = RTYPE_CLASS_PLT,
871   .dynamic_linker = "/lib64/ld64.so.1",
872   .adjust_section = ppc64_adjust_section,
873   .adjust_dyn = ppc64_adjust_dyn,
874   .adjust_rel = ppc64_adjust_rel,
875   .adjust_rela = ppc64_adjust_rela,
876   .prelink_rel = ppc64_prelink_rel,
877   .prelink_rela = ppc64_prelink_rela,
878   .prelink_conflict_rel = ppc64_prelink_conflict_rel,
879   .prelink_conflict_rela = ppc64_prelink_conflict_rela,
880   .apply_conflict_rela = ppc64_apply_conflict_rela,
881   .apply_rel = ppc64_apply_rel,
882   .apply_rela = ppc64_apply_rela,
883   .rel_to_rela = ppc64_rel_to_rela,
884   .need_rel_to_rela = ppc64_need_rel_to_rela,
885   .reloc_size = ppc64_reloc_size,
886   .reloc_class = ppc64_reloc_class,
887   .read_opd = ppc64_read_opd,
888   .free_opd = ppc64_free_opd,
889   .max_reloc_size = 8,
890   .undo_prelink_rela = ppc64_undo_prelink_rela,
891   /* Although TASK_UNMAPPED_BASE is 0x8000000000, we leave some
892      area so that mmap of /etc/ld.so.cache and ld.so's malloc
893      does not take some library's VA slot.
894      Also, if this guard area isn't too small, typically
895      even dlopened libraries will get the slots they desire.  */
896   .mmap_base = 0x8001000000LL,
897   .mmap_end =  0x8100000000LL,
898   .max_page_size = 0x10000,
899   .page_size = 0x1000
900 };