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
);
524 SET_APCS_FLAG (obfd
, APCS_FLAG (ibfd
));
531 /* Display the flags field */
534 coff_arm_bfd_print_private_bfd_data (abfd
, ptr
)
538 FILE * file
= (FILE *) ptr
;
540 BFD_ASSERT (abfd
!= NULL
&& ptr
!= NULL
)
542 fprintf (file
, "private flags = %x", coff_data( abfd
)->flags
);
545 fprintf (file
, ": [APCS-%d]", APCS_FLAG( abfd
) ? 26 : 32);
553 /* Copies the given flags into the coff_tdata.flags field.
554 Typically these flags come from the f_flags[] field of
555 the COFF filehdr structure, which contains important,
556 target specific information. */
559 coff_arm_bfd_set_private_flags (abfd
, flags
)
565 BFD_ASSERT (abfd
!= NULL
);
567 flag
= (flags
& F_APCS26
) ? F_APCS_26
: 0;
569 /* Make sure that the APCS field has not been initialised to the opposite value */
570 if (APCS_SET (abfd
) && (APCS_FLAG (abfd
) != flag
))
573 SET_APCS_FLAG (abfd
, flag
);
579 /* Copy the important parts of the target specific data
580 from one instance of a BFD to another. */
583 coff_arm_bfd_copy_private_bfd_data (src
, dest
)
587 BFD_ASSERT (src
!= NULL
&& dest
!= NULL
)
592 /* If the destination is not in the same format as the source, do not do the copy */
593 if (src
->xvec
!= dest
->xvec
)
596 /* copy the flags field */
601 /* If the src and dest have different APCS flag bits set, fail */
602 if (APCS_FLAG (dest
) != APCS_FLAG (src
))
606 SET_APCS_FLAG (dest
, APCS_FLAG (src
));
613 #define coff_adjust_symndx coff_arm_adjust_symndx
614 #define coff_bfd_merge_private_bfd_data coff_arm_bfd_merge_private_bfd_data
615 #define coff_bfd_print_private_bfd_data coff_arm_bfd_print_private_bfd_data
616 #define coff_bfd_set_private_flags coff_arm_bfd_set_private_flags
617 #define coff_bfd_copy_private_bfd_data coff_arm_bfd_copy_private_bfd_data
619 #include "coffcode.h"
622 #ifdef TARGET_LITTLE_SYM
628 #ifdef TARGET_LITTLE_NAME
633 bfd_target_coff_flavour
,
634 BFD_ENDIAN_LITTLE
, /* data byte order is little */
635 BFD_ENDIAN_LITTLE
, /* header byte order is little */
637 (HAS_RELOC
| EXEC_P
| /* object flags */
638 HAS_LINENO
| HAS_DEBUG
|
639 HAS_SYMS
| HAS_LOCALS
| WP_TEXT
| D_PAGED
),
642 (SEC_HAS_CONTENTS
| SEC_ALLOC
| SEC_LOAD
| SEC_RELOC
), /* section flags */
644 (SEC_HAS_CONTENTS
| SEC_ALLOC
| SEC_LOAD
| SEC_RELOC
/* section flags */
645 | SEC_LINK_ONCE
| SEC_LINK_DUPLICATES
),
648 #ifdef TARGET_UNDERSCORE
649 TARGET_UNDERSCORE
, /* leading underscore */
651 0, /* leading underscore */
653 '/', /* ar_pad_char */
654 15, /* ar_max_namelen */
656 bfd_getl64
, bfd_getl_signed_64
, bfd_putl64
,
657 bfd_getl32
, bfd_getl_signed_32
, bfd_putl32
,
658 bfd_getl16
, bfd_getl_signed_16
, bfd_putl16
, /* data */
659 bfd_getl64
, bfd_getl_signed_64
, bfd_putl64
,
660 bfd_getl32
, bfd_getl_signed_32
, bfd_putl32
,
661 bfd_getl16
, bfd_getl_signed_16
, bfd_putl16
, /* hdrs */
663 /* Note that we allow an object file to be treated as a core file as well. */
664 {_bfd_dummy_target
, coff_object_p
, /* bfd_check_format */
665 bfd_generic_archive_p
, coff_object_p
},
666 {bfd_false
, coff_mkobject
, _bfd_generic_mkarchive
, /* bfd_set_format */
668 {bfd_false
, coff_write_object_contents
, /* bfd_write_contents */
669 _bfd_write_archive_contents
, bfd_false
},
671 BFD_JUMP_TABLE_GENERIC (coff
),
672 BFD_JUMP_TABLE_COPY (coff
),
673 BFD_JUMP_TABLE_CORE (_bfd_nocore
),
674 BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff
),
675 BFD_JUMP_TABLE_SYMBOLS (coff
),
676 BFD_JUMP_TABLE_RELOCS (coff
),
677 BFD_JUMP_TABLE_WRITE (coff
),
678 BFD_JUMP_TABLE_LINK (coff
),
679 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic
),
685 #ifdef TARGET_BIG_SYM
691 #ifdef TARGET_BIG_NAME
696 bfd_target_coff_flavour
,
697 BFD_ENDIAN_BIG
, /* data byte order is big */
698 BFD_ENDIAN_BIG
, /* header byte order is big */
700 (HAS_RELOC
| EXEC_P
| /* object flags */
701 HAS_LINENO
| HAS_DEBUG
|
702 HAS_SYMS
| HAS_LOCALS
| WP_TEXT
| D_PAGED
),
705 (SEC_HAS_CONTENTS
| SEC_ALLOC
| SEC_LOAD
| SEC_RELOC
), /* section flags */
707 (SEC_HAS_CONTENTS
| SEC_ALLOC
| SEC_LOAD
| SEC_RELOC
/* section flags */
708 | SEC_LINK_ONCE
| SEC_LINK_DUPLICATES
),
711 #ifdef TARGET_UNDERSCORE
712 TARGET_UNDERSCORE
, /* leading underscore */
714 0, /* leading underscore */
716 '/', /* ar_pad_char */
717 15, /* ar_max_namelen */
719 bfd_getb64
, bfd_getb_signed_64
, bfd_putb64
,
720 bfd_getb32
, bfd_getb_signed_32
, bfd_putb32
,
721 bfd_getb16
, bfd_getb_signed_16
, bfd_putb16
, /* data */
722 bfd_getb64
, bfd_getb_signed_64
, bfd_putb64
,
723 bfd_getb32
, bfd_getb_signed_32
, bfd_putb32
,
724 bfd_getb16
, bfd_getb_signed_16
, bfd_putb16
, /* hdrs */
726 /* Note that we allow an object file to be treated as a core file as well. */
727 {_bfd_dummy_target
, coff_object_p
, /* bfd_check_format */
728 bfd_generic_archive_p
, coff_object_p
},
729 {bfd_false
, coff_mkobject
, _bfd_generic_mkarchive
, /* bfd_set_format */
731 {bfd_false
, coff_write_object_contents
, /* bfd_write_contents */
732 _bfd_write_archive_contents
, bfd_false
},
734 BFD_JUMP_TABLE_GENERIC (coff
),
735 BFD_JUMP_TABLE_COPY (coff
),
736 BFD_JUMP_TABLE_CORE (_bfd_nocore
),
737 BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff
),
738 BFD_JUMP_TABLE_SYMBOLS (coff
),
739 BFD_JUMP_TABLE_RELOCS (coff
),
740 BFD_JUMP_TABLE_WRITE (coff
),
741 BFD_JUMP_TABLE_LINK (coff
),
742 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic
),