2005-08-05 Paul Brook <paul@codesourcery.com>
[deliverable/binutils-gdb.git] / gas / config / tc-arm.c
index 2288d991ee44c34f826c1c211d0f0e7b7004385e..6a587f3c9ce4a2fcb7449596fd60cef233c44123 100644 (file)
@@ -226,17 +226,17 @@ struct arm_it
   struct
   {
     unsigned reg;
-    unsigned imm;
-    unsigned present   : 1;  /* operand present */
-    unsigned isreg     : 1;  /* operand was a register */
-    unsigned immisreg  : 1;  /* .imm field is a second register */
-    unsigned hasreloc  : 1;  /* operand has relocation suffix */
-    unsigned writeback : 1;  /* operand has trailing ! */
-    unsigned preind    : 1;  /* preindexed address */
-    unsigned postind   : 1;  /* postindexed address */
-    unsigned negative  : 1;  /* index register was negated */
-    unsigned shifted   : 1;  /* shift applied to operation */
-    unsigned shift_kind : 3;  /* shift operation (enum shift_kind) */
+    signed int imm;
+    unsigned present   : 1;  /* Operand present.  */
+    unsigned isreg     : 1;  /* Operand was a register.  */
+    unsigned immisreg  : 1;  /* .imm field is a second register */
+    unsigned hasreloc  : 1;  /* Operand has relocation suffix.  */
+    unsigned writeback : 1;  /* Operand has trailing !  */
+    unsigned preind    : 1;  /* Preindexed address.  */
+    unsigned postind   : 1;  /* Postindexed address.  */
+    unsigned negative  : 1;  /* Index register was negated.  */
+    unsigned shifted   : 1;  /* Shift applied to operation.  */
+    unsigned shift_kind : 3;  /* Shift operation (enum shift_kind).  */
   } operands[6];
 };
 
@@ -485,7 +485,7 @@ struct asm_opcode
 #define T_OPCODE_PUSH  0xb400
 #define T_OPCODE_POP   0xbc00
 
-#define T_OPCODE_BRANCH 0xe7fe
+#define T_OPCODE_BRANCH 0xe000
 
 #define THUMB_SIZE     2       /* Size of thumb instruction.  */
 #define THUMB_PP_PC_LR 0x0100
@@ -535,6 +535,11 @@ typedef struct literal_pool
 
 /* Pointer to a linked list of literal pools.  */
 literal_pool * list_of_pools = NULL;
+
+/* State variables for IT block handling.  */
+static bfd_boolean current_it_mask = 0;
+static int current_cc;
+
 \f
 /* Pure syntax.         */
 
@@ -1035,7 +1040,7 @@ parse_reg_list (char ** strp)
    register.  Double precision registers are matched if DP is nonzero. */
 
 static int
-parse_vfp_reg_list (char **str, int *pbase, int dp)
+parse_vfp_reg_list (char **str, unsigned int *pbase, int dp)
 {
   int base_reg;
   int new_base;
@@ -1970,8 +1975,15 @@ s_arm_elf_cons (int nbytes)
              reloc_howto_type *howto = bfd_reloc_type_lookup (stdoutput, reloc);
              int size = bfd_get_reloc_size (howto);
 
+             if (reloc == BFD_RELOC_ARM_PLT32)
+               {
+                 as_bad (_("(plt) is only valid on branch targets"));
+                 reloc = BFD_RELOC_UNUSED;
+                 size = 0;
+               }
+
              if (size > nbytes)
-               as_bad ("%s relocations do not fit in %d bytes",
+               as_bad (_("%s relocations do not fit in %d bytes"),
                        howto->name, nbytes);
              else
                {
@@ -2328,7 +2340,7 @@ static void
 s_arm_unwind_save_vfp (void)
 {
   int count;
-  int reg;
+  unsigned int reg;
   valueT op;
 
   count = parse_vfp_reg_list (&input_line_pointer, &reg, 1);
@@ -3239,7 +3251,7 @@ parse_address (char **str, int i)
        {
          /* [Rn], {expr} - unindexed, with option */
          if (parse_immediate (&p, &inst.operands[i].imm,
-                                      0, 255, TRUE) == FAIL)
+                              0, 255, TRUE) == FAIL)
            return FAIL;
 
          if (skip_past_char (&p, '}') == FAIL)
@@ -3484,6 +3496,55 @@ parse_cond (char **str)
   return c->value;
 }
 
+/* Parse the operands of a table branch instruction.  Similar to a memory
+   operand.  */
+static int
+parse_tb (char **str)
+{
+  char * p = *str;
+  int reg;
+
+  if (skip_past_char (&p, '[') == FAIL)
+    return FAIL;
+
+  if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL)
+    {
+      inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
+      return FAIL;
+    }
+  inst.operands[0].reg = reg;
+
+  if (skip_past_comma (&p) == FAIL)
+    return FAIL;
+  
+  if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL)
+    {
+      inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
+      return FAIL;
+    }
+  inst.operands[0].imm = reg;
+
+  if (skip_past_comma (&p) == SUCCESS)
+    {
+      if (parse_shift (&p, 0, SHIFT_LSL_IMMEDIATE) == FAIL)
+       return FAIL;
+      if (inst.reloc.exp.X_add_number != 1)
+       {
+         inst.error = _("invalid shift");
+         return FAIL;
+       }
+      inst.operands[0].shifted = 1;
+    }
+
+  if (skip_past_char (&p, ']') == FAIL)
+    {
+      inst.error = _("']' expected");
+      return FAIL;
+    }
+  *str = p;
+  return SUCCESS;
+}
+
 /* Matcher codes for parse_operands.  */
 enum operand_parse_code
 {
@@ -3539,6 +3600,7 @@ enum operand_parse_code
   OP_ENDI,     /* Endianness specifier */
   OP_PSR,      /* CPSR/SPSR mask for msr */
   OP_COND,     /* conditional code */
+  OP_TB,       /* Table branch.  */
 
   OP_RRnpc_I0, /* ARM register or literal 0 */
   OP_RR_EXr,   /* ARM register or expression with opt. reloc suff. */
@@ -3567,7 +3629,7 @@ enum operand_parse_code
    structure.  Returns SUCCESS or FAIL depending on whether the
    specified grammar matched.  */
 static int
-parse_operands (char *str, const char *pattern)
+parse_operands (char *str, const unsigned char *pattern)
 {
   unsigned const char *upat = pattern;
   char *backtrack_pos = 0;
@@ -3780,6 +3842,10 @@ parse_operands (char *str, const char *pattern)
        case OP_PSR:     val = parse_psr (&str);                break;
        case OP_COND:    val = parse_cond (&str);               break;
 
+       case OP_TB:
+         po_misc_or_fail (parse_tb (&str));
+         break;
+
          /* Register lists */
        case OP_REGLST:
          val = parse_reg_list (&str);
@@ -3928,14 +3994,14 @@ encode_thumb32_immediate (unsigned int val)
 {
   unsigned int a, i;
 
-  if (val <= 255)
+  if (val <= 0xff)
     return val;
 
-  for (i = 0; i < 32; i++)
+  for (i = 1; i <= 24; i++)
     {
-      a = rotate_left (val, i);
-      if (a >= 128 && a <= 255)
-       return (a & 0x7f) | (i << 7);
+      a = val >> i;
+      if ((val & ~(0xff << i)) == 0)
+       return ((val >> i) & 0x7f) | ((32 - i) << 7);
     }
 
   a = val & 0xff;
@@ -4075,8 +4141,6 @@ encode_arm_addr_mode_2 (int i, bfd_boolean is_t)
     {
       if (inst.reloc.type == BFD_RELOC_UNUSED)
        inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
-      if (inst.reloc.pc_rel)
-       inst.reloc.exp.X_add_number -= 8;  /* pipeline offset */
     }
 }
 
@@ -4107,8 +4171,6 @@ encode_arm_addr_mode_3 (int i, bfd_boolean is_t)
       inst.instruction |= HWOFFSET_IMM;
       if (inst.reloc.type == BFD_RELOC_UNUSED)
        inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
-      if (inst.reloc.pc_rel)
-       inst.reloc.exp.X_add_number -= 8;  /* pipeline offset */
     }
 }
 
