commit ee67d69a3ff0eed25d98c5e97ed6c3ede8069edc Author: Alan Modra Date: Tue Oct 29 15:06:09 2013 +1030 Add .abiversion related support for ELFv2 Defines bits in ELF e_flags to differentiate ELFv2 objects from ELFv2, adds .abiversion directive to explicitly choose the ABI, and code to check and automatically select ABI. include/elf/ * ppc64.h (EF_PPC64_ABI): Define. bfd/ * elf64-ppc.c (abiversion, set_abiversion): New functions. (ppc64_elf_get_synthetic_symtab): Handle ELFv2 objects without .opd. (struct ppc_link_hash_table): Add opd_abi. (ppc64_elf_check_relocs): Check no .opd with ELFv2. (ppc64_elf_merge_private_bfd_data): New function. (ppc64_elf_print_private_bfd_data): New function. (ppc64_elf_tls_setup): Set htab->opd_abi. (ppc64_elf_size_dynamic_sections): Don't emit OPD related dynamic tags for ELFv2. (ppc_build_one_stub): Use R_PPC64_IRELATIVE for ELFv2 ifunc. (ppc64_elf_finish_dynamic_symbol): Likewise binutils/ * readelf.c (get_machine_flags): Display ABI version for EM_PPC64. gas/ * config/tc-ppc.c: Include elf/ppc64.h. (ppc_abiversion): New variable. (md_pseudo_table): Add .abiversion. (ppc_elf_abiversion, ppc_elf_end): New functions. * config/tc-ppc.h (md_end): Define. Index: gdb-7.6.1/bfd/elf64-ppc.c =================================================================== --- gdb-7.6.1.orig/bfd/elf64-ppc.c +++ gdb-7.6.1/bfd/elf64-ppc.c @@ -81,7 +81,8 @@ static bfd_vma opd_entry_value #define bfd_elf64_mkobject ppc64_elf_mkobject #define bfd_elf64_bfd_reloc_type_lookup ppc64_elf_reloc_type_lookup #define bfd_elf64_bfd_reloc_name_lookup ppc64_elf_reloc_name_lookup -#define bfd_elf64_bfd_merge_private_bfd_data _bfd_generic_verify_endian_match +#define bfd_elf64_bfd_merge_private_bfd_data ppc64_elf_merge_private_bfd_data +#define bfd_elf64_bfd_print_private_bfd_data ppc64_elf_print_private_bfd_data #define bfd_elf64_new_section_hook ppc64_elf_new_section_hook #define bfd_elf64_bfd_link_hash_table_create ppc64_elf_link_hash_table_create #define bfd_elf64_bfd_link_hash_table_free ppc64_elf_link_hash_table_free @@ -2836,6 +2837,19 @@ get_opd_info (asection * sec) return &ppc64_elf_section_data (sec)->u.opd; return NULL; } + +static inline int +abiversion (bfd *abfd) +{ + return elf_elfheader (abfd)->e_flags & EF_PPC64_ABI; +} + +static inline void +set_abiversion (bfd *abfd, int ver) +{ + elf_elfheader (abfd)->e_flags &= ~EF_PPC64_ABI; + elf_elfheader (abfd)->e_flags |= ver & EF_PPC64_ABI; +} /* Parameters for the qsort hook. */ static bfd_boolean synthetic_relocatable; @@ -2982,15 +2996,19 @@ ppc64_elf_get_synthetic_symtab (bfd *abf long count; char *names; long symcount, codesecsym, codesecsymend, secsymend, opdsymend; - asection *opd; + asection *opd = NULL; bfd_boolean relocatable = (abfd->flags & (EXEC_P | DYNAMIC)) == 0; asymbol **syms; + int abi = abiversion (abfd); *ret = NULL; - opd = bfd_get_section_by_name (abfd, ".opd"); - if (opd == NULL) - return 0; + if (abi < 2) + { + opd = bfd_get_section_by_name (abfd, ".opd"); + if (opd == NULL && abi == 1) + return 0; + } symcount = static_count; if (!relocatable) @@ -3159,20 +3177,18 @@ ppc64_elf_get_synthetic_symtab (bfd *abf else { bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); - bfd_byte *contents; + bfd_byte *contents = NULL; size_t size; long plt_count = 0; bfd_vma glink_vma = 0, resolv_vma = 0; asection *dynamic, *glink = NULL, *relplt = NULL; arelent *p; - if (!bfd_malloc_and_get_section (abfd, opd, &contents)) + if (opd != NULL && !bfd_malloc_and_get_section (abfd, opd, &contents)) { + free_contents_and_exit: if (contents) - { - free_contents_and_exit: - free (contents); - } + free (contents); count = -1; goto done; } @@ -3772,6 +3788,9 @@ struct ppc_link_hash_table /* Alignment of PLT call stubs. */ unsigned int plt_stub_align:4; + /* Set if we're linking code with function descriptors. */ + unsigned int opd_abi:1; + /* Set if PLT call stubs should load r11. */ unsigned int plt_static_chain:1; @@ -4959,6 +4978,15 @@ ppc64_elf_check_relocs (bfd *abfd, struc information about the associated function section. */ bfd_size_type amt; + if (abiversion (abfd) == 0) + set_abiversion (abfd, 1); + else if (abiversion (abfd) == 2) + { + info->callbacks->einfo (_("%P: .opd not allowed in ABI version %d\n"), + abiversion (abfd)); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } amt = sec->size * sizeof (*opd_sym_map) / 8; opd_sym_map = bfd_zalloc (abfd, amt); if (opd_sym_map == NULL) @@ -5518,6 +5546,78 @@ ppc64_elf_check_relocs (bfd *abfd, struc return TRUE; } +/* Merge backend specific data from an object file to the output + object file when linking. */ + +static bfd_boolean +ppc64_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) +{ + unsigned long iflags, oflags; + + if ((ibfd->flags & BFD_LINKER_CREATED) != 0) + return TRUE; + + if (!is_ppc64_elf (ibfd) || !is_ppc64_elf (obfd)) + return TRUE; + + if (!_bfd_generic_verify_endian_match (ibfd, obfd)) + return FALSE; + + iflags = elf_elfheader (ibfd)->e_flags; + oflags = elf_elfheader (obfd)->e_flags; + + if (!elf_flags_init (obfd) || oflags == 0) + { + elf_flags_init (obfd) = TRUE; + elf_elfheader (obfd)->e_flags = iflags; + } + else if (iflags == oflags || iflags == 0) + ; + else if (iflags & ~EF_PPC64_ABI) + { + (*_bfd_error_handler) + (_("%B uses unknown e_flags 0x%lx"), ibfd, iflags); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + else + { + (*_bfd_error_handler) + (_("%B: ABI version %ld is not compatible with ABI version %ld output"), + ibfd, iflags, oflags); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + /* Merge Tag_compatibility attributes and any common GNU ones. */ + _bfd_elf_merge_object_attributes (ibfd, obfd); + + return TRUE; +} + +static bfd_boolean +ppc64_elf_print_private_bfd_data (bfd *abfd, void *ptr) +{ + /* Print normal ELF private data. */ + _bfd_elf_print_private_bfd_data (abfd, ptr); + + if (elf_elfheader (abfd)->e_flags != 0) + { + FILE *file = ptr; + + /* xgettext:c-format */ + fprintf (file, _("private flags = 0x%lx:"), + elf_elfheader (abfd)->e_flags); + + if ((elf_elfheader (abfd)->e_flags & EF_PPC64_ABI) != 0) + fprintf (file, _(" [abiv%ld]"), + elf_elfheader (abfd)->e_flags & EF_PPC64_ABI); + fputc ('\n', file); + } + + return TRUE; +} + /* OFFSET in OPD_SEC specifies a function descriptor. Return the address of the code entry point, and its section. */ @@ -7504,6 +7604,9 @@ ppc64_elf_tls_setup (struct bfd_link_inf if (htab == NULL) return NULL; + if (abiversion (info->output_bfd) == 1) + htab->opd_abi = 1; + if (*no_multi_toc) htab->do_multi_toc = 0; else if (!htab->do_multi_toc) @@ -9127,7 +9230,7 @@ readonly_dynrelocs (struct elf_link_hash /* Set the sizes of the dynamic sections. */ static bfd_boolean -ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, +ppc64_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) { struct ppc_link_hash_table *htab; @@ -9439,7 +9542,7 @@ ppc64_elf_size_dynamic_sections (bfd *ou return FALSE; } - if (NO_OPD_RELOCS) + if (NO_OPD_RELOCS && abiversion (output_bfd) <= 1) { if (!add_dynamic_entry (DT_PPC64_OPD, 0) || !add_dynamic_entry (DT_PPC64_OPDSZ, 0)) @@ -10202,7 +10305,10 @@ ppc_build_one_stub (struct bfd_hash_entr bfd_byte *rl; rela.r_offset = dest; - rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL); + if (htab->opd_abi) + rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL); + else + rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE); rela.r_addend = (stub_entry->target_value + stub_entry->target_section->output_offset + stub_entry->target_section->output_section->vma); @@ -14012,7 +14118,10 @@ ppc64_elf_finish_dynamic_symbol (bfd *ou rela.r_offset = (htab->iplt->output_section->vma + htab->iplt->output_offset + ent->plt.offset); - rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL); + if (htab->opd_abi) + rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL); + else + rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE); rela.r_addend = (h->root.u.def.value + h->root.u.def.section->output_offset + h->root.u.def.section->output_section->vma --- a/include/elf/ppc64.h +++ b/include/elf/ppc64.h @@ -173,6 +173,13 @@ END_RELOC_NUMBERS (R_PPC64_max) (((R) >= R_PPC64_TLS && (R) <= R_PPC64_DTPREL16_HIGHESTA) \ || ((R) >= R_PPC64_TPREL16_HIGH && (R) <= R_PPC64_DTPREL16_HIGHA)) + +/* e_flags bits specifying ABI. + 1 for original function descriptor using ABI, + 2 for revised ABI without function descriptors, + 0 for unspecified or not using any features affected by the differences. */ +#define EF_PPC64_ABI 3 + /* Specify the start of the .glink section. */ #define DT_PPC64_GLINK DT_LOPROC