1 /* BFD back-end for ARM COFF files.
2 Copyright 1990, 91, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
3 Written by Cygnus Support.
5 This file is part of BFD, the Binary File Descriptor library.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
27 #include "coff/internal.h"
35 static bfd_reloc_status_type
36 aoutarm_fix_pcrel_26_done PARAMS ((bfd *, arelent *, asymbol *, PTR,
37 asection *, bfd *, char **));
39 static bfd_reloc_status_type
40 aoutarm_fix_pcrel_26 PARAMS ((bfd *, arelent *, asymbol *, PTR,
41 asection *, bfd *, char **));
44 static bfd_reloc_status_type coff_arm_reloc
45 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
46 static boolean coff_arm_adjust_symndx
47 PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *,
48 struct internal_reloc *, boolean *));
50 /* Used by the assembler. */
51 static bfd_reloc_status_type
52 coff_arm_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd,
58 asection *input_section;
63 if (output_bfd == (bfd *) NULL)
64 return bfd_reloc_continue;
66 diff = reloc_entry->addend;
69 x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask))
73 reloc_howto_type *howto = reloc_entry->howto;
74 unsigned char *addr = (unsigned char *) data + reloc_entry->address;
80 char x = bfd_get_8 (abfd, addr);
82 bfd_put_8 (abfd, x, addr);
88 short x = bfd_get_16 (abfd, addr);
90 bfd_put_16 (abfd, x, addr);
96 long x = bfd_get_32 (abfd, addr);
98 bfd_put_32 (abfd, x, addr);
107 /* Now let bfd_perform_relocation finish everything up. */
108 return bfd_reloc_continue;
112 #define PCRELOFFSET true
115 static reloc_howto_type aoutarm_std_reloc_howto[] =
117 /* type rs size bsz pcrel bitpos ovrf sf name part_inpl readmask setmask pcdone */
124 complain_overflow_bitfield, /* ovf */
125 coff_arm_reloc, /* sf */
128 0x000000ff, /*read mask */
129 0x000000ff, /* setmask */
130 PCRELOFFSET /* pcdone */),
137 complain_overflow_bitfield,
150 complain_overflow_bitfield,
163 complain_overflow_signed,
164 aoutarm_fix_pcrel_26 ,
176 complain_overflow_signed,
189 complain_overflow_signed,
202 complain_overflow_signed,
215 complain_overflow_signed,
216 aoutarm_fix_pcrel_26_done,
229 complain_overflow_bitfield,
242 complain_overflow_bitfield,
255 complain_overflow_bitfield,
264 /* Return true if this relocation should
265 appear in the output .reloc section. */
267 static boolean in_reloc_p (abfd, howto)
269 reloc_howto_type *howto;
271 return !howto->pc_relative && howto->type != 11;
276 #define RTYPE2HOWTO(cache_ptr, dst) \
277 (cache_ptr)->howto = aoutarm_std_reloc_howto + (dst)->r_type;
279 #define coff_rtype_to_howto coff_arm_rtype_to_howto
281 static reloc_howto_type *
282 coff_arm_rtype_to_howto (abfd, sec, rel, h, sym, addendp)
285 struct internal_reloc *rel;
286 struct coff_link_hash_entry *h;
287 struct internal_syment *sym;
290 reloc_howto_type *howto;
292 howto = aoutarm_std_reloc_howto + rel->r_type;
294 if (rel->r_type == 11)
296 *addendp -= pe_data(sec->output_section->owner)->pe_opthdr.ImageBase;
299 /* The relocation_section function will skip pcrel_offset relocs
300 when doing a relocateable link. However, we want to convert
301 ARM26 to ARM26D relocs if possible. We return a fake howto in
302 this case without pcrel_offset set, and adjust the addend to
306 && (h->root.type == bfd_link_hash_defined
307 || h->root.type == bfd_link_hash_defweak)
308 && h->root.u.def.section->output_section == sec->output_section)
310 static reloc_howto_type fake_arm26_reloc =
317 complain_overflow_signed,
318 aoutarm_fix_pcrel_26 ,
325 *addendp -= rel->r_vaddr - sec->vma;
326 return &fake_arm26_reloc;
332 /* Used by the assembler. */
334 static bfd_reloc_status_type
335 aoutarm_fix_pcrel_26_done (abfd, reloc_entry, symbol, data, input_section,
336 output_bfd, error_message)
338 arelent *reloc_entry;
341 asection *input_section;
343 char **error_message;
345 /* This is dead simple at present. */
349 /* Used by the assembler. */
351 static bfd_reloc_status_type
352 aoutarm_fix_pcrel_26 (abfd, reloc_entry, symbol, data, input_section,
353 output_bfd, error_message)
355 arelent *reloc_entry;
358 asection *input_section;
360 char **error_message;
363 bfd_size_type addr = reloc_entry->address;
364 long target = bfd_get_32 (abfd, (bfd_byte *) data + addr);
365 bfd_reloc_status_type flag = bfd_reloc_ok;
367 /* If this is an undefined symbol, return error */
368 if (symbol->section == &bfd_und_section
369 && (symbol->flags & BSF_WEAK) == 0)
370 return output_bfd ? bfd_reloc_continue : bfd_reloc_undefined;
372 /* If the sections are different, and we are doing a partial relocation,
373 just ignore it for now. */
374 if (symbol->section->name != input_section->name
375 && output_bfd != (bfd *)NULL)
376 return bfd_reloc_continue;
378 relocation = (target & 0x00ffffff) << 2;
379 relocation = (relocation ^ 0x02000000) - 0x02000000; /* Sign extend */
380 relocation += symbol->value;
381 relocation += symbol->section->output_section->vma;
382 relocation += symbol->section->output_offset;
383 relocation += reloc_entry->addend;
384 relocation -= input_section->output_section->vma;
385 relocation -= input_section->output_offset;
388 return bfd_reloc_overflow;
390 /* Check for overflow */
391 if (relocation & 0x02000000)
393 if ((relocation & ~0x03ffffff) != ~0x03ffffff)
394 flag = bfd_reloc_overflow;
396 else if (relocation & ~0x03ffffff)
397 flag = bfd_reloc_overflow;
399 target &= ~0x00ffffff;
400 target |= (relocation >> 2) & 0x00ffffff;
401 bfd_put_32 (abfd, target, (bfd_byte *) data + addr);
403 /* Now the ARM magic... Change the reloc type so that it is marked as done.
404 Strictly this is only necessary if we are doing a partial relocation. */
405 reloc_entry->howto = &aoutarm_std_reloc_howto[7];
411 static CONST struct reloc_howto_struct *
412 arm_reloc_type_lookup(abfd,code)
414 bfd_reloc_code_real_type code;
416 #define ASTD(i,j) case i: return &aoutarm_std_reloc_howto[j]
417 if (code == BFD_RELOC_CTOR)
418 switch (bfd_get_arch_info (abfd)->bits_per_address)
423 default: return (CONST struct reloc_howto_struct *) 0;
428 ASTD (BFD_RELOC_16, 1);
429 ASTD (BFD_RELOC_32, 2);
430 ASTD (BFD_RELOC_ARM_PCREL_BRANCH, 3);
431 ASTD (BFD_RELOC_8_PCREL, 4);
432 ASTD (BFD_RELOC_16_PCREL, 5);
433 ASTD (BFD_RELOC_32_PCREL, 6);
434 ASTD (BFD_RELOC_RVA, 11);
435 default: return (CONST struct reloc_howto_struct *) 0;
440 #define coff_bfd_reloc_type_lookup arm_reloc_type_lookup
442 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
443 #define COFF_PAGE_SIZE 0x1000
444 /* Turn a howto into a reloc nunmber */
446 #define SELECT_RELOC(x,howto) { x.r_type = howto->type; }
447 #define BADMAG(x) ARMBADMAG(x)
448 #define ARM 1 /* Customize coffcode.h */
451 /* We use the special COFF backend linker. */
452 #define coff_relocate_section _bfd_coff_generic_relocate_section
454 /* When doing a relocateable link, we want to convert ARM26 relocs
455 into ARM26D relocs. */
458 coff_arm_adjust_symndx (obfd, info, ibfd, sec, irel, adjustedp)
460 struct bfd_link_info *info;
463 struct internal_reloc *irel;
466 if (irel->r_type == 3)
468 struct coff_link_hash_entry *h;
470 h = obj_coff_sym_hashes (ibfd)[irel->r_symndx];
472 && (h->root.type == bfd_link_hash_defined
473 || h->root.type == bfd_link_hash_defweak)
474 && h->root.u.def.section->output_section == sec->output_section)
482 #define APCS_FLAG( abfd ) (coff_data (abfd)->flags & F_APCS_26)
483 #define APCS_SET( abfd ) (coff_data (abfd)->flags & F_APCS_SET)
484 #define SET_APCS_FLAG( abfd, flg ) (coff_data (abfd)->flags = (coff_data (abfd)->flags & ~ F_APCS_26) | (flg | F_APCS_SET))
486 /* Called when merging the private data areas of two BFDs.
487 This is important as it allows us to detect if we are
488 attempting to merge binaries compiled for different ARM
489 targets, eg different CPUs or differents APCS's. */
492 coff_arm_bfd_merge_private_bfd_data (ibfd, obfd)
496 BFD_ASSERT (ibfd != NULL && obfd != NULL);
501 /* If the two formats are different we cannot check anything */
502 if (ibfd->xvec != obfd->xvec)
505 /* Verify that the APCS is the same for the two BFDs */
510 /* If the src and dest have different APCS flag bits set, fail */
511 if (APCS_FLAG (obfd) != APCS_FLAG (ibfd))
514 ("%s: ERROR: compiled for APCS-%d whereas target %s uses APCS-%d",
515 bfd_get_filename (ibfd), APCS_FLAG (ibfd) ? 26 : 32,
516 bfd_get_filename (obfd), APCS_FLAG (obfd) ? 26 : 32
519 bfd_set_error (bfd_error_wrong_format);
525 SET_APCS_FLAG (obfd, APCS_FLAG (ibfd));
527 /* Set up the arch and fields as well as these are probably wrong */
528 bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd));
536 /* Display the flags field */
539 coff_arm_bfd_print_private_bfd_data (abfd, ptr)
543 FILE * file = (FILE *) ptr;
545 BFD_ASSERT (abfd != NULL && ptr != NULL)
547 fprintf (file, "private flags = %x", coff_data( abfd )->flags);
550 fprintf (file, ": [APCS-%d]", APCS_FLAG( abfd ) ? 26 : 32);
558 /* Copies the given flags into the coff_tdata.flags field.
559 Typically these flags come from the f_flags[] field of
560 the COFF filehdr structure, which contains important,
561 target specific information. */
564 coff_arm_bfd_set_private_flags (abfd, flags)
570 BFD_ASSERT (abfd != NULL);
572 flag = (flags & F_APCS26) ? F_APCS_26 : 0;
574 /* Make sure that the APCS field has not been initialised to the opposite value */
575 if (APCS_SET (abfd) && (APCS_FLAG (abfd) != flag))
578 SET_APCS_FLAG (abfd, flag);
584 /* Copy the important parts of the target specific data
585 from one instance of a BFD to another. */
588 coff_arm_bfd_copy_private_bfd_data (src, dest)
592 BFD_ASSERT (src != NULL && dest != NULL);
597 /* If the destination is not in the same format as the source, do not do the copy */
598 if (src->xvec != dest->xvec)
601 /* copy the flags field */
606 /* If the src and dest have different APCS flag bits set, fail */
607 if (APCS_FLAG (dest) != APCS_FLAG (src))
611 SET_APCS_FLAG (dest, APCS_FLAG (src));
618 #define coff_adjust_symndx coff_arm_adjust_symndx
619 #define coff_bfd_merge_private_bfd_data coff_arm_bfd_merge_private_bfd_data
620 #define coff_bfd_print_private_bfd_data coff_arm_bfd_print_private_bfd_data
621 #define coff_bfd_set_private_flags coff_arm_bfd_set_private_flags
622 #define coff_bfd_copy_private_bfd_data coff_arm_bfd_copy_private_bfd_data
624 #include "coffcode.h"
627 #ifdef TARGET_LITTLE_SYM
633 #ifdef TARGET_LITTLE_NAME
638 bfd_target_coff_flavour,
639 BFD_ENDIAN_LITTLE, /* data byte order is little */
640 BFD_ENDIAN_LITTLE, /* header byte order is little */
642 (HAS_RELOC | EXEC_P | /* object flags */
643 HAS_LINENO | HAS_DEBUG |
644 HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
647 (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
649 (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC /* section flags */
650 | SEC_LINK_ONCE | SEC_LINK_DUPLICATES),
653 #ifdef TARGET_UNDERSCORE
654 TARGET_UNDERSCORE, /* leading underscore */
656 0, /* leading underscore */
658 '/', /* ar_pad_char */
659 15, /* ar_max_namelen */
661 bfd_getl64, bfd_getl_signed_64, bfd_putl64,
662 bfd_getl32, bfd_getl_signed_32, bfd_putl32,
663 bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
664 bfd_getl64, bfd_getl_signed_64, bfd_putl64,
665 bfd_getl32, bfd_getl_signed_32, bfd_putl32,
666 bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
668 /* Note that we allow an object file to be treated as a core file as well. */
669 {_bfd_dummy_target, coff_object_p, /* bfd_check_format */
670 bfd_generic_archive_p, coff_object_p},
671 {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */
673 {bfd_false, coff_write_object_contents, /* bfd_write_contents */
674 _bfd_write_archive_contents, bfd_false},
676 BFD_JUMP_TABLE_GENERIC (coff),
677 BFD_JUMP_TABLE_COPY (coff),
678 BFD_JUMP_TABLE_CORE (_bfd_nocore),
679 BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
680 BFD_JUMP_TABLE_SYMBOLS (coff),
681 BFD_JUMP_TABLE_RELOCS (coff),
682 BFD_JUMP_TABLE_WRITE (coff),
683 BFD_JUMP_TABLE_LINK (coff),
684 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
690 #ifdef TARGET_BIG_SYM
696 #ifdef TARGET_BIG_NAME
701 bfd_target_coff_flavour,
702 BFD_ENDIAN_BIG, /* data byte order is big */
703 BFD_ENDIAN_BIG, /* header byte order is big */
705 (HAS_RELOC | EXEC_P | /* object flags */
706 HAS_LINENO | HAS_DEBUG |
707 HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
710 (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
712 (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC /* section flags */
713 | SEC_LINK_ONCE | SEC_LINK_DUPLICATES),
716 #ifdef TARGET_UNDERSCORE
717 TARGET_UNDERSCORE, /* leading underscore */
719 0, /* leading underscore */
721 '/', /* ar_pad_char */
722 15, /* ar_max_namelen */
724 bfd_getb64, bfd_getb_signed_64, bfd_putb64,
725 bfd_getb32, bfd_getb_signed_32, bfd_putb32,
726 bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
727 bfd_getb64, bfd_getb_signed_64, bfd_putb64,
728 bfd_getb32, bfd_getb_signed_32, bfd_putb32,
729 bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
731 /* Note that we allow an object file to be treated as a core file as well. */
732 {_bfd_dummy_target, coff_object_p, /* bfd_check_format */
733 bfd_generic_archive_p, coff_object_p},
734 {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */
736 {bfd_false, coff_write_object_contents, /* bfd_write_contents */
737 _bfd_write_archive_contents, bfd_false},
739 BFD_JUMP_TABLE_GENERIC (coff),
740 BFD_JUMP_TABLE_COPY (coff),
741 BFD_JUMP_TABLE_CORE (_bfd_nocore),
742 BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
743 BFD_JUMP_TABLE_SYMBOLS (coff),
744 BFD_JUMP_TABLE_RELOCS (coff),
745 BFD_JUMP_TABLE_WRITE (coff),
746 BFD_JUMP_TABLE_LINK (coff),
747 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),