/* tc-arm.c -- Assemble for the ARM
- Copyright (C) 1994, 95, 96, 97, 98, 1999 Free Software Foundation, Inc.
+ Copyright (C) 1994, 95, 96, 97, 98, 1999, 2000 Free Software Foundation, Inc.
Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
Modified by David Taylor (dtaylor@armltd.co.uk)
#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_EXT_V5E 0x00000200 /* "El Segundo" */
-/* Architectures are the sum of the base and extensions */
+/* 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_V5 (ARM_ARCH_V4 | ARM_EXT_V5)
#define ARM_ARCH_V5T (ARM_ARCH_V5 | ARM_THUMB)
/* Some useful combinations: */
#endif
/* This array holds the chars that always start a comment. If the
- pre-processor is disabled, these aren't very useful */
+ pre-processor is disabled, these aren't very useful. */
CONST char comment_chars[] = "@";
/* This array holds the chars that only start a comment at the beginning of
a line. If the line seems to have the form '# 123 filename'
- .line and .file directives will appear in the pre-processed output */
+ .line and .file directives will appear in the pre-processed output. */
/* Note that input_file.c hand checks for '#' at the beginning of the
first line of the input file. This is because the compiler outputs
- #NO_APP at the beginning of its output. */
-/* Also note that comments like this one will always work. */
+ #NO_APP at the beginning of its output. */
+/* Also note that comments like this one will always work. */
CONST char line_comment_chars[] = "#";
#ifdef TE_LINUX
CONST char line_separator_chars[] = "";
#endif
-/* Chars that can be used to separate mant from exp in floating point nums */
+/* Chars that can be used to separate mant
+ from exp in floating point numbers. */
CONST char EXP_CHARS[] = "eE";
/* Chars that mean this number is a floating point constant */
static int thumb_mode = 0; /* 0: assemble for ARM, 1: assemble for Thumb,
2: assemble for Thumb even though target cpu
- does not support thumb instructions */
+ does not support thumb instructions. */
typedef struct arm_fix
{
int thumb_mode;
"0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0", 0
};
-/* Number of littlenums required to hold an extended precision number */
+/* Number of littlenums required to hold an extended precision number. */
#define MAX_LITTLENUMS 6
LITTLENUM_TYPE fp_values[NUM_FLOAT_VALS][MAX_LITTLENUMS];
unsigned long value;
};
-/* This is to save a hash look-up in the common case */
+/* This is to save a hash look-up in the common case. */
#define COND_ALWAYS 0xe0000000
static CONST struct asm_cond conds[] =
/* Warning: If the top bit of the set_bits is set, then the standard
instruction bitmask is ignored, and the new bitmask is taken from
- the set_bits: */
+ the set_bits: */
struct asm_flg
{
CONST char * template; /* Basic flag string */
struct asm_psr
{
CONST char * template;
- unsigned long number;
+ boolean cpsr;
+ unsigned long field;
};
-#define PSR_FIELD_MASK 0x000f0000
+#define SPSR_BIT (1 << 22) /* The bit that distnguishes CPSR and SPSR. */
+#define PSR_SHIFT 16 /* How many bits to shift the PSR_xxx bits up by. */
-#define PSR_FLAGS 0x00080000
-#define PSR_CONTROL 0x00010000 /* Undocumented instruction, its use is discouraged by ARM */
-#define PSR_ALL 0x00090000
-
-#define CPSR_ALL 0
-#define SPSR_ALL 1
-#define CPSR_FLG 2
-#define SPSR_FLG 3
-#define CPSR_CTL 4
-#define SPSR_CTL 5
+#define PSR_c (1 << 0)
+#define PSR_x (1 << 1)
+#define PSR_s (1 << 2)
+#define PSR_f (1 << 3)
static CONST struct asm_psr psrs[] =
{
- /* Valid <psr>'s */
- {"cpsr", CPSR_ALL},
- {"cpsr_all", CPSR_ALL},
- {"spsr", SPSR_ALL},
- {"spsr_all", SPSR_ALL},
-
- /* Valid <psrf>'s */
- {"cpsr_flg", CPSR_FLG},
- {"spsr_flg", SPSR_FLG},
-
- /* Valid <psrc>'s */
- {"cpsr_c", CPSR_CTL},
- {"cpsr_ctl", CPSR_CTL},
- {"spsr_c", SPSR_CTL},
- {"spsr_ctl", SPSR_CTL}
+ {"CPSR", true, PSR_c | PSR_f},
+ {"CPSR_all", true, PSR_c | PSR_f},
+ {"SPSR", false, PSR_c | PSR_f},
+ {"SPSR_all", false, PSR_c | PSR_f},
+ {"CPSR_flg", true, PSR_f},
+ {"CPSR_f", true, PSR_f},
+ {"SPSR_flg", false, PSR_f},
+ {"SPSR_f", false, PSR_f},
+ {"CPSR_c", true, PSR_c},
+ {"CPSR_ctl", true, PSR_c},
+ {"SPSR_c", false, PSR_c},
+ {"SPSR_ctl", false, PSR_c},
+ {"CPSR_x", true, PSR_x},
+ {"CPSR_s", true, PSR_s},
+ {"SPSR_x", false, PSR_x},
+ {"SPSR_s", false, PSR_s},
+ /* For backwards compatability with older toolchain we also
+ support lower case versions of some of these flags. */
+ {"cpsr", true, PSR_c | PSR_f},
+ {"cpsr_all", true, PSR_c | PSR_f},
+ {"spsr", false, PSR_c | PSR_f},
+ {"spsr_all", false, PSR_c | PSR_f},
+ {"cpsr_flg", true, PSR_f},
+ {"cpsr_f", true, PSR_f},
+ {"spsr_flg", false, PSR_f},
+ {"spsr_f", false, PSR_f},
+ {"cpsr_c", true, PSR_c},
+ {"cpsr_ctl", true, PSR_c},
+ {"spsr_c", false, PSR_c},
+ {"spsr_ctl", false, PSR_c}
};
-/* Functions called by parser */
+/* Functions called by parser. */
/* ARM instructions */
static void do_arit PARAMS ((char *, unsigned long));
static void do_cmp PARAMS ((char *, unsigned long));
static void fix_new_arm PARAMS ((fragS *, int, short, expressionS *, int, int));
static int arm_reg_parse PARAMS ((char **));
-static int arm_psr_parse PARAMS ((char **));
+static CONST struct asm_psr * arm_psr_parse PARAMS ((char **));
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 void opcode_select PARAMS ((int));
static void end_of_line PARAMS ((char *));
static int reg_required_here PARAMS ((char **, int));
-static int psr_required_here PARAMS ((char **, int, int));
+static int psr_required_here PARAMS ((char **));
static int co_proc_number PARAMS ((char **));
static int cp_opc_expr PARAMS ((char **, int, int));
static int cp_reg_required_here PARAMS ((char **, int));
#endif
/* ARM instructions take 4bytes in the object file, Thumb instructions
- take 2: */
+ take 2: */
#define INSN_SIZE 4
/* LONGEST_INST is the longest basic instruction name without conditions or
- * flags.
- * ARM7M has 4 of length 5
- */
+ flags. ARM7M has 4 of length 5. */
#define LONGEST_INST 5
{"stm", 0x08000000, NULL, stm_flags, ARM_ANY, do_ldmstm},
{"ldm", 0x08100000, NULL, ldm_flags, ARM_ANY, do_ldmstm},
{"swi", 0x0f000000, NULL, NULL, ARM_ANY, do_swi},
+#ifdef TE_WINCE
+ {"bl", 0x0b000000, NULL, NULL, ARM_ANY, do_branch},
+ {"b", 0x0a000000, NULL, NULL, ARM_ANY, do_branch},
+#else
{"bl", 0x0bfffffe, NULL, NULL, ARM_ANY, do_branch},
{"b", 0x0afffffe, NULL, NULL, ARM_ANY, do_branch},
-
+#endif
+
/* Pseudo ops */
{"adr", 0x028f0000, NULL, NULL, ARM_ANY, do_adr},
{"adrl", 0x028f0000, NULL, NULL, ARM_ANY, do_adrl},
{"mrs", 0x010f0000, NULL, NULL, ARM_6UP, do_mrs},
{"msr", 0x0120f000, NULL, NULL, ARM_6UP, do_msr},
/* ScottB: our code uses 0x0128f000 for msr.
- NickC: but this is wrong because the bits 16 and 19 are handled
- by the PSR_xxx defines above. */
+ NickC: but this is wrong because the bits 16 through 19 are
+ handled by the PSR_xxx defines above. */
/* ARM 7M long multiplies - need signed/unsigned flags! */
{"smull", 0x00c00090, NULL, s_flag, ARM_LONGMUL, do_mull},
{"flt", 0x0e000110, "sde", round_flags, FPU_ALL, do_fp_from_reg},
{"fix", 0x0e100110, NULL, fix_flags, FPU_ALL, do_fp_to_reg},
-/* Generic copressor instructions */
+/* Generic copressor instructions. */
{"cdp", 0x0e000000, NULL, NULL, ARM_2UP, do_cdp},
{"ldc", 0x0c100000, NULL, cplong_flag, ARM_2UP, do_lstc},
{"stc", 0x0c000000, NULL, cplong_flag, ARM_2UP, do_lstc},
{"mrc", 0x0e100010, NULL, NULL, ARM_2UP, do_co_reg},
};
-/* defines for various bits that we will want to toggle */
-
+/* Defines for various bits that we will want to toggle. */
#define INST_IMMEDIATE 0x02000000
#define OFFSET_REG 0x02000000
#define HWOFFSET_IMM 0x00400000
#define OPCODE_MASK 0xfe1fffff
#define DATA_OP_SHIFT 21
-/* Codes to distinguish the arithmetic instructions */
-
+/* Codes to distinguish the arithmetic instructions. */
#define OPCODE_AND 0
#define OPCODE_EOR 1
#define OPCODE_SUB 2
static int thumb_reg PARAMS ((char ** str, int hi_lo));
-#define THUMB_SIZE 2 /* Size of thumb instruction */
+#define THUMB_SIZE 2 /* Size of thumb instruction. */
#define THUMB_REG_LO 0x1
#define THUMB_REG_HI 0x2
#define THUMB_REG_ANY 0x3
#define THUMB_PP_PC_LR 0x0100
-/* These three are used for immediate shifts, do not alter */
+/* These three are used for immediate shifts, do not alter. */
#define THUMB_WORD 2
#define THUMB_HALFWORD 1
#define THUMB_BYTE 0
{"blt", 0xdbfe, 2, ARM_THUMB, do_t_branch9},
{"bgt", 0xdcfe, 2, ARM_THUMB, do_t_branch9},
{"ble", 0xddfe, 2, ARM_THUMB, do_t_branch9},
+ {"bal", 0xdefe, 2, ARM_THUMB, do_t_branch9},
{"bic", 0x4380, 2, ARM_THUMB, do_t_arit},
{"bl", 0xf7fffffe, 4, ARM_THUMB, do_t_branch23},
{"bx", 0x4700, 2, ARM_THUMB, do_t_bx},
#define REG_LR 14
#define REG_SP 13
-/* These are the standard names; Users can add aliases with .req */
+/* These are the standard names. Users can add aliases with .req */
static CONST struct reg_entry reg_table[] =
{
- /* Processor Register Numbers */
+ /* Processor Register Numbers. */
{"r0", 0}, {"r1", 1}, {"r2", 2}, {"r3", 3},
{"r4", 4}, {"r5", 5}, {"r6", 6}, {"r7", 7},
{"r8", 8}, {"r9", 9}, {"r10", 10}, {"r11", 11},
{"r12", 12}, {"r13", REG_SP},{"r14", REG_LR},{"r15", REG_PC},
- /* APCS conventions */
+ /* APCS conventions. */
{"a1", 0}, {"a2", 1}, {"a3", 2}, {"a4", 3},
{"v1", 4}, {"v2", 5}, {"v3", 6}, {"v4", 7}, {"v5", 8},
{"v6", 9}, {"sb", 9}, {"v7", 10}, {"sl", 10},
{"fp", 11}, {"ip", 12}, {"sp", REG_SP},{"lr", REG_LR},{"pc", REG_PC},
- /* FP Registers */
+ /* ATPCS additions to APCS conventions. */
+ {"wr", 7}, {"v8", 11},
+ /* FP Registers. */
{"f0", 16}, {"f1", 17}, {"f2", 18}, {"f3", 19},
{"f4", 20}, {"f5", 21}, {"f6", 22}, {"f7", 23},
{"c0", 32}, {"c1", 33}, {"c2", 34}, {"c3", 35},
{"cr4", 36}, {"cr5", 37}, {"cr6", 38}, {"cr7", 39},
{"cr8", 40}, {"cr9", 41}, {"cr10", 42}, {"cr11", 43},
{"cr12", 44}, {"cr13", 45}, {"cr14", 46}, {"cr15", 47},
+ /* ATPCS additions to float register names. */
+ {"s0",16}, {"s1",17}, {"s2",18}, {"s3",19},
+ {"s4",20}, {"s5",21}, {"s6",22}, {"s7",23},
+ {"d0",16}, {"d1",17}, {"d2",18}, {"d3",19},
+ {"d4",20}, {"d5",21}, {"d6",22}, {"d7",23},
+ /* FIXME: At some point we need to add VFP register names. */
+ /* Array terminator. */
{NULL, 0}
};
/* This table describes all the machine specific pseudo-ops the assembler
has to support. The fields are:
- pseudo-op name without dot
- function to call to execute this pseudo-op
- Integer arg to pass to the function
- */
+ pseudo-op name without dot
+ function to call to execute this pseudo-op
+ Integer arg to pass to the function. */
static void s_req PARAMS ((int));
static void s_align PARAMS ((int));
current_poolP = symbol_create (FAKE_LABEL_NAME, undefined_section,
(valueT) 0, &zero_address_frag);
- /* Check if this literal value is already in the pool: */
+ /* Check if this literal value is already in the pool: */
while (lit_count < next_literal_pool_place)
{
if (literals[lit_count].exp.X_op == inst.reloc.exp.X_op
&& inst.reloc.exp.X_op == O_constant
- && literals[lit_count].exp.X_add_number == inst.reloc.exp.X_add_number
+ && literals[lit_count].exp.X_add_number
+ == inst.reloc.exp.X_add_number
&& literals[lit_count].exp.X_unsigned == inst.reloc.exp.X_unsigned)
break;
lit_count++;
#endif /* DEBUG_SYMS */
}
-/* Check that an immediate is valid, and if so, convert it to the right format. */
-
+/* Check that an immediate is valid, and if so,
+ convert it to the right format. */
static unsigned int
validate_immediate (val)
unsigned int val;
/* 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;
static void
s_req (a)
- int a;
+ int a ATTRIBUTE_UNUSED;
{
as_bad (_("Invalid syntax for .req directive."));
}
static void
s_bss (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
/* We don't support putting frags in the BSS segment, we fake it by
marking in_bss, then looking at s_skip for clues?.. */
static void
s_even (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
if (!need_pass_2) /* Never make frag if expect extra pass. */
frag_align (1, 0, 0);
static void
s_ltorg (ignored)
- int ignored;
+ int ignored ATTRIBUTE_UNUSED;
{
int lit_count = 0;
char sym_name[20];
#endif
while (lit_count < next_literal_pool_place)
- /* First output the expression in the instruction to the pool */
+ /* First output the expression in the instruction to the pool. */
emit_expr (&(literals[lit_count++].exp), 4); /* .word */
next_literal_pool_place = 0;
static void
s_align (unused) /* Same as s_align_ptwo but align 0 => align 2 */
- int unused;
+ int unused ATTRIBUTE_UNUSED;
{
register int temp;
register long temp_fill;
static void
s_force_thumb (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
/* If we are not already in thumb mode go into it, EVEN if
the target processor does not support thumb instructions.
static void
s_thumb_func (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
/* The following label is the name/address of the start of a Thumb function.
We need to know this for the interworking support. */
static void
s_arm (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
opcode_select (32);
demand_empty_rest_of_line ();
static void
s_thumb (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
opcode_select (16);
demand_empty_rest_of_line ();
static void
s_code (unused)
- int unused;
+ int unused ATTRIBUTE_UNUSED;
{
register int temp;
/* A standard register must be given at this point.
Shift is the place to put it in inst.instruction.
Restores input start point on err.
- Returns the reg#, or FAIL. */
-
+ Returns the reg#, or FAIL. */
static int
reg_required_here (str, shift)
char ** str;
return FAIL;
}
+static CONST struct asm_psr *
+arm_psr_parse (ccp)
+ register char ** ccp;
+{
+ char * start = * ccp;
+ char c;
+ char * p;
+ CONST struct asm_psr * psr;
+
+ p = start;
+
+ /* Skip to the end of the next word in the input stream. */
+ do
+ {
+ c = *p++;
+ }
+ while (isalpha (c) || c == '_');
+
+ /* Terminate the word. */
+ *--p = 0;
+
+ /* Now locate the word in the psr hash table. */
+ psr = (CONST struct asm_psr *) hash_find (arm_psr_hsh, start);
+
+ /* Restore the input stream. */
+ *p = c;
+
+ /* If we found a valid match, advance the
+ stream pointer past the end of the word. */
+ *ccp = p;
+
+ return psr;
+}
+
+/* Parse the input looking for a PSR flag. */
static int
-psr_required_here (str, cpsr, spsr)
+psr_required_here (str)
char ** str;
- int cpsr;
- int spsr;
{
- int psr;
char * start = *str;
- psr = arm_psr_parse (str);
+ CONST struct asm_psr * psr;
- if (psr == cpsr || psr == spsr)
+ psr = arm_psr_parse (str);
+
+ if (psr)
{
- if (psr == spsr)
- inst.instruction |= 1 << 22;
+ /* If this is the SPSR that is being modified, set the R bit. */
+ if (! psr->cpsr)
+ inst.instruction |= SPSR_BIT;
+
+ /* Set the psr flags in the MSR instruction. */
+ inst.instruction |= psr->field << PSR_SHIFT;
return SUCCESS;
}
- /* In the few cases where we might be able to accept something else
- this error can be overridden. */
- inst.error = _("<psr(f)> expected");
+ /* In the few cases where we might be able to accept
+ something else this error can be overridden. */
+ inst.error = _("flag for {c}psr instruction expected");
/* Restore the start point. */
*str = start;
return;
}
- if (skip_past_comma (&str) == FAIL
- || psr_required_here (& str, CPSR_ALL, SPSR_ALL) == FAIL)
+ if (skip_past_comma (&str) == FAIL)
+ {
+ inst.error = _("comma expected after register name");
+ return;
+ }
+
+ skip_whitespace (str);
+
+ if ( strcmp (str, "CPSR") == 0
+ || strcmp (str, "SPSR") == 0
+ /* Lower case versions for backwards compatability. */
+ || strcmp (str, "cpsr") == 0
+ || strcmp (str, "spsr") == 0)
+ str += 4;
+ /* This is for backwards compatability with older toolchains. */
+ else if (strcmp (str, "cpsr_all") == 0
+ || strcmp (str, "spsr_all") == 0)
+ str += 7;
+ else
{
- inst.error = _("<psr> expected");
+ inst.error = _("{C|S}PSR expected");
return;
}
+ if (* str == 's' || * str == 'S')
+ inst.instruction |= SPSR_BIT;
+
inst.instruction |= flags;
end_of_line (str);
- return;
}
-/* Three possible forms: "<psr>, Rm", "<psrf>, Rm", "<psrf>, #expression". */
+/* Two possible forms:
+ "{C|S}PSR_<field>, Rm",
+ "{C|S}PSR_f, #expression". */
static void
do_msr (str, flags)
char * str;
unsigned long flags;
{
- int reg;
+ skip_whitespace (str);
+
+ if (psr_required_here (& str) == FAIL)
+ return;
+
+ if (skip_past_comma (& str) == FAIL)
+ {
+ inst.error = _("comma missing after psr flags");
+ return;
+ }
skip_whitespace (str);
- if (psr_required_here (&str, CPSR_ALL, SPSR_ALL) == SUCCESS)
+ if (reg_required_here (& str, 0) != FAIL)
{
- inst.instruction |= PSR_ALL;
+ inst.error = NULL;
+ inst.instruction |= flags;
+ end_of_line (str);
+ return;
+ }
- /* Sytax should be "<psr>, Rm" */
- if (skip_past_comma (&str) == FAIL
- || (reg = reg_required_here (&str, 0)) == FAIL)
- {
- inst.error = BAD_ARGS;
- return;
- }
+ if (! is_immediate_prefix (* str))
+ {
+ inst.error = _("only a register or immediate value can follow a psr flag");
+ return;
+ }
+
+ str ++;
+ inst.error = NULL;
+
+ if (my_get_expression (& inst.reloc.exp, & str))
+ {
+ inst.error = _("only a register or immediate value can follow a psr flag");
+ return;
+ }
+
+ if (inst.instruction & ((PSR_c | PSR_x | PSR_s) << PSR_SHIFT))
+ {
+ inst.error = _("can only set flag field with immediate value");
+ return;
+ }
+
+ flags |= INST_IMMEDIATE;
+
+ if (inst.reloc.exp.X_add_symbol)
+ {
+ inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
+ inst.reloc.pc_rel = 0;
}
else
{
- if (psr_required_here (& str, CPSR_FLG, SPSR_FLG) == SUCCESS)
- inst.instruction |= PSR_FLAGS;
- else if (psr_required_here (& str, CPSR_CTL, SPSR_CTL) == SUCCESS)
- inst.instruction |= PSR_CONTROL;
- else
- {
- inst.error = BAD_ARGS;
- return;
- }
+ unsigned value = validate_immediate (inst.reloc.exp.X_add_number);
- if (skip_past_comma (&str) == FAIL)
+ if (value == (unsigned) FAIL)
{
- inst.error = BAD_ARGS;
+ inst.error = _("Invalid constant");
return;
}
- /* Syntax could be "<psrf>, rm", "<psrf>, #expression" */
-
- if ((reg = reg_required_here (& str, 0)) != FAIL)
- ;
- /* Immediate expression. */
- else if (is_immediate_prefix (* str))
- {
- str ++;
- inst.error = NULL;
-
- if (my_get_expression (& inst.reloc.exp, & str))
- {
- inst.error = _("Register or shift expression expected");
- return;
- }
-
- if (inst.reloc.exp.X_add_symbol)
- {
- inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
- inst.reloc.pc_rel = 0;
- }
- else
- {
- unsigned value = validate_immediate (inst.reloc.exp.X_add_number);
- if (value == FAIL)
- {
- inst.error = _("Invalid constant");
- return;
- }
-
- inst.instruction |= value;
- }
-
- flags |= INST_IMMEDIATE;
- }
- else
- {
- inst.error = _("Error: unrecognised syntax for second argument to msr instruction");
- return;
- }
+ inst.instruction |= value;
}
inst.error = NULL;
inst.instruction |= flags;
end_of_line (str);
- return;
}
/* Long Multiply Parser
return FAIL;
}
- if (value == FAIL)
+ if (value == (unsigned) FAIL)
return FAIL;
*instruction &= OPCODE_MASK;
unsigned long flags;
{
/* This is a pseudo-op of the form "adr rd, label" to be converted
- into a relative address of the form "add rd, pc, #label-.-8" */
-
+ into a relative address of the form "add rd, pc, #label-.-8". */
skip_whitespace (str);
if (reg_required_here (&str, 12) == FAIL
inst.error = BAD_ARGS;
return;
}
+
/* Frag hacking will turn this into a sub instruction if the offset turns
out to be negative. */
inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
- inst.reloc.exp.X_add_number -= 8; /* PC relative adjust */
+ inst.reloc.exp.X_add_number -= 8; /* PC relative adjust. */
inst.reloc.pc_rel = 1;
inst.instruction |= flags;
+
end_of_line (str);
- return;
}
static void
}
else
inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
+#ifndef TE_WINCE
inst.reloc.exp.X_add_number -= 8; /* PC rel adjust */
+#endif
inst.reloc.pc_rel = 1;
inst.instruction |= (REG_PC << 16);
pre_inc = 1;
static void
do_branch (str, flags)
char * str;
- unsigned long flags;
+ unsigned long flags ATTRIBUTE_UNUSED;
{
if (my_get_expression (&inst.reloc.exp, &str))
return;
static void
do_bx (str, flags)
char * str;
- unsigned long flags;
+ unsigned long flags ATTRIBUTE_UNUSED;
{
int reg;
static void
do_cdp (str, flags)
char * str;
- unsigned long flags;
+ unsigned long flags ATTRIBUTE_UNUSED;
{
/* Co-processor data operation.
Format: CDP{cond} CP#,<expr>,CRd,CRn,CRm{,<expr>} */
static void
do_fp_ctrl (str, flags)
char * str;
- unsigned long flags;
+ unsigned long flags ATTRIBUTE_UNUSED;
{
/* FP control registers.
Format: <WFS|RFS|WFC|RFC>{cond} Rn */
static void
do_fp_ldst (str, flags)
char * str;
- unsigned long flags;
+ unsigned long flags ATTRIBUTE_UNUSED;
{
skip_whitespace (str);
}
}
}
+
end_of_line (str);
}
{
/* Two operand immediate format, set Rs to Rd. */
Rs = Rd;
- str++;
+ str ++;
if (my_get_expression (&inst.reloc.exp, &str))
return;
}
inst.instruction |= Rd | (Rs << 3);
}
+
end_of_line (str);
}
do_t_adr (str)
char * str;
{
+ int reg;
+
/* This is a pseudo-op of the form "adr rd, label" to be converted
- into a relative address of the form "add rd, pc, #label-.-4" */
+ into a relative address of the form "add rd, pc, #label-.-4". */
skip_whitespace (str);
- if (reg_required_here (&str, 4) == FAIL /* Store Rd in temporary location inside instruction. */
+ /* Store Rd in temporary location inside instruction. */
+ if ((reg = reg_required_here (&str, 4)) == FAIL
+ || (reg > 7) /* For Thumb reg must be r0..r7. */
|| skip_past_comma (&str) == FAIL
|| my_get_expression (&inst.reloc.exp, &str))
{
}
inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
- inst.reloc.exp.X_add_number -= 4; /* PC relative adjust */
+ inst.reloc.exp.X_add_number -= 4; /* PC relative adjust. */
inst.reloc.pc_rel = 1;
- inst.instruction |= REG_PC; /* Rd is already placed into the instruction */
+ inst.instruction |= REG_PC; /* Rd is already placed into the instruction. */
+
end_of_line (str);
}
void
md_begin ()
{
- int i;
+ unsigned mach;
+ unsigned int i;
if ( (arm_ops_hsh = hash_new ()) == NULL
|| (arm_tops_hsh = hash_new ()) == NULL
{
unsigned int flags = 0;
- /* Set the flags in the private structure */
+ /* Set the flags in the private structure. */
if (uses_apcs_26) flags |= F_APCS26;
if (support_interwork) flags |= F_INTERWORK;
if (uses_apcs_float) flags |= F_APCS_FLOAT;
}
#endif
- {
- unsigned mach;
-
- /* Record the CPU type as well */
- switch (cpu_variant & ARM_CPU_MASK)
- {
- case ARM_2:
- mach = bfd_mach_arm_2;
- break;
-
- case ARM_3: /* also ARM_250 */
- mach = bfd_mach_arm_2a;
- break;
-
- default:
- case ARM_6 | ARM_3 | ARM_2: /* Actually no CPU type defined */
+ /* Record the CPU type as well. */
+ switch (cpu_variant & ARM_CPU_MASK)
+ {
+ case ARM_2:
+ mach = bfd_mach_arm_2;
+ break;
+
+ case ARM_3: /* Also ARM_250. */
+ mach = bfd_mach_arm_2a;
+ break;
+
+ default:
+ case ARM_6 | ARM_3 | ARM_2: /* Actually no CPU type defined. */
+ mach = bfd_mach_arm_4;
+ break;
+
+ case ARM_7: /* Also ARM_6. */
+ mach = bfd_mach_arm_3;
+ break;
+ }
+
+ /* Catch special cases. */
+ if (cpu_variant != (FPU_DEFAULT | CPU_DEFAULT))
+ {
+ 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_ARCH_V4) == ARM_ARCH_V4)
mach = bfd_mach_arm_4;
- break;
-
- case ARM_7: /* also ARM_6 */
- mach = bfd_mach_arm_3;
- break;
- }
-
- /* Catch special cases. */
- if (cpu_variant != (FPU_DEFAULT | CPU_DEFAULT))
- {
- 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_ARCH_V4) == ARM_ARCH_V4)
- mach = bfd_mach_arm_4;
- else if (cpu_variant & ARM_LONGMUL)
- mach = bfd_mach_arm_3M;
- }
-
- bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach);
- }
+ else if (cpu_variant & ARM_LONGMUL)
+ mach = bfd_mach_arm_3M;
+ }
+
+ bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach);
}
/* Turn an integer of n bytes (in val) into a stream of bytes appropriate
return (fixP->fx_where + fixP->fx_frag->fr_address) & ~3;
}
+#ifdef TE_WINCE
+ /* The pattern was adjusted to accomodate CE's off-by-one fixups,
+ so we un-adjust here to compensate for the accomodation. */
+ return fixP->fx_where + fixP->fx_frag->fr_address + 8;
+#else
return fixP->fx_where + fixP->fx_frag->fr_address;
+#endif
}
/* Round up a section size to the appropriate boundary. */
valueT
md_section_align (segment, size)
- segT segment;
+ segT segment ATTRIBUTE_UNUSED;
valueT size;
{
#ifdef OBJ_ELF
/* ARGSUSED */
symbolS *
md_undefined_symbol (name)
- char * name;
+ char * name ATTRIBUTE_UNUSED;
{
#ifdef OBJ_ELF
if (name[0] == '_' && name[1] == 'G'
return FAIL;
}
-static int
-arm_psr_parse (ccp)
- register char ** ccp;
-{
- char * start = * ccp;
- char c;
- char * p;
- CONST struct asm_psr * psr;
-
- p = start;
- c = *p++;
- while (isalpha (c) || c == '_')
- c = *p++;
-
- *--p = 0;
- psr = (CONST struct asm_psr *) hash_find (arm_psr_hsh, start);
- *p = c;
-
- if (psr)
- {
- *ccp = p;
- return psr->number;
- }
-
- return FAIL;
-}
-
int
md_apply_fix3 (fixP, val, seg)
fixS * fixP;
{
if (target_oabi
&& (fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH
+ || fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BLX
))
value = 0;
else
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 (! target_oabi)
- value = fixP->fx_offset;
+ value = fixP->fx_offset;
#endif
- value = (value >> 2) & 0x00ffffff;
- value = (value + (newval & 0x00ffffff)) & 0x00ffffff;
- newval = value | (newval & 0xff000000);
+
+ /* 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 instruciton itself, then we can compute the relocation for
+ ourselves and not have to bother the linker with it.
+
+ FIXME: The tests for OBJ_ELF and ! target_oabi are only here
+ because I have not worked out how to do this for OBJ_COFF or
+ target_oabi. */
+ if (! target_oabi
+ && 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 = * val;
+
+ /* 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)))
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("out of range branch"));
+
+ 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);
+
+#ifdef OBJ_ELF
+ if (! target_oabi)
+ value = fixP->fx_offset;
+#endif
+ hbit = (value >> 1) & 1;
+ value = (value >> 2) & 0x00ffffff;
+ value = (value + (newval & 0x00ffffff)) & 0x00ffffff;
+ newval = value | (newval & 0xfe000000) | (hbit << 24);
+ md_number_to_chars (buf, newval, INSN_SIZE);
+ }
+ break;
case BFD_RELOC_THUMB_PCREL_BRANCH9: /* conditional branch */
newval = md_chars_to_number (buf, THUMB_SIZE);
md_number_to_chars (buf, newval, THUMB_SIZE);
break;
+ case BFD_RELOC_THUMB_PCREL_BLX:
case BFD_RELOC_THUMB_PCREL_BRANCH23:
{
offsetT newval2;
format. */
arelent *
tc_gen_reloc (section, fixp)
- asection * section;
+ asection * section ATTRIBUTE_UNUSED;
fixS * fixp;
{
arelent * reloc;
}
case BFD_RELOC_ARM_PCREL_BRANCH:
+ case BFD_RELOC_ARM_PCREL_BLX:
case BFD_RELOC_RVA:
case BFD_RELOC_THUMB_PCREL_BRANCH9:
case BFD_RELOC_THUMB_PCREL_BRANCH12:
case BFD_RELOC_THUMB_PCREL_BRANCH23:
+ case BFD_RELOC_THUMB_PCREL_BLX:
case BFD_RELOC_VTABLE_ENTRY:
case BFD_RELOC_VTABLE_INHERIT:
code = fixp->fx_r_type;
int
md_estimate_size_before_relax (fragP, segtype)
- fragS * fragP;
- segT segtype;
+ fragS * fragP ATTRIBUTE_UNUSED;
+ segT segtype ATTRIBUTE_UNUSED;
{
as_fatal (_("md_estimate_size_before_relax\n"));
return 1;
keep trying with progressively smaller basic instructions until one
matches, or we run out of opcode. */
q = (p - str > LONGEST_INST) ? str + LONGEST_INST : p;
+
for (; q != str; q--)
{
c = *q;
*q = '\0';
+
opcode = (CONST struct asm_opcode *) hash_find (arm_ops_hsh, str);
*q = c;
if (opcode->comp_suffix)
{
if (*opcode->comp_suffix != '\0')
- as_bad (_("Opcode `%s' must have suffix from <%s>\n"),
+ as_bad (_("Opcode `%s' must have suffix from list: <%s>"),
str, opcode->comp_suffix);
else
/* Not a conditional instruction. */
else
cond_code = COND_ALWAYS;
-
/* Apply the conditional, or complain it's not allowed. */
if (opcode->comp_suffix && *opcode->comp_suffix == '\0')
{
else if (regnum != FAIL)
{
if (reg != regnum)
- as_warn (_("ignoring redefinition of register alias '%s'"), copy_of_str );
+ as_warn (_("ignoring redefinition of register alias '%s'"),
+ copy_of_str );
/* Do not warn about redefinitions to the same alias. */
}
* -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 architectures
+ * -m[arm]v[2345[t]] Arm architectures
* -mall All (except the ARM1)
* FP variants:
* -mfpa10, -mfpa11 FPA10 and 11 co-processor instructions
}
else if (streq (str, "thumb-interwork"))
{
- cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_THUMB | ARM_ARCH_V4;
+ if ((cpu_variant & ARM_THUMB) == 0)
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCH_V4T;
#if defined OBJ_COFF || defined OBJ_ELF
support_interwork = true;
#endif
case '8':
if (streq (str, "8") || streq (str, "810"))
- cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_8 | ARM_ARCH_V4 | 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_ARCH_V4 | 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_ARCH_V4 | 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_ARCH_V4 | 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_ARCH_V4 | ARM_LONGMUL | ARM_THUMB;
+ cpu_variant = (cpu_variant & ~ARM_ANY)
+ | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL | ARM_THUMB;
else
goto bad;
break;
if (streq (str, "strongarm")
|| streq (str, "strongarm110")
|| streq (str, "strongarm1100"))
- cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_8 | ARM_ARCH_V4 | ARM_LONGMUL;
+ cpu_variant = (cpu_variant & ~ARM_ANY)
+ | ARM_8 | ARM_ARCH_V4 | ARM_LONGMUL;
else
goto bad;
break;
case 'v':
- /* Select variant based on architecture rather than processor */
+ /* Select variant based on architecture rather than processor. */
switch (*++str)
{
case '2':
switch (*++str)
{
- case 'a': cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_3; break;
- case 0: cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_2; break;
- default: as_bad (_("Invalid architecture variant -m%s"), arg); break;
+ case 'a':
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_3;
+ break;
+ case 0:
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_2;
+ break;
+ default:
+ as_bad (_("Invalid architecture variant -m%s"), arg);
+ break;
}
break;
{
case 'm': cpu_variant |= ARM_LONGMUL; break;
case 0: break;
- default: as_bad (_("Invalid architecture variant -m%s"), arg); break;
+ default:
+ as_bad (_("Invalid architecture variant -m%s"), arg);
+ break;
}
break;
{
case 't': cpu_variant |= ARM_THUMB; break;
case 0: break;
- default: as_bad (_("Invalid architecture variant -m%s"), arg); break;
+ default:
+ as_bad (_("Invalid architecture variant -m%s"), arg);
+ break;
}
break;
switch (*++str)
{
case 't': cpu_variant |= ARM_THUMB; break;
- case 'e': cpu_variant |= ARM_EXT_V5E; break;
case 0: break;
- default: as_bad (_("Invalid architecture variant -m%s"), arg); break;
+ default:
+ as_bad (_("Invalid architecture variant -m%s"), arg);
+ break;
}
break;
-
default:
as_bad (_("Invalid architecture variant -m%s"), arg);
md_show_usage (fp)
FILE * fp;
{
- fprintf (fp,
-_("\
+ fprintf (fp, _("\
ARM Specific Assembler Options:\n\
-m[arm][<processor name>] select processor variant\n\
- -m[arm]v[2|2a|3|3m|4|4t|5]select architecture variant\n\
+ -m[arm]v[2|2a|3|3m|4|4t|5[t][e]] 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\
-mfpa10, -mfpa11 select floating point architecture\n\
-mfpe-old don't allow floating-point multiple instructions\n\
- -mno-fpu don't allow any floating-point instructions.\n"));
- fprintf (fp,
-_("\
+ -mno-fpu don't allow any floating-point instructions.\n\
-k generate PIC code.\n"));
#if defined OBJ_COFF || defined OBJ_ELF
- fprintf (fp,
-_("\
- -mapcs-32, -mapcs-26 specify which ARM Procedure Calling Standard to use\n"));
- fprintf (fp,
-_("\
- -mapcs-float floating point args are passed in FP regs\n"));
- fprintf (fp,
-_("\
+ fprintf (fp, _("\
+ -mapcs-32, -mapcs-26 specify which ARM Procedure Calling Standard to use\n\
+ -mapcs-float floating point args are passed in FP regs\n\
-mapcs-reentrant the code is position independent/reentrant\n"));
#endif
#ifdef OBJ_ELF
- fprintf (fp,
-_("\
+ fprintf (fp, _("\
-moabi support the old ELF ABI\n"));
#endif
#ifdef ARM_BI_ENDIAN
- fprintf (fp,
-_("\
+ fprintf (fp, _("\
-EB assemble code for a big endian cpu\n\
-EL assemble code for a little endian cpu\n"));
#endif
#endif
#ifdef OBJ_ELF
symbolS * sym;
- elf_symbol_type * elf_sym;
char bind;
for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
{
if (ARM_IS_THUMB (sym))
{
+ elf_symbol_type * elf_sym;
+
+ elf_sym = elf_symbol (symbol_get_bfdsym (sym));
+ bind = ELF_ST_BIND (elf_sym);
+
+ /* If it's a .thumb_func, declare it as so,
+ otherwise tag label as .code 16. */
if (THUMB_IS_FUNC (sym))
- {
- elf_sym = elf_symbol (symbol_get_bfdsym (sym));
- bind = ELF_ST_BIND (elf_sym);
- elf_sym->internal_elf_sym.st_info = ELF_ST_INFO (bind, STT_ARM_TFUNC);
- }
+ elf_sym->internal_elf_sym.st_info =
+ ELF_ST_INFO (bind, STT_ARM_TFUNC);
+ else
+ elf_sym->internal_elf_sym.st_info =
+ ELF_ST_INFO (bind, STT_ARM_16BIT);
}
}
#endif
if ( fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
|| fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY
|| fixp->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH
+ || fixp->fx_r_type == BFD_RELOC_ARM_PCREL_BLX
+ || fixp->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX
|| fixp->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23)
return 1;
{
char id[16];
char * ip;
- int i;
+ unsigned int i;
static struct
{
char * str;
int size = bfd_get_reloc_size (howto);
if (size > nbytes)
- as_bad ("%s relocations do not fit in %d bytes", howto->name, nbytes);
+ as_bad ("%s relocations do not fit in %d bytes",
+ howto->name, nbytes);
else
{
register char * p = frag_more ((int) nbytes);
}
while (*input_line_pointer++ == ',');
- input_line_pointer--; /* Put terminator back into stream. */
+ input_line_pointer--; /* Put terminator back into stream. */
demand_empty_rest_of_line ();
}