@@ -4161,8 +4223,6 @@ encode_arm_cp_address (int i, int wb_ok, int unind_ok, int reloc_override)
     inst.reloc.type = reloc_override;
   else
     inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
-  if (inst.reloc.pc_rel)
-    inst.reloc.exp.X_add_number -= 8;
   return SUCCESS;
 }
 
@@ -4329,10 +4389,8 @@ do_adr (void)
   /* Frag hacking will turn this into a sub instruction if the offset turns
      out to be negative.  */
   inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
-#ifndef TE_WINCE
-  inst.reloc.exp.X_add_number -= 8; /* PC relative adjust.  */
-#endif
   inst.reloc.pc_rel = 1;
+  inst.reloc.exp.X_add_number -= 8;
 }
 
 /* This is a pseudo-op of the form "adrl rd, label" to be converted
@@ -4348,11 +4406,9 @@ do_adrl (void)
   /* Frag hacking will turn this into a sub instruction if the offset turns
      out to be negative.  */
   inst.reloc.type             = BFD_RELOC_ARM_ADRL_IMMEDIATE;
-#ifndef TE_WINCE
-  inst.reloc.exp.X_add_number -= 8; /* PC relative adjust  */
-#endif
   inst.reloc.pc_rel           = 1;
   inst.size                   = INSN_SIZE * 2;
+  inst.reloc.exp.X_add_number -= 8;
 }
 
 static void
@@ -4432,13 +4488,12 @@ encode_branch (int default_reloc)
       constraint (inst.operands[0].imm != BFD_RELOC_ARM_PLT32,
                  _("the only suffix valid here is '(plt)'"));
       inst.reloc.type  = BFD_RELOC_ARM_PLT32;
-      inst.reloc.pc_rel = 0;
     }
   else
     {
       inst.reloc.type = default_reloc;
-      inst.reloc.pc_rel = 1;
     }
+  inst.reloc.pc_rel = 1;
 }
 
 static void
@@ -4472,7 +4527,7 @@ do_blx (void)
       /* Arg is an address; this instruction cannot be executed
         conditionally, and the opcode must be adjusted.  */
       constraint (inst.cond != COND_ALWAYS, BAD_COND);
-      inst.instruction = 0xfafffffe;
+      inst.instruction = 0xfa000000;
       encode_branch (BFD_RELOC_ARM_PCREL_BLX);
     }
 }
@@ -4649,8 +4704,8 @@ do_ldrd (void)
       /* For an index-register load, the index register must not overlap the
         destination (even if not write-back).  */
       else if (inst.operands[2].immisreg
-              && (inst.operands[2].imm == inst.operands[0].reg
-                  || inst.operands[2].imm == inst.operands[1].reg))
+              && ((unsigned) inst.operands[2].imm == inst.operands[0].reg
+                  || (unsigned) inst.operands[2].imm == inst.operands[1].reg))
        as_warn (_("index register overlaps destination register"));
     }
 
@@ -5466,7 +5521,7 @@ static void
 do_iwmmxt_wldstd (void)
 {
   inst.instruction |= inst.operands[0].reg << 12;
-  encode_arm_cp_address (1, TRUE, FALSE, BFD_RELOC_ARM_CP_OFF_IMM_S2);
+  encode_arm_cp_address (1, TRUE, FALSE, 0);
 }
 
 static void
@@ -5587,6 +5642,8 @@ encode_thumb32_shifted_operand (int i)
   unsigned int value = inst.reloc.exp.X_add_number;
   unsigned int shift = inst.operands[i].shift_kind;
 
+  constraint (inst.operands[i].immisreg,
+             _("shift by register not allowed in thumb mode"));
   inst.instruction |= inst.operands[i].reg;
   if (shift == SHIFT_RRX)
     inst.instruction |= SHIFT_ROR << 4;
@@ -5645,9 +5702,10 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
        {
          constraint (inst.reloc.exp.X_op != O_constant,
                      _("expression too complex"));
-         constraint (inst.reloc.exp.X_add_number < 0 || inst.reloc.exp.X_add_number > 3,
+         constraint (inst.reloc.exp.X_add_number < 0
+                     || inst.reloc.exp.X_add_number > 3,
                      _("shift out of range"));
-         inst.instruction |= inst.reloc.exp.X_op << 4;
+         inst.instruction |= inst.reloc.exp.X_add_number << 4;
        }
       inst.reloc.type = BFD_RELOC_UNUSED;
     }
@@ -5671,7 +5729,6 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
            inst.instruction |= 0x00000100;
        }
       inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_IMM;
