From ee67d69a3ff0eed25d98c5e97ed6c3ede8069edc Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Tue, 29 Oct 2013 15:06:09 +1030 Subject: [PATCH] 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. --- bfd/ChangeLog | 14 +++++ bfd/elf64-ppc.c | 139 +++++++++++++++++++++++++++++++++++++----- binutils/ChangeLog | 4 ++ binutils/readelf.c | 10 +++ gas/ChangeLog | 8 +++ gas/config/tc-ppc.c | 39 ++++++++++++ gas/config/tc-ppc.h | 3 + include/elf/ChangeLog | 4 ++ include/elf/ppc64.h | 7 +++ 9 files changed, 213 insertions(+), 15 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 39060f31ea1..2c4bb314ff9 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,17 @@ +2013-10-30 Alan Modra + + * 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 + 2013-10-30 Alan Modra * elf64-ppc.c (build_plt_stub): Switch stubs to use r11 as base diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 94a9402312f..0067295922d 100644 --- a/bfd/elf64-ppc.c +++ b/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 @@ -2943,6 +2944,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; @@ -3089,15 +3103,19 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd, 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) @@ -3266,20 +3284,18 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd, 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; } @@ -3890,6 +3906,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; @@ -5089,6 +5108,15 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, 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) @@ -5674,6 +5702,78 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, 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. */ @@ -7711,6 +7811,9 @@ ppc64_elf_tls_setup (struct bfd_link_info *info, 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) @@ -9333,7 +9436,7 @@ readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf) /* 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; @@ -9649,7 +9752,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, 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)) @@ -10412,7 +10515,10 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) 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); @@ -14271,7 +14377,10 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd, 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 diff --git a/binutils/ChangeLog b/binutils/ChangeLog index ae505262af9..8457dc7ac1b 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,7 @@ +2013-10-30 Alan Modra + + * readelf.c (get_machine_flags): Display ABI version for EM_PPC64. + 2013-10-24 Nick Clifton * nm.c (display_rel_file): Treat bfd_error_no_symbols as diff --git a/binutils/readelf.c b/binutils/readelf.c index 79201006300..ab2943def14 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -2461,6 +2461,16 @@ get_machine_flags (unsigned e_flags, unsigned e_machine) strcat (buf, _(", relocatable-lib")); break; + case EM_PPC64: + if (e_flags & EF_PPC64_ABI) + { + char abi[] = ", abiv0"; + + abi[6] += e_flags & EF_PPC64_ABI; + strcat (buf, abi); + } + break; + case EM_V800: if ((e_flags & EF_RH850_ABI) == EF_RH850_ABI) strcat (buf, ", RH850 ABI"); diff --git a/gas/ChangeLog b/gas/ChangeLog index a1b71b07582..25e87d166ea 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,11 @@ +2013-10-30 Alan Modra + + * 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. + 2013-10-30 Alan Modra * config/tc-ppc.c (SEX16): Don't mask. diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c index 34afc916903..c249cec9ab9 100644 --- a/gas/config/tc-ppc.c +++ b/gas/config/tc-ppc.c @@ -29,6 +29,7 @@ #ifdef OBJ_ELF #include "elf/ppc.h" +#include "elf/ppc64.h" #include "dwarf2dbg.h" #endif @@ -133,6 +134,7 @@ static void ppc_vbyte (int); static void ppc_elf_cons (int); static void ppc_elf_rdata (int); static void ppc_elf_lcomm (int); +static void ppc_elf_abiversion (int); #endif #ifdef TE_PE @@ -203,6 +205,9 @@ unsigned long nop_limit = 4; ppc_cpu_t ppc_cpu = 0; ppc_cpu_t sticky = 0; +/* Value for ELF e_flags EF_PPC64_ABI. */ +unsigned int ppc_abiversion = 0; + /* Flags set on encountering toc relocs. */ enum { has_large_toc_reloc = 1, @@ -261,6 +266,7 @@ const pseudo_typeS md_pseudo_table[] = { "rdata", ppc_elf_rdata, 0 }, { "rodata", ppc_elf_rdata, 0 }, { "lcomm", ppc_elf_lcomm, 0 }, + { "abiversion", ppc_elf_abiversion, 0 }, #endif #ifdef TE_PE @@ -2220,6 +2226,39 @@ ppc_elf_lcomm (int xxx ATTRIBUTE_UNUSED) demand_empty_rest_of_line (); } +/* Pseudo op to set ABI version. */ +static void +ppc_elf_abiversion (int ignore ATTRIBUTE_UNUSED) +{ + expressionS exp; + + expression (&exp); + if (exp.X_op == O_absent) + { + as_bad (_("missing expression in .abiversion directive")); + exp.X_op = O_constant; + exp.X_add_number = 0; + } + + if (resolve_expression (&exp) + && exp.X_op == O_constant) + ppc_abiversion = exp.X_add_number; + else + as_bad (_(".abiversion expression does not evaluate to a constant")); + demand_empty_rest_of_line (); +} + +/* Set ABI version in output file. */ +void +ppc_elf_end (void) +{ + if (ppc_obj64 && ppc_abiversion != 0) + { + elf_elfheader (stdoutput)->e_flags &= ~EF_PPC64_ABI; + elf_elfheader (stdoutput)->e_flags |= ppc_abiversion & EF_PPC64_ABI; + } +} + /* Validate any relocations emitted for -mrelocatable, possibly adding fixups for word relocations in writable segments, so we can adjust them at runtime. */ diff --git a/gas/config/tc-ppc.h b/gas/config/tc-ppc.h index 3dd3f8190b3..60954161e3e 100644 --- a/gas/config/tc-ppc.h +++ b/gas/config/tc-ppc.h @@ -238,6 +238,9 @@ extern void ppc_frob_file_before_adjust (void); #define tc_adjust_symtab() ppc_elf_adjust_symtab () extern void ppc_elf_adjust_symtab (void); +extern void ppc_elf_end (void); +#define md_end ppc_elf_end + #endif /* OBJ_ELF */ #if defined (OBJ_ELF) || defined (OBJ_XCOFF) diff --git a/include/elf/ChangeLog b/include/elf/ChangeLog index fae0bf89e4e..2999bc8a49f 100644 --- a/include/elf/ChangeLog +++ b/include/elf/ChangeLog @@ -1,3 +1,7 @@ +2013-10-30 Alan Modra + + * ppc64.h (EF_PPC64_ABI): Define. + 2013-10-30 Alan Modra * ppc64.h (R_PPC64_ADDR16_HIGH, R_PPC64_ADDR16_HIGHA, diff --git a/include/elf/ppc64.h b/include/elf/ppc64.h index 221786f1ac1..112164935af 100644 --- 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 -- 2.30.2