R_PPC64_REL24_NOTOC support
[deliverable/binutils-gdb.git] / gas / config / tc-ppc.c
index fd5cc35cd26ec47e29b22394c7f5c3d8d996d4e1..6135cb40f93d9b5f5f52477befdca623e958a4d1 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-ppc.c -- Assemble for the PowerPC or POWER (RS/6000)
-   Copyright (C) 1994-2017 Free Software Foundation, Inc.
+   Copyright (C) 1994-2018 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
    This file is part of GAS, the GNU Assembler.
@@ -217,7 +217,7 @@ static enum {
 
 /* Warn on emitting data to code sections.  */
 int warn_476;
-unsigned long last_insn;
+uint64_t last_insn;
 segT last_seg;
 subsegT last_subseg;
 \f
@@ -974,7 +974,7 @@ ppc_optimize_expr (expressionS *left, operatorT op, expressionS *right)
   /* Accept reg +/- constant.  */
   if (left->X_op == O_register
       && !((op == O_add || op == O_subtract) && right->X_op == O_constant))
-    as_bad (_("invalid register expression"));
+    as_warn (_("invalid register expression"));
 
   /* Accept constant + reg.  */
   if (right->X_op == O_register)
@@ -982,7 +982,7 @@ ppc_optimize_expr (expressionS *left, operatorT op, expressionS *right)
       if (op == O_add && left->X_op == O_constant)
        left->X_md = right->X_md;
       else
-       as_bad (_("invalid register expression"));
+       as_warn (_("invalid register expression"));
     }
 
   return 0;
@@ -1193,7 +1193,8 @@ md_parse_option (int c, const char *arg)
 
     case 'm':
       new_cpu = ppc_parse_cpu (ppc_cpu, &sticky, arg);
-      if (new_cpu != 0)
+      /* "raw" is only valid for the disassembler.  */
+      if (new_cpu != 0 && (new_cpu & PPC_OPCODE_RAW) == 0)
        {
          ppc_cpu = new_cpu;
          if (strcmp (arg, "vle") == 0)
@@ -1205,6 +1206,16 @@ md_parse_option (int c, const char *arg)
            }
        }
 
+      else if (strcmp (arg, "no-vle") == 0)
+       {
+         sticky &= ~PPC_OPCODE_VLE;
+
+         new_cpu = ppc_parse_cpu (ppc_cpu, &sticky, "booke");
+         new_cpu &= ~PPC_OPCODE_VLE;
+
+         ppc_cpu = new_cpu;
+       }
+
       else if (strcmp (arg, "regnames") == 0)
        reg_names_p = TRUE;
 
@@ -1257,6 +1268,10 @@ md_parse_option (int c, const char *arg)
          msolaris = FALSE;
          ppc_comment_chars = ppc_eabi_comment_chars;
        }
