PowerPC relocations for prefix insns
[deliverable/binutils-gdb.git] / gas / config / tc-ppc.c
index 4026c722939dd992ddbff29fe169ba62feebb502..64ff149b215a53af06224c4a2c93ccbe64e02a21 100644 (file)
@@ -2151,6 +2151,13 @@ ppc_elf_suffix (char **str_p, expressionS *exp_p)
     MAP64 ("tprel@highest",    BFD_RELOC_PPC64_TPREL16_HIGHEST),
     MAP64 ("tprel@highesta",   BFD_RELOC_PPC64_TPREL16_HIGHESTA),
     MAP64 ("notoc",            BFD_RELOC_PPC64_REL24_NOTOC),
+    MAP64 ("pcrel",            BFD_RELOC_PPC64_PCREL34),
+    MAP64 ("got@pcrel",                BFD_RELOC_PPC64_GOT_PCREL34),
+    MAP64 ("plt@pcrel",                BFD_RELOC_PPC64_PLT_PCREL34),
+    MAP64 ("higher34",         BFD_RELOC_PPC64_ADDR16_HIGHER34),
+    MAP64 ("highera34",                BFD_RELOC_PPC64_ADDR16_HIGHERA34),
+    MAP64 ("highest34",                BFD_RELOC_PPC64_ADDR16_HIGHEST34),
+    MAP64 ("highesta34",       BFD_RELOC_PPC64_ADDR16_HIGHESTA34),
     { (char *) 0, 0, 0, 0,     BFD_RELOC_NONE }
   };
 
@@ -2931,6 +2938,10 @@ fixup_size (bfd_reloc_code_real_type reloc, bfd_boolean *pc_relative)
     case BFD_RELOC_PPC64_ADDR16_DS:
     case BFD_RELOC_PPC64_ADDR16_HIGH:
     case BFD_RELOC_PPC64_ADDR16_HIGHA:
+    case BFD_RELOC_PPC64_ADDR16_HIGHER34:
+    case BFD_RELOC_PPC64_ADDR16_HIGHERA34:
+    case BFD_RELOC_PPC64_ADDR16_HIGHEST34:
+    case BFD_RELOC_PPC64_ADDR16_HIGHESTA34:
     case BFD_RELOC_PPC64_ADDR16_LO_DS:
     case BFD_RELOC_PPC64_DTPREL16_DS:
     case BFD_RELOC_PPC64_DTPREL16_HIGH:
@@ -3018,9 +3029,13 @@ fixup_size (bfd_reloc_code_real_type reloc, bfd_boolean *pc_relative)
     case BFD_RELOC_PPC64_REL16_HIGH:
     case BFD_RELOC_PPC64_REL16_HIGHA:
     case BFD_RELOC_PPC64_REL16_HIGHER:
+    case BFD_RELOC_PPC64_REL16_HIGHER34:
     case BFD_RELOC_PPC64_REL16_HIGHERA:
+    case BFD_RELOC_PPC64_REL16_HIGHERA34:
     case BFD_RELOC_PPC64_REL16_HIGHEST:
+    case BFD_RELOC_PPC64_REL16_HIGHEST34:
     case BFD_RELOC_PPC64_REL16_HIGHESTA:
+    case BFD_RELOC_PPC64_REL16_HIGHESTA34:
 #ifdef OBJ_XCOFF
     case BFD_RELOC_PPC_B16:
 #endif
@@ -3100,12 +3115,21 @@ fixup_size (bfd_reloc_code_real_type reloc, bfd_boolean *pc_relative)
     case BFD_RELOC_64:
     case BFD_RELOC_64_PLTOFF:
     case BFD_RELOC_PPC64_ADDR64_LOCAL:
+    case BFD_RELOC_PPC64_D28:
+    case BFD_RELOC_PPC64_D34:
+    case BFD_RELOC_PPC64_D34_LO:
+    case BFD_RELOC_PPC64_D34_HI30:
+    case BFD_RELOC_PPC64_D34_HA30:
     case BFD_RELOC_PPC64_TOC:
       size = 8;
       break;
 
     case BFD_RELOC_64_PCREL:
     case BFD_RELOC_64_PLT_PCREL:
