2010-09-24 Thomas Schwinge <thomas@codesourcery.com>
[deliverable/binutils-gdb.git] / bfd / elf64-ppc.c
index 97d607b22c2fd7cc5df1ecff7e0076ffb1f74f3c..a4f3064a4f7702210a929e632f2082e3e63a7bed 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;
@@ -8039,13 +8040,21 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
                              r_symndx, ibfd))
                goto error_ret;
 
-             if (!SYMBOL_REFERENCES_LOCAL (info, h))
+             if (!SYMBOL_CALLS_LOCAL (info, h))
                continue;
 
              if (h != NULL)
-               val = h->root.u.def.value;
+               {
+                 if (h->type == STT_GNU_IFUNC)
+                   continue;
+                 val = h->root.u.def.value;
+               }
              else
-               val = sym->st_value;
+               {
+                 if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+                   continue;
+                 val = sym->st_value;
+               }
              val += rel->r_addend;
              val += sym_sec->output_section->vma + sym_sec->output_offset;
 
@@ -8240,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
@@ -8284,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);
@@ -8363,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)
@@ -11393,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)
 {
@@ -11430,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;
@@ -11490,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'.  */
@@ -11516,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;
@@ -11654,7 +11668,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
       /* Check that tls relocs are used with tls syms, and non-tls
         relocs are used with non-tls syms.  */
-      if (r_symndx != 0
+      if (r_symndx != STN_UNDEF
          && r_type != R_PPC64_NONE
          && (h == NULL
              || h->elf.root.type == bfd_link_hash_defined
@@ -11903,9 +11917,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                        if (local_sections[r_symndx] == sec)
                          break;
                      if (r_symndx >= symtab_hdr->sh_info)
-                       r_symndx = 0;
+                       r_symndx = STN_UNDEF;
                      rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
-                     if (r_symndx != 0)
+                     if (r_symndx != STN_UNDEF)
                        rel->r_addend -= (local_syms[r_symndx].st_value
                                          + sec->output_offset
                                          + sec->output_section->vma);
@@ -12011,9 +12025,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                if (local_sections[r_symndx] == sec)
                  break;
              if (r_symndx >= symtab_hdr->sh_info)
-               r_symndx = 0;
+               r_symndx = STN_UNDEF;
              rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
-             if (r_symndx != 0)
+             if (r_symndx != STN_UNDEF)
                rel->r_addend -= (local_syms[r_symndx].st_value
                                  + sec->output_offset
                                  + sec->output_section->vma);
@@ -12367,7 +12381,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                    if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared,
                                                          &h->elf)
                        || (info->shared
-                           && SYMBOL_REFERENCES_LOCAL (info, &h->elf)))
+                           && SYMBOL_CALLS_LOCAL (info, &h->elf)))
                      /* This is actually a static link, or it is a
                         -Bsymbolic link and the symbol is defined
                         locally, or the symbol was forced to be local
@@ -12555,7 +12569,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_TOC:
          /* Relocation value is TOC base.  */
          relocation = TOCstart;
-         if (r_symndx == 0)
+         if (r_symndx == STN_UNDEF)
            relocation += htab->stub_group[input_section->id].toc_off;
          else if (unresolved_reloc)
            ;
@@ -12744,7 +12758,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
              if (skip)
                memset (&outrel, 0, sizeof outrel);
-             else if (!SYMBOL_REFERENCES_LOCAL (info, &h->elf)
+             else if (!SYMBOL_CALLS_LOCAL (info, &h->elf)
                       && !is_opd
                       && r_type != R_PPC64_TOC)
                outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type);
@@ -12805,7 +12819,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                             sym_name);
                          ret = FALSE;
                        }
-                     else if (r_symndx == 0 || bfd_is_abs_section (sec))
+                     else if (r_symndx == STN_UNDEF || bfd_is_abs_section (sec))
                        ;
                      else if (sec == NULL || sec->owner == NULL)
                        {
@@ -12941,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:
@@ -12976,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;
@@ -13139,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.031669 seconds and 4 git commands to generate.