daily update
[deliverable/binutils-gdb.git] / bfd / elf64-ppc.c
index b97bd3aed3bd2b44a8a4e6af2c6e5f926cbff4b7..2073bdc11da94c62dbd7da3a7b4ca043b3c7e949 100644 (file)
@@ -61,6 +61,7 @@ static bfd_vma opd_entry_value
 #define TARGET_BIG_SYM         bfd_elf64_powerpc_vec
 #define TARGET_BIG_NAME                "elf64-powerpc"
 #define ELF_ARCH               bfd_arch_powerpc
+#define ELF_TARGET_ID          PPC64_ELF_DATA
 #define ELF_MACHINE_CODE       EM_PPC64
 #define ELF_MAXPAGESIZE                0x10000
 #define ELF_COMMONPAGESIZE     0x1000
@@ -2651,7 +2652,7 @@ ppc64_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
   elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
 
   /* pr_pid */
-  elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 32);
+  elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 32);
 
   /* pr_reg */
   offset = 112;
@@ -8248,6 +8249,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
        {
          bfd_byte *contents, *src;
          unsigned long off;
+         Elf_Internal_Sym *sym;
          bfd_boolean local_toc_syms = FALSE;
 
          /* Shuffle the toc contents, and at the same time convert the
@@ -8292,7 +8294,6 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
                  unsigned long r_symndx;
                  asection *sym_sec;
                  struct elf_link_hash_entry *h;
-                 Elf_Internal_Sym *sym;
                  bfd_vma val;
 
                  r_type = ELF64_R_TYPE (rel->r_info);
@@ -8371,38 +8372,34 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
 
          /* We shouldn't have local or global symbols defined in the TOC,
             but handle them anyway.  */
-         if (local_toc_syms)
-           {
-             Elf_Internal_Sym *sym;
-
-             for (sym = local_syms;
-                  sym < local_syms + symtab_hdr->sh_info;
-                  ++sym)
-               if (sym->st_value != 0
-                   && bfd_section_from_elf_index (ibfd, sym->st_shndx) == toc)
-                 {
-                   unsigned long i;
-
-                   if (sym->st_value > toc->rawsize)
-                     i = toc->rawsize >> 3;
-                   else
-                     i = sym->st_value >> 3;
+         for (sym = local_syms;
+              sym < local_syms + symtab_hdr->sh_info;
+              ++sym)
+           if (sym->st_value != 0
+               && bfd_section_from_elf_index (ibfd, sym->st_shndx) == toc)
+             {
+               unsigned long i;
 
-                   if ((skip[i] & (ref_from_discarded | can_optimize)) != 0)
-                     {
-                       (*_bfd_error_handler)
-                         (_("%s defined on removed toc entry"),
-                          bfd_elf_sym_name (ibfd, symtab_hdr, sym, NULL));
-                       do
-                         ++i;
-                       while ((skip[i] & (ref_from_discarded | can_optimize)));
-                       sym->st_value = (bfd_vma) i << 3;
-                     }
+               if (sym->st_value > toc->rawsize)
+                 i = toc->rawsize >> 3;
+               else
+                 i = sym->st_value >> 3;
 
-                   sym->st_value -= skip[i];
-                   symtab_hdr->contents = (unsigned char *) local_syms;
+               if ((skip[i] & (ref_from_discarded | can_optimize)) != 0)
+                 {
+                   if (local_toc_syms)
+                     (*_bfd_error_handler)
+                       (_("%s defined on removed toc entry"),
+                        bfd_elf_sym_name (ibfd, symtab_hdr, sym, NULL));
+                   do
+                     ++i;
+                   while ((skip[i] & (ref_from_discarded | can_optimize)));
+                   sym->st_value = (bfd_vma) i << 3;
                  }
-           }
+
+               sym->st_value -= skip[i];
+               symtab_hdr->contents = (unsigned char *) local_syms;
+             }
 
          /* Adjust any global syms defined in this toc input section.  */
          if (toc_inf.global_toc_syms)
@@ -11401,12 +11398,14 @@ ppc64_elf_action_discarded (asection *sec)
 
 /* REL points to a low-part reloc on a largetoc instruction sequence.
    Find the matching high-part reloc instruction and verify that it
-   is addis REG,r2,x.  If so, return a pointer to the high-part reloc.  */
+   is addis REG,x,imm.  If so, set *REG to x and return a pointer to
+   the high-part reloc.  */
 
 static const Elf_Internal_Rela *
 ha_reloc_match (const Elf_Internal_Rela *relocs,
                const Elf_Internal_Rela *rel,
-               unsigned int reg,
+               unsigned int *reg,
+               bfd_boolean match_addend,
                const bfd *input_bfd,
                const bfd_byte *contents)
 {
@@ -11438,14 +11437,17 @@ ha_reloc_match (const Elf_Internal_Rela *relocs,
 
   while (--rel >= relocs)
     if (rel->r_info == r_info_ha
-       && rel->r_addend == r_addend)
+       && (!match_addend
+           || rel->r_addend == r_addend))
       {
        const bfd_byte *p = contents + (rel->r_offset & ~3);
        unsigned int insn = bfd_get_32 (input_bfd, p);
-       if ((insn & ((0x3f << 26) | (0x1f << 16)))
-           == ((15u << 26) | (2 << 16)) /* addis rt,r2,x */
-           && (insn & (0x1f << 21)) == (reg << 21))
-         return rel;
+       if ((insn & (0x3f << 26)) == (15u << 26) /* addis rt,x,imm */
+           && (insn & (0x1f << 21)) == (*reg << 21))
+         {
+           *reg = (insn >> 16) & 0x1f;
+           return rel;
+         }
        break;
       }
   return NULL;
@@ -11498,7 +11500,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
   Elf_Internal_Rela outrel;
   bfd_byte *loc;
   struct got_entry **local_got_ents;
+  unsigned char *ha_opt;
   bfd_vma TOCstart;
+  bfd_boolean no_ha_opt;
   bfd_boolean ret = TRUE;
   bfd_boolean is_opd;
   /* Disabled until we sort out how ld should choose 'y' vs 'at'.  */
@@ -11524,6 +11528,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
   symtab_hdr = &elf_symtab_hdr (input_bfd);
   sym_hashes = elf_sym_hashes (input_bfd);
   is_opd = ppc64_elf_section_data (input_section)->sec_type == sec_opd;
+  ha_opt = NULL;
+  no_ha_opt = FALSE;
 
   rel = relocs;
   relend = relocs + input_section->reloc_count;
@@ -12949,7 +12955,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_GOT_DTPREL16_HA:
        case R_PPC64_GOT16_HA:
        case R_PPC64_TOC16_HA:
-         /* For now we don't nop out the first instruction.  */
+         /* nop is done later.  */
          break;
 
        case R_PPC64_GOT_TLSLD16_LO:
@@ -12984,12 +12990,31 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                      && ((insn & 3) == 0 || (insn & 3) == 3)))
                {
                  unsigned int reg = (insn >> 16) & 0x1f;
-                 if (ha_reloc_match (relocs, rel, reg, input_bfd, contents))
+                 const Elf_Internal_Rela *ha;
+                 bfd_boolean match_addend;
+
+                 match_addend = (sym != NULL
+                                 && ELF_ST_TYPE (sym->st_info) == STT_SECTION);
+                 ha = ha_reloc_match (relocs, rel, &reg, match_addend,
+                                      input_bfd, contents);
+                 if (ha != NULL)
                    {
                      insn &= ~(0x1f << 16);
-                     insn |= 2 << 16;
+                     insn |= reg << 16;
                      bfd_put_32 (input_bfd, insn, p);
+                     if (ha_opt == NULL)
+                       {
+                         ha_opt = bfd_zmalloc (input_section->reloc_count);
+                         if (ha_opt == NULL)
+                           return FALSE;
+                       }
+                     ha_opt[ha - relocs] = 1;
                    }
+                 else
+                   /* If we don't find a matching high part insn,
+                      something is fishy.  Refuse to nop any high
+                      part insn in this section.  */
+                   no_ha_opt = TRUE;
                }
            }
          break;
@@ -13147,6 +13172,23 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        }
     }
 
+  if (ha_opt != NULL)
+    {
+      if (!no_ha_opt)
+       {
+         unsigned char *opt = ha_opt;
+         rel = relocs;
+         relend = relocs + input_section->reloc_count;
+         for (; rel < relend; opt++, rel++)
+           if (*opt != 0)
+             {
+               bfd_byte *p = contents + (rel->r_offset & ~3);
+               bfd_put_32 (input_bfd, NOP, p);
+             }
+       }
+      free (ha_opt);
+    }
+
   /* If we're emitting relocations, then shortly after this function
      returns, reloc offsets and addends for this section will be
      adjusted.  Worse, reloc symbol indices will be for the output
This page took 0.028639 seconds and 4 git commands to generate.