Initialize Tizen 2.3
[external/prelink.git] / src / arch-arm.c
1 /* Copyright (C) 2001, 2002, 2004, 2009 Red Hat, Inc.
2    Written by Jakub Jelinek <jakub@redhat.com>, 2001.
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
31 static int
32 arm_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
33                 GElf_Addr adjust)
34 {
35   if (dyn->d_tag == DT_PLTGOT)
36     {
37       int sec = addr_to_sec (dso, dyn->d_un.d_ptr);
38       Elf32_Addr data;
39
40       if (sec == -1)
41         return 0;
42
43       data = read_une32 (dso, dyn->d_un.d_ptr);
44       /* If .got.plt[0] points to _DYNAMIC, it needs to be adjusted.  */
45       if (data == dso->shdr[n].sh_addr && data >= start)
46         write_ne32 (dso, dyn->d_un.d_ptr, data + adjust);
47
48       data = read_une32 (dso, dyn->d_un.d_ptr + 4);
49       /* If .got.plt[1] points to .plt, it needs to be adjusted.  */
50       if (data && data >= start)
51         {
52           int i;
53
54           for (i = 1; i < dso->ehdr.e_shnum; i++)
55             if (data == dso->shdr[i].sh_addr
56                 && dso->shdr[i].sh_type == SHT_PROGBITS
57                 && strcmp (strptr (dso, dso->ehdr.e_shstrndx,
58                                    dso->shdr[i].sh_name), ".plt") == 0)
59               {
60                 write_ne32 (dso, dyn->d_un.d_ptr + 4, data + adjust);
61                 break;
62               }
63         }
64     }
65   return 0;
66 }
67
68 static int
69 arm_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
70                 GElf_Addr adjust)
71 {
72   Elf32_Addr data;
73   switch (GELF_R_TYPE (rel->r_info))
74     {
75     case R_ARM_RELATIVE:
76     case R_ARM_JUMP_SLOT:
77       data = read_une32 (dso, rel->r_offset);
78       if (data >= start)
79         write_ne32 (dso, rel->r_offset, data + adjust);
80       break;
81     }
82   return 0;
83 }
84
85 static int
86 arm_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
87                  GElf_Addr adjust)
88 {
89   Elf32_Addr data;
90
91   switch (GELF_R_TYPE (rela->r_info))
92     {
93     case R_ARM_RELATIVE:
94       if ((Elf32_Addr) rela->r_addend >= start)
95         {
96           rela->r_addend += (Elf32_Sword) adjust;
97           /* Write it to the memory location as well.
98              Not necessary, but we can do it.  */
99           write_ne32 (dso, rela->r_offset, rela->r_addend);
100         }
101       break;
102     case R_ARM_JUMP_SLOT:
103       data = read_une32 (dso, rela->r_offset);
104       if (data >= start)
105         write_ne32 (dso, rela->r_offset, data + adjust);
106       break;
107       break;
108     }
109   return 0;
110 }
111
112 static int
113 arm_prelink_rel (struct prelink_info *info, GElf_Rel *rel, GElf_Addr reladdr)
114 {
115   DSO *dso;
116   GElf_Addr value;
117
118   if (GELF_R_TYPE (rel->r_info) == R_ARM_RELATIVE
119       || GELF_R_TYPE (rel->r_info) == R_ARM_NONE)
120     /* Fast path: nothing to do.  */
121     return 0;
122   dso = info->dso;
123   value = info->resolve (info, GELF_R_SYM (rel->r_info),
124                          GELF_R_TYPE (rel->r_info));
125   switch (GELF_R_TYPE (rel->r_info))
126     {
127     case R_ARM_GLOB_DAT:
128     case R_ARM_JUMP_SLOT:
129       write_ne32 (dso, rel->r_offset, value);
130       break;
131     case R_ARM_ABS32:
132       {
133         if (read_une32 (dso, rel->r_offset))
134           {
135             error (0, 0, "%s: R_ARM_ABS32 relocs with non-zero addend should not be present in prelinked REL sections",
136                    dso->filename);
137             return 1;
138           }
139         rel->r_info = GELF_R_INFO (GELF_R_SYM (rel->r_info), R_ARM_GLOB_DAT);
140         write_ne32 (dso, rel->r_offset, value);
141         /* Tell prelink_rel routine *rel has changed.  */
142         return 2;
143       }
144     case R_ARM_PC24:
145       error (0, 0, "%s: R_ARM_PC24 relocs with non-zero addend should not be present in prelinked REL sections",
146              dso->filename);
147       return 1;
148     case R_ARM_COPY:
149       if (dso->ehdr.e_type == ET_EXEC)
150         /* COPY relocs are handled specially in generic code.  */
151         return 0;
152       error (0, 0, "%s: R_ARM_COPY reloc in shared library?", dso->filename);
153       return 1;
154     case R_ARM_TLS_DTPOFF32:
155       write_ne32 (dso, rel->r_offset, value);
156       break;
157     /* DTPMOD32 and TPOFF32 is impossible to predict in shared libraries
158        unless prelink sets the rules.  */
159     case R_ARM_TLS_DTPMOD32:
160       if (dso->ehdr.e_type == ET_EXEC)
161         {
162           error (0, 0, "%s: R_ARM_TLS_DTPMOD32 reloc in executable?",
163                  dso->filename);
164           return 1;
165         }
166       break;
167     case R_ARM_TLS_TPOFF32:
168       if (dso->ehdr.e_type == ET_EXEC)
169         error (0, 0, "%s: R_ARM_TLS_TPOFF32 relocs should not be present in "
170                "prelinked ET_EXEC REL sections",
171                dso->filename);
172       break;
173     default:
174       error (0, 0, "%s: Unknown arm relocation type %d", dso->filename,
175              (int) GELF_R_TYPE (rel->r_info));
176       return 1;
177     }
178   return 0;
179 }
180
181 static int
182 arm_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
183                   GElf_Addr relaaddr)
184 {
185   DSO *dso;
186   GElf_Addr value;
187   Elf32_Sword val;
188
189   if (GELF_R_TYPE (rela->r_info) == R_ARM_RELATIVE
190       || GELF_R_TYPE (rela->r_info) == R_ARM_NONE)
191     /* Fast path: nothing to do.  */
192     return 0;
193   dso = info->dso;
194   value = info->resolve (info, GELF_R_SYM (rela->r_info),
195                          GELF_R_TYPE (rela->r_info));
196   switch (GELF_R_TYPE (rela->r_info))
197     {
198     case R_ARM_GLOB_DAT:
199     case R_ARM_JUMP_SLOT:
200       write_ne32 (dso, rela->r_offset, value + rela->r_addend);
201       break;
202     case R_ARM_ABS32:
203       write_ne32 (dso, rela->r_offset, value + rela->r_addend);
204       break;
205     case R_ARM_PC24:
206       val = value + rela->r_addend - rela->r_offset;
207       val >>= 2;
208       if ((Elf32_Word) val + 0x800000 >= 0x1000000)
209         {
210           error (0, 0, "%s: R_ARM_PC24 overflow", dso->filename);
211           return 1;
212         }
213       val &= 0xffffff;
214       write_ne32 (dso, rela->r_offset,
215                   (read_une32 (dso, rela->r_offset) & 0xff000000) | val);
216       break;
217     case R_ARM_COPY:
218       if (dso->ehdr.e_type == ET_EXEC)
219         /* COPY relocs are handled specially in generic code.  */
220         return 0;
221       error (0, 0, "%s: R_ARM_COPY reloc in shared library?", dso->filename);
222       return 1;
223     case R_ARM_TLS_DTPOFF32:
224       write_ne32 (dso, rela->r_offset, value + rela->r_addend);
225       break;
226     /* DTPMOD32 and TPOFF32 is impossible to predict in shared libraries
227        unless prelink sets the rules.  */
228     case R_ARM_TLS_DTPMOD32:
229       if (dso->ehdr.e_type == ET_EXEC)
230         {
231           error (0, 0, "%s: R_ARM_TLS_DTPMOD32 reloc in executable?",
232                  dso->filename);
233           return 1;
234         }
235       break;
236     case R_ARM_TLS_TPOFF32:
237       if (dso->ehdr.e_type == ET_EXEC && info->resolvetls)
238         write_ne32 (dso, rela->r_offset,
239                     value + rela->r_addend + info->resolvetls->offset);
240       break;
241     default:
242       error (0, 0, "%s: Unknown arm relocation type %d", dso->filename,
243              (int) GELF_R_TYPE (rela->r_info));
244       return 1;
245     }
246   return 0;
247 }
248
249 static int
250 arm_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
251                          char *buf, GElf_Addr dest_addr)
252 {
253   switch (GELF_R_TYPE (rela->r_info))
254     {
255     case R_ARM_GLOB_DAT:
256     case R_ARM_JUMP_SLOT:
257     case R_ARM_ABS32:
258       buf_write_ne32 (info->dso, buf, rela->r_addend);
259       break;
260     default:
261       abort ();
262     }
263   return 0;
264 }
265
266 static int
267 arm_apply_rel (struct prelink_info *info, GElf_Rel *rel, char *buf)
268 {
269   GElf_Addr value;
270   Elf32_Sword val;
271
272   value = info->resolve (info, GELF_R_SYM (rel->r_info),
273                          GELF_R_TYPE (rel->r_info));
274   switch (GELF_R_TYPE (rel->r_info))
275     {
276     case R_ARM_NONE:
277       break;
278     case R_ARM_GLOB_DAT:
279     case R_ARM_JUMP_SLOT:
280       buf_write_ne32 (info->dso, buf, value);
281       break;
282     case R_ARM_ABS32:
283       buf_write_ne32 (info->dso, buf, value + read_une32 (info->dso, rel->r_offset));
284       break;
285     case R_ARM_PC24:
286       val = value + rel->r_offset;
287       value = read_une32 (info->dso, rel->r_offset) << 8;
288       value = ((Elf32_Sword) value) >> 6;
289       val += value;
290       val >>= 2;
291       if ((Elf32_Word) val + 0x800000 >= 0x1000000)
292         {
293           error (0, 0, "%s: R_ARM_PC24 overflow", info->dso->filename);
294           return 1;
295         }
296       val &= 0xffffff;
297       buf_write_ne32 (info->dso, buf, (buf_read_une32 (info->dso, buf) & 0xff000000) | val);
298       break;
299     case R_ARM_COPY:
300       abort ();
301     case R_ARM_RELATIVE:
302       error (0, 0, "%s: R_ARM_RELATIVE in ET_EXEC object?", info->dso->filename);
303       return 1;
304     default:
305       return 1;
306     }
307   return 0;
308 }
309
310 static int
311 arm_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
312 {
313   GElf_Addr value;
314   Elf32_Sword val;
315
316   value = info->resolve (info, GELF_R_SYM (rela->r_info),
317                          GELF_R_TYPE (rela->r_info));
318   switch (GELF_R_TYPE (rela->r_info))
319     {
320     case R_ARM_NONE:
321       break;
322     case R_ARM_GLOB_DAT:
323     case R_ARM_JUMP_SLOT:
324     case R_ARM_ABS32:
325       buf_write_ne32 (info->dso, buf, value + rela->r_addend);
326       break;
327     case R_ARM_PC24:
328       val = value + rela->r_addend - rela->r_offset;
329       val >>= 2;
330       if ((Elf32_Word) val + 0x800000 >= 0x1000000)
331         {
332           error (0, 0, "%s: R_ARM_PC24 overflow", info->dso->filename);
333           return 1;
334         }
335       val &= 0xffffff;
336       buf_write_ne32 (info->dso, buf, (buf_read_une32 (info->dso, buf) & 0xff000000) | val);
337       break;
338     case R_ARM_COPY:
339       abort ();
340     case R_ARM_RELATIVE:
341       error (0, 0, "%s: R_ARM_RELATIVE in ET_EXEC object?", info->dso->filename);
342       return 1;
343     default:
344       return 1;
345     }
346   return 0;
347 }
348
349 static int
350 arm_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
351                           GElf_Addr reladdr)
352 {
353   GElf_Addr value;
354   struct prelink_conflict *conflict;
355   struct prelink_tls *tls;
356   GElf_Rela *ret;
357
358   if (GELF_R_TYPE (rel->r_info) == R_ARM_RELATIVE
359       || GELF_R_TYPE (rel->r_info) == R_ARM_NONE
360       || info->dso == dso)
361     /* Fast path: nothing to do.  */
362     return 0;
363   conflict = prelink_conflict (info, GELF_R_SYM (rel->r_info),
364                                GELF_R_TYPE (rel->r_info));
365   if (conflict == NULL)
366     {
367       if (info->curtls == NULL)
368         return 0;
369
370       switch (GELF_R_TYPE (rel->r_info))
371         {
372         /* Even local DTPMOD and TPOFF relocs need conflicts.  */
373         case R_ARM_TLS_DTPMOD32:
374         case R_ARM_TLS_TPOFF32:
375           break;
376
377         default:
378           return 0;
379         }
380       value = 0;
381     }
382   else if (conflict->ifunc)
383     {
384       error (0, 0, "%s: STT_GNU_IFUNC not handled on ARM yet",
385              dso->filename);
386       return 1;
387     }
388   else
389     {
390       /* DTPOFF32 wants to see only real conflicts, not lookups
391          with reloc_class RTYPE_CLASS_TLS.  */
392       if (GELF_R_TYPE (rel->r_info) == R_ARM_TLS_DTPOFF32
393           && conflict->lookup.tls == conflict->conflict.tls
394           && conflict->lookupval == conflict->conflictval)
395         return 0;
396
397       value = conflict_lookup_value (conflict);
398     }
399
400   ret = prelink_conflict_add_rela (info);
401   if (ret == NULL)
402     return 1;
403   ret->r_offset = rel->r_offset;
404   ret->r_info = GELF_R_INFO (0, GELF_R_TYPE (rel->r_info));
405   switch (GELF_R_TYPE (rel->r_info))
406     {
407     case R_ARM_GLOB_DAT:
408     case R_ARM_JUMP_SLOT:
409       ret->r_addend = (Elf32_Sword) value;
410       break;
411     case R_ARM_ABS32:
412     case R_ARM_PC24:
413       error (0, 0, "%s: R_ARM_%s relocs should not be present in prelinked REL sections",
414              dso->filename, GELF_R_TYPE (rel->r_info) == R_ARM_ABS32 ? "ABS32" : "PC24");
415       return 1;
416     case R_ARM_COPY:
417       error (0, 0, "R_ARM_COPY should not be present in shared libraries");
418       return 1;
419     case R_ARM_TLS_DTPMOD32:
420     case R_ARM_TLS_DTPOFF32:
421     case R_ARM_TLS_TPOFF32:
422       if (conflict != NULL
423           && (conflict->reloc_class != RTYPE_CLASS_TLS
424               || conflict->lookup.tls == NULL))
425         {
426           error (0, 0, "%s: TLS reloc not resolving to STT_TLS symbol",
427                  dso->filename);
428           return 1;
429         }
430       tls = conflict ? conflict->lookup.tls : info->curtls;
431       ret->r_info = GELF_R_INFO (0, R_ARM_ABS32);
432       switch (GELF_R_TYPE (rel->r_info))
433         {
434         case R_ARM_TLS_DTPMOD32:
435           ret->r_addend = tls->modid;
436           break;
437         case R_ARM_TLS_DTPOFF32:
438           ret->r_addend = value;
439           break;
440         case R_ARM_TLS_TPOFF32:
441           ret->r_addend = (value + read_une32 (dso, rel->r_offset)
442                            + tls->offset);
443           break;
444         }
445       break;
446     default:
447       error (0, 0, "%s: Unknown arm relocation type %d", dso->filename,
448              (int) GELF_R_TYPE (rel->r_info));
449       return 1;
450     }
451   return 0;
452 }
453
454 static int
455 arm_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
456                            GElf_Rela *rela, GElf_Addr relaaddr)
457 {
458   GElf_Addr value;
459   struct prelink_conflict *conflict;
460   struct prelink_tls *tls;
461   GElf_Rela *ret;
462   Elf32_Sword val;
463
464   if (GELF_R_TYPE (rela->r_info) == R_ARM_RELATIVE
465       || GELF_R_TYPE (rela->r_info) == R_ARM_NONE
466       || info->dso == dso)
467     /* Fast path: nothing to do.  */
468     return 0;
469   conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
470                                GELF_R_TYPE (rela->r_info));
471
472   if (conflict == NULL)
473     {
474       if (info->curtls == NULL)
475         return 0;
476
477       switch (GELF_R_TYPE (rela->r_info))
478         {
479         /* Even local DTPMOD and TPOFF relocs need conflicts.  */
480         case R_ARM_TLS_DTPMOD32:
481         case R_ARM_TLS_TPOFF32:
482           break;
483
484         default:
485           return 0;
486         }
487       value = 0;
488     }
489   else if (conflict->ifunc)
490     {
491       error (0, 0, "%s: STT_GNU_IFUNC not handled on ARM yet",
492              dso->filename);
493       return 1;
494     }
495   else
496     {
497       /* DTPOFF32 wants to see only real conflicts, not lookups
498          with reloc_class RTYPE_CLASS_TLS.  */
499       if (GELF_R_TYPE (rela->r_info) == R_ARM_TLS_DTPOFF32
500           && conflict->lookup.tls == conflict->conflict.tls
501           && conflict->lookupval == conflict->conflictval)
502         return 0;
503
504       value = conflict_lookup_value (conflict);
505     }
506
507   ret = prelink_conflict_add_rela (info);
508   if (ret == NULL)
509     return 1;
510   ret->r_offset = rela->r_offset;
511   ret->r_info = GELF_R_INFO (0, GELF_R_TYPE (rela->r_info));
512   switch (GELF_R_TYPE (rela->r_info))
513     {
514     case R_ARM_GLOB_DAT:
515     case R_ARM_JUMP_SLOT:
516     case R_ARM_ABS32:
517       ret->r_addend = (Elf32_Sword) (value + rela->r_addend);
518       break;
519     case R_ARM_PC24:
520       val = value + rela->r_addend - rela->r_offset;
521       val >>= 2;
522       if ((Elf32_Word) val + 0x800000 >= 0x1000000)
523         {
524           error (0, 0, "%s: R_ARM_PC24 overflow", dso->filename);
525           return 1;
526         }
527       value = read_une32 (dso, rela->r_offset) & 0xff000000;
528       ret->r_addend = (Elf32_Sword) (value | (val & 0xffffff));
529       ret->r_info = GELF_R_INFO (0, R_ARM_ABS32);
530       break;
531     case R_ARM_COPY:
532       error (0, 0, "R_ARM_COPY should not be present in shared libraries");
533       return 1;
534     case R_ARM_TLS_DTPMOD32:
535     case R_ARM_TLS_DTPOFF32:
536     case R_ARM_TLS_TPOFF32:
537       if (conflict != NULL
538           && (conflict->reloc_class != RTYPE_CLASS_TLS
539               || conflict->lookup.tls == NULL))
540         {
541           error (0, 0, "%s: TLS reloc not resolving to STT_TLS symbol",
542                  dso->filename);
543           return 1;
544         }
545       tls = conflict ? conflict->lookup.tls : info->curtls;
546       ret->r_info = GELF_R_INFO (0, R_ARM_ABS32);
547       switch (GELF_R_TYPE (rela->r_info))
548         {
549         case R_ARM_TLS_DTPMOD32:
550           ret->r_addend = tls->modid;
551           break;
552         case R_ARM_TLS_DTPOFF32:
553           ret->r_addend = value;
554           break;
555         case R_ARM_TLS_TPOFF32:
556           ret->r_addend = value + rela->r_addend + tls->offset;
557           break;
558         }
559       break;
560     default:
561       error (0, 0, "%s: Unknown arm relocation type %d", dso->filename,
562              (int) GELF_R_TYPE (rela->r_info));
563       return 1;
564     }
565   return 0;
566 }
567
568 static int
569 arm_rel_to_rela (DSO *dso, GElf_Rel *rel, GElf_Rela *rela)
570 {
571   rela->r_offset = rel->r_offset;
572   rela->r_info = rel->r_info;
573   switch (GELF_R_TYPE (rel->r_info))
574     {
575     case R_ARM_JUMP_SLOT:
576       /* We should be never converting .rel.plt into .rela.plt.  */
577       abort ();
578     case R_ARM_RELATIVE:
579     case R_ARM_ABS32:
580     case R_ARM_TLS_TPOFF32:
581       rela->r_addend = (Elf32_Sword) read_une32 (dso, rel->r_offset);
582       break;
583     case R_ARM_PC24:
584       rela->r_addend = read_une32 (dso, rel->r_offset) << 8;
585       rela->r_addend = ((Elf32_Sword) rela->r_addend) >> 6;
586       break;
587     case R_ARM_COPY:
588     case R_ARM_GLOB_DAT:
589     case R_ARM_TLS_DTPMOD32:
590     case R_ARM_TLS_DTPOFF32:
591       rela->r_addend = 0;
592       break;
593     }
594   return 0;
595 }
596
597 static int
598 arm_rela_to_rel (DSO *dso, GElf_Rela *rela, GElf_Rel *rel)
599 {
600   rel->r_offset = rela->r_offset;
601   rel->r_info = rela->r_info;
602   switch (GELF_R_TYPE (rel->r_info))
603     {
604     case R_ARM_JUMP_SLOT:
605       /* We should be never converting .rel.plt into .rela.plt
606          and thus never .rela.plt back to .rel.plt.  */
607       abort ();
608     case R_ARM_RELATIVE:
609     case R_ARM_ABS32:
610     case R_ARM_TLS_TPOFF32:
611       write_ne32 (dso, rela->r_offset, rela->r_addend);
612       break;
613     case R_ARM_PC24:
614       write_ne32 (dso, rela->r_offset,
615                   (read_une32 (dso, rela->r_offset) & 0xff000000)
616                   | ((rela->r_addend >> 2) & 0xffffff));
617       break;
618     case R_ARM_GLOB_DAT:
619     case R_ARM_TLS_DTPMOD32:
620     case R_ARM_TLS_DTPOFF32:
621       write_ne32 (dso, rela->r_offset, 0);
622       break;
623     }
624   return 0;
625 }
626
627 static int
628 arm_need_rel_to_rela (DSO *dso, int first, int last)
629 {
630   Elf_Data *data;
631   Elf_Scn *scn;
632   Elf32_Rel *rel, *relend;
633   unsigned int val;
634
635   while (first <= last)
636     {
637       data = NULL;
638       scn = dso->scn[first++];
639       while ((data = elf_getdata (scn, data)) != NULL)
640         {
641           rel = (Elf32_Rel *) data->d_buf;
642           relend = rel + data->d_size / sizeof (Elf32_Rel);
643           for (; rel < relend; rel++)
644             switch (ELF32_R_TYPE (rel->r_info))
645               {
646               case R_ARM_ABS32:
647                 val = read_une32 (dso, rel->r_offset);
648                 /* R_ARM_ABS32 with addend 0 can be converted
649                    to R_ARM_GLOB_DAT and we don't have to convert
650                    to RELA because of that.  */
651                 if (val == 0)
652                   break;
653                 /* FALLTHROUGH */
654               case R_ARM_PC24:
655                 return 1;
656               case R_ARM_TLS_TPOFF32:
657                 /* In shared libraries TPOFF is changed always into
658                    conflicts, for executables we need to preserve
659                    original addend.  */
660                 if (dso->ehdr.e_type == ET_EXEC)
661                   return 1;
662
663                 break;
664               }
665         }
666     }
667   return 0;
668 }
669
670 static int
671 arm_arch_prelink (struct prelink_info *info)
672 {
673   DSO *dso;
674   int i;
675
676   dso = info->dso;
677   if (dso->info[DT_PLTGOT])
678     {
679       /* Write address of .plt into got[1].
680          .plt is what got[3] contains unless prelinking.  */
681       int sec = addr_to_sec (dso, dso->info[DT_PLTGOT]);
682       Elf32_Addr data;
683
684       if (sec == -1)
685         return 1;
686
687       for (i = 1; i < dso->ehdr.e_shnum; i++)
688         if (dso->shdr[i].sh_type == SHT_PROGBITS
689             && ! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
690                                  dso->shdr[i].sh_name),
691                          ".plt"))
692         break;
693
694       if (i == dso->ehdr.e_shnum)
695         return 0;
696       data = dso->shdr[i].sh_addr;
697       write_ne32 (dso, dso->info[DT_PLTGOT] + 4, data);
698     }
699
700   return 0;
701 }
702
703 static int
704 arm_arch_undo_prelink (DSO *dso)
705 {
706   int i;
707
708   if (dso->info[DT_PLTGOT])
709     {
710       /* Clear got[1] if it contains address of .plt.  */
711       int sec = addr_to_sec (dso, dso->info[DT_PLTGOT]);
712       Elf32_Addr data;
713
714       if (sec == -1)
715         return 1;
716
717       for (i = 1; i < dso->ehdr.e_shnum; i++)
718         if (dso->shdr[i].sh_type == SHT_PROGBITS
719             && ! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
720                                  dso->shdr[i].sh_name),
721                          ".plt"))
722         break;
723
724       if (i == dso->ehdr.e_shnum)
725         return 0;
726       data = read_une32 (dso, dso->info[DT_PLTGOT] + 4);
727       if (data == dso->shdr[i].sh_addr)
728         write_ne32 (dso, dso->info[DT_PLTGOT] + 4, 0);
729     }
730
731   return 0;
732 }
733
734 static int
735 arm_undo_prelink_rel (DSO *dso, GElf_Rel *rel, GElf_Addr reladdr)
736 {
737   int sec;
738   const char *name;
739
740   switch (GELF_R_TYPE (rel->r_info))
741     {
742     case R_ARM_RELATIVE:
743     case R_ARM_NONE:
744       break;
745     case R_ARM_JUMP_SLOT:
746       sec = addr_to_sec (dso, rel->r_offset);
747       name = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[sec].sh_name);
748       if (sec == -1 || (strcmp (name, ".got") && strcmp (name, ".got.plt")))
749         {
750           error (0, 0, "%s: R_ARM_JMP_SLOT not pointing into .got section",
751                  dso->filename);
752           return 1;
753         }
754       else
755         {
756           Elf32_Addr data = read_une32 (dso, dso->shdr[sec].sh_addr + 4);
757
758           assert (rel->r_offset >= dso->shdr[sec].sh_addr + 12);
759           assert (((rel->r_offset - dso->shdr[sec].sh_addr) & 3) == 0);
760           write_ne32 (dso, rel->r_offset, data);
761         }
762       break;
763     case R_ARM_GLOB_DAT:
764       sec = addr_to_sec (dso, rel->r_offset);
765
766       write_ne32 (dso, rel->r_offset, 0);
767       if (sec != -1)
768         {
769           if (strcmp (strptr (dso, dso->ehdr.e_shstrndx,
770                               dso->shdr[sec].sh_name),
771                       ".got"))
772             {
773               rel->r_info = GELF_R_INFO (GELF_R_SYM (rel->r_info), R_ARM_ABS32);
774               return 2;
775             }
776         }
777       break;
778     case R_ARM_ABS32:
779     case R_ARM_PC24:
780       error (0, 0, "%s: R_ARM_%s relocs should not be present in prelinked REL sections",
781              GELF_R_TYPE (rel->r_info) == R_ARM_ABS32 ? "ABS32" : "PC24",
782              dso->filename);
783       return 1;
784     case R_ARM_COPY:
785       if (dso->ehdr.e_type == ET_EXEC)
786         /* COPY relocs are handled specially in generic code.  */
787         return 0;
788       error (0, 0, "%s: R_ARM_COPY reloc in shared library?", dso->filename);
789       return 1;
790     case R_ARM_TLS_DTPMOD32:
791     case R_ARM_TLS_DTPOFF32:
792       write_ne32 (dso, rel->r_offset, 0);
793       break;
794     case R_ARM_TLS_TPOFF32:
795       break;
796     default:
797       error (0, 0, "%s: Unknown arm relocation type %d", dso->filename,
798              (int) GELF_R_TYPE (rel->r_info));
799       return 1;
800     }
801   return 0;
802 }
803
804 static int
805 arm_reloc_size (int reloc_type)
806 {
807   assert (reloc_type != R_ARM_COPY);
808   return 4;
809 }
810
811 static int
812 arm_reloc_class (int reloc_type)
813 {
814   switch (reloc_type)
815     {
816     case R_ARM_COPY: return RTYPE_CLASS_COPY;
817     case R_ARM_JUMP_SLOT: return RTYPE_CLASS_PLT;
818     case R_ARM_TLS_DTPMOD32:
819     case R_ARM_TLS_DTPOFF32:
820     case R_ARM_TLS_TPOFF32:
821       return RTYPE_CLASS_TLS;
822     default: return RTYPE_CLASS_VALID;
823     }
824 }
825
826 PL_ARCH = {
827   .name = "ARM",
828   .class = ELFCLASS32,
829   .machine = EM_ARM,
830   .alternate_machine = { EM_NONE },
831   .R_JMP_SLOT = R_ARM_JUMP_SLOT,
832   .R_COPY = R_ARM_COPY,
833   .R_RELATIVE = R_ARM_RELATIVE,
834   .rtype_class_valid = RTYPE_CLASS_VALID,
835   .dynamic_linker = "/lib/ld-linux.so.2",
836   .adjust_dyn = arm_adjust_dyn,
837   .adjust_rel = arm_adjust_rel,
838   .adjust_rela = arm_adjust_rela,
839   .prelink_rel = arm_prelink_rel,
840   .prelink_rela = arm_prelink_rela,
841   .prelink_conflict_rel = arm_prelink_conflict_rel,
842   .prelink_conflict_rela = arm_prelink_conflict_rela,
843   .apply_conflict_rela = arm_apply_conflict_rela,
844   .apply_rel = arm_apply_rel,
845   .apply_rela = arm_apply_rela,
846   .rel_to_rela = arm_rel_to_rela,
847   .rela_to_rel = arm_rela_to_rel,
848   .need_rel_to_rela = arm_need_rel_to_rela,
849   .reloc_size = arm_reloc_size,
850   .reloc_class = arm_reloc_class,
851   .max_reloc_size = 4,
852   .arch_prelink = arm_arch_prelink,
853   .arch_undo_prelink = arm_arch_undo_prelink,
854   .undo_prelink_rel = arm_undo_prelink_rel,
855   /* Although TASK_UNMAPPED_BASE is 0x40000000, we leave some
856      area so that mmap of /etc/ld.so.cache and ld.so's malloc
857      does not take some library's VA slot.
858      Also, if this guard area isn't too small, typically
859      even dlopened libraries will get the slots they desire.  */
860   .mmap_base = 0x41000000,
861   .mmap_end =  0x50000000,
862   .max_page_size = 0x8000,
863   .page_size = 0x1000
864 };