sparc: support %dN and %qN syntax for FP registers.
[deliverable/binutils-gdb.git] / bfd / elf32-ppc.c
index 5c26077ad03bf8007c20ad6f1637d35c6f917680..ea03598c2ead3709edf888aa0dc23c4df1684664 100644 (file)
@@ -1731,6 +1731,21 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         0xffff,                /* dst_mask */
         TRUE),                 /* pcrel_offset */
 
+  /* Like R_PPC_REL16_HA but for split field in addpcis.  */
+  HOWTO (R_PPC_REL16DX_HA,     /* type */
+        16,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        ppc_elf_addr16_ha_reloc, /* special_function */
+        "R_PPC_REL16DX_HA",    /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x1fffc1,              /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
   /* GNU extension to record C++ vtable hierarchy.  */
   HOWTO (R_PPC_GNU_VTINHERIT,  /* type */
         0,                     /* rightshift */
@@ -1989,6 +2004,7 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
     case BFD_RELOC_LO16_PCREL:         r = R_PPC_REL16_LO;             break;
     case BFD_RELOC_HI16_PCREL:         r = R_PPC_REL16_HI;             break;
     case BFD_RELOC_HI16_S_PCREL:       r = R_PPC_REL16_HA;             break;
+    case BFD_RELOC_PPC_REL16DX_HA:     r = R_PPC_REL16DX_HA;           break;
     case BFD_RELOC_VTABLE_INHERIT:     r = R_PPC_GNU_VTINHERIT;        break;
     case BFD_RELOC_VTABLE_ENTRY:       r = R_PPC_GNU_VTENTRY;          break;
     }
@@ -2058,7 +2074,10 @@ ppc_elf_addr16_ha_reloc (bfd *abfd ATTRIBUTE_UNUSED,
                         bfd *output_bfd,
                         char **error_message ATTRIBUTE_UNUSED)
 {
-  bfd_vma relocation;
+  enum elf_ppc_reloc_type r_type;
+  long insn;
+  bfd_size_type octets;
+  bfd_vma value;
 
   if (output_bfd != NULL)
     {
@@ -2066,20 +2085,28 @@ ppc_elf_addr16_ha_reloc (bfd *abfd ATTRIBUTE_UNUSED,
       return bfd_reloc_ok;
     }
 
-  if (bfd_is_com_section (symbol->section))
-    relocation = 0;
-  else
-    relocation = symbol->value;
-
-  relocation += symbol->section->output_section->vma;
-  relocation += symbol->section->output_offset;
-  relocation += reloc_entry->addend;
-  if (reloc_entry->howto->pc_relative)
-    relocation -= reloc_entry->address;
-
-  reloc_entry->addend += (relocation & 0x8000) << 1;
-
-  return bfd_reloc_continue;
+  reloc_entry->addend += 0x8000;
+  r_type = reloc_entry->howto->type;
+  if (r_type != R_PPC_REL16DX_HA)
+    return bfd_reloc_continue;
+
+  value = 0;
+  if (!bfd_is_com_section (symbol->section))
+    value = symbol->value;
+  value += (reloc_entry->addend
+           + symbol->section->output_offset
+           + symbol->section->output_section->vma);
+  value -= (reloc_entry->address
+           + input_section->output_offset
+           + input_section->output_section->vma);
+  value >>= 16;
+
+  octets = reloc_entry->address * bfd_octets_per_byte (abfd);
+  insn = bfd_get_32 (abfd, (bfd_byte *) data + octets);
+  insn &= ~0x1fffc1;
+  insn |= (value & 0xffc1) | ((value & 0x3e) << 15);
+  bfd_put_32 (abfd, insn, (bfd_byte *) data + octets);
+  return bfd_reloc_ok;
 }
 
 static bfd_reloc_status_type
@@ -3921,6 +3948,7 @@ ppc_elf_check_relocs (bfd *abfd,
       enum elf_ppc_reloc_type r_type;
       struct elf_link_hash_entry *h;
       int tls_type;
+      struct plt_entry **ifunc;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
@@ -3953,6 +3981,7 @@ ppc_elf_check_relocs (bfd *abfd,
 
       tls_type = 0;
       r_type = ELF32_R_TYPE (rel->r_info);
+      ifunc = NULL;
       if (h == NULL && !htab->is_vxworks)
        {
          Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache,
@@ -3962,8 +3991,6 @@ ppc_elf_check_relocs (bfd *abfd,
 
          if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
            {
-             struct plt_entry **ifunc;
-
              /* Set PLT_IFUNC flag for this sym, no GOT entry yet.  */
              ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
                                             PLT_IFUNC);
@@ -4197,21 +4224,20 @@ ppc_elf_check_relocs (bfd *abfd,
 #ifdef DEBUG
          fprintf (stderr, "Reloc requires a PLT entry\n");
 #endif
-         /* This symbol requires a procedure linkage table entry.  We
-            actually build the entry in finish_dynamic_symbol,
-            because this might be a case of linking PIC code without
-            linking in any dynamic objects, in which case we don't
-            need to generate a procedure linkage table after all.  */
-
+         /* This symbol requires a procedure linkage table entry.  */
          if (h == NULL)
            {
-             /* It does not make sense to have a procedure linkage
-                table entry for a local symbol.  */
-             info->callbacks->einfo (_("%P: %H: %s reloc against local symbol\n"),
-                                     abfd, sec, rel->r_offset,
-                                     ppc_elf_howto_table[r_type]->name);
-             bfd_set_error (bfd_error_bad_value);
-             return FALSE;
+             if (ifunc == NULL)
+               {
+                 /* It does not make sense to have a procedure linkage
+                    table entry for a non-ifunc local symbol.  */
+                 info->callbacks->einfo
+                   (_("%P: %H: %s reloc against local symbol\n"),
+                    abfd, sec, rel->r_offset,
+                    ppc_elf_howto_table[r_type]->name);
+                 bfd_set_error (bfd_error_bad_value);
+                 return FALSE;
+               }
            }
          else
            {
@@ -4247,6 +4273,7 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_REL16_LO:
        case R_PPC_REL16_HI:
        case R_PPC_REL16_HA:
+       case R_PPC_REL16DX_HA:
          ppc_elf_tdata (abfd)->has_rel16 = 1;
          break;
 
@@ -4288,9 +4315,10 @@ ppc_elf_check_relocs (bfd *abfd,
            {
              if (bfd_link_pic (info))
                {
-                 info->callbacks->einfo (_("%P: %H: @local call to ifunc %s\n"),
-                                         abfd, sec, rel->r_offset,
-                                         h->root.root.string);
+                 info->callbacks->einfo
+                   (_("%P: %H: @local call to ifunc %s\n"),
+                    abfd, sec, rel->r_offset,
+                    h->root.root.string);
                  bfd_set_error (bfd_error_bad_value);
                  return FALSE;
                }
@@ -7604,7 +7632,9 @@ is_insn_ds_form (unsigned int insn)
 static bfd_boolean
 is_insn_dq_form (unsigned int insn)
 {
-  return (insn & (0x3f << 26)) == 56u << 26; /* lq */
+  return ((insn & (0x3f << 26)) == 56u << 26 /* lq */
+         || ((insn & (0x3f << 26)) == (61u << 26) /* lxv, stxv */
+             && (insn & 3) == 1));
 }
 
 /* The RELOCATE_SECTION function is called by the ELF backend linker
@@ -8605,6 +8635,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_REL16_LO:
        case R_PPC_REL16_HI:
        case R_PPC_REL16_HA:
+       case R_PPC_REL16DX_HA:
          break;
 
        case R_PPC_REL32:
@@ -8937,8 +8968,10 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_PLTREL24:
          if (h != NULL && ifunc == NULL)
            {
-             struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2,
-                                                   bfd_link_pic (info) ? addend : 0);
+             struct plt_entry *ent;
+
+             ent = find_plt_ent (&h->plt.plist, got2,
+                                 bfd_link_pic (info) ? addend : 0);
              if (ent == NULL
                  || htab->plt == NULL)
                {
@@ -9311,6 +9344,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC_ADDR16_HA:
        case R_PPC_REL16_HA:
+       case R_PPC_REL16DX_HA:
        case R_PPC_SECTOFF_HA:
        case R_PPC_TPREL16_HA:
        case R_PPC_DTPREL16_HA:
@@ -9369,10 +9403,12 @@ ppc_elf_relocate_section (bfd *output_bfd,
              mask = 15;
            else
              break;
-           lobit = mask & (relocation + addend);
+           relocation += addend;
+           addend = insn & mask;
+           lobit = mask & relocation;
            if (lobit != 0)
              {
-               addend -= lobit;
+               relocation ^= lobit;
                info->callbacks->einfo
                  (_("%P: %H: error: %s against `%s' not a multiple of %u\n"),
                   input_bfd, input_section, rel->r_offset,
@@ -9380,7 +9416,6 @@ ppc_elf_relocate_section (bfd *output_bfd,
                bfd_set_error (bfd_error_bad_value);
                ret = FALSE;
              }
-           addend += insn & mask;
          }
          break;
        }
@@ -9439,8 +9474,30 @@ ppc_elf_relocate_section (bfd *output_bfd,
            }
        }
 
-      r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
-                                   rel->r_offset, relocation, addend);
+      if (r_type == R_PPC_REL16DX_HA)
+       {
+         /* Split field reloc isn't handled by _bfd_final_link_relocate.  */
+         if (rel->r_offset + 4 > input_section->size)
+           r = bfd_reloc_outofrange;
+         else
+           {
+             unsigned int insn;
+
+             relocation += addend;
+             relocation -= (rel->r_offset
+                            + input_section->output_offset
+                            + input_section->output_section->vma);
+             relocation >>= 16;
+             insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+             insn &= ~0x1fffc1;
+             insn |= (relocation & 0xffc1) | ((relocation & 0x3e) << 15);
+             bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+             r = bfd_reloc_ok;
+           }
+       }
+      else
+       r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
+                                     rel->r_offset, relocation, addend);
 
       if (r != bfd_reloc_ok)
        {
This page took 0.031739 seconds and 4 git commands to generate.