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];
};
#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
/* 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. */
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;
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
{
s_arm_unwind_save_vfp (void)
{
int count;
- int reg;
+ unsigned int reg;
valueT op;
count = parse_vfp_reg_list (&input_line_pointer, ®, 1);
{
/* [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)
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
{
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. */
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;
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);
{
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;
{
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 */
}
}
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 */
}
}
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;
}
/* 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
/* 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
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
/* 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);
}
}
/* 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"));
}
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
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;
{
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;
}
inst.instruction |= 0x00000100;
}
inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_IMM;
- inst.reloc.pc_rel = is_pc;
}
else if (inst.operands[i].postind)
{
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), \
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), \
/* 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. */
{
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);
/* 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);
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
}
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);
}
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)
{
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;
}
{
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;
}
}
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;
}
}
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;
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
{
return;
}
- inst.instruction |= inst.operands[0].imm;
+ inst.instruction |= mask;
}
static 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)
{
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);
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),
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),
#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
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),
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),
/* 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.
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. */
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;
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. */
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,
break;
}
- newval &= 0xfbff8f00;
newval |= (newimm & 0x800) << 15;
newval |= (newimm & 0x700) << 4;
newval |= (newimm & 0x0ff);
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;
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);
}
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);
}
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
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
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)
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:
*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)
{