+    case BFD_RELOC_PPC64_GOT_PCREL34:
+    case BFD_RELOC_PPC64_PCREL28:
+    case BFD_RELOC_PPC64_PCREL34:
+    case BFD_RELOC_PPC64_PLT_PCREL34:
       size = 8;
       pcrel = TRUE;
       break;
@@ -3665,24 +3689,47 @@ md_assemble (char *str)
                  reloc = BFD_RELOC_PPC_TPREL16;
                  break;
 
-               case BFD_RELOC_LO16:
-                 if ((operand->bitm | 0xf) != 0xffff
-                     || operand->shift != 0
+               case BFD_RELOC_PPC64_PCREL34:
+                 if (operand->bitm == 0xfffffffULL)
+                   {
+                     reloc = BFD_RELOC_PPC64_PCREL28;
+                     break;
+                   }
+                 /* Fall through.  */
+               case BFD_RELOC_PPC64_GOT_PCREL34:
+               case BFD_RELOC_PPC64_PLT_PCREL34:
+                 if (operand->bitm != 0x3ffffffffULL
                      || (operand->flags & PPC_OPERAND_NEGATIVE) != 0)
+                   as_warn (_("%s unsupported on this instruction"), "@pcrel");
+                 break;
+
+               case BFD_RELOC_LO16:
+                 if (operand->bitm == 0x3ffffffffULL
+                     && (operand->flags & PPC_OPERAND_NEGATIVE) == 0)
+                   reloc = BFD_RELOC_PPC64_D34_LO;
+                 else if ((operand->bitm | 0xf) != 0xffff
+                          || operand->shift != 0
+                          || (operand->flags & PPC_OPERAND_NEGATIVE) != 0)
                    as_warn (_("%s unsupported on this instruction"), "@l");
                  break;
 
                case BFD_RELOC_HI16:
-                 if (operand->bitm != 0xffff
-                     || operand->shift != 0
-                     || (operand->flags & PPC_OPERAND_NEGATIVE) != 0)
+                 if (operand->bitm == 0x3ffffffffULL
+                     && (operand->flags & PPC_OPERAND_NEGATIVE) == 0)
+                   reloc = BFD_RELOC_PPC64_D34_HI30;
+                 else if (operand->bitm != 0xffff
+                          || operand->shift != 0
+                          || (operand->flags & PPC_OPERAND_NEGATIVE) != 0)
                    as_warn (_("%s unsupported on this instruction"), "@h");
                  break;
 
                case BFD_RELOC_HI16_S:
-                 if (operand->bitm == 0xffff
-                     && operand->shift == (int) PPC_OPSHIFT_INV
-                     && opcode->opcode == (19 << 26) + (2 << 1))
+                 if (operand->bitm == 0x3ffffffffULL
+                     && (operand->flags & PPC_OPERAND_NEGATIVE) == 0)
+                   reloc = BFD_RELOC_PPC64_D34_HA30;
+                 else if (operand->bitm == 0xffff
+                          && operand->shift == (int) PPC_OPSHIFT_INV
+                          && opcode->opcode == (19 << 26) + (2 << 1))
                    /* addpcis.  */
                    reloc = BFD_RELOC_PPC_16DX_HA;
                  else if (operand->bitm != 0xffff
@@ -3738,6 +3785,10 @@ md_assemble (char *str)
                }
 #endif
            }
+         else if (operand->bitm == 0x3ffffffffULL)
+           reloc = BFD_RELOC_PPC64_D34;
+         else if (operand->bitm == 0xfffffffULL)
+           reloc = BFD_RELOC_PPC64_D28;
 
          /* For the absolute forms of branches, convert the PC
             relative form back into the absolute.  */
@@ -3787,53 +3838,69 @@ md_assemble (char *str)
                case BFD_RELOC_16:
                  reloc = BFD_RELOC_PPC64_ADDR16_DS;
                  break;
+
                case BFD_RELOC_LO16:
                  reloc = BFD_RELOC_PPC64_ADDR16_LO_DS;
                  break;