-      inst.reloc.pc_rel = is_pc;
     }
   else if (inst.operands[i].postind)
     {
@@ -5699,6 +5756,7 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
   X(adcs,  4140, eb500000),                    \
   X(add,   1c00, eb000000),                    \
   X(adds,  1c00, eb100000),                    \
+  X(adr,   000f, f20f0000),                    \
   X(and,   4000, ea000000),                    \
   X(ands,  4000, ea100000),                    \
   X(asr,   1000, fa40f000),                    \
@@ -5732,8 +5790,8 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
   X(negs,  4240, f1d00000), /* rsbs #0 */      \
   X(orr,   4300, ea400000),                    \
   X(orrs,  4300, ea500000),                    \
-  X(pop,   bc00, e8ad0000), /* ldmia sp!,... */        \
-  X(push,  b400, e8bd0000), /* stmia sp!,... */        \
+  X(pop,   bc00, e8bd0000), /* ldmia sp!,... */        \
+  X(push,  b400, e92d0000), /* stmdb sp!,... */        \
   X(rev,   ba00, fa90f080),                    \
   X(rev16, ba40, fa90f090),                    \
   X(revsh, bac0, fa90f0b0),                    \
@@ -5779,6 +5837,20 @@ static const unsigned int thumb_op32[] = { T16_32_TAB };
 
 /* Thumb instruction encoders, in alphabetical order.  */
 
+/* ADDW or SUBW.  */
+static void
+do_t_add_sub_w (void)
+{
+  int Rd, Rn;
+
+  Rd = inst.operands[0].reg;
+  Rn = inst.operands[1].reg;
+
+  constraint (Rd == 15, _("PC not allowed as destination"));
+  inst.instruction |= (Rn << 16) | (Rd << 8);
+  inst.reloc.type = BFD_RELOC_ARM_T32_IMM12;
+}
+
 /* Parse an add or subtract instruction.  We get here with inst.instruction
    equalling any of THUMB_OPCODE_add, adds, sub, or subs.  */
 
@@ -5796,6 +5868,8 @@ do_t_add_sub (void)
     {
       if (!inst.operands[2].isreg)
        {
+         /* ??? Convert large immediates to addw/subw.  */
+         /* ??? 16-bit adds with small immediates.  */
          /* For an immediate, we always generate a 32-bit opcode;
             section relaxation will shrink it later if possible.  */
          inst.instruction = THUMB_OP32 (inst.instruction);
@@ -5810,11 +5884,20 @@ do_t_add_sub (void)
          /* See if we can do this with a 16-bit instruction.  */
          if (!inst.operands[2].shifted && inst.size_req != 4)
            {
-             if (Rd <= 7 && Rn <= 7 && Rn <= 7
-                 && (inst.instruction == T_MNEM_adds
-                     || inst.instruction == T_MNEM_subs))
+             bfd_boolean narrow;
+
+             if (inst.instruction == T_MNEM_adds
+                 || inst.instruction == T_MNEM_subs)
+               narrow = (current_it_mask == 0);
+             else
+               narrow = (current_it_mask != 0);
+             if (Rd > 7 || Rs > 7 || Rn > 7)
+               narrow = FALSE;
+
+             if (narrow)
                {
-                 inst.instruction = (inst.instruction == T_MNEM_adds
+                 inst.instruction = ((inst.instruction == T_MNEM_adds
+                                      || inst.instruction == T_MNEM_add)
                                      ? T_OPCODE_ADD_R3
                                      : T_OPCODE_SUB_R3);
                  inst.instruction |= Rd | (Rs << 3) | (Rn << 6);
@@ -5900,11 +5983,24 @@ do_t_add_sub (void)
 static void
 do_t_adr (void)
 {
-  inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
-  inst.reloc.exp.X_add_number -= 4; /* PC relative adjust.  */
-  inst.reloc.pc_rel = 1;
+  if (unified_syntax && inst.size_req != 2)
+    {
+      /* Always generate a 32-bit opcode;
+        section relaxation will shrink it later if possible.  */
+      inst.instruction = THUMB_OP32 (inst.instruction);
+      inst.instruction |= inst.operands[0].reg << 8;
+      inst.reloc.type = BFD_RELOC_ARM_T32_ADD_PC12;
+      inst.reloc.pc_rel = 1;
+    }
+  else
+    {
+      inst.instruction = THUMB_OP16 (inst.instruction);
+      inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
+      inst.reloc.exp.X_add_number -= 4; /* PC relative adjust.  */
+      inst.reloc.pc_rel = 1;
 
-  inst.instruction |= inst.operands[0].reg << 4;
+      inst.instruction |= inst.operands[0].reg << 4;
+    }
 }
 
 /* Arithmetic instructions for which there is just one 16-bit
@@ -5938,10 +6034,22 @@ do_t_arit3 (void)
        }
       else
        {
+         bfd_boolean narrow;
+
          /* See if we can do this with a 16-bit instruction.  */
-         if (THUMB_SETS_FLAGS (inst.instruction)
-             && !inst.operands[2].shifted
-             && inst.size_req != 4
+         if (THUMB_SETS_FLAGS (inst.instruction))
+           narrow = current_it_mask == 0;
+         else
+           narrow = current_it_mask != 0;
+
+         if (Rd > 7 || Rn > 7 || Rs > 7)
+           narrow = FALSE;
+         if (inst.operands[2].shifted)
+           narrow = FALSE;
+         if (inst.size_req == 4)
+           narrow = FALSE;
+
+         if (narrow
              && Rd == Rs)
            {
              inst.instruction = THUMB_OP16 (inst.instruction);
@@ -6009,10 +6117,22 @@ do_t_arit3c (void)
        }
       else
        {
+         bfd_boolean narrow;
+
          /* See if we can do this with a 16-bit instruction.  */
-         if (THUMB_SETS_FLAGS (inst.instruction)
-             && !inst.operands[2].shifted
-             && inst.size_req != 4)
+         if (THUMB_SETS_FLAGS (inst.instruction))
+           narrow = current_it_mask == 0;
+         else
+           narrow = current_it_mask != 0;
+
+         if (Rd > 7 || Rn > 7 || Rs > 7)
+           narrow = FALSE;
+         if (inst.operands[2].shifted)
+           narrow = FALSE;
+         if (inst.size_req == 4)
+           narrow = FALSE;
+
+         if (narrow)
            {
              if (Rd == Rs)
                {
@@ -6128,7 +6248,7 @@ do_t_blx (void)
   else
     {
       /* No register.  This must be BLX(1).  */
-      inst.instruction = 0xf7ffeffe;
+      inst.instruction = 0xf000e800;
       inst.reloc.type  = BFD_RELOC_THUMB_PCREL_BLX;
       inst.reloc.pc_rel = 1;
     }
@@ -6141,13 +6261,13 @@ do_t_branch (void)
     {
       if (inst.cond == COND_ALWAYS)
        {
-         inst.instruction = 0xf7ffbffe;
+         inst.instruction = 0xf000b000;
          inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH25;
        }
       else
        {
          assert (inst.cond != 0xF);
-         inst.instruction = (inst.cond << 22) | 0xf43faffe;
+         inst.instruction = (inst.cond << 22) | 0xf0008000;
          inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH20;
        }
     }
@@ -6157,7 +6277,7 @@ do_t_branch (void)
        inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH12;
       else
        {
-         inst.instruction = 0xd0fe | (inst.cond << 8);
+         inst.instruction = 0xd000 | (inst.cond << 8);
          inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH9;
        }
     }
@@ -6283,21 +6403,26 @@ static void
 do_t_it (void)
 {
   unsigned int cond = inst.operands[0].imm;
+
+  current_it_mask = (inst.instruction & 0xf) | 0x10;
+  current_cc = cond;
+
+  /* If the condition is a negative condition, invert the mask.  */
   if ((cond & 0x1) == 0x0)
     {
       unsigned int mask = inst.instruction & 0x000f;
-      inst.instruction &= 0xfff0;
 
       if ((mask & 0x7) == 0)
        /* no conversion needed */;
       else if ((mask & 0x3) == 0)
-       mask = (~(mask & 0x8) & 0x8) | 0x4;
-      else if ((mask & 1) == 0)
-       mask = (~(mask & 0xC) & 0xC) | 0x2;
+       mask ^= 0x8;
+      else if ((mask & 0x1) == 0)
+       mask ^= 0xC;
       else
-       mask = (~(mask & 0xE) & 0xE) | 0x1;
+       mask ^= 0xE;
 
-      inst.instruction |= (mask & 0xF);
+      inst.instruction &= 0xfff0;
+      inst.instruction |= mask;
     }
 
   inst.instruction |= cond << 4;
@@ -6885,39 +7010,52 @@ do_t_pld (void)
 static void
 do_t_push_pop (void)
 {
+  unsigned mask;
+  
   constraint (inst.operands[0].writeback,
              _("push/pop do not support {reglist}^"));
   constraint (inst.reloc.type != BFD_RELOC_UNUSED,
              _("expression too complex"));
 
-  if ((inst.operands[0].imm & ~0xff) == 0)
+  mask = inst.operands[0].imm;
+  if ((mask & ~0xff) == 0)
     inst.instruction = THUMB_OP16 (inst.instruction);
   else if ((inst.instruction == T_MNEM_push
-           && (inst.operands[0].imm & ~0xff) == 1 << REG_LR)
+           && (mask & ~0xff) == 1 << REG_LR)
           || (inst.instruction == T_MNEM_pop
-              && (inst.operands[0].imm & ~0xff) == 1 << REG_PC))
+              && (mask & ~0xff) == 1 << REG_PC))
     {
       inst.instruction = THUMB_OP16 (inst.instruction);
       inst.instruction |= THUMB_PP_PC_LR;
-      inst.operands[0].imm &= 0xff;
+      mask &= 0xff;
     }
   else if (unified_syntax)
     {
-      if (inst.operands[1].imm & (1 << 13))
-       as_warn (_("SP should not be in register list"));
+      if (mask & (1 << 13))
+       inst.error =  _("SP not allowed in register list");
       if (inst.instruction == T_MNEM_push)
        {
-         if (inst.operands[1].imm & (1 << 15))
-           as_warn (_("PC should not be in register list"));
+         if (mask & (1 << 15))
+           inst.error = _("PC not allowed in register list");
        }
       else
        {
-         if (inst.operands[1].imm & (1 << 14)
-             && inst.operands[1].imm & (1 << 15))
-           as_warn (_("LR and PC should not both be in register list"));
+         if (mask & (1 << 14)
+             && mask & (1 << 15))
+           inst.error = _("LR and PC should not both be in register list");
        }
-
-      inst.instruction = THUMB_OP32 (inst.instruction);
+      if ((mask & (mask - 1)) == 0)
+       {
+         /* Single register push/pop implemented as str/ldr.  */
+         if (inst.instruction == T_MNEM_push)
+           inst.instruction = 0xf84d0d04; /* str reg, [sp, #-4]! */
+         else
+           inst.instruction = 0xf85d0b04; /* ldr reg, [sp], #4 */
+         mask = ffs(mask) - 1;
+         mask <<= 12;
+       }
+      else
+       inst.instruction = THUMB_OP32 (inst.instruction);
     }
   else
     {
@@ -6925,7 +7063,7 @@ do_t_push_pop (void)
       return;
     }
 
-  inst.instruction |= inst.operands[0].imm;
+  inst.instruction |= mask;
 }
 
 static void
@@ -7228,6 +7366,21 @@ do_t_swi (void)
   inst.reloc.type = BFD_RELOC_ARM_SWI;
 }
 
+static void
+do_t_tb (void)
+{
+  int half;
+
+  half = (inst.instruction & 0x10) != 0;
+  constraint (inst.operands[0].imm == 15,
+             _("PC is not a valid index register"));
+  constraint (!half && inst.operands[0].shifted,
+             _("instruction does not allow shifted index"));
+  constraint (half && !inst.operands[0].shifted,
+             _("instruction requires shifted index"));
+  inst.instruction |= (inst.operands[0].reg << 16) | inst.operands[0].imm;
+}
+
 static void
 do_t_usat (void)
 {
@@ -7579,12 +7732,35 @@ md_assemble (char *str)
          return;
        }
 
+      /* Check conditional suffixes.  */
+      if (current_it_mask)
+       {
+         int cond;
+         cond = current_cc ^ ((current_it_mask >> 4) & 1) ^ 1;
+         if (cond != inst.cond)
+           {
+             as_bad (_("incorrect condition in IT block"));
+             return;
+           }
+         current_it_mask <<= 1;
+         current_it_mask &= 0x1f;
+       }
+      else if (inst.cond != COND_ALWAYS && opcode->tencode != do_t_branch)
+       {
+         as_bad (_("thumb conditional instrunction not in IT block"));
+         return;
+       }
+
       mapping_state (MAP_THUMB);
       inst.instruction = opcode->tvalue;
 
       if (!parse_operands (p, opcode->operands))
        opcode->tencode ();
 
+      /* Clear current_it_mask at the end of an IT block.  */
+      if (current_it_mask == 0x10)
+       current_it_mask = 0;
+
       if (!inst.error)
        {
          assert (inst.instruction < 0xe800 || inst.instruction > 0xffff);
@@ -8123,19 +8299,13 @@ static const struct asm_opcode insns[] =
  tC3(ldmfd,    8900000, ldmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
 
  TCE(swi,      f000000, df00,     1, (EXPi),        swi, t_swi),
-#ifdef TE_WINCE
-  /* XXX This is the wrong place to do this.  Think multi-arch.         */
- TCE(b,                a000000, e7fe,       1, (EXPr),     branch, t_branch),
- TCE(bl,       b000000, f7fffffe,   1, (EXPr),     branch, t_branch23),
-#else
- TCE(b,                afffffe, e7fe,       1, (EXPr),     branch, t_branch),
- TCE(bl,       bfffffe, f7fffffe,   1, (EXPr),     branch, t_branch23),
-#endif
+ TCE(b,                a000000, e000,     1, (EXPr),        branch, t_branch),
+ TCE(bl,       b000000, f000f800, 1, (EXPr),        branch, t_branch23),
 
   /* Pseudo ops.  */
TCE(adr,      28f0000, 000f,     2, (RR, EXP),    adr,  t_adr),
-  C3(adrl,     28f0000,           2, (RR, EXP),    adrl),
- tCE(nop,      1a00000, nop,      1, (oI255c),     nop,  t_nop),
tCE(adr,      28f0000, adr,      2, (RR, EXP),     adr,  t_adr),
+  C3(adrl,     28f0000,           2, (RR, EXP),     adrl),
+ tCE(nop,      1a00000, nop,      1, (oI255c),      nop,  t_nop),
 
   /* Thumb-compatibility pseudo ops.  */
  tCE(lsl,      1a00000, lsl,      3, (RR, oRR, SH), shift, t_shift),
@@ -8143,7 +8313,7 @@ static const struct asm_opcode insns[] =
  tCE(lsr,      1a00020, lsr,      3, (RR, oRR, SH), shift, t_shift),
  tC3(lsrs,     1b00020, lsrs,     3, (RR, oRR, SH), shift, t_shift),
  tCE(asr,      1a00040, asr,      3, (RR, oRR, SH), shift, t_shift),
- tC3(asrs,     1b00040, asrs,     3, (RR, oRR, SH), shift, t_shift),
+ tC3(asrs,      1b00040, asrs,     3, (RR, oRR, SH), shift, t_shift),
  tCE(ror,      1a00060, ror,      3, (RR, oRR, SH), shift, t_shift),
  tC3(rors,     1b00060, rors,     3, (RR, oRR, SH), shift, t_shift),
  tCE(neg,      2600000, neg,      2, (RR, RR),      rd_rn, t_neg),
@@ -8153,7 +8323,7 @@ static const struct asm_opcode insns[] =
 
 #undef THUMB_VARIANT
 #define THUMB_VARIANT ARM_EXT_V6
- TCE(cpy,       1a00000, 4600,     2, (RR, RR),          rd_rm, t_cpy),
+ TCE(cpy,       1a00000, 4600,     2, (RR, RR),      rd_rm, t_cpy),
 
  /* V1 instructions with no Thumb analogue prior to V6T2.  */
 #undef THUMB_VARIANT
@@ -8169,11 +8339,11 @@ static const struct asm_opcode insns[] =
  TC3(strt,     4200000, f8400e00, 2, (RR, ADDR),    ldstt, t_ldstt),
  TC3(strbt,    4600000, f8200e00, 2, (RR, ADDR),    ldstt, t_ldstt),
 
- TC3(stmdb,    9000000, e9100000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
- TC3(stmfd,    9000000, e9100000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
+ TC3(stmdb,    9000000, e9000000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
+ TC3(stmfd,     9000000, e9000000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
 
- TC3(ldmdb,    9100000, e9000000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
- TC3(ldmea,    9100000, e9000000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
+ TC3(ldmdb,    9100000, e9100000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
+ TC3(ldmea,    9100000, e9100000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
 
  /* V1 instructions with no Thumb analogue at all.  */
   CE(rsc,      0e00000,           3, (RR, oRR, SH), arit),
@@ -8475,6 +8645,15 @@ static const struct asm_opcode insns[] =
  TUE(ittee,     0, bf09, 1, (COND),    it, t_it),
  TUE(iteee,     0, bf01, 1, (COND),    it, t_it),
 
+ /* Thumb2 only instructions.  */
+#undef ARM_VARIANT
+#define ARM_VARIANT 0
+
+ TCE(addw,     0, f2000000, 3, (RR, RR, EXPi), 0, t_add_sub_w),
+ TCE(subw,     0, f2a00000, 3, (RR, RR, EXPi), 0, t_add_sub_w),
+ TCE(tbb,       0, e8d0f000, 1, (TB), 0, t_tb),
+ TCE(tbh,       0, e8d0f010, 1, (TB), 0, t_tb),
+
 #undef ARM_VARIANT
 #define ARM_VARIANT FPU_FPA_EXT_V1  /* Core FPA instruction set (V1).  */
   CE(wfs,      e200110, 1, (RR),            rd),
@@ -9898,41 +10077,76 @@ tc_arm_frame_initial_instructions (void)
 
 /* MD interface: Symbol and relocation handling.  */
 
-/* The knowledge of the PC's pipeline offset is built into the insns
-   themselves. */
+/* Return the address within the segment that a PC-relative fixup is
+   relative to.  For ARM, PC-relative fixups applied to instructions
+   are generally relative to the location of the fixup plus 8 bytes.
+   Thumb branches are offset by 4, and Thumb loads relative to PC
+   require special handling.  */
 
 long
-md_pcrel_from (fixS * fixP)
+md_pcrel_from_section (fixS * fixP, segT seg)
 {
-  if (fixP->fx_addsy
-      && S_GET_SEGMENT (fixP->fx_addsy) == undefined_section
-      && fixP->fx_subsy == NULL)
-    return 0;
+  offsetT base = fixP->fx_where + fixP->fx_frag->fr_address;
+
+  /* If this is pc-relative and we are going to emit a relocation
+     then we just want to put out any pipeline compensation that the linker
+     will need.  Otherwise we want to use the calculated base.  */
+  if (fixP->fx_pcrel 
+      && ((fixP->fx_addsy && S_GET_SEGMENT (fixP->fx_addsy) != seg)
+         || arm_force_relocation (fixP)))
+    base = 0;
 
-  /* PC relative addressing on the Thumb is slightly odd as the bottom
-     two bits of the PC are forced to zero for the calculation.  This
-     happens *after* application of the pipeline offset.  However,
-     Thumb adrl already adjusts for this, so we need not do it again.  */
   switch (fixP->fx_r_type)
     {
+      /* PC relative addressing on the Thumb is slightly odd as the
+        bottom two bits of the PC are forced to zero for the
+        calculation.  This happens *after* application of the
+        pipeline offset.  However, Thumb adrl already adjusts for
+        this, so we need not do it again.  */
     case BFD_RELOC_ARM_THUMB_ADD:
-      return (fixP->fx_where + fixP->fx_frag->fr_address) & ~3;
+      return base & ~3;
 
     case BFD_RELOC_ARM_THUMB_OFFSET:
     case BFD_RELOC_ARM_T32_OFFSET_IMM:
-      return (fixP->fx_where + fixP->fx_frag->fr_address + 4) & ~3;
+    case BFD_RELOC_ARM_T32_ADD_PC12:
+      return (base + 4) & ~3;
 
-    default:
-      break;
-    }
+      /* Thumb branches are simply offset by +4.  */
+    case BFD_RELOC_THUMB_PCREL_BRANCH7:
+    case BFD_RELOC_THUMB_PCREL_BRANCH9:
+    case BFD_RELOC_THUMB_PCREL_BRANCH12:
+    case BFD_RELOC_THUMB_PCREL_BRANCH20:
+    case BFD_RELOC_THUMB_PCREL_BRANCH23:
+    case BFD_RELOC_THUMB_PCREL_BRANCH25:
+    case BFD_RELOC_THUMB_PCREL_BLX:
+      return base + 4;
 
+      /* ARM mode branches are offset by +8.  However, the Windows CE
+        loader expects the relocation not to take this into account.  */
+    case BFD_RELOC_ARM_PCREL_BRANCH:
+    case BFD_RELOC_ARM_PCREL_BLX:
+    case BFD_RELOC_ARM_PLT32:
 #ifdef TE_WINCE
-  /* The pattern was adjusted to accommodate CE's off-by-one fixups,
-     so we un-adjust here to compensate for the accommodation. */
-  return fixP->fx_where + fixP->fx_frag->fr_address + 8;
+      return base;
 #else
-  return fixP->fx_where + fixP->fx_frag->fr_address;
+      return base + 8;
 #endif
+
+      /* ARM mode loads relative to PC are also offset by +8.  Unlike
+        branches, the Windows CE loader *does* expect the relocation
+        to take this into account.  */
+    case BFD_RELOC_ARM_OFFSET_IMM:
+    case BFD_RELOC_ARM_OFFSET_IMM8:
+    case BFD_RELOC_ARM_HWLITERAL:
+    case BFD_RELOC_ARM_LITERAL:
+    case BFD_RELOC_ARM_CP_OFF_IMM:
+      return base + 8;
+
+
+      /* Other PC-relative relocations are un-offset.  */
+    default:
+      return base;
+    }
 }
 
 /* Under ELF we need to default _GLOBAL_OFFSET_TABLE.
@@ -10115,17 +10329,6 @@ md_apply_fix (fixS *   fixP,
   if (fixP->fx_addsy == 0 && !fixP->fx_pcrel)
     fixP->fx_done = 1;
 
-  /* If this symbol is in a different section then we need to leave it for
-     the linker to deal with.  Unfortunately, md_pcrel_from can't tell,
-     so we have to undo its effects here.  */
-  if (fixP->fx_pcrel)
-    {
-      if (fixP->fx_addsy != NULL
-         && S_IS_DEFINED (fixP->fx_addsy)
-         && S_GET_SEGMENT (fixP->fx_addsy) != seg)
-       value += md_pcrel_from (fixP);
-    }
-
   /* On a 64-bit host, silently truncate 'value' to 32 bits for
      consistency with the behavior on 32-bit hosts.  Remember value
      for emit_reloc.  */
@@ -10286,7 +10489,6 @@ md_apply_fix (fixS *    fixP,
       value /= 4;
 
       newval = md_chars_to_number (buf+2, THUMB_SIZE);
-      newval &= 0xff00;
       newval |= value;
       md_number_to_chars (buf+2, newval, THUMB_SIZE);
       break;
@@ -10428,6 +10630,8 @@ md_apply_fix (fixS *    fixP,
       break;
 
     case BFD_RELOC_ARM_T32_IMMEDIATE:
+    case BFD_RELOC_ARM_T32_IMM12:
+    case BFD_RELOC_ARM_T32_ADD_PC12:
       /* We claim that this fixup has been processed here,
         even if in fact we generate an error because we do
         not have a reloc for it, so tc_gen_reloc will reject it.  */
@@ -10446,9 +10650,23 @@ md_apply_fix (fixS *   fixP,
       newval <<= 16;
       newval |= md_chars_to_number (buf+2, THUMB_SIZE);
 
-      newimm = encode_thumb32_immediate (value);
-
       /* FUTURE: Implement analogue of negate_data_op for T32.  */
+      if (fixP->fx_r_type == BFD_RELOC_ARM_T32_IMMEDIATE)
+       newimm = encode_thumb32_immediate (value);
+      else
+       {
+         /* 12 bit immediate for addw/subw.  */
+         if (value < 0)
+           {
+             value = -value;
+             newval ^= 0x00a00000;
+           }
+         if (value > 0xfff)
+           newimm = (unsigned int) FAIL;
+         else
+           newimm = value;
+       }
+
       if (newimm == (unsigned int)FAIL)
        {
          as_bad_where (fixP->fx_file, fixP->fx_line,
@@ -10457,7 +10675,6 @@ md_apply_fix (fixS *    fixP,
          break;
        }
 
-      newval &= 0xfbff8f00;
       newval |= (newimm & 0x800) << 15;
       newval |= (newimm & 0x700) << 4;
       newval |= (newimm & 0x0ff);
@@ -10470,7 +10687,7 @@ md_apply_fix (fixS *    fixP,
       if (((unsigned long) value) > 0xffff)
        as_bad_where (fixP->fx_file, fixP->fx_line,
                      _("invalid smi expression"));
-      newval = md_chars_to_number (buf, INSN_SIZE) & 0xfff000f0;
+      newval = md_chars_to_number (buf, INSN_SIZE);
       newval |= (value & 0xf) | ((value & 0xfff0) << 4);
       md_number_to_chars (buf, newval, INSN_SIZE);
       break;
@@ -10481,7 +10698,7 @@ md_apply_fix (fixS *    fixP,
          if (((unsigned long) value) > 0xff)
            as_bad_where (fixP->fx_file, fixP->fx_line,
                          _("invalid swi expression"));
-         newval = md_chars_to_number (buf, THUMB_SIZE) & 0xff00;
+         newval = md_chars_to_number (buf, THUMB_SIZE);
          newval |= value;
          md_number_to_chars (buf, newval, THUMB_SIZE);
        }
@@ -10490,7 +10707,7 @@ md_apply_fix (fixS *    fixP,
          if (((unsigned long) value) > 0x00ffffff)
            as_bad_where (fixP->fx_file, fixP->fx_line,
                          _("invalid swi expression"));
-         newval = md_chars_to_number (buf, INSN_SIZE) & 0xff000000;
+         newval = md_chars_to_number (buf, INSN_SIZE);
          newval |= value;
          md_number_to_chars (buf, newval, INSN_SIZE);
        }
@@ -10505,358 +10722,180 @@ md_apply_fix (fixS *        fixP,
       break;
 
     case BFD_RELOC_ARM_PCREL_BRANCH:
-      newval = md_chars_to_number (buf, INSN_SIZE);
-
-      /* Sign-extend a 24-bit number.  */
-#define SEXT24(x)      ((((x) & 0xffffff) ^ (~ 0x7fffff)) + 0x800000)
-
 #ifdef OBJ_ELF
-      if (!fixP->fx_done)
-       value = fixP->fx_offset;
+    case BFD_RELOC_ARM_PLT32:
 #endif
 
       /* We are going to store value (shifted right by two) in the
-        instruction, in a 24 bit, signed field  Thus we need to check
-        that none of the top 8 bits of the shifted value (top 7 bits of
-        the unshifted, unsigned value) are set, or that they are all set.  */
-      if ((value & ~ ((offsetT) 0x1ffffff)) != 0
-         && ((value & ~ ((offsetT) 0x1ffffff)) != ~ ((offsetT) 0x1ffffff)))
-       {
-#ifdef OBJ_ELF
-         /* Normally we would be stuck at this point, since we cannot store
-            the absolute address that is the destination of the branch in the
-            24 bits of the branch instruction.  If however, we happen to know
-            that the destination of the branch is in the same section as the
-            branch instruction itself, then we can compute the relocation for
-            ourselves and not have to bother the linker with it.
-
-            FIXME: The test for OBJ_ELF is only here because I have not
-            worked out how to do this for OBJ_COFF.  */
-         if (fixP->fx_addsy != NULL
-             && S_IS_DEFINED (fixP->fx_addsy)
-             && S_GET_SEGMENT (fixP->fx_addsy) == seg)
-           {
-             /* Get pc relative value to go into the branch.  */
-             value = * valP;
-
-             /* Permit a backward branch provided that enough bits
-                are set.  Allow a forwards branch, provided that
-                enough bits are clear.  */
-             if (   (value & ~ ((offsetT) 0x1ffffff)) == ~ ((offsetT) 0x1ffffff)
-                 || (value & ~ ((offsetT) 0x1ffffff)) == 0)
-               fixP->fx_done = 1;
-           }
-
-         if (! fixP->fx_done)
-#endif
-           as_bad_where (fixP->fx_file, fixP->fx_line,
-                         _("GAS can't handle same-section branch dest >= 0x04000000"));
-       }
-
-      value >>= 2;
-      value += SEXT24 (newval);
-
-      if (    (value & ~ ((offsetT) 0xffffff)) != 0
-         && ((value & ~ ((offsetT) 0xffffff)) != ~ ((offsetT) 0xffffff)))
+        instruction, in a 24 bit, signed field.  Bits 0 and 1 must be
+        clear, and bits 26 through 32 either all clear or all set. */
+      if (value & 0x00000003)
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     _("misaligned branch destination"));
+      if ((value & (offsetT)0xfe000000) != (offsetT)0
+         && (value & (offsetT)0xfe000000) != (offsetT)0xfe000000)
        as_bad_where (fixP->fx_file, fixP->fx_line,
-                     _("out of range branch"));
+                     _("branch out of range"));
 
-      if (seg->use_rela_p && !fixP->fx_done)
+      if (fixP->fx_done || !seg->use_rela_p)
        {
-         /* Must unshift the value before storing it in the addend.  */
-         value <<= 2;
-#ifdef OBJ_ELF
-         fixP->fx_offset = value;
-#endif
-         fixP->fx_addnumber = value;
-         newval = newval & 0xff000000;
+         newval = md_chars_to_number (buf, INSN_SIZE);
+         newval |= (value >> 2) & 0x00ffffff;
+         md_number_to_chars (buf, newval, INSN_SIZE);
        }
-      else
-         newval = (value & 0x00ffffff) | (newval & 0xff000000);
-      md_number_to_chars (buf, newval, INSN_SIZE);
       break;
 
     case BFD_RELOC_ARM_PCREL_BLX:
-      {
-       offsetT hbit;
-       newval = md_chars_to_number (buf, INSN_SIZE);
+      /* BLX allows bit 1 to be set in the branch destination, since
+        it targets a Thumb instruction which is only required to be
+        aligned modulo 2.  Other constraints are as for B/BL.  */
+      if (value & 0x00000001)
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     _("misaligned BLX destination"));
+      if ((value & (offsetT)0xfe000000) != (offsetT)0
+         && (value & (offsetT)0xfe000000) != (offsetT)0xfe000000)
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     _("branch out of range"));
 
-#ifdef OBJ_ELF
-       if (!fixP->fx_done)
-         value = fixP->fx_offset;
-#endif
-       hbit   = (value >> 1) & 1;
-       value  = (value >> 2) & 0x00ffffff;
-       value  = (value + (newval & 0x00ffffff)) & 0x00ffffff;
+      if (fixP->fx_done || !seg->use_rela_p)
+       {
+         offsetT hbit;
+         hbit   = (value >> 1) & 1;
+         value  = (value >> 2) & 0x00ffffff;
 
-       if (seg->use_rela_p && !fixP->fx_done)
-         {
-           /* Must sign-extend and unshift the value before storing
-              it in the addend.  */
-           value = SEXT24 (value);
-           value = (value << 2) | hbit;
-#ifdef OBJ_ELF
-           fixP->fx_offset = value;
-#endif
-           fixP->fx_addnumber = value;
-           newval = newval & 0xfe000000;
-         }
-       else
-         newval = value | (newval & 0xfe000000) | (hbit << 24);
-       md_number_to_chars (buf, newval, INSN_SIZE);
-      }
+         newval = md_chars_to_number (buf, INSN_SIZE);
+         newval |= value | hbit << 24;
+         md_number_to_chars (buf, newval, INSN_SIZE);
+       }
       break;
 
     case BFD_RELOC_THUMB_PCREL_BRANCH7: /* CZB */
-      newval = md_chars_to_number (buf, THUMB_SIZE);
-      {
-       addressT diff = ((newval & 0x00f8) >> 2) | (newval & 0x0200) >> 3;
-       /* This one does not have the offset encoded in the pattern.  */
-       value = value + diff - 4;
-       /* CZB can only branch forward.  */
-       if (value & ~0x7e)
-         as_bad_where (fixP->fx_file, fixP->fx_line,
-                       _("branch out of range"));
+      /* CZB can only branch forward.  */
+      if (value & ~0x7e)
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     _("branch out of range"));
 
-       newval &= 0xfd07;
-       if (seg->use_rela_p && !fixP->fx_done)
-         {
-#ifdef OBJ_ELF
-           fixP->fx_offset = value;
-#endif
-           fixP->fx_addnumber = value;
-         }
-       else
+      if (fixP->fx_done || !seg->use_rela_p)
+       {
+         newval = md_chars_to_number (buf, THUMB_SIZE);
          newval |= ((value & 0x2e) << 2) | ((value & 0x40) << 3);
-      }
-      md_number_to_chars (buf, newval, THUMB_SIZE);
+         md_number_to_chars (buf, newval, THUMB_SIZE);
+       }
       break;
 
     case BFD_RELOC_THUMB_PCREL_BRANCH9: /* Conditional branch. */
-      newval = md_chars_to_number (buf, THUMB_SIZE);
-      {
-       addressT diff = (newval & 0xff) << 1;
-       if (diff & 0x100)
-         diff |= ~0xff;
+      if ((value & ~0xff) && ((value & ~0xff) != ~0xff))
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     _("branch out of range"));
 
-       value += diff;
-       if ((value & ~0xff) && ((value & ~0xff) != ~0xff))
-         as_bad_where (fixP->fx_file, fixP->fx_line,
-                       _("branch out of range"));
-       if (seg->use_rela_p && !fixP->fx_done)
-         {
-#ifdef OBJ_ELF
-           fixP->fx_offset = value;
-#endif
-           fixP->fx_addnumber = value;
-           newval = newval & 0xff00;
-         }
-       else
-         newval = (newval & 0xff00) | ((value & 0x1ff) >> 1);
-      }
-      md_number_to_chars (buf, newval, THUMB_SIZE);
+      if (fixP->fx_done || !seg->use_rela_p)
+       {
+         newval = md_chars_to_number (buf, THUMB_SIZE);
+         newval |= (value & 0x1ff) >> 1;
+         md_number_to_chars (buf, newval, THUMB_SIZE);
+       }
       break;
 
     case BFD_RELOC_THUMB_PCREL_BRANCH12: /* Unconditional branch.  */
-      newval = md_chars_to_number (buf, THUMB_SIZE);
-      {
-       addressT diff = (newval & 0x7ff) << 1;
-       if (diff & 0x800)
-         diff |= ~0x7ff;
+      if ((value & ~0x7ff) && ((value & ~0x7ff) != ~0x7ff))
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     _("branch out of range"));
 
-       value += diff;
-       if ((value & ~0x7ff) && ((value & ~0x7ff) != ~0x7ff))
-         as_bad_where (fixP->fx_file, fixP->fx_line,
-                       _("branch out of range"));
-       if (seg->use_rela_p && !fixP->fx_done)
-         {
-#ifdef OBJ_ELF
-           fixP->fx_offset = value;
-#endif
-           fixP->fx_addnumber = value;
-           newval = newval & 0xf800;
-         }
-       else
-         newval = (newval & 0xf800) | ((value & 0xfff) >> 1);
-      }
-      md_number_to_chars (buf, newval, THUMB_SIZE);
+      if (fixP->fx_done || !seg->use_rela_p)
+       {
+         newval = md_chars_to_number (buf, THUMB_SIZE);
+         newval |= (value & 0xfff) >> 1;
+         md_number_to_chars (buf, newval, THUMB_SIZE);
+       }
       break;
 
     case BFD_RELOC_THUMB_PCREL_BRANCH20:
-      {
-       offsetT newval2;
-       addressT diff, S, J1, J2, lo, hi;
-
-       newval  = md_chars_to_number (buf, THUMB_SIZE);
-       newval2 = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
-
-       S  = !(newval & 0x0400);  /* flipped - 0=negative */
-       hi = (newval  & 0x003f);
-       J1 = (newval2 & 0x2000) >> 13;
-       J2 = (newval2 & 0x0800) >> 11;
-       lo = (newval2 & 0x07ff);
-
-       diff = ((S << 20) | (J2 << 19) | (J1 << 18) | (hi << 12) | (lo << 1));
-       diff -= (1 << 20);  /* sign extend */
-       value += diff;
+      if ((value & ~0x1fffff) && ((value & ~0x1fffff) != ~0x1fffff))
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     _("conditional branch out of range"));
 
-       if ((value & ~0x1fffff) && ((value & ~0x1fffff) != ~0x1fffff))
-         as_bad_where (fixP->fx_file, fixP->fx_line,
-                       _("conditional branch out of range"));
+      if (fixP->fx_done || !seg->use_rela_p)
+       {
+         offsetT newval2;
+         addressT S, J1, J2, lo, hi;
 
-       newval  = newval  & 0xfbc0;
-       newval2 = newval2 & 0xd000;
-       if (seg->use_rela_p && !fixP->fx_done)
-         {
-#ifdef OBJ_ELF
-           fixP->fx_offset = value;
-#endif
-           fixP->fx_addnumber = value;
-         }
-       else
-         {
-           S  = (value & 0x00100000) >> 20;
-           J2 = (value & 0x00080000) >> 19;
-           J1 = (value & 0x00040000) >> 18;
-           hi = (value & 0x0003f000) >> 12;
-           lo = (value & 0x00000ffe) >> 1;
-
-           newval  = newval  | (S << 10) | hi;
-           newval2 = newval2 | (J1 << 13) | (J2 << 11) | lo;
-         }
+         S  = (value & 0x00100000) >> 20;
+         J2 = (value & 0x00080000) >> 19;
+         J1 = (value & 0x00040000) >> 18;
+         hi = (value & 0x0003f000) >> 12;
+         lo = (value & 0x00000ffe) >> 1;
 
-       md_number_to_chars (buf, newval, THUMB_SIZE);
-       md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
-      }
+         newval   = md_chars_to_number (buf, THUMB_SIZE);
+         newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
+         newval  |= (S << 10) | hi;
+         newval2 |= (J1 << 13) | (J2 << 11) | lo;
+         md_number_to_chars (buf, newval, THUMB_SIZE);
+         md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
+       }
       break;
 
     case BFD_RELOC_THUMB_PCREL_BLX:
     case BFD_RELOC_THUMB_PCREL_BRANCH23:
-      {
-       offsetT newval2;
-       addressT diff;
-
-       newval  = md_chars_to_number (buf, THUMB_SIZE);
-       newval2 = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
-       diff = ((newval & 0x7ff) << 12) | ((newval2 & 0x7ff) << 1);
-       if (diff & 0x400000)
-         diff |= ~0x3fffff;
-#ifdef OBJ_ELF
-       if (!fixP->fx_done)
-         value = fixP->fx_offset;
-#endif
-       value += diff;
-
-       if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff))
-         as_bad_where (fixP->fx_file, fixP->fx_line,
-                       _("branch with link out of range"));
+      if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff))
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     _("branch out of range"));
 
-       if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
-         /* For a BLX instruction, make sure that the relocation is rounded up
-            to a word boundary.  This follows the semantics of the instruction
-            which specifies that bit 1 of the target address will come from bit
-            1 of the base address.  */
-         value = (value + 1) & ~ 1;
+      if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
+       /* For a BLX instruction, make sure that the relocation is rounded up
+          to a word boundary.  This follows the semantics of the instruction
+          which specifies that bit 1 of the target address will come from bit
+          1 of the base address.  */
+       value = (value + 1) & ~ 1;
 
-       if (seg->use_rela_p && !fixP->fx_done)
-         {
-#ifdef OBJ_ELF
-           fixP->fx_offset = value;
-#endif
-           fixP->fx_addnumber = value;
-           newval = newval & 0xf800;
-           newval2 = newval2 & 0xf800;
-         }
-       else
-         {
-           newval  = (newval  & 0xf800) | ((value & 0x7fffff) >> 12);
-           newval2 = (newval2 & 0xf800) | ((value & 0xfff) >> 1);
-         }
-       md_number_to_chars (buf, newval, THUMB_SIZE);
-       md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
-      }
-      break;
-
-    case BFD_RELOC_8:
-      if (seg->use_rela_p && !fixP->fx_done)
-       break;
-      if (fixP->fx_done || fixP->fx_pcrel)
-       md_number_to_chars (buf, value, 1);
-#ifdef OBJ_ELF
-      else
+      if (fixP->fx_done || !seg->use_rela_p)
        {
-         value = fixP->fx_offset;
-         md_number_to_chars (buf, value, 1);
+         offsetT newval2;
+
+         newval   = md_chars_to_number (buf, THUMB_SIZE);
+         newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
+         newval  |= (value & 0x7fffff) >> 12;
+         newval2 |= (value & 0xfff) >> 1;
+         md_number_to_chars (buf, newval, THUMB_SIZE);
+         md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
        }
-#endif
       break;
 
     case BFD_RELOC_THUMB_PCREL_BRANCH25:
-      {
-       offsetT newval2;
-       addressT diff, S, I1, I2, lo, hi;
-
-       newval  = md_chars_to_number (buf, THUMB_SIZE);
-       newval2 = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
-
-       S  = (newval  & 0x0400) >> 10;
-       hi = (newval  & 0x03ff);
-       I1 = (newval2 & 0x2000) >> 13;
-       I2 = (newval2 & 0x0800) >> 11;
-       lo = (newval2 & 0x07ff);
+      if ((value & ~0x1ffffff) && ((value & ~0x1ffffff) != ~0x1ffffff))
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     _("branch out of range"));
 
-       I1 = !(I1 ^ S);
-       I2 = !(I2 ^ S);
-       S  = !S;
+      if (fixP->fx_done || !seg->use_rela_p)
+       {
+         offsetT newval2;
+         addressT S, I1, I2, lo, hi;
 
-       diff = ((S << 24) | (I1 << 23) | (I2 << 22) | (hi << 12) | (lo << 1));
-       diff -= (1 << 24);  /* sign extend */
-       value += diff;
+         S  = (value & 0x01000000) >> 24;
+         I1 = (value & 0x00800000) >> 23;
+         I2 = (value & 0x00400000) >> 22;
+         hi = (value & 0x003ff000) >> 12;
+         lo = (value & 0x00000ffe) >> 1;
 
-       if ((value & ~0x1ffffff) && ((value & ~0x1ffffff) != ~0x1ffffff))
-         as_bad_where (fixP->fx_file, fixP->fx_line,
-                       _("branch out of range"));
+         I1 = !(I1 ^ S);
+         I2 = !(I2 ^ S);
 
-       newval  = newval  & 0xf800;
-       newval2 = newval2 & 0xd000;
-       if (seg->use_rela_p && !fixP->fx_done)
-         {
-#ifdef OBJ_ELF
-           fixP->fx_offset = value;
-#endif
-           fixP->fx_addnumber = value;
-         }
-       else
-         {
-           S  = (value & 0x01000000) >> 24;
-           I1 = (value & 0x00800000) >> 23;
-           I2 = (value & 0x00400000) >> 22;
-           hi = (value & 0x003ff000) >> 12;
-           lo = (value & 0x00000ffe) >> 1;
-
-           I1 = !(I1 ^ S);
-           I2 = !(I2 ^ S);
+         newval   = md_chars_to_number (buf, THUMB_SIZE);
+         newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
+         newval  |= (S << 10) | hi;
+         newval2 |= (I1 << 13) | (I2 << 11) | lo;
+         md_number_to_chars (buf, newval, THUMB_SIZE);
+         md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
+       }
+      break;
 
-           newval  = newval  | (S << 10) | hi;
-           newval2 = newval2 | (I1 << 13) | (I2 << 11) | lo;
-         }
-       md_number_to_chars (buf, newval, THUMB_SIZE);
-       md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
-      }
+    case BFD_RELOC_8:
+      if (fixP->fx_done || !seg->use_rela_p)
+       md_number_to_chars (buf, value, 1);
       break;
 
     case BFD_RELOC_16:
-      if (seg->use_rela_p && !fixP->fx_done)
-       break;
-      if (fixP->fx_done || fixP->fx_pcrel)
+      if (fixP->fx_done || !seg->use_rela_p)
        md_number_to_chars (buf, value, 2);
-#ifdef OBJ_ELF
-      else
-       {
-         value = fixP->fx_offset;
-         md_number_to_chars (buf, value, 2);
-       }
-#endif
       break;
 
 #ifdef OBJ_ELF
@@ -10871,9 +10910,8 @@ md_apply_fix (fixS *    fixP,
     case BFD_RELOC_ARM_GOT32:
     case BFD_RELOC_ARM_GOTOFF:
     case BFD_RELOC_ARM_TARGET2:
-      if (seg->use_rela_p && !fixP->fx_done)
-       break;
-      md_number_to_chars (buf, 0, 4);
+      if (fixP->fx_done || !seg->use_rela_p)
+       md_number_to_chars (buf, 0, 4);
       break;
 #endif
 
@@ -10883,22 +10921,13 @@ md_apply_fix (fixS *  fixP,
     case BFD_RELOC_ARM_ROSEGREL32:
     case BFD_RELOC_ARM_SBREL32:
     case BFD_RELOC_32_PCREL:
-      if (seg->use_rela_p && !fixP->fx_done)
-       break;
-      if (fixP->fx_done || fixP->fx_pcrel)
+      if (fixP->fx_done || !seg->use_rela_p)
        md_number_to_chars (buf, value, 4);
-#ifdef OBJ_ELF
-      else
-       {
-         value = fixP->fx_offset;
-         md_number_to_chars (buf, value, 4);
-       }
-#endif
       break;
 
 #ifdef OBJ_ELF
     case BFD_RELOC_ARM_PREL31:
-      if (fixP->fx_done || fixP->fx_pcrel)
+      if (fixP->fx_done || !seg->use_rela_p)
        {
          newval = md_chars_to_number (buf, 4) & 0x80000000;
          if ((value ^ (value >> 1)) & 0x40000000)
@@ -10910,10 +10939,6 @@ md_apply_fix (fixS *   fixP,
          md_number_to_chars (buf, newval, 4);
        }
       break;
-
-    case BFD_RELOC_ARM_PLT32:
-      /* It appears the instruction is fully prepared at this point.  */
-      break;
 #endif
 
     case BFD_RELOC_ARM_CP_OFF_IMM:
@@ -11135,15 +11160,9 @@ tc_gen_reloc (asection * section ATTRIBUTE_UNUSED,
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
-  /* @@ Why fx_addnumber sometimes and fx_offset other times?  */
-#ifndef OBJ_ELF
-  if (fixp->fx_pcrel == 0)
-    reloc->addend = fixp->fx_offset;
-  else
-    reloc->addend = fixp->fx_offset = reloc->address;
-#else  /* OBJ_ELF */
+  if (fixp->fx_pcrel)
+    fixp->fx_offset = reloc->address;
   reloc->addend = fixp->fx_offset;
-#endif
 
   switch (fixp->fx_r_type)
     {
This page took 0.043546 seconds and 4 git commands to generate.