+      else if (strcmp (arg, "spe2") == 0)
+       {
+         ppc_cpu |= PPC_OPCODE_SPE2;
+       }
 #endif
       else
        {
@@ -1325,7 +1340,8 @@ PowerPC options:\n\
 -m476                   generate code for PowerPC 476\n\
 -m7400, -m7410, -m7450, -m7455\n\
                         generate code for PowerPC 7400/7410/7450/7455\n\
--m750cl                 generate code for PowerPC 750cl\n\
+-m750cl, -mgekko, -mbroadway\n\
+                        generate code for PowerPC 750cl/Gekko/Broadway\n\
 -m821, -m850, -m860     generate code for PowerPC 821/850/860\n"));
   fprintf (stream, _("\
 -mppc64, -m620          generate code for PowerPC 620/625/630\n\
@@ -1345,7 +1361,6 @@ PowerPC options:\n\
   fprintf (stream, _("\
 -maltivec               generate code for AltiVec\n\
 -mvsx                   generate code for Vector-Scalar (VSX) instructions\n\
--mhtm                   generate code for Hardware Transactional Memory\n\
 -me300                  generate code for PowerPC e300 family\n\
 -me500, -me500x2        generate code for Motorola e500 core complex\n\
 -me500mc,               generate code for Freescale e500mc core complex\n\
@@ -1353,6 +1368,7 @@ PowerPC options:\n\
 -me5500,                generate code for Freescale e5500 core complex\n\
 -me6500,                generate code for Freescale e6500 core complex\n\
 -mspe                   generate code for Motorola SPE instructions\n\
+-mspe2                  generate code for Freescale SPE2 instructions\n\
 -mvle                   generate code for Freescale VLE instructions\n\
 -mtitan                 generate code for AppliedMicro Titan core complex\n\
 -mregnames              Allow symbolic names for registers\n\
@@ -1388,7 +1404,11 @@ ppc_set_cpu (void)
   if ((ppc_cpu & ~(ppc_cpu_t) PPC_OPCODE_ANY) == 0)
     {
       if (ppc_obj64)
-       ppc_cpu |= PPC_OPCODE_PPC | PPC_OPCODE_64;
+       if (target_big_endian)
+         ppc_cpu |= PPC_OPCODE_PPC | PPC_OPCODE_64;
+       else
+         /* The minimum supported cpu for 64-bit little-endian is power8.  */
+         ppc_cpu |= ppc_parse_cpu (ppc_cpu, &sticky, "power8");
       else if (strncmp (default_os, "aix", 3) == 0
               && default_os[3] >= '4' && default_os[3] <= '9')
        ppc_cpu |= PPC_OPCODE_COMMON;
@@ -1482,7 +1502,7 @@ static bfd_boolean
 insn_validate (const struct powerpc_opcode *op)
 {
   const unsigned char *o;
-  unsigned long omask = op->mask;
+  uint64_t omask = op->mask;
 
   /* The mask had better not trim off opcode bits.  */
   if ((op->opcode & omask) != op->opcode)
@@ -1504,7 +1524,7 @@ insn_validate (const struct powerpc_opcode *op)
          const struct powerpc_operand *operand = &powerpc_operands[*o];
          if (operand->shift != (int) PPC_OPSHIFT_INV)
            {
-             unsigned long mask;
+             uint64_t mask;
 
              if (operand->shift >= 0)
                mask = operand->bitm << operand->shift;
@@ -1555,8 +1575,8 @@ ppc_setup_opcodes (void)
         all the 1's in the mask are contiguous.  */
       for (i = 0; i < num_powerpc_operands; ++i)
        {
-         unsigned long mask = powerpc_operands[i].bitm;
-         unsigned long right_bit;
+         uint64_t mask = powerpc_operands[i].bitm;
+         uint64_t right_bit;
          unsigned int j;
 
          right_bit = mask & -mask;
@@ -1583,28 +1603,24 @@ ppc_setup_opcodes (void)
     {
       if (ENABLE_CHECKING)
        {
-         if (op != powerpc_opcodes)
-           {
-             int old_opcode = PPC_OP (op[-1].opcode);
-             int new_opcode = PPC_OP (op[0].opcode);
+         unsigned int new_opcode = PPC_OP (op[0].opcode);
 
 #ifdef PRINT_OPCODE_TABLE
-             printf ("%-14s\t#%04u\tmajor op: 0x%x\top: 0x%x\tmask: 0x%x\tflags: 0x%llx\n",
-                     op->name, (unsigned int) (op - powerpc_opcodes),
-                     (unsigned int) new_opcode, (unsigned int) op->opcode,
-                     (unsigned int) op->mask, (unsigned long long) op->flags);
+         printf ("%-14s\t#%04u\tmajor op: 0x%x\top: 0x%llx\tmask: 0x%llx\tflags: 0x%llx\n",
+                 op->name, (unsigned int) (op - powerpc_opcodes),
+                 new_opcode, (unsigned long long) op->opcode,
+                 (unsigned long long) op->mask, (unsigned long long) op->flags);
 #endif
 
-             /* The major opcodes had better be sorted.  Code in the
-                disassembler assumes the insns are sorted according to
-                major opcode.  */
-             if (new_opcode < old_opcode)
-               {
-                 as_bad (_("major opcode is not sorted for %s"),
-                         op->name);
-                 bad_insn = TRUE;
-               }
+         /* The major opcodes had better be sorted.  Code in the disassembler
+            assumes the insns are sorted according to major opcode.  */
+         if (op != powerpc_opcodes
+             && new_opcode < PPC_OP (op[-1].opcode))
+           {
+             as_bad (_("major opcode is not sorted for %s"), op->name);
+             bad_insn = TRUE;
            }
+
          if ((op->flags & PPC_OPCODE_VLE) != 0)
            {
              as_bad (_("%s is enabled by vle flag"), op->name);
@@ -1644,30 +1660,22 @@ ppc_setup_opcodes (void)
     {
       if (ENABLE_CHECKING)
        {
-         if (op != vle_opcodes)
-           {
-             unsigned old_seg, new_seg;
-
-             old_seg = VLE_OP (op[-1].opcode, op[-1].mask);
-             old_seg = VLE_OP_TO_SEG (old_seg);
-             new_seg = VLE_OP (op[0].opcode, op[0].mask);
-             new_seg = VLE_OP_TO_SEG (new_seg);
+         unsigned new_seg = VLE_OP_TO_SEG (VLE_OP (op[0].opcode, op[0].mask));
 
 #ifdef PRINT_OPCODE_TABLE
-             printf ("%-14s\t#%04u\tmajor op: 0x%x\top: 0x%x\tmask: 0x%x\tflags: 0x%llx\n",
-                     op->name, (unsigned int) (op - powerpc_opcodes),
-                     (unsigned int) new_seg, (unsigned int) op->opcode,
-                     (unsigned int) op->mask, (unsigned long long) op->flags);
+         printf ("%-14s\t#%04u\tmajor op: 0x%x\top: 0x%llx\tmask: 0x%llx\tflags: 0x%llx\n",
+                 op->name, (unsigned int) (op - vle_opcodes),
+                 (unsigned int) new_seg, (unsigned long long) op->opcode,
+                 (unsigned long long) op->mask, (unsigned long long) op->flags);
 #endif
-             /* The major opcodes had better be sorted.  Code in the
-                disassembler assumes the insns are sorted according to
-                major opcode.  */
-             if (new_seg < old_seg)
-               {
-                 as_bad (_("major opcode is not sorted for %s"),
-                         op->name);
-                 bad_insn = TRUE;
-               }
+
+         /* The major opcodes had better be sorted.  Code in the disassembler
+            assumes the insns are sorted according to major opcode.  */
+         if (op != vle_opcodes
+             && new_seg < VLE_OP_TO_SEG (VLE_OP (op[-1].opcode, op[-1].mask)))
+           {
+             as_bad (_("major opcode is not sorted for %s"), op->name);
+             bad_insn = TRUE;
            }
 
          bad_insn |= insn_validate (op);
@@ -1688,6 +1696,54 @@ ppc_setup_opcodes (void)
        }
     }
 
+  /* SPE2 instructions */
+  if ((ppc_cpu & PPC_OPCODE_SPE2) == PPC_OPCODE_SPE2)
+    {
+      op_end = spe2_opcodes + spe2_num_opcodes;
+      for (op = spe2_opcodes; op < op_end; op++)
+       {
+         if (ENABLE_CHECKING)
+           {
+             if (op != spe2_opcodes)
+               {
+               unsigned old_seg, new_seg;
+
+               old_seg = VLE_OP (op[-1].opcode, op[-1].mask);
+               old_seg = VLE_OP_TO_SEG (old_seg);
+               new_seg = VLE_OP (op[0].opcode, op[0].mask);
+               new_seg = VLE_OP_TO_SEG (new_seg);
+
+               /* The major opcodes had better be sorted.  Code in the
+                   disassembler assumes the insns are sorted according to
+                   major opcode.  */
+               if (new_seg < old_seg)
+                 {
+                 as_bad (_("major opcode is not sorted for %s"), op->name);
+                 bad_insn = TRUE;
+                 }
+               }
+
+             bad_insn |= insn_validate (op);
+           }
+
+         if ((ppc_cpu & op->flags) != 0 && !(ppc_cpu & op->deprecated))
+           {
+             const char *retval;
+
+             retval = hash_insert (ppc_hash, op->name, (void *) op);
+             if (retval != NULL)
+               {
+                 as_bad (_("duplicate instruction %s"),
+                         op->name);
+                 bad_insn = TRUE;
+               }
+           }
+       }
+
+      for (op = spe2_opcodes; op < op_end; op++)
+       hash_insert (ppc_hash, op->name, (void *) op);
+    }
+
   /* Insert the macros into a hash table.  */
   ppc_macro_hash = hash_new ();
 
@@ -1821,15 +1877,15 @@ ppc_cleanup (void)
 
 /* Insert an operand value into an instruction.  */
 
-static unsigned long
-ppc_insert_operand (unsigned long insn,
+static uint64_t
+ppc_insert_operand (uint64_t insn,
                    const struct powerpc_operand *operand,
-                   offsetT val,
+                   int64_t val,
                    ppc_cpu_t cpu,
                    const char *file,
                    unsigned int line)
 {
-  long min, max, right;
+  int64_t min, max, right;
 
   max = operand->bitm;
   right = max & -max;
@@ -1858,7 +1914,7 @@ ppc_insert_operand (unsigned long insn,
 
   if ((operand->flags & PPC_OPERAND_NEGATIVE) != 0)
     {
-      long tmp = min;
+      int64_t tmp = min;
       min = -max;
       max = -tmp;
     }
@@ -1871,18 +1927,18 @@ ppc_insert_operand (unsigned long insn,
         sign extend the 32-bit value to 64 bits if so doing makes the
         value valid.  */
       if (val > max
-         && (offsetT) (val - 0x80000000 - 0x80000000) >= min
-         && (offsetT) (val - 0x80000000 - 0x80000000) <= max
-         && ((val - 0x80000000 - 0x80000000) & (right - 1)) == 0)
-       val = val - 0x80000000 - 0x80000000;
+         && (val - (1LL << 32)) >= min
+         && (val - (1LL << 32)) <= max
+         && ((val - (1LL << 32)) & (right - 1)) == 0)
+       val = val - (1LL << 32);
 
       /* Similarly, people write expressions like ~(1<<15), and expect
         this to be OK for a 32-bit unsigned value.  */
       else if (val < min
-              && (offsetT) (val + 0x80000000 + 0x80000000) >= min
-              && (offsetT) (val + 0x80000000 + 0x80000000) <= max
-              && ((val + 0x80000000 + 0x80000000) & (right - 1)) == 0)
-       val = val + 0x80000000 + 0x80000000;
+              && (val + (1LL << 32)) >= min
+              && (val + (1LL << 32)) <= max
+              && ((val + (1LL << 32)) & (right - 1)) == 0)
+       val = val + (1LL << 32);
 
       else if (val < min
               || val > max
@@ -1895,14 +1951,14 @@ ppc_insert_operand (unsigned long insn,
       const char *errmsg;
 
       errmsg = NULL;
-      insn = (*operand->insert) (insn, (long) val, cpu, &errmsg);
+      insn = (*operand->insert) (insn, val, cpu, &errmsg);
       if (errmsg != (const char *) NULL)
        as_bad_where (file, line, "%s", errmsg);
     }
   else if (operand->shift >= 0)
-    insn |= ((long) val & operand->bitm) << operand->shift;
+    insn |= (val & operand->bitm) << operand->shift;
   else
-    insn |= ((long) val & operand->bitm) >> -operand->shift;
+    insn |= (val & operand->bitm) >> -operand->shift;
 
   return insn;
 }
@@ -2029,6 +2085,7 @@ ppc_elf_suffix (char **str_p, expressionS *exp_p)
     MAP64 ("tprel@highera",    BFD_RELOC_PPC64_TPREL16_HIGHERA),
     MAP64 ("tprel@highest",    BFD_RELOC_PPC64_TPREL16_HIGHEST),
     MAP64 ("tprel@highesta",   BFD_RELOC_PPC64_TPREL16_HIGHESTA),
+    MAP64 ("notoc",            BFD_RELOC_PPC64_REL24_NOTOC),
     { (char *) 0, 0, 0, 0,     BFD_RELOC_NONE }
   };
 
@@ -2323,12 +2380,22 @@ ppc_elf_localentry (int ignore ATTRIBUTE_UNUSED)
   if (resolve_expression (&exp)
       && exp.X_op == O_constant)
     {
-      unsigned char encoded = PPC64_SET_LOCAL_ENTRY_OFFSET (exp.X_add_number);
+      unsigned int encoded, ok;
 
-      if (exp.X_add_number != (offsetT) PPC64_LOCAL_ENTRY_OFFSET (encoded))
-        as_bad (_(".localentry expression for `%s' "
-                 "is not a valid power of 2"), S_GET_NAME (sym));
+      ok = 1;
+      if (exp.X_add_number == 1 || exp.X_add_number == 7)
+       encoded = exp.X_add_number << STO_PPC64_LOCAL_BIT;
       else
+       {
+         encoded = PPC64_SET_LOCAL_ENTRY_OFFSET (exp.X_add_number);
+         if (exp.X_add_number != (offsetT) PPC64_LOCAL_ENTRY_OFFSET (encoded))
+           {
+             as_bad (_(".localentry expression for `%s' "
+                       "is not a valid power of 2"), S_GET_NAME (sym));
+             ok = 0;
+           }
+       }
+      if (ok)
        {
          bfdsym = symbol_get_bfdsym (sym);
          elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym);
@@ -2676,7 +2743,7 @@ md_assemble (char *str)
 {
   char *s;
   const struct powerpc_opcode *opcode;
-  unsigned long insn;
+  uint64_t insn;
   const unsigned char *opindex_ptr;
   int skip_optional;
   int need_paren;
@@ -2684,7 +2751,7 @@ md_assemble (char *str)
   struct ppc_fixup fixups[MAX_INSN_FIXUPS];
   int fc;
   char *f;
-  int addr_mod;
+  int addr_mask;
   int i;
   unsigned int insn_length;
 
@@ -2752,11 +2819,9 @@ md_assemble (char *str)
                }
            }
 
-         /* Compute the number of expected operands.
-            Do not count fake operands.  */
+         /* Compute the number of expected operands.  */
          for (num_operands_expected = 0, i = 0; opcode->operands[i]; i ++)
-           if ((powerpc_operands [opcode->operands[i]].flags & PPC_OPERAND_FAKE) == 0)
-             ++ num_operands_expected;
+           ++ num_operands_expected;
 
          /* If there are fewer operands in the line then are called
             for by the instruction, we want to skip the optional
@@ -2789,23 +2854,13 @@ md_assemble (char *str)
        }
       errmsg = NULL;
 
-      /* If this is a fake operand, then we do not expect anything
-        from the input.  */
-      if ((operand->flags & PPC_OPERAND_FAKE) != 0)
-       {
-         insn = (*operand->insert) (insn, 0L, ppc_cpu, &errmsg);
-         if (errmsg != (const char *) NULL)
-           as_bad ("%s", errmsg);
-         continue;
-       }
-
       /* If this is an optional operand, and we are skipping it, just
         insert a zero.  */
       if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
          && !((operand->flags & PPC_OPERAND_OPTIONAL32) != 0 && ppc_obj64)
          && skip_optional)
        {
-         long val = ppc_optional_operand_value (operand);
+         int64_t val = ppc_optional_operand_value (operand);
          if (operand->insert)
            {
              insn = (*operand->insert) (insn, val, ppc_cpu, &errmsg);
@@ -2813,9 +2868,9 @@ md_assemble (char *str)
                as_bad ("%s", errmsg);
            }
          else if (operand->shift >= 0)
-           insn |= ((long) val & operand->bitm) << operand->shift;
+           insn |= (val & operand->bitm) << operand->shift;
          else
-           insn |= ((long) val & operand->bitm) >> -operand->shift;
+           insn |= (val & operand->bitm) >> -operand->shift;
 
          if ((operand->flags & PPC_OPERAND_NEXT) != 0)
            next_opindex = *opindex_ptr + 1;
@@ -2976,8 +3031,8 @@ md_assemble (char *str)
              && !((ex.X_md & PPC_OPERAND_GPR) != 0
                   && ex.X_add_number != 0
                   && (operand->flags & PPC_OPERAND_GPR_0) != 0))
-           as_bad (_("invalid register expression"));
-         insn = ppc_insert_operand (insn, operand, ex.X_add_number & 0xff,
+           as_warn (_("invalid register expression"));
+         insn = ppc_insert_operand (insn, operand, ex.X_add_number,
                                     ppc_cpu, (char *) NULL, 0);
        }
       else if (ex.X_op == O_constant)
@@ -3151,12 +3206,12 @@ md_assemble (char *str)
              /* addpcis.  */
              if (opcode->opcode == (19 << 26) + (2 << 1)
                  && reloc == BFD_RELOC_HI16_S)
-               reloc = BFD_RELOC_PPC_REL16DX_HA;
+               reloc = BFD_RELOC_PPC_16DX_HA;
 
              /* If VLE-mode convert LO/HI/HA relocations.  */
              if (opcode->flags & PPC_OPCODE_VLE)
                {
-                 int tmp_insn = insn & opcode->mask;
+                 uint64_t tmp_insn = insn & opcode->mask;
 
                  int use_a_reloc = (tmp_insn == E_OR2I_INSN
                                     || tmp_insn == E_AND2I_DOT_INSN
@@ -3457,31 +3512,34 @@ md_assemble (char *str)
 #endif
 
   /* Write out the instruction.  */
-  /* Differentiate between two and four byte insns.  */
+
+  addr_mask = 3;
   if ((ppc_cpu & PPC_OPCODE_VLE) != 0)
+    /* All instructions can start on a 2 byte boundary for VLE.  */
+    addr_mask = 1;
+
+  if (frag_now->insn_addr != addr_mask)
     {
-      if (PPC_OP_SE_VLE (insn))
-        insn_length = 2;
-      else
-        insn_length = 4;
-      addr_mod = frag_now_fix () & 1;
-    }
-  else
-    {
-      insn_length = 4;
-      addr_mod = frag_now_fix () & 3;
+      /* Don't emit instructions to a frag started for data, or for a
+        CPU differing in VLE mode.  Data is allowed to be misaligned,
+        and it's possible to start a new frag in the middle of
+        misaligned data.  */
+      frag_wane (frag_now);
+      frag_new (0);
     }
-  /* All instructions can start on a 2 byte boundary for VLE.  */
+
+  /* Check that insns within the frag are aligned.  ppc_frag_check
+     will ensure that the frag start address is aligned.  */
+  if ((frag_now_fix () & addr_mask) != 0)
+    as_bad (_("instruction address is not a multiple of %d"), addr_mask + 1);
+
+  /* Differentiate between two and four byte insns.  */
+  insn_length = 4;
+  if ((ppc_cpu & PPC_OPCODE_VLE) != 0 && PPC_OP_SE_VLE (insn))
+    insn_length = 2;
+
   f = frag_more (insn_length);
-  if (frag_now->has_code && frag_now->insn_addr != addr_mod)
-    {
-      if ((ppc_cpu & PPC_OPCODE_VLE) != 0)
-        as_bad (_("instruction address is not a multiple of 2"));
-      else
-        as_bad (_("instruction address is not a multiple of 4"));
-    }
-  frag_now->insn_addr = addr_mod;
-  frag_now->has_code = 1;
+  frag_now->insn_addr = addr_mask;
   md_number_to_chars (f, insn, insn_length);
   last_insn = insn;
   last_seg = now_seg;
@@ -3630,6 +3688,16 @@ ppc_section_flags (flagword flags, bfd_vma attr ATTRIBUTE_UNUSED, int type)
 
   return flags;
 }
+
+bfd_vma
+ppc_elf_section_letter (int letter, const char **ptrmsg)
+{
+  if (letter == 'v')
+    return SHF_PPC_VLE;
+
+  *ptrmsg = _("bad .section directive: want a,e,v,w,x,M,S,G,T in string");
+  return -1;
+}
 #endif /* OBJ_ELF */
 
 \f
@@ -6349,6 +6417,7 @@ ppc_force_relocation (fixS *fix)
     case BFD_RELOC_PPC_BA26:
     case BFD_RELOC_PPC_B16:
     case BFD_RELOC_PPC_BA16:
+    case BFD_RELOC_PPC64_REL24_NOTOC:
       /* All branch fixups targeting a localentry symbol must
          force a relocation.  */
       if (fix->fx_addsy)
@@ -6387,6 +6456,7 @@ ppc_fix_adjustable (fixS *fix)
     case BFD_RELOC_PPC_B16_BRNTAKEN:
     case BFD_RELOC_PPC_BA16_BRTAKEN:
     case BFD_RELOC_PPC_BA16_BRNTAKEN:
+    case BFD_RELOC_PPC64_REL24_NOTOC:
       if (fix->fx_addsy)
        {
          asymbol *bfdsym = symbol_get_bfdsym (fix->fx_addsy);
@@ -6418,19 +6488,10 @@ ppc_fix_adjustable (fixS *fix)
 void
 ppc_frag_check (struct frag *fragP)
 {
-  if (!fragP->has_code)
-    return;
-
-  if ((ppc_cpu & PPC_OPCODE_VLE) != 0)
-    {
-      if (((fragP->fr_address + fragP->insn_addr) & 1) != 0)
-        as_bad (_("instruction address is not a multiple of 2"));
-    }
-  else
-    {
-      if (((fragP->fr_address + fragP->insn_addr) & 3) != 0)
-        as_bad (_("instruction address is not a multiple of 4"));
-    }
+  if ((fragP->fr_address & fragP->insn_addr) != 0)
+    as_bad_where (fragP->fr_file, fragP->fr_line,
+                 _("instruction address is not a multiple of %d"),
+                 fragP->insn_addr + 1);
 }
 
 /* Implement HANDLE_ALIGN.  This writes the NOP pattern into an
@@ -6482,15 +6543,13 @@ ppc_handle_align (struct frag *fragP)
       md_number_to_chars (dest, 0x60000000, 4);
 
       if ((ppc_cpu & PPC_OPCODE_POWER6) != 0
-         || (ppc_cpu & PPC_OPCODE_POWER7) != 0
-         || (ppc_cpu & PPC_OPCODE_POWER8) != 0
-         || (ppc_cpu & PPC_OPCODE_POWER9) != 0)
+         && (ppc_cpu & PPC_OPCODE_POWER9) == 0)
        {
-         /* For power6, power7, power8 and power9, we want the last nop to be
-            a group terminating one.  Do this by inserting an rs_fill frag
-            immediately after this one, with its address set to the last nop
-            location.  This will automatically reduce the number of nops in
-            the current frag by one.  */
+         /* For power6, power7, and power8, we want the last nop to
+            be a group terminating one.  Do this by inserting an
+            rs_fill frag immediately after this one, with its address
+            set to the last nop location.  This will automatically
+            reduce the number of nops in the current frag by one.  */
          if (count > 4)
            {
              struct frag *group_nop = xmalloc (SIZEOF_STRUCT_FRAG + 4);
@@ -6504,15 +6563,13 @@ ppc_handle_align (struct frag *fragP)
              dest = group_nop->fr_literal;
            }
 
-         if ((ppc_cpu & PPC_OPCODE_POWER7) != 0
-             || (ppc_cpu & PPC_OPCODE_POWER8) != 0
-             || (ppc_cpu & PPC_OPCODE_POWER9) != 0)
+         if ((ppc_cpu & PPC_OPCODE_POWER7) != 0)
            {
              if (ppc_cpu & PPC_OPCODE_E500MC)
                /* e500mc group terminating nop: "ori 0,0,0".  */
                md_number_to_chars (dest, 0x60000000, 4);
              else
-               /* power7/power8/power9 group terminating nop: "ori 2,2,0".  */
+               /* power7/power8 group terminating nop: "ori 2,2,0".  */
                md_number_to_chars (dest, 0x60420000, 4);
            }
          else
@@ -6566,10 +6623,50 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
     }
 #endif
 
-  if (fixP->fx_subsy != (symbolS *) NULL)
+  /* We are only able to convert some relocs to pc-relative.  */
+  if (fixP->fx_pcrel)
     {
-      /* We can't actually support subtracting a symbol.  */
-      as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
+      switch (fixP->fx_r_type)
+       {
+       case BFD_RELOC_LO16:
+         fixP->fx_r_type = BFD_RELOC_LO16_PCREL;
+         break;
+
+       case BFD_RELOC_HI16:
+         fixP->fx_r_type = BFD_RELOC_HI16_PCREL;
+         break;
+
+       case BFD_RELOC_HI16_S:
+         fixP->fx_r_type = BFD_RELOC_HI16_S_PCREL;
+         break;
+
+       case BFD_RELOC_64:
+         fixP->fx_r_type = BFD_RELOC_64_PCREL;
+         break;
+
+       case BFD_RELOC_32:
+         fixP->fx_r_type = BFD_RELOC_32_PCREL;
+         break;
+
+       case BFD_RELOC_16:
+         fixP->fx_r_type = BFD_RELOC_16_PCREL;
+         break;
+
+       case BFD_RELOC_PPC_16DX_HA:
+         fixP->fx_r_type = BFD_RELOC_PPC_REL16DX_HA;
+         break;
+
+       default:
+         break;
+       }
+    }
+  else if (!fixP->fx_done
+          && fixP->fx_r_type == BFD_RELOC_PPC_16DX_HA)
+    {
+      /* addpcis is relative to next insn address.  */
+      value -= 4;
+      fixP->fx_r_type = BFD_RELOC_PPC_REL16DX_HA;
+      fixP->fx_pcrel = 1;
     }
 
   operand = NULL;
@@ -6651,6 +6748,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
 
     case BFD_RELOC_HI16_S:
     case BFD_RELOC_HI16_S_PCREL:
+    case BFD_RELOC_PPC_16DX_HA:
     case BFD_RELOC_PPC_REL16DX_HA:
 #ifdef OBJ_ELF
       if (REPORT_OVERFLOW_HI && ppc_obj64)
@@ -7078,83 +7176,6 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
                       _("data in executable section"));
     }
 
-  /* We are only able to convert some relocs to pc-relative.  */
-  if (!fixP->fx_done && fixP->fx_pcrel)
-    {
-      switch (fixP->fx_r_type)
-       {
-       case BFD_RELOC_LO16:
-         fixP->fx_r_type = BFD_RELOC_LO16_PCREL;
-         break;
-
-       case BFD_RELOC_HI16:
-         fixP->fx_r_type = BFD_RELOC_HI16_PCREL;
-         break;
-
-       case BFD_RELOC_HI16_S:
-         fixP->fx_r_type = BFD_RELOC_HI16_S_PCREL;
-         break;
-
-       case BFD_RELOC_64:
-         fixP->fx_r_type = BFD_RELOC_64_PCREL;
-         break;
-
-       case BFD_RELOC_32:
-         fixP->fx_r_type = BFD_RELOC_32_PCREL;
-         break;
-
-       case BFD_RELOC_16:
-         fixP->fx_r_type = BFD_RELOC_16_PCREL;
-         break;
-
-         /* Some of course are already pc-relative.  */
-       case BFD_RELOC_LO16_PCREL:
-       case BFD_RELOC_HI16_PCREL:
-       case BFD_RELOC_HI16_S_PCREL:
-       case BFD_RELOC_PPC_REL16DX_HA:
-       case BFD_RELOC_64_PCREL:
-       case BFD_RELOC_32_PCREL:
-       case BFD_RELOC_16_PCREL:
-       case BFD_RELOC_PPC_B16:
-       case BFD_RELOC_PPC_B16_BRTAKEN:
-       case BFD_RELOC_PPC_B16_BRNTAKEN:
-       case BFD_RELOC_PPC_B26:
-       case BFD_RELOC_PPC_LOCAL24PC:
-       case BFD_RELOC_24_PLT_PCREL:
-       case BFD_RELOC_32_PLT_PCREL:
-       case BFD_RELOC_64_PLT_PCREL:
-       case BFD_RELOC_PPC_VLE_REL8:
-       case BFD_RELOC_PPC_VLE_REL15:
-       case BFD_RELOC_PPC_VLE_REL24:
-         break;
-
-       default:
-         if (fixP->fx_addsy)
-           {
-             const char *sfile;
-             unsigned int sline;
-
-             /* Use expr_symbol_where to see if this is an
-                expression symbol.  */
-             if (expr_symbol_where (fixP->fx_addsy, &sfile, &sline))
-               as_bad_where (fixP->fx_file, fixP->fx_line,
-                             _("unresolved expression that must"
-                               " be resolved"));
-             else
-               as_bad_where (fixP->fx_file, fixP->fx_line,
-                             _("cannot emit PC relative %s relocation"
-                               " against %s"),
-                             bfd_get_reloc_code_name (fixP->fx_r_type),
-                             S_GET_NAME (fixP->fx_addsy));
-           }
-         else
-           as_bad_where (fixP->fx_file, fixP->fx_line,
-                         _("unable to resolve expression"));
-         fixP->fx_done = 1;
-         break;
-       }
-    }
-
 #ifdef OBJ_ELF
   ppc_elf_validate_fix (fixP, seg);
   fixP->fx_addnumber = value;
This page took 0.035481 seconds and 4 git commands to generate.