Add .abiversion related support for ELFv2
authorAlan Modra <amodra@gmail.com>
Tue, 29 Oct 2013 04:36:09 +0000 (15:06 +1030)
committerAlan Modra <amodra@gmail.com>
Wed, 30 Oct 2013 03:07:47 +0000 (13:37 +1030)
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
bfd/elf64-ppc.c
binutils/ChangeLog
binutils/readelf.c
gas/ChangeLog
gas/config/tc-ppc.c
gas/config/tc-ppc.h
include/elf/ChangeLog
include/elf/ppc64.h

index 39060f31ea101943042b396ac6dbc119aee78f2e..2c4bb314ff93f2e208eccecfa031a93712ffcf67 100644 (file)
@@ -1,3 +1,17 @@
+2013-10-30  Alan Modra  <amodra@gmail.com>
+
+       * 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  <amodra@gmail.com>
 
        * elf64-ppc.c (build_plt_stub): Switch stubs to use r11 as base
index 94a9402312fcc309318fff4ee9dbf305d05d2c67..0067295922d244a8947cf0a12483ef9584372503 100644 (file)
@@ -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;
+}
 \f
 /* 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
index ae505262af92b4d055aea3259351a0e3796ca786..8457dc7ac1b2812aaf968a4f228ce983c75b666d 100644 (file)
@@ -1,3 +1,7 @@
+2013-10-30  Alan Modra  <amodra@gmail.com>
+
+       * readelf.c (get_machine_flags): Display ABI version for EM_PPC64.
+
 2013-10-24  Nick Clifton  <nickc@redhat.com>
 
        * nm.c (display_rel_file): Treat bfd_error_no_symbols as
index 7920100630038dfba93ae9bf2c4d4a9bfaa17bde..ab2943def142548e644b6af019e2f19035e3500e 100644 (file)
@@ -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");
index a1b71b0758242c7125a7d1d61addb302574aaa01..25e87d166ea1686d69537fb4158cf09bd3e43277 100644 (file)
@@ -1,3 +1,11 @@
+2013-10-30  Alan Modra  <amodra@gmail.com>
+
+       * 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  <amodra@gmail.com>
 
        * config/tc-ppc.c (SEX16): Don't mask.
index 34afc916903925001b5f816957f7265c34af654b..c249cec9ab9bc7ed91cef450ac1a9b9aed9cedee 100644 (file)
@@ -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.  */
index 3dd3f8190b3aa7a7929e72f97b13b77938a5bdb9..60954161e3e4333ded3585789c9d793bd773b66e 100644 (file)
@@ -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)
index fae0bf89e4e6751df44b461b3fc0b7cc6dd3fee6..2999bc8a49f2521932a9b4693d44d233ed7697a0 100644 (file)
@@ -1,3 +1,7 @@
+2013-10-30  Alan Modra  <amodra@gmail.com>
+
+       * ppc64.h (EF_PPC64_ABI): Define.
+
 2013-10-30  Alan Modra  <amodra@gmail.com>
 
        * ppc64.h (R_PPC64_ADDR16_HIGH, R_PPC64_ADDR16_HIGHA,
index 221786f1ac182b0585535c754f15bc51f005ebbe..112164935af528a015c9243b14d668bb3900246f 100644 (file)
@@ -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