* Makefile.am: Add support for elf32-arm.lo.
[deliverable/binutils-gdb.git] / bfd / elf32-arm.c
CommitLineData
efaa65c9
CM
1/* start-sanitize-armelf */
2/* 32-bit ELF support for ARM
3 Copyright 1993, 1995, 1998 Free Software Foundation, Inc.
4
5This file is part of BFD, the Binary File Descriptor library.
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2 of the License, or
10(at your option) any later version.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program; if not, write to the Free Software
19Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20
21#include "bfd.h"
22#include "sysdep.h"
23#include "libbfd.h"
24#include "elf-bfd.h"
25
26#include "elf/arm.h"
27
28static reloc_howto_type *elf32_arm_reloc_type_lookup
29 PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
30static void elf32_arm_info_to_howto
31 PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));
32
33#define USE_RELA
34#define TARGET_UNDERSCORE '_'
35
36static reloc_howto_type elf32_arm_howto_table[] =
37{
38 /* No relocation */
39 HOWTO (R_ARM_NONE, /* type */
40 0, /* rightshift */
41 0, /* size (0 = byte, 1 = short, 2 = long) */
42 0, /* bitsize */
43 false, /* pc_relative */
44 0, /* bitpos */
45 complain_overflow_dont, /* complain_on_overflow */
46 bfd_elf_generic_reloc, /* special_function */
47 "R_ARM_NONE", /* name */
48 false, /* partial_inplace */
49 0, /* src_mask */
50 0, /* dst_mask */
51 false), /* pcrel_offset */
52
53 HOWTO (R_ARM_PC24, /* type */
54 2, /* rightshift */
55 2, /* size (0 = byte, 1 = short, 2 = long) */
56 24, /* bitsize */
57 true, /* pc_relative */
58 0, /* bitpos */
59 complain_overflow_signed, /* complain_on_overflow */
60 bfd_elf_generic_reloc, /* special_function */
61 "R_ARM_PC24", /* name */
62 false, /* partial_inplace */
63 0x00ffffff, /* src_mask */
64 0x00ffffff, /* dst_mask */
65 true), /* pcrel_offset */
66
67 /* 32 bit absolute */
68 HOWTO (R_ARM_ABS32, /* type */
69 0, /* rightshift */
70 2, /* size (0 = byte, 1 = short, 2 = long) */
71 32, /* bitsize */
72 false, /* pc_relative */
73 0, /* bitpos */
74 complain_overflow_bitfield, /* complain_on_overflow */
75 bfd_elf_generic_reloc, /* special_function */
76 "R_ARM_ABS32", /* name */
77 false, /* partial_inplace */
78 0xffffffff, /* src_mask */
79 0xffffffff, /* dst_mask */
80 false), /* pcrel_offset */
81
82 /* standard 32bit pc-relative reloc */
83 HOWTO (R_ARM_REL32, /* type */
84 0, /* rightshift */
85 2, /* size (0 = byte, 1 = short, 2 = long) */
86 32, /* bitsize */
87 true, /* pc_relative */
88 0, /* bitpos */
89 complain_overflow_bitfield, /* complain_on_overflow */
90 bfd_elf_generic_reloc, /* special_function */
91 "R_ARM_REL32", /* name */
92 false, /* partial_inplace */
93 0xffffffff, /* src_mask */
94 0xffffffff, /* dst_mask */
95 true), /* pcrel_offset */
96
97 /* 8 bit absolute */
98 HOWTO (R_ARM_ABS8, /* type */
99 0, /* rightshift */
100 0, /* size (0 = byte, 1 = short, 2 = long) */
101 8, /* bitsize */
102 false, /* pc_relative */
103 0, /* bitpos */
104 complain_overflow_bitfield, /* complain_on_overflow */
105 bfd_elf_generic_reloc, /* special_function */
106 "R_ARM_ABS8", /* name */
107 false, /* partial_inplace */
108 0x000000ff, /* src_mask */
109 0x000000ff, /* dst_mask */
110 false), /* pcrel_offset */
111
112 /* 16 bit absolute */
113 HOWTO (R_ARM_ABS16, /* type */
114 0, /* rightshift */
115 1, /* size (0 = byte, 1 = short, 2 = long) */
116 16, /* bitsize */
117 false, /* pc_relative */
118 0, /* bitpos */
119 complain_overflow_bitfield, /* complain_on_overflow */
120 bfd_elf_generic_reloc, /* special_function */
121 "R_ARM_ABS16", /* name */
122 false, /* partial_inplace */
123 0, /* src_mask */
124 0, /* dst_mask */
125 false), /* pcrel_offset */
126
127 /* 12 bit absolute */
128 HOWTO (R_ARM_ABS12, /* type */
129 0, /* rightshift */
130 2, /* size (0 = byte, 1 = short, 2 = long) */
131 12, /* bitsize */
132 false, /* pc_relative */
133 0, /* bitpos */
134 complain_overflow_bitfield, /* complain_on_overflow */
135 bfd_elf_generic_reloc, /* special_function */
136 "R_ARM_ABS12", /* name */
137 false, /* partial_inplace */
138 0x000008ff, /* src_mask */
139 0x000008ff, /* dst_mask */
140 false), /* pcrel_offset */
141
142 HOWTO (R_ARM_THM_ABS5, /* type */
143 0, /* rightshift */
144 2, /* size (0 = byte, 1 = short, 2 = long) */
145 5, /* bitsize */
146 false, /* pc_relative */
147 0, /* bitpos */
148 complain_overflow_bitfield, /* complain_on_overflow */
149 bfd_elf_generic_reloc, /* special_function */
150 "R_ARM_THM_ABS5", /* name */
151 false, /* partial_inplace */
152 0x000007e0, /* src_mask */
153 0x000007e0, /* dst_mask */
154 false), /* pcrel_offset */
155
156 HOWTO (R_ARM_THM_PC22, /* type */
157 1, /* rightshift */
158 2, /* size (0 = byte, 1 = short, 2 = long) */
159 22, /* bitsize */
160 true, /* pc_relative */
161 0, /* bitpos */
162 complain_overflow_signed, /* complain_on_overflow */
163 bfd_elf_generic_reloc, /* special_function */
164 "R_ARM_THM_PC22", /* name */
165 false, /* partial_inplace */
166 0x07ff07ff, /* src_mask */
167 0x07ff07ff, /* dst_mask */
168 true), /* pcrel_offset */
169
170 HOWTO (R_ARM_SBREL32, /* type */
171 0, /* rightshift */
172 0, /* size (0 = byte, 1 = short, 2 = long) */
173 0, /* bitsize */
174 false, /* pc_relative */
175 0, /* bitpos */
176 complain_overflow_dont, /* complain_on_overflow */
177 bfd_elf_generic_reloc, /* special_function */
178 "R_ARM_SBREL32", /* name */
179 false, /* partial_inplace */
180 0, /* src_mask */
181 0, /* dst_mask */
182 false), /* pcrel_offset */
183
184 HOWTO (R_ARM_AMP_VCALL9, /* type */
185 1, /* rightshift */
186 1, /* size (0 = byte, 1 = short, 2 = long) */
187 8, /* bitsize */
188 true, /* pc_relative */
189 0, /* bitpos */
190 complain_overflow_signed, /* complain_on_overflow */
191 bfd_elf_generic_reloc, /* special_function */
192 "R_ARM_AMP_VCALL9", /* name */
193 false, /* partial_inplace */
194 0x000000ff, /* src_mask */
195 0x000000ff, /* dst_mask */
196 true), /* pcrel_offset */
197
198 /* 12 bit pc relative */
199 HOWTO (R_ARM_THM_PC11, /* type */
200 1, /* rightshift */
201 1, /* size (0 = byte, 1 = short, 2 = long) */
202 11, /* bitsize */
203 true, /* pc_relative */
204 0, /* bitpos */
205 complain_overflow_signed, /* complain_on_overflow */
206 bfd_elf_generic_reloc, /* special_function */
207 "R_ARM_THM_PC11", /* name */
208 false, /* partial_inplace */
209 0x000007ff, /* src_mask */
210 0x000007ff, /* dst_mask */
211 true), /* pcrel_offset */
212
213 /* 12 bit pc relative */
214 HOWTO (R_ARM_THM_PC9, /* type */
215 1, /* rightshift */
216 1, /* size (0 = byte, 1 = short, 2 = long) */
217 8, /* bitsize */
218 true, /* pc_relative */
219 0, /* bitpos */
220 complain_overflow_signed, /* complain_on_overflow */
221 bfd_elf_generic_reloc, /* special_function */
222 "R_ARM_THM_PC9", /* name */
223 false, /* partial_inplace */
224 0x000000ff, /* src_mask */
225 0x000000ff, /* dst_mask */
226 true), /* pcrel_offset */
227
228/* FILL ME IN (#13-249) */
229
230
231 HOWTO (R_ARM_RREL32, /* type */
232 0, /* rightshift */
233 0, /* size (0 = byte, 1 = short, 2 = long) */
234 0, /* bitsize */
235 false, /* pc_relative */
236 0, /* bitpos */
237 complain_overflow_dont, /* complain_on_overflow */
238 bfd_elf_generic_reloc, /* special_function */
239 "R_ARM_RREL32", /* name */
240 false, /* partial_inplace */
241 0, /* src_mask */
242 0, /* dst_mask */
243 false), /* pcrel_offset */
244
245 HOWTO (R_ARM_RABS32, /* type */
246 0, /* rightshift */
247 0, /* size (0 = byte, 1 = short, 2 = long) */
248 0, /* bitsize */
249 false, /* pc_relative */
250 0, /* bitpos */
251 complain_overflow_dont, /* complain_on_overflow */
252 bfd_elf_generic_reloc, /* special_function */
253 "R_ARM_RABS32", /* name */
254 false, /* partial_inplace */
255 0, /* src_mask */
256 0, /* dst_mask */
257 false), /* pcrel_offset */
258
259 HOWTO (R_ARM_RPC24, /* type */
260 0, /* rightshift */
261 0, /* size (0 = byte, 1 = short, 2 = long) */
262 0, /* bitsize */
263 false, /* pc_relative */
264 0, /* bitpos */
265 complain_overflow_dont, /* complain_on_overflow */
266 bfd_elf_generic_reloc, /* special_function */
267 "R_ARM_RPC24", /* name */
268 false, /* partial_inplace */
269 0, /* src_mask */
270 0, /* dst_mask */
271 false), /* pcrel_offset */
272
273 HOWTO (R_ARM_RBASE, /* type */
274 0, /* rightshift */
275 0, /* size (0 = byte, 1 = short, 2 = long) */
276 0, /* bitsize */
277 false, /* pc_relative */
278 0, /* bitpos */
279 complain_overflow_dont, /* complain_on_overflow */
280 bfd_elf_generic_reloc, /* special_function */
281 "R_ARM_RBASE", /* name */
282 false, /* partial_inplace */
283 0, /* src_mask */
284 0, /* dst_mask */
285 false), /* pcrel_offset */
286
287};
288struct elf32_arm_reloc_map
289{
290 unsigned char bfd_reloc_val;
291 unsigned char elf_reloc_val;
292};
293
294static const struct elf32_arm_reloc_map elf32_arm_reloc_map[] =
295{
296 { BFD_RELOC_NONE, R_ARM_NONE, },
297 { BFD_RELOC_ARM_PCREL_BRANCH, R_ARM_PC24, },
298 { BFD_RELOC_32, R_ARM_ABS32, },
299 { BFD_RELOC_32_PCREL, R_ARM_REL32, },
300 { BFD_RELOC_8, R_ARM_ABS8, },
301 { BFD_RELOC_16, R_ARM_ABS16, },
302 { BFD_RELOC_ARM_OFFSET_IMM, R_ARM_ABS12, },
303 { BFD_RELOC_ARM_THUMB_OFFSET, R_ARM_THM_ABS5, },
304 { BFD_RELOC_THUMB_PCREL_BRANCH23, R_ARM_THM_PC22, },
305 { BFD_RELOC_NONE, R_ARM_SBREL32 , },
306 { BFD_RELOC_NONE, R_ARM_AMP_VCALL9, },
307 { BFD_RELOC_THUMB_PCREL_BRANCH12, R_ARM_THM_PC11, },
308 { BFD_RELOC_THUMB_PCREL_BRANCH9, R_ARM_THM_PC9, }
309};
310
311static reloc_howto_type *
312elf32_arm_reloc_type_lookup (abfd, code)
313 bfd *abfd;
314 bfd_reloc_code_real_type code;
315{
316 unsigned int i;
317
318 for (i = 0;
319 i < sizeof (elf32_arm_reloc_map) / sizeof (struct elf32_arm_reloc_map);
320 i++)
321 {
322 if (elf32_arm_reloc_map[i].bfd_reloc_val == code)
323 return &elf32_arm_howto_table[elf32_arm_reloc_map[i].elf_reloc_val];
324 }
325
326 return NULL;
327}
328
329static void
330elf32_arm_info_to_howto (abfd, bfd_reloc, elf_reloc)
331 bfd *abfd;
332 arelent *bfd_reloc;
333 Elf32_Internal_Rela *elf_reloc;
334{
335 unsigned int r_type;
336
337 r_type = ELF32_R_TYPE (elf_reloc->r_info);
338 /* fixme: need range test */
339 /* BFD_ASSERT (r_type < (unsigned int) R_ELF32_ARM_MAX); */
340 bfd_reloc->howto = &elf32_arm_howto_table[r_type];
341}
342
343/* Perform a relocation as part of a final link. */
344static bfd_reloc_status_type
345elf32_arm_final_link_relocate (howto, input_bfd, output_bfd,
346 input_section, contents, offset, value,
347 addend, info, sym_sec, is_local)
348 reloc_howto_type *howto;
349 bfd *input_bfd;
350 bfd *output_bfd;
351 asection *input_section;
352 bfd_byte *contents;
353 bfd_vma offset;
354 bfd_vma value;
355 bfd_vma addend;
356 struct bfd_link_info *info;
357 asection *sym_sec;
358 int is_local;
359{
360 unsigned long r_type = howto->type;
361 bfd_byte *hit_data = contents + offset;
362
363 switch (r_type)
364 {
365
366 case R_ARM_NONE:
367 return bfd_reloc_ok;
368
369 case R_ARM_PC24:
370 value -= (input_section->output_offset + offset + 8);
371 value += addend;
372 value = value >> 2;
373
374 /* if ((long) value > 0xffffff || (long) value < -0x1000000)
375 return bfd_reloc_overflow; */
376
377 value &= 0xffffff;
378 value |= (bfd_get_32 (input_bfd, hit_data) & 0xff000000);
379 bfd_put_32 (input_bfd, value, hit_data);
380 return bfd_reloc_ok;
381
382 case R_ARM_ABS32:
383 value += addend;
384 bfd_put_32 (input_bfd, value, hit_data);
385 return bfd_reloc_ok;
386
387 case R_ARM_REL32:
388 value -= (input_section->output_section->vma
389 + input_section->output_offset);
390 value += addend;
391
392 bfd_put_32 (input_bfd, value, hit_data);
393 return bfd_reloc_ok;
394
395 case R_ARM_ABS8:
396 value += addend;
397
398 if ((long) value > 0x7f || (long) value < -0x80)
399 return bfd_reloc_overflow;
400
401 bfd_put_8 (input_bfd, value, hit_data);
402 return bfd_reloc_ok;
403
404 case R_ARM_ABS16:
405 value += addend;
406
407 if ((long) value > 0x7fff || (long) value < -0x8000)
408 return bfd_reloc_overflow;
409
410 bfd_put_16 (input_bfd, value, hit_data);
411 return bfd_reloc_ok;
412
413 case R_ARM_ABS12:
414 /* Support ldr and str instruction for the arm */
415 /* Also thumb b (unconditional branch) */
416 value += addend;
417
418 if ((long) value > 0x7ff || (long) value < -0x800)
419 return bfd_reloc_overflow;
420
421 value |= (bfd_get_32 (input_bfd, hit_data) & 0xfffff000);
422 bfd_put_32 (input_bfd, value, hit_data);
423 return bfd_reloc_ok;
424
425 case R_ARM_THM_ABS5:
426 /* Support ldr and str instructions for the thumb. */
427 value += addend;
428
429 if ((long) value > 0x1f || (long) value < -0x10)
430 return bfd_reloc_overflow;
431
432 value |= bfd_get_16 (input_bfd, hit_data) & 0xf82f;
433 bfd_put_16 (input_bfd, value, hit_data);
434 return bfd_reloc_ok;
435 break;
436
437#define LOW_HI_ORDER 0xF800F000
438#define HI_LOW_ORDER 0xF000F800
439
440 /* thumb BL (branch long instruction). */
441 case R_ARM_THM_PC22:
442 {
443 unsigned int low_bits;
444 unsigned int high_bits;
445 bfd_vma insn;
446
447 value -= (input_section->output_offset + offset + 8);
448 value += addend;
449 value = value >> 1;
450
451 low_bits = value & 0x000007ff;
452 high_bits = (value >> 11) & 0x000007ff;
453 insn = bfd_get_32 (input_bfd, hit_data);
454
455 if ((insn & LOW_HI_ORDER) == LOW_HI_ORDER)
456 insn = LOW_HI_ORDER | (low_bits << 16) | high_bits;
457 else if ((insn & HI_LOW_ORDER) == HI_LOW_ORDER)
458 insn = HI_LOW_ORDER | (high_bits << 16) | low_bits;
459 else
460 abort(); /* error - not a valid branch instruction form */
461
462 bfd_put_32 (input_bfd, insn, hit_data);
463 return bfd_reloc_ok;
464 }
465 break;
466
467 case R_ARM_SBREL32:
468 break;
469
470 case R_ARM_AMP_VCALL9:
471 return bfd_reloc_notsupported;
472
473 case R_ARM_RSBREL32:
474 return bfd_reloc_notsupported;
475
476 case R_ARM_THM_RPC22:
477 return bfd_reloc_notsupported;
478
479 case R_ARM_RREL32:
480 return bfd_reloc_notsupported;
481
482 case R_ARM_RABS32:
483 return bfd_reloc_notsupported;
484
485 case R_ARM_RPC24:
486 return bfd_reloc_notsupported;
487
488 case R_ARM_RBASE:
489 return bfd_reloc_notsupported;
490
491 default:
492 return bfd_reloc_notsupported;
493 }
494}
495/* Relocate an ARM ELF section. */
496static boolean
497elf32_arm_relocate_section (output_bfd, info, input_bfd, input_section,
498 contents, relocs, local_syms, local_sections)
499 bfd *output_bfd;
500 struct bfd_link_info *info;
501 bfd *input_bfd;
502 asection *input_section;
503 bfd_byte *contents;
504 Elf_Internal_Rela *relocs;
505 Elf_Internal_Sym *local_syms;
506 asection **local_sections;
507{
508 Elf_Internal_Shdr *symtab_hdr;
509 struct elf_link_hash_entry **sym_hashes;
510 Elf_Internal_Rela *rel, *relend;
511
512 symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
513 sym_hashes = elf_sym_hashes (input_bfd);
514
515 rel = relocs;
516 relend = relocs + input_section->reloc_count;
517 for (; rel < relend; rel++)
518 {
519 int r_type;
520 reloc_howto_type *howto;
521 unsigned long r_symndx;
522 Elf_Internal_Sym *sym;
523 asection *sec;
524 struct elf_link_hash_entry *h;
525 bfd_vma relocation;
526 bfd_reloc_status_type r;
527
528 r_symndx = ELF32_R_SYM (rel->r_info);
529 r_type = ELF32_R_TYPE (rel->r_info);
530 howto = elf32_arm_howto_table + r_type;
531
532 if (info->relocateable)
533 {
534 /* This is a relocateable link. We don't have to change
535 anything, unless the reloc is against a section symbol,
536 in which case we have to adjust according to where the
537 section symbol winds up in the output section. */
538 if (r_symndx < symtab_hdr->sh_info)
539 {
540 sym = local_syms + r_symndx;
541 if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
542 {
543 sec = local_sections[r_symndx];
544 rel->r_addend += sec->output_offset + sym->st_value;
545 }
546 }
547
548 continue;
549 }
550
551 /* This is a final link. */
552 h = NULL;
553 sym = NULL;
554 sec = NULL;
555 if (r_symndx < symtab_hdr->sh_info)
556 {
557 sym = local_syms + r_symndx;
558 sec = local_sections[r_symndx];
559 relocation = (sec->output_section->vma
560 + sec->output_offset
561 + sym->st_value);
562 }
563 else
564 {
565 h = sym_hashes[r_symndx - symtab_hdr->sh_info];
566 while (h->root.type == bfd_link_hash_indirect
567 || h->root.type == bfd_link_hash_warning)
568 h = (struct elf_link_hash_entry *) h->root.u.i.link;
569 if (h->root.type == bfd_link_hash_defined
570 || h->root.type == bfd_link_hash_defweak)
571 {
572 sec = h->root.u.def.section;
573 relocation = (h->root.u.def.value
574 + sec->output_section->vma
575 + sec->output_offset);
576 }
577 else if (h->root.type == bfd_link_hash_undefweak)
578 relocation = 0;
579 else
580 {
581 if (! ((*info->callbacks->undefined_symbol)
582 (info, h->root.root.string, input_bfd,
583 input_section, rel->r_offset)))
584 return false;
585 relocation = 0;
586 }
587 }
588
589 r = elf32_arm_final_link_relocate (howto, input_bfd, output_bfd,
590 input_section,
591 contents, rel->r_offset,
592 relocation, rel->r_addend,
593 info, sec, h == NULL);
594
595
596 if (r != bfd_reloc_ok)
597 {
598 const char *name;
599 const char *msg = (const char *)0;
600
601 if (h != NULL)
602 name = h->root.root.string;
603 else
604 {
605 name = (bfd_elf_string_from_elf_section
606 (input_bfd, symtab_hdr->sh_link, sym->st_name));
607 if (name == NULL || *name == '\0')
608 name = bfd_section_name (input_bfd, sec);
609 }
610
611 switch (r)
612 {
613 case bfd_reloc_overflow:
614 if (! ((*info->callbacks->reloc_overflow)
615 (info, name, howto->name, (bfd_vma) 0,
616 input_bfd, input_section, rel->r_offset)))
617 return false;
618 break;
619
620 case bfd_reloc_undefined:
621 if (! ((*info->callbacks->undefined_symbol)
622 (info, name, input_bfd, input_section,
623 rel->r_offset)))
624 return false;
625 break;
626
627 case bfd_reloc_outofrange:
628 msg = _("internal error: out of range error");
629 goto common_error;
630
631 case bfd_reloc_notsupported:
632 msg = _("internal error: unsupported relocation error");
633 goto common_error;
634
635 case bfd_reloc_dangerous:
636 msg = _("internal error: dangerous error");
637 goto common_error;
638
639 default:
640 msg = _("internal error: unknown error");
641 /* fall through */
642
643 common_error:
644 if (!((*info->callbacks->warning)
645 (info, msg, name, input_bfd, input_section,
646 rel->r_offset)))
647 return false;
648 break;
649 }
650 }
651 }
652
653 return true;
654}
655
656#define TARGET_LITTLE_SYM bfd_elf32_littlearm_vec
657#define TARGET_LITTLE_NAME "elf32-littlearm"
658#define TARGET_BIG_SYM bfd_elf32_bigarm_vec
659#define TARGET_BIG_NAME "elf32-bigarm"
660#define ELF_ARCH bfd_arch_arm
661#define ELF_MACHINE_CODE EM_ARM
662
663#define bfd_elf32_bfd_reloc_type_lookup elf32_arm_reloc_type_lookup
664#define elf_info_to_howto elf32_arm_info_to_howto
665#define elf_info_to_howto_rel 0
666#define elf_backend_relocate_section elf32_arm_relocate_section
667
668#define elf_symbol_leading_char '_'
669
670#include "elf32-target.h"
671/* end-sanitize-armelf */
This page took 0.048802 seconds and 4 git commands to generate.