+
                case BFD_RELOC_16_GOTOFF:
                  reloc = BFD_RELOC_PPC64_GOT16_DS;
                  break;
+
                case BFD_RELOC_LO16_GOTOFF:
                  reloc = BFD_RELOC_PPC64_GOT16_LO_DS;
                  break;
+
                case BFD_RELOC_LO16_PLTOFF:
                  reloc = BFD_RELOC_PPC64_PLT16_LO_DS;
                  break;
+
                case BFD_RELOC_16_BASEREL:
                  reloc = BFD_RELOC_PPC64_SECTOFF_DS;
                  break;
+
                case BFD_RELOC_LO16_BASEREL:
                  reloc = BFD_RELOC_PPC64_SECTOFF_LO_DS;
                  break;
+
                case BFD_RELOC_PPC_TOC16:
                  reloc = BFD_RELOC_PPC64_TOC16_DS;
                  break;
+
                case BFD_RELOC_PPC64_TOC16_LO:
                  reloc = BFD_RELOC_PPC64_TOC16_LO_DS;
                  break;
+
                case BFD_RELOC_PPC64_PLTGOT16:
                  reloc = BFD_RELOC_PPC64_PLTGOT16_DS;
                  break;
+
                case BFD_RELOC_PPC64_PLTGOT16_LO:
                  reloc = BFD_RELOC_PPC64_PLTGOT16_LO_DS;
                  break;
+
                case BFD_RELOC_PPC_DTPREL16:
                  reloc = BFD_RELOC_PPC64_DTPREL16_DS;
                  break;
+
                case BFD_RELOC_PPC_DTPREL16_LO:
                  reloc = BFD_RELOC_PPC64_DTPREL16_LO_DS;
                  break;
+
                case BFD_RELOC_PPC_TPREL16:
                  reloc = BFD_RELOC_PPC64_TPREL16_DS;
                  break;
+
                case BFD_RELOC_PPC_TPREL16_LO:
                  reloc = BFD_RELOC_PPC64_TPREL16_LO_DS;
                  break;
+
                case BFD_RELOC_PPC_GOT_DTPREL16:
                case BFD_RELOC_PPC_GOT_DTPREL16_LO:
                case BFD_RELOC_PPC_GOT_TPREL16:
                case BFD_RELOC_PPC_GOT_TPREL16_LO:
                  break;
+
                default:
                  as_bad (_("unsupported relocation for DS offset field"));
                  break;
@@ -6903,6 +6970,7 @@ ppc_fix_adjustable (fixS *fix)
          && fix->fx_r_type != BFD_RELOC_PPC64_GOT16_LO_DS
          && fix->fx_r_type != BFD_RELOC_16_GOT_PCREL
          && fix->fx_r_type != BFD_RELOC_32_GOTOFF
+         && fix->fx_r_type != BFD_RELOC_PPC64_GOT_PCREL34
          && fix->fx_r_type != BFD_RELOC_24_PLT_PCREL
          && fix->fx_r_type != BFD_RELOC_32_PLTOFF
          && fix->fx_r_type != BFD_RELOC_32_PLT_PCREL
@@ -6912,6 +6980,7 @@ ppc_fix_adjustable (fixS *fix)
          && fix->fx_r_type != BFD_RELOC_64_PLTOFF
          && fix->fx_r_type != BFD_RELOC_64_PLT_PCREL
          && fix->fx_r_type != BFD_RELOC_PPC64_PLT16_LO_DS
+         && fix->fx_r_type != BFD_RELOC_PPC64_PLT_PCREL34
          && fix->fx_r_type != BFD_RELOC_PPC64_PLTGOT16
          && fix->fx_r_type != BFD_RELOC_PPC64_PLTGOT16_LO
          && fix->fx_r_type != BFD_RELOC_PPC64_PLTGOT16_HI
@@ -7120,10 +7189,34 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
          fixP->fx_r_type = BFD_RELOC_PPC64_REL16_HIGHESTA;
          break;
 
