aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
Diffstat (limited to 'gas')
-rw-r--r--gas/ChangeLog12
-rw-r--r--gas/config/tc-arm.c166
-rw-r--r--gas/doc/c-arm.texi40
3 files changed, 207 insertions, 11 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 35a8dbe..c97bb65 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,5 +1,17 @@
2006-05-11 Paul Brook <paul@codesourcery.com>
+ * config/tc-arm.c (parse_half): New function.
+ (operand_parse_code): Remove OP_Iffff. Add OP_HALF.
+ (parse_operands): Ditto.
+ (do_mov16): Reject invalid relocations.
+ (do_t_mov16): Ditto. Use Thumb reloc numbers.
+ (insns): Replace Iffff with HALF.
+ (md_apply_fix): Add MOVW and MOVT relocs.
+ (tc_gen_reloc): Ditto.
+ * doc/c-arm.texi: Document relocation operators
+
+2006-05-11 Paul Brook <paul@codesourcery.com>
+
* config/tc-arm.c (arm_fix_adjustable): Return 0 for function symbols.
2006-05-11 Thiemo Seufer <ths@mips.com>
diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index 50940dc..8d19407 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -4435,6 +4435,46 @@ parse_address (char **str, int i)
return SUCCESS;
}
+/* Parse an operand for a MOVW or MOVT instruction. */
+static int
+parse_half (char **str)
+{
+ char * p;
+
+ p = *str;
+ skip_past_char (&p, '#');
+ if (strncasecmp (p, ":lower16:", 9) == 0)
+ inst.reloc.type = BFD_RELOC_ARM_MOVW;
+ else if (strncasecmp (p, ":upper16:", 9) == 0)
+ inst.reloc.type = BFD_RELOC_ARM_MOVT;
+
+ if (inst.reloc.type != BFD_RELOC_UNUSED)
+ {
+ p += 9;
+ skip_whitespace(p);
+ }
+
+ if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX))
+ return FAIL;
+
+ if (inst.reloc.type == BFD_RELOC_UNUSED)
+ {
+ if (inst.reloc.exp.X_op != O_constant)
+ {
+ inst.error = _("constant expression expected");
+ return FAIL;
+ }
+ if (inst.reloc.exp.X_add_number < 0
+ || inst.reloc.exp.X_add_number > 0xffff)
+ {
+ inst.error = _("immediate value out of range");
+ return FAIL;
+ }
+ }
+ *str = p;
+ return SUCCESS;
+}
+
/* Miscellaneous. */
/* Parse a PSR flag operand. The value returned is FAIL on syntax error,
@@ -4925,7 +4965,6 @@ enum operand_parse_code
OP_I64, /* 1 .. 64 */
OP_I64z, /* 0 .. 64 */
OP_I255, /* 0 .. 255 */
- OP_Iffff, /* 0 .. 65535 */
OP_I4b, /* immediate, prefix optional, 1 .. 4 */
OP_I7b, /* 0 .. 7 */
@@ -4937,6 +4976,7 @@ enum operand_parse_code
OP_EXP, /* arbitrary expression */
OP_EXPi, /* same, with optional immediate prefix */
OP_EXPr, /* same, with optional relocation suffix */
+ OP_HALF, /* 0 .. 65535 or low/high reloc. */
OP_CPSF, /* CPS flags */
OP_ENDI, /* Endianness specifier */
@@ -5197,7 +5237,6 @@ parse_operands (char *str, const unsigned char *pattern)
case OP_I64: po_imm_or_fail ( 1, 64, FALSE); break;
case OP_I64z: po_imm_or_fail ( 0, 64, FALSE); break;
case OP_I255: po_imm_or_fail ( 0, 255, FALSE); break;
- case OP_Iffff: po_imm_or_fail ( 0, 0xffff, FALSE); break;
case OP_I4b: po_imm_or_fail ( 1, 4, TRUE); break;
case OP_oI7b:
@@ -5263,6 +5302,11 @@ parse_operands (char *str, const unsigned char *pattern)
}
break;
+ /* Operand for MOVW or MOVT. */
+ case OP_HALF:
+ po_misc_or_fail (parse_half (&str));
+ break;
+
/* Register or expression */
case OP_RR_EXr: po_reg_or_goto (REG_TYPE_RN, EXPr); break;
case OP_RR_EXi: po_reg_or_goto (REG_TYPE_RN, EXPi); break;
@@ -6438,10 +6482,22 @@ do_mov (void)
static void
do_mov16 (void)
{
+ bfd_vma imm;
+ bfd_boolean top;
+
+ top = (inst.instruction & 0x00400000) != 0;
+ constraint (top && inst.reloc.type == BFD_RELOC_ARM_MOVW,
+ _(":lower16: not allowed this instruction"));
+ constraint (!top && inst.reloc.type == BFD_RELOC_ARM_MOVT,
+ _(":upper16: not allowed instruction"));
inst.instruction |= inst.operands[0].reg << 12;
- /* The value is in two pieces: 0:11, 16:19. */
- inst.instruction |= (inst.operands[1].imm & 0x00000fff);
- inst.instruction |= (inst.operands[1].imm & 0x0000f000) << 4;
+ if (inst.reloc.type == BFD_RELOC_UNUSED)
+ {
+ imm = inst.reloc.exp.X_add_number;
+ /* The value is in two pieces: 0:11, 16:19. */
+ inst.instruction |= (imm & 0x00000fff);
+ inst.instruction |= (imm & 0x0000f000) << 4;
+ }
}
static void
@@ -8709,11 +8765,30 @@ do_t_mov_cmp (void)
static void
do_t_mov16 (void)
{
+ bfd_vma imm;
+ bfd_boolean top;
+
+ top = (inst.instruction & 0x00800000) != 0;
+ if (inst.reloc.type == BFD_RELOC_ARM_MOVW)
+ {
+ constraint (top, _(":lower16: not allowed this instruction"));
+ inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVW;
+ }
+ else if (inst.reloc.type == BFD_RELOC_ARM_MOVT)
+ {
+ constraint (!top, _(":upper16: not allowed this instruction"));
+ inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVT;
+ }
+
inst.instruction |= inst.operands[0].reg << 8;
- inst.instruction |= (inst.operands[1].imm & 0xf000) << 4;
- inst.instruction |= (inst.operands[1].imm & 0x0800) << 15;
- inst.instruction |= (inst.operands[1].imm & 0x0700) << 4;
- inst.instruction |= (inst.operands[1].imm & 0x00ff);
+ if (inst.reloc.type == BFD_RELOC_UNUSED)
+ {
+ imm = inst.reloc.exp.X_add_number;
+ inst.instruction |= (imm & 0xf000) << 4;
+ inst.instruction |= (imm & 0x0800) << 15;
+ inst.instruction |= (imm & 0x0700) << 4;
+ inst.instruction |= (imm & 0x00ff);
+ }
}
static void
@@ -13425,8 +13500,8 @@ static const struct asm_opcode insns[] =
TCE(ubfx, 7e00050, f3c00000, 4, (RR, RR, I31, I32), bfx, t_bfx),
TCE(mls, 0600090, fb000010, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mlas, t_mla),
- TCE(movw, 3000000, f2400000, 2, (RRnpc, Iffff), mov16, t_mov16),
- TCE(movt, 3400000, f2c00000, 2, (RRnpc, Iffff), mov16, t_mov16),
+ TCE(movw, 3000000, f2400000, 2, (RRnpc, HALF), mov16, t_mov16),
+ TCE(movt, 3400000, f2c00000, 2, (RRnpc, HALF), mov16, t_mov16),
TCE(rbit, 3ff0f30, fa90f0a0, 2, (RR, RR), rd_rm, t_rbit),
TC3(ldrht, 03000b0, f8300e00, 2, (RR, ADDR), ldsttv4, t_ldstt),
@@ -16761,6 +16836,47 @@ md_apply_fix (fixS * fixP,
fixP->fx_done = 0;
return;
+ case BFD_RELOC_ARM_MOVW:
+ case BFD_RELOC_ARM_MOVT:
+ case BFD_RELOC_ARM_THUMB_MOVW:
+ case BFD_RELOC_ARM_THUMB_MOVT:
+ if (fixP->fx_done || !seg->use_rela_p)
+ {
+ /* REL format relocations are limited to a 16-bit addend. */
+ if (!fixP->fx_done)
+ {
+ if (value < -0x1000 || value > 0xffff)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("offset too big"));
+ }
+ else if (fixP->fx_r_type == BFD_RELOC_ARM_MOVT
+ || fixP->fx_r_type == BFD_RELOC_ARM_THUMB_MOVT)
+ {
+ value >>= 16;
+ }
+
+ if (fixP->fx_r_type == BFD_RELOC_ARM_THUMB_MOVW
+ || fixP->fx_r_type == BFD_RELOC_ARM_THUMB_MOVT)
+ {
+ newval = get_thumb32_insn (buf);
+ newval &= 0xfbf08f00;
+ newval |= (value & 0xf000) << 4;
+ newval |= (value & 0x0800) << 15;
+ newval |= (value & 0x0700) << 4;
+ newval |= (value & 0x00ff);
+ put_thumb32_insn (buf, newval);
+ }
+ else
+ {
+ newval = md_chars_to_number (buf, 4);
+ newval &= 0xfff0f000;
+ newval |= value & 0x0fff;
+ newval |= (value & 0xf000) << 4;
+ md_number_to_chars (buf, newval, 4);
+ }
+ }
+ return;
+
case BFD_RELOC_UNUSED:
default:
as_bad_where (fixP->fx_file, fixP->fx_line,
@@ -16815,6 +16931,34 @@ tc_gen_reloc (asection *section, fixS *fixp)
break;
}
+ case BFD_RELOC_ARM_MOVW:
+ if (fixp->fx_pcrel)
+ {
+ code = BFD_RELOC_ARM_MOVW_PCREL;
+ break;
+ }
+
+ case BFD_RELOC_ARM_MOVT:
+ if (fixp->fx_pcrel)
+ {
+ code = BFD_RELOC_ARM_MOVT_PCREL;
+ break;
+ }
+
+ case BFD_RELOC_ARM_THUMB_MOVW:
+ if (fixp->fx_pcrel)
+ {
+ code = BFD_RELOC_ARM_THUMB_MOVW_PCREL;
+ break;
+ }
+
+ case BFD_RELOC_ARM_THUMB_MOVT:
+ if (fixp->fx_pcrel)
+ {
+ code = BFD_RELOC_ARM_THUMB_MOVT_PCREL;
+ break;
+ }
+
case BFD_RELOC_NONE:
case BFD_RELOC_ARM_PCREL_BRANCH:
case BFD_RELOC_ARM_PCREL_BLX:
diff --git a/gas/doc/c-arm.texi b/gas/doc/c-arm.texi
index ca0998b..0b113f9 100644
--- a/gas/doc/c-arm.texi
+++ b/gas/doc/c-arm.texi
@@ -284,6 +284,7 @@ as position-independent code (PIC).
@menu
* ARM-Chars:: Special Characters
* ARM-Regs:: Register Names
+* ARM-Relocations:: Relocations
@end menu
@node ARM-Chars
@@ -323,7 +324,46 @@ Either @samp{#} or @samp{$} can be used to indicate immediate operands.
@cindex ARM floating point (@sc{ieee})
The ARM family uses @sc{ieee} floating-point numbers.
+@node ARM-Relocations
+@subsection ARM relocation generation
+@cindex data relocations, ARM
+@cindex ARM data relocations
+Specific data relocations can be generated by putting the relocation name
+in parentheses after the symbol name. For example:
+
+@smallexample
+ .word foo(TARGET1)
+@end smallexample
+
+This will generate an @samp{R_ARM_TARGET1} relocation against the symbol
+@var{foo}.
+The following relocations are supported:
+@code{GOT},
+@code{GOTOFF},
+@code{TARGET1},
+@code{TARGET2},
+@code{SBREL},
+@code{TLSGD},
+@code{TLSLDM},
+@code{TLSLDO},
+@code{GOTTPOFF}
+and
+@code{TPOFF}.
+
+For compatibility with older toolchains the assembler also accepts
+@code{(PLT)} after branch targets. This will generate the deprecated
+@samp{R_ARM_PLT32} relocation.
+
+@cindex MOVW and MOVT relocations, ARM
+Relocations for @samp{MOVW} and @samp{MOVT} instructions can be generated
+by prefixing the value with @samp{#:lower16:} and @samp{#:upper16}
+respectively. For example to load the 32-bit addresss of foo into r0:
+
+@smallexample
+ MOVW r0, #:lower16:foo
+ MOVT r0, #:upper16:foo
+@end smallexample
@node ARM Directives
@section ARM Machine Directives