aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
Diffstat (limited to 'gas')
-rw-r--r--gas/ChangeLog23
-rw-r--r--gas/config/tc-arm.c219
-rw-r--r--gas/doc/c-arm.texi53
3 files changed, 258 insertions, 37 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index e90d867..d7db6e6 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,26 @@
+1999-07-05 Nick Clifton <nickc@cygnus.com>
+
+ * config/tc-arm.c (ARM_EXT_V5): Define.
+ (ARM_ARCH_V5, ARM_ARCH_V5T): Define.
+ (md_begin): Detect ARM v5 architectures.
+ (md_parse_option): Accept arm v5 specification.
+ (md_show_usage): Documment -marmv5 switch.
+
+ * doc/c-arm.texi: Document -marmv5 command line option.
+
+ * config/tc-arm.c (do_adrl): New function. Implement ADRL pseudo
+ op.
+ (validate_immediate_twopart): New function. Determine if a
+ constant can be computed by two ADD instructions.
+ (output_inst): Remove its command line parameter - it was never
+ used.
+ (md_apply_fix3): Support BFD_RELOC_ARM_ADRL_IMMEDIATE, used to
+ implememt the ADRL pseudo op.
+ (tc_gen_reloc): Generate a suitable error message if an ADRL
+ instruction tries to generate a real reloc.
+
+ * doc/c-arm.texi: Document NOP, ADR and ADRL pseudo ops.
+
Thu Jul 1 15:33:10 1999 Jeffrey A Law (law@cygnus.com)
* config/tc-hppa.c (pa_ip): Convert the opcode and all completers
diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index 9900b31..93c6d82 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -51,12 +51,17 @@
#define ARM_LONGMUL 0x00000010 /* allow long multiplies */
#define ARM_HALFWORD 0x00000020 /* allow half word loads */
#define ARM_THUMB 0x00000040 /* allow BX instruction */
+#define ARM_EXT_V5 0x00000080 /* allow CLZ etc */
-#define ARM_ARCHv4 (ARM_7 | ARM_LONGMUL | ARM_HALFWORD)
+/* Architectures are the sum of the base and extensions */
+#define ARM_ARCH_V4 (ARM_7 | ARM_LONGMUL | ARM_HALFWORD)
+#define ARM_ARCH_V4T (ARM_ARCH_V4 | ARM_THUMB)
+#define ARM_ARCH_V5 (ARM_ARCH_V4 | ARM_EXT_V5)
+#define ARM_ARCH_V5T (ARM_ARCH_V5 | ARM_THUMB)
/* Some useful combinations: */
#define ARM_ANY 0x00ffffff
-#define ARM_2UP 0x00fffffe
+#define ARM_2UP (ARM_ANY - ARM_1)
#define ARM_ALL ARM_2UP /* Not arm1 only */
#define ARM_3UP 0x00fffffc
#define ARM_6UP 0x00fffff8 /* Includes ARM7 */
@@ -73,7 +78,7 @@
#ifndef CPU_DEFAULT
#if defined __thumb__
-#define CPU_DEFAULT (ARM_ARCHv4 | ARM_THUMB)
+#define CPU_DEFAULT (ARM_ARCH_V4 | ARM_THUMB)
#else
#define CPU_DEFAULT ARM_ALL
#endif
@@ -419,6 +424,7 @@ static void do_branch PARAMS ((char *operands, unsigned long flags));
static void do_swi PARAMS ((char *operands, unsigned long flags));
/* Pseudo Op codes */
static void do_adr PARAMS ((char *operands, unsigned long flags));
+static void do_adrl PARAMS ((char * operands, unsigned long flags));
static void do_nop PARAMS ((char *operands, unsigned long flags));
/* ARM 2 */
static void do_mul PARAMS ((char *operands, unsigned long flags));
@@ -455,6 +461,7 @@ static void symbol_locate PARAMS ((symbolS *, CONST char *, segT,
valueT, fragS *));
static int add_to_lit_pool PARAMS ((void));
static unsigned validate_immediate PARAMS ((unsigned));
+static unsigned validate_immediate_twopart PARAMS ((unsigned int, unsigned int *));
static int validate_offset_imm PARAMS ((int, int));
static void opcode_select PARAMS ((int));
static void end_of_line PARAMS ((char *));
@@ -484,7 +491,7 @@ static void thumb_mov_compare PARAMS ((char *, int));
static void set_constant_flonums PARAMS ((void));
static valueT md_chars_to_number PARAMS ((char *, int));
static void insert_reg_alias PARAMS ((char *, int));
-static void output_inst PARAMS ((char *));
+static void output_inst PARAMS ((void));
#ifdef OBJ_ELF
static bfd_reloc_code_real_type arm_parse_reloc PARAMS ((void));
#endif
@@ -540,6 +547,7 @@ static CONST struct asm_opcode insns[] =
/* Pseudo ops */
{"adr", 0x028f0000, NULL, NULL, ARM_ANY, do_adr},
+ {"adrl", 0x028f0000, NULL, NULL, ARM_ANY, do_adrl},
{"nop", 0x01a00000, NULL, NULL, ARM_ANY, do_nop},
/* ARM 2 multiplies */
@@ -870,8 +878,8 @@ static CONST struct reg_entry reg_table[] =
{NULL, 0}
};
-#define bad_args _("Bad arguments to instruction");
-#define bad_pc _("r15 not allowed here");
+#define bad_args _("Bad arguments to instruction");
+#define bad_pc _("r15 not allowed here");
static struct hash_control * arm_ops_hsh = NULL;
static struct hash_control * arm_tops_hsh = NULL;
@@ -1079,6 +1087,47 @@ validate_immediate (val)
return FAIL;
}
+/* Check to see if an immediate can be computed as two seperate immediate
+ values, added together. We already know that this value cannot be
+ computed by just one ARM instruction. */
+
+static unsigned int
+validate_immediate_twopart (val, highpart)
+ unsigned int val;
+ unsigned int * highpart;
+{
+ unsigned int a;
+ unsigned int i;
+
+ for (i = 0; i < 32; i += 2)
+ if (((a = rotate_left (val, i)) & 0xff) != 0)
+ {
+ if (a & 0xff00)
+ {
+ if (a & ~ 0xffff)
+ continue;
+ * highpart = (a >> 8) | ((i + 24) << 7);
+ }
+ else if (a & 0xff0000)
+ {
+ if (a & 0xff000000)
+ continue;
+
+ * highpart = (a >> 16) | ((i + 16) << 7);
+ }
+ else
+ {
+ assert (a & 0xff000000);
+
+ * highpart = (a >> 24) | ((i + 8) << 7);
+ }
+
+ return (a & 0xff) | (i << 7);
+ }
+
+ return FAIL;
+}
+
static int
validate_offset_imm (val, hwse)
int val;
@@ -2607,6 +2656,41 @@ do_adr (str, flags)
}
static void
+do_adrl (str, flags)
+ char * str;
+ unsigned long flags;
+{
+ /* This is a pseudo-op of the form "adrl rd, label" to be converted
+ into a relative address of the form:
+ add rd, pc, #low(label-.-8)"
+ add rd, rd, #high(label-.-8)" */
+
+ while (* str == ' ')
+ str ++;
+
+ if (reg_required_here (& str, 12) == FAIL
+ || skip_past_comma (& str) == FAIL
+ || my_get_expression (& inst.reloc.exp, & str))
+ {
+ if (!inst.error)
+ inst.error = bad_args;
+ return;
+ }
+
+ end_of_line (str);
+
+ /* 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;
+ inst.reloc.exp.X_add_number -= 8; /* PC relative adjust */
+ inst.reloc.pc_rel = 1;
+ inst.instruction |= flags;
+ inst.size = INSN_SIZE * 2;
+
+ return;
+}
+
+static void
do_cmp (str, flags)
char * str;
unsigned long flags;
@@ -4984,9 +5068,13 @@ md_begin ()
/* Catch special cases */
if (cpu_variant != (FPU_DEFAULT | CPU_DEFAULT))
{
- if (cpu_variant & ARM_THUMB)
+ if (cpu_variant & (ARM_EXT_V5 & ARM_THUMB))
+ mach = bfd_mach_arm_5T;
+ else if (cpu_variant & ARM_EXT_V5)
+ mach = bfd_mach_arm_5;
+ else if (cpu_variant & ARM_THUMB)
mach = bfd_mach_arm_4T;
- else if ((cpu_variant & ARM_ARCHv4) == ARM_ARCHv4)
+ else if ((cpu_variant & ARM_ARCH_V4) == ARM_ARCH_V4)
mach = bfd_mach_arm_4;
else if (cpu_variant & ARM_LONGMUL)
mach = bfd_mach_arm_3M;
@@ -5326,7 +5414,51 @@ md_apply_fix3 (fixP, val, seg)
md_number_to_chars (buf, (valueT) newimm, INSN_SIZE);
break;
- case BFD_RELOC_ARM_OFFSET_IMM:
+ case BFD_RELOC_ARM_ADRL_IMMEDIATE:
+ {
+ unsigned int highpart = 0;
+ unsigned int newinsn = 0xe1a00000; /* nop */
+ newimm = validate_immediate (value);
+ temp = md_chars_to_number (buf, INSN_SIZE);
+
+ /* If the instruction will fail, see if we can fix things up by
+ changing the opcode. */
+ if (newimm == (unsigned int) FAIL
+ && (newimm = negate_data_op (& temp, value)) == (unsigned int) FAIL)
+ {
+ /* No ? OK - try using two ADD instructions to generate the value. */
+ newimm = validate_immediate_twopart (value, & highpart);
+
+ /* Yes - then make sure that the second instruction is also an add. */
+ if (newimm != (unsigned int) FAIL)
+ newinsn = temp;
+ /* Still No ? Try using a negated value. */
+ else if (validate_immediate_twopart (- value, & highpart) != (unsigned int) FAIL)
+ temp = newinsn = (temp & OPCODE_MASK) | OPCODE_SUB << DATA_OP_SHIFT;
+ /* Otherwise - give up. */
+ else
+ {
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("Unable to compute ADRL instructions for PC offset of 0x%x\n"), value);
+ break;
+ }
+
+ /* Replace the first operand in the 2nd instruction (which is the PC)
+ with the destination register. We have already added in the PC in the
+ first instruction and we do not want to do it again. */
+ newinsn &= ~ 0xf0000;
+ newinsn |= ((newinsn & 0x0f000) << 4);
+ }
+
+ newimm |= (temp & 0xfffff000);
+ md_number_to_chars (buf, (valueT) newimm, INSN_SIZE);
+
+ highpart |= (newinsn & 0xfffff000);
+ md_number_to_chars (buf + INSN_SIZE, (valueT) highpart, INSN_SIZE);
+ }
+ break;
+
+ case BFD_RELOC_ARM_OFFSET_IMM:
sign = value >= 0;
if ((value = validate_offset_imm (value, 0)) == FAIL)
{
@@ -5816,6 +5948,12 @@ tc_gen_reloc (section, fixp)
fixp->fx_r_type);
return NULL;
+ case BFD_RELOC_ARM_ADRL_IMMEDIATE:
+ as_bad_where (fixp->fx_file, fixp->fx_line,
+ _("ADRL used for a symbol not defined in the same file"),
+ fixp->fx_r_type);
+ return NULL;
+
case BFD_RELOC_ARM_OFFSET_IMM:
as_bad_where (fixp->fx_file, fixp->fx_line,
_("Internal_relocation (type %d) not fixed up (OFFSET_IMM)"),
@@ -5880,8 +6018,7 @@ md_estimate_size_before_relax (fragP, segtype)
}
static void
-output_inst (str)
- char * str;
+output_inst PARAMS ((void))
{
char * to = NULL;
@@ -5896,7 +6033,13 @@ output_inst (str)
{
assert (inst.size == (2 * THUMB_SIZE));
md_number_to_chars (to, inst.instruction >> 16, THUMB_SIZE);
- md_number_to_chars (to + 2, inst.instruction, THUMB_SIZE);
+ md_number_to_chars (to + THUMB_SIZE, inst.instruction, THUMB_SIZE);
+ }
+ else if (inst.size > INSN_SIZE)
+ {
+ assert (inst.size == (2 * INSN_SIZE));
+ md_number_to_chars (to, inst.instruction, INSN_SIZE);
+ md_number_to_chars (to + INSN_SIZE, inst.instruction, INSN_SIZE);
}
else
md_number_to_chars (to, inst.instruction, inst.size);
@@ -5936,7 +6079,7 @@ md_assemble (str)
if (*str == ' ')
str++; /* Skip leading white space */
-
+
/* Scan up to the end of the op-code, which must end in white space or
end of string. */
for (start = p = str; *p != '\0'; p++)
@@ -5951,24 +6094,25 @@ md_assemble (str)
if (thumb_mode)
{
- CONST struct thumb_opcode *opcode;
+ CONST struct thumb_opcode * opcode;
c = *p;
*p = '\0';
opcode = (CONST struct thumb_opcode *) hash_find (arm_tops_hsh, str);
*p = c;
+
if (opcode)
{
inst.instruction = opcode->value;
inst.size = opcode->size;
(*opcode->parms)(p);
- output_inst (start);
+ output_inst ();
return;
}
}
else
{
- CONST struct asm_opcode *opcode;
+ CONST struct asm_opcode * opcode;
inst.size = INSN_SIZE;
/* p now points to the end of the opcode, probably white space, but we
@@ -5982,10 +6126,11 @@ md_assemble (str)
*q = '\0';
opcode = (CONST struct asm_opcode *) hash_find (arm_ops_hsh, str);
*q = c;
+
if (opcode && opcode->template)
{
unsigned long flag_bits = 0;
- char *r;
+ char * r;
/* Check that this instruction is supported for this CPU */
if ((opcode->variants & cpu_variant) == 0)
@@ -6002,7 +6147,7 @@ md_assemble (str)
inst.instruction |= COND_ALWAYS;
(*opcode->parms)(q, 0);
}
- output_inst (start);
+ output_inst ();
return;
}
@@ -6087,7 +6232,7 @@ _("Warning: Use of the 'nv' conditional is deprecated\n"));
}
(*opcode->parms) (p, flag_bits);
- output_inst (start);
+ output_inst ();
return;
}
@@ -6174,9 +6319,10 @@ _("Warning: Use of the 'nv' conditional is deprecated\n"));
* -m[arm]3 Arm 3 processor
* -m[arm]6[xx], Arm 6 processors
* -m[arm]7[xx][t][[d]m] Arm 7 processors
- * -m8[10] Arm 8 processors
- * -m9[20][tdmi] Arm 9 processors
+ * -m[arm]8[10] Arm 8 processors
+ * -m[arm]9[20][tdmi] Arm 9 processors
* -mstrongarm[110[0]] StrongARM processors
+ * -m[arm]v[2345] Arm architecures
* -mall All (except the ARM1)
* FP variants:
* -mfpa10, -mfpa11 FPA10 and 11 co-processor instructions
@@ -6265,7 +6411,7 @@ md_parse_option (c, arg)
}
else if (streq (str, "thumb-interwork"))
{
- cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_THUMB | ARM_ARCHv4;
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_THUMB | ARM_ARCH_V4;
#if defined OBJ_COFF || defined OBJ_ELF
support_interwork = true;
#endif
@@ -6399,7 +6545,7 @@ md_parse_option (c, arg)
switch (* str)
{
case 't':
- cpu_variant |= (ARM_THUMB | ARM_ARCHv4);
+ cpu_variant |= (ARM_THUMB | ARM_ARCH_V4);
break;
case 'm':
@@ -6426,20 +6572,20 @@ md_parse_option (c, arg)
case '8':
if (streq (str, "8") || streq (str, "810"))
- cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_8 | ARM_ARCHv4 | ARM_LONGMUL;
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_8 | ARM_ARCH_V4 | ARM_LONGMUL;
else
goto bad;
break;
case '9':
if (streq (str, "9"))
- cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_9 | ARM_ARCHv4 | ARM_LONGMUL | ARM_THUMB;
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL | ARM_THUMB;
else if (streq (str, "920"))
- cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_9 | ARM_ARCHv4 | ARM_LONGMUL;
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL;
else if (streq (str, "920t"))
- cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_9 | ARM_ARCHv4 | ARM_LONGMUL | ARM_THUMB;
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL | ARM_THUMB;
else if (streq (str, "9tdmi"))
- cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_9 | ARM_ARCHv4 | ARM_LONGMUL | ARM_THUMB;
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL | ARM_THUMB;
else
goto bad;
break;
@@ -6448,7 +6594,7 @@ md_parse_option (c, arg)
if (streq (str, "strongarm")
|| streq (str, "strongarm110")
|| streq (str, "strongarm1100"))
- cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_8 | ARM_ARCHv4 | ARM_LONGMUL;
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_8 | ARM_ARCH_V4 | ARM_LONGMUL;
else
goto bad;
break;
@@ -6478,7 +6624,18 @@ md_parse_option (c, arg)
break;
case '4':
- cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCHv4;
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCH_V4;
+
+ switch (*++str)
+ {
+ case 't': cpu_variant |= ARM_THUMB; break;
+ case 0: break;
+ default: as_bad (_("Invalid architecture variant -m%s"), arg); break;
+ }
+ break;
+
+ case '5':
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCH_V5;
switch (*++str)
{
@@ -6521,7 +6678,7 @@ md_show_usage (fp)
_("\
ARM Specific Assembler Options:\n\
-m[arm][<processor name>] select processor variant\n\
- -m[arm]v[2|2a|3|3m|4|4t] select architecture variant\n\
+ -m[arm]v[2|2a|3|3m|4|4t|5]select architecture variant\n\
-mthumb only allow Thumb instructions\n\
-mthumb-interwork mark the assembled code as supporting interworking\n\
-mall allow any instruction\n\
diff --git a/gas/doc/c-arm.texi b/gas/doc/c-arm.texi
index b94fb2a..1538ac9 100644
--- a/gas/doc/c-arm.texi
+++ b/gas/doc/c-arm.texi
@@ -29,12 +29,12 @@
@cindex options for ARM (none)
@table @code
@cindex @code{-marm} command line option, ARM
-@item -marm @var{[2|250|3|6|60|600|610|620|7|7m|7d|7dm|7di|7dmi|70|700|700i|710|710c|7100|7500|7500fe|7tdmi|8|810|9|9tdmistrongarm|strongarm110|strongarm1100]}
+@item -marm @var{[2|250|3|6|60|600|610|620|7|7m|7d|7dm|7di|7dmi|70|700|700i|710|710c|7100|7500|7500fe|7tdmi|8|810|9|9tdmi|920||strongarm|strongarm110|strongarm1100]}
This option specifies the target processor. The assembler will issue an
error message if an attempt is made to assemble an instruction which
will not execute on the target processor.
@cindex @code{-marmv} command line option, ARM
-@item -marmv @var{[2|2a|3|3m|4|4t]}
+@item -marmv @var{[2|2a|3|3m|4|4t|5|5t]}
This option specifies the target architecture. The assembler will issue
an error message if an attempt is made to assemble an instruction which
will not execute on the target architecture.
@@ -184,13 +184,23 @@ This is a synonym for .ltorg.
@cindex ARM opcodes
@cindex opcodes for ARM
-@code{@value{AS}} implements all the standard ARM opcodes.
+@code{@value{AS}} implements all the standard ARM opcodes. It also
+implements several pseudo opcodes, including several synthetic load
+instructions.
-*TODO* Document the pseudo-ops (adr, nop)
+@table @code
+
+@cindex @code{NOP} pseudo op, ARM
+@item NOP
+@smallexample
+ nop
+@end smallexample
-GAS for the ARM supports a synthetic register load instruction whoes
-syntax is:
+This pseudo op will always evaluate to a legal ARM instruction that does
+nothing. Currently it will evaluate to MOV r0, r0.
+@cindex @code{LDR reg,=<label>} pseudo op, ARM
+@item LDR
@smallexample
ldr <register> , = <expression>
@end smallexample
@@ -201,6 +211,37 @@ constant can be generated by either of these instructions. Otherwise
the constant will be placed into the nearest literal pool (if it not
already there) and a PC relative LDR instruction will be generated.
+@cindex @code{ADR reg,<label>} pseudo op, ARM
+@item ADR
+@smallexample
+ adr <register> <label>
+@end smallexample
+
+This instruction will load the address of @var{label} into the indicated
+register. The instruction will evaluate to a PC relative ADD or SUB
+instruction depending upon where the label is located. If the label is
+out of range, or if it is not defined in the same file (and section) as
+the ADR instruction, then an error will be generated. This instruction
+will not make use of the literal pool.
+
+@cindex @code{ADRL reg,<label>} pseudo op, ARM
+@item ADRL
+@smallexample
+ adrl <register> <label>
+@end smallexample
+
+This instruction will load the address of @var{label} into the indicated
+register. The instruction will evaluate to one or two a PC relative ADD
+or SUB instructions depending upon where the label is located. If a
+second instruction is not needed a NOP instruction will be generated in
+its place, so that this instruction is always 8 bytes long.
+
+If the label is out of range, or if it is not defined in the same file
+(and section) as the ADRL instruction, then an error will be generated.
+This instruction will not make use of the literal pool.
+
+@end table
+
For information on the ARM or Thumb instruction sets, see @cite{ARM
Software Development Toolkit Reference Manual}, Advanced RISC Machines
Ltd.