+       case BFD_RELOC_PPC64_ADDR16_HIGHER34:
+         fixP->fx_r_type = BFD_RELOC_PPC64_REL16_HIGHER34;
+         break;
+
+       case BFD_RELOC_PPC64_ADDR16_HIGHERA34:
+         fixP->fx_r_type = BFD_RELOC_PPC64_REL16_HIGHERA34;
+         break;
+
+       case BFD_RELOC_PPC64_ADDR16_HIGHEST34:
+         fixP->fx_r_type = BFD_RELOC_PPC64_REL16_HIGHEST34;
+         break;
+
+       case BFD_RELOC_PPC64_ADDR16_HIGHESTA34:
+         fixP->fx_r_type = BFD_RELOC_PPC64_REL16_HIGHESTA34;
+         break;
+
        case BFD_RELOC_PPC_16DX_HA:
          fixP->fx_r_type = BFD_RELOC_PPC_REL16DX_HA;
          break;
 
+       case BFD_RELOC_PPC64_D34:
+         fixP->fx_r_type = BFD_RELOC_PPC64_PCREL34;
+         break;
+
+       case BFD_RELOC_PPC64_D28:
+         fixP->fx_r_type = BFD_RELOC_PPC64_PCREL28;
+         break;
+
        default:
          break;
        }
@@ -7370,6 +7463,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
        case BFD_RELOC_PPC_VLE_SDAREL_HI16D:
        case BFD_RELOC_PPC_VLE_SDAREL_HA16A:
        case BFD_RELOC_PPC_VLE_SDAREL_HA16D:
+       case BFD_RELOC_PPC64_GOT_PCREL34:
+       case BFD_RELOC_PPC64_PLT_PCREL34:
          gas_assert (fixP->fx_addsy != NULL);
          /* Fallthru */
 
@@ -7421,9 +7516,12 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
 #else
 #define APPLY_RELOC 1
 #endif
+      /* We need to call the insert function even when fieldval is
+        zero if the insert function would translate that zero to a
+        bit pattern other than all zeros.  */
       if ((fieldval != 0 && APPLY_RELOC) || operand->insert != NULL)
        {
-         unsigned long insn;
+         uint64_t insn;
          unsigned char *where;
 
          /* Fetch the instruction, insert the fully resolved operand
@@ -7431,34 +7529,56 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
          where = (unsigned char *) fixP->fx_frag->fr_literal + fixP->fx_where;
          if (target_big_endian)
            {
-             if (fixP->fx_size == 4)
-               insn = bfd_getb32 (where);
-             else
+             if (fixP->fx_size < 4)
                insn = bfd_getb16 (where);
+             else
+               {
+                 insn = bfd_getb32 (where);
+                 if (fixP->fx_size > 4)
+                   insn = insn << 32 | bfd_getb32 (where + 4);
+               }
            }
          else
            {
-             if (fixP->fx_size == 4)
-               insn = bfd_getl32 (where);
-             else
+             if (fixP->fx_size < 4)
                insn = bfd_getl16 (where);
+             else
+               {
+                 insn = bfd_getl32 (where);
+                 if (fixP->fx_size > 4)
+                   insn = insn << 32 | bfd_getl32 (where + 4);
+               }
            }
          insn = ppc_insert_operand (insn, operand, fieldval,
                                     fixP->tc_fix_data.ppc_cpu,
                                     fixP->fx_file, fixP->fx_line);
          if (target_big_endian)
            {
-             if (fixP->fx_size == 4)
-               bfd_putb32 (insn, where);
-             else
+             if (fixP->fx_size < 4)
                bfd_putb16 (insn, where);
+             else
+               {
+                 if (fixP->fx_size > 4)
+                   {
+                     bfd_putb32 (insn, where + 4);
+                     insn >>= 32;
+                   }
+                 bfd_putb32 (insn, where);
+               }
            }
          else
            {
-             if (fixP->fx_size == 4)
-               bfd_putl32 (insn, where);
-             else
+             if (fixP->fx_size < 4)
                bfd_putl16 (insn, where);
+             else
+               {
+                 if (fixP->fx_size > 4)
+                   {
+                     bfd_putl32 (insn, where + 4);
+                     insn >>= 32;
+                   }
+                 bfd_putl32 (insn, where);
+               }
            }
        }
 
This page took 0.028742 seconds and 4 git commands to generate.