| /* BFD back-end for IBM RS/6000 "XCOFF64" files. |
| Copyright (C) 2000-2024 Free Software Foundation, Inc. |
| Written Clinton Popetz. |
| Contributed by Cygnus Support. |
| |
| This file is part of BFD, the Binary File Descriptor library. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
| MA 02110-1301, USA. */ |
| |
| #include "sysdep.h" |
| #include "bfd.h" |
| #include "bfdlink.h" |
| #include "libbfd.h" |
| #include "coff/internal.h" |
| #include "coff/xcoff.h" |
| #include "coff/rs6k64.h" |
| #include "libcoff.h" |
| #include "libxcoff.h" |
| |
| #define GET_FILEHDR_SYMPTR H_GET_64 |
| #define PUT_FILEHDR_SYMPTR H_PUT_64 |
| #define GET_AOUTHDR_DATA_START H_GET_64 |
| #define PUT_AOUTHDR_DATA_START H_PUT_64 |
| #define GET_AOUTHDR_TEXT_START H_GET_64 |
| #define PUT_AOUTHDR_TEXT_START H_PUT_64 |
| #define GET_AOUTHDR_TSIZE H_GET_64 |
| #define PUT_AOUTHDR_TSIZE H_PUT_64 |
| #define GET_AOUTHDR_DSIZE H_GET_64 |
| #define PUT_AOUTHDR_DSIZE H_PUT_64 |
| #define GET_AOUTHDR_BSIZE H_GET_64 |
| #define PUT_AOUTHDR_BSIZE H_PUT_64 |
| #define GET_AOUTHDR_ENTRY H_GET_64 |
| #define PUT_AOUTHDR_ENTRY H_PUT_64 |
| #define GET_SCNHDR_PADDR H_GET_64 |
| #define PUT_SCNHDR_PADDR H_PUT_64 |
| #define GET_SCNHDR_VADDR H_GET_64 |
| #define PUT_SCNHDR_VADDR H_PUT_64 |
| #define GET_SCNHDR_SIZE H_GET_64 |
| #define PUT_SCNHDR_SIZE H_PUT_64 |
| #define GET_SCNHDR_SCNPTR H_GET_64 |
| #define PUT_SCNHDR_SCNPTR H_PUT_64 |
| #define GET_SCNHDR_RELPTR H_GET_64 |
| #define PUT_SCNHDR_RELPTR H_PUT_64 |
| #define GET_SCNHDR_LNNOPTR H_GET_64 |
| #define PUT_SCNHDR_LNNOPTR H_PUT_64 |
| #define GET_SCNHDR_NRELOC H_GET_32 |
| #define MAX_SCNHDR_NRELOC 0xffffffff |
| #define PUT_SCNHDR_NRELOC H_PUT_32 |
| #define GET_SCNHDR_NLNNO H_GET_32 |
| #define MAX_SCNHDR_NLNNO 0xffffffff |
| #define PUT_SCNHDR_NLNNO H_PUT_32 |
| #define GET_RELOC_VADDR H_GET_64 |
| #define PUT_RELOC_VADDR H_PUT_64 |
| |
| #define COFF_FORCE_SYMBOLS_IN_STRINGS |
| #define COFF_DEBUG_STRING_WIDE_PREFIX |
| |
| |
| #define COFF_ADJUST_SCNHDR_OUT_POST(ABFD, INT, EXT) \ |
| do \ |
| { \ |
| memset (((SCNHDR *) EXT)->s_pad, 0, \ |
| sizeof (((SCNHDR *) EXT)->s_pad)); \ |
| } \ |
| while (0) |
| |
| #define NO_COFF_LINENOS |
| |
| #define coff_SWAP_lineno_in _bfd_xcoff64_swap_lineno_in |
| #define coff_SWAP_lineno_out _bfd_xcoff64_swap_lineno_out |
| |
| static void _bfd_xcoff64_swap_lineno_in |
| (bfd *, void *, void *); |
| static unsigned int _bfd_xcoff64_swap_lineno_out |
| (bfd *, void *, void *); |
| static bool _bfd_xcoff64_put_symbol_name |
| (struct bfd_link_info *, struct bfd_strtab_hash *, |
| struct internal_syment *, const char *); |
| static bool _bfd_xcoff64_put_ldsymbol_name |
| (bfd *, struct xcoff_loader_info *, struct internal_ldsym *, const char *); |
| static void _bfd_xcoff64_swap_sym_in |
| (bfd *, void *, void *); |
| static unsigned int _bfd_xcoff64_swap_sym_out |
| (bfd *, void *, void *); |
| static void _bfd_xcoff64_swap_aux_in |
| (bfd *, void *, int, int, int, int, void *); |
| static unsigned int _bfd_xcoff64_swap_aux_out |
| (bfd *, void *, int, int, int, int, void *); |
| static void xcoff64_swap_reloc_in |
| (bfd *, void *, void *); |
| static unsigned int xcoff64_swap_reloc_out |
| (bfd *, void *, void *); |
| extern bool _bfd_xcoff_mkobject |
| (bfd *); |
| extern bool _bfd_xcoff_copy_private_bfd_data |
| (bfd *, bfd *); |
| extern bool _bfd_xcoff_is_local_label_name |
| (bfd *, const char *); |
| extern void xcoff64_rtype2howto |
| (arelent *, struct internal_reloc *); |
| extern reloc_howto_type * xcoff64_reloc_type_lookup |
| (bfd *, bfd_reloc_code_real_type); |
| extern bool _bfd_xcoff_slurp_armap |
| (bfd *); |
| extern void *_bfd_xcoff_read_ar_hdr |
| (bfd *); |
| extern bfd *_bfd_xcoff_openr_next_archived_file |
| (bfd *, bfd *); |
| extern int _bfd_xcoff_stat_arch_elt |
| (bfd *, struct stat *); |
| extern bool _bfd_xcoff_write_armap |
| (bfd *, unsigned int, struct orl *, unsigned int, int); |
| extern bool _bfd_xcoff_write_archive_contents |
| (bfd *); |
| extern int _bfd_xcoff_sizeof_headers |
| (bfd *, struct bfd_link_info *); |
| extern void _bfd_xcoff_swap_sym_in |
| (bfd *, void *, void *); |
| extern unsigned int _bfd_xcoff_swap_sym_out |
| (bfd *, void *, void *); |
| extern void _bfd_xcoff_swap_aux_in |
| (bfd *, void *, int, int, int, int, void *); |
| extern unsigned int _bfd_xcoff_swap_aux_out |
| (bfd *, void *, int, int, int, int, void *); |
| static void xcoff64_swap_ldhdr_in |
| (bfd *, const void *, struct internal_ldhdr *); |
| static void xcoff64_swap_ldhdr_out |
| (bfd *, const struct internal_ldhdr *, void *d); |
| static void xcoff64_swap_ldsym_in |
| (bfd *, const void *, struct internal_ldsym *); |
| static void xcoff64_swap_ldsym_out |
| (bfd *, const struct internal_ldsym *, void *d); |
| static void xcoff64_swap_ldrel_in |
| (bfd *, const void *, struct internal_ldrel *); |
| static void xcoff64_swap_ldrel_out |
| (bfd *, const struct internal_ldrel *, void *d); |
| static bool xcoff64_ppc_relocate_section |
| (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, |
| struct internal_reloc *, struct internal_syment *, |
| asection **); |
| static bool xcoff64_slurp_armap |
| (bfd *); |
| static bfd_cleanup xcoff64_archive_p |
| (bfd *); |
| static bfd *xcoff64_openr_next_archived_file |
| (bfd *, bfd *); |
| static int xcoff64_sizeof_headers |
| (bfd *, struct bfd_link_info *); |
| static asection *xcoff64_create_csect_from_smclas |
| (bfd *, union internal_auxent *, const char *); |
| static bool xcoff64_is_lineno_count_overflow |
| (bfd *, bfd_vma); |
| static bool xcoff64_is_reloc_count_overflow |
| (bfd *, bfd_vma); |
| static bfd_vma xcoff64_loader_symbol_offset |
| (bfd *, struct internal_ldhdr *); |
| static bfd_vma xcoff64_loader_reloc_offset |
| (bfd *, struct internal_ldhdr *); |
| static bool xcoff64_generate_rtinit |
| (bfd *, const char *, const char *, bool); |
| static bool xcoff64_bad_format_hook |
| (bfd *, void *); |
| |
| /* Relocation functions */ |
| static xcoff_reloc_function xcoff64_reloc_type_br; |
| |
| xcoff_reloc_function *const |
| xcoff64_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION] = |
| { |
| xcoff_reloc_type_pos, /* R_POS (0x00) */ |
| xcoff_reloc_type_neg, /* R_NEG (0x01) */ |
| xcoff_reloc_type_rel, /* R_REL (0x02) */ |
| xcoff_reloc_type_toc, /* R_TOC (0x03) */ |
| xcoff_reloc_type_toc, /* R_TRL (0x04) */ |
| xcoff_reloc_type_toc, /* R_GL (0x05) */ |
| xcoff_reloc_type_toc, /* R_TCL (0x06) */ |
| xcoff_reloc_type_fail, /* (0x07) */ |
| xcoff_reloc_type_ba, /* R_BA (0x08) */ |
| xcoff_reloc_type_fail, /* (0x09) */ |
| xcoff64_reloc_type_br, /* R_BR (0x0a) */ |
| xcoff_reloc_type_fail, /* (0x0b) */ |
| xcoff_reloc_type_pos, /* R_RL (0x0c) */ |
| xcoff_reloc_type_pos, /* R_RLA (0x0d) */ |
| xcoff_reloc_type_fail, /* (0x0e) */ |
| xcoff_reloc_type_noop, /* R_REF (0x0f) */ |
| xcoff_reloc_type_fail, /* (0x10) */ |
| xcoff_reloc_type_fail, /* (0x11) */ |
| xcoff_reloc_type_fail, /* (0x12) */ |
| xcoff_reloc_type_toc, /* R_TRLA (0x13) */ |
| xcoff_reloc_type_fail, /* R_RRTBI (0x14) */ |
| xcoff_reloc_type_fail, /* R_RRTBA (0x15) */ |
| xcoff_reloc_type_ba, /* R_CAI (0x16) */ |
| xcoff_reloc_type_crel, /* R_CREL (0x17) */ |
| xcoff_reloc_type_ba, /* R_RBA (0x18) */ |
| xcoff_reloc_type_ba, /* R_RBAC (0x19) */ |
| xcoff64_reloc_type_br, /* R_RBR (0x1a) */ |
| xcoff_reloc_type_ba, /* R_RBRC (0x1b) */ |
| xcoff_reloc_type_fail, /* (0x1c) */ |
| xcoff_reloc_type_fail, /* (0x1d) */ |
| xcoff_reloc_type_fail, /* (0x1e) */ |
| xcoff_reloc_type_fail, /* (0x1f) */ |
| xcoff_reloc_type_tls, /* R_TLS (0x20) */ |
| xcoff_reloc_type_tls, /* R_TLS_IE (0x21) */ |
| xcoff_reloc_type_tls, /* R_TLS_LD (0x22) */ |
| xcoff_reloc_type_tls, /* R_TLS_LE (0x23) */ |
| xcoff_reloc_type_tls, /* R_TLSM (0x24) */ |
| xcoff_reloc_type_tls, /* R_TLSML (0x25) */ |
| xcoff_reloc_type_fail, /* (0x26) */ |
| xcoff_reloc_type_fail, /* (0x27) */ |
| xcoff_reloc_type_fail, /* (0x28) */ |
| xcoff_reloc_type_fail, /* (0x29) */ |
| xcoff_reloc_type_fail, /* (0x2a) */ |
| xcoff_reloc_type_fail, /* (0x2b) */ |
| xcoff_reloc_type_fail, /* (0x2c) */ |
| xcoff_reloc_type_fail, /* (0x2d) */ |
| xcoff_reloc_type_fail, /* (0x2e) */ |
| xcoff_reloc_type_fail, /* (0x2f) */ |
| xcoff_reloc_type_toc, /* R_TOCU (0x30) */ |
| xcoff_reloc_type_toc, /* R_TOCL (0x31) */ |
| }; |
| |
| /* coffcode.h needs these to be defined. */ |
| /* Internalcoff.h and coffcode.h modify themselves based on these flags. */ |
| #define XCOFF64 |
| #define RS6000COFF_C 1 |
| |
| #define SELECT_RELOC(internal, howto) \ |
| { \ |
| internal.r_type = howto->type; \ |
| internal.r_size = \ |
| ((howto->complain_on_overflow == complain_overflow_signed \ |
| ? 0x80 \ |
| : 0) \ |
| | (howto->bitsize - 1)); \ |
| } |
| |
| #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3) |
| #define COFF_LONG_FILENAMES |
| #define NO_COFF_SYMBOLS |
| #define RTYPE2HOWTO(cache_ptr, dst) xcoff64_rtype2howto (cache_ptr, dst) |
| #define coff_mkobject _bfd_xcoff_mkobject |
| #define coff_bfd_copy_private_bfd_data _bfd_xcoff_copy_private_bfd_data |
| #define coff_bfd_is_local_label_name _bfd_xcoff_is_local_label_name |
| #define coff_bfd_reloc_type_lookup xcoff64_reloc_type_lookup |
| #define coff_bfd_reloc_name_lookup xcoff64_reloc_name_lookup |
| #ifdef AIX_CORE |
| extern bfd_cleanup rs6000coff_core_p |
| (bfd *abfd); |
| extern bool rs6000coff_core_file_matches_executable_p |
| (bfd *cbfd, bfd *ebfd); |
| extern char *rs6000coff_core_file_failing_command |
| (bfd *abfd); |
| extern int rs6000coff_core_file_failing_signal |
| (bfd *abfd); |
| #define CORE_FILE_P rs6000coff_core_p |
| #define coff_core_file_failing_command \ |
| rs6000coff_core_file_failing_command |
| #define coff_core_file_failing_signal \ |
| rs6000coff_core_file_failing_signal |
| #define coff_core_file_matches_executable_p \ |
| rs6000coff_core_file_matches_executable_p |
| #define coff_core_file_pid \ |
| _bfd_nocore_core_file_pid |
| #else |
| #define CORE_FILE_P _bfd_dummy_target |
| #define coff_core_file_failing_command \ |
| _bfd_nocore_core_file_failing_command |
| #define coff_core_file_failing_signal \ |
| _bfd_nocore_core_file_failing_signal |
| #define coff_core_file_matches_executable_p \ |
| _bfd_nocore_core_file_matches_executable_p |
| #define coff_core_file_pid \ |
| _bfd_nocore_core_file_pid |
| #endif |
| #define coff_SWAP_sym_in _bfd_xcoff64_swap_sym_in |
| #define coff_SWAP_sym_out _bfd_xcoff64_swap_sym_out |
| #define coff_SWAP_aux_in _bfd_xcoff64_swap_aux_in |
| #define coff_SWAP_aux_out _bfd_xcoff64_swap_aux_out |
| #define coff_swap_reloc_in xcoff64_swap_reloc_in |
| #define coff_swap_reloc_out xcoff64_swap_reloc_out |
| #define NO_COFF_RELOCS |
| |
| #ifndef bfd_pe_print_pdata |
| #define bfd_pe_print_pdata NULL |
| #endif |
| |
| #include "coffcode.h" |
| |
| /* For XCOFF64, the effective width of symndx changes depending on |
| whether we are the first entry. Sigh. */ |
| static void |
| _bfd_xcoff64_swap_lineno_in (bfd *abfd, void *ext1, void *in1) |
| { |
| LINENO *ext = (LINENO *) ext1; |
| struct internal_lineno *in = (struct internal_lineno *) in1; |
| |
| in->l_lnno = H_GET_32 (abfd, (ext->l_lnno)); |
| if (in->l_lnno == 0) |
| in->l_addr.l_symndx = H_GET_32 (abfd, ext->l_addr.l_symndx); |
| else |
| in->l_addr.l_paddr = H_GET_64 (abfd, ext->l_addr.l_paddr); |
| } |
| |
| static unsigned int |
| _bfd_xcoff64_swap_lineno_out (bfd *abfd, void *inp, void *outp) |
| { |
| struct internal_lineno *in = (struct internal_lineno *) inp; |
| struct external_lineno *ext = (struct external_lineno *) outp; |
| |
| H_PUT_32 (abfd, in->l_addr.l_symndx, ext->l_addr.l_symndx); |
| H_PUT_32 (abfd, in->l_lnno, (ext->l_lnno)); |
| |
| if (in->l_lnno == 0) |
| H_PUT_32 (abfd, in->l_addr.l_symndx, ext->l_addr.l_symndx); |
| else |
| H_PUT_64 (abfd, in->l_addr.l_paddr, ext->l_addr.l_paddr); |
| |
| return bfd_coff_linesz (abfd); |
| } |
| |
| static void |
| _bfd_xcoff64_swap_sym_in (bfd *abfd, void *ext1, void *in1) |
| { |
| struct external_syment *ext = (struct external_syment *) ext1; |
| struct internal_syment *in = (struct internal_syment *) in1; |
| |
| in->_n._n_n._n_zeroes = 0; |
| in->_n._n_n._n_offset = H_GET_32 (abfd, ext->e_offset); |
| in->n_value = H_GET_64 (abfd, ext->e_value); |
| in->n_scnum = (short) H_GET_16 (abfd, ext->e_scnum); |
| in->n_type = H_GET_16 (abfd, ext->e_type); |
| in->n_sclass = H_GET_8 (abfd, ext->e_sclass); |
| in->n_numaux = H_GET_8 (abfd, ext->e_numaux); |
| } |
| |
| static unsigned int |
| _bfd_xcoff64_swap_sym_out (bfd *abfd, void *inp, void *extp) |
| { |
| struct internal_syment *in = (struct internal_syment *) inp; |
| struct external_syment *ext = (struct external_syment *) extp; |
| |
| H_PUT_32 (abfd, in->_n._n_n._n_offset, ext->e_offset); |
| H_PUT_64 (abfd, in->n_value, ext->e_value); |
| H_PUT_16 (abfd, in->n_scnum, ext->e_scnum); |
| H_PUT_16 (abfd, in->n_type, ext->e_type); |
| H_PUT_8 (abfd, in->n_sclass, ext->e_sclass); |
| H_PUT_8 (abfd, in->n_numaux, ext->e_numaux); |
| return bfd_coff_symesz (abfd); |
| } |
| |
| static void |
| _bfd_xcoff64_swap_aux_in (bfd *abfd, void *ext1, int type ATTRIBUTE_UNUSED, |
| int in_class, int indx, int numaux, void *in1) |
| { |
| union external_auxent *ext = (union external_auxent *) ext1; |
| union internal_auxent *in = (union internal_auxent *) in1; |
| unsigned char auxtype; |
| |
| switch (in_class) |
| { |
| default: |
| _bfd_error_handler |
| /* xgettext: c-format */ |
| (_("%pB: unsupported swap_aux_in for storage class %#x"), |
| abfd, (unsigned int) in_class); |
| bfd_set_error (bfd_error_bad_value); |
| break; |
| |
| case C_FILE: |
| auxtype = H_GET_8 (abfd, ext->x_file.x_auxtype); |
| if (auxtype != _AUX_FILE) |
| goto error; |
| |
| if (ext->x_file.x_n.x_n.x_zeroes[0] == 0) |
| { |
| in->x_file.x_n.x_n.x_zeroes = 0; |
| in->x_file.x_n.x_n.x_offset = |
| H_GET_32 (abfd, ext->x_file.x_n.x_n.x_offset); |
| } |
| else |
| memcpy (in->x_file.x_n.x_fname, ext->x_file.x_n.x_fname, FILNMLEN); |
| in->x_file.x_ftype = H_GET_8 (abfd, ext->x_file.x_ftype); |
| break; |
| |
| /* RS/6000 "csect" auxents. |
| There is always a CSECT auxiliary entry. But functions can |
| have FCN and EXCEPT ones too. In this case, CSECT is always the last |
| one. |
| For now, we only support FCN types. */ |
| case C_EXT: |
| case C_AIX_WEAKEXT: |
| case C_HIDEXT: |
| if (indx + 1 == numaux) |
| { |
| /* C_EXT can have several aux enties. But the _AUX_CSECT is always |
| the last one. */ |
| auxtype = H_GET_8 (abfd, ext->x_csect.x_auxtype); |
| if (auxtype != _AUX_CSECT) |
| goto error; |
| |
| bfd_vma h = H_GET_32 (abfd, ext->x_csect.x_scnlen_hi); |
| bfd_vma l = H_GET_32 (abfd, ext->x_csect.x_scnlen_lo); |
| |
| in->x_csect.x_scnlen.u64 = h << 32 | (l & 0xffffffff); |
| |
| in->x_csect.x_parmhash = H_GET_32 (abfd, ext->x_csect.x_parmhash); |
| in->x_csect.x_snhash = H_GET_16 (abfd, ext->x_csect.x_snhash); |
| /* We don't have to hack bitfields in x_smtyp because it's |
| defined by shifts-and-ands, which are equivalent on all |
| byte orders. */ |
| in->x_csect.x_smtyp = H_GET_8 (abfd, ext->x_csect.x_smtyp); |
| in->x_csect.x_smclas = H_GET_8 (abfd, ext->x_csect.x_smclas); |
| } |
| else |
| { |
| /* It can also be a _AUX_EXCEPT entry. But it's not supported |
| for now. */ |
| auxtype = H_GET_8 (abfd, ext->x_fcn.x_auxtype); |
| if (auxtype != _AUX_FCN) |
| goto error; |
| |
| in->x_sym.x_fcnary.x_fcn.x_lnnoptr |
| = H_GET_64 (abfd, ext->x_fcn.x_lnnoptr); |
| in->x_sym.x_misc.x_fsize |
| = H_GET_32 (abfd, ext->x_fcn.x_fsize); |
| in->x_sym.x_fcnary.x_fcn.x_endndx.u32 |
| = H_GET_32 (abfd, ext->x_fcn.x_endndx); |
| } |
| break; |
| |
| case C_STAT: |
| _bfd_error_handler |
| /* xgettext: c-format */ |
| (_("%pB: C_STAT isn't supported by XCOFF64"), |
| abfd); |
| bfd_set_error (bfd_error_bad_value); |
| break; |
| |
| case C_BLOCK: |
| case C_FCN: |
| auxtype = H_GET_8 (abfd, ext->x_sym.x_auxtype); |
| if (auxtype != _AUX_SYM) |
| goto error; |
| |
| in->x_sym.x_misc.x_lnsz.x_lnno |
| = H_GET_32 (abfd, ext->x_sym.x_lnno); |
| break; |
| |
| case C_DWARF: |
| auxtype = H_GET_8 (abfd, ext->x_sect.x_auxtype); |
| if (auxtype != _AUX_SECT) |
| goto error; |
| |
| in->x_sect.x_scnlen = H_GET_64 (abfd, ext->x_sect.x_scnlen); |
| in->x_sect.x_nreloc = H_GET_64 (abfd, ext->x_sect.x_nreloc); |
| break; |
| } |
| |
| return; |
| |
| error: |
| _bfd_error_handler |
| /* xgettext: c-format */ |
| (_("%pB: wrong auxtype %#x for storage class %#x"), |
| abfd, auxtype, (unsigned int) in_class); |
| bfd_set_error (bfd_error_bad_value); |
| |
| |
| } |
| |
| static unsigned int |
| _bfd_xcoff64_swap_aux_out (bfd *abfd, void *inp, int type ATTRIBUTE_UNUSED, |
| int in_class, int indx, int numaux, void *extp) |
| { |
| union internal_auxent *in = (union internal_auxent *) inp; |
| union external_auxent *ext = (union external_auxent *) extp; |
| |
| memset (ext, 0, bfd_coff_auxesz (abfd)); |
| switch (in_class) |
| { |
| default: |
| _bfd_error_handler |
| /* xgettext: c-format */ |
| (_("%pB: unsupported swap_aux_out for storage class %#x"), |
| abfd, (unsigned int) in_class); |
| bfd_set_error (bfd_error_bad_value); |
| break; |
| |
| case C_FILE: |
| if (in->x_file.x_n.x_n.x_zeroes == 0) |
| { |
| H_PUT_32 (abfd, 0, ext->x_file.x_n.x_n.x_zeroes); |
| H_PUT_32 (abfd, in->x_file.x_n.x_n.x_offset, |
| ext->x_file.x_n.x_n.x_offset); |
| } |
| else |
| memcpy (ext->x_file.x_n.x_fname, in->x_file.x_n.x_fname, FILNMLEN); |
| H_PUT_8 (abfd, in->x_file.x_ftype, ext->x_file.x_ftype); |
| H_PUT_8 (abfd, _AUX_FILE, ext->x_file.x_auxtype); |
| break; |
| |
| /* RS/6000 "csect" auxents. |
| There is always a CSECT auxiliary entry. But functions can |
| have FCN and EXCEPT ones too. In this case, CSECT is always the last |
| one. |
| For now, we only support FCN types. */ |
| case C_EXT: |
| case C_AIX_WEAKEXT: |
| case C_HIDEXT: |
| if (indx + 1 == numaux) |
| { |
| bfd_vma temp; |
| |
| temp = in->x_csect.x_scnlen.u64 & 0xffffffff; |
| H_PUT_32 (abfd, temp, ext->x_csect.x_scnlen_lo); |
| temp = in->x_csect.x_scnlen.u64 >> 32; |
| H_PUT_32 (abfd, temp, ext->x_csect.x_scnlen_hi); |
| H_PUT_32 (abfd, in->x_csect.x_parmhash, ext->x_csect.x_parmhash); |
| H_PUT_16 (abfd, in->x_csect.x_snhash, ext->x_csect.x_snhash); |
| /* We don't have to hack bitfields in x_smtyp because it's |
| defined by shifts-and-ands, which are equivalent on all |
| byte orders. */ |
| H_PUT_8 (abfd, in->x_csect.x_smtyp, ext->x_csect.x_smtyp); |
| H_PUT_8 (abfd, in->x_csect.x_smclas, ext->x_csect.x_smclas); |
| H_PUT_8 (abfd, _AUX_CSECT, ext->x_csect.x_auxtype); |
| } |
| else |
| { |
| H_PUT_64 (abfd, in->x_sym.x_fcnary.x_fcn.x_lnnoptr, |
| ext->x_fcn.x_lnnoptr); |
| H_PUT_32 (abfd, in->x_sym.x_misc.x_fsize, ext->x_fcn.x_fsize); |
| H_PUT_32 (abfd, in->x_sym.x_fcnary.x_fcn.x_endndx.u32, |
| ext->x_fcn.x_endndx); |
| H_PUT_8 (abfd, _AUX_FCN, ext->x_csect.x_auxtype); |
| } |
| break; |
| |
| case C_STAT: |
| _bfd_error_handler |
| /* xgettext: c-format */ |
| (_("%pB: C_STAT isn't supported by XCOFF64"), |
| abfd); |
| bfd_set_error (bfd_error_bad_value); |
| break; |
| |
| case C_BLOCK: |
| case C_FCN: |
| H_PUT_32 (abfd, in->x_sym.x_misc.x_lnsz.x_lnno, ext->x_sym.x_lnno); |
| H_PUT_8 (abfd, _AUX_SYM, ext->x_sym.x_auxtype); |
| break; |
| |
| case C_DWARF: |
| H_PUT_64 (abfd, in->x_sect.x_scnlen, ext->x_sect.x_scnlen); |
| H_PUT_64 (abfd, in->x_sect.x_nreloc, ext->x_sect.x_nreloc); |
| H_PUT_8 (abfd, _AUX_SECT, ext->x_sect.x_auxtype); |
| break; |
| } |
| |
| return bfd_coff_auxesz (abfd); |
| } |
| |
| static bool |
| _bfd_xcoff64_put_symbol_name (struct bfd_link_info *info, |
| struct bfd_strtab_hash *strtab, |
| struct internal_syment *sym, |
| const char *name) |
| { |
| bool hash; |
| bfd_size_type indx; |
| |
| hash = !info->traditional_format; |
| indx = _bfd_stringtab_add (strtab, name, hash, false); |
| |
| if (indx == (bfd_size_type) -1) |
| return false; |
| |
| sym->_n._n_n._n_zeroes = 0; |
| sym->_n._n_n._n_offset = STRING_SIZE_SIZE + indx; |
| |
| return true; |
| } |
| |
| static bool |
| _bfd_xcoff64_put_ldsymbol_name (bfd *abfd ATTRIBUTE_UNUSED, |
| struct xcoff_loader_info *ldinfo, |
| struct internal_ldsym *ldsym, |
| const char *name) |
| { |
| size_t len; |
| len = strlen (name); |
| |
| if (ldinfo->string_size + len + 3 > ldinfo->string_alc) |
| { |
| bfd_size_type newalc; |
| char *newstrings; |
| |
| newalc = ldinfo->string_alc * 2; |
| if (newalc == 0) |
| newalc = 32; |
| while (ldinfo->string_size + len + 3 > newalc) |
| newalc *= 2; |
| |
| newstrings = bfd_realloc (ldinfo->strings, newalc); |
| if (newstrings == NULL) |
| { |
| ldinfo->failed = true; |
| return false; |
| } |
| ldinfo->string_alc = newalc; |
| ldinfo->strings = newstrings; |
| } |
| |
| ldinfo->strings[ldinfo->string_size] = ((len + 1) >> 8) & 0xff; |
| ldinfo->strings[ldinfo->string_size + 1] = ((len + 1)) & 0xff; |
| strcpy (ldinfo->strings + ldinfo->string_size + 2, name); |
| ldsym->_l._l_l._l_zeroes = 0; |
| ldsym->_l._l_l._l_offset = ldinfo->string_size + 2; |
| ldinfo->string_size += len + 3; |
| |
| return true; |
| } |
| |
| /* Routines to swap information in the XCOFF .loader section. If we |
| ever need to write an XCOFF loader, this stuff will need to be |
| moved to another file shared by the linker (which XCOFF calls the |
| ``binder'') and the loader. */ |
| |
| /* Swap in the ldhdr structure. */ |
| |
| static void |
| xcoff64_swap_ldhdr_in (bfd *abfd, |
| const void *s, |
| struct internal_ldhdr *dst) |
| { |
| const struct external_ldhdr *src = (const struct external_ldhdr *) s; |
| |
| dst->l_version = bfd_get_32 (abfd, src->l_version); |
| dst->l_nsyms = bfd_get_32 (abfd, src->l_nsyms); |
| dst->l_nreloc = bfd_get_32 (abfd, src->l_nreloc); |
| dst->l_istlen = bfd_get_32 (abfd, src->l_istlen); |
| dst->l_nimpid = bfd_get_32 (abfd, src->l_nimpid); |
| dst->l_stlen = bfd_get_32 (abfd, src->l_stlen); |
| dst->l_impoff = bfd_get_64 (abfd, src->l_impoff); |
| dst->l_stoff = bfd_get_64 (abfd, src->l_stoff); |
| dst->l_symoff = bfd_get_64 (abfd, src->l_symoff); |
| dst->l_rldoff = bfd_get_64 (abfd, src->l_rldoff); |
| } |
| |
| /* Swap out the ldhdr structure. */ |
| |
| static void |
| xcoff64_swap_ldhdr_out (bfd *abfd, const struct internal_ldhdr *src, void *d) |
| { |
| struct external_ldhdr *dst = (struct external_ldhdr *) d; |
| |
| bfd_put_32 (abfd, (bfd_vma) src->l_version, dst->l_version); |
| bfd_put_32 (abfd, src->l_nsyms, dst->l_nsyms); |
| bfd_put_32 (abfd, src->l_nreloc, dst->l_nreloc); |
| bfd_put_32 (abfd, src->l_istlen, dst->l_istlen); |
| bfd_put_32 (abfd, src->l_nimpid, dst->l_nimpid); |
| bfd_put_32 (abfd, src->l_stlen, dst->l_stlen); |
| bfd_put_64 (abfd, src->l_impoff, dst->l_impoff); |
| bfd_put_64 (abfd, src->l_stoff, dst->l_stoff); |
| bfd_put_64 (abfd, src->l_symoff, dst->l_symoff); |
| bfd_put_64 (abfd, src->l_rldoff, dst->l_rldoff); |
| } |
| |
| /* Swap in the ldsym structure. */ |
| |
| static void |
| xcoff64_swap_ldsym_in (bfd *abfd, const void *s, struct internal_ldsym *dst) |
| { |
| const struct external_ldsym *src = (const struct external_ldsym *) s; |
| /* XCOFF64 does not use l_zeroes like XCOFF32 |
| Set the internal l_zeroes to 0 so the common 32/64 code uses l_value |
| as an offset into the loader symbol table. */ |
| dst->_l._l_l._l_zeroes = 0; |
| dst->_l._l_l._l_offset = bfd_get_32 (abfd, src->l_offset); |
| dst->l_value = bfd_get_64 (abfd, src->l_value); |
| dst->l_scnum = bfd_get_16 (abfd, src->l_scnum); |
| dst->l_smtype = bfd_get_8 (abfd, src->l_smtype); |
| dst->l_smclas = bfd_get_8 (abfd, src->l_smclas); |
| dst->l_ifile = bfd_get_32 (abfd, src->l_ifile); |
| dst->l_parm = bfd_get_32 (abfd, src->l_parm); |
| } |
| |
| /* Swap out the ldsym structure. */ |
| |
| static void |
| xcoff64_swap_ldsym_out (bfd *abfd, const struct internal_ldsym *src, void *d) |
| { |
| struct external_ldsym *dst = (struct external_ldsym *) d; |
| |
| bfd_put_64 (abfd, src->l_value, dst->l_value); |
| bfd_put_32 (abfd, (bfd_vma) src->_l._l_l._l_offset, dst->l_offset); |
| bfd_put_16 (abfd, (bfd_vma) src->l_scnum, dst->l_scnum); |
| bfd_put_8 (abfd, src->l_smtype, dst->l_smtype); |
| bfd_put_8 (abfd, src->l_smclas, dst->l_smclas); |
| bfd_put_32 (abfd, src->l_ifile, dst->l_ifile); |
| bfd_put_32 (abfd, src->l_parm, dst->l_parm); |
| } |
| |
| static void |
| xcoff64_swap_reloc_in (bfd *abfd, void *s, void *d) |
| { |
| struct external_reloc *src = (struct external_reloc *) s; |
| struct internal_reloc *dst = (struct internal_reloc *) d; |
| |
| memset (dst, 0, sizeof (struct internal_reloc)); |
| |
| dst->r_vaddr = bfd_get_64 (abfd, src->r_vaddr); |
| dst->r_symndx = bfd_get_32 (abfd, src->r_symndx); |
| dst->r_size = bfd_get_8 (abfd, src->r_size); |
| dst->r_type = bfd_get_8 (abfd, src->r_type); |
| } |
| |
| static unsigned int |
| xcoff64_swap_reloc_out (bfd *abfd, void *s, void *d) |
| { |
| struct internal_reloc *src = (struct internal_reloc *) s; |
| struct external_reloc *dst = (struct external_reloc *) d; |
| |
| bfd_put_64 (abfd, src->r_vaddr, dst->r_vaddr); |
| bfd_put_32 (abfd, src->r_symndx, dst->r_symndx); |
| bfd_put_8 (abfd, src->r_type, dst->r_type); |
| bfd_put_8 (abfd, src->r_size, dst->r_size); |
| |
| return bfd_coff_relsz (abfd); |
| } |
| |
| /* Swap in the ldrel structure. */ |
| |
| static void |
| xcoff64_swap_ldrel_in (bfd *abfd, const void *s, struct internal_ldrel *dst) |
| { |
| const struct external_ldrel *src = (const struct external_ldrel *) s; |
| |
| dst->l_vaddr = bfd_get_64 (abfd, src->l_vaddr); |
| dst->l_symndx = bfd_get_32 (abfd, src->l_symndx); |
| dst->l_rtype = bfd_get_16 (abfd, src->l_rtype); |
| dst->l_rsecnm = bfd_get_16 (abfd, src->l_rsecnm); |
| } |
| |
| /* Swap out the ldrel structure. */ |
| |
| static void |
| xcoff64_swap_ldrel_out (bfd *abfd, const struct internal_ldrel *src, void *d) |
| { |
| struct external_ldrel *dst = (struct external_ldrel *) d; |
| |
| bfd_put_64 (abfd, src->l_vaddr, dst->l_vaddr); |
| bfd_put_16 (abfd, (bfd_vma) src->l_rtype, dst->l_rtype); |
| bfd_put_16 (abfd, (bfd_vma) src->l_rsecnm, dst->l_rsecnm); |
| bfd_put_32 (abfd, src->l_symndx, dst->l_symndx); |
| } |
| |
| |
| static bool |
| xcoff64_reloc_type_br (bfd *input_bfd, |
| asection *input_section, |
| bfd *output_bfd ATTRIBUTE_UNUSED, |
| struct internal_reloc *rel, |
| struct internal_syment *sym ATTRIBUTE_UNUSED, |
| struct reloc_howto_struct *howto, |
| bfd_vma val, |
| bfd_vma addend, |
| bfd_vma *relocation, |
| bfd_byte *contents, |
| struct bfd_link_info *info) |
| { |
| struct xcoff_link_hash_entry *h; |
| bfd_vma section_offset; |
| struct xcoff_stub_hash_entry *stub_entry = NULL; |
| enum xcoff_stub_type stub_type; |
| |
| if (0 > rel->r_symndx) |
| return false; |
| |
| h = obj_xcoff_sym_hashes (input_bfd)[rel->r_symndx]; |
| section_offset = rel->r_vaddr - input_section->vma; |
| |
| /* If we see an R_BR or R_RBR reloc which is jumping to global |
| linkage code, and it is followed by an appropriate cror nop |
| instruction, we replace the cror with ld r2,40(r1). This |
| restores the TOC after the glink code. Contrariwise, if the |
| call is followed by a ld r2,40(r1), but the call is not |
| going to global linkage code, we can replace the load with a |
| cror. */ |
| if (NULL != h |
| && (bfd_link_hash_defined == h->root.type |
| || bfd_link_hash_defweak == h->root.type) |
| && section_offset + 8 <= input_section->size) |
| { |
| bfd_byte *pnext; |
| unsigned long next; |
| |
| pnext = contents + section_offset + 4; |
| next = bfd_get_32 (input_bfd, pnext); |
| |
| /* The _ptrgl function is magic. It is used by the AIX compiler to call |
| a function through a pointer. */ |
| if (h->smclas == XMC_GL || strcmp (h->root.root.string, "._ptrgl") == 0) |
| { |
| if (next == 0x4def7b82 /* cror 15,15,15 */ |
| || next == 0x4ffffb82 /* cror 31,31,31 */ |
| || next == 0x60000000) /* ori r0,r0,0 */ |
| bfd_put_32 (input_bfd, 0xe8410028, pnext); /* ld r2,40(r1) */ |
| } |
| else |
| { |
| if (next == 0xe8410028) /* ld r2,40(r1) */ |
| bfd_put_32 (input_bfd, 0x60000000, pnext); /* ori r0,r0,0 */ |
| } |
| } |
| else if (NULL != h && bfd_link_hash_undefined == h->root.type) |
| { |
| /* Normally, this relocation is against a defined symbol. In the |
| case where this is a partial link and the output section offset |
| is greater than 2^25, the linker will return an invalid error |
| message that the relocation has been truncated. Yes it has been |
| truncated but no it not important. For this case, disable the |
| overflow checking. */ |
| howto->complain_on_overflow = complain_overflow_dont; |
| } |
| |
| /* Check if a stub is needed. */ |
| stub_type = bfd_xcoff_type_of_stub (input_section, rel, val, h); |
| if (stub_type != xcoff_stub_none) |
| { |
| asection *stub_csect; |
| |
| stub_entry = bfd_xcoff_get_stub_entry (input_section, h, info); |
| if (stub_entry == NULL) |
| { |
| _bfd_error_handler (_("Unable to find the stub entry targeting %s"), |
| h->root.root.string); |
| bfd_set_error (bfd_error_bad_value); |
| return false; |
| } |
| |
| stub_csect = stub_entry->hcsect->root.u.def.section; |
| val = (stub_entry->stub_offset |
| + stub_csect->output_section->vma |
| + stub_csect->output_offset); |
| } |
| |
| /* The original PC-relative relocation is biased by -r_vaddr, so adding |
| the value below will give the absolute target address. */ |
| *relocation = val + addend + rel->r_vaddr; |
| |
| howto->src_mask &= ~3; |
| howto->dst_mask = howto->src_mask; |
| |
| if (h != NULL |
| && (h->root.type == bfd_link_hash_defined |
| || h->root.type == bfd_link_hash_defweak) |
| && bfd_is_abs_section (h->root.u.def.section) |
| && section_offset + 4 <= input_section->size) |
| { |
| bfd_byte *ptr; |
| bfd_vma insn; |
| |
| /* Turn the relative branch into an absolute one by setting the |
| AA bit. */ |
| ptr = contents + section_offset; |
| insn = bfd_get_32 (input_bfd, ptr); |
| insn |= 2; |
| bfd_put_32 (input_bfd, insn, ptr); |
| |
| /* Make the howto absolute too. */ |
| howto->pc_relative = false; |
| howto->complain_on_overflow = complain_overflow_bitfield; |
| } |
| else |
| { |
| /* Use a PC-relative howto and subtract the instruction's address |
| from the target address we calculated above. */ |
| howto->pc_relative = true; |
| *relocation -= (input_section->output_section->vma |
| + input_section->output_offset |
| + section_offset); |
| } |
| return true; |
| } |
| |
| |
| |
| /* The XCOFF reloc table. |
| Cf xcoff_howto_table comments. */ |
| |
| reloc_howto_type xcoff64_howto_table[] = |
| { |
| /* 0x00: Standard 64 bit relocation. */ |
| HOWTO (R_POS, /* type */ |
| 0, /* rightshift */ |
| 8, /* size */ |
| 64, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_POS_64", /* name */ |
| true, /* partial_inplace */ |
| MINUS_ONE, /* src_mask */ |
| MINUS_ONE, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x01: 64 bit relocation, but store negative value. */ |
| HOWTO (R_NEG, /* type */ |
| 0, /* rightshift */ |
| -8, /* size */ |
| 64, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_NEG", /* name */ |
| true, /* partial_inplace */ |
| MINUS_ONE, /* src_mask */ |
| MINUS_ONE, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x02: 64 bit PC relative relocation. */ |
| HOWTO (R_REL, /* type */ |
| 0, /* rightshift */ |
| 8, /* size */ |
| 64, /* bitsize */ |
| true, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_signed, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_REL", /* name */ |
| true, /* partial_inplace */ |
| MINUS_ONE, /* src_mask */ |
| MINUS_ONE, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x03: 16 bit TOC relative relocation. */ |
| HOWTO (R_TOC, /* type */ |
| 0, /* rightshift */ |
| 2, /* size */ |
| 16, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_TOC", /* name */ |
| true, /* partial_inplace */ |
| 0, /* src_mask */ |
| 0xffff, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x04: Same as R_TOC. */ |
| HOWTO (R_TRL, /* type */ |
| 0, /* rightshift */ |
| 2, /* size */ |
| 16, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_TRL", /* name */ |
| true, /* partial_inplace */ |
| 0, /* src_mask */ |
| 0xffff, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x05: External TOC relative symbol. */ |
| HOWTO (R_GL, /* type */ |
| 0, /* rightshift */ |
| 2, /* size */ |
| 16, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_GL", /* name */ |
| true, /* partial_inplace */ |
| 0, /* src_mask */ |
| 0xffff, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x06: Local TOC relative symbol. */ |
| HOWTO (R_TCL, /* type */ |
| 0, /* rightshift */ |
| 2, /* size */ |
| 16, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_TCL", /* name */ |
| true, /* partial_inplace */ |
| 0, /* src_mask */ |
| 0xffff, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| EMPTY_HOWTO (7), |
| |
| /* 0x08: Same as R_RBA. */ |
| HOWTO (R_BA, /* type */ |
| 0, /* rightshift */ |
| 4, /* size */ |
| 26, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_BA_26", /* name */ |
| true, /* partial_inplace */ |
| 0x03fffffc, /* src_mask */ |
| 0x03fffffc, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| EMPTY_HOWTO (9), |
| |
| /* 0x0a: Same as R_RBR. */ |
| HOWTO (R_BR, /* type */ |
| 0, /* rightshift */ |
| 4, /* size */ |
| 26, /* bitsize */ |
| true, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_signed, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_BR", /* name */ |
| true, /* partial_inplace */ |
| 0x03fffffc, /* src_mask */ |
| 0x03fffffc, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| EMPTY_HOWTO (0xb), |
| |
| /* 0x0c: Same as R_POS. */ |
| HOWTO (R_RL, /* type */ |
| 0, /* rightshift */ |
| 8, /* size */ |
| 64, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_RL", /* name */ |
| true, /* partial_inplace */ |
| MINUS_ONE, /* src_mask */ |
| MINUS_ONE, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x0d: Same as R_POS. */ |
| HOWTO (R_RLA, /* type */ |
| 0, /* rightshift */ |
| 8, /* size */ |
| 64, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_RLA", /* name */ |
| true, /* partial_inplace */ |
| MINUS_ONE, /* src_mask */ |
| MINUS_ONE, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| EMPTY_HOWTO (0xe), |
| |
| /* 0x0f: Non-relocating reference. Bitsize is 1 so that r_rsize is 0. */ |
| HOWTO (R_REF, /* type */ |
| 0, /* rightshift */ |
| 1, /* size */ |
| 1, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_dont, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_REF", /* name */ |
| false, /* partial_inplace */ |
| 0, /* src_mask */ |
| 0, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| EMPTY_HOWTO (0x10), |
| EMPTY_HOWTO (0x11), |
| EMPTY_HOWTO (0x12), |
| |
| /* 0x13: Same as R_TOC */ |
| HOWTO (R_TRLA, /* type */ |
| 0, /* rightshift */ |
| 2, /* size */ |
| 16, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_TRLA", /* name */ |
| true, /* partial_inplace */ |
| 0xffff, /* src_mask */ |
| 0xffff, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x14: Modifiable relative branch. */ |
| HOWTO (R_RRTBI, /* type */ |
| 1, /* rightshift */ |
| 4, /* size */ |
| 32, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_RRTBI", /* name */ |
| true, /* partial_inplace */ |
| 0xffffffff, /* src_mask */ |
| 0xffffffff, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x15: Modifiable absolute branch. */ |
| HOWTO (R_RRTBA, /* type */ |
| 1, /* rightshift */ |
| 4, /* size */ |
| 32, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_RRTBA", /* name */ |
| true, /* partial_inplace */ |
| 0xffffffff, /* src_mask */ |
| 0xffffffff, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x16: Modifiable call absolute indirect. */ |
| HOWTO (R_CAI, /* type */ |
| 0, /* rightshift */ |
| 2, /* size */ |
| 16, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_CAI", /* name */ |
| true, /* partial_inplace */ |
| 0xffff, /* src_mask */ |
| 0xffff, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x17: Modifiable call relative. */ |
| HOWTO (R_CREL, /* type */ |
| 0, /* rightshift */ |
| 2, /* size */ |
| 16, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_CREL", /* name */ |
| true, /* partial_inplace */ |
| 0xffff, /* src_mask */ |
| 0xffff, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x18: Modifiable branch absolute. */ |
| HOWTO (R_RBA, /* type */ |
| 0, /* rightshift */ |
| 4, /* size */ |
| 26, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_RBA", /* name */ |
| true, /* partial_inplace */ |
| 0x03fffffc, /* src_mask */ |
| 0x03fffffc, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x19: Modifiable branch absolute. */ |
| HOWTO (R_RBAC, /* type */ |
| 0, /* rightshift */ |
| 4, /* size */ |
| 32, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_RBAC", /* name */ |
| true, /* partial_inplace */ |
| 0xffffffff, /* src_mask */ |
| 0xffffffff, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x1a: Modifiable branch relative. */ |
| HOWTO (R_RBR, /* type */ |
| 0, /* rightshift */ |
| 4, /* size */ |
| 26, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_signed, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_RBR_26", /* name */ |
| true, /* partial_inplace */ |
| 0x03fffffc, /* src_mask */ |
| 0x03fffffc, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x1b: Modifiable branch absolute. */ |
| HOWTO (R_RBRC, /* type */ |
| 0, /* rightshift */ |
| 2, /* size */ |
| 16, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_RBRC", /* name */ |
| true, /* partial_inplace */ |
| 0xffff, /* src_mask */ |
| 0xffff, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x1c: Standard 32 bit relocation. */ |
| HOWTO (R_POS, /* type */ |
| 0, /* rightshift */ |
| 4, /* size */ |
| 32, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_POS_32", /* name */ |
| true, /* partial_inplace */ |
| 0xffffffff, /* src_mask */ |
| 0xffffffff, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x1d: 16 bit Non modifiable absolute branch. */ |
| HOWTO (R_BA, /* type */ |
| 0, /* rightshift */ |
| 2, /* size */ |
| 16, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_BA_16", /* name */ |
| true, /* partial_inplace */ |
| 0xfffc, /* src_mask */ |
| 0xfffc, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x1e: Modifiable branch relative. */ |
| HOWTO (R_RBR, /* type */ |
| 0, /* rightshift */ |
| 2, /* size */ |
| 16, /* bitsize */ |
| true, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_signed, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_RBR_16", /* name */ |
| true, /* partial_inplace */ |
| 0xfffc, /* src_mask */ |
| 0xfffc, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x1f: Modifiable branch absolute. */ |
| HOWTO (R_RBA, /* type */ |
| 0, /* rightshift */ |
| 2, /* size */ |
| 16, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_RBA_16", /* name */ |
| true, /* partial_inplace */ |
| 0xffff, /* src_mask */ |
| 0xffff, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x20: General-dynamic TLS relocation. */ |
| HOWTO (R_TLS, /* type */ |
| 0, /* rightshift */ |
| 8, /* size */ |
| 64, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_TLS", /* name */ |
| true, /* partial_inplace */ |
| MINUS_ONE, /* src_mask */ |
| MINUS_ONE, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x21: Initial-exec TLS relocation. */ |
| HOWTO (R_TLS_IE, /* type */ |
| 0, /* rightshift */ |
| 8, /* size */ |
| 64, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_TLS_IE", /* name */ |
| true, /* partial_inplace */ |
| MINUS_ONE, /* src_mask */ |
| MINUS_ONE, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x22: Local-dynamic TLS relocation. */ |
| HOWTO (R_TLS_LD, /* type */ |
| 0, /* rightshift */ |
| 8, /* size */ |
| 64, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_TLS_LD", /* name */ |
| true, /* partial_inplace */ |
| MINUS_ONE, /* src_mask */ |
| MINUS_ONE, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x23: Local-exec TLS relocation. */ |
| HOWTO (R_TLS_LE, /* type */ |
| 0, /* rightshift */ |
| 8, /* size */ |
| 64, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_TLS_LE", /* name */ |
| true, /* partial_inplace */ |
| MINUS_ONE, /* src_mask */ |
| MINUS_ONE, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x24: TLS relocation. */ |
| HOWTO (R_TLSM, /* type */ |
| 0, /* rightshift */ |
| 8, /* size */ |
| 64, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_TLSM", /* name */ |
| true, /* partial_inplace */ |
| MINUS_ONE, /* src_mask */ |
| MINUS_ONE, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x25: TLS module relocation. */ |
| HOWTO (R_TLSML, /* type */ |
| 0, /* rightshift */ |
| 8, /* size */ |
| 64, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_TLSML", /* name */ |
| true, /* partial_inplace */ |
| MINUS_ONE, /* src_mask */ |
| MINUS_ONE, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x26: 32 bit relocation, but store negative value. */ |
| HOWTO (R_NEG, /* type */ |
| 0, /* rightshift */ |
| -4, /* size */ |
| 32, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_NEG_32", /* name */ |
| true, /* partial_inplace */ |
| MINUS_ONE, /* src_mask */ |
| MINUS_ONE, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| EMPTY_HOWTO(0x27), |
| EMPTY_HOWTO(0x28), |
| EMPTY_HOWTO(0x29), |
| EMPTY_HOWTO(0x2a), |
| EMPTY_HOWTO(0x2b), |
| EMPTY_HOWTO(0x2c), |
| EMPTY_HOWTO(0x2d), |
| EMPTY_HOWTO(0x2e), |
| EMPTY_HOWTO(0x2f), |
| |
| HOWTO (R_TOCU, /* type */ |
| 16, /* rightshift */ |
| 2, /* size */ |
| 16, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_TOCU", /* name */ |
| true, /* partial_inplace */ |
| 0, /* src_mask */ |
| 0xffff, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| /* 0x31: Low-order 16 bit TOC relative relocation. */ |
| HOWTO (R_TOCL, /* type */ |
| 0, /* rightshift */ |
| 2, /* size */ |
| 16, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_dont, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_TOCL", /* name */ |
| true, /* partial_inplace */ |
| 0, /* src_mask */ |
| 0xffff, /* dst_mask */ |
| false), /* pcrel_offset */ |
| |
| }; |
| |
| void |
| xcoff64_rtype2howto (arelent *relent, struct internal_reloc *internal) |
| { |
| if (internal->r_type > R_TOCL) |
| abort (); |
| |
| /* Default howto layout works most of the time */ |
| relent->howto = &xcoff64_howto_table[internal->r_type]; |
| |
| /* Special case some 16 bit reloc */ |
| if (15 == (internal->r_size & 0x3f)) |
| { |
| if (R_BA == internal->r_type) |
| relent->howto = &xcoff64_howto_table[0x1d]; |
| else if (R_RBR == internal->r_type) |
| relent->howto = &xcoff64_howto_table[0x1e]; |
| else if (R_RBA == internal->r_type) |
| relent->howto = &xcoff64_howto_table[0x1f]; |
| } |
| /* Special case 32 bit */ |
| else if (31 == (internal->r_size & 0x3f)) |
| { |
| if (R_POS == internal->r_type) |
| relent->howto = &xcoff64_howto_table[0x1c]; |
| |
| if (R_NEG == internal->r_type) |
| relent->howto = &xcoff64_howto_table[0x26]; |
| } |
| |
| /* The r_size field of an XCOFF reloc encodes the bitsize of the |
| relocation, as well as indicating whether it is signed or not. |
| Doublecheck that the relocation information gathered from the |
| type matches this information. The bitsize is not significant |
| for R_REF relocs. */ |
| if (relent->howto->dst_mask != 0 |
| && (relent->howto->bitsize |
| != ((unsigned int) internal->r_size & 0x3f) + 1)) |
| abort (); |
| } |
| |
| reloc_howto_type * |
| xcoff64_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, |
| bfd_reloc_code_real_type code) |
| { |
| switch (code) |
| { |
| case BFD_RELOC_PPC_B26: |
| return &xcoff64_howto_table[0xa]; |
| case BFD_RELOC_PPC_BA16: |
| return &xcoff64_howto_table[0x1d]; |
| case BFD_RELOC_PPC_BA26: |
| return &xcoff64_howto_table[8]; |
| case BFD_RELOC_PPC_TOC16: |
| return &xcoff64_howto_table[3]; |
| case BFD_RELOC_PPC_TOC16_HI: |
| return &xcoff64_howto_table[0x30]; |
| case BFD_RELOC_PPC_TOC16_LO: |
| return &xcoff64_howto_table[0x31]; |
| case BFD_RELOC_PPC_B16: |
| return &xcoff64_howto_table[0x1e]; |
| case BFD_RELOC_32: |
| case BFD_RELOC_CTOR: |
| return &xcoff64_howto_table[0x1c]; |
| case BFD_RELOC_64: |
| return &xcoff64_howto_table[0]; |
| case BFD_RELOC_NONE: |
| return &xcoff64_howto_table[0xf]; |
| case BFD_RELOC_PPC_NEG: |
| return &xcoff64_howto_table[0x1]; |
| case BFD_RELOC_PPC64_TLSGD: |
| return &xcoff64_howto_table[0x20]; |
| case BFD_RELOC_PPC64_TLSIE: |
| return &xcoff64_howto_table[0x21]; |
| case BFD_RELOC_PPC64_TLSLD: |
| return &xcoff64_howto_table[0x22]; |
| case BFD_RELOC_PPC64_TLSLE: |
| return &xcoff64_howto_table[0x23]; |
| case BFD_RELOC_PPC64_TLSM: |
| return &xcoff64_howto_table[0x24]; |
| case BFD_RELOC_PPC64_TLSML: |
| return &xcoff64_howto_table[0x25]; |
| default: |
| return NULL; |
| } |
| } |
| |
| static reloc_howto_type * |
| xcoff64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, |
| const char *r_name) |
| { |
| unsigned int i; |
| |
| for (i = 0; |
| i < sizeof (xcoff64_howto_table) / sizeof (xcoff64_howto_table[0]); |
| i++) |
| if (xcoff64_howto_table[i].name != NULL |
| && strcasecmp (xcoff64_howto_table[i].name, r_name) == 0) |
| return &xcoff64_howto_table[i]; |
| |
| return NULL; |
| } |
| |
| /* This is the relocation function for the PowerPC64. |
| See xcoff_ppc_relocation_section for more information. */ |
| |
| bool |
| xcoff64_ppc_relocate_section (bfd *output_bfd, |
| struct bfd_link_info *info, |
| bfd *input_bfd, |
| asection *input_section, |
| bfd_byte *contents, |
| struct internal_reloc *relocs, |
| struct internal_syment *syms, |
| asection **sections) |
| { |
| struct internal_reloc *rel; |
| struct internal_reloc *relend; |
| |
| rel = relocs; |
| relend = rel + input_section->reloc_count; |
| for (; rel < relend; rel++) |
| { |
| long symndx; |
| struct xcoff_link_hash_entry *h; |
| struct internal_syment *sym; |
| bfd_vma addend; |
| bfd_vma val; |
| struct reloc_howto_struct howto; |
| bfd_vma relocation; |
| bfd_vma value_to_relocate; |
| bfd_vma address; |
| bfd_byte *location; |
| |
| /* Relocation type R_REF is a special relocation type which is |
| merely used to prevent garbage collection from occurring for |
| the csect including the symbol which it references. */ |
| if (rel->r_type == R_REF) |
| continue; |
| |
| /* Retrieve default value in HOWTO table and fix up according |
| to r_size field, if it can be different. |
| This should be made during relocation reading but the algorithms |
| are expecting constant howtos. */ |
| memcpy (&howto, &xcoff64_howto_table[rel->r_type], sizeof (howto)); |
| if (howto.bitsize != (rel->r_size & 0x3f) + 1) |
| { |
| switch (rel->r_type) |
| { |
| case R_POS: |
| case R_NEG: |
| howto.bitsize = (rel->r_size & 0x3f) + 1; |
| howto.size = HOWTO_RSIZE (howto.bitsize <= 16 |
| ? 2 : howto.bitsize <= 32 |
| ? 4 : 8); |
| howto.src_mask = howto.dst_mask = N_ONES (howto.bitsize); |
| break; |
| |
| default: |
| _bfd_error_handler |
| (_("%pB: relocation (%d) at (0x%" PRIx64 ") has wrong" |
| " r_rsize (0x%x)\n"), |
| input_bfd, rel->r_type, rel->r_vaddr, rel->r_size); |
| return false; |
| } |
| } |
| |
| howto.complain_on_overflow = (rel->r_size & 0x80 |
| ? complain_overflow_signed |
| : complain_overflow_bitfield); |
| |
| /* symbol */ |
| val = 0; |
| addend = 0; |
| h = NULL; |
| sym = NULL; |
| symndx = rel->r_symndx; |
| |
| if (-1 != symndx) |
| { |
| asection *sec; |
| |
| h = obj_xcoff_sym_hashes (input_bfd)[symndx]; |
| sym = syms + symndx; |
| addend = - sym->n_value; |
| |
| if (NULL == h) |
| { |
| sec = sections[symndx]; |
| /* Hack to make sure we use the right TOC anchor value |
| if this reloc is against the TOC anchor. */ |
| if (sec->name[3] == '0' |
| && strcmp (sec->name, ".tc0") == 0) |
| val = xcoff_data (output_bfd)->toc; |
| else |
| val = (sec->output_section->vma |
| + sec->output_offset |
| + sym->n_value |
| - sec->vma); |
| } |
| else |
| { |
| if (info->unresolved_syms_in_objects != RM_IGNORE |
| && (h->flags & XCOFF_WAS_UNDEFINED) != 0) |
| info->callbacks->undefined_symbol |
| (info, h->root.root.string, input_bfd, input_section, |
| rel->r_vaddr - input_section->vma, |
| info->unresolved_syms_in_objects == RM_DIAGNOSE |
| && !info->warn_unresolved_syms); |
| |
| if (h->root.type == bfd_link_hash_defined |
| || h->root.type == bfd_link_hash_defweak) |
| { |
| sec = h->root.u.def.section; |
| val = (h->root.u.def.value |
| + sec->output_section->vma |
| + sec->output_offset); |
| } |
| else if (h->root.type == bfd_link_hash_common) |
| { |
| sec = h->root.u.c.p->section; |
| val = (sec->output_section->vma |
| + sec->output_offset); |
| } |
| else |
| { |
| BFD_ASSERT (bfd_link_relocatable (info) |
| || (h->flags & XCOFF_DEF_DYNAMIC) != 0 |
| || (h->flags & XCOFF_IMPORT) != 0); |
| } |
| } |
| } |
| |
| if (rel->r_type >= XCOFF_MAX_CALCULATE_RELOCATION |
| || !((*xcoff64_calculate_relocation[rel->r_type]) |
| (input_bfd, input_section, output_bfd, rel, sym, &howto, val, |
| addend, &relocation, contents, info))) |
| return false; |
| |
| /* address */ |
| address = rel->r_vaddr - input_section->vma; |
| location = contents + address; |
| |
| if (address > input_section->size) |
| abort (); |
| |
| /* Get the value we are going to relocate. */ |
| switch (bfd_get_reloc_size (&howto)) |
| { |
| case 2: |
| value_to_relocate = bfd_get_16 (input_bfd, location); |
| break; |
| case 4: |
| value_to_relocate = bfd_get_32 (input_bfd, location); |
| break; |
| default: |
| value_to_relocate = bfd_get_64 (input_bfd, location); |
| break; |
| } |
| |
| /* overflow. |
| |
| FIXME: We may drop bits during the addition |
| which we don't check for. We must either check at every single |
| operation, which would be tedious, or we must do the computations |
| in a type larger than bfd_vma, which would be inefficient. */ |
| |
| if (((*xcoff_complain_overflow[howto.complain_on_overflow]) |
| (input_bfd, value_to_relocate, relocation, &howto))) |
| { |
| const char *name; |
| char buf[SYMNMLEN + 1]; |
| char reloc_type_name[10]; |
| |
| if (symndx == -1) |
| { |
| name = "*ABS*"; |
| } |
| else if (h != NULL) |
| { |
| name = NULL; |
| } |
| else |
| { |
| name = _bfd_coff_internal_syment_name (input_bfd, sym, buf); |
| if (name == NULL) |
| name = "UNKNOWN"; |
| } |
| sprintf (reloc_type_name, "0x%02x", rel->r_type); |
| |
| (*info->callbacks->reloc_overflow) |
| (info, (h ? &h->root : NULL), name, reloc_type_name, |
| (bfd_vma) 0, input_bfd, input_section, |
| rel->r_vaddr - input_section->vma); |
| } |
| |
| /* Add RELOCATION to the right bits of VALUE_TO_RELOCATE. */ |
| value_to_relocate = ((value_to_relocate & ~howto.dst_mask) |
| | (((value_to_relocate & howto.src_mask) |
| + relocation) & howto.dst_mask)); |
| |
| /* Put the value back in the object file. */ |
| switch (bfd_get_reloc_size (&howto)) |
| { |
| case 2: |
| bfd_put_16 (input_bfd, value_to_relocate, location); |
| break; |
| case 4: |
| bfd_put_32 (input_bfd, value_to_relocate, location); |
| break; |
| default: |
| bfd_put_64 (input_bfd, value_to_relocate, location); |
| break; |
| } |
| } |
| return true; |
| } |
| |
| |
| /* PR 21786: The PE/COFF standard does not require NUL termination for any of |
| the ASCII fields in the archive headers. So in order to be able to extract |
| numerical values we provide our own versions of strtol and strtoll which |
| take a maximum length as an additional parameter. Also - just to save space, |
| we omit the endptr return parameter, since we know that it is never used. */ |
| |
| static long |
| _bfd_strntol (const char * nptr, int base, unsigned int maxlen) |
| { |
| char buf[24]; /* Should be enough. */ |
| |
| BFD_ASSERT (maxlen < (sizeof (buf) - 1)); |
| |
| memcpy (buf, nptr, maxlen); |
| buf[maxlen] = 0; |
| return strtol (buf, NULL, base); |
| } |
| |
| static long long |
| _bfd_strntoll (const char * nptr, int base, unsigned int maxlen) |
| { |
| char buf[32]; /* Should be enough. */ |
| |
| BFD_ASSERT (maxlen < (sizeof (buf) - 1)); |
| |
| memcpy (buf, nptr, maxlen); |
| buf[maxlen] = 0; |
| return strtoll (buf, NULL, base); |
| } |
| |
| /* Macro to read an ASCII value stored in an archive header field. */ |
| #define GET_VALUE_IN_FIELD(VAR, FIELD, BASE) \ |
| do \ |
| { \ |
| (VAR) = (sizeof (VAR) > sizeof (long) \ |
| ? _bfd_strntoll (FIELD, BASE, sizeof FIELD) \ |
| : _bfd_strntol (FIELD, BASE, sizeof FIELD)); \ |
| } \ |
| while (0) |
| |
| /* Read in the armap of an XCOFF archive. */ |
| |
| static bool |
| xcoff64_slurp_armap (bfd *abfd) |
| { |
| file_ptr off; |
| size_t namlen; |
| bfd_size_type sz, amt; |
| bfd_byte *contents, *cend; |
| bfd_vma c, i; |
| carsym *arsym; |
| bfd_byte *p; |
| file_ptr pos; |
| |
| /* This is for the new format. */ |
| struct xcoff_ar_hdr_big hdr; |
| |
| if (x_artdata (abfd) == NULL) |
| { |
| abfd->has_armap = false; |
| return true; |
| } |
| |
| off = bfd_scan_vma (x_artdata (abfd)->u.bhdr.symoff64, |
| (const char **) NULL, 10); |
| if (off == 0) |
| { |
| abfd->has_armap = false; |
| return true; |
| } |
| |
| if (bfd_seek (abfd, off, SEEK_SET) != 0) |
| return false; |
| |
| /* The symbol table starts with a normal archive header. */ |
| if (bfd_read (&hdr, SIZEOF_AR_HDR_BIG, abfd) != SIZEOF_AR_HDR_BIG) |
| return false; |
| |
| /* Skip the name (normally empty). */ |
| GET_VALUE_IN_FIELD (namlen, hdr.namlen, 10); |
| pos = ((namlen + 1) & ~(size_t) 1) + SXCOFFARFMAG; |
| if (bfd_seek (abfd, pos, SEEK_CUR) != 0) |
| return false; |
| |
| sz = bfd_scan_vma (hdr.size, (const char **) NULL, 10); |
| if (sz + 1 < 9) |
| { |
| bfd_set_error (bfd_error_bad_value); |
| return false; |
| } |
| |
| /* Read in the entire symbol table. */ |
| contents = (bfd_byte *) _bfd_alloc_and_read (abfd, sz + 1, sz); |
| if (contents == NULL) |
| return false; |
| |
| /* Ensure strings are NULL terminated so we don't wander off the end |
| of the buffer. */ |
| contents[sz] = 0; |
| |
| /* The symbol table starts with an eight byte count. */ |
| c = H_GET_64 (abfd, contents); |
| |
| if (c >= sz / 8) |
| { |
| bfd_set_error (bfd_error_bad_value); |
| return false; |
| } |
| amt = c; |
| amt *= sizeof (carsym); |
| bfd_ardata (abfd)->symdefs = (carsym *) bfd_alloc (abfd, amt); |
| if (bfd_ardata (abfd)->symdefs == NULL) |
| return false; |
| |
| /* After the count comes a list of eight byte file offsets. */ |
| for (i = 0, arsym = bfd_ardata (abfd)->symdefs, p = contents + 8; |
| i < c; |
| ++i, ++arsym, p += 8) |
| arsym->file_offset = H_GET_64 (abfd, p); |
| |
| /* After the file offsets come null terminated symbol names. */ |
| cend = contents + sz; |
| for (i = 0, arsym = bfd_ardata (abfd)->symdefs; |
| i < c; |
| ++i, ++arsym, p += strlen ((char *) p) + 1) |
| { |
| if (p >= cend) |
| { |
| bfd_set_error (bfd_error_bad_value); |
| return false; |
| } |
| arsym->name = (char *) p; |
| } |
| |
| bfd_ardata (abfd)->symdef_count = c; |
| abfd->has_armap = true; |
| |
| return true; |
| } |
| |
| |
| /* See if this is an NEW XCOFF archive. */ |
| |
| static bfd_cleanup |
| xcoff64_archive_p (bfd *abfd) |
| { |
| struct artdata *tdata_hold; |
| char magic[SXCOFFARMAG]; |
| /* This is the new format. */ |
| struct xcoff_ar_file_hdr_big hdr; |
| size_t amt = SXCOFFARMAG; |
| |
| if (bfd_read (magic, amt, abfd) != amt) |
| { |
| if (bfd_get_error () != bfd_error_system_call) |
| bfd_set_error (bfd_error_wrong_format); |
| return NULL; |
| } |
| |
| if (strncmp (magic, XCOFFARMAGBIG, SXCOFFARMAG) != 0) |
| { |
| bfd_set_error (bfd_error_wrong_format); |
| return NULL; |
| } |
| |
| /* Copy over the magic string. */ |
| memcpy (hdr.magic, magic, SXCOFFARMAG); |
| |
| /* Now read the rest of the file header. */ |
| amt = SIZEOF_AR_FILE_HDR_BIG - SXCOFFARMAG; |
| if (bfd_read (&hdr.memoff, amt, abfd) != amt) |
| { |
| if (bfd_get_error () != bfd_error_system_call) |
| bfd_set_error (bfd_error_wrong_format); |
| return NULL; |
| } |
| |
| tdata_hold = bfd_ardata (abfd); |
| |
| amt = sizeof (struct artdata); |
| bfd_ardata (abfd) = (struct artdata *) bfd_zalloc (abfd, amt); |
| if (bfd_ardata (abfd) == (struct artdata *) NULL) |
| goto error_ret_restore; |
| |
| bfd_ardata (abfd)->first_file_filepos = bfd_scan_vma (hdr.firstmemoff, |
| (const char **) NULL, |
| 10); |
| |
| amt = sizeof (struct xcoff_artdata); |
| bfd_ardata (abfd)->tdata = bfd_zalloc (abfd, amt); |
| if (bfd_ardata (abfd)->tdata == NULL) |
| goto error_ret; |
| |
| memcpy (&x_artdata (abfd)->u.bhdr, &hdr, SIZEOF_AR_FILE_HDR_BIG); |
| |
| if (! xcoff64_slurp_armap (abfd)) |
| { |
| error_ret: |
| bfd_release (abfd, bfd_ardata (abfd)); |
| error_ret_restore: |
| bfd_ardata (abfd) = tdata_hold; |
| return NULL; |
| } |
| |
| return _bfd_no_cleanup; |
| } |
| |
| |
| /* Open the next element in an XCOFF archive. */ |
| |
| static bfd * |
| xcoff64_openr_next_archived_file (bfd *archive, bfd *last_file) |
| { |
| if (x_artdata (archive) == NULL |
| || ! xcoff_big_format_p (archive)) |
| { |
| bfd_set_error (bfd_error_invalid_operation); |
| return NULL; |
| } |
| |
| return _bfd_xcoff_openr_next_archived_file (archive, last_file); |
| } |
| |
| /* We can't use the usual coff_sizeof_headers routine, because AIX |
| always uses an a.out header. */ |
| |
| static int |
| xcoff64_sizeof_headers (bfd *abfd, |
| struct bfd_link_info *info ATTRIBUTE_UNUSED) |
| { |
| int size; |
| |
| size = bfd_coff_filhsz (abfd); |
| |
| /* Don't think the small aout header can be used since some of the |
| old elements have been reordered past the end of the old coff |
| small aout size. */ |
| |
| if (xcoff_data (abfd)->full_aouthdr) |
| size += bfd_coff_aoutsz (abfd); |
| |
| size += abfd->section_count * bfd_coff_scnhsz (abfd); |
| return size; |
| } |
| |
| static asection * |
| xcoff64_create_csect_from_smclas (bfd *abfd, union internal_auxent *aux, |
| const char *symbol_name) |
| { |
| asection *return_value = NULL; |
| |
| /* Changes from 32 : |
| .sv == 8, is only for 32 bit programs |
| .ti == 12 and .tb == 13 are now reserved. */ |
| static const char * const names[] = |
| { |
| ".pr", ".ro", ".db", ".tc", ".ua", ".rw", ".gl", ".xo", |
| NULL, ".bs", ".ds", ".uc", NULL, NULL, NULL, ".tc0", |
| ".td", ".sv64", ".sv3264", NULL, ".tl", ".ul", ".te" |
| }; |
| |
| if ((aux->x_csect.x_smclas < ARRAY_SIZE (names)) |
| && (NULL != names[aux->x_csect.x_smclas])) |
| { |
| |
| return_value = bfd_make_section_anyway |
| (abfd, names[aux->x_csect.x_smclas]); |
| |
| } |
| else |
| { |
| _bfd_error_handler |
| /* xgettext: c-format */ |
| (_("%pB: symbol `%s' has unrecognized smclas %d"), |
| abfd, symbol_name, aux->x_csect.x_smclas); |
| bfd_set_error (bfd_error_bad_value); |
| } |
| |
| return return_value; |
| } |
| |
| static bool |
| xcoff64_is_lineno_count_overflow (bfd *abfd ATTRIBUTE_UNUSED, |
| bfd_vma value ATTRIBUTE_UNUSED) |
| { |
| return false; |
| } |
| |
| static bool |
| xcoff64_is_reloc_count_overflow (bfd *abfd ATTRIBUTE_UNUSED, |
| bfd_vma value ATTRIBUTE_UNUSED) |
| { |
| return false; |
| } |
| |
| static bfd_vma |
| xcoff64_loader_symbol_offset (bfd *abfd ATTRIBUTE_UNUSED, |
| struct internal_ldhdr *ldhdr) |
| { |
| return (ldhdr->l_symoff); |
| } |
| |
| static bfd_vma |
| xcoff64_loader_reloc_offset (bfd *abfd ATTRIBUTE_UNUSED, |
| struct internal_ldhdr *ldhdr) |
| { |
| return (ldhdr->l_rldoff); |
| } |
| |
| static bool |
| xcoff64_bad_format_hook (bfd * abfd, void *filehdr) |
| { |
| struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; |
| |
| /* Check flavor first. */ |
| if (bfd_get_flavour (abfd) != bfd_target_xcoff_flavour) |
| return false; |
| |
| if (bfd_xcoff_magic_number (abfd) != internal_f->f_magic) |
| return false; |
| |
| return true; |
| } |
| |
| static bool |
| xcoff64_generate_rtinit (bfd *abfd, const char *init, const char *fini, |
| bool rtld) |
| { |
| bfd_byte filehdr_ext[FILHSZ]; |
| bfd_byte scnhdr_ext[SCNHSZ * 3]; |
| bfd_byte syment_ext[SYMESZ * 10]; |
| bfd_byte reloc_ext[RELSZ * 3]; |
| bfd_byte *data_buffer; |
| bfd_size_type data_buffer_size; |
| bfd_byte *string_table, *st_tmp; |
| bfd_size_type string_table_size; |
| bfd_vma val; |
| size_t initsz, finisz; |
| struct internal_filehdr filehdr; |
| struct internal_scnhdr text_scnhdr; |
| struct internal_scnhdr data_scnhdr; |
| struct internal_scnhdr bss_scnhdr; |
| struct internal_syment syment; |
| union internal_auxent auxent; |
| struct internal_reloc reloc; |
| |
| char *text_name = ".text"; |
| char *data_name = ".data"; |
| char *bss_name = ".bss"; |
| char *rtinit_name = "__rtinit"; |
| char *rtld_name = "__rtld"; |
| |
| if (! bfd_xcoff_rtinit_size (abfd)) |
| return false; |
| |
| initsz = (init == NULL ? 0 : 1 + strlen (init)); |
| finisz = (fini == NULL ? 0 : 1 + strlen (fini)); |
| |
| /* File header. */ |
| memset (filehdr_ext, 0, FILHSZ); |
| memset (&filehdr, 0, sizeof (struct internal_filehdr)); |
| filehdr.f_magic = bfd_xcoff_magic_number (abfd); |
| filehdr.f_nscns = 3; |
| filehdr.f_timdat = 0; |
| filehdr.f_nsyms = 0; /* at least 6, no more than 8 */ |
| filehdr.f_symptr = 0; /* set below */ |
| filehdr.f_opthdr = 0; |
| filehdr.f_flags = 0; |
| |
| /* Section headers. */ |
| memset (scnhdr_ext, 0, 3 * SCNHSZ); |
| |
| /* Text. */ |
| memset (&text_scnhdr, 0, sizeof (struct internal_scnhdr)); |
| memcpy (text_scnhdr.s_name, text_name, strlen (text_name)); |
| text_scnhdr.s_paddr = 0; |
| text_scnhdr.s_vaddr = 0; |
| text_scnhdr.s_size = 0; |
| text_scnhdr.s_scnptr = 0; |
| text_scnhdr.s_relptr = 0; |
| text_scnhdr.s_lnnoptr = 0; |
| text_scnhdr.s_nreloc = 0; |
| text_scnhdr.s_nlnno = 0; |
| text_scnhdr.s_flags = STYP_TEXT; |
| |
| /* Data. */ |
| memset (&data_scnhdr, 0, sizeof (struct internal_scnhdr)); |
| memcpy (data_scnhdr.s_name, data_name, strlen (data_name)); |
| data_scnhdr.s_paddr = 0; |
| data_scnhdr.s_vaddr = 0; |
| data_scnhdr.s_size = 0; /* set below */ |
| data_scnhdr.s_scnptr = FILHSZ + 3 * SCNHSZ; |
| data_scnhdr.s_relptr = 0; /* set below */ |
| data_scnhdr.s_lnnoptr = 0; |
| data_scnhdr.s_nreloc = 0; /* either 1 or 2 */ |
| data_scnhdr.s_nlnno = 0; |
| data_scnhdr.s_flags = STYP_DATA; |
| |
| /* Bss. */ |
| memset (&bss_scnhdr, 0, sizeof (struct internal_scnhdr)); |
| memcpy (bss_scnhdr.s_name, bss_name, strlen (bss_name)); |
| bss_scnhdr.s_paddr = 0; /* set below */ |
| bss_scnhdr.s_vaddr = 0; /* set below */ |
| bss_scnhdr.s_size = 0; /* set below */ |
| bss_scnhdr.s_scnptr = 0; |
| bss_scnhdr.s_relptr = 0; |
| bss_scnhdr.s_lnnoptr = 0; |
| bss_scnhdr.s_nreloc = 0; |
| bss_scnhdr.s_nlnno = 0; |
| bss_scnhdr.s_flags = STYP_BSS; |
| |
| /* .data |
| 0x0000 0x00000000 : rtl |
| 0x0004 0x00000000 : |
| 0x0008 0x00000018 : offset to init, or 0 |
| 0x000C 0x00000038 : offset to fini, or 0 |
| 0x0010 0x00000010 : size of descriptor |
| 0x0014 0x00000000 : pad |
| 0x0018 0x00000000 : init, needs a reloc |
| 0x001C 0x00000000 : |
| 0x0020 0x00000058 : offset to init name |
| 0x0024 0x00000000 : flags, padded to a word |
| 0x0028 0x00000000 : empty init |
| 0x002C 0x00000000 : |
| 0x0030 0x00000000 : |
| 0x0034 0x00000000 : |
| 0x0038 0x00000000 : fini, needs a reloc |
| 0x003C 0x00000000 : |
| 0x0040 0x00000??? : offset to fini name |
| 0x0044 0x00000000 : flags, padded to a word |
| 0x0048 0x00000000 : empty fini |
| 0x004C 0x00000000 : |
| 0x0050 0x00000000 : |
| 0x0054 0x00000000 : |
| 0x0058 init name |
| 0x0058 + initsz fini name */ |
| |
| data_buffer_size = 0x0058 + initsz + finisz; |
| data_buffer_size = (data_buffer_size + 7) &~ (bfd_size_type) 7; |
| data_buffer = NULL; |
| data_buffer = (bfd_byte *) bfd_zmalloc (data_buffer_size); |
| if (data_buffer == NULL) |
| return false; |
| |
| if (initsz) |
| { |
| val = 0x18; |
| bfd_put_32 (abfd, val, &data_buffer[0x08]); |
| val = 0x58; |
| bfd_put_32 (abfd, val, &data_buffer[0x20]); |
| memcpy (&data_buffer[val], init, initsz); |
| } |
| |
| if (finisz) |
| { |
| val = 0x38; |
| bfd_put_32 (abfd, val, &data_buffer[0x0C]); |
| val = 0x58 + initsz; |
| bfd_put_32 (abfd, val, &data_buffer[0x40]); |
| memcpy (&data_buffer[val], fini, finisz); |
| } |
| |
| val = 0x10; |
| bfd_put_32 (abfd, val, &data_buffer[0x10]); |
| data_scnhdr.s_size = data_buffer_size; |
| bss_scnhdr.s_paddr = bss_scnhdr.s_vaddr = data_scnhdr.s_size; |
| |
| /* String table. */ |
| string_table_size = 4; |
| string_table_size += strlen (data_name) + 1; |
| string_table_size += strlen (rtinit_name) + 1; |
| string_table_size += initsz; |
| string_table_size += finisz; |
| if (rtld) |
| string_table_size += strlen (rtld_name) + 1; |
| |
| string_table = (bfd_byte *) bfd_zmalloc (string_table_size); |
| if (string_table == NULL) |
| { |
| free (data_buffer); |
| return false; |
| } |
| |
| val = string_table_size; |
| bfd_put_32 (abfd, val, &string_table[0]); |
| st_tmp = string_table + 4; |
| |
| /* symbols |
| 0. .data csect |
| 2. __rtinit |
| 4. init function |
| 6. fini function |
| 8. __rtld */ |
| memset (syment_ext, 0, 10 * SYMESZ); |
| memset (reloc_ext, 0, 3 * RELSZ); |
| |
| /* .data csect */ |
| memset (&syment, 0, sizeof (struct internal_syment)); |
| memset (&auxent, 0, sizeof (union internal_auxent)); |
| |
| syment._n._n_n._n_offset = st_tmp - string_table; |
| memcpy (st_tmp, data_name, strlen (data_name)); |
| st_tmp += strlen (data_name) + 1; |
| |
| syment.n_scnum = 2; |
| syment.n_sclass = C_HIDEXT; |
| syment.n_numaux = 1; |
| auxent.x_csect.x_scnlen.u64 = data_buffer_size; |
| auxent.x_csect.x_smtyp = 3 << 3 | XTY_SD; |
| auxent.x_csect.x_smclas = XMC_RW; |
| bfd_coff_swap_sym_out (abfd, &syment, |
| &syment_ext[filehdr.f_nsyms * SYMESZ]); |
| bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0, |
| syment.n_numaux, |
| &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]); |
| filehdr.f_nsyms += 2; |
| |
| /* __rtinit */ |
| memset (&syment, 0, sizeof (struct internal_syment)); |
| memset (&auxent, 0, sizeof (union internal_auxent)); |
| syment._n._n_n._n_offset = st_tmp - string_table; |
| memcpy (st_tmp, rtinit_name, strlen (rtinit_name)); |
| st_tmp += strlen (rtinit_name) + 1; |
| |
| syment.n_scnum = 2; |
| syment.n_sclass = C_EXT; |
| syment.n_numaux = 1; |
| auxent.x_csect.x_smtyp = XTY_LD; |
| auxent.x_csect.x_smclas = XMC_RW; |
| bfd_coff_swap_sym_out (abfd, &syment, |
| &syment_ext[filehdr.f_nsyms * SYMESZ]); |
| bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0, |
| syment.n_numaux, |
| &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]); |
| filehdr.f_nsyms += 2; |
| |
| /* Init. */ |
| if (initsz) |
| { |
| memset (&syment, 0, sizeof (struct internal_syment)); |
| memset (&auxent, 0, sizeof (union internal_auxent)); |
| |
| syment._n._n_n._n_offset = st_tmp - string_table; |
| memcpy (st_tmp, init, initsz); |
| st_tmp += initsz; |
| |
| syment.n_sclass = C_EXT; |
| syment.n_numaux = 1; |
| bfd_coff_swap_sym_out (abfd, &syment, |
| &syment_ext[filehdr.f_nsyms * SYMESZ]); |
| bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0, |
| syment.n_numaux, |
| &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]); |
| /* Reloc. */ |
| memset (&reloc, 0, sizeof (struct internal_reloc)); |
| reloc.r_vaddr = 0x0018; |
| reloc.r_symndx = filehdr.f_nsyms; |
| reloc.r_type = R_POS; |
| reloc.r_size = 63; |
| bfd_coff_swap_reloc_out (abfd, &reloc, &reloc_ext[0]); |
| |
| filehdr.f_nsyms += 2; |
| data_scnhdr.s_nreloc += 1; |
| } |
| |
| /* Finit. */ |
| if (finisz) |
| { |
| memset (&syment, 0, sizeof (struct internal_syment)); |
| memset (&auxent, 0, sizeof (union internal_auxent)); |
| |
| syment._n._n_n._n_offset = st_tmp - string_table; |
| memcpy (st_tmp, fini, finisz); |
| st_tmp += finisz; |
| |
| syment.n_sclass = C_EXT; |
| syment.n_numaux = 1; |
| bfd_coff_swap_sym_out (abfd, &syment, |
| &syment_ext[filehdr.f_nsyms * SYMESZ]); |
| bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0, |
| syment.n_numaux, |
| &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]); |
| |
| /* Reloc. */ |
| memset (&reloc, 0, sizeof (struct internal_reloc)); |
| reloc.r_vaddr = 0x0038; |
| reloc.r_symndx = filehdr.f_nsyms; |
| reloc.r_type = R_POS; |
| reloc.r_size = 63; |
| bfd_coff_swap_reloc_out (abfd, &reloc, |
| &reloc_ext[data_scnhdr.s_nreloc * RELSZ]); |
| |
| filehdr.f_nsyms += 2; |
| data_scnhdr.s_nreloc += 1; |
| } |
| |
| if (rtld) |
| { |
| memset (&syment, 0, sizeof (struct internal_syment)); |
| memset (&auxent, 0, sizeof (union internal_auxent)); |
| |
| syment._n._n_n._n_offset = st_tmp - string_table; |
| memcpy (st_tmp, rtld_name, strlen (rtld_name)); |
| st_tmp += strlen (rtld_name) + 1; |
| |
| syment.n_sclass = C_EXT; |
| syment.n_numaux = 1; |
| bfd_coff_swap_sym_out (abfd, &syment, |
| &syment_ext[filehdr.f_nsyms * SYMESZ]); |
| bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0, |
| syment.n_numaux, |
| &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]); |
| |
| /* Reloc. */ |
| memset (&reloc, 0, sizeof (struct internal_reloc)); |
| reloc.r_vaddr = 0x0000; |
| reloc.r_symndx = filehdr.f_nsyms; |
| reloc.r_type = R_POS; |
| reloc.r_size = 63; |
| bfd_coff_swap_reloc_out (abfd, &reloc, |
| &reloc_ext[data_scnhdr.s_nreloc * RELSZ]); |
| |
| filehdr.f_nsyms += 2; |
| data_scnhdr.s_nreloc += 1; |
| |
| bss_scnhdr.s_size = 0; |
| } |
| |
| data_scnhdr.s_relptr = data_scnhdr.s_scnptr + data_buffer_size; |
| filehdr.f_symptr = data_scnhdr.s_relptr + data_scnhdr.s_nreloc * RELSZ; |
| |
| bfd_coff_swap_filehdr_out (abfd, &filehdr, filehdr_ext); |
| bfd_coff_swap_scnhdr_out (abfd, &text_scnhdr, &scnhdr_ext[SCNHSZ * 0]); |
| bfd_coff_swap_scnhdr_out (abfd, &data_scnhdr, &scnhdr_ext[SCNHSZ * 1]); |
| bfd_coff_swap_scnhdr_out (abfd, &bss_scnhdr, &scnhdr_ext[SCNHSZ * 2]); |
| bool ret = true; |
| if (bfd_write (filehdr_ext, FILHSZ, abfd) != FILHSZ |
| || bfd_write (scnhdr_ext, 3 * SCNHSZ, abfd) != 3 * SCNHSZ |
| || bfd_write (data_buffer, data_buffer_size, abfd) != data_buffer_size |
| || (bfd_write (reloc_ext, data_scnhdr.s_nreloc * RELSZ, abfd) |
| != data_scnhdr.s_nreloc * RELSZ) |
| || (bfd_write (syment_ext, filehdr.f_nsyms * SYMESZ, abfd) |
| != (bfd_size_type) filehdr.f_nsyms * SYMESZ) |
| || bfd_write (string_table, string_table_size, abfd) != string_table_size) |
| ret = false; |
| |
| free (string_table); |
| free (data_buffer); |
| return ret; |
| } |
| |
| /* The typical dynamic reloc. */ |
| |
| static reloc_howto_type xcoff64_dynamic_reloc = |
| HOWTO (0, /* type */ |
| 0, /* rightshift */ |
| 8, /* size */ |
| 64, /* bitsize */ |
| false, /* pc_relative */ |
| 0, /* bitpos */ |
| complain_overflow_bitfield, /* complain_on_overflow */ |
| 0, /* special_function */ |
| "R_POS", /* name */ |
| true, /* partial_inplace */ |
| MINUS_ONE, /* src_mask */ |
| MINUS_ONE, /* dst_mask */ |
| false); /* pcrel_offset */ |
| |
| /* Indirect call stub */ |
| static const unsigned long xcoff64_stub_indirect_call_code[4] = |
| { |
| 0xe9820000, /* ld r12,0(r2) */ |
| 0xe80c0000, /* ld r0,0(r12) */ |
| 0x7c0903a6, /* mtctr r0 */ |
| 0x4e800420, /* bctr */ |
| }; |
| |
| /* Shared call stub */ |
| static const unsigned long xcoff64_stub_shared_call_code[6] = |
| { |
| 0xe9820000, /* ld r12,0(r2) */ |
| 0xf8410028, /* std r2,40(r1) */ |
| 0xe80c0000, /* ld r0,0(r12) */ |
| 0xe84c0008, /* ld r2,8(r12) */ |
| 0x7c0903a6, /* mtctr r0 */ |
| 0x4e800420, /* bctr */ |
| }; |
| |
| static const unsigned long xcoff64_glink_code[10] = |
| { |
| 0xe9820000, /* ld r12,0(r2) */ |
| 0xf8410028, /* std r2,40(r1) */ |
| 0xe80c0000, /* ld r0,0(r12) */ |
| 0xe84c0008, /* ld r2,8(r12) */ |
| 0x7c0903a6, /* mtctr r0 */ |
| 0x4e800420, /* bctr */ |
| 0x00000000, /* start of traceback table */ |
| 0x000ca000, /* traceback table */ |
| 0x00000000, /* traceback table */ |
| 0x00000018, /* ??? */ |
| }; |
| |
| static const struct xcoff_backend_data_rec bfd_xcoff_backend_data = |
| { |
| { /* COFF backend, defined in libcoff.h. */ |
| _bfd_xcoff64_swap_aux_in, |
| _bfd_xcoff64_swap_sym_in, |
| _bfd_xcoff64_swap_lineno_in, |
| _bfd_xcoff64_swap_aux_out, |
| _bfd_xcoff64_swap_sym_out, |
| _bfd_xcoff64_swap_lineno_out, |
| xcoff64_swap_reloc_out, |
| coff_swap_filehdr_out, |
| coff_swap_aouthdr_out, |
| coff_swap_scnhdr_out, |
| FILHSZ, |
| AOUTSZ, |
| SCNHSZ, |
| SYMESZ, |
| AUXESZ, |
| RELSZ, |
| LINESZ, |
| FILNMLEN, |
| true, /* _bfd_coff_long_filenames */ |
| XCOFF_NO_LONG_SECTION_NAMES, /* _bfd_coff_long_section_names */ |
| 3, /* _bfd_coff_default_section_alignment_power */ |
| true, /* _bfd_coff_force_symnames_in_strings */ |
| 4, /* _bfd_coff_debug_string_prefix_length */ |
| 32768, /* _bfd_coff_max_nscns */ |
| coff_swap_filehdr_in, |
| coff_swap_aouthdr_in, |
| coff_swap_scnhdr_in, |
| xcoff64_swap_reloc_in, |
| xcoff64_bad_format_hook, |
| coff_set_arch_mach_hook, |
| coff_mkobject_hook, |
| styp_to_sec_flags, |
| coff_set_alignment_hook, |
| coff_slurp_symbol_table, |
| symname_in_debug_hook, |
| coff_pointerize_aux_hook, |
| coff_print_aux, |
| dummy_reloc16_extra_cases, |
| dummy_reloc16_estimate, |
| NULL, /* bfd_coff_symbol_classification */ |
| coff_compute_section_file_positions, |
| NULL, /* _bfd_coff_start_final_link */ |
| xcoff64_ppc_relocate_section, |
| coff_rtype_to_howto, |
| NULL, /* _bfd_coff_adjust_symndx */ |
| _bfd_generic_link_add_one_symbol, |
| coff_link_output_has_begun, |
| coff_final_link_postscript, |
| NULL /* print_pdata. */ |
| }, |
| |
| 0x01EF, /* magic number */ |
| bfd_arch_powerpc, |
| bfd_mach_ppc_620, |
| |
| /* Function pointers to xcoff specific swap routines. */ |
| xcoff64_swap_ldhdr_in, |
| xcoff64_swap_ldhdr_out, |
| xcoff64_swap_ldsym_in, |
| xcoff64_swap_ldsym_out, |
| xcoff64_swap_ldrel_in, |
| xcoff64_swap_ldrel_out, |
| |
| /* Sizes. */ |
| LDHDRSZ, |
| LDSYMSZ, |
| LDRELSZ, |
| 24, /* _xcoff_function_descriptor_size */ |
| 0, /* _xcoff_small_aout_header_size */ |
| |
| /* Versions. */ |
| 2, /* _xcoff_ldhdr_version */ |
| |
| _bfd_xcoff64_put_symbol_name, |
| _bfd_xcoff64_put_ldsymbol_name, |
| &xcoff64_dynamic_reloc, |
| xcoff64_create_csect_from_smclas, |
| |
| /* Lineno and reloc count overflow. */ |
| xcoff64_is_lineno_count_overflow, |
| xcoff64_is_reloc_count_overflow, |
| |
| xcoff64_loader_symbol_offset, |
| xcoff64_loader_reloc_offset, |
| |
| /* glink. */ |
| &xcoff64_glink_code[0], |
| 40, /* _xcoff_glink_size */ |
| |
| /* rtinit. */ |
| 88, /* _xcoff_rtinit_size */ |
| xcoff64_generate_rtinit, |
| |
| /* Stub indirect call. */ |
| &xcoff64_stub_indirect_call_code[0], |
| 16, /* _xcoff_stub_indirect_call_size */ |
| |
| /* Stub shared call. */ |
| &xcoff64_stub_shared_call_code[0], |
| 24, /* _xcoff_stub_shared_call_size */ |
| }; |
| |
| /* The transfer vector that leads the outside world to all of the above. */ |
| const bfd_target rs6000_xcoff64_vec = |
| { |
| "aixcoff64-rs6000", |
| bfd_target_xcoff_flavour, |
| BFD_ENDIAN_BIG, /* data byte order is big */ |
| BFD_ENDIAN_BIG, /* header byte order is big */ |
| |
| (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | DYNAMIC |
| | HAS_SYMS | HAS_LOCALS | WP_TEXT), |
| |
| SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA, |
| 0, /* leading char */ |
| '/', /* ar_pad_char */ |
| 15, /* ar_max_namelen */ |
| 0, /* match priority. */ |
| TARGET_KEEP_UNUSED_SECTION_SYMBOLS, /* keep unused section symbols. */ |
| |
| /* data */ |
| bfd_getb64, |
| bfd_getb_signed_64, |
| bfd_putb64, |
| bfd_getb32, |
| bfd_getb_signed_32, |
| bfd_putb32, |
| bfd_getb16, |
| bfd_getb_signed_16, |
| bfd_putb16, |
| |
| /* hdrs */ |
| bfd_getb64, |
| bfd_getb_signed_64, |
| bfd_putb64, |
| bfd_getb32, |
| bfd_getb_signed_32, |
| bfd_putb32, |
| bfd_getb16, |
| bfd_getb_signed_16, |
| bfd_putb16, |
| |
| { /* bfd_check_format */ |
| _bfd_dummy_target, |
| coff_object_p, |
| xcoff64_archive_p, |
| CORE_FILE_P |
| }, |
| |
| { /* bfd_set_format */ |
| _bfd_bool_bfd_false_error, |
| coff_mkobject, |
| _bfd_generic_mkarchive, |
| _bfd_bool_bfd_false_error |
| }, |
| |
| {/* bfd_write_contents */ |
| _bfd_bool_bfd_false_error, |
| coff_write_object_contents, |
| _bfd_xcoff_write_archive_contents, |
| _bfd_bool_bfd_false_error |
| }, |
| |
| /* Generic */ |
| coff_close_and_cleanup, |
| coff_bfd_free_cached_info, |
| coff_new_section_hook, |
| _bfd_generic_get_section_contents, |
| |
| /* Copy */ |
| _bfd_xcoff_copy_private_bfd_data, |
| _bfd_generic_bfd_merge_private_bfd_data, |
| _bfd_generic_init_private_section_data, |
| _bfd_generic_bfd_copy_private_section_data, |
| _bfd_generic_bfd_copy_private_symbol_data, |
| _bfd_generic_bfd_copy_private_header_data, |
| _bfd_generic_bfd_set_private_flags, |
| _bfd_generic_bfd_print_private_bfd_data, |
| |
| /* Core */ |
| BFD_JUMP_TABLE_CORE (coff), |
| |
| /* Archive */ |
| xcoff64_slurp_armap, |
| _bfd_noarchive_slurp_extended_name_table, |
| _bfd_noarchive_construct_extended_name_table, |
| bfd_dont_truncate_arname, |
| _bfd_xcoff_write_armap, |
| _bfd_xcoff_read_ar_hdr, |
| _bfd_generic_write_ar_hdr, |
| xcoff64_openr_next_archived_file, |
| _bfd_generic_get_elt_at_index, |
| _bfd_xcoff_stat_arch_elt, |
| _bfd_bool_bfd_true, |
| |
| /* Symbols */ |
| coff_get_symtab_upper_bound, |
| coff_canonicalize_symtab, |
| coff_make_empty_symbol, |
| coff_print_symbol, |
| coff_get_symbol_info, |
| coff_get_symbol_version_string, |
| _bfd_xcoff_is_local_label_name, |
| coff_bfd_is_target_special_symbol, |
| coff_get_lineno, |
| coff_find_nearest_line, |
| coff_find_nearest_line_with_alt, |
| coff_find_line, |
| coff_find_inliner_info, |
| coff_bfd_make_debug_symbol, |
| _bfd_generic_read_minisymbols, |
| _bfd_generic_minisymbol_to_symbol, |
| |
| /* Reloc */ |
| coff_get_reloc_upper_bound, |
| coff_canonicalize_reloc, |
| _bfd_generic_set_reloc, |
| xcoff64_reloc_type_lookup, |
| xcoff64_reloc_name_lookup, |
| |
| /* Write */ |
| coff_set_arch_mach, |
| coff_set_section_contents, |
| |
| /* Link */ |
| xcoff64_sizeof_headers, |
| bfd_generic_get_relocated_section_contents, |
| bfd_generic_relax_section, |
| _bfd_xcoff_bfd_link_hash_table_create, |
| _bfd_xcoff_bfd_link_add_symbols, |
| _bfd_generic_link_just_syms, |
| _bfd_generic_copy_link_hash_symbol_type, |
| _bfd_xcoff_bfd_final_link, |
| _bfd_generic_link_split_section, |
| _bfd_generic_link_check_relocs, |
| bfd_generic_gc_sections, |
| bfd_generic_lookup_section_flags, |
| bfd_generic_merge_sections, |
| bfd_generic_is_group_section, |
| bfd_generic_group_name, |
| bfd_generic_discard_group, |
| _bfd_generic_section_already_linked, |
| _bfd_xcoff_define_common_symbol, |
| _bfd_generic_link_hide_symbol, |
| bfd_generic_define_start_stop, |
| |
| /* Dynamic */ |
| _bfd_xcoff_get_dynamic_symtab_upper_bound, |
| _bfd_xcoff_canonicalize_dynamic_symtab, |
| _bfd_nodynamic_get_synthetic_symtab, |
| _bfd_xcoff_get_dynamic_reloc_upper_bound, |
| _bfd_xcoff_canonicalize_dynamic_reloc, |
| |
| /* Opposite endian version, none exists */ |
| NULL, |
| |
| &bfd_xcoff_backend_data, |
| }; |
| |
| extern bfd_cleanup xcoff64_core_p |
| (bfd *); |
| extern bool xcoff64_core_file_matches_executable_p |
| (bfd *, bfd *); |
| extern char *xcoff64_core_file_failing_command |
| (bfd *); |
| extern int xcoff64_core_file_failing_signal |
| (bfd *); |
| #define xcoff64_core_file_pid _bfd_nocore_core_file_pid |
| |
| /* AIX 5 */ |
| static const struct xcoff_backend_data_rec bfd_xcoff_aix5_backend_data = |
| { |
| { /* COFF backend, defined in libcoff.h. */ |
| _bfd_xcoff64_swap_aux_in, |
| _bfd_xcoff64_swap_sym_in, |
| _bfd_xcoff64_swap_lineno_in, |
| _bfd_xcoff64_swap_aux_out, |
| _bfd_xcoff64_swap_sym_out, |
| _bfd_xcoff64_swap_lineno_out, |
| xcoff64_swap_reloc_out, |
| coff_swap_filehdr_out, |
| coff_swap_aouthdr_out, |
| coff_swap_scnhdr_out, |
| FILHSZ, |
| AOUTSZ, |
| SCNHSZ, |
| SYMESZ, |
| AUXESZ, |
| RELSZ, |
| LINESZ, |
| FILNMLEN, |
| true, /* _bfd_coff_long_filenames */ |
| XCOFF_NO_LONG_SECTION_NAMES, /* _bfd_coff_long_section_names */ |
| 3, /* _bfd_coff_default_section_alignment_power */ |
| true, /* _bfd_coff_force_symnames_in_strings */ |
| 4, /* _bfd_coff_debug_string_prefix_length */ |
| 32768, /* _bfd_coff_max_nscns */ |
| coff_swap_filehdr_in, |
| coff_swap_aouthdr_in, |
| coff_swap_scnhdr_in, |
| xcoff64_swap_reloc_in, |
| xcoff64_bad_format_hook, |
| coff_set_arch_mach_hook, |
| coff_mkobject_hook, |
| styp_to_sec_flags, |
| coff_set_alignment_hook, |
| coff_slurp_symbol_table, |
| symname_in_debug_hook, |
| coff_pointerize_aux_hook, |
| coff_print_aux, |
| dummy_reloc16_extra_cases, |
| dummy_reloc16_estimate, |
| NULL, /* bfd_coff_sym_is_global */ |
| coff_compute_section_file_positions, |
| NULL, /* _bfd_coff_start_final_link */ |
| xcoff64_ppc_relocate_section, |
| coff_rtype_to_howto, |
| NULL, /* _bfd_coff_adjust_symndx */ |
| _bfd_generic_link_add_one_symbol, |
| coff_link_output_has_begun, |
| coff_final_link_postscript, |
| NULL /* print_pdata. */ |
| }, |
| |
| U64_TOCMAGIC, /* magic number */ |
| bfd_arch_powerpc, |
| bfd_mach_ppc_620, |
| |
| /* Function pointers to xcoff specific swap routines. */ |
| xcoff64_swap_ldhdr_in, |
| xcoff64_swap_ldhdr_out, |
| xcoff64_swap_ldsym_in, |
| xcoff64_swap_ldsym_out, |
| xcoff64_swap_ldrel_in, |
| xcoff64_swap_ldrel_out, |
| |
| /* Sizes. */ |
| LDHDRSZ, |
| LDSYMSZ, |
| LDRELSZ, |
| 24, /* _xcoff_function_descriptor_size */ |
| 0, /* _xcoff_small_aout_header_size */ |
| /* Versions. */ |
| 2, /* _xcoff_ldhdr_version */ |
| |
| _bfd_xcoff64_put_symbol_name, |
| _bfd_xcoff64_put_ldsymbol_name, |
| &xcoff64_dynamic_reloc, |
| xcoff64_create_csect_from_smclas, |
| |
| /* Lineno and reloc count overflow. */ |
| xcoff64_is_lineno_count_overflow, |
| xcoff64_is_reloc_count_overflow, |
| |
| xcoff64_loader_symbol_offset, |
| xcoff64_loader_reloc_offset, |
| |
| /* glink. */ |
| &xcoff64_glink_code[0], |
| 40, /* _xcoff_glink_size */ |
| |
| /* rtinit. */ |
| 88, /* _xcoff_rtinit_size */ |
| xcoff64_generate_rtinit, |
| |
| /* Stub indirect call. */ |
| &xcoff64_stub_indirect_call_code[0], |
| 16, /* _xcoff_stub_indirect_call_size */ |
| |
| /* Stub shared call. */ |
| &xcoff64_stub_shared_call_code[0], |
| 24, /* _xcoff_stub_shared_call_size */ |
| }; |
| |
| /* The transfer vector that leads the outside world to all of the above. */ |
| const bfd_target rs6000_xcoff64_aix_vec = |
| { |
| "aix5coff64-rs6000", |
| bfd_target_xcoff_flavour, |
| BFD_ENDIAN_BIG, /* data byte order is big */ |
| BFD_ENDIAN_BIG, /* header byte order is big */ |
| |
| (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | DYNAMIC |
| | HAS_SYMS | HAS_LOCALS | WP_TEXT), |
| |
| SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA, |
| 0, /* leading char */ |
| '/', /* ar_pad_char */ |
| 15, /* ar_max_namelen */ |
| 0, /* match priority. */ |
| TARGET_KEEP_UNUSED_SECTION_SYMBOLS, /* keep unused section symbols. */ |
| |
| /* data */ |
| bfd_getb64, |
| bfd_getb_signed_64, |
| bfd_putb64, |
| bfd_getb32, |
| bfd_getb_signed_32, |
| bfd_putb32, |
| bfd_getb16, |
| bfd_getb_signed_16, |
| bfd_putb16, |
| |
| /* hdrs */ |
| bfd_getb64, |
| bfd_getb_signed_64, |
| bfd_putb64, |
| bfd_getb32, |
| bfd_getb_signed_32, |
| bfd_putb32, |
| bfd_getb16, |
| bfd_getb_signed_16, |
| bfd_putb16, |
| |
| { /* bfd_check_format */ |
| _bfd_dummy_target, |
| coff_object_p, |
| xcoff64_archive_p, |
| xcoff64_core_p |
| }, |
| |
| { /* bfd_set_format */ |
| _bfd_bool_bfd_false_error, |
| coff_mkobject, |
| _bfd_generic_mkarchive, |
| _bfd_bool_bfd_false_error |
| }, |
| |
| {/* bfd_write_contents */ |
| _bfd_bool_bfd_false_error, |
| coff_write_object_contents, |
| _bfd_xcoff_write_archive_contents, |
| _bfd_bool_bfd_false_error |
| }, |
| |
| /* Generic */ |
| coff_close_and_cleanup, |
| coff_bfd_free_cached_info, |
| coff_new_section_hook, |
| _bfd_generic_get_section_contents, |
| |
| /* Copy */ |
| _bfd_xcoff_copy_private_bfd_data, |
| _bfd_generic_bfd_merge_private_bfd_data, |
| _bfd_generic_init_private_section_data, |
| _bfd_generic_bfd_copy_private_section_data, |
| _bfd_generic_bfd_copy_private_symbol_data, |
| _bfd_generic_bfd_copy_private_header_data, |
| _bfd_generic_bfd_set_private_flags, |
| _bfd_generic_bfd_print_private_bfd_data, |
| |
| /* Core */ |
| BFD_JUMP_TABLE_CORE (xcoff64), |
| |
| /* Archive */ |
| xcoff64_slurp_armap, |
| _bfd_noarchive_slurp_extended_name_table, |
| _bfd_noarchive_construct_extended_name_table, |
| bfd_dont_truncate_arname, |
| _bfd_xcoff_write_armap, |
| _bfd_xcoff_read_ar_hdr, |
| _bfd_generic_write_ar_hdr, |
| xcoff64_openr_next_archived_file, |
| _bfd_generic_get_elt_at_index, |
| _bfd_xcoff_stat_arch_elt, |
| _bfd_bool_bfd_true, |
| |
| /* Symbols */ |
| coff_get_symtab_upper_bound, |
| coff_canonicalize_symtab, |
| coff_make_empty_symbol, |
| coff_print_symbol, |
| coff_get_symbol_info, |
| coff_get_symbol_version_string, |
| _bfd_xcoff_is_local_label_name, |
| coff_bfd_is_target_special_symbol, |
| coff_get_lineno, |
| coff_find_nearest_line, |
| coff_find_nearest_line_with_alt, |
| coff_find_line, |
| coff_find_inliner_info, |
| coff_bfd_make_debug_symbol, |
| _bfd_generic_read_minisymbols, |
| _bfd_generic_minisymbol_to_symbol, |
| |
| /* Reloc */ |
| coff_get_reloc_upper_bound, |
| coff_canonicalize_reloc, |
| _bfd_generic_set_reloc, |
| xcoff64_reloc_type_lookup, |
| xcoff64_reloc_name_lookup, |
| |
| /* Write */ |
| coff_set_arch_mach, |
| coff_set_section_contents, |
| |
| /* Link */ |
| xcoff64_sizeof_headers, |
| bfd_generic_get_relocated_section_contents, |
| bfd_generic_relax_section, |
| _bfd_xcoff_bfd_link_hash_table_create, |
| _bfd_xcoff_bfd_link_add_symbols, |
| _bfd_generic_link_just_syms, |
| _bfd_generic_copy_link_hash_symbol_type, |
| _bfd_xcoff_bfd_final_link, |
| _bfd_generic_link_split_section, |
| _bfd_generic_link_check_relocs, |
| bfd_generic_gc_sections, |
| bfd_generic_lookup_section_flags, |
| bfd_generic_merge_sections, |
| bfd_generic_is_group_section, |
| bfd_generic_group_name, |
| bfd_generic_discard_group, |
| _bfd_generic_section_already_linked, |
| _bfd_xcoff_define_common_symbol, |
| _bfd_generic_link_hide_symbol, |
| bfd_generic_define_start_stop, |
| |
| /* Dynamic */ |
| _bfd_xcoff_get_dynamic_symtab_upper_bound, |
| _bfd_xcoff_canonicalize_dynamic_symtab, |
| _bfd_nodynamic_get_synthetic_symtab, |
| _bfd_xcoff_get_dynamic_reloc_upper_bound, |
| _bfd_xcoff_canonicalize_dynamic_reloc, |
| |
| /* Opposite endian version, none exists. */ |
| NULL, |
| |
| & bfd_xcoff_aix5_backend_data, |
| }; |