diff options
Diffstat (limited to 'gas')
54 files changed, 11501 insertions, 11522 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index ea056d4..b24c126 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,18 @@ +2005-05-17 Zack Weinberg <zack@codesourcery.com> + + * hash.c (hash_lookup): Add len parameter. All callers changed. + (hash_find_n): New interface. + * hash.h: Prototype hash_find_n. + * sb.c: Include as.h. + (scrub_from_sb, sb_to_scrub, scrub_position): New statics. + (sb_scrub_and_add_sb): New interface. + * sb.h: Prototype sb_scrub_and_add_sb. + * input-scrub.c (input_scrub_include_sb): Use sb_scrub_and_add_sb. + + * config/tc-arm.h (TC_FORCE_RELOCATION_LOCAL): Remove + reference to BFD_RELOC_ARM_GOT12 which is never generated. + * config/tc-arm.c: Rewrite, adding Thumb-2 support. + 2005-05-17 Daniel Jacobowitz <dan@codesourcery.com> * doc/Makefile.am (gasver.texi): Don't use $<. diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index 4ca8d49..a0804f3 100644 --- a/gas/config/tc-arm.c +++ b/gas/config/tc-arm.c @@ -17,7 +17,7 @@ GAS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License @@ -26,7 +26,7 @@ 02110-1301, USA. */ #include <string.h> -#define NO_RELOC 0 +#define NO_RELOC 0 #include "as.h" #include "safe-ctype.h" @@ -56,31 +56,31 @@ static struct { - symbolS * proc_start; - symbolS * table_entry; - symbolS * personality_routine; - int personality_index; + symbolS * proc_start; + symbolS * table_entry; + symbolS * personality_routine; + int personality_index; /* The segment containing the function. */ - segT saved_seg; - subsegT saved_subseg; + segT saved_seg; + subsegT saved_subseg; /* Opcodes generated from this function. */ unsigned char * opcodes; - int opcode_count; - int opcode_alloc; + int opcode_count; + int opcode_alloc; /* The number of bytes pushed to the stack. */ - offsetT frame_size; + offsetT frame_size; /* We don't add stack adjustment opcodes immediately so that we can merge multiple adjustments. We can also omit the final adjustment when using a frame pointer. */ - offsetT pending_offset; + offsetT pending_offset; /* These two fields are set by both unwind_movsp and unwind_setfp. They - hold the reg+offset to use when restoring sp from a frame pointer. */ - offsetT fp_offset; - int fp_reg; + hold the reg+offset to use when restoring sp from a frame pointer. */ + offsetT fp_offset; + int fp_reg; /* Nonzero if an unwind_setfp directive has been seen. */ - unsigned fp_used:1; + unsigned fp_used:1; /* Nonzero if the last opcode restores sp from fp_reg. */ - unsigned sp_restored:1; + unsigned sp_restored:1; } unwind; /* Bit N indicates that an R_ARM_NONE relocation has been output for @@ -97,7 +97,7 @@ enum arm_float_abi ARM_FLOAT_ABI_SOFT }; -/* Types of processor to assemble for. */ +/* Types of processor to assemble for. */ #define ARM_1 ARM_ARCH_V1 #define ARM_2 ARM_ARCH_V2 #define ARM_3 ARM_ARCH_V2S @@ -107,16 +107,16 @@ enum arm_float_abi #define ARM_8 ARM_ARCH_V4 #define ARM_9 ARM_ARCH_V4T #define ARM_STRONG ARM_ARCH_V4 -#define ARM_CPU_MASK 0x0000000f /* XXX? */ +#define ARM_CPU_MASK 0x0000000f /* XXX? */ #ifndef CPU_DEFAULT #if defined __XSCALE__ #define CPU_DEFAULT (ARM_ARCH_XSCALE) #else #if defined __thumb__ -#define CPU_DEFAULT (ARM_ARCH_V5T) +#define CPU_DEFAULT (ARM_ARCH_V5T) #else -#define CPU_DEFAULT ARM_ANY +#define CPU_DEFAULT ARM_ANY #endif #endif #endif @@ -139,17 +139,16 @@ enum arm_float_abi # endif #endif /* ifndef FPU_DEFAULT */ -#define streq(a, b) (strcmp (a, b) == 0) -#define skip_whitespace(str) while (*(str) == ' ') ++(str) +#define streq(a, b) (strcmp (a, b) == 0) static unsigned long cpu_variant; /* Flags stored in private area of BFD structure. */ -static int uses_apcs_26 = FALSE; -static int atpcs = FALSE; +static int uses_apcs_26 = FALSE; +static int atpcs = FALSE; static int support_interwork = FALSE; static int uses_apcs_float = FALSE; -static int pic_code = FALSE; +static int pic_code = FALSE; /* Variables that we set while parsing command-line options. Once all options have been read we re-process these values to set the real @@ -171,37 +170,8 @@ static int meabi_flags = EF_ARM_EABI_UNKNOWN; # endif #endif -/* This array holds the chars that always start a comment. If the - 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. */ -/* 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. */ -const char line_comment_chars[] = "#"; - -const char line_separator_chars[] = ";"; - -/* 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. */ -/* As in 0f12.456 */ -/* or 0d1.2345e12 */ - -const char FLT_CHARS[] = "rRsSfFdDxXeEpP"; - -/* Prefix characters that indicate the start of an immediate - value. */ -#define is_immediate_prefix(C) ((C) == '#' || (C) == '$') - #ifdef OBJ_ELF -/* Pre-defined "_GLOBAL_OFFSET_TABLE_" */ +/* Pre-defined "_GLOBAL_OFFSET_TABLE_" */ symbolS * GOT_symbol; #endif @@ -214,84 +184,63 @@ const int md_reloc_size = 8; instructions. */ static int thumb_mode = 0; -typedef struct arm_fix -{ - int thumb_mode; -} arm_fix_data; +/* If unified_syntax is true, we are processing the new unified + ARM/Thumb syntax. Important differences from the old ARM mode: + + - Immediate operands do not require a # prefix. + - Conditional affixes always appear at the end of the + instruction. (For backward compatibility, those instructions + that formerly had them in the middle, continue to accept them + there.) + - The IT instruction may appear, and if it does is validated + against subsequent conditional affixes. It does not generate + machine code. + + Important differences from the old Thumb mode: + + - Immediate operands do not require a # prefix. + - Most of the V6T2 instructions are only available in unified mode. + - The .N and .W suffixes are recognized and honored (it is an error + if they cannot be honored). + - All instructions set the flags if and only if they have an 's' affix. + - Conditional affixes may be used. They are validated against + preceding IT instructions. Unlike ARM mode, you cannot use a + conditional affix except in the scope of an IT instruction. */ + +static bfd_boolean unified_syntax = FALSE; struct arm_it { - const char * error; + const char * error; unsigned long instruction; - int size; + int size; + int size_req; + int cond; struct { bfd_reloc_code_real_type type; - expressionS exp; - int pc_rel; + expressionS exp; + int pc_rel; } reloc; -}; - -struct arm_it inst; -enum asm_shift_index -{ - SHIFT_LSL = 0, - SHIFT_LSR, - SHIFT_ASR, - SHIFT_ROR, - SHIFT_RRX -}; - -struct asm_shift_properties -{ - enum asm_shift_index index; - unsigned long bit_field; - unsigned int allows_0 : 1; - unsigned int allows_32 : 1; -}; - -static const struct asm_shift_properties shift_properties [] = -{ - { SHIFT_LSL, 0, 1, 0}, - { SHIFT_LSR, 0x20, 0, 1}, - { SHIFT_ASR, 0x40, 0, 1}, - { SHIFT_ROR, 0x60, 0, 0}, - { SHIFT_RRX, 0x60, 0, 0} -}; - -struct asm_shift_name -{ - const char * name; - const struct asm_shift_properties * properties; -}; - -static const struct asm_shift_name shift_names [] = -{ - { "asl", shift_properties + SHIFT_LSL }, - { "lsl", shift_properties + SHIFT_LSL }, - { "lsr", shift_properties + SHIFT_LSR }, - { "asr", shift_properties + SHIFT_ASR }, - { "ror", shift_properties + SHIFT_ROR }, - { "rrx", shift_properties + SHIFT_RRX }, - { "ASL", shift_properties + SHIFT_LSL }, - { "LSL", shift_properties + SHIFT_LSL }, - { "LSR", shift_properties + SHIFT_LSR }, - { "ASR", shift_properties + SHIFT_ASR }, - { "ROR", shift_properties + SHIFT_ROR }, - { "RRX", shift_properties + SHIFT_RRX } + 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) */ + } operands[6]; }; -/* Any kind of shift is accepted. */ -#define NO_SHIFT_RESTRICT 1 -/* The shift operand must be an immediate value, not a register. */ -#define SHIFT_IMMEDIATE 0 -/* The shift must be LSL or ASR and the operand must be an immediate. */ -#define SHIFT_LSL_OR_ASR_IMMEDIATE 2 -/* The shift must be ASR and the operand must be an immediate. */ -#define SHIFT_ASR_IMMEDIATE 3 -/* The shift must be LSL and the operand must be an immediate. */ -#define SHIFT_LSL_IMMEDIATE 4 +static struct arm_it inst; #define NUM_FLOAT_VALS 8 @@ -300,7 +249,7 @@ const char * fp_const[] = "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]; @@ -308,246 +257,46 @@ LITTLENUM_TYPE fp_values[NUM_FLOAT_VALS][MAX_LITTLENUMS]; #define FAIL (-1) #define SUCCESS (0) -/* Whether a Co-processor load/store operation accepts write-back forms. */ -#define CP_WB_OK 1 -#define CP_NO_WB 0 - #define SUFF_S 1 #define SUFF_D 2 #define SUFF_E 3 #define SUFF_P 4 -#define CP_T_X 0x00008000 -#define CP_T_Y 0x00400000 -#define CP_T_Pre 0x01000000 -#define CP_T_UD 0x00800000 -#define CP_T_WB 0x00200000 +#define CP_T_X 0x00008000 +#define CP_T_Y 0x00400000 -#define CONDS_BIT 0x00100000 -#define LOAD_BIT 0x00100000 +#define CONDS_BIT 0x00100000 +#define LOAD_BIT 0x00100000 #define DOUBLE_LOAD_FLAG 0x00000001 struct asm_cond { - const char * template; + const char * template; unsigned long value; }; -#define COND_ALWAYS 0xe0000000 -#define COND_MASK 0xf0000000 - -static const struct asm_cond conds[] = -{ - {"eq", 0x00000000}, - {"ne", 0x10000000}, - {"cs", 0x20000000}, {"hs", 0x20000000}, - {"cc", 0x30000000}, {"ul", 0x30000000}, {"lo", 0x30000000}, - {"mi", 0x40000000}, - {"pl", 0x50000000}, - {"vs", 0x60000000}, - {"vc", 0x70000000}, - {"hi", 0x80000000}, - {"ls", 0x90000000}, - {"ge", 0xa0000000}, - {"lt", 0xb0000000}, - {"gt", 0xc0000000}, - {"le", 0xd0000000}, - {"al", 0xe0000000}, - {"nv", 0xf0000000} -}; +#define COND_ALWAYS 0xE struct asm_psr { const char *template; - bfd_boolean cpsr; unsigned long field; }; /* The bit that distinguishes CPSR and SPSR. */ #define SPSR_BIT (1 << 22) -/* How many bits to shift the PSR_xxx bits up by. */ -#define PSR_SHIFT 16 +/* The individual PSR flag bits. */ +#define PSR_c (1 << 16) +#define PSR_x (1 << 17) +#define PSR_s (1 << 18) +#define PSR_f (1 << 19) -#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[] = -{ - {"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}, - /* Combinations of flags. */ - {"CPSR_fs", TRUE, PSR_f | PSR_s}, - {"CPSR_fx", TRUE, PSR_f | PSR_x}, - {"CPSR_fc", TRUE, PSR_f | PSR_c}, - {"CPSR_sf", TRUE, PSR_s | PSR_f}, - {"CPSR_sx", TRUE, PSR_s | PSR_x}, - {"CPSR_sc", TRUE, PSR_s | PSR_c}, - {"CPSR_xf", TRUE, PSR_x | PSR_f}, - {"CPSR_xs", TRUE, PSR_x | PSR_s}, - {"CPSR_xc", TRUE, PSR_x | PSR_c}, - {"CPSR_cf", TRUE, PSR_c | PSR_f}, - {"CPSR_cs", TRUE, PSR_c | PSR_s}, - {"CPSR_cx", TRUE, PSR_c | PSR_x}, - {"CPSR_fsx", TRUE, PSR_f | PSR_s | PSR_x}, - {"CPSR_fsc", TRUE, PSR_f | PSR_s | PSR_c}, - {"CPSR_fxs", TRUE, PSR_f | PSR_x | PSR_s}, - {"CPSR_fxc", TRUE, PSR_f | PSR_x | PSR_c}, - {"CPSR_fcs", TRUE, PSR_f | PSR_c | PSR_s}, - {"CPSR_fcx", TRUE, PSR_f | PSR_c | PSR_x}, - {"CPSR_sfx", TRUE, PSR_s | PSR_f | PSR_x}, - {"CPSR_sfc", TRUE, PSR_s | PSR_f | PSR_c}, - {"CPSR_sxf", TRUE, PSR_s | PSR_x | PSR_f}, - {"CPSR_sxc", TRUE, PSR_s | PSR_x | PSR_c}, - {"CPSR_scf", TRUE, PSR_s | PSR_c | PSR_f}, - {"CPSR_scx", TRUE, PSR_s | PSR_c | PSR_x}, - {"CPSR_xfs", TRUE, PSR_x | PSR_f | PSR_s}, - {"CPSR_xfc", TRUE, PSR_x | PSR_f | PSR_c}, - {"CPSR_xsf", TRUE, PSR_x | PSR_s | PSR_f}, - {"CPSR_xsc", TRUE, PSR_x | PSR_s | PSR_c}, - {"CPSR_xcf", TRUE, PSR_x | PSR_c | PSR_f}, - {"CPSR_xcs", TRUE, PSR_x | PSR_c | PSR_s}, - {"CPSR_cfs", TRUE, PSR_c | PSR_f | PSR_s}, - {"CPSR_cfx", TRUE, PSR_c | PSR_f | PSR_x}, - {"CPSR_csf", TRUE, PSR_c | PSR_s | PSR_f}, - {"CPSR_csx", TRUE, PSR_c | PSR_s | PSR_x}, - {"CPSR_cxf", TRUE, PSR_c | PSR_x | PSR_f}, - {"CPSR_cxs", TRUE, PSR_c | PSR_x | PSR_s}, - {"CPSR_fsxc", TRUE, PSR_f | PSR_s | PSR_x | PSR_c}, - {"CPSR_fscx", TRUE, PSR_f | PSR_s | PSR_c | PSR_x}, - {"CPSR_fxsc", TRUE, PSR_f | PSR_x | PSR_s | PSR_c}, - {"CPSR_fxcs", TRUE, PSR_f | PSR_x | PSR_c | PSR_s}, - {"CPSR_fcsx", TRUE, PSR_f | PSR_c | PSR_s | PSR_x}, - {"CPSR_fcxs", TRUE, PSR_f | PSR_c | PSR_x | PSR_s}, - {"CPSR_sfxc", TRUE, PSR_s | PSR_f | PSR_x | PSR_c}, - {"CPSR_sfcx", TRUE, PSR_s | PSR_f | PSR_c | PSR_x}, - {"CPSR_sxfc", TRUE, PSR_s | PSR_x | PSR_f | PSR_c}, - {"CPSR_sxcf", TRUE, PSR_s | PSR_x | PSR_c | PSR_f}, - {"CPSR_scfx", TRUE, PSR_s | PSR_c | PSR_f | PSR_x}, - {"CPSR_scxf", TRUE, PSR_s | PSR_c | PSR_x | PSR_f}, - {"CPSR_xfsc", TRUE, PSR_x | PSR_f | PSR_s | PSR_c}, - {"CPSR_xfcs", TRUE, PSR_x | PSR_f | PSR_c | PSR_s}, - {"CPSR_xsfc", TRUE, PSR_x | PSR_s | PSR_f | PSR_c}, - {"CPSR_xscf", TRUE, PSR_x | PSR_s | PSR_c | PSR_f}, - {"CPSR_xcfs", TRUE, PSR_x | PSR_c | PSR_f | PSR_s}, - {"CPSR_xcsf", TRUE, PSR_x | PSR_c | PSR_s | PSR_f}, - {"CPSR_cfsx", TRUE, PSR_c | PSR_f | PSR_s | PSR_x}, - {"CPSR_cfxs", TRUE, PSR_c | PSR_f | PSR_x | PSR_s}, - {"CPSR_csfx", TRUE, PSR_c | PSR_s | PSR_f | PSR_x}, - {"CPSR_csxf", TRUE, PSR_c | PSR_s | PSR_x | PSR_f}, - {"CPSR_cxfs", TRUE, PSR_c | PSR_x | PSR_f | PSR_s}, - {"CPSR_cxsf", TRUE, PSR_c | PSR_x | PSR_s | PSR_f}, - {"SPSR_fs", FALSE, PSR_f | PSR_s}, - {"SPSR_fx", FALSE, PSR_f | PSR_x}, - {"SPSR_fc", FALSE, PSR_f | PSR_c}, - {"SPSR_sf", FALSE, PSR_s | PSR_f}, - {"SPSR_sx", FALSE, PSR_s | PSR_x}, - {"SPSR_sc", FALSE, PSR_s | PSR_c}, - {"SPSR_xf", FALSE, PSR_x | PSR_f}, - {"SPSR_xs", FALSE, PSR_x | PSR_s}, - {"SPSR_xc", FALSE, PSR_x | PSR_c}, - {"SPSR_cf", FALSE, PSR_c | PSR_f}, - {"SPSR_cs", FALSE, PSR_c | PSR_s}, - {"SPSR_cx", FALSE, PSR_c | PSR_x}, - {"SPSR_fsx", FALSE, PSR_f | PSR_s | PSR_x}, - {"SPSR_fsc", FALSE, PSR_f | PSR_s | PSR_c}, - {"SPSR_fxs", FALSE, PSR_f | PSR_x | PSR_s}, - {"SPSR_fxc", FALSE, PSR_f | PSR_x | PSR_c}, - {"SPSR_fcs", FALSE, PSR_f | PSR_c | PSR_s}, - {"SPSR_fcx", FALSE, PSR_f | PSR_c | PSR_x}, - {"SPSR_sfx", FALSE, PSR_s | PSR_f | PSR_x}, - {"SPSR_sfc", FALSE, PSR_s | PSR_f | PSR_c}, - {"SPSR_sxf", FALSE, PSR_s | PSR_x | PSR_f}, - {"SPSR_sxc", FALSE, PSR_s | PSR_x | PSR_c}, - {"SPSR_scf", FALSE, PSR_s | PSR_c | PSR_f}, - {"SPSR_scx", FALSE, PSR_s | PSR_c | PSR_x}, - {"SPSR_xfs", FALSE, PSR_x | PSR_f | PSR_s}, - {"SPSR_xfc", FALSE, PSR_x | PSR_f | PSR_c}, - {"SPSR_xsf", FALSE, PSR_x | PSR_s | PSR_f}, - {"SPSR_xsc", FALSE, PSR_x | PSR_s | PSR_c}, - {"SPSR_xcf", FALSE, PSR_x | PSR_c | PSR_f}, - {"SPSR_xcs", FALSE, PSR_x | PSR_c | PSR_s}, - {"SPSR_cfs", FALSE, PSR_c | PSR_f | PSR_s}, - {"SPSR_cfx", FALSE, PSR_c | PSR_f | PSR_x}, - {"SPSR_csf", FALSE, PSR_c | PSR_s | PSR_f}, - {"SPSR_csx", FALSE, PSR_c | PSR_s | PSR_x}, - {"SPSR_cxf", FALSE, PSR_c | PSR_x | PSR_f}, - {"SPSR_cxs", FALSE, PSR_c | PSR_x | PSR_s}, - {"SPSR_fsxc", FALSE, PSR_f | PSR_s | PSR_x | PSR_c}, - {"SPSR_fscx", FALSE, PSR_f | PSR_s | PSR_c | PSR_x}, - {"SPSR_fxsc", FALSE, PSR_f | PSR_x | PSR_s | PSR_c}, - {"SPSR_fxcs", FALSE, PSR_f | PSR_x | PSR_c | PSR_s}, - {"SPSR_fcsx", FALSE, PSR_f | PSR_c | PSR_s | PSR_x}, - {"SPSR_fcxs", FALSE, PSR_f | PSR_c | PSR_x | PSR_s}, - {"SPSR_sfxc", FALSE, PSR_s | PSR_f | PSR_x | PSR_c}, - {"SPSR_sfcx", FALSE, PSR_s | PSR_f | PSR_c | PSR_x}, - {"SPSR_sxfc", FALSE, PSR_s | PSR_x | PSR_f | PSR_c}, - {"SPSR_sxcf", FALSE, PSR_s | PSR_x | PSR_c | PSR_f}, - {"SPSR_scfx", FALSE, PSR_s | PSR_c | PSR_f | PSR_x}, - {"SPSR_scxf", FALSE, PSR_s | PSR_c | PSR_x | PSR_f}, - {"SPSR_xfsc", FALSE, PSR_x | PSR_f | PSR_s | PSR_c}, - {"SPSR_xfcs", FALSE, PSR_x | PSR_f | PSR_c | PSR_s}, - {"SPSR_xsfc", FALSE, PSR_x | PSR_s | PSR_f | PSR_c}, - {"SPSR_xscf", FALSE, PSR_x | PSR_s | PSR_c | PSR_f}, - {"SPSR_xcfs", FALSE, PSR_x | PSR_c | PSR_f | PSR_s}, - {"SPSR_xcsf", FALSE, PSR_x | PSR_c | PSR_s | PSR_f}, - {"SPSR_cfsx", FALSE, PSR_c | PSR_f | PSR_s | PSR_x}, - {"SPSR_cfxs", FALSE, PSR_c | PSR_f | PSR_x | PSR_s}, - {"SPSR_csfx", FALSE, PSR_c | PSR_s | PSR_f | PSR_x}, - {"SPSR_csxf", FALSE, PSR_c | PSR_s | PSR_x | PSR_f}, - {"SPSR_cxfs", FALSE, PSR_c | PSR_x | PSR_f | PSR_s}, - {"SPSR_cxsf", FALSE, PSR_c | PSR_x | PSR_s | PSR_f}, -}; - -enum wreg_type - { - IWMMXT_REG_WR = 0, - IWMMXT_REG_WC = 1, - IWMMXT_REG_WR_OR_WC = 2, - IWMMXT_REG_WCG - }; - -enum iwmmxt_insn_type -{ - check_rd, - check_wr, - check_wrwr, - check_wrwrwr, - check_wrwrwcg, - check_tbcst, - check_tmovmsk, - check_tmia, - check_tmcrr, - check_tmrrc, - check_tmcr, - check_tmrc, - check_tinsr, - check_textrc, - check_waligni, - check_textrm, - check_wshufh -}; - -enum vfp_dp_reg_pos +struct reloc_entry { - VFP_REG_Dd, VFP_REG_Dm, VFP_REG_Dn + char *name; + bfd_reloc_code_real_type reloc; }; enum vfp_sp_reg_pos @@ -560,291 +309,101 @@ enum vfp_ldstm_type VFP_LDSTMIA, VFP_LDSTMDB, VFP_LDSTMIAX, VFP_LDSTMDBX }; -/* VFP system registers. */ -struct vfp_reg -{ - const char *name; - unsigned long regno; -}; - -static const struct vfp_reg vfp_regs[] = +/* ARM register categories. This includes coprocessor numbers and various + architecture extensions' registers. */ +enum arm_reg_type { - {"fpsid", 0x00000000}, - {"FPSID", 0x00000000}, - {"fpscr", 0x00010000}, - {"FPSCR", 0x00010000}, - {"fpexc", 0x00080000}, - {"FPEXC", 0x00080000} + REG_TYPE_RN, + REG_TYPE_CP, + REG_TYPE_CN, + REG_TYPE_FN, + REG_TYPE_VFS, + REG_TYPE_VFD, + REG_TYPE_VFC, + REG_TYPE_MVF, + REG_TYPE_MVD, + REG_TYPE_MVFX, + REG_TYPE_MVDX, + REG_TYPE_MVAX, + REG_TYPE_DSPSC, + REG_TYPE_MMXWR, + REG_TYPE_MMXWC, + REG_TYPE_MMXWCG, + REG_TYPE_XSCALE, }; /* Structure for a hash table entry for a register. */ struct reg_entry { - const char * name; - int number; - bfd_boolean builtin; -}; - -/* Some well known registers that we refer to directly elsewhere. */ -#define REG_SP 13 -#define REG_LR 14 -#define REG_PC 15 - -#define wr_register(reg) ((reg ^ WR_PREFIX) >= 0 && (reg ^ WR_PREFIX) <= 15) -#define wc_register(reg) ((reg ^ WC_PREFIX) >= 0 && (reg ^ WC_PREFIX) <= 15) -#define wcg_register(reg) ((reg ^ WC_PREFIX) >= 8 && (reg ^ WC_PREFIX) <= 11) - -/* These are the standard names. Users can add aliases with .req. - and delete them with .unreq. */ - -/* Integer Register Numbers. */ -static const struct reg_entry rn_table[] = -{ - {"r0", 0, TRUE}, {"r1", 1, TRUE}, {"r2", 2, TRUE}, {"r3", 3, TRUE}, - {"r4", 4, TRUE}, {"r5", 5, TRUE}, {"r6", 6, TRUE}, {"r7", 7, TRUE}, - {"r8", 8, TRUE}, {"r9", 9, TRUE}, {"r10", 10, TRUE}, {"r11", 11, TRUE}, - {"r12", 12, TRUE}, {"r13", REG_SP, TRUE}, {"r14", REG_LR, TRUE}, {"r15", REG_PC, TRUE}, - /* ATPCS Synonyms. */ - {"a1", 0, TRUE}, {"a2", 1, TRUE}, {"a3", 2, TRUE}, {"a4", 3, TRUE}, - {"v1", 4, TRUE}, {"v2", 5, TRUE}, {"v3", 6, TRUE}, {"v4", 7, TRUE}, - {"v5", 8, TRUE}, {"v6", 9, TRUE}, {"v7", 10, TRUE}, {"v8", 11, TRUE}, - /* Well-known aliases. */ - {"wr", 7, TRUE}, {"sb", 9, TRUE}, {"sl", 10, TRUE}, {"fp", 11, TRUE}, - {"ip", 12, TRUE}, {"sp", REG_SP, TRUE}, {"lr", REG_LR, TRUE}, {"pc", REG_PC, TRUE}, - {NULL, 0, TRUE} -}; - -#define WR_PREFIX 0x200 -#define WC_PREFIX 0x400 - -static const struct reg_entry iwmmxt_table[] = -{ - /* Intel Wireless MMX technology register names. */ - { "wr0", 0x0 | WR_PREFIX, TRUE}, {"wr1", 0x1 | WR_PREFIX, TRUE}, - { "wr2", 0x2 | WR_PREFIX, TRUE}, {"wr3", 0x3 | WR_PREFIX, TRUE}, - { "wr4", 0x4 | WR_PREFIX, TRUE}, {"wr5", 0x5 | WR_PREFIX, TRUE}, - { "wr6", 0x6 | WR_PREFIX, TRUE}, {"wr7", 0x7 | WR_PREFIX, TRUE}, - { "wr8", 0x8 | WR_PREFIX, TRUE}, {"wr9", 0x9 | WR_PREFIX, TRUE}, - { "wr10", 0xa | WR_PREFIX, TRUE}, {"wr11", 0xb | WR_PREFIX, TRUE}, - { "wr12", 0xc | WR_PREFIX, TRUE}, {"wr13", 0xd | WR_PREFIX, TRUE}, - { "wr14", 0xe | WR_PREFIX, TRUE}, {"wr15", 0xf | WR_PREFIX, TRUE}, - { "wcid", 0x0 | WC_PREFIX, TRUE}, {"wcon", 0x1 | WC_PREFIX, TRUE}, - {"wcssf", 0x2 | WC_PREFIX, TRUE}, {"wcasf", 0x3 | WC_PREFIX, TRUE}, - {"wcgr0", 0x8 | WC_PREFIX, TRUE}, {"wcgr1", 0x9 | WC_PREFIX, TRUE}, - {"wcgr2", 0xa | WC_PREFIX, TRUE}, {"wcgr3", 0xb | WC_PREFIX, TRUE}, - - { "wR0", 0x0 | WR_PREFIX, TRUE}, {"wR1", 0x1 | WR_PREFIX, TRUE}, - { "wR2", 0x2 | WR_PREFIX, TRUE}, {"wR3", 0x3 | WR_PREFIX, TRUE}, - { "wR4", 0x4 | WR_PREFIX, TRUE}, {"wR5", 0x5 | WR_PREFIX, TRUE}, - { "wR6", 0x6 | WR_PREFIX, TRUE}, {"wR7", 0x7 | WR_PREFIX, TRUE}, - { "wR8", 0x8 | WR_PREFIX, TRUE}, {"wR9", 0x9 | WR_PREFIX, TRUE}, - { "wR10", 0xa | WR_PREFIX, TRUE}, {"wR11", 0xb | WR_PREFIX, TRUE}, - { "wR12", 0xc | WR_PREFIX, TRUE}, {"wR13", 0xd | WR_PREFIX, TRUE}, - { "wR14", 0xe | WR_PREFIX, TRUE}, {"wR15", 0xf | WR_PREFIX, TRUE}, - { "wCID", 0x0 | WC_PREFIX, TRUE}, {"wCon", 0x1 | WC_PREFIX, TRUE}, - {"wCSSF", 0x2 | WC_PREFIX, TRUE}, {"wCASF", 0x3 | WC_PREFIX, TRUE}, - {"wCGR0", 0x8 | WC_PREFIX, TRUE}, {"wCGR1", 0x9 | WC_PREFIX, TRUE}, - {"wCGR2", 0xa | WC_PREFIX, TRUE}, {"wCGR3", 0xb | WC_PREFIX, TRUE}, - {NULL, 0, TRUE} -}; - -/* Co-processor Numbers. */ -static const struct reg_entry cp_table[] = -{ - {"p0", 0, TRUE}, {"p1", 1, TRUE}, {"p2", 2, TRUE}, {"p3", 3, TRUE}, - {"p4", 4, TRUE}, {"p5", 5, TRUE}, {"p6", 6, TRUE}, {"p7", 7, TRUE}, - {"p8", 8, TRUE}, {"p9", 9, TRUE}, {"p10", 10, TRUE}, {"p11", 11, TRUE}, - {"p12", 12, TRUE}, {"p13", 13, TRUE}, {"p14", 14, TRUE}, {"p15", 15, TRUE}, - {NULL, 0, TRUE} -}; - -/* Co-processor Register Numbers. */ -static const struct reg_entry cn_table[] = -{ - {"c0", 0, TRUE}, {"c1", 1, TRUE}, {"c2", 2, TRUE}, {"c3", 3, TRUE}, - {"c4", 4, TRUE}, {"c5", 5, TRUE}, {"c6", 6, TRUE}, {"c7", 7, TRUE}, - {"c8", 8, TRUE}, {"c9", 9, TRUE}, {"c10", 10, TRUE}, {"c11", 11, TRUE}, - {"c12", 12, TRUE}, {"c13", 13, TRUE}, {"c14", 14, TRUE}, {"c15", 15, TRUE}, - /* Not really valid, but kept for back-wards compatibility. */ - {"cr0", 0, TRUE}, {"cr1", 1, TRUE}, {"cr2", 2, TRUE}, {"cr3", 3, TRUE}, - {"cr4", 4, TRUE}, {"cr5", 5, TRUE}, {"cr6", 6, TRUE}, {"cr7", 7, TRUE}, - {"cr8", 8, TRUE}, {"cr9", 9, TRUE}, {"cr10", 10, TRUE}, {"cr11", 11, TRUE}, - {"cr12", 12, TRUE}, {"cr13", 13, TRUE}, {"cr14", 14, TRUE}, {"cr15", 15, TRUE}, - {NULL, 0, TRUE} -}; - -/* FPA Registers. */ -static const struct reg_entry fn_table[] = -{ - {"f0", 0, TRUE}, {"f1", 1, TRUE}, {"f2", 2, TRUE}, {"f3", 3, TRUE}, - {"f4", 4, TRUE}, {"f5", 5, TRUE}, {"f6", 6, TRUE}, {"f7", 7, TRUE}, - {NULL, 0, TRUE} -}; - -/* VFP SP Registers. */ -static const struct reg_entry sn_table[] = -{ - {"s0", 0, TRUE}, {"s1", 1, TRUE}, {"s2", 2, TRUE}, {"s3", 3, TRUE}, - {"s4", 4, TRUE}, {"s5", 5, TRUE}, {"s6", 6, TRUE}, {"s7", 7, TRUE}, - {"s8", 8, TRUE}, {"s9", 9, TRUE}, {"s10", 10, TRUE}, {"s11", 11, TRUE}, - {"s12", 12, TRUE}, {"s13", 13, TRUE}, {"s14", 14, TRUE}, {"s15", 15, TRUE}, - {"s16", 16, TRUE}, {"s17", 17, TRUE}, {"s18", 18, TRUE}, {"s19", 19, TRUE}, - {"s20", 20, TRUE}, {"s21", 21, TRUE}, {"s22", 22, TRUE}, {"s23", 23, TRUE}, - {"s24", 24, TRUE}, {"s25", 25, TRUE}, {"s26", 26, TRUE}, {"s27", 27, TRUE}, - {"s28", 28, TRUE}, {"s29", 29, TRUE}, {"s30", 30, TRUE}, {"s31", 31, TRUE}, - {NULL, 0, TRUE} -}; - -/* VFP DP Registers. */ -static const struct reg_entry dn_table[] = -{ - {"d0", 0, TRUE}, {"d1", 1, TRUE}, {"d2", 2, TRUE}, {"d3", 3, TRUE}, - {"d4", 4, TRUE}, {"d5", 5, TRUE}, {"d6", 6, TRUE}, {"d7", 7, TRUE}, - {"d8", 8, TRUE}, {"d9", 9, TRUE}, {"d10", 10, TRUE}, {"d11", 11, TRUE}, - {"d12", 12, TRUE}, {"d13", 13, TRUE}, {"d14", 14, TRUE}, {"d15", 15, TRUE}, - {NULL, 0, TRUE} -}; - -/* Maverick DSP coprocessor registers. */ -static const struct reg_entry mav_mvf_table[] = -{ - {"mvf0", 0, TRUE}, {"mvf1", 1, TRUE}, {"mvf2", 2, TRUE}, {"mvf3", 3, TRUE}, - {"mvf4", 4, TRUE}, {"mvf5", 5, TRUE}, {"mvf6", 6, TRUE}, {"mvf7", 7, TRUE}, - {"mvf8", 8, TRUE}, {"mvf9", 9, TRUE}, {"mvf10", 10, TRUE}, {"mvf11", 11, TRUE}, - {"mvf12", 12, TRUE}, {"mvf13", 13, TRUE}, {"mvf14", 14, TRUE}, {"mvf15", 15, TRUE}, - {NULL, 0, TRUE} -}; - -static const struct reg_entry mav_mvd_table[] = -{ - {"mvd0", 0, TRUE}, {"mvd1", 1, TRUE}, {"mvd2", 2, TRUE}, {"mvd3", 3, TRUE}, - {"mvd4", 4, TRUE}, {"mvd5", 5, TRUE}, {"mvd6", 6, TRUE}, {"mvd7", 7, TRUE}, - {"mvd8", 8, TRUE}, {"mvd9", 9, TRUE}, {"mvd10", 10, TRUE}, {"mvd11", 11, TRUE}, - {"mvd12", 12, TRUE}, {"mvd13", 13, TRUE}, {"mvd14", 14, TRUE}, {"mvd15", 15, TRUE}, - {NULL, 0, TRUE} + const char *name; + unsigned char number; + unsigned char type; + unsigned char builtin; }; -static const struct reg_entry mav_mvfx_table[] = -{ - {"mvfx0", 0, TRUE}, {"mvfx1", 1, TRUE}, {"mvfx2", 2, TRUE}, {"mvfx3", 3, TRUE}, - {"mvfx4", 4, TRUE}, {"mvfx5", 5, TRUE}, {"mvfx6", 6, TRUE}, {"mvfx7", 7, TRUE}, - {"mvfx8", 8, TRUE}, {"mvfx9", 9, TRUE}, {"mvfx10", 10, TRUE}, {"mvfx11", 11, TRUE}, - {"mvfx12", 12, TRUE}, {"mvfx13", 13, TRUE}, {"mvfx14", 14, TRUE}, {"mvfx15", 15, TRUE}, - {NULL, 0, TRUE} -}; - -static const struct reg_entry mav_mvdx_table[] = -{ - {"mvdx0", 0, TRUE}, {"mvdx1", 1, TRUE}, {"mvdx2", 2, TRUE}, {"mvdx3", 3, TRUE}, - {"mvdx4", 4, TRUE}, {"mvdx5", 5, TRUE}, {"mvdx6", 6, TRUE}, {"mvdx7", 7, TRUE}, - {"mvdx8", 8, TRUE}, {"mvdx9", 9, TRUE}, {"mvdx10", 10, TRUE}, {"mvdx11", 11, TRUE}, - {"mvdx12", 12, TRUE}, {"mvdx13", 13, TRUE}, {"mvdx14", 14, TRUE}, {"mvdx15", 15, TRUE}, - {NULL, 0, TRUE} +/* Diagnostics used when we don't get a register of the expected type. */ +const char *const reg_expected_msgs[] = +{ + N_("ARM register expected"), + N_("bad or missing co-processor number"), + N_("co-processor register expected"), + N_("FPA register expected"), + N_("VFP single precision register expected"), + N_("VFP double precision register expected"), + N_("VFP system register expected"), + N_("Maverick MVF register expected"), + N_("Maverick MVD register expected"), + N_("Maverick MVFX register expected"), + N_("Maverick MVDX register expected"), + N_("Maverick MVAX register expected"), + N_("Maverick DSPSC register expected"), + N_("iWMMXt data register expected"), + N_("iWMMXt control register expected"), + N_("iWMMXt scalar register expected"), + N_("XScale accumulator register expected"), }; -static const struct reg_entry mav_mvax_table[] = -{ - {"mvax0", 0, TRUE}, {"mvax1", 1, TRUE}, {"mvax2", 2, TRUE}, {"mvax3", 3, TRUE}, - {NULL, 0, TRUE} -}; - -static const struct reg_entry mav_dspsc_table[] = -{ - {"dspsc", 0, TRUE}, - {NULL, 0, TRUE} -}; - -struct reg_map -{ - const struct reg_entry * names; - int max_regno; - struct hash_control * htab; - const char * expected; -}; - -struct reg_map all_reg_maps[] = -{ - {rn_table, 15, NULL, N_("ARM register expected")}, - {cp_table, 15, NULL, N_("bad or missing co-processor number")}, - {cn_table, 15, NULL, N_("co-processor register expected")}, - {fn_table, 7, NULL, N_("FPA register expected")}, - {sn_table, 31, NULL, N_("VFP single precision register expected")}, - {dn_table, 15, NULL, N_("VFP double precision register expected")}, - {mav_mvf_table, 15, NULL, N_("Maverick MVF register expected")}, - {mav_mvd_table, 15, NULL, N_("Maverick MVD register expected")}, - {mav_mvfx_table, 15, NULL, N_("Maverick MVFX register expected")}, - {mav_mvdx_table, 15, NULL, N_("Maverick MVDX register expected")}, - {mav_mvax_table, 3, NULL, N_("Maverick MVAX register expected")}, - {mav_dspsc_table, 0, NULL, N_("Maverick DSPSC register expected")}, - {iwmmxt_table, 23, NULL, N_("Intel Wireless MMX technology register expected")}, -}; - -/* Enumeration matching entries in table above. */ -enum arm_reg_type -{ - REG_TYPE_RN = 0, -#define REG_TYPE_FIRST REG_TYPE_RN - REG_TYPE_CP = 1, - REG_TYPE_CN = 2, - REG_TYPE_FN = 3, - REG_TYPE_SN = 4, - REG_TYPE_DN = 5, - REG_TYPE_MVF = 6, - REG_TYPE_MVD = 7, - REG_TYPE_MVFX = 8, - REG_TYPE_MVDX = 9, - REG_TYPE_MVAX = 10, - REG_TYPE_DSPSC = 11, - REG_TYPE_IWMMXT = 12, - - REG_TYPE_MAX = 13 -}; +/* Some well known registers that we refer to directly elsewhere. */ +#define REG_SP 13 +#define REG_LR 14 +#define REG_PC 15 /* ARM instructions take 4bytes in the object file, Thumb instructions take 2: */ -#define INSN_SIZE 4 - -/* "INSN<cond> X,Y" where X:bit12, Y:bit16. */ -#define MAV_MODE1 0x100c - -/* "INSN<cond> X,Y" where X:bit16, Y:bit12. */ -#define MAV_MODE2 0x0c10 - -/* "INSN<cond> X,Y" where X:bit12, Y:bit16. */ -#define MAV_MODE3 0x100c - -/* "INSN<cond> X,Y,Z" where X:16, Y:0, Z:12. */ -#define MAV_MODE4 0x0c0010 - -/* "INSN<cond> X,Y,Z" where X:12, Y:16, Z:0. */ -#define MAV_MODE5 0x00100c - -/* "INSN<cond> W,X,Y,Z" where W:5, X:12, Y:16, Z:0. */ -#define MAV_MODE6 0x00100c05 +#define INSN_SIZE 4 struct asm_opcode { /* Basic string to match. */ - const char * template; + const char *template; + + /* Parameters to instruction. */ + unsigned char operands[8]; + + /* Conditional tag - see opcode_lookup. */ + unsigned int tag : 4; /* Basic instruction code. */ - unsigned long value; + unsigned int avalue : 28; - /* Offset into the template where the condition code (if any) will be. - If zero, then the instruction is never conditional. */ - unsigned cond_offset; + /* Thumb-format instruction code. */ + unsigned int tvalue; /* Which architecture variant provides this instruction. */ - unsigned long variant; + unsigned long avariant; + unsigned long tvariant; + + /* Function to call to encode instruction in ARM format. */ + void (* aencode) (void); - /* Function to call to parse args. */ - void (* parms) (char *); + /* Function to call to encode instruction in Thumb format. */ + void (* tencode) (void); }; /* Defines for various bits that we will want to toggle. */ #define INST_IMMEDIATE 0x02000000 #define OFFSET_REG 0x02000000 -#define HWOFFSET_IMM 0x00400000 +#define HWOFFSET_IMM 0x00400000 #define SHIFT_BY_REG 0x00000010 #define PRE_INDEX 0x01000000 #define INDEX_UP 0x00800000 @@ -895,7 +454,8 @@ struct asm_opcode #define T_OPCODE_ASR_R 0x4100 #define T_OPCODE_LSL_R 0x4080 -#define T_OPCODE_LSR_R 0x40c0 +#define T_OPCODE_LSR_R 0x40c0 +#define T_OPCODE_ROR_R 0x41c0 #define T_OPCODE_ASR_I 0x1000 #define T_OPCODE_LSL_I 0x0000 #define T_OPCODE_LSR_I 0x0800 @@ -928,58 +488,22 @@ struct asm_opcode #define T_OPCODE_BRANCH 0xe7fe #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_H1 0x0080 -#define THUMB_H2 0x0040 - -#define THUMB_ASR 0 -#define THUMB_LSL 1 -#define THUMB_LSR 2 - -#define THUMB_MOVE 0 -#define THUMB_COMPARE 1 -#define THUMB_CPY 2 - -#define THUMB_LOAD 0 -#define THUMB_STORE 1 - #define THUMB_PP_PC_LR 0x0100 - -/* These three are used for immediate shifts, do not alter. */ -#define THUMB_WORD 2 -#define THUMB_HALFWORD 1 -#define THUMB_BYTE 0 - -struct thumb_opcode -{ - /* Basic string to match. */ - const char * template; - - /* Basic instruction code. */ - unsigned long value; - - int size; - - /* Which CPU variants this exists for. */ - unsigned long variant; - - /* Function to call to parse args. */ - void (* parms) (char *); -}; - -#define BAD_ARGS _("bad arguments to instruction") -#define BAD_PC _("r15 not allowed here") -#define BAD_COND _("instruction is not conditional") -#define ERR_NO_ACCUM _("acc0 expected") - -static struct hash_control * arm_ops_hsh = NULL; -static struct hash_control * arm_tops_hsh = NULL; -static struct hash_control * arm_cond_hsh = NULL; -static struct hash_control * arm_shift_hsh = NULL; -static struct hash_control * arm_psr_hsh = NULL; +#define THUMB_LOAD_BIT 0x0800 + +#define BAD_ARGS _("bad arguments to instruction") +#define BAD_PC _("r15 not allowed here") +#define BAD_COND _("instruction cannot be conditional") +#define BAD_OVERLAP _("registers may not be the same") +#define BAD_HIREG _("lo register required") +#define BAD_THUMB32 _("instruction not supported in Thumb16 mode") + +static struct hash_control *arm_ops_hsh; +static struct hash_control *arm_cond_hsh; +static struct hash_control *arm_shift_hsh; +static struct hash_control *arm_psr_hsh; +static struct hash_control *arm_reg_hsh; +static struct hash_control *arm_reloc_hsh; /* Stuff needed to resolve the label ambiguity As: @@ -988,255 +512,822 @@ static struct hash_control * arm_psr_hsh = NULL; may differ from: ... label: - <insn> + <insn> */ symbolS * last_label_seen; static int label_is_thumb_function_name = FALSE; -/* Literal Pool stuff. */ - -#define MAX_LITERAL_POOL_SIZE 1024 - /* Literal pool structure. Held on a per-section and per-sub-section basis. */ +#define MAX_LITERAL_POOL_SIZE 1024 typedef struct literal_pool { - expressionS literals [MAX_LITERAL_POOL_SIZE]; - unsigned int next_free_entry; - unsigned int id; - symbolS * symbol; - segT section; - subsegT sub_section; + expressionS literals [MAX_LITERAL_POOL_SIZE]; + unsigned int next_free_entry; + unsigned int id; + symbolS * symbol; + segT section; + subsegT sub_section; struct literal_pool * next; } literal_pool; /* Pointer to a linked list of literal pools. */ literal_pool * list_of_pools = NULL; + +/* Pure syntax. */ -static literal_pool * -find_literal_pool (void) +/* This array holds the chars that always start a comment. If the + 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. */ +/* 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. */ +const char line_comment_chars[] = "#"; + +const char line_separator_chars[] = ";"; + +/* 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. */ +/* As in 0f12.456 */ +/* or 0d1.2345e12 */ + +const char FLT_CHARS[] = "rRsSfFdDxXeEpP"; + +/* Prefix characters that indicate the start of an immediate + value. */ +#define is_immediate_prefix(C) ((C) == '#' || (C) == '$') + +/* Separator character handling. */ + +#define skip_whitespace(str) do { if (*(str) == ' ') ++(str); } while (0) + +static inline int +skip_past_char (char ** str, char c) { - literal_pool * pool; + if (**str == c) + { + (*str)++; + return SUCCESS; + } + else + return FAIL; +} +#define skip_past_comma(str) skip_past_char (str, ',') - for (pool = list_of_pools; pool != NULL; pool = pool->next) +/* Arithmetic expressions (possibly involving symbols). */ + +/* Return TRUE if anything in the expression is a bignum. */ + +static int +walk_no_bignums (symbolS * sp) +{ + if (symbol_get_value_expression (sp)->X_op == O_big) + return 1; + + if (symbol_get_value_expression (sp)->X_add_symbol) { - if (pool->section == now_seg - && pool->sub_section == now_subseg) - break; + return (walk_no_bignums (symbol_get_value_expression (sp)->X_add_symbol) + || (symbol_get_value_expression (sp)->X_op_symbol + && walk_no_bignums (symbol_get_value_expression (sp)->X_op_symbol))); } - return pool; + return 0; } -static literal_pool * -find_or_make_literal_pool (void) +static int in_my_get_expression = 0; + +/* Third argument to my_get_expression. */ +#define GE_NO_PREFIX 0 +#define GE_IMM_PREFIX 1 +#define GE_OPT_PREFIX 2 + +static int +my_get_expression (expressionS * ep, char ** str, int prefix_mode) { - /* Next literal pool ID number. */ - static unsigned int latest_pool_num = 1; - literal_pool * pool; + char * save_in; + segT seg; - pool = find_literal_pool (); + /* In unified syntax, all prefixes are optional. */ + if (unified_syntax) + prefix_mode = GE_OPT_PREFIX; - if (pool == NULL) + switch (prefix_mode) { - /* Create a new pool. */ - pool = xmalloc (sizeof (* pool)); - if (! pool) - return NULL; + case GE_NO_PREFIX: break; + case GE_IMM_PREFIX: + if (!is_immediate_prefix (**str)) + { + inst.error = _("immediate expression requires a # prefix"); + return FAIL; + } + (*str)++; + break; + case GE_OPT_PREFIX: + if (is_immediate_prefix (**str)) + (*str)++; + break; + default: abort (); + } - pool->next_free_entry = 0; - pool->section = now_seg; - pool->sub_section = now_subseg; - pool->next = list_of_pools; - pool->symbol = NULL; + memset (ep, 0, sizeof (expressionS)); - /* Add it to the list. */ - list_of_pools = pool; + save_in = input_line_pointer; + input_line_pointer = *str; + in_my_get_expression = 1; + seg = expression (ep); + in_my_get_expression = 0; + + if (ep->X_op == O_illegal) + { + /* We found a bad expression in md_operand(). */ + *str = input_line_pointer; + input_line_pointer = save_in; + if (inst.error == NULL) + inst.error = _("bad expression"); + return 1; } - /* New pools, and emptied pools, will have a NULL symbol. */ - if (pool->symbol == NULL) +#ifdef OBJ_AOUT + if (seg != absolute_section + && seg != text_section + && seg != data_section + && seg != bss_section + && seg != undefined_section) { - pool->symbol = symbol_create (FAKE_LABEL_NAME, undefined_section, - (valueT) 0, &zero_address_frag); - pool->id = latest_pool_num ++; + inst.error = _("bad segment"); + *str = input_line_pointer; + input_line_pointer = save_in; + return 1; } +#endif - /* Done. */ - return pool; + /* Get rid of any bignums now, so that we don't generate an error for which + we can't establish a line number later on. Big numbers are never valid + in instructions, which is where this routine is always called. */ + if (ep->X_op == O_big + || (ep->X_add_symbol + && (walk_no_bignums (ep->X_add_symbol) + || (ep->X_op_symbol + && walk_no_bignums (ep->X_op_symbol))))) + { + inst.error = _("invalid constant"); + *str = input_line_pointer; + input_line_pointer = save_in; + return 1; + } + + *str = input_line_pointer; + input_line_pointer = save_in; + return 0; } -/* Add the literal in the global 'inst' - structure to the relevent literal pool. */ +/* Turn a string in input_line_pointer into a floating point constant + of type TYPE, and store the appropriate bytes in *LITP. The number + of LITTLENUMS emitted is stored in *SIZEP. An error message is + returned, or NULL on OK. -static int -add_to_lit_pool (void) -{ - literal_pool * pool; - unsigned int entry; + Note that fp constants aren't represent in the normal way on the ARM. + In big endian mode, things are as expected. However, in little endian + mode fp constants are big-endian word-wise, and little-endian byte-wise + within the words. For example, (double) 1.1 in big endian mode is + the byte sequence 3f f1 99 99 99 99 99 9a, and in little endian mode is + the byte sequence 99 99 f1 3f 9a 99 99 99. - pool = find_or_make_literal_pool (); + ??? The format of 12 byte floats is uncertain according to gcc's arm.h. */ - /* Check if this literal value is already in the pool. */ - for (entry = 0; entry < pool->next_free_entry; entry ++) +char * +md_atof (int type, char * litP, int * sizeP) +{ + int prec; + LITTLENUM_TYPE words[MAX_LITTLENUMS]; + char *t; + int i; + + switch (type) { - if ((pool->literals[entry].X_op == inst.reloc.exp.X_op) - && (inst.reloc.exp.X_op == O_constant) - && (pool->literals[entry].X_add_number - == inst.reloc.exp.X_add_number) - && (pool->literals[entry].X_unsigned - == inst.reloc.exp.X_unsigned)) - break; + case 'f': + case 'F': + case 's': + case 'S': + prec = 2; + break; - if ((pool->literals[entry].X_op == inst.reloc.exp.X_op) - && (inst.reloc.exp.X_op == O_symbol) - && (pool->literals[entry].X_add_number - == inst.reloc.exp.X_add_number) - && (pool->literals[entry].X_add_symbol - == inst.reloc.exp.X_add_symbol) - && (pool->literals[entry].X_op_symbol - == inst.reloc.exp.X_op_symbol)) - break; + case 'd': + case 'D': + case 'r': + case 'R': + prec = 4; + break; + + case 'x': + case 'X': + prec = 6; + break; + + case 'p': + case 'P': + prec = 6; + break; + + default: + *sizeP = 0; + return _("bad call to MD_ATOF()"); } - /* Do we need to create a new entry? */ - if (entry == pool->next_free_entry) + t = atof_ieee (input_line_pointer, type, words); + if (t) + input_line_pointer = t; + *sizeP = prec * 2; + + if (target_big_endian) { - if (entry >= MAX_LITERAL_POOL_SIZE) + for (i = 0; i < prec; i++) { - inst.error = _("literal pool overflow"); - return FAIL; + md_number_to_chars (litP, (valueT) words[i], 2); + litP += 2; } - - pool->literals[entry] = inst.reloc.exp; - pool->next_free_entry += 1; + } + else + { + if (cpu_variant & FPU_ARCH_VFP) + for (i = prec - 1; i >= 0; i--) + { + md_number_to_chars (litP, (valueT) words[i], 2); + litP += 2; + } + else + /* For a 4 byte float the order of elements in `words' is 1 0. + For an 8 byte float the order is 1 0 3 2. */ + for (i = 0; i < prec; i += 2) + { + md_number_to_chars (litP, (valueT) words[i + 1], 2); + md_number_to_chars (litP + 2, (valueT) words[i], 2); + litP += 4; + } } - inst.reloc.exp.X_op = O_symbol; - inst.reloc.exp.X_add_number = ((int) entry) * 4 - 8; - inst.reloc.exp.X_add_symbol = pool->symbol; + return 0; +} - return SUCCESS; +/* We handle all bad expressions here, so that we can report the faulty + instruction in the error message. */ +void +md_operand (expressionS * expr) +{ + if (in_my_get_expression) + expr->X_op = O_illegal; } -/* Can't use symbol_new here, so have to create a symbol and then at - a later date assign it a value. Thats what these functions do. */ +/* Immediate values. */ -static void -symbol_locate (symbolS * symbolP, - const char * name, /* It is copied, the caller can modify. */ - segT segment, /* Segment identifier (SEG_<something>). */ - valueT valu, /* Symbol value. */ - fragS * frag) /* Associated fragment. */ +/* Generic immediate-value read function for use in directives. + Accepts anything that 'expression' can fold to a constant. + *val receives the number. */ +#ifdef OBJ_ELF +static int +immediate_for_directive (int *val) { - unsigned int name_length; - char * preserved_copy_of_name; + expressionS exp; + exp.X_op = O_illegal; - name_length = strlen (name) + 1; /* +1 for \0. */ - obstack_grow (¬es, name, name_length); - preserved_copy_of_name = obstack_finish (¬es); + if (is_immediate_prefix (*input_line_pointer)) + { + input_line_pointer++; + expression (&exp); + } -#ifdef tc_canonicalize_symbol_name - preserved_copy_of_name = - tc_canonicalize_symbol_name (preserved_copy_of_name); + if (exp.X_op != O_constant) + { + as_bad (_("expected #constant")); + ignore_rest_of_line (); + return FAIL; + } + *val = exp.X_add_number; + return SUCCESS; +} #endif - S_SET_NAME (symbolP, preserved_copy_of_name); +/* Register parsing. */ - S_SET_SEGMENT (symbolP, segment); - S_SET_VALUE (symbolP, valu); - symbol_clear_list_pointers (symbolP); +/* Generic register parser. CCP points to what should be the + beginning of a register name. If it is indeed a valid register + name, advance CCP over it and return the reg_entry structure; + otherwise return NULL. Does not issue diagnostics. */ - symbol_set_frag (symbolP, frag); +static struct reg_entry * +arm_reg_parse_multi (char **ccp) +{ + char *start = *ccp; + char *p; + struct reg_entry *reg; - /* Link to end of symbol chain. */ - { - extern int symbol_table_frozen; +#ifdef REGISTER_PREFIX + if (*start != REGISTER_PREFIX) + return FAIL; + start++; +#endif +#ifdef OPTIONAL_REGISTER_PREFIX + if (*start == OPTIONAL_REGISTER_PREFIX) + start++; +#endif - if (symbol_table_frozen) - abort (); - } + p = start; + if (!ISALPHA (*p) || !is_name_beginner (*p)) + return NULL; - symbol_append (symbolP, symbol_lastP, & symbol_rootP, & symbol_lastP); + do + p++; + while (ISALPHA (*p) || ISDIGIT (*p) || *p == '_'); - obj_symbol_new_hook (symbolP); + reg = (struct reg_entry *) hash_find_n (arm_reg_hsh, start, p - start); -#ifdef tc_symbol_new_hook - tc_symbol_new_hook (symbolP); -#endif + if (!reg) + return NULL; -#ifdef DEBUG_SYMS - verify_symbol_chain (symbol_rootP, symbol_lastP); -#endif /* DEBUG_SYMS */ + *ccp = p; + return reg; } -/* Check that an immediate is valid. - If so, convert it to the right format. */ +/* As above, but the register must be of type TYPE, and the return + value is the register number or NULL. */ -static unsigned int -validate_immediate (unsigned int val) +static int +arm_reg_parse (char **ccp, enum arm_reg_type type) { - unsigned int a; - unsigned int i; + char *start = *ccp; + struct reg_entry *reg = arm_reg_parse_multi (ccp); -#define rotate_left(v, n) (v << n | v >> (32 - n)) + if (reg && reg->type == type) + return reg->number; - for (i = 0; i < 32; i += 2) - if ((a = rotate_left (val, i)) <= 0xff) - return a | (i << 7); /* 12-bit pack: [shift-cnt,const]. */ + /* Alternative syntaxes are accepted for a few register classes. */ + switch (type) + { + case REG_TYPE_MVF: + case REG_TYPE_MVD: + case REG_TYPE_MVFX: + case REG_TYPE_MVDX: + /* Generic coprocessor register names are allowed for these. */ + if (reg->type == REG_TYPE_CN) + return reg->number; + break; + + case REG_TYPE_CP: + /* For backward compatibility, a bare number is valid here. */ + { + unsigned long processor = strtoul (start, ccp, 10); + if (*ccp != start && processor <= 15) + return processor; + } + + case REG_TYPE_MMXWC: + /* WC includes WCG. ??? I'm not sure this is true for all + instructions that take WC registers. */ + if (reg->type == REG_TYPE_MMXWCG) + return reg->number; + break; + + default: + break; + } + *ccp = start; return FAIL; } -/* Check to see if an immediate can be computed as two separate immediate - values, added together. We already know that this value cannot be - computed by just one ARM instruction. */ - -static unsigned int -validate_immediate_twopart (unsigned int val, - unsigned int * highpart) +/* Parse an ARM register list. Returns the bitmask, or FAIL. */ +static long +parse_reg_list (char ** strp) { - unsigned int a; - unsigned int i; + char * str = * strp; + long range = 0; + int another_range; - 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); - } + /* We come back here if we get ranges concatenated by '+' or '|'. */ + do + { + another_range = 0; - return (a & 0xff) | (i << 7); - } + if (*str == '{') + { + int in_range = 0; + int cur_reg = -1; - return FAIL; + str++; + do + { + int reg; + + if ((reg = arm_reg_parse (&str, REG_TYPE_RN)) == FAIL) + { + inst.error = _(reg_expected_msgs[REG_TYPE_RN]); + return FAIL; + } + + if (in_range) + { + int i; + + if (reg <= cur_reg) + { + inst.error = _("bad range in register list"); + return FAIL; + } + + for (i = cur_reg + 1; i < reg; i++) + { + if (range & (1 << i)) + as_tsktsk + (_("Warning: duplicated register (r%d) in register list"), + i); + else + range |= 1 << i; + } + in_range = 0; + } + + if (range & (1 << reg)) + as_tsktsk (_("Warning: duplicated register (r%d) in register list"), + reg); + else if (reg <= cur_reg) + as_tsktsk (_("Warning: register range not in ascending order")); + + range |= 1 << reg; + cur_reg = reg; + } + while (skip_past_comma (&str) != FAIL + || (in_range = 1, *str++ == '-')); + str--; + + if (*str++ != '}') + { + inst.error = _("missing `}'"); + return FAIL; + } + } + else + { + expressionS expr; + + if (my_get_expression (&expr, &str, GE_NO_PREFIX)) + return FAIL; + + if (expr.X_op == O_constant) + { + if (expr.X_add_number + != (expr.X_add_number & 0x0000ffff)) + { + inst.error = _("invalid register mask"); + return FAIL; + } + + if ((range & expr.X_add_number) != 0) + { + int regno = range & expr.X_add_number; + + regno &= -regno; + regno = (1 << regno) - 1; + as_tsktsk + (_("Warning: duplicated register (r%d) in register list"), + regno); + } + + range |= expr.X_add_number; + } + else + { + if (inst.reloc.type != 0) + { + inst.error = _("expression too complex"); + return FAIL; + } + + memcpy (&inst.reloc.exp, &expr, sizeof (expressionS)); + inst.reloc.type = BFD_RELOC_ARM_MULTI; + inst.reloc.pc_rel = 0; + } + } + + if (*str == '|' || *str == '+') + { + str++; + another_range = 1; + } + } + while (another_range); + + *strp = str; + return range; } +/* Parse a VFP register list. If the string is invalid return FAIL. + Otherwise return the number of registers, and set PBASE to the first + register. Double precision registers are matched if DP is nonzero. */ + static int -validate_offset_imm (unsigned int val, int hwse) +parse_vfp_reg_list (char **str, int *pbase, int dp) { - if ((hwse && val > 255) || val > 4095) + int base_reg; + int new_base; + int regtype; + int max_regs; + int count = 0; + int warned = 0; + unsigned long mask = 0; + int i; + + if (**str != '{') return FAIL; - return val; + + (*str)++; + + if (dp) + { + regtype = REG_TYPE_VFD; + max_regs = 16; + } + else + { + regtype = REG_TYPE_VFS; + max_regs = 32; + } + + base_reg = max_regs; + + do + { + new_base = arm_reg_parse (str, regtype); + if (new_base == FAIL) + { + inst.error = gettext (reg_expected_msgs[regtype]); + return FAIL; + } + + if (new_base < base_reg) + base_reg = new_base; + + if (mask & (1 << new_base)) + { + inst.error = _("invalid register list"); + return FAIL; + } + + if ((mask >> new_base) != 0 && ! warned) + { + as_tsktsk (_("register list not in ascending order")); + warned = 1; + } + + mask |= 1 << new_base; + count++; + + if (**str == '-') /* We have the start of a range expression */ + { + int high_range; + + (*str)++; + + if ((high_range = arm_reg_parse (str, regtype)) == FAIL) + { + inst.error = gettext (reg_expected_msgs[regtype]); + return FAIL; + } + + if (high_range <= new_base) + { + inst.error = _("register range not in ascending order"); + return FAIL; + } + + for (new_base++; new_base <= high_range; new_base++) + { + if (mask & (1 << new_base)) + { + inst.error = _("invalid register list"); + return FAIL; + } + + mask |= 1 << new_base; + count++; + } + } + } + while (skip_past_comma (str) != FAIL); + + (*str)++; + + /* Sanity check -- should have raised a parse error above. */ + if (count == 0 || count > max_regs) + abort (); + + *pbase = base_reg; + + /* Final test -- the registers must be consecutive. */ + mask >>= base_reg; + for (i = 0; i < count; i++) + { + if ((mask & (1u << i)) == 0) + { + inst.error = _("non-contiguous register range"); + return FAIL; + } + } + + return count; } - +/* Parse an explicit relocation suffix on an expression. This is + either nothing, or a word in parentheses. Note that if !OBJ_ELF, + arm_reloc_hsh contains no entries, so this function can only + succeed if there is no () after the word. Returns -1 on error, + BFD_RELOC_UNUSED if there wasn't any suffix. */ +static int +parse_reloc (char **str) +{ + struct reloc_entry *r; + char *p, *q; + + if (**str != '(') + return BFD_RELOC_UNUSED; + + p = *str + 1; + q = p; + + while (*q && *q != ')' && *q != ',') + q++; + if (*q != ')') + return -1; + + if ((r = hash_find_n (arm_reloc_hsh, p, q - p)) == NULL) + return -1; + + *str = q + 1; + return r->reloc; +} + +/* Directives: register aliases. */ + +static void +insert_reg_alias (char *str, int number, int type) +{ + struct reg_entry *new; + const char *name; + + if ((new = hash_find (arm_reg_hsh, str)) != 0) + { + if (new->builtin) + as_warn (_("ignoring attempt to redefine built-in register '%s'"), str); + + /* Only warn about a redefinition if it's not defined as the + same register. */ + else if (new->number != number || new->type != type) + as_warn (_("ignoring redefinition of register alias '%s'"), str); + + return; + } + + name = xstrdup (str); + new = xmalloc (sizeof (struct reg_entry)); + + new->name = name; + new->number = number; + new->type = type; + new->builtin = FALSE; + + if (hash_insert (arm_reg_hsh, name, (PTR) new)) + abort (); +} + +/* Look for the .req directive. This is of the form: + + new_register_name .req existing_register_name + + If we find one, or if it looks sufficiently like one that we want to + handle any error here, return non-zero. Otherwise return zero. */ + +static int +create_register_alias (char * newname, char *p) +{ + struct reg_entry *old; + char *oldname, *nbuf; + size_t nlen; + + /* The input scrubber ensures that whitespace after the mnemonic is + collapsed to single spaces. */ + oldname = p; + if (strncmp (oldname, " .req ", 6) != 0) + return 0; + + oldname += 6; + if (*oldname == '\0') + return 0; + + old = hash_find (arm_reg_hsh, oldname); + if (!old) + { + as_warn (_("unknown register '%s' -- .req ignored"), oldname); + return 1; + } + + /* If TC_CASE_SENSITIVE is defined, then newname already points to + the desired alias name, and p points to its end. If not, then + the desired alias name is in the global original_case_string. */ +#ifdef TC_CASE_SENSITIVE + nlen = p - newname; +#else + newname = original_case_string; + nlen = strlen (newname); +#endif + + nbuf = alloca (nlen + 1); + memcpy (nbuf, newname, nlen); + nbuf[nlen] = '\0'; + + /* Create aliases under the new name as stated; an all-lowercase + version of the new name; and an all-uppercase version of the new + name. */ + insert_reg_alias (nbuf, old->number, old->type); + + for (p = nbuf; *p; p++) + *p = TOUPPER (*p); + + if (strncmp (nbuf, newname, nlen)) + insert_reg_alias (nbuf, old->number, old->type); + + for (p = nbuf; *p; p++) + *p = TOLOWER (*p); + + if (strncmp (nbuf, newname, nlen)) + insert_reg_alias (nbuf, old->number, old->type); + + return 1; +} + +/* Should never be called, as .req goes between the alias and the + register name, not at the beginning of the line. */ +static void +s_req (int a ATTRIBUTE_UNUSED) +{ + as_bad (_("invalid syntax for .req directive")); +} + +/* The .unreq directive deletes an alias which was previously defined + by .req. For example: + + my_alias .req r11 + .unreq my_alias */ + +static void +s_unreq (int a ATTRIBUTE_UNUSED) +{ + char * name; + char saved_char; + + name = input_line_pointer; + + while (*input_line_pointer != 0 + && *input_line_pointer != ' ' + && *input_line_pointer != '\n') + ++input_line_pointer; + + saved_char = *input_line_pointer; + *input_line_pointer = 0; + + if (!*name) + as_bad (_("invalid syntax for .unreq directive")); + else + { + struct reg_entry *reg = hash_find (arm_reg_hsh, name); + + if (!reg) + as_bad (_("unknown register alias '%s'"), name); + else if (reg->builtin) + as_warn (_("ignoring attempt to undefine built-in register '%s'"), + name); + else + { + hash_delete (arm_reg_hsh, name); + free ((char *) reg->name); + free (reg); + } + } + + *input_line_pointer = saved_char; + demand_empty_rest_of_line (); +} + +/* Directives: Instruction set selection. */ + #ifdef OBJ_ELF /* This code is to handle mapping symbols as defined in the ARM ELF spec. (See "Mapping symbols", section 4.5.5, ARM AAELF version 1.0). @@ -1304,102 +1395,45 @@ mapping_state (enum mstate state) return; } } +#else +#define mapping_state(x) /* nothing */ +#endif -/* When we change sections we need to issue a new mapping symbol. */ - -void -arm_elf_change_section (void) -{ - flagword flags; - segment_info_type *seginfo; - - /* Link an unlinked unwind index table section to the .text section. */ - if (elf_section_type (now_seg) == SHT_ARM_EXIDX - && elf_linked_to_section (now_seg) == NULL) - elf_linked_to_section (now_seg) = text_section; - - if (!SEG_NORMAL (now_seg)) - return; - - flags = bfd_get_section_flags (stdoutput, now_seg); - - /* We can ignore sections that only contain debug info. */ - if ((flags & SEC_ALLOC) == 0) - return; - - seginfo = seg_info (now_seg); - mapstate = seginfo->tc_segment_info_data.mapstate; - marked_pr_dependency = seginfo->tc_segment_info_data.marked_pr_dependency; -} +/* Find the real, Thumb encoded start of a Thumb function. */ -int -arm_elf_section_type (const char * str, size_t len) +static symbolS * +find_real_start (symbolS * symbolP) { - if (len == 5 && strncmp (str, "exidx", 5) == 0) - return SHT_ARM_EXIDX; + char * real_start; + const char * name = S_GET_NAME (symbolP); + symbolS * new_target; - return -1; -} -#else -#define mapping_state(a) -#endif /* OBJ_ELF */ - -/* arm_reg_parse () := if it looks like a register, return its token and - advance the pointer. */ + /* This definition must agree with the one in gcc/config/arm/thumb.c. */ +#define STUB_NAME ".real_start_of" -static int -arm_reg_parse (char ** ccp, struct hash_control * htab) -{ - char * start = * ccp; - char c; - char * p; - struct reg_entry * reg; + if (name == NULL) + abort (); -#ifdef REGISTER_PREFIX - if (*start != REGISTER_PREFIX) - return FAIL; - p = start + 1; -#else - p = start; -#ifdef OPTIONAL_REGISTER_PREFIX - if (*p == OPTIONAL_REGISTER_PREFIX) - p++, start++; -#endif -#endif - if (!ISALPHA (*p) || !is_name_beginner (*p)) - return FAIL; + /* Names that start with '.' are local labels, not function entry points. + The compiler may generate BL instructions to these labels because it + needs to perform a branch to a far away location. */ + if (name[0] == '.') + return symbolP; - c = *p++; - while (ISALPHA (c) || ISDIGIT (c) || c == '_') - c = *p++; + real_start = malloc (strlen (name) + strlen (STUB_NAME) + 1); + sprintf (real_start, "%s%s", STUB_NAME, name); - *--p = 0; - reg = (struct reg_entry *) hash_find (htab, start); - *p = c; + new_target = symbol_find (real_start); - if (reg) + if (new_target == NULL) { - *ccp = p; - return reg->number; + as_warn ("Failed to find real start of function: %s\n", name); + new_target = symbolP; } - return FAIL; -} - -/* Search for the following register name in each of the possible reg name - tables. Return the classification if found, or REG_TYPE_MAX if not - present. */ - -static enum arm_reg_type -arm_reg_parse_any (char *cp) -{ - int i; - - for (i = (int) REG_TYPE_FIRST; i < (int) REG_TYPE_MAX; i++) - if (arm_reg_parse (&cp, all_reg_maps[i].htab) != FAIL) - return (enum arm_reg_type) i; + free (real_start); - return REG_TYPE_MAX; + return new_target; } static void @@ -1415,7 +1449,7 @@ opcode_select (int width) thumb_mode = 1; /* No need to force the alignment, since we will have been - coming from ARM mode, which is word-aligned. */ + coming from ARM mode, which is word-aligned. */ record_alignment (now_seg, 1); } mapping_state (MAP_THUMB); @@ -1443,182 +1477,35 @@ opcode_select (int width) } static void -s_req (int a ATTRIBUTE_UNUSED) -{ - as_bad (_("invalid syntax for .req directive")); -} - -/* The .unreq directive deletes an alias which was previously defined - by .req. For example: - - my_alias .req r11 - .unreq my_alias */ - -static void -s_unreq (int a ATTRIBUTE_UNUSED) -{ - char * name; - char saved_char; - - skip_whitespace (input_line_pointer); - name = input_line_pointer; - - while (*input_line_pointer != 0 - && *input_line_pointer != ' ' - && *input_line_pointer != '\n') - ++input_line_pointer; - - saved_char = *input_line_pointer; - *input_line_pointer = 0; - - if (*name) - { - enum arm_reg_type req_type = arm_reg_parse_any (name); - - if (req_type != REG_TYPE_MAX) - { - char *temp_name = name; - int req_no = arm_reg_parse (&temp_name, all_reg_maps[req_type].htab); - - if (req_no != FAIL) - { - struct reg_entry *req_entry; - - /* Check to see if this alias is a builtin one. */ - req_entry = hash_delete (all_reg_maps[req_type].htab, name); - - if (!req_entry) - as_bad (_("unreq: missing hash entry for \"%s\""), name); - else if (req_entry->builtin) - /* FIXME: We are deleting a built in register alias which - points to a const data structure, so we only need to - free up the memory used by the key in the hash table. - Unfortunately we have not recorded this value, so this - is a memory leak. */ - /* FIXME: Should we issue a warning message ? */ - ; - else - { - /* Deleting a user defined alias. We need to free the - key and the value, but fortunately the key is the same - as the value->name field. */ - free ((char *) req_entry->name); - free (req_entry); - } - } - else - as_bad (_(".unreq: unrecognized symbol \"%s\""), name); - } - else - as_bad (_(".unreq: unrecognized symbol \"%s\""), name); - } - else - as_bad (_("invalid syntax for .unreq directive")); - - *input_line_pointer = saved_char; - demand_empty_rest_of_line (); -} - -static void -s_bss (int ignore ATTRIBUTE_UNUSED) +s_arm (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. */ - subseg_set (bss_section, 0); + opcode_select (32); demand_empty_rest_of_line (); - mapping_state (MAP_DATA); } static void -s_even (int ignore ATTRIBUTE_UNUSED) +s_thumb (int ignore ATTRIBUTE_UNUSED) { - /* Never make frag if expect extra pass. */ - if (!need_pass_2) - frag_align (1, 0, 0); - - record_alignment (now_seg, 1); - + opcode_select (16); demand_empty_rest_of_line (); } static void -s_ltorg (int ignored ATTRIBUTE_UNUSED) -{ - unsigned int entry; - literal_pool * pool; - char sym_name[20]; - - pool = find_literal_pool (); - if (pool == NULL - || pool->symbol == NULL - || pool->next_free_entry == 0) - return; - - mapping_state (MAP_DATA); - - /* Align pool as you have word accesses. - Only make a frag if we have to. */ - if (!need_pass_2) - frag_align (2, 0, 0); - - record_alignment (now_seg, 2); - - sprintf (sym_name, "$$lit_\002%x", pool->id); - - symbol_locate (pool->symbol, sym_name, now_seg, - (valueT) frag_now_fix (), frag_now); - symbol_table_insert (pool->symbol); - - ARM_SET_THUMB (pool->symbol, thumb_mode); - -#if defined OBJ_COFF || defined OBJ_ELF - ARM_SET_INTERWORK (pool->symbol, support_interwork); -#endif - - for (entry = 0; entry < pool->next_free_entry; entry ++) - /* First output the expression in the instruction to the pool. */ - emit_expr (&(pool->literals[entry]), 4); /* .word */ - - /* Mark the pool as empty. */ - pool->next_free_entry = 0; - pool->symbol = NULL; -} - -/* Same as s_align_ptwo but align 0 => align 2. */ - -static void -s_align (int unused ATTRIBUTE_UNUSED) +s_code (int unused ATTRIBUTE_UNUSED) { int temp; - long temp_fill; - long max_alignment = 15; temp = get_absolute_expression (); - if (temp > max_alignment) - as_bad (_("alignment too large: %d assumed"), temp = max_alignment); - else if (temp < 0) + switch (temp) { - as_bad (_("alignment negative. 0 assumed.")); - temp = 0; - } + case 16: + case 32: + opcode_select (temp); + break; - if (*input_line_pointer == ',') - { - input_line_pointer++; - temp_fill = get_absolute_expression (); + default: + as_bad (_("invalid operand to .code directive (%d) (expecting 16 or 32)"), temp); } - else - temp_fill = 0; - - if (!temp) - temp = 2; - - /* Only make a frag if we HAVE to. */ - if (temp && !need_pass_2) - frag_align (temp, (int) temp_fill, 0); - demand_empty_rest_of_line (); - - record_alignment (now_seg, temp); } static void @@ -1628,11 +1515,10 @@ s_force_thumb (int ignore ATTRIBUTE_UNUSED) the target processor does not support thumb instructions. This is used by gcc/config/arm/lib1funcs.asm for example to compile interworking support functions even if the - target processor should not support interworking. */ + target processor should not support interworking. */ if (! thumb_mode) { thumb_mode = 2; - record_alignment (now_seg, 1); } @@ -1642,14 +1528,11 @@ s_force_thumb (int ignore ATTRIBUTE_UNUSED) static void s_thumb_func (int ignore ATTRIBUTE_UNUSED) { - if (! thumb_mode) - opcode_select (16); + s_thumb (0); /* The following label is the name/address of the start of a Thumb function. - We need to know this for the interworking support. */ + We need to know this for the interworking support. */ label_is_thumb_function_name = TRUE; - - demand_empty_rest_of_line (); } /* Perform a .set directive, but also mark the alias as @@ -1662,20 +1545,18 @@ s_thumb_set (int equiv) We cannot just call that code as we need to get at the symbol that is created. */ char * name; - char delim; + char delim; char * end_name; symbolS * symbolP; /* Especial apologies for the random logic: This just grew, and could be parsed much more simply! Dean - in haste. */ - name = input_line_pointer; - delim = get_symbol_end (); + name = input_line_pointer; + delim = get_symbol_end (); end_name = input_line_pointer; *end_name = delim; - SKIP_WHITESPACE (); - if (*input_line_pointer != ',') { *end_name = 0; @@ -1700,7 +1581,7 @@ s_thumb_set (int equiv) #ifndef NO_LISTING /* When doing symbol listings, play games with dummy fragments living outside the normal fragment chain to record the file and line info - for this symbol. */ + for this symbol. */ if (listing & LISTING_SYMBOLS) { extern struct list_info_struct * listing_tail; @@ -1735,7 +1616,7 @@ s_thumb_set (int equiv) demand_empty_rest_of_line (); - /* XXX Now we come to the Thumb specific bit of code. */ + /* XXX Now we come to the Thumb specific bit of code. */ THUMB_SET_FUNC (symbolP, 1); ARM_SET_THUMB (symbolP, 1); @@ -1744,4055 +1625,2996 @@ s_thumb_set (int equiv) #endif } -static void -s_arm (int ignore ATTRIBUTE_UNUSED) -{ - opcode_select (32); - demand_empty_rest_of_line (); -} +/* Directives: Mode selection. */ +/* .syntax [unified|divided] - choose the new unified syntax + (same for Arm and Thumb encoding, modulo slight differences in what + can be represented) or the old divergent syntax for each mode. */ static void -s_thumb (int ignore ATTRIBUTE_UNUSED) +s_syntax (int unused ATTRIBUTE_UNUSED) { - opcode_select (16); + char *name, delim; + + name = input_line_pointer; + delim = get_symbol_end (); + + if (!strcasecmp (name, "unified")) + unified_syntax = TRUE; + else if (!strcasecmp (name, "divided")) + unified_syntax = FALSE; + else + { + as_bad (_("unrecognized syntax mode \"%s\""), name); + return; + } + *input_line_pointer = delim; demand_empty_rest_of_line (); } +/* Directives: sectioning and alignment. */ + +/* Same as s_align_ptwo but align 0 => align 2. */ + static void -s_code (int unused ATTRIBUTE_UNUSED) +s_align (int unused ATTRIBUTE_UNUSED) { int temp; + long temp_fill; + long max_alignment = 15; temp = get_absolute_expression (); - switch (temp) + if (temp > max_alignment) + as_bad (_("alignment too large: %d assumed"), temp = max_alignment); + else if (temp < 0) { - case 16: - case 32: - opcode_select (temp); - break; - - default: - as_bad (_("invalid operand to .code directive (%d) (expecting 16 or 32)"), temp); + as_bad (_("alignment negative. 0 assumed.")); + temp = 0; } -} - -static void -end_of_line (char * str) -{ - skip_whitespace (str); - if (*str != '\0' && !inst.error) - inst.error = _("garbage following instruction"); -} - -static int -skip_past_comma (char ** str) -{ - char * p = * str, c; - int comma = 0; - - while ((c = *p) == ' ' || c == ',') + if (*input_line_pointer == ',') { - p++; - if (c == ',' && comma++) - return FAIL; + input_line_pointer++; + temp_fill = get_absolute_expression (); } + else + temp_fill = 0; - if (c == '\0') - return FAIL; + if (!temp) + temp = 2; - *str = p; - return comma ? SUCCESS : FAIL; -} + /* Only make a frag if we HAVE to. */ + if (temp && !need_pass_2) + frag_align (temp, (int) temp_fill, 0); + demand_empty_rest_of_line (); -/* Return TRUE if anything in the expression is a bignum. */ + record_alignment (now_seg, temp); +} -static int -walk_no_bignums (symbolS * sp) +static void +s_bss (int ignore ATTRIBUTE_UNUSED) { - if (symbol_get_value_expression (sp)->X_op == O_big) - return 1; - - if (symbol_get_value_expression (sp)->X_add_symbol) - { - return (walk_no_bignums (symbol_get_value_expression (sp)->X_add_symbol) - || (symbol_get_value_expression (sp)->X_op_symbol - && walk_no_bignums (symbol_get_value_expression (sp)->X_op_symbol))); - } - - return 0; + /* We don't support putting frags in the BSS segment, we fake it by + marking in_bss, then looking at s_skip for clues. */ + subseg_set (bss_section, 0); + demand_empty_rest_of_line (); + mapping_state (MAP_DATA); } -static int in_my_get_expression = 0; - -static int -my_get_expression (expressionS * ep, char ** str) +static void +s_even (int ignore ATTRIBUTE_UNUSED) { - char * save_in; - segT seg; - - save_in = input_line_pointer; - input_line_pointer = *str; - in_my_get_expression = 1; - seg = expression (ep); - in_my_get_expression = 0; - - if (ep->X_op == O_illegal) - { - /* We found a bad expression in md_operand(). */ - *str = input_line_pointer; - input_line_pointer = save_in; - return 1; - } - -#ifdef OBJ_AOUT - if (seg != absolute_section - && seg != text_section - && seg != data_section - && seg != bss_section - && seg != undefined_section) - { - inst.error = _("bad_segment"); - *str = input_line_pointer; - input_line_pointer = save_in; - return 1; - } -#endif + /* Never make frag if expect extra pass. */ + if (!need_pass_2) + frag_align (1, 0, 0); - /* Get rid of any bignums now, so that we don't generate an error for which - we can't establish a line number later on. Big numbers are never valid - in instructions, which is where this routine is always called. */ - if (ep->X_op == O_big - || (ep->X_add_symbol - && (walk_no_bignums (ep->X_add_symbol) - || (ep->X_op_symbol - && walk_no_bignums (ep->X_op_symbol))))) - { - inst.error = _("invalid constant"); - *str = input_line_pointer; - input_line_pointer = save_in; - return 1; - } + record_alignment (now_seg, 1); - *str = input_line_pointer; - input_line_pointer = save_in; - return 0; + demand_empty_rest_of_line (); } -/* A standard register must be given at this point. - SHIFT is the place to put it in inst.instruction. - Restores input start point on error. - Returns the reg#, or FAIL. */ +/* Directives: Literal pools. */ -static int -reg_required_here (char ** str, int shift) +static literal_pool * +find_literal_pool (void) { - static char buff [128]; /* XXX */ - int reg; - char * start = * str; + literal_pool * pool; - if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_RN].htab)) != FAIL) + for (pool = list_of_pools; pool != NULL; pool = pool->next) { - if (shift >= 0) - inst.instruction |= reg << shift; - return reg; + if (pool->section == now_seg + && pool->sub_section == now_subseg) + break; } - /* Restore the start point, we may have got a reg of the wrong class. */ - *str = start; - - /* In the few cases where we might be able to accept something else - this error can be overridden. */ - sprintf (buff, _("register expected, not '%.100s'"), start); - inst.error = buff; - - return FAIL; -} - -/* A Intel Wireless MMX technology 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. */ - -static int -wreg_required_here (char ** str, - int shift, - enum wreg_type reg_type) -{ - static char buff [128]; - int reg; - char * start = *str; - - if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_IWMMXT].htab)) != FAIL) - { - if (wr_register (reg) - && (reg_type == IWMMXT_REG_WR || reg_type == IWMMXT_REG_WR_OR_WC)) - { - if (shift >= 0) - inst.instruction |= (reg ^ WR_PREFIX) << shift; - return reg; - } - else if (wc_register (reg) - && (reg_type == IWMMXT_REG_WC || reg_type == IWMMXT_REG_WR_OR_WC)) - { - if (shift >= 0) - inst.instruction |= (reg ^ WC_PREFIX) << shift; - return reg; - } - else if ((wcg_register (reg) && reg_type == IWMMXT_REG_WCG)) - { - if (shift >= 0) - inst.instruction |= ((reg ^ WC_PREFIX) - 8) << shift; - return reg; - } - } - - /* Restore the start point, we may have got a reg of the wrong class. */ - *str = start; - - /* In the few cases where we might be able to accept - something else this error can be overridden. */ - sprintf (buff, _("Intel Wireless MMX technology register expected, not '%.100s'"), start); - inst.error = buff; - - return FAIL; + return pool; } -static const struct asm_psr * -arm_psr_parse (char ** ccp) +static literal_pool * +find_or_make_literal_pool (void) { - char * start = * ccp; - char c; - char * p; - const struct asm_psr * psr; + /* Next literal pool ID number. */ + static unsigned int latest_pool_num = 1; + literal_pool * pool; - p = start; + pool = find_literal_pool (); - /* Skip to the end of the next word in the input stream. */ - do + if (pool == NULL) { - c = *p++; - } - while (ISALPHA (c) || c == '_'); - - /* Terminate the word. */ - *--p = 0; - - /* CPSR's and SPSR's can now be lowercase. This is just a convenience - feature for ease of use and backwards compatibility. */ - if (!strncmp (start, "cpsr", 4)) - strncpy (start, "CPSR", 4); - else if (!strncmp (start, "spsr", 4)) - strncpy (start, "SPSR", 4); + /* Create a new pool. */ + pool = xmalloc (sizeof (* pool)); + if (! pool) + return NULL; - /* Now locate the word in the psr hash table. */ - psr = (const struct asm_psr *) hash_find (arm_psr_hsh, start); + pool->next_free_entry = 0; + pool->section = now_seg; + pool->sub_section = now_subseg; + pool->next = list_of_pools; + pool->symbol = NULL; - /* Restore the input stream. */ - *p = c; + /* Add it to the list. */ + list_of_pools = pool; + } - /* If we found a valid match, advance the - stream pointer past the end of the word. */ - *ccp = p; + /* New pools, and emptied pools, will have a NULL symbol. */ + if (pool->symbol == NULL) + { + pool->symbol = symbol_create (FAKE_LABEL_NAME, undefined_section, + (valueT) 0, &zero_address_frag); + pool->id = latest_pool_num ++; + } - return psr; + /* Done. */ + return pool; } -/* Parse the input looking for a PSR flag. */ +/* Add the literal in the global 'inst' + structure to the relevent literal pool. */ static int -psr_required_here (char ** str) +add_to_lit_pool (void) { - char * start = * str; - const struct asm_psr * psr; + literal_pool * pool; + unsigned int entry; - psr = arm_psr_parse (str); + pool = find_or_make_literal_pool (); - if (psr) + /* Check if this literal value is already in the pool. */ + for (entry = 0; entry < pool->next_free_entry; entry ++) { - /* 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; + if ((pool->literals[entry].X_op == inst.reloc.exp.X_op) + && (inst.reloc.exp.X_op == O_constant) + && (pool->literals[entry].X_add_number + == inst.reloc.exp.X_add_number) + && (pool->literals[entry].X_unsigned + == inst.reloc.exp.X_unsigned)) + break; - return SUCCESS; + if ((pool->literals[entry].X_op == inst.reloc.exp.X_op) + && (inst.reloc.exp.X_op == O_symbol) + && (pool->literals[entry].X_add_number + == inst.reloc.exp.X_add_number) + && (pool->literals[entry].X_add_symbol + == inst.reloc.exp.X_add_symbol) + && (pool->literals[entry].X_op_symbol + == inst.reloc.exp.X_op_symbol)) + break; } - /* 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 FAIL; -} - -static int -co_proc_number (char ** str) -{ - int processor, pchar; - char *start; - - skip_whitespace (*str); - start = *str; - - /* The data sheet seems to imply that just a number on its own is valid - here, but the RISC iX assembler seems to accept a prefix 'p'. We will - accept either. */ - if ((processor = arm_reg_parse (str, all_reg_maps[REG_TYPE_CP].htab)) - == FAIL) + /* Do we need to create a new entry? */ + if (entry == pool->next_free_entry) { - *str = start; - - pchar = *(*str)++; - if (pchar >= '0' && pchar <= '9') - { - processor = pchar - '0'; - if (**str >= '0' && **str <= '9') - { - processor = processor * 10 + *(*str)++ - '0'; - if (processor > 15) - { - inst.error = _("illegal co-processor number"); - return FAIL; - } - } - } - else + if (entry >= MAX_LITERAL_POOL_SIZE) { - inst.error = all_reg_maps[REG_TYPE_CP].expected; + inst.error = _("literal pool overflow"); return FAIL; } - } - - inst.instruction |= processor << 8; - return SUCCESS; -} - -static int -cp_opc_expr (char ** str, int where, int length) -{ - expressionS expr; - skip_whitespace (* str); - - memset (&expr, '\0', sizeof (expr)); - - if (my_get_expression (&expr, str)) - return FAIL; - if (expr.X_op != O_constant) - { - inst.error = _("bad or missing expression"); - return FAIL; + pool->literals[entry] = inst.reloc.exp; + pool->next_free_entry += 1; } - if ((expr.X_add_number & ((1 << length) - 1)) != expr.X_add_number) - { - inst.error = _("immediate co-processor expression too large"); - return FAIL; - } + inst.reloc.exp.X_op = O_symbol; + inst.reloc.exp.X_add_number = ((int) entry) * 4; + inst.reloc.exp.X_add_symbol = pool->symbol; - inst.instruction |= expr.X_add_number << where; return SUCCESS; } -static int -cp_reg_required_here (char ** str, int where) -{ - int reg; - char * start = *str; - - if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_CN].htab)) != FAIL) - { - inst.instruction |= reg << where; - return reg; - } - - /* In the few cases where we might be able to accept something else - this error can be overridden. */ - inst.error = all_reg_maps[REG_TYPE_CN].expected; - - /* Restore the start point. */ - *str = start; - return FAIL; -} +/* Can't use symbol_new here, so have to create a symbol and then at + a later date assign it a value. Thats what these functions do. */ -static int -fp_reg_required_here (char ** str, int where) +static void +symbol_locate (symbolS * symbolP, + const char * name, /* It is copied, the caller can modify. */ + segT segment, /* Segment identifier (SEG_<something>). */ + valueT valu, /* Symbol value. */ + fragS * frag) /* Associated fragment. */ { - int reg; - char * start = * str; - - if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_FN].htab)) != FAIL) - { - inst.instruction |= reg << where; - return reg; - } - - /* In the few cases where we might be able to accept something else - this error can be overridden. */ - inst.error = all_reg_maps[REG_TYPE_FN].expected; - - /* Restore the start point. */ - *str = start; - return FAIL; -} + unsigned int name_length; + char * preserved_copy_of_name; -static int -cp_address_offset (char ** str) -{ - int offset; + name_length = strlen (name) + 1; /* +1 for \0. */ + obstack_grow (¬es, name, name_length); + preserved_copy_of_name = obstack_finish (¬es); - skip_whitespace (* str); +#ifdef tc_canonicalize_symbol_name + preserved_copy_of_name = + tc_canonicalize_symbol_name (preserved_copy_of_name); +#endif - if (! is_immediate_prefix (**str)) - { - inst.error = _("immediate expression expected"); - return FAIL; - } + S_SET_NAME (symbolP, preserved_copy_of_name); - (*str)++; + S_SET_SEGMENT (symbolP, segment); + S_SET_VALUE (symbolP, valu); + symbol_clear_list_pointers (symbolP); - if (my_get_expression (& inst.reloc.exp, str)) - return FAIL; + symbol_set_frag (symbolP, frag); - if (inst.reloc.exp.X_op == O_constant) - { - offset = inst.reloc.exp.X_add_number; + /* Link to end of symbol chain. */ + { + extern int symbol_table_frozen; - if (offset & 3) - { - inst.error = _("co-processor address must be word aligned"); - return FAIL; - } + if (symbol_table_frozen) + abort (); + } - if (offset > 1023 || offset < -1023) - { - inst.error = _("offset too large"); - return FAIL; - } + symbol_append (symbolP, symbol_lastP, & symbol_rootP, & symbol_lastP); - if (offset >= 0) - inst.instruction |= INDEX_UP; - else - offset = -offset; + obj_symbol_new_hook (symbolP); - inst.instruction |= offset >> 2; - } - else - inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM; +#ifdef tc_symbol_new_hook + tc_symbol_new_hook (symbolP); +#endif - return SUCCESS; +#ifdef DEBUG_SYMS + verify_symbol_chain (symbol_rootP, symbol_lastP); +#endif /* DEBUG_SYMS */ } -static int -cp_address_required_here (char ** str, int wb_ok) + +static void +s_ltorg (int ignored ATTRIBUTE_UNUSED) { - char * p = * str; - int pre_inc = 0; - int write_back = 0; + unsigned int entry; + literal_pool * pool; + char sym_name[20]; - if (*p == '[') - { - int reg; + pool = find_literal_pool (); + if (pool == NULL + || pool->symbol == NULL + || pool->next_free_entry == 0) + return; - p++; - skip_whitespace (p); + mapping_state (MAP_DATA); - if ((reg = reg_required_here (& p, 16)) == FAIL) - return FAIL; + /* Align pool as you have word accesses. + Only make a frag if we have to. */ + if (!need_pass_2) + frag_align (2, 0, 0); - skip_whitespace (p); + record_alignment (now_seg, 2); - if (*p == ']') - { - p++; + sprintf (sym_name, "$$lit_\002%x", pool->id); - skip_whitespace (p); + symbol_locate (pool->symbol, sym_name, now_seg, + (valueT) frag_now_fix (), frag_now); + symbol_table_insert (pool->symbol); - if (*p == '\0') - { - /* As an extension to the official ARM syntax we allow: - [Rn] - as a short hand for: - [Rn,#0] */ - inst.instruction |= PRE_INDEX | INDEX_UP; - *str = p; - return SUCCESS; - } + ARM_SET_THUMB (pool->symbol, thumb_mode); - if (skip_past_comma (& p) == FAIL) - { - inst.error = _("comma expected after closing square bracket"); - return FAIL; - } +#if defined OBJ_COFF || defined OBJ_ELF + ARM_SET_INTERWORK (pool->symbol, support_interwork); +#endif - skip_whitespace (p); + for (entry = 0; entry < pool->next_free_entry; entry ++) + /* First output the expression in the instruction to the pool. */ + emit_expr (&(pool->literals[entry]), 4); /* .word */ - if (*p == '#') - { - if (wb_ok) - { - /* [Rn], #expr */ - write_back = WRITE_BACK; + /* Mark the pool as empty. */ + pool->next_free_entry = 0; + pool->symbol = NULL; +} - if (reg == REG_PC) - { - inst.error = _("pc may not be used in post-increment"); - return FAIL; - } +#ifdef OBJ_ELF +/* Forward declarations for functions below, in the MD interface + section. */ +static void fix_new_arm (fragS *, int, short, expressionS *, int, int); +static valueT create_unwind_entry (int); +static void start_unwind_section (const segT, int); +static void add_unwind_opcode (valueT, int); +static void flush_pending_unwind (void); - if (cp_address_offset (& p) == FAIL) - return FAIL; - } - else - pre_inc = PRE_INDEX | INDEX_UP; - } - else if (*p == '{') - { - int option; +/* Directives: Data. */ - /* [Rn], {<expr>} */ - p++; +static void +s_arm_elf_cons (int nbytes) +{ + expressionS exp; - skip_whitespace (p); +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif - if (my_get_expression (& inst.reloc.exp, & p)) - return FAIL; + if (is_it_end_of_statement ()) + { + demand_empty_rest_of_line (); + return; + } - if (inst.reloc.exp.X_op == O_constant) - { - option = inst.reloc.exp.X_add_number; +#ifdef md_cons_align + md_cons_align (nbytes); +#endif - if (option > 255 || option < 0) - { - inst.error = _("'option' field too large"); - return FAIL; - } + mapping_state (MAP_DATA); + do + { + int reloc; + char *base = input_line_pointer; - skip_whitespace (p); + expression (& exp); - if (*p != '}') - { - inst.error = _("'}' expected at end of 'option' field"); - return FAIL; - } - else - { - p++; - inst.instruction |= option; - inst.instruction |= INDEX_UP; - } - } - else - { - inst.error = _("non-constant expressions for 'option' field not supported"); - return FAIL; - } - } - else - { - inst.error = _("# or { expected after comma"); - return FAIL; - } - } + if (exp.X_op != O_symbol) + emit_expr (&exp, (unsigned int) nbytes); else { - /* '['Rn, #expr']'[!] */ - - if (skip_past_comma (& p) == FAIL) + char *before_reloc = input_line_pointer; + reloc = parse_reloc (&input_line_pointer); + if (reloc == -1) { - inst.error = _("pre-indexed expression expected"); - return FAIL; + as_bad (_("unrecognized relocation suffix")); + ignore_rest_of_line (); + return; } - - pre_inc = PRE_INDEX; - - if (cp_address_offset (& p) == FAIL) - return FAIL; - - skip_whitespace (p); - - if (*p++ != ']') + else if (reloc == BFD_RELOC_UNUSED) + emit_expr (&exp, (unsigned int) nbytes); + else { - inst.error = _("missing ]"); - return FAIL; - } - - skip_whitespace (p); + reloc_howto_type *howto = bfd_reloc_type_lookup (stdoutput, reloc); + int size = bfd_get_reloc_size (howto); - if (wb_ok && *p == '!') - { - if (reg == REG_PC) + if (size > nbytes) + as_bad ("%s relocations do not fit in %d bytes", + howto->name, nbytes); + else { - inst.error = _("pc may not be used with write-back"); - return FAIL; + /* We've parsed an expression stopping at O_symbol. + But there may be more expression left now that we + have parsed the relocation marker. Parse it again. + XXX Surely there is a cleaner way to do this. */ + char *p = input_line_pointer; + int offset; + char *save_buf = alloca (input_line_pointer - base); + memcpy (save_buf, base, input_line_pointer - base); + memmove (base + (input_line_pointer - before_reloc), + base, before_reloc - base); + + input_line_pointer = base + (input_line_pointer-before_reloc); + expression (&exp); + memcpy (base, save_buf, p - base); + + offset = nbytes - size; + p = frag_more ((int) nbytes); + fix_new_exp (frag_now, p - frag_now->fr_literal + offset, + size, &exp, 0, reloc); } - - p++; - write_back = WRITE_BACK; } } } - else - { - if (my_get_expression (&inst.reloc.exp, &p)) - return FAIL; - - inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM; - inst.reloc.exp.X_add_number -= 8; /* PC rel adjust. */ - inst.reloc.pc_rel = 1; - inst.instruction |= (REG_PC << 16); - pre_inc = PRE_INDEX; - } + while (*input_line_pointer++ == ','); - inst.instruction |= write_back | pre_inc; - *str = p; - return SUCCESS; + /* Put terminator back into stream. */ + input_line_pointer --; + demand_empty_rest_of_line (); } -static int -cp_byte_address_offset (char ** str) -{ - int offset; - skip_whitespace (* str); - - if (! is_immediate_prefix (**str)) - { - inst.error = _("immediate expression expected"); - return FAIL; - } +/* Parse a .rel31 directive. */ - (*str)++; +static void +s_arm_rel31 (int ignored ATTRIBUTE_UNUSED) +{ + expressionS exp; + char *p; + valueT highbit; - if (my_get_expression (& inst.reloc.exp, str)) - return FAIL; + highbit = 0; + if (*input_line_pointer == '1') + highbit = 0x80000000; + else if (*input_line_pointer != '0') + as_bad (_("expected 0 or 1")); - if (inst.reloc.exp.X_op == O_constant) - { - offset = inst.reloc.exp.X_add_number; + input_line_pointer++; + if (*input_line_pointer != ',') + as_bad (_("missing comma")); + input_line_pointer++; - if (offset > 255 || offset < -255) - { - inst.error = _("offset too large"); - return FAIL; - } +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif - if (offset >= 0) - inst.instruction |= INDEX_UP; - else - offset = -offset; +#ifdef md_cons_align + md_cons_align (4); +#endif - inst.instruction |= offset; - } - else - inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM_S2; + mapping_state (MAP_DATA); - return SUCCESS; -} + expression (&exp); -static int -cp_byte_address_required_here (char ** str) -{ - char * p = * str; - int pre_inc = 0; - int write_back = 0; + p = frag_more (4); + md_number_to_chars (p, highbit, 4); + fix_new_arm (frag_now, p - frag_now->fr_literal, 4, &exp, 1, + BFD_RELOC_ARM_PREL31); - if (*p == '[') - { - int reg; + demand_empty_rest_of_line (); +} - p++; - skip_whitespace (p); +/* Directives: AEABI stack-unwind tables. */ - if ((reg = reg_required_here (& p, 16)) == FAIL) - return FAIL; +/* Parse an unwind_fnstart directive. Simply records the current location. */ - skip_whitespace (p); +static void +s_arm_unwind_fnstart (int ignored ATTRIBUTE_UNUSED) +{ + demand_empty_rest_of_line (); + /* Mark the start of the function. */ + unwind.proc_start = expr_build_dot (); - if (*p == ']') - { - p++; - - if (skip_past_comma (& p) == SUCCESS) - { - /* [Rn], #expr */ - write_back = WRITE_BACK; - - if (reg == REG_PC) - { - inst.error = _("pc may not be used in post-increment"); - return FAIL; - } - - if (cp_byte_address_offset (& p) == FAIL) - return FAIL; - } - else - pre_inc = PRE_INDEX | INDEX_UP; - } - else - { - /* '['Rn, #expr']'[!] */ + /* Reset the rest of the unwind info. */ + unwind.opcode_count = 0; + unwind.table_entry = NULL; + unwind.personality_routine = NULL; + unwind.personality_index = -1; + unwind.frame_size = 0; + unwind.fp_offset = 0; + unwind.fp_reg = 13; + unwind.fp_used = 0; + unwind.sp_restored = 0; +} - if (skip_past_comma (& p) == FAIL) - { - inst.error = _("pre-indexed expression expected"); - return FAIL; - } - pre_inc = PRE_INDEX; +/* Parse a handlerdata directive. Creates the exception handling table entry + for the function. */ - if (cp_byte_address_offset (& p) == FAIL) - return FAIL; +static void +s_arm_unwind_handlerdata (int ignored ATTRIBUTE_UNUSED) +{ + demand_empty_rest_of_line (); + if (unwind.table_entry) + as_bad (_("dupicate .handlerdata directive")); - skip_whitespace (p); + create_unwind_entry (1); +} - if (*p++ != ']') - { - inst.error = _("missing ]"); - return FAIL; - } +/* Parse an unwind_fnend directive. Generates the index table entry. */ - skip_whitespace (p); +static void +s_arm_unwind_fnend (int ignored ATTRIBUTE_UNUSED) +{ + long where; + char *ptr; + valueT val; - if (*p == '!') - { - if (reg == REG_PC) - { - inst.error = _("pc may not be used with write-back"); - return FAIL; - } + demand_empty_rest_of_line (); - p++; - write_back = WRITE_BACK; - } - } - } + /* Add eh table entry. */ + if (unwind.table_entry == NULL) + val = create_unwind_entry (0); else - { - if (my_get_expression (&inst.reloc.exp, &p)) - return FAIL; + val = 0; - inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM_S2; - inst.reloc.exp.X_add_number -= 8; /* PC rel adjust. */ - inst.reloc.pc_rel = 1; - inst.instruction |= (REG_PC << 16); - pre_inc = PRE_INDEX; - } + /* Add index table entry. This is two words. */ + start_unwind_section (unwind.saved_seg, 1); + frag_align (2, 0, 0); + record_alignment (now_seg, 2); - inst.instruction |= write_back | pre_inc; - *str = p; - return SUCCESS; -} + ptr = frag_more (8); + where = frag_now_fix () - 8; -static void -do_nop (char * str) -{ - skip_whitespace (str); - if (*str == '{') + /* Self relative offset of the function start. */ + fix_new (frag_now, where, 4, unwind.proc_start, 0, 1, + BFD_RELOC_ARM_PREL31); + + /* Indicate dependency on EHABI-defined personality routines to the + linker, if it hasn't been done already. */ + if (unwind.personality_index >= 0 && unwind.personality_index < 3 + && !(marked_pr_dependency & (1 << unwind.personality_index))) { - str++; + static const char *const name[] = { + "__aeabi_unwind_cpp_pr0", + "__aeabi_unwind_cpp_pr1", + "__aeabi_unwind_cpp_pr2" + }; + symbolS *pr = symbol_find_or_make (name[unwind.personality_index]); + fix_new (frag_now, where, 0, pr, 0, 1, BFD_RELOC_NONE); + marked_pr_dependency |= 1 << unwind.personality_index; + seg_info (now_seg)->tc_segment_info_data.marked_pr_dependency + = marked_pr_dependency; + } - if (my_get_expression (&inst.reloc.exp, &str)) - inst.reloc.exp.X_op = O_illegal; - else - { - skip_whitespace (str); - if (*str == '}') - str++; - else - inst.reloc.exp.X_op = O_illegal; - } + if (val) + /* Inline exception table entry. */ + md_number_to_chars (ptr + 4, val, 4); + else + /* Self relative offset of the table entry. */ + fix_new (frag_now, where + 4, 4, unwind.table_entry, 0, 1, + BFD_RELOC_ARM_PREL31); - if (inst.reloc.exp.X_op != O_constant - || inst.reloc.exp.X_add_number > 255 - || inst.reloc.exp.X_add_number < 0) - { - inst.error = _("Invalid NOP hint"); - return; - } + /* Restore the original section. */ + subseg_set (unwind.saved_seg, unwind.saved_subseg); +} - /* Arcitectural NOP hints are CPSR sets with no bits selected. */ - inst.instruction &= 0xf0000000; - inst.instruction |= 0x0320f000 + inst.reloc.exp.X_add_number; - } - end_of_line (str); -} +/* Parse an unwind_cantunwind directive. */ static void -do_empty (char * str) +s_arm_unwind_cantunwind (int ignored ATTRIBUTE_UNUSED) { - /* Do nothing really. */ - end_of_line (str); + demand_empty_rest_of_line (); + if (unwind.personality_routine || unwind.personality_index != -1) + as_bad (_("personality routine specified for cantunwind frame")); + + unwind.personality_index = -2; } -static void -do_mrs (char * str) -{ - int skip = 0; - /* Only one syntax. */ - skip_whitespace (str); +/* Parse a personalityindex directive. */ - if (reg_required_here (&str, 12) == FAIL) - { - inst.error = BAD_ARGS; - return; - } +static void +s_arm_unwind_personalityindex (int ignored ATTRIBUTE_UNUSED) +{ + expressionS exp; - if (skip_past_comma (&str) == FAIL) - { - inst.error = _("comma expected after register name"); - return; - } + if (unwind.personality_routine || unwind.personality_index != -1) + as_bad (_("duplicate .personalityindex directive")); - skip_whitespace (str); + expression (&exp); - if ( streq (str, "CPSR") - || streq (str, "SPSR") - /* Lower case versions for backwards compatibility. */ - || streq (str, "cpsr") - || streq (str, "spsr")) - skip = 4; - - /* This is for backwards compatibility with older toolchains. */ - else if ( streq (str, "cpsr_all") - || streq (str, "spsr_all")) - skip = 8; - else + if (exp.X_op != O_constant + || exp.X_add_number < 0 || exp.X_add_number > 15) { - inst.error = _("CPSR or SPSR expected"); + as_bad (_("bad personality routine number")); + ignore_rest_of_line (); return; } - if (* str == 's' || * str == 'S') - inst.instruction |= SPSR_BIT; - str += skip; + unwind.personality_index = exp.X_add_number; - end_of_line (str); + demand_empty_rest_of_line (); } -/* Two possible forms: - "{C|S}PSR_<field>, Rm", - "{C|S}PSR_f, #expression". */ + +/* Parse a personality directive. */ static void -do_msr (char * str) +s_arm_unwind_personality (int ignored ATTRIBUTE_UNUSED) { - skip_whitespace (str); - - if (psr_required_here (& str) == FAIL) - return; + char *name, *p, c; - if (skip_past_comma (& str) == FAIL) - { - inst.error = _("comma missing after psr flags"); - return; - } + if (unwind.personality_routine || unwind.personality_index != -1) + as_bad (_("duplicate .personality directive")); - skip_whitespace (str); + name = input_line_pointer; + c = get_symbol_end (); + p = input_line_pointer; + unwind.personality_routine = symbol_find_or_make (name); + *p = c; + demand_empty_rest_of_line (); +} - if (reg_required_here (& str, 0) != FAIL) - { - inst.error = NULL; - end_of_line (str); - return; - } - if (! is_immediate_prefix (* str)) - { - inst.error = - _("only a register or immediate value can follow a psr flag"); - return; - } +/* Parse a directive saving core registers. */ - str ++; - inst.error = NULL; +static void +s_arm_unwind_save_core (void) +{ + valueT op; + long range; + int n; - if (my_get_expression (& inst.reloc.exp, & str)) + range = parse_reg_list (&input_line_pointer); + if (range == FAIL) { - inst.error = - _("only a register or immediate value can follow a psr flag"); + as_bad (_("expected register list")); + ignore_rest_of_line (); return; } - inst.instruction |= INST_IMMEDIATE; + demand_empty_rest_of_line (); - if (inst.reloc.exp.X_add_symbol) - { - inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE; - inst.reloc.pc_rel = 0; - } - else + /* Turn .unwind_movsp ip followed by .unwind_save {..., ip, ...} + into .unwind_save {..., sp...}. We aren't bothered about the value of + ip because it is clobbered by calls. */ + if (unwind.sp_restored && unwind.fp_reg == 12 + && (range & 0x3000) == 0x1000) { - unsigned value = validate_immediate (inst.reloc.exp.X_add_number); - - if (value == (unsigned) FAIL) - { - inst.error = _("invalid constant"); - return; - } - - inst.instruction |= value; + unwind.opcode_count--; + unwind.sp_restored = 0; + range = (range | 0x2000) & ~0x1000; + unwind.pending_offset = 0; } - inst.error = NULL; - end_of_line (str); -} - -/* Long Multiply Parser - UMULL RdLo, RdHi, Rm, Rs - SMULL RdLo, RdHi, Rm, Rs - UMLAL RdLo, RdHi, Rm, Rs - SMLAL RdLo, RdHi, Rm, Rs. */ - -static void -do_mull (char * str) -{ - int rdlo, rdhi, rm, rs; - - /* Only one format "rdlo, rdhi, rm, rs". */ - skip_whitespace (str); - - if ((rdlo = reg_required_here (&str, 12)) == FAIL) + /* See if we can use the short opcodes. These pop a block of upto 8 + registers starting with r4, plus maybe r14. */ + for (n = 0; n < 8; n++) { - inst.error = BAD_ARGS; - return; + /* Break at the first non-saved register. */ + if ((range & (1 << (n + 4))) == 0) + break; } - - if (skip_past_comma (&str) == FAIL - || (rdhi = reg_required_here (&str, 16)) == FAIL) + /* See if there are any other bits set. */ + if (n == 0 || (range & (0xfff0 << n) & 0xbff0) != 0) { - inst.error = BAD_ARGS; - return; + /* Use the long form. */ + op = 0x8000 | ((range >> 4) & 0xfff); + add_unwind_opcode (op, 2); } - - if (skip_past_comma (&str) == FAIL - || (rm = reg_required_here (&str, 0)) == FAIL) + else { - inst.error = BAD_ARGS; - return; + /* Use the short form. */ + if (range & 0x4000) + op = 0xa8; /* Pop r14. */ + else + op = 0xa0; /* Do not pop r14. */ + op |= (n - 1); + add_unwind_opcode (op, 1); } - /* rdhi, rdlo and rm must all be different. */ - if (rdlo == rdhi || rdlo == rm || rdhi == rm) - as_tsktsk (_("rdhi, rdlo and rm must all be different")); - - if (skip_past_comma (&str) == FAIL - || (rs = reg_required_here (&str, 8)) == FAIL) + /* Pop r0-r3. */ + if (range & 0xf) { - inst.error = BAD_ARGS; - return; + op = 0xb100 | (range & 0xf); + add_unwind_opcode (op, 2); } - if (rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC) + /* Record the number of bytes pushed. */ + for (n = 0; n < 16; n++) { - inst.error = BAD_PC; - return; + if (range & (1 << n)) + unwind.frame_size += 4; } - - end_of_line (str); } + +/* Parse a directive saving FPA registers. */ + static void -do_mul (char * str) +s_arm_unwind_save_fpa (int reg) { - int rd, rm; - - /* Only one format "rd, rm, rs". */ - skip_whitespace (str); + expressionS exp; + int num_regs; + valueT op; - if ((rd = reg_required_here (&str, 16)) == FAIL) - { - inst.error = BAD_ARGS; - return; - } + /* Get Number of registers to transfer. */ + if (skip_past_comma (&input_line_pointer) != FAIL) + expression (&exp); + else + exp.X_op = O_illegal; - if (rd == REG_PC) + if (exp.X_op != O_constant) { - inst.error = BAD_PC; + as_bad (_("expected , <constant>")); + ignore_rest_of_line (); return; } - if (skip_past_comma (&str) == FAIL - || (rm = reg_required_here (&str, 0)) == FAIL) - { - inst.error = BAD_ARGS; - return; - } + num_regs = exp.X_add_number; - if (rm == REG_PC) + if (num_regs < 1 || num_regs > 4) { - inst.error = BAD_PC; + as_bad (_("number of registers must be in the range [1:4]")); + ignore_rest_of_line (); return; } - if (rm == rd) - as_tsktsk (_("rd and rm should be different in mul")); + demand_empty_rest_of_line (); - if (skip_past_comma (&str) == FAIL - || (rm = reg_required_here (&str, 8)) == FAIL) + if (reg == 4) { - inst.error = BAD_ARGS; - return; + /* Short form. */ + op = 0xb4 | (num_regs - 1); + add_unwind_opcode (op, 1); } - - if (rm == REG_PC) + else { - inst.error = BAD_PC; - return; + /* Long form. */ + op = 0xc800 | (reg << 4) | (num_regs - 1); + add_unwind_opcode (op, 2); } - - end_of_line (str); + unwind.frame_size += num_regs * 12; } -static void -do_mlas (char * str, bfd_boolean is_mls) -{ - int rd, rm; - - /* Only one format "rd, rm, rs, rn". */ - skip_whitespace (str); - - if ((rd = reg_required_here (&str, 16)) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - if (rd == REG_PC) - { - inst.error = BAD_PC; - return; - } +/* Parse a directive saving VFP registers. */ - if (skip_past_comma (&str) == FAIL - || (rm = reg_required_here (&str, 0)) == FAIL) - { - inst.error = BAD_ARGS; - return; - } +static void +s_arm_unwind_save_vfp (void) +{ + int count; + int reg; + valueT op; - if (rm == REG_PC) + count = parse_vfp_reg_list (&input_line_pointer, ®, 1); + if (count == FAIL) { - inst.error = BAD_PC; + as_bad (_("expected register list")); + ignore_rest_of_line (); return; } - /* This restriction does not apply to mls (nor to mla in v6, but - that's hard to detect at present). */ - if (rm == rd && !is_mls) - as_tsktsk (_("rd and rm should be different in mla")); + demand_empty_rest_of_line (); - if (skip_past_comma (&str) == FAIL - || (rd = reg_required_here (&str, 8)) == FAIL - || skip_past_comma (&str) == FAIL - || (rm = reg_required_here (&str, 12)) == FAIL) + if (reg == 8) { - inst.error = BAD_ARGS; - return; + /* Short form. */ + op = 0xb8 | (count - 1); + add_unwind_opcode (op, 1); } - - if (rd == REG_PC || rm == REG_PC) + else { - inst.error = BAD_PC; - return; + /* Long form. */ + op = 0xb300 | (reg << 4) | (count - 1); + add_unwind_opcode (op, 2); } - - end_of_line (str); -} - -static void -do_mla (char *str) -{ - do_mlas (str, FALSE); -} - -static void -do_mls (char *str) -{ - do_mlas (str, TRUE); + unwind.frame_size += count * 8 + 4; } -/* Expects *str -> the characters "acc0", possibly with leading blanks. - Advances *str to the next non-alphanumeric. - Returns 0, or else FAIL (in which case sets inst.error). - (In a future XScale, there may be accumulators other than zero. - At that time this routine and its callers can be upgraded to suit.) */ +/* Parse a directive saving iWMMXt data registers. */ -static int -accum0_required_here (char ** str) +static void +s_arm_unwind_save_mmxwr (void) { - static char buff [128]; /* Note the address is taken. Hence, static. */ - char * p = * str; - char c; - int result = 0; /* The accum number. */ - - skip_whitespace (p); - - *str = p; /* Advance caller's string pointer too. */ - c = *p++; - while (ISALNUM (c)) - c = *p++; + int reg; + int hi_reg; + int i; + unsigned mask = 0; + valueT op; - *--p = 0; /* Aap nul into input buffer at non-alnum. */ + if (*input_line_pointer == '{') + input_line_pointer++; - if (! ( streq (*str, "acc0") || streq (*str, "ACC0"))) + do { - sprintf (buff, _("acc0 expected, not '%.100s'"), *str); - inst.error = buff; - result = FAIL; - } - - *p = c; /* Unzap. */ - *str = p; /* Caller's string pointer to after match. */ - return result; -} + reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWR); -static int -ldst_extend_v4 (char ** str) -{ - int add = INDEX_UP; + if (reg == FAIL) + { + as_bad (_(reg_expected_msgs[REG_TYPE_MMXWR])); + goto error; + } - switch (**str) - { - case '#': - case '$': - (*str)++; - if (my_get_expression (& inst.reloc.exp, str)) - return FAIL; + if (mask >> reg) + as_tsktsk (_("register list not in ascending order")); + mask |= 1 << reg; - if (inst.reloc.exp.X_op == O_constant) + if (*input_line_pointer == '-') { - int value = inst.reloc.exp.X_add_number; - - if (value < -255 || value > 255) + input_line_pointer++; + hi_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWR); + if (hi_reg == FAIL) { - inst.error = _("address offset too large"); - return FAIL; + as_bad (_(reg_expected_msgs[REG_TYPE_MMXWR])); + goto error; } - - if (value < 0) + else if (reg >= hi_reg) { - value = -value; - add = 0; + as_bad (_("bad register range")); + goto error; } - - /* Halfword and signextension instructions have the - immediate value split across bits 11..8 and bits 3..0. */ - inst.instruction |= (add | HWOFFSET_IMM - | ((value >> 4) << 8) | (value & 0xF)); + for (; reg < hi_reg; reg++) + mask |= 1 << reg; } - else - { - inst.instruction |= HWOFFSET_IMM; - inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8; - inst.reloc.pc_rel = 0; - } - return SUCCESS; - - case '-': - add = 0; - /* Fall through. */ - - case '+': - (*str)++; - /* Fall through. */ - - default: - if (reg_required_here (str, 0) == FAIL) - return FAIL; - - inst.instruction |= add; - return SUCCESS; } -} - -/* Expects **str -> after a comma. May be leading blanks. - Advances *str, recognizing a load mode, and setting inst.instruction. - Returns rn, or else FAIL (in which case may set inst.error - and not advance str) + while (skip_past_comma (&input_line_pointer) != FAIL); - Note: doesn't know Rd, so no err checks that require such knowledge. */ + if (*input_line_pointer == '}') + input_line_pointer++; -static int -ld_mode_required_here (char ** string) -{ - char * str = * string; - int rn; - int pre_inc = 0; + demand_empty_rest_of_line (); - skip_whitespace (str); + /* Generate any deferred opcodes becuuse we're going to be looking at + the list. */ + flush_pending_unwind (); - if (* str == '[') + for (i = 0; i < 16; i++) { - str++; - - skip_whitespace (str); - - if ((rn = reg_required_here (& str, 16)) == FAIL) - return FAIL; - - skip_whitespace (str); + if (mask & (1 << i)) + unwind.frame_size += 8; + } - if (* str == ']') + /* Attempt to combine with a previous opcode. We do this because gcc + likes to output separate unwind directives for a single block of + registers. */ + if (unwind.opcode_count > 0) + { + i = unwind.opcodes[unwind.opcode_count - 1]; + if ((i & 0xf8) == 0xc0) { - str ++; - - if (skip_past_comma (& str) == SUCCESS) + i &= 7; + /* Only merge if the blocks are contiguous. */ + if (i < 6) { - /* [Rn],... (post inc) */ - if (ldst_extend_v4 (&str) == FAIL) - return FAIL; + if ((mask & 0xfe00) == (1 << 9)) + { + mask |= ((1 << (i + 11)) - 1) & 0xfc00; + unwind.opcode_count--; + } } - else /* [Rn] */ + else if (i == 6 && unwind.opcode_count >= 2) { - skip_whitespace (str); + i = unwind.opcodes[unwind.opcode_count - 2]; + reg = i >> 4; + i &= 0xf; - if (* str == '!') + op = 0xffff << (reg - 1); + if (reg > 0 + || ((mask & op) == (1u << (reg - 1)))) { - str ++; - inst.instruction |= WRITE_BACK; + op = (1 << (reg + i + 1)) - 1; + op &= ~((1 << reg) - 1); + mask |= op; + unwind.opcode_count -= 2; } - - inst.instruction |= INDEX_UP | HWOFFSET_IMM; - pre_inc = 1; } } - else /* [Rn,...] */ + } + + hi_reg = 15; + /* We want to generate opcodes in the order the registers have been + saved, ie. descending order. */ + for (reg = 15; reg >= -1; reg--) + { + /* Save registers in blocks. */ + if (reg < 0 + || !(mask & (1 << reg))) { - if (skip_past_comma (& str) == FAIL) + /* We found an unsaved reg. Generate opcodes to save the + preceeding block. */ + if (reg != hi_reg) { - inst.error = _("pre-indexed expression expected"); - return FAIL; + if (reg == 9) + { + /* Short form. */ + op = 0xc0 | (hi_reg - 10); + add_unwind_opcode (op, 1); + } + else + { + /* Long form. */ + op = 0xc600 | ((reg + 1) << 4) | ((hi_reg - reg) - 1); + add_unwind_opcode (op, 2); + } } + hi_reg = reg - 1; + } + } - pre_inc = 1; + return; +error: + ignore_rest_of_line (); +} - if (ldst_extend_v4 (&str) == FAIL) - return FAIL; +static void +s_arm_unwind_save_mmxwcg (void) +{ + int reg; + int hi_reg; + unsigned mask = 0; + valueT op; - skip_whitespace (str); + if (*input_line_pointer == '{') + input_line_pointer++; - if (* str ++ != ']') - { - inst.error = _("missing ]"); - return FAIL; - } + do + { + reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWCG); - skip_whitespace (str); + if (reg == FAIL) + { + as_bad (_(reg_expected_msgs[REG_TYPE_MMXWCG])); + goto error; + } - if (* str == '!') + reg -= 8; + if (mask >> reg) + as_tsktsk (_("register list not in ascending order")); + mask |= 1 << reg; + + if (*input_line_pointer == '-') + { + input_line_pointer++; + hi_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWCG); + if (hi_reg == FAIL) { - str ++; - inst.instruction |= WRITE_BACK; + as_bad (_(reg_expected_msgs[REG_TYPE_MMXWCG])); + goto error; } + else if (reg >= hi_reg) + { + as_bad (_("bad register range")); + goto error; + } + for (; reg < hi_reg; reg++) + mask |= 1 << reg; } } - else if (* str == '=') /* ldr's "r,=label" syntax */ - /* We should never reach here, because <text> = <expression> is - caught gas/read.c read_a_source_file() as a .set operation. */ - return FAIL; - else /* PC +- 8 bit immediate offset. */ - { - if (my_get_expression (& inst.reloc.exp, & str)) - return FAIL; + while (skip_past_comma (&input_line_pointer) != FAIL); - inst.instruction |= HWOFFSET_IMM; /* The I bit. */ - inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8; - inst.reloc.exp.X_add_number -= 8; /* PC rel adjust. */ - inst.reloc.pc_rel = 1; - inst.instruction |= (REG_PC << 16); + if (*input_line_pointer == '}') + input_line_pointer++; - rn = REG_PC; - pre_inc = 1; - } + demand_empty_rest_of_line (); - inst.instruction |= (pre_inc ? PRE_INDEX : 0); - * string = str; + /* Generate any deferred opcodes becuuse we're going to be looking at + the list. */ + flush_pending_unwind (); - return rn; + for (reg = 0; reg < 16; reg++) + { + if (mask & (1 << reg)) + unwind.frame_size += 4; + } + op = 0xc700 | mask; + add_unwind_opcode (op, 2); + return; +error: + ignore_rest_of_line (); } -/* ARM V5E (El Segundo) signed-multiply-accumulate (argument parse) - SMLAxy{cond} Rd,Rm,Rs,Rn - SMLAWy{cond} Rd,Rm,Rs,Rn - Error if any register is R15. */ - -static void -do_smla (char * str) -{ - int rd, rm, rs, rn; - - skip_whitespace (str); - - if ((rd = reg_required_here (& str, 16)) == FAIL - || skip_past_comma (& str) == FAIL - || (rm = reg_required_here (& str, 0)) == FAIL - || skip_past_comma (& str) == FAIL - || (rs = reg_required_here (& str, 8)) == FAIL - || skip_past_comma (& str) == FAIL - || (rn = reg_required_here (& str, 12)) == FAIL) - inst.error = BAD_ARGS; - - else if (rd == REG_PC || rm == REG_PC || rs == REG_PC || rn == REG_PC) - inst.error = BAD_PC; - else - end_of_line (str); -} - -/* ARM V5E (El Segundo) signed-multiply-accumulate-long (argument parse) - SMLALxy{cond} Rdlo,Rdhi,Rm,Rs - Error if any register is R15. - Warning if Rdlo == Rdhi. */ +/* Parse an unwind_save directive. */ static void -do_smlal (char * str) +s_arm_unwind_save (int ignored ATTRIBUTE_UNUSED) { - int rdlo, rdhi, rm, rs; + char *peek; + struct reg_entry *reg; + bfd_boolean had_brace = FALSE; - skip_whitespace (str); + /* Figure out what sort of save we have. */ + peek = input_line_pointer; - if ((rdlo = reg_required_here (& str, 12)) == FAIL - || skip_past_comma (& str) == FAIL - || (rdhi = reg_required_here (& str, 16)) == FAIL - || skip_past_comma (& str) == FAIL - || (rm = reg_required_here (& str, 0)) == FAIL - || skip_past_comma (& str) == FAIL - || (rs = reg_required_here (& str, 8)) == FAIL) + if (*peek == '{') { - inst.error = BAD_ARGS; - return; + had_brace = TRUE; + peek++; } - if (rdlo == REG_PC || rdhi == REG_PC || rm == REG_PC || rs == REG_PC) + reg = arm_reg_parse_multi (&peek); + + if (!reg) { - inst.error = BAD_PC; + as_bad (_("register expected")); + ignore_rest_of_line (); return; } - if (rdlo == rdhi) - as_tsktsk (_("rdhi and rdlo must be different")); - - end_of_line (str); -} - -/* ARM V5E (El Segundo) signed-multiply (argument parse) - SMULxy{cond} Rd,Rm,Rs - Error if any register is R15. */ - -static void -do_smul (char * str) -{ - int rd, rm, rs; - - skip_whitespace (str); - - if ((rd = reg_required_here (& str, 16)) == FAIL - || skip_past_comma (& str) == FAIL - || (rm = reg_required_here (& str, 0)) == FAIL - || skip_past_comma (& str) == FAIL - || (rs = reg_required_here (& str, 8)) == FAIL) - inst.error = BAD_ARGS; - - else if (rd == REG_PC || rm == REG_PC || rs == REG_PC) - inst.error = BAD_PC; - - else - end_of_line (str); -} - -/* ARM V5E (El Segundo) saturating-add/subtract (argument parse) - Q[D]{ADD,SUB}{cond} Rd,Rm,Rn - Error if any register is R15. */ - -static void -do_qadd (char * str) -{ - int rd, rm, rn; - - skip_whitespace (str); - - if ((rd = reg_required_here (& str, 12)) == FAIL - || skip_past_comma (& str) == FAIL - || (rm = reg_required_here (& str, 0)) == FAIL - || skip_past_comma (& str) == FAIL - || (rn = reg_required_here (& str, 16)) == FAIL) - inst.error = BAD_ARGS; + switch (reg->type) + { + case REG_TYPE_FN: + if (had_brace) + { + as_bad (_("FPA .unwind_save does not take a register list")); + ignore_rest_of_line (); + return; + } + s_arm_unwind_save_fpa (reg->number); + return; - else if (rd == REG_PC || rm == REG_PC || rn == REG_PC) - inst.error = BAD_PC; + case REG_TYPE_RN: s_arm_unwind_save_core (); return; + case REG_TYPE_VFD: s_arm_unwind_save_vfp (); return; + case REG_TYPE_MMXWR: s_arm_unwind_save_mmxwr (); return; + case REG_TYPE_MMXWCG: s_arm_unwind_save_mmxwcg (); return; - else - end_of_line (str); + default: + as_bad (_(".unwind_save does not support this kind of register")); + ignore_rest_of_line (); + } } -/* ARM V5E (el Segundo) - MCRRcc <coproc>, <opcode>, <Rd>, <Rn>, <CRm>. - MRRCcc <coproc>, <opcode>, <Rd>, <Rn>, <CRm>. - - These are equivalent to the XScale instructions MAR and MRA, - respectively, when coproc == 0, opcode == 0, and CRm == 0. - Result unpredicatable if Rd or Rn is R15. */ +/* Parse an unwind_movsp directive. */ static void -do_co_reg2c (char * str) +s_arm_unwind_movsp (int ignored ATTRIBUTE_UNUSED) { - int rd, rn; - - skip_whitespace (str); - - if (co_proc_number (& str) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (& str) == FAIL - || cp_opc_expr (& str, 4, 4) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } + int reg; + valueT op; - if (skip_past_comma (& str) == FAIL - || (rd = reg_required_here (& str, 12)) == FAIL) + reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN); + if (reg == FAIL) { - if (!inst.error) - inst.error = BAD_ARGS; + as_bad (_(reg_expected_msgs[REG_TYPE_RN])); + ignore_rest_of_line (); return; } + demand_empty_rest_of_line (); - if (skip_past_comma (& str) == FAIL - || (rn = reg_required_here (& str, 16)) == FAIL) + if (reg == REG_SP || reg == REG_PC) { - if (!inst.error) - inst.error = BAD_ARGS; + as_bad (_("SP and PC not permitted in .unwind_movsp directive")); return; } - /* Unpredictable result if rd or rn is R15. */ - if (rd == REG_PC || rn == REG_PC) - as_tsktsk - (_("Warning: instruction unpredictable when using r15")); + if (unwind.fp_reg != REG_SP) + as_bad (_("unexpected .unwind_movsp directive")); - if (skip_past_comma (& str) == FAIL - || cp_reg_required_here (& str, 0) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } + /* Generate opcode to restore the value. */ + op = 0x90 | reg; + add_unwind_opcode (op, 1); - end_of_line (str); + /* Record the information for later. */ + unwind.fp_reg = reg; + unwind.fp_offset = unwind.frame_size; + unwind.sp_restored = 1; } -/* ARM V5 count-leading-zeroes instruction (argument parse) - CLZ{<cond>} <Rd>, <Rm> - Condition defaults to COND_ALWAYS. - Error if Rd or Rm are R15. */ +/* Parse an unwind_pad directive. */ static void -do_clz (char * str) +s_arm_unwind_pad (int ignored ATTRIBUTE_UNUSED) { - int rd, rm; + int offset; - skip_whitespace (str); + if (immediate_for_directive (&offset) == FAIL) + return; - if (((rd = reg_required_here (& str, 12)) == FAIL) - || (skip_past_comma (& str) == FAIL) - || ((rm = reg_required_here (& str, 0)) == FAIL)) - inst.error = BAD_ARGS; + if (offset & 3) + { + as_bad (_("stack increment must be multiple of 4")); + ignore_rest_of_line (); + return; + } - else if (rd == REG_PC || rm == REG_PC ) - inst.error = BAD_PC; + /* Don't generate any opcodes, just record the details for later. */ + unwind.frame_size += offset; + unwind.pending_offset += offset; - else - end_of_line (str); + demand_empty_rest_of_line (); } -/* ARM V5 (argument parse) - LDC2{L} <coproc>, <CRd>, <addressing mode> - STC2{L} <coproc>, <CRd>, <addressing mode> - Instruction is not conditional, and has 0xf in the condition field. - Otherwise, it's the same as LDC/STC. */ +/* Parse an unwind_setfp directive. */ static void -do_lstc2 (char * str) +s_arm_unwind_setfp (int ignored ATTRIBUTE_UNUSED) { - skip_whitespace (str); + int sp_reg; + int fp_reg; + int offset; - if (co_proc_number (& str) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - } - else if (skip_past_comma (& str) == FAIL - || cp_reg_required_here (& str, 12) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - } - else if (skip_past_comma (& str) == FAIL - || cp_address_required_here (&str, CP_WB_OK) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - } + fp_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN); + if (skip_past_comma (&input_line_pointer) == FAIL) + sp_reg = FAIL; else - end_of_line (str); -} - -/* ARM V5 (argument parse) - CDP2 <coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>, <opcode_2> - Instruction is not conditional, and has 0xf in the condition field. - Otherwise, it's the same as CDP. */ + sp_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN); -static void -do_cdp2 (char * str) -{ - skip_whitespace (str); - - if (co_proc_number (& str) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (& str) == FAIL - || cp_opc_expr (& str, 20,4) == FAIL) + if (fp_reg == FAIL || sp_reg == FAIL) { - if (!inst.error) - inst.error = BAD_ARGS; + as_bad (_("expected <reg>, <reg>")); + ignore_rest_of_line (); return; } - if (skip_past_comma (& str) == FAIL - || cp_reg_required_here (& str, 12) == FAIL) + /* Optional constant. */ + if (skip_past_comma (&input_line_pointer) != FAIL) { - if (!inst.error) - inst.error = BAD_ARGS; - return; + if (immediate_for_directive (&offset) == FAIL) + return; } + else + offset = 0; - if (skip_past_comma (& str) == FAIL - || cp_reg_required_here (& str, 16) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } + demand_empty_rest_of_line (); - if (skip_past_comma (& str) == FAIL - || cp_reg_required_here (& str, 0) == FAIL) + if (sp_reg != 13 && sp_reg != unwind.fp_reg) { - if (!inst.error) - inst.error = BAD_ARGS; + as_bad (_("register must be either sp or set by a previous" + "unwind_movsp directive")); return; } - if (skip_past_comma (& str) == SUCCESS) - { - if (cp_opc_expr (& str, 5, 3) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - } - - end_of_line (str); + /* Don't generate any opcodes, just record the information for later. */ + unwind.fp_reg = fp_reg; + unwind.fp_used = 1; + if (sp_reg == 13) + unwind.fp_offset = unwind.frame_size - offset; + else + unwind.fp_offset -= offset; } -/* ARM V5 (argument parse) - MCR2 <coproc>, <opcode_1>, <Rd>, <CRn>, <CRm>, <opcode_2> - MRC2 <coproc>, <opcode_1>, <Rd>, <CRn>, <CRm>, <opcode_2> - Instruction is not conditional, and has 0xf in the condition field. - Otherwise, it's the same as MCR/MRC. */ +/* Parse an unwind_raw directive. */ static void -do_co_reg2 (char * str) +s_arm_unwind_raw (int ignored ATTRIBUTE_UNUSED) { - skip_whitespace (str); - - if (co_proc_number (& str) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (& str) == FAIL - || cp_opc_expr (& str, 21, 3) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } + expressionS exp; + /* This is an arbitary limit. */ + unsigned char op[16]; + int count; - if (skip_past_comma (& str) == FAIL - || reg_required_here (& str, 12) == FAIL) + expression (&exp); + if (exp.X_op == O_constant + && skip_past_comma (&input_line_pointer) != FAIL) { - if (!inst.error) - inst.error = BAD_ARGS; - return; + unwind.frame_size += exp.X_add_number; + expression (&exp); } + else + exp.X_op = O_illegal; - if (skip_past_comma (& str) == FAIL - || cp_reg_required_here (& str, 16) == FAIL) + if (exp.X_op != O_constant) { - if (!inst.error) - inst.error = BAD_ARGS; + as_bad (_("expected <offset>, <opcode>")); + ignore_rest_of_line (); return; } - if (skip_past_comma (& str) == FAIL - || cp_reg_required_here (& str, 0) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } + count = 0; - if (skip_past_comma (& str) == SUCCESS) + /* Parse the opcode. */ + for (;;) { - if (cp_opc_expr (& str, 5, 3) == FAIL) + if (count >= 16) + { + as_bad (_("unwind opcode too long")); + ignore_rest_of_line (); + } + if (exp.X_op != O_constant || exp.X_add_number & ~0xff) { - if (!inst.error) - inst.error = BAD_ARGS; + as_bad (_("invalid unwind opcode")); + ignore_rest_of_line (); return; } - } - - end_of_line (str); -} - -static void -do_bx (char * str) -{ - int reg; + op[count++] = exp.X_add_number; - skip_whitespace (str); + /* Parse the next byte. */ + if (skip_past_comma (&input_line_pointer) == FAIL) + break; - if ((reg = reg_required_here (&str, 0)) == FAIL) - { - inst.error = BAD_ARGS; - return; + expression (&exp); } - /* Note - it is not illegal to do a "bx pc". Useless, but not illegal. */ - if (reg == REG_PC) - as_tsktsk (_("use of r15 in bx in ARM mode is not really useful")); + /* Add the opcode bytes in reverse order. */ + while (count--) + add_unwind_opcode (op[count], 1); - end_of_line (str); + demand_empty_rest_of_line (); } +#endif /* OBJ_ELF */ -/* ARM v5TEJ. Jump to Jazelle code. */ +/* 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. */ -static void -do_bxj (char * str) +const pseudo_typeS md_pseudo_table[] = { - int reg; + /* Never called because '.req' does not start a line. */ + { "req", s_req, 0 }, + { "unreq", s_unreq, 0 }, + { "bss", s_bss, 0 }, + { "align", s_align, 0 }, + { "arm", s_arm, 0 }, + { "thumb", s_thumb, 0 }, + { "code", s_code, 0 }, + { "force_thumb", s_force_thumb, 0 }, + { "thumb_func", s_thumb_func, 0 }, + { "thumb_set", s_thumb_set, 0 }, + { "even", s_even, 0 }, + { "ltorg", s_ltorg, 0 }, + { "pool", s_ltorg, 0 }, + { "syntax", s_syntax, 0 }, +#ifdef OBJ_ELF + { "word", s_arm_elf_cons, 4 }, + { "long", s_arm_elf_cons, 4 }, + { "rel31", s_arm_rel31, 0 }, + { "fnstart", s_arm_unwind_fnstart, 0 }, + { "fnend", s_arm_unwind_fnend, 0 }, + { "cantunwind", s_arm_unwind_cantunwind, 0 }, + { "personality", s_arm_unwind_personality, 0 }, + { "personalityindex", s_arm_unwind_personalityindex, 0 }, + { "handlerdata", s_arm_unwind_handlerdata, 0 }, + { "save", s_arm_unwind_save, 0 }, + { "movsp", s_arm_unwind_movsp, 0 }, + { "pad", s_arm_unwind_pad, 0 }, + { "setfp", s_arm_unwind_setfp, 0 }, + { "unwind_raw", s_arm_unwind_raw, 0 }, +#else + { "word", cons, 4}, +#endif + { "extend", float_cons, 'x' }, + { "ldouble", float_cons, 'x' }, + { "packed", float_cons, 'p' }, + { 0, 0, 0 } +}; + +/* Parser functions used exclusively in instruction operands. */ - skip_whitespace (str); +/* Generic immediate-value read function for use in insn parsing. + STR points to the beginning of the immediate (the leading #); + VAL receives the value; if the value is outside [MIN, MAX] + issue an error. PREFIX_OPT is true if the immediate prefix is + optional. */ - if ((reg = reg_required_here (&str, 0)) == FAIL) +static int +parse_immediate (char **str, int *val, int min, int max, + bfd_boolean prefix_opt) +{ + expressionS exp; + my_get_expression (&exp, str, prefix_opt ? GE_OPT_PREFIX : GE_IMM_PREFIX); + if (exp.X_op != O_constant) { - inst.error = BAD_ARGS; - return; + inst.error = _("constant expression required"); + return FAIL; } - /* Note - it is not illegal to do a "bxj pc". Useless, but not illegal. */ - if (reg == REG_PC) - as_tsktsk (_("use of r15 in bxj is not really useful")); + if (exp.X_add_number < min || exp.X_add_number > max) + { + inst.error = _("immediate value out of range"); + return FAIL; + } - end_of_line (str); + *val = exp.X_add_number; + return SUCCESS; } -/* ARM V6 umaal (argument parse). */ +/* Returns the pseudo-register number of an FPA immediate constant, + or FAIL if there isn't a valid constant here. */ -static void -do_umaal (char * str) +static int +parse_fpa_immediate (char ** str) { - int rdlo, rdhi, rm, rs; + LITTLENUM_TYPE words[MAX_LITTLENUMS]; + char * save_in; + expressionS exp; + int i; + int j; - skip_whitespace (str); - if ((rdlo = reg_required_here (& str, 12)) == FAIL - || skip_past_comma (& str) == FAIL - || (rdhi = reg_required_here (& str, 16)) == FAIL - || skip_past_comma (& str) == FAIL - || (rm = reg_required_here (& str, 0)) == FAIL - || skip_past_comma (& str) == FAIL - || (rs = reg_required_here (& str, 8)) == FAIL) - { - inst.error = BAD_ARGS; - return; - } + /* First try and match exact strings, this is to guarantee + that some formats will work even for cross assembly. */ - if (rdlo == REG_PC || rdhi == REG_PC || rm == REG_PC || rs == REG_PC) + for (i = 0; fp_const[i]; i++) { - inst.error = BAD_PC; - return; - } + if (strncmp (*str, fp_const[i], strlen (fp_const[i])) == 0) + { + char *start = *str; - end_of_line (str); -} + *str += strlen (fp_const[i]); + if (is_end_of_line[(unsigned char) **str]) + return i + 8; + *str = start; + } + } -/* ARM V6 strex (argument parse). */ + /* Just because we didn't get a match doesn't mean that the constant + isn't valid, just that it is in a format that we don't + automatically recognize. Try parsing it with the standard + expression routines. */ -static void -do_strex (char * str) -{ - int rd, rm, rn; + memset (words, 0, MAX_LITTLENUMS * sizeof (LITTLENUM_TYPE)); - /* Parse Rd, Rm,. */ - skip_whitespace (str); - if ((rd = reg_required_here (& str, 12)) == FAIL - || skip_past_comma (& str) == FAIL - || (rm = reg_required_here (& str, 0)) == FAIL - || skip_past_comma (& str) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - if (rd == REG_PC || rm == REG_PC) + /* Look for a raw floating point number. */ + if ((save_in = atof_ieee (*str, 'x', words)) != NULL + && is_end_of_line[(unsigned char) *save_in]) { - inst.error = BAD_PC; - return; + for (i = 0; i < NUM_FLOAT_VALS; i++) + { + for (j = 0; j < MAX_LITTLENUMS; j++) + { + if (words[j] != fp_values[i][j]) + break; + } + + if (j == MAX_LITTLENUMS) + { + *str = save_in; + return i + 8; + } + } } - if (rd == rm) + + /* Try and parse a more complex expression, this will probably fail + unless the code uses a floating point prefix (eg "0f"). */ + save_in = input_line_pointer; + input_line_pointer = *str; + if (expression (&exp) == absolute_section + && exp.X_op == O_big + && exp.X_add_number < 0) { - inst.error = _("Rd equal to Rm or Rn yields unpredictable results"); - return; + /* FIXME: 5 = X_PRECISION, should be #define'd where we can use it. + Ditto for 15. */ + if (gen_to_words (words, 5, (long) 15) == 0) + { + for (i = 0; i < NUM_FLOAT_VALS; i++) + { + for (j = 0; j < MAX_LITTLENUMS; j++) + { + if (words[j] != fp_values[i][j]) + break; + } + + if (j == MAX_LITTLENUMS) + { + *str = input_line_pointer; + input_line_pointer = save_in; + return i + 8; + } + } + } } - /* Skip past '['. */ - if ((strlen (str) >= 1) - && strncmp (str, "[", 1) == 0) - str += 1; + *str = input_line_pointer; + input_line_pointer = save_in; + inst.error = _("invalid FPA immediate expression"); + return FAIL; +} - skip_whitespace (str); +/* Shift operands. */ +enum shift_kind +{ + SHIFT_LSL, SHIFT_LSR, SHIFT_ASR, SHIFT_ROR, SHIFT_RRX +}; - /* Parse Rn. */ - if ((rn = reg_required_here (& str, 16)) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - else if (rn == REG_PC) - { - inst.error = BAD_PC; - return; - } - if (rd == rn) - { - inst.error = _("Rd equal to Rm or Rn yields unpredictable results"); - return; - } - skip_whitespace (str); +struct asm_shift_name +{ + const char *name; + enum shift_kind kind; +}; - /* Skip past ']'. */ - if ((strlen (str) >= 1) - && strncmp (str, "]", 1) == 0) - str += 1; +/* Third argument to parse_shift. */ +enum parse_shift_mode +{ + NO_SHIFT_RESTRICT, /* Any kind of shift is accepted. */ + SHIFT_IMMEDIATE, /* Shift operand must be an immediate. */ + SHIFT_LSL_OR_ASR_IMMEDIATE, /* Shift must be LSL or ASR immediate. */ + SHIFT_ASR_IMMEDIATE, /* Shift must be ASR immediate. */ + SHIFT_LSL_IMMEDIATE, /* Shift must be LSL immediate. */ +}; - end_of_line (str); -} +/* Parse a <shift> specifier on an ARM data processing instruction. + This has three forms: + + (LSL|LSR|ASL|ASR|ROR) Rs + (LSL|LSR|ASL|ASR|ROR) #imm + RRX -/* KIND indicates what kind of shifts are accepted. */ + Note that ASL is assimilated to LSL in the instruction encoding, and + RRX to ROR #0 (which cannot be written as such). */ static int -decode_shift (char ** str, int kind) +parse_shift (char **str, int i, enum parse_shift_mode mode) { - const struct asm_shift_name * shift; - char * p; - char c; - - skip_whitespace (* str); + const struct asm_shift_name *shift_name; + enum shift_kind shift; + char *s = *str; + char *p = s; + int reg; - for (p = * str; ISALPHA (* p); p ++) + for (p = *str; ISALPHA (*p); p++) ; - if (p == * str) + if (p == *str) { inst.error = _("shift expression expected"); return FAIL; } - c = * p; - * p = '\0'; - shift = (const struct asm_shift_name *) hash_find (arm_shift_hsh, * str); - * p = c; + shift_name = hash_find_n (arm_shift_hsh, *str, p - *str); - if (shift == NULL) + if (shift_name == NULL) { inst.error = _("shift expression expected"); return FAIL; } - assert (shift->properties->index == shift_properties[shift->properties->index].index); - - if (kind == SHIFT_LSL_OR_ASR_IMMEDIATE - && shift->properties->index != SHIFT_LSL - && shift->properties->index != SHIFT_ASR) - { - inst.error = _("'LSL' or 'ASR' required"); - return FAIL; - } - else if (kind == SHIFT_LSL_IMMEDIATE - && shift->properties->index != SHIFT_LSL) - { - inst.error = _("'LSL' required"); - return FAIL; - } - else if (kind == SHIFT_ASR_IMMEDIATE - && shift->properties->index != SHIFT_ASR) - { - inst.error = _("'ASR' required"); - return FAIL; - } + shift = shift_name->kind; - if (shift->properties->index == SHIFT_RRX) + switch (mode) { - * str = p; - inst.instruction |= shift->properties->bit_field; - return SUCCESS; - } - - skip_whitespace (p); + case NO_SHIFT_RESTRICT: + case SHIFT_IMMEDIATE: break; - if (kind == NO_SHIFT_RESTRICT && reg_required_here (& p, 8) != FAIL) - { - inst.instruction |= shift->properties->bit_field | SHIFT_BY_REG; - * str = p; - return SUCCESS; - } - else if (! is_immediate_prefix (* p)) - { - inst.error = (NO_SHIFT_RESTRICT - ? _("shift requires register or #expression") - : _("shift requires #expression")); - * str = p; - return FAIL; - } - - inst.error = NULL; - p ++; - - if (my_get_expression (& inst.reloc.exp, & p)) - return FAIL; + case SHIFT_LSL_OR_ASR_IMMEDIATE: + if (shift != SHIFT_LSL && shift != SHIFT_ASR) + { + inst.error = _("'LSL' or 'ASR' required"); + return FAIL; + } + break; - /* Validate some simple #expressions. */ - if (inst.reloc.exp.X_op == O_constant) - { - unsigned num = inst.reloc.exp.X_add_number; - - /* Reject operations greater than 32. */ - if (num > 32 - /* Reject a shift of 0 unless the mode allows it. */ - || (num == 0 && shift->properties->allows_0 == 0) - /* Reject a shift of 32 unless the mode allows it. */ - || (num == 32 && shift->properties->allows_32 == 0) - ) - { - /* As a special case we allow a shift of zero for - modes that do not support it to be recoded as an - logical shift left of zero (ie nothing). We warn - about this though. */ - if (num == 0) - { - as_warn (_("shift of 0 ignored.")); - shift = & shift_names[0]; - assert (shift->properties->index == SHIFT_LSL); - } - else - { - inst.error = _("invalid immediate shift"); - return FAIL; - } + case SHIFT_LSL_IMMEDIATE: + if (shift != SHIFT_LSL) + { + inst.error = _("'LSL' required"); + return FAIL; } + break; - /* Shifts of 32 are encoded as 0, for those shifts that - support it. */ - if (num == 32) - num = 0; + case SHIFT_ASR_IMMEDIATE: + if (shift != SHIFT_ASR) + { + inst.error = _("'ASR' required"); + return FAIL; + } + break; - inst.instruction |= (num << 7) | shift->properties->bit_field; + default: abort (); } - else + + if (shift != SHIFT_RRX) { - inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM; - inst.reloc.pc_rel = 0; - inst.instruction |= shift->properties->bit_field; - } + /* Whitespace can appear here if the next thing is a bare digit. */ + skip_whitespace (p); - * str = p; + if (mode == NO_SHIFT_RESTRICT + && (reg = arm_reg_parse (&p, REG_TYPE_RN)) != FAIL) + { + inst.operands[i].imm = reg; + inst.operands[i].immisreg = 1; + } + else if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX)) + return FAIL; + } + inst.operands[i].shift_kind = shift; + inst.operands[i].shifted = 1; + *str = p; return SUCCESS; } -static void -do_sat (char ** str, int bias) -{ - int rd, rm; - expressionS expr; +/* Parse a <shifter_operand> for an ARM data processing instruction: - skip_whitespace (*str); + #<immediate> + #<immediate>, <rotate> + <Rm> + <Rm>, <shift> - /* Parse <Rd>, field. */ - if ((rd = reg_required_here (str, 12)) == FAIL - || skip_past_comma (str) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - if (rd == REG_PC) - { - inst.error = BAD_PC; - return; - } + where <shift> is defined by parse_shift above, and <rotate> is a + multiple of 2 between 0 and 30. Validation of immediate operands + is deferred to md_apply_fix3. */ - /* Parse #<immed>, field. */ - if (is_immediate_prefix (**str)) - (*str)++; - else - { - inst.error = _("immediate expression expected"); - return; - } - if (my_get_expression (&expr, str)) - { - inst.error = _("bad expression"); - return; - } - if (expr.X_op != O_constant) - { - inst.error = _("constant expression expected"); - return; - } - if (expr.X_add_number + bias < 0 - || expr.X_add_number + bias > 31) - { - inst.error = _("immediate value out of range"); - return; - } - inst.instruction |= (expr.X_add_number + bias) << 16; - if (skip_past_comma (str) == FAIL) - { - inst.error = BAD_ARGS; - return; - } +static int +parse_shifter_operand (char **str, int i) +{ + int value; + expressionS expr; - /* Parse <Rm> field. */ - if ((rm = reg_required_here (str, 0)) == FAIL) + if ((value = arm_reg_parse (str, REG_TYPE_RN)) != FAIL) { - inst.error = BAD_ARGS; - return; - } - if (rm == REG_PC) - { - inst.error = BAD_PC; - return; - } + inst.operands[i].reg = value; + inst.operands[i].isreg = 1; - if (skip_past_comma (str) == SUCCESS) - decode_shift (str, SHIFT_LSL_OR_ASR_IMMEDIATE); -} - -/* ARM V6 ssat (argument parse). */ + /* parse_shift will override this if appropriate */ + inst.reloc.exp.X_op = O_constant; + inst.reloc.exp.X_add_number = 0; -static void -do_ssat (char * str) -{ - do_sat (&str, /*bias=*/-1); - end_of_line (str); -} + if (skip_past_comma (str) == FAIL) + return SUCCESS; -/* ARM V6 usat (argument parse). */ + /* Shift operation on register. */ + return parse_shift (str, i, NO_SHIFT_RESTRICT); + } -static void -do_usat (char * str) -{ - do_sat (&str, /*bias=*/0); - end_of_line (str); -} + if (my_get_expression (&inst.reloc.exp, str, GE_IMM_PREFIX)) + return FAIL; -static void -do_sat16 (char ** str, int bias) -{ - int rd, rm; - expressionS expr; + if (skip_past_comma (str) == SUCCESS) + { + /* #x, y -- ie explicit rotation by Y. */ + if (my_get_expression (&expr, str, GE_NO_PREFIX)) + return FAIL; - skip_whitespace (*str); + if (expr.X_op != O_constant || inst.reloc.exp.X_op != O_constant) + { + inst.error = _("constant expression expected"); + return FAIL; + } - /* Parse the <Rd> field. */ - if ((rd = reg_required_here (str, 12)) == FAIL - || skip_past_comma (str) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - if (rd == REG_PC) - { - inst.error = BAD_PC; - return; - } + value = expr.X_add_number; + if (value < 0 || value > 30 || value % 2 != 0) + { + inst.error = _("invalid rotation"); + return FAIL; + } + if (inst.reloc.exp.X_add_number < 0 || inst.reloc.exp.X_add_number > 255) + { + inst.error = _("invalid constant"); + return FAIL; + } - /* Parse #<immed>, field. */ - if (is_immediate_prefix (**str)) - (*str)++; - else - { - inst.error = _("immediate expression expected"); - return; - } - if (my_get_expression (&expr, str)) - { - inst.error = _("bad expression"); - return; - } - if (expr.X_op != O_constant) - { - inst.error = _("constant expression expected"); - return; - } - if (expr.X_add_number + bias < 0 - || expr.X_add_number + bias > 15) - { - inst.error = _("immediate value out of range"); - return; - } - inst.instruction |= (expr.X_add_number + bias) << 16; - if (skip_past_comma (str) == FAIL) - { - inst.error = BAD_ARGS; - return; + /* Convert to decoded value. md_apply_fix3 will put it back. */ + inst.reloc.exp.X_add_number + = (((inst.reloc.exp.X_add_number << (32 - value)) + | (inst.reloc.exp.X_add_number >> value)) & 0xffffffff); } - /* Parse <Rm> field. */ - if ((rm = reg_required_here (str, 0)) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - if (rm == REG_PC) - { - inst.error = BAD_PC; - return; - } + inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE; + inst.reloc.pc_rel = 0; + return SUCCESS; } -/* ARM V6 ssat16 (argument parse). */ +/* Parse all forms of an ARM address expression. Information is written + to inst.operands[i] and/or inst.reloc. -static void -do_ssat16 (char * str) -{ - do_sat16 (&str, /*bias=*/-1); - end_of_line (str); -} + Preindexed addressing (.preind=1): -static void -do_usat16 (char * str) -{ - do_sat16 (&str, /*bias=*/0); - end_of_line (str); -} + [Rn, #offset] .reg=Rn .reloc.exp=offset + [Rn, +/-Rm] .reg=Rn .imm=Rm .immisreg=1 .negative=0/1 + [Rn, +/-Rm, shift] .reg=Rn .imm=Rm .immisreg=1 .negative=0/1 + .shift_kind=shift .reloc.exp=shift_imm -static void -do_cps_mode (char ** str) -{ - expressionS expr; + These three may have a trailing ! which causes .writeback to be set also. - skip_whitespace (*str); + Postindexed addressing (.postind=1, .writeback=1): - if (! is_immediate_prefix (**str)) - { - inst.error = _("immediate expression expected"); - return; - } + [Rn], #offset .reg=Rn .reloc.exp=offset + [Rn], +/-Rm .reg=Rn .imm=Rm .immisreg=1 .negative=0/1 + [Rn], +/-Rm, shift .reg=Rn .imm=Rm .immisreg=1 .negative=0/1 + .shift_kind=shift .reloc.exp=shift_imm - (*str)++; /* Strip off the immediate signifier. */ - if (my_get_expression (&expr, str)) - { - inst.error = _("bad expression"); - return; - } + Unindexed addressing (.preind=0, .postind=0): - if (expr.X_op != O_constant) - { - inst.error = _("constant expression expected"); - return; - } + [Rn], {option} .reg=Rn .imm=option .immisreg=0 - /* The mode is a 5 bit field. Valid values are 0-31. */ - if (((unsigned) expr.X_add_number) > 31 - || (inst.reloc.exp.X_add_number) < 0) - { - inst.error = _("invalid constant"); - return; - } + Other: - inst.instruction |= expr.X_add_number; -} + [Rn]{!} shorthand for [Rn,#0]{!} + =immediate .isreg=0 .reloc.exp=immediate + label .reg=PC .reloc.pc_rel=1 .reloc.exp=label -/* ARM V6 srs (argument parse). */ + It is the caller's responsibility to check for addressing modes not + supported by the instruction, and to set inst.reloc.type. */ -static void -do_srs (char * str) +static int +parse_address (char **str, int i) { - char *exclam; - skip_whitespace (str); - exclam = strchr (str, '!'); - if (exclam) - *exclam = '\0'; - do_cps_mode (&str); - if (exclam) - *exclam = '!'; - if (*str == '!') + char *p = *str; + int reg; + + if (skip_past_char (&p, '[') == FAIL) { - inst.instruction |= WRITE_BACK; - str++; - } - end_of_line (str); -} + if (skip_past_char (&p, '=') == FAIL) + { + /* bare address - translate to PC-relative offset */ + inst.reloc.pc_rel = 1; + inst.operands[i].reg = REG_PC; + inst.operands[i].isreg = 1; + inst.operands[i].preind = 1; + } + /* else a load-constant pseudo op, no special treatment needed here */ -/* ARM V6 SMMUL (argument parse). */ + if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX)) + return FAIL; -static void -do_smmul (char * str) -{ - int rd, rm, rs; + *str = p; + return SUCCESS; + } - skip_whitespace (str); - if ((rd = reg_required_here (&str, 16)) == FAIL - || skip_past_comma (&str) == FAIL - || (rm = reg_required_here (&str, 0)) == FAIL - || skip_past_comma (&str) == FAIL - || (rs = reg_required_here (&str, 8)) == FAIL) + if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL) { - inst.error = BAD_ARGS; - return; + inst.error = _(reg_expected_msgs[REG_TYPE_RN]); + return FAIL; } + inst.operands[i].reg = reg; + inst.operands[i].isreg = 1; - if ( rd == REG_PC - || rm == REG_PC - || rs == REG_PC) + if (skip_past_comma (&p) == SUCCESS) { - inst.error = BAD_PC; - return; - } + inst.operands[i].preind = 1; - end_of_line (str); -} + if (*p == '+') p++; + else if (*p == '-') p++, inst.operands[i].negative = 1; -/* ARM V6 SMLALD (argument parse). */ + if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) != FAIL) + { + inst.operands[i].imm = reg; + inst.operands[i].immisreg = 1; -static void -do_smlald (char * str) -{ - int rdlo, rdhi, rm, rs; + if (skip_past_comma (&p) == SUCCESS) + if (parse_shift (&p, i, SHIFT_IMMEDIATE) == FAIL) + return FAIL; + } + else + { + if (inst.operands[i].negative) + { + inst.operands[i].negative = 0; + p--; + } + if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX)) + return FAIL; + } + } - skip_whitespace (str); - if ((rdlo = reg_required_here (&str, 12)) == FAIL - || skip_past_comma (&str) == FAIL - || (rdhi = reg_required_here (&str, 16)) == FAIL - || skip_past_comma (&str) == FAIL - || (rm = reg_required_here (&str, 0)) == FAIL - || skip_past_comma (&str) == FAIL - || (rs = reg_required_here (&str, 8)) == FAIL) + if (skip_past_char (&p, ']') == FAIL) { - inst.error = BAD_ARGS; - return; + inst.error = _("']' expected"); + return FAIL; } - if ( rdlo == REG_PC - || rdhi == REG_PC - || rm == REG_PC - || rs == REG_PC) + if (skip_past_char (&p, '!') == SUCCESS) + inst.operands[i].writeback = 1; + + else if (skip_past_comma (&p) == SUCCESS) { - inst.error = BAD_PC; - return; - } + if (skip_past_char (&p, '{') == SUCCESS) + { + /* [Rn], {expr} - unindexed, with option */ + if (parse_immediate (&p, &inst.operands[i].imm, + 0, 255, TRUE) == FAIL) + return FAIL; - end_of_line (str); -} + if (skip_past_char (&p, '}') == FAIL) + { + inst.error = _("'}' expected at end of 'option' field"); + return FAIL; + } + if (inst.operands[i].preind) + { + inst.error = _("cannot combine index with option"); + return FAIL; + } + *str = p; + return SUCCESS; + } + else + { + inst.operands[i].postind = 1; + inst.operands[i].writeback = 1; -/* ARM V6 SMLAD (argument parse). Signed multiply accumulate dual. - smlad{x}{<cond>} Rd, Rm, Rs, Rn */ + if (inst.operands[i].preind) + { + inst.error = _("cannot combine pre- and post-indexing"); + return FAIL; + } -static void -do_smlad (char * str) -{ - int rd, rm, rs, rn; + if (*p == '+') p++; + else if (*p == '-') p++, inst.operands[i].negative = 1; - skip_whitespace (str); - if ((rd = reg_required_here (&str, 16)) == FAIL - || skip_past_comma (&str) == FAIL - || (rm = reg_required_here (&str, 0)) == FAIL - || skip_past_comma (&str) == FAIL - || (rs = reg_required_here (&str, 8)) == FAIL - || skip_past_comma (&str) == FAIL - || (rn = reg_required_here (&str, 12)) == FAIL) - { - inst.error = BAD_ARGS; - return; + if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) != FAIL) + { + inst.operands[i].imm = reg; + inst.operands[i].immisreg = 1; + + if (skip_past_comma (&p) == SUCCESS) + if (parse_shift (&p, i, SHIFT_IMMEDIATE) == FAIL) + return FAIL; + } + else + { + if (inst.operands[i].negative) + { + inst.operands[i].negative = 0; + p--; + } + if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX)) + return FAIL; + } + } } - if ( rd == REG_PC - || rn == REG_PC - || rs == REG_PC - || rm == REG_PC) + /* If at this point neither .preind nor .postind is set, we have a + bare [Rn]{!}, which is shorthand for [Rn,#0]{!}. */ + if (inst.operands[i].preind == 0 && inst.operands[i].postind == 0) { - inst.error = BAD_PC; - return; + inst.operands[i].preind = 1; + inst.reloc.exp.X_op = O_constant; + inst.reloc.exp.X_add_number = 0; } - - end_of_line (str); + *str = p; + return SUCCESS; } -/* Returns true if the endian-specifier indicates big-endianness. */ +/* Miscellaneous. */ +/* Parse a PSR flag operand. The value returned is FAIL on syntax error, + or a bitmask suitable to be or-ed into the ARM msr instruction. */ static int -do_endian_specifier (char * str) +parse_psr (char **str) { - int big_endian = 0; + char *p; + unsigned long psr_field; - skip_whitespace (str); - if (strlen (str) < 2) - inst.error = _("missing endian specifier"); - else if (strncasecmp (str, "BE", 2) == 0) - { - str += 2; - big_endian = 1; - } - else if (strncasecmp (str, "LE", 2) == 0) - str += 2; + /* CPSR's and SPSR's can now be lowercase. This is just a convenience + feature for ease of use and backwards compatibility. */ + p = *str; + if (*p == 's' || *p == 'S') + psr_field = SPSR_BIT; + else if (*p == 'c' || *p == 'C') + psr_field = 0; else - inst.error = _("valid endian specifiers are be or le"); - - end_of_line (str); - - return big_endian; -} - -/* ARM V6 SETEND (argument parse). Sets the E bit in the CPSR while - preserving the other bits. - - setend <endian_specifier>, where <endian_specifier> is either - BE or LE. */ - -static void -do_setend (char * str) -{ - if (do_endian_specifier (str)) - inst.instruction |= 0x200; -} + goto error; -/* ARM V6 SXTH. - - SXTH {<cond>} <Rd>, <Rm>{, <rotation>} - Condition defaults to COND_ALWAYS. - Error if any register uses R15. */ - -static void -do_sxth (char * str) -{ - int rd, rm; - expressionS expr; - int rotation_clear_mask = 0xfffff3ff; - int rotation_eight_mask = 0x00000400; - int rotation_sixteen_mask = 0x00000800; - int rotation_twenty_four_mask = 0x00000c00; + p++; + if (strncasecmp (p, "PSR", 3) != 0) + goto error; + p += 3; - skip_whitespace (str); - if ((rd = reg_required_here (&str, 12)) == FAIL - || skip_past_comma (&str) == FAIL - || (rm = reg_required_here (&str, 0)) == FAIL) + if (*p == '_') { - inst.error = BAD_ARGS; - return; - } + /* A suffix follows. */ + const struct asm_psr *psr; + char *start; - else if (rd == REG_PC || rm == REG_PC) - { - inst.error = BAD_PC; - return; - } + p++; + start = p; - /* Zero out the rotation field. */ - inst.instruction &= rotation_clear_mask; + do + p++; + while (ISALNUM (*p) || *p == '_'); - /* Check for lack of optional rotation field. */ - if (skip_past_comma (&str) == FAIL) - { - end_of_line (str); - return; - } + psr = hash_find_n (arm_psr_hsh, start, p - start); + if (!psr) + goto error; - /* Move past 'ROR'. */ - skip_whitespace (str); - if (strncasecmp (str, "ROR", 3) == 0) - str += 3; - else - { - inst.error = _("missing rotation field after comma"); - return; + psr_field |= psr->field; } - - /* Get the immediate constant. */ - skip_whitespace (str); - if (is_immediate_prefix (* str)) - str++; else { - inst.error = _("immediate expression expected"); - return; - } + if (ISALNUM (*p)) + goto error; /* Garbage after "[CS]PSR". */ - if (my_get_expression (&expr, &str)) - { - inst.error = _("bad expression"); - return; + psr_field |= (PSR_c | PSR_f); } + *str = p; + return psr_field; - if (expr.X_op != O_constant) - { - inst.error = _("constant expression expected"); - return; - } + error: + inst.error = _("flag for {c}psr instruction expected"); + return FAIL; +} - switch (expr.X_add_number) - { - case 0: - /* Rotation field has already been zeroed. */ - break; - case 8: - inst.instruction |= rotation_eight_mask; - break; +/* Parse the flags argument to CPSI[ED]. Returns FAIL on error, or a + value suitable for splatting into the AIF field of the instruction. */ - case 16: - inst.instruction |= rotation_sixteen_mask; - break; +static int +parse_cps_flags (char **str) +{ + int val = 0; + int saw_a_flag = 0; + char *s = *str; - case 24: - inst.instruction |= rotation_twenty_four_mask; - break; + for (;;) + switch (*s++) + { + case '\0': case ',': + goto done; - default: - inst.error = _("rotation can be 8, 16, 24 or 0 when field is ommited"); - break; + case 'a': case 'A': saw_a_flag = 1; val |= 0x4; break; + case 'i': case 'I': saw_a_flag = 1; val |= 0x2; break; + case 'f': case 'F': saw_a_flag = 1; val |= 0x1; break; + + default: + inst.error = _("unrecognized CPS flag"); + return FAIL; + } + + done: + if (saw_a_flag == 0) + { + inst.error = _("missing CPS flags"); + return FAIL; } - end_of_line (str); + *str = s - 1; + return val; } -/* ARM V6 SXTAH extracts a 16-bit value from a register, sign - extends it to 32-bits, and adds the result to a value in another - register. You can specify a rotation by 0, 8, 16, or 24 bits - before extracting the 16-bit value. - SXTAH{<cond>} <Rd>, <Rn>, <Rm>{, <rotation>} - Condition defaults to COND_ALWAYS. - Error if any register uses R15. */ +/* Parse an endian specifier ("BE" or "LE", case insensitive); + returns 0 for big-endian, 1 for little-endian, FAIL for an error. */ -static void -do_sxtah (char * str) +static int +parse_endian_specifier (char **str) { - int rd, rn, rm; - expressionS expr; - int rotation_clear_mask = 0xfffff3ff; - int rotation_eight_mask = 0x00000400; - int rotation_sixteen_mask = 0x00000800; - int rotation_twenty_four_mask = 0x00000c00; + int little_endian; + char *s = *str; - skip_whitespace (str); - if ((rd = reg_required_here (&str, 12)) == FAIL - || skip_past_comma (&str) == FAIL - || (rn = reg_required_here (&str, 16)) == FAIL - || skip_past_comma (&str) == FAIL - || (rm = reg_required_here (&str, 0)) == FAIL) + if (strncasecmp (s, "BE", 2)) + little_endian = 0; + else if (strncasecmp (s, "LE", 2)) + little_endian = 1; + else { - inst.error = BAD_ARGS; - return; + inst.error = _("valid endian specifiers are be or le"); + return FAIL; } - else if (rd == REG_PC || rn == REG_PC || rm == REG_PC) + if (ISALNUM (s[2]) || s[2] == '_') { - inst.error = BAD_PC; - return; + inst.error = _("valid endian specifiers are be or le"); + return FAIL; } - /* Zero out the rotation field. */ - inst.instruction &= rotation_clear_mask; + *str = s + 2; + return little_endian; +} - /* Check for lack of optional rotation field. */ - if (skip_past_comma (&str) == FAIL) - { - end_of_line (str); - return; - } +/* Parse a rotation specifier: ROR #0, #8, #16, #24. *val receives a + value suitable for poking into the rotate field of an sxt or sxta + instruction, or FAIL on error. */ - /* Move past 'ROR'. */ - skip_whitespace (str); - if (strncasecmp (str, "ROR", 3) == 0) - str += 3; - else - { - inst.error = _("missing rotation field after comma"); - return; - } +static int +parse_ror (char **str) +{ + int rot; + char *s = *str; - /* Get the immediate constant. */ - skip_whitespace (str); - if (is_immediate_prefix (* str)) - str++; + if (strncasecmp (s, "ROR", 3) == 0) + s += 3; else { - inst.error = _("immediate expression expected"); - return; - } - - if (my_get_expression (&expr, &str)) - { - inst.error = _("bad expression"); - return; + inst.error = _("missing rotation field after comma"); + return FAIL; } - if (expr.X_op != O_constant) - { - inst.error = _("constant expression expected"); - return; - } + if (parse_immediate (&s, &rot, 0, 24, FALSE) == FAIL) + return FAIL; - switch (expr.X_add_number) + switch (rot) { - case 0: - /* Rotation field has already been zeroed. */ - break; - - case 8: - inst.instruction |= rotation_eight_mask; - break; - - case 16: - inst.instruction |= rotation_sixteen_mask; - break; - - case 24: - inst.instruction |= rotation_twenty_four_mask; - break; + case 0: *str = s; return 0x0; + case 8: *str = s; return 0x1; + case 16: *str = s; return 0x2; + case 24: *str = s; return 0x3; default: - inst.error = _("rotation can be 8, 16, 24 or 0 when field is ommited"); - break; + inst.error = _("rotation can only be 0, 8, 16, or 24"); + return FAIL; } - - end_of_line (str); } - -/* ARM V6 RFE (Return from Exception) loads the PC and CPSR from the - word at the specified address and the following word - respectively. - Unconditionally executed. - Error if Rn is R15. */ - -static void -do_rfe (char * str) +/* Parse a conditional code (from conds[] below). The value returned is in the + range 0 .. 14, or FAIL. */ +static int +parse_cond (char **str) { - int rn; + char *p, *q; + const struct asm_cond *c; - skip_whitespace (str); + p = q = *str; + while (ISALPHA (*q)) + q++; - if ((rn = reg_required_here (&str, 16)) == FAIL) - return; - - if (rn == REG_PC) + c = hash_find_n (arm_cond_hsh, p, q - p); + if (!c) { - inst.error = BAD_PC; - return; + inst.error = _("condition required"); + return FAIL; } - skip_whitespace (str); - - if (*str == '!') - { - inst.instruction |= WRITE_BACK; - str++; - } - end_of_line (str); -} + *str = q; + return c->value; +} + +/* Matcher codes for parse_operands. */ +enum operand_parse_code +{ + OP_stop, /* end of line */ + + OP_RR, /* ARM register */ + OP_RRnpc, /* ARM register, not r15 */ + OP_RRnpcb, /* ARM register, not r15, in square brackets */ + OP_RRw, /* ARM register, not r15, optional trailing ! */ + OP_RCP, /* Coprocessor number */ + OP_RCN, /* Coprocessor register */ + OP_RF, /* FPA register */ + OP_RVS, /* VFP single precision register */ + OP_RVD, /* VFP double precision register */ + OP_RVC, /* VFP control register */ + OP_RMF, /* Maverick F register */ + OP_RMD, /* Maverick D register */ + OP_RMFX, /* Maverick FX register */ + OP_RMDX, /* Maverick DX register */ + OP_RMAX, /* Maverick AX register */ + OP_RMDS, /* Maverick DSPSC register */ + OP_RIWR, /* iWMMXt wR register */ + OP_RIWC, /* iWMMXt wC register */ + OP_RIWG, /* iWMMXt wCG register */ + OP_RXA, /* XScale accumulator register */ + + OP_REGLST, /* ARM register list */ + OP_VRSLST, /* VFP single-precision register list */ + OP_VRDLST, /* VFP double-precision register list */ + + OP_I7, /* immediate value 0 .. 7 */ + OP_I15, /* 0 .. 15 */ + OP_I16, /* 1 .. 16 */ + OP_I31, /* 0 .. 31 */ + OP_I31w, /* 0 .. 31, optional trailing ! */ + OP_I32, /* 1 .. 32 */ + OP_I63s, /* -64 .. 63 */ + OP_I255, /* 0 .. 255 */ + OP_Iffff, /* 0 .. 65535 */ + + OP_I4b, /* immediate, prefix optional, 1 .. 4 */ + OP_I7b, /* 0 .. 7 */ + OP_I15b, /* 0 .. 15 */ + OP_I31b, /* 0 .. 31 */ + + OP_SH, /* shifter operand */ + OP_ADDR, /* Memory address expression (any mode) */ + OP_EXP, /* arbitrary expression */ + OP_EXPi, /* same, with optional immediate prefix */ + OP_EXPr, /* same, with optional relocation suffix */ + + OP_CPSF, /* CPS flags */ + OP_ENDI, /* Endianness specifier */ + OP_PSR, /* CPSR/SPSR mask for msr */ + OP_COND, /* conditional code */ + + OP_RRnpc_I0, /* ARM register or literal 0 */ + OP_RR_EXr, /* ARM register or expression with opt. reloc suff. */ + OP_RR_EXi, /* ARM register or expression with imm prefix */ + OP_RF_IF, /* FPA register or immediate */ + OP_RIWR_RIWC, /* iWMMXt R or C reg */ + + /* Optional operands. */ + OP_oI7b, /* immediate, prefix optional, 0 .. 7 */ + OP_oI31b, /* 0 .. 31 */ + OP_oIffffb, /* 0 .. 65535 */ + OP_oI255c, /* curly-brace enclosed, 0 .. 255 */ + + OP_oRR, /* ARM register */ + OP_oRRnpc, /* ARM register, not the PC */ + OP_oSHll, /* LSL immediate */ + OP_oSHar, /* ASR immediate */ + OP_oSHllar, /* LSL or ASR immediate */ + OP_oROR, /* ROR 0/8/16/24 */ + + OP_FIRST_OPTIONAL = OP_oI7b +}; -/* ARM V6 REV (Byte Reverse Word) reverses the byte order in a 32-bit - register (argument parse). - REV{<cond>} Rd, Rm. - Condition defaults to COND_ALWAYS. - Error if Rd or Rm are R15. */ +/* Generic instruction operand parser. This does no encoding and no + semantic validation; it merely squirrels values away in the inst + structure. Returns SUCCESS or FAIL depending on whether the + specified grammar matched. */ +static int +parse_operands (char *str, const char *pattern) +{ + unsigned const char *upat = pattern; + char *backtrack_pos = 0; + const char *backtrack_error = 0; + int i, val, backtrack_index = 0; + +#define po_char_or_fail(chr) do { \ + if (skip_past_char (&str, chr) == FAIL) \ + goto bad_args; \ +} while (0) + +#define po_reg_or_fail(regtype) do { \ + val = arm_reg_parse (&str, regtype); \ + if (val == FAIL) \ + { \ + inst.error = _(reg_expected_msgs[regtype]); \ + goto failure; \ + } \ + inst.operands[i].reg = val; \ + inst.operands[i].isreg = 1; \ +} while (0) + +#define po_reg_or_goto(regtype, label) do { \ + val = arm_reg_parse (&str, regtype); \ + if (val == FAIL) \ + goto label; \ + \ + inst.operands[i].reg = val; \ + inst.operands[i].isreg = 1; \ +} while (0) + +#define po_imm_or_fail(min, max, popt) do { \ + if (parse_immediate (&str, &val, min, max, popt) == FAIL) \ + goto failure; \ + inst.operands[i].imm = val; \ +} while (0) + +#define po_misc_or_fail(expr) do { \ + if (expr) \ + goto failure; \ +} while (0) + + skip_whitespace (str); + + for (i = 0; upat[i] != OP_stop; i++) + { + if (upat[i] >= OP_FIRST_OPTIONAL) + { + /* Remember where we are in case we need to backtrack. */ + assert (!backtrack_pos); + backtrack_pos = str; + backtrack_error = inst.error; + backtrack_index = i; + } + + if (i > 0) + po_char_or_fail (','); + + switch (upat[i]) + { + /* Registers */ + case OP_oRRnpc: + case OP_RRnpc: + case OP_oRR: + case OP_RR: po_reg_or_fail (REG_TYPE_RN); break; + case OP_RCP: po_reg_or_fail (REG_TYPE_CP); break; + case OP_RCN: po_reg_or_fail (REG_TYPE_CN); break; + case OP_RF: po_reg_or_fail (REG_TYPE_FN); break; + case OP_RVS: po_reg_or_fail (REG_TYPE_VFS); break; + case OP_RVD: po_reg_or_fail (REG_TYPE_VFD); break; + case OP_RVC: po_reg_or_fail (REG_TYPE_VFC); break; + case OP_RMF: po_reg_or_fail (REG_TYPE_MVF); break; + case OP_RMD: po_reg_or_fail (REG_TYPE_MVD); break; + case OP_RMFX: po_reg_or_fail (REG_TYPE_MVFX); break; + case OP_RMDX: po_reg_or_fail (REG_TYPE_MVDX); break; + case OP_RMAX: po_reg_or_fail (REG_TYPE_MVAX); break; + case OP_RMDS: po_reg_or_fail (REG_TYPE_DSPSC); break; + case OP_RIWR: po_reg_or_fail (REG_TYPE_MMXWR); break; + case OP_RIWC: po_reg_or_fail (REG_TYPE_MMXWC); break; + case OP_RIWG: po_reg_or_fail (REG_TYPE_MMXWCG); break; + case OP_RXA: po_reg_or_fail (REG_TYPE_XSCALE); break; + + case OP_RRnpcb: + po_char_or_fail ('['); + po_reg_or_fail (REG_TYPE_RN); + po_char_or_fail (']'); + break; -static void -do_rev (char * str) -{ - int rd, rm; + case OP_RRw: + po_reg_or_fail (REG_TYPE_RN); + if (skip_past_char (&str, '!') == SUCCESS) + inst.operands[i].writeback = 1; + break; - skip_whitespace (str); + /* Immediates */ + case OP_I7: po_imm_or_fail ( 0, 7, FALSE); break; + case OP_I15: po_imm_or_fail ( 0, 15, FALSE); break; + case OP_I16: po_imm_or_fail ( 1, 16, FALSE); break; + case OP_I31: po_imm_or_fail ( 0, 31, FALSE); break; + case OP_I32: po_imm_or_fail ( 1, 32, FALSE); break; + case OP_I63s: po_imm_or_fail (-64, 63, 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: + case OP_I7b: po_imm_or_fail ( 0, 7, TRUE); break; + case OP_I15b: po_imm_or_fail ( 0, 15, TRUE); break; + case OP_oI31b: + case OP_I31b: po_imm_or_fail ( 0, 31, TRUE); break; + case OP_oIffffb: po_imm_or_fail ( 0, 0xffff, TRUE); break; + + /* Immediate variants */ + case OP_oI255c: + po_char_or_fail ('{'); + po_imm_or_fail (0, 255, TRUE); + po_char_or_fail ('}'); + break; - if ((rd = reg_required_here (&str, 12)) == FAIL - || skip_past_comma (&str) == FAIL - || (rm = reg_required_here (&str, 0)) == FAIL) - inst.error = BAD_ARGS; + case OP_I31w: + /* The expression parser chokes on a trailing !, so we have + to find it first and zap it. */ + { + char *s = str; + while (*s && *s != ',') + s++; + if (s[-1] == '!') + { + s[-1] = '\0'; + inst.operands[i].writeback = 1; + } + po_imm_or_fail (0, 31, TRUE); + if (str == s - 1) + str = s; + } + break; - else if (rd == REG_PC || rm == REG_PC) - inst.error = BAD_PC; + /* Expressions */ + case OP_EXPi: EXPi: + po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str, + GE_OPT_PREFIX)); + break; - else - end_of_line (str); -} + case OP_EXP: + po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str, + GE_NO_PREFIX)); + break; -/* ARM V6 Perform Two Sixteen Bit Integer Additions. (argument parse). - QADD16{<cond>} <Rd>, <Rn>, <Rm> - Condition defaults to COND_ALWAYS. - Error if Rd, Rn or Rm are R15. */ + case OP_EXPr: EXPr: + po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str, + GE_NO_PREFIX)); + if (inst.reloc.exp.X_op == O_symbol) + { + val = parse_reloc (&str); + if (val == -1) + { + inst.error = _("unrecognized relocation suffix"); + goto failure; + } + else if (val != BFD_RELOC_UNUSED) + { + inst.operands[i].imm = val; + inst.operands[i].hasreloc = 1; + } + } + break; -static void -do_qadd16 (char * str) -{ - int rd, rm, rn; + /* 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; - skip_whitespace (str); + /* Register or immediate */ + case OP_RRnpc_I0: po_reg_or_goto (REG_TYPE_RN, I0); break; + I0: po_imm_or_fail (0, 0, FALSE); break; - if ((rd = reg_required_here (&str, 12)) == FAIL - || skip_past_comma (&str) == FAIL - || (rn = reg_required_here (&str, 16)) == FAIL - || skip_past_comma (&str) == FAIL - || (rm = reg_required_here (&str, 0)) == FAIL) - inst.error = BAD_ARGS; + case OP_RF_IF: po_reg_or_goto (REG_TYPE_FN, IF); break; + IF: + if (!is_immediate_prefix (*str)) + goto bad_args; + str++; + val = parse_fpa_immediate (&str); + if (val == FAIL) + goto failure; + /* FPA immediates are encoded as registers 8-15. + parse_fpa_immediate has already applied the offset. */ + inst.operands[i].reg = val; + inst.operands[i].isreg = 1; + break; - else if (rd == REG_PC || rm == REG_PC || rn == REG_PC) - inst.error = BAD_PC; + /* Two kinds of register */ + case OP_RIWR_RIWC: + { + struct reg_entry *rege = arm_reg_parse_multi (&str); + if (rege->type != REG_TYPE_MMXWR + && rege->type != REG_TYPE_MMXWC + && rege->type != REG_TYPE_MMXWCG) + { + inst.error = _("iWMMXt data or control register expected"); + goto failure; + } + inst.operands[i].reg = rege->number; + inst.operands[i].isreg = (rege->type == REG_TYPE_MMXWR); + } + break; - else - end_of_line (str); -} + /* Misc */ + case OP_CPSF: val = parse_cps_flags (&str); break; + case OP_ENDI: val = parse_endian_specifier (&str); break; + case OP_oROR: val = parse_ror (&str); break; + case OP_PSR: val = parse_psr (&str); break; + case OP_COND: val = parse_cond (&str); break; + + /* Register lists */ + case OP_REGLST: + val = parse_reg_list (&str); + if (*str == '^') + { + inst.operands[1].writeback = 1; + str++; + } + break; -static void -do_pkh_core (char * str, int shift) -{ - int rd, rn, rm; + case OP_VRSLST: + val = parse_vfp_reg_list (&str, &inst.operands[i].reg, 0); + break; - skip_whitespace (str); - if (((rd = reg_required_here (&str, 12)) == FAIL) - || (skip_past_comma (&str) == FAIL) - || ((rn = reg_required_here (&str, 16)) == FAIL) - || (skip_past_comma (&str) == FAIL) - || ((rm = reg_required_here (&str, 0)) == FAIL)) - { - inst.error = BAD_ARGS; - return; - } + case OP_VRDLST: + val = parse_vfp_reg_list (&str, &inst.operands[i].reg, 1); + break; - else if (rd == REG_PC || rn == REG_PC || rm == REG_PC) - { - inst.error = BAD_PC; - return; - } + /* Addressing modes */ + case OP_ADDR: + po_misc_or_fail (parse_address (&str, i)); + break; - /* Check for optional shift immediate constant. */ - if (skip_past_comma (&str) == FAIL) - { - if (shift == SHIFT_ASR_IMMEDIATE) - { - /* If the shift specifier is ommited, turn the instruction - into pkhbt rd, rm, rn. First, switch the instruction - code, and clear the rn and rm fields. */ - inst.instruction &= 0xfff0f010; - /* Now, re-encode the registers. */ - inst.instruction |= (rm << 16) | rn; - } - return; - } + case OP_SH: + po_misc_or_fail (parse_shifter_operand (&str, i)); + break; - decode_shift (&str, shift); -} + case OP_oSHll: + po_misc_or_fail (parse_shift (&str, i, SHIFT_LSL_IMMEDIATE)); + break; -/* ARM V6 Pack Halfword Bottom Top instruction (argument parse). - PKHBT {<cond>} <Rd>, <Rn>, <Rm> {, LSL #<shift_imm>} - Condition defaults to COND_ALWAYS. - Error if Rd, Rn or Rm are R15. */ + case OP_oSHar: + po_misc_or_fail (parse_shift (&str, i, SHIFT_ASR_IMMEDIATE)); + break; -static void -do_pkhbt (char * str) -{ - do_pkh_core (str, SHIFT_LSL_IMMEDIATE); -} + case OP_oSHllar: + po_misc_or_fail (parse_shift (&str, i, SHIFT_LSL_OR_ASR_IMMEDIATE)); + break; -/* ARM V6 PKHTB (Argument Parse). */ + default: + as_fatal ("unhandled operand code %d", upat[i]); + } -static void -do_pkhtb (char * str) -{ - do_pkh_core (str, SHIFT_ASR_IMMEDIATE); -} + /* Various value-based sanity checks and shared operations. We + do not signal immediate failures for the register constraints; + this allows a syntax error to take precedence. */ + switch (upat[i]) + { + case OP_oRRnpc: + case OP_RRnpc: + case OP_RRnpcb: + case OP_RRw: + case OP_RRnpc_I0: + if (inst.operands[i].isreg && inst.operands[i].reg == REG_PC) + inst.error = BAD_PC; + break; -/* ARM V6 Load Register Exclusive instruction (argument parse). - LDREX{,B,D,H}{<cond>} <Rd, [<Rn>] - Condition defaults to COND_ALWAYS. - Error if Rd or Rn are R15. - See ARMARMv6 A4.1.27: LDREX. */ + case OP_CPSF: + case OP_ENDI: + case OP_oROR: + case OP_PSR: + case OP_COND: + case OP_REGLST: + case OP_VRSLST: + case OP_VRDLST: + if (val == FAIL) + goto failure; + inst.operands[i].imm = val; + break; -static void -do_ldrex (char * str) -{ - int rd, rn; + default: + break; + } - skip_whitespace (str); + /* If we get here, this operand was successfully parsed. */ + inst.operands[i].present = 1; + continue; - /* Parse Rd. */ - if (((rd = reg_required_here (&str, 12)) == FAIL) - || (skip_past_comma (&str) == FAIL)) - { + bad_args: inst.error = BAD_ARGS; - return; - } - else if (rd == REG_PC) - { - inst.error = BAD_PC; - return; - } - skip_whitespace (str); - /* Skip past '['. */ - if ((strlen (str) >= 1) - &&strncmp (str, "[", 1) == 0) - str += 1; - skip_whitespace (str); + failure: + if (!backtrack_pos) + return FAIL; - /* Parse Rn. */ - if ((rn = reg_required_here (&str, 16)) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - else if (rn == REG_PC) - { - inst.error = BAD_PC; - return; + /* Do not backtrack over a trailing optional argument that + absorbed some text. We will only fail again, with the + 'garbage following instruction' error message, which is + probably less helpful than the current one. */ + if (backtrack_index == i && backtrack_pos != str + && upat[i+1] == OP_stop) + return FAIL; + + /* Try again, skipping the optional argument at backtrack_pos. */ + str = backtrack_pos; + inst.error = backtrack_error; + inst.operands[backtrack_index].present = 0; + i = backtrack_index; + backtrack_pos = 0; } - skip_whitespace (str); - /* Skip past ']'. */ - if ((strlen (str) >= 1) - && strncmp (str, "]", 1) == 0) - str += 1; + /* Check that we have parsed all the arguments. */ + if (*str != '\0' && !inst.error) + inst.error = _("garbage following instruction"); - end_of_line (str); + return inst.error ? FAIL : SUCCESS; } -/* ARM V6 change processor state instruction (argument parse) - CPS, CPSIE, CSPID . */ - -static void -do_cps (char * str) -{ - do_cps_mode (&str); - end_of_line (str); -} +#undef po_char_or_fail +#undef po_reg_or_fail +#undef po_reg_or_goto +#undef po_imm_or_fail + +/* Shorthand macro for instruction encoding functions issuing errors. */ +#define constraint(expr, err) do { \ + if (expr) \ + { \ + inst.error = err; \ + return; \ + } \ +} while (0) -static void -do_cps_flags (char ** str, int thumb_p) -{ - struct cps_flag - { - char character; - unsigned long arm_value; - unsigned long thumb_value; - }; - static struct cps_flag flag_table[] = - { - {'a', 0x100, 0x4 }, - {'i', 0x080, 0x2 }, - {'f', 0x040, 0x1 } - }; +/* Functions for operand encoding. ARM, then Thumb. */ - int saw_a_flag = 0; +#define rotate_left(v, n) (v << n | v >> (32 - n)) - skip_whitespace (*str); +/* If VAL can be encoded in the immediate field of an ARM instruction, + return the encoded form. Otherwise, return FAIL. */ - /* Get the a, f and i flags. */ - while (**str && **str != ',') - { - struct cps_flag *p; - struct cps_flag *q = flag_table + sizeof (flag_table)/sizeof (*p); +static unsigned int +encode_arm_immediate (unsigned int val) +{ + unsigned int a, i; - for (p = flag_table; p < q; ++p) - if (strncasecmp (*str, &p->character, 1) == 0) - { - inst.instruction |= (thumb_p ? p->thumb_value : p->arm_value); - saw_a_flag = 1; - break; - } - if (p == q) - { - inst.error = _("unrecognized flag"); - return; - } - (*str)++; - } + for (i = 0; i < 32; i += 2) + if ((a = rotate_left (val, i)) <= 0xff) + return a | (i << 7); /* 12-bit pack: [shift-cnt,const]. */ - if (!saw_a_flag) - inst.error = _("no 'a', 'i', or 'f' flags for 'cps'"); + return FAIL; } -static void -do_cpsi (char * str) +/* If VAL can be encoded in the immediate field of a Thumb32 instruction, + return the encoded form. Otherwise, return FAIL. */ +static unsigned int +encode_thumb32_immediate (unsigned int val) { - do_cps_flags (&str, /*thumb_p=*/0); + unsigned int a, i; - if (skip_past_comma (&str) == SUCCESS) + if (val <= 255) + return val; + + for (i = 0; i < 32; i++) { - skip_whitespace (str); - do_cps_mode (&str); + a = rotate_left (val, i); + if (a >= 128 && a <= 255) + return (a & 0x7f) | (i << 7); } - end_of_line (str); -} -/* ARM V6T2 bitfield manipulation instructions. */ + a = val & 0xff; + if (val == ((a << 16) | a)) + return 0x100 | a; + if (val == ((a << 24) | (a << 16) | (a << 8) | a)) + return 0x300 | a; -static int -five_bit_unsigned_immediate (char **str) -{ - expressionS expr; + a = val & 0xff00; + if (val == ((a << 16) | a)) + return 0x200 | (a >> 8); - skip_whitespace (*str); - if (!is_immediate_prefix (**str)) - { - inst.error = _("immediate expression expected"); - return -1; - } - (*str)++; - if (my_get_expression (&expr, str)) - { - inst.error = _("bad expression"); - return -1; - } - if (expr.X_op != O_constant) - { - inst.error = _("constant expression expected"); - return -1; - } - if (expr.X_add_number < 0 || expr.X_add_number > 32) - { - inst.error = _("immediate value out of range"); - return -1; - } - - return expr.X_add_number; + return FAIL; } +/* Encode a VFP SP register number into inst.instruction. */ static void -bfci_lsb_and_width (char *str) +encode_arm_vfp_sp_reg (int reg, enum vfp_sp_reg_pos pos) { - int lsb, width; - - if ((lsb = five_bit_unsigned_immediate (&str)) == -1) - return; - - if (skip_past_comma (&str) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - if ((width = five_bit_unsigned_immediate (&str)) == -1) - return; - - end_of_line (str); - - if (width == 0 || lsb == 32) - { - inst.error = _("immediate value out of range"); - return; - } - else if (width + lsb > 32) + switch (pos) { - inst.error = _("bit-field extends past end of register"); - return; - } + case VFP_REG_Sd: + inst.instruction |= ((reg >> 1) << 12) | ((reg & 1) << 22); + break; - /* Convert to LSB/MSB and write to register. */ - inst.instruction |= lsb << 7; - inst.instruction |= (width + lsb - 1) << 16; -} + case VFP_REG_Sn: + inst.instruction |= ((reg >> 1) << 16) | ((reg & 1) << 7); + break; -static void -do_bfc (char *str) -{ - int rd; + case VFP_REG_Sm: + inst.instruction |= ((reg >> 1) << 0) | ((reg & 1) << 5); + break; - /* Rd. */ - skip_whitespace (str); - if (((rd = reg_required_here (&str, 12)) == FAIL) - || (skip_past_comma (&str) == FAIL)) - { - inst.error = BAD_ARGS; - return; - } - else if (rd == REG_PC) - { - inst.error = BAD_PC; - return; + default: + abort (); } - - bfci_lsb_and_width (str); } +/* Encode a <shift> in an ARM-format instruction. The immediate, + if any, is handled by md_apply_fix3. */ static void -do_bfi (char *str) +encode_arm_shift (int i) { - int rd, rm; - - /* Rd. */ - skip_whitespace (str); - if (((rd = reg_required_here (&str, 12)) == FAIL) - || (skip_past_comma (&str) == FAIL)) - { - inst.error = BAD_ARGS; - return; - } - else if (rd == REG_PC) - { - inst.error = BAD_PC; - return; - } - - /* Rm. Accept #0 in this position as an alternative syntax for bfc. */ - skip_whitespace (str); - if (is_immediate_prefix (*str)) - { - expressionS expr; - str++; - if (my_get_expression (&expr, &str)) - { - inst.error = _("bad expression"); - return; - } - if (expr.X_op != O_constant) - { - inst.error = _("constant expression expected"); - return; - } - if (expr.X_add_number != 0) - { - inst.error = _("immediate value out of range"); - return; - } - inst.instruction |= 0x0000000f; /* Rm = PC -> bfc, not bfi. */ - } + if (inst.operands[i].shift_kind == SHIFT_RRX) + inst.instruction |= SHIFT_ROR << 5; else { - if ((rm = reg_required_here (&str, 0)) == FAIL) + inst.instruction |= inst.operands[i].shift_kind << 5; + if (inst.operands[i].immisreg) { - inst.error = BAD_ARGS; - return; - } - else if (rm == REG_PC) - { - inst.error = BAD_PC; - return; + inst.instruction |= SHIFT_BY_REG; + inst.instruction |= inst.operands[i].imm << 8; } + else + inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM; } - if (skip_past_comma (&str) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - - bfci_lsb_and_width (str); -} - -static void -do_bfx (char *str) -{ - int lsb, width; - - /* Rd. */ - skip_whitespace (str); - if (reg_required_here (&str, 12) == FAIL - || skip_past_comma (&str) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - - /* Rm. */ - skip_whitespace (str); - if (reg_required_here (&str, 0) == FAIL - || skip_past_comma (&str) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - - if ((lsb = five_bit_unsigned_immediate (&str)) == -1) - return; - - if (skip_past_comma (&str) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - if ((width = five_bit_unsigned_immediate (&str)) == -1) - return; - - end_of_line (str); - - if (width == 0 || lsb == 32) - { - inst.error = _("immediate value out of range"); - return; - } - else if (width + lsb > 32) - { - inst.error = _("bit-field extends past end of register"); - return; - } - - inst.instruction |= lsb << 7; - inst.instruction |= (width - 1) << 16; } static void -do_rbit (char *str) +encode_arm_shifter_operand (int i) { - /* Rd. */ - skip_whitespace (str); - if (reg_required_here (&str, 12) == FAIL - || skip_past_comma (&str) == FAIL) + if (inst.operands[i].isreg) { - inst.error = BAD_ARGS; - return; + inst.instruction |= inst.operands[i].reg; + encode_arm_shift (i); } - - /* Rm. */ - skip_whitespace (str); - if (reg_required_here (&str, 0) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - - end_of_line (str); + else + inst.instruction |= INST_IMMEDIATE; } -/* ARM V6T2 16-bit immediate register load: MOV[WT]{cond} Rd, #<imm16>. */ +/* Subroutine of encode_arm_addr_mode_2 and encode_arm_addr_mode_3. */ static void -do_mov16 (char *str) +encode_arm_addr_mode_common (int i, bfd_boolean is_t) { - int rd; - expressionS expr; + assert (inst.operands[i].isreg); + inst.instruction |= inst.operands[i].reg << 16; - /* Rd. */ - skip_whitespace (str); - if (((rd = reg_required_here (&str, 12)) == FAIL) - || (skip_past_comma (&str) == FAIL)) - { - inst.error = BAD_ARGS; - return; - } - else if (rd == REG_PC) + if (inst.operands[i].preind) { - inst.error = BAD_PC; - return; - } + if (is_t) + { + inst.error = _("instruction does not accept preindexed addressing"); + return; + } + inst.instruction |= PRE_INDEX; + if (inst.operands[i].writeback) + inst.instruction |= WRITE_BACK; - /* Imm16. */ - skip_whitespace (str); - if (!is_immediate_prefix (*str)) - { - inst.error = _("immediate expression expected"); - return; } - str++; - if (my_get_expression (&expr, &str)) + else if (inst.operands[i].postind) { - inst.error = _("bad expression"); - return; + assert (inst.operands[i].writeback); + if (is_t) + inst.instruction |= WRITE_BACK; } - if (expr.X_op != O_constant) + else /* unindexed - only for coprocessor */ { - inst.error = _("constant expression expected"); + inst.error = _("instruction does not accept unindexed addressing"); return; } - if (expr.X_add_number < 0 || expr.X_add_number > 65535) - { - inst.error = _("immediate value out of range"); - return; - } - - end_of_line (str); - /* The value is in two pieces: 0:11, 16:19. */ - inst.instruction |= (expr.X_add_number & 0x00000fff); - inst.instruction |= (expr.X_add_number & 0x0000f000) << 4; + if (((inst.instruction & WRITE_BACK) || !(inst.instruction & PRE_INDEX)) + && (((inst.instruction & 0x000f0000) >> 16) + == ((inst.instruction & 0x0000f000) >> 12))) + as_warn ((inst.instruction & LOAD_BIT) + ? _("destination register same as write-back base") + : _("source register same as write-back base")); } - - -/* THUMB V5 breakpoint instruction (argument parse) - BKPT <immed_8>. */ +/* inst.operands[i] was set up by parse_address. Encode it into an + ARM-format mode 2 load or store instruction. If is_t is true, + reject forms that cannot be used with a T instruction (i.e. not + post-indexed). */ static void -do_t_bkpt (char * str) +encode_arm_addr_mode_2 (int i, bfd_boolean is_t) { - expressionS expr; - unsigned long number; - - skip_whitespace (str); + encode_arm_addr_mode_common (i, is_t); - /* Allow optional leading '#'. */ - if (is_immediate_prefix (*str)) - str ++; - - memset (& expr, '\0', sizeof (expr)); - if (my_get_expression (& expr, & str) - || (expr.X_op != O_constant - /* As a convenience we allow 'bkpt' without an operand. */ - && expr.X_op != O_absent)) + if (inst.operands[i].immisreg) { - inst.error = _("bad expression"); - return; + inst.instruction |= INST_IMMEDIATE; /* yes, this is backwards */ + inst.instruction |= inst.operands[i].imm; + if (!inst.operands[i].negative) + inst.instruction |= INDEX_UP; + if (inst.operands[i].shifted) + { + if (inst.operands[i].shift_kind == SHIFT_RRX) + inst.instruction |= SHIFT_ROR << 5; + else + { + inst.instruction |= inst.operands[i].shift_kind << 5; + inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM; + } + } } - - number = expr.X_add_number; - - /* Check it fits an 8 bit unsigned. */ - if (number != (number & 0xff)) + else /* immediate offset in inst.reloc */ { - inst.error = _("immediate value out of range"); - return; + 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 |= number; - - end_of_line (str); -} - -#ifdef OBJ_ELF -static bfd_reloc_code_real_type -arm_parse_reloc (void) -{ - char id [16]; - char * ip; - unsigned int i; - static struct - { - char * str; - int len; - bfd_reloc_code_real_type reloc; - } - reloc_map[] = - { -#define MAP(str,reloc) { str, sizeof (str) - 1, reloc } - MAP ("(got)", BFD_RELOC_ARM_GOT32), - MAP ("(gotoff)", BFD_RELOC_ARM_GOTOFF), - /* ScottB: Jan 30, 1998 - Added support for parsing "var(PLT)" - branch instructions generated by GCC for PLT relocs. */ - MAP ("(plt)", BFD_RELOC_ARM_PLT32), - MAP ("(target1)", BFD_RELOC_ARM_TARGET1), - MAP ("(sbrel)", BFD_RELOC_ARM_SBREL32), - MAP ("(target2)", BFD_RELOC_ARM_TARGET2), - MAP ("(tlsgd)", BFD_RELOC_ARM_TLS_GD32), - MAP ("(tlsldm)", BFD_RELOC_ARM_TLS_LDM32), - MAP ("(tlsldo)", BFD_RELOC_ARM_TLS_LDO32), - MAP ("(gottpoff)", BFD_RELOC_ARM_TLS_IE32), - MAP ("(tpoff)", BFD_RELOC_ARM_TLS_LE32), - { NULL, 0, BFD_RELOC_UNUSED } -#undef MAP - }; - - for (i = 0, ip = input_line_pointer; - i < sizeof (id) && (ISALNUM (*ip) || ISPUNCT (*ip)); - i++, ip++) - id[i] = TOLOWER (*ip); - - for (i = 0; reloc_map[i].str; i++) - if (strncmp (id, reloc_map[i].str, reloc_map[i].len) == 0) - break; - - input_line_pointer += reloc_map[i].len; - - return reloc_map[i].reloc; -} -#endif - -/* ARM V5 branch-link-exchange (argument parse) for BLX(1) only. - Expects inst.instruction is set for BLX(1). - Note: this is cloned from do_branch, and the reloc changed to be a - new one that can cope with setting one extra bit (the H bit). */ - -static void -do_branch25 (char * str) -{ - if (my_get_expression (& inst.reloc.exp, & str)) - return; - -#ifdef OBJ_ELF - { - char * save_in; - - /* ScottB: February 5, 1998 */ - /* Check to see of PLT32 reloc required for the instruction. */ - - /* arm_parse_reloc() works on input_line_pointer. - We actually want to parse the operands to the branch instruction - passed in 'str'. Save the input pointer and restore it later. */ - save_in = input_line_pointer; - input_line_pointer = str; - - if (inst.reloc.exp.X_op == O_symbol - && *str == '(' - && arm_parse_reloc () == BFD_RELOC_ARM_PLT32) - { - inst.reloc.type = BFD_RELOC_ARM_PLT32; - inst.reloc.pc_rel = 0; - /* Modify str to point to after parsed operands, otherwise - end_of_line() will complain about the (PLT) left in str. */ - str = input_line_pointer; - } - else - { - inst.reloc.type = BFD_RELOC_ARM_PCREL_BLX; - inst.reloc.pc_rel = 1; - } - - input_line_pointer = save_in; - } -#else - inst.reloc.type = BFD_RELOC_ARM_PCREL_BLX; - inst.reloc.pc_rel = 1; -#endif /* OBJ_ELF */ - - end_of_line (str); } -/* ARM V5 branch-link-exchange instruction (argument parse) - BLX <target_addr> ie BLX(1) - BLX{<condition>} <Rm> ie BLX(2) - Unfortunately, there are two different opcodes for this mnemonic. - So, the insns[].value is not used, and the code here zaps values - into inst.instruction. - Also, the <target_addr> can be 25 bits, hence has its own reloc. */ - +/* inst.operands[i] was set up by parse_address. Encode it into an + ARM-format mode 3 load or store instruction. Reject forms that + cannot be used with such instructions. If is_t is true, reject + forms that cannot be used with a T instruction (i.e. not + post-indexed). */ static void -do_blx (char * str) +encode_arm_addr_mode_3 (int i, bfd_boolean is_t) { - char * mystr = str; - int rm; - - skip_whitespace (mystr); - rm = reg_required_here (& mystr, 0); - - /* The above may set inst.error. Ignore his opinion. */ - inst.error = 0; - - if (rm != FAIL) - { - /* Arg is a register. - Use the condition code our caller put in inst.instruction. - Pass ourselves off as a BX with a funny opcode. */ - inst.instruction |= 0x012fff30; - do_bx (str); - } - else + if (inst.operands[i].immisreg && inst.operands[i].shifted) { - /* This must be is BLX <target address>, no condition allowed. */ - if (inst.instruction != COND_ALWAYS) - { - inst.error = BAD_COND; - return; - } - - inst.instruction = 0xfafffffe; - - /* Process like a B/BL, but with a different reloc. - Note that B/BL expecte fffffe, not 0, offset in the opcode table. */ - do_branch25 (str); + inst.error = _("instruction does not accept scaled register index"); + return; } -} -/* ARM V5 Thumb BLX (argument parse) - BLX <target_addr> which is BLX(1) - BLX <Rm> which is BLX(2) - Unfortunately, there are two different opcodes for this mnemonic. - So, the tinsns[].value is not used, and the code here zaps values - into inst.instruction. */ + encode_arm_addr_mode_common (i, is_t); -static void -do_t_blx (char * str) -{ - char * mystr = str; - int rm; - - skip_whitespace (mystr); - inst.instruction = 0x4780; - - /* Note that this call is to the ARM register recognizer. BLX(2) - uses the ARM register space, not the Thumb one, so a call to - thumb_reg() would be wrong. */ - rm = reg_required_here (& mystr, 3); - inst.error = 0; - - if (rm != FAIL) + if (inst.operands[i].immisreg) { - /* It's BLX(2). The .instruction was zapped with rm & is final. */ - inst.size = 2; + inst.instruction |= inst.operands[i].imm; + if (!inst.operands[i].negative) + inst.instruction |= INDEX_UP; } - else + else /* immediate offset in inst.reloc */ { - /* No ARM register. This must be BLX(1). Change the .instruction. */ - inst.instruction = 0xf7ffeffe; - inst.size = 4; - - if (my_get_expression (& inst.reloc.exp, & mystr)) - return; - - inst.reloc.type = BFD_RELOC_THUMB_PCREL_BLX; - inst.reloc.pc_rel = 1; + 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 */ } - - end_of_line (mystr); } -/* ARM V5 breakpoint instruction (argument parse) - BKPT <16 bit unsigned immediate> - Instruction is not conditional. - The bit pattern given in insns[] has the COND_ALWAYS condition, - and it is an error if the caller tried to override that. */ +/* inst.operands[i] was set up by parse_address. Encode it into an + ARM-format instruction. Reject all forms which cannot be encoded + into a coprocessor load/store instruction. If wb_ok is false, + reject use of writeback; if unind_ok is false, reject use of + unindexed addressing. If reloc_override is not 0, use it instead + of BFD_ARM_CP_OFF_IMM. */ -static void -do_bkpt (char * str) +static int +encode_arm_cp_address (int i, int wb_ok, int unind_ok, int reloc_override) { - expressionS expr; - unsigned long number; + inst.instruction |= inst.operands[i].reg << 16; - skip_whitespace (str); + assert (!(inst.operands[i].preind && inst.operands[i].postind)); - /* Allow optional leading '#'. */ - if (is_immediate_prefix (* str)) - str++; - - memset (& expr, '\0', sizeof (expr)); - - if (my_get_expression (& expr, & str) - || (expr.X_op != O_constant - /* As a convenience we allow 'bkpt' without an operand. */ - && expr.X_op != O_absent)) + if (!inst.operands[i].preind && !inst.operands[i].postind) /* unindexed */ { - inst.error = _("bad expression"); - return; - } - - number = expr.X_add_number; - - /* Check it fits a 16 bit unsigned. */ - if (number != (number & 0xffff)) - { - inst.error = _("immediate value out of range"); - return; + assert (!inst.operands[i].writeback); + if (!unind_ok) + { + inst.error = _("instruction does not support unindexed addressing"); + return FAIL; + } + inst.instruction |= inst.operands[i].imm; + inst.instruction |= INDEX_UP; + return SUCCESS; } - /* Top 12 of 16 bits to bits 19:8. */ - inst.instruction |= (number & 0xfff0) << 4; - - /* Bottom 4 of 16 bits to bits 3:0. */ - inst.instruction |= number & 0xf; - - end_of_line (str); -} - -/* THUMB CPS instruction (argument parse). */ - -static void -do_t_cps (char * str) -{ - do_cps_flags (&str, /*thumb_p=*/1); - end_of_line (str); -} - -/* Parse and validate that a register is of the right form, this saves - repeated checking of this information in many similar cases. - Unlike the 32-bit case we do not insert the register into the opcode - here, since the position is often unknown until the full instruction - has been parsed. */ - -static int -thumb_reg (char ** strp, int hi_lo) -{ - int reg; - - if ((reg = reg_required_here (strp, -1)) == FAIL) - return FAIL; + if (inst.operands[i].preind) + inst.instruction |= PRE_INDEX; - switch (hi_lo) + if (inst.operands[i].writeback) { - case THUMB_REG_LO: - if (reg > 7) + if (inst.operands[i].reg == REG_PC) { - inst.error = _("lo register required"); + inst.error = _("pc may not be used with write-back"); return FAIL; } - break; - - case THUMB_REG_HI: - if (reg < 8) + if (!wb_ok) { - inst.error = _("hi register required"); + inst.error = _("instruction does not support writeback"); return FAIL; } - break; - - default: - break; + inst.instruction |= WRITE_BACK; } - return reg; + if (reloc_override) + inst.reloc.type = reloc_override; + else + inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM; + if (inst.reloc.pc_rel) + inst.reloc.exp.X_add_number -= 8; + return SUCCESS; } -static void -thumb_mov_compare (char * str, int move) -{ - int Rd, Rs = FAIL; +/* inst.reloc.exp describes an "=expr" load pseudo-operation. + Determine whether it can be performed with a move instruction; if + it can, convert inst.instruction to that move instruction and + return 1; if it can't, convert inst.instruction to a literal-pool + load and return 0. If this is not a valid thing to do in the + current context, set inst.error and return 1. - skip_whitespace (str); - - if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL - || skip_past_comma (&str) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } + inst.operands[i] describes the destination register. */ - if (move != THUMB_CPY && is_immediate_prefix (*str)) +static int +move_or_literal_pool (int i, bfd_boolean thumb_p, bfd_boolean mode_3) +{ + if ((inst.instruction & (thumb_p ? THUMB_LOAD_BIT : LOAD_BIT)) == 0) { - str++; - if (my_get_expression (&inst.reloc.exp, &str)) - return; + inst.error = _("invalid pseudo operation"); + return 1; } - else if ((Rs = thumb_reg (&str, THUMB_REG_ANY)) == FAIL) - return; - - if (Rs != FAIL) + if (inst.reloc.exp.X_op != O_constant && inst.reloc.exp.X_op != O_symbol) { - if (move != THUMB_CPY && Rs < 8 && Rd < 8) - { - if (move == THUMB_MOVE) - /* A move of two lowregs is encoded as ADD Rd, Rs, #0 - since a MOV instruction produces unpredictable results. */ - inst.instruction = T_OPCODE_ADD_I3; - else - inst.instruction = T_OPCODE_CMP_LR; - inst.instruction |= Rd | (Rs << 3); - } - else - { - if (move == THUMB_MOVE) - inst.instruction = T_OPCODE_MOV_HR; - else if (move != THUMB_CPY) - inst.instruction = T_OPCODE_CMP_HR; - - if (Rd > 7) - inst.instruction |= THUMB_H1; - - if (Rs > 7) - inst.instruction |= THUMB_H2; - - inst.instruction |= (Rd & 7) | ((Rs & 7) << 3); - } + inst.error = _("constant expression expected"); + return 1; } - else + if (inst.reloc.exp.X_op == O_constant) { - if (Rd > 7) + if (thumb_p) { - inst.error = _("only lo regs allowed with immediate"); - return; + if ((inst.reloc.exp.X_add_number & ~0xFF) == 0) + { + /* This can be done with a mov(1) instruction. */ + inst.instruction = T_OPCODE_MOV_I8 | (inst.operands[i].reg << 8); + inst.instruction |= inst.reloc.exp.X_add_number; + return 1; + } } - - if (move == THUMB_MOVE) - inst.instruction = T_OPCODE_MOV_I8; - else - inst.instruction = T_OPCODE_CMP_I8; - - inst.instruction |= Rd << 8; - - if (inst.reloc.exp.X_op != O_constant) - inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM; else { - unsigned value = inst.reloc.exp.X_add_number; - - if (value > 255) + int value = encode_arm_immediate (inst.reloc.exp.X_add_number); + if (value != FAIL) { - inst.error = _("invalid immediate"); - return; + /* This can be done with a mov instruction. */ + inst.instruction &= LITERAL_MASK; + inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT); + inst.instruction |= value & 0xfff; + return 1; } - inst.instruction |= value; + value = encode_arm_immediate (~inst.reloc.exp.X_add_number); + if (value != FAIL) + { + /* This can be done with a mvn instruction. */ + inst.instruction &= LITERAL_MASK; + inst.instruction |= INST_IMMEDIATE | (OPCODE_MVN << DATA_OP_SHIFT); + inst.instruction |= value & 0xfff; + return 1; + } } } - end_of_line (str); + if (add_to_lit_pool () == FAIL) + { + inst.error = _("literal pool insertion failed"); + return 1; + } + inst.operands[1].reg = REG_PC; + inst.operands[1].isreg = 1; + inst.operands[1].preind = 1; + inst.reloc.pc_rel = 1; + inst.reloc.type = (thumb_p + ? BFD_RELOC_ARM_THUMB_OFFSET + : (mode_3 + ? BFD_RELOC_ARM_HWLITERAL + : BFD_RELOC_ARM_LITERAL)); + return 0; } -/* THUMB CPY instruction (argument parse). */ +/* Functions for instruction encoding, sorted by subarchitecture. + First some generics; their names are taken from the conventional + bit positions for register arguments in ARM format instructions. */ static void -do_t_cpy (char * str) +do_noargs (void) { - thumb_mov_compare (str, THUMB_CPY); } -/* THUMB SETEND instruction (argument parse). */ - static void -do_t_setend (char * str) +do_rd (void) { - if (do_endian_specifier (str)) - inst.instruction |= 0x8; -} - -/* Parse INSN_TYPE insn STR having a possible IMMEDIATE_SIZE immediate. */ - -static unsigned long -check_iwmmxt_insn (char * str, - enum iwmmxt_insn_type insn_type, - int immediate_size) -{ - int reg = 0; - const char * inst_error; - expressionS expr; - unsigned long number; - - inst_error = inst.error; - if (!inst.error) - inst.error = BAD_ARGS; - skip_whitespace (str); - - switch (insn_type) - { - case check_rd: - if ((reg = reg_required_here (&str, 12)) == FAIL) - return FAIL; - break; - - case check_wr: - if ((wreg_required_here (&str, 0, IWMMXT_REG_WR)) == FAIL) - return FAIL; - break; - - case check_wrwr: - if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL - || skip_past_comma (&str) == FAIL - || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL)) - return FAIL; - break; - - case check_wrwrwr: - if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL - || skip_past_comma (&str) == FAIL - || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL - || skip_past_comma (&str) == FAIL - || wreg_required_here (&str, 0, IWMMXT_REG_WR) == FAIL)) - return FAIL; - break; - - case check_wrwrwcg: - if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL - || skip_past_comma (&str) == FAIL - || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL - || skip_past_comma (&str) == FAIL - || wreg_required_here (&str, 0, IWMMXT_REG_WCG) == FAIL)) - return FAIL; - break; - - case check_tbcst: - if ((wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL - || skip_past_comma (&str) == FAIL - || reg_required_here (&str, 12) == FAIL)) - return FAIL; - break; - - case check_tmovmsk: - if ((reg_required_here (&str, 12) == FAIL - || skip_past_comma (&str) == FAIL - || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL)) - return FAIL; - break; - - case check_tmia: - if ((wreg_required_here (&str, 5, IWMMXT_REG_WR) == FAIL - || skip_past_comma (&str) == FAIL - || reg_required_here (&str, 0) == FAIL - || skip_past_comma (&str) == FAIL - || reg_required_here (&str, 12) == FAIL)) - return FAIL; - break; - - case check_tmcrr: - if ((wreg_required_here (&str, 0, IWMMXT_REG_WR) == FAIL - || skip_past_comma (&str) == FAIL - || reg_required_here (&str, 12) == FAIL - || skip_past_comma (&str) == FAIL - || reg_required_here (&str, 16) == FAIL)) - return FAIL; - break; - - case check_tmrrc: - if ((reg_required_here (&str, 12) == FAIL - || skip_past_comma (&str) == FAIL - || reg_required_here (&str, 16) == FAIL - || skip_past_comma (&str) == FAIL - || wreg_required_here (&str, 0, IWMMXT_REG_WR) == FAIL)) - return FAIL; - break; - - case check_tmcr: - if ((wreg_required_here (&str, 16, IWMMXT_REG_WC) == FAIL - || skip_past_comma (&str) == FAIL - || reg_required_here (&str, 12) == FAIL)) - return FAIL; - break; - - case check_tmrc: - if ((reg_required_here (&str, 12) == FAIL - || skip_past_comma (&str) == FAIL - || wreg_required_here (&str, 16, IWMMXT_REG_WC) == FAIL)) - return FAIL; - break; - - case check_tinsr: - if ((wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL - || skip_past_comma (&str) == FAIL - || reg_required_here (&str, 12) == FAIL - || skip_past_comma (&str) == FAIL)) - return FAIL; - break; - - case check_textrc: - if ((reg_required_here (&str, 12) == FAIL - || skip_past_comma (&str) == FAIL)) - return FAIL; - break; - - case check_waligni: - if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL - || skip_past_comma (&str) == FAIL - || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL - || skip_past_comma (&str) == FAIL - || wreg_required_here (&str, 0, IWMMXT_REG_WR) == FAIL - || skip_past_comma (&str) == FAIL)) - return FAIL; - break; - - case check_textrm: - if ((reg_required_here (&str, 12) == FAIL - || skip_past_comma (&str) == FAIL - || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL - || skip_past_comma (&str) == FAIL)) - return FAIL; - break; - - case check_wshufh: - if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL - || skip_past_comma (&str) == FAIL - || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL - || skip_past_comma (&str) == FAIL)) - return FAIL; - break; - } - - if (immediate_size == 0) - { - end_of_line (str); - inst.error = inst_error; - return reg; - } - else - { - skip_whitespace (str); - - /* Allow optional leading '#'. */ - if (is_immediate_prefix (* str)) - str++; - - memset (& expr, '\0', sizeof (expr)); - - if (my_get_expression (& expr, & str) || (expr.X_op != O_constant)) - { - inst.error = _("bad or missing expression"); - return FAIL; - } - - number = expr.X_add_number; - - if (number != (number & immediate_size)) - { - inst.error = _("immediate value out of range"); - return FAIL; - } - end_of_line (str); - inst.error = inst_error; - return number; - } + inst.instruction |= inst.operands[0].reg << 12; } static void -do_iwmmxt_byte_addr (char * str) +do_rd_rm (void) { - int op = (inst.instruction & 0x300) >> 8; - int reg; - - inst.instruction &= ~0x300; - inst.instruction |= (op & 1) << 22 | (op & 2) << 7; - - skip_whitespace (str); - - if ((reg = wreg_required_here (&str, 12, IWMMXT_REG_WR_OR_WC)) == FAIL - || skip_past_comma (& str) == FAIL - || cp_byte_address_required_here (&str) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - } - else - end_of_line (str); - - if (wc_register (reg)) - { - as_bad (_("non-word size not supported with control register")); - inst.instruction |= 0xf0000100; - inst.instruction &= ~0x00400000; - } + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg; } static void -do_iwmmxt_tandc (char * str) +do_rd_rn (void) { - int reg; - - reg = check_iwmmxt_insn (str, check_rd, 0); - - if (reg != REG_PC && !inst.error) - inst.error = _("only r15 allowed here"); + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg << 16; } static void -do_iwmmxt_tbcst (char * str) +do_rn_rd (void) { - check_iwmmxt_insn (str, check_tbcst, 0); + inst.instruction |= inst.operands[0].reg << 16; + inst.instruction |= inst.operands[1].reg << 12; } static void -do_iwmmxt_textrc (char * str) +do_rd_rm_rn (void) { - unsigned long number; - - if ((number = check_iwmmxt_insn (str, check_textrc, 7)) == (unsigned long) FAIL) - return; - - inst.instruction |= number & 0x7; + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg; + inst.instruction |= inst.operands[2].reg << 16; } static void -do_iwmmxt_textrm (char * str) +do_rd_rn_rm (void) { - unsigned long number; - - if ((number = check_iwmmxt_insn (str, check_textrm, 7)) == (unsigned long) FAIL) - return; - - inst.instruction |= number & 0x7; + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= inst.operands[2].reg; } static void -do_iwmmxt_tinsr (char * str) +do_rm_rd_rn (void) { - unsigned long number; - - if ((number = check_iwmmxt_insn (str, check_tinsr, 7)) == (unsigned long) FAIL) - return; - - inst.instruction |= number & 0x7; + inst.instruction |= inst.operands[0].reg; + inst.instruction |= inst.operands[1].reg << 12; + inst.instruction |= inst.operands[2].reg << 16; } static void -do_iwmmxt_tmcr (char * str) +do_imm0 (void) { - check_iwmmxt_insn (str, check_tmcr, 0); + inst.instruction |= inst.operands[0].imm; } static void -do_iwmmxt_tmcrr (char * str) +do_rd_cpaddr (void) { - check_iwmmxt_insn (str, check_tmcrr, 0); + inst.instruction |= inst.operands[0].reg << 12; + encode_arm_cp_address (1, TRUE, TRUE, 0); } -static void -do_iwmmxt_tmia (char * str) -{ - check_iwmmxt_insn (str, check_tmia, 0); -} +/* ARM instructions, in alphabetical order by function name (except + that wrapper functions appear immediately after the function they + wrap). */ + +/* 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". */ static void -do_iwmmxt_tmovmsk (char * str) +do_adr (void) { - check_iwmmxt_insn (str, check_tmovmsk, 0); + inst.instruction |= (inst.operands[0].reg << 12); /* Rd */ + + /* 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; } +/* 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)" */ + static void -do_iwmmxt_tmrc (char * str) +do_adrl (void) { - check_iwmmxt_insn (str, check_tmrc, 0); + inst.instruction |= (inst.operands[0].reg << 12); /* Rd */ + + /* 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; } static void -do_iwmmxt_tmrrc (char * str) +do_arit (void) { - check_iwmmxt_insn (str, check_tmrrc, 0); + if (!inst.operands[1].present) + inst.operands[1].reg = inst.operands[0].reg; + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg << 16; + encode_arm_shifter_operand (2); } static void -do_iwmmxt_torc (char * str) +do_bfc (void) { - check_iwmmxt_insn (str, check_rd, 0); + unsigned int msb = inst.operands[1].imm + inst.operands[2].imm; + constraint (msb > 32, _("bit-field extends past end of register")); + /* The instruction encoding stores the LSB and MSB, + not the LSB and width. */ + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].imm << 7; + inst.instruction |= (msb - 1) << 16; } static void -do_iwmmxt_waligni (char * str) +do_bfi (void) { - unsigned long number; + unsigned int msb; - if ((number = check_iwmmxt_insn (str, check_waligni, 7)) == (unsigned long) FAIL) - return; + /* #0 in second position is alternative syntax for bfc, which is + the same instruction but with REG_PC in the Rm field. */ + if (!inst.operands[1].isreg) + inst.operands[1].reg = REG_PC; - inst.instruction |= ((number & 0x7) << 20); + msb = inst.operands[2].imm + inst.operands[3].imm; + constraint (msb > 32, _("bit-field extends past end of register")); + /* The instruction encoding stores the LSB and MSB, + not the LSB and width. */ + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg; + inst.instruction |= inst.operands[2].imm << 7; + inst.instruction |= (msb - 1) << 16; } static void -do_iwmmxt_wmov (char * str) +do_bfx (void) { - if (check_iwmmxt_insn (str, check_wrwr, 0) == (unsigned long) FAIL) - return; - - inst.instruction |= ((inst.instruction >> 16) & 0xf); + constraint (inst.operands[2].imm + inst.operands[3].imm > 32, + _("bit-field extends past end of register")); + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg; + inst.instruction |= inst.operands[2].imm << 7; + inst.instruction |= (inst.operands[3].imm - 1) << 16; } +/* ARM V5 breakpoint instruction (argument parse) + BKPT <16 bit unsigned immediate> + Instruction is not conditional. + The bit pattern given in insns[] has the COND_ALWAYS condition, + and it is an error if the caller tried to override that. */ + static void -do_iwmmxt_word_addr (char * str) +do_bkpt (void) { - int op = (inst.instruction & 0x300) >> 8; - int reg; - - inst.instruction &= ~0x300; - inst.instruction |= (op & 1) << 22 | (op & 2) << 7; + /* Top 12 of 16 bits to bits 19:8. */ + inst.instruction |= (inst.operands[0].imm & 0xfff0) << 4; - skip_whitespace (str); + /* Bottom 4 of 16 bits to bits 3:0. */ + inst.instruction |= inst.operands[0].imm & 0xf; +} - if ((reg = wreg_required_here (&str, 12, IWMMXT_REG_WR_OR_WC)) == FAIL - || skip_past_comma (& str) == FAIL - || cp_address_required_here (& str, CP_WB_OK) == FAIL) +static void +encode_branch (int default_reloc) +{ + if (inst.operands[0].hasreloc) { - if (! inst.error) - inst.error = BAD_ARGS; + 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 - end_of_line (str); - - if (wc_register (reg)) { - if ((inst.instruction & COND_MASK) != COND_ALWAYS) - as_bad (_("conditional execution not supported with control register")); - if (op != 2) - as_bad (_("non-word size not supported with control register")); - inst.instruction |= 0xf0000100; - inst.instruction &= ~0x00400000; + inst.reloc.type = default_reloc; + inst.reloc.pc_rel = 1; } } static void -do_iwmmxt_wrwr (char * str) +do_branch (void) { - check_iwmmxt_insn (str, check_wrwr, 0); + encode_branch (BFD_RELOC_ARM_PCREL_BRANCH); } +/* ARM V5 branch-link-exchange instruction (argument parse) + BLX <target_addr> ie BLX(1) + BLX{<condition>} <Rm> ie BLX(2) + Unfortunately, there are two different opcodes for this mnemonic. + So, the insns[].value is not used, and the code here zaps values + into inst.instruction. + Also, the <target_addr> can be 25 bits, hence has its own reloc. */ + static void -do_iwmmxt_wrwrwcg (char * str) +do_blx (void) { - check_iwmmxt_insn (str, check_wrwrwcg, 0); + if (inst.operands[0].isreg) + { + /* Arg is a register; the opcode provided by insns[] is correct. + It is not illegal to do "blx pc", just useless. */ + if (inst.operands[0].reg == REG_PC) + as_tsktsk (_("use of r15 in blx in ARM mode is not really useful")); + + inst.instruction |= inst.operands[0].reg; + } + else + { + /* 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; + encode_branch (BFD_RELOC_ARM_PCREL_BLX); + } } static void -do_iwmmxt_wrwrwr (char * str) +do_bx (void) { - check_iwmmxt_insn (str, check_wrwrwr, 0); + if (inst.operands[0].reg == REG_PC) + as_tsktsk (_("use of r15 in bx in ARM mode is not really useful")); + + inst.instruction |= inst.operands[0].reg; } + +/* ARM v5TEJ. Jump to Jazelle code. */ + static void -do_iwmmxt_wshufh (char * str) +do_bxj (void) { - unsigned long number; - - if ((number = check_iwmmxt_insn (str, check_wshufh, 0xff)) == (unsigned long) FAIL) - return; + if (inst.operands[0].reg == REG_PC) + as_tsktsk (_("use of r15 in bxj is not really useful")); - inst.instruction |= ((number & 0xf0) << 16) | (number & 0xf); + inst.instruction |= inst.operands[0].reg; } +/* Co-processor data operation: + CDP{cond} <coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>{, <opcode_2>} + CDP2 <coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>{, <opcode_2>} */ static void -do_iwmmxt_wzero (char * str) +do_cdp (void) { - if (check_iwmmxt_insn (str, check_wr, 0) == (unsigned long) FAIL) - return; - - inst.instruction |= ((inst.instruction & 0xf) << 12) | ((inst.instruction & 0xf) << 16); + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].imm << 20; + inst.instruction |= inst.operands[2].reg << 12; + inst.instruction |= inst.operands[3].reg << 16; + inst.instruction |= inst.operands[4].reg; + inst.instruction |= inst.operands[5].imm << 5; } -/* Xscale multiply-accumulate (argument parse) - MIAcc acc0,Rm,Rs - MIAPHcc acc0,Rm,Rs - MIAxycc acc0,Rm,Rs. */ - static void -do_xsc_mia (char * str) +do_cmp (void) { - int rs; - int rm; - - if (accum0_required_here (& str) == FAIL) - inst.error = ERR_NO_ACCUM; - - else if (skip_past_comma (& str) == FAIL - || (rm = reg_required_here (& str, 0)) == FAIL) - inst.error = BAD_ARGS; - - else if (skip_past_comma (& str) == FAIL - || (rs = reg_required_here (& str, 12)) == FAIL) - inst.error = BAD_ARGS; - - /* inst.instruction has now been zapped with both rm and rs. */ - else if (rm == REG_PC || rs == REG_PC) - inst.error = BAD_PC; /* Undefined result if rm or rs is R15. */ - - else - end_of_line (str); + inst.instruction |= inst.operands[0].reg << 16; + encode_arm_shifter_operand (1); } -/* Xscale move-accumulator-register (argument parse) +/* Transfer between coprocessor and ARM registers. + MRC{cond} <coproc>, <opcode_1>, <Rd>, <CRn>, <CRm>{, <opcode_2>} + MRC2 + MCR{cond} + MCR2 - MARcc acc0,RdLo,RdHi. */ + No special properties. */ static void -do_xsc_mar (char * str) +do_co_reg (void) { - int rdlo, rdhi; + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].imm << 21; + inst.instruction |= inst.operands[2].reg << 12; + inst.instruction |= inst.operands[3].reg << 16; + inst.instruction |= inst.operands[4].reg; + inst.instruction |= inst.operands[5].imm << 5; +} - if (accum0_required_here (& str) == FAIL) - inst.error = ERR_NO_ACCUM; +/* Transfer between coprocessor register and pair of ARM registers. + MCRR{cond} <coproc>, <opcode>, <Rd>, <Rn>, <CRm>. + MCRR2 + MRRC{cond} + MRRC2 - else if (skip_past_comma (& str) == FAIL - || (rdlo = reg_required_here (& str, 12)) == FAIL) - inst.error = BAD_ARGS; + Two XScale instructions are special cases of these: - else if (skip_past_comma (& str) == FAIL - || (rdhi = reg_required_here (& str, 16)) == FAIL) - inst.error = BAD_ARGS; + MAR{cond} acc0, <RdLo>, <RdHi> == MCRR{cond} p0, #0, <RdLo>, <RdHi>, c0 + MRA{cond} acc0, <RdLo>, <RdHi> == MRRC{cond} p0, #0, <RdLo>, <RdHi>, c0 - /* inst.instruction has now been zapped with both rdlo and rdhi. */ - else if (rdlo == REG_PC || rdhi == REG_PC) - inst.error = BAD_PC; /* Undefined result if rdlo or rdhi is R15. */ + Result unpredicatable if Rd or Rn is R15. */ - else - end_of_line (str); +static void +do_co_reg2c (void) +{ + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].imm << 4; + inst.instruction |= inst.operands[2].reg << 12; + inst.instruction |= inst.operands[3].reg << 16; + inst.instruction |= inst.operands[4].reg; } -/* Xscale move-register-accumulator (argument parse) - - MRAcc RdLo,RdHi,acc0. */ - static void -do_xsc_mra (char * str) +do_cpsi (void) { - int rdlo; - int rdhi; - - skip_whitespace (str); - - if ((rdlo = reg_required_here (& str, 12)) == FAIL) - inst.error = BAD_ARGS; - - else if (skip_past_comma (& str) == FAIL - || (rdhi = reg_required_here (& str, 16)) == FAIL) - inst.error = BAD_ARGS; - - else if (skip_past_comma (& str) == FAIL - || accum0_required_here (& str) == FAIL) - inst.error = ERR_NO_ACCUM; - - /* inst.instruction has now been zapped with both rdlo and rdhi. */ - else if (rdlo == rdhi) - inst.error = BAD_ARGS; /* Undefined result if 2 writes to same reg. */ - - else if (rdlo == REG_PC || rdhi == REG_PC) - inst.error = BAD_PC; /* Undefined result if rdlo or rdhi is R15. */ - else - end_of_line (str); + inst.instruction |= inst.operands[0].imm << 6; + inst.instruction |= inst.operands[1].imm; } -static int -ldst_extend (char ** str) +static void +do_it (void) { - int add = INDEX_UP; - - switch (**str) - { - case '#': - case '$': - (*str)++; - if (my_get_expression (& inst.reloc.exp, str)) - return FAIL; - - if (inst.reloc.exp.X_op == O_constant) - { - int value = inst.reloc.exp.X_add_number; - - if (value < -4095 || value > 4095) - { - inst.error = _("address offset too large"); - return FAIL; - } - - if (value < 0) - { - value = -value; - add = 0; - } - - inst.instruction |= add | value; - } - else - { - inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM; - inst.reloc.pc_rel = 0; - } - return SUCCESS; - - case '-': - add = 0; - /* Fall through. */ - - case '+': - (*str)++; - /* Fall through. */ - - default: - if (reg_required_here (str, 0) == FAIL) - return FAIL; - - inst.instruction |= add | OFFSET_REG; - if (skip_past_comma (str) == SUCCESS) - return decode_shift (str, SHIFT_IMMEDIATE); - - return SUCCESS; - } + /* There is no IT instruction in ARM mode. We + process it but do not generate code for it. */ + inst.size = 0; } -/* ARMv5TE: Preload-Cache - - PLD <addr_mode> - - Syntactically, like LDR with B=1, W=0, L=1. */ - static void -do_pld (char * str) +do_ldmstm (void) { - int rd; - - skip_whitespace (str); + int base_reg = inst.operands[0].reg; + int range = inst.operands[1].imm; - if (* str != '[') - { - inst.error = _("'[' expected after PLD mnemonic"); - return; - } - - ++str; - skip_whitespace (str); - - if ((rd = reg_required_here (& str, 16)) == FAIL) - return; - - skip_whitespace (str); + inst.instruction |= base_reg << 16; + inst.instruction |= range; - if (*str == ']') - { - /* [Rn], ... ? */ - ++str; - skip_whitespace (str); + if (inst.operands[1].writeback) + inst.instruction |= LDM_TYPE_2_OR_3; - /* Post-indexed addressing is not allowed with PLD. */ - if (skip_past_comma (&str) == SUCCESS) - { - inst.error - = _("post-indexed expression used in preload instruction"); - return; - } - else if (*str == '!') /* [Rn]! */ - { - inst.error = _("writeback used in preload instruction"); - ++str; - } - else /* [Rn] */ - inst.instruction |= INDEX_UP | PRE_INDEX; - } - else /* [Rn, ...] */ + if (inst.operands[0].writeback) { - if (skip_past_comma (& str) == FAIL) - { - inst.error = _("pre-indexed expression expected"); - return; - } - - if (ldst_extend (&str) == FAIL) - return; - - skip_whitespace (str); - - if (* str != ']') + inst.instruction |= WRITE_BACK; + /* Check for unpredictable uses of writeback. */ + if (inst.instruction & LOAD_BIT) { - inst.error = _("missing ]"); - return; + /* Not allowed in LDM type 2. */ + if ((inst.instruction & LDM_TYPE_2_OR_3) + && ((range & (1 << REG_PC)) == 0)) + as_warn (_("writeback of base register is UNPREDICTABLE")); + /* Only allowed if base reg not in list for other types. */ + else if (range & (1 << base_reg)) + as_warn (_("writeback of base register when in register list is UNPREDICTABLE")); } - - ++ str; - skip_whitespace (str); - - if (* str == '!') /* [Rn]! */ + else /* STM. */ { - inst.error = _("writeback used in preload instruction"); - ++ str; + /* Not allowed for type 2. */ + if (inst.instruction & LDM_TYPE_2_OR_3) + as_warn (_("writeback of base register is UNPREDICTABLE")); + /* Only allowed if base reg not in list, or first in list. */ + else if ((range & (1 << base_reg)) + && (range & ((1 << base_reg) - 1))) + as_warn (_("if writeback register is in list, it must be the lowest reg in the list")); } - - inst.instruction |= PRE_INDEX; } - - end_of_line (str); } /* ARMv5TE load-consecutive (argument parse) @@ -5802,5824 +4624,5251 @@ do_pld (char * str) STRccD R, mode. */ static void -do_ldrd (char * str) +do_ldrd (void) { - int rd; - int rn; - - skip_whitespace (str); - - if ((rd = reg_required_here (& str, 12)) == FAIL) - { - inst.error = BAD_ARGS; - return; - } + constraint (inst.operands[0].reg % 2 != 0, + _("first destination register must be even")); + constraint (inst.operands[1].present + && inst.operands[1].reg != inst.operands[0].reg + 1, + _("can only load two consecutive registers")); + constraint (inst.operands[0].reg == REG_LR, _("r14 not allowed here")); + constraint (!inst.operands[2].isreg, _("'[' expected")); - if (skip_past_comma (& str) == FAIL - || (rn = ld_mode_required_here (& str)) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - /* inst.instruction has now been zapped with Rd and the addressing mode. */ - if (rd & 1) /* Unpredictable result if Rd is odd. */ - { - inst.error = _("destination register must be even"); - return; - } - - if (rd == REG_LR) + if (!inst.operands[1].present) + inst.operands[1].reg = inst.operands[0].reg + 1; + + if (inst.instruction & LOAD_BIT) { - inst.error = _("r14 not allowed here"); - return; - } + /* encode_arm_addr_mode_3 will diagnose overlap between the base + register and the first register written; we have to diagnose + overlap between the base and the second register written here. */ - if (((rd == rn) || (rd + 1 == rn)) - && ((inst.instruction & WRITE_BACK) - || (!(inst.instruction & PRE_INDEX)))) - as_warn (_("pre/post-indexing used when modified address register is destination")); - - /* For an index-register load, the index register must not overlap the - destination (even if not write-back). */ - if ((inst.instruction & V4_STR_BIT) == 0 - && (inst.instruction & HWOFFSET_IMM) == 0) - { - int rm = inst.instruction & 0x0000000f; + if (inst.operands[2].reg == inst.operands[1].reg + && (inst.operands[2].writeback || inst.operands[2].postind)) + as_warn (_("base register written back, and overlaps " + "second destination register")); - if (rm == rd || (rm == rd + 1)) - as_warn (_("ldrd destination registers must not overlap index register")); + /* 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)) + as_warn (_("index register overlaps destination register")); } - end_of_line (str); + inst.instruction |= inst.operands[0].reg << 12; + encode_arm_addr_mode_3 (2, /*is_t=*/FALSE); } -/* Returns the index into fp_values of a floating point number, - or -1 if not in the table. */ - -static int -my_get_float_expression (char ** str) +static void +do_ldrex (void) { - LITTLENUM_TYPE words[MAX_LITTLENUMS]; - char * save_in; - expressionS exp; - int i; - int j; + constraint (!inst.operands[1].isreg || !inst.operands[1].preind + || inst.operands[1].postind || inst.operands[1].writeback + || inst.operands[1].immisreg || inst.operands[1].shifted + || inst.operands[1].negative, + _("instruction does not accept this addressing mode")); - memset (words, 0, MAX_LITTLENUMS * sizeof (LITTLENUM_TYPE)); + constraint (inst.operands[1].reg == REG_PC, BAD_PC); - /* Look for a raw floating point number. */ - if ((save_in = atof_ieee (*str, 'x', words)) != NULL - && is_end_of_line[(unsigned char) *save_in]) - { - for (i = 0; i < NUM_FLOAT_VALS; i++) - { - for (j = 0; j < MAX_LITTLENUMS; j++) - { - if (words[j] != fp_values[i][j]) - break; - } + constraint (inst.reloc.exp.X_op != O_constant + || inst.reloc.exp.X_add_number != 0, + _("offset must be zero in ARM encoding")); - if (j == MAX_LITTLENUMS) - { - *str = save_in; - return i; - } - } - } - - /* Try and parse a more complex expression, this will probably fail - unless the code uses a floating point prefix (eg "0f"). */ - save_in = input_line_pointer; - input_line_pointer = *str; - if (expression (&exp) == absolute_section - && exp.X_op == O_big - && exp.X_add_number < 0) - { - /* FIXME: 5 = X_PRECISION, should be #define'd where we can use it. - Ditto for 15. */ - if (gen_to_words (words, 5, (long) 15) == 0) - { - for (i = 0; i < NUM_FLOAT_VALS; i++) - { - for (j = 0; j < MAX_LITTLENUMS; j++) - { - if (words[j] != fp_values[i][j]) - break; - } - - if (j == MAX_LITTLENUMS) - { - *str = input_line_pointer; - input_line_pointer = save_in; - return i; - } - } - } - } - - *str = input_line_pointer; - input_line_pointer = save_in; - return -1; + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg << 16; + inst.reloc.type = BFD_RELOC_UNUSED; } -/* We handle all bad expressions here, so that we can report the faulty - instruction in the error message. */ -void -md_operand (expressionS * expr) +static void +do_ldrexd (void) { - if (in_my_get_expression) - { - expr->X_op = O_illegal; - if (inst.error == NULL) - inst.error = _("bad expression"); - } -} + constraint (inst.operands[0].reg % 2 != 0, + _("even register required")); + constraint (inst.operands[1].present + && inst.operands[1].reg != inst.operands[0].reg + 1, + _("can only load two consecutive registers")); + /* If op 1 were present and equal to PC, this function wouldn't + have been called in the first place. */ + constraint (inst.operands[0].reg == REG_LR, _("r14 not allowed here")); -/* Do those data_ops which can take a negative immediate constant - by altering the instruction. A bit of a hack really. - MOV <-> MVN - AND <-> BIC - ADC <-> SBC - by inverting the second operand, and - ADD <-> SUB - CMP <-> CMN - by negating the second operand. */ + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[2].reg << 16; +} -static int -negate_data_op (unsigned long * instruction, - unsigned long value) +static void +do_ldst (void) { - int op, new_inst; - unsigned long negated, inverted; - - negated = validate_immediate (-value); - inverted = validate_immediate (~value); - - op = (*instruction >> DATA_OP_SHIFT) & 0xf; - switch (op) - { - /* First negates. */ - case OPCODE_SUB: /* ADD <-> SUB */ - new_inst = OPCODE_ADD; - value = negated; - break; - - case OPCODE_ADD: - new_inst = OPCODE_SUB; - value = negated; - break; - - case OPCODE_CMP: /* CMP <-> CMN */ - new_inst = OPCODE_CMN; - value = negated; - break; - - case OPCODE_CMN: - new_inst = OPCODE_CMP; - value = negated; - break; - - /* Now Inverted ops. */ - case OPCODE_MOV: /* MOV <-> MVN */ - new_inst = OPCODE_MVN; - value = inverted; - break; - - case OPCODE_MVN: - new_inst = OPCODE_MOV; - value = inverted; - break; - - case OPCODE_AND: /* AND <-> BIC */ - new_inst = OPCODE_BIC; - value = inverted; - break; - - case OPCODE_BIC: - new_inst = OPCODE_AND; - value = inverted; - break; - - case OPCODE_ADC: /* ADC <-> SBC */ - new_inst = OPCODE_SBC; - value = inverted; - break; - - case OPCODE_SBC: - new_inst = OPCODE_ADC; - value = inverted; - break; - - /* We cannot do anything. */ - default: - return FAIL; - } - - if (value == (unsigned) FAIL) - return FAIL; - - *instruction &= OPCODE_MASK; - *instruction |= new_inst << DATA_OP_SHIFT; - return value; + inst.instruction |= inst.operands[0].reg << 12; + if (!inst.operands[1].isreg) + if (move_or_literal_pool (0, /*thumb_p=*/FALSE, /*mode_3=*/FALSE)) + return; + encode_arm_addr_mode_2 (1, /*is_t=*/FALSE); } -static int -data_op2 (char ** str) +static void +do_ldstt (void) { - int value; - expressionS expr; - - skip_whitespace (* str); - - if (reg_required_here (str, 0) != FAIL) + /* ldrt/strt always use post-indexed addressing. Turn [Rn] into [Rn]! and + reject [Rn,...]. */ + if (inst.operands[1].preind) { - if (skip_past_comma (str) == SUCCESS) - /* Shift operation on register. */ - return decode_shift (str, NO_SHIFT_RESTRICT); + constraint (inst.reloc.exp.X_op != O_constant || + inst.reloc.exp.X_add_number != 0, + _("this instruction requires a post-indexed address")); - return SUCCESS; + inst.operands[1].preind = 0; + inst.operands[1].postind = 1; + inst.operands[1].writeback = 1; } - else - { - /* Immediate expression. */ - if (is_immediate_prefix (**str)) - { - (*str)++; - inst.error = NULL; - - if (my_get_expression (&inst.reloc.exp, str)) - return FAIL; - - if (inst.reloc.exp.X_add_symbol) - { - inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE; - inst.reloc.pc_rel = 0; - } - else - { - if (skip_past_comma (str) == SUCCESS) - { - /* #x, y -- ie explicit rotation by Y. */ - if (my_get_expression (&expr, str)) - return FAIL; - - if (expr.X_op != O_constant) - { - inst.error = _("constant expression expected"); - return FAIL; - } - - /* Rotate must be a multiple of 2. */ - if (((unsigned) expr.X_add_number) > 30 - || (expr.X_add_number & 1) != 0 - || ((unsigned) inst.reloc.exp.X_add_number) > 255) - { - inst.error = _("invalid constant"); - return FAIL; - } - inst.instruction |= INST_IMMEDIATE; - inst.instruction |= inst.reloc.exp.X_add_number; - inst.instruction |= expr.X_add_number << 7; - return SUCCESS; - } - - /* Implicit rotation, select a suitable one. */ - value = validate_immediate (inst.reloc.exp.X_add_number); - - if (value == FAIL) - { - /* Can't be done. Perhaps the code reads something like - "add Rd, Rn, #-n", where "sub Rd, Rn, #n" would be OK. */ - if ((value = negate_data_op (&inst.instruction, - inst.reloc.exp.X_add_number)) - == FAIL) - { - inst.error = _("invalid constant"); - return FAIL; - } - } - - inst.instruction |= value; - } + inst.instruction |= inst.operands[0].reg << 12; + encode_arm_addr_mode_2 (1, /*is_t=*/TRUE); +} - inst.instruction |= INST_IMMEDIATE; - return SUCCESS; - } +/* Halfword and signed-byte load/store operations. */ - (*str)++; - inst.error = _("register or shift expression expected"); - return FAIL; - } +static void +do_ldstv4 (void) +{ + inst.instruction |= inst.operands[0].reg << 12; + if (!inst.operands[1].isreg) + if (move_or_literal_pool (0, /*thumb_p=*/FALSE, /*mode_3=*/TRUE)) + return; + encode_arm_addr_mode_3 (1, /*is_t=*/FALSE); } -static int -fp_op2 (char ** str) +static void +do_ldsttv4 (void) { - skip_whitespace (* str); - - if (fp_reg_required_here (str, 0) != FAIL) - return SUCCESS; - else + /* ldrt/strt always use post-indexed addressing. Turn [Rn] into [Rn]! and + reject [Rn,...]. */ + if (inst.operands[1].preind) { - /* Immediate expression. */ - if (*((*str)++) == '#') - { - int i; - - inst.error = NULL; - - skip_whitespace (* str); - - /* First try and match exact strings, this is to guarantee - that some formats will work even for cross assembly. */ - - for (i = 0; fp_const[i]; i++) - { - if (strncmp (*str, fp_const[i], strlen (fp_const[i])) == 0) - { - char *start = *str; - - *str += strlen (fp_const[i]); - if (is_end_of_line[(unsigned char) **str]) - { - inst.instruction |= i + 8; - return SUCCESS; - } - *str = start; - } - } + constraint (inst.reloc.exp.X_op != O_constant || + inst.reloc.exp.X_add_number != 0, + _("this instruction requires a post-indexed address")); - /* Just because we didn't get a match doesn't mean that the - constant isn't valid, just that it is in a format that we - don't automatically recognize. Try parsing it with - the standard expression routines. */ - if ((i = my_get_float_expression (str)) >= 0) - { - inst.instruction |= i + 8; - return SUCCESS; - } - - inst.error = _("invalid floating point immediate expression"); - return FAIL; - } - inst.error = - _("floating point register or immediate expression expected"); - return FAIL; + inst.operands[1].preind = 0; + inst.operands[1].postind = 1; + inst.operands[1].writeback = 1; } + inst.instruction |= inst.operands[0].reg << 12; + encode_arm_addr_mode_3 (1, /*is_t=*/TRUE); } +/* Co-processor register load/store. + Format: <LDC|STC>{cond}[L] CP#,CRd,<address> */ static void -do_arit (char * str) +do_lstc (void) { - skip_whitespace (str); - - if (reg_required_here (&str, 12) == FAIL - || skip_past_comma (&str) == FAIL - || reg_required_here (&str, 16) == FAIL - || skip_past_comma (&str) == FAIL - || data_op2 (&str) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - end_of_line (str); + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].reg << 12; + encode_arm_cp_address (2, TRUE, TRUE, 0); } static void -do_adr (char * str) +do_mlas (void) { - /* 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". */ - skip_whitespace (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; - } + /* This restriction does not apply to mls (nor to mla in v6, but + that's hard to detect at present). */ + if (inst.operands[0].reg == inst.operands[1].reg + && !(inst.instruction & 0x00400000)) + as_tsktsk (_("rd and rm should be different in mla")); - /* 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.instruction |= inst.operands[0].reg << 16; + inst.instruction |= inst.operands[1].reg; + inst.instruction |= inst.operands[2].reg << 8; + inst.instruction |= inst.operands[3].reg << 12; - end_of_line (str); } static void -do_adrl (char * str) +do_mov (void) { - /* 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)" */ - - skip_whitespace (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; -#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.instruction |= inst.operands[0].reg << 12; + encode_arm_shifter_operand (1); } +/* ARM V6T2 16-bit immediate register load: MOV[WT]{cond} Rd, #<imm16>. */ static void -do_cmp (char * str) +do_mov16 (void) { - skip_whitespace (str); - - if (reg_required_here (&str, 16) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || data_op2 (&str) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - end_of_line (str); + 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; } static void -do_mov (char * str) +do_mrs (void) { - skip_whitespace (str); - - if (reg_required_here (&str, 12) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || data_op2 (&str) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - end_of_line (str); + /* mrs only accepts CPSR/SPSR/CPSR_all/SPSR_all. */ + constraint ((inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f)) + != (PSR_c|PSR_f), + _("'CPSR' or 'SPSR' expected")); + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= (inst.operands[1].imm & SPSR_BIT); } +/* Two possible forms: + "{C|S}PSR_<field>, Rm", + "{C|S}PSR_f, #expression". */ + static void -do_ldst (char * str) +do_msr (void) { - int pre_inc = 0; - int conflict_reg; - int value; - - skip_whitespace (str); - - if ((conflict_reg = reg_required_here (&str, 12)) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL) - { - inst.error = _("address expected"); - return; - } - - if (*str == '[') - { - int reg; - - str++; - - skip_whitespace (str); - - if ((reg = reg_required_here (&str, 16)) == FAIL) - return; - - /* Conflicts can occur on stores as well as loads. */ - conflict_reg = (conflict_reg == reg); - - skip_whitespace (str); - - if (*str == ']') - { - str ++; - - if (skip_past_comma (&str) == SUCCESS) - { - /* [Rn],... (post inc) */ - if (ldst_extend (&str) == FAIL) - return; - if (conflict_reg) - as_warn (_("%s register same as write-back base"), - ((inst.instruction & LOAD_BIT) - ? _("destination") : _("source"))); - } - else - { - /* [Rn] */ - skip_whitespace (str); - - if (*str == '!') - { - if (conflict_reg) - as_warn (_("%s register same as write-back base"), - ((inst.instruction & LOAD_BIT) - ? _("destination") : _("source"))); - str++; - inst.instruction |= WRITE_BACK; - } - - inst.instruction |= INDEX_UP; - pre_inc = 1; - } - } - else - { - /* [Rn,...] */ - if (skip_past_comma (&str) == FAIL) - { - inst.error = _("pre-indexed expression expected"); - return; - } - - pre_inc = 1; - if (ldst_extend (&str) == FAIL) - return; - - skip_whitespace (str); - - if (*str++ != ']') - { - inst.error = _("missing ]"); - return; - } - - skip_whitespace (str); - - if (*str == '!') - { - if (conflict_reg) - as_warn (_("%s register same as write-back base"), - ((inst.instruction & LOAD_BIT) - ? _("destination") : _("source"))); - str++; - inst.instruction |= WRITE_BACK; - } - } - } - else if (*str == '=') - { - if ((inst.instruction & LOAD_BIT) == 0) - { - inst.error = _("invalid pseudo operation"); - return; - } - - /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op. */ - str++; - - skip_whitespace (str); - - if (my_get_expression (&inst.reloc.exp, &str)) - return; - - if (inst.reloc.exp.X_op != O_constant - && inst.reloc.exp.X_op != O_symbol) - { - inst.error = _("constant expression expected"); - return; - } - - if (inst.reloc.exp.X_op == O_constant) - { - value = validate_immediate (inst.reloc.exp.X_add_number); - - if (value != FAIL) - { - /* This can be done with a mov instruction. */ - inst.instruction &= LITERAL_MASK; - inst.instruction |= (INST_IMMEDIATE - | (OPCODE_MOV << DATA_OP_SHIFT)); - inst.instruction |= value & 0xfff; - end_of_line (str); - return; - } - - value = validate_immediate (~inst.reloc.exp.X_add_number); - - if (value != FAIL) - { - /* This can be done with a mvn instruction. */ - inst.instruction &= LITERAL_MASK; - inst.instruction |= (INST_IMMEDIATE - | (OPCODE_MVN << DATA_OP_SHIFT)); - inst.instruction |= value & 0xfff; - end_of_line (str); - return; - } - } - - /* Insert into literal pool. */ - if (add_to_lit_pool () == FAIL) - { - if (!inst.error) - inst.error = _("literal pool insertion failed"); - return; - } - - /* Change the instruction exp to point to the pool. */ - inst.reloc.type = BFD_RELOC_ARM_LITERAL; - inst.reloc.pc_rel = 1; - inst.instruction |= (REG_PC << 16); - pre_inc = 1; - } + inst.instruction |= inst.operands[0].imm; + if (inst.operands[1].isreg) + inst.instruction |= inst.operands[1].reg; else { - if (my_get_expression (&inst.reloc.exp, &str)) - return; - - inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM; -#ifndef TE_WINCE - /* PC rel adjust. */ - inst.reloc.exp.X_add_number -= 8; -#endif - inst.reloc.pc_rel = 1; - inst.instruction |= (REG_PC << 16); - pre_inc = 1; + inst.instruction |= INST_IMMEDIATE; + inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE; + inst.reloc.pc_rel = 0; } - - inst.instruction |= (pre_inc ? PRE_INDEX : 0); - end_of_line (str); } static void -do_ldstt (char * str) +do_mul (void) { - int conflict_reg; + if (!inst.operands[2].present) + inst.operands[2].reg = inst.operands[0].reg; + inst.instruction |= inst.operands[0].reg << 16; + inst.instruction |= inst.operands[1].reg; + inst.instruction |= inst.operands[2].reg << 8; - skip_whitespace (str); - - if ((conflict_reg = reg_required_here (& str, 12)) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (& str) == FAIL) - { - inst.error = _("address expected"); - return; - } - - if (*str == '[') - { - int reg; - - str++; - - skip_whitespace (str); - - if ((reg = reg_required_here (&str, 16)) == FAIL) - return; - - /* ldrt/strt always use post-indexed addressing, so if the base is - the same as Rd, we warn. */ - if (conflict_reg == reg) - as_warn (_("%s register same as write-back base"), - ((inst.instruction & LOAD_BIT) - ? _("destination") : _("source"))); - - skip_whitespace (str); + if (inst.operands[0].reg == inst.operands[1].reg) + as_tsktsk (_("rd and rm should be different in mul")); +} - if (*str == ']') - { - str ++; +/* Long Multiply Parser + UMULL RdLo, RdHi, Rm, Rs + SMULL RdLo, RdHi, Rm, Rs + UMLAL RdLo, RdHi, Rm, Rs + SMLAL RdLo, RdHi, Rm, Rs. */ - if (skip_past_comma (&str) == SUCCESS) - { - /* [Rn],... (post inc) */ - if (ldst_extend (&str) == FAIL) - return; - } - else - { - /* [Rn] */ - skip_whitespace (str); +static void +do_mull (void) +{ + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= inst.operands[2].reg; + inst.instruction |= inst.operands[3].reg << 8; - /* Skip a write-back '!'. */ - if (*str == '!') - str++; + /* rdhi, rdlo and rm must all be different. */ + if (inst.operands[0].reg == inst.operands[1].reg + || inst.operands[0].reg == inst.operands[2].reg + || inst.operands[1].reg == inst.operands[2].reg) + as_tsktsk (_("rdhi, rdlo and rm must all be different")); +} - inst.instruction |= INDEX_UP; - } - } - else - { - inst.error = _("post-indexed expression expected"); - return; - } - } - else +static void +do_nop (void) +{ + if (inst.operands[0].present) { - inst.error = _("post-indexed expression expected"); - return; + /* Architectural NOP hints are CPSR sets with no bits selected. */ + inst.instruction &= 0xf0000000; + inst.instruction |= 0x0320f000 + inst.operands[0].imm; } - - end_of_line (str); } -/* Halfword and signed-byte load/store operations. */ +/* ARM V6 Pack Halfword Bottom Top instruction (argument parse). + PKHBT {<cond>} <Rd>, <Rn>, <Rm> {, LSL #<shift_imm>} + Condition defaults to COND_ALWAYS. + Error if Rd, Rn or Rm are R15. */ static void -do_ldstv4 (char * str) +do_pkhbt (void) { - int pre_inc = 0; - int conflict_reg; - int value; - - skip_whitespace (str); + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= inst.operands[2].reg; + if (inst.operands[3].present) + encode_arm_shift (3); +} - if ((conflict_reg = reg_required_here (& str, 12)) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } +/* ARM V6 PKHTB (Argument Parse). */ - if (skip_past_comma (& str) == FAIL) +static void +do_pkhtb (void) +{ + if (!inst.operands[3].present) { - inst.error = _("address expected"); - return; + /* If the shift specifier is omitted, turn the instruction + into pkhbt rd, rm, rn. */ + inst.instruction &= 0xfff00010; + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg; + inst.instruction |= inst.operands[2].reg << 16; } - - if (*str == '[') + else { - int reg; - - str++; - - skip_whitespace (str); - - if ((reg = reg_required_here (&str, 16)) == FAIL) - return; - - /* Conflicts can occur on stores as well as loads. */ - conflict_reg = (conflict_reg == reg); - - skip_whitespace (str); - - if (*str == ']') - { - str ++; - - if (skip_past_comma (&str) == SUCCESS) - { - /* [Rn],... (post inc) */ - if (ldst_extend_v4 (&str) == FAIL) - return; - if (conflict_reg) - as_warn (_("%s register same as write-back base"), - ((inst.instruction & LOAD_BIT) - ? _("destination") : _("source"))); - } - else - { - /* [Rn] */ - inst.instruction |= HWOFFSET_IMM; - - skip_whitespace (str); - - if (*str == '!') - { - if (conflict_reg) - as_warn (_("%s register same as write-back base"), - ((inst.instruction & LOAD_BIT) - ? _("destination") : _("source"))); - str++; - inst.instruction |= WRITE_BACK; - } - - inst.instruction |= INDEX_UP; - pre_inc = 1; - } - } - else - { - /* [Rn,...] */ - if (skip_past_comma (&str) == FAIL) - { - inst.error = _("pre-indexed expression expected"); - return; - } - - pre_inc = 1; - if (ldst_extend_v4 (&str) == FAIL) - return; - - skip_whitespace (str); - - if (*str++ != ']') - { - inst.error = _("missing ]"); - return; - } - - skip_whitespace (str); - - if (*str == '!') - { - if (conflict_reg) - as_warn (_("%s register same as write-back base"), - ((inst.instruction & LOAD_BIT) - ? _("destination") : _("source"))); - str++; - inst.instruction |= WRITE_BACK; - } - } + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= inst.operands[2].reg; + encode_arm_shift (3); } - else if (*str == '=') - { - if ((inst.instruction & LOAD_BIT) == 0) - { - inst.error = _("invalid pseudo operation"); - return; - } - - /* XXX Does this work correctly for half-word/byte ops? */ - /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op. */ - str++; - - skip_whitespace (str); - - if (my_get_expression (&inst.reloc.exp, &str)) - return; - - if (inst.reloc.exp.X_op != O_constant - && inst.reloc.exp.X_op != O_symbol) - { - inst.error = _("constant expression expected"); - return; - } - - if (inst.reloc.exp.X_op == O_constant) - { - value = validate_immediate (inst.reloc.exp.X_add_number); - - if (value != FAIL) - { - /* This can be done with a mov instruction. */ - inst.instruction &= LITERAL_MASK; - inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT); - inst.instruction |= value & 0xfff; - end_of_line (str); - return; - } - - value = validate_immediate (~ inst.reloc.exp.X_add_number); - - if (value != FAIL) - { - /* This can be done with a mvn instruction. */ - inst.instruction &= LITERAL_MASK; - inst.instruction |= INST_IMMEDIATE | (OPCODE_MVN << DATA_OP_SHIFT); - inst.instruction |= value & 0xfff; - end_of_line (str); - return; - } - } +} - /* Insert into literal pool. */ - if (add_to_lit_pool () == FAIL) - { - if (!inst.error) - inst.error = _("literal pool insertion failed"); - return; - } +/* ARMv5TE: Preload-Cache - /* Change the instruction exp to point to the pool. */ - inst.instruction |= HWOFFSET_IMM; - inst.reloc.type = BFD_RELOC_ARM_HWLITERAL; - inst.reloc.pc_rel = 1; - inst.instruction |= (REG_PC << 16); - pre_inc = 1; - } - else - { - if (my_get_expression (&inst.reloc.exp, &str)) - return; + PLD <addr_mode> - inst.instruction |= HWOFFSET_IMM; - inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8; -#ifndef TE_WINCE - /* PC rel adjust. */ - inst.reloc.exp.X_add_number -= 8; -#endif - inst.reloc.pc_rel = 1; - inst.instruction |= (REG_PC << 16); - pre_inc = 1; - } + Syntactically, like LDR with B=1, W=0, L=1. */ - inst.instruction |= (pre_inc ? PRE_INDEX : 0); - end_of_line (str); +static void +do_pld (void) +{ + constraint (!inst.operands[0].isreg, + _("'[' expected after PLD mnemonic")); + constraint (inst.operands[0].postind, + _("post-indexed expression used in preload instruction")); + constraint (inst.operands[0].writeback, + _("writeback used in preload instruction")); + constraint (!inst.operands[0].preind, + _("unindexed addressing used in preload instruction")); + inst.instruction |= inst.operands[0].reg; + encode_arm_addr_mode_2 (0, /*is_t=*/FALSE); } static void -do_ldsttv4 (char * str) +do_push_pop (void) { - int conflict_reg; - - skip_whitespace (str); - - if ((conflict_reg = reg_required_here (& str, 12)) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (& str) == FAIL) - { - inst.error = _("address expected"); - return; - } - - if (*str == '[') - { - int reg; - - str++; - - skip_whitespace (str); - - if ((reg = reg_required_here (&str, 16)) == FAIL) - return; - - /* ldrt/strt always use post-indexed addressing, so if the base is - the same as Rd, we warn. */ - if (conflict_reg == reg) - as_warn (_("%s register same as write-back base"), - ((inst.instruction & LOAD_BIT) - ? _("destination") : _("source"))); - - skip_whitespace (str); - - if (*str == ']') - { - str ++; - - if (skip_past_comma (&str) == SUCCESS) - { - /* [Rn],... (post inc) */ - if (ldst_extend_v4 (&str) == FAIL) - return; - } - else - { - /* [Rn] */ - skip_whitespace (str); - - /* Skip a write-back '!'. */ - if (*str == '!') - str++; - - inst.instruction |= (INDEX_UP|HWOFFSET_IMM); - } - } - else - { - inst.error = _("post-indexed expression expected"); - return; - } - } - else - { - inst.error = _("post-indexed expression expected"); - return; - } - - end_of_line (str); + inst.operands[1] = inst.operands[0]; + memset (&inst.operands[0], 0, sizeof inst.operands[0]); + inst.operands[0].isreg = 1; + inst.operands[0].writeback = 1; + inst.operands[0].reg = REG_SP; + do_ldmstm (); } +/* ARM V6 RFE (Return from Exception) loads the PC and CPSR from the + word at the specified address and the following word + respectively. + Unconditionally executed. + Error if Rn is R15. */ -static long -reg_list (char ** strp) +static void +do_rfe (void) { - char * str = * strp; - long range = 0; - int another_range; - - /* We come back here if we get ranges concatenated by '+' or '|'. */ - do - { - another_range = 0; - - if (*str == '{') - { - int in_range = 0; - int cur_reg = -1; - - str++; - do - { - int reg; - - skip_whitespace (str); - - if ((reg = reg_required_here (& str, -1)) == FAIL) - return FAIL; - - if (in_range) - { - int i; - - if (reg <= cur_reg) - { - inst.error = _("bad range in register list"); - return FAIL; - } - - for (i = cur_reg + 1; i < reg; i++) - { - if (range & (1 << i)) - as_tsktsk - (_("Warning: duplicated register (r%d) in register list"), - i); - else - range |= 1 << i; - } - in_range = 0; - } - - if (range & (1 << reg)) - as_tsktsk (_("Warning: duplicated register (r%d) in register list"), - reg); - else if (reg <= cur_reg) - as_tsktsk (_("Warning: register range not in ascending order")); - - range |= 1 << reg; - cur_reg = reg; - } - while (skip_past_comma (&str) != FAIL - || (in_range = 1, *str++ == '-')); - str--; - skip_whitespace (str); - - if (*str++ != '}') - { - inst.error = _("missing `}'"); - return FAIL; - } - } - else - { - expressionS expr; - - if (my_get_expression (&expr, &str)) - return FAIL; + inst.instruction |= inst.operands[0].reg << 16; + if (inst.operands[0].writeback) + inst.instruction |= WRITE_BACK; +} - if (expr.X_op == O_constant) - { - if (expr.X_add_number - != (expr.X_add_number & 0x0000ffff)) - { - inst.error = _("invalid register mask"); - return FAIL; - } +/* ARM V6 ssat (argument parse). */ - if ((range & expr.X_add_number) != 0) - { - int regno = range & expr.X_add_number; +static void +do_ssat (void) +{ + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= (inst.operands[1].imm - 1) << 16; + inst.instruction |= inst.operands[2].reg; - regno &= -regno; - regno = (1 << regno) - 1; - as_tsktsk - (_("Warning: duplicated register (r%d) in register list"), - regno); - } + if (inst.operands[3].present) + encode_arm_shift (3); +} - range |= expr.X_add_number; - } - else - { - if (inst.reloc.type != 0) - { - inst.error = _("expression too complex"); - return FAIL; - } +/* ARM V6 usat (argument parse). */ - memcpy (&inst.reloc.exp, &expr, sizeof (expressionS)); - inst.reloc.type = BFD_RELOC_ARM_MULTI; - inst.reloc.pc_rel = 0; - } - } +static void +do_usat (void) +{ + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].imm << 16; + inst.instruction |= inst.operands[2].reg; - skip_whitespace (str); + if (inst.operands[3].present) + encode_arm_shift (3); +} - if (*str == '|' || *str == '+') - { - str++; - another_range = 1; - } - } - while (another_range); +/* ARM V6 ssat16 (argument parse). */ - *strp = str; - return range; +static void +do_ssat16 (void) +{ + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= ((inst.operands[1].imm - 1) << 16); + inst.instruction |= inst.operands[2].reg; } static void -do_ldmstm (char * str) +do_usat16 (void) { - int base_reg; - long range; - - skip_whitespace (str); - - if ((base_reg = reg_required_here (&str, 16)) == FAIL) - return; + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].imm << 16; + inst.instruction |= inst.operands[2].reg; +} - if (base_reg == REG_PC) - { - inst.error = _("r15 not allowed as base register"); - return; - } +/* ARM V6 SETEND (argument parse). Sets the E bit in the CPSR while + preserving the other bits. - skip_whitespace (str); + setend <endian_specifier>, where <endian_specifier> is either + BE or LE. */ - if (*str == '!') - { - inst.instruction |= WRITE_BACK; - str++; - } +static void +do_setend (void) +{ + if (inst.operands[0].imm) + inst.instruction |= 0x200; +} - if (skip_past_comma (&str) == FAIL - || (range = reg_list (&str)) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } +static void +do_shift (void) +{ + unsigned int Rm = (inst.operands[1].present + ? inst.operands[1].reg + : inst.operands[0].reg); - if (*str == '^') + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= Rm; + if (inst.operands[2].isreg) /* Rd, {Rm,} Rs */ { - str++; - inst.instruction |= LDM_TYPE_2_OR_3; + constraint (inst.operands[0].reg != Rm, + _("source1 and dest must be same register")); + inst.instruction |= inst.operands[2].reg << 8; + inst.instruction |= SHIFT_BY_REG; } - - if (inst.instruction & WRITE_BACK) - { - /* Check for unpredictable uses of writeback. */ - if (inst.instruction & LOAD_BIT) - { - /* Not allowed in LDM type 2. */ - if ((inst.instruction & LDM_TYPE_2_OR_3) - && ((range & (1 << REG_PC)) == 0)) - as_warn (_("writeback of base register is UNPREDICTABLE")); - /* Only allowed if base reg not in list for other types. */ - else if (range & (1 << base_reg)) - as_warn (_("writeback of base register when in register list is UNPREDICTABLE")); - } - else /* STM. */ - { - /* Not allowed for type 2. */ - if (inst.instruction & LDM_TYPE_2_OR_3) - as_warn (_("writeback of base register is UNPREDICTABLE")); - /* Only allowed if base reg not in list, or first in list. */ - else if ((range & (1 << base_reg)) - && (range & ((1 << base_reg) - 1))) - as_warn (_("if writeback register is in list, it must be the lowest reg in the list")); - } - } - - inst.instruction |= range; - end_of_line (str); + else + inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM; } static void -do_smi (char * str) +do_smi (void) { - skip_whitespace (str); - - /* Allow optional leading '#'. */ - if (is_immediate_prefix (*str)) - str++; - - if (my_get_expression (& inst.reloc.exp, & str)) - return; - inst.reloc.type = BFD_RELOC_ARM_SMI; inst.reloc.pc_rel = 0; - end_of_line (str); } static void -do_swi (char * str) +do_swi (void) { - skip_whitespace (str); - - /* Allow optional leading '#'. */ - if (is_immediate_prefix (*str)) - str++; - - if (my_get_expression (& inst.reloc.exp, & str)) - return; - inst.reloc.type = BFD_RELOC_ARM_SWI; inst.reloc.pc_rel = 0; - end_of_line (str); } +/* ARM V5E (El Segundo) signed-multiply-accumulate (argument parse) + SMLAxy{cond} Rd,Rm,Rs,Rn + SMLAWy{cond} Rd,Rm,Rs,Rn + Error if any register is R15. */ + static void -do_swap (char * str) +do_smla (void) { - int reg; + inst.instruction |= inst.operands[0].reg << 16; + inst.instruction |= inst.operands[1].reg; + inst.instruction |= inst.operands[2].reg << 8; + inst.instruction |= inst.operands[3].reg << 12; +} - skip_whitespace (str); +/* ARM V5E (El Segundo) signed-multiply-accumulate-long (argument parse) + SMLALxy{cond} Rdlo,Rdhi,Rm,Rs + Error if any register is R15. + Warning if Rdlo == Rdhi. */ - if ((reg = reg_required_here (&str, 12)) == FAIL) - return; +static void +do_smlal (void) +{ + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= inst.operands[2].reg; + inst.instruction |= inst.operands[3].reg << 8; - if (reg == REG_PC) - { - inst.error = _("r15 not allowed in swap"); - return; - } + if (inst.operands[0].reg == inst.operands[1].reg) + as_tsktsk (_("rdhi and rdlo must be different")); +} - if (skip_past_comma (&str) == FAIL - || (reg = reg_required_here (&str, 0)) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } +/* ARM V5E (El Segundo) signed-multiply (argument parse) + SMULxy{cond} Rd,Rm,Rs + Error if any register is R15. */ - if (reg == REG_PC) - { - inst.error = _("r15 not allowed in swap"); - return; - } +static void +do_smul (void) +{ + inst.instruction |= inst.operands[0].reg << 16; + inst.instruction |= inst.operands[1].reg; + inst.instruction |= inst.operands[2].reg << 8; +} - if (skip_past_comma (&str) == FAIL - || *str++ != '[') - { - inst.error = BAD_ARGS; - return; - } +/* ARM V6 srs (argument parse). */ - skip_whitespace (str); +static void +do_srs (void) +{ + inst.instruction |= inst.operands[0].imm; + if (inst.operands[0].writeback) + inst.instruction |= WRITE_BACK; +} - if ((reg = reg_required_here (&str, 16)) == FAIL) - return; +/* ARM V6 strex (argument parse). */ - if (reg == REG_PC) - { - inst.error = BAD_PC; - return; - } +static void +do_strex (void) +{ + constraint (!inst.operands[2].isreg || !inst.operands[2].preind + || inst.operands[2].postind || inst.operands[2].writeback + || inst.operands[2].immisreg || inst.operands[2].shifted + || inst.operands[2].negative, + _("instruction does not accept this addressing mode")); - skip_whitespace (str); + constraint (inst.operands[2].reg == REG_PC, BAD_PC); - if (*str++ != ']') - { - inst.error = _("missing ]"); - return; - } + constraint (inst.operands[0].reg == inst.operands[1].reg + || inst.operands[0].reg == inst.operands[2].reg, BAD_OVERLAP); + + constraint (inst.reloc.exp.X_op != O_constant + || inst.reloc.exp.X_add_number != 0, + _("offset must be zero in ARM encoding")); - end_of_line (str); + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg; + inst.instruction |= inst.operands[2].reg << 16; + inst.reloc.type = BFD_RELOC_UNUSED; } static void -do_branch (char * str) +do_strexd (void) { - if (my_get_expression (&inst.reloc.exp, &str)) - return; + constraint (inst.operands[1].reg % 2 != 0, + _("even register required")); + constraint (inst.operands[2].present + && inst.operands[2].reg != inst.operands[1].reg + 1, + _("can only store two consecutive registers")); + /* If op 2 were present and equal to PC, this function wouldn't + have been called in the first place. */ + constraint (inst.operands[1].reg == REG_LR, _("r14 not allowed here")); -#ifdef OBJ_ELF - { - char * save_in; - - /* ScottB: February 5, 1998 - Check to see of PLT32 reloc - required for the instruction. */ - - /* arm_parse_reloc () works on input_line_pointer. - We actually want to parse the operands to the branch instruction - passed in 'str'. Save the input pointer and restore it later. */ - save_in = input_line_pointer; - input_line_pointer = str; - if (inst.reloc.exp.X_op == O_symbol - && *str == '(' - && arm_parse_reloc () == BFD_RELOC_ARM_PLT32) - { - inst.reloc.type = BFD_RELOC_ARM_PLT32; - inst.reloc.pc_rel = 0; - /* Modify str to point to after parsed operands, otherwise - end_of_line() will complain about the (PLT) left in str. */ - str = input_line_pointer; - } - else - { - inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH; - inst.reloc.pc_rel = 1; - } - input_line_pointer = save_in; - } -#else - inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH; - inst.reloc.pc_rel = 1; -#endif /* OBJ_ELF */ + constraint (inst.operands[0].reg == inst.operands[1].reg + || inst.operands[0].reg == inst.operands[1].reg + 1 + || inst.operands[0].reg == inst.operands[3].reg, + BAD_OVERLAP); - end_of_line (str); + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg; + inst.instruction |= inst.operands[3].reg << 16; } +/* ARM V6 SXTAH extracts a 16-bit value from a register, sign + extends it to 32-bits, and adds the result to a value in another + register. You can specify a rotation by 0, 8, 16, or 24 bits + before extracting the 16-bit value. + SXTAH{<cond>} <Rd>, <Rn>, <Rm>{, <rotation>} + Condition defaults to COND_ALWAYS. + Error if any register uses R15. */ + static void -do_cdp (char * str) +do_sxtah (void) { - /* Co-processor data operation. - Format: CDP{cond} CP#,<expr>,CRd,CRn,CRm{,<expr>} */ - skip_whitespace (str); - - if (co_proc_number (&str) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= inst.operands[2].reg; + inst.instruction |= inst.operands[3].imm << 10; +} - if (skip_past_comma (&str) == FAIL - || cp_opc_expr (&str, 20,4) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } +/* ARM V6 SXTH. - if (skip_past_comma (&str) == FAIL - || cp_reg_required_here (&str, 12) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } + SXTH {<cond>} <Rd>, <Rm>{, <rotation>} + Condition defaults to COND_ALWAYS. + Error if any register uses R15. */ - if (skip_past_comma (&str) == FAIL - || cp_reg_required_here (&str, 16) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } +static void +do_sxth (void) +{ + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg; + inst.instruction |= inst.operands[2].imm << 10; +} + +/* VFP instructions. In a logical order: SP variant first, monad + before dyad, arithmetic then move then load/store. */ - if (skip_past_comma (&str) == FAIL - || cp_reg_required_here (&str, 0) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } +static void +do_vfp_sp_monadic (void) +{ + encode_arm_vfp_sp_reg (inst.operands[0].reg, VFP_REG_Sd); + encode_arm_vfp_sp_reg (inst.operands[1].reg, VFP_REG_Sm); +} - if (skip_past_comma (&str) == SUCCESS) - { - if (cp_opc_expr (&str, 5, 3) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - } +static void +do_vfp_sp_dyadic (void) +{ + encode_arm_vfp_sp_reg (inst.operands[0].reg, VFP_REG_Sd); + encode_arm_vfp_sp_reg (inst.operands[1].reg, VFP_REG_Sn); + encode_arm_vfp_sp_reg (inst.operands[2].reg, VFP_REG_Sm); +} - end_of_line (str); +static void +do_vfp_sp_compare_z (void) +{ + encode_arm_vfp_sp_reg (inst.operands[0].reg, VFP_REG_Sd); } static void -do_lstc (char * str) +do_vfp_dp_sp_cvt (void) { - /* Co-processor register load/store. - Format: <LDC|STC{cond}[L] CP#,CRd,<address> */ + inst.instruction |= inst.operands[0].reg << 12; + encode_arm_vfp_sp_reg (inst.operands[1].reg, VFP_REG_Sm); +} - skip_whitespace (str); +static void +do_vfp_sp_dp_cvt (void) +{ + encode_arm_vfp_sp_reg (inst.operands[0].reg, VFP_REG_Sd); + inst.instruction |= inst.operands[1].reg; +} - if (co_proc_number (&str) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } +static void +do_vfp_reg_from_sp (void) +{ + inst.instruction |= inst.operands[0].reg << 12; + encode_arm_vfp_sp_reg (inst.operands[1].reg, VFP_REG_Sn); +} - if (skip_past_comma (&str) == FAIL - || cp_reg_required_here (&str, 12) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } +static void +do_vfp_reg2_from_sp2 (void) +{ + constraint (inst.operands[2].imm != 2, + _("only two consecutive VFP SP registers allowed here")); + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg << 16; + encode_arm_vfp_sp_reg (inst.operands[2].reg, VFP_REG_Sm); +} - if (skip_past_comma (&str) == FAIL - || cp_address_required_here (&str, CP_WB_OK) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } +static void +do_vfp_sp_from_reg (void) +{ + encode_arm_vfp_sp_reg (inst.operands[0].reg, VFP_REG_Sn); + inst.instruction |= inst.operands[1].reg << 12; +} - end_of_line (str); +static void +do_vfp_sp2_from_reg2 (void) +{ + constraint (inst.operands[0].imm != 2, + _("only two consecutive VFP SP registers allowed here")); + encode_arm_vfp_sp_reg (inst.operands[0].reg, VFP_REG_Sm); + inst.instruction |= inst.operands[1].reg << 12; + inst.instruction |= inst.operands[2].reg << 16; } static void -do_co_reg (char * str) +do_vfp_sp_ldst (void) { - /* Co-processor register transfer. - Format: <MCR|MRC>{cond} CP#,<expr1>,Rd,CRn,CRm{,<expr2>} */ + encode_arm_vfp_sp_reg (inst.operands[0].reg, VFP_REG_Sd); + encode_arm_cp_address (1, FALSE, TRUE, 0); +} - skip_whitespace (str); +static void +do_vfp_dp_ldst (void) +{ + inst.instruction |= inst.operands[0].reg << 12; + encode_arm_cp_address (1, FALSE, TRUE, 0); +} - if (co_proc_number (&str) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - if (skip_past_comma (&str) == FAIL - || cp_opc_expr (&str, 21, 3) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } +static void +vfp_sp_ldstm (enum vfp_ldstm_type ldstm_type) +{ + if (inst.operands[0].writeback) + inst.instruction |= WRITE_BACK; + else + constraint (ldstm_type != VFP_LDSTMIA, + _("this addressing mode requires base-register writeback")); + inst.instruction |= inst.operands[0].reg << 16; + encode_arm_vfp_sp_reg (inst.operands[1].reg, VFP_REG_Sd); + inst.instruction |= inst.operands[1].imm; +} - if (skip_past_comma (&str) == FAIL - || reg_required_here (&str, 12) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } +static void +vfp_dp_ldstm (enum vfp_ldstm_type ldstm_type) +{ + int count; - if (skip_past_comma (&str) == FAIL - || cp_reg_required_here (&str, 16) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } + if (inst.operands[0].writeback) + inst.instruction |= WRITE_BACK; + else + constraint (ldstm_type != VFP_LDSTMIA && ldstm_type != VFP_LDSTMIAX, + _("this addressing mode requires base-register writeback")); - if (skip_past_comma (&str) == FAIL - || cp_reg_required_here (&str, 0) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } + inst.instruction |= inst.operands[0].reg << 16; + inst.instruction |= inst.operands[1].reg << 12; - if (skip_past_comma (&str) == SUCCESS) - { - if (cp_opc_expr (&str, 5, 3) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - } + count = inst.operands[1].imm << 1; + if (ldstm_type == VFP_LDSTMIAX || ldstm_type == VFP_LDSTMDBX) + count += 1; - end_of_line (str); + inst.instruction |= count; } static void -do_fpa_ctrl (char * str) +do_vfp_sp_ldstmia (void) { - /* FP control registers. - Format: <WFS|RFS|WFC|RFC>{cond} Rn */ - - skip_whitespace (str); - - if (reg_required_here (&str, 12) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - end_of_line (str); + vfp_sp_ldstm (VFP_LDSTMIA); } static void -do_fpa_ldst (char * str) +do_vfp_sp_ldstmdb (void) { - skip_whitespace (str); - - if (fp_reg_required_here (&str, 12) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || cp_address_required_here (&str, CP_WB_OK) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - end_of_line (str); + vfp_sp_ldstm (VFP_LDSTMDB); } static void -do_fpa_ldmstm (char * str) +do_vfp_dp_ldstmia (void) { - int num_regs; - - skip_whitespace (str); - - if (fp_reg_required_here (&str, 12) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } + vfp_dp_ldstm (VFP_LDSTMIA); +} - /* Get Number of registers to transfer. */ - if (skip_past_comma (&str) == FAIL - || my_get_expression (&inst.reloc.exp, &str)) - { - if (! inst.error) - inst.error = _("constant expression expected"); - return; - } +static void +do_vfp_dp_ldstmdb (void) +{ + vfp_dp_ldstm (VFP_LDSTMDB); +} - if (inst.reloc.exp.X_op != O_constant) - { - inst.error = _("constant value required for number of registers"); - return; - } +static void +do_vfp_xp_ldstmia (void) +{ + vfp_dp_ldstm (VFP_LDSTMIAX); +} - num_regs = inst.reloc.exp.X_add_number; +static void +do_vfp_xp_ldstmdb (void) +{ + vfp_dp_ldstm (VFP_LDSTMDBX); +} + +/* FPA instructions. Also in a logical order. */ - if (num_regs < 1 || num_regs > 4) - { - inst.error = _("number of registers must be in the range [1:4]"); - return; - } +static void +do_fpa_cmp (void) +{ + inst.instruction |= inst.operands[0].reg << 16; + inst.instruction |= inst.operands[1].reg; +} - switch (num_regs) +static void +do_fpa_ldmstm (void) +{ + inst.instruction |= inst.operands[0].reg << 12; + switch (inst.operands[1].imm) { - case 1: - inst.instruction |= CP_T_X; - break; - case 2: - inst.instruction |= CP_T_Y; - break; - case 3: - inst.instruction |= CP_T_Y | CP_T_X; - break; - case 4: - break; - default: - abort (); + case 1: inst.instruction |= CP_T_X; break; + case 2: inst.instruction |= CP_T_Y; break; + case 3: inst.instruction |= CP_T_Y | CP_T_X; break; + case 4: break; + default: abort (); } - if (inst.instruction & (CP_T_Pre | CP_T_UD)) /* ea/fd format. */ + if (inst.instruction & (PRE_INDEX | INDEX_UP)) { - int reg; - int write_back; - int offset; - /* The instruction specified "ea" or "fd", so we can only accept [Rn]{!}. The instruction does not really support stacking or unstacking, so we have to emulate these by setting appropriate bits and offsets. */ - if (skip_past_comma (&str) == FAIL - || *str != '[') - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } + constraint (inst.reloc.exp.X_op != O_constant + || inst.reloc.exp.X_add_number != 0, + _("this instruction does not support indexing")); - str++; - skip_whitespace (str); + if ((inst.instruction & PRE_INDEX) || inst.operands[2].writeback) + inst.reloc.exp.X_add_number = 12 * inst.operands[1].imm; - if ((reg = reg_required_here (&str, 16)) == FAIL) - return; - - skip_whitespace (str); - - if (*str != ']') - { - inst.error = BAD_ARGS; - return; - } - - str++; - if (*str == '!') - { - write_back = 1; - str++; - if (reg == REG_PC) - { - inst.error = - _("r15 not allowed as base register with write-back"); - return; - } - } - else - write_back = 0; + if (!(inst.instruction & INDEX_UP)) + inst.reloc.exp.X_add_number = -inst.reloc.exp.X_add_number; - if (inst.instruction & CP_T_Pre) - { - /* Pre-decrement. */ - offset = 3 * num_regs; - if (write_back) - inst.instruction |= CP_T_WB; - } - else + if (!(inst.instruction & PRE_INDEX) && inst.operands[2].writeback) { - /* Post-increment. */ - if (write_back) - { - inst.instruction |= CP_T_WB; - offset = 3 * num_regs; - } - else - { - /* No write-back, so convert this into a standard pre-increment - instruction -- aesthetically more pleasing. */ - inst.instruction |= CP_T_Pre | CP_T_UD; - offset = 0; - } + inst.operands[2].preind = 0; + inst.operands[2].postind = 1; } - - inst.instruction |= offset; - } - else if (skip_past_comma (&str) == FAIL - || cp_address_required_here (&str, CP_WB_OK) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; } - end_of_line (str); + encode_arm_cp_address (2, TRUE, TRUE, 0); } + +/* iWMMXt instructions: strictly in alphabetical order. */ static void -do_fpa_dyadic (char * str) +do_iwmmxt_tandorc (void) { - skip_whitespace (str); - - if (fp_reg_required_here (&str, 12) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || fp_reg_required_here (&str, 16) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || fp_op2 (&str) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - end_of_line (str); + constraint (inst.operands[0].reg != REG_PC, _("only r15 allowed here")); } static void -do_fpa_monadic (char * str) +do_iwmmxt_textrc (void) { - skip_whitespace (str); - - if (fp_reg_required_here (&str, 12) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || fp_op2 (&str) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - end_of_line (str); + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].imm; } static void -do_fpa_cmp (char * str) +do_iwmmxt_textrm (void) { - skip_whitespace (str); - - if (fp_reg_required_here (&str, 16) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || fp_op2 (&str) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - end_of_line (str); + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= inst.operands[2].imm; } static void -do_fpa_from_reg (char * str) +do_iwmmxt_tinsr (void) { - skip_whitespace (str); - - if (fp_reg_required_here (&str, 16) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || reg_required_here (&str, 12) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - end_of_line (str); + inst.instruction |= inst.operands[0].reg << 16; + inst.instruction |= inst.operands[1].reg << 12; + inst.instruction |= inst.operands[2].imm; } static void -do_fpa_to_reg (char * str) +do_iwmmxt_tmia (void) { - skip_whitespace (str); - - if (reg_required_here (&str, 12) == FAIL) - return; - - if (skip_past_comma (&str) == FAIL - || fp_reg_required_here (&str, 0) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - end_of_line (str); + inst.instruction |= inst.operands[0].reg << 5; + inst.instruction |= inst.operands[1].reg; + inst.instruction |= inst.operands[2].reg << 12; } -/* Encode a VFP SP register number. */ - static void -vfp_sp_encode_reg (int reg, enum vfp_sp_reg_pos pos) +do_iwmmxt_waligni (void) { - switch (pos) - { - case VFP_REG_Sd: - inst.instruction |= ((reg >> 1) << 12) | ((reg & 1) << 22); - break; - - case VFP_REG_Sn: - inst.instruction |= ((reg >> 1) << 16) | ((reg & 1) << 7); - break; - - case VFP_REG_Sm: - inst.instruction |= ((reg >> 1) << 0) | ((reg & 1) << 5); - break; + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= inst.operands[2].reg; + inst.instruction |= inst.operands[3].imm << 20; +} - default: - abort (); - } +static void +do_iwmmxt_wmov (void) +{ + /* WMOV rD, rN is an alias for WOR rD, rN, rN. */ + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= inst.operands[1].reg; } -static int -vfp_sp_reg_required_here (char ** str, - enum vfp_sp_reg_pos pos) +static void +do_iwmmxt_wldstbh (void) { - int reg; - char * start = *str; + inst.instruction |= inst.operands[0].reg << 12; + inst.reloc.exp.X_add_number *= 4; + encode_arm_cp_address (1, TRUE, FALSE, BFD_RELOC_ARM_CP_OFF_IMM_S2); +} - if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_SN].htab)) != FAIL) +static void +do_iwmmxt_wldstw (void) +{ + /* RIWR_RIWC clears .isreg for a control register. */ + if (!inst.operands[0].isreg) { - vfp_sp_encode_reg (reg, pos); - return reg; + constraint (inst.cond != COND_ALWAYS, BAD_COND); + inst.instruction |= 0xf0000000; } - /* In the few cases where we might be able to accept something else - this error can be overridden. */ - inst.error = _(all_reg_maps[REG_TYPE_SN].expected); - - /* Restore the start point. */ - *str = start; - return FAIL; + inst.instruction |= inst.operands[0].reg << 12; + encode_arm_cp_address (1, TRUE, TRUE, 0); } -static int -vfp_dp_reg_required_here (char ** str, - enum vfp_dp_reg_pos pos) +static void +do_iwmmxt_wldstd (void) { - int reg; - char * start = *str; + inst.instruction |= inst.operands[0].reg << 12; + encode_arm_cp_address (1, TRUE, FALSE, BFD_RELOC_ARM_CP_OFF_IMM_S2); +} - if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_DN].htab)) != FAIL) - { - switch (pos) - { - case VFP_REG_Dd: - inst.instruction |= reg << 12; - break; +static void +do_iwmmxt_wshufh (void) +{ + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= ((inst.operands[2].imm & 0xf0) << 16); + inst.instruction |= (inst.operands[2].imm & 0x0f); +} - case VFP_REG_Dn: - inst.instruction |= reg << 16; - break; +static void +do_iwmmxt_wzero (void) +{ + /* WZERO reg is an alias for WANDN reg, reg, reg. */ + inst.instruction |= inst.operands[0].reg; + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[0].reg << 16; +} + +/* Cirrus Maverick instructions. Simple 2-, 3-, and 4-register + operations first, then control, shift, and load/store. */ - case VFP_REG_Dm: - inst.instruction |= reg << 0; - break; +/* Insns like "foo X,Y,Z". */ - default: - abort (); - } - return reg; - } +static void +do_mav_triple (void) +{ + inst.instruction |= inst.operands[0].reg << 16; + inst.instruction |= inst.operands[1].reg; + inst.instruction |= inst.operands[2].reg << 12; +} - /* In the few cases where we might be able to accept something else - this error can be overridden. */ - inst.error = _(all_reg_maps[REG_TYPE_DN].expected); +/* Insns like "foo W,X,Y,Z". + where W=MVAX[0:3] and X,Y,Z=MVFX[0:15]. */ - /* Restore the start point. */ - *str = start; - return FAIL; +static void +do_mav_quad (void) +{ + inst.instruction |= inst.operands[0].reg << 5; + inst.instruction |= inst.operands[1].reg << 12; + inst.instruction |= inst.operands[2].reg << 16; + inst.instruction |= inst.operands[3].reg; } +/* cfmvsc32<cond> DSPSC,MVDX[15:0]. */ static void -do_vfp_sp_monadic (char * str) +do_mav_dspsc (void) { - skip_whitespace (str); - - if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL) - return; - - if (skip_past_comma (&str) == FAIL - || vfp_sp_reg_required_here (&str, VFP_REG_Sm) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - end_of_line (str); + inst.instruction |= inst.operands[1].reg << 12; } +/* Maverick shift immediate instructions. + cfsh32<cond> MVFX[15:0],MVFX[15:0],Shift[6:0]. + cfsh64<cond> MVDX[15:0],MVDX[15:0],Shift[6:0]. */ + static void -do_vfp_dp_monadic (char * str) +do_mav_shift (void) { - skip_whitespace (str); + int imm = inst.operands[2].imm; - if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL) - return; + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg << 16; - if (skip_past_comma (&str) == FAIL - || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } + /* Bits 0-3 of the insn should have bits 0-3 of the immediate. + Bits 5-7 of the insn should have bits 4-6 of the immediate. + Bit 4 should be 0. */ + imm = (imm & 0xf) | ((imm & 0x70) << 1); - end_of_line (str); + inst.instruction |= imm; } + +/* XScale instructions. Also sorted arithmetic before move. */ + +/* Xscale multiply-accumulate (argument parse) + MIAcc acc0,Rm,Rs + MIAPHcc acc0,Rm,Rs + MIAxycc acc0,Rm,Rs. */ static void -do_vfp_sp_dyadic (char * str) +do_xsc_mia (void) { - skip_whitespace (str); - - if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL) - return; + inst.instruction |= inst.operands[1].reg; + inst.instruction |= inst.operands[2].reg << 12; +} - if (skip_past_comma (&str) == FAIL - || vfp_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL - || skip_past_comma (&str) == FAIL - || vfp_sp_reg_required_here (&str, VFP_REG_Sm) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } +/* Xscale move-accumulator-register (argument parse) - end_of_line (str); -} + MARcc acc0,RdLo,RdHi. */ static void -do_vfp_dp_dyadic (char * str) +do_xsc_mar (void) { - skip_whitespace (str); + inst.instruction |= inst.operands[1].reg << 12; + inst.instruction |= inst.operands[2].reg << 16; +} - if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL) - return; +/* Xscale move-register-accumulator (argument parse) - if (skip_past_comma (&str) == FAIL - || vfp_dp_reg_required_here (&str, VFP_REG_Dn) == FAIL - || skip_past_comma (&str) == FAIL - || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } + MRAcc RdLo,RdHi,acc0. */ - end_of_line (str); +static void +do_xsc_mra (void) +{ + constraint (inst.operands[0].reg == inst.operands[1].reg, BAD_OVERLAP); + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg << 16; } + +/* Encoding functions relevant only to Thumb. */ + +/* inst.operands[i] is a shifted-register operand; encode + it into inst.instruction in the format used by Thumb32. */ static void -do_vfp_reg_from_sp (char * str) +encode_thumb32_shifted_operand (int i) { - skip_whitespace (str); - - if (reg_required_here (&str, 12) == FAIL) - return; + unsigned int value = inst.reloc.exp.X_add_number; + unsigned int shift = inst.operands[i].shift_kind; - if (skip_past_comma (&str) == FAIL - || vfp_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL) + inst.instruction |= inst.operands[i].reg; + if (shift == SHIFT_RRX) + inst.instruction |= SHIFT_ROR << 4; + else { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } + constraint (inst.reloc.exp.X_op != O_constant, + _("expression too complex")); - end_of_line (str); -} + constraint (value > 32 + || (value == 32 && (shift == SHIFT_LSL + || shift == SHIFT_ROR)), + _("shift expression is too large")); -/* Parse a VFP register list. If the string is invalid return FAIL. - Otherwise return the number of registers, and set PBASE to the first - register. Double precision registers are matched if DP is nonzero. */ + if (value == 0) + shift = SHIFT_LSL; + else if (value == 32) + value = 0; -static int -vfp_parse_reg_list (char **str, int *pbase, int dp) -{ - int base_reg; - int new_base; - int regtype; - int max_regs; - int count = 0; - int warned = 0; - unsigned long mask = 0; - int i; + inst.instruction |= shift << 4; + inst.instruction |= (value & 0x1c) << 10; + inst.instruction |= (value & 0x03) << 6; + } +} - if (**str != '{') - return FAIL; - (*str)++; - skip_whitespace (*str); +/* inst.operands[i] was set up by parse_address. Encode it into a + Thumb32 format load or store instruction. Reject forms that cannot + be used with such instructions. If is_t is true, reject forms that + cannot be used with a T instruction; if is_d is true, reject forms + that cannot be used with a D instruction. */ - if (dp) - { - regtype = REG_TYPE_DN; - max_regs = 16; - } - else - { - regtype = REG_TYPE_SN; - max_regs = 32; - } +static void +encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d) +{ + bfd_boolean is_pc = (inst.operands[i].reg == REG_PC); - base_reg = max_regs; + constraint (!inst.operands[i].isreg, + _("Thumb does not support the ldr =N pseudo-operation")); - do + inst.instruction |= inst.operands[i].reg << 16; + if (inst.operands[i].immisreg) { - new_base = arm_reg_parse (str, all_reg_maps[regtype].htab); - if (new_base == FAIL) + constraint (is_pc, _("cannot use register index with PC-relative addressing")); + constraint (is_t || is_d, _("cannot use register index with this instruction")); + constraint (inst.operands[i].negative, + _("Thumb does not support negative register indexing")); + constraint (inst.operands[i].postind, + _("Thumb does not support register post-indexing")); + constraint (inst.operands[i].writeback, + _("Thumb does not support register indexing with writeback")); + constraint (inst.operands[i].shifted && inst.operands[i].shift_kind != SHIFT_LSL, + _("Thumb supports only LSL in shifted register indexing")); + + inst.instruction |= inst.operands[1].imm; + if (inst.operands[i].shifted) { - inst.error = _(all_reg_maps[regtype].expected); - return FAIL; + 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, + _("shift out of range")); + inst.instruction |= inst.reloc.exp.X_op << 4; } + inst.reloc.type = BFD_RELOC_UNUSED; + } + else if (inst.operands[i].preind) + { + constraint (is_pc && inst.operands[i].writeback, + _("cannot use writeback with PC-relative addressing")); + constraint (is_t && inst.operands[1].writeback, + _("cannot use writeback with this instruction")); - if (new_base < base_reg) - base_reg = new_base; - - if (mask & (1 << new_base)) + if (is_d) { - inst.error = _("invalid register list"); - return FAIL; + inst.instruction |= 0x01000000; + if (inst.operands[i].writeback) + inst.instruction |= 0x00200000; } - - if ((mask >> new_base) != 0 && ! warned) + else { - as_tsktsk (_("register list not in ascending order")); - warned = 1; + inst.instruction |= 0x00000c00; + if (inst.operands[i].writeback) + inst.instruction |= 0x00000100; } + inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_IMM; + inst.reloc.pc_rel = is_pc; + } + else if (inst.operands[i].postind) + { + assert (inst.operands[i].writeback); + constraint (is_pc, _("cannot use post-indexing with PC-relative addressing")); + constraint (is_t, _("cannot use post-indexing with this instruction")); - mask |= 1 << new_base; - count++; + if (is_d) + inst.instruction |= 0x00200000; + else + inst.instruction |= 0x00000900; + inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_IMM; + } + else /* unindexed - only for coprocessor */ + inst.error = _("instruction does not accept unindexed addressing"); +} + +/* Table of Thumb instructions which exist in both 16- and 32-bit + encodings (the latter only in post-V6T2 cores). The index is the + value used in the insns table below. When there is more than one + possible 16-bit encoding for the instruction, this table always + holds variant (1). */ +#define T16_32_TAB \ + X(adc, 4140, eb400000), \ + X(adcs, 4140, eb500000), \ + X(add, 1c00, eb000000), \ + X(adds, 1c00, eb100000), \ + X(and, 4000, ea000000), \ + X(ands, 4000, ea100000), \ + X(asr, 1000, fa40f000), \ + X(asrs, 1000, fa50f000), \ + X(bic, 4380, ea200000), \ + X(bics, 4380, ea300000), \ + X(cmn, 42c0, eb100f00), \ + X(cmp, 2800, ebb00f00), \ + X(cpsie, b660, f3af8400), \ + X(cpsid, b670, f3af8600), \ + X(cpy, 4600, ea4f0000), \ + X(eor, 4040, ea800000), \ + X(eors, 4040, ea900000), \ + X(ldmia, c800, e8900000), \ + X(ldr, 6800, f8500000), \ + X(ldrb, 7800, f8100000), \ + X(ldrh, 8800, f8300000), \ + X(ldrsb, 5600, f9100000), \ + X(ldrsh, 5e00, f9300000), \ + X(lsl, 0000, fa00f000), \ + X(lsls, 0000, fa10f000), \ + X(lsr, 0800, fa20f000), \ + X(lsrs, 0800, fa30f000), \ + X(mov, 2000, ea4f0000), \ + X(movs, 2000, ea5f0000), \ + X(mul, 4340, fb00f000), \ + X(muls, 4340, ffffffff), /* no 32b muls */ \ + X(mvn, 43c0, ea6f0000), \ + X(mvns, 43c0, ea7f0000), \ + X(neg, 4240, f1c00000), /* rsb #0 */ \ + 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(rev, ba00, fa90f080), \ + X(rev16, ba40, fa90f090), \ + X(revsh, bac0, fa90f0b0), \ + X(ror, 41c0, fa60f000), \ + X(rors, 41c0, fa70f000), \ + X(sbc, 4180, eb600000), \ + X(sbcs, 4180, eb700000), \ + X(stmia, c000, e8800000), \ + X(str, 6000, f8400000), \ + X(strb, 7000, f8000000), \ + X(strh, 8000, f8200000), \ + X(sub, 1e00, eba00000), \ + X(subs, 1e00, ebb00000), \ + X(sxtb, b240, fa4ff080), \ + X(sxth, b200, fa0ff080), \ + X(tst, 4200, ea100f00), \ + X(uxtb, b2c0, fa5ff080), \ + X(uxth, b280, fa1ff080), \ + X(nop, bf00, f3af8000), \ + X(yield, bf10, f3af8001), \ + X(wfe, bf20, f3af8002), \ + X(wfi, bf30, f3af8003), \ + X(sev, bf40, f3af9004), /* typo, 8004? */ + +/* To catch errors in encoding functions, the codes are all offset by + 0xF800, putting them in one of the 32-bit prefix ranges, ergo undefined + as 16-bit instructions. */ +#define X(a,b,c) T_MNEM_##a +enum t16_32_codes { T16_32_OFFSET = 0xF7FF, T16_32_TAB }; +#undef X + +#define X(a,b,c) 0x##b +static const unsigned short thumb_op16[] = { T16_32_TAB }; +#define THUMB_OP16(n) (thumb_op16[(n) - (T16_32_OFFSET + 1)]) +#undef X + +#define X(a,b,c) 0x##c +static const unsigned int thumb_op32[] = { T16_32_TAB }; +#define THUMB_OP32(n) (thumb_op32[(n) - (T16_32_OFFSET + 1)]) +#define THUMB_SETS_FLAGS(n) (THUMB_OP32 (n) & 0x00100000) +#undef X +#undef T16_32_TAB + +/* Thumb instruction encoders, in alphabetical order. */ + +/* Parse an add or subtract instruction. We get here with inst.instruction + equalling any of THUMB_OPCODE_add, adds, sub, or subs. */ + +static void +do_t_add_sub (void) +{ + int Rd, Rs, Rn; - skip_whitespace (*str); + Rd = inst.operands[0].reg; + Rs = (inst.operands[1].present + ? inst.operands[1].reg /* Rd, Rs, foo */ + : inst.operands[0].reg); /* Rd, foo -> Rd, Rd, foo */ - if (**str == '-') /* We have the start of a range expression */ + if (unified_syntax) + { + if (!inst.operands[2].isreg) { - int high_range; - - (*str)++; - - if ((high_range - = arm_reg_parse (str, all_reg_maps[regtype].htab)) - == FAIL) - { - inst.error = _(all_reg_maps[regtype].expected); - return FAIL; - } - - if (high_range <= new_base) - { - inst.error = _("register range not in ascending order"); - return FAIL; - } - - for (new_base++; new_base <= high_range; new_base++) + /* For an immediate, we always generate a 32-bit opcode; + section relaxation will shrink it later if possible. */ + inst.instruction = THUMB_OP32 (inst.instruction); + inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000; + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].reg << 16; + inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE; + } + else + { + Rn = inst.operands[2].reg; + /* See if we can do this with a 16-bit instruction. */ + if (!inst.operands[2].shifted && inst.size_req != 4) { - if (mask & (1 << new_base)) + if (Rd <= 7 && Rn <= 7 && Rn <= 7 + && (inst.instruction == T_MNEM_adds + || inst.instruction == T_MNEM_subs)) { - inst.error = _("invalid register list"); - return FAIL; + inst.instruction = (inst.instruction == T_MNEM_adds + ? T_OPCODE_ADD_R3 + : T_OPCODE_SUB_R3); + inst.instruction |= Rd | (Rs << 3) | (Rn << 6); + return; } - mask |= 1 << new_base; - count++; + if (inst.instruction == T_MNEM_add) + { + if (Rd == Rs) + { + inst.instruction = T_OPCODE_ADD_HI; + inst.instruction |= (Rd & 8) << 4; + inst.instruction |= (Rd & 7); + inst.instruction |= Rn << 3; + return; + } + /* ... because addition is commutative! */ + else if (Rd == Rn) + { + inst.instruction = T_OPCODE_ADD_HI; + inst.instruction |= (Rd & 8) << 4; + inst.instruction |= (Rd & 7); + inst.instruction |= Rs << 3; + return; + } + } } + /* If we get here, it can't be done in 16 bits. */ + constraint (inst.operands[2].shifted && inst.operands[2].immisreg, + _("shift must be constant")); + inst.instruction = THUMB_OP32 (inst.instruction); + inst.instruction |= Rd << 8; + inst.instruction |= Rs << 16; + encode_thumb32_shifted_operand (2); } } - while (skip_past_comma (str) != FAIL); + else + { + constraint (inst.instruction == T_MNEM_adds + || inst.instruction == T_MNEM_subs, + BAD_THUMB32); - (*str)++; + if (!inst.operands[2].isreg) /* Rd, Rs, #imm */ + { + constraint ((Rd > 7 && (Rd != REG_SP || Rs != REG_SP)) + || (Rs > 7 && Rs != REG_SP && Rs != REG_PC), + BAD_HIREG); - /* Sanity check -- should have raised a parse error above. */ - if (count == 0 || count > max_regs) - abort (); + inst.instruction = (inst.instruction == T_MNEM_add + ? 0x0000 : 0x8000); + inst.instruction |= (Rd << 4) | Rs; + inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD; + return; + } - *pbase = base_reg; + Rn = inst.operands[2].reg; + constraint (inst.operands[2].shifted, _("unshifted register required")); - /* Final test -- the registers must be consecutive. */ - mask >>= base_reg; - for (i = 0; i < count; i++) - { - if ((mask & (1u << i)) == 0) + /* We now have Rd, Rs, and Rn set to registers. */ + if (Rd > 7 || Rs > 7 || Rn > 7) { - inst.error = _("non-contiguous register range"); - return FAIL; + /* Can't do this for SUB. */ + constraint (inst.instruction == T_MNEM_sub, BAD_HIREG); + inst.instruction = T_OPCODE_ADD_HI; + inst.instruction |= (Rd & 8) << 4; + inst.instruction |= (Rd & 7); + if (Rs == Rd) + inst.instruction |= Rn << 3; + else if (Rn == Rd) + inst.instruction |= Rs << 3; + else + constraint (1, _("dest must overlap one source register")); + } + else + { + inst.instruction = (inst.instruction == T_MNEM_add + ? T_OPCODE_ADD_R3 : T_OPCODE_SUB_R3); + inst.instruction |= Rd | (Rs << 3) | (Rn << 6); } } - - return count; } static void -do_vfp_reg2_from_sp2 (char * str) +do_t_adr (void) { - int reg; - - skip_whitespace (str); - - if (reg_required_here (&str, 12) == FAIL - || skip_past_comma (&str) == FAIL - || reg_required_here (&str, 16) == FAIL - || skip_past_comma (&str) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - /* We require exactly two consecutive SP registers. */ - if (vfp_parse_reg_list (&str, ®, 0) != 2) - { - if (! inst.error) - inst.error = _("only two consecutive VFP SP registers allowed here"); - } - vfp_sp_encode_reg (reg, VFP_REG_Sm); + inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD; + inst.reloc.exp.X_add_number -= 4; /* PC relative adjust. */ + inst.reloc.pc_rel = 1; - end_of_line (str); + inst.instruction |= inst.operands[0].reg << 4; } +/* Arithmetic instructions for which there is just one 16-bit + instruction encoding, and it allows only two low registers. + For maximal compatibility with ARM syntax, we allow three register + operands even when Thumb-32 instructions are not available, as long + as the first two are identical. For instance, both "sbc r0,r1" and + "sbc r0,r0,r1" are allowed. */ static void -do_vfp_sp_from_reg (char * str) +do_t_arit3 (void) { - skip_whitespace (str); + int Rd, Rs, Rn; - if (vfp_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL) - return; + Rd = inst.operands[0].reg; + Rs = (inst.operands[1].present + ? inst.operands[1].reg /* Rd, Rs, foo */ + : inst.operands[0].reg); /* Rd, foo -> Rd, Rd, foo */ + Rn = inst.operands[2].reg; - if (skip_past_comma (&str) == FAIL - || reg_required_here (&str, 12) == FAIL) + if (unified_syntax) { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - end_of_line (str); -} - -static void -do_vfp_sp2_from_reg2 (char * str) -{ - int reg; - - skip_whitespace (str); + if (!inst.operands[2].isreg) + { + /* For an immediate, we always generate a 32-bit opcode; + section relaxation will shrink it later if possible. */ + inst.instruction = THUMB_OP32 (inst.instruction); + inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000; + inst.instruction |= Rd << 8; + inst.instruction |= Rs << 16; + inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE; + } + else + { + /* 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 + && Rd == Rs) + { + inst.instruction = THUMB_OP16 (inst.instruction); + inst.instruction |= Rd; + inst.instruction |= Rn << 3; + return; + } - /* We require exactly two consecutive SP registers. */ - if (vfp_parse_reg_list (&str, ®, 0) != 2) - { - if (! inst.error) - inst.error = _("only two consecutive VFP SP registers allowed here"); + /* If we get here, it can't be done in 16 bits. */ + constraint (inst.operands[2].shifted + && inst.operands[2].immisreg, + _("shift must be constant")); + inst.instruction = THUMB_OP32 (inst.instruction); + inst.instruction |= Rd << 8; + inst.instruction |= Rs << 16; + encode_thumb32_shifted_operand (2); + } } - vfp_sp_encode_reg (reg, VFP_REG_Sm); - - if (skip_past_comma (&str) == FAIL - || reg_required_here (&str, 12) == FAIL - || skip_past_comma (&str) == FAIL - || reg_required_here (&str, 16) == FAIL) + else { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } + /* On its face this is a lie - the instruction does set the + flags. However, the only supported mnemonic in this mode + says it doesn't. */ + constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32); - end_of_line (str); -} - -static void -do_vfp_reg_from_dp (char * str) -{ - skip_whitespace (str); - - if (reg_required_here (&str, 12) == FAIL) - return; + constraint (!inst.operands[2].isreg || inst.operands[2].shifted, + _("unshifted register required")); + constraint (Rd > 7 || Rs > 7 || Rn > 7, BAD_HIREG); + constraint (Rd != Rs, + _("dest and source1 must be the same register")); - if (skip_past_comma (&str) == FAIL - || vfp_dp_reg_required_here (&str, VFP_REG_Dn) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; + inst.instruction = THUMB_OP16 (inst.instruction); + inst.instruction |= Rd; + inst.instruction |= Rn << 3; } - - end_of_line (str); } +/* Similarly, but for instructions where the arithmetic operation is + commutative, so we can allow either of them to be different from + the destination operand in a 16-bit instruction. For instance, all + three of "adc r0,r1", "adc r0,r0,r1", and "adc r0,r1,r0" are + accepted. */ static void -do_vfp_reg2_from_dp (char * str) +do_t_arit3c (void) { - skip_whitespace (str); + int Rd, Rs, Rn; - if (reg_required_here (&str, 12) == FAIL) - return; + Rd = inst.operands[0].reg; + Rs = (inst.operands[1].present + ? inst.operands[1].reg /* Rd, Rs, foo */ + : inst.operands[0].reg); /* Rd, foo -> Rd, Rd, foo */ + Rn = inst.operands[2].reg; - if (skip_past_comma (&str) == FAIL - || reg_required_here (&str, 16) == FAIL - || skip_past_comma (&str) == FAIL - || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL) + if (unified_syntax) { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - end_of_line (str); -} - -static void -do_vfp_dp_from_reg (char * str) -{ - skip_whitespace (str); - - if (vfp_dp_reg_required_here (&str, VFP_REG_Dn) == FAIL) - return; + if (!inst.operands[2].isreg) + { + /* For an immediate, we always generate a 32-bit opcode; + section relaxation will shrink it later if possible. */ + inst.instruction = THUMB_OP32 (inst.instruction); + inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000; + inst.instruction |= Rd << 8; + inst.instruction |= Rs << 16; + inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE; + } + else + { + /* 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 (Rd == Rs) + { + inst.instruction = THUMB_OP16 (inst.instruction); + inst.instruction |= Rd; + inst.instruction |= Rn << 3; + return; + } + if (Rd == Rn) + { + inst.instruction = THUMB_OP16 (inst.instruction); + inst.instruction |= Rd; + inst.instruction |= Rs << 3; + return; + } + } - if (skip_past_comma (&str) == FAIL - || reg_required_here (&str, 12) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; + /* If we get here, it can't be done in 16 bits. */ + constraint (inst.operands[2].shifted + && inst.operands[2].immisreg, + _("shift must be constant")); + inst.instruction = THUMB_OP32 (inst.instruction); + inst.instruction |= Rd << 8; + inst.instruction |= Rs << 16; + encode_thumb32_shifted_operand (2); + } } - - end_of_line (str); -} - -static void -do_vfp_dp_from_reg2 (char * str) -{ - skip_whitespace (str); - - if (vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL) - return; - - if (skip_past_comma (&str) == FAIL - || reg_required_here (&str, 12) == FAIL - || skip_past_comma (&str) == FAIL - || reg_required_here (&str, 16) == FAIL) + else { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - end_of_line (str); -} + /* On its face this is a lie - the instruction does set the + flags. However, the only supported mnemonic in this mode + says it doesn't. */ + constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32); -static const struct vfp_reg * -vfp_psr_parse (char ** str) -{ - char *start = *str; - char c; - char *p; - const struct vfp_reg *vreg; - - p = start; - - /* Find the end of the current token. */ - do - { - c = *p++; - } - while (ISALPHA (c)); + constraint (!inst.operands[2].isreg || inst.operands[2].shifted, + _("unshifted register required")); + constraint (Rd > 7 || Rs > 7 || Rn > 7, BAD_HIREG); - /* Mark it. */ - *--p = 0; + inst.instruction = THUMB_OP16 (inst.instruction); + inst.instruction |= Rd; - for (vreg = vfp_regs + 0; - vreg < vfp_regs + sizeof (vfp_regs) / sizeof (struct vfp_reg); - vreg++) - { - if (streq (start, vreg->name)) - { - *p = c; - *str = p; - return vreg; - } + if (Rd == Rs) + inst.instruction |= Rn << 3; + else if (Rd == Rn) + inst.instruction |= Rs << 3; + else + constraint (1, _("dest must overlap one source register")); } - - *p = c; - return NULL; } -static int -vfp_psr_required_here (char ** str) +static void +do_t_bfc (void) { - char *start = *str; - const struct vfp_reg *vreg; - - vreg = vfp_psr_parse (str); - - if (vreg) - { - inst.instruction |= vreg->regno; - return SUCCESS; - } - - inst.error = _("VFP system register expected"); - - *str = start; - return FAIL; + unsigned int msb = inst.operands[1].imm + inst.operands[2].imm; + constraint (msb > 32, _("bit-field extends past end of register")); + /* The instruction encoding stores the LSB and MSB, + not the LSB and width. */ + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= (inst.operands[1].imm & 0x1c) << 10; + inst.instruction |= (inst.operands[1].imm & 0x03) << 6; + inst.instruction |= msb - 1; } static void -do_vfp_reg_from_ctrl (char * str) +do_t_bfi (void) { - skip_whitespace (str); + unsigned int msb; - if (reg_required_here (&str, 12) == FAIL) - return; - - if (skip_past_comma (&str) == FAIL - || vfp_psr_required_here (&str) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } + /* #0 in second position is alternative syntax for bfc, which is + the same instruction but with REG_PC in the Rm field. */ + if (!inst.operands[1].isreg) + inst.operands[1].reg = REG_PC; - end_of_line (str); + msb = inst.operands[2].imm + inst.operands[3].imm; + constraint (msb > 32, _("bit-field extends past end of register")); + /* The instruction encoding stores the LSB and MSB, + not the LSB and width. */ + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= (inst.operands[2].imm & 0x1c) << 10; + inst.instruction |= (inst.operands[2].imm & 0x03) << 6; + inst.instruction |= msb - 1; } static void -do_vfp_ctrl_from_reg (char * str) +do_t_bfx (void) { - skip_whitespace (str); - - if (vfp_psr_required_here (&str) == FAIL) - return; + constraint (inst.operands[2].imm + inst.operands[3].imm > 32, + _("bit-field extends past end of register")); + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= (inst.operands[2].imm & 0x1c) << 10; + inst.instruction |= (inst.operands[2].imm & 0x03) << 6; + inst.instruction |= inst.operands[3].imm - 1; +} - if (skip_past_comma (&str) == FAIL - || reg_required_here (&str, 12) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } +/* ARM V5 Thumb BLX (argument parse) + BLX <target_addr> which is BLX(1) + BLX <Rm> which is BLX(2) + Unfortunately, there are two different opcodes for this mnemonic. + So, the insns[].value is not used, and the code here zaps values + into inst.instruction. - end_of_line (str); -} + ??? How to take advantage of the additional two bits of displacement + available in Thumb32 mode? Need new relocation? */ static void -do_vfp_sp_ldst (char * str) +do_t_blx (void) { - skip_whitespace (str); - - if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || cp_address_required_here (&str, CP_NO_WB) == FAIL) + if (inst.operands[0].isreg) + /* We have a register, so this is BLX(2). */ + inst.instruction |= inst.operands[0].reg << 3; + else { - if (!inst.error) - inst.error = BAD_ARGS; - return; + /* No register. This must be BLX(1). */ + inst.instruction = 0xf7ffeffe; + inst.reloc.type = BFD_RELOC_THUMB_PCREL_BLX; + inst.reloc.pc_rel = 1; } - - end_of_line (str); } static void -do_vfp_dp_ldst (char * str) +do_t_branch (void) { - skip_whitespace (str); - - if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL) + if (unified_syntax && inst.size_req != 2) { - if (!inst.error) - inst.error = BAD_ARGS; - return; + if (inst.cond == COND_ALWAYS) + { + inst.instruction = 0xf7ffbffe; + inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH25; + } + else + { + assert (inst.cond != 0xF); + inst.instruction = (inst.cond << 22) | 0xf43faffe; + inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH20; + } } - - if (skip_past_comma (&str) == FAIL - || cp_address_required_here (&str, CP_NO_WB) == FAIL) + else { - if (!inst.error) - inst.error = BAD_ARGS; - return; + if (inst.cond == COND_ALWAYS) + inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH12; + else + { + inst.instruction = 0xd0fe | (inst.cond << 8); + inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH9; + } } - end_of_line (str); + inst.reloc.pc_rel = 1; } - static void -vfp_sp_ldstm (char * str, enum vfp_ldstm_type ldstm_type) +do_t_bkpt (void) { - int count; - int reg; - - skip_whitespace (str); - - if (reg_required_here (&str, 16) == FAIL) - return; - - skip_whitespace (str); - - if (*str == '!') - { - inst.instruction |= WRITE_BACK; - str++; - } - else if (ldstm_type != VFP_LDSTMIA) + if (inst.operands[0].present) { - inst.error = _("this addressing mode requires base-register writeback"); - return; + constraint (inst.operands[0].imm > 255, + _("immediate value out of range")); + inst.instruction |= inst.operands[0].imm; } - - if (skip_past_comma (&str) == FAIL - || (count = vfp_parse_reg_list (&str, ®, 0)) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - vfp_sp_encode_reg (reg, VFP_REG_Sd); - - inst.instruction |= count; - end_of_line (str); } static void -vfp_dp_ldstm (char * str, enum vfp_ldstm_type ldstm_type) +do_t_branch23 (void) { - int count; - int reg; - - skip_whitespace (str); - - if (reg_required_here (&str, 16) == FAIL) - return; - - skip_whitespace (str); - - if (*str == '!') - { - inst.instruction |= WRITE_BACK; - str++; - } - else if (ldstm_type != VFP_LDSTMIA && ldstm_type != VFP_LDSTMIAX) - { - inst.error = _("this addressing mode requires base-register writeback"); - return; - } - - if (skip_past_comma (&str) == FAIL - || (count = vfp_parse_reg_list (&str, ®, 1)) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - count <<= 1; - if (ldstm_type == VFP_LDSTMIAX || ldstm_type == VFP_LDSTMDBX) - count += 1; + inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH23; + inst.reloc.pc_rel = 1; - inst.instruction |= (reg << 12) | count; - end_of_line (str); + /* If the destination of the branch is a defined symbol which does not have + the THUMB_FUNC attribute, then we must be calling a function which has + the (interfacearm) attribute. We look for the Thumb entry point to that + function and change the branch to refer to that function instead. */ + if ( inst.reloc.exp.X_op == O_symbol + && inst.reloc.exp.X_add_symbol != NULL + && S_IS_DEFINED (inst.reloc.exp.X_add_symbol) + && ! THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol)) + inst.reloc.exp.X_add_symbol = + find_real_start (inst.reloc.exp.X_add_symbol); } static void -do_vfp_sp_ldstmia (char * str) +do_t_bx (void) { - vfp_sp_ldstm (str, VFP_LDSTMIA); + inst.instruction |= inst.operands[0].reg << 3; + /* ??? FIXME: Should add a hacky reloc here if reg is REG_PC. The reloc + should cause the alignment to be checked once it is known. This is + because BX PC only works if the instruction is word aligned. */ } static void -do_vfp_sp_ldstmdb (char * str) +do_t_bxj (void) { - vfp_sp_ldstm (str, VFP_LDSTMDB); -} + if (inst.operands[0].reg == REG_PC) + as_tsktsk (_("use of r15 in bxj is not really useful")); -static void -do_vfp_dp_ldstmia (char * str) -{ - vfp_dp_ldstm (str, VFP_LDSTMIA); + inst.instruction |= inst.operands[0].reg << 16; } static void -do_vfp_dp_ldstmdb (char * str) +do_t_clz (void) { - vfp_dp_ldstm (str, VFP_LDSTMDB); + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= inst.operands[1].reg; } static void -do_vfp_xp_ldstmia (char *str) +do_t_cpsi (void) { - vfp_dp_ldstm (str, VFP_LDSTMIAX); + if (unified_syntax + && (inst.operands[1].present || inst.size_req == 4)) + { + unsigned int imod = (inst.instruction & 0x0030) >> 4; + inst.instruction = 0xf3af8000; + inst.instruction |= imod << 9; + inst.instruction |= inst.operands[0].imm << 5; + if (inst.operands[1].present) + inst.instruction |= 0x100 | inst.operands[1].imm; + } + else + { + constraint (inst.operands[1].present, + _("Thumb does not support the 2-argument " + "form of this instruction")); + inst.instruction |= inst.operands[0].imm; + } } -static void -do_vfp_xp_ldstmdb (char * str) -{ - vfp_dp_ldstm (str, VFP_LDSTMDBX); -} +/* THUMB CPY instruction (argument parse). */ static void -do_vfp_sp_compare_z (char * str) +do_t_cpy (void) { - skip_whitespace (str); - - if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL) + if (inst.size_req == 4) { - if (!inst.error) - inst.error = BAD_ARGS; - return; + inst.instruction = THUMB_OP32 (T_MNEM_mov); + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].reg; + } + else + { + inst.instruction |= (inst.operands[0].reg & 0x8) << 4; + inst.instruction |= (inst.operands[0].reg & 0x7); + inst.instruction |= inst.operands[1].reg << 3; } - - end_of_line (str); } static void -do_vfp_dp_compare_z (char * str) +do_t_czb (void) { - skip_whitespace (str); - - if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - end_of_line (str); + constraint (inst.operands[0].reg > 7, BAD_HIREG); + inst.instruction |= inst.operands[0].reg; + inst.reloc.pc_rel = 1; + inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH7; } static void -do_vfp_dp_sp_cvt (char * str) +do_t_hint (void) { - skip_whitespace (str); - - if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL) - return; - - if (skip_past_comma (&str) == FAIL - || vfp_sp_reg_required_here (&str, VFP_REG_Sm) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - end_of_line (str); + if (unified_syntax && inst.size_req == 4) + inst.instruction = THUMB_OP32 (inst.instruction); + else + inst.instruction = THUMB_OP16 (inst.instruction); } static void -do_vfp_sp_dp_cvt (char * str) +do_t_it (void) { - skip_whitespace (str); + unsigned int cond = inst.operands[0].imm; + if ((cond & 0x1) == 0x0) + { + unsigned int mask = inst.instruction & 0x000f; + inst.instruction &= 0xfff0; - if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL) - return; + 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; + else + mask = (~(mask & 0xE) & 0xE) | 0x1; - if (skip_past_comma (&str) == FAIL - || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; + inst.instruction |= (mask & 0xF); } - end_of_line (str); + inst.instruction |= cond << 4; } -/* Thumb specific routines. */ - -/* Parse an add or subtract instruction, SUBTRACT is non-zero if the opcode - was SUB. */ - static void -thumb_add_sub (char * str, int subtract) +do_t_ldmstm (void) { - int Rd, Rs, Rn = FAIL; - - skip_whitespace (str); - - if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL - || skip_past_comma (&str) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } + /* This really doesn't seem worth it. */ + constraint (inst.reloc.type != BFD_RELOC_UNUSED, + _("expression too complex")); + constraint (inst.operands[1].writeback, + _("Thumb load/store multiple does not support {reglist}^")); - if (is_immediate_prefix (*str)) + if (unified_syntax) { - Rs = Rd; - str++; - if (my_get_expression (&inst.reloc.exp, &str)) - return; - } - else - { - if ((Rs = thumb_reg (&str, THUMB_REG_ANY)) == FAIL) - return; - - if (skip_past_comma (&str) == FAIL) - { - /* Two operand format, shuffle the registers - and pretend there are 3. */ - Rn = Rs; - Rs = Rd; - } - else if (is_immediate_prefix (*str)) + /* See if we can use a 16-bit instruction. */ + if (inst.instruction < 0xffff /* not ldmdb/stmdb */ + && inst.size_req != 4 + && inst.operands[0].reg <= 7 + && !(inst.operands[1].imm & ~0xff) + && (inst.instruction == T_MNEM_stmia + ? inst.operands[0].writeback + : (inst.operands[0].writeback + == !(inst.operands[1].imm & (1 << inst.operands[0].reg))))) { - str++; - if (my_get_expression (&inst.reloc.exp, &str)) - return; - } - else if ((Rn = thumb_reg (&str, THUMB_REG_ANY)) == FAIL) - return; - } + if (inst.instruction == T_MNEM_stmia + && (inst.operands[1].imm & (1 << inst.operands[0].reg)) + && (inst.operands[1].imm & ((1 << inst.operands[0].reg) - 1))) + as_warn (_("value stored for r%d is UNPREDICTABLE"), + inst.operands[0].reg); - /* We now have Rd and Rs set to registers, and Rn set to a register or FAIL; - for the latter case, EXPR contains the immediate that was found. */ - if (Rn != FAIL) - { - /* All register format. */ - if (Rd > 7 || Rs > 7 || Rn > 7) + inst.instruction = THUMB_OP16 (inst.instruction); + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].imm; + } + else { - if (Rs != Rd) + if (inst.operands[1].imm & (1 << 13)) + as_warn (_("SP should not be in register list")); + if (inst.instruction == T_MNEM_stmia) { - inst.error = _("dest and source1 must be the same register"); - return; + if (inst.operands[1].imm & (1 << 15)) + as_warn (_("PC should not be in register list")); + if (inst.operands[1].imm & (1 << inst.operands[0].reg)) + as_warn (_("value stored for r%d is UNPREDICTABLE"), + inst.operands[0].reg); } - - /* Can't do this for SUB. */ - if (subtract) + else { - inst.error = _("subtract valid only on lo regs"); - return; + 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 ((inst.operands[1].imm & (1 << inst.operands[0].reg)) + && inst.operands[0].writeback) + as_warn (_("base register should not be in register list " + "when written back")); } - - inst.instruction = (T_OPCODE_ADD_HI - | (Rd > 7 ? THUMB_H1 : 0) - | (Rn > 7 ? THUMB_H2 : 0)); - inst.instruction |= (Rd & 7) | ((Rn & 7) << 3); - } - else - { - inst.instruction = subtract ? T_OPCODE_SUB_R3 : T_OPCODE_ADD_R3; - inst.instruction |= Rd | (Rs << 3) | (Rn << 6); + if (inst.instruction < 0xffff) + inst.instruction = THUMB_OP32 (inst.instruction); + inst.instruction |= inst.operands[0].reg << 16; + inst.instruction |= inst.operands[1].imm; + if (inst.operands[0].writeback) + inst.instruction |= WRITE_BACK; } } else { - /* Immediate expression, now things start to get nasty. */ - - /* First deal with HI regs, only very restricted cases allowed: - Adjusting SP, and using PC or SP to get an address. */ - if ((Rd > 7 && (Rd != REG_SP || Rs != REG_SP)) - || (Rs > 7 && Rs != REG_SP && Rs != REG_PC)) + constraint (inst.operands[0].reg > 7 + || (inst.operands[1].imm & ~0xff), BAD_HIREG); + if (inst.instruction == T_MNEM_stmia) { - inst.error = _("invalid Hi register with immediate"); - return; - } - - if (inst.reloc.exp.X_op != O_constant) - { - /* Value isn't known yet, all we can do is store all the fragments - we know about in the instruction and let the reloc hacking - work it all out. */ - inst.instruction = (subtract ? 0x8000 : 0) | (Rd << 4) | Rs; - inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD; + if (!inst.operands[0].writeback) + as_warn (_("this instruction will write back the base register")); + if ((inst.operands[1].imm & (1 << inst.operands[0].reg)) + && (inst.operands[1].imm & ((1 << inst.operands[0].reg) - 1))) + as_warn (_("value stored for r%d is UNPREDICTABLE"), + inst.operands[0].reg); } else { - int offset = inst.reloc.exp.X_add_number; - - if (subtract) - offset = - offset; - - if (offset < 0) - { - offset = - offset; - subtract = 1; - - /* Quick check, in case offset is MIN_INT. */ - if (offset < 0) - { - inst.error = _("immediate value out of range"); - return; - } - } - /* Note - you cannot convert a subtract of 0 into an - add of 0 because the carry flag is set differently. */ - else if (offset > 0) - subtract = 0; - - if (Rd == REG_SP) - { - if (offset & ~0x1fc) - { - inst.error = _("invalid immediate value for stack adjust"); - return; - } - inst.instruction = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST; - inst.instruction |= offset >> 2; - } - else if (Rs == REG_PC || Rs == REG_SP) - { - if (subtract - || (offset & ~0x3fc)) - { - inst.error = _("invalid immediate for address calculation"); - return; - } - inst.instruction = (Rs == REG_PC ? T_OPCODE_ADD_PC - : T_OPCODE_ADD_SP); - inst.instruction |= (Rd << 8) | (offset >> 2); - } - else if (Rs == Rd) - { - if (offset & ~0xff) - { - inst.error = _("immediate value out of range"); - return; - } - inst.instruction = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8; - inst.instruction |= (Rd << 8) | offset; - } - else - { - if (offset & ~0x7) - { - inst.error = _("immediate value out of range"); - return; - } - inst.instruction = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3; - inst.instruction |= Rd | (Rs << 3) | (offset << 6); - } + if (!inst.operands[0].writeback + && !(inst.operands[1].imm & (1 << inst.operands[0].reg))) + as_warn (_("this instruction will write back the base register")); + else if (inst.operands[0].writeback + && (inst.operands[1].imm & (1 << inst.operands[0].reg))) + as_warn (_("this instruction will not write back the base register")); } - } - end_of_line (str); + inst.instruction = THUMB_OP16 (inst.instruction); + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].imm; + } } static void -thumb_shift (char * str, int shift) +do_t_ldrex (void) { - int Rd, Rs, Rn = FAIL; + constraint (!inst.operands[1].isreg || !inst.operands[1].preind + || inst.operands[1].postind || inst.operands[1].writeback + || inst.operands[1].immisreg || inst.operands[1].shifted + || inst.operands[1].negative, + _("instruction does not accept this addressing mode")); - skip_whitespace (str); + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg << 16; + inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_U8; +} - if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL - || skip_past_comma (&str) == FAIL) +static void +do_t_ldrexd (void) +{ + if (!inst.operands[1].present) { - if (! inst.error) - inst.error = BAD_ARGS; - return; + constraint (inst.operands[0].reg == REG_LR, + _("r14 not allowed as first register " + "when second register is omitted")); + inst.operands[1].reg = inst.operands[0].reg + 1; } + constraint (inst.operands[0].reg == inst.operands[1].reg, + BAD_OVERLAP); - if (is_immediate_prefix (*str)) - { - /* Two operand immediate format, set Rs to Rd. */ - Rs = Rd; - str ++; - if (my_get_expression (&inst.reloc.exp, &str)) - return; - } - else - { - if ((Rs = thumb_reg (&str, THUMB_REG_LO)) == FAIL) - return; + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg << 8; + inst.instruction |= inst.operands[2].reg << 16; +} - if (skip_past_comma (&str) == FAIL) - { - /* Two operand format, shuffle the registers - and pretend there are 3. */ - Rn = Rs; - Rs = Rd; - } - else if (is_immediate_prefix (*str)) +static void +do_t_ldst (void) +{ + if (unified_syntax) + { + /* Generation of 16-bit instructions for anything other than + Rd, [Rn, Ri] is deferred to section relaxation time. */ + if (inst.operands[1].isreg && inst.operands[1].immisreg + && !inst.operands[1].shifted && !inst.operands[1].postind + && !inst.operands[1].negative && inst.operands[0].reg <= 7 + && inst.operands[1].reg <= 7 && inst.operands[1].imm <= 7 + && inst.instruction <= 0xffff) { - str++; - if (my_get_expression (&inst.reloc.exp, &str)) - return; + inst.instruction = THUMB_OP16 (inst.instruction); + goto op16; } - else if ((Rn = thumb_reg (&str, THUMB_REG_LO)) == FAIL) - return; + + inst.instruction = THUMB_OP32 (inst.instruction); + inst.instruction |= inst.operands[0].reg << 12; + encode_thumb32_addr_mode (1, /*is_t=*/FALSE, /*is_d=*/FALSE); + return; } - /* We now have Rd and Rs set to registers, and Rn set to a register or FAIL; - for the latter case, EXPR contains the immediate that was found. */ + constraint (inst.operands[0].reg > 7, BAD_HIREG); - if (Rn != FAIL) + if (inst.instruction == T_MNEM_ldrsh || inst.instruction == T_MNEM_ldrsb) { - if (Rs != Rd) - { - inst.error = _("source1 and dest must be same register"); - return; - } - - switch (shift) - { - case THUMB_ASR: inst.instruction = T_OPCODE_ASR_R; break; - case THUMB_LSL: inst.instruction = T_OPCODE_LSL_R; break; - case THUMB_LSR: inst.instruction = T_OPCODE_LSR_R; break; - } - - inst.instruction |= Rd | (Rn << 3); + /* Only [Rn,Rm] is acceptable. */ + constraint (inst.operands[1].reg > 7 || inst.operands[1].imm > 7, BAD_HIREG); + constraint (!inst.operands[1].isreg || !inst.operands[1].immisreg + || inst.operands[1].postind || inst.operands[1].shifted + || inst.operands[1].negative, + _("Thumb does not support this addressing mode")); + inst.instruction = THUMB_OP16 (inst.instruction); + goto op16; } - else + + inst.instruction = THUMB_OP16 (inst.instruction); + if (!inst.operands[1].isreg) + if (move_or_literal_pool (0, /*thumb_p=*/TRUE, /*mode_3=*/FALSE)) + return; + + constraint (!inst.operands[1].preind + || inst.operands[1].shifted + || inst.operands[1].writeback, + _("Thumb does not support this addressing mode")); + if (inst.operands[1].reg == REG_PC || inst.operands[1].reg == REG_SP) { - switch (shift) - { - case THUMB_ASR: inst.instruction = T_OPCODE_ASR_I; break; - case THUMB_LSL: inst.instruction = T_OPCODE_LSL_I; break; - case THUMB_LSR: inst.instruction = T_OPCODE_LSR_I; break; - } + constraint (inst.instruction & 0x0600, + _("byte or halfword not valid for base register")); + constraint (inst.operands[1].reg == REG_PC + && !(inst.instruction & THUMB_LOAD_BIT), + _("r15 based store not allowed")); + constraint (inst.operands[1].immisreg, + _("invalid base register for register offset")); - if (inst.reloc.exp.X_op != O_constant) - { - /* Value isn't known yet, create a dummy reloc and let reloc - hacking fix it up. */ - inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT; - } + if (inst.operands[1].reg == REG_PC) + inst.instruction = T_OPCODE_LDR_PC; + else if (inst.instruction & THUMB_LOAD_BIT) + inst.instruction = T_OPCODE_LDR_SP; else - { - unsigned shift_value = inst.reloc.exp.X_add_number; - - if (shift_value > 32 || (shift_value == 32 && shift == THUMB_LSL)) - { - inst.error = _("invalid immediate for shift"); - return; - } + inst.instruction = T_OPCODE_STR_SP; - /* Shifts of zero are handled by converting to LSL. */ - if (shift_value == 0) - inst.instruction = T_OPCODE_LSL_I; + inst.instruction |= inst.operands[0].reg << 8; + inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET; + return; + } - /* Shifts of 32 are encoded as a shift of zero. */ - if (shift_value == 32) - shift_value = 0; + constraint (inst.operands[1].reg > 7, BAD_HIREG); + if (!inst.operands[1].immisreg) + { + /* Immediate offset. */ + inst.instruction |= inst.operands[0].reg; + inst.instruction |= inst.operands[1].reg << 3; + inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET; + return; + } - inst.instruction |= shift_value << 6; - } + /* Register offset. */ + constraint (inst.operands[1].imm > 7, BAD_HIREG); + constraint (inst.operands[1].negative, + _("Thumb does not support this addressing mode")); - inst.instruction |= Rd | (Rs << 3); + op16: + switch (inst.instruction) + { + case T_OPCODE_STR_IW: inst.instruction = T_OPCODE_STR_RW; break; + case T_OPCODE_STR_IH: inst.instruction = T_OPCODE_STR_RH; break; + case T_OPCODE_STR_IB: inst.instruction = T_OPCODE_STR_RB; break; + case T_OPCODE_LDR_IW: inst.instruction = T_OPCODE_LDR_RW; break; + case T_OPCODE_LDR_IH: inst.instruction = T_OPCODE_LDR_RH; break; + case T_OPCODE_LDR_IB: inst.instruction = T_OPCODE_LDR_RB; break; + case 0x5600 /* ldrsb */: + case 0x5e00 /* ldrsh */: break; + default: abort (); } - end_of_line (str); + inst.instruction |= inst.operands[0].reg; + inst.instruction |= inst.operands[1].reg << 3; + inst.instruction |= inst.operands[1].imm << 6; } static void -thumb_load_store (char * str, int load_store, int size) +do_t_ldstd (void) { - int Rd, Rb, Ro = FAIL; - - skip_whitespace (str); - - if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL - || skip_past_comma (&str) == FAIL) + if (!inst.operands[1].present) { - if (! inst.error) - inst.error = BAD_ARGS; - return; + inst.operands[1].reg = inst.operands[0].reg + 1; + constraint (inst.operands[0].reg == REG_LR, + _("r14 not allowed here")); } + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg << 8; + encode_thumb32_addr_mode (2, /*is_t=*/FALSE, /*is_d=*/TRUE); + +} - if (*str == '[') - { - str++; - if ((Rb = thumb_reg (&str, THUMB_REG_ANY)) == FAIL) - return; +static void +do_t_ldstt (void) +{ + inst.instruction |= inst.operands[0].reg << 12; + encode_thumb32_addr_mode (1, /*is_t=*/TRUE, /*is_d=*/FALSE); +} - if (skip_past_comma (&str) != FAIL) - { - if (is_immediate_prefix (*str)) - { - str++; - if (my_get_expression (&inst.reloc.exp, &str)) - return; - } - else if ((Ro = thumb_reg (&str, THUMB_REG_LO)) == FAIL) - return; - } - else - { - inst.reloc.exp.X_op = O_constant; - inst.reloc.exp.X_add_number = 0; - } +static void +do_t_mla (void) +{ + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= inst.operands[2].reg; + inst.instruction |= inst.operands[3].reg << 12; +} - if (*str != ']') +static void +do_t_mlal (void) +{ + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg << 8; + inst.instruction |= inst.operands[2].reg << 16; + inst.instruction |= inst.operands[3].reg; +} + +static void +do_t_mov_cmp (void) +{ + if (unified_syntax) + { + int r0off = (inst.instruction == T_MNEM_mov + || inst.instruction == T_MNEM_movs) ? 8 : 16; + if (!inst.operands[1].isreg) { - inst.error = _("expected ']'"); - return; + /* For an immediate, we always generate a 32-bit opcode; + section relaxation will shrink it later if possible. */ + inst.instruction = THUMB_OP32 (inst.instruction); + inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000; + inst.instruction |= inst.operands[0].reg << r0off; + inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE; } - str++; - } - else if (*str == '=') - { - if (load_store != THUMB_LOAD) + else if (inst.size_req == 4 + || inst.operands[1].shifted + || (inst.instruction == T_MNEM_movs + && (inst.operands[0].reg > 7 || inst.operands[1].reg > 7))) { - inst.error = _("invalid pseudo operation"); - return; + inst.instruction = THUMB_OP32 (inst.instruction); + inst.instruction |= inst.operands[0].reg << r0off; + encode_thumb32_shifted_operand (1); } + else + switch (inst.instruction) + { + case T_MNEM_mov: + inst.instruction = T_OPCODE_MOV_HR; + inst.instruction |= (inst.operands[0].reg & 0x8) << 4; + inst.instruction |= (inst.operands[0].reg & 0x7); + inst.instruction |= inst.operands[1].reg << 3; + break; - /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op. */ - str++; - - skip_whitespace (str); - - if (my_get_expression (& inst.reloc.exp, & str)) - return; - - end_of_line (str); + case T_MNEM_movs: + /* We know we have low registers at this point. + Generate ADD Rd, Rs, #0. */ + inst.instruction = T_OPCODE_ADD_I3; + inst.instruction |= inst.operands[0].reg; + inst.instruction |= inst.operands[1].reg << 3; + break; - if ( inst.reloc.exp.X_op != O_constant - && inst.reloc.exp.X_op != O_symbol) - { - inst.error = "Constant expression expected"; - return; - } + case T_MNEM_cmp: + if (inst.operands[0].reg <= 7 && inst.operands[1].reg <= 7) + { + inst.instruction = T_OPCODE_CMP_LR; + inst.instruction |= inst.operands[0].reg; + inst.instruction |= inst.operands[1].reg << 3; + } + else + { + inst.instruction = T_OPCODE_CMP_HR; + inst.instruction |= (inst.operands[0].reg & 0x8) << 4; + inst.instruction |= (inst.operands[0].reg & 0x7); + inst.instruction |= inst.operands[1].reg << 3; + } + break; + } + return; + } - if (inst.reloc.exp.X_op == O_constant - && ((inst.reloc.exp.X_add_number & ~0xFF) == 0)) + inst.instruction = THUMB_OP16 (inst.instruction); + if (inst.operands[1].isreg) + { + if (inst.operands[0].reg < 8 && inst.operands[1].reg < 8) { - /* This can be done with a mov instruction. */ + /* A move of two lowregs is encoded as ADD Rd, Rs, #0 + since a MOV instruction produces unpredictable results. */ + if (inst.instruction == T_OPCODE_MOV_I8) + inst.instruction = T_OPCODE_ADD_I3; + else + inst.instruction = T_OPCODE_CMP_LR; - inst.instruction = T_OPCODE_MOV_I8 | (Rd << 8); - inst.instruction |= inst.reloc.exp.X_add_number; - return; + inst.instruction |= inst.operands[0].reg; + inst.instruction |= inst.operands[1].reg << 3; } - - /* Insert into literal pool. */ - if (add_to_lit_pool () == FAIL) + else { - if (!inst.error) - inst.error = "literal pool insertion failed"; - return; + if (inst.instruction == T_OPCODE_MOV_I8) + inst.instruction = T_OPCODE_MOV_HR; + else + inst.instruction = T_OPCODE_CMP_HR; + do_t_cpy (); } - - inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET; - inst.reloc.pc_rel = 1; - inst.instruction = T_OPCODE_LDR_PC | (Rd << 8); - /* Adjust ARM pipeline offset to Thumb. */ - inst.reloc.exp.X_add_number += 4; - - return; } else { - if (my_get_expression (&inst.reloc.exp, &str)) - return; - - inst.instruction = T_OPCODE_LDR_PC | (Rd << 8); - inst.reloc.pc_rel = 1; - inst.reloc.exp.X_add_number -= 4; /* Pipeline offset. */ - inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET; - end_of_line (str); - return; + constraint (inst.operands[0].reg > 7, + _("only lo regs allowed with immediate")); + inst.instruction |= inst.operands[0].reg << 8; + inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM; } +} + +static void +do_t_mov16 (void) +{ + 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 (Rb == REG_PC || Rb == REG_SP) +static void +do_t_mvn_tst (void) +{ + if (unified_syntax) { - if (size != THUMB_WORD) + int r0off = (inst.instruction == T_MNEM_mvn + || inst.instruction == T_MNEM_mvns) ? 8 : 16; + if (!inst.operands[1].isreg) { - inst.error = _("byte or halfword not valid for base register"); - return; + /* For an immediate, we always generate a 32-bit opcode; + section relaxation will shrink it later if possible. */ + if (inst.instruction < 0xffff) + inst.instruction = THUMB_OP32 (inst.instruction); + inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000; + inst.instruction |= inst.operands[0].reg << r0off; + inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE; } - else if (Rb == REG_PC && load_store != THUMB_LOAD) - { - inst.error = _("r15 based store not allowed"); - return; - } - else if (Ro != FAIL) - { - inst.error = _("invalid base register for register offset"); - return; - } - - if (Rb == REG_PC) - inst.instruction = T_OPCODE_LDR_PC; - else if (load_store == THUMB_LOAD) - inst.instruction = T_OPCODE_LDR_SP; else - inst.instruction = T_OPCODE_STR_SP; - - inst.instruction |= Rd << 8; - if (inst.reloc.exp.X_op == O_constant) { - unsigned offset = inst.reloc.exp.X_add_number; - - if (offset & ~0x3fc) + /* See if we can do this with a 16-bit instruction. */ + if (inst.instruction < 0xffff + && THUMB_SETS_FLAGS (inst.instruction) + && !inst.operands[1].shifted + && inst.operands[0].reg <= 7 + && inst.operands[1].reg <= 7 + && inst.size_req != 4) { - inst.error = _("invalid offset"); - return; + inst.instruction = THUMB_OP16 (inst.instruction); + inst.instruction |= inst.operands[0].reg; + inst.instruction |= inst.operands[1].reg << 3; } - - inst.instruction |= offset >> 2; - } - else - inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET; - } - else if (Rb > 7) - { - inst.error = _("invalid base register in load/store"); - return; - } - else if (Ro == FAIL) - { - /* Immediate offset. */ - if (size == THUMB_WORD) - inst.instruction = (load_store == THUMB_LOAD - ? T_OPCODE_LDR_IW : T_OPCODE_STR_IW); - else if (size == THUMB_HALFWORD) - inst.instruction = (load_store == THUMB_LOAD - ? T_OPCODE_LDR_IH : T_OPCODE_STR_IH); - else - inst.instruction = (load_store == THUMB_LOAD - ? T_OPCODE_LDR_IB : T_OPCODE_STR_IB); - - inst.instruction |= Rd | (Rb << 3); - - if (inst.reloc.exp.X_op == O_constant) - { - unsigned offset = inst.reloc.exp.X_add_number; - - if (offset & ~(0x1f << size)) + else { - inst.error = _("invalid offset"); - return; + constraint (inst.operands[1].shifted + && inst.operands[1].immisreg, + _("shift must be constant")); + if (inst.instruction < 0xffff) + inst.instruction = THUMB_OP32 (inst.instruction); + inst.instruction |= inst.operands[0].reg << r0off; + encode_thumb32_shifted_operand (1); } - inst.instruction |= (offset >> size) << 6; } - else - inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET; } else { - /* Register offset. */ - if (size == THUMB_WORD) - inst.instruction = (load_store == THUMB_LOAD - ? T_OPCODE_LDR_RW : T_OPCODE_STR_RW); - else if (size == THUMB_HALFWORD) - inst.instruction = (load_store == THUMB_LOAD - ? T_OPCODE_LDR_RH : T_OPCODE_STR_RH); - else - inst.instruction = (load_store == THUMB_LOAD - ? T_OPCODE_LDR_RB : T_OPCODE_STR_RB); + constraint (inst.instruction > 0xffff + || inst.instruction == T_MNEM_mvns, BAD_THUMB32); + constraint (!inst.operands[1].isreg || inst.operands[1].shifted, + _("unshifted register required")); + constraint (inst.operands[0].reg > 7 || inst.operands[1].reg > 7, + BAD_HIREG); - inst.instruction |= Rd | (Rb << 3) | (Ro << 6); + inst.instruction = THUMB_OP16 (inst.instruction); + inst.instruction |= inst.operands[0].reg; + inst.instruction |= inst.operands[1].reg << 3; } - - end_of_line (str); } -/* A register must be given at this point. - - Shift is the place to put it in inst.instruction. +static void +do_t_mrs (void) +{ + /* mrs only accepts CPSR/SPSR/CPSR_all/SPSR_all. */ + constraint ((inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f)) + != (PSR_c|PSR_f), + _("'CPSR' or 'SPSR' expected")); + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= (inst.operands[1].imm & SPSR_BIT) >> 2; +} - Restores input start point on err. - Returns the reg#, or FAIL. */ +static void +do_t_msr (void) +{ + constraint (!inst.operands[1].isreg, + _("Thumb encoding does not support an immediate here")); + inst.instruction |= (inst.operands[0].imm & SPSR_BIT) >> 2; + inst.instruction |= (inst.operands[0].imm & ~SPSR_BIT) >> 8; + inst.instruction |= inst.operands[1].reg << 16; +} -static int -mav_reg_required_here (char ** str, int shift, enum arm_reg_type regtype) +static void +do_t_mul (void) { - int reg; - char *start = *str; + if (!inst.operands[2].present) + inst.operands[2].reg = inst.operands[0].reg; - if ((reg = arm_reg_parse (str, all_reg_maps[regtype].htab)) != FAIL) + /* There is no 32-bit MULS and no 16-bit MUL. */ + if (unified_syntax && inst.instruction == T_MNEM_mul) { - if (shift >= 0) - inst.instruction |= reg << shift; - - return reg; + inst.instruction = THUMB_OP32 (inst.instruction); + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= inst.operands[2].reg << 0; } - - /* Restore the start point. */ - *str = start; - - /* Try generic coprocessor name if applicable. */ - if (regtype == REG_TYPE_MVF || - regtype == REG_TYPE_MVD || - regtype == REG_TYPE_MVFX || - regtype == REG_TYPE_MVDX) + else { - if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_CN].htab)) != FAIL) - { - if (shift >= 0) - inst.instruction |= reg << shift; + constraint (!unified_syntax + && inst.instruction == T_MNEM_muls, BAD_THUMB32); + constraint (inst.operands[0].reg > 7 || inst.operands[1].reg > 7, + BAD_HIREG); - return reg; - } + inst.instruction = THUMB_OP16 (inst.instruction); + inst.instruction |= inst.operands[0].reg; - /* Restore the start point. */ - *str = start; + if (inst.operands[0].reg == inst.operands[1].reg) + inst.instruction |= inst.operands[2].reg << 3; + else if (inst.operands[0].reg == inst.operands[2].reg) + inst.instruction |= inst.operands[1].reg << 3; + else + constraint (1, _("dest must overlap one source register")); } - - /* In the few cases where we might be able to accept something else - this error can be overridden. */ - inst.error = _(all_reg_maps[regtype].expected); - - return FAIL; } -/* Cirrus Maverick Instructions. */ - -/* Isnsn like "foo X,Y". */ - static void -do_mav_binops (char * str, - int mode, - enum arm_reg_type reg0, - enum arm_reg_type reg1) +do_t_mull (void) { - int shift0, shift1; - - shift0 = mode & 0xff; - shift1 = (mode >> 8) & 0xff; + inst.instruction |= inst.operands[0].reg << 12; + inst.instruction |= inst.operands[1].reg << 8; + inst.instruction |= inst.operands[2].reg << 16; + inst.instruction |= inst.operands[3].reg; - skip_whitespace (str); - - if (mav_reg_required_here (&str, shift0, reg0) == FAIL - || skip_past_comma (&str) == FAIL - || mav_reg_required_here (&str, shift1, reg1) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - } - else - end_of_line (str); + if (inst.operands[0].reg == inst.operands[1].reg) + as_tsktsk (_("rdhi and rdlo must be different")); } -/* Isnsn like "foo X,Y,Z". */ - static void -do_mav_triple (char * str, - int mode, - enum arm_reg_type reg0, - enum arm_reg_type reg1, - enum arm_reg_type reg2) +do_t_nop (void) { - int shift0, shift1, shift2; - - shift0 = mode & 0xff; - shift1 = (mode >> 8) & 0xff; - shift2 = (mode >> 16) & 0xff; - - skip_whitespace (str); - - if (mav_reg_required_here (&str, shift0, reg0) == FAIL - || skip_past_comma (&str) == FAIL - || mav_reg_required_here (&str, shift1, reg1) == FAIL - || skip_past_comma (&str) == FAIL - || mav_reg_required_here (&str, shift2, reg2) == FAIL) + if (unified_syntax) { - if (!inst.error) - inst.error = BAD_ARGS; + if (inst.size_req == 4 || inst.operands[0].imm > 15) + { + inst.instruction = THUMB_OP32 (inst.instruction); + inst.instruction |= inst.operands[0].imm; + } + else + { + inst.instruction = THUMB_OP16 (inst.instruction); + inst.instruction |= inst.operands[0].imm << 4; + } } else - end_of_line (str); -} - -/* Wrapper functions. */ - -static void -do_mav_binops_1a (char * str) -{ - do_mav_binops (str, MAV_MODE1, REG_TYPE_RN, REG_TYPE_MVF); + { + constraint (inst.operands[0].present, + _("Thumb does not support NOP with hints")); + inst.instruction = 0x46c0; + } } static void -do_mav_binops_1b (char * str) +do_t_neg (void) { - do_mav_binops (str, MAV_MODE1, REG_TYPE_RN, REG_TYPE_MVD); -} + if (unified_syntax) + { + if (inst.operands[0].reg > 7 || inst.operands[1].reg > 7 + || !THUMB_SETS_FLAGS (inst.instruction) + || inst.size_req == 4) + { + inst.instruction = THUMB_OP32 (inst.instruction); + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].reg << 16; + } + else + { + inst.instruction = THUMB_OP16 (inst.instruction); + inst.instruction |= inst.operands[0].reg; + inst.instruction |= inst.operands[1].reg << 3; + } + } + else + { + constraint (inst.operands[0].reg > 7 || inst.operands[1].reg > 7, + BAD_HIREG); + constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32); -static void -do_mav_binops_1c (char * str) -{ - do_mav_binops (str, MAV_MODE1, REG_TYPE_RN, REG_TYPE_MVDX); + inst.instruction = THUMB_OP16 (inst.instruction); + inst.instruction |= inst.operands[0].reg; + inst.instruction |= inst.operands[1].reg << 3; + } } static void -do_mav_binops_1d (char * str) +do_t_pkhbt (void) { - do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVF); + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= inst.operands[2].reg; + if (inst.operands[3].present) + { + unsigned int val = inst.reloc.exp.X_add_number; + constraint (inst.reloc.exp.X_op != O_constant, + _("expression too complex")); + inst.instruction |= (val & 0x1c) << 10; + inst.instruction |= (val & 0x03) << 6; + } } static void -do_mav_binops_1e (char * str) +do_t_pkhtb (void) { - do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVD); + if (!inst.operands[3].present) + inst.instruction &= ~0x00000020; + do_t_pkhbt (); } static void -do_mav_binops_1f (char * str) +do_t_pld (void) { - do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVF); + encode_thumb32_addr_mode (0, /*is_t=*/FALSE, /*is_d=*/FALSE); } static void -do_mav_binops_1g (char * str) +do_t_push_pop (void) { - do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVD); -} + constraint (inst.operands[0].writeback, + _("push/pop do not support {reglist}^")); + constraint (inst.reloc.type != BFD_RELOC_UNUSED, + _("expression too complex")); -static void -do_mav_binops_1h (char * str) -{ - do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVFX); -} + if ((inst.operands[0].imm & ~0xff) == 0) + inst.instruction = THUMB_OP16 (inst.instruction); + else if ((inst.instruction == T_MNEM_push + && (inst.operands[0].imm & ~0xff) == 1 << REG_LR) + || (inst.instruction == T_MNEM_pop + && (inst.operands[0].imm & ~0xff) == 1 << REG_PC)) + { + inst.instruction = THUMB_OP16 (inst.instruction); + inst.instruction |= THUMB_PP_PC_LR; + inst.operands[0].imm &= 0xff; + } + else if (unified_syntax) + { + if (inst.operands[1].imm & (1 << 13)) + as_warn (_("SP should not be 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")); + } + 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")); + } -static void -do_mav_binops_1i (char * str) -{ - do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVFX); -} + inst.instruction = THUMB_OP32 (inst.instruction); + } + else + { + inst.error = _("invalid register list to push/pop instruction"); + return; + } -static void -do_mav_binops_1j (char * str) -{ - do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVDX); + inst.instruction |= inst.operands[0].imm; } static void -do_mav_binops_1k (char * str) +do_t_rbit (void) { - do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVDX); + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].reg << 16; } static void -do_mav_binops_1l (char * str) +do_t_rev (void) { - do_mav_binops (str, MAV_MODE1, REG_TYPE_MVFX, REG_TYPE_MVF); + if (inst.operands[0].reg <= 7 && inst.operands[1].reg <= 7 + && inst.size_req != 4) + { + inst.instruction = THUMB_OP16 (inst.instruction); + inst.instruction |= inst.operands[0].reg; + inst.instruction |= inst.operands[1].reg << 3; + } + else if (unified_syntax) + { + inst.instruction = THUMB_OP32 (inst.instruction); + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= inst.operands[1].reg; + } + else + inst.error = BAD_HIREG; } static void -do_mav_binops_1m (char * str) +do_t_rsb (void) { - do_mav_binops (str, MAV_MODE1, REG_TYPE_MVFX, REG_TYPE_MVD); -} + int Rd, Rs; -static void -do_mav_binops_1n (char * str) -{ - do_mav_binops (str, MAV_MODE1, REG_TYPE_MVFX, REG_TYPE_MVFX); -} + Rd = inst.operands[0].reg; + Rs = (inst.operands[1].present + ? inst.operands[1].reg /* Rd, Rs, foo */ + : inst.operands[0].reg); /* Rd, foo -> Rd, Rd, foo */ -static void -do_mav_binops_1o (char * str) -{ - do_mav_binops (str, MAV_MODE1, REG_TYPE_MVDX, REG_TYPE_MVDX); + inst.instruction |= Rd << 8; + inst.instruction |= Rs << 16; + if (!inst.operands[2].isreg) + { + inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000; + inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE; + } + else + encode_thumb32_shifted_operand (2); } static void -do_mav_binops_2a (char * str) +do_t_setend (void) { - do_mav_binops (str, MAV_MODE2, REG_TYPE_MVF, REG_TYPE_RN); + if (inst.operands[0].imm) + inst.instruction |= 0x8; } static void -do_mav_binops_2b (char * str) +do_t_shift (void) { - do_mav_binops (str, MAV_MODE2, REG_TYPE_MVD, REG_TYPE_RN); -} + if (!inst.operands[1].present) + inst.operands[1].reg = inst.operands[0].reg; -static void -do_mav_binops_2c (char * str) -{ - do_mav_binops (str, MAV_MODE2, REG_TYPE_MVDX, REG_TYPE_RN); -} + if (unified_syntax) + { + if (inst.operands[0].reg > 7 + || inst.operands[1].reg > 7 + || !THUMB_SETS_FLAGS (inst.instruction) + || (!inst.operands[2].isreg && inst.instruction == T_MNEM_rors) + || (inst.operands[2].isreg && inst.operands[1].reg != inst.operands[0].reg) + || inst.size_req == 4) + { + if (inst.operands[2].isreg) + { + inst.instruction = THUMB_OP32 (inst.instruction); + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= inst.operands[2].reg; + } + else + { + inst.operands[1].shifted = 1; + switch (inst.instruction) + { + case T_MNEM_asr: + case T_MNEM_asrs: inst.operands[1].shift_kind = SHIFT_ASR; break; + case T_MNEM_lsl: + case T_MNEM_lsls: inst.operands[1].shift_kind = SHIFT_LSL; break; + case T_MNEM_lsr: + case T_MNEM_lsrs: inst.operands[1].shift_kind = SHIFT_LSR; break; + case T_MNEM_ror: + case T_MNEM_rors: inst.operands[1].shift_kind = SHIFT_ROR; break; + default: abort (); + } + + inst.instruction = THUMB_OP32 (THUMB_SETS_FLAGS (inst.instruction) + ? T_MNEM_movs : T_MNEM_mov); + inst.instruction |= inst.operands[0].reg << 8; + encode_thumb32_shifted_operand (1); + /* Prevent the incorrect generation of an ARM_IMMEDIATE fixup. */ + inst.reloc.type = BFD_RELOC_UNUSED; + } + } + else + { + if (inst.operands[2].isreg) + { + switch (inst.instruction) + { + case T_MNEM_asrs: inst.instruction = T_OPCODE_ASR_R; break; + case T_MNEM_lsls: inst.instruction = T_OPCODE_LSL_R; break; + case T_MNEM_lsrs: inst.instruction = T_OPCODE_LSR_R; break; + case T_MNEM_rors: inst.instruction = T_OPCODE_ROR_R; break; + default: abort (); + } + + inst.instruction |= inst.operands[0].reg; + inst.instruction |= inst.operands[2].reg << 3; + } + else + { + switch (inst.instruction) + { + case T_MNEM_asrs: inst.instruction = T_OPCODE_ASR_I; break; + case T_MNEM_lsls: inst.instruction = T_OPCODE_LSL_I; break; + case T_MNEM_lsrs: inst.instruction = T_OPCODE_LSR_I; break; + default: abort (); + } + inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT; + inst.instruction |= inst.operands[0].reg; + inst.instruction |= inst.operands[1].reg << 3; + } + } + } + else + { + constraint (inst.operands[0].reg > 7 + || inst.operands[1].reg > 7, BAD_HIREG); + constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32); -static void -do_mav_binops_3a (char * str) -{ - do_mav_binops (str, MAV_MODE3, REG_TYPE_MVAX, REG_TYPE_MVFX); -} + if (inst.operands[2].isreg) /* Rd, {Rs,} Rn */ + { + constraint (inst.operands[2].reg > 7, BAD_HIREG); + constraint (inst.operands[0].reg != inst.operands[1].reg, + _("source1 and dest must be same register")); -static void -do_mav_binops_3b (char * str) -{ - do_mav_binops (str, MAV_MODE3, REG_TYPE_MVFX, REG_TYPE_MVAX); + switch (inst.instruction) + { + case T_MNEM_asr: inst.instruction = T_OPCODE_ASR_R; break; + case T_MNEM_lsl: inst.instruction = T_OPCODE_LSL_R; break; + case T_MNEM_lsr: inst.instruction = T_OPCODE_LSR_R; break; + case T_MNEM_ror: inst.instruction = T_OPCODE_ROR_R; break; + default: abort (); + } + + inst.instruction |= inst.operands[0].reg; + inst.instruction |= inst.operands[2].reg << 3; + } + else + { + switch (inst.instruction) + { + case T_MNEM_asr: inst.instruction = T_OPCODE_ASR_I; break; + case T_MNEM_lsl: inst.instruction = T_OPCODE_LSL_I; break; + case T_MNEM_lsr: inst.instruction = T_OPCODE_LSR_I; break; + case T_MNEM_ror: inst.error = _("ror #imm not supported"); return; + default: abort (); + } + inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT; + inst.instruction |= inst.operands[0].reg; + inst.instruction |= inst.operands[1].reg << 3; + } + } } static void -do_mav_binops_3c (char * str) +do_t_simd (void) { - do_mav_binops (str, MAV_MODE3, REG_TYPE_MVAX, REG_TYPE_MVDX); + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= inst.operands[2].reg; } static void -do_mav_binops_3d (char * str) +do_t_smi (void) { - do_mav_binops (str, MAV_MODE3, REG_TYPE_MVDX, REG_TYPE_MVAX); + unsigned int value = inst.reloc.exp.X_add_number; + constraint (inst.reloc.exp.X_op != O_constant, + _("expression too complex")); + inst.reloc.type = BFD_RELOC_UNUSED; + inst.instruction |= (value & 0xf000) >> 12; + inst.instruction |= (value & 0x0ff0); + inst.instruction |= (value & 0x000f) << 16; } static void -do_mav_triple_4a (char * str) +do_t_ssat (void) { - do_mav_triple (str, MAV_MODE4, REG_TYPE_MVFX, REG_TYPE_MVFX, REG_TYPE_RN); -} + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].imm - 1; + inst.instruction |= inst.operands[2].reg << 16; -static void -do_mav_triple_4b (char * str) -{ - do_mav_triple (str, MAV_MODE4, REG_TYPE_MVDX, REG_TYPE_MVDX, REG_TYPE_RN); -} + if (inst.operands[3].present) + { + constraint (inst.reloc.exp.X_op != O_constant, + _("expression too complex")); -static void -do_mav_triple_5a (char * str) -{ - do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVF, REG_TYPE_MVF); + if (inst.reloc.exp.X_add_number != 0) + { + if (inst.operands[3].shift_kind == SHIFT_ASR) + inst.instruction |= 0x00200000; /* sh bit */ + inst.instruction |= (inst.reloc.exp.X_add_number & 0x1c) << 10; + inst.instruction |= (inst.reloc.exp.X_add_number & 0x03) << 6; + } + inst.reloc.type = BFD_RELOC_UNUSED; + } } static void -do_mav_triple_5b (char * str) +do_t_ssat16 (void) { - do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVD, REG_TYPE_MVD); + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].imm - 1; + inst.instruction |= inst.operands[2].reg << 16; } static void -do_mav_triple_5c (char * str) +do_t_strex (void) { - do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVFX, REG_TYPE_MVFX); -} + constraint (!inst.operands[2].isreg || !inst.operands[2].preind + || inst.operands[2].postind || inst.operands[2].writeback + || inst.operands[2].immisreg || inst.operands[2].shifted + || inst.operands[2].negative, + _("instruction does not accept this addressing mode")); -static void -do_mav_triple_5d (char * str) -{ - do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVDX, REG_TYPE_MVDX); + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].reg << 12; + inst.instruction |= inst.operands[2].reg << 16; + inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_U8; } static void -do_mav_triple_5e (char * str) +do_t_strexd (void) { - do_mav_triple (str, MAV_MODE5, REG_TYPE_MVF, REG_TYPE_MVF, REG_TYPE_MVF); -} + if (!inst.operands[2].present) + inst.operands[2].reg = inst.operands[1].reg + 1; -static void -do_mav_triple_5f (char * str) -{ - do_mav_triple (str, MAV_MODE5, REG_TYPE_MVD, REG_TYPE_MVD, REG_TYPE_MVD); -} + constraint (inst.operands[0].reg == inst.operands[1].reg + || inst.operands[0].reg == inst.operands[2].reg + || inst.operands[0].reg == inst.operands[3].reg + || inst.operands[1].reg == inst.operands[2].reg, + BAD_OVERLAP); -static void -do_mav_triple_5g (char * str) -{ - do_mav_triple (str, MAV_MODE5, REG_TYPE_MVFX, REG_TYPE_MVFX, REG_TYPE_MVFX); + inst.instruction |= inst.operands[0].reg; + inst.instruction |= inst.operands[1].reg << 12; + inst.instruction |= inst.operands[2].reg << 8; + inst.instruction |= inst.operands[3].reg << 16; } static void -do_mav_triple_5h (char * str) +do_t_sxtah (void) { - do_mav_triple (str, MAV_MODE5, REG_TYPE_MVDX, REG_TYPE_MVDX, REG_TYPE_MVDX); + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].reg << 16; + inst.instruction |= inst.operands[2].reg; + inst.instruction |= inst.operands[3].imm << 4; } -/* Isnsn like "foo W,X,Y,Z". - where W=MVAX[0:3] and X,Y,Z=MVFX[0:15]. */ - static void -do_mav_quad (char * str, - int mode, - enum arm_reg_type reg0, - enum arm_reg_type reg1, - enum arm_reg_type reg2, - enum arm_reg_type reg3) +do_t_sxth (void) { - int shift0, shift1, shift2, shift3; - - shift0= mode & 0xff; - shift1 = (mode >> 8) & 0xff; - shift2 = (mode >> 16) & 0xff; - shift3 = (mode >> 24) & 0xff; - - skip_whitespace (str); - - if (mav_reg_required_here (&str, shift0, reg0) == FAIL - || skip_past_comma (&str) == FAIL - || mav_reg_required_here (&str, shift1, reg1) == FAIL - || skip_past_comma (&str) == FAIL - || mav_reg_required_here (&str, shift2, reg2) == FAIL - || skip_past_comma (&str) == FAIL - || mav_reg_required_here (&str, shift3, reg3) == FAIL) + if (inst.instruction <= 0xffff && inst.size_req != 4 + && inst.operands[0].reg <= 7 && inst.operands[1].reg <= 7 + && (!inst.operands[2].present || inst.operands[2].imm == 0)) { - if (!inst.error) - inst.error = BAD_ARGS; + inst.instruction = THUMB_OP16 (inst.instruction); + inst.instruction |= inst.operands[0].reg; + inst.instruction |= inst.operands[1].reg << 3; + } + else if (unified_syntax) + { + if (inst.instruction <= 0xffff) + inst.instruction = THUMB_OP32 (inst.instruction); + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].reg; + inst.instruction |= inst.operands[2].imm << 4; } else - end_of_line (str); + { + constraint (inst.operands[2].present && inst.operands[2].imm != 0, + _("Thumb encoding does not support rotation")); + constraint (1, BAD_HIREG); + } } static void -do_mav_quad_6a (char * str) +do_t_swi (void) { - do_mav_quad (str, MAV_MODE6, REG_TYPE_MVAX, REG_TYPE_MVFX, REG_TYPE_MVFX, - REG_TYPE_MVFX); + inst.reloc.type = BFD_RELOC_ARM_SWI; } static void -do_mav_quad_6b (char * str) +do_t_usat (void) { - do_mav_quad (str, MAV_MODE6, REG_TYPE_MVAX, REG_TYPE_MVAX, REG_TYPE_MVFX, - REG_TYPE_MVFX); -} + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].imm; + inst.instruction |= inst.operands[2].reg << 16; -/* cfmvsc32<cond> DSPSC,MVDX[15:0]. */ -static void -do_mav_dspsc_1 (char * str) -{ - skip_whitespace (str); - - /* cfmvsc32. */ - if (mav_reg_required_here (&str, -1, REG_TYPE_DSPSC) == FAIL - || skip_past_comma (&str) == FAIL - || mav_reg_required_here (&str, 12, REG_TYPE_MVDX) == FAIL) + if (inst.operands[3].present) { - if (!inst.error) - inst.error = BAD_ARGS; + constraint (inst.reloc.exp.X_op != O_constant, + _("expression too complex")); + if (inst.reloc.exp.X_add_number != 0) + { + if (inst.operands[3].shift_kind == SHIFT_ASR) + inst.instruction |= 0x00200000; /* sh bit */ - return; + inst.instruction |= (inst.reloc.exp.X_add_number & 0x1c) << 10; + inst.instruction |= (inst.reloc.exp.X_add_number & 0x03) << 6; + } + inst.reloc.type = BFD_RELOC_UNUSED; } +} - end_of_line (str); +static void +do_t_usat16 (void) +{ + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].imm; + inst.instruction |= inst.operands[2].reg << 16; } + +/* Overall per-instruction processing. */ + +/* We need to be able to fix up arbitrary expressions in some statements. + This is so that we can handle symbols that are an arbitrary distance from + the pc. The most common cases are of the form ((+/-sym -/+ . - 8) & mask), + which returns part of an address in a form which will be valid for + a data instruction. We do this by pushing the expression into a symbol + in the expr_section, and creating a fix for that. */ -/* cfmv32sc<cond> MVDX[15:0],DSPSC. */ static void -do_mav_dspsc_2 (char * str) +fix_new_arm (fragS * frag, + int where, + short int size, + expressionS * exp, + int pc_rel, + int reloc) { - skip_whitespace (str); + fixS * new_fix; - /* cfmv32sc. */ - if (mav_reg_required_here (&str, 12, REG_TYPE_MVDX) == FAIL - || skip_past_comma (&str) == FAIL - || mav_reg_required_here (&str, -1, REG_TYPE_DSPSC) == FAIL) + switch (exp->X_op) { - if (!inst.error) - inst.error = BAD_ARGS; + case O_constant: + case O_symbol: + case O_add: + case O_subtract: + new_fix = fix_new_exp (frag, where, size, exp, pc_rel, reloc); + break; - return; + default: + new_fix = fix_new (frag, where, size, make_expr_symbol (exp), 0, + pc_rel, reloc); + break; } - end_of_line (str); + /* Mark whether the fix is to a THUMB instruction, or an ARM + instruction. */ + new_fix->tc_fix_data = (PTR) thumb_mode; } -/* Maverick shift immediate instructions. - cfsh32<cond> MVFX[15:0],MVFX[15:0],Shift[6:0]. - cfsh64<cond> MVDX[15:0],MVDX[15:0],Shift[6:0]. */ - static void -do_mav_shift (char * str, - enum arm_reg_type reg0, - enum arm_reg_type reg1) +output_inst (const char * str) { - int error; - int imm, neg = 0; - - skip_whitespace (str); - - error = 0; + char * to = NULL; - if (mav_reg_required_here (&str, 12, reg0) == FAIL - || skip_past_comma (&str) == FAIL - || mav_reg_required_here (&str, 16, reg1) == FAIL - || skip_past_comma (&str) == FAIL) + if (inst.error) { - if (!inst.error) - inst.error = BAD_ARGS; + as_bad ("%s -- `%s'", inst.error, str); return; } + if (inst.size == 0) + return; - /* Calculate the immediate operand. - The operand is a 7bit signed number. */ - skip_whitespace (str); - - if (*str == '#') - ++str; + to = frag_more (inst.size); - if (!ISDIGIT (*str) && *str != '-') + if (thumb_mode && (inst.size > THUMB_SIZE)) { - inst.error = _("expecting immediate, 7bit operand"); - return; + assert (inst.size == (2 * THUMB_SIZE)); + md_number_to_chars (to, inst.instruction >> 16, THUMB_SIZE); + md_number_to_chars (to + THUMB_SIZE, inst.instruction, THUMB_SIZE); } - - if (*str == '-') + else if (inst.size > INSN_SIZE) { - neg = 1; - ++str; + 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); - for (imm = 0; *str && ISDIGIT (*str); ++str) - imm = imm * 10 + *str - '0'; + if (inst.reloc.type != BFD_RELOC_UNUSED) + fix_new_arm (frag_now, to - frag_now->fr_literal, + inst.size, & inst.reloc.exp, inst.reloc.pc_rel, + inst.reloc.type); - if (imm > 64) - { - inst.error = _("immediate out of range"); - return; - } +#ifdef OBJ_ELF + dwarf2_emit_insn (inst.size); +#endif +} - /* Make negative imm's into 7bit signed numbers. */ - if (neg) - { - imm = -imm; - imm &= 0x0000007f; - } +/* Tag values used in struct asm_opcode's tag field. */ +enum opcode_tag +{ + OT_unconditional, /* Instruction cannot be conditionalized. + The ARM condition field is still 0xE. */ + OT_unconditionalF, /* Instruction cannot be conditionalized + and carries 0xF in its ARM condition field. */ + OT_csuffix, /* Instruction takes a conditional suffix. */ + OT_cinfix3, /* Instruction takes a conditional infix, + beginning at character index 3. (In + unified mode, it becomes a suffix.) */ + OT_csuf_or_in3, /* Instruction takes either a conditional + suffix or an infix at character index 3. + (In unified mode, a suffix only. */ + OT_odd_infix_unc, /* This is the unconditional variant of an + instruction that takes a conditional infix + at an unusual position. In unified mode, + this variant will accept a suffix. */ + OT_odd_infix_0 /* Values greater than or equal to OT_odd_infix_0 + are the conditional variants of instructions that + take conditional infixes in unusual positions. + The infix appears at character index + (tag - OT_odd_infix_0). These are not accepted + in unified mode. */ +}; - /* Bits 0-3 of the insn should have bits 0-3 of the immediate. - Bits 5-7 of the insn should have bits 4-6 of the immediate. - Bit 4 should be 0. */ - imm = (imm & 0xf) | ((imm & 0x70) << 1); +/* Subroutine of md_assemble, responsible for looking up the primary + opcode from the mnemonic the user wrote. STR points to the + beginning of the mnemonic. + + This is not simply a hash table lookup, because of conditional + variants. Most instructions have conditional variants, which are + expressed with a _conditional affix_ to the mnemonic. If we were + to encode each conditional variant as a literal string in the opcode + table, it would have approximately 20,000 entries. + + Most mnemonics take this affix as a suffix, and in unified syntax, + 'most' is upgraded to 'all'. However, in the divided syntax, some + instructions take the affix as an infix, notably the s-variants of + the arithmetic instructions. Of those instructions, all but six + have the infix appear after the third character of the mnemonic. + + Accordingly, the algorithm for looking up primary opcodes given + an identifier is: + + 1. Look up the identifier in the opcode table. + If we find a match, go to step U. + + 2. Look up the last two characters of the identifier in the + conditions table. If we find a match, look up the first N-2 + characters of the identifier in the opcode table. If we + find a match, go to step CE. + + 3. Look up the fourth and fifth characters of the identifier in + the conditions table. If we find a match, extract those + characters from the identifier, and look up the remaining + characters in the opcode table. If we find a match, go + to step CM. + + 4. Fail. + + U. Examine the tag field of the opcode structure, in case this is + one of the six instructions with its conditional infix in an + unusual place. If it is, the tag tells us where to find the + infix; look it up in the conditions table and set inst.cond + accordingly. Otherwise, this is an unconditional instruction. + Again set inst.cond accordingly. Return the opcode structure. + + CE. Examine the tag field to make sure this is an instruction that + should receive a conditional suffix. If it is not, fail. + Otherwise, set inst.cond from the suffix we already looked up, + and return the opcode structure. + + CM. Examine the tag field to make sure this is an instruction that + should receive a conditional infix after the third character. + If it is not, fail. Otherwise, undo the edits to the current + line of input and proceed as for case CE. */ + +static const struct asm_opcode * +opcode_lookup (char **str) +{ + char *end, *base; + char *affix; + const struct asm_opcode *opcode; + const struct asm_cond *cond; + + /* Scan up to the end of the mnemonic, which must end in white space, + '.' (in unified mode only), or end of string. */ + for (base = end = *str; *end != '\0'; end++) + if (*end == ' ' || (unified_syntax && *end == '.')) + break; - inst.instruction |= imm; - end_of_line (str); -} + if (end == base) + return 0; -static void -do_mav_shift_1 (char * str) -{ - do_mav_shift (str, REG_TYPE_MVFX, REG_TYPE_MVFX); -} + /* Handle a possible width suffix. */ + if (end[0] == '.') + { + if (end[1] == 'w' && (end[2] == ' ' || end[2] == '\0')) + inst.size_req = 4; + else if (end[1] == 'n' && (end[2] == ' ' || end[2] == '\0')) + inst.size_req = 2; + else + return 0; -static void -do_mav_shift_2 (char * str) -{ - do_mav_shift (str, REG_TYPE_MVDX, REG_TYPE_MVDX); -} + *str = end + 2; + } + else + *str = end; -static int -mav_parse_offset (char ** str, int * negative) -{ - char * p = *str; - int offset; + /* Look for unaffixed or special-case affixed mnemonic. */ + opcode = hash_find_n (arm_ops_hsh, base, end - base); + if (opcode) + { + /* step U */ + if (opcode->tag < OT_odd_infix_0) + { + inst.cond = COND_ALWAYS; + return opcode; + } - *negative = 0; + if (unified_syntax) + as_warn (_("conditional infixes are deprecated in unified syntax")); + affix = base + (opcode->tag - OT_odd_infix_0); + cond = hash_find_n (arm_cond_hsh, affix, 2); + assert (cond); - skip_whitespace (p); + inst.cond = cond->value; + return opcode; + } - if (*p == '#') - ++p; + /* Cannot have a conditional suffix on a mnemonic of less than two + characters. */ + if (end - base < 3) + return 0; - if (*p == '-') - { - *negative = 1; - ++p; - } + /* Look for suffixed mnemonic. */ + affix = end - 2; + cond = hash_find_n (arm_cond_hsh, affix, 2); + opcode = hash_find_n (arm_ops_hsh, base, affix - base); + if (opcode && cond) + { + /* step CE */ + switch (opcode->tag) + { + case OT_cinfix3: + case OT_odd_infix_unc: + if (!unified_syntax) + return 0; + /* else fall through */ + + case OT_csuffix: + case OT_csuf_or_in3: + inst.cond = cond->value; + return opcode; + + case OT_unconditional: + case OT_unconditionalF: + /* delayed diagnostic */ + inst.error = BAD_COND; + inst.cond = COND_ALWAYS; + return opcode; - if (!ISDIGIT (*p)) - { - inst.error = _("offset expected"); - return 0; + default: + return 0; + } } - for (offset = 0; *p && ISDIGIT (*p); ++p) - offset = offset * 10 + *p - '0'; + /* Cannot have a usual-position infix on a mnemonic of less than + six characters (five would be a suffix). */ + if (end - base < 6) + return 0; - if (offset > 0x3fc) + /* Look for infixed mnemonic in the usual position. */ + affix = base + 3; + cond = hash_find_n (arm_cond_hsh, affix, 2); + if (cond) { - inst.error = _("offset out of range"); - return 0; + char save[2]; + memcpy (save, affix, 2); + memmove (affix, affix + 2, (end - affix) - 2); + opcode = hash_find_n (arm_ops_hsh, base, (end - base) - 2); + memmove (affix + 2, affix, (end - affix) - 2); + memcpy (affix, save, 2); } - if (offset & 0x3) + if (opcode && (opcode->tag == OT_cinfix3 || opcode->tag == OT_csuf_or_in3)) { - inst.error = _("offset not a multiple of 4"); - return 0; - } + /* step CM */ + if (unified_syntax) + as_warn (_("conditional infixes are deprecated in unified syntax")); - *str = p; + inst.cond = cond->value; + return opcode; + } - return *negative ? -offset : offset; + return 0; } -/* Maverick load/store instructions. - <insn><cond> CRd,[Rn,<offset>]{!}. - <insn><cond> CRd,[Rn],<offset>. */ - -static void -do_mav_ldst (char * str, enum arm_reg_type reg0) +void +md_assemble (char *str) { - int offset, negative; + char *p = str; + const struct asm_opcode * opcode; - skip_whitespace (str); + /* Align the previous label if needed. */ + if (last_label_seen != NULL) + { + symbol_set_frag (last_label_seen, frag_now); + S_SET_VALUE (last_label_seen, (valueT) frag_now_fix ()); + S_SET_SEGMENT (last_label_seen, now_seg); + } - if (mav_reg_required_here (&str, 12, reg0) == FAIL - || skip_past_comma (&str) == FAIL - || *str++ != '[' - || reg_required_here (&str, 16) == FAIL) - goto fail_ldst; + memset (&inst, '\0', sizeof (inst)); + inst.reloc.type = BFD_RELOC_UNUSED; - if (skip_past_comma (&str) == SUCCESS) + opcode = opcode_lookup (&p); + if (!opcode) { - /* You are here: "<offset>]{!}". */ - inst.instruction |= PRE_INDEX; - - offset = mav_parse_offset (&str, &negative); + /* It wasn't an instruction, but it might be a register alias of + the form alias .req reg. */ + if (!create_register_alias (str, p)) + as_bad (_("bad instruction `%s'"), str); - if (inst.error) - return; + return; + } - if (*str++ != ']') + if (thumb_mode) + { + /* Check that this instruction is supported for this CPU. */ + if (thumb_mode == 1 && (opcode->tvariant & cpu_variant) == 0) { - inst.error = _("missing ]"); + as_bad (_("selected processor does not support `%s'"), str); return; } + if (inst.cond != COND_ALWAYS && !unified_syntax + && opcode->tencode != do_t_branch) + { + as_bad (_("Thumb does not support conditional execution")); + return; + } + + mapping_state (MAP_THUMB); + inst.instruction = opcode->tvalue; + + if (!parse_operands (p, opcode->operands)) + opcode->tencode (); - if (*str == '!') + if (!inst.error) { - inst.instruction |= WRITE_BACK; - ++str; + assert (inst.instruction < 0xe800 || inst.instruction > 0xffff); + inst.size = (inst.instruction > 0xffff ? 4 : 2); + if (inst.size_req && inst.size_req != inst.size) + { + as_bad (_("cannot honor width suffix -- `%s'"), str); + return; + } } } else { - /* You are here: "], <offset>". */ - if (*str++ != ']') + /* Check that this instruction is supported for this CPU. */ + if ((opcode->avariant & cpu_variant) == 0) { - inst.error = _("missing ]"); + as_bad (_("selected processor does not support `%s'"), str); + return; + } + if (inst.size_req) + { + as_bad (_("width suffixes are invalid in ARM mode -- `%s'"), str); return; } - if (skip_past_comma (&str) == FAIL - || (offset = mav_parse_offset (&str, &negative), inst.error)) - goto fail_ldst; - - inst.instruction |= CP_T_WB; /* Post indexed, set bit W. */ + mapping_state (MAP_ARM); + inst.instruction = opcode->avalue; + if (opcode->tag == OT_unconditionalF) + inst.instruction |= 0xF << 28; + else + inst.instruction |= inst.cond << 28; + inst.size = INSN_SIZE; + if (!parse_operands (p, opcode->operands)) + opcode->aencode (); } - - if (negative) - offset = -offset; - else - inst.instruction |= CP_T_UD; /* Positive, so set bit U. */ - - inst.instruction |= offset >> 2; - end_of_line (str); - return; - -fail_ldst: - if (!inst.error) - inst.error = BAD_ARGS; + output_inst (str); } -static void -do_mav_ldst_1 (char * str) -{ - do_mav_ldst (str, REG_TYPE_MVF); -} +/* Various frobbings of labels and their addresses. */ -static void -do_mav_ldst_2 (char * str) +void +arm_start_line_hook (void) { - do_mav_ldst (str, REG_TYPE_MVD); + last_label_seen = NULL; } -static void -do_mav_ldst_3 (char * str) +void +arm_frob_label (symbolS * sym) { - do_mav_ldst (str, REG_TYPE_MVFX); -} + last_label_seen = sym; -static void -do_mav_ldst_4 (char * str) -{ - do_mav_ldst (str, REG_TYPE_MVDX); -} + ARM_SET_THUMB (sym, thumb_mode); -static void -do_t_nop (char * str) -{ - /* Do nothing. */ - end_of_line (str); -} +#if defined OBJ_COFF || defined OBJ_ELF + ARM_SET_INTERWORK (sym, support_interwork); +#endif -/* Handle the Format 4 instructions that do not have equivalents in other - formats. That is, ADC, AND, EOR, SBC, ROR, TST, NEG, CMN, ORR, MUL, - BIC and MVN. */ + /* Note - do not allow local symbols (.Lxxx) to be labeled + as Thumb functions. This is because these labels, whilst + they exist inside Thumb code, are not the entry points for + possible ARM->Thumb calls. Also, these labels can be used + as part of a computed goto or switch statement. eg gcc + can generate code that looks like this: -static void -do_t_arit (char * str) -{ - int Rd, Rs, Rn; + ldr r2, [pc, .Laaa] + lsl r3, r3, #2 + ldr r2, [r3, r2] + mov pc, r2 - skip_whitespace (str); + .Lbbb: .word .Lxxx + .Lccc: .word .Lyyy + ..etc... + .Laaa: .word Lbbb - if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL - || skip_past_comma (&str) == FAIL - || (Rs = thumb_reg (&str, THUMB_REG_LO)) == FAIL) - { - inst.error = BAD_ARGS; - return; - } + The first instruction loads the address of the jump table. + The second instruction converts a table index into a byte offset. + The third instruction gets the jump address out of the table. + The fourth instruction performs the jump. - if (skip_past_comma (&str) != FAIL) + If the address stored at .Laaa is that of a symbol which has the + Thumb_Func bit set, then the linker will arrange for this address + to have the bottom bit set, which in turn would mean that the + address computation performed by the third instruction would end + up with the bottom bit set. Since the ARM is capable of unaligned + word loads, the instruction would then load the incorrect address + out of the jump table, and chaos would ensue. */ + if (label_is_thumb_function_name + && (S_GET_NAME (sym)[0] != '.' || S_GET_NAME (sym)[1] != 'L') + && (bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0) { - /* Three operand format not allowed for TST, CMN, NEG and MVN. - (It isn't allowed for CMP either, but that isn't handled by this - function.) */ - if (inst.instruction == T_OPCODE_TST - || inst.instruction == T_OPCODE_CMN - || inst.instruction == T_OPCODE_NEG - || inst.instruction == T_OPCODE_MVN) - { - inst.error = BAD_ARGS; - return; - } + /* When the address of a Thumb function is taken the bottom + bit of that address should be set. This will allow + interworking between Arm and Thumb functions to work + correctly. */ - if ((Rn = thumb_reg (&str, THUMB_REG_LO)) == FAIL) - return; + THUMB_SET_FUNC (sym, 1); - if (Rs != Rd) - { - inst.error = _("dest and source1 must be the same register"); - return; - } - Rs = Rn; + label_is_thumb_function_name = FALSE; } - - if (inst.instruction == T_OPCODE_MUL - && Rs == Rd) - as_tsktsk (_("Rs and Rd must be different in MUL")); - - inst.instruction |= Rd | (Rs << 3); - end_of_line (str); } -static void -do_t_add (char * str) +int +arm_data_in_code (void) { - thumb_add_sub (str, 0); -} + if (thumb_mode && ! strncmp (input_line_pointer + 1, "data:", 5)) + { + *input_line_pointer = '/'; + input_line_pointer += 5; + *input_line_pointer = 0; + return 1; + } -static void -do_t_asr (char * str) -{ - thumb_shift (str, THUMB_ASR); + return 0; } -static void -do_t_branch9 (char * str) +char * +arm_canonicalize_symbol_name (char * name) { - if (my_get_expression (&inst.reloc.exp, &str)) - return; - inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH9; - inst.reloc.pc_rel = 1; - end_of_line (str); -} + int len; -static void -do_t_branch12 (char * str) -{ - if (my_get_expression (&inst.reloc.exp, &str)) - return; - inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH12; - inst.reloc.pc_rel = 1; - end_of_line (str); + if (thumb_mode && (len = strlen (name)) > 5 + && streq (name + len - 5, "/data")) + *(name + len - 5) = 0; + + return name; } + +/* Table of all register names defined by default. The user can + define additional names with .req. Note that all register names + should appear in both upper and lowercase variants. Some registers + also have mixed-case names. */ -/* Find the real, Thumb encoded start of a Thumb function. */ +#define REGDEF(s,n,t) { #s, n, REG_TYPE_##t, TRUE } +#define REGNUM(p,n,t) REGDEF(p##n, n, t) +#define REGSET(p,t) \ + REGNUM(p, 0,t), REGNUM(p, 1,t), REGNUM(p, 2,t), REGNUM(p, 3,t), \ + REGNUM(p, 4,t), REGNUM(p, 5,t), REGNUM(p, 6,t), REGNUM(p, 7,t), \ + REGNUM(p, 8,t), REGNUM(p, 9,t), REGNUM(p,10,t), REGNUM(p,11,t), \ + REGNUM(p,12,t), REGNUM(p,13,t), REGNUM(p,14,t), REGNUM(p,15,t) -static symbolS * -find_real_start (symbolS * symbolP) +static const struct reg_entry reg_names[] = { - char * real_start; - const char * name = S_GET_NAME (symbolP); - symbolS * new_target; - - /* This definition must agree with the one in gcc/config/arm/thumb.c. */ -#define STUB_NAME ".real_start_of" - - if (name == NULL) - abort (); + /* ARM integer registers. */ + REGSET(r, RN), REGSET(R, RN), - /* Names that start with '.' are local labels, not function entry points. - The compiler may generate BL instructions to these labels because it - needs to perform a branch to a far away location. */ - if (name[0] == '.') - return symbolP; + /* ATPCS synonyms. */ + REGDEF(a1,0,RN), REGDEF(a2,1,RN), REGDEF(a3, 2,RN), REGDEF(a4, 3,RN), + REGDEF(v1,4,RN), REGDEF(v2,5,RN), REGDEF(v3, 6,RN), REGDEF(v4, 7,RN), + REGDEF(v5,8,RN), REGDEF(v6,9,RN), REGDEF(v7,10,RN), REGDEF(v8,11,RN), - real_start = malloc (strlen (name) + strlen (STUB_NAME) + 1); - sprintf (real_start, "%s%s", STUB_NAME, name); + REGDEF(A1,0,RN), REGDEF(A2,1,RN), REGDEF(A3, 2,RN), REGDEF(A4, 3,RN), + REGDEF(V1,4,RN), REGDEF(V2,5,RN), REGDEF(V3, 6,RN), REGDEF(V4, 7,RN), + REGDEF(V5,8,RN), REGDEF(V6,9,RN), REGDEF(V7,10,RN), REGDEF(V8,11,RN), - new_target = symbol_find (real_start); + /* Well-known aliases. */ + REGDEF(wr, 7,RN), REGDEF(sb, 9,RN), REGDEF(sl,10,RN), REGDEF(fp,11,RN), + REGDEF(ip,12,RN), REGDEF(sp,13,RN), REGDEF(lr,14,RN), REGDEF(pc,15,RN), + + REGDEF(WR, 7,RN), REGDEF(SB, 9,RN), REGDEF(SL,10,RN), REGDEF(FP,11,RN), + REGDEF(IP,12,RN), REGDEF(SP,13,RN), REGDEF(LR,14,RN), REGDEF(PC,15,RN), + + /* Coprocessor numbers. */ + REGSET(p, CP), REGSET(P, CP), + + /* Coprocessor register numbers. The "cr" variants are for backward + compatibility. */ + REGSET(c, CN), REGSET(C, CN), + REGSET(cr, CN), REGSET(CR, CN), + + /* FPA registers. */ + REGNUM(f,0,FN), REGNUM(f,1,FN), REGNUM(f,2,FN), REGNUM(f,3,FN), + REGNUM(f,4,FN), REGNUM(f,5,FN), REGNUM(f,6,FN), REGNUM(f,7, FN), + + REGNUM(F,0,FN), REGNUM(F,1,FN), REGNUM(F,2,FN), REGNUM(F,3,FN), + REGNUM(F,4,FN), REGNUM(F,5,FN), REGNUM(F,6,FN), REGNUM(F,7, FN), + + /* VFP SP registers. */ + REGSET(s,VFS), + REGNUM(s,16,VFS), REGNUM(s,17,VFS), REGNUM(s,18,VFS), REGNUM(s,19,VFS), + REGNUM(s,20,VFS), REGNUM(s,21,VFS), REGNUM(s,22,VFS), REGNUM(s,23,VFS), + REGNUM(s,24,VFS), REGNUM(s,25,VFS), REGNUM(s,26,VFS), REGNUM(s,27,VFS), + REGNUM(s,28,VFS), REGNUM(s,29,VFS), REGNUM(s,30,VFS), REGNUM(s,31,VFS), + + REGSET(S,VFS), + REGNUM(S,16,VFS), REGNUM(S,17,VFS), REGNUM(S,18,VFS), REGNUM(S,19,VFS), + REGNUM(S,20,VFS), REGNUM(S,21,VFS), REGNUM(S,22,VFS), REGNUM(S,23,VFS), + REGNUM(S,24,VFS), REGNUM(S,25,VFS), REGNUM(S,26,VFS), REGNUM(S,27,VFS), + REGNUM(S,28,VFS), REGNUM(S,29,VFS), REGNUM(S,30,VFS), REGNUM(S,31,VFS), + + /* VFP DP Registers. */ + REGSET(d,VFD), REGSET(D,VFS), + + /* VFP control registers. */ + REGDEF(fpsid,0,VFC), REGDEF(fpscr,1,VFC), REGDEF(fpexc,8,VFC), + REGDEF(FPSID,0,VFC), REGDEF(FPSCR,1,VFC), REGDEF(FPEXC,8,VFC), + + /* Maverick DSP coprocessor registers. */ + REGSET(mvf,MVF), REGSET(mvd,MVD), REGSET(mvfx,MVFX), REGSET(mvdx,MVDX), + REGSET(MVF,MVF), REGSET(MVD,MVD), REGSET(MVFX,MVFX), REGSET(MVDX,MVDX), + + REGNUM(mvax,0,MVAX), REGNUM(mvax,1,MVAX), + REGNUM(mvax,2,MVAX), REGNUM(mvax,3,MVAX), + REGDEF(dspsc,0,DSPSC), + + REGNUM(MVAX,0,MVAX), REGNUM(MVAX,1,MVAX), + REGNUM(MVAX,2,MVAX), REGNUM(MVAX,3,MVAX), + REGDEF(DSPSC,0,DSPSC), + + /* iWMMXt data registers - p0, c0-15. */ + REGSET(wr,MMXWR), REGSET(wR,MMXWR), REGSET(WR, MMXWR), + + /* iWMMXt control registers - p1, c0-3. */ + REGDEF(wcid, 0,MMXWC), REGDEF(wCID, 0,MMXWC), REGDEF(WCID, 0,MMXWC), + REGDEF(wcon, 1,MMXWC), REGDEF(wCon, 1,MMXWC), REGDEF(WCON, 1,MMXWC), + REGDEF(wcssf, 2,MMXWC), REGDEF(wCSSF, 2,MMXWC), REGDEF(WCSSF, 2,MMXWC), + REGDEF(wcasf, 3,MMXWC), REGDEF(wCASF, 3,MMXWC), REGDEF(WCASF, 3,MMXWC), + + /* iWMMXt scalar (constant/offset) registers - p1, c8-11. */ + REGDEF(wcgr0, 8,MMXWCG), REGDEF(wCGR0, 8,MMXWCG), REGDEF(WCGR0, 8,MMXWCG), + REGDEF(wcgr1, 9,MMXWCG), REGDEF(wCGR1, 9,MMXWCG), REGDEF(WCGR1, 9,MMXWCG), + REGDEF(wcgr2,10,MMXWCG), REGDEF(wCGR2,10,MMXWCG), REGDEF(WCGR2,10,MMXWCG), + REGDEF(wcgr3,11,MMXWCG), REGDEF(wCGR3,11,MMXWCG), REGDEF(WCGR3,11,MMXWCG), + + /* XScale accumulator registers. */ + REGNUM(acc,0,XSCALE), REGNUM(ACC,0,XSCALE), +}; +#undef REGDEF +#undef REGNUM +#undef REGSET - if (new_target == NULL) - { - as_warn ("Failed to find real start of function: %s\n", name); - new_target = symbolP; - } +/* Table of all PSR suffixes. Bare "CPSR" and "SPSR" are handled + within psr_required_here. */ +static const struct asm_psr psrs[] = +{ + /* Backward compatibility notation. Note that "all" is no longer + truly all possible PSR bits. */ + {"all", PSR_c | PSR_f}, + {"flg", PSR_f}, + {"ctl", PSR_c}, + + /* Individual flags. */ + {"f", PSR_f}, + {"c", PSR_c}, + {"x", PSR_x}, + {"s", PSR_s}, + /* Combinations of flags. */ + {"fs", PSR_f | PSR_s}, + {"fx", PSR_f | PSR_x}, + {"fc", PSR_f | PSR_c}, + {"sf", PSR_s | PSR_f}, + {"sx", PSR_s | PSR_x}, + {"sc", PSR_s | PSR_c}, + {"xf", PSR_x | PSR_f}, + {"xs", PSR_x | PSR_s}, + {"xc", PSR_x | PSR_c}, + {"cf", PSR_c | PSR_f}, + {"cs", PSR_c | PSR_s}, + {"cx", PSR_c | PSR_x}, + {"fsx", PSR_f | PSR_s | PSR_x}, + {"fsc", PSR_f | PSR_s | PSR_c}, + {"fxs", PSR_f | PSR_x | PSR_s}, + {"fxc", PSR_f | PSR_x | PSR_c}, + {"fcs", PSR_f | PSR_c | PSR_s}, + {"fcx", PSR_f | PSR_c | PSR_x}, + {"sfx", PSR_s | PSR_f | PSR_x}, + {"sfc", PSR_s | PSR_f | PSR_c}, + {"sxf", PSR_s | PSR_x | PSR_f}, + {"sxc", PSR_s | PSR_x | PSR_c}, + {"scf", PSR_s | PSR_c | PSR_f}, + {"scx", PSR_s | PSR_c | PSR_x}, + {"xfs", PSR_x | PSR_f | PSR_s}, + {"xfc", PSR_x | PSR_f | PSR_c}, + {"xsf", PSR_x | PSR_s | PSR_f}, + {"xsc", PSR_x | PSR_s | PSR_c}, + {"xcf", PSR_x | PSR_c | PSR_f}, + {"xcs", PSR_x | PSR_c | PSR_s}, + {"cfs", PSR_c | PSR_f | PSR_s}, + {"cfx", PSR_c | PSR_f | PSR_x}, + {"csf", PSR_c | PSR_s | PSR_f}, + {"csx", PSR_c | PSR_s | PSR_x}, + {"cxf", PSR_c | PSR_x | PSR_f}, + {"cxs", PSR_c | PSR_x | PSR_s}, + {"fsxc", PSR_f | PSR_s | PSR_x | PSR_c}, + {"fscx", PSR_f | PSR_s | PSR_c | PSR_x}, + {"fxsc", PSR_f | PSR_x | PSR_s | PSR_c}, + {"fxcs", PSR_f | PSR_x | PSR_c | PSR_s}, + {"fcsx", PSR_f | PSR_c | PSR_s | PSR_x}, + {"fcxs", PSR_f | PSR_c | PSR_x | PSR_s}, + {"sfxc", PSR_s | PSR_f | PSR_x | PSR_c}, + {"sfcx", PSR_s | PSR_f | PSR_c | PSR_x}, + {"sxfc", PSR_s | PSR_x | PSR_f | PSR_c}, + {"sxcf", PSR_s | PSR_x | PSR_c | PSR_f}, + {"scfx", PSR_s | PSR_c | PSR_f | PSR_x}, + {"scxf", PSR_s | PSR_c | PSR_x | PSR_f}, + {"xfsc", PSR_x | PSR_f | PSR_s | PSR_c}, + {"xfcs", PSR_x | PSR_f | PSR_c | PSR_s}, + {"xsfc", PSR_x | PSR_s | PSR_f | PSR_c}, + {"xscf", PSR_x | PSR_s | PSR_c | PSR_f}, + {"xcfs", PSR_x | PSR_c | PSR_f | PSR_s}, + {"xcsf", PSR_x | PSR_c | PSR_s | PSR_f}, + {"cfsx", PSR_c | PSR_f | PSR_s | PSR_x}, + {"cfxs", PSR_c | PSR_f | PSR_x | PSR_s}, + {"csfx", PSR_c | PSR_s | PSR_f | PSR_x}, + {"csxf", PSR_c | PSR_s | PSR_x | PSR_f}, + {"cxfs", PSR_c | PSR_x | PSR_f | PSR_s}, + {"cxsf", PSR_c | PSR_x | PSR_s | PSR_f}, +}; - free (real_start); +/* Table of all shift-in-operand names. */ +static const struct asm_shift_name shift_names [] = +{ + { "asl", SHIFT_LSL }, { "ASL", SHIFT_LSL }, + { "lsl", SHIFT_LSL }, { "LSL", SHIFT_LSL }, + { "lsr", SHIFT_LSR }, { "LSR", SHIFT_LSR }, + { "asr", SHIFT_ASR }, { "ASR", SHIFT_ASR }, + { "ror", SHIFT_ROR }, { "ROR", SHIFT_ROR }, + { "rrx", SHIFT_RRX }, { "RRX", SHIFT_RRX } +}; - return new_target; -} +/* Table of all explicit relocation names. */ +#ifdef OBJ_ELF +static struct reloc_entry reloc_names[] = +{ + { "got", BFD_RELOC_ARM_GOT32 }, { "GOT", BFD_RELOC_ARM_GOT32 }, + { "gotoff", BFD_RELOC_ARM_GOTOFF }, { "GOTOFF", BFD_RELOC_ARM_GOTOFF }, + { "plt", BFD_RELOC_ARM_PLT32 }, { "PLT", BFD_RELOC_ARM_PLT32 }, + { "target1", BFD_RELOC_ARM_TARGET1 }, { "TARGET1", BFD_RELOC_ARM_TARGET1 }, + { "target2", BFD_RELOC_ARM_TARGET2 }, { "TARGET2", BFD_RELOC_ARM_TARGET2 }, + { "sbrel", BFD_RELOC_ARM_SBREL32 }, { "SBREL", BFD_RELOC_ARM_SBREL32 }, + { "tlsgd", BFD_RELOC_ARM_TLS_GD32}, { "TLSGD", BFD_RELOC_ARM_TLS_GD32}, + { "tlsldm", BFD_RELOC_ARM_TLS_LDM32}, { "TLSLDM", BFD_RELOC_ARM_TLS_LDM32}, + { "tlsldo", BFD_RELOC_ARM_TLS_LDO32}, { "TLSLDO", BFD_RELOC_ARM_TLS_LDO32}, + { "gottpoff",BFD_RELOC_ARM_TLS_IE32}, { "GOTTPOFF",BFD_RELOC_ARM_TLS_IE32}, + { "tpoff", BFD_RELOC_ARM_TLS_LE32}, { "TPOFF", BFD_RELOC_ARM_TLS_LE32} +}; +#endif -static void -do_t_branch23 (char * str) +/* Table of all conditional affixes. 0xF is not defined as a condition code. */ +static const struct asm_cond conds[] = { - if (my_get_expression (& inst.reloc.exp, & str)) - return; - - inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH23; - inst.reloc.pc_rel = 1; - end_of_line (str); + {"eq", 0x0}, + {"ne", 0x1}, + {"cs", 0x2}, {"hs", 0x2}, + {"cc", 0x3}, {"ul", 0x3}, {"lo", 0x3}, + {"mi", 0x4}, + {"pl", 0x5}, + {"vs", 0x6}, + {"vc", 0x7}, + {"hi", 0x8}, + {"ls", 0x9}, + {"ge", 0xa}, + {"lt", 0xb}, + {"gt", 0xc}, + {"le", 0xd}, + {"al", 0xe} +}; - /* If the destination of the branch is a defined symbol which does not have - the THUMB_FUNC attribute, then we must be calling a function which has - the (interfacearm) attribute. We look for the Thumb entry point to that - function and change the branch to refer to that function instead. */ - if ( inst.reloc.exp.X_op == O_symbol - && inst.reloc.exp.X_add_symbol != NULL - && S_IS_DEFINED (inst.reloc.exp.X_add_symbol) - && ! THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol)) - inst.reloc.exp.X_add_symbol = - find_real_start (inst.reloc.exp.X_add_symbol); -} +/* Table of ARM-format instructions. */ + +/* Macros for gluing together operand strings. N.B. In all cases + other than OPS0, the trailing OP_stop comes from default + zero-initialization of the unspecified elements of the array. */ +#define OPS0() { OP_stop, } +#define OPS1(a) { OP_##a, } +#define OPS2(a,b) { OP_##a,OP_##b, } +#define OPS3(a,b,c) { OP_##a,OP_##b,OP_##c, } +#define OPS4(a,b,c,d) { OP_##a,OP_##b,OP_##c,OP_##d, } +#define OPS5(a,b,c,d,e) { OP_##a,OP_##b,OP_##c,OP_##d,OP_##e, } +#define OPS6(a,b,c,d,e,f) { OP_##a,OP_##b,OP_##c,OP_##d,OP_##e,OP_##f, } + +/* These macros abstract out the exact format of the mnemonic table and + save some repeated characters. */ + +/* The normal sort of mnemonic; has a Thumb variant; takes a conditional suffix. */ +#define TxCE(mnem, op, top, nops, ops, ae, te) \ + { #mnem, OPS##nops ops, OT_csuffix, 0x##op, top, ARM_VARIANT, \ + do_##te ? THUMB_VARIANT : 0, do_##ae, do_##te } + +/* Two variants of the above - TCE for a numeric Thumb opcode, tCE for + a T_MNEM_xyz enumerator. */ +#define TCE(mnem, aop, top, nops, ops, ae, te) \ + TxCE(mnem, aop, 0x##top, nops, ops, ae, te) +#define tCE(mnem, aop, top, nops, ops, ae, te) \ + TxCE(mnem, aop, T_MNEM_##top, nops, ops, ae, te) + +/* Second most common sort of mnemonic: has a Thumb variant, takes a conditional + infix after the third character. */ +#define TxC3(mnem, op, top, nops, ops, ae, te) \ + { #mnem, OPS##nops ops, OT_cinfix3, 0x##op, top, ARM_VARIANT, \ + do_##te ? THUMB_VARIANT : 0, do_##ae, do_##te } +#define TC3(mnem, aop, top, nops, ops, ae, te) \ + TxC3(mnem, aop, 0x##top, nops, ops, ae, te) +#define tC3(mnem, aop, top, nops, ops, ae, te) \ + TxC3(mnem, aop, T_MNEM_##top, nops, ops, ae, te) + +/* Mnemonic with a conditional infix in an unusual place. Each and every variant has to + appear in the condition table. */ +#define TxCM_(m1, m2, m3, op, top, nops, ops, ae, te) \ + { #m1 #m2 #m3, OPS##nops ops, sizeof(#m2) == 1 ? OT_odd_infix_unc : OT_odd_infix_0 + sizeof(#m1) - 1, \ + 0x##op, top, ARM_VARIANT, do_##te ? THUMB_VARIANT : 0, do_##ae, do_##te } + +#define TxCM(m1, m2, op, top, nops, ops, ae, te) \ + TxCM_(m1, , m2, op, top, nops, ops, ae, te), \ + TxCM_(m1, eq, m2, op, top, nops, ops, ae, te), \ + TxCM_(m1, ne, m2, op, top, nops, ops, ae, te), \ + TxCM_(m1, cs, m2, op, top, nops, ops, ae, te), \ + TxCM_(m1, hs, m2, op, top, nops, ops, ae, te), \ + TxCM_(m1, cc, m2, op, top, nops, ops, ae, te), \ + TxCM_(m1, ul, m2, op, top, nops, ops, ae, te), \ + TxCM_(m1, lo, m2, op, top, nops, ops, ae, te), \ + TxCM_(m1, mi, m2, op, top, nops, ops, ae, te), \ + TxCM_(m1, pl, m2, op, top, nops, ops, ae, te), \ + TxCM_(m1, vs, m2, op, top, nops, ops, ae, te), \ + TxCM_(m1, vc, m2, op, top, nops, ops, ae, te), \ + TxCM_(m1, hi, m2, op, top, nops, ops, ae, te), \ + TxCM_(m1, ls, m2, op, top, nops, ops, ae, te), \ + TxCM_(m1, ge, m2, op, top, nops, ops, ae, te), \ + TxCM_(m1, lt, m2, op, top, nops, ops, ae, te), \ + TxCM_(m1, gt, m2, op, top, nops, ops, ae, te), \ + TxCM_(m1, le, m2, op, top, nops, ops, ae, te), \ + TxCM_(m1, al, m2, op, top, nops, ops, ae, te) + +#define TCM(m1,m2, aop, top, nops, ops, ae, te) \ + TxCM(m1,m2, aop, 0x##top, nops, ops, ae, te) +#define tCM(m1,m2, aop, top, nops, ops, ae, te) \ + TxCM(m1,m2, aop, T_MNEM_##top, nops, ops, ae, te) + +/* Mnemonic that cannot be conditionalized. The ARM condition-code + field is still 0xE. */ +#define TUE(mnem, op, top, nops, ops, ae, te) \ + { #mnem, OPS##nops ops, OT_unconditional, 0x##op, 0x##top, ARM_VARIANT, \ + do_##te ? THUMB_VARIANT : 0, do_##ae, do_##te } + +/* Mnemonic that cannot be conditionalized, and bears 0xF in its ARM + condition code field. */ +#define TUF(mnem, op, top, nops, ops, ae, te) \ + { #mnem, OPS##nops ops, OT_unconditionalF, 0x##op, 0x##top, ARM_VARIANT, \ + do_##te ? THUMB_VARIANT : 0, do_##ae, do_##te } + +/* ARM-only variants of all the above. */ +#define CE(mnem, op, nops, ops, ae) TCE(mnem, op, 0, nops, ops, ae, 0) +#define C3(mnem, op, nops, ops, ae) TC3(mnem, op, 0, nops, ops, ae, 0) +#define CM(m1,m2, op, nops, ops, ae) TCM(m1,m2, op, 0, nops, ops, ae, 0) +#define UE(mnem, op, nops, ops, ae) TUE(mnem, op, 0, nops, ops, ae, 0) +#define UF(mnem, op, nops, ops, ae) TUF(mnem, op, 0, nops, ops, ae, 0) +#define do_0 0 + +/* Thumb-only, unconditional. */ +#define UT(mnem, op, nops, ops, te) TUE(mnem, 0, op, nops, ops, 0, te) + +/* ARM-only, takes either a suffix or a position-3 infix + (for an FPA corner case). */ +#define C3E(mnem, op, nops, ops, ae) \ + { #mnem, OPS##nops ops, OT_csuf_or_in3, 0x##op, 0, ARM_VARIANT, 0, do_##ae, 0 } -static void -do_t_bx (char * str) +static const struct asm_opcode insns[] = { - int reg; +#define ARM_VARIANT ARM_EXT_V1 /* Core ARM Instructions. */ +#define THUMB_VARIANT ARM_EXT_V4T + tCE(and, 0000000, and, 3, (RR, oRR, SH), arit, t_arit3c), + tC3(ands, 0100000, ands, 3, (RR, oRR, SH), arit, t_arit3c), + tCE(eor, 0200000, eor, 3, (RR, oRR, SH), arit, t_arit3c), + tC3(eors, 0300000, eors, 3, (RR, oRR, SH), arit, t_arit3c), + tCE(sub, 0400000, sub, 3, (RR, oRR, SH), arit, t_add_sub), + tC3(subs, 0500000, subs, 3, (RR, oRR, SH), arit, t_add_sub), + tCE(add, 0800000, add, 3, (RR, oRR, SH), arit, t_add_sub), + tC3(adds, 0900000, adds, 3, (RR, oRR, SH), arit, t_add_sub), + tCE(adc, 0a00000, adc, 3, (RR, oRR, SH), arit, t_arit3c), + tC3(adcs, 0b00000, adcs, 3, (RR, oRR, SH), arit, t_arit3c), + tCE(sbc, 0c00000, sbc, 3, (RR, oRR, SH), arit, t_arit3), + tC3(sbcs, 0d00000, sbcs, 3, (RR, oRR, SH), arit, t_arit3), + tCE(orr, 1800000, orr, 3, (RR, oRR, SH), arit, t_arit3c), + tC3(orrs, 1900000, orrs, 3, (RR, oRR, SH), arit, t_arit3c), + tCE(bic, 1c00000, bic, 3, (RR, oRR, SH), arit, t_arit3), + tC3(bics, 1d00000, bics, 3, (RR, oRR, SH), arit, t_arit3), + + /* The p-variants of tst/cmp/cmn/teq (below) are the pre-V6 mechanism + for setting PSR flag bits. They are obsolete in V6 and do not + have Thumb equivalents. */ + tCE(tst, 1100000, tst, 2, (RR, SH), cmp, t_mvn_tst), + tC3(tsts, 1100000, tst, 2, (RR, SH), cmp, t_mvn_tst), + C3(tstp, 110f000, 2, (RR, SH), cmp), + tCE(cmp, 1500000, cmp, 2, (RR, SH), cmp, t_mov_cmp), + tC3(cmps, 1500000, cmp, 2, (RR, SH), cmp, t_mov_cmp), + C3(cmpp, 150f000, 2, (RR, SH), cmp), + tCE(cmn, 1700000, cmn, 2, (RR, SH), cmp, t_mvn_tst), + tC3(cmns, 1700000, cmn, 2, (RR, SH), cmp, t_mvn_tst), + C3(cmnp, 170f000, 2, (RR, SH), cmp), + + tCE(mov, 1a00000, mov, 2, (RR, SH), mov, t_mov_cmp), + tC3(movs, 1b00000, movs, 2, (RR, SH), mov, t_mov_cmp), + tCE(mvn, 1e00000, mvn, 2, (RR, SH), mov, t_mvn_tst), + tC3(mvns, 1f00000, mvns, 2, (RR, SH), mov, t_mvn_tst), + + tCE(ldr, 4100000, ldr, 2, (RR, ADDR), ldst, t_ldst), + tC3(ldrb, 4500000, ldrb, 2, (RR, ADDR), ldst, t_ldst), + tCE(str, 4000000, str, 2, (RR, ADDR), ldst, t_ldst), + tC3(strb, 4400000, strb, 2, (RR, ADDR), ldst, t_ldst), + + tC3(stmia, 8800000, stmia, 2, (RRw, REGLST), ldmstm, t_ldmstm), + tC3(stmea, 8800000, stmia, 2, (RRw, REGLST), ldmstm, t_ldmstm), + tC3(ldmia, 8900000, ldmia, 2, (RRw, REGLST), ldmstm, t_ldmstm), + 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 - skip_whitespace (str); + /* 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), + + /* Thumb-compatibility pseudo ops. */ + tCE(lsl, 1a00000, lsl, 3, (RR, oRR, SH), shift, t_shift), + tC3(lsls, 1b00000, lsls, 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), + 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), + tC3(negs, 2700000, negs, 2, (RR, RR), rd_rn, t_neg), + tCE(push, 92d0000, push, 1, (REGLST), push_pop, t_push_pop), + tCE(pop, 8bd0000, pop, 1, (REGLST), push_pop, t_push_pop), + +#undef THUMB_VARIANT +#define THUMB_VARIANT ARM_EXT_V6 + TCE(cpy, 1a00000, 4600, 2, (RR, RR), rd_rm, t_cpy), + + /* V1 instructions with no Thumb analogue prior to V6T2. */ +#undef THUMB_VARIANT +#define THUMB_VARIANT ARM_EXT_V6T2 + TCE(rsb, 0600000, ebc00000, 3, (RR, oRR, SH), arit, t_rsb), + TC3(rsbs, 0700000, ebd00000, 3, (RR, oRR, SH), arit, t_rsb), + TCE(teq, 1300000, ea900f00, 2, (RR, SH), cmp, t_mvn_tst), + TC3(teqs, 1300000, ea900f00, 2, (RR, SH), cmp, t_mvn_tst), + C3(teqp, 130f000, 2, (RR, SH), cmp), + + TC3(ldrt, 4300000, f8500e00, 2, (RR, ADDR), ldstt, t_ldstt), + TC3(ldrbt, 4700000, f8300e00, 2, (RR, ADDR), ldstt, t_ldstt), + 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(ldmdb, 9100000, e9000000, 2, (RRw, REGLST), ldmstm, t_ldmstm), + TC3(ldmea, 9100000, e9000000, 2, (RRw, REGLST), ldmstm, t_ldmstm), + + /* V1 instructions with no Thumb analogue at all. */ + CE(rsc, 0e00000, 3, (RR, oRR, SH), arit), + C3(rscs, 0f00000, 3, (RR, oRR, SH), arit), + + C3(stmib, 9800000, 2, (RRw, REGLST), ldmstm), + C3(stmfa, 9800000, 2, (RRw, REGLST), ldmstm), + C3(stmda, 8000000, 2, (RRw, REGLST), ldmstm), + C3(stmed, 8000000, 2, (RRw, REGLST), ldmstm), + C3(ldmib, 9900000, 2, (RRw, REGLST), ldmstm), + C3(ldmed, 9900000, 2, (RRw, REGLST), ldmstm), + C3(ldmda, 8100000, 2, (RRw, REGLST), ldmstm), + C3(ldmfa, 8100000, 2, (RRw, REGLST), ldmstm), + +#undef ARM_VARIANT +#define ARM_VARIANT ARM_EXT_V2 /* ARM 2 - multiplies. */ +#undef THUMB_VARIANT +#define THUMB_VARIANT ARM_EXT_V4T + tCE(mul, 0000090, mul, 3, (RRnpc, RRnpc, oRR), mul, t_mul), + tC3(muls, 0100090, muls, 3, (RRnpc, RRnpc, oRR), mul, t_mul), + +#undef THUMB_VARIANT +#define THUMB_VARIANT ARM_EXT_V6T2 + TCE(mla, 0200090, fb000000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mlas, t_mla), + C3(mlas, 0300090, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mlas), + + /* Generic coprocessor instructions. */ + TCE(cdp, e000000, ee000000, 6, (RCP, I15b, RCN, RCN, RCN, oI7b), cdp, cdp), + TCE(ldc, c100000, ec100000, 3, (RCP, RCN, ADDR), lstc, lstc), + TC3(ldcl, c500000, ec500000, 3, (RCP, RCN, ADDR), lstc, lstc), + TCE(stc, c000000, ec000000, 3, (RCP, RCN, ADDR), lstc, lstc), + TC3(stcl, c400000, ec400000, 3, (RCP, RCN, ADDR), lstc, lstc), + TCE(mcr, e000010, ee000010, 6, (RCP, I7b, RR, RCN, RCN, oI7b), co_reg, co_reg), + TCE(mrc, e100010, ee100010, 6, (RCP, I7b, RR, RCN, RCN, oI7b), co_reg, co_reg), + +#undef ARM_VARIANT +#define ARM_VARIANT ARM_EXT_V2S /* ARM 3 - swp instructions. */ + CE(swp, 1000090, 3, (RRnpc, RRnpc, RRnpcb), rd_rm_rn), + C3(swpb, 1400090, 3, (RRnpc, RRnpc, RRnpcb), rd_rm_rn), + +#undef ARM_VARIANT +#define ARM_VARIANT ARM_EXT_V3 /* ARM 6 Status register instructions. */ + TCE(mrs, 10f0000, f3ef8000, 2, (RR, PSR), mrs, t_mrs), + TCE(msr, 120f000, f3808000, 2, (PSR, RR_EXi), msr, t_msr), + +#undef ARM_VARIANT +#define ARM_VARIANT ARM_EXT_V3M /* ARM 7M long multiplies. */ + TCE(smull, 0c00090, fb800000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull, t_mull), + CM(smull,s, 0d00090, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull), + TCE(umull, 0800090, fba00000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull, t_mull), + CM(umull,s, 0900090, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull), + TCE(smlal, 0e00090, fbc00000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull, t_mull), + CM(smlal,s, 0f00090, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull), + TCE(umlal, 0a00090, fbe00000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull, t_mull), + CM(umlal,s, 0b00090, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull), + +#undef ARM_VARIANT +#define ARM_VARIANT ARM_EXT_V4 /* ARM Architecture 4. */ +#undef THUMB_VARIANT +#define THUMB_VARIANT ARM_EXT_V4T + tC3(ldrh, 01000b0, ldrh, 2, (RR, ADDR), ldstv4, t_ldst), + tC3(strh, 00000b0, strh, 2, (RR, ADDR), ldstv4, t_ldst), + tC3(ldrsh, 01000f0, ldrsh, 2, (RR, ADDR), ldstv4, t_ldst), + tC3(ldrsb, 01000d0, ldrsb, 2, (RR, ADDR), ldstv4, t_ldst), + tCM(ld,sh, 01000f0, ldrsh, 2, (RR, ADDR), ldstv4, t_ldst), + tCM(ld,sb, 01000d0, ldrsb, 2, (RR, ADDR), ldstv4, t_ldst), + +#undef ARM_VARIANT +#define ARM_VARIANT ARM_EXT_V4T|ARM_EXT_V5 + /* ARM Architecture 4T. */ + /* Note: bx (and blx) are required on V5, even if the processor does + not support Thumb. */ + TCE(bx, 12fff10, 4700, 1, (RR), bx, t_bx), + +#undef ARM_VARIANT +#define ARM_VARIANT ARM_EXT_V5 /* ARM Architecture 5T. */ +#undef THUMB_VARIANT +#define THUMB_VARIANT ARM_EXT_V5T + /* Note: blx has 2 variants; the .value coded here is for + BLX(2). Only this variant has conditional execution. */ + TCE(blx, 12fff30, 4780, 1, (RR_EXr), blx, t_blx), + TUE(bkpt, 1200070, be00, 1, (oIffffb), bkpt, t_bkpt), + +#undef THUMB_VARIANT +#define THUMB_VARIANT ARM_EXT_V6T2 + TCE(clz, 16f0f10, fab0f080, 2, (RRnpc, RRnpc), rd_rm, t_clz), + TUF(ldc2, c100000, fc100000, 3, (RCP, RCN, ADDR), lstc, lstc), + TUF(ldc2l, c500000, fc500000, 3, (RCP, RCN, ADDR), lstc, lstc), + TUF(stc2, c000000, fc000000, 3, (RCP, RCN, ADDR), lstc, lstc), + TUF(stc2l, c400000, fc400000, 3, (RCP, RCN, ADDR), lstc, lstc), + TUF(cdp2, e000000, fe000000, 6, (RCP, I15b, RCN, RCN, RCN, oI7b), cdp, cdp), + TUF(mcr2, e000010, fe000010, 6, (RCP, I7b, RR, RCN, RCN, oI7b), co_reg, co_reg), + TUF(mrc2, e100010, fe100010, 6, (RCP, I7b, RR, RCN, RCN, oI7b), co_reg, co_reg), + +#undef ARM_VARIANT +#define ARM_VARIANT ARM_EXT_V5ExP /* ARM Architecture 5TExP. */ + TCE(smlabb, 1000080, fb100000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), smla, t_mla), + TCE(smlatb, 10000a0, fb100020, 4, (RRnpc, RRnpc, RRnpc, RRnpc), smla, t_mla), + TCE(smlabt, 10000c0, fb100010, 4, (RRnpc, RRnpc, RRnpc, RRnpc), smla, t_mla), + TCE(smlatt, 10000e0, fb100030, 4, (RRnpc, RRnpc, RRnpc, RRnpc), smla, t_mla), + + TCE(smlawb, 1200080, fb300000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), smla, t_mla), + TCE(smlawt, 12000c0, fb300010, 4, (RRnpc, RRnpc, RRnpc, RRnpc), smla, t_mla), + + TCE(smlalbb, 1400080, fbc00080, 4, (RRnpc, RRnpc, RRnpc, RRnpc), smlal, t_mlal), + TCE(smlaltb, 14000a0, fbc000a0, 4, (RRnpc, RRnpc, RRnpc, RRnpc), smlal, t_mlal), + TCE(smlalbt, 14000c0, fbc00090, 4, (RRnpc, RRnpc, RRnpc, RRnpc), smlal, t_mlal), + TCE(smlaltt, 14000e0, fbc000b0, 4, (RRnpc, RRnpc, RRnpc, RRnpc), smlal, t_mlal), + + TCE(smulbb, 1600080, fb10f000, 3, (RRnpc, RRnpc, RRnpc), smul, t_simd), + TCE(smultb, 16000a0, fb10f020, 3, (RRnpc, RRnpc, RRnpc), smul, t_simd), + TCE(smulbt, 16000c0, fb10f010, 3, (RRnpc, RRnpc, RRnpc), smul, t_simd), + TCE(smultt, 16000e0, fb10f030, 3, (RRnpc, RRnpc, RRnpc), smul, t_simd), + + TCE(smulwb, 12000a0, fb30f000, 3, (RRnpc, RRnpc, RRnpc), smul, t_simd), + TCE(smulwt, 12000e0, fb30f010, 3, (RRnpc, RRnpc, RRnpc), smul, t_simd), + + TCE(qadd, 1000050, fa80f080, 3, (RRnpc, RRnpc, RRnpc), rd_rm_rn, rd_rm_rn), + TCE(qdadd, 1400050, fa80f090, 3, (RRnpc, RRnpc, RRnpc), rd_rm_rn, rd_rm_rn), + TCE(qsub, 1200050, fa80f0a0, 3, (RRnpc, RRnpc, RRnpc), rd_rm_rn, rd_rm_rn), + TCE(qdsub, 1600050, fa80f0b0, 3, (RRnpc, RRnpc, RRnpc), rd_rm_rn, rd_rm_rn), + +#undef ARM_VARIANT +#define ARM_VARIANT ARM_EXT_V5E /* ARM Architecture 5TE. */ + TUF(pld, 450f000, f810f000, 1, (ADDR), pld, t_pld), + TC3(ldrd, 00000d0, e9500000, 3, (RRnpc, oRRnpc, ADDR), ldrd, t_ldstd), + TC3(strd, 00000f0, e9400000, 3, (RRnpc, oRRnpc, ADDR), ldrd, t_ldstd), + + TCE(mcrr, c400000, ec400000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c), + TCE(mrrc, c500000, ec500000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c), + +#undef ARM_VARIANT +#define ARM_VARIANT ARM_EXT_V5J /* ARM Architecture 5TEJ. */ + TCE(bxj, 12fff20, f3c08f00, 1, (RR), bxj, t_bxj), + +#undef ARM_VARIANT +#define ARM_VARIANT ARM_EXT_V6 /* ARM V6. */ +#undef THUMB_VARIANT +#define THUMB_VARIANT ARM_EXT_V6 + TUF(cpsie, 1080000, b660, 2, (CPSF, oI31b), cpsi, t_cpsi), + TUF(cpsid, 10c0000, b670, 2, (CPSF, oI31b), cpsi, t_cpsi), + tCE(rev, 6bf0f30, rev, 2, (RRnpc, RRnpc), rd_rm, t_rev), + tCE(rev16, 6bf0fb0, rev16, 2, (RRnpc, RRnpc), rd_rm, t_rev), + tCE(revsh, 6ff0fb0, revsh, 2, (RRnpc, RRnpc), rd_rm, t_rev), + tCE(sxth, 6bf0070, sxth, 3, (RRnpc, RRnpc, oROR), sxth, t_sxth), + tCE(uxth, 6ff0070, uxth, 3, (RRnpc, RRnpc, oROR), sxth, t_sxth), + tCE(sxtb, 6af0070, sxtb, 3, (RRnpc, RRnpc, oROR), sxth, t_sxth), + tCE(uxtb, 6ef0070, uxtb, 3, (RRnpc, RRnpc, oROR), sxth, t_sxth), + TUF(setend, 1010000, b650, 1, (ENDI), setend, t_setend), + +#undef THUMB_VARIANT +#define THUMB_VARIANT ARM_EXT_V6T2 + TUF(cps, 1020000, f3af8100, 1, (I31b), imm0, imm0), + TCE(ldrex, 1900f9f, e8500f00, 2, (RRnpc, ADDR), ldrex, t_ldrex), + TUF(mcrr2, c400000, fc400000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c), + TUF(mrrc2, c500000, fc500000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c), + TCE(pkhbt, 6800010, eac00000, 4, (RRnpc, RRnpc, RRnpc, oSHll), pkhbt, t_pkhbt), + TCE(pkhtb, 6800050, eac00020, 4, (RRnpc, RRnpc, RRnpc, oSHar), pkhtb, t_pkhtb), + TCE(qadd16, 6200f10, fa90f010, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(qadd8, 6200f90, fa80f010, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(qaddsubx, 6200f30, faa0f010, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(qsub16, 6200f70, fad0f010, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(qsub8, 6200ff0, fac0f010, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(qsubaddx, 6200f50, fae0f010, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(sadd16, 6100f10, fa90f000, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(sadd8, 6100f90, fa80f000, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(saddsubx, 6100f30, faa0f000, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(shadd16, 6300f10, fa90f020, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(shadd8, 6300f90, fa80f020, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(shaddsubx, 6300f30, faa0f020, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(shsub16, 6300f70, fad0f020, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(shsub8, 6300ff0, fac0f020, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(shsubaddx, 6300f50, fae0f020, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(ssub16, 6100f70, fad0f000, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(ssub8, 6100ff0, fac0f000, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(ssubaddx, 6100f50, fae0f000, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(uadd16, 6500f10, fa90f040, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(uadd8, 6500f90, fa80f040, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(uaddsubx, 6500f30, faa0f040, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(uhadd16, 6700f10, fa90f060, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(uhadd8, 6700f90, fa80f060, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(uhaddsubx, 6700f30, faa0f060, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(uhsub16, 6700f70, fad0f060, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(uhsub8, 6700ff0, fac0f060, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(uhsubaddx, 6700f50, fae0f060, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(uqadd16, 6600f10, fa90f050, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(uqadd8, 6600f90, fa80f050, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(uqaddsubx, 6600f30, faa0f050, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(uqsub16, 6600f70, fad0f050, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(uqsub8, 6600ff0, fac0f050, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(uqsubaddx, 6600f50, fae0f050, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(usub16, 6500f70, fad0f040, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(usub8, 6500ff0, fac0f040, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(usubaddx, 6500f50, fae0f040, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TUF(rfeia, 8900a00, e990c000, 1, (RRw), rfe, rfe), + UF(rfeib, 9900a00, 1, (RRw), rfe), + UF(rfeda, 8100a00, 1, (RRw), rfe), + TUF(rfedb, 9100a00, e810c000, 1, (RRw), rfe, rfe), + TUF(rfefd, 8900a00, e990c000, 1, (RRw), rfe, rfe), + UF(rfefa, 9900a00, 1, (RRw), rfe), + UF(rfeea, 8100a00, 1, (RRw), rfe), + TUF(rfeed, 9100a00, e810c000, 1, (RRw), rfe, rfe), + TCE(sxtah, 6b00070, fa00f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah), + TCE(sxtab16, 6800070, fa20f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah), + TCE(sxtab, 6a00070, fa40f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah), + TCE(sxtb16, 68f0070, fa2ff080, 3, (RRnpc, RRnpc, oROR), sxth, t_sxth), + TCE(uxtah, 6f00070, fa10f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah), + TCE(uxtab16, 6c00070, fa30f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah), + TCE(uxtab, 6e00070, fa50f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah), + TCE(uxtb16, 6cf0070, fa3ff080, 3, (RRnpc, RRnpc, oROR), sxth, t_sxth), + TCE(sel, 68000b0, faa0f080, 3, (RRnpc, RRnpc, RRnpc), rd_rn_rm, t_simd), + TCE(smlad, 7000010, fb200000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla), + TCE(smladx, 7000030, fb200010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla), + TCE(smlald, 7400010, fbc000c0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,t_mlal), + TCE(smlaldx, 7400030, fbc000d0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,t_mlal), + TCE(smlsd, 7000050, fb400000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla), + TCE(smlsdx, 7000070, fb400010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla), + TCE(smlsld, 7400050, fbd000c0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,t_mlal), + TCE(smlsldx, 7400070, fbd000d0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,t_mlal), + TCE(smmla, 7500010, fb500000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla), + TCE(smmlar, 7500030, fb500010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla), + TCE(smmls, 75000d0, fb600000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla), + TCE(smmlsr, 75000f0, fb600010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla), + TCE(smmul, 750f010, fb50f000, 3, (RRnpc, RRnpc, RRnpc), smul, t_simd), + TCE(smmulr, 750f030, fb50f010, 3, (RRnpc, RRnpc, RRnpc), smul, t_simd), + TCE(smuad, 700f010, fb20f000, 3, (RRnpc, RRnpc, RRnpc), smul, t_simd), + TCE(smuadx, 700f030, fb20f010, 3, (RRnpc, RRnpc, RRnpc), smul, t_simd), + TCE(smusd, 700f050, fb40f000, 3, (RRnpc, RRnpc, RRnpc), smul, t_simd), + TCE(smusdx, 700f070, fb40f010, 3, (RRnpc, RRnpc, RRnpc), smul, t_simd), + TUF(srsia, 8cd0500, e980c000, 1, (I31w), srs, srs), + UF(srsib, 9cd0500, 1, (I31w), srs), + UF(srsda, 84d0500, 1, (I31w), srs), + TUF(srsdb, 94d0500, e800c000, 1, (I31w), srs, srs), + TCE(ssat, 6a00010, f3000000, 4, (RRnpc, I32, RRnpc, oSHllar),ssat, t_ssat), + TCE(ssat16, 6a00f30, f3200000, 3, (RRnpc, I16, RRnpc), ssat16, t_ssat16), + TCE(strex, 1800f90, e8400000, 3, (RRnpc, RRnpc, ADDR), strex, t_strex), + TCE(umaal, 0400090, fbe00060, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal, t_mlal), + TCE(usad8, 780f010, fb70f000, 3, (RRnpc, RRnpc, RRnpc), smul, t_simd), + TCE(usada8, 7800010, fb700000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla), + TCE(usat, 6e00010, f3800000, 4, (RRnpc, I31, RRnpc, oSHllar),usat, t_usat), + TCE(usat16, 6e00f30, f3a00000, 3, (RRnpc, I15, RRnpc), usat16, t_usat16), + +#undef ARM_VARIANT +#define ARM_VARIANT ARM_EXT_V6K +#undef THUMB_VARIANT +#define THUMB_VARIANT ARM_EXT_V6K + tCE(yield, 320f001, yield, 0, (), noargs, t_hint), + tCE(wfe, 320f002, wfe, 0, (), noargs, t_hint), + tCE(wfi, 320f003, wfi, 0, (), noargs, t_hint), + tCE(sev, 320f004, sev, 0, (), noargs, t_hint), + +#undef THUMB_VARIANT +#define THUMB_VARIANT ARM_EXT_V6T2 + TCE(ldrexb, 1d00f9f, e8d00f4f, 2, (RRnpc, RRnpcb), rd_rn, rd_rn), + TCE(ldrexh, 1f00f9f, e8d00f5f, 2, (RRnpc, RRnpcb), rd_rn, rd_rn), + TCE(ldrexd, 1b00f9f, e8d0007f, 3, (RRnpc, oRRnpc, RRnpcb), ldrexd, t_ldrexd), + TCE(strexb, 1c00f90, e8c00f40, 3, (RRnpc, RRnpc, ADDR), strex, rm_rd_rn), + TCE(strexh, 1e00f90, e8c00f50, 3, (RRnpc, RRnpc, ADDR), strex, rm_rd_rn), + TCE(strexd, 1a00f90, e8c00070, 4, (RRnpc, RRnpc, oRRnpc, RRnpcb), strexd, t_strexd), + TUF(clrex, 57ff01f, f3bf8f2f, 0, (), noargs, noargs), + +#undef ARM_VARIANT +#define ARM_VARIANT ARM_EXT_V6Z + TCE(smi, 1600070, f7f08000, 1, (EXPi), smi, t_smi), + +#undef ARM_VARIANT +#define ARM_VARIANT ARM_EXT_V6T2 + TCE(bfc, 7c0001f, f36f0000, 3, (RRnpc, I31, I32), bfc, t_bfc), + TCE(bfi, 7c00010, f3600000, 4, (RRnpc, RRnpc_I0, I31, I32), bfi, t_bfi), + TCE(sbfx, 7a00050, f3400000, 4, (RR, RR, I31, I32), bfx, t_bfx), + 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(rbit, 3ff0f30, fa90f0a0, 2, (RR, RR), rd_rm, t_rbit), + + TC3(ldrht, 03000b0, f8300e00, 2, (RR, ADDR), ldsttv4, t_ldstt), + TC3(ldrsht, 03000f0, f9300e00, 2, (RR, ADDR), ldsttv4, t_ldstt), + TC3(ldrsbt, 03000d0, f9100e00, 2, (RR, ADDR), ldsttv4, t_ldstt), + TC3(strht, 02000b0, f8200e00, 2, (RR, ADDR), ldsttv4, t_ldstt), + + UT(cbnz, b900, 2, (RR, EXP), t_czb), + UT(cbz, b100, 2, (RR, EXP), t_czb), + /* ARM does not really have an IT instruction. */ + TUE(it, 0, bf08, 1, (COND), it, t_it), + TUE(itt, 0, bf0c, 1, (COND), it, t_it), + TUE(ite, 0, bf04, 1, (COND), it, t_it), + TUE(ittt, 0, bf0e, 1, (COND), it, t_it), + TUE(itet, 0, bf06, 1, (COND), it, t_it), + TUE(itte, 0, bf0a, 1, (COND), it, t_it), + TUE(itee, 0, bf02, 1, (COND), it, t_it), + TUE(itttt, 0, bf0f, 1, (COND), it, t_it), + TUE(itett, 0, bf07, 1, (COND), it, t_it), + TUE(ittet, 0, bf0b, 1, (COND), it, t_it), + TUE(iteet, 0, bf03, 1, (COND), it, t_it), + TUE(ittte, 0, bf0d, 1, (COND), it, t_it), + TUE(itete, 0, bf05, 1, (COND), it, t_it), + TUE(ittee, 0, bf09, 1, (COND), it, t_it), + TUE(iteee, 0, bf01, 1, (COND), it, t_it), + +#undef ARM_VARIANT +#define ARM_VARIANT FPU_FPA_EXT_V1 /* Core FPA instruction set (V1). */ + CE(wfs, e200110, 1, (RR), rd), + CE(rfs, e300110, 1, (RR), rd), + CE(wfc, e400110, 1, (RR), rd), + CE(rfc, e500110, 1, (RR), rd), + + C3(ldfs, c100100, 2, (RF, ADDR), rd_cpaddr), + C3(ldfd, c108100, 2, (RF, ADDR), rd_cpaddr), + C3(ldfe, c500100, 2, (RF, ADDR), rd_cpaddr), + C3(ldfp, c508100, 2, (RF, ADDR), rd_cpaddr), + + C3(stfs, c000100, 2, (RF, ADDR), rd_cpaddr), + C3(stfd, c008100, 2, (RF, ADDR), rd_cpaddr), + C3(stfe, c400100, 2, (RF, ADDR), rd_cpaddr), + C3(stfp, c408100, 2, (RF, ADDR), rd_cpaddr), + + C3(mvfs, e008100, 2, (RF, RF_IF), rd_rm), + C3(mvfsp, e008120, 2, (RF, RF_IF), rd_rm), + C3(mvfsm, e008140, 2, (RF, RF_IF), rd_rm), + C3(mvfsz, e008160, 2, (RF, RF_IF), rd_rm), + C3(mvfd, e008180, 2, (RF, RF_IF), rd_rm), + C3(mvfdp, e0081a0, 2, (RF, RF_IF), rd_rm), + C3(mvfdm, e0081c0, 2, (RF, RF_IF), rd_rm), + C3(mvfdz, e0081e0, 2, (RF, RF_IF), rd_rm), + C3(mvfe, e088100, 2, (RF, RF_IF), rd_rm), + C3(mvfep, e088120, 2, (RF, RF_IF), rd_rm), + C3(mvfem, e088140, 2, (RF, RF_IF), rd_rm), + C3(mvfez, e088160, 2, (RF, RF_IF), rd_rm), + + C3(mnfs, e108100, 2, (RF, RF_IF), rd_rm), + C3(mnfsp, e108120, 2, (RF, RF_IF), rd_rm), + C3(mnfsm, e108140, 2, (RF, RF_IF), rd_rm), + C3(mnfsz, e108160, 2, (RF, RF_IF), rd_rm), + C3(mnfd, e108180, 2, (RF, RF_IF), rd_rm), + C3(mnfdp, e1081a0, 2, (RF, RF_IF), rd_rm), + C3(mnfdm, e1081c0, 2, (RF, RF_IF), rd_rm), + C3(mnfdz, e1081e0, 2, (RF, RF_IF), rd_rm), + C3(mnfe, e188100, 2, (RF, RF_IF), rd_rm), + C3(mnfep, e188120, 2, (RF, RF_IF), rd_rm), + C3(mnfem, e188140, 2, (RF, RF_IF), rd_rm), + C3(mnfez, e188160, 2, (RF, RF_IF), rd_rm), + + C3(abss, e208100, 2, (RF, RF_IF), rd_rm), + C3(abssp, e208120, 2, (RF, RF_IF), rd_rm), + C3(abssm, e208140, 2, (RF, RF_IF), rd_rm), + C3(abssz, e208160, 2, (RF, RF_IF), rd_rm), + C3(absd, e208180, 2, (RF, RF_IF), rd_rm), + C3(absdp, e2081a0, 2, (RF, RF_IF), rd_rm), + C3(absdm, e2081c0, 2, (RF, RF_IF), rd_rm), + C3(absdz, e2081e0, 2, (RF, RF_IF), rd_rm), + C3(abse, e288100, 2, (RF, RF_IF), rd_rm), + C3(absep, e288120, 2, (RF, RF_IF), rd_rm), + C3(absem, e288140, 2, (RF, RF_IF), rd_rm), + C3(absez, e288160, 2, (RF, RF_IF), rd_rm), + + C3(rnds, e308100, 2, (RF, RF_IF), rd_rm), + C3(rndsp, e308120, 2, (RF, RF_IF), rd_rm), + C3(rndsm, e308140, 2, (RF, RF_IF), rd_rm), + C3(rndsz, e308160, 2, (RF, RF_IF), rd_rm), + C3(rndd, e308180, 2, (RF, RF_IF), rd_rm), + C3(rnddp, e3081a0, 2, (RF, RF_IF), rd_rm), + C3(rnddm, e3081c0, 2, (RF, RF_IF), rd_rm), + C3(rnddz, e3081e0, 2, (RF, RF_IF), rd_rm), + C3(rnde, e388100, 2, (RF, RF_IF), rd_rm), + C3(rndep, e388120, 2, (RF, RF_IF), rd_rm), + C3(rndem, e388140, 2, (RF, RF_IF), rd_rm), + C3(rndez, e388160, 2, (RF, RF_IF), rd_rm), + + C3(sqts, e408100, 2, (RF, RF_IF), rd_rm), + C3(sqtsp, e408120, 2, (RF, RF_IF), rd_rm), + C3(sqtsm, e408140, 2, (RF, RF_IF), rd_rm), + C3(sqtsz, e408160, 2, (RF, RF_IF), rd_rm), + C3(sqtd, e408180, 2, (RF, RF_IF), rd_rm), + C3(sqtdp, e4081a0, 2, (RF, RF_IF), rd_rm), + C3(sqtdm, e4081c0, 2, (RF, RF_IF), rd_rm), + C3(sqtdz, e4081e0, 2, (RF, RF_IF), rd_rm), + C3(sqte, e488100, 2, (RF, RF_IF), rd_rm), + C3(sqtep, e488120, 2, (RF, RF_IF), rd_rm), + C3(sqtem, e488140, 2, (RF, RF_IF), rd_rm), + C3(sqtez, e488160, 2, (RF, RF_IF), rd_rm), + + C3(logs, e508100, 2, (RF, RF_IF), rd_rm), + C3(logsp, e508120, 2, (RF, RF_IF), rd_rm), + C3(logsm, e508140, 2, (RF, RF_IF), rd_rm), + C3(logsz, e508160, 2, (RF, RF_IF), rd_rm), + C3(logd, e508180, 2, (RF, RF_IF), rd_rm), + C3(logdp, e5081a0, 2, (RF, RF_IF), rd_rm), + C3(logdm, e5081c0, 2, (RF, RF_IF), rd_rm), + C3(logdz, e5081e0, 2, (RF, RF_IF), rd_rm), + C3(loge, e588100, 2, (RF, RF_IF), rd_rm), + C3(logep, e588120, 2, (RF, RF_IF), rd_rm), + C3(logem, e588140, 2, (RF, RF_IF), rd_rm), + C3(logez, e588160, 2, (RF, RF_IF), rd_rm), + + C3(lgns, e608100, 2, (RF, RF_IF), rd_rm), + C3(lgnsp, e608120, 2, (RF, RF_IF), rd_rm), + C3(lgnsm, e608140, 2, (RF, RF_IF), rd_rm), + C3(lgnsz, e608160, 2, (RF, RF_IF), rd_rm), + C3(lgnd, e608180, 2, (RF, RF_IF), rd_rm), + C3(lgndp, e6081a0, 2, (RF, RF_IF), rd_rm), + C3(lgndm, e6081c0, 2, (RF, RF_IF), rd_rm), + C3(lgndz, e6081e0, 2, (RF, RF_IF), rd_rm), + C3(lgne, e688100, 2, (RF, RF_IF), rd_rm), + C3(lgnep, e688120, 2, (RF, RF_IF), rd_rm), + C3(lgnem, e688140, 2, (RF, RF_IF), rd_rm), + C3(lgnez, e688160, 2, (RF, RF_IF), rd_rm), + + C3(exps, e708100, 2, (RF, RF_IF), rd_rm), + C3(expsp, e708120, 2, (RF, RF_IF), rd_rm), + C3(expsm, e708140, 2, (RF, RF_IF), rd_rm), + C3(expsz, e708160, 2, (RF, RF_IF), rd_rm), + C3(expd, e708180, 2, (RF, RF_IF), rd_rm), + C3(expdp, e7081a0, 2, (RF, RF_IF), rd_rm), + C3(expdm, e7081c0, 2, (RF, RF_IF), rd_rm), + C3(expdz, e7081e0, 2, (RF, RF_IF), rd_rm), + C3(expe, e788100, 2, (RF, RF_IF), rd_rm), + C3(expep, e788120, 2, (RF, RF_IF), rd_rm), + C3(expem, e788140, 2, (RF, RF_IF), rd_rm), + C3(expdz, e788160, 2, (RF, RF_IF), rd_rm), + + C3(sins, e808100, 2, (RF, RF_IF), rd_rm), + C3(sinsp, e808120, 2, (RF, RF_IF), rd_rm), + C3(sinsm, e808140, 2, (RF, RF_IF), rd_rm), + C3(sinsz, e808160, 2, (RF, RF_IF), rd_rm), + C3(sind, e808180, 2, (RF, RF_IF), rd_rm), + C3(sindp, e8081a0, 2, (RF, RF_IF), rd_rm), + C3(sindm, e8081c0, 2, (RF, RF_IF), rd_rm), + C3(sindz, e8081e0, 2, (RF, RF_IF), rd_rm), + C3(sine, e888100, 2, (RF, RF_IF), rd_rm), + C3(sinep, e888120, 2, (RF, RF_IF), rd_rm), + C3(sinem, e888140, 2, (RF, RF_IF), rd_rm), + C3(sinez, e888160, 2, (RF, RF_IF), rd_rm), + + C3(coss, e908100, 2, (RF, RF_IF), rd_rm), + C3(cossp, e908120, 2, (RF, RF_IF), rd_rm), + C3(cossm, e908140, 2, (RF, RF_IF), rd_rm), + C3(cossz, e908160, 2, (RF, RF_IF), rd_rm), + C3(cosd, e908180, 2, (RF, RF_IF), rd_rm), + C3(cosdp, e9081a0, 2, (RF, RF_IF), rd_rm), + C3(cosdm, e9081c0, 2, (RF, RF_IF), rd_rm), + C3(cosdz, e9081e0, 2, (RF, RF_IF), rd_rm), + C3(cose, e988100, 2, (RF, RF_IF), rd_rm), + C3(cosep, e988120, 2, (RF, RF_IF), rd_rm), + C3(cosem, e988140, 2, (RF, RF_IF), rd_rm), + C3(cosez, e988160, 2, (RF, RF_IF), rd_rm), + + C3(tans, ea08100, 2, (RF, RF_IF), rd_rm), + C3(tansp, ea08120, 2, (RF, RF_IF), rd_rm), + C3(tansm, ea08140, 2, (RF, RF_IF), rd_rm), + C3(tansz, ea08160, 2, (RF, RF_IF), rd_rm), + C3(tand, ea08180, 2, (RF, RF_IF), rd_rm), + C3(tandp, ea081a0, 2, (RF, RF_IF), rd_rm), + C3(tandm, ea081c0, 2, (RF, RF_IF), rd_rm), + C3(tandz, ea081e0, 2, (RF, RF_IF), rd_rm), + C3(tane, ea88100, 2, (RF, RF_IF), rd_rm), + C3(tanep, ea88120, 2, (RF, RF_IF), rd_rm), + C3(tanem, ea88140, 2, (RF, RF_IF), rd_rm), + C3(tanez, ea88160, 2, (RF, RF_IF), rd_rm), + + C3(asns, eb08100, 2, (RF, RF_IF), rd_rm), + C3(asnsp, eb08120, 2, (RF, RF_IF), rd_rm), + C3(asnsm, eb08140, 2, (RF, RF_IF), rd_rm), + C3(asnsz, eb08160, 2, (RF, RF_IF), rd_rm), + C3(asnd, eb08180, 2, (RF, RF_IF), rd_rm), + C3(asndp, eb081a0, 2, (RF, RF_IF), rd_rm), + C3(asndm, eb081c0, 2, (RF, RF_IF), rd_rm), + C3(asndz, eb081e0, 2, (RF, RF_IF), rd_rm), + C3(asne, eb88100, 2, (RF, RF_IF), rd_rm), + C3(asnep, eb88120, 2, (RF, RF_IF), rd_rm), + C3(asnem, eb88140, 2, (RF, RF_IF), rd_rm), + C3(asnez, eb88160, 2, (RF, RF_IF), rd_rm), + + C3(acss, ec08100, 2, (RF, RF_IF), rd_rm), + C3(acssp, ec08120, 2, (RF, RF_IF), rd_rm), + C3(acssm, ec08140, 2, (RF, RF_IF), rd_rm), + C3(acssz, ec08160, 2, (RF, RF_IF), rd_rm), + C3(acsd, ec08180, 2, (RF, RF_IF), rd_rm), + C3(acsdp, ec081a0, 2, (RF, RF_IF), rd_rm), + C3(acsdm, ec081c0, 2, (RF, RF_IF), rd_rm), + C3(acsdz, ec081e0, 2, (RF, RF_IF), rd_rm), + C3(acse, ec88100, 2, (RF, RF_IF), rd_rm), + C3(acsep, ec88120, 2, (RF, RF_IF), rd_rm), + C3(acsem, ec88140, 2, (RF, RF_IF), rd_rm), + C3(acsez, ec88160, 2, (RF, RF_IF), rd_rm), + + C3(atns, ed08100, 2, (RF, RF_IF), rd_rm), + C3(atnsp, ed08120, 2, (RF, RF_IF), rd_rm), + C3(atnsm, ed08140, 2, (RF, RF_IF), rd_rm), + C3(atnsz, ed08160, 2, (RF, RF_IF), rd_rm), + C3(atnd, ed08180, 2, (RF, RF_IF), rd_rm), + C3(atndp, ed081a0, 2, (RF, RF_IF), rd_rm), + C3(atndm, ed081c0, 2, (RF, RF_IF), rd_rm), + C3(atndz, ed081e0, 2, (RF, RF_IF), rd_rm), + C3(atne, ed88100, 2, (RF, RF_IF), rd_rm), + C3(atnep, ed88120, 2, (RF, RF_IF), rd_rm), + C3(atnem, ed88140, 2, (RF, RF_IF), rd_rm), + C3(atnez, ed88160, 2, (RF, RF_IF), rd_rm), + + C3(urds, ee08100, 2, (RF, RF_IF), rd_rm), + C3(urdsp, ee08120, 2, (RF, RF_IF), rd_rm), + C3(urdsm, ee08140, 2, (RF, RF_IF), rd_rm), + C3(urdsz, ee08160, 2, (RF, RF_IF), rd_rm), + C3(urdd, ee08180, 2, (RF, RF_IF), rd_rm), + C3(urddp, ee081a0, 2, (RF, RF_IF), rd_rm), + C3(urddm, ee081c0, 2, (RF, RF_IF), rd_rm), + C3(urddz, ee081e0, 2, (RF, RF_IF), rd_rm), + C3(urde, ee88100, 2, (RF, RF_IF), rd_rm), + C3(urdep, ee88120, 2, (RF, RF_IF), rd_rm), + C3(urdem, ee88140, 2, (RF, RF_IF), rd_rm), + C3(urdez, ee88160, 2, (RF, RF_IF), rd_rm), + + C3(nrms, ef08100, 2, (RF, RF_IF), rd_rm), + C3(nrmsp, ef08120, 2, (RF, RF_IF), rd_rm), + C3(nrmsm, ef08140, 2, (RF, RF_IF), rd_rm), + C3(nrmsz, ef08160, 2, (RF, RF_IF), rd_rm), + C3(nrmd, ef08180, 2, (RF, RF_IF), rd_rm), + C3(nrmdp, ef081a0, 2, (RF, RF_IF), rd_rm), + C3(nrmdm, ef081c0, 2, (RF, RF_IF), rd_rm), + C3(nrmdz, ef081e0, 2, (RF, RF_IF), rd_rm), + C3(nrme, ef88100, 2, (RF, RF_IF), rd_rm), + C3(nrmep, ef88120, 2, (RF, RF_IF), rd_rm), + C3(nrmem, ef88140, 2, (RF, RF_IF), rd_rm), + C3(nrmez, ef88160, 2, (RF, RF_IF), rd_rm), + + C3(adfs, e000100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(adfsp, e000120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(adfsm, e000140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(adfsz, e000160, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(adfd, e000180, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(adfdp, e0001a0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(adfdm, e0001c0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(adfdz, e0001e0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(adfe, e080100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(adfep, e080120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(adfem, e080140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(adfez, e080160, 3, (RF, RF, RF_IF), rd_rn_rm), + + C3(sufs, e200100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(sufsp, e200120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(sufsm, e200140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(sufsz, e200160, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(sufd, e200180, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(sufdp, e2001a0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(sufdm, e2001c0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(sufdz, e2001e0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(sufe, e280100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(sufep, e280120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(sufem, e280140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(sufez, e280160, 3, (RF, RF, RF_IF), rd_rn_rm), + + C3(rsfs, e300100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rsfsp, e300120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rsfsm, e300140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rsfsz, e300160, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rsfd, e300180, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rsfdp, e3001a0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rsfdm, e3001c0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rsfdz, e3001e0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rsfe, e380100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rsfep, e380120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rsfem, e380140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rsfez, e380160, 3, (RF, RF, RF_IF), rd_rn_rm), + + C3(mufs, e100100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(mufsp, e100120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(mufsm, e100140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(mufsz, e100160, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(mufd, e100180, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(mufdp, e1001a0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(mufdm, e1001c0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(mufdz, e1001e0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(mufe, e180100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(mufep, e180120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(mufem, e180140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(mufez, e180160, 3, (RF, RF, RF_IF), rd_rn_rm), + + C3(dvfs, e400100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(dvfsp, e400120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(dvfsm, e400140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(dvfsz, e400160, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(dvfd, e400180, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(dvfdp, e4001a0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(dvfdm, e4001c0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(dvfdz, e4001e0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(dvfe, e480100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(dvfep, e480120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(dvfem, e480140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(dvfez, e480160, 3, (RF, RF, RF_IF), rd_rn_rm), + + C3(rdfs, e500100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rdfsp, e500120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rdfsm, e500140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rdfsz, e500160, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rdfd, e500180, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rdfdp, e5001a0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rdfdm, e5001c0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rdfdz, e5001e0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rdfe, e580100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rdfep, e580120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rdfem, e580140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rdfez, e580160, 3, (RF, RF, RF_IF), rd_rn_rm), + + C3(pows, e600100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(powsp, e600120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(powsm, e600140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(powsz, e600160, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(powd, e600180, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(powdp, e6001a0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(powdm, e6001c0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(powdz, e6001e0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(powe, e680100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(powep, e680120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(powem, e680140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(powez, e680160, 3, (RF, RF, RF_IF), rd_rn_rm), + + C3(rpws, e700100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rpwsp, e700120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rpwsm, e700140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rpwsz, e700160, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rpwd, e700180, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rpwdp, e7001a0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rpwdm, e7001c0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rpwdz, e7001e0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rpwe, e780100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rpwep, e780120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rpwem, e780140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rpwez, e780160, 3, (RF, RF, RF_IF), rd_rn_rm), + + C3(rmfs, e800100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rmfsp, e800120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rmfsm, e800140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rmfsz, e800160, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rmfd, e800180, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rmfdp, e8001a0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rmfdm, e8001c0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rmfdz, e8001e0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rmfe, e880100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rmfep, e880120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rmfem, e880140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(rmfez, e880160, 3, (RF, RF, RF_IF), rd_rn_rm), + + C3(fmls, e900100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(fmlsp, e900120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(fmlsm, e900140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(fmlsz, e900160, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(fmld, e900180, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(fmldp, e9001a0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(fmldm, e9001c0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(fmldz, e9001e0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(fmle, e980100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(fmlep, e980120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(fmlem, e980140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(fmlez, e980160, 3, (RF, RF, RF_IF), rd_rn_rm), + + C3(fdvs, ea00100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(fdvsp, ea00120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(fdvsm, ea00140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(fdvsz, ea00160, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(fdvd, ea00180, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(fdvdp, ea001a0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(fdvdm, ea001c0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(fdvdz, ea001e0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(fdve, ea80100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(fdvep, ea80120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(fdvem, ea80140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(fdvez, ea80160, 3, (RF, RF, RF_IF), rd_rn_rm), + + C3(frds, eb00100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(frdsp, eb00120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(frdsm, eb00140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(frdsz, eb00160, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(frdd, eb00180, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(frddp, eb001a0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(frddm, eb001c0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(frddz, eb001e0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(frde, eb80100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(frdep, eb80120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(frdem, eb80140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(frdez, eb80160, 3, (RF, RF, RF_IF), rd_rn_rm), + + C3(pols, ec00100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(polsp, ec00120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(polsm, ec00140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(polsz, ec00160, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(pold, ec00180, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(poldp, ec001a0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(poldm, ec001c0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(poldz, ec001e0, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(pole, ec80100, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(polep, ec80120, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(polem, ec80140, 3, (RF, RF, RF_IF), rd_rn_rm), + C3(polez, ec80160, 3, (RF, RF, RF_IF), rd_rn_rm), + + CE(cmf, e90f110, 2, (RF, RF_IF), fpa_cmp), + C3E(cmfe, ed0f110, 2, (RF, RF_IF), fpa_cmp), + CE(cnf, eb0f110, 2, (RF, RF_IF), fpa_cmp), + C3E(cnfe, ef0f110, 2, (RF, RF_IF), fpa_cmp), + + C3(flts, e000110, 2, (RF, RR), rn_rd), + C3(fltsp, e000130, 2, (RF, RR), rn_rd), + C3(fltsm, e000150, 2, (RF, RR), rn_rd), + C3(fltsz, e000170, 2, (RF, RR), rn_rd), + C3(fltd, e000190, 2, (RF, RR), rn_rd), + C3(fltdp, e0001b0, 2, (RF, RR), rn_rd), + C3(fltdm, e0001d0, 2, (RF, RR), rn_rd), + C3(fltdz, e0001f0, 2, (RF, RR), rn_rd), + C3(flte, e080110, 2, (RF, RR), rn_rd), + C3(fltep, e080130, 2, (RF, RR), rn_rd), + C3(fltem, e080150, 2, (RF, RR), rn_rd), + C3(fltez, e080170, 2, (RF, RR), rn_rd), - if ((reg = thumb_reg (&str, THUMB_REG_ANY)) == FAIL) - return; + /* The implementation of the FIX instruction is broken on some + assemblers, in that it accepts a precision specifier as well as a + rounding specifier, despite the fact that this is meaningless. + To be more compatible, we accept it as well, though of course it + does not set any bits. */ + CE(fix, e100110, 2, (RR, RF), rd_rm), + C3(fixp, e100130, 2, (RR, RF), rd_rm), + C3(fixm, e100150, 2, (RR, RF), rd_rm), + C3(fixz, e100170, 2, (RR, RF), rd_rm), + C3(fixsp, e100130, 2, (RR, RF), rd_rm), + C3(fixsm, e100150, 2, (RR, RF), rd_rm), + C3(fixsz, e100170, 2, (RR, RF), rd_rm), + C3(fixdp, e100130, 2, (RR, RF), rd_rm), + C3(fixdm, e100150, 2, (RR, RF), rd_rm), + C3(fixdz, e100170, 2, (RR, RF), rd_rm), + C3(fixep, e100130, 2, (RR, RF), rd_rm), + C3(fixem, e100150, 2, (RR, RF), rd_rm), + C3(fixez, e100170, 2, (RR, RF), rd_rm), - /* This sets THUMB_H2 from the top bit of reg. */ - inst.instruction |= reg << 3; + /* Instructions that were new with the real FPA, call them V2. */ +#undef ARM_VARIANT +#define ARM_VARIANT FPU_FPA_EXT_V2 + CE(lfm, c100200, 3, (RF, I4b, ADDR), fpa_ldmstm), + C3(lfmfd, c900200, 3, (RF, I4b, ADDR), fpa_ldmstm), + C3(lfmea, d100200, 3, (RF, I4b, ADDR), fpa_ldmstm), + CE(sfm, c000200, 3, (RF, I4b, ADDR), fpa_ldmstm), + C3(sfmfd, d000200, 3, (RF, I4b, ADDR), fpa_ldmstm), + C3(sfmea, c800200, 3, (RF, I4b, ADDR), fpa_ldmstm), + +#undef ARM_VARIANT +#define ARM_VARIANT FPU_VFP_EXT_V1xD /* VFP V1xD (single precision). */ + /* Moves and type conversions. */ + CE(fcpys, eb00a40, 2, (RVS, RVS), vfp_sp_monadic), + CE(fmrs, e100a10, 2, (RR, RVS), vfp_reg_from_sp), + CE(fmsr, e000a10, 2, (RVS, RR), vfp_sp_from_reg), + CE(fmstat, ef1fa10, 0, (), noargs), + CE(fsitos, eb80ac0, 2, (RVS, RVS), vfp_sp_monadic), + CE(fuitos, eb80a40, 2, (RVS, RVS), vfp_sp_monadic), + CE(ftosis, ebd0a40, 2, (RVS, RVS), vfp_sp_monadic), + CE(ftosizs, ebd0ac0, 2, (RVS, RVS), vfp_sp_monadic), + CE(ftouis, ebc0a40, 2, (RVS, RVS), vfp_sp_monadic), + CE(ftouizs, ebc0ac0, 2, (RVS, RVS), vfp_sp_monadic), + CE(fmrx, ef00a10, 2, (RR, RVC), rd_rn), + CE(fmxr, ee00a10, 2, (RVC, RR), rn_rd), + + /* Memory operations. */ + CE(flds, d100a00, 2, (RVS, ADDR), vfp_sp_ldst), + CE(fsts, d000a00, 2, (RVS, ADDR), vfp_sp_ldst), + CE(fldmias, c900a00, 2, (RRw, VRSLST), vfp_sp_ldstmia), + CE(fldmfds, c900a00, 2, (RRw, VRSLST), vfp_sp_ldstmia), + CE(fldmdbs, d300a00, 2, (RRw, VRSLST), vfp_sp_ldstmdb), + CE(fldmeas, d300a00, 2, (RRw, VRSLST), vfp_sp_ldstmdb), + CE(fldmiax, c900b00, 2, (RRw, VRDLST), vfp_xp_ldstmia), + CE(fldmfdx, c900b00, 2, (RRw, VRDLST), vfp_xp_ldstmia), + CE(fldmdbx, d300b00, 2, (RRw, VRDLST), vfp_xp_ldstmdb), + CE(fldmeax, d300b00, 2, (RRw, VRDLST), vfp_xp_ldstmdb), + CE(fstmias, c800a00, 2, (RRw, VRSLST), vfp_sp_ldstmia), + CE(fstmeas, c800a00, 2, (RRw, VRSLST), vfp_sp_ldstmia), + CE(fstmdbs, d200a00, 2, (RRw, VRSLST), vfp_sp_ldstmdb), + CE(fstmfds, d200a00, 2, (RRw, VRSLST), vfp_sp_ldstmdb), + CE(fstmiax, c800b00, 2, (RRw, VRDLST), vfp_xp_ldstmia), + CE(fstmeax, c800b00, 2, (RRw, VRDLST), vfp_xp_ldstmia), + CE(fstmdbx, d200b00, 2, (RRw, VRDLST), vfp_xp_ldstmdb), + CE(fstmfdx, d200b00, 2, (RRw, VRDLST), vfp_xp_ldstmdb), - /* ??? FIXME: Should add a hacky reloc here if reg is REG_PC. The reloc - should cause the alignment to be checked once it is known. This is - because BX PC only works if the instruction is word aligned. */ + /* Monadic operations. */ + CE(fabss, eb00ac0, 2, (RVS, RVS), vfp_sp_monadic), + CE(fnegs, eb10a40, 2, (RVS, RVS), vfp_sp_monadic), + CE(fsqrts, eb10ac0, 2, (RVS, RVS), vfp_sp_monadic), + + /* Dyadic operations. */ + CE(fadds, e300a00, 3, (RVS, RVS, RVS), vfp_sp_dyadic), + CE(fsubs, e300a40, 3, (RVS, RVS, RVS), vfp_sp_dyadic), + CE(fmuls, e200a00, 3, (RVS, RVS, RVS), vfp_sp_dyadic), + CE(fdivs, e800a00, 3, (RVS, RVS, RVS), vfp_sp_dyadic), + CE(fmacs, e000a00, 3, (RVS, RVS, RVS), vfp_sp_dyadic), + CE(fmscs, e100a00, 3, (RVS, RVS, RVS), vfp_sp_dyadic), + CE(fnmuls, e200a40, 3, (RVS, RVS, RVS), vfp_sp_dyadic), + CE(fnmacs, e000a40, 3, (RVS, RVS, RVS), vfp_sp_dyadic), + CE(fnmscs, e100a40, 3, (RVS, RVS, RVS), vfp_sp_dyadic), - end_of_line (str); -} + /* Comparisons. */ + CE(fcmps, eb40a40, 2, (RVS, RVS), vfp_sp_monadic), + CE(fcmpzs, eb50a40, 1, (RVS), vfp_sp_compare_z), + CE(fcmpes, eb40ac0, 2, (RVS, RVS), vfp_sp_monadic), + CE(fcmpezs, eb50ac0, 1, (RVS), vfp_sp_compare_z), -static void -do_t_compare (char * str) -{ - thumb_mov_compare (str, THUMB_COMPARE); -} +#undef ARM_VARIANT +#define ARM_VARIANT FPU_VFP_EXT_V1 /* VFP V1 (Double precision). */ + /* Moves and type conversions. */ + CE(fcpyd, eb00b40, 2, (RVD, RVD), rd_rm), + CE(fcvtds, eb70ac0, 2, (RVD, RVS), vfp_dp_sp_cvt), + CE(fcvtsd, eb70bc0, 2, (RVS, RVD), vfp_sp_dp_cvt), + CE(fmdhr, e200b10, 2, (RVD, RR), rn_rd), + CE(fmdlr, e000b10, 2, (RVD, RR), rn_rd), + CE(fmrdh, e300b10, 2, (RR, RVD), rd_rn), + CE(fmrdl, e100b10, 2, (RR, RVD), rd_rn), + CE(fsitod, eb80bc0, 2, (RVD, RVS), vfp_dp_sp_cvt), + CE(fuitod, eb80b40, 2, (RVD, RVS), vfp_dp_sp_cvt), + CE(ftosid, ebd0b40, 2, (RVS, RVD), vfp_sp_dp_cvt), + CE(ftosizd, ebd0bc0, 2, (RVS, RVD), vfp_sp_dp_cvt), + CE(ftouid, ebc0b40, 2, (RVS, RVD), vfp_sp_dp_cvt), + CE(ftouizd, ebc0bc0, 2, (RVS, RVD), vfp_sp_dp_cvt), + + /* Memory operations. */ + CE(fldd, d100b00, 2, (RVD, ADDR), vfp_dp_ldst), + CE(fstd, d000b00, 2, (RVD, ADDR), vfp_dp_ldst), + CE(fldmiad, c900b00, 2, (RRw, VRDLST), vfp_dp_ldstmia), + CE(fldmfdd, c900b00, 2, (RRw, VRDLST), vfp_dp_ldstmia), + CE(fldmdbd, d300b00, 2, (RRw, VRDLST), vfp_dp_ldstmdb), + CE(fldmead, d300b00, 2, (RRw, VRDLST), vfp_dp_ldstmdb), + CE(fstmiad, c800b00, 2, (RRw, VRDLST), vfp_dp_ldstmia), + CE(fstmead, c800b00, 2, (RRw, VRDLST), vfp_dp_ldstmia), + CE(fstmdbd, d200b00, 2, (RRw, VRDLST), vfp_dp_ldstmdb), + CE(fstmfdd, d200b00, 2, (RRw, VRDLST), vfp_dp_ldstmdb), -static void -do_t_ldmstm (char * str) -{ - int Rb; - long range; + /* Monadic operations. */ + CE(fabsd, eb00bc0, 2, (RVD, RVD), rd_rm), + CE(fnegd, eb10b40, 2, (RVD, RVD), rd_rm), + CE(fsqrtd, eb10bc0, 2, (RVD, RVD), rd_rm), + + /* Dyadic operations. */ + CE(faddd, e300b00, 3, (RVD, RVD, RVD), rd_rn_rm), + CE(fsubd, e300b40, 3, (RVD, RVD, RVD), rd_rn_rm), + CE(fmuld, e200b00, 3, (RVD, RVD, RVD), rd_rn_rm), + CE(fdivd, e800b00, 3, (RVD, RVD, RVD), rd_rn_rm), + CE(fmacd, e000b00, 3, (RVD, RVD, RVD), rd_rn_rm), + CE(fmscd, e100b00, 3, (RVD, RVD, RVD), rd_rn_rm), + CE(fnmuld, e200b40, 3, (RVD, RVD, RVD), rd_rn_rm), + CE(fnmacd, e000b40, 3, (RVD, RVD, RVD), rd_rn_rm), + CE(fnmscd, e100b40, 3, (RVD, RVD, RVD), rd_rn_rm), - skip_whitespace (str); + /* Comparisons. */ + CE(fcmpd, eb40b40, 2, (RVD, RVD), rd_rm), + CE(fcmpzd, eb50b40, 1, (RVD), rd), + CE(fcmped, eb40bc0, 2, (RVD, RVD), rd_rm), + CE(fcmpezd, eb50bc0, 1, (RVD), rd), + +#undef ARM_VARIANT +#define ARM_VARIANT FPU_VFP_EXT_V2 + CE(fmsrr, c400a10, 3, (VRSLST, RR, RR), vfp_sp2_from_reg2), + CE(fmrrs, c500a10, 3, (RR, RR, VRSLST), vfp_reg2_from_sp2), + CE(fmdrr, c400b10, 3, (RVD, RR, RR), rm_rd_rn), + CE(fmrrd, c500b10, 3, (RR, RR, RVD), rd_rn_rm), + +#undef ARM_VARIANT +#define ARM_VARIANT ARM_CEXT_XSCALE /* Intel XScale extensions. */ + CE(mia, e200010, 3, (RXA, RRnpc, RRnpc), xsc_mia), + CE(miaph, e280010, 3, (RXA, RRnpc, RRnpc), xsc_mia), + CE(miabb, e2c0010, 3, (RXA, RRnpc, RRnpc), xsc_mia), + CE(miabt, e2d0010, 3, (RXA, RRnpc, RRnpc), xsc_mia), + CE(miatb, e2e0010, 3, (RXA, RRnpc, RRnpc), xsc_mia), + CE(miatt, e2f0010, 3, (RXA, RRnpc, RRnpc), xsc_mia), + CE(mar, c400000, 3, (RXA, RRnpc, RRnpc), xsc_mar), + CE(mra, c500000, 3, (RRnpc, RRnpc, RXA), xsc_mra), + +#undef ARM_VARIANT +#define ARM_VARIANT ARM_CEXT_IWMMXT /* Intel Wireless MMX technology. */ + CE(tandcb, e13f130, 1, (RR), iwmmxt_tandorc), + CE(tandch, e53f130, 1, (RR), iwmmxt_tandorc), + CE(tandcw, e93f130, 1, (RR), iwmmxt_tandorc), + CE(tbcstb, e400010, 2, (RIWR, RR), rn_rd), + CE(tbcsth, e400050, 2, (RIWR, RR), rn_rd), + CE(tbcstw, e400090, 2, (RIWR, RR), rn_rd), + CE(textrcb, e130170, 2, (RR, I7), iwmmxt_textrc), + CE(textrch, e530170, 2, (RR, I7), iwmmxt_textrc), + CE(textrcw, e930170, 2, (RR, I7), iwmmxt_textrc), + CE(textrmub, e100070, 3, (RR, RIWR, I7), iwmmxt_textrm), + CE(textrmuh, e500070, 3, (RR, RIWR, I7), iwmmxt_textrm), + CE(textrmuw, e900070, 3, (RR, RIWR, I7), iwmmxt_textrm), + CE(textrmsb, e100078, 3, (RR, RIWR, I7), iwmmxt_textrm), + CE(textrmsh, e500078, 3, (RR, RIWR, I7), iwmmxt_textrm), + CE(textrmsw, e900078, 3, (RR, RIWR, I7), iwmmxt_textrm), + CE(tinsrb, e600010, 3, (RIWR, RR, I7), iwmmxt_tinsr), + CE(tinsrh, e600050, 3, (RIWR, RR, I7), iwmmxt_tinsr), + CE(tinsrw, e600090, 3, (RIWR, RR, I7), iwmmxt_tinsr), + CE(tmcr, e000110, 2, (RIWC, RR), rn_rd), + CE(tmcrr, c400000, 3, (RIWR, RR, RR), rm_rd_rn), + CE(tmia, e200010, 3, (RIWR, RR, RR), iwmmxt_tmia), + CE(tmiaph, e280010, 3, (RIWR, RR, RR), iwmmxt_tmia), + CE(tmiabb, e2c0010, 3, (RIWR, RR, RR), iwmmxt_tmia), + CE(tmiabt, e2d0010, 3, (RIWR, RR, RR), iwmmxt_tmia), + CE(tmiatb, e2e0010, 3, (RIWR, RR, RR), iwmmxt_tmia), + CE(tmiatt, e2f0010, 3, (RIWR, RR, RR), iwmmxt_tmia), + CE(tmovmskb, e100030, 2, (RR, RIWR), rd_rn), + CE(tmovmskh, e500030, 2, (RR, RIWR), rd_rn), + CE(tmovmskw, e900030, 2, (RR, RIWR), rd_rn), + CE(tmrc, e100110, 2, (RR, RIWC), rd_rn), + CE(tmrrc, c500000, 3, (RR, RR, RIWR), rd_rn_rm), + CE(torcb, e13f150, 1, (RR), iwmmxt_tandorc), + CE(torch, e53f150, 1, (RR), iwmmxt_tandorc), + CE(torcw, e93f150, 1, (RR), iwmmxt_tandorc), + CE(waccb, e0001c0, 2, (RIWR, RIWR), rd_rn), + CE(wacch, e4001c0, 2, (RIWR, RIWR), rd_rn), + CE(waccw, e8001c0, 2, (RIWR, RIWR), rd_rn), + CE(waddbss, e300180, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(waddb, e000180, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(waddbus, e100180, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(waddhss, e700180, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(waddh, e400180, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(waddhus, e500180, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(waddwss, eb00180, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(waddw, e800180, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(waddwus, e900180, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(waligni, e000020, 4, (RIWR, RIWR, RIWR, I7), iwmmxt_waligni), + CE(walignr0, e800020, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(walignr1, e900020, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(walignr2, ea00020, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(walignr3, eb00020, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wand, e200000, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wandn, e300000, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wavg2b, e800000, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wavg2br, e900000, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wavg2h, ec00000, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wavg2hr, ed00000, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wcmpeqb, e000060, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wcmpeqh, e400060, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wcmpeqw, e800060, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wcmpgtub, e100060, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wcmpgtuh, e500060, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wcmpgtuw, e900060, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wcmpgtsb, e300060, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wcmpgtsh, e700060, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wcmpgtsw, eb00060, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wldrb, c100000, 2, (RIWR, ADDR), iwmmxt_wldstbh), + CE(wldrh, c500000, 2, (RIWR, ADDR), iwmmxt_wldstbh), + CE(wldrw, c100100, 2, (RIWR_RIWC, ADDR), iwmmxt_wldstw), + CE(wldrd, c500100, 2, (RIWR, ADDR), iwmmxt_wldstd), + CE(wmacs, e600100, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wmacsz, e700100, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wmacu, e400100, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wmacuz, e500100, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wmadds, ea00100, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wmaddu, e800100, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wmaxsb, e200160, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wmaxsh, e600160, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wmaxsw, ea00160, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wmaxub, e000160, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wmaxuh, e400160, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wmaxuw, e800160, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wminsb, e300160, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wminsh, e700160, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wminsw, eb00160, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wminub, e100160, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wminuh, e500160, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wminuw, e900160, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wmov, e000000, 2, (RIWR, RIWR), iwmmxt_wmov), + CE(wmulsm, e300100, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wmulsl, e200100, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wmulum, e100100, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wmulul, e000100, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wor, e000000, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wpackhss, e700080, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wpackhus, e500080, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wpackwss, eb00080, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wpackwus, e900080, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wpackdss, ef00080, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wpackdus, ed00080, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wrorh, e700040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wrorhg, e700148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), + CE(wrorw, eb00040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wrorwg, eb00148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), + CE(wrord, ef00040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wrordg, ef00148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), + CE(wsadb, e000120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wsadbz, e100120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wsadh, e400120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wsadhz, e500120, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wshufh, e0001e0, 3, (RIWR, RIWR, I255), iwmmxt_wshufh), + CE(wsllh, e500040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wsllhg, e500148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), + CE(wsllw, e900040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wsllwg, e900148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), + CE(wslld, ed00040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wslldg, ed00148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), + CE(wsrah, e400040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wsrahg, e400148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), + CE(wsraw, e800040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wsrawg, e800148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), + CE(wsrad, ec00040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wsradg, ec00148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), + CE(wsrlh, e600040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wsrlhg, e600148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), + CE(wsrlw, ea00040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wsrlwg, ea00148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), + CE(wsrld, ee00040, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wsrldg, ee00148, 3, (RIWR, RIWR, RIWG), rd_rn_rm), + CE(wstrb, c000000, 2, (RIWR, ADDR), iwmmxt_wldstbh), + CE(wstrh, c400000, 2, (RIWR, ADDR), iwmmxt_wldstbh), + CE(wstrw, c000100, 2, (RIWR_RIWC, ADDR), iwmmxt_wldstw), + CE(wstrd, c400100, 2, (RIWR, ADDR), iwmmxt_wldstd), + CE(wsubbss, e3001a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wsubb, e0001a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wsubbus, e1001a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wsubhss, e7001a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wsubh, e4001a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wsubhus, e5001a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wsubwss, eb001a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wsubw, e8001a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wsubwus, e9001a0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wunpckehub,e0000c0, 2, (RIWR, RIWR), rd_rn), + CE(wunpckehuh,e4000c0, 2, (RIWR, RIWR), rd_rn), + CE(wunpckehuw,e8000c0, 2, (RIWR, RIWR), rd_rn), + CE(wunpckehsb,e2000c0, 2, (RIWR, RIWR), rd_rn), + CE(wunpckehsh,e6000c0, 2, (RIWR, RIWR), rd_rn), + CE(wunpckehsw,ea000c0, 2, (RIWR, RIWR), rd_rn), + CE(wunpckihb, e1000c0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wunpckihh, e5000c0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wunpckihw, e9000c0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wunpckelub,e0000e0, 2, (RIWR, RIWR), rd_rn), + CE(wunpckeluh,e4000e0, 2, (RIWR, RIWR), rd_rn), + CE(wunpckeluw,e8000e0, 2, (RIWR, RIWR), rd_rn), + CE(wunpckelsb,e2000e0, 2, (RIWR, RIWR), rd_rn), + CE(wunpckelsh,e6000e0, 2, (RIWR, RIWR), rd_rn), + CE(wunpckelsw,ea000e0, 2, (RIWR, RIWR), rd_rn), + CE(wunpckilb, e1000e0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wunpckilh, e5000e0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wunpckilw, e9000e0, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wxor, e100000, 3, (RIWR, RIWR, RIWR), rd_rn_rm), + CE(wzero, e300000, 1, (RIWR), iwmmxt_wzero), + +#undef ARM_VARIANT +#define ARM_VARIANT ARM_CEXT_MAVERICK /* Cirrus Maverick instructions. */ + CE(cfldrs, c100400, 2, (RMF, ADDR), rd_cpaddr), + CE(cfldrd, c500400, 2, (RMD, ADDR), rd_cpaddr), + CE(cfldr32, c100500, 2, (RMFX, ADDR), rd_cpaddr), + CE(cfldr64, c500500, 2, (RMDX, ADDR), rd_cpaddr), + CE(cfstrs, c000400, 2, (RMF, ADDR), rd_cpaddr), + CE(cfstrd, c400400, 2, (RMD, ADDR), rd_cpaddr), + CE(cfstr32, c000500, 2, (RMFX, ADDR), rd_cpaddr), + CE(cfstr64, c400500, 2, (RMDX, ADDR), rd_cpaddr), + CE(cfmvsr, e000450, 2, (RMF, RR), rn_rd), + CE(cfmvrs, e100450, 2, (RR, RMF), rd_rn), + CE(cfmvdlr, e000410, 2, (RMD, RR), rn_rd), + CE(cfmvrdl, e100410, 2, (RR, RMD), rd_rn), + CE(cfmvdhr, e000430, 2, (RMD, RR), rn_rd), + CE(cfmvrdh, e100430, 2, (RR, RMD), rd_rn), + CE(cfmv64lr, e000510, 2, (RMDX, RR), rn_rd), + CE(cfmvr64l, e100510, 2, (RR, RMDX), rd_rn), + CE(cfmv64hr, e000530, 2, (RMDX, RR), rn_rd), + CE(cfmvr64h, e100530, 2, (RR, RMDX), rd_rn), + CE(cfmval32, e200440, 2, (RMAX, RMFX), rd_rn), + CE(cfmv32al, e100440, 2, (RMFX, RMAX), rd_rn), + CE(cfmvam32, e200460, 2, (RMAX, RMFX), rd_rn), + CE(cfmv32am, e100460, 2, (RMFX, RMAX), rd_rn), + CE(cfmvah32, e200480, 2, (RMAX, RMFX), rd_rn), + CE(cfmv32ah, e100480, 2, (RMFX, RMAX), rd_rn), + CE(cfmva32, e2004a0, 2, (RMAX, RMFX), rd_rn), + CE(cfmv32a, e1004a0, 2, (RMFX, RMAX), rd_rn), + CE(cfmva64, e2004c0, 2, (RMAX, RMDX), rd_rn), + CE(cfmv64a, e1004c0, 2, (RMDX, RMAX), rd_rn), + CE(cfmvsc32, e2004e0, 2, (RMDS, RMDX), mav_dspsc), + CE(cfmv32sc, e1004e0, 2, (RMDX, RMDS), rd), + CE(cfcpys, e000400, 2, (RMF, RMF), rd_rn), + CE(cfcpyd, e000420, 2, (RMD, RMD), rd_rn), + CE(cfcvtsd, e000460, 2, (RMD, RMF), rd_rn), + CE(cfcvtds, e000440, 2, (RMF, RMD), rd_rn), + CE(cfcvt32s, e000480, 2, (RMF, RMFX), rd_rn), + CE(cfcvt32d, e0004a0, 2, (RMD, RMFX), rd_rn), + CE(cfcvt64s, e0004c0, 2, (RMF, RMDX), rd_rn), + CE(cfcvt64d, e0004e0, 2, (RMD, RMDX), rd_rn), + CE(cfcvts32, e100580, 2, (RMFX, RMF), rd_rn), + CE(cfcvtd32, e1005a0, 2, (RMFX, RMD), rd_rn), + CE(cftruncs32,e1005c0, 2, (RMFX, RMF), rd_rn), + CE(cftruncd32,e1005e0, 2, (RMFX, RMD), rd_rn), + CE(cfrshl32, e000550, 3, (RMFX, RMFX, RR), mav_triple), + CE(cfrshl64, e000570, 3, (RMDX, RMDX, RR), mav_triple), + CE(cfsh32, e000500, 3, (RMFX, RMFX, I63s), mav_shift), + CE(cfsh64, e200500, 3, (RMDX, RMDX, I63s), mav_shift), + CE(cfcmps, e100490, 3, (RR, RMF, RMF), rd_rn_rm), + CE(cfcmpd, e1004b0, 3, (RR, RMD, RMD), rd_rn_rm), + CE(cfcmp32, e100590, 3, (RR, RMFX, RMFX), rd_rn_rm), + CE(cfcmp64, e1005b0, 3, (RR, RMDX, RMDX), rd_rn_rm), + CE(cfabss, e300400, 2, (RMF, RMF), rd_rn), + CE(cfabsd, e300420, 2, (RMD, RMD), rd_rn), + CE(cfnegs, e300440, 2, (RMF, RMF), rd_rn), + CE(cfnegd, e300460, 2, (RMD, RMD), rd_rn), + CE(cfadds, e300480, 3, (RMF, RMF, RMF), rd_rn_rm), + CE(cfaddd, e3004a0, 3, (RMD, RMD, RMD), rd_rn_rm), + CE(cfsubs, e3004c0, 3, (RMF, RMF, RMF), rd_rn_rm), + CE(cfsubd, e3004e0, 3, (RMD, RMD, RMD), rd_rn_rm), + CE(cfmuls, e100400, 3, (RMF, RMF, RMF), rd_rn_rm), + CE(cfmuld, e100420, 3, (RMD, RMD, RMD), rd_rn_rm), + CE(cfabs32, e300500, 2, (RMFX, RMFX), rd_rn), + CE(cfabs64, e300520, 2, (RMDX, RMDX), rd_rn), + CE(cfneg32, e300540, 2, (RMFX, RMFX), rd_rn), + CE(cfneg64, e300560, 2, (RMDX, RMDX), rd_rn), + CE(cfadd32, e300580, 3, (RMFX, RMFX, RMFX), rd_rn_rm), + CE(cfadd64, e3005a0, 3, (RMDX, RMDX, RMDX), rd_rn_rm), + CE(cfsub32, e3005c0, 3, (RMFX, RMFX, RMFX), rd_rn_rm), + CE(cfsub64, e3005e0, 3, (RMDX, RMDX, RMDX), rd_rn_rm), + CE(cfmul32, e100500, 3, (RMFX, RMFX, RMFX), rd_rn_rm), + CE(cfmul64, e100520, 3, (RMDX, RMDX, RMDX), rd_rn_rm), + CE(cfmac32, e100540, 3, (RMFX, RMFX, RMFX), rd_rn_rm), + CE(cfmsc32, e100560, 3, (RMFX, RMFX, RMFX), rd_rn_rm), + CE(cfmadd32, e000600, 4, (RMAX, RMFX, RMFX, RMFX), mav_quad), + CE(cfmsub32, e100600, 4, (RMAX, RMFX, RMFX, RMFX), mav_quad), + CE(cfmadda32, e200600, 4, (RMAX, RMAX, RMFX, RMFX), mav_quad), + CE(cfmsuba32, e300600, 4, (RMAX, RMAX, RMFX, RMFX), mav_quad), +}; +#undef ARM_VARIANT +#undef THUMB_VARIANT +#undef TCE +#undef TCM +#undef TUE +#undef TUF +#undef TCC +#undef CE +#undef CM +#undef UE +#undef UF +#undef UT +#undef OPS0 +#undef OPS1 +#undef OPS2 +#undef OPS3 +#undef OPS4 +#undef OPS5 +#undef OPS6 +#undef do_0 + +/* MD interface: bits in the object file. */ - if ((Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL) - return; +/* Turn an integer of n bytes (in val) into a stream of bytes appropriate + for use in the a.out file, and stores them in the array pointed to by buf. + This knows about the endian-ness of the target machine and does + THE RIGHT THING, whatever it is. Possible values for n are 1 (byte) + 2 (short) and 4 (long) Floating numbers are put out as a series of + LITTLENUMS (shorts, here at least). */ - if (*str != '!') - as_warn (_("inserted missing '!': load/store multiple always writes back base register")); +void +md_number_to_chars (char * buf, valueT val, int n) +{ + if (target_big_endian) + number_to_chars_bigendian (buf, val, n); else - str++; + number_to_chars_littleendian (buf, val, n); +} - if (skip_past_comma (&str) == FAIL - || (range = reg_list (&str)) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } +static valueT +md_chars_to_number (char * buf, int n) +{ + valueT result = 0; + unsigned char * where = (unsigned char *) buf; - if (inst.reloc.type != BFD_RELOC_UNUSED) + if (target_big_endian) { - /* This really doesn't seem worth it. */ - inst.reloc.type = BFD_RELOC_UNUSED; - inst.error = _("expression too complex"); - return; + while (n--) + { + result <<= 8; + result |= (*where++ & 255); + } } - - if (range & ~0xff) + else { - inst.error = _("only lo-regs valid in load/store multiple"); - return; + while (n--) + { + result <<= 8; + result |= (where[n] & 255); + } } - inst.instruction |= (Rb << 8) | range; - end_of_line (str); + return result; } -static void -do_t_ldr (char * str) -{ - thumb_load_store (str, THUMB_LOAD, THUMB_WORD); -} +/* MD interface: Sections. */ -static void -do_t_ldrb (char * str) +int +md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED, + segT segtype ATTRIBUTE_UNUSED) { - thumb_load_store (str, THUMB_LOAD, THUMB_BYTE); + as_fatal (_("md_estimate_size_before_relax\n")); + return 1; } -static void -do_t_ldrh (char * str) -{ - thumb_load_store (str, THUMB_LOAD, THUMB_HALFWORD); -} +/* Round up a section size to the appropriate boundary. */ -static void -do_t_lds (char * str) +valueT +md_section_align (segT segment ATTRIBUTE_UNUSED, + valueT size) { - int Rd, Rb, Ro; - - skip_whitespace (str); - - if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL - || skip_past_comma (&str) == FAIL - || *str++ != '[' - || (Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL - || skip_past_comma (&str) == FAIL - || (Ro = thumb_reg (&str, THUMB_REG_LO)) == FAIL - || *str++ != ']') - { - if (! inst.error) - inst.error = _("syntax: ldrs[b] Rd, [Rb, Ro]"); - return; - } - - inst.instruction |= Rd | (Rb << 3) | (Ro << 6); - end_of_line (str); +#ifdef OBJ_ELF + return size; +#else + /* Round all sects to multiple of 4. */ + return (size + 3) & ~3; +#endif } -static void -do_t_lsl (char * str) -{ - thumb_shift (str, THUMB_LSL); -} +/* This is called from HANDLE_ALIGN in write.c. Fill in the contents + of an rs_align_code fragment. */ -static void -do_t_lsr (char * str) +void +arm_handle_align (fragS * fragP) { - thumb_shift (str, THUMB_LSR); -} + static char const arm_noop[4] = { 0x00, 0x00, 0xa0, 0xe1 }; + static char const thumb_noop[2] = { 0xc0, 0x46 }; + static char const arm_bigend_noop[4] = { 0xe1, 0xa0, 0x00, 0x00 }; + static char const thumb_bigend_noop[2] = { 0x46, 0xc0 }; -static void -do_t_mov (char * str) -{ - thumb_mov_compare (str, THUMB_MOVE); -} + int bytes, fix, noop_size; + char * p; + const char * noop; -static void -do_t_push_pop (char * str) -{ - long range; + if (fragP->fr_type != rs_align_code) + return; - skip_whitespace (str); + bytes = fragP->fr_next->fr_address - fragP->fr_address - fragP->fr_fix; + p = fragP->fr_literal + fragP->fr_fix; + fix = 0; - if ((range = reg_list (&str)) == FAIL) + if (bytes > MAX_MEM_FOR_RS_ALIGN_CODE) + bytes &= MAX_MEM_FOR_RS_ALIGN_CODE; + + if (fragP->tc_frag_data) { - if (! inst.error) - inst.error = BAD_ARGS; - return; + if (target_big_endian) + noop = thumb_bigend_noop; + else + noop = thumb_noop; + noop_size = sizeof (thumb_noop); + } + else + { + if (target_big_endian) + noop = arm_bigend_noop; + else + noop = arm_noop; + noop_size = sizeof (arm_noop); } - if (inst.reloc.type != BFD_RELOC_UNUSED) + if (bytes & (noop_size - 1)) { - /* This really doesn't seem worth it. */ - inst.reloc.type = BFD_RELOC_UNUSED; - inst.error = _("expression too complex"); - return; + fix = bytes & (noop_size - 1); + memset (p, 0, fix); + p += fix; + bytes -= fix; } - if (range & ~0xff) + while (bytes >= noop_size) { - if ((inst.instruction == T_OPCODE_PUSH - && (range & ~0xff) == 1 << REG_LR) - || (inst.instruction == T_OPCODE_POP - && (range & ~0xff) == 1 << REG_PC)) - { - inst.instruction |= THUMB_PP_PC_LR; - range &= 0xff; - } - else - { - inst.error = _("invalid register list to push/pop instruction"); - return; - } + memcpy (p, noop, noop_size); + p += noop_size; + bytes -= noop_size; + fix += noop_size; } - inst.instruction |= range; - end_of_line (str); + fragP->fr_fix += fix; + fragP->fr_var = noop_size; } -static void -do_t_str (char * str) -{ - thumb_load_store (str, THUMB_STORE, THUMB_WORD); -} +/* Called from md_do_align. Used to create an alignment + frag in a code section. */ -static void -do_t_strb (char * str) +void +arm_frag_align_code (int n, int max) { - thumb_load_store (str, THUMB_STORE, THUMB_BYTE); -} + char * p; -static void -do_t_strh (char * str) -{ - thumb_load_store (str, THUMB_STORE, THUMB_HALFWORD); -} + /* We assume that there will never be a requirement + to support alignments greater than 32 bytes. */ + if (max > MAX_MEM_FOR_RS_ALIGN_CODE) + as_fatal (_("alignments greater than 32 bytes not supported in .text sections.")); -static void -do_t_sub (char * str) -{ - thumb_add_sub (str, 1); + p = frag_var (rs_align_code, + MAX_MEM_FOR_RS_ALIGN_CODE, + 1, + (relax_substateT) max, + (symbolS *) NULL, + (offsetT) n, + (char *) NULL); + *p = 0; } -static void -do_t_swi (char * str) -{ - skip_whitespace (str); - - if (my_get_expression (&inst.reloc.exp, &str)) - return; +/* Perform target specific initialisation of a frag. */ - inst.reloc.type = BFD_RELOC_ARM_SWI; - end_of_line (str); +void +arm_init_frag (fragS * fragP) +{ + /* Record whether this frag is in an ARM or a THUMB area. */ + fragP->tc_frag_data = thumb_mode; } -static void -do_t_adr (char * str) +#ifdef OBJ_ELF +/* When we change sections we need to issue a new mapping symbol. */ + +void +arm_elf_change_section (void) { - int reg; + flagword flags; + segment_info_type *seginfo; - /* 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". */ - skip_whitespace (str); + /* Link an unlinked unwind index table section to the .text section. */ + if (elf_section_type (now_seg) == SHT_ARM_EXIDX + && elf_linked_to_section (now_seg) == NULL) + elf_linked_to_section (now_seg) = text_section; - /* 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)) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } + if (!SEG_NORMAL (now_seg)) + return; - 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 |= REG_PC; /* Rd is already placed into the instruction. */ + flags = bfd_get_section_flags (stdoutput, now_seg); - end_of_line (str); + /* We can ignore sections that only contain debug info. */ + if ((flags & SEC_ALLOC) == 0) + return; + + seginfo = seg_info (now_seg); + mapstate = seginfo->tc_segment_info_data.mapstate; + marked_pr_dependency = seginfo->tc_segment_info_data.marked_pr_dependency; } -static void -insert_reg (const struct reg_entry * r, - struct hash_control * htab) +int +arm_elf_section_type (const char * str, size_t len) { - int len = strlen (r->name) + 2; - char * buf = xmalloc (len); - char * buf2 = xmalloc (len); - int i = 0; - -#ifdef REGISTER_PREFIX - buf[i++] = REGISTER_PREFIX; -#endif - - strcpy (buf + i, r->name); + if (len == 5 && strncmp (str, "exidx", 5) == 0) + return SHT_ARM_EXIDX; - for (i = 0; buf[i]; i++) - buf2[i] = TOUPPER (buf[i]); + return -1; +} + +/* Code to deal with unwinding tables. */ - buf2[i] = '\0'; +static void add_unwind_adjustsp (offsetT); - hash_insert (htab, buf, (PTR) r); - hash_insert (htab, buf2, (PTR) r); -} +/* Cenerate and deferred unwind frame offset. */ static void -build_reg_hsh (struct reg_map * map) +flush_pending_unwind (void) { - const struct reg_entry *r; - - if ((map->htab = hash_new ()) == NULL) - as_fatal (_("virtual memory exhausted")); + offsetT offset; - for (r = map->names; r->name != NULL; r++) - insert_reg (r, map->htab); + offset = unwind.pending_offset; + unwind.pending_offset = 0; + if (offset != 0) + add_unwind_adjustsp (offset); } +/* Add an opcode to this list for this function. Two-byte opcodes should + be passed as op[0] << 8 | op[1]. The list of opcodes is built in reverse + order. */ + static void -insert_reg_alias (char * str, - int regnum, - struct hash_control *htab) +add_unwind_opcode (valueT op, int length) { - const char * error; - struct reg_entry * new = xmalloc (sizeof (struct reg_entry)); - const char * name = xmalloc (strlen (str) + 1); - - strcpy ((char *) name, str); + /* Add any deferred stack adjustment. */ + if (unwind.pending_offset) + flush_pending_unwind (); - new->name = name; - new->number = regnum; - new->builtin = FALSE; + unwind.sp_restored = 0; - error = hash_insert (htab, name, (PTR) new); - if (error) + if (unwind.opcode_count + length > unwind.opcode_alloc) + { + unwind.opcode_alloc += ARM_OPCODE_CHUNK_SIZE; + if (unwind.opcodes) + unwind.opcodes = xrealloc (unwind.opcodes, + unwind.opcode_alloc); + else + unwind.opcodes = xmalloc (unwind.opcode_alloc); + } + while (length > 0) { - as_bad (_("failed to create an alias for %s, reason: %s"), - str, error); - free ((char *) name); - free (new); + length--; + unwind.opcodes[unwind.opcode_count] = op & 0xff; + op >>= 8; + unwind.opcode_count++; } } -/* Look for the .req directive. This is of the form: - - new_register_name .req existing_register_name - - If we find one, or if it looks sufficiently like one that we want to - handle any error here, return non-zero. Otherwise return zero. */ +/* Add unwind opcodes to adjust the stack pointer. */ -static int -create_register_alias (char * newname, char * p) +static void +add_unwind_adjustsp (offsetT offset) { - char * q; - char c; - - q = p; - skip_whitespace (q); - - c = *p; - *p = '\0'; + valueT op; - if (*q && !strncmp (q, ".req ", 5)) + if (offset > 0x200) { - char *copy_of_str; - char *r; - -#ifndef IGNORE_OPCODE_CASE - newname = original_case_string; -#endif - copy_of_str = newname; - - q += 4; - skip_whitespace (q); + /* We need at most 5 bytes to hold a 32-bit value in a uleb128. */ + char bytes[5]; + int n; + valueT o; - for (r = q; *r != '\0'; r++) - if (*r == ' ') - break; + /* Long form: 0xb2, uleb128. */ + /* This might not fit in a word so add the individual bytes, + remembering the list is built in reverse order. */ + o = (valueT) ((offset - 0x204) >> 2); + if (o == 0) + add_unwind_opcode (0, 1); - if (r != q) + /* Calculate the uleb128 encoding of the offset. */ + n = 0; + while (o) { - enum arm_reg_type new_type, old_type; - int old_regno; - char d = *r; - - *r = '\0'; - old_type = arm_reg_parse_any (q); - *r = d; - - new_type = arm_reg_parse_any (newname); - - if (new_type == REG_TYPE_MAX) - { - if (old_type != REG_TYPE_MAX) - { - old_regno = arm_reg_parse (&q, all_reg_maps[old_type].htab); - insert_reg_alias (newname, old_regno, - all_reg_maps[old_type].htab); - } - else - as_warn (_("register '%s' does not exist\n"), q); - } - else if (old_type == REG_TYPE_MAX) - { - as_warn (_("ignoring redefinition of register alias '%s' to non-existant register '%s'"), - copy_of_str, q); - } - else - { - /* Do not warn about redefinitions to the same alias. */ - if (new_type != old_type - || (arm_reg_parse (&q, all_reg_maps[old_type].htab) - != arm_reg_parse (&q, all_reg_maps[new_type].htab))) - as_warn (_("ignoring redefinition of register alias '%s'"), - copy_of_str); - - } + bytes[n] = o & 0x7f; + o >>= 7; + if (o) + bytes[n] |= 0x80; + n++; } - else - as_warn (_("ignoring incomplete .req pseuso op")); - - *p = c; - return 1; + /* Add the insn. */ + for (; n; n--) + add_unwind_opcode (bytes[n - 1], 1); + add_unwind_opcode (0xb2, 1); + } + else if (offset > 0x100) + { + /* Two short opcodes. */ + add_unwind_opcode (0x3f, 1); + op = (offset - 0x104) >> 2; + add_unwind_opcode (op, 1); + } + else if (offset > 0) + { + /* Short opcode. */ + op = (offset - 4) >> 2; + add_unwind_opcode (op, 1); + } + else if (offset < 0) + { + offset = -offset; + while (offset > 0x100) + { + add_unwind_opcode (0x7f, 1); + offset -= 0x100; + } + op = ((offset - 4) >> 2) | 0x40; + add_unwind_opcode (op, 1); } - - *p = c; - return 0; } +/* Finish the list of unwind opcodes for this function. */ static void -set_constant_flonums (void) -{ - int i; - - for (i = 0; i < NUM_FLOAT_VALS; i++) - if (atof_ieee ((char *) fp_const[i], 'x', fp_values[i]) == NULL) - abort (); -} - - -static const struct asm_opcode insns[] = +finish_unwind_opcodes (void) { - /* Core ARM Instructions. */ - {"and", 0xe0000000, 3, ARM_EXT_V1, do_arit}, - {"ands", 0xe0100000, 3, ARM_EXT_V1, do_arit}, - {"eor", 0xe0200000, 3, ARM_EXT_V1, do_arit}, - {"eors", 0xe0300000, 3, ARM_EXT_V1, do_arit}, - {"sub", 0xe0400000, 3, ARM_EXT_V1, do_arit}, - {"subs", 0xe0500000, 3, ARM_EXT_V1, do_arit}, - {"rsb", 0xe0600000, 3, ARM_EXT_V1, do_arit}, - {"rsbs", 0xe0700000, 3, ARM_EXT_V1, do_arit}, - {"add", 0xe0800000, 3, ARM_EXT_V1, do_arit}, - {"adds", 0xe0900000, 3, ARM_EXT_V1, do_arit}, - {"adc", 0xe0a00000, 3, ARM_EXT_V1, do_arit}, - {"adcs", 0xe0b00000, 3, ARM_EXT_V1, do_arit}, - {"sbc", 0xe0c00000, 3, ARM_EXT_V1, do_arit}, - {"sbcs", 0xe0d00000, 3, ARM_EXT_V1, do_arit}, - {"rsc", 0xe0e00000, 3, ARM_EXT_V1, do_arit}, - {"rscs", 0xe0f00000, 3, ARM_EXT_V1, do_arit}, - {"orr", 0xe1800000, 3, ARM_EXT_V1, do_arit}, - {"orrs", 0xe1900000, 3, ARM_EXT_V1, do_arit}, - {"bic", 0xe1c00000, 3, ARM_EXT_V1, do_arit}, - {"bics", 0xe1d00000, 3, ARM_EXT_V1, do_arit}, - - {"tst", 0xe1100000, 3, ARM_EXT_V1, do_cmp}, - {"tsts", 0xe1100000, 3, ARM_EXT_V1, do_cmp}, - {"tstp", 0xe110f000, 3, ARM_EXT_V1, do_cmp}, - {"teq", 0xe1300000, 3, ARM_EXT_V1, do_cmp}, - {"teqs", 0xe1300000, 3, ARM_EXT_V1, do_cmp}, - {"teqp", 0xe130f000, 3, ARM_EXT_V1, do_cmp}, - {"cmp", 0xe1500000, 3, ARM_EXT_V1, do_cmp}, - {"cmps", 0xe1500000, 3, ARM_EXT_V1, do_cmp}, - {"cmpp", 0xe150f000, 3, ARM_EXT_V1, do_cmp}, - {"cmn", 0xe1700000, 3, ARM_EXT_V1, do_cmp}, - {"cmns", 0xe1700000, 3, ARM_EXT_V1, do_cmp}, - {"cmnp", 0xe170f000, 3, ARM_EXT_V1, do_cmp}, - - {"mov", 0xe1a00000, 3, ARM_EXT_V1, do_mov}, - {"movs", 0xe1b00000, 3, ARM_EXT_V1, do_mov}, - {"mvn", 0xe1e00000, 3, ARM_EXT_V1, do_mov}, - {"mvns", 0xe1f00000, 3, ARM_EXT_V1, do_mov}, - - {"ldr", 0xe4100000, 3, ARM_EXT_V1, do_ldst}, - {"ldrb", 0xe4500000, 3, ARM_EXT_V1, do_ldst}, - {"ldrt", 0xe4300000, 3, ARM_EXT_V1, do_ldstt}, - {"ldrbt", 0xe4700000, 3, ARM_EXT_V1, do_ldstt}, - {"str", 0xe4000000, 3, ARM_EXT_V1, do_ldst}, - {"strb", 0xe4400000, 3, ARM_EXT_V1, do_ldst}, - {"strt", 0xe4200000, 3, ARM_EXT_V1, do_ldstt}, - {"strbt", 0xe4600000, 3, ARM_EXT_V1, do_ldstt}, - - {"stmia", 0xe8800000, 3, ARM_EXT_V1, do_ldmstm}, - {"stmib", 0xe9800000, 3, ARM_EXT_V1, do_ldmstm}, - {"stmda", 0xe8000000, 3, ARM_EXT_V1, do_ldmstm}, - {"stmdb", 0xe9000000, 3, ARM_EXT_V1, do_ldmstm}, - {"stmfd", 0xe9000000, 3, ARM_EXT_V1, do_ldmstm}, - {"stmfa", 0xe9800000, 3, ARM_EXT_V1, do_ldmstm}, - {"stmea", 0xe8800000, 3, ARM_EXT_V1, do_ldmstm}, - {"stmed", 0xe8000000, 3, ARM_EXT_V1, do_ldmstm}, - - {"ldmia", 0xe8900000, 3, ARM_EXT_V1, do_ldmstm}, - {"ldmib", 0xe9900000, 3, ARM_EXT_V1, do_ldmstm}, - {"ldmda", 0xe8100000, 3, ARM_EXT_V1, do_ldmstm}, - {"ldmdb", 0xe9100000, 3, ARM_EXT_V1, do_ldmstm}, - {"ldmfd", 0xe8900000, 3, ARM_EXT_V1, do_ldmstm}, - {"ldmfa", 0xe8100000, 3, ARM_EXT_V1, do_ldmstm}, - {"ldmea", 0xe9100000, 3, ARM_EXT_V1, do_ldmstm}, - {"ldmed", 0xe9900000, 3, ARM_EXT_V1, do_ldmstm}, - - {"swi", 0xef000000, 3, ARM_EXT_V1, do_swi}, -#ifdef TE_WINCE - /* XXX This is the wrong place to do this. Think multi-arch. */ - {"bl", 0xeb000000, 2, ARM_EXT_V1, do_branch}, - {"b", 0xea000000, 1, ARM_EXT_V1, do_branch}, -#else - {"bl", 0xebfffffe, 2, ARM_EXT_V1, do_branch}, - {"b", 0xeafffffe, 1, ARM_EXT_V1, do_branch}, -#endif - - /* Pseudo ops. */ - {"adr", 0xe28f0000, 3, ARM_EXT_V1, do_adr}, - {"adrl", 0xe28f0000, 3, ARM_EXT_V1, do_adrl}, - {"nop", 0xe1a00000, 3, ARM_EXT_V1, do_nop}, - - /* ARM 2 multiplies. */ - {"mul", 0xe0000090, 3, ARM_EXT_V2, do_mul}, - {"muls", 0xe0100090, 3, ARM_EXT_V2, do_mul}, - {"mla", 0xe0200090, 3, ARM_EXT_V2, do_mla}, - {"mlas", 0xe0300090, 3, ARM_EXT_V2, do_mla}, - - /* Generic coprocessor instructions. */ - {"cdp", 0xee000000, 3, ARM_EXT_V2, do_cdp}, - {"ldc", 0xec100000, 3, ARM_EXT_V2, do_lstc}, - {"ldcl", 0xec500000, 3, ARM_EXT_V2, do_lstc}, - {"stc", 0xec000000, 3, ARM_EXT_V2, do_lstc}, - {"stcl", 0xec400000, 3, ARM_EXT_V2, do_lstc}, - {"mcr", 0xee000010, 3, ARM_EXT_V2, do_co_reg}, - {"mrc", 0xee100010, 3, ARM_EXT_V2, do_co_reg}, - - /* ARM 3 - swp instructions. */ - {"swp", 0xe1000090, 3, ARM_EXT_V2S, do_swap}, - {"swpb", 0xe1400090, 3, ARM_EXT_V2S, do_swap}, - - /* ARM 6 Status register instructions. */ - {"mrs", 0xe10f0000, 3, ARM_EXT_V3, do_mrs}, - {"msr", 0xe120f000, 3, ARM_EXT_V3, do_msr}, - /* ScottB: our code uses 0xe128f000 for msr. - NickC: but this is wrong because the bits 16 through 19 are - handled by the PSR_xxx defines above. */ - - /* ARM 7M long multiplies. */ - {"smull", 0xe0c00090, 5, ARM_EXT_V3M, do_mull}, - {"smulls", 0xe0d00090, 5, ARM_EXT_V3M, do_mull}, - {"umull", 0xe0800090, 5, ARM_EXT_V3M, do_mull}, - {"umulls", 0xe0900090, 5, ARM_EXT_V3M, do_mull}, - {"smlal", 0xe0e00090, 5, ARM_EXT_V3M, do_mull}, - {"smlals", 0xe0f00090, 5, ARM_EXT_V3M, do_mull}, - {"umlal", 0xe0a00090, 5, ARM_EXT_V3M, do_mull}, - {"umlals", 0xe0b00090, 5, ARM_EXT_V3M, do_mull}, - - /* ARM Architecture 4. */ - {"ldrh", 0xe01000b0, 3, ARM_EXT_V4, do_ldstv4}, - {"ldrsh", 0xe01000f0, 3, ARM_EXT_V4, do_ldstv4}, - {"ldrsb", 0xe01000d0, 3, ARM_EXT_V4, do_ldstv4}, - {"strh", 0xe00000b0, 3, ARM_EXT_V4, do_ldstv4}, - - /* ARM Architecture 4T. */ - /* Note: bx (and blx) are required on V5, even if the processor does - not support Thumb. */ - {"bx", 0xe12fff10, 2, ARM_EXT_V4T | ARM_EXT_V5, do_bx}, - - /* ARM Architecture 5T. */ - /* Note: blx has 2 variants, so the .value is set dynamically. - Only one of the variants has conditional execution. */ - {"blx", 0xe0000000, 3, ARM_EXT_V5, do_blx}, - {"clz", 0xe16f0f10, 3, ARM_EXT_V5, do_clz}, - {"bkpt", 0xe1200070, 0, ARM_EXT_V5, do_bkpt}, - {"ldc2", 0xfc100000, 0, ARM_EXT_V5, do_lstc2}, - {"ldc2l", 0xfc500000, 0, ARM_EXT_V5, do_lstc2}, - {"stc2", 0xfc000000, 0, ARM_EXT_V5, do_lstc2}, - {"stc2l", 0xfc400000, 0, ARM_EXT_V5, do_lstc2}, - {"cdp2", 0xfe000000, 0, ARM_EXT_V5, do_cdp2}, - {"mcr2", 0xfe000010, 0, ARM_EXT_V5, do_co_reg2}, - {"mrc2", 0xfe100010, 0, ARM_EXT_V5, do_co_reg2}, - - /* ARM Architecture 5TExP. */ - {"smlabb", 0xe1000080, 6, ARM_EXT_V5ExP, do_smla}, - {"smlatb", 0xe10000a0, 6, ARM_EXT_V5ExP, do_smla}, - {"smlabt", 0xe10000c0, 6, ARM_EXT_V5ExP, do_smla}, - {"smlatt", 0xe10000e0, 6, ARM_EXT_V5ExP, do_smla}, - - {"smlawb", 0xe1200080, 6, ARM_EXT_V5ExP, do_smla}, - {"smlawt", 0xe12000c0, 6, ARM_EXT_V5ExP, do_smla}, - - {"smlalbb", 0xe1400080, 7, ARM_EXT_V5ExP, do_smlal}, - {"smlaltb", 0xe14000a0, 7, ARM_EXT_V5ExP, do_smlal}, - {"smlalbt", 0xe14000c0, 7, ARM_EXT_V5ExP, do_smlal}, - {"smlaltt", 0xe14000e0, 7, ARM_EXT_V5ExP, do_smlal}, - - {"smulbb", 0xe1600080, 6, ARM_EXT_V5ExP, do_smul}, - {"smultb", 0xe16000a0, 6, ARM_EXT_V5ExP, do_smul}, - {"smulbt", 0xe16000c0, 6, ARM_EXT_V5ExP, do_smul}, - {"smultt", 0xe16000e0, 6, ARM_EXT_V5ExP, do_smul}, - - {"smulwb", 0xe12000a0, 6, ARM_EXT_V5ExP, do_smul}, - {"smulwt", 0xe12000e0, 6, ARM_EXT_V5ExP, do_smul}, - - {"qadd", 0xe1000050, 4, ARM_EXT_V5ExP, do_qadd}, - {"qdadd", 0xe1400050, 5, ARM_EXT_V5ExP, do_qadd}, - {"qsub", 0xe1200050, 4, ARM_EXT_V5ExP, do_qadd}, - {"qdsub", 0xe1600050, 5, ARM_EXT_V5ExP, do_qadd}, - - /* ARM Architecture 5TE. */ - {"pld", 0xf450f000, 0, ARM_EXT_V5E, do_pld}, - {"ldrd", 0xe00000d0, 3, ARM_EXT_V5E, do_ldrd}, - {"strd", 0xe00000f0, 3, ARM_EXT_V5E, do_ldrd}, - - {"mcrr", 0xec400000, 4, ARM_EXT_V5E, do_co_reg2c}, - {"mrrc", 0xec500000, 4, ARM_EXT_V5E, do_co_reg2c}, - - /* ARM Architecture 5TEJ. */ - {"bxj", 0xe12fff20, 3, ARM_EXT_V5J, do_bxj}, - - /* ARM V6. */ - { "cps", 0xf1020000, 0, ARM_EXT_V6, do_cps}, - { "cpsie", 0xf1080000, 0, ARM_EXT_V6, do_cpsi}, - { "cpsid", 0xf10C0000, 0, ARM_EXT_V6, do_cpsi}, - { "ldrex", 0xe1900f9f, 5, ARM_EXT_V6, do_ldrex}, - { "mcrr2", 0xfc400000, 0, ARM_EXT_V6, do_co_reg2c}, - { "mrrc2", 0xfc500000, 0, ARM_EXT_V6, do_co_reg2c}, - { "pkhbt", 0xe6800010, 5, ARM_EXT_V6, do_pkhbt}, - { "pkhtb", 0xe6800050, 5, ARM_EXT_V6, do_pkhtb}, - { "qadd16", 0xe6200f10, 6, ARM_EXT_V6, do_qadd16}, - { "qadd8", 0xe6200f90, 5, ARM_EXT_V6, do_qadd16}, - { "qaddsubx", 0xe6200f30, 8, ARM_EXT_V6, do_qadd16}, - { "qsub16", 0xe6200f70, 6, ARM_EXT_V6, do_qadd16}, - { "qsub8", 0xe6200ff0, 5, ARM_EXT_V6, do_qadd16}, - { "qsubaddx", 0xe6200f50, 8, ARM_EXT_V6, do_qadd16}, - { "sadd16", 0xe6100f10, 6, ARM_EXT_V6, do_qadd16}, - { "sadd8", 0xe6100f90, 5, ARM_EXT_V6, do_qadd16}, - { "saddsubx", 0xe6100f30, 8, ARM_EXT_V6, do_qadd16}, - { "shadd16", 0xe6300f10, 7, ARM_EXT_V6, do_qadd16}, - { "shadd8", 0xe6300f90, 6, ARM_EXT_V6, do_qadd16}, - { "shaddsubx", 0xe6300f30, 9, ARM_EXT_V6, do_qadd16}, - { "shsub16", 0xe6300f70, 7, ARM_EXT_V6, do_qadd16}, - { "shsub8", 0xe6300ff0, 6, ARM_EXT_V6, do_qadd16}, - { "shsubaddx", 0xe6300f50, 9, ARM_EXT_V6, do_qadd16}, - { "ssub16", 0xe6100f70, 6, ARM_EXT_V6, do_qadd16}, - { "ssub8", 0xe6100ff0, 5, ARM_EXT_V6, do_qadd16}, - { "ssubaddx", 0xe6100f50, 8, ARM_EXT_V6, do_qadd16}, - { "uadd16", 0xe6500f10, 6, ARM_EXT_V6, do_qadd16}, - { "uadd8", 0xe6500f90, 5, ARM_EXT_V6, do_qadd16}, - { "uaddsubx", 0xe6500f30, 8, ARM_EXT_V6, do_qadd16}, - { "uhadd16", 0xe6700f10, 7, ARM_EXT_V6, do_qadd16}, - { "uhadd8", 0xe6700f90, 6, ARM_EXT_V6, do_qadd16}, - { "uhaddsubx", 0xe6700f30, 9, ARM_EXT_V6, do_qadd16}, - { "uhsub16", 0xe6700f70, 7, ARM_EXT_V6, do_qadd16}, - { "uhsub8", 0xe6700ff0, 6, ARM_EXT_V6, do_qadd16}, - { "uhsubaddx", 0xe6700f50, 9, ARM_EXT_V6, do_qadd16}, - { "uqadd16", 0xe6600f10, 7, ARM_EXT_V6, do_qadd16}, - { "uqadd8", 0xe6600f90, 6, ARM_EXT_V6, do_qadd16}, - { "uqaddsubx", 0xe6600f30, 9, ARM_EXT_V6, do_qadd16}, - { "uqsub16", 0xe6600f70, 7, ARM_EXT_V6, do_qadd16}, - { "uqsub8", 0xe6600ff0, 6, ARM_EXT_V6, do_qadd16}, - { "uqsubaddx", 0xe6600f50, 9, ARM_EXT_V6, do_qadd16}, - { "usub16", 0xe6500f70, 6, ARM_EXT_V6, do_qadd16}, - { "usub8", 0xe6500ff0, 5, ARM_EXT_V6, do_qadd16}, - { "usubaddx", 0xe6500f50, 8, ARM_EXT_V6, do_qadd16}, - { "rev", 0xe6bf0f30, 3, ARM_EXT_V6, do_rev}, - { "rev16", 0xe6bf0fb0, 5, ARM_EXT_V6, do_rev}, - { "revsh", 0xe6ff0fb0, 5, ARM_EXT_V6, do_rev}, - { "rfeia", 0xf8900a00, 0, ARM_EXT_V6, do_rfe}, - { "rfeib", 0xf9900a00, 0, ARM_EXT_V6, do_rfe}, - { "rfeda", 0xf8100a00, 0, ARM_EXT_V6, do_rfe}, - { "rfedb", 0xf9100a00, 0, ARM_EXT_V6, do_rfe}, - { "rfefd", 0xf8900a00, 0, ARM_EXT_V6, do_rfe}, - { "rfefa", 0xf9900a00, 0, ARM_EXT_V6, do_rfe}, - { "rfeea", 0xf8100a00, 0, ARM_EXT_V6, do_rfe}, - { "rfeed", 0xf9100a00, 0, ARM_EXT_V6, do_rfe}, - { "sxtah", 0xe6b00070, 5, ARM_EXT_V6, do_sxtah}, - { "sxtab16", 0xe6800070, 7, ARM_EXT_V6, do_sxtah}, - { "sxtab", 0xe6a00070, 5, ARM_EXT_V6, do_sxtah}, - { "sxth", 0xe6bf0070, 4, ARM_EXT_V6, do_sxth}, - { "sxtb16", 0xe68f0070, 6, ARM_EXT_V6, do_sxth}, - { "sxtb", 0xe6af0070, 4, ARM_EXT_V6, do_sxth}, - { "uxtah", 0xe6f00070, 5, ARM_EXT_V6, do_sxtah}, - { "uxtab16", 0xe6c00070, 7, ARM_EXT_V6, do_sxtah}, - { "uxtab", 0xe6e00070, 5, ARM_EXT_V6, do_sxtah}, - { "uxth", 0xe6ff0070, 4, ARM_EXT_V6, do_sxth}, - { "uxtb16", 0xe6cf0070, 6, ARM_EXT_V6, do_sxth}, - { "uxtb", 0xe6ef0070, 4, ARM_EXT_V6, do_sxth}, - { "sel", 0xe68000b0, 3, ARM_EXT_V6, do_qadd16}, - { "setend", 0xf1010000, 0, ARM_EXT_V6, do_setend}, - { "smlad", 0xe7000010, 5, ARM_EXT_V6, do_smlad}, - { "smladx", 0xe7000030, 6, ARM_EXT_V6, do_smlad}, - { "smlald", 0xe7400010, 6, ARM_EXT_V6, do_smlald}, - { "smlaldx", 0xe7400030, 7, ARM_EXT_V6, do_smlald}, - { "smlsd", 0xe7000050, 5, ARM_EXT_V6, do_smlad}, - { "smlsdx", 0xe7000070, 6, ARM_EXT_V6, do_smlad}, - { "smlsld", 0xe7400050, 6, ARM_EXT_V6, do_smlald}, - { "smlsldx", 0xe7400070, 7, ARM_EXT_V6, do_smlald}, - { "smmla", 0xe7500010, 5, ARM_EXT_V6, do_smlad}, - { "smmlar", 0xe7500030, 6, ARM_EXT_V6, do_smlad}, - { "smmls", 0xe75000d0, 5, ARM_EXT_V6, do_smlad}, - { "smmlsr", 0xe75000f0, 6, ARM_EXT_V6, do_smlad}, - { "smmul", 0xe750f010, 5, ARM_EXT_V6, do_smmul}, - { "smmulr", 0xe750f030, 6, ARM_EXT_V6, do_smmul}, - { "smuad", 0xe700f010, 5, ARM_EXT_V6, do_smmul}, - { "smuadx", 0xe700f030, 6, ARM_EXT_V6, do_smmul}, - { "smusd", 0xe700f050, 5, ARM_EXT_V6, do_smmul}, - { "smusdx", 0xe700f070, 6, ARM_EXT_V6, do_smmul}, - { "srsia", 0xf8cd0500, 0, ARM_EXT_V6, do_srs}, - { "srsib", 0xf9cd0500, 0, ARM_EXT_V6, do_srs}, - { "srsda", 0xf84d0500, 0, ARM_EXT_V6, do_srs}, - { "srsdb", 0xf94d0500, 0, ARM_EXT_V6, do_srs}, - { "ssat", 0xe6a00010, 4, ARM_EXT_V6, do_ssat}, - { "ssat16", 0xe6a00f30, 6, ARM_EXT_V6, do_ssat16}, - { "strex", 0xe1800f90, 5, ARM_EXT_V6, do_strex}, - { "umaal", 0xe0400090, 5, ARM_EXT_V6, do_umaal}, - { "usad8", 0xe780f010, 5, ARM_EXT_V6, do_smmul}, - { "usada8", 0xe7800010, 6, ARM_EXT_V6, do_smlad}, - { "usat", 0xe6e00010, 4, ARM_EXT_V6, do_usat}, - { "usat16", 0xe6e00f30, 6, ARM_EXT_V6, do_usat16}, - - /* ARM V6K. */ - { "clrex", 0xf57ff01f, 0, ARM_EXT_V6K, do_empty}, - { "ldrexb", 0xe1d00f9f, 6, ARM_EXT_V6K, do_ldrex}, - { "ldrexd", 0xe1b00f9f, 6, ARM_EXT_V6K, do_ldrex}, - { "ldrexh", 0xe1f00f9f, 6, ARM_EXT_V6K, do_ldrex}, - { "sev", 0xe320f004, 3, ARM_EXT_V6K, do_empty}, - { "strexb", 0xe1c00f90, 6, ARM_EXT_V6K, do_strex}, - { "strexd", 0xe1a00f90, 6, ARM_EXT_V6K, do_strex}, - { "strexh", 0xe1e00f90, 6, ARM_EXT_V6K, do_strex}, - { "wfe", 0xe320f002, 3, ARM_EXT_V6K, do_empty}, - { "wfi", 0xe320f003, 3, ARM_EXT_V6K, do_empty}, - { "yield", 0xe320f001, 5, ARM_EXT_V6K, do_empty}, - - /* ARM V6Z. */ - { "smi", 0xe1600070, 3, ARM_EXT_V6Z, do_smi}, - - /* ARM V6T2. */ - { "bfc", 0xe7c0001f, 3, ARM_EXT_V6T2, do_bfc}, - { "bfi", 0xe7c00010, 3, ARM_EXT_V6T2, do_bfi}, - { "mls", 0xe0600090, 3, ARM_EXT_V6T2, do_mls}, - { "movw", 0xe3000000, 4, ARM_EXT_V6T2, do_mov16}, - { "movt", 0xe3400000, 4, ARM_EXT_V6T2, do_mov16}, - { "rbit", 0xe3ff0f30, 4, ARM_EXT_V6T2, do_rbit}, - { "sbfx", 0xe7a00050, 4, ARM_EXT_V6T2, do_bfx}, - { "ubfx", 0xe7e00050, 4, ARM_EXT_V6T2, do_bfx}, - - { "ldrht", 0xe03000b0, 3, ARM_EXT_V6T2, do_ldsttv4}, - { "ldrsht", 0xe03000f0, 3, ARM_EXT_V6T2, do_ldsttv4}, - { "ldrsbt", 0xe03000d0, 3, ARM_EXT_V6T2, do_ldsttv4}, - { "strht", 0xe02000b0, 3, ARM_EXT_V6T2, do_ldsttv4}, - - /* Core FPA instruction set (V1). */ - {"wfs", 0xee200110, 3, FPU_FPA_EXT_V1, do_fpa_ctrl}, - {"rfs", 0xee300110, 3, FPU_FPA_EXT_V1, do_fpa_ctrl}, - {"wfc", 0xee400110, 3, FPU_FPA_EXT_V1, do_fpa_ctrl}, - {"rfc", 0xee500110, 3, FPU_FPA_EXT_V1, do_fpa_ctrl}, - - {"ldfs", 0xec100100, 3, FPU_FPA_EXT_V1, do_fpa_ldst}, - {"ldfd", 0xec108100, 3, FPU_FPA_EXT_V1, do_fpa_ldst}, - {"ldfe", 0xec500100, 3, FPU_FPA_EXT_V1, do_fpa_ldst}, - {"ldfp", 0xec508100, 3, FPU_FPA_EXT_V1, do_fpa_ldst}, - - {"stfs", 0xec000100, 3, FPU_FPA_EXT_V1, do_fpa_ldst}, - {"stfd", 0xec008100, 3, FPU_FPA_EXT_V1, do_fpa_ldst}, - {"stfe", 0xec400100, 3, FPU_FPA_EXT_V1, do_fpa_ldst}, - {"stfp", 0xec408100, 3, FPU_FPA_EXT_V1, do_fpa_ldst}, - - {"mvfs", 0xee008100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"mvfsp", 0xee008120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"mvfsm", 0xee008140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"mvfsz", 0xee008160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"mvfd", 0xee008180, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"mvfdp", 0xee0081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"mvfdm", 0xee0081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"mvfdz", 0xee0081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"mvfe", 0xee088100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"mvfep", 0xee088120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"mvfem", 0xee088140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"mvfez", 0xee088160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - - {"mnfs", 0xee108100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"mnfsp", 0xee108120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"mnfsm", 0xee108140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"mnfsz", 0xee108160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"mnfd", 0xee108180, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"mnfdp", 0xee1081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"mnfdm", 0xee1081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"mnfdz", 0xee1081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"mnfe", 0xee188100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"mnfep", 0xee188120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"mnfem", 0xee188140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"mnfez", 0xee188160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - - {"abss", 0xee208100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"abssp", 0xee208120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"abssm", 0xee208140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"abssz", 0xee208160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"absd", 0xee208180, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"absdp", 0xee2081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"absdm", 0xee2081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"absdz", 0xee2081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"abse", 0xee288100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"absep", 0xee288120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"absem", 0xee288140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"absez", 0xee288160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - - {"rnds", 0xee308100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"rndsp", 0xee308120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"rndsm", 0xee308140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"rndsz", 0xee308160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"rndd", 0xee308180, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"rnddp", 0xee3081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"rnddm", 0xee3081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"rnddz", 0xee3081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"rnde", 0xee388100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"rndep", 0xee388120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"rndem", 0xee388140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"rndez", 0xee388160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - - {"sqts", 0xee408100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"sqtsp", 0xee408120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"sqtsm", 0xee408140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"sqtsz", 0xee408160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"sqtd", 0xee408180, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"sqtdp", 0xee4081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"sqtdm", 0xee4081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"sqtdz", 0xee4081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"sqte", 0xee488100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"sqtep", 0xee488120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"sqtem", 0xee488140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"sqtez", 0xee488160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - - {"logs", 0xee508100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"logsp", 0xee508120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"logsm", 0xee508140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"logsz", 0xee508160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"logd", 0xee508180, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"logdp", 0xee5081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"logdm", 0xee5081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"logdz", 0xee5081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"loge", 0xee588100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"logep", 0xee588120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"logem", 0xee588140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"logez", 0xee588160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - - {"lgns", 0xee608100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"lgnsp", 0xee608120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"lgnsm", 0xee608140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"lgnsz", 0xee608160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"lgnd", 0xee608180, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"lgndp", 0xee6081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"lgndm", 0xee6081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"lgndz", 0xee6081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"lgne", 0xee688100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"lgnep", 0xee688120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"lgnem", 0xee688140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"lgnez", 0xee688160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - - {"exps", 0xee708100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"expsp", 0xee708120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"expsm", 0xee708140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"expsz", 0xee708160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"expd", 0xee708180, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"expdp", 0xee7081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"expdm", 0xee7081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"expdz", 0xee7081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"expe", 0xee788100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"expep", 0xee788120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"expem", 0xee788140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"expdz", 0xee788160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - - {"sins", 0xee808100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"sinsp", 0xee808120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"sinsm", 0xee808140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"sinsz", 0xee808160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"sind", 0xee808180, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"sindp", 0xee8081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"sindm", 0xee8081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"sindz", 0xee8081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"sine", 0xee888100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"sinep", 0xee888120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"sinem", 0xee888140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"sinez", 0xee888160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - - {"coss", 0xee908100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"cossp", 0xee908120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"cossm", 0xee908140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"cossz", 0xee908160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"cosd", 0xee908180, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"cosdp", 0xee9081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"cosdm", 0xee9081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"cosdz", 0xee9081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"cose", 0xee988100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"cosep", 0xee988120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"cosem", 0xee988140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"cosez", 0xee988160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - - {"tans", 0xeea08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"tansp", 0xeea08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"tansm", 0xeea08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"tansz", 0xeea08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"tand", 0xeea08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"tandp", 0xeea081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"tandm", 0xeea081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"tandz", 0xeea081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"tane", 0xeea88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"tanep", 0xeea88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"tanem", 0xeea88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"tanez", 0xeea88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - - {"asns", 0xeeb08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"asnsp", 0xeeb08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"asnsm", 0xeeb08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"asnsz", 0xeeb08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"asnd", 0xeeb08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"asndp", 0xeeb081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"asndm", 0xeeb081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"asndz", 0xeeb081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"asne", 0xeeb88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"asnep", 0xeeb88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"asnem", 0xeeb88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"asnez", 0xeeb88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - - {"acss", 0xeec08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"acssp", 0xeec08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"acssm", 0xeec08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"acssz", 0xeec08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"acsd", 0xeec08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"acsdp", 0xeec081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"acsdm", 0xeec081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"acsdz", 0xeec081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"acse", 0xeec88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"acsep", 0xeec88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"acsem", 0xeec88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"acsez", 0xeec88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - - {"atns", 0xeed08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"atnsp", 0xeed08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"atnsm", 0xeed08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"atnsz", 0xeed08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"atnd", 0xeed08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"atndp", 0xeed081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"atndm", 0xeed081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"atndz", 0xeed081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"atne", 0xeed88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"atnep", 0xeed88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"atnem", 0xeed88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"atnez", 0xeed88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - - {"urds", 0xeee08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"urdsp", 0xeee08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"urdsm", 0xeee08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"urdsz", 0xeee08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"urdd", 0xeee08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"urddp", 0xeee081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"urddm", 0xeee081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"urddz", 0xeee081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"urde", 0xeee88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"urdep", 0xeee88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"urdem", 0xeee88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"urdez", 0xeee88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - - {"nrms", 0xeef08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"nrmsp", 0xeef08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"nrmsm", 0xeef08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"nrmsz", 0xeef08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"nrmd", 0xeef08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"nrmdp", 0xeef081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"nrmdm", 0xeef081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"nrmdz", 0xeef081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"nrme", 0xeef88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"nrmep", 0xeef88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"nrmem", 0xeef88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - {"nrmez", 0xeef88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic}, - - {"adfs", 0xee000100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"adfsp", 0xee000120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"adfsm", 0xee000140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"adfsz", 0xee000160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"adfd", 0xee000180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"adfdp", 0xee0001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"adfdm", 0xee0001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"adfdz", 0xee0001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"adfe", 0xee080100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"adfep", 0xee080120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"adfem", 0xee080140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"adfez", 0xee080160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - - {"sufs", 0xee200100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"sufsp", 0xee200120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"sufsm", 0xee200140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"sufsz", 0xee200160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"sufd", 0xee200180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"sufdp", 0xee2001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"sufdm", 0xee2001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"sufdz", 0xee2001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"sufe", 0xee280100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"sufep", 0xee280120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"sufem", 0xee280140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"sufez", 0xee280160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - - {"rsfs", 0xee300100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rsfsp", 0xee300120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rsfsm", 0xee300140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rsfsz", 0xee300160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rsfd", 0xee300180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rsfdp", 0xee3001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rsfdm", 0xee3001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rsfdz", 0xee3001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rsfe", 0xee380100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rsfep", 0xee380120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rsfem", 0xee380140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rsfez", 0xee380160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - - {"mufs", 0xee100100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"mufsp", 0xee100120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"mufsm", 0xee100140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"mufsz", 0xee100160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"mufd", 0xee100180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"mufdp", 0xee1001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"mufdm", 0xee1001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"mufdz", 0xee1001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"mufe", 0xee180100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"mufep", 0xee180120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"mufem", 0xee180140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"mufez", 0xee180160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - - {"dvfs", 0xee400100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"dvfsp", 0xee400120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"dvfsm", 0xee400140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"dvfsz", 0xee400160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"dvfd", 0xee400180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"dvfdp", 0xee4001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"dvfdm", 0xee4001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"dvfdz", 0xee4001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"dvfe", 0xee480100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"dvfep", 0xee480120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"dvfem", 0xee480140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"dvfez", 0xee480160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - - {"rdfs", 0xee500100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rdfsp", 0xee500120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rdfsm", 0xee500140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rdfsz", 0xee500160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rdfd", 0xee500180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rdfdp", 0xee5001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rdfdm", 0xee5001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rdfdz", 0xee5001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rdfe", 0xee580100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rdfep", 0xee580120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rdfem", 0xee580140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rdfez", 0xee580160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - - {"pows", 0xee600100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"powsp", 0xee600120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"powsm", 0xee600140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"powsz", 0xee600160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"powd", 0xee600180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"powdp", 0xee6001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"powdm", 0xee6001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"powdz", 0xee6001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"powe", 0xee680100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"powep", 0xee680120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"powem", 0xee680140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"powez", 0xee680160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - - {"rpws", 0xee700100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rpwsp", 0xee700120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rpwsm", 0xee700140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rpwsz", 0xee700160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rpwd", 0xee700180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rpwdp", 0xee7001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rpwdm", 0xee7001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rpwdz", 0xee7001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rpwe", 0xee780100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rpwep", 0xee780120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rpwem", 0xee780140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rpwez", 0xee780160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - - {"rmfs", 0xee800100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rmfsp", 0xee800120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rmfsm", 0xee800140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rmfsz", 0xee800160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rmfd", 0xee800180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rmfdp", 0xee8001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rmfdm", 0xee8001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rmfdz", 0xee8001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rmfe", 0xee880100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rmfep", 0xee880120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rmfem", 0xee880140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"rmfez", 0xee880160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - - {"fmls", 0xee900100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"fmlsp", 0xee900120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"fmlsm", 0xee900140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"fmlsz", 0xee900160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"fmld", 0xee900180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"fmldp", 0xee9001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"fmldm", 0xee9001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"fmldz", 0xee9001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"fmle", 0xee980100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"fmlep", 0xee980120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"fmlem", 0xee980140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"fmlez", 0xee980160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - - {"fdvs", 0xeea00100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"fdvsp", 0xeea00120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"fdvsm", 0xeea00140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"fdvsz", 0xeea00160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"fdvd", 0xeea00180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"fdvdp", 0xeea001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"fdvdm", 0xeea001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"fdvdz", 0xeea001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"fdve", 0xeea80100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"fdvep", 0xeea80120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"fdvem", 0xeea80140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"fdvez", 0xeea80160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - - {"frds", 0xeeb00100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"frdsp", 0xeeb00120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"frdsm", 0xeeb00140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"frdsz", 0xeeb00160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"frdd", 0xeeb00180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"frddp", 0xeeb001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"frddm", 0xeeb001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"frddz", 0xeeb001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"frde", 0xeeb80100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"frdep", 0xeeb80120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"frdem", 0xeeb80140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"frdez", 0xeeb80160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - - {"pols", 0xeec00100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"polsp", 0xeec00120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"polsm", 0xeec00140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"polsz", 0xeec00160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"pold", 0xeec00180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"poldp", 0xeec001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"poldm", 0xeec001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"poldz", 0xeec001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"pole", 0xeec80100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"polep", 0xeec80120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"polem", 0xeec80140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - {"polez", 0xeec80160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic}, - - {"cmf", 0xee90f110, 3, FPU_FPA_EXT_V1, do_fpa_cmp}, - {"cmfe", 0xeed0f110, 3, FPU_FPA_EXT_V1, do_fpa_cmp}, - {"cnf", 0xeeb0f110, 3, FPU_FPA_EXT_V1, do_fpa_cmp}, - {"cnfe", 0xeef0f110, 3, FPU_FPA_EXT_V1, do_fpa_cmp}, - /* The FPA10 data sheet suggests that the 'E' of cmfe/cnfe should - not be an optional suffix, but part of the instruction. To be - compatible, we accept either. */ - {"cmfe", 0xeed0f110, 4, FPU_FPA_EXT_V1, do_fpa_cmp}, - {"cnfe", 0xeef0f110, 4, FPU_FPA_EXT_V1, do_fpa_cmp}, - - {"flts", 0xee000110, 3, FPU_FPA_EXT_V1, do_fpa_from_reg}, - {"fltsp", 0xee000130, 3, FPU_FPA_EXT_V1, do_fpa_from_reg}, - {"fltsm", 0xee000150, 3, FPU_FPA_EXT_V1, do_fpa_from_reg}, - {"fltsz", 0xee000170, 3, FPU_FPA_EXT_V1, do_fpa_from_reg}, - {"fltd", 0xee000190, 3, FPU_FPA_EXT_V1, do_fpa_from_reg}, - {"fltdp", 0xee0001b0, 3, FPU_FPA_EXT_V1, do_fpa_from_reg}, - {"fltdm", 0xee0001d0, 3, FPU_FPA_EXT_V1, do_fpa_from_reg}, - {"fltdz", 0xee0001f0, 3, FPU_FPA_EXT_V1, do_fpa_from_reg}, - {"flte", 0xee080110, 3, FPU_FPA_EXT_V1, do_fpa_from_reg}, - {"fltep", 0xee080130, 3, FPU_FPA_EXT_V1, do_fpa_from_reg}, - {"fltem", 0xee080150, 3, FPU_FPA_EXT_V1, do_fpa_from_reg}, - {"fltez", 0xee080170, 3, FPU_FPA_EXT_V1, do_fpa_from_reg}, - - /* The implementation of the FIX instruction is broken on some - assemblers, in that it accepts a precision specifier as well as a - rounding specifier, despite the fact that this is meaningless. - To be more compatible, we accept it as well, though of course it - does not set any bits. */ - {"fix", 0xee100110, 3, FPU_FPA_EXT_V1, do_fpa_to_reg}, - {"fixp", 0xee100130, 3, FPU_FPA_EXT_V1, do_fpa_to_reg}, - {"fixm", 0xee100150, 3, FPU_FPA_EXT_V1, do_fpa_to_reg}, - {"fixz", 0xee100170, 3, FPU_FPA_EXT_V1, do_fpa_to_reg}, - {"fixsp", 0xee100130, 3, FPU_FPA_EXT_V1, do_fpa_to_reg}, - {"fixsm", 0xee100150, 3, FPU_FPA_EXT_V1, do_fpa_to_reg}, - {"fixsz", 0xee100170, 3, FPU_FPA_EXT_V1, do_fpa_to_reg}, - {"fixdp", 0xee100130, 3, FPU_FPA_EXT_V1, do_fpa_to_reg}, - {"fixdm", 0xee100150, 3, FPU_FPA_EXT_V1, do_fpa_to_reg}, - {"fixdz", 0xee100170, 3, FPU_FPA_EXT_V1, do_fpa_to_reg}, - {"fixep", 0xee100130, 3, FPU_FPA_EXT_V1, do_fpa_to_reg}, - {"fixem", 0xee100150, 3, FPU_FPA_EXT_V1, do_fpa_to_reg}, - {"fixez", 0xee100170, 3, FPU_FPA_EXT_V1, do_fpa_to_reg}, - - /* Instructions that were new with the real FPA, call them V2. */ - {"lfm", 0xec100200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm}, - {"lfmfd", 0xec900200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm}, - {"lfmea", 0xed100200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm}, - {"sfm", 0xec000200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm}, - {"sfmfd", 0xed000200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm}, - {"sfmea", 0xec800200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm}, - - /* VFP V1xD (single precision). */ - /* Moves and type conversions. */ - {"fcpys", 0xeeb00a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic}, - {"fmrs", 0xee100a10, 4, FPU_VFP_EXT_V1xD, do_vfp_reg_from_sp}, - {"fmsr", 0xee000a10, 4, FPU_VFP_EXT_V1xD, do_vfp_sp_from_reg}, - {"fmstat", 0xeef1fa10, 6, FPU_VFP_EXT_V1xD, do_empty}, - {"fsitos", 0xeeb80ac0, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic}, - {"fuitos", 0xeeb80a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic}, - {"ftosis", 0xeebd0a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic}, - {"ftosizs", 0xeebd0ac0, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic}, - {"ftouis", 0xeebc0a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic}, - {"ftouizs", 0xeebc0ac0, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic}, - {"fmrx", 0xeef00a10, 4, FPU_VFP_EXT_V1xD, do_vfp_reg_from_ctrl}, - {"fmxr", 0xeee00a10, 4, FPU_VFP_EXT_V1xD, do_vfp_ctrl_from_reg}, - - /* Memory operations. */ - {"flds", 0xed100a00, 4, FPU_VFP_EXT_V1xD, do_vfp_sp_ldst}, - {"fsts", 0xed000a00, 4, FPU_VFP_EXT_V1xD, do_vfp_sp_ldst}, - {"fldmias", 0xec900a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia}, - {"fldmfds", 0xec900a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia}, - {"fldmdbs", 0xed300a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb}, - {"fldmeas", 0xed300a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb}, - {"fldmiax", 0xec900b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia}, - {"fldmfdx", 0xec900b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia}, - {"fldmdbx", 0xed300b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb}, - {"fldmeax", 0xed300b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb}, - {"fstmias", 0xec800a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia}, - {"fstmeas", 0xec800a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia}, - {"fstmdbs", 0xed200a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb}, - {"fstmfds", 0xed200a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb}, - {"fstmiax", 0xec800b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia}, - {"fstmeax", 0xec800b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia}, - {"fstmdbx", 0xed200b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb}, - {"fstmfdx", 0xed200b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb}, - - /* Monadic operations. */ - {"fabss", 0xeeb00ac0, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic}, - {"fnegs", 0xeeb10a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic}, - {"fsqrts", 0xeeb10ac0, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic}, - - /* Dyadic operations. */ - {"fadds", 0xee300a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic}, - {"fsubs", 0xee300a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic}, - {"fmuls", 0xee200a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic}, - {"fdivs", 0xee800a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic}, - {"fmacs", 0xee000a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic}, - {"fmscs", 0xee100a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic}, - {"fnmuls", 0xee200a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic}, - {"fnmacs", 0xee000a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic}, - {"fnmscs", 0xee100a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic}, - - /* Comparisons. */ - {"fcmps", 0xeeb40a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic}, - {"fcmpzs", 0xeeb50a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_compare_z}, - {"fcmpes", 0xeeb40ac0, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic}, - {"fcmpezs", 0xeeb50ac0, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_compare_z}, + valueT op; - /* VFP V1 (Double precision). */ - /* Moves and type conversions. */ - {"fcpyd", 0xeeb00b40, 5, FPU_VFP_EXT_V1, do_vfp_dp_monadic}, - {"fcvtds", 0xeeb70ac0, 6, FPU_VFP_EXT_V1, do_vfp_dp_sp_cvt}, - {"fcvtsd", 0xeeb70bc0, 6, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt}, - {"fmdhr", 0xee200b10, 5, FPU_VFP_EXT_V1, do_vfp_dp_from_reg}, - {"fmdlr", 0xee000b10, 5, FPU_VFP_EXT_V1, do_vfp_dp_from_reg}, - {"fmrdh", 0xee300b10, 5, FPU_VFP_EXT_V1, do_vfp_reg_from_dp}, - {"fmrdl", 0xee100b10, 5, FPU_VFP_EXT_V1, do_vfp_reg_from_dp}, - {"fsitod", 0xeeb80bc0, 6, FPU_VFP_EXT_V1, do_vfp_dp_sp_cvt}, - {"fuitod", 0xeeb80b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_sp_cvt}, - {"ftosid", 0xeebd0b40, 6, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt}, - {"ftosizd", 0xeebd0bc0, 7, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt}, - {"ftouid", 0xeebc0b40, 6, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt}, - {"ftouizd", 0xeebc0bc0, 7, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt}, - - /* Memory operations. */ - {"fldd", 0xed100b00, 4, FPU_VFP_EXT_V1, do_vfp_dp_ldst}, - {"fstd", 0xed000b00, 4, FPU_VFP_EXT_V1, do_vfp_dp_ldst}, - {"fldmiad", 0xec900b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmia}, - {"fldmfdd", 0xec900b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmia}, - {"fldmdbd", 0xed300b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmdb}, - {"fldmead", 0xed300b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmdb}, - {"fstmiad", 0xec800b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmia}, - {"fstmead", 0xec800b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmia}, - {"fstmdbd", 0xed200b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmdb}, - {"fstmfdd", 0xed200b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmdb}, + if (unwind.fp_used) + { + /* Adjust sp as neccessary. */ + unwind.pending_offset += unwind.fp_offset - unwind.frame_size; + flush_pending_unwind (); - /* Monadic operations. */ - {"fabsd", 0xeeb00bc0, 5, FPU_VFP_EXT_V1, do_vfp_dp_monadic}, - {"fnegd", 0xeeb10b40, 5, FPU_VFP_EXT_V1, do_vfp_dp_monadic}, - {"fsqrtd", 0xeeb10bc0, 6, FPU_VFP_EXT_V1, do_vfp_dp_monadic}, - - /* Dyadic operations. */ - {"faddd", 0xee300b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic}, - {"fsubd", 0xee300b40, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic}, - {"fmuld", 0xee200b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic}, - {"fdivd", 0xee800b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic}, - {"fmacd", 0xee000b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic}, - {"fmscd", 0xee100b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic}, - {"fnmuld", 0xee200b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_dyadic}, - {"fnmacd", 0xee000b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_dyadic}, - {"fnmscd", 0xee100b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_dyadic}, + /* After restoring sp from the frame pointer. */ + op = 0x90 | unwind.fp_reg; + add_unwind_opcode (op, 1); + } + else + flush_pending_unwind (); +} - /* Comparisons. */ - {"fcmpd", 0xeeb40b40, 5, FPU_VFP_EXT_V1, do_vfp_dp_monadic}, - {"fcmpzd", 0xeeb50b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_compare_z}, - {"fcmped", 0xeeb40bc0, 6, FPU_VFP_EXT_V1, do_vfp_dp_monadic}, - {"fcmpezd", 0xeeb50bc0, 7, FPU_VFP_EXT_V1, do_vfp_dp_compare_z}, - - /* VFP V2. */ - {"fmsrr", 0xec400a10, 5, FPU_VFP_EXT_V2, do_vfp_sp2_from_reg2}, - {"fmrrs", 0xec500a10, 5, FPU_VFP_EXT_V2, do_vfp_reg2_from_sp2}, - {"fmdrr", 0xec400b10, 5, FPU_VFP_EXT_V2, do_vfp_dp_from_reg2}, - {"fmrrd", 0xec500b10, 5, FPU_VFP_EXT_V2, do_vfp_reg2_from_dp}, - - /* Intel XScale extensions to ARM V5 ISA. (All use CP0). */ - {"mia", 0xee200010, 3, ARM_CEXT_XSCALE, do_xsc_mia}, - {"miaph", 0xee280010, 5, ARM_CEXT_XSCALE, do_xsc_mia}, - {"miabb", 0xee2c0010, 5, ARM_CEXT_XSCALE, do_xsc_mia}, - {"miabt", 0xee2d0010, 5, ARM_CEXT_XSCALE, do_xsc_mia}, - {"miatb", 0xee2e0010, 5, ARM_CEXT_XSCALE, do_xsc_mia}, - {"miatt", 0xee2f0010, 5, ARM_CEXT_XSCALE, do_xsc_mia}, - {"mar", 0xec400000, 3, ARM_CEXT_XSCALE, do_xsc_mar}, - {"mra", 0xec500000, 3, ARM_CEXT_XSCALE, do_xsc_mra}, - - /* Intel Wireless MMX technology instructions. */ - {"tandcb", 0xee130130, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tandc}, - {"tandch", 0xee530130, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tandc}, - {"tandcw", 0xee930130, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tandc}, - {"tbcstb", 0xee400010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tbcst}, - {"tbcsth", 0xee400050, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tbcst}, - {"tbcstw", 0xee400090, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tbcst}, - {"textrcb", 0xee130170, 7, ARM_CEXT_IWMMXT, do_iwmmxt_textrc}, - {"textrch", 0xee530170, 7, ARM_CEXT_IWMMXT, do_iwmmxt_textrc}, - {"textrcw", 0xee930170, 7, ARM_CEXT_IWMMXT, do_iwmmxt_textrc}, - {"textrmub", 0xee100070, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm}, - {"textrmuh", 0xee500070, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm}, - {"textrmuw", 0xee900070, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm}, - {"textrmsb", 0xee100078, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm}, - {"textrmsh", 0xee500078, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm}, - {"textrmsw", 0xee900078, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm}, - {"tinsrb", 0xee600010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tinsr}, - {"tinsrh", 0xee600050, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tinsr}, - {"tinsrw", 0xee600090, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tinsr}, - {"tmcr", 0xee000110, 4, ARM_CEXT_IWMMXT, do_iwmmxt_tmcr}, - {"tmcrr", 0xec400000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_tmcrr}, - {"tmia", 0xee200010, 4, ARM_CEXT_IWMMXT, do_iwmmxt_tmia}, - {"tmiaph", 0xee280010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia}, - {"tmiabb", 0xee2c0010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia}, - {"tmiabt", 0xee2d0010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia}, - {"tmiatb", 0xee2e0010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia}, - {"tmiatt", 0xee2f0010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia}, - {"tmovmskb", 0xee100030, 8, ARM_CEXT_IWMMXT, do_iwmmxt_tmovmsk}, - {"tmovmskh", 0xee500030, 8, ARM_CEXT_IWMMXT, do_iwmmxt_tmovmsk}, - {"tmovmskw", 0xee900030, 8, ARM_CEXT_IWMMXT, do_iwmmxt_tmovmsk}, - {"tmrc", 0xee100110, 4, ARM_CEXT_IWMMXT, do_iwmmxt_tmrc}, - {"tmrrc", 0xec500000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_tmrrc}, - {"torcb", 0xee130150, 5, ARM_CEXT_IWMMXT, do_iwmmxt_torc}, - {"torch", 0xee530150, 5, ARM_CEXT_IWMMXT, do_iwmmxt_torc}, - {"torcw", 0xee930150, 5, ARM_CEXT_IWMMXT, do_iwmmxt_torc}, - {"waccb", 0xee0001c0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr}, - {"wacch", 0xee4001c0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr}, - {"waccw", 0xee8001c0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr}, - {"waddbss", 0xee300180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"waddb", 0xee000180, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"waddbus", 0xee100180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"waddhss", 0xee700180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"waddh", 0xee400180, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"waddhus", 0xee500180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"waddwss", 0xeeb00180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"waddw", 0xee800180, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"waddwus", 0xee900180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"waligni", 0xee000020, 7, ARM_CEXT_IWMMXT, do_iwmmxt_waligni}, - {"walignr0", 0xee800020, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"walignr1", 0xee900020, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"walignr2", 0xeea00020, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"walignr3", 0xeeb00020, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wand", 0xee200000, 4, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wandn", 0xee300000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wavg2b", 0xee800000, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wavg2br", 0xee900000, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wavg2h", 0xeec00000, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wavg2hr", 0xeed00000, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wcmpeqb", 0xee000060, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wcmpeqh", 0xee400060, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wcmpeqw", 0xee800060, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wcmpgtub", 0xee100060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wcmpgtuh", 0xee500060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wcmpgtuw", 0xee900060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wcmpgtsb", 0xee300060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wcmpgtsh", 0xee700060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wcmpgtsw", 0xeeb00060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wldrb", 0xec100000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_byte_addr}, - {"wldrh", 0xec100100, 5, ARM_CEXT_IWMMXT, do_iwmmxt_byte_addr}, - {"wldrw", 0xec100200, 5, ARM_CEXT_IWMMXT, do_iwmmxt_word_addr}, - {"wldrd", 0xec100300, 5, ARM_CEXT_IWMMXT, do_iwmmxt_word_addr}, - {"wmacs", 0xee600100, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wmacsz", 0xee700100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wmacu", 0xee400100, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wmacuz", 0xee500100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wmadds", 0xeea00100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wmaddu", 0xee800100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wmaxsb", 0xee200160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wmaxsh", 0xee600160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wmaxsw", 0xeea00160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wmaxub", 0xee000160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wmaxuh", 0xee400160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wmaxuw", 0xee800160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wminsb", 0xee300160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wminsh", 0xee700160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wminsw", 0xeeb00160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wminub", 0xee100160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wminuh", 0xee500160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wminuw", 0xee900160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wmov", 0xee000000, 4, ARM_CEXT_IWMMXT, do_iwmmxt_wmov}, - {"wmulsm", 0xee300100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wmulsl", 0xee200100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wmulum", 0xee100100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wmulul", 0xee000100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wor", 0xee000000, 3, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wpackhss", 0xee700080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wpackhus", 0xee500080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wpackwss", 0xeeb00080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wpackwus", 0xee900080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wpackdss", 0xeef00080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wpackdus", 0xeed00080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wrorh", 0xee700040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wrorhg", 0xee700148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg}, - {"wrorw", 0xeeb00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wrorwg", 0xeeb00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg}, - {"wrord", 0xeef00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wrordg", 0xeef00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg}, - {"wsadb", 0xee000120, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wsadbz", 0xee100120, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wsadh", 0xee400120, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wsadhz", 0xee500120, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wshufh", 0xee0001e0, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wshufh}, - {"wsllh", 0xee500040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wsllhg", 0xee500148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg}, - {"wsllw", 0xee900040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wsllwg", 0xee900148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg}, - {"wslld", 0xeed00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wslldg", 0xeed00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg}, - {"wsrah", 0xee400040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wsrahg", 0xee400148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg}, - {"wsraw", 0xee800040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wsrawg", 0xee800148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg}, - {"wsrad", 0xeec00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wsradg", 0xeec00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg}, - {"wsrlh", 0xee600040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wsrlhg", 0xee600148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg}, - {"wsrlw", 0xeea00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wsrlwg", 0xeea00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg}, - {"wsrld", 0xeee00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wsrldg", 0xeee00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg}, - {"wstrb", 0xec000000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_byte_addr}, - {"wstrh", 0xec000100, 5, ARM_CEXT_IWMMXT, do_iwmmxt_byte_addr}, - {"wstrw", 0xec000200, 5, ARM_CEXT_IWMMXT, do_iwmmxt_word_addr}, - {"wstrd", 0xec000300, 5, ARM_CEXT_IWMMXT, do_iwmmxt_word_addr}, - {"wsubbss", 0xee3001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wsubb", 0xee0001a0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wsubbus", 0xee1001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wsubhss", 0xee7001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wsubh", 0xee4001a0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wsubhus", 0xee5001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wsubwss", 0xeeb001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wsubw", 0xee8001a0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wsubwus", 0xee9001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wunpckehub", 0xee0000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr}, - {"wunpckehuh", 0xee4000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr}, - {"wunpckehuw", 0xee8000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr}, - {"wunpckehsb", 0xee2000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr}, - {"wunpckehsh", 0xee6000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr}, - {"wunpckehsw", 0xeea000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr}, - {"wunpckihb", 0xee1000c0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wunpckihh", 0xee5000c0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wunpckihw", 0xee9000c0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wunpckelub", 0xee0000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr}, - {"wunpckeluh", 0xee4000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr}, - {"wunpckeluw", 0xee8000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr}, - {"wunpckelsb", 0xee2000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr}, - {"wunpckelsh", 0xee6000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr}, - {"wunpckelsw", 0xeea000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr}, - {"wunpckilb", 0xee1000e0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wunpckilh", 0xee5000e0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wunpckilw", 0xee9000e0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wxor", 0xee100000, 4, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr}, - {"wzero", 0xee300000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wzero}, - - /* Cirrus Maverick instructions. */ - {"cfldrs", 0xec100400, 6, ARM_CEXT_MAVERICK, do_mav_ldst_1}, - {"cfldrd", 0xec500400, 6, ARM_CEXT_MAVERICK, do_mav_ldst_2}, - {"cfldr32", 0xec100500, 7, ARM_CEXT_MAVERICK, do_mav_ldst_3}, - {"cfldr64", 0xec500500, 7, ARM_CEXT_MAVERICK, do_mav_ldst_4}, - {"cfstrs", 0xec000400, 6, ARM_CEXT_MAVERICK, do_mav_ldst_1}, - {"cfstrd", 0xec400400, 6, ARM_CEXT_MAVERICK, do_mav_ldst_2}, - {"cfstr32", 0xec000500, 7, ARM_CEXT_MAVERICK, do_mav_ldst_3}, - {"cfstr64", 0xec400500, 7, ARM_CEXT_MAVERICK, do_mav_ldst_4}, - {"cfmvsr", 0xee000450, 6, ARM_CEXT_MAVERICK, do_mav_binops_2a}, - {"cfmvrs", 0xee100450, 6, ARM_CEXT_MAVERICK, do_mav_binops_1a}, - {"cfmvdlr", 0xee000410, 7, ARM_CEXT_MAVERICK, do_mav_binops_2b}, - {"cfmvrdl", 0xee100410, 7, ARM_CEXT_MAVERICK, do_mav_binops_1b}, - {"cfmvdhr", 0xee000430, 7, ARM_CEXT_MAVERICK, do_mav_binops_2b}, - {"cfmvrdh", 0xee100430, 7, ARM_CEXT_MAVERICK, do_mav_binops_1b}, - {"cfmv64lr", 0xee000510, 8, ARM_CEXT_MAVERICK, do_mav_binops_2c}, - {"cfmvr64l", 0xee100510, 8, ARM_CEXT_MAVERICK, do_mav_binops_1c}, - {"cfmv64hr", 0xee000530, 8, ARM_CEXT_MAVERICK, do_mav_binops_2c}, - {"cfmvr64h", 0xee100530, 8, ARM_CEXT_MAVERICK, do_mav_binops_1c}, - {"cfmval32", 0xee200440, 8, ARM_CEXT_MAVERICK, do_mav_binops_3a}, - {"cfmv32al", 0xee100440, 8, ARM_CEXT_MAVERICK, do_mav_binops_3b}, - {"cfmvam32", 0xee200460, 8, ARM_CEXT_MAVERICK, do_mav_binops_3a}, - {"cfmv32am", 0xee100460, 8, ARM_CEXT_MAVERICK, do_mav_binops_3b}, - {"cfmvah32", 0xee200480, 8, ARM_CEXT_MAVERICK, do_mav_binops_3a}, - {"cfmv32ah", 0xee100480, 8, ARM_CEXT_MAVERICK, do_mav_binops_3b}, - {"cfmva32", 0xee2004a0, 7, ARM_CEXT_MAVERICK, do_mav_binops_3a}, - {"cfmv32a", 0xee1004a0, 7, ARM_CEXT_MAVERICK, do_mav_binops_3b}, - {"cfmva64", 0xee2004c0, 7, ARM_CEXT_MAVERICK, do_mav_binops_3c}, - {"cfmv64a", 0xee1004c0, 7, ARM_CEXT_MAVERICK, do_mav_binops_3d}, - {"cfmvsc32", 0xee2004e0, 8, ARM_CEXT_MAVERICK, do_mav_dspsc_1}, - {"cfmv32sc", 0xee1004e0, 8, ARM_CEXT_MAVERICK, do_mav_dspsc_2}, - {"cfcpys", 0xee000400, 6, ARM_CEXT_MAVERICK, do_mav_binops_1d}, - {"cfcpyd", 0xee000420, 6, ARM_CEXT_MAVERICK, do_mav_binops_1e}, - {"cfcvtsd", 0xee000460, 7, ARM_CEXT_MAVERICK, do_mav_binops_1f}, - {"cfcvtds", 0xee000440, 7, ARM_CEXT_MAVERICK, do_mav_binops_1g}, - {"cfcvt32s", 0xee000480, 8, ARM_CEXT_MAVERICK, do_mav_binops_1h}, - {"cfcvt32d", 0xee0004a0, 8, ARM_CEXT_MAVERICK, do_mav_binops_1i}, - {"cfcvt64s", 0xee0004c0, 8, ARM_CEXT_MAVERICK, do_mav_binops_1j}, - {"cfcvt64d", 0xee0004e0, 8, ARM_CEXT_MAVERICK, do_mav_binops_1k}, - {"cfcvts32", 0xee100580, 8, ARM_CEXT_MAVERICK, do_mav_binops_1l}, - {"cfcvtd32", 0xee1005a0, 8, ARM_CEXT_MAVERICK, do_mav_binops_1m}, - {"cftruncs32", 0xee1005c0, 10, ARM_CEXT_MAVERICK, do_mav_binops_1l}, - {"cftruncd32", 0xee1005e0, 10, ARM_CEXT_MAVERICK, do_mav_binops_1m}, - {"cfrshl32", 0xee000550, 8, ARM_CEXT_MAVERICK, do_mav_triple_4a}, - {"cfrshl64", 0xee000570, 8, ARM_CEXT_MAVERICK, do_mav_triple_4b}, - {"cfsh32", 0xee000500, 6, ARM_CEXT_MAVERICK, do_mav_shift_1}, - {"cfsh64", 0xee200500, 6, ARM_CEXT_MAVERICK, do_mav_shift_2}, - {"cfcmps", 0xee100490, 6, ARM_CEXT_MAVERICK, do_mav_triple_5a}, - {"cfcmpd", 0xee1004b0, 6, ARM_CEXT_MAVERICK, do_mav_triple_5b}, - {"cfcmp32", 0xee100590, 7, ARM_CEXT_MAVERICK, do_mav_triple_5c}, - {"cfcmp64", 0xee1005b0, 7, ARM_CEXT_MAVERICK, do_mav_triple_5d}, - {"cfabss", 0xee300400, 6, ARM_CEXT_MAVERICK, do_mav_binops_1d}, - {"cfabsd", 0xee300420, 6, ARM_CEXT_MAVERICK, do_mav_binops_1e}, - {"cfnegs", 0xee300440, 6, ARM_CEXT_MAVERICK, do_mav_binops_1d}, - {"cfnegd", 0xee300460, 6, ARM_CEXT_MAVERICK, do_mav_binops_1e}, - {"cfadds", 0xee300480, 6, ARM_CEXT_MAVERICK, do_mav_triple_5e}, - {"cfaddd", 0xee3004a0, 6, ARM_CEXT_MAVERICK, do_mav_triple_5f}, - {"cfsubs", 0xee3004c0, 6, ARM_CEXT_MAVERICK, do_mav_triple_5e}, - {"cfsubd", 0xee3004e0, 6, ARM_CEXT_MAVERICK, do_mav_triple_5f}, - {"cfmuls", 0xee100400, 6, ARM_CEXT_MAVERICK, do_mav_triple_5e}, - {"cfmuld", 0xee100420, 6, ARM_CEXT_MAVERICK, do_mav_triple_5f}, - {"cfabs32", 0xee300500, 7, ARM_CEXT_MAVERICK, do_mav_binops_1n}, - {"cfabs64", 0xee300520, 7, ARM_CEXT_MAVERICK, do_mav_binops_1o}, - {"cfneg32", 0xee300540, 7, ARM_CEXT_MAVERICK, do_mav_binops_1n}, - {"cfneg64", 0xee300560, 7, ARM_CEXT_MAVERICK, do_mav_binops_1o}, - {"cfadd32", 0xee300580, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g}, - {"cfadd64", 0xee3005a0, 7, ARM_CEXT_MAVERICK, do_mav_triple_5h}, - {"cfsub32", 0xee3005c0, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g}, - {"cfsub64", 0xee3005e0, 7, ARM_CEXT_MAVERICK, do_mav_triple_5h}, - {"cfmul32", 0xee100500, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g}, - {"cfmul64", 0xee100520, 7, ARM_CEXT_MAVERICK, do_mav_triple_5h}, - {"cfmac32", 0xee100540, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g}, - {"cfmsc32", 0xee100560, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g}, - {"cfmadd32", 0xee000600, 8, ARM_CEXT_MAVERICK, do_mav_quad_6a}, - {"cfmsub32", 0xee100600, 8, ARM_CEXT_MAVERICK, do_mav_quad_6a}, - {"cfmadda32", 0xee200600, 9, ARM_CEXT_MAVERICK, do_mav_quad_6b}, - {"cfmsuba32", 0xee300600, 9, ARM_CEXT_MAVERICK, do_mav_quad_6b}, -}; -/* Iterate over the base tables to create the instruction patterns. */ +/* Start an exception table entry. If idx is nonzero this is an index table + entry. */ static void -build_arm_ops_hsh (void) +start_unwind_section (const segT text_seg, int idx) { - unsigned int i; - unsigned int j; - static struct obstack insn_obstack; - - obstack_begin (&insn_obstack, 4000); + const char * text_name; + const char * prefix; + const char * prefix_once; + const char * group_name; + size_t prefix_len; + size_t text_len; + char * sec_name; + size_t sec_name_len; + int type; + int flags; + int linkonce; - for (i = 0; i < sizeof (insns) / sizeof (struct asm_opcode); i++) + if (idx) { - const struct asm_opcode *insn = insns + i; - - if (insn->cond_offset != 0) - { - /* Insn supports conditional execution. Build the varaints - and insert them in the hash table. */ - for (j = 0; j < sizeof (conds) / sizeof (struct asm_cond); j++) - { - unsigned len = strlen (insn->template); - struct asm_opcode *new; - char *template; - - new = obstack_alloc (&insn_obstack, sizeof (struct asm_opcode)); - /* All condition codes are two characters. */ - template = obstack_alloc (&insn_obstack, len + 3); - - strncpy (template, insn->template, insn->cond_offset); - strcpy (template + insn->cond_offset, conds[j].template); - if (len > insn->cond_offset) - strcpy (template + insn->cond_offset + 2, - insn->template + insn->cond_offset); - new->template = template; - new->cond_offset = 0; - new->variant = insn->variant; - new->parms = insn->parms; - new->value = (insn->value & ~COND_MASK) | conds[j].value; - - hash_insert (arm_ops_hsh, new->template, (PTR) new); - } - } - /* Finally, insert the unconditional insn in the table directly; - no need to build a copy. */ - hash_insert (arm_ops_hsh, insn->template, (PTR) insn); + prefix = ELF_STRING_ARM_unwind; + prefix_once = ELF_STRING_ARM_unwind_once; + type = SHT_ARM_EXIDX; + } + else + { + prefix = ELF_STRING_ARM_unwind_info; + prefix_once = ELF_STRING_ARM_unwind_info_once; + type = SHT_PROGBITS; } -} - - -static const struct thumb_opcode tinsns[] = -{ - /* Thumb v1 (ARMv4T). */ - {"adc", 0x4140, 2, ARM_EXT_V4T, do_t_arit}, - {"add", 0x0000, 2, ARM_EXT_V4T, do_t_add}, - {"and", 0x4000, 2, ARM_EXT_V4T, do_t_arit}, - {"asr", 0x0000, 2, ARM_EXT_V4T, do_t_asr}, - {"b", T_OPCODE_BRANCH, 2, ARM_EXT_V4T, do_t_branch12}, - {"beq", 0xd0fe, 2, ARM_EXT_V4T, do_t_branch9}, - {"bne", 0xd1fe, 2, ARM_EXT_V4T, do_t_branch9}, - {"bcs", 0xd2fe, 2, ARM_EXT_V4T, do_t_branch9}, - {"bhs", 0xd2fe, 2, ARM_EXT_V4T, do_t_branch9}, - {"bcc", 0xd3fe, 2, ARM_EXT_V4T, do_t_branch9}, - {"bul", 0xd3fe, 2, ARM_EXT_V4T, do_t_branch9}, - {"blo", 0xd3fe, 2, ARM_EXT_V4T, do_t_branch9}, - {"bmi", 0xd4fe, 2, ARM_EXT_V4T, do_t_branch9}, - {"bpl", 0xd5fe, 2, ARM_EXT_V4T, do_t_branch9}, - {"bvs", 0xd6fe, 2, ARM_EXT_V4T, do_t_branch9}, - {"bvc", 0xd7fe, 2, ARM_EXT_V4T, do_t_branch9}, - {"bhi", 0xd8fe, 2, ARM_EXT_V4T, do_t_branch9}, - {"bls", 0xd9fe, 2, ARM_EXT_V4T, do_t_branch9}, - {"bge", 0xdafe, 2, ARM_EXT_V4T, do_t_branch9}, - {"blt", 0xdbfe, 2, ARM_EXT_V4T, do_t_branch9}, - {"bgt", 0xdcfe, 2, ARM_EXT_V4T, do_t_branch9}, - {"ble", 0xddfe, 2, ARM_EXT_V4T, do_t_branch9}, - {"bal", 0xdefe, 2, ARM_EXT_V4T, do_t_branch9}, - {"bic", 0x4380, 2, ARM_EXT_V4T, do_t_arit}, - {"bl", 0xf7fffffe, 4, ARM_EXT_V4T, do_t_branch23}, - {"bx", 0x4700, 2, ARM_EXT_V4T, do_t_bx}, - {"cmn", T_OPCODE_CMN, 2, ARM_EXT_V4T, do_t_arit}, - {"cmp", 0x0000, 2, ARM_EXT_V4T, do_t_compare}, - {"eor", 0x4040, 2, ARM_EXT_V4T, do_t_arit}, - {"ldmia", 0xc800, 2, ARM_EXT_V4T, do_t_ldmstm}, - {"ldr", 0x0000, 2, ARM_EXT_V4T, do_t_ldr}, - {"ldrb", 0x0000, 2, ARM_EXT_V4T, do_t_ldrb}, - {"ldrh", 0x0000, 2, ARM_EXT_V4T, do_t_ldrh}, - {"ldrsb", 0x5600, 2, ARM_EXT_V4T, do_t_lds}, - {"ldrsh", 0x5e00, 2, ARM_EXT_V4T, do_t_lds}, - {"ldsb", 0x5600, 2, ARM_EXT_V4T, do_t_lds}, - {"ldsh", 0x5e00, 2, ARM_EXT_V4T, do_t_lds}, - {"lsl", 0x0000, 2, ARM_EXT_V4T, do_t_lsl}, - {"lsr", 0x0000, 2, ARM_EXT_V4T, do_t_lsr}, - {"mov", 0x0000, 2, ARM_EXT_V4T, do_t_mov}, - {"mul", T_OPCODE_MUL, 2, ARM_EXT_V4T, do_t_arit}, - {"mvn", T_OPCODE_MVN, 2, ARM_EXT_V4T, do_t_arit}, - {"neg", T_OPCODE_NEG, 2, ARM_EXT_V4T, do_t_arit}, - {"orr", 0x4300, 2, ARM_EXT_V4T, do_t_arit}, - {"pop", 0xbc00, 2, ARM_EXT_V4T, do_t_push_pop}, - {"push", 0xb400, 2, ARM_EXT_V4T, do_t_push_pop}, - {"ror", 0x41c0, 2, ARM_EXT_V4T, do_t_arit}, - {"sbc", 0x4180, 2, ARM_EXT_V4T, do_t_arit}, - {"stmia", 0xc000, 2, ARM_EXT_V4T, do_t_ldmstm}, - {"str", 0x0000, 2, ARM_EXT_V4T, do_t_str}, - {"strb", 0x0000, 2, ARM_EXT_V4T, do_t_strb}, - {"strh", 0x0000, 2, ARM_EXT_V4T, do_t_strh}, - {"swi", 0xdf00, 2, ARM_EXT_V4T, do_t_swi}, - {"sub", 0x0000, 2, ARM_EXT_V4T, do_t_sub}, - {"tst", T_OPCODE_TST, 2, ARM_EXT_V4T, do_t_arit}, - /* Pseudo ops: */ - {"adr", 0x0000, 2, ARM_EXT_V4T, do_t_adr}, - {"nop", 0x46C0, 2, ARM_EXT_V4T, do_t_nop}, /* mov r8,r8 */ - /* Thumb v2 (ARMv5T). */ - {"blx", 0, 0, ARM_EXT_V5T, do_t_blx}, - {"bkpt", 0xbe00, 2, ARM_EXT_V5T, do_t_bkpt}, - - /* ARM V6. */ - {"cpsie", 0xb660, 2, ARM_EXT_V6, do_t_cps}, - {"cpsid", 0xb670, 2, ARM_EXT_V6, do_t_cps}, - {"cpy", 0x4600, 2, ARM_EXT_V6, do_t_cpy}, - {"rev", 0xba00, 2, ARM_EXT_V6, do_t_arit}, - {"rev16", 0xba40, 2, ARM_EXT_V6, do_t_arit}, - {"revsh", 0xbac0, 2, ARM_EXT_V6, do_t_arit}, - {"setend", 0xb650, 2, ARM_EXT_V6, do_t_setend}, - {"sxth", 0xb200, 2, ARM_EXT_V6, do_t_arit}, - {"sxtb", 0xb240, 2, ARM_EXT_V6, do_t_arit}, - {"uxth", 0xb280, 2, ARM_EXT_V6, do_t_arit}, - {"uxtb", 0xb2c0, 2, ARM_EXT_V6, do_t_arit}, - - /* ARM V6K. */ - {"sev", 0xbf40, 2, ARM_EXT_V6K, do_empty}, - {"wfe", 0xbf20, 2, ARM_EXT_V6K, do_empty}, - {"wfi", 0xbf30, 2, ARM_EXT_V6K, do_empty}, - {"yield", 0xbf10, 2, ARM_EXT_V6K, do_empty}, -}; - -void -md_begin (void) -{ - unsigned mach; - unsigned int i; - if ( (arm_ops_hsh = hash_new ()) == NULL - || (arm_tops_hsh = hash_new ()) == NULL - || (arm_cond_hsh = hash_new ()) == NULL - || (arm_shift_hsh = hash_new ()) == NULL - || (arm_psr_hsh = hash_new ()) == NULL) - as_fatal (_("virtual memory exhausted")); + text_name = segment_name (text_seg); + if (streq (text_name, ".text")) + text_name = ""; - build_arm_ops_hsh (); - for (i = 0; i < sizeof (tinsns) / sizeof (struct thumb_opcode); i++) - hash_insert (arm_tops_hsh, tinsns[i].template, (PTR) (tinsns + i)); - for (i = 0; i < sizeof (conds) / sizeof (struct asm_cond); i++) - hash_insert (arm_cond_hsh, conds[i].template, (PTR) (conds + i)); - for (i = 0; i < sizeof (shift_names) / sizeof (struct asm_shift_name); i++) - hash_insert (arm_shift_hsh, shift_names[i].name, (PTR) (shift_names + i)); - for (i = 0; i < sizeof (psrs) / sizeof (struct asm_psr); i++) - hash_insert (arm_psr_hsh, psrs[i].template, (PTR) (psrs + i)); + if (strncmp (text_name, ".gnu.linkonce.t.", + strlen (".gnu.linkonce.t.")) == 0) + { + prefix = prefix_once; + text_name += strlen (".gnu.linkonce.t."); + } - for (i = (int) REG_TYPE_FIRST; i < (int) REG_TYPE_MAX; i++) - build_reg_hsh (all_reg_maps + i); + prefix_len = strlen (prefix); + text_len = strlen (text_name); + sec_name_len = prefix_len + text_len; + sec_name = xmalloc (sec_name_len + 1); + memcpy (sec_name, prefix, prefix_len); + memcpy (sec_name + prefix_len, text_name, text_len); + sec_name[prefix_len + text_len] = '\0'; - set_constant_flonums (); + flags = SHF_ALLOC; + linkonce = 0; + group_name = 0; - /* Set the cpu variant based on the command-line options. We prefer - -mcpu= over -march= if both are set (as for GCC); and we prefer - -mfpu= over any other way of setting the floating point unit. - Use of legacy options with new options are faulted. */ - if (legacy_cpu != -1) + /* Handle COMDAT group. */ + if (prefix != prefix_once && (text_seg->flags & SEC_LINK_ONCE) != 0) { - if (mcpu_cpu_opt != -1 || march_cpu_opt != -1) - as_bad (_("use of old and new-style options to set CPU type")); - - mcpu_cpu_opt = legacy_cpu; + group_name = elf_group_name (text_seg); + if (group_name == NULL) + { + as_bad ("Group section `%s' has no group signature", + segment_name (text_seg)); + ignore_rest_of_line (); + return; + } + flags |= SHF_GROUP; + linkonce = 1; } - else if (mcpu_cpu_opt == -1) - mcpu_cpu_opt = march_cpu_opt; - if (legacy_fpu != -1) - { - if (mfpu_opt != -1) - as_bad (_("use of old and new-style options to set FPU type")); + obj_elf_change_section (sec_name, type, flags, 0, group_name, linkonce, 0); - mfpu_opt = legacy_fpu; - } - else if (mfpu_opt == -1) - { -#if !(defined (TE_LINUX) || defined (TE_NetBSD) || defined (TE_VXWORKS)) - /* Some environments specify a default FPU. If they don't, infer it - from the processor. */ - if (mcpu_fpu_opt != -1) - mfpu_opt = mcpu_fpu_opt; - else - mfpu_opt = march_fpu_opt; -#else - mfpu_opt = FPU_DEFAULT; -#endif - } + /* Set the setion link for index tables. */ + if (idx) + elf_linked_to_section (now_seg) = text_seg; +} - if (mfpu_opt == -1) - { - if (mcpu_cpu_opt == -1) - mfpu_opt = FPU_DEFAULT; - else if (mcpu_cpu_opt & ARM_EXT_V5) - mfpu_opt = FPU_ARCH_VFP_V2; - else - mfpu_opt = FPU_ARCH_FPA; - } - if (mcpu_cpu_opt == -1) - mcpu_cpu_opt = CPU_DEFAULT; +/* Start an unwind table entry. HAVE_DATA is nonzero if we have additional + personality routine data. Returns zero, or the index table value for + and inline entry. */ - cpu_variant = mcpu_cpu_opt | mfpu_opt; +static valueT +create_unwind_entry (int have_data) +{ + int size; + addressT where; + char *ptr; + /* The current word of data. */ + valueT data; + /* The number of bytes left in this word. */ + int n; -#if defined OBJ_COFF || defined OBJ_ELF - { - unsigned int flags = 0; + finish_unwind_opcodes (); -#if defined OBJ_ELF - flags = meabi_flags; + /* Remember the current text section. */ + unwind.saved_seg = now_seg; + unwind.saved_subseg = now_subseg; - switch (meabi_flags) - { - case EF_ARM_EABI_UNKNOWN: -#endif - /* 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; - if (pic_code) flags |= F_PIC; - if ((cpu_variant & FPU_ANY) == FPU_NONE - || (cpu_variant & FPU_ANY) == FPU_ARCH_VFP) /* VFP layout only. */ - flags |= F_SOFT_FLOAT; + start_unwind_section (now_seg, 0); - switch (mfloat_abi_opt) - { - case ARM_FLOAT_ABI_SOFT: - case ARM_FLOAT_ABI_SOFTFP: - flags |= F_SOFT_FLOAT; - break; + if (unwind.personality_routine == NULL) + { + if (unwind.personality_index == -2) + { + if (have_data) + as_bad (_("handerdata in cantunwind frame")); + return 1; /* EXIDX_CANTUNWIND. */ + } - case ARM_FLOAT_ABI_HARD: - if (flags & F_SOFT_FLOAT) - as_bad (_("hard-float conflicts with specified fpu")); - break; - } + /* Use a default personality routine if none is specified. */ + if (unwind.personality_index == -1) + { + if (unwind.opcode_count > 3) + unwind.personality_index = 1; + else + unwind.personality_index = 0; + } - /* Using VFP conventions (even if soft-float). */ - if (cpu_variant & FPU_VFP_EXT_NONE) - flags |= F_VFP_FLOAT; + /* Space for the personality routine entry. */ + if (unwind.personality_index == 0) + { + if (unwind.opcode_count > 3) + as_bad (_("too many unwind opcodes for personality routine 0")); -#if defined OBJ_ELF - if (cpu_variant & FPU_ARCH_MAVERICK) - flags |= EF_ARM_MAVERICK_FLOAT; - break; + if (!have_data) + { + /* All the data is inline in the index table. */ + data = 0x80; + n = 3; + while (unwind.opcode_count > 0) + { + unwind.opcode_count--; + data = (data << 8) | unwind.opcodes[unwind.opcode_count]; + n--; + } - case EF_ARM_EABI_VER4: - /* No additional flags to set. */ - break; + /* Pad with "finish" opcodes. */ + while (n--) + data = (data << 8) | 0xb0; - default: - abort (); - } -#endif - bfd_set_private_flags (stdoutput, flags); + return data; + } + size = 0; + } + else + /* We get two opcodes "free" in the first word. */ + size = unwind.opcode_count - 2; + } + else + /* An extra byte is required for the opcode count. */ + size = unwind.opcode_count + 1; - /* We have run out flags in the COFF header to encode the - status of ATPCS support, so instead we create a dummy, - empty, debug section called .arm.atpcs. */ - if (atpcs) - { - asection * sec; + size = (size + 3) >> 2; + if (size > 0xff) + as_bad (_("too many unwind opcodes")); - sec = bfd_make_section (stdoutput, ".arm.atpcs"); + frag_align (2, 0, 0); + record_alignment (now_seg, 2); + unwind.table_entry = expr_build_dot (); - if (sec != NULL) - { - bfd_set_section_flags - (stdoutput, sec, SEC_READONLY | SEC_DEBUGGING /* | SEC_HAS_CONTENTS */); - bfd_set_section_size (stdoutput, sec, 0); - bfd_set_section_contents (stdoutput, sec, NULL, 0, 0); - } - } - } -#endif + /* Allocate the table entry. */ + ptr = frag_more ((size << 2) + 4); + where = frag_now_fix () - ((size << 2) + 4); - /* Record the CPU type as well. */ - switch (cpu_variant & ARM_CPU_MASK) + switch (unwind.personality_index) { - case ARM_2: - mach = bfd_mach_arm_2; + case -1: + /* ??? Should this be a PLT generating relocation? */ + /* Custom personality routine. */ + fix_new (frag_now, where, 4, unwind.personality_routine, 0, 1, + BFD_RELOC_ARM_PREL31); + + where += 4; + ptr += 4; + + /* Set the first byte to the number of additional words. */ + data = size - 1; + n = 3; break; - case ARM_3: /* Also ARM_250. */ - mach = bfd_mach_arm_2a; + /* ABI defined personality routines. */ + case 0: + /* Three opcodes bytes are packed into the first word. */ + data = 0x80; + n = 3; break; - case ARM_6: /* Also ARM_7. */ - mach = bfd_mach_arm_3; + case 1: + case 2: + /* The size and first two opcode bytes go in the first word. */ + data = ((0x80 + unwind.personality_index) << 8) | size; + n = 2; break; default: - mach = bfd_mach_arm_unknown; - break; + /* Should never happen. */ + abort (); } - /* Catch special cases. */ - if (cpu_variant & ARM_CEXT_IWMMXT) - mach = bfd_mach_arm_iWMMXt; - else if (cpu_variant & ARM_CEXT_XSCALE) - mach = bfd_mach_arm_XScale; - else if (cpu_variant & ARM_CEXT_MAVERICK) - mach = bfd_mach_arm_ep9312; - else if (cpu_variant & ARM_EXT_V5E) - mach = bfd_mach_arm_5TE; - else if (cpu_variant & ARM_EXT_V5) - { - if (cpu_variant & ARM_EXT_V4T) - mach = bfd_mach_arm_5T; - else - mach = bfd_mach_arm_5; - } - else if (cpu_variant & ARM_EXT_V4) + /* Pack the opcodes into words (MSB first), reversing the list at the same + time. */ + while (unwind.opcode_count > 0) { - if (cpu_variant & ARM_EXT_V4T) - mach = bfd_mach_arm_4T; - else - mach = bfd_mach_arm_4; + if (n == 0) + { + md_number_to_chars (ptr, data, 4); + ptr += 4; + n = 4; + data = 0; + } + unwind.opcode_count--; + n--; + data = (data << 8) | unwind.opcodes[unwind.opcode_count]; } - else if (cpu_variant & ARM_EXT_V3M) - 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 - for use in the a.out file, and stores them in the array pointed to by buf. - This knows about the endian-ness of the target machine and does - THE RIGHT THING, whatever it is. Possible values for n are 1 (byte) - 2 (short) and 4 (long) Floating numbers are put out as a series of - LITTLENUMS (shorts, here at least). */ - -void -md_number_to_chars (char * buf, valueT val, int n) -{ - if (target_big_endian) - number_to_chars_bigendian (buf, val, n); - else - number_to_chars_littleendian (buf, val, n); -} - -static valueT -md_chars_to_number (char * buf, int n) -{ - valueT result = 0; - unsigned char * where = (unsigned char *) buf; - if (target_big_endian) + /* Finish off the last word. */ + if (n < 4) { + /* Pad with "finish" opcodes. */ while (n--) - { - result <<= 8; - result |= (*where++ & 255); - } + data = (data << 8) | 0xb0; + + md_number_to_chars (ptr, data, 4); } - else + + if (!have_data) { - while (n--) - { - result <<= 8; - result |= (where[n] & 255); - } + /* Add an empty descriptor if there is no user-specified data. */ + ptr = frag_more (4); + md_number_to_chars (ptr, 0, 4); } - return result; + return 0; } -/* Turn a string in input_line_pointer into a floating point constant - of type TYPE, and store the appropriate bytes in *LITP. The number - of LITTLENUMS emitted is stored in *SIZEP. An error message is - returned, or NULL on OK. - - Note that fp constants aren't represent in the normal way on the ARM. - In big endian mode, things are as expected. However, in little endian - mode fp constants are big-endian word-wise, and little-endian byte-wise - within the words. For example, (double) 1.1 in big endian mode is - the byte sequence 3f f1 99 99 99 99 99 9a, and in little endian mode is - the byte sequence 99 99 f1 3f 9a 99 99 99. - - ??? The format of 12 byte floats is uncertain according to gcc's arm.h. */ +/* Convert REGNAME to a DWARF-2 register number. */ -char * -md_atof (int type, char * litP, int * sizeP) +int +tc_arm_regname_to_dw2regnum (const char *regname) { - int prec; - LITTLENUM_TYPE words[MAX_LITTLENUMS]; - char *t; - int i; + int reg = arm_reg_parse ((char **) ®name, REG_TYPE_RN); - switch (type) - { - case 'f': - case 'F': - case 's': - case 'S': - prec = 2; - break; + if (reg == FAIL) + return -1; - case 'd': - case 'D': - case 'r': - case 'R': - prec = 4; - break; + return reg; +} - case 'x': - case 'X': - prec = 6; - break; +/* Initialize the DWARF-2 unwind information for this procedure. */ - case 'p': - case 'P': - prec = 6; - break; +void +tc_arm_frame_initial_instructions (void) +{ + cfi_add_CFA_def_cfa (REG_SP, 0); +} +#endif /* OBJ_ELF */ - default: - *sizeP = 0; - return _("bad call to MD_ATOF()"); - } - t = atof_ieee (input_line_pointer, type, words); - if (t) - input_line_pointer = t; - *sizeP = prec * 2; - - if (target_big_endian) - { - for (i = 0; i < prec; i++) - { - md_number_to_chars (litP, (valueT) words[i], 2); - litP += 2; - } - } - else - { - if (cpu_variant & FPU_ARCH_VFP) - for (i = prec - 1; i >= 0; i--) - { - md_number_to_chars (litP, (valueT) words[i], 2); - litP += 2; - } - else - /* For a 4 byte float the order of elements in `words' is 1 0. - For an 8 byte float the order is 1 0 3 2. */ - for (i = 0; i < prec; i += 2) - { - md_number_to_chars (litP, (valueT) words[i + 1], 2); - md_number_to_chars (litP + 2, (valueT) words[i], 2); - litP += 4; - } - } - - return 0; -} +/* MD interface: Symbol and relocation handling. */ /* The knowledge of the PC's pipeline offset is built into the insns - themselves. */ + themselves. */ long md_pcrel_from (fixS * fixP) @@ -11629,37 +9878,32 @@ md_pcrel_from (fixS * fixP) && fixP->fx_subsy == NULL) return 0; - if (fixP->fx_pcrel && (fixP->fx_r_type == BFD_RELOC_ARM_THUMB_ADD)) + /* 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. */ + case BFD_RELOC_ARM_THUMB_ADD: return (fixP->fx_where + fixP->fx_frag->fr_address) & ~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; + + default: + break; } #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. */ + so we un-adjust here to compensate for the accommodation. */ 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 (segT segment ATTRIBUTE_UNUSED, - valueT size) -{ -#ifdef OBJ_ELF - return size; -#else - /* Round all sects to multiple of 4. */ - return (size + 3) & ~3; -#endif -} - /* Under ELF we need to default _GLOBAL_OFFSET_TABLE. Otherwise we have no need to default values of symbols. */ @@ -11686,18 +9930,156 @@ md_undefined_symbol (char * name ATTRIBUTE_UNUSED) return 0; } +/* Subroutine of md_apply_fix3. Check to see if an immediate can be + computed as two separate immediate values, added together. We + already know that this value cannot be computed by just one ARM + instruction. */ + +static unsigned int +validate_immediate_twopart (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 (unsigned int val, int hwse) +{ + if ((hwse && val > 255) || val > 4095) + return FAIL; + return val; +} + +/* Subroutine of md_apply_fix3. Do those data_ops which can take a + negative immediate constant by altering the instruction. A bit of + a hack really. + MOV <-> MVN + AND <-> BIC + ADC <-> SBC + by inverting the second operand, and + ADD <-> SUB + CMP <-> CMN + by negating the second operand. */ + +static int +negate_data_op (unsigned long * instruction, + unsigned long value) +{ + int op, new_inst; + unsigned long negated, inverted; + + negated = encode_arm_immediate (-value); + inverted = encode_arm_immediate (~value); + + op = (*instruction >> DATA_OP_SHIFT) & 0xf; + switch (op) + { + /* First negates. */ + case OPCODE_SUB: /* ADD <-> SUB */ + new_inst = OPCODE_ADD; + value = negated; + break; + + case OPCODE_ADD: + new_inst = OPCODE_SUB; + value = negated; + break; + + case OPCODE_CMP: /* CMP <-> CMN */ + new_inst = OPCODE_CMN; + value = negated; + break; + + case OPCODE_CMN: + new_inst = OPCODE_CMP; + value = negated; + break; + + /* Now Inverted ops. */ + case OPCODE_MOV: /* MOV <-> MVN */ + new_inst = OPCODE_MVN; + value = inverted; + break; + + case OPCODE_MVN: + new_inst = OPCODE_MOV; + value = inverted; + break; + + case OPCODE_AND: /* AND <-> BIC */ + new_inst = OPCODE_BIC; + value = inverted; + break; + + case OPCODE_BIC: + new_inst = OPCODE_AND; + value = inverted; + break; + + case OPCODE_ADC: /* ADC <-> SBC */ + new_inst = OPCODE_SBC; + value = inverted; + break; + + case OPCODE_SBC: + new_inst = OPCODE_ADC; + value = inverted; + break; + + /* We cannot do anything. */ + default: + return FAIL; + } + + if (value == (unsigned) FAIL) + return FAIL; + + *instruction &= OPCODE_MASK; + *instruction |= new_inst << DATA_OP_SHIFT; + return value; +} + void -md_apply_fix3 (fixS * fixP, +md_apply_fix3 (fixS * fixP, valueT * valP, - segT seg) -{ - offsetT value = * valP; - offsetT newval; - unsigned int newimm; - unsigned long temp; - int sign; - char * buf = fixP->fx_where + fixP->fx_frag->fr_literal; - arm_fix_data * arm_data = (arm_fix_data *) fixP->tc_fix_data; + segT seg) +{ + offsetT value = * valP; + offsetT newval; + unsigned int newimm; + unsigned long temp; + int sign; + char * buf = fixP->fx_where + fixP->fx_frag->fr_literal; + /* The double cast here prevents warnings about converting a pointer + to an integer of different size. We know the value is 0, 1, or 2. */ + int fix_is_thumb = (int) (size_t) fixP->tc_fix_data; assert (fixP->fx_r_type <= BFD_RELOC_UNUSED); @@ -11707,7 +10089,7 @@ md_apply_fix3 (fixS * fixP, /* 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 it's effects here. */ + so we have to undo its effects here. */ if (fixP->fx_pcrel) { if (fixP->fx_addsy != NULL @@ -11725,7 +10107,7 @@ md_apply_fix3 (fixS * fixP, /* This will need to go in the object file. */ fixP->fx_done = 0; break; - + case BFD_RELOC_ARM_IMMEDIATE: /* We claim that this fixup has been processed here, even if in fact we generate an error because we do @@ -11741,7 +10123,7 @@ md_apply_fix3 (fixS * fixP, break; } - newimm = validate_immediate (value); + newimm = encode_arm_immediate (value); temp = md_chars_to_number (buf, INSN_SIZE); /* If the instruction will fail, see if we can fix things up by @@ -11764,20 +10146,20 @@ md_apply_fix3 (fixS * fixP, unsigned int highpart = 0; unsigned int newinsn = 0xe1a00000; /* nop. */ - newimm = validate_immediate (value); + newimm = encode_arm_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. */ + 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. */ + the value. */ newimm = validate_immediate_twopart (value, & highpart); /* Yes - then make sure that the second instruction is - also an add. */ + also an add. */ if (newimm != (unsigned int) FAIL) newinsn = temp; /* Still No ? Try using a negated value. */ @@ -11809,6 +10191,7 @@ md_apply_fix3 (fixS * fixP, break; case BFD_RELOC_ARM_OFFSET_IMM: + case BFD_RELOC_ARM_LITERAL: sign = value >= 0; if (value < 0) @@ -11816,9 +10199,13 @@ md_apply_fix3 (fixS * fixP, if (validate_offset_imm (value, 0) == FAIL) { - as_bad_where (fixP->fx_file, fixP->fx_line, - _("bad immediate value for offset (%ld)"), - (long) value); + if (fixP->fx_r_type == BFD_RELOC_ARM_LITERAL) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("invalid literal constant: pool needs to be closer")); + else + as_bad_where (fixP->fx_file, fixP->fx_line, + _("bad immediate value for offset (%ld)"), + (long) value); break; } @@ -11852,23 +10239,131 @@ md_apply_fix3 (fixS * fixP, md_number_to_chars (buf, newval, INSN_SIZE); break; - case BFD_RELOC_ARM_LITERAL: - sign = value >= 0; + case BFD_RELOC_ARM_T32_OFFSET_U8: + if (value < 0 || value > 1020 || value % 4 != 0) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("bad immediate value for offset (%ld)"), (long) value); + value /= 4; - if (value < 0) - value = - value; + newval = md_chars_to_number (buf+2, THUMB_SIZE); + newval &= 0xff00; + newval |= value; + md_number_to_chars (buf+2, newval, THUMB_SIZE); + break; - if (validate_offset_imm (value, 0) == FAIL) + case BFD_RELOC_ARM_T32_OFFSET_IMM: + /* This is a complicated relocation used for all varieties of Thumb32 + load/store instruction with immediate offset: + + 1110 100P u1WL NNNN XXXX YYYY iiii iiii - +/-(U) pre/post(P) 8-bit, + *4, optional writeback(W) + (doubleword load/store) + + 1111 100S uTTL 1111 XXXX iiii iiii iiii - +/-(U) 12-bit PC-rel + 1111 100S 0TTL NNNN XXXX 1Pu1 iiii iiii - +/-(U) pre/post(P) 8-bit + 1111 100S 0TTL NNNN XXXX 1110 iiii iiii - positive 8-bit (T instruction) + 1111 100S 1TTL NNNN XXXX iiii iiii iiii - positive 12-bit + 1111 100S 0TTL NNNN XXXX 1100 iiii iiii - negative 8-bit + + Uppercase letters indicate bits that are already encoded at + this point. Lowercase letters are our problem. For the + second block of instructions, the secondary opcode nybble + (bits 8..11) is present, and bit 23 is zero, even if this is + a PC-relative operation. */ + newval = md_chars_to_number (buf, THUMB_SIZE); + newval <<= 16; + newval |= md_chars_to_number (buf+THUMB_SIZE, THUMB_SIZE); + + if ((newval & 0xf0000000) == 0xe0000000) { - as_bad_where (fixP->fx_file, fixP->fx_line, - _("invalid literal constant: pool needs to be closer")); - break; + /* Doubleword load/store: 8-bit offset, scaled by 4. */ + if (value >= 0) + newval |= (1 << 23); + else + value = -value; + if (value % 4 != 0) + { + as_bad_where (fixP->fx_file, fixP->fx_line, + _("offset not a multiple of 4")); + break; + } + value /= 4; + if (value >= 0xff) + { + as_bad_where (fixP->fx_file, fixP->fx_line, + _("offset out of range")); + break; + } + newval &= ~0xff; + } + else if ((newval & 0x000f0000) == 0x000f0000) + { + /* PC-relative, 12-bit offset. */ + if (value >= 0) + newval |= (1 << 23); + else + value = -value; + if (value >= 0xfff) + { + as_bad_where (fixP->fx_file, fixP->fx_line, + _("offset out of range")); + break; + } + newval &= ~0xfff; + } + else if ((newval & 0x00000100) == 0x00000100) + { + /* Writeback: 8-bit, +/- offset. */ + if (value >= 0) + newval |= (1 << 9); + else + value = -value; + if (value >= 0xff) + { + as_bad_where (fixP->fx_file, fixP->fx_line, + _("offset out of range")); + break; + } + newval &= ~0xff; + } + else if ((newval & 0x00000f00) == 0x00000e00) + { + /* T-instruction: positive 8-bit offset. */ + if (value < 0 || value >= 0xff) + { + as_bad_where (fixP->fx_file, fixP->fx_line, + _("offset out of range")); + break; + } + newval &= ~0xff; + newval |= value; + } + else + { + /* Positive 12-bit or negative 8-bit offset. */ + int limit; + if (value >= 0) + { + newval |= (1 << 23); + limit = 0xfff; + } + else + { + value = -value; + limit = 0xff; + } + if (value > limit) + { + as_bad_where (fixP->fx_file, fixP->fx_line, + _("offset out of range")); + break; + } + newval &= ~limit; } - newval = md_chars_to_number (buf, INSN_SIZE); - newval &= 0xff7ff000; - newval |= value | (sign ? INDEX_UP : 0); - md_number_to_chars (buf, newval, INSN_SIZE); + newval |= value; + md_number_to_chars (buf, (newval >> 16) & 0xffff, THUMB_SIZE); + md_number_to_chars (buf + THUMB_SIZE, newval & 0xffff, THUMB_SIZE); break; case BFD_RELOC_ARM_SHIFT_IMM: @@ -11883,7 +10378,7 @@ md_apply_fix3 (fixS * fixP, } if (value == 0) - /* Shifts of zero must be done as lsl. */ + /* Shifts of zero must be done as lsl. */ newval &= ~0x60; else if (value == 32) value = 0; @@ -11892,6 +10387,45 @@ md_apply_fix3 (fixS * fixP, md_number_to_chars (buf, newval, INSN_SIZE); break; + case BFD_RELOC_ARM_T32_IMMEDIATE: + /* 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. */ + fixP->fx_done = 1; + + if (fixP->fx_addsy + && ! S_IS_DEFINED (fixP->fx_addsy)) + { + as_bad_where (fixP->fx_file, fixP->fx_line, + _("undefined symbol %s used as an immediate value"), + S_GET_NAME (fixP->fx_addsy)); + break; + } + + newval = md_chars_to_number (buf, THUMB_SIZE); + 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 (newimm == (unsigned int)FAIL) + { + as_bad_where (fixP->fx_file, fixP->fx_line, + _("invalid constant (%lx) after fixup"), + (unsigned long) value); + break; + } + + newval &= 0xfbff8f00; + newval |= (newimm & 0x800) << 15; + newval |= (newimm & 0x700) << 4; + newval |= (newimm & 0x0ff); + + md_number_to_chars (buf, (valueT) ((newval >> 16) & 0xffff), THUMB_SIZE); + md_number_to_chars (buf+2, (valueT) (newval & 0xffff), THUMB_SIZE); + break; + case BFD_RELOC_ARM_SMI: if (((unsigned long) value) > 0xffff) as_bad_where (fixP->fx_file, fixP->fx_line, @@ -11902,7 +10436,7 @@ md_apply_fix3 (fixS * fixP, break; case BFD_RELOC_ARM_SWI: - if (arm_data->thumb_mode) + if (fix_is_thumb) { if (((unsigned long) value) > 0xff) as_bad_where (fixP->fx_file, fixP->fx_line, @@ -11941,16 +10475,16 @@ md_apply_fix3 (fixS * fixP, #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 + 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. */ + 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 + 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. @@ -11966,7 +10500,7 @@ md_apply_fix3 (fixS * fixP, /* Permit a backward branch provided that enough bits are set. Allow a forwards branch, provided that - enough bits are clear. */ + enough bits are clear. */ if ( (value & ~ ((offsetT) 0x1ffffff)) == ~ ((offsetT) 0x1ffffff) || (value & ~ ((offsetT) 0x1ffffff)) == 0) fixP->fx_done = 1; @@ -12031,7 +10565,32 @@ md_apply_fix3 (fixS * fixP, } break; - case BFD_RELOC_THUMB_PCREL_BRANCH9: /* Conditional branch. */ + 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")); + + newval &= 0xfd07; + if (seg->use_rela_p && !fixP->fx_done) + { +#ifdef OBJ_ELF + fixP->fx_offset = value; +#endif + fixP->fx_addnumber = value; + } + else + newval |= ((value & 0x2e) << 2) | ((value & 0x40) << 3); + } + 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; @@ -12081,13 +10640,61 @@ md_apply_fix3 (fixS * fixP, 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")); + + 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; + } + + 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); + 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) @@ -12141,6 +10748,60 @@ md_apply_fix3 (fixS * fixP, #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); + + I1 = !(I1 ^ S); + I2 = !(I2 ^ S); + S = !S; + + diff = ((S << 24) | (I1 << 23) | (I2 << 22) | (hi << 12) | (lo << 1)); + diff -= (1 << 24); /* sign extend */ + value += diff; + + if ((value & ~0x1ffffff) && ((value & ~0x1ffffff) != ~0x1ffffff)) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("branch out of range")); + + 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 = 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); + } + break; + case BFD_RELOC_16: if (seg->use_rela_p && !fixP->fx_done) break; @@ -12156,13 +10817,13 @@ md_apply_fix3 (fixS * fixP, break; #ifdef OBJ_ELF - case BFD_RELOC_ARM_TLS_GD32: - case BFD_RELOC_ARM_TLS_LE32: - case BFD_RELOC_ARM_TLS_IE32: - case BFD_RELOC_ARM_TLS_LDM32: - case BFD_RELOC_ARM_TLS_LDO32: - S_SET_THREAD_LOCAL (fixP->fx_addsy); - /* fall through */ + case BFD_RELOC_ARM_TLS_GD32: + case BFD_RELOC_ARM_TLS_LE32: + case BFD_RELOC_ARM_TLS_IE32: + case BFD_RELOC_ARM_TLS_LDM32: + case BFD_RELOC_ARM_TLS_LDO32: + S_SET_THREAD_LOCAL (fixP->fx_addsy); + /* fall through */ case BFD_RELOC_ARM_GOT32: case BFD_RELOC_ARM_GOTOFF: @@ -12213,28 +10874,25 @@ md_apply_fix3 (fixS * fixP, #endif case BFD_RELOC_ARM_CP_OFF_IMM: - sign = value >= 0; if (value < -1023 || value > 1023 || (value & 3)) as_bad_where (fixP->fx_file, fixP->fx_line, - _("illegal value for co-processor offset")); + _("co-processor offset out of range")); + cp_off_common: + sign = value >= 0; if (value < 0) value = -value; newval = md_chars_to_number (buf, INSN_SIZE) & 0xff7fff00; newval |= (value >> 2) | (sign ? INDEX_UP : 0); + if (value == 0) + newval &= ~WRITE_BACK; md_number_to_chars (buf, newval, INSN_SIZE); break; case BFD_RELOC_ARM_CP_OFF_IMM_S2: - sign = value >= 0; if (value < -255 || value > 255) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Illegal value for co-processor offset")); - if (value < 0) - value = -value; - newval = md_chars_to_number (buf, INSN_SIZE) & 0xff7fff00; - newval |= value | (sign ? INDEX_UP : 0); - md_number_to_chars (buf, newval , INSN_SIZE); - break; + as_bad_where (fixP->fx_file, fixP->fx_line, + _("co-processor offset out of range")); + goto cp_off_common; case BFD_RELOC_ARM_THUMB_OFFSET: newval = md_chars_to_number (buf, THUMB_SIZE); @@ -12245,24 +10903,20 @@ md_apply_fix3 (fixS * fixP, { case 4: /* PC load. */ /* Thumb PC loads are somewhat odd, bit 1 of the PC is - forced to zero for these loads, so we will need to round - up the offset if the instruction address is not word - aligned (since the final address produced must be, and - we can only describe word-aligned immediate offsets). */ - - if ((fixP->fx_frag->fr_address + fixP->fx_where + value) & 3) + forced to zero for these loads; md_pcrel_from has already + compensated for this. */ + if (value & 3) as_bad_where (fixP->fx_file, fixP->fx_line, - _("invalid offset, target not word aligned (0x%08X)"), - (unsigned int) (fixP->fx_frag->fr_address - + fixP->fx_where + value)); + _("invalid offset, target not word aligned (0x%08lX)"), + (((unsigned int) fixP->fx_frag->fr_address + + (unsigned int) fixP->fx_where) & ~3) + value); - if ((value + 2) & ~0x3fe) + if (value & ~0x3fc) as_bad_where (fixP->fx_file, fixP->fx_line, _("invalid offset, value too big (0x%08lX)"), (long) value); - /* Round up, since pc will be rounded down. */ - newval |= (value + 2) >> 2; + newval |= value >> 2; break; case 9: /* SP load/store. */ @@ -12289,7 +10943,7 @@ md_apply_fix3 (fixS * fixP, newval |= value << 6; break; - case 8: /* Halfword load/store. */ + case 8: /* Halfword load/store. */ if (value & ~0x3e) as_bad_where (fixP->fx_file, fixP->fx_line, _("invalid offset, value too big (0x%08lX)"), @@ -12308,15 +10962,15 @@ md_apply_fix3 (fixS * fixP, case BFD_RELOC_ARM_THUMB_ADD: /* This is a complicated relocation, since we use it for all of - the following immediate relocations: + the following immediate relocations: 3bit ADD/SUB 8bit ADD/SUB 9bit ADD/SUB SP word-aligned 10bit ADD PC/SP word-aligned - The type of instruction being processed is encoded in the - instruction field: + The type of instruction being processed is encoded in the + instruction field: 0x8000 SUB 0x00F0 Rd @@ -12326,7 +10980,24 @@ md_apply_fix3 (fixS * fixP, { int rd = (newval >> 4) & 0xf; int rs = newval & 0xf; - int subtract = newval & 0x8000; + int subtract = !!(newval & 0x8000); + + /* Check for HI regs, only very restricted cases allowed: + Adjusting SP, and using PC or SP to get an address. */ + if ((rd > 7 && (rd != REG_SP || rs != REG_SP)) + || (rs > 7 && rs != REG_SP && rs != REG_PC)) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("invalid Hi register with immediate")); + + /* If value is negative, choose the opposite instruction. */ + if (value < 0) + { + value = -value; + subtract = !subtract; + if (value < 0) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("immediate value out of range")); + } if (rd == REG_SP) { @@ -12338,8 +11009,7 @@ md_apply_fix3 (fixS * fixP, } else if (rs == REG_PC || rs == REG_SP) { - if (subtract || - value & ~0x3fc) + if (subtract || value & ~0x3fc) as_bad_where (fixP->fx_file, fixP->fx_line, _("invalid immediate for address calculation (value = 0x%08lX)"), (unsigned long) value); @@ -12351,7 +11021,7 @@ md_apply_fix3 (fixS * fixP, { if (value & ~0xff) as_bad_where (fixP->fx_file, fixP->fx_line, - _("invalid 8bit immediate")); + _("immediate value out of range")); newval = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8; newval |= (rd << 8) | value; } @@ -12359,7 +11029,7 @@ md_apply_fix3 (fixS * fixP, { if (value & ~0x7) as_bad_where (fixP->fx_file, fixP->fx_line, - _("invalid 3bit immediate")); + _("immediate value out of range")); newval = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3; newval |= rd | (rs << 3) | (value << 6); } @@ -12369,29 +11039,27 @@ md_apply_fix3 (fixS * fixP, case BFD_RELOC_ARM_THUMB_IMM: newval = md_chars_to_number (buf, THUMB_SIZE); - switch (newval >> 11) - { - case 0x04: /* 8bit immediate MOV. */ - case 0x05: /* 8bit immediate CMP. */ - if (value < 0 || value > 255) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("invalid immediate: %ld is too large"), - (long) value); - newval |= value; - break; - - default: - abort (); - } + if (value < 0 || value > 255) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("invalid immediate: %ld is too large"), + (long) value); + newval |= value; md_number_to_chars (buf, newval, THUMB_SIZE); break; case BFD_RELOC_ARM_THUMB_SHIFT: - /* 5bit shift value (0..31). */ - if (value < 0 || value > 31) + /* 5bit shift value (0..32). LSL cannot take 32. */ + newval = md_chars_to_number (buf, THUMB_SIZE) & 0xf83f; + temp = newval & 0xf800; + if (value < 0 || value > 32 || (value == 32 && temp == T_OPCODE_LSL_I)) as_bad_where (fixP->fx_file, fixP->fx_line, - _("illegal Thumb shift value: %ld"), (long) value); - newval = md_chars_to_number (buf, THUMB_SIZE) & 0xf03f; + _("invalid shift value: %ld"), (long) value); + /* Shifts of zero must be encoded as LSL. */ + if (value == 0) + newval = (newval & 0x003f) | T_OPCODE_LSL_I; + /* Shifts of 32 are encoded as zero. */ + else if (value == 32) + value = 0; newval |= value << 6; md_number_to_chars (buf, newval, THUMB_SIZE); break; @@ -12413,7 +11081,7 @@ md_apply_fix3 (fixS * fixP, arelent * tc_gen_reloc (asection * section ATTRIBUTE_UNUSED, - fixS * fixp) + fixS * fixp) { arelent * reloc; bfd_reloc_code_real_type code; @@ -12461,9 +11129,12 @@ tc_gen_reloc (asection * section ATTRIBUTE_UNUSED, case BFD_RELOC_ARM_PCREL_BRANCH: case BFD_RELOC_ARM_PCREL_BLX: case BFD_RELOC_RVA: + 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: case BFD_RELOC_VTABLE_ENTRY: case BFD_RELOC_VTABLE_INHERIT: @@ -12495,7 +11166,7 @@ tc_gen_reloc (asection * section ATTRIBUTE_UNUSED, case BFD_RELOC_ARM_TLS_GD32: case BFD_RELOC_ARM_TLS_IE32: case BFD_RELOC_ARM_TLS_LDM32: - /* BFD will include the symbol's address in the addend. + /* BFD will include the symbol's address in the addend. But we don't want that, so subtract it out again here. */ if (!S_IS_COMMON (fixp->fx_addsy)) reloc->addend -= (*reloc->sym_ptr_ptr)->value; @@ -12534,18 +11205,18 @@ tc_gen_reloc (asection * section ATTRIBUTE_UNUSED, switch (fixp->fx_r_type) { - case BFD_RELOC_NONE: type = "NONE"; break; + case BFD_RELOC_NONE: type = "NONE"; break; case BFD_RELOC_ARM_OFFSET_IMM8: type = "OFFSET_IMM8"; break; - case BFD_RELOC_ARM_SHIFT_IMM: type = "SHIFT_IMM"; break; - case BFD_RELOC_ARM_SMI: type = "SMI"; break; - case BFD_RELOC_ARM_SWI: type = "SWI"; break; - case BFD_RELOC_ARM_MULTI: type = "MULTI"; break; - case BFD_RELOC_ARM_CP_OFF_IMM: type = "CP_OFF_IMM"; break; - case BFD_RELOC_ARM_THUMB_ADD: type = "THUMB_ADD"; break; + case BFD_RELOC_ARM_SHIFT_IMM: type = "SHIFT_IMM"; break; + case BFD_RELOC_ARM_SMI: type = "SMI"; break; + case BFD_RELOC_ARM_SWI: type = "SWI"; break; + case BFD_RELOC_ARM_MULTI: type = "MULTI"; break; + case BFD_RELOC_ARM_CP_OFF_IMM: type = "CP_OFF_IMM"; break; + case BFD_RELOC_ARM_THUMB_ADD: type = "THUMB_ADD"; break; case BFD_RELOC_ARM_THUMB_SHIFT: type = "THUMB_SHIFT"; break; - case BFD_RELOC_ARM_THUMB_IMM: type = "THUMB_IMM"; break; + case BFD_RELOC_ARM_THUMB_IMM: type = "THUMB_IMM"; break; case BFD_RELOC_ARM_THUMB_OFFSET: type = "THUMB_OFFSET"; break; - default: type = _("<unknown>"); break; + default: type = _("<unknown>"); break; } as_bad_where (fixp->fx_file, fixp->fx_line, _("cannot represent %s relocation in this object file format"), @@ -12582,185 +11253,482 @@ tc_gen_reloc (asection * section ATTRIBUTE_UNUSED, return reloc; } -int -md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED, - segT segtype ATTRIBUTE_UNUSED) -{ - as_fatal (_("md_estimate_size_before_relax\n")); - return 1; -} - -/* We need to be able to fix up arbitrary expressions in some statements. - This is so that we can handle symbols that are an arbitrary distance from - the pc. The most common cases are of the form ((+/-sym -/+ . - 8) & mask), - which returns part of an address in a form which will be valid for - a data instruction. We do this by pushing the expression into a symbol - in the expr_section, and creating a fix for that. */ +/* This fix_new is called by cons via TC_CONS_FIX_NEW. */ -static void -fix_new_arm (fragS * frag, - int where, - short int size, - expressionS * exp, - int pc_rel, - int reloc) +void +cons_fix_new_arm (fragS * frag, + int where, + int size, + expressionS * exp) { - fixS * new_fix; - arm_fix_data * arm_data; + bfd_reloc_code_real_type type; + int pcrel = 0; - switch (exp->X_op) + /* Pick a reloc. + FIXME: @@ Should look at CPU word size. */ + switch (size) { - case O_constant: - case O_symbol: - case O_add: - case O_subtract: - new_fix = fix_new_exp (frag, where, size, exp, pc_rel, reloc); + case 1: + type = BFD_RELOC_8; break; - + case 2: + type = BFD_RELOC_16; + break; + case 4: default: - new_fix = fix_new (frag, where, size, make_expr_symbol (exp), 0, - pc_rel, reloc); + type = BFD_RELOC_32; + break; + case 8: + type = BFD_RELOC_64; break; } - /* Mark whether the fix is to a THUMB instruction, or an ARM - instruction. */ - arm_data = obstack_alloc (& notes, sizeof (arm_fix_data)); - new_fix->tc_fix_data = (PTR) arm_data; - arm_data->thumb_mode = thumb_mode; + fix_new_exp (frag, where, (int) size, exp, pcrel, type); } -static void -output_inst (const char * str) +#if defined OBJ_COFF || defined OBJ_ELF +void +arm_validate_fix (fixS * fixP) { - char * to = NULL; - - if (inst.error) + /* If the destination of the branch is a defined symbol which does not have + the THUMB_FUNC attribute, then we must be calling a function which has + the (interfacearm) attribute. We look for the Thumb entry point to that + function and change the branch to refer to that function instead. */ + if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23 + && fixP->fx_addsy != NULL + && S_IS_DEFINED (fixP->fx_addsy) + && ! THUMB_IS_FUNC (fixP->fx_addsy)) { - as_bad ("%s -- `%s'", inst.error, str); - return; + fixP->fx_addsy = find_real_start (fixP->fx_addsy); } +} +#endif - to = frag_more (inst.size); +int +arm_force_relocation (struct fix * fixp) +{ +#if defined (OBJ_COFF) && defined (TE_PE) + if (fixp->fx_r_type == BFD_RELOC_RVA) + return 1; +#endif +#ifdef OBJ_ELF + if (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; +#endif - if (thumb_mode && (inst.size > THUMB_SIZE)) - { - assert (inst.size == (2 * THUMB_SIZE)); - md_number_to_chars (to, inst.instruction >> 16, 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); + /* Resolve these relocations even if the symbol is extern or weak. */ + if (fixp->fx_r_type == BFD_RELOC_ARM_IMMEDIATE + || fixp->fx_r_type == BFD_RELOC_ARM_OFFSET_IMM + || fixp->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE) + return 0; - if (inst.reloc.type != BFD_RELOC_UNUSED) - fix_new_arm (frag_now, to - frag_now->fr_literal, - inst.size, & inst.reloc.exp, inst.reloc.pc_rel, - inst.reloc.type); + return generic_force_reloc (fixp); +} + +#ifdef OBJ_COFF +/* This is a little hack to help the gas/arm/adrl.s test. It prevents + local labels from being added to the output symbol table when they + are used with the ADRL pseudo op. The ADRL relocation should always + be resolved before the binbary is emitted, so it is safe to say that + it is adjustable. */ + +bfd_boolean +arm_fix_adjustable (fixS * fixP) +{ + if (fixP->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE) + return 1; + return 0; +} +#endif #ifdef OBJ_ELF - dwarf2_emit_insn (inst.size); +/* Relocations against Thumb function names must be left unadjusted, + so that the linker can use this information to correctly set the + bottom bit of their addresses. The MIPS version of this function + also prevents relocations that are mips-16 specific, but I do not + know why it does this. + + FIXME: + There is one other problem that ought to be addressed here, but + which currently is not: Taking the address of a label (rather + than a function) and then later jumping to that address. Such + addresses also ought to have their bottom bit set (assuming that + they reside in Thumb code), but at the moment they will not. */ + +bfd_boolean +arm_fix_adjustable (fixS * fixP) +{ + if (fixP->fx_addsy == NULL) + return 1; + + if (THUMB_IS_FUNC (fixP->fx_addsy) + && fixP->fx_subsy == NULL) + return 0; + + /* We need the symbol name for the VTABLE entries. */ + if ( fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT + || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) + return 0; + + /* Don't allow symbols to be discarded on GOT related relocs. */ + if (fixP->fx_r_type == BFD_RELOC_ARM_PLT32 + || fixP->fx_r_type == BFD_RELOC_ARM_GOT32 + || fixP->fx_r_type == BFD_RELOC_ARM_GOTOFF + || fixP->fx_r_type == BFD_RELOC_ARM_TLS_GD32 + || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LE32 + || fixP->fx_r_type == BFD_RELOC_ARM_TLS_IE32 + || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDM32 + || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDO32 + || fixP->fx_r_type == BFD_RELOC_ARM_TARGET2) + return 0; + + return 1; +} + +const char * +elf32_arm_target_format (void) +{ +#ifdef TE_SYMBIAN + return (target_big_endian + ? "elf32-bigarm-symbian" + : "elf32-littlearm-symbian"); +#elif defined (TE_VXWORKS) + return (target_big_endian + ? "elf32-bigarm-vxworks" + : "elf32-littlearm-vxworks"); +#else + if (target_big_endian) + return "elf32-bigarm"; + else + return "elf32-littlearm"; #endif } void -md_assemble (char * str) +armelf_frob_symbol (symbolS * symp, + int * puntp) { - char c; - char *p; - char *start; + elf_frob_symbol (symp, puntp); +} +#endif - /* Align the previous label if needed. */ - if (last_label_seen != NULL) - { - symbol_set_frag (last_label_seen, frag_now); - S_SET_VALUE (last_label_seen, (valueT) frag_now_fix ()); - S_SET_SEGMENT (last_label_seen, now_seg); - } +/* MD interface: Finalization. */ - memset (&inst, '\0', sizeof (inst)); - inst.reloc.type = BFD_RELOC_UNUSED; - - skip_whitespace (str); +/* A good place to do this, although this was probably not intended + for this kind of use. We need to dump the literal pool before + references are made to a null symbol pointer. */ - /* 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++) - if (*p == ' ') - break; +void +arm_cleanup (void) +{ + literal_pool * pool; - if (p == str) + for (pool = list_of_pools; pool; pool = pool->next) { - as_bad (_("no operator -- statement `%s'\n"), str); - return; + /* Put it at the end of the relevent section. */ + subseg_set (pool->section, pool->sub_section); +#ifdef OBJ_ELF + arm_elf_change_section (); +#endif + s_ltorg (0); } +} - if (thumb_mode) - { - const struct thumb_opcode * opcode; +/* Adjust the symbol table. This marks Thumb symbols as distinct from + ARM ones. */ - c = *p; - *p = '\0'; - opcode = (const struct thumb_opcode *) hash_find (arm_tops_hsh, str); - *p = c; +void +arm_adjust_symtab (void) +{ +#ifdef OBJ_COFF + symbolS * sym; - if (opcode) + for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym)) + { + if (ARM_IS_THUMB (sym)) { - /* Check that this instruction is supported for this CPU. */ - if (thumb_mode == 1 && (opcode->variant & cpu_variant) == 0) + if (THUMB_IS_FUNC (sym)) { - as_bad (_("selected processor does not support `%s'"), str); - return; - } + /* Mark the symbol as a Thumb function. */ + if ( S_GET_STORAGE_CLASS (sym) == C_STAT + || S_GET_STORAGE_CLASS (sym) == C_LABEL) /* This can happen! */ + S_SET_STORAGE_CLASS (sym, C_THUMBSTATFUNC); - mapping_state (MAP_THUMB); - inst.instruction = opcode->value; - inst.size = opcode->size; - opcode->parms (p); - output_inst (str); - return; + else if (S_GET_STORAGE_CLASS (sym) == C_EXT) + S_SET_STORAGE_CLASS (sym, C_THUMBEXTFUNC); + else + as_bad (_("%s: unexpected function type: %d"), + S_GET_NAME (sym), S_GET_STORAGE_CLASS (sym)); + } + else switch (S_GET_STORAGE_CLASS (sym)) + { + case C_EXT: + S_SET_STORAGE_CLASS (sym, C_THUMBEXT); + break; + case C_STAT: + S_SET_STORAGE_CLASS (sym, C_THUMBSTAT); + break; + case C_LABEL: + S_SET_STORAGE_CLASS (sym, C_THUMBLABEL); + break; + default: + /* Do nothing. */ + break; + } } + + if (ARM_IS_INTERWORK (sym)) + coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_flags = 0xFF; } - else +#endif +#ifdef OBJ_ELF + symbolS * sym; + char bind; + + for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym)) { - const struct asm_opcode * opcode; + if (ARM_IS_THUMB (sym)) + { + elf_symbol_type * elf_sym; - c = *p; - *p = '\0'; - opcode = (const struct asm_opcode *) hash_find (arm_ops_hsh, str); - *p = c; + elf_sym = elf_symbol (symbol_get_bfdsym (sym)); + bind = ELF_ST_BIND (elf_sym->internal_elf_sym.st_info); - if (opcode) - { - /* Check that this instruction is supported for this CPU. */ - if ((opcode->variant & cpu_variant) == 0) + if (! bfd_is_arm_mapping_symbol_name (elf_sym->symbol.name)) { - as_bad (_("selected processor does not support `%s'"), str); - return; + /* If it's a .thumb_func, declare it as so, + otherwise tag label as .code 16. */ + if (THUMB_IS_FUNC (sym)) + 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); } - - mapping_state (MAP_ARM); - inst.instruction = opcode->value; - inst.size = INSN_SIZE; - opcode->parms (p); - output_inst (str); - return; } } +#endif +} + +/* MD interface: Initialization. */ + +static void +set_constant_flonums (void) +{ + int i; + + for (i = 0; i < NUM_FLOAT_VALS; i++) + if (atof_ieee ((char *) fp_const[i], 'x', fp_values[i]) == NULL) + abort (); +} + +void +md_begin (void) +{ + unsigned mach; + unsigned int i; + + if ( (arm_ops_hsh = hash_new ()) == NULL + || (arm_cond_hsh = hash_new ()) == NULL + || (arm_shift_hsh = hash_new ()) == NULL + || (arm_psr_hsh = hash_new ()) == NULL + || (arm_reg_hsh = hash_new ()) == NULL + || (arm_reloc_hsh = hash_new ()) == NULL) + as_fatal (_("virtual memory exhausted")); + + for (i = 0; i < sizeof (insns) / sizeof (struct asm_opcode); i++) + hash_insert (arm_ops_hsh, insns[i].template, (PTR) (insns + i)); + for (i = 0; i < sizeof (conds) / sizeof (struct asm_cond); i++) + hash_insert (arm_cond_hsh, conds[i].template, (PTR) (conds + i)); + for (i = 0; i < sizeof (shift_names) / sizeof (struct asm_shift_name); i++) + hash_insert (arm_shift_hsh, shift_names[i].name, (PTR) (shift_names + i)); + for (i = 0; i < sizeof (psrs) / sizeof (struct asm_psr); i++) + hash_insert (arm_psr_hsh, psrs[i].template, (PTR) (psrs + i)); + for (i = 0; i < sizeof (reg_names) / sizeof (struct reg_entry); i++) + hash_insert (arm_reg_hsh, reg_names[i].name, (PTR) (reg_names + i)); +#ifdef OBJ_ELF + for (i = 0; i < sizeof (reloc_names) / sizeof (struct reloc_entry); i++) + hash_insert (arm_reloc_hsh, reloc_names[i].name, (PTR) (reloc_names + i)); +#endif + + set_constant_flonums (); + + /* Set the cpu variant based on the command-line options. We prefer + -mcpu= over -march= if both are set (as for GCC); and we prefer + -mfpu= over any other way of setting the floating point unit. + Use of legacy options with new options are faulted. */ + if (legacy_cpu != -1) + { + if (mcpu_cpu_opt != -1 || march_cpu_opt != -1) + as_bad (_("use of old and new-style options to set CPU type")); + + mcpu_cpu_opt = legacy_cpu; + } + else if (mcpu_cpu_opt == -1) + mcpu_cpu_opt = march_cpu_opt; - /* It wasn't an instruction, but it might be a register alias of the form - alias .req reg. */ - if (create_register_alias (str, p)) - return; + if (legacy_fpu != -1) + { + if (mfpu_opt != -1) + as_bad (_("use of old and new-style options to set FPU type")); + + mfpu_opt = legacy_fpu; + } + else if (mfpu_opt == -1) + { +#if !(defined (TE_LINUX) || defined (TE_NetBSD) || defined (TE_VXWORKS)) + /* Some environments specify a default FPU. If they don't, infer it + from the processor. */ + if (mcpu_fpu_opt != -1) + mfpu_opt = mcpu_fpu_opt; + else + mfpu_opt = march_fpu_opt; +#else + mfpu_opt = FPU_DEFAULT; +#endif + } + + if (mfpu_opt == -1) + { + if (mcpu_cpu_opt == -1) + mfpu_opt = FPU_DEFAULT; + else if (mcpu_cpu_opt & ARM_EXT_V5) + mfpu_opt = FPU_ARCH_VFP_V2; + else + mfpu_opt = FPU_ARCH_FPA; + } + + if (mcpu_cpu_opt == -1) + mcpu_cpu_opt = CPU_DEFAULT; + + cpu_variant = mcpu_cpu_opt | mfpu_opt; + +#if defined OBJ_COFF || defined OBJ_ELF + { + unsigned int flags = 0; + +#if defined OBJ_ELF + flags = meabi_flags; + + switch (meabi_flags) + { + case EF_ARM_EABI_UNKNOWN: +#endif + /* 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; + if (pic_code) flags |= F_PIC; + if ((cpu_variant & FPU_ANY) == FPU_NONE + || (cpu_variant & FPU_ANY) == FPU_ARCH_VFP) /* VFP layout only. */ + flags |= F_SOFT_FLOAT; - as_bad (_("bad instruction `%s'"), start); + switch (mfloat_abi_opt) + { + case ARM_FLOAT_ABI_SOFT: + case ARM_FLOAT_ABI_SOFTFP: + flags |= F_SOFT_FLOAT; + break; + + case ARM_FLOAT_ABI_HARD: + if (flags & F_SOFT_FLOAT) + as_bad (_("hard-float conflicts with specified fpu")); + break; + } + + /* Using VFP conventions (even if soft-float). */ + if (cpu_variant & FPU_VFP_EXT_NONE) + flags |= F_VFP_FLOAT; + +#if defined OBJ_ELF + if (cpu_variant & FPU_ARCH_MAVERICK) + flags |= EF_ARM_MAVERICK_FLOAT; + break; + + case EF_ARM_EABI_VER4: + /* No additional flags to set. */ + break; + + default: + abort (); + } +#endif + bfd_set_private_flags (stdoutput, flags); + + /* We have run out flags in the COFF header to encode the + status of ATPCS support, so instead we create a dummy, + empty, debug section called .arm.atpcs. */ + if (atpcs) + { + asection * sec; + + sec = bfd_make_section (stdoutput, ".arm.atpcs"); + + if (sec != NULL) + { + bfd_set_section_flags + (stdoutput, sec, SEC_READONLY | SEC_DEBUGGING /* | SEC_HAS_CONTENTS */); + bfd_set_section_size (stdoutput, sec, 0); + bfd_set_section_contents (stdoutput, sec, NULL, 0, 0); + } + } + } +#endif + + /* 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; + + case ARM_6: /* Also ARM_7. */ + mach = bfd_mach_arm_3; + break; + + default: + mach = bfd_mach_arm_unknown; + break; + } + + /* Catch special cases. */ + if (cpu_variant & ARM_CEXT_IWMMXT) + mach = bfd_mach_arm_iWMMXt; + else if (cpu_variant & ARM_CEXT_XSCALE) + mach = bfd_mach_arm_XScale; + else if (cpu_variant & ARM_CEXT_MAVERICK) + mach = bfd_mach_arm_ep9312; + else if (cpu_variant & ARM_EXT_V5E) + mach = bfd_mach_arm_5TE; + else if (cpu_variant & ARM_EXT_V5) + { + if (cpu_variant & ARM_EXT_V4T) + mach = bfd_mach_arm_5T; + else + mach = bfd_mach_arm_5; + } + else if (cpu_variant & ARM_EXT_V4) + { + if (cpu_variant & ARM_EXT_V4T) + mach = bfd_mach_arm_4T; + else + mach = bfd_mach_arm_4; + } + else if (cpu_variant & ARM_EXT_V3M) + mach = bfd_mach_arm_3M; + + bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach); } +/* Command line processing. */ + /* md_parse_option Invocation line includes a switch not recognized by the base assembler. See if it's a processor-specific option. @@ -12793,23 +11761,23 @@ md_assemble (char * str) The remaining options are only supported for back-wards compatibility. Cpu variants, the arm part is optional: - -m[arm]1 Currently not supported. - -m[arm]2, -m[arm]250 Arm 2 and Arm 250 processor - -m[arm]3 Arm 3 processor - -m[arm]6[xx], Arm 6 processors - -m[arm]7[xx][t][[d]m] Arm 7 processors - -m[arm]8[10] Arm 8 processors - -m[arm]9[20][tdmi] Arm 9 processors - -mstrongarm[110[0]] StrongARM processors - -mxscale XScale processors - -m[arm]v[2345[t[e]]] Arm architectures - -mall All (except the ARM1) + -m[arm]1 Currently not supported. + -m[arm]2, -m[arm]250 Arm 2 and Arm 250 processor + -m[arm]3 Arm 3 processor + -m[arm]6[xx], Arm 6 processors + -m[arm]7[xx][t][[d]m] Arm 7 processors + -m[arm]8[10] Arm 8 processors + -m[arm]9[20][tdmi] Arm 9 processors + -mstrongarm[110[0]] StrongARM processors + -mxscale XScale processors + -m[arm]v[2345[t[e]]] Arm architectures + -mall All (except the ARM1) FP variants: - -mfpa10, -mfpa11 FPA10 and 11 co-processor instructions - -mfpe-old (No float load/store multiples) + -mfpa10, -mfpa11 FPA10 and 11 co-processor instructions + -mfpe-old (No float load/store multiples) -mvfpxd VFP Single precision -mvfp All VFP - -mno-fpu Disable all floating point instructions + -mno-fpu Disable all floating point instructions The following CPU names are recognized: arm1, arm2, arm250, arm3, arm6, arm600, arm610, arm620, @@ -12852,15 +11820,15 @@ struct arm_option_table { char *option; /* Option name to match. */ char *help; /* Help information. */ - int *var; /* Variable to change. */ - int value; /* What to change it to. */ + int *var; /* Variable to change. */ + int value; /* What to change it to. */ char *deprecated; /* If non-null, print this message. */ }; struct arm_option_table arm_opts[] = { - {"k", N_("generate PIC code"), &pic_code, 1, NULL}, - {"mthumb", N_("assemble Thumb code"), &thumb_mode, 1, NULL}, + {"k", N_("generate PIC code"), &pic_code, 1, NULL}, + {"mthumb", N_("assemble Thumb code"), &thumb_mode, 1, NULL}, {"mthumb-interwork", N_("support ARM/Thumb interworking"), &support_interwork, 1, NULL}, {"mapcs-32", N_("code uses 32-bit program counter"), &uses_apcs_26, 0, NULL}, @@ -12873,7 +11841,7 @@ struct arm_option_table arm_opts[] = {"mlittle-endian", N_("assemble for little-endian"), &target_big_endian, 0, NULL}, - /* These are recognized by the assembler, but have no affect on code. */ + /* These are recognized by the assembler, but have no affect on code. */ {"mapcs-frame", N_("use frame pointer"), NULL, 0, NULL}, {"mapcs-stack-check", N_("use stack size checking"), NULL, 0, NULL}, @@ -12956,7 +11924,7 @@ struct arm_option_table arm_opts[] = N_("use -mcpu=strongarm1110")}, {"mxscale", NULL, &legacy_cpu, ARM_ARCH_XSCALE, N_("use -mcpu=xscale")}, {"miwmmxt", NULL, &legacy_cpu, ARM_ARCH_IWMMXT, N_("use -mcpu=iwmmxt")}, - {"mall", NULL, &legacy_cpu, ARM_ANY, N_("use -mcpu=all")}, + {"mall", NULL, &legacy_cpu, ARM_ANY, N_("use -mcpu=all")}, /* Architecture variants -- don't add any more to this list either. */ {"mv2", NULL, &legacy_cpu, ARM_ARCH_V2, N_("use -march=armv2")}, @@ -12978,7 +11946,7 @@ struct arm_option_table arm_opts[] = {"mv5e", NULL, &legacy_cpu, ARM_ARCH_V5TE, N_("use -march=armv5te")}, {"marmv5e", NULL, &legacy_cpu, ARM_ARCH_V5TE, N_("use -march=armv5te")}, - /* Floating point variants -- don't add any more to this list either. */ + /* Floating point variants -- don't add any more to this list either. */ {"mfpe-old", NULL, &legacy_fpu, FPU_ARCH_FPE, N_("use -mfpu=fpe")}, {"mfpa10", NULL, &legacy_fpu, FPU_ARCH_FPA, N_("use -mfpu=fpa10")}, {"mfpa11", NULL, &legacy_fpu, FPU_ARCH_FPA, N_("use -mfpu=fpa11")}, @@ -12991,10 +11959,10 @@ struct arm_option_table arm_opts[] = struct arm_cpu_option_table { char *name; - int value; + int value; /* For some CPUs we assume an FPU unless the user explicitly sets - -mfpu=... */ - int default_fpu; + -mfpu=... */ + int default_fpu; }; /* This list should, at a minimum, contain all the cpu names @@ -13046,14 +12014,14 @@ static struct arm_cpu_option_table arm_cpus[] = {"arm940t", ARM_ARCH_V4T, FPU_ARCH_FPA}, {"arm9tdmi", ARM_ARCH_V4T, FPU_ARCH_FPA}, /* For V5 or later processors we default to using VFP; but the user - should really set the FPU type explicitly. */ + should really set the FPU type explicitly. */ {"arm9e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2}, - {"arm9e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2}, + {"arm9e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2}, {"arm926ej", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2}, {"arm926ejs", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2}, {"arm926ej-s", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2}, {"arm946e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2}, - {"arm946e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2}, + {"arm946e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2}, {"arm966e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2}, {"arm966e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2}, {"arm10t", ARM_ARCH_V5T, FPU_ARCH_VFP_V1}, @@ -13063,14 +12031,14 @@ static struct arm_cpu_option_table arm_cpus[] = {"arm1020e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2}, {"arm1026ejs", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2}, {"arm1026ej-s", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2}, - {"arm1136js", ARM_ARCH_V6, FPU_NONE}, - {"arm1136j-s", ARM_ARCH_V6, FPU_NONE}, - {"arm1136jfs", ARM_ARCH_V6, FPU_ARCH_VFP_V2}, - {"arm1136jf-s", ARM_ARCH_V6, FPU_ARCH_VFP_V2}, - {"mpcore", ARM_ARCH_V6K, FPU_ARCH_VFP_V2}, - {"mpcorenovfp", ARM_ARCH_V6K, FPU_NONE}, - {"arm1176jz-s", ARM_ARCH_V6ZK, FPU_NONE}, - {"arm1176jzf-s", ARM_ARCH_V6ZK, FPU_ARCH_VFP_V2}, + {"arm1136js", ARM_ARCH_V6, FPU_NONE}, + {"arm1136j-s", ARM_ARCH_V6, FPU_NONE}, + {"arm1136jfs", ARM_ARCH_V6, FPU_ARCH_VFP_V2}, + {"arm1136jf-s", ARM_ARCH_V6, FPU_ARCH_VFP_V2}, + {"mpcore", ARM_ARCH_V6K, FPU_ARCH_VFP_V2}, + {"mpcorenovfp", ARM_ARCH_V6K, FPU_NONE}, + {"arm1176jz-s", ARM_ARCH_V6ZK, FPU_NONE}, + {"arm1176jzf-s", ARM_ARCH_V6ZK, FPU_ARCH_VFP_V2}, /* ??? XSCALE is really an architecture. */ {"xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2}, /* ??? iwmmxt is not a processor. */ @@ -13084,8 +12052,8 @@ static struct arm_cpu_option_table arm_cpus[] = struct arm_arch_option_table { char *name; - int value; - int default_fpu; + int value; + int default_fpu; }; /* This list should, at a minimum, contain all the architecture names @@ -13108,15 +12076,15 @@ static struct arm_arch_option_table arm_archs[] = {"armv5txm", ARM_ARCH_V5TxM, FPU_ARCH_VFP}, {"armv5te", ARM_ARCH_V5TE, FPU_ARCH_VFP}, {"armv5texp", ARM_ARCH_V5TExP, FPU_ARCH_VFP}, - {"armv5tej", ARM_ARCH_V5TEJ, FPU_ARCH_VFP}, - {"armv6", ARM_ARCH_V6, FPU_ARCH_VFP}, - {"armv6j", ARM_ARCH_V6, FPU_ARCH_VFP}, - {"armv6k", ARM_ARCH_V6K, FPU_ARCH_VFP}, - {"armv6z", ARM_ARCH_V6Z, FPU_ARCH_VFP}, - {"armv6zk", ARM_ARCH_V6ZK, FPU_ARCH_VFP}, - {"armv6t2", ARM_ARCH_V6T2, FPU_ARCH_VFP}, - {"armv6kt2", ARM_ARCH_V6KT2, FPU_ARCH_VFP}, - {"armv6zt2", ARM_ARCH_V6ZT2, FPU_ARCH_VFP}, + {"armv5tej", ARM_ARCH_V5TEJ, FPU_ARCH_VFP}, + {"armv6", ARM_ARCH_V6, FPU_ARCH_VFP}, + {"armv6j", ARM_ARCH_V6, FPU_ARCH_VFP}, + {"armv6k", ARM_ARCH_V6K, FPU_ARCH_VFP}, + {"armv6z", ARM_ARCH_V6Z, FPU_ARCH_VFP}, + {"armv6zk", ARM_ARCH_V6ZK, FPU_ARCH_VFP}, + {"armv6t2", ARM_ARCH_V6T2, FPU_ARCH_VFP}, + {"armv6kt2", ARM_ARCH_V6KT2, FPU_ARCH_VFP}, + {"armv6zt2", ARM_ARCH_V6ZT2, FPU_ARCH_VFP}, {"armv6zkt2", ARM_ARCH_V6ZKT2, FPU_ARCH_VFP}, {"xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP}, {"iwmmxt", ARM_ARCH_IWMMXT, FPU_ARCH_VFP}, @@ -13124,13 +12092,13 @@ static struct arm_arch_option_table arm_archs[] = }; /* ISA extensions in the co-processor space. */ -struct arm_arch_extension_table +struct arm_option_value_table { char *name; int value; }; -static struct arm_arch_extension_table arm_extensions[] = +static struct arm_option_value_table arm_extensions[] = { {"maverick", ARM_CEXT_MAVERICK}, {"xscale", ARM_CEXT_XSCALE}, @@ -13138,15 +12106,9 @@ static struct arm_arch_extension_table arm_extensions[] = {NULL, 0} }; -struct arm_fpu_option_table -{ - char *name; - int value; -}; - /* This list should, at a minimum, contain all the fpu names recognized by GCC. */ -static struct arm_fpu_option_table arm_fpus[] = +static struct arm_option_value_table arm_fpus[] = { {"softfpa", FPU_NONE}, {"fpe", FPU_ARCH_FPE}, @@ -13171,13 +12133,7 @@ static struct arm_fpu_option_table arm_fpus[] = {NULL, 0} }; -struct arm_float_abi_option_table -{ - char *name; - int value; -}; - -static struct arm_float_abi_option_table arm_float_abis[] = +static struct arm_option_value_table arm_float_abis[] = { {"hard", ARM_FLOAT_ABI_HARD}, {"softfp", ARM_FLOAT_ABI_SOFTFP}, @@ -13185,15 +12141,9 @@ static struct arm_float_abi_option_table arm_float_abis[] = {NULL, 0} }; -struct arm_eabi_option_table -{ - char *name; - unsigned int value; -}; - #ifdef OBJ_ELF /* We only know how to output GNU and ver 4 (AAELF) formats. */ -static struct arm_eabi_option_table arm_eabis[] = +static struct arm_option_value_table arm_eabis[] = { {"gnu", EF_ARM_EABI_UNKNOWN}, {"4", EF_ARM_EABI_VER4}, @@ -13203,7 +12153,7 @@ static struct arm_eabi_option_table arm_eabis[] = struct arm_long_option_table { - char * option; /* Substring to match. */ + char * option; /* Substring to match. */ char * help; /* Help information. */ int (* func) (char * subopt); /* Function to decode sub-option. */ char * deprecated; /* If non-null, print this message. */ @@ -13214,7 +12164,7 @@ arm_parse_extension (char * str, int * opt_p) { while (str != NULL && *str != 0) { - struct arm_arch_extension_table * opt; + struct arm_option_value_table * opt; char * ext; int optlen; @@ -13329,7 +12279,7 @@ arm_parse_arch (char * str) static int arm_parse_fpu (char * str) { - struct arm_fpu_option_table * opt; + struct arm_option_value_table * opt; for (opt = arm_fpus; opt->name != NULL; opt++) if (streq (opt->name, str)) @@ -13345,7 +12295,7 @@ arm_parse_fpu (char * str) static int arm_parse_float_abi (char * str) { - struct arm_float_abi_option_table * opt; + struct arm_option_value_table * opt; for (opt = arm_float_abis; opt->name != NULL; opt++) if (streq (opt->name, str)) @@ -13362,7 +12312,7 @@ arm_parse_float_abi (char * str) static int arm_parse_eabi (char * str) { - struct arm_eabi_option_table *opt; + struct arm_option_value_table *opt; for (opt = arm_eabis; opt->name != NULL; opt++) if (streq (opt->name, str)) @@ -13414,7 +12364,7 @@ md_parse_option (int c, char * arg) case 'a': /* Listing option. Just ignore these, we don't support additional - ones. */ + ones. */ return 0; default: @@ -13490,1769 +12440,3 @@ md_show_usage (FILE * fp) -EL assemble code for a little-endian cpu\n")); #endif } - -/* This fix_new is called by cons via TC_CONS_FIX_NEW. */ - -void -cons_fix_new_arm (fragS * frag, - int where, - int size, - expressionS * exp) -{ - bfd_reloc_code_real_type type; - int pcrel = 0; - - /* Pick a reloc. - FIXME: @@ Should look at CPU word size. */ - switch (size) - { - case 1: - type = BFD_RELOC_8; - break; - case 2: - type = BFD_RELOC_16; - break; - case 4: - default: - type = BFD_RELOC_32; - break; - case 8: - type = BFD_RELOC_64; - break; - } - - fix_new_exp (frag, where, (int) size, exp, pcrel, type); -} - -/* A good place to do this, although this was probably not intended - for this kind of use. We need to dump the literal pool before - references are made to a null symbol pointer. */ - -void -arm_cleanup (void) -{ - literal_pool * pool; - - for (pool = list_of_pools; pool; pool = pool->next) - { - /* Put it at the end of the relevent section. */ - subseg_set (pool->section, pool->sub_section); -#ifdef OBJ_ELF - arm_elf_change_section (); -#endif - s_ltorg (0); - } -} - -void -arm_start_line_hook (void) -{ - last_label_seen = NULL; -} - -void -arm_frob_label (symbolS * sym) -{ - last_label_seen = sym; - - ARM_SET_THUMB (sym, thumb_mode); - -#if defined OBJ_COFF || defined OBJ_ELF - ARM_SET_INTERWORK (sym, support_interwork); -#endif - - /* Note - do not allow local symbols (.Lxxx) to be labeled - as Thumb functions. This is because these labels, whilst - they exist inside Thumb code, are not the entry points for - possible ARM->Thumb calls. Also, these labels can be used - as part of a computed goto or switch statement. eg gcc - can generate code that looks like this: - - ldr r2, [pc, .Laaa] - lsl r3, r3, #2 - ldr r2, [r3, r2] - mov pc, r2 - - .Lbbb: .word .Lxxx - .Lccc: .word .Lyyy - ..etc... - .Laaa: .word Lbbb - - The first instruction loads the address of the jump table. - The second instruction converts a table index into a byte offset. - The third instruction gets the jump address out of the table. - The fourth instruction performs the jump. - - If the address stored at .Laaa is that of a symbol which has the - Thumb_Func bit set, then the linker will arrange for this address - to have the bottom bit set, which in turn would mean that the - address computation performed by the third instruction would end - up with the bottom bit set. Since the ARM is capable of unaligned - word loads, the instruction would then load the incorrect address - out of the jump table, and chaos would ensue. */ - if (label_is_thumb_function_name - && (S_GET_NAME (sym)[0] != '.' || S_GET_NAME (sym)[1] != 'L') - && (bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0) - { - /* When the address of a Thumb function is taken the bottom - bit of that address should be set. This will allow - interworking between Arm and Thumb functions to work - correctly. */ - - THUMB_SET_FUNC (sym, 1); - - label_is_thumb_function_name = FALSE; - } -} - -/* Adjust the symbol table. This marks Thumb symbols as distinct from - ARM ones. */ - -void -arm_adjust_symtab (void) -{ -#ifdef OBJ_COFF - symbolS * sym; - - for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym)) - { - if (ARM_IS_THUMB (sym)) - { - if (THUMB_IS_FUNC (sym)) - { - /* Mark the symbol as a Thumb function. */ - if ( S_GET_STORAGE_CLASS (sym) == C_STAT - || S_GET_STORAGE_CLASS (sym) == C_LABEL) /* This can happen! */ - S_SET_STORAGE_CLASS (sym, C_THUMBSTATFUNC); - - else if (S_GET_STORAGE_CLASS (sym) == C_EXT) - S_SET_STORAGE_CLASS (sym, C_THUMBEXTFUNC); - else - as_bad (_("%s: unexpected function type: %d"), - S_GET_NAME (sym), S_GET_STORAGE_CLASS (sym)); - } - else switch (S_GET_STORAGE_CLASS (sym)) - { - case C_EXT: - S_SET_STORAGE_CLASS (sym, C_THUMBEXT); - break; - case C_STAT: - S_SET_STORAGE_CLASS (sym, C_THUMBSTAT); - break; - case C_LABEL: - S_SET_STORAGE_CLASS (sym, C_THUMBLABEL); - break; - default: - /* Do nothing. */ - break; - } - } - - if (ARM_IS_INTERWORK (sym)) - coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_flags = 0xFF; - } -#endif -#ifdef OBJ_ELF - symbolS * 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->internal_elf_sym.st_info); - - if (! bfd_is_arm_mapping_symbol_name (elf_sym->symbol.name)) - { - /* If it's a .thumb_func, declare it as so, - otherwise tag label as .code 16. */ - if (THUMB_IS_FUNC (sym)) - 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 -} - -int -arm_data_in_code (void) -{ - if (thumb_mode && ! strncmp (input_line_pointer + 1, "data:", 5)) - { - *input_line_pointer = '/'; - input_line_pointer += 5; - *input_line_pointer = 0; - return 1; - } - - return 0; -} - -char * -arm_canonicalize_symbol_name (char * name) -{ - int len; - - if (thumb_mode && (len = strlen (name)) > 5 - && streq (name + len - 5, "/data")) - *(name + len - 5) = 0; - - return name; -} - -#if defined OBJ_COFF || defined OBJ_ELF -void -arm_validate_fix (fixS * fixP) -{ - /* If the destination of the branch is a defined symbol which does not have - the THUMB_FUNC attribute, then we must be calling a function which has - the (interfacearm) attribute. We look for the Thumb entry point to that - function and change the branch to refer to that function instead. */ - if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23 - && fixP->fx_addsy != NULL - && S_IS_DEFINED (fixP->fx_addsy) - && ! THUMB_IS_FUNC (fixP->fx_addsy)) - { - fixP->fx_addsy = find_real_start (fixP->fx_addsy); - } -} -#endif - -int -arm_force_relocation (struct fix * fixp) -{ -#if defined (OBJ_COFF) && defined (TE_PE) - if (fixp->fx_r_type == BFD_RELOC_RVA) - return 1; -#endif -#ifdef OBJ_ELF - if (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; -#endif - - /* Resolve these relocations even if the symbol is extern or weak. */ - if (fixp->fx_r_type == BFD_RELOC_ARM_IMMEDIATE - || fixp->fx_r_type == BFD_RELOC_ARM_OFFSET_IMM - || fixp->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE) - return 0; - - return generic_force_reloc (fixp); -} - -#ifdef OBJ_COFF -/* This is a little hack to help the gas/arm/adrl.s test. It prevents - local labels from being added to the output symbol table when they - are used with the ADRL pseudo op. The ADRL relocation should always - be resolved before the binbary is emitted, so it is safe to say that - it is adjustable. */ - -bfd_boolean -arm_fix_adjustable (fixS * fixP) -{ - if (fixP->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE) - return 1; - return 0; -} -#endif - -#ifdef OBJ_ELF -/* Relocations against Thumb function names must be left unadjusted, - so that the linker can use this information to correctly set the - bottom bit of their addresses. The MIPS version of this function - also prevents relocations that are mips-16 specific, but I do not - know why it does this. - - FIXME: - There is one other problem that ought to be addressed here, but - which currently is not: Taking the address of a label (rather - than a function) and then later jumping to that address. Such - addresses also ought to have their bottom bit set (assuming that - they reside in Thumb code), but at the moment they will not. */ - -bfd_boolean -arm_fix_adjustable (fixS * fixP) -{ - if (fixP->fx_addsy == NULL) - return 1; - - if (THUMB_IS_FUNC (fixP->fx_addsy) - && fixP->fx_subsy == NULL) - return 0; - - /* We need the symbol name for the VTABLE entries. */ - if ( fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT - || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) - return 0; - - /* Don't allow symbols to be discarded on GOT related relocs. */ - if (fixP->fx_r_type == BFD_RELOC_ARM_PLT32 - || fixP->fx_r_type == BFD_RELOC_ARM_GOT32 - || fixP->fx_r_type == BFD_RELOC_ARM_GOTOFF - || fixP->fx_r_type == BFD_RELOC_ARM_TLS_GD32 - || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LE32 - || fixP->fx_r_type == BFD_RELOC_ARM_TLS_IE32 - || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDM32 - || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDO32 - || fixP->fx_r_type == BFD_RELOC_ARM_TARGET2) - return 0; - - return 1; -} - -const char * -elf32_arm_target_format (void) -{ -#ifdef TE_SYMBIAN - return (target_big_endian - ? "elf32-bigarm-symbian" - : "elf32-littlearm-symbian"); -#elif defined (TE_VXWORKS) - return (target_big_endian - ? "elf32-bigarm-vxworks" - : "elf32-littlearm-vxworks"); -#else - if (target_big_endian) - return "elf32-bigarm"; - else - return "elf32-littlearm"; -#endif -} - -void -armelf_frob_symbol (symbolS * symp, - int * puntp) -{ - elf_frob_symbol (symp, puntp); -} - -static void -s_arm_elf_cons (int nbytes) -{ - expressionS exp; - -#ifdef md_flush_pending_output - md_flush_pending_output (); -#endif - - if (is_it_end_of_statement ()) - { - demand_empty_rest_of_line (); - return; - } - -#ifdef md_cons_align - md_cons_align (nbytes); -#endif - - mapping_state (MAP_DATA); - do - { - bfd_reloc_code_real_type reloc; - char *sym_start; - int sym_len; - - sym_start = input_line_pointer; - expression (& exp); - sym_len = input_line_pointer - sym_start; - - if (exp.X_op == O_symbol - && * input_line_pointer == '(' - && (reloc = arm_parse_reloc ()) != BFD_RELOC_UNUSED) - { - reloc_howto_type *howto = bfd_reloc_type_lookup (stdoutput, reloc); - int size = bfd_get_reloc_size (howto); - - if (size > nbytes) - as_bad ("%s relocations do not fit in %d bytes", - howto->name, nbytes); - else - { - char *p; - int offset = nbytes - size; - char *saved_buf = alloca (sym_len), *saved_input; - - /* We've parsed an expression stopping at O_symbol. But there - may be more expression left now that we have parsed the - relocation marker. Parse it again. */ - saved_input = input_line_pointer - sym_len; - memcpy (saved_buf, saved_input, sym_len); - memmove (saved_input, sym_start, sym_len); - input_line_pointer = saved_input; - expression (& exp); - memcpy (saved_input, saved_buf, sym_len); - assert (input_line_pointer >= saved_input + sym_len); - - p = frag_more ((int) nbytes); - fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size, - &exp, 0, reloc); - } - } - else - emit_expr (&exp, (unsigned int) nbytes); - } - while (*input_line_pointer++ == ','); - - /* Put terminator back into stream. */ - input_line_pointer --; - demand_empty_rest_of_line (); -} - - -/* Parse a .rel31 directive. */ - -static void -s_arm_rel31 (int ignored ATTRIBUTE_UNUSED) -{ - expressionS exp; - char *p; - valueT highbit; - - SKIP_WHITESPACE (); - - highbit = 0; - if (*input_line_pointer == '1') - highbit = 0x80000000; - else if (*input_line_pointer != '0') - as_bad (_("expected 0 or 1")); - - input_line_pointer++; - SKIP_WHITESPACE (); - if (*input_line_pointer != ',') - as_bad (_("missing comma")); - input_line_pointer++; - -#ifdef md_flush_pending_output - md_flush_pending_output (); -#endif - -#ifdef md_cons_align - md_cons_align (4); -#endif - - mapping_state (MAP_DATA); - - expression (&exp); - - p = frag_more (4); - md_number_to_chars (p, highbit, 4); - fix_new_arm (frag_now, p - frag_now->fr_literal, 4, &exp, 1, - BFD_RELOC_ARM_PREL31); - - demand_empty_rest_of_line (); -} - -/* Code to deal with unwinding tables. */ - -static void add_unwind_adjustsp (offsetT); - -/* Switch to section NAME and create section if necessary. It's - rather ugly that we have to manipulate input_line_pointer but I - don't see any other way to accomplish the same thing without - changing obj-elf.c (which may be the Right Thing, in the end). - Copied from tc-ia64.c. */ - -static void -set_section (char *name) -{ - char *saved_input_line_pointer; - - saved_input_line_pointer = input_line_pointer; - input_line_pointer = name; - obj_elf_section (0); - input_line_pointer = saved_input_line_pointer; -} - -/* Cenerate and deferred unwind frame offset. */ - -static void -flush_pending_unwind (void) -{ - offsetT offset; - - offset = unwind.pending_offset; - unwind.pending_offset = 0; - if (offset != 0) - add_unwind_adjustsp (offset); -} - -/* Add an opcode to this list for this function. Two-byte opcodes should - be passed as op[0] << 8 | op[1]. The list of opcodes is built in reverse - order. */ - -static void -add_unwind_opcode (valueT op, int length) -{ - /* Add any deferred stack adjustment. */ - if (unwind.pending_offset) - flush_pending_unwind (); - - unwind.sp_restored = 0; - - if (unwind.opcode_count + length > unwind.opcode_alloc) - { - unwind.opcode_alloc += ARM_OPCODE_CHUNK_SIZE; - if (unwind.opcodes) - unwind.opcodes = xrealloc (unwind.opcodes, - unwind.opcode_alloc); - else - unwind.opcodes = xmalloc (unwind.opcode_alloc); - } - while (length > 0) - { - length--; - unwind.opcodes[unwind.opcode_count] = op & 0xff; - op >>= 8; - unwind.opcode_count++; - } -} - -/* Add unwind opcodes to adjust the stack pointer. */ - -static void -add_unwind_adjustsp (offsetT offset) -{ - valueT op; - - if (offset > 0x200) - { - /* We need at most 5 bytes to hold a 32-bit value in a uleb128. */ - char bytes[5]; - int n; - valueT o; - - /* Long form: 0xb2, uleb128. */ - /* This might not fit in a word so add the individual bytes, - remembering the list is built in reverse order. */ - o = (valueT) ((offset - 0x204) >> 2); - if (o == 0) - add_unwind_opcode (0, 1); - - /* Calculate the uleb128 encoding of the offset. */ - n = 0; - while (o) - { - bytes[n] = o & 0x7f; - o >>= 7; - if (o) - bytes[n] |= 0x80; - n++; - } - /* Add the insn. */ - for (; n; n--) - add_unwind_opcode (bytes[n - 1], 1); - add_unwind_opcode (0xb2, 1); - } - else if (offset > 0x100) - { - /* Two short opcodes. */ - add_unwind_opcode (0x3f, 1); - op = (offset - 0x104) >> 2; - add_unwind_opcode (op, 1); - } - else if (offset > 0) - { - /* Short opcode. */ - op = (offset - 4) >> 2; - add_unwind_opcode (op, 1); - } - else if (offset < 0) - { - offset = -offset; - while (offset > 0x100) - { - add_unwind_opcode (0x7f, 1); - offset -= 0x100; - } - op = ((offset - 4) >> 2) | 0x40; - add_unwind_opcode (op, 1); - } -} - -/* Finish the list of unwind opcodes for this function. */ -static void -finish_unwind_opcodes (void) -{ - valueT op; - - if (unwind.fp_used) - { - /* Adjust sp as neccessary. */ - unwind.pending_offset += unwind.fp_offset - unwind.frame_size; - flush_pending_unwind (); - - /* After restoring sp from the frame pointer. */ - op = 0x90 | unwind.fp_reg; - add_unwind_opcode (op, 1); - } - else - flush_pending_unwind (); -} - - -/* Start an exception table entry. If idx is nonzero this is an index table - entry. */ - -static void -start_unwind_section (const segT text_seg, int idx) -{ - const char * text_name; - const char * prefix; - const char * prefix_once; - size_t prefix_len; - size_t text_len; - char * sec_name; - size_t sec_name_len; - - if (idx) - { - prefix = ELF_STRING_ARM_unwind; - prefix_once = ELF_STRING_ARM_unwind_once; - } - else - { - prefix = ELF_STRING_ARM_unwind_info; - prefix_once = ELF_STRING_ARM_unwind_info_once; - } - - text_name = segment_name (text_seg); - if (streq (text_name, ".text")) - text_name = ""; - - if (strncmp (text_name, ".gnu.linkonce.t.", - strlen (".gnu.linkonce.t.")) == 0) - { - prefix = prefix_once; - text_name += strlen (".gnu.linkonce.t."); - } - - prefix_len = strlen (prefix); - text_len = strlen (text_name); - sec_name_len = prefix_len + text_len; - sec_name = alloca (sec_name_len + 1); - memcpy (sec_name, prefix, prefix_len); - memcpy (sec_name + prefix_len, text_name, text_len); - sec_name[prefix_len + text_len] = '\0'; - - /* Handle COMDAT group. */ - if (prefix != prefix_once && (text_seg->flags & SEC_LINK_ONCE) != 0) - { - char *section; - size_t len, group_name_len; - const char *group_name = elf_group_name (text_seg); - - if (group_name == NULL) - { - as_bad ("Group section `%s' has no group signature", - segment_name (text_seg)); - ignore_rest_of_line (); - return; - } - /* We have to construct a fake section directive. */ - group_name_len = strlen (group_name); - if (idx) - prefix_len = 13; - else - prefix_len = 16; - - len = (sec_name_len - + prefix_len /* ,"aG",%sectiontype, */ - + group_name_len /* ,group_name */ - + 7); /* ,comdat */ - - section = alloca (len + 1); - memcpy (section, sec_name, sec_name_len); - if (idx) - memcpy (section + sec_name_len, ",\"aG\",%exidx,", 13); - else - memcpy (section + sec_name_len, ",\"aG\",%progbits,", 16); - memcpy (section + sec_name_len + prefix_len, group_name, group_name_len); - memcpy (section + len - 7, ",comdat", 7); - section [len] = '\0'; - set_section (section); - } - else - { - set_section (sec_name); - bfd_set_section_flags (stdoutput, now_seg, - SEC_LOAD | SEC_ALLOC | SEC_READONLY); - } - - /* Set the setion link for index tables. */ - if (idx) - elf_linked_to_section (now_seg) = text_seg; -} - - -/* Start an unwind table entry. HAVE_DATA is nonzero if we have additional - personality routine data. Returns zero, or the index table value for - and inline entry. */ - -static valueT -create_unwind_entry (int have_data) -{ - int size; - addressT where; - char *ptr; - /* The current word of data. */ - valueT data; - /* The number of bytes left in this word. */ - int n; - - finish_unwind_opcodes (); - - /* Remember the current text section. */ - unwind.saved_seg = now_seg; - unwind.saved_subseg = now_subseg; - - start_unwind_section (now_seg, 0); - - if (unwind.personality_routine == NULL) - { - if (unwind.personality_index == -2) - { - if (have_data) - as_bad (_("handerdata in cantunwind frame")); - return 1; /* EXIDX_CANTUNWIND. */ - } - - /* Use a default personality routine if none is specified. */ - if (unwind.personality_index == -1) - { - if (unwind.opcode_count > 3) - unwind.personality_index = 1; - else - unwind.personality_index = 0; - } - - /* Space for the personality routine entry. */ - if (unwind.personality_index == 0) - { - if (unwind.opcode_count > 3) - as_bad (_("too many unwind opcodes for personality routine 0")); - - if (!have_data) - { - /* All the data is inline in the index table. */ - data = 0x80; - n = 3; - while (unwind.opcode_count > 0) - { - unwind.opcode_count--; - data = (data << 8) | unwind.opcodes[unwind.opcode_count]; - n--; - } - - /* Pad with "finish" opcodes. */ - while (n--) - data = (data << 8) | 0xb0; - - return data; - } - size = 0; - } - else - /* We get two opcodes "free" in the first word. */ - size = unwind.opcode_count - 2; - } - else - /* An extra byte is required for the opcode count. */ - size = unwind.opcode_count + 1; - - size = (size + 3) >> 2; - if (size > 0xff) - as_bad (_("too many unwind opcodes")); - - frag_align (2, 0, 0); - record_alignment (now_seg, 2); - unwind.table_entry = expr_build_dot (); - - /* Allocate the table entry. */ - ptr = frag_more ((size << 2) + 4); - where = frag_now_fix () - ((size << 2) + 4); - - switch (unwind.personality_index) - { - case -1: - /* ??? Should this be a PLT generating relocation? */ - /* Custom personality routine. */ - fix_new (frag_now, where, 4, unwind.personality_routine, 0, 1, - BFD_RELOC_ARM_PREL31); - - where += 4; - ptr += 4; - - /* Set the first byte to the number of additional words. */ - data = size - 1; - n = 3; - break; - - /* ABI defined personality routines. */ - case 0: - /* Three opcodes bytes are packed into the first word. */ - data = 0x80; - n = 3; - break; - - case 1: - case 2: - /* The size and first two opcode bytes go in the first word. */ - data = ((0x80 + unwind.personality_index) << 8) | size; - n = 2; - break; - - default: - /* Should never happen. */ - abort (); - } - - /* Pack the opcodes into words (MSB first), reversing the list at the same - time. */ - while (unwind.opcode_count > 0) - { - if (n == 0) - { - md_number_to_chars (ptr, data, 4); - ptr += 4; - n = 4; - data = 0; - } - unwind.opcode_count--; - n--; - data = (data << 8) | unwind.opcodes[unwind.opcode_count]; - } - - /* Finish off the last word. */ - if (n < 4) - { - /* Pad with "finish" opcodes. */ - while (n--) - data = (data << 8) | 0xb0; - - md_number_to_chars (ptr, data, 4); - } - - if (!have_data) - { - /* Add an empty descriptor if there is no user-specified data. */ - ptr = frag_more (4); - md_number_to_chars (ptr, 0, 4); - } - - return 0; -} - - -/* Parse an unwind_fnstart directive. Simply records the current location. */ - -static void -s_arm_unwind_fnstart (int ignored ATTRIBUTE_UNUSED) -{ - demand_empty_rest_of_line (); - /* Mark the start of the function. */ - unwind.proc_start = expr_build_dot (); - - /* Reset the rest of the unwind info. */ - unwind.opcode_count = 0; - unwind.table_entry = NULL; - unwind.personality_routine = NULL; - unwind.personality_index = -1; - unwind.frame_size = 0; - unwind.fp_offset = 0; - unwind.fp_reg = 13; - unwind.fp_used = 0; - unwind.sp_restored = 0; -} - - -/* Parse a handlerdata directive. Creates the exception handling table entry - for the function. */ - -static void -s_arm_unwind_handlerdata (int ignored ATTRIBUTE_UNUSED) -{ - demand_empty_rest_of_line (); - if (unwind.table_entry) - as_bad (_("dupicate .handlerdata directive")); - - create_unwind_entry (1); -} - -/* Parse an unwind_fnend directive. Generates the index table entry. */ - -static void -s_arm_unwind_fnend (int ignored ATTRIBUTE_UNUSED) -{ - long where; - char *ptr; - valueT val; - - demand_empty_rest_of_line (); - - /* Add eh table entry. */ - if (unwind.table_entry == NULL) - val = create_unwind_entry (0); - else - val = 0; - - /* Add index table entry. This is two words. */ - start_unwind_section (unwind.saved_seg, 1); - frag_align (2, 0, 0); - record_alignment (now_seg, 2); - - ptr = frag_more (8); - where = frag_now_fix () - 8; - - /* Self relative offset of the function start. */ - fix_new (frag_now, where, 4, unwind.proc_start, 0, 1, - BFD_RELOC_ARM_PREL31); - - /* Indicate dependency on EHABI-defined personality routines to the - linker, if it hasn't been done already. */ - if (unwind.personality_index >= 0 && unwind.personality_index < 3) - { - char *name[] = { "__aeabi_unwind_cpp_pr0", - "__aeabi_unwind_cpp_pr1", - "__aeabi_unwind_cpp_pr2" }; - if (!(marked_pr_dependency & (1 << unwind.personality_index))) - { - symbolS *pr = symbol_find_or_make (name[unwind.personality_index]); - fix_new (frag_now, where, 0, pr, 0, 1, BFD_RELOC_NONE); - marked_pr_dependency |= 1 << unwind.personality_index; - seg_info (now_seg)->tc_segment_info_data.marked_pr_dependency - = marked_pr_dependency; - } - } - - if (val) - /* Inline exception table entry. */ - md_number_to_chars (ptr + 4, val, 4); - else - /* Self relative offset of the table entry. */ - fix_new (frag_now, where + 4, 4, unwind.table_entry, 0, 1, - BFD_RELOC_ARM_PREL31); - - /* Restore the original section. */ - subseg_set (unwind.saved_seg, unwind.saved_subseg); -} - - -/* Parse an unwind_cantunwind directive. */ - -static void -s_arm_unwind_cantunwind (int ignored ATTRIBUTE_UNUSED) -{ - demand_empty_rest_of_line (); - if (unwind.personality_routine || unwind.personality_index != -1) - as_bad (_("personality routine specified for cantunwind frame")); - - unwind.personality_index = -2; -} - - -/* Parse a personalityindex directive. */ - -static void -s_arm_unwind_personalityindex (int ignored ATTRIBUTE_UNUSED) -{ - expressionS exp; - - if (unwind.personality_routine || unwind.personality_index != -1) - as_bad (_("duplicate .personalityindex directive")); - - SKIP_WHITESPACE (); - - expression (&exp); - - if (exp.X_op != O_constant - || exp.X_add_number < 0 || exp.X_add_number > 15) - { - as_bad (_("bad personality routine number")); - ignore_rest_of_line (); - return; - } - - unwind.personality_index = exp.X_add_number; - - demand_empty_rest_of_line (); -} - - -/* Parse a personality directive. */ - -static void -s_arm_unwind_personality (int ignored ATTRIBUTE_UNUSED) -{ - char *name, *p, c; - - if (unwind.personality_routine || unwind.personality_index != -1) - as_bad (_("duplicate .personality directive")); - - SKIP_WHITESPACE (); - name = input_line_pointer; - c = get_symbol_end (); - p = input_line_pointer; - unwind.personality_routine = symbol_find_or_make (name); - *p = c; - SKIP_WHITESPACE (); - demand_empty_rest_of_line (); -} - - -/* Parse a directive saving core registers. */ - -static void -s_arm_unwind_save_core (void) -{ - valueT op; - long range; - int n; - - SKIP_WHITESPACE (); - range = reg_list (&input_line_pointer); - if (range == FAIL) - { - as_bad (_("expected register list")); - ignore_rest_of_line (); - return; - } - - demand_empty_rest_of_line (); - - /* Turn .unwind_movsp ip followed by .unwind_save {..., ip, ...} - into .unwind_save {..., sp...}. We aren't bothered about the value of - ip because it is clobbered by calls. */ - if (unwind.sp_restored && unwind.fp_reg == 12 - && (range & 0x3000) == 0x1000) - { - unwind.opcode_count--; - unwind.sp_restored = 0; - range = (range | 0x2000) & ~0x1000; - unwind.pending_offset = 0; - } - - /* See if we can use the short opcodes. These pop a block of upto 8 - registers starting with r4, plus maybe r14. */ - for (n = 0; n < 8; n++) - { - /* Break at the first non-saved register. */ - if ((range & (1 << (n + 4))) == 0) - break; - } - /* See if there are any other bits set. */ - if (n == 0 || (range & (0xfff0 << n) & 0xbff0) != 0) - { - /* Use the long form. */ - op = 0x8000 | ((range >> 4) & 0xfff); - add_unwind_opcode (op, 2); - } - else - { - /* Use the short form. */ - if (range & 0x4000) - op = 0xa8; /* Pop r14. */ - else - op = 0xa0; /* Do not pop r14. */ - op |= (n - 1); - add_unwind_opcode (op, 1); - } - - /* Pop r0-r3. */ - if (range & 0xf) - { - op = 0xb100 | (range & 0xf); - add_unwind_opcode (op, 2); - } - - /* Record the number of bytes pushed. */ - for (n = 0; n < 16; n++) - { - if (range & (1 << n)) - unwind.frame_size += 4; - } -} - - -/* Parse a directive saving FPA registers. */ - -static void -s_arm_unwind_save_fpa (int reg) -{ - expressionS exp; - int num_regs; - valueT op; - - /* Get Number of registers to transfer. */ - if (skip_past_comma (&input_line_pointer) != FAIL) - expression (&exp); - else - exp.X_op = O_illegal; - - if (exp.X_op != O_constant) - { - as_bad (_("expected , <constant>")); - ignore_rest_of_line (); - return; - } - - num_regs = exp.X_add_number; - - if (num_regs < 1 || num_regs > 4) - { - as_bad (_("number of registers must be in the range [1:4]")); - ignore_rest_of_line (); - return; - } - - demand_empty_rest_of_line (); - - if (reg == 4) - { - /* Short form. */ - op = 0xb4 | (num_regs - 1); - add_unwind_opcode (op, 1); - } - else - { - /* Long form. */ - op = 0xc800 | (reg << 4) | (num_regs - 1); - add_unwind_opcode (op, 2); - } - unwind.frame_size += num_regs * 12; -} - - -/* Parse a directive saving VFP registers. */ - -static void -s_arm_unwind_save_vfp (void) -{ - int count; - int reg; - valueT op; - - count = vfp_parse_reg_list (&input_line_pointer, ®, 1); - if (count == FAIL) - { - as_bad (_("expected register list")); - ignore_rest_of_line (); - return; - } - - demand_empty_rest_of_line (); - - if (reg == 8) - { - /* Short form. */ - op = 0xb8 | (count - 1); - add_unwind_opcode (op, 1); - } - else - { - /* Long form. */ - op = 0xb300 | (reg << 4) | (count - 1); - add_unwind_opcode (op, 2); - } - unwind.frame_size += count * 8 + 4; -} - - -/* Parse a directive saving iWMMXt registers. */ - -static void -s_arm_unwind_save_wmmx (void) -{ - int reg; - int hi_reg; - int i; - unsigned wcg_mask; - unsigned wr_mask; - valueT op; - - if (*input_line_pointer == '{') - input_line_pointer++; - - wcg_mask = 0; - wr_mask = 0; - do - { - reg = arm_reg_parse (&input_line_pointer, - all_reg_maps[REG_TYPE_IWMMXT].htab); - - if (wr_register (reg)) - { - i = reg & ~WR_PREFIX; - if (wr_mask >> i) - as_tsktsk (_("register list not in ascending order")); - wr_mask |= 1 << i; - } - else if (wcg_register (reg)) - { - i = (reg & ~WC_PREFIX) - 8; - if (wcg_mask >> i) - as_tsktsk (_("register list not in ascending order")); - wcg_mask |= 1 << i; - } - else - { - as_bad (_("expected wr or wcgr")); - goto error; - } - - SKIP_WHITESPACE (); - if (*input_line_pointer == '-') - { - hi_reg = arm_reg_parse (&input_line_pointer, - all_reg_maps[REG_TYPE_IWMMXT].htab); - if (wr_register (reg) && wr_register (hi_reg)) - { - for (; reg < hi_reg; reg++) - wr_mask |= 1 << (reg & ~WR_PREFIX); - } - else if (wcg_register (reg) && wcg_register (hi_reg)) - { - for (; reg < hi_reg; reg++) - wcg_mask |= 1 << ((reg & ~WC_PREFIX) - 8); - } - else - { - as_bad (_("bad register range")); - goto error; - } - } - } - while (skip_past_comma (&input_line_pointer) != FAIL); - - SKIP_WHITESPACE (); - if (*input_line_pointer == '}') - input_line_pointer++; - - demand_empty_rest_of_line (); - - if (wr_mask && wcg_mask) - { - as_bad (_("inconsistent register types")); - goto error; - } - - /* Generate any deferred opcodes becuuse we're going to be looking at - the list. */ - flush_pending_unwind (); - - if (wcg_mask) - { - for (i = 0; i < 16; i++) - { - if (wcg_mask & (1 << i)) - unwind.frame_size += 4; - } - op = 0xc700 | wcg_mask; - add_unwind_opcode (op, 2); - } - else - { - for (i = 0; i < 16; i++) - { - if (wr_mask & (1 << i)) - unwind.frame_size += 8; - } - /* Attempt to combine with a previous opcode. We do this because gcc - likes to output separate unwind directives for a single block of - registers. */ - if (unwind.opcode_count > 0) - { - i = unwind.opcodes[unwind.opcode_count - 1]; - if ((i & 0xf8) == 0xc0) - { - i &= 7; - /* Only merge if the blocks are contiguous. */ - if (i < 6) - { - if ((wr_mask & 0xfe00) == (1 << 9)) - { - wr_mask |= ((1 << (i + 11)) - 1) & 0xfc00; - unwind.opcode_count--; - } - } - else if (i == 6 && unwind.opcode_count >= 2) - { - i = unwind.opcodes[unwind.opcode_count - 2]; - reg = i >> 4; - i &= 0xf; - - op = 0xffff << (reg - 1); - if (reg > 0 - || ((wr_mask & op) == (1u << (reg - 1)))) - { - op = (1 << (reg + i + 1)) - 1; - op &= ~((1 << reg) - 1); - wr_mask |= op; - unwind.opcode_count -= 2; - } - } - } - } - - hi_reg = 15; - /* We want to generate opcodes in the order the registers have been - saved, ie. descending order. */ - for (reg = 15; reg >= -1; reg--) - { - /* Save registers in blocks. */ - if (reg < 0 - || !(wr_mask & (1 << reg))) - { - /* We found an unsaved reg. Generate opcodes to save the - preceeding block. */ - if (reg != hi_reg) - { - if (reg == 9) - { - /* Short form. */ - op = 0xc0 | (hi_reg - 10); - add_unwind_opcode (op, 1); - } - else - { - /* Long form. */ - op = 0xc600 | ((reg + 1) << 4) | ((hi_reg - reg) - 1); - add_unwind_opcode (op, 2); - } - } - hi_reg = reg - 1; - } - } - } - return; -error: - ignore_rest_of_line (); -} - - -/* Parse an unwind_save directive. */ - -static void -s_arm_unwind_save (int ignored ATTRIBUTE_UNUSED) -{ - char *saved_ptr; - int reg; - - /* Figure out what sort of save we have. */ - SKIP_WHITESPACE (); - saved_ptr = input_line_pointer; - - reg = arm_reg_parse (&input_line_pointer, all_reg_maps[REG_TYPE_FN].htab); - if (reg != FAIL) - { - s_arm_unwind_save_fpa (reg); - return; - } - - if (*input_line_pointer == '{') - input_line_pointer++; - - SKIP_WHITESPACE (); - - reg = arm_reg_parse (&input_line_pointer, all_reg_maps[REG_TYPE_RN].htab); - if (reg != FAIL) - { - input_line_pointer = saved_ptr; - s_arm_unwind_save_core (); - return; - } - - reg = arm_reg_parse (&input_line_pointer, all_reg_maps[REG_TYPE_DN].htab); - if (reg != FAIL) - { - input_line_pointer = saved_ptr; - s_arm_unwind_save_vfp (); - return; - } - - reg = arm_reg_parse (&input_line_pointer, - all_reg_maps[REG_TYPE_IWMMXT].htab); - if (reg != FAIL) - { - input_line_pointer = saved_ptr; - s_arm_unwind_save_wmmx (); - return; - } - - /* TODO: Maverick registers. */ - as_bad (_("unrecognised register")); -} - - -/* Parse an unwind_movsp directive. */ - -static void -s_arm_unwind_movsp (int ignored ATTRIBUTE_UNUSED) -{ - int reg; - valueT op; - - SKIP_WHITESPACE (); - reg = reg_required_here (&input_line_pointer, -1); - if (reg == FAIL) - { - as_bad (_("ARM register expected")); - ignore_rest_of_line (); - return; - } - - if (reg == 13 || reg == 15) - { - as_bad (_("r%d not permitted in .unwind_movsp directive"), reg); - ignore_rest_of_line (); - return; - } - - if (unwind.fp_reg != 13) - as_bad (_("unexpected .unwind_movsp directive")); - - /* Generate opcode to restore the value. */ - op = 0x90 | reg; - add_unwind_opcode (op, 1); - - /* Record the information for later. */ - unwind.fp_reg = reg; - unwind.fp_offset = unwind.frame_size; - unwind.sp_restored = 1; - demand_empty_rest_of_line (); -} - - -/* Parse #<number>. */ - -static int -require_hashconst (int * val) -{ - expressionS exp; - - SKIP_WHITESPACE (); - if (*input_line_pointer == '#') - { - input_line_pointer++; - expression (&exp); - } - else - exp.X_op = O_illegal; - - if (exp.X_op != O_constant) - { - as_bad (_("expected #constant")); - ignore_rest_of_line (); - return FAIL; - } - *val = exp.X_add_number; - return SUCCESS; -} - -/* Parse an unwind_pad directive. */ - -static void -s_arm_unwind_pad (int ignored ATTRIBUTE_UNUSED) -{ - int offset; - - if (require_hashconst (&offset) == FAIL) - return; - - if (offset & 3) - { - as_bad (_("stack increment must be multiple of 4")); - ignore_rest_of_line (); - return; - } - - /* Don't generate any opcodes, just record the details for later. */ - unwind.frame_size += offset; - unwind.pending_offset += offset; - - demand_empty_rest_of_line (); -} - -/* Parse an unwind_setfp directive. */ - -static void -s_arm_unwind_setfp (int ignored ATTRIBUTE_UNUSED) -{ - int sp_reg; - int fp_reg; - int offset; - - fp_reg = reg_required_here (&input_line_pointer, -1); - if (skip_past_comma (&input_line_pointer) == FAIL) - sp_reg = FAIL; - else - sp_reg = reg_required_here (&input_line_pointer, -1); - - if (fp_reg == FAIL || sp_reg == FAIL) - { - as_bad (_("expected <reg>, <reg>")); - ignore_rest_of_line (); - return; - } - - /* Optonal constant. */ - if (skip_past_comma (&input_line_pointer) != FAIL) - { - if (require_hashconst (&offset) == FAIL) - return; - } - else - offset = 0; - - demand_empty_rest_of_line (); - - if (sp_reg != 13 && sp_reg != unwind.fp_reg) - { - as_bad (_("register must be either sp or set by a previous" - "unwind_movsp directive")); - return; - } - - /* Don't generate any opcodes, just record the information for later. */ - unwind.fp_reg = fp_reg; - unwind.fp_used = 1; - if (sp_reg == 13) - unwind.fp_offset = unwind.frame_size - offset; - else - unwind.fp_offset -= offset; -} - -/* Parse an unwind_raw directive. */ - -static void -s_arm_unwind_raw (int ignored ATTRIBUTE_UNUSED) -{ - expressionS exp; - /* This is an arbitary limit. */ - unsigned char op[16]; - int count; - - SKIP_WHITESPACE (); - expression (&exp); - if (exp.X_op == O_constant - && skip_past_comma (&input_line_pointer) != FAIL) - { - unwind.frame_size += exp.X_add_number; - expression (&exp); - } - else - exp.X_op = O_illegal; - - if (exp.X_op != O_constant) - { - as_bad (_("expected <offset>, <opcode>")); - ignore_rest_of_line (); - return; - } - - count = 0; - - /* Parse the opcode. */ - for (;;) - { - if (count >= 16) - { - as_bad (_("unwind opcode too long")); - ignore_rest_of_line (); - } - if (exp.X_op != O_constant || exp.X_add_number & ~0xff) - { - as_bad (_("invalid unwind opcode")); - ignore_rest_of_line (); - return; - } - op[count++] = exp.X_add_number; - - /* Parse the next byte. */ - if (skip_past_comma (&input_line_pointer) == FAIL) - break; - - expression (&exp); - } - - /* Add the opcode bytes in reverse order. */ - while (count--) - add_unwind_opcode (op[count], 1); - - demand_empty_rest_of_line (); -} - -#endif /* OBJ_ELF */ - -/* This is called from HANDLE_ALIGN in write.c. Fill in the contents - of an rs_align_code fragment. */ - -void -arm_handle_align (fragS * fragP) -{ - static char const arm_noop[4] = { 0x00, 0x00, 0xa0, 0xe1 }; - static char const thumb_noop[2] = { 0xc0, 0x46 }; - static char const arm_bigend_noop[4] = { 0xe1, 0xa0, 0x00, 0x00 }; - static char const thumb_bigend_noop[2] = { 0x46, 0xc0 }; - - int bytes, fix, noop_size; - char * p; - const char * noop; - - if (fragP->fr_type != rs_align_code) - return; - - bytes = fragP->fr_next->fr_address - fragP->fr_address - fragP->fr_fix; - p = fragP->fr_literal + fragP->fr_fix; - fix = 0; - - if (bytes > MAX_MEM_FOR_RS_ALIGN_CODE) - bytes &= MAX_MEM_FOR_RS_ALIGN_CODE; - - if (fragP->tc_frag_data) - { - if (target_big_endian) - noop = thumb_bigend_noop; - else - noop = thumb_noop; - noop_size = sizeof (thumb_noop); - } - else - { - if (target_big_endian) - noop = arm_bigend_noop; - else - noop = arm_noop; - noop_size = sizeof (arm_noop); - } - - if (bytes & (noop_size - 1)) - { - fix = bytes & (noop_size - 1); - memset (p, 0, fix); - p += fix; - bytes -= fix; - } - - while (bytes >= noop_size) - { - memcpy (p, noop, noop_size); - p += noop_size; - bytes -= noop_size; - fix += noop_size; - } - - fragP->fr_fix += fix; - fragP->fr_var = noop_size; -} - -/* Called from md_do_align. Used to create an alignment - frag in a code section. */ - -void -arm_frag_align_code (int n, int max) -{ - char * p; - - /* We assume that there will never be a requirement - to support alignments greater than 32 bytes. */ - if (max > MAX_MEM_FOR_RS_ALIGN_CODE) - as_fatal (_("alignments greater than 32 bytes not supported in .text sections.")); - - p = frag_var (rs_align_code, - MAX_MEM_FOR_RS_ALIGN_CODE, - 1, - (relax_substateT) max, - (symbolS *) NULL, - (offsetT) n, - (char *) NULL); - *p = 0; -} - -/* Perform target specific initialisation of a frag. */ - -void -arm_init_frag (fragS * fragP) -{ - /* Record whether this frag is in an ARM or a THUMB area. */ - fragP->tc_frag_data = thumb_mode; -} - -#ifdef OBJ_ELF - -/* Convert REGNAME to a DWARF-2 register number. */ - -int -tc_arm_regname_to_dw2regnum (const char *regname) -{ - unsigned int i; - - for (i = 0; rn_table[i].name; i++) - if (streq (regname, rn_table[i].name)) - return rn_table[i].number; - - return -1; -} - -/* Initialize the DWARF-2 unwind information for this procedure. */ - -void -tc_arm_frame_initial_instructions (void) -{ - cfi_add_CFA_def_cfa (REG_SP, 0); -} -#endif - -/* 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. */ - -const pseudo_typeS md_pseudo_table[] = -{ - /* Never called because '.req' does not start a line. */ - { "req", s_req, 0 }, - { "unreq", s_unreq, 0 }, - { "bss", s_bss, 0 }, - { "align", s_align, 0 }, - { "arm", s_arm, 0 }, - { "thumb", s_thumb, 0 }, - { "code", s_code, 0 }, - { "force_thumb", s_force_thumb, 0 }, - { "thumb_func", s_thumb_func, 0 }, - { "thumb_set", s_thumb_set, 0 }, - { "even", s_even, 0 }, - { "ltorg", s_ltorg, 0 }, - { "pool", s_ltorg, 0 }, -#ifdef OBJ_ELF - { "word", s_arm_elf_cons, 4 }, - { "long", s_arm_elf_cons, 4 }, - { "rel31", s_arm_rel31, 0 }, - { "fnstart", s_arm_unwind_fnstart, 0 }, - { "fnend", s_arm_unwind_fnend, 0 }, - { "cantunwind", s_arm_unwind_cantunwind, 0 }, - { "personality", s_arm_unwind_personality, 0 }, - { "personalityindex", s_arm_unwind_personalityindex, 0 }, - { "handlerdata", s_arm_unwind_handlerdata, 0 }, - { "save", s_arm_unwind_save, 0 }, - { "movsp", s_arm_unwind_movsp, 0 }, - { "pad", s_arm_unwind_pad, 0 }, - { "setfp", s_arm_unwind_setfp, 0 }, - { "unwind_raw", s_arm_unwind_raw, 0 }, -#else - { "word", cons, 4}, -#endif - { "extend", float_cons, 'x' }, - { "ldouble", float_cons, 'x' }, - { "packed", float_cons, 'p' }, - { 0, 0, 0 } -}; diff --git a/gas/config/tc-arm.h b/gas/config/tc-arm.h index 09e8eb4..7660cfc 100644 --- a/gas/config/tc-arm.h +++ b/gas/config/tc-arm.h @@ -140,7 +140,6 @@ struct fix; #define TC_FORCE_RELOCATION_LOCAL(FIX) \ (!(FIX)->fx_pcrel \ || (FIX)->fx_plt \ - || (FIX)->fx_r_type == BFD_RELOC_ARM_GOT12 \ || (FIX)->fx_r_type == BFD_RELOC_ARM_GOT32 \ || (FIX)->fx_r_type == BFD_RELOC_32 \ || TC_FORCE_RELOCATION (FIX)) @@ -150,19 +150,13 @@ hash_die (struct hash_control *table) Each time we look up a string, we move it to the start of the list for its hash code, to take advantage of referential locality. */ -static struct hash_entry *hash_lookup (struct hash_control *, - const char *, - struct hash_entry ***, - unsigned long *); - static struct hash_entry * -hash_lookup (struct hash_control *table, const char *key, +hash_lookup (struct hash_control *table, const char *key, size_t len, struct hash_entry ***plist, unsigned long *phash) { - register unsigned long hash; - unsigned int len; - register const unsigned char *s; - register unsigned int c; + unsigned long hash; + size_t n; + unsigned int c; unsigned int index; struct hash_entry **list; struct hash_entry *p; @@ -173,13 +167,11 @@ hash_lookup (struct hash_control *table, const char *key, #endif hash = 0; - len = 0; - s = (const unsigned char *) key; - while ((c = *s++) != '\0') + for (n = 0; n < len; n++) { + c = key[n]; hash += c + (c << 17); hash ^= hash >> 2; - ++len; } hash += len + (len << 17); hash ^= hash >> 2; @@ -206,7 +198,7 @@ hash_lookup (struct hash_control *table, const char *key, ++table->string_compares; #endif - if (strcmp (p->string, key) == 0) + if (strncmp (p->string, key, len) == 0 && p->string[len] == '\0') { if (prev != NULL) { @@ -237,7 +229,7 @@ hash_insert (struct hash_control *table, const char *key, PTR value) struct hash_entry **list; unsigned long hash; - p = hash_lookup (table, key, &list, &hash); + p = hash_lookup (table, key, strlen (key), &list, &hash); if (p != NULL) return "exists"; @@ -267,7 +259,7 @@ hash_jam (struct hash_control *table, const char *key, PTR value) struct hash_entry **list; unsigned long hash; - p = hash_lookup (table, key, &list, &hash); + p = hash_lookup (table, key, strlen (key), &list, &hash); if (p != NULL) { #ifdef HASH_STATISTICS @@ -304,7 +296,7 @@ hash_replace (struct hash_control *table, const char *key, PTR value) struct hash_entry *p; PTR ret; - p = hash_lookup (table, key, NULL, NULL); + p = hash_lookup (table, key, strlen (key), NULL, NULL); if (p == NULL) return NULL; @@ -327,7 +319,22 @@ hash_find (struct hash_control *table, const char *key) { struct hash_entry *p; - p = hash_lookup (table, key, NULL, NULL); + p = hash_lookup (table, key, strlen (key), NULL, NULL); + if (p == NULL) + return NULL; + + return p->data; +} + +/* As hash_find, but KEY is of length LEN and is not guaranteed to be + NUL-terminated. */ + +PTR +hash_find_n (struct hash_control *table, const char *key, size_t len) +{ + struct hash_entry *p; + + p = hash_lookup (table, key, len, NULL, NULL); if (p == NULL) return NULL; @@ -343,7 +350,7 @@ hash_delete (struct hash_control *table, const char *key) struct hash_entry *p; struct hash_entry **list; - p = hash_lookup (table, key, &list, NULL); + p = hash_lookup (table, key, strlen (key), &list, NULL); if (p == NULL) return NULL; @@ -63,6 +63,11 @@ extern PTR hash_replace (struct hash_control *, const char *key, extern PTR hash_find (struct hash_control *, const char *key); +/* As hash_find, but KEY is of length LEN and is not guaranteed to be + NUL-terminated. */ + +extern PTR hash_find_n (struct hash_control *, const char *key, size_t len); + /* Delete an entry from a hash table. This returns the value stored for that entry, or NULL if there is no such entry. */ diff --git a/gas/input-scrub.c b/gas/input-scrub.c index 32c39cd..8562ee2 100644 --- a/gas/input-scrub.c +++ b/gas/input-scrub.c @@ -279,7 +279,7 @@ input_scrub_include_sb (sb *from, char *position, int is_expansion) /* Add the sentinel required by read.c. */ sb_add_char (&from_sb, '\n'); } - sb_add_sb (&from_sb, from); + sb_scrub_and_add_sb (&from_sb, from); sb_index = 1; /* These variables are reset by input_scrub_push. Restore them @@ -33,6 +33,7 @@ #endif #include "libiberty.h" #include "sb.h" +#include "as.h" /* These routines are about manipulating strings. @@ -115,6 +116,38 @@ sb_add_sb (sb *ptr, sb *s) ptr->len += s->len; } +/* Helper for sb_scrub_and_add_sb. */ + +static sb *sb_to_scrub; +static char *scrub_position; +static int +scrub_from_sb (char *buf, int buflen) +{ + int copy; + copy = sb_to_scrub->len - (scrub_position - sb_to_scrub->ptr); + if (copy > buflen) + copy = buflen; + memcpy (buf, scrub_position, copy); + scrub_position += copy; + return copy; +} + +/* Run the sb at s through do_scrub_chars and add the result to the sb + at ptr. */ + +void +sb_scrub_and_add_sb (sb *ptr, sb *s) +{ + sb_to_scrub = s; + scrub_position = s->ptr; + + sb_check (ptr, s->len); + ptr->len += do_scrub_chars (scrub_from_sb, ptr->ptr + ptr->len, s->len); + + sb_to_scrub = 0; + scrub_position = 0; +} + /* Make sure that the sb at ptr has room for another len characters, and grow it if it doesn't. */ @@ -81,6 +81,7 @@ sb_list_vector; extern void sb_new (sb *); extern void sb_kill (sb *); extern void sb_add_sb (sb *, sb *); +extern void sb_scrub_and_add_sb (sb *, sb *); extern void sb_reset (sb *); extern void sb_add_char (sb *, int); extern void sb_add_string (sb *, const char *); diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index 71a98c5..552458b 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,36 @@ +2005-05-17 Zack Weinberg <zack@codesourcery.com> + + * gas/arm/arm.exp: Convert all existing "gas_test" tests to + "run_dump_test" tests. Run more tests unconditionally. Run new tests. + * gas/arm/arch4t.s, gas/arm/arch6zk.s, gas/arm/arm3.s, gas/arm/arm6.s + * gas/arm/arm7dm.s, gas/arm/bignum1.s, gas/arm/float.s + * gas/arm/immed.s, gas/arm/iwmmxt.s, gas/arm/offset.s, gas/arm/thumb.s: + Adjust to work as a dump test. + * gas/arm/arch4t.d, gas/arm/arch6zk.d, gas/arm/arm3.d, gas/arm/arm6.d + * gas/arm/arm7dm.d, gas/arm/bignum1.d, gas/arm/float.d + * gas/arm/immed.d, gas/arm/iwmmxt.d, gas/arm/offset.d, gas/arm/thumb.d: + New files. + + * gas/arm/armv1-bad.l, gas/arm/armv1-bad.s: Remove tests for + diagnostics that don't happen in the first pass anymore. + + * gas/arm/iwmmxt-bad.l, gas/arm/r15-bad.l, gas/arm/req.l + * gas/arm/vfp-bad.l: + Update expected diagnostics. + * gas/arm/pic.d: Update expected reloc name. + * gas/arm/thumbv6.d: CPY no longer appears in disassembly. + * gas/arm/r15-bad.s: Avoid two-argument mul. + * gas/arm/req.s: Adjust comments. + * gas/arm/maverick.d, gas/arm/maverick.s: Avoid inappropriate + use of PC. + + * gas/arm/macro-1.d, gas/arm/macro1.s + * gas/arm/t16-bad.l, gas/arm/t16-bad.s + * gas/arm/tcompat.d, gas/arm/tcompat.s + * gas/arm/tcompat2.d, gas/arm/tcompat2.s + * gas/arm/thumb32.d, gas/arm/thumb32.s + New test pair. + 2005-05-17 Jan Beulich <jbeulich@novell.com> * gas/mmix/err-byte1.s: Adjust expected error text on line 10. diff --git a/gas/testsuite/gas/arm/arch4t.d b/gas/testsuite/gas/arm/arch4t.d new file mode 100644 index 0000000..0fdaa8f --- /dev/null +++ b/gas/testsuite/gas/arm/arch4t.d @@ -0,0 +1,36 @@ +# name: ARM architecture 4t instructions +# as: -march=armv4t +# objdump: -dr --prefix-addresses --show-raw-insn + +.*: +file format .*arm.* + +Disassembly of section .text: +0+00 <[^>]+> e12fff10 ? bx r0 +0+04 <[^>]+> 012fff11 ? bxeq r1 +0+08 <[^>]+> e15f30b8 ? ldrh r3, \[pc, #-8\] ; 0+08 <[^>]+> +0+0c <[^>]+> e1d540f0 ? ldrsh r4, \[r5\] +0+10 <[^>]+> e19140d3 ? ldrsb r4, \[r1, r3\] +0+14 <[^>]+> e1b410f4 ? ldrsh r1, \[r4, r4\]! +0+18 <[^>]+> 011510d3 ? ldreqsb r1, \[r5, -r3\] +0+1c <[^>]+> 109620b7 ? ldrneh r2, \[r6\], r7 +0+20 <[^>]+> 309720f8 ? ldrccsh r2, \[r7\], r8 +0+24 <[^>]+> e1d32fdf ? ldrsb r2, \[r3, #255\] +0+28 <[^>]+> e1541ffa ? ldrsh r1, \[r4, #-250\] +0+2c <[^>]+> e1d51fd0 ? ldrsb r1, \[r5, #240\] +0+30 <[^>]+> e1cf23b0 ? strh r2, \[pc, #48\] ; 0+68 <[^>]+> +0+34 <[^>]+> 11c330b0 ? strneh r3, \[r3\] +0+38 <[^>]+> e328f002 ? msr CPSR_f, #2 ; 0x2 +0+3c <[^>]+> e121f003 ? msr CPSR_c, r3 +0+40 <[^>]+> e122f004 ? msr CPSR_x, r4 +0+44 <[^>]+> e124f005 ? msr CPSR_s, r5 +0+48 <[^>]+> e128f006 ? msr CPSR_f, r6 +0+4c <[^>]+> e129f007 ? msr CPSR_fc, r7 +0+50 <[^>]+> e368f004 ? msr SPSR_f, #4 ; 0x4 +0+54 <[^>]+> e161f008 ? msr SPSR_c, r8 +0+58 <[^>]+> e162f009 ? msr SPSR_x, r9 +0+5c <[^>]+> e164f00a ? msr SPSR_s, sl +0+60 <[^>]+> e168f00b ? msr SPSR_f, fp +0+64 <[^>]+> e169f00c ? msr SPSR_fc, ip +0+68 <[^>]+> e1a00000 ? nop \(mov r0,r0\) +0+6c <[^>]+> e1a00000 ? nop \(mov r0,r0\) + diff --git a/gas/testsuite/gas/arm/arch4t.s b/gas/testsuite/gas/arm/arch4t.s index 417b3c6..984829d 100644 --- a/gas/testsuite/gas/arm/arch4t.s +++ b/gas/testsuite/gas/arm/arch4t.s @@ -1,6 +1,6 @@ -.text -.align 0 - + .text + .align 0 +l: bx r0 bxeq r1 @@ -33,3 +33,6 @@ foo: msr SPSR_f, r11 msr SPSR_all, r12 bar: + @ section padding for a.out's benefit + nop + nop diff --git a/gas/testsuite/gas/arm/arch6zk.d b/gas/testsuite/gas/arm/arch6zk.d index d4adda6..e645ca0 100644 --- a/gas/testsuite/gas/arm/arch6zk.d +++ b/gas/testsuite/gas/arm/arch6zk.d @@ -6,21 +6,21 @@ Disassembly of section .text: 0+000 <[^>]*> f57ff01f ? clrex -0+004 <[^>]*> e1dc3f9f ? ldrexb r3, \[ip\] -0+008 <[^>]*> 11d3cf9f ? ldrexbne ip, \[r3\] -0+00c <[^>]*> e1bc3f9f ? ldrexd r3, \[ip\] -0+010 <[^>]*> 11b3cf9f ? ldrexdne ip, \[r3\] -0+014 <[^>]*> e1fc3f9f ? ldrexh r3, \[ip\] -0+018 <[^>]*> 11f3cf9f ? ldrexhne ip, \[r3\] +0+004 <[^>]*> e1dc4f9f ? ldrexb r4, \[ip\] +0+008 <[^>]*> 11d4cf9f ? ldrexbne ip, \[r4\] +0+00c <[^>]*> e1bc4f9f ? ldrexd r4, \[ip\] +0+010 <[^>]*> 11b4cf9f ? ldrexdne ip, \[r4\] +0+014 <[^>]*> e1fc4f9f ? ldrexh r4, \[ip\] +0+018 <[^>]*> 11f4cf9f ? ldrexhne ip, \[r4\] 0+01c <[^>]*> e320f080 ? nop \{128\} 0+020 <[^>]*> 1320f07f ? nopne \{127\} 0+024 <[^>]*> e320f004 ? sev -0+028 <[^>]*> e1c73f9c ? strexb r3, ip, \[r7\] -0+02c <[^>]*> 11c8cf93 ? strexbne ip, r3, \[r8\] -0+030 <[^>]*> e1a73f9c ? strexd r3, ip, \[r7\] -0+034 <[^>]*> 11a8cf93 ? strexdne ip, r3, \[r8\] -0+038 <[^>]*> e1e73f9c ? strexh r3, ip, \[r7\] -0+03c <[^>]*> 11e8cf93 ? strexhne ip, r3, \[r8\] +0+028 <[^>]*> e1c74f9c ? strexb r4, ip, \[r7\] +0+02c <[^>]*> 11c8cf94 ? strexbne ip, r4, \[r8\] +0+030 <[^>]*> e1a74f9c ? strexd r4, ip, \[r7\] +0+034 <[^>]*> 11a8cf94 ? strexdne ip, r4, \[r8\] +0+038 <[^>]*> e1e74f9c ? strexh r4, ip, \[r7\] +0+03c <[^>]*> 11e8cf94 ? strexhne ip, r4, \[r8\] 0+040 <[^>]*> e320f002 ? wfe 0+044 <[^>]*> e320f003 ? wfi 0+048 <[^>]*> e320f001 ? yield diff --git a/gas/testsuite/gas/arm/arch6zk.s b/gas/testsuite/gas/arm/arch6zk.s index af57185..f182406 100644 --- a/gas/testsuite/gas/arm/arch6zk.s +++ b/gas/testsuite/gas/arm/arch6zk.s @@ -4,21 +4,21 @@ label: # ARMV6K instructions clrex - ldrexb r3, [r12] - ldrexbne r12, [r3] - ldrexd r3, [r12] - ldrexdne r12, [r3] - ldrexh r3, [r12] - ldrexhne r12, [r3] - nop {128} - nopne {127} + ldrexb r4, [r12] + ldrexbne r12, [r4] + ldrexd r4, [r12] + ldrexdne r12, [r4] + ldrexh r4, [r12] + ldrexhne r12, [r4] + nop {128} + nopne {127} sev - strexb r3, r12, [r7] - strexbne r12, r3, [r8] - strexd r3, r12, [r7] - strexdne r12, r3, [r8] - strexh r3, r12, [r7] - strexhne r12, r3, [r8] + strexb r4, r12, [r7] + strexbne r12, r4, [r8] + strexd r4, r12, [r7] + strexdne r12, r4, [r8] + strexh r4, r12, [r7] + strexhne r12, r4, [r8] wfe wfi yield diff --git a/gas/testsuite/gas/arm/arm.exp b/gas/testsuite/gas/arm/arm.exp index 7cd5630..5fb82ad 100644 --- a/gas/testsuite/gas/arm/arm.exp +++ b/gas/testsuite/gas/arm/arm.exp @@ -28,14 +28,13 @@ if {[istarget *arm*-*-*] || [istarget "xscale-*-*"]} then { run_dump_test "copro" } - gas_test "arm3.s" "-mcpu=arm3" $stdoptlist "Arm 3 instructions" - gas_test "arm6.s" "-mcpu=arm6" $stdoptlist "Arm 6 instructions" - gas_test "arm7dm.s" "-mcpu=arm7dm" $stdoptlist "Arm 7DM instructions" - gas_test "arch4t.s" "-march=armv4t" $stdoptlist "Arm architecture 4t instructions" - gas_test "immed.s" "" $stdoptlist "immediate expressions" - gas_test "float.s" "-mcpu=arm7tdmi -mfpu=fpa" $stdoptlist "Core floating point instructions" - gas_test "offset.s" "" $stdoptlist "OFFSET_IMM regression" - + run_dump_test "arm3" + run_dump_test "arm6" + run_dump_test "arm7dm" + run_dump_test "arch4t" + run_dump_test "immed" + run_dump_test "float" + run_dump_test "offset" run_dump_test "armv1" run_dump_test "arch5tej" run_dump_test "fpa-monadic" @@ -53,12 +52,18 @@ if {[istarget *arm*-*-*] || [istarget "xscale-*-*"]} then { run_dump_test "thumbv6" run_dump_test "thumbv6k" run_dump_test "arch6zk" + run_dump_test "tcompat" + run_dump_test "tcompat2" + run_dump_test "iwmmxt" + run_dump_test "macro1" run_errors_test "vfp-bad" "-mfpu=vfp" "VFP errors" run_errors_test "req" "-mcpu=arm7m" ".req errors" run_errors_test "armv1-bad" "-mcpu=arm7m" "ARM v1 errors" run_errors_test "r15-bad" "" "Invalid use of r15 errors" run_errors_test "archv6t2-bad" "-march=armv6t2" "Invalid V6T2 instructions" + run_errors_test "t16-bad" "-march=armv6k" "Valid ARM, invalid Thumb" + run_errors_test "iwmmxt-bad" "-mcpu=iwmmxt" "iWMMXt errors" if {[istarget *-*-*coff] || [istarget *-*-pe] || [istarget *-*-wince] || [istarget *-*-*aout*] || [istarget *-*-netbsd] || [istarget *-*-riscix*]} then { @@ -70,29 +75,20 @@ if {[istarget *arm*-*-*] || [istarget "xscale-*-*"]} then { run_dump_test "pic" run_dump_test "mapping" - gas_test "bignum1.s" "" $stdoptlist "bignums" + run_dump_test "bignum1" run_dump_test "unwind" - run_dump_test "tls" } + # The arm-aout port does not support Thumb branch relocations. if {! [istarget arm*-*-aout] && ![istarget arm-*-pe]} then { - # The arm-aout port does not support Thumb mode. - gas_test "thumb.s" "-mcpu=arm7t" $stdoptlist "Thumb instructions" + run_dump_test "thumb" + run_dump_test "thumb32" } -} - -# Not all arm targets are bi-endian, so only run this test on ones -# we know that are. FIXME: We should probably also key off armeb/armel. -if [istarget arm-*-pe] { - run_dump_test "le-fpconst" - - # Since big-endian numbers have the normal format, this doesn't exist. - #run_dump_test "be-fpconst" -} - -if [istarget xscale-*] { - run_dump_test "iwmmxt" - run_errors_test "iwmmxt-bad" "-mcpu=iwmmxt" "iWMMXt errors" + # Not all arm targets are bi-endian, so only run this test on ones + # we know that are. FIXME: We should probably also key off armeb/armel. + if [istarget *-*-pe] { + run_dump_test "le-fpconst" + } } diff --git a/gas/testsuite/gas/arm/arm3.d b/gas/testsuite/gas/arm/arm3.d new file mode 100644 index 0000000..8f1c8a4 --- /dev/null +++ b/gas/testsuite/gas/arm/arm3.d @@ -0,0 +1,11 @@ +# name: ARM 3 instructions +# as: -mcpu=arm3 +# objdump: -dr --prefix-addresses --show-raw-insn + +.*: +file format .*arm.* + +Disassembly of section .text: +0+0 <[^>]*> e1080091 ? swp r0, r1, \[r8\] +0+4 <[^>]*> e1432093 ? swpb r2, r3, \[r3\] +0+8 <[^>]*> a1444091 ? swpgeb r4, r1, \[r4\] +0+c <[^>]*> e1a00000 ? nop \(mov r0,r0\) diff --git a/gas/testsuite/gas/arm/arm3.s b/gas/testsuite/gas/arm/arm3.s index ebcf915..8de03b9 100644 --- a/gas/testsuite/gas/arm/arm3.s +++ b/gas/testsuite/gas/arm/arm3.s @@ -1,6 +1,7 @@ -.text -.align 0 + .text + .align 0 +l: swp r0, r1, [r8] swpb r2, r3, [r3] swpgeb r4, r1, [r4] - + nop diff --git a/gas/testsuite/gas/arm/arm6.d b/gas/testsuite/gas/arm/arm6.d new file mode 100644 index 0000000..3fc0de8 --- /dev/null +++ b/gas/testsuite/gas/arm/arm6.d @@ -0,0 +1,19 @@ +# name: ARM 6 instructions +# as: -mcpu=arm6 +# objdump: -dr --prefix-addresses --show-raw-insn + +.*: +file format .*arm.* + +Disassembly of section .text: +0+00 <[^>]+> e10f8000 ? mrs r8, CPSR +0+04 <[^>]+> e14f2000 ? mrs r2, SPSR +0+08 <[^>]+> e129f001 ? msr CPSR_fc, r1 +0+0c <[^>]+> 1328f20f ? msrne CPSR_f, #-268435456 ; 0xf0000000 +0+10 <[^>]+> e168f008 ? msr SPSR_f, r8 +0+14 <[^>]+> e169f009 ? msr SPSR_fc, r9 +0+18 <[^>]+> e10f8000 ? mrs r8, CPSR +0+1c <[^>]+> e14f2000 ? mrs r2, SPSR +0+20 <[^>]+> e129f001 ? msr CPSR_fc, r1 +0+24 <[^>]+> 1328f20f ? msrne CPSR_f, #-268435456 ; 0xf0000000 +0+28 <[^>]+> e168f008 ? msr SPSR_f, r8 +0+2c <[^>]+> e169f009 ? msr SPSR_fc, r9 diff --git a/gas/testsuite/gas/arm/arm6.s b/gas/testsuite/gas/arm/arm6.s index e82837f..1883eba 100644 --- a/gas/testsuite/gas/arm/arm6.s +++ b/gas/testsuite/gas/arm/arm6.s @@ -1,6 +1,6 @@ -.text -.align 0 - + .text + .align 0 +l: mrs r8, cpsr mrs r2, spsr @@ -16,4 +16,3 @@ msrne CPSR_flg, #0xf0000000 msr SPSR_flg, r8 msr SPSR_all, r9 - diff --git a/gas/testsuite/gas/arm/arm7dm.d b/gas/testsuite/gas/arm/arm7dm.d new file mode 100644 index 0000000..ef47ca6 --- /dev/null +++ b/gas/testsuite/gas/arm/arm7dm.d @@ -0,0 +1,19 @@ +# name: ARM 7DM instructions +# as: -mcpu=arm7dm +# objdump: -dr --prefix-addresses --show-raw-insn + +.*: +file format .*arm.* + +Disassembly of section .text: +0+00 <[^>]+> e0c10392 ? smull r0, r1, r2, r3 +0+04 <[^>]+> e0810392 ? umull r0, r1, r2, r3 +0+08 <[^>]+> e0e10392 ? smlal r0, r1, r2, r3 +0+0c <[^>]+> e0a10394 ? umlal r0, r1, r4, r3 +0+10 <[^>]+> 10c10493 ? smullne r0, r1, r3, r4 +0+14 <[^>]+> e0d01b99 ? smulls r1, r0, r9, fp +0+18 <[^>]+> 00b92994 ? umlaleqs r2, r9, r4, r9 +0+1c <[^>]+> a0eaee98 ? smlalge lr, sl, r8, lr +0+20 <[^>]+> e322f000 ? msr CPSR_x, #0 ; 0x0 +0+24 <[^>]+> e1a00000 ? nop \(mov r0,r0\) +0+28 <[^>]+> e1a00000 ? nop \(mov r0,r0\) +0+2c <[^>]+> e1a00000 ? nop \(mov r0,r0\) diff --git a/gas/testsuite/gas/arm/arm7dm.s b/gas/testsuite/gas/arm/arm7dm.s index 99eaa9f..ee62e8c 100644 --- a/gas/testsuite/gas/arm/arm7dm.s +++ b/gas/testsuite/gas/arm/arm7dm.s @@ -1,6 +1,6 @@ -.text -.align 0 - + .text + .align 0 +l: smull r0, r1, r2, r3 umull r0, r1, r2, r3 smlal r0, r1, r2, r3 @@ -11,4 +11,10 @@ umlaleqs r2, r9, r4, r9 smlalge r14, r10, r8, r14 - msr CPSR_x, #0 @ This used to be illegal, but rev 2 of the ARM ARM allows it. + @ This used to be illegal, but rev 2 of the ARM ARM allows it. + msr CPSR_x, #0 + + @ padding for a.out's sake + nop + nop + nop diff --git a/gas/testsuite/gas/arm/armv1-bad.l b/gas/testsuite/gas/arm/armv1-bad.l index 19a7e9a..423672c 100644 --- a/gas/testsuite/gas/arm/armv1-bad.l +++ b/gas/testsuite/gas/arm/armv1-bad.l @@ -1,12 +1,9 @@ [^:]*: Assembler messages: [^:]*:4: Error: invalid pseudo operation -- `str r0,=0x00ff0000' [^:]*:5: Error: bad expression -- `ldr r0,{r1}' -[^:]*:6: Error: address offset too large -- `ldr r0,\[r1,#4096\]' -[^:]*:7: Error: address offset too large -- `ldr r0,\[r1,#-4096\]' -[^:]*:8: Error: invalid constant -- `mov r0,#0x1ff' -[^:]*:9: Error: bad instruction `cmpl r0,r0' -[^:]*:10: Error: selected processor does not support `strh r0,\[r1\]' -[^:]*:11: Warning: writeback of base register is UNPREDICTABLE -[^:]*:12: Warning: writeback of base register when in register list is UNPREDICTABLE -[^:]*:13: Warning: writeback of base register is UNPREDICTABLE -[^:]*:15: Warning: if writeback register is in list, it must be the lowest reg in the list +[^:]*:6: Error: bad instruction `cmpl r0,r0' +[^:]*:7: Error: selected processor does not support `strh r0,\[r1\]' +[^:]*:8: Warning: writeback of base register is UNPREDICTABLE +[^:]*:9: Warning: writeback of base register when in register list is UNPREDICTABLE +[^:]*:10: Warning: writeback of base register is UNPREDICTABLE +[^:]*:12: Warning: if writeback register is in list, it must be the lowest reg in the list diff --git a/gas/testsuite/gas/arm/armv1-bad.s b/gas/testsuite/gas/arm/armv1-bad.s index 751aefe..7e5f683 100644 --- a/gas/testsuite/gas/arm/armv1-bad.s +++ b/gas/testsuite/gas/arm/armv1-bad.s @@ -3,9 +3,6 @@ entry: str r0, =0x00ff0000 ldr r0, {r1} - ldr r0, [r1, #4096] - ldr r0, [r1, #-4096] - mov r0, #0x1ff cmpl r0, r0 strh r0, [r1] ldmfa r4!, {r8, r9}^ diff --git a/gas/testsuite/gas/arm/bignum1.d b/gas/testsuite/gas/arm/bignum1.d new file mode 100644 index 0000000..fb49708 --- /dev/null +++ b/gas/testsuite/gas/arm/bignum1.d @@ -0,0 +1,8 @@ +# name: bignums +# as: +# objdump: --full-contents + +.*: +file format .*arm.* + +Contents of section .data: + 0000 [08]0000000 000000[08]0 11111111 11111111 \.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\. diff --git a/gas/testsuite/gas/arm/bignum1.s b/gas/testsuite/gas/arm/bignum1.s index 3c45d23..2b9d736 100644 --- a/gas/testsuite/gas/arm/bignum1.s +++ b/gas/testsuite/gas/arm/bignum1.s @@ -1 +1,3 @@ + .data .8byte -9223372036854775808 + .8byte 1229782938247303441 diff --git a/gas/testsuite/gas/arm/float.d b/gas/testsuite/gas/arm/float.d new file mode 100644 index 0000000..c9754b2 --- /dev/null +++ b/gas/testsuite/gas/arm/float.d @@ -0,0 +1,131 @@ +# name: Core floating point instructions +# as: -mcpu=arm7tdmi -mfpu=fpa +# objdump: -dr --prefix-addresses --show-raw-insn + +.*: +file format .*arm.* + +Disassembly of section .text: +0+000 <[^>]+> ee088101 ? mvfe f0, f1 +0+004 <[^>]+> 0e08b105 ? mvfeqe f3, f5 +0+008 <[^>]+> 0e00c189 ? mvfeqd f4, #1\.0 +0+00c <[^>]+> ee00c107 ? mvfs f4, f7 +0+010 <[^>]+> ee008121 ? mvfsp f0, f1 +0+014 <[^>]+> ee00b1c4 ? mvfdm f3, f4 +0+018 <[^>]+> ee08f167 ? mvfez f7, f7 +0+01c <[^>]+> ee09010a ? adfe f0, f1, #2\.0 +0+020 <[^>]+> 0e0a110e ? adfeqe f1, f2, #0\.5 +0+024 <[^>]+> ee043145 ? adfsm f3, f4, f5 +0+028 <[^>]+> ee20018a ? sufd f0, f0, #2\.0 +0+02c <[^>]+> ee22110f ? sufs f1, f2, #10\.0 +0+030 <[^>]+> 1e2c3165 ? sufneez f3, f4, f5 +0+034 <[^>]+> ee311108 ? rsfs f1, f1, #0\.0 +0+038 <[^>]+> ee3031ad ? rsfdp f3, f0, #5\.0 +0+03c <[^>]+> de367180 ? rsfled f7, f6, f0 +0+040 <[^>]+> ee100180 ? mufd f0, f0, f0 +0+044 <[^>]+> ee1a116b ? mufez f1, f2, #3\.0 +0+048 <[^>]+> ee10010c ? mufs f0, f0, #4\.0 +0+04c <[^>]+> ee400189 ? dvfd f0, f0, #1\.0 +0+050 <[^>]+> ee49016f ? dvfez f0, f1, #10\.0 +0+054 <[^>]+> 4e443145 ? dvfmism f3, f4, f5 +0+058 <[^>]+> ee59010f ? rdfe f0, f1, #10\.0 +0+05c <[^>]+> ee573109 ? rdfs f3, f7, #1\.0 +0+060 <[^>]+> 3e5441a3 ? rdfccdp f4, f4, f3 +0+064 <[^>]+> ee620183 ? powd f0, f2, f3 +0+068 <[^>]+> ee63110f ? pows f1, f3, #10\.0 +0+06c <[^>]+> 2e6f4169 ? powcsez f4, f7, #1\.0 +0+070 <[^>]+> ee767107 ? rpws f7, f6, f7 +0+074 <[^>]+> 0e710182 ? rpweqd f0, f1, f2 +0+078 <[^>]+> ee7a2143 ? rpwem f2, f2, f3 +0+07c <[^>]+> ee82118b ? rmfd f1, f2, #3\.0 +0+080 <[^>]+> 6e843104 ? rmfvss f3, f4, f4 +0+084 <[^>]+> ee8f4120 ? rmfep f4, f7, f0 +0+088 <[^>]+> ee910102 ? fmls f0, f1, f2 +0+08c <[^>]+> 0e931105 ? fmleqs f1, f3, f5 +0+090 <[^>]+> 5e964160 ? fmlplsz f4, f6, f0 +0+094 <[^>]+> eea3110f ? fdvs f1, f3, #10\.0 +0+098 <[^>]+> eea10122 ? fdvsp f0, f1, f2 +0+09c <[^>]+> 2ea44144 ? fdvcssm f4, f4, f4 +0+0a0 <[^>]+> eeb11109 ? frds f1, f1, #1\.0 +0+0a4 <[^>]+> ceb12100 ? frdgts f2, f1, f0 +0+0a8 <[^>]+> ceb44165 ? frdgtsz f4, f4, f5 +0+0ac <[^>]+> eec10182 ? pold f0, f1, f2 +0+0b0 <[^>]+> eec6416b ? polsz f4, f6, #3\.0 +0+0b4 <[^>]+> 0ece5107 ? poleqe f5, f6, f7 +0+0b8 <[^>]+> ee108101 ? mnfs f0, f1 +0+0bc <[^>]+> ee10818b ? mnfd f0, #3\.0 +0+0c0 <[^>]+> ee18816c ? mnfez f0, #4\.0 +0+0c4 <[^>]+> 0e188165 ? mnfeqez f0, f5 +0+0c8 <[^>]+> ee108124 ? mnfsp f0, f4 +0+0cc <[^>]+> ee1091c7 ? mnfdm f1, f7 +0+0d0 <[^>]+> ee208181 ? absd f0, f1 +0+0d4 <[^>]+> ee20912b ? abssp f1, #3\.0 +0+0d8 <[^>]+> 0e28c105 ? abseqe f4, f5 +0+0dc <[^>]+> ee309102 ? rnds f1, f2 +0+0e0 <[^>]+> ee30b184 ? rndd f3, f4 +0+0e4 <[^>]+> 0e38e16c ? rndeqez f6, #4\.0 +0+0e8 <[^>]+> ee40d105 ? sqts f5, f5 +0+0ec <[^>]+> ee40e1a6 ? sqtdp f6, f6 +0+0f0 <[^>]+> 5e48f166 ? sqtplez f7, f6 +0+0f4 <[^>]+> ee50810f ? logs f0, #10\.0 +0+0f8 <[^>]+> ee58810f ? loge f0, #10\.0 +0+0fc <[^>]+> 1e5081e1 ? lognedz f0, f1 +0+100 <[^>]+> ee689102 ? lgne f1, f2 +0+104 <[^>]+> ee6091e3 ? lgndz f1, f3 +0+108 <[^>]+> 7e60b104 ? lgnvcs f3, f4 +0+10c <[^>]+> ee709103 ? exps f1, f3 +0+110 <[^>]+> ee78b14f ? expem f3, #10\.0 +0+114 <[^>]+> 5e70e187 ? exppld f6, f7 +0+118 <[^>]+> ee808181 ? sind f0, f1 +0+11c <[^>]+> ee809142 ? sinsm f1, f2 +0+120 <[^>]+> ce88c10d ? singte f4, #5\.0 +0+124 <[^>]+> ee909183 ? cosd f1, f3 +0+128 <[^>]+> ee98c145 ? cosem f4, f5 +0+12c <[^>]+> 1e90e1a1 ? cosnedp f6, f1 +0+130 <[^>]+> eea89105 ? tane f1, f5 +0+134 <[^>]+> eea0c167 ? tansz f4, f7 +0+138 <[^>]+> aea091ec ? tangedz f1, #4\.0 +0+13c <[^>]+> eeb8c105 ? asne f4, f5 +0+140 <[^>]+> eeb0e12e ? asnsp f6, #0\.5 +0+144 <[^>]+> 4eb0d1e5 ? asnmidz f5, f5 +0+148 <[^>]+> eec0d106 ? acss f5, f6 +0+14c <[^>]+> eec0e180 ? acsd f6, f0 +0+150 <[^>]+> 2ec8914e ? acscsem f1, #0\.5 +0+154 <[^>]+> eed88105 ? atne f0, f5 +0+158 <[^>]+> eed0916d ? atnsz f1, #5\.0 +0+15c <[^>]+> bed0b182 ? atnltd f3, f2 +0+160 <[^>]+> eee8d104 ? urde f5, f4 +0+164 <[^>]+> eef8e105 ? nrme f6, f5 +0+168 <[^>]+> 5ef0f1e5 ? nrmpldz f7, f5 +0+16c <[^>]+> ee008130 ? fltsp f0, r8 +0+170 <[^>]+> ee090110 ? flte f1, r0 +0+174 <[^>]+> 0e0571f0 ? flteqdz f5, r7 +0+178 <[^>]+> ee100111 ? fix r0, f1 +0+17c <[^>]+> ee101177 ? fixz r1, f7 +0+180 <[^>]+> 2e105155 ? fixcsm r5, f5 +0+184 <[^>]+> ee400110 ? wfc r0 +0+188 <[^>]+> ee201110 ? wfs r1 +0+18c <[^>]+> 0e302110 ? rfseq r2 +0+190 <[^>]+> ee504110 ? rfc r4 +0+194 <[^>]+> ee90f119 ? cmf f0, #1\.0 +0+198 <[^>]+> ee91f112 ? cmf f1, f2 +0+19c <[^>]+> 0e90f111 ? cmfeq f0, f1 +0+1a0 <[^>]+> eeb0f11b ? cnf f0, #3\.0 +0+1a4 <[^>]+> eeb1f11e ? cnf f1, #0\.5 +0+1a8 <[^>]+> 6eb3f114 ? cnfvs f3, f4 +0+1ac <[^>]+> eed0f111 ? cmfe f0, f1 +0+1b0 <[^>]+> 0ed1f112 ? cmfeeq f1, f2 +0+1b4 <[^>]+> 0ed3f11d ? cmfeeq f3, #5\.0 +0+1b8 <[^>]+> eef1f113 ? cnfe f1, f3 +0+1bc <[^>]+> 0ef3f114 ? cnfeeq f3, f4 +0+1c0 <[^>]+> 0ef4f117 ? cnfeeq f4, f7 +0+1c4 <[^>]+> eef4f11d ? cnfe f4, #5\.0 +0+1c8 <[^>]+> ed900200 ? lfm f0, 4, \[r0\] +0+1cc <[^>]+> ed900200 ? lfm f0, 4, \[r0\] +0+1d0 <[^>]+> ed911210 ? lfm f1, 4, \[r1, #64\] +0+1d4 <[^>]+> edae22ff ? sfm f2, 4, \[lr, #1020\]! +0+1d8 <[^>]+> 0c68f2ff ? sfmeq f7, 3, \[r8\], #-1020 +0+1dc <[^>]+> eddf6200 ? lfm f6, 2, \[pc\] +0+1e0 <[^>]+> eca8f203 ? sfm f7, 1, \[r8\], #12 +0+1e4 <[^>]+> 0d16520c ? lfmeq f5, 4, \[r6, #-48\] +0+1e8 <[^>]+> 1d42c209 ? sfmne f4, 3, \[r2, #-36\] +0+1ec <[^>]+> 1d62c209 ? sfmne f4, 3, \[r2, #-36\]! diff --git a/gas/testsuite/gas/arm/float.s b/gas/testsuite/gas/arm/float.s index 48aee96..437d298 100644 --- a/gas/testsuite/gas/arm/float.s +++ b/gas/testsuite/gas/arm/float.s @@ -1,5 +1,6 @@ -.text -.align 0 + .text + .align 0 +l: mvfe f0, f1 mvfeqe f3, f5 mvfeqd f4, #1.0 diff --git a/gas/testsuite/gas/arm/immed.d b/gas/testsuite/gas/arm/immed.d new file mode 100644 index 0000000..62b7eb7 --- /dev/null +++ b/gas/testsuite/gas/arm/immed.d @@ -0,0 +1,16 @@ +# name: immediate expressions +# as: +# objdump: -dr --prefix-addresses --show-raw-insn + +.*: +file format .*arm.* + +Disassembly of section .text: +0+0000 <[^>]+> e3a00000 ? mov r0, #0 ; 0x0 +0+0004 <[^>]+> e3e00003 ? mvn r0, #3 ; 0x3 +0+0008 <[^>]+> e51f0010 ? ldr r0, \[pc, #-16\] ; 0+0 <[^>]+> +0+000c <[^>]+> e51f0014 ? ldr r0, \[pc, #-20\] ; 0+0 <[^>]+> + \.\.\. +0+1010 <[^>]+> e3a00008 ? mov r0, #8 ; 0x8 +0+1014 <[^>]+> e59f00e4 ? ldr r0, \[pc, #228\] ; 0+1100 <[^>]+> +0+1018 <[^>]+> e1a00000 ? nop \(mov r0,r0\) +0+101c <[^>]+> e1a00000 ? nop \(mov r0,r0\) diff --git a/gas/testsuite/gas/arm/immed.s b/gas/testsuite/gas/arm/immed.s index 5d2092b..400f628 100644 --- a/gas/testsuite/gas/arm/immed.s +++ b/gas/testsuite/gas/arm/immed.s @@ -9,3 +9,7 @@ bar: .space 4096 mov r0, #(. - bar - 8) & 0xff ldr r0, [pc, # (bar - . -8) & 0xff] + + @ section padding for a.out's benefit + nop + nop diff --git a/gas/testsuite/gas/arm/iwmmxt-bad.l b/gas/testsuite/gas/arm/iwmmxt-bad.l index 66144aa..962bc46 100644 --- a/gas/testsuite/gas/arm/iwmmxt-bad.l +++ b/gas/testsuite/gas/arm/iwmmxt-bad.l @@ -1,9 +1,9 @@ [^:]*: Assembler messages: -[^:]*:1: Error: conditional execution not supported with control register -[^:]*:2: Error: non-word size not supported with control register -[^:]*:3: Error: non-word size not supported with control register -[^:]*:4: Error: non-word size not supported with control register -[^:]*:5: Error: conditional execution not supported with control register -[^:]*:6: Error: non-word size not supported with control register -[^:]*:7: Error: non-word size not supported with control register -[^:]*:8: Error: non-word size not supported with control register +[^:]*:1: Error: instruction cannot be conditional -- `wldrwgt wcgr0,\[r1\]' +[^:]*:2: Error: iWMMXt data register expected -- `wldrb wcgr0,\[r1\]' +[^:]*:3: Error: iWMMXt data register expected -- `wldrh wcgr0,\[r1\]' +[^:]*:4: Error: iWMMXt data register expected -- `wldrd wcgr0,\[r1\]' +[^:]*:5: Error: instruction cannot be conditional -- `wstrwgt wcgr0,\[r1\]' +[^:]*:6: Error: iWMMXt data register expected -- `wstrb wcgr0,\[r1\]' +[^:]*:7: Error: iWMMXt data register expected -- `wstrh wcgr0,\[r1\]' +[^:]*:8: Error: iWMMXt data register expected -- `wstrd wcgr0,\[r1\]' diff --git a/gas/testsuite/gas/arm/iwmmxt.d b/gas/testsuite/gas/arm/iwmmxt.d index 7ff62e4..f7d81ec 100644 --- a/gas/testsuite/gas/arm/iwmmxt.d +++ b/gas/testsuite/gas/arm/iwmmxt.d @@ -166,3 +166,6 @@ Disassembly of section .text: 0+278 <[^>]*> 0e9540ea[ ]+wunpckilweq[ ]+wr4, wr5, wr10 0+27c <[^>]*> 1e143005[ ]+wxorne[ ]+wr3, wr4, wr5 0+280 <[^>]*> ae377007[ ]+wandnge[ ]+wr7, wr7, wr7 +0+284 <[^>]*> e1a00000[ ]+nop[ ]+\(mov r0,r0\) +0+288 <[^>]*> e1a00000[ ]+nop[ ]+\(mov r0,r0\) +0+28c <[^>]*> e1a00000[ ]+nop[ ]+\(mov r0,r0\) diff --git a/gas/testsuite/gas/arm/iwmmxt.s b/gas/testsuite/gas/arm/iwmmxt.s index 1aa433a..5cf1551 100644 --- a/gas/testsuite/gas/arm/iwmmxt.s +++ b/gas/testsuite/gas/arm/iwmmxt.s @@ -202,3 +202,8 @@ iwmmxt: wxorne wr3, wr4, wr5 wzeroge wr7 + + @ a.out-required section size padding + nop + nop + nop diff --git a/gas/testsuite/gas/arm/macro1.d b/gas/testsuite/gas/arm/macro1.d new file mode 100644 index 0000000..2384594 --- /dev/null +++ b/gas/testsuite/gas/arm/macro1.d @@ -0,0 +1,12 @@ +# name: Macro scrubbing +# as: +# objdump: -dr --prefix-addresses --show-raw-insn + +[^:]+: +file format .*arm.* + +Disassembly of section .text: + +0+0 <[^>]*> e8bd8030 ? ldmia sp!, {r4, r5, pc} +0+4 <[^>]*> e1a00000 ? nop \(mov r0,r0\) +0+8 <[^>]*> e1a00000 ? nop \(mov r0,r0\) +0+c <[^>]*> e1a00000 ? nop \(mov r0,r0\) diff --git a/gas/testsuite/gas/arm/macro1.s b/gas/testsuite/gas/arm/macro1.s new file mode 100644 index 0000000..e2880e7 --- /dev/null +++ b/gas/testsuite/gas/arm/macro1.s @@ -0,0 +1,12 @@ + @ Test that macro expansions are properly scrubbed. + .macro popret regs + ldmia sp!, {\regs, pc} + .endm + .text +l: + popret "r4, r5" + + @ section padding for a.out's sake + nop + nop + nop diff --git a/gas/testsuite/gas/arm/maverick.d b/gas/testsuite/gas/arm/maverick.d index dcf5c7d..7c41457 100644 --- a/gas/testsuite/gas/arm/maverick.d +++ b/gas/testsuite/gas/arm/maverick.d @@ -13,121 +13,121 @@ Disassembly of section .text: 0*8 <load_store\+0x8> 7d ?1c ?24 ?ef ? * cfldrsvc mvf2, ?\[ip, #-956\] 0*c <load_store\+0xc> bd ?1a ?04 ?ff ? * cfldrslt mvf0, ?\[sl, #-1020\] 0*10 <load_store\+0x10> 3d ?11 ?c4 ?27 ? * cfldrscc mvf12, ?\[r1, #-156\] -0*14 <load_store\+0x14> ed ?bf ?d4 ?68 ? * cfldrs mvf13, ?\[pc, #416\]! +0*14 <load_store\+0x14> ed ?b9 ?d4 ?68 ? * cfldrs mvf13, ?\[r9, #416\]! 0*18 <load_store\+0x18> 2d ?30 ?94 ?ff ? * cfldrscs mvf9, ?\[r0, #-1020\]! 0*1c <load_store\+0x1c> 9d ?31 ?44 ?27 ? * cfldrsls mvf4, ?\[r1, #-156\]! -0*20 <load_store\+0x20> dd ?bf ?74 ?68 ? * cfldrsle mvf7, ?\[pc, #416\]! +0*20 <load_store\+0x20> dd ?b9 ?74 ?68 ? * cfldrsle mvf7, ?\[r9, #416\]! 0*24 <load_store\+0x24> 6d ?30 ?b4 ?ff ? * cfldrsvs mvf11, ?\[r0, #-1020\]! 0*28 <load_store\+0x28> 3c ?31 ?c4 ?27 ? * cfldrscc mvf12, ?\[r1\], #-156 -0*2c <load_store\+0x2c> ec ?bf ?d4 ?68 ? * cfldrs mvf13, ?\[pc\], #416 +0*2c <load_store\+0x2c> ec ?b9 ?d4 ?68 ? * cfldrs mvf13, ?\[r9\], #416 0*30 <load_store\+0x30> 2c ?30 ?94 ?ff ? * cfldrscs mvf9, ?\[r0\], #-1020 0*34 <load_store\+0x34> 9c ?31 ?44 ?27 ? * cfldrsls mvf4, ?\[r1\], #-156 -0*38 <load_store\+0x38> dc ?bf ?74 ?68 ? * cfldrsle mvf7, ?\[pc\], #416 +0*38 <load_store\+0x38> dc ?b9 ?74 ?68 ? * cfldrsle mvf7, ?\[r9\], #416 0*3c <load_store\+0x3c> 6d ?50 ?b4 ?ff ? * cfldrdvs mvd11, ?\[r0, #-1020\] 0*40 <load_store\+0x40> 3d ?51 ?c4 ?27 ? * cfldrdcc mvd12, ?\[r1, #-156\] -0*44 <load_store\+0x44> ed ?df ?d4 ?68 ? * cfldrd mvd13, ?\[pc, #416\] +0*44 <load_store\+0x44> ed ?d9 ?d4 ?68 ? * cfldrd mvd13, ?\[r9, #416\] 0*48 <load_store\+0x48> 2d ?50 ?94 ?ff ? * cfldrdcs mvd9, ?\[r0, #-1020\] 0*4c <load_store\+0x4c> 9d ?51 ?44 ?27 ? * cfldrdls mvd4, ?\[r1, #-156\] -0*50 <load_store\+0x50> dd ?ff ?74 ?68 ? * cfldrdle mvd7, ?\[pc, #416\]! +0*50 <load_store\+0x50> dd ?f9 ?74 ?68 ? * cfldrdle mvd7, ?\[r9, #416\]! 0*54 <load_store\+0x54> 6d ?70 ?b4 ?ff ? * cfldrdvs mvd11, ?\[r0, #-1020\]! 0*58 <load_store\+0x58> 3d ?71 ?c4 ?27 ? * cfldrdcc mvd12, ?\[r1, #-156\]! -0*5c <load_store\+0x5c> ed ?ff ?d4 ?68 ? * cfldrd mvd13, ?\[pc, #416\]! +0*5c <load_store\+0x5c> ed ?f9 ?d4 ?68 ? * cfldrd mvd13, ?\[r9, #416\]! 0*60 <load_store\+0x60> 2d ?70 ?94 ?ff ? * cfldrdcs mvd9, ?\[r0, #-1020\]! 0*64 <load_store\+0x64> 9c ?71 ?44 ?27 ? * cfldrdls mvd4, ?\[r1\], #-156 -0*68 <load_store\+0x68> dc ?ff ?74 ?68 ? * cfldrdle mvd7, ?\[pc\], #416 +0*68 <load_store\+0x68> dc ?f9 ?74 ?68 ? * cfldrdle mvd7, ?\[r9\], #416 0*6c <load_store\+0x6c> 6c ?70 ?b4 ?ff ? * cfldrdvs mvd11, ?\[r0\], #-1020 0*70 <load_store\+0x70> 3c ?71 ?c4 ?27 ? * cfldrdcc mvd12, ?\[r1\], #-156 -0*74 <load_store\+0x74> ec ?ff ?d4 ?68 ? * cfldrd mvd13, ?\[pc\], #416 +0*74 <load_store\+0x74> ec ?f9 ?d4 ?68 ? * cfldrd mvd13, ?\[r9\], #416 0*78 <load_store\+0x78> 2d ?10 ?95 ?ff ? * cfldr32cs mvfx9, ?\[r0, #-1020\] 0*7c <load_store\+0x7c> 9d ?11 ?45 ?27 ? * cfldr32ls mvfx4, ?\[r1, #-156\] -0*80 <load_store\+0x80> dd ?9f ?75 ?68 ? * cfldr32le mvfx7, ?\[pc, #416\] +0*80 <load_store\+0x80> dd ?99 ?75 ?68 ? * cfldr32le mvfx7, ?\[r9, #416\] 0*84 <load_store\+0x84> 6d ?10 ?b5 ?ff ? * cfldr32vs mvfx11, ?\[r0, #-1020\] 0*88 <load_store\+0x88> 3d ?11 ?c5 ?27 ? * cfldr32cc mvfx12, ?\[r1, #-156\] -0*8c <load_store\+0x8c> ed ?bf ?d5 ?68 ? * cfldr32 mvfx13, ?\[pc, #416\]! +0*8c <load_store\+0x8c> ed ?b9 ?d5 ?68 ? * cfldr32 mvfx13, ?\[r9, #416\]! 0*90 <load_store\+0x90> 2d ?30 ?95 ?ff ? * cfldr32cs mvfx9, ?\[r0, #-1020\]! 0*94 <load_store\+0x94> 9d ?31 ?45 ?27 ? * cfldr32ls mvfx4, ?\[r1, #-156\]! -0*98 <load_store\+0x98> dd ?bf ?75 ?68 ? * cfldr32le mvfx7, ?\[pc, #416\]! +0*98 <load_store\+0x98> dd ?b9 ?75 ?68 ? * cfldr32le mvfx7, ?\[r9, #416\]! 0*9c <load_store\+0x9c> 6d ?30 ?b5 ?ff ? * cfldr32vs mvfx11, ?\[r0, #-1020\]! 0*a0 <load_store\+0xa0> 3c ?31 ?c5 ?27 ? * cfldr32cc mvfx12, ?\[r1\], #-156 -0*a4 <load_store\+0xa4> ec ?bf ?d5 ?68 ? * cfldr32 mvfx13, ?\[pc\], #416 +0*a4 <load_store\+0xa4> ec ?b9 ?d5 ?68 ? * cfldr32 mvfx13, ?\[r9\], #416 0*a8 <load_store\+0xa8> 2c ?30 ?95 ?ff ? * cfldr32cs mvfx9, ?\[r0\], #-1020 0*ac <load_store\+0xac> 9c ?31 ?45 ?27 ? * cfldr32ls mvfx4, ?\[r1\], #-156 -0*b0 <load_store\+0xb0> dc ?bf ?75 ?68 ? * cfldr32le mvfx7, ?\[pc\], #416 +0*b0 <load_store\+0xb0> dc ?b9 ?75 ?68 ? * cfldr32le mvfx7, ?\[r9\], #416 0*b4 <load_store\+0xb4> 6d ?50 ?b5 ?ff ? * cfldr64vs mvdx11, ?\[r0, #-1020\] 0*b8 <load_store\+0xb8> 3d ?51 ?c5 ?27 ? * cfldr64cc mvdx12, ?\[r1, #-156\] -0*bc <load_store\+0xbc> ed ?df ?d5 ?68 ? * cfldr64 mvdx13, ?\[pc, #416\] +0*bc <load_store\+0xbc> ed ?d9 ?d5 ?68 ? * cfldr64 mvdx13, ?\[r9, #416\] 0*c0 <load_store\+0xc0> 2d ?50 ?95 ?ff ? * cfldr64cs mvdx9, ?\[r0, #-1020\] 0*c4 <load_store\+0xc4> 9d ?51 ?45 ?27 ? * cfldr64ls mvdx4, ?\[r1, #-156\] -0*c8 <load_store\+0xc8> dd ?ff ?75 ?68 ? * cfldr64le mvdx7, ?\[pc, #416\]! +0*c8 <load_store\+0xc8> dd ?f9 ?75 ?68 ? * cfldr64le mvdx7, ?\[r9, #416\]! 0*cc <load_store\+0xcc> 6d ?70 ?b5 ?ff ? * cfldr64vs mvdx11, ?\[r0, #-1020\]! 0*d0 <load_store\+0xd0> 3d ?71 ?c5 ?27 ? * cfldr64cc mvdx12, ?\[r1, #-156\]! -0*d4 <load_store\+0xd4> ed ?ff ?d5 ?68 ? * cfldr64 mvdx13, ?\[pc, #416\]! +0*d4 <load_store\+0xd4> ed ?f9 ?d5 ?68 ? * cfldr64 mvdx13, ?\[r9, #416\]! 0*d8 <load_store\+0xd8> 2d ?70 ?95 ?ff ? * cfldr64cs mvdx9, ?\[r0, #-1020\]! 0*dc <load_store\+0xdc> 9c ?71 ?45 ?27 ? * cfldr64ls mvdx4, ?\[r1\], #-156 -0*e0 <load_store\+0xe0> dc ?ff ?75 ?68 ? * cfldr64le mvdx7, ?\[pc\], #416 +0*e0 <load_store\+0xe0> dc ?f9 ?75 ?68 ? * cfldr64le mvdx7, ?\[r9\], #416 0*e4 <load_store\+0xe4> 6c ?70 ?b5 ?ff ? * cfldr64vs mvdx11, ?\[r0\], #-1020 0*e8 <load_store\+0xe8> 3c ?71 ?c5 ?27 ? * cfldr64cc mvdx12, ?\[r1\], #-156 -0*ec <load_store\+0xec> ec ?ff ?d5 ?68 ? * cfldr64 mvdx13, ?\[pc\], #416 +0*ec <load_store\+0xec> ec ?f9 ?d5 ?68 ? * cfldr64 mvdx13, ?\[r9\], #416 0*f0 <load_store\+0xf0> 2d ?00 ?94 ?ff ? * cfstrscs mvf9, ?\[r0, #-1020\] 0*f4 <load_store\+0xf4> 9d ?01 ?44 ?27 ? * cfstrsls mvf4, ?\[r1, #-156\] -0*f8 <load_store\+0xf8> dd ?8f ?74 ?68 ? * cfstrsle mvf7, ?\[pc, #416\] +0*f8 <load_store\+0xf8> dd ?89 ?74 ?68 ? * cfstrsle mvf7, ?\[r9, #416\] 0*fc <load_store\+0xfc> 6d ?00 ?b4 ?ff ? * cfstrsvs mvf11, ?\[r0, #-1020\] 0*100 <load_store\+0x100> 3d ?01 ?c4 ?27 ? * cfstrscc mvf12, ?\[r1, #-156\] -0*104 <load_store\+0x104> ed ?af ?d4 ?68 ? * cfstrs mvf13, ?\[pc, #416\]! +0*104 <load_store\+0x104> ed ?a9 ?d4 ?68 ? * cfstrs mvf13, ?\[r9, #416\]! 0*108 <load_store\+0x108> 2d ?20 ?94 ?ff ? * cfstrscs mvf9, ?\[r0, #-1020\]! 0*10c <load_store\+0x10c> 9d ?21 ?44 ?27 ? * cfstrsls mvf4, ?\[r1, #-156\]! -0*110 <load_store\+0x110> dd ?af ?74 ?68 ? * cfstrsle mvf7, ?\[pc, #416\]! +0*110 <load_store\+0x110> dd ?a9 ?74 ?68 ? * cfstrsle mvf7, ?\[r9, #416\]! 0*114 <load_store\+0x114> 6d ?20 ?b4 ?ff ? * cfstrsvs mvf11, ?\[r0, #-1020\]! 0*118 <load_store\+0x118> 3c ?21 ?c4 ?27 ? * cfstrscc mvf12, ?\[r1\], #-156 -0*11c <load_store\+0x11c> ec ?af ?d4 ?68 ? * cfstrs mvf13, ?\[pc\], #416 +0*11c <load_store\+0x11c> ec ?a9 ?d4 ?68 ? * cfstrs mvf13, ?\[r9\], #416 0*120 <load_store\+0x120> 2c ?20 ?94 ?ff ? * cfstrscs mvf9, ?\[r0\], #-1020 0*124 <load_store\+0x124> 9c ?21 ?44 ?27 ? * cfstrsls mvf4, ?\[r1\], #-156 -0*128 <load_store\+0x128> dc ?af ?74 ?68 ? * cfstrsle mvf7, ?\[pc\], #416 +0*128 <load_store\+0x128> dc ?a9 ?74 ?68 ? * cfstrsle mvf7, ?\[r9\], #416 0*12c <load_store\+0x12c> 6d ?40 ?b4 ?ff ? * cfstrdvs mvd11, ?\[r0, #-1020\] 0*130 <load_store\+0x130> 3d ?41 ?c4 ?27 ? * cfstrdcc mvd12, ?\[r1, #-156\] -0*134 <load_store\+0x134> ed ?cf ?d4 ?68 ? * cfstrd mvd13, ?\[pc, #416\] +0*134 <load_store\+0x134> ed ?c9 ?d4 ?68 ? * cfstrd mvd13, ?\[r9, #416\] 0*138 <load_store\+0x138> 2d ?40 ?94 ?ff ? * cfstrdcs mvd9, ?\[r0, #-1020\] 0*13c <load_store\+0x13c> 9d ?41 ?44 ?27 ? * cfstrdls mvd4, ?\[r1, #-156\] -0*140 <load_store\+0x140> dd ?ef ?74 ?68 ? * cfstrdle mvd7, ?\[pc, #416\]! +0*140 <load_store\+0x140> dd ?e9 ?74 ?68 ? * cfstrdle mvd7, ?\[r9, #416\]! 0*144 <load_store\+0x144> 6d ?60 ?b4 ?ff ? * cfstrdvs mvd11, ?\[r0, #-1020\]! 0*148 <load_store\+0x148> 3d ?61 ?c4 ?27 ? * cfstrdcc mvd12, ?\[r1, #-156\]! -0*14c <load_store\+0x14c> ed ?ef ?d4 ?68 ? * cfstrd mvd13, ?\[pc, #416\]! +0*14c <load_store\+0x14c> ed ?e9 ?d4 ?68 ? * cfstrd mvd13, ?\[r9, #416\]! 0*150 <load_store\+0x150> 2d ?60 ?94 ?ff ? * cfstrdcs mvd9, ?\[r0, #-1020\]! 0*154 <load_store\+0x154> 9c ?61 ?44 ?27 ? * cfstrdls mvd4, ?\[r1\], #-156 -0*158 <load_store\+0x158> dc ?ef ?74 ?68 ? * cfstrdle mvd7, ?\[pc\], #416 +0*158 <load_store\+0x158> dc ?e9 ?74 ?68 ? * cfstrdle mvd7, ?\[r9\], #416 0*15c <load_store\+0x15c> 6c ?60 ?b4 ?ff ? * cfstrdvs mvd11, ?\[r0\], #-1020 0*160 <load_store\+0x160> 3c ?61 ?c4 ?27 ? * cfstrdcc mvd12, ?\[r1\], #-156 -0*164 <load_store\+0x164> ec ?ef ?d4 ?68 ? * cfstrd mvd13, ?\[pc\], #416 +0*164 <load_store\+0x164> ec ?e9 ?d4 ?68 ? * cfstrd mvd13, ?\[r9\], #416 0*168 <load_store\+0x168> 2d ?00 ?95 ?ff ? * cfstr32cs mvfx9, ?\[r0, #-1020\] 0*16c <load_store\+0x16c> 9d ?01 ?45 ?27 ? * cfstr32ls mvfx4, ?\[r1, #-156\] -0*170 <load_store\+0x170> dd ?8f ?75 ?68 ? * cfstr32le mvfx7, ?\[pc, #416\] +0*170 <load_store\+0x170> dd ?89 ?75 ?68 ? * cfstr32le mvfx7, ?\[r9, #416\] 0*174 <load_store\+0x174> 6d ?00 ?b5 ?ff ? * cfstr32vs mvfx11, ?\[r0, #-1020\] 0*178 <load_store\+0x178> 3d ?01 ?c5 ?27 ? * cfstr32cc mvfx12, ?\[r1, #-156\] -0*17c <load_store\+0x17c> ed ?af ?d5 ?68 ? * cfstr32 mvfx13, ?\[pc, #416\]! +0*17c <load_store\+0x17c> ed ?a9 ?d5 ?68 ? * cfstr32 mvfx13, ?\[r9, #416\]! 0*180 <load_store\+0x180> 2d ?20 ?95 ?ff ? * cfstr32cs mvfx9, ?\[r0, #-1020\]! 0*184 <load_store\+0x184> 9d ?21 ?45 ?27 ? * cfstr32ls mvfx4, ?\[r1, #-156\]! -0*188 <load_store\+0x188> dd ?af ?75 ?68 ? * cfstr32le mvfx7, ?\[pc, #416\]! +0*188 <load_store\+0x188> dd ?a9 ?75 ?68 ? * cfstr32le mvfx7, ?\[r9, #416\]! 0*18c <load_store\+0x18c> 6d ?20 ?b5 ?ff ? * cfstr32vs mvfx11, ?\[r0, #-1020\]! 0*190 <load_store\+0x190> 3c ?21 ?c5 ?27 ? * cfstr32cc mvfx12, ?\[r1\], #-156 -0*194 <load_store\+0x194> ec ?af ?d5 ?68 ? * cfstr32 mvfx13, ?\[pc\], #416 +0*194 <load_store\+0x194> ec ?a9 ?d5 ?68 ? * cfstr32 mvfx13, ?\[r9\], #416 0*198 <load_store\+0x198> 2c ?20 ?95 ?ff ? * cfstr32cs mvfx9, ?\[r0\], #-1020 0*19c <load_store\+0x19c> 9c ?21 ?45 ?27 ? * cfstr32ls mvfx4, ?\[r1\], #-156 -0*1a0 <load_store\+0x1a0> dc ?af ?75 ?68 ? * cfstr32le mvfx7, ?\[pc\], #416 +0*1a0 <load_store\+0x1a0> dc ?a9 ?75 ?68 ? * cfstr32le mvfx7, ?\[r9\], #416 0*1a4 <load_store\+0x1a4> 6d ?40 ?b5 ?ff ? * cfstr64vs mvdx11, ?\[r0, #-1020\] 0*1a8 <load_store\+0x1a8> 3d ?41 ?c5 ?27 ? * cfstr64cc mvdx12, ?\[r1, #-156\] -0*1ac <load_store\+0x1ac> ed ?cf ?d5 ?68 ? * cfstr64 mvdx13, ?\[pc, #416\] +0*1ac <load_store\+0x1ac> ed ?c9 ?d5 ?68 ? * cfstr64 mvdx13, ?\[r9, #416\] 0*1b0 <load_store\+0x1b0> 2d ?40 ?95 ?ff ? * cfstr64cs mvdx9, ?\[r0, #-1020\] 0*1b4 <load_store\+0x1b4> 9d ?41 ?45 ?27 ? * cfstr64ls mvdx4, ?\[r1, #-156\] -0*1b8 <load_store\+0x1b8> dd ?ef ?75 ?68 ? * cfstr64le mvdx7, ?\[pc, #416\]! +0*1b8 <load_store\+0x1b8> dd ?e9 ?75 ?68 ? * cfstr64le mvdx7, ?\[r9, #416\]! 0*1bc <load_store\+0x1bc> 6d ?60 ?b5 ?ff ? * cfstr64vs mvdx11, ?\[r0, #-1020\]! 0*1c0 <load_store\+0x1c0> 3d ?61 ?c5 ?27 ? * cfstr64cc mvdx12, ?\[r1, #-156\]! -0*1c4 <load_store\+0x1c4> ed ?ef ?d5 ?68 ? * cfstr64 mvdx13, ?\[pc, #416\]! +0*1c4 <load_store\+0x1c4> ed ?e9 ?d5 ?68 ? * cfstr64 mvdx13, ?\[r9, #416\]! 0*1c8 <load_store\+0x1c8> 2d ?60 ?95 ?ff ? * cfstr64cs mvdx9, ?\[r0, #-1020\]! 0*1cc <load_store\+0x1cc> 9c ?61 ?45 ?27 ? * cfstr64ls mvdx4, ?\[r1\], #-156 -0*1d0 <load_store\+0x1d0> dc ?ef ?75 ?68 ? * cfstr64le mvdx7, ?\[pc\], #416 +0*1d0 <load_store\+0x1d0> dc ?e9 ?75 ?68 ? * cfstr64le mvdx7, ?\[r9\], #416 0*1d4 <load_store\+0x1d4> 6c ?60 ?b5 ?ff ? * cfstr64vs mvdx11, ?\[r0\], #-1020 0*1d8 <load_store\+0x1d8> 3c ?61 ?c5 ?27 ? * cfstr64cc mvdx12, ?\[r1\], #-156 -0*1dc <load_store\+0x1dc> ec ?ef ?d5 ?68 ? * cfstr64 mvdx13, ?\[pc\], #416 +0*1dc <load_store\+0x1dc> ec ?e9 ?d5 ?68 ? * cfstr64 mvdx13, ?\[r9\], #416 # move: 0*1e0 <move> 2e ?09 ?04 ?50 ? * cfmvsrcs mvf9, ?r0 0*1e4 <move\+0x4> 5e ?0f ?74 ?50 ? * cfmvsrpl mvf15, ?r7 diff --git a/gas/testsuite/gas/arm/maverick.s b/gas/testsuite/gas/arm/maverick.s index ca39f63..e32d36b 100644 --- a/gas/testsuite/gas/arm/maverick.s +++ b/gas/testsuite/gas/arm/maverick.s @@ -6,121 +6,121 @@ load_store: cfldrsvc mvf2, [r12, #-956] cfldrslt mvf0, [sl, #-1020] cfldrscc mvf12, [r1, #-156] - cfldrs mvf13, [r15, #416]! + cfldrs mvf13, [r9, #416]! cfldrscs mvf9, [r0, #-1020]! cfldrsls mvf4, [r1, #-156]! - cfldrsle mvf7, [pc, #416]! + cfldrsle mvf7, [r9, #416]! cfldrsvs mvf11, [r0, #-1020]! cfldrscc mvf12, [r1], #-156 - cfldrs mvf13, [r15], #416 + cfldrs mvf13, [r9], #416 cfldrscs mvf9, [r0], #-1020 cfldrsls mvf4, [r1], #-156 - cfldrsle mvf7, [pc], #416 + cfldrsle mvf7, [r9], #416 cfldrdvs mvd11, [r0, #-1020] cfldrdcc mvd12, [r1, #-156] - cfldrd mvd13, [r15, #416] + cfldrd mvd13, [r9, #416] cfldrdcs mvd9, [r0, #-1020] cfldrdls mvd4, [r1, #-156] - cfldrdle mvd7, [pc, #416]! + cfldrdle mvd7, [r9, #416]! cfldrdvs mvd11, [r0, #-1020]! cfldrdcc mvd12, [r1, #-156]! - cfldrd mvd13, [r15, #416]! + cfldrd mvd13, [r9, #416]! cfldrdcs mvd9, [r0, #-1020]! cfldrdls mvd4, [r1], #-156 - cfldrdle mvd7, [pc], #416 + cfldrdle mvd7, [r9], #416 cfldrdvs mvd11, [r0], #-1020 cfldrdcc mvd12, [r1], #-156 - cfldrd mvd13, [r15], #416 + cfldrd mvd13, [r9], #416 cfldr32cs mvfx9, [r0, #-1020] cfldr32ls mvfx4, [r1, #-156] - cfldr32le mvfx7, [pc, #416] + cfldr32le mvfx7, [r9, #416] cfldr32vs mvfx11, [r0, #-1020] cfldr32cc mvfx12, [r1, #-156] - cfldr32 mvfx13, [r15, #416]! + cfldr32 mvfx13, [r9, #416]! cfldr32cs mvfx9, [r0, #-1020]! cfldr32ls mvfx4, [r1, #-156]! - cfldr32le mvfx7, [pc, #416]! + cfldr32le mvfx7, [r9, #416]! cfldr32vs mvfx11, [r0, #-1020]! cfldr32cc mvfx12, [r1], #-156 - cfldr32 mvfx13, [r15], #416 + cfldr32 mvfx13, [r9], #416 cfldr32cs mvfx9, [r0], #-1020 cfldr32ls mvfx4, [r1], #-156 - cfldr32le mvfx7, [pc], #416 + cfldr32le mvfx7, [r9], #416 cfldr64vs mvdx11, [r0, #-1020] cfldr64cc mvdx12, [r1, #-156] - cfldr64 mvdx13, [r15, #416] + cfldr64 mvdx13, [r9, #416] cfldr64cs mvdx9, [r0, #-1020] cfldr64ls mvdx4, [r1, #-156] - cfldr64le mvdx7, [pc, #416]! + cfldr64le mvdx7, [r9, #416]! cfldr64vs mvdx11, [r0, #-1020]! cfldr64cc mvdx12, [r1, #-156]! - cfldr64 mvdx13, [r15, #416]! + cfldr64 mvdx13, [r9, #416]! cfldr64cs mvdx9, [r0, #-1020]! cfldr64ls mvdx4, [r1], #-156 - cfldr64le mvdx7, [pc], #416 + cfldr64le mvdx7, [r9], #416 cfldr64vs mvdx11, [r0], #-1020 cfldr64cc mvdx12, [r1], #-156 - cfldr64 mvdx13, [r15], #416 + cfldr64 mvdx13, [r9], #416 cfstrscs mvf9, [r0, #-1020] cfstrsls mvf4, [r1, #-156] - cfstrsle mvf7, [pc, #416] + cfstrsle mvf7, [r9, #416] cfstrsvs mvf11, [r0, #-1020] cfstrscc mvf12, [r1, #-156] - cfstrs mvf13, [r15, #416]! + cfstrs mvf13, [r9, #416]! cfstrscs mvf9, [r0, #-1020]! cfstrsls mvf4, [r1, #-156]! - cfstrsle mvf7, [pc, #416]! + cfstrsle mvf7, [r9, #416]! cfstrsvs mvf11, [r0, #-1020]! cfstrscc mvf12, [r1], #-156 - cfstrs mvf13, [r15], #416 + cfstrs mvf13, [r9], #416 cfstrscs mvf9, [r0], #-1020 cfstrsls mvf4, [r1], #-156 - cfstrsle mvf7, [pc], #416 + cfstrsle mvf7, [r9], #416 cfstrdvs mvd11, [r0, #-1020] cfstrdcc mvd12, [r1, #-156] - cfstrd mvd13, [r15, #416] + cfstrd mvd13, [r9, #416] cfstrdcs mvd9, [r0, #-1020] cfstrdls mvd4, [r1, #-156] - cfstrdle mvd7, [pc, #416]! + cfstrdle mvd7, [r9, #416]! cfstrdvs mvd11, [r0, #-1020]! cfstrdcc mvd12, [r1, #-156]! - cfstrd mvd13, [r15, #416]! + cfstrd mvd13, [r9, #416]! cfstrdcs mvd9, [r0, #-1020]! cfstrdls mvd4, [r1], #-156 - cfstrdle mvd7, [pc], #416 + cfstrdle mvd7, [r9], #416 cfstrdvs mvd11, [r0], #-1020 cfstrdcc mvd12, [r1], #-156 - cfstrd mvd13, [r15], #416 + cfstrd mvd13, [r9], #416 cfstr32cs mvfx9, [r0, #-1020] cfstr32ls mvfx4, [r1, #-156] - cfstr32le mvfx7, [pc, #416] + cfstr32le mvfx7, [r9, #416] cfstr32vs mvfx11, [r0, #-1020] cfstr32cc mvfx12, [r1, #-156] - cfstr32 mvfx13, [r15, #416]! + cfstr32 mvfx13, [r9, #416]! cfstr32cs mvfx9, [r0, #-1020]! cfstr32ls mvfx4, [r1, #-156]! - cfstr32le mvfx7, [pc, #416]! + cfstr32le mvfx7, [r9, #416]! cfstr32vs mvfx11, [r0, #-1020]! cfstr32cc mvfx12, [r1], #-156 - cfstr32 mvfx13, [r15], #416 + cfstr32 mvfx13, [r9], #416 cfstr32cs mvfx9, [r0], #-1020 cfstr32ls mvfx4, [r1], #-156 - cfstr32le mvfx7, [pc], #416 + cfstr32le mvfx7, [r9], #416 cfstr64vs mvdx11, [r0, #-1020] cfstr64cc mvdx12, [r1, #-156] - cfstr64 mvdx13, [r15, #416] + cfstr64 mvdx13, [r9, #416] cfstr64cs mvdx9, [r0, #-1020] cfstr64ls mvdx4, [r1, #-156] - cfstr64le mvdx7, [pc, #416]! + cfstr64le mvdx7, [r9, #416]! cfstr64vs mvdx11, [r0, #-1020]! cfstr64cc mvdx12, [r1, #-156]! - cfstr64 mvdx13, [r15, #416]! + cfstr64 mvdx13, [r9, #416]! cfstr64cs mvdx9, [r0, #-1020]! cfstr64ls mvdx4, [r1], #-156 - cfstr64le mvdx7, [pc], #416 + cfstr64le mvdx7, [r9], #416 cfstr64vs mvdx11, [r0], #-1020 cfstr64cc mvdx12, [r1], #-156 - cfstr64 mvdx13, [r15], #416 + cfstr64 mvdx13, [r9], #416 move: cfmvsrcs mvf9, r0 cfmvsrpl mvf15, r7 diff --git a/gas/testsuite/gas/arm/offset.d b/gas/testsuite/gas/arm/offset.d new file mode 100644 index 0000000..f6957c0 --- /dev/null +++ b/gas/testsuite/gas/arm/offset.d @@ -0,0 +1,11 @@ +# name: OFFSET_IMM regression +# as: +# objdump: -dr --prefix-addresses --show-raw-insn + +.*: +file format .*arm.* + +Disassembly of section .text: +0+0 <[^>]+> e51f0004 ? ldr r0, \[pc, #-4\] ; 0+4 <[^>]+> +0+4 <[^>]+> e1a00000 ? nop \(mov r0,r0\) +0+8 <[^>]+> e1a00000 ? nop \(mov r0,r0\) +0+c <[^>]+> e1a00000 ? nop \(mov r0,r0\) diff --git a/gas/testsuite/gas/arm/offset.s b/gas/testsuite/gas/arm/offset.s index ba3ecba..53d567d 100644 --- a/gas/testsuite/gas/arm/offset.s +++ b/gas/testsuite/gas/arm/offset.s @@ -1,5 +1,14 @@ -@ test for OFFSET_IMM reloc against global symbols + @ test that an OFFSET_IMM reloc against a global symbol is + @ still resolved by the assembler, as long as the symbol is in + @ the same section as the reference + .text + .globl l + .globl foo +l: + ldr r0, foo +foo: + nop -.globl foo -foo: .word 0 -ldr r0, foo + @ pad section for a.out's benefit + nop + nop diff --git a/gas/testsuite/gas/arm/pic.d b/gas/testsuite/gas/arm/pic.d index b9dc4d9..5a87262 100644 --- a/gas/testsuite/gas/arm/pic.d +++ b/gas/testsuite/gas/arm/pic.d @@ -13,7 +13,7 @@ Disassembly of section .text: \.\.\. 8: R_ARM_ABS32 sym c: R_ARM_GOT32 sym - 10: R_ARM_GOTOFF sym + 10: R_ARM_GOTOFF32 sym 14: R_ARM_GOTPC _GLOBAL_OFFSET_TABLE_ 18: R_ARM_TARGET1 foo2 1c: R_ARM_SBREL32 foo3 diff --git a/gas/testsuite/gas/arm/r15-bad.l b/gas/testsuite/gas/arm/r15-bad.l index b0c370f..0230636 100644 --- a/gas/testsuite/gas/arm/r15-bad.l +++ b/gas/testsuite/gas/arm/r15-bad.l @@ -1,6 +1,6 @@ [^:]*: Assembler messages: -[^:]*:5: Error: r15 not allowed here -- `mul r15,r1' -[^:]*:6: Error: r15 not allowed here -- `mul r1,r15' +[^:]*:5: Error: r15 not allowed here -- `mul r15,r1,r2' +[^:]*:6: Error: r15 not allowed here -- `mul r1,r15,r2' [^:]*:7: Error: r15 not allowed here -- `mla r15,r2,r3,r4' [^:]*:8: Error: r15 not allowed here -- `mla r1,r15,r3,r4' [^:]*:9: Error: r15 not allowed here -- `mla r1,r2,r15,r4' @@ -59,6 +59,6 @@ [^:]*:62: Error: r15 not allowed here -- `pkhtb r1,r2,r15' [^:]*:63: Error: r15 not allowed here -- `ldrex r15,[[]r2[]]' [^:]*:64: Error: r15 not allowed here -- `ldrex r1,[[]r15[]]' -[^:]*:65: Error: r15 not allowed in swap -- `swp r15,r2,[[]r3[]]' -[^:]*:66: Error: r15 not allowed in swap -- `swp r1,r15,[[]r3[]]' +[^:]*:65: Error: r15 not allowed here -- `swp r15,r2,[[]r3[]]' +[^:]*:66: Error: r15 not allowed here -- `swp r1,r15,[[]r3[]]' [^:]*:67: Error: r15 not allowed here -- `swp r1,r2,[[]r15[]]' diff --git a/gas/testsuite/gas/arm/r15-bad.s b/gas/testsuite/gas/arm/r15-bad.s index 5c91e72..59a6ea8 100644 --- a/gas/testsuite/gas/arm/r15-bad.s +++ b/gas/testsuite/gas/arm/r15-bad.s @@ -2,8 +2,8 @@ .align 0 label: - mul r15, r1 - mul r1, r15 + mul r15, r1, r2 + mul r1, r15, r2 mla r15, r2, r3, r4 mla r1, r15, r3, r4 mla r1, r2, r15, r4 diff --git a/gas/testsuite/gas/arm/req.l b/gas/testsuite/gas/arm/req.l index 6dbf135..165d1d8 100644 --- a/gas/testsuite/gas/arm/req.l +++ b/gas/testsuite/gas/arm/req.l @@ -1,3 +1,3 @@ [^:]*: Assembler messages: -[^:]*:18: Error: register expected, not 'foo,foo,foo' -- `add foo,foo,foo' -[^:]*:24: Error: register expected, not 'r0,r0,r0' -- `add r0,r0,r0' +[^:]*:18: Error: ARM register expected -- `add foo,foo,foo' +[^:]*:21: Warning: ignoring attempt to undefine built-in register 'r0' diff --git a/gas/testsuite/gas/arm/req.s b/gas/testsuite/gas/arm/req.s index 212308a..341f66d 100644 --- a/gas/testsuite/gas/arm/req.s +++ b/gas/testsuite/gas/arm/req.s @@ -2,7 +2,7 @@ .global test_dot_req_and_unreq test_dot_req_and_unreq: - # Check that builtin register alias 'r0' works. + # Check that builtin register alias 'r0' works. add r0, r0, r0 # Create an alias for r0. @@ -17,9 +17,9 @@ test_dot_req_and_unreq: # And make sure that it no longer works. add foo, foo, foo - # Finally remove the builtin alias for r0. + # Attempt to remove the builtin alias for r0. .unreq r0 - # And make sure that this no longer works. + # That is ignored, so this should still work. add r0, r0, r0 diff --git a/gas/testsuite/gas/arm/t16-bad.l b/gas/testsuite/gas/arm/t16-bad.l new file mode 100644 index 0000000..7c32260 --- /dev/null +++ b/gas/testsuite/gas/arm/t16-bad.l @@ -0,0 +1,186 @@ +[^:]*: Assembler messages: +[^:]*:36: Error: lo register required -- `tst r8,r0' +[^:]*:36: Error: lo register required -- `tst r0,r8' +[^:]*:36: Error: unshifted register required -- `tst r0,#12' +[^:]*:36: Error: unshifted register required -- `tst r0,r1,lsl#2' +[^:]*:36: Error: unshifted register required -- `tst r0,r1,lsl r3' +[^:]*:37: Error: lo register required -- `cmn r8,r0' +[^:]*:37: Error: lo register required -- `cmn r0,r8' +[^:]*:37: Error: unshifted register required -- `cmn r0,#12' +[^:]*:37: Error: unshifted register required -- `cmn r0,r1,lsl#2' +[^:]*:37: Error: unshifted register required -- `cmn r0,r1,lsl r3' +[^:]*:38: Error: lo register required -- `mvn r8,r0' +[^:]*:38: Error: lo register required -- `mvn r0,r8' +[^:]*:38: Error: unshifted register required -- `mvn r0,#12' +[^:]*:38: Error: unshifted register required -- `mvn r0,r1,lsl#2' +[^:]*:38: Error: unshifted register required -- `mvn r0,r1,lsl r3' +[^:]*:39: Error: lo register required -- `neg r8,r0' +[^:]*:39: Error: lo register required -- `neg r0,r8' +[^:]*:40: Error: lo register required -- `rev r8,r0' +[^:]*:40: Error: lo register required -- `rev r0,r8' +[^:]*:41: Error: lo register required -- `rev16 r8,r0' +[^:]*:41: Error: lo register required -- `rev16 r0,r8' +[^:]*:42: Error: lo register required -- `revsh r8,r0' +[^:]*:42: Error: lo register required -- `revsh r0,r8' +[^:]*:43: Error: lo register required -- `sxtb r8,r0' +[^:]*:43: Error: lo register required -- `sxtb r0,r8' +[^:]*:43: Error: Thumb encoding does not support rotation -- `sxtb r0,r1,ror#8' +[^:]*:44: Error: lo register required -- `sxth r8,r0' +[^:]*:44: Error: lo register required -- `sxth r0,r8' +[^:]*:44: Error: Thumb encoding does not support rotation -- `sxth r0,r1,ror#8' +[^:]*:45: Error: lo register required -- `uxtb r8,r0' +[^:]*:45: Error: lo register required -- `uxtb r0,r8' +[^:]*:45: Error: Thumb encoding does not support rotation -- `uxtb r0,r1,ror#8' +[^:]*:46: Error: lo register required -- `uxth r8,r0' +[^:]*:46: Error: lo register required -- `uxth r0,r8' +[^:]*:46: Error: Thumb encoding does not support rotation -- `uxth r0,r1,ror#8' +[^:]*:48: Error: dest must overlap one source register -- `adc r1,r2,r3' +[^:]*:48: Error: lo register required -- `adc r8,r0' +[^:]*:48: Error: lo register required -- `adc r0,r8' +[^:]*:48: Error: unshifted register required -- `adc r0,#12' +[^:]*:48: Error: unshifted register required -- `adc r0,r1,lsl#2' +[^:]*:48: Error: unshifted register required -- `adc r0,r1,lsl r3' +[^:]*:49: Error: dest must overlap one source register -- `and r1,r2,r3' +[^:]*:49: Error: lo register required -- `and r8,r0' +[^:]*:49: Error: lo register required -- `and r0,r8' +[^:]*:49: Error: unshifted register required -- `and r0,#12' +[^:]*:49: Error: unshifted register required -- `and r0,r1,lsl#2' +[^:]*:49: Error: unshifted register required -- `and r0,r1,lsl r3' +[^:]*:50: Error: dest and source1 must be the same register -- `bic r1,r2,r3' +[^:]*:50: Error: lo register required -- `bic r8,r0' +[^:]*:50: Error: lo register required -- `bic r0,r8' +[^:]*:50: Error: unshifted register required -- `bic r0,#12' +[^:]*:50: Error: unshifted register required -- `bic r0,r1,lsl#2' +[^:]*:50: Error: unshifted register required -- `bic r0,r1,lsl r3' +[^:]*:51: Error: dest must overlap one source register -- `eor r1,r2,r3' +[^:]*:51: Error: lo register required -- `eor r8,r0' +[^:]*:51: Error: lo register required -- `eor r0,r8' +[^:]*:51: Error: unshifted register required -- `eor r0,#12' +[^:]*:51: Error: unshifted register required -- `eor r0,r1,lsl#2' +[^:]*:51: Error: unshifted register required -- `eor r0,r1,lsl r3' +[^:]*:52: Error: dest must overlap one source register -- `orr r1,r2,r3' +[^:]*:52: Error: lo register required -- `orr r8,r0' +[^:]*:52: Error: lo register required -- `orr r0,r8' +[^:]*:52: Error: unshifted register required -- `orr r0,#12' +[^:]*:52: Error: unshifted register required -- `orr r0,r1,lsl#2' +[^:]*:52: Error: unshifted register required -- `orr r0,r1,lsl r3' +[^:]*:53: Error: dest and source1 must be the same register -- `sbc r1,r2,r3' +[^:]*:53: Error: lo register required -- `sbc r8,r0' +[^:]*:53: Error: lo register required -- `sbc r0,r8' +[^:]*:53: Error: unshifted register required -- `sbc r0,#12' +[^:]*:53: Error: unshifted register required -- `sbc r0,r1,lsl#2' +[^:]*:53: Error: unshifted register required -- `sbc r0,r1,lsl r3' +[^:]*:54: Error: dest must overlap one source register -- `mul r1,r2,r3' +[^:]*:54: Error: lo register required -- `mul r8,r0' +[^:]*:54: Error: lo register required -- `mul r0,r8' +[^:]*:62: Error: lo register required -- `asr r8,r0,#12' +[^:]*:62: Error: lo register required -- `asr r0,r8,#12' +[^:]*:62: Error: lo register required -- `asr r8,r0' +[^:]*:62: Error: lo register required -- `asr r0,r8' +[^:]*:63: Error: lo register required -- `lsl r8,r0,#12' +[^:]*:63: Error: lo register required -- `lsl r0,r8,#12' +[^:]*:63: Error: lo register required -- `lsl r8,r0' +[^:]*:63: Error: lo register required -- `lsl r0,r8' +[^:]*:64: Error: lo register required -- `lsr r8,r0,#12' +[^:]*:64: Error: lo register required -- `lsr r0,r8,#12' +[^:]*:64: Error: lo register required -- `lsr r8,r0' +[^:]*:64: Error: lo register required -- `lsr r0,r8' +[^:]*:65: Error: lo register required -- `ror r8,r0,#12' +[^:]*:65: Error: lo register required -- `ror r0,r8,#12' +[^:]*:65: Error: lo register required -- `ror r8,r0' +[^:]*:65: Error: lo register required -- `ror r0,r8' +[^:]*:66: Error: ror #imm not supported -- `ror r0,r1,#12' +[^:]*:69: Error: unshifted register required -- `add r0,r1,lsl#2' +[^:]*:70: Error: unshifted register required -- `add r0,r1,lsl r3' +[^:]*:71: Error: lo register required -- `add r8,r0,#1' +[^:]*:72: Error: lo register required -- `add r0,r8,#1' +[^:]*:73: Error: lo register required -- `add r8,#10' +[^:]*:74: Error: dest must overlap one source register -- `add r8,r1,r2' +[^:]*:75: Error: dest must overlap one source register -- `add r1,r8,r2' +[^:]*:76: Error: dest must overlap one source register -- `add r1,r2,r8' +[^:]*:77: Error: lo register required -- `add r8,pc,#4' +[^:]*:78: Error: lo register required -- `add r8,sp,#4' +[^:]*:80: Error: lo register required -- `sub r8,r0' +[^:]*:80: Error: lo register required -- `sub r0,r8' +[^:]*:80: Error: unshifted register required -- `sub r0,r1,lsl#2' +[^:]*:80: Error: unshifted register required -- `sub r0,r1,lsl r3' +[^:]*:81: Error: lo register required -- `sub r8,r0,#1' +[^:]*:82: Error: lo register required -- `sub r0,r8,#1' +[^:]*:83: Error: lo register required -- `sub r8,#10' +[^:]*:84: Error: lo register required -- `sub r8,r1,r2' +[^:]*:85: Error: lo register required -- `sub r1,r8,r2' +[^:]*:86: Error: lo register required -- `sub r1,r2,r8' +[^:]*:90: Error: only lo regs allowed with immediate -- `cmp r8,#255' +[^:]*:94: Error: only lo regs allowed with immediate -- `mov r8,#255' +[^:]*:106: Error: lo register required -- `ldr r8,\[r0\]' +[^:]*:106: Error: lo register required -- `ldr r0,\[r8\]' +[^:]*:106: Error: lo register required -- `ldr r0,\[r0,r8\]' +[^:]*:106: Error: Thumb does not support this addressing mode -- `ldr r0,\[r1,#4\]!' +[^:]*:106: Error: Thumb does not support this addressing mode -- `ldr r0,\[r1\],#4' +[^:]*:106: Error: Thumb does not support this addressing mode -- `ldr r0,\[r1,-r2\]' +[^:]*:106: Error: Thumb does not support this addressing mode -- `ldr r0,\[r1\],r2' +[^:]*:107: Error: lo register required -- `ldrb r8,\[r0\]' +[^:]*:107: Error: lo register required -- `ldrb r0,\[r8\]' +[^:]*:107: Error: lo register required -- `ldrb r0,\[r0,r8\]' +[^:]*:107: Error: Thumb does not support this addressing mode -- `ldrb r0,\[r1,#4\]!' +[^:]*:107: Error: Thumb does not support this addressing mode -- `ldrb r0,\[r1\],#4' +[^:]*:107: Error: Thumb does not support this addressing mode -- `ldrb r0,\[r1,-r2\]' +[^:]*:107: Error: Thumb does not support this addressing mode -- `ldrb r0,\[r1\],r2' +[^:]*:108: Error: lo register required -- `ldrh r8,\[r0\]' +[^:]*:108: Error: lo register required -- `ldrh r0,\[r8\]' +[^:]*:108: Error: lo register required -- `ldrh r0,\[r0,r8\]' +[^:]*:108: Error: Thumb does not support this addressing mode -- `ldrh r0,\[r1,#4\]!' +[^:]*:108: Error: Thumb does not support this addressing mode -- `ldrh r0,\[r1\],#4' +[^:]*:108: Error: Thumb does not support this addressing mode -- `ldrh r0,\[r1,-r2\]' +[^:]*:108: Error: Thumb does not support this addressing mode -- `ldrh r0,\[r1\],r2' +[^:]*:109: Error: lo register required -- `ldrsb r8,\[r0\]' +[^:]*:109: Error: lo register required -- `ldrsb r0,\[r8\]' +[^:]*:109: Error: lo register required -- `ldrsb r0,\[r0,r8\]' +[^:]*:109: Error: Thumb does not support this addressing mode -- `ldrsb r0,\[r1,#4\]!' +[^:]*:109: Error: Thumb does not support this addressing mode -- `ldrsb r0,\[r1\],#4' +[^:]*:109: Error: Thumb does not support this addressing mode -- `ldrsb r0,\[r1,-r2\]' +[^:]*:109: Error: Thumb does not support this addressing mode -- `ldrsb r0,\[r1\],r2' +[^:]*:110: Error: lo register required -- `ldrsh r8,\[r0\]' +[^:]*:110: Error: lo register required -- `ldrsh r0,\[r8\]' +[^:]*:110: Error: lo register required -- `ldrsh r0,\[r0,r8\]' +[^:]*:110: Error: Thumb does not support this addressing mode -- `ldrsh r0,\[r1,#4\]!' +[^:]*:110: Error: Thumb does not support this addressing mode -- `ldrsh r0,\[r1\],#4' +[^:]*:110: Error: Thumb does not support this addressing mode -- `ldrsh r0,\[r1,-r2\]' +[^:]*:110: Error: Thumb does not support this addressing mode -- `ldrsh r0,\[r1\],r2' +[^:]*:111: Error: lo register required -- `str r8,\[r0\]' +[^:]*:111: Error: lo register required -- `str r0,\[r8\]' +[^:]*:111: Error: lo register required -- `str r0,\[r0,r8\]' +[^:]*:111: Error: Thumb does not support this addressing mode -- `str r0,\[r1,#4\]!' +[^:]*:111: Error: Thumb does not support this addressing mode -- `str r0,\[r1\],#4' +[^:]*:111: Error: Thumb does not support this addressing mode -- `str r0,\[r1,-r2\]' +[^:]*:111: Error: Thumb does not support this addressing mode -- `str r0,\[r1\],r2' +[^:]*:112: Error: lo register required -- `strb r8,\[r0\]' +[^:]*:112: Error: lo register required -- `strb r0,\[r8\]' +[^:]*:112: Error: lo register required -- `strb r0,\[r0,r8\]' +[^:]*:112: Error: Thumb does not support this addressing mode -- `strb r0,\[r1,#4\]!' +[^:]*:112: Error: Thumb does not support this addressing mode -- `strb r0,\[r1\],#4' +[^:]*:112: Error: Thumb does not support this addressing mode -- `strb r0,\[r1,-r2\]' +[^:]*:112: Error: Thumb does not support this addressing mode -- `strb r0,\[r1\],r2' +[^:]*:113: Error: lo register required -- `strh r8,\[r0\]' +[^:]*:113: Error: lo register required -- `strh r0,\[r8\]' +[^:]*:113: Error: lo register required -- `strh r0,\[r0,r8\]' +[^:]*:113: Error: Thumb does not support this addressing mode -- `strh r0,\[r1,#4\]!' +[^:]*:113: Error: Thumb does not support this addressing mode -- `strh r0,\[r1\],#4' +[^:]*:113: Error: Thumb does not support this addressing mode -- `strh r0,\[r1,-r2\]' +[^:]*:113: Error: Thumb does not support this addressing mode -- `strh r0,\[r1\],r2' +[^:]*:115: Error: Thumb does not support this addressing mode -- `ldr r0,\[r1,r2,lsl#1\]' +[^:]*:116: Error: Thumb does not support this addressing mode -- `str r0,\[r1,r2,lsl#1\]' +[^:]*:119: Error: lo register required -- `ldmia r8!,{r1,r2}' +[^:]*:120: Error: lo register required -- `ldmia r7!,{r8}' +[^:]*:121: Warning: this instruction will write back the base register +[^:]*:122: Warning: this instruction will not write back the base register +[^:]*:124: Error: lo register required -- `stmia r8!,{r1,r2}' +[^:]*:125: Error: lo register required -- `stmia r7!,{r8}' +[^:]*:126: Warning: this instruction will write back the base register +[^:]*:127: Warning: value stored for r7 is UNPREDICTABLE +[^:]*:129: Error: invalid register list to push/pop instruction -- `push {r8,r9}' +[^:]*:130: Error: invalid register list to push/pop instruction -- `pop {r8,r9}' +[^:]*:133: Error: immediate value out of range -- `bkpt #257' +[^:]*:134: Error: Thumb does not support the 2-argument form of this instruction -- `cpsie ai,#5' +[^:]*:135: Error: Thumb does not support the 2-argument form of this instruction -- `cpsid ai,#5' +[^:]*:138: Error: Thumb does not support conditional execution diff --git a/gas/testsuite/gas/arm/t16-bad.s b/gas/testsuite/gas/arm/t16-bad.s new file mode 100644 index 0000000..a80a81f --- /dev/null +++ b/gas/testsuite/gas/arm/t16-bad.s @@ -0,0 +1,138 @@ + @ Things you can't do with 16-bit Thumb instructions, but you can + @ do with the equivalent ARM instruction. Does not include errors + @ caught by fixup processing (e.g. out-of-range immediates). + + .text + .code 16 + .thumb_func +l: + @ Arithmetic instruction templates + .macro ar2 opc + \opc r8,r0 + \opc r0,r8 + .endm + .macro ar2sh opc + ar2 \opc + \opc r0,#12 + \opc r0,r1,lsl #2 + \opc r0,r1,lsl r3 + .endm + .macro ar2r opc + ar2 \opc + \opc r0,r1,ror #8 + .endm + .macro ar3 opc + \opc r1,r2,r3 + \opc r8,r0 + \opc r0,r8 + .endm + .macro ar3sh opc + ar3 \opc + \opc r0,#12 + \opc r0,r1,lsl #2 + \opc r0,r1,lsl r3 + .endm + + ar2sh tst + ar2sh cmn + ar2sh mvn + ar2 neg + ar2 rev + ar2 rev16 + ar2 revsh + ar2r sxtb + ar2r sxth + ar2r uxtb + ar2r uxth + + ar3sh adc + ar3sh and + ar3sh bic + ar3sh eor + ar3sh orr + ar3sh sbc + ar3 mul + + @ Shift instruction template + .macro shift opc + \opc r8,r0,#12 @ form 1 + \opc r0,r8,#12 + ar2 \opc @ form 2 + .endm + shift asr + shift lsl + shift lsr + shift ror + ror r0,r1,#12 + + @ add/sub/mov/cmp are idiosyncratic + add r0,r1,lsl #2 + add r0,r1,lsl r3 + add r8,r0,#1 @ form 1 + add r0,r8,#1 + add r8,#10 @ form 2 + add r8,r1,r2 @ form 3 + add r1,r8,r2 + add r1,r2,r8 + add r8,pc,#4 @ form 5 + add r8,sp,#4 @ form 6 + + ar3sh sub + sub r8,r0,#1 @ form 1 + sub r0,r8,#1 + sub r8,#10 @ form 2 + sub r8,r1,r2 @ form 3 + sub r1,r8,r2 + sub r1,r2,r8 + + cmp r0,r1,lsl #2 + cmp r0,r1,lsl r3 + cmp r8,#255 + + mov r0,r1,lsl #2 + mov r0,r1,lsl r3 + mov r8,#255 + + @ Load/store template + .macro ldst opc + \opc r8,[r0] + \opc r0,[r8] + \opc r0,[r0,r8] + \opc r0,[r1,#4]! + \opc r0,[r1],#4 + \opc r0,[r1,-r2] + \opc r0,[r1],r2 + .endm + ldst ldr + ldst ldrb + ldst ldrh + ldst ldrsb + ldst ldrsh + ldst str + ldst strb + ldst strh + + ldr r0,[r1,r2,lsl #1] + str r0,[r1,r2,lsl #1] + + @ Load/store multiple + ldmia r8!,{r1,r2} + ldmia r7!,{r8} + ldmia r7,{r1,r2} + ldmia r7!,{r1,r7} + + stmia r8!,{r1,r2} + stmia r7!,{r8} + stmia r7,{r1,r2} + stmia r7!,{r1,r7} + + push {r8,r9} + pop {r8,r9} + + @ Miscellaneous + bkpt #257 + cpsie ai,#5 + cpsid ai,#5 + + @ Conditional suffixes + addeq r0,r1,r2 diff --git a/gas/testsuite/gas/arm/tcompat.d b/gas/testsuite/gas/arm/tcompat.d new file mode 100644 index 0000000..47e9d89 --- /dev/null +++ b/gas/testsuite/gas/arm/tcompat.d @@ -0,0 +1,50 @@ +#name: ARM Thumb-compat pseudos +#objdump: -dr --prefix-addresses --show-raw-insn +#as: + +# Test the ARM pseudo instructions that exist for Thumb source compatibility + +.*: +file format .*arm.* + +Disassembly of section .text: + +0+00 <[^>]*> 91a00000 ? movls r0, r0 +0+04 <[^>]*> e1a09000 ? mov r9, r0 +0+08 <[^>]*> e1a00009 ? mov r0, r9 +0+0c <[^>]*> e1a0c00e ? mov ip, lr +0+10 <[^>]*> 91b09019 ? movlss r9, r9, lsl r0 +0+14 <[^>]*> 91a00910 ? movls r0, r0, lsl r9 +0+18 <[^>]*> e1b00880 ? movs r0, r0, lsl #17 +0+1c <[^>]*> e1a00889 ? mov r0, r9, lsl #17 +0+20 <[^>]*> 91b09039 ? movlss r9, r9, lsr r0 +0+24 <[^>]*> 91a00930 ? movls r0, r0, lsr r9 +0+28 <[^>]*> e1b008a0 ? movs r0, r0, lsr #17 +0+2c <[^>]*> e1a008a9 ? mov r0, r9, lsr #17 +0+30 <[^>]*> 91b09059 ? movlss r9, r9, asr r0 +0+34 <[^>]*> 91a00950 ? movls r0, r0, asr r9 +0+38 <[^>]*> e1b008c0 ? movs r0, r0, asr #17 +0+3c <[^>]*> e1a008c9 ? mov r0, r9, asr #17 +0+40 <[^>]*> 91b09079 ? movlss r9, r9, ror r0 +0+44 <[^>]*> 91a00970 ? movls r0, r0, ror r9 +0+48 <[^>]*> e1b008e0 ? movs r0, r0, ror #17 +0+4c <[^>]*> e1a008e9 ? mov r0, r9, ror #17 +0+50 <[^>]*> e2690000 ? rsb r0, r9, #0 ; 0x0 +0+54 <[^>]*> e2709000 ? rsbs r9, r0, #0 ; 0x0 +0+58 <[^>]*> 92600000 ? rsbls r0, r0, #0 ; 0x0 +0+5c <[^>]*> 92799000 ? rsblss r9, r9, #0 ; 0x0 +0+60 <[^>]*> e92d000e ? stmdb sp!, {r1, r2, r3} +0+64 <[^>]*> 992d8154 ? stmlsdb sp!, {r2, r4, r6, r8, pc} +0+68 <[^>]*> e8bd000e ? ldmia sp!, {r1, r2, r3} +0+6c <[^>]*> 98bd8154 ? ldmlsia sp!, {r2, r4, r6, r8, pc} +0+70 <[^>]*> e0000001 ? and r0, r0, r1 +0+74 <[^>]*> e0200001 ? eor r0, r0, r1 +0+78 <[^>]*> e0400001 ? sub r0, r0, r1 +0+7c <[^>]*> e0600001 ? rsb r0, r0, r1 +0+80 <[^>]*> e0800001 ? add r0, r0, r1 +0+84 <[^>]*> e0a00001 ? adc r0, r0, r1 +0+88 <[^>]*> e0c00001 ? sbc r0, r0, r1 +0+8c <[^>]*> e0e00001 ? rsc r0, r0, r1 +0+90 <[^>]*> e1800001 ? orr r0, r0, r1 +0+94 <[^>]*> e1c00001 ? bic r0, r0, r1 +0+98 <[^>]*> e0000091 ? mul r0, r1, r0 +0+9c <[^>]*> e1a00000 ? nop \(mov r0,r0\) diff --git a/gas/testsuite/gas/arm/tcompat.s b/gas/testsuite/gas/arm/tcompat.s new file mode 100644 index 0000000..c0042e8 --- /dev/null +++ b/gas/testsuite/gas/arm/tcompat.s @@ -0,0 +1,45 @@ + @ ARM instructions defined for source compatibility with Thumb. + .macro shift op opls ops oplss + \oplss r9,r0 + \opls r0,r0,r9 + \ops r0,#17 + \op r0,r9,#17 + .endm + .text + .global l +l: + cpyls r0,r0 + cpy r9,r0 + cpy r0,r9 + cpy ip,lr + + shift lsl lslls lsls lsllss + shift lsr lsrls lsrs lsrlss + shift asr asrls asrs asrlss + shift ror rorls rors rorlss + + neg r0,r9 + negs r9,r0 + negls r0,r0 + neglss r9,r9 + + push {r1,r2,r3} + pushls {r2,r4,r6,r8,pc} + pop {r1,r2,r3} + popls {r2,r4,r6,r8,pc} + + @ Two-argument forms of ARM arithmetic instructions. + and r0,r1 + eor r0,r1 + sub r0,r1 + rsb r0,r1 + + add r0,r1 + adc r0,r1 + sbc r0,r1 + rsc r0,r1 + + orr r0,r1 + bic r0,r1 + mul r0,r1 + nop diff --git a/gas/testsuite/gas/arm/tcompat2.d b/gas/testsuite/gas/arm/tcompat2.d new file mode 100644 index 0000000..ba39db1 --- /dev/null +++ b/gas/testsuite/gas/arm/tcompat2.d @@ -0,0 +1,26 @@ +#name: Thumb ARM-compat pseudos +#objdump: -dr --prefix-addresses --show-raw-insn -M force-thumb +#as: + +# Test the Thumb pseudo instructions that exist for ARM source compatibility + +.*: +file format .*arm.* + +Disassembly of section .text: + +0+00 <[^>]*> 4148 * adcs r0, r1 +0+02 <[^>]*> 4148 * adcs r0, r1 +0+04 <[^>]*> 4008 * ands r0, r1 +0+06 <[^>]*> 4008 * ands r0, r1 +0+08 <[^>]*> 4048 * eors r0, r1 +0+0a <[^>]*> 4048 * eors r0, r1 +0+0c <[^>]*> 4348 * muls r0, r1 +0+0e <[^>]*> 4348 * muls r0, r1 +0+10 <[^>]*> 4308 * orrs r0, r1 +0+12 <[^>]*> 4308 * orrs r0, r1 +0+14 <[^>]*> 4388 * bics r0, r1 +0+16 <[^>]*> 4188 * sbcs r0, r1 +0+18 <[^>]*> 46c0 * nop \(mov r8, r8\) +0+1a <[^>]*> 46c0 * nop \(mov r8, r8\) +0+1c <[^>]*> 46c0 * nop \(mov r8, r8\) +0+1e <[^>]*> 46c0 * nop \(mov r8, r8\) diff --git a/gas/testsuite/gas/arm/tcompat2.s b/gas/testsuite/gas/arm/tcompat2.s new file mode 100644 index 0000000..b034ce2 --- /dev/null +++ b/gas/testsuite/gas/arm/tcompat2.s @@ -0,0 +1,32 @@ + @ Three-argument forms of Thumb arithmetic instructions. + @ Commutative instructions allow either the second or third + @ operand to equal the first. + + .text + .global m + .thumb_func +m: + adc r0,r0,r1 + adc r0,r1,r0 + + and r0,r0,r1 + and r0,r1,r0 + + eor r0,r0,r1 + eor r0,r1,r0 + + mul r0,r0,r1 + mul r0,r1,r0 + + orr r0,r0,r1 + orr r0,r1,r0 + + bic r0,r0,r1 + + sbc r0,r0,r1 + + @ section padding for a.out's sake + nop + nop + nop + nop diff --git a/gas/testsuite/gas/arm/thumb.d b/gas/testsuite/gas/arm/thumb.d new file mode 100644 index 0000000..3561441 --- /dev/null +++ b/gas/testsuite/gas/arm/thumb.d @@ -0,0 +1,189 @@ +# name: Thumb instructions +# as: -mcpu=arm7t +# objdump: -dr --prefix-addresses --show-raw-insn + +.*: +file format .*arm.* + +Disassembly of section \.text: +0+000 <[^>]+> 00ca lsls r2, r1, #3 +0+002 <[^>]+> 0fe3 lsrs r3, r4, #31 +0+004 <[^>]+> 1147 asrs r7, r0, #5 +0+006 <[^>]+> 0011 lsls r1, r2, #0 +0+008 <[^>]+> 0023 lsls r3, r4, #0 +0+00a <[^>]+> 002c lsls r4, r5, #0 +0+00c <[^>]+> 083e lsrs r6, r7, #32 +0+00e <[^>]+> 1008 asrs r0, r1, #32 +0+010 <[^>]+> 18d1 adds r1, r2, r3 +0+012 <[^>]+> 1ca2 adds r2, r4, #2 +0+014 <[^>]+> 1beb sub r3, r5, r7 +0+016 <[^>]+> 1fe2 sub r2, r4, #7 +0+018 <[^>]+> 24ff movs r4, #255 +0+01a <[^>]+> 2bfa cmp r3, #250 +0+01c <[^>]+> 367b adds r6, #123 +0+01e <[^>]+> 3d80 subs r5, #128 +0+020 <[^>]+> 402b ands r3, r5 +0+022 <[^>]+> 4074 eors r4, r6 +0+024 <[^>]+> 4081 lsls r1, r0 +0+026 <[^>]+> 40da lsrs r2, r3 +0+028 <[^>]+> 4134 asrs r4, r6 +0+02a <[^>]+> 417d adcs r5, r7 +0+02c <[^>]+> 41a0 sbcs r0, r4 +0+02e <[^>]+> 41e1 rors r1, r4 +0+030 <[^>]+> 422a tst r2, r5 +0+032 <[^>]+> 4249 negs r1, r1 +0+034 <[^>]+> 429a cmp r2, r3 +0+036 <[^>]+> 42e1 cmn r1, r4 +0+038 <[^>]+> 4318 orrs r0, r3 +0+03a <[^>]+> 436c muls r4, r5 +0+03c <[^>]+> 43bd bics r5, r7 +0+03e <[^>]+> 43ed mvns r5, r5 +0+040 <[^>]+> 4469 add r1, sp +0+042 <[^>]+> 4494 add ip, r2 +0+044 <[^>]+> 44c9 add r9, r9 +0+046 <[^>]+> 4571 cmp r1, lr +0+048 <[^>]+> 4580 cmp r8, r0 +0+04a <[^>]+> 45f4 cmp ip, lr +0+04c <[^>]+> 4648 mov r0, r9 +0+04e <[^>]+> 46a1 mov r9, r4 +0+050 <[^>]+> 46c0 nop \(mov r8, r8\) +0+052 <[^>]+> 4738 bx r7 +0+054 <[^>]+> 4740 bx r8 +0+056 <[^>]+> 0000 lsls r0, r0, #0 +0+058 <[^>]+> 4778 bx pc +0+05a <[^>]+> 4b20 ldr r3, \[pc, #128\] \(0+0dc <[^>]+>\) +0+05c <[^>]+> 4c02 ldr r4, \[pc, #8\] \(0+068 <[^>]+>\) +0+05e <[^>]+> 5088 str r0, \[r1, r2\] +0+060 <[^>]+> 5511 strb r1, \[r2, r4\] +0+062 <[^>]+> 59f5 ldr r5, \[r6, r7\] +0+064 <[^>]+> 5d62 ldrb r2, \[r4, r5\] + \.\.\. +0+068 <[^>]+> 52d1 strh r1, \[r2, r3\] +0+06a <[^>]+> 5a23 ldrh r3, \[r4, r0\] +0+06c <[^>]+> 57f1 ldrsb r1, \[r6, r7\] +0+06e <[^>]+> 5f42 ldrsh r2, \[r0, r5\] +0+070 <[^>]+> 67db str r3, \[r3, #124\] +0+072 <[^>]+> 6fe1 ldr r1, \[r4, #124\] +0+074 <[^>]+> 682d ldr r5, \[r5, #0\] +0+076 <[^>]+> 77e9 strb r1, \[r5, #31\] +0+078 <[^>]+> 7161 strb r1, \[r4, #5\] +0+07a <[^>]+> 7032 strb r2, \[r6, #0\] +0+07c <[^>]+> 87ec strh r4, \[r5, #62\] +0+07e <[^>]+> 8885 ldrh r5, \[r0, #4\] +0+080 <[^>]+> 8813 ldrh r3, \[r2, #0\] +0+082 <[^>]+> 93ff str r3, \[sp, #1020\] +0+084 <[^>]+> 990b ldr r1, \[sp, #44\] +0+086 <[^>]+> 9a00 ldr r2, \[sp, #0\] +0+088 <[^>]+> a7ff add r7, pc, #1020 \(adr r7,0+488 <[^>]+>\) +0+08a <[^>]+> ac80 add r4, sp, #512 +0+08c <[^>]+> b043 add sp, #268 +0+08e <[^>]+> b09a sub sp, #104 +0+090 <[^>]+> b0c3 sub sp, #268 +0+092 <[^>]+> b01b add sp, #108 +0+094 <[^>]+> b417 push {r0, r1, r2, r4} +0+096 <[^>]+> b5f9 push {r0, r3, r4, r5, r6, r7, lr} +0+098 <[^>]+> bc98 pop {r3, r4, r7} +0+09a <[^>]+> bdff pop {r0, r1, r2, r3, r4, r5, r6, r7, pc} +0+09c <[^>]+> c3f3 stmia r3!, {r0, r1, r4, r5, r6, r7} +0+09e <[^>]+> c8fe ldmia r0!, {r1, r2, r3, r4, r5, r6, r7} +0+0a0 <[^>]+> d0e2 beq.n 0+068 <[^>]+> +0+0a2 <[^>]+> d1e1 bne.n 0+068 <[^>]+> +0+0a4 <[^>]+> d2e0 bcs.n 0+068 <[^>]+> +0+0a6 <[^>]+> d3df bcc.n 0+068 <[^>]+> +0+0a8 <[^>]+> d4de bmi.n 0+068 <[^>]+> +0+0aa <[^>]+> d5dd bpl.n 0+068 <[^>]+> +0+0ac <[^>]+> d6dc bvs.n 0+068 <[^>]+> +0+0ae <[^>]+> d7db bvc.n 0+068 <[^>]+> +0+0b0 <[^>]+> d8da bhi.n 0+068 <[^>]+> +0+0b2 <[^>]+> d9d9 bls.n 0+068 <[^>]+> +0+0b4 <[^>]+> dad8 bge.n 0+068 <[^>]+> +0+0b6 <[^>]+> dcd7 bgt.n 0+068 <[^>]+> +0+0b8 <[^>]+> dbd6 blt.n 0+068 <[^>]+> +0+0ba <[^>]+> dcd5 bgt.n 0+068 <[^>]+> +0+0bc <[^>]+> ddd4 ble.n 0+068 <[^>]+> +0+0be <[^>]+> d8d3 bhi.n 0+068 <[^>]+> +0+0c0 <[^>]+> d3d2 bcc.n 0+068 <[^>]+> +0+0c2 <[^>]+> d3d1 bcc.n 0+068 <[^>]+> +0+0c4 <[^>]+> e7d0 b.n 0+068 <[^>]+> +0+0c6 <[^>]+> 00ac lsls r4, r5, #2 +0+0c8 <[^>]+> 1c9a adds r2, r3, #2 +0+0ca <[^>]+> b07f add sp, #508 +0+0cc <[^>]+> b0ff sub sp, #508 +0+0ce <[^>]+> a8ff add r0, sp, #1020 +0+0d0 <[^>]+> a0ff add r0, pc, #1020 \(adr r0,0+4d0 <[^>]+>\) +0+0d2 <[^>]+> b01a add sp, #104 +0+0d4 <[^>]+> b09a sub sp, #104 +0+0d6 <[^>]+> a81a add r0, sp, #104 +0+0d8 <[^>]+> a01a add r0, pc, #104 \(adr r0,0+144 <[^>]+>\) +0+0da <[^>]+> 3168 adds r1, #104 +0+0dc <[^>]+> 2668 movs r6, #104 +0+0de <[^>]+> 2f68 cmp r7, #104 +0+0e0 <[^>]+> 46c0 nop \(mov r8, r8\) +0+0e2 <[^>]+> 46c0 nop \(mov r8, r8\) +0+0e4 <[^>]+> ea000037 b 0+0e4 <[^>]+> + e4: R_ARM_PC24 \.text +0+0e8 <[^>]+> eafffffe b 0+000 <[^>]+> + e8: R_ARM_PC24 \.wombat +0+0ec <[^>]+> eb000037 bl 0+0e4 <[^>]+> + ec: R_ARM_PC24 \.text +0+0f0 <[^>]+> ebfffffe bl 0+000 <[^>]+> + f0: R_ARM_PC24 \.wombat +0+0f4 <[^>]+> e12fff10 bx r0 +0+0f8 <[^>]+> ef123456 swi 0x00123456 +0+0fc <[^>]+> a004 add r0, pc, #16 \(adr r0,0+110 <[^>]+>\) +0+0fe <[^>]+> e77f b.n 0+000 <[^>]+> +0+100 <[^>]+> e7fe b.n 0+000 <[^>]+> + 100: R_ARM_THM_JUMP11 \.wombat +0+102 <[^>]+> f7ff fffe bl 0+000 <[^>]+> + 102: R_ARM_THM_CALL \.text +0+106 <[^>]+> f7ff fffe bl 0+000 <[^>]+> + 106: R_ARM_THM_CALL \.wombat +0+10a <[^>]+> 4700 bx r0 +0+10c <[^>]+> dfff swi 255 + \.\.\. +0+110 <[^>]+> d0fe beq.n 0+000 <[^>]+> + 110: R_ARM_THM_JUMP8 \.wombat +0+112 <[^>]+> d1fe bne.n 0+000 <[^>]+> + 112: R_ARM_THM_JUMP8 \.wombat +0+114 <[^>]+> d2fe bcs.n 0+000 <[^>]+> + 114: R_ARM_THM_JUMP8 \.wombat +0+116 <[^>]+> d3fe bcc.n 0+000 <[^>]+> + 116: R_ARM_THM_JUMP8 \.wombat +0+118 <[^>]+> d4fe bmi.n 0+000 <[^>]+> + 118: R_ARM_THM_JUMP8 \.wombat +0+11a <[^>]+> d5fe bpl.n 0+000 <[^>]+> + 11a: R_ARM_THM_JUMP8 \.wombat +0+11c <[^>]+> d6fe bvs.n 0+000 <[^>]+> + 11c: R_ARM_THM_JUMP8 \.wombat +0+11e <[^>]+> d7fe bvc.n 0+000 <[^>]+> + 11e: R_ARM_THM_JUMP8 \.wombat +0+120 <[^>]+> d8fe bhi.n 0+000 <[^>]+> + 120: R_ARM_THM_JUMP8 \.wombat +0+122 <[^>]+> d9fe bls.n 0+000 <[^>]+> + 122: R_ARM_THM_JUMP8 \.wombat +0+124 <[^>]+> dafe bge.n 0+000 <[^>]+> + 124: R_ARM_THM_JUMP8 \.wombat +0+126 <[^>]+> dcfe bgt.n 0+000 <[^>]+> + 126: R_ARM_THM_JUMP8 \.wombat +0+128 <[^>]+> dbfe blt.n 0+000 <[^>]+> + 128: R_ARM_THM_JUMP8 \.wombat +0+12a <[^>]+> dcfe bgt.n 0+000 <[^>]+> + 12a: R_ARM_THM_JUMP8 \.wombat +0+12c <[^>]+> ddfe ble.n 0+000 <[^>]+> + 12c: R_ARM_THM_JUMP8 \.wombat +0+12e <[^>]+> d8fe bhi.n 0+000 <[^>]+> + 12e: R_ARM_THM_JUMP8 \.wombat +0+130 <[^>]+> d3fe bcc.n 0+000 <[^>]+> + 130: R_ARM_THM_JUMP8 \.wombat +0+132 <[^>]+> d3fe bcc.n 0+000 <[^>]+> + 132: R_ARM_THM_JUMP8 \.wombat +0+134 <[^>]+> f000 fc9a bl 0+938 <[^>]+> + 134: R_ARM_THM_CALL \.text + \.\.\. +0+938 <[^>]+> f000 f898 bl 0+134 <[^>]+> + 938: R_ARM_THM_CALL \.text +0+93c <[^>]+> 4801 ldr r0, \[pc, #4\] \(0+944 <[^>]+>\) +0+93e <[^>]+> 4801 ldr r0, \[pc, #4\] \(0+944 <[^>]+>\) +0+940 <[^>]+> 4801 ldr r0, \[pc, #4\] \(0+948 <[^>]+>\) +0+942 <[^>]+> 4801 ldr r0, \[pc, #4\] \(0+948 <[^>]+>\) +0+944 <[^>]+> 46c0 nop \(mov r8, r8\) +0+946 <[^>]+> 46c0 nop \(mov r8, r8\) diff --git a/gas/testsuite/gas/arm/thumb.s b/gas/testsuite/gas/arm/thumb.s index 422b088..82c1ccd 100644 --- a/gas/testsuite/gas/arm/thumb.s +++ b/gas/testsuite/gas/arm/thumb.s @@ -192,3 +192,11 @@ forwardonly: .space (1 << 11) @ leave space to force long offsets .local: bl .back + + ldr r0, .target + ldr r0, .target + ldr r0, [pc, #4] + ldr r0, [pc, #4] +.target: + nop @ pad for a.out + nop diff --git a/gas/testsuite/gas/arm/thumb32.d b/gas/testsuite/gas/arm/thumb32.d new file mode 100644 index 0000000..3d0fc6d --- /dev/null +++ b/gas/testsuite/gas/arm/thumb32.d @@ -0,0 +1,995 @@ +# name: 32-bit Thumb instructions +# as: -march=armv6kt2 +# objdump: -dr --prefix-addresses --show-raw-insn + +.*: +file format .*arm.* + +Disassembly of section .text: +0+000 <[^>]+> f041 0000 orr\.w r0, r1, #0 ; 0x0 +0+004 <[^>]+> f041 00a5 orr\.w r0, r1, #165 ; 0xa5 +0+008 <[^>]+> f041 10a5 orr\.w r0, r1, #10813605 ; 0xa500a5 +0+00c <[^>]+> f041 20a5 orr\.w r0, r1, #2768282880 ; 0xa500a500 +0+010 <[^>]+> f041 30a5 orr\.w r0, r1, #2779096485 ; 0xa5a5a5a5 +0+014 <[^>]+> f041 4000 orr\.w r0, r1, #2147483648 ; 0x80000000 +0+018 <[^>]+> f041 4080 orr\.w r0, r1, #1073741824 ; 0x40000000 +0+01c <[^>]+> f041 4020 orr\.w r0, r1, #2684354560 ; 0xa0000000 +0+020 <[^>]+> f041 40a0 orr\.w r0, r1, #1342177280 ; 0x50000000 +0+024 <[^>]+> f041 5020 orr\.w r0, r1, #671088640 ; 0x28000000 +0+028 <[^>]+> f041 4014 orr\.w r0, r1, #2483027968 ; 0x94000000 +0+02c <[^>]+> f041 4094 orr\.w r0, r1, #1241513984 ; 0x4a000000 +0+030 <[^>]+> f041 4025 orr\.w r0, r1, #2768240640 ; 0xa5000000 +0+034 <[^>]+> f041 40a5 orr\.w r0, r1, #1384120320 ; 0x52800000 +0+038 <[^>]+> f041 5025 orr\.w r0, r1, #692060160 ; 0x29400000 +0+03c <[^>]+> f041 50a5 orr\.w r0, r1, #346030080 ; 0x14a00000 +0+040 <[^>]+> f041 6025 orr\.w r0, r1, #173015040 ; 0xa500000 +0+044 <[^>]+> f041 60a5 orr\.w r0, r1, #86507520 ; 0x5280000 +0+048 <[^>]+> f041 7025 orr\.w r0, r1, #43253760 ; 0x2940000 +0+04c <[^>]+> f041 70a5 orr\.w r0, r1, #21626880 ; 0x14a0000 +0+050 <[^>]+> f441 0025 orr\.w r0, r1, #10813440 ; 0xa50000 +0+054 <[^>]+> f441 00a5 orr\.w r0, r1, #5406720 ; 0x528000 +0+058 <[^>]+> f441 1025 orr\.w r0, r1, #2703360 ; 0x294000 +0+05c <[^>]+> f441 10a5 orr\.w r0, r1, #1351680 ; 0x14a000 +0+060 <[^>]+> f441 2025 orr\.w r0, r1, #675840 ; 0xa5000 +0+064 <[^>]+> f441 20a5 orr\.w r0, r1, #337920 ; 0x52800 +0+068 <[^>]+> f441 3025 orr\.w r0, r1, #168960 ; 0x29400 +0+06c <[^>]+> f441 30a5 orr\.w r0, r1, #84480 ; 0x14a00 +0+070 <[^>]+> f441 4025 orr\.w r0, r1, #42240 ; 0xa500 +0+074 <[^>]+> f441 40a5 orr\.w r0, r1, #21120 ; 0x5280 +0+078 <[^>]+> f441 5025 orr\.w r0, r1, #10560 ; 0x2940 +0+07c <[^>]+> f441 50a5 orr\.w r0, r1, #5280 ; 0x14a0 +0+080 <[^>]+> f441 6025 orr\.w r0, r1, #2640 ; 0xa50 +0+084 <[^>]+> f441 60a5 orr\.w r0, r1, #1320 ; 0x528 +0+088 <[^>]+> f441 7025 orr\.w r0, r1, #660 ; 0x294 +0+08c <[^>]+> f441 70a5 orr\.w r0, r1, #330 ; 0x14a +0+090 <[^>]+> f110 0000 adds\.w r0, r0, #0 ; 0x0 +0+094 <[^>]+> f110 0500 adds\.w r5, r0, #0 ; 0x0 +0+098 <[^>]+> f115 0000 adds\.w r0, r5, #0 ; 0x0 +0+09c <[^>]+> f110 0005 adds\.w r0, r0, #5 ; 0x5 +0+0a0 <[^>]+> f110 0081 adds\.w r0, r0, #129 ; 0x81 +0+0a4 <[^>]+> f110 0081 adds\.w r0, r0, #129 ; 0x81 +0+0a8 <[^>]+> f110 057e adds\.w r5, r0, #126 ; 0x7e +0+0ac <[^>]+> 1800 adds r0, r0, r0 +0+0ae <[^>]+> 1805 adds r5, r0, r0 +0+0b0 <[^>]+> 1828 adds r0, r5, r0 +0+0b2 <[^>]+> 1940 adds r0, r0, r5 +0+0b4 <[^>]+> 18d1 adds r1, r2, r3 +0+0b6 <[^>]+> 4480 add r8, r0 +0+0b8 <[^>]+> 4440 add r0, r8 +0+0ba <[^>]+> 4440 add r0, r8 +0+0bc <[^>]+> 4440 add r0, r8 +0+0be <[^>]+> eb00 0800 add\.w r8, r0, r0 +0+0c2 <[^>]+> 4401 add r1, r0 +0+0c4 <[^>]+> 4408 add r0, r1 +0+0c6 <[^>]+> f10f 0000 add\.w r0, pc, #0 ; 0x0 +0+0ca <[^>]+> f10f 0500 add\.w r5, pc, #0 ; 0x0 +0+0ce <[^>]+> f50f 7001 add\.w r0, pc, #516 ; 0x204 +0+0d2 <[^>]+> f10d 0000 add\.w r0, sp, #0 ; 0x0 +0+0d6 <[^>]+> f10d 0500 add\.w r5, sp, #0 ; 0x0 +0+0da <[^>]+> f50d 7001 add\.w r0, sp, #516 ; 0x204 +0+0de <[^>]+> f100 0d00 add\.w sp, r0, #0 ; 0x0 +0+0e2 <[^>]+> f10d 0d00 add\.w sp, sp, #0 ; 0x0 +0+0e6 <[^>]+> f500 7d82 add\.w sp, r0, #260 ; 0x104 +0+0ea <[^>]+> f100 0000 add\.w r0, r0, #0 ; 0x0 +0+0ee <[^>]+> f110 0000 adds\.w r0, r0, #0 ; 0x0 +0+0f2 <[^>]+> f100 0900 add\.w r9, r0, #0 ; 0x0 +0+0f6 <[^>]+> f109 0000 add\.w r0, r9, #0 ; 0x0 +0+0fa <[^>]+> f100 0081 add\.w r0, r0, #129 ; 0x81 +0+0fe <[^>]+> eb00 0000 add\.w r0, r0, r0 +0+102 <[^>]+> eb10 0000 adds\.w r0, r0, r0 +0+106 <[^>]+> eb00 0900 add\.w r9, r0, r0 +0+10a <[^>]+> eb09 0000 add\.w r0, r9, r0 +0+10e <[^>]+> eb00 0009 add\.w r0, r0, r9 +0+112 <[^>]+> eb09 080a add\.w r8, r9, sl +0+116 <[^>]+> eb09 484a add\.w r8, r9, sl, lsl #17 +0+11a <[^>]+> eb08 081a add\.w r8, r8, sl, lsr #32 +0+11e <[^>]+> eb08 485a add\.w r8, r8, sl, lsr #17 +0+122 <[^>]+> eb09 082a add\.w r8, r9, sl, asr #32 +0+126 <[^>]+> eb09 486a add\.w r8, r9, sl, asr #17 +0+12a <[^>]+> eb09 083a add\.w r8, r9, sl, rrx +0+12e <[^>]+> eb09 487a add\.w r8, r9, sl, ror #17 +0+132 <[^>]+> f1b0 0000 subs\.w r0, r0, #0 ; 0x0 +0+136 <[^>]+> f1b0 0500 subs\.w r5, r0, #0 ; 0x0 +0+13a <[^>]+> f1b5 0000 subs\.w r0, r5, #0 ; 0x0 +0+13e <[^>]+> f1b0 0005 subs\.w r0, r0, #5 ; 0x5 +0+142 <[^>]+> f1b0 0081 subs\.w r0, r0, #129 ; 0x81 +0+146 <[^>]+> f1b0 0508 subs\.w r5, r0, #8 ; 0x8 +0+14a <[^>]+> 1a00 sub r0, r0, r0 +0+14c <[^>]+> 1a05 sub r5, r0, r0 +0+14e <[^>]+> 1a28 sub r0, r5, r0 +0+150 <[^>]+> 1b40 sub r0, r0, r5 +0+152 <[^>]+> f5a0 7d82 sub\.w sp, r0, #260 ; 0x104 +0+156 <[^>]+> f5ad 7d82 sub\.w sp, sp, #260 ; 0x104 +0+15a <[^>]+> ebb8 0800 subs\.w r8, r8, r0 +0+15e <[^>]+> ebb0 0008 subs\.w r0, r0, r8 +0+162 <[^>]+> f5b0 7082 subs\.w r0, r0, #260 ; 0x104 +0+166 <[^>]+> 4140 adcs r0, r0 +0+168 <[^>]+> 4145 adcs r5, r0 +0+16a <[^>]+> 4168 adcs r0, r5 +0+16c <[^>]+> 4168 adcs r0, r5 +0+16e <[^>]+> 4168 adcs r0, r5 +0+170 <[^>]+> eb45 0000 adc\.w r0, r5, r0 +0+174 <[^>]+> eb41 0002 adc\.w r0, r1, r2 +0+178 <[^>]+> eb40 0900 adc\.w r9, r0, r0 +0+17c <[^>]+> eb49 0000 adc\.w r0, r9, r0 +0+180 <[^>]+> eb40 0009 adc\.w r0, r0, r9 +0+184 <[^>]+> eb50 0000 adcs\.w r0, r0, r0 +0+188 <[^>]+> eb41 4062 adc\.w r0, r1, r2, asr #17 +0+18c <[^>]+> f141 0081 adc\.w r0, r1, #129 ; 0x81 +0+190 <[^>]+> 4000 ands r0, r0 +0+192 <[^>]+> 4005 ands r5, r0 +0+194 <[^>]+> 4028 ands r0, r5 +0+196 <[^>]+> 4028 ands r0, r5 +0+198 <[^>]+> 4028 ands r0, r5 +0+19a <[^>]+> ea05 0000 and\.w r0, r5, r0 +0+19e <[^>]+> ea01 0002 and\.w r0, r1, r2 +0+1a2 <[^>]+> ea00 0900 and\.w r9, r0, r0 +0+1a6 <[^>]+> ea09 0000 and\.w r0, r9, r0 +0+1aa <[^>]+> ea00 0009 and\.w r0, r0, r9 +0+1ae <[^>]+> ea10 0000 ands\.w r0, r0, r0 +0+1b2 <[^>]+> ea01 4062 and\.w r0, r1, r2, asr #17 +0+1b6 <[^>]+> f001 0081 and\.w r0, r1, #129 ; 0x81 +0+1ba <[^>]+> 4380 bics r0, r0 +0+1bc <[^>]+> 4385 bics r5, r0 +0+1be <[^>]+> 43a8 bics r0, r5 +0+1c0 <[^>]+> 43a8 bics r0, r5 +0+1c2 <[^>]+> ea35 0000 bics\.w r0, r5, r0 +0+1c6 <[^>]+> ea25 0000 bic\.w r0, r5, r0 +0+1ca <[^>]+> ea21 0002 bic\.w r0, r1, r2 +0+1ce <[^>]+> ea20 0900 bic\.w r9, r0, r0 +0+1d2 <[^>]+> ea29 0000 bic\.w r0, r9, r0 +0+1d6 <[^>]+> ea20 0009 bic\.w r0, r0, r9 +0+1da <[^>]+> ea30 0000 bics\.w r0, r0, r0 +0+1de <[^>]+> ea21 4062 bic\.w r0, r1, r2, asr #17 +0+1e2 <[^>]+> f021 0081 bic\.w r0, r1, #129 ; 0x81 +0+1e6 <[^>]+> 4040 eors r0, r0 +0+1e8 <[^>]+> 4045 eors r5, r0 +0+1ea <[^>]+> 4068 eors r0, r5 +0+1ec <[^>]+> 4068 eors r0, r5 +0+1ee <[^>]+> 4068 eors r0, r5 +0+1f0 <[^>]+> ea85 0000 eor\.w r0, r5, r0 +0+1f4 <[^>]+> ea81 0002 eor\.w r0, r1, r2 +0+1f8 <[^>]+> ea80 0900 eor\.w r9, r0, r0 +0+1fc <[^>]+> ea89 0000 eor\.w r0, r9, r0 +0+200 <[^>]+> ea80 0009 eor\.w r0, r0, r9 +0+204 <[^>]+> ea90 0000 eors\.w r0, r0, r0 +0+208 <[^>]+> ea81 4062 eor\.w r0, r1, r2, asr #17 +0+20c <[^>]+> f081 0081 eor\.w r0, r1, #129 ; 0x81 +0+210 <[^>]+> 4300 orrs r0, r0 +0+212 <[^>]+> 4305 orrs r5, r0 +0+214 <[^>]+> 4328 orrs r0, r5 +0+216 <[^>]+> 4328 orrs r0, r5 +0+218 <[^>]+> 4328 orrs r0, r5 +0+21a <[^>]+> ea45 0000 orr\.w r0, r5, r0 +0+21e <[^>]+> ea41 0002 orr\.w r0, r1, r2 +0+222 <[^>]+> ea40 0900 orr\.w r9, r0, r0 +0+226 <[^>]+> ea49 0000 orr\.w r0, r9, r0 +0+22a <[^>]+> ea40 0009 orr\.w r0, r0, r9 +0+22e <[^>]+> ea50 0000 orrs\.w r0, r0, r0 +0+232 <[^>]+> ea41 4062 orr\.w r0, r1, r2, asr #17 +0+236 <[^>]+> f041 0081 orr\.w r0, r1, #129 ; 0x81 +0+23a <[^>]+> ebd0 0000 rsbs r0, r0, r0 +0+23e <[^>]+> ebd5 0500 rsbs r5, r5, r0 +0+242 <[^>]+> ebd0 0005 rsbs r0, r0, r5 +0+246 <[^>]+> ebd0 0005 rsbs r0, r0, r5 +0+24a <[^>]+> ebd5 0000 rsbs r0, r5, r0 +0+24e <[^>]+> ebc5 0000 rsb r0, r5, r0 +0+252 <[^>]+> ebc1 0002 rsb r0, r1, r2 +0+256 <[^>]+> ebc0 0900 rsb r9, r0, r0 +0+25a <[^>]+> ebc9 0000 rsb r0, r9, r0 +0+25e <[^>]+> ebc0 0009 rsb r0, r0, r9 +0+262 <[^>]+> ebd0 0000 rsbs r0, r0, r0 +0+266 <[^>]+> ebc1 4062 rsb r0, r1, r2, asr #17 +0+26a <[^>]+> f1c1 0081 rsb r0, r1, #129 ; 0x81 +0+26e <[^>]+> 4180 sbcs r0, r0 +0+270 <[^>]+> 4185 sbcs r5, r0 +0+272 <[^>]+> 41a8 sbcs r0, r5 +0+274 <[^>]+> 41a8 sbcs r0, r5 +0+276 <[^>]+> eb75 0000 sbcs\.w r0, r5, r0 +0+27a <[^>]+> eb65 0000 sbc\.w r0, r5, r0 +0+27e <[^>]+> eb61 0002 sbc\.w r0, r1, r2 +0+282 <[^>]+> eb60 0900 sbc\.w r9, r0, r0 +0+286 <[^>]+> eb69 0000 sbc\.w r0, r9, r0 +0+28a <[^>]+> eb60 0009 sbc\.w r0, r0, r9 +0+28e <[^>]+> eb70 0000 sbcs\.w r0, r0, r0 +0+292 <[^>]+> eb61 4062 sbc\.w r0, r1, r2, asr #17 +0+296 <[^>]+> f161 0081 sbc\.w r0, r1, #129 ; 0x81 +0+29a <[^>]+> f36f 0000 bfc r0, #0, #1 +0+29e <[^>]+> f36f 0900 bfc r9, #0, #1 +0+2a2 <[^>]+> f36f 0900 bfc r9, #0, #1 +0+2a6 <[^>]+> f36f 5055 bfc r0, #21, #1 +0+2aa <[^>]+> f36f 0011 bfc r0, #0, #18 +0+2ae <[^>]+> f360 0000 bfi r0, r0, #0, #1 +0+2b2 <[^>]+> f360 0900 bfi r9, r0, #0, #1 +0+2b6 <[^>]+> f369 0000 bfi r0, r9, #0, #1 +0+2ba <[^>]+> f360 5055 bfi r0, r0, #21, #1 +0+2be <[^>]+> f360 0011 bfi r0, r0, #0, #18 +0+2c2 <[^>]+> f340 0000 sbfx r0, r0, #0, #1 +0+2c6 <[^>]+> f3c0 0900 ubfx r9, r0, #0, #1 +0+2ca <[^>]+> f349 0000 sbfx r0, r9, #0, #1 +0+2ce <[^>]+> f3c0 5040 ubfx r0, r0, #21, #1 +0+2d2 <[^>]+> f340 0011 sbfx r0, r0, #0, #18 +0+2d6 <[^>]+> d0fe beq\.n 0+2d6 <[^>]+> +0+2d8 <[^>]+> d02a beq\.n 0+330 <[^>]+> +0+2da <[^>]+> d1fc bne\.n 0+2d6 <[^>]+> +0+2dc <[^>]+> d128 bne\.n 0+330 <[^>]+> +0+2de <[^>]+> d2fa bcs\.n 0+2d6 <[^>]+> +0+2e0 <[^>]+> d226 bcs\.n 0+330 <[^>]+> +0+2e2 <[^>]+> d2f8 bcs\.n 0+2d6 <[^>]+> +0+2e4 <[^>]+> d224 bcs\.n 0+330 <[^>]+> +0+2e6 <[^>]+> d3f6 bcc\.n 0+2d6 <[^>]+> +0+2e8 <[^>]+> d322 bcc\.n 0+330 <[^>]+> +0+2ea <[^>]+> d3f4 bcc\.n 0+2d6 <[^>]+> +0+2ec <[^>]+> d320 bcc\.n 0+330 <[^>]+> +0+2ee <[^>]+> d3f2 bcc\.n 0+2d6 <[^>]+> +0+2f0 <[^>]+> d31e bcc\.n 0+330 <[^>]+> +0+2f2 <[^>]+> d4f0 bmi\.n 0+2d6 <[^>]+> +0+2f4 <[^>]+> d41c bmi\.n 0+330 <[^>]+> +0+2f6 <[^>]+> d5ee bpl\.n 0+2d6 <[^>]+> +0+2f8 <[^>]+> d51a bpl\.n 0+330 <[^>]+> +0+2fa <[^>]+> d6ec bvs\.n 0+2d6 <[^>]+> +0+2fc <[^>]+> d618 bvs\.n 0+330 <[^>]+> +0+2fe <[^>]+> d7ea bvc\.n 0+2d6 <[^>]+> +0+300 <[^>]+> d716 bvc\.n 0+330 <[^>]+> +0+302 <[^>]+> d8e8 bhi\.n 0+2d6 <[^>]+> +0+304 <[^>]+> d814 bhi\.n 0+330 <[^>]+> +0+306 <[^>]+> d9e6 bls\.n 0+2d6 <[^>]+> +0+308 <[^>]+> d912 bls\.n 0+330 <[^>]+> +0+30a <[^>]+> d7e4 bvc\.n 0+2d6 <[^>]+> +0+30c <[^>]+> d710 bvc\.n 0+330 <[^>]+> +0+30e <[^>]+> d8e2 bhi\.n 0+2d6 <[^>]+> +0+310 <[^>]+> d80e bhi\.n 0+330 <[^>]+> +0+312 <[^>]+> d9e0 bls\.n 0+2d6 <[^>]+> +0+314 <[^>]+> d90c bls\.n 0+330 <[^>]+> +0+316 <[^>]+> dade bge\.n 0+2d6 <[^>]+> +0+318 <[^>]+> da0a bge\.n 0+330 <[^>]+> +0+31a <[^>]+> dbdc blt\.n 0+2d6 <[^>]+> +0+31c <[^>]+> db08 blt\.n 0+330 <[^>]+> +0+31e <[^>]+> dcda bgt\.n 0+2d6 <[^>]+> +0+320 <[^>]+> dc06 bgt\.n 0+330 <[^>]+> +0+322 <[^>]+> ddd8 ble\.n 0+2d6 <[^>]+> +0+324 <[^>]+> dd04 ble\.n 0+330 <[^>]+> +0+326 <[^>]+> e7d6 b\.n 0+2d6 <[^>]+> +0+328 <[^>]+> e002 b\.n 0+330 <[^>]+> +0+32a <[^>]+> e7d4 b\.n 0+2d6 <[^>]+> +0+32c <[^>]+> e000 b\.n 0+330 <[^>]+> +0+32e <[^>]+> 46c0 nop \(mov r8, r8\) +0+330 <[^>]+> f43f affe beq\.w 0+330 <[^>]+> +0+334 <[^>]+> f000 8058 beq\.w 0+3e8 <[^>]+> +0+338 <[^>]+> f47f affa bne\.w 0+330 <[^>]+> +0+33c <[^>]+> f040 8054 bne\.w 0+3e8 <[^>]+> +0+340 <[^>]+> f4bf aff6 bcs\.w 0+330 <[^>]+> +0+344 <[^>]+> f080 8050 bcs\.w 0+3e8 <[^>]+> +0+348 <[^>]+> f4bf aff2 bcs\.w 0+330 <[^>]+> +0+34c <[^>]+> f080 804c bcs\.w 0+3e8 <[^>]+> +0+350 <[^>]+> f4ff afee bcc\.w 0+330 <[^>]+> +0+354 <[^>]+> f0c0 8048 bcc\.w 0+3e8 <[^>]+> +0+358 <[^>]+> f4ff afea bcc\.w 0+330 <[^>]+> +0+35c <[^>]+> f0c0 8044 bcc\.w 0+3e8 <[^>]+> +0+360 <[^>]+> f4ff afe6 bcc\.w 0+330 <[^>]+> +0+364 <[^>]+> f0c0 8040 bcc\.w 0+3e8 <[^>]+> +0+368 <[^>]+> f53f afe2 bmi\.w 0+330 <[^>]+> +0+36c <[^>]+> f100 803c bmi\.w 0+3e8 <[^>]+> +0+370 <[^>]+> f57f afde bpl\.w 0+330 <[^>]+> +0+374 <[^>]+> f140 8038 bpl\.w 0+3e8 <[^>]+> +0+378 <[^>]+> f5bf afda bvs\.w 0+330 <[^>]+> +0+37c <[^>]+> f180 8034 bvs\.w 0+3e8 <[^>]+> +0+380 <[^>]+> f5ff afd6 bvc\.w 0+330 <[^>]+> +0+384 <[^>]+> f1c0 8030 bvc\.w 0+3e8 <[^>]+> +0+388 <[^>]+> f63f afd2 bhi\.w 0+330 <[^>]+> +0+38c <[^>]+> f200 802c bhi\.w 0+3e8 <[^>]+> +0+390 <[^>]+> f67f afce bls\.w 0+330 <[^>]+> +0+394 <[^>]+> f240 8028 bls\.w 0+3e8 <[^>]+> +0+398 <[^>]+> f5ff afca bvc\.w 0+330 <[^>]+> +0+39c <[^>]+> f1c0 8024 bvc\.w 0+3e8 <[^>]+> +0+3a0 <[^>]+> f63f afc6 bhi\.w 0+330 <[^>]+> +0+3a4 <[^>]+> f200 8020 bhi\.w 0+3e8 <[^>]+> +0+3a8 <[^>]+> f67f afc2 bls\.w 0+330 <[^>]+> +0+3ac <[^>]+> f240 801c bls\.w 0+3e8 <[^>]+> +0+3b0 <[^>]+> f6bf afbe bge\.w 0+330 <[^>]+> +0+3b4 <[^>]+> f280 8018 bge\.w 0+3e8 <[^>]+> +0+3b8 <[^>]+> f6ff afba blt\.w 0+330 <[^>]+> +0+3bc <[^>]+> f2c0 8014 blt\.w 0+3e8 <[^>]+> +0+3c0 <[^>]+> f73f afb6 bgt\.w 0+330 <[^>]+> +0+3c4 <[^>]+> f300 8010 bgt\.w 0+3e8 <[^>]+> +0+3c8 <[^>]+> f77f afb2 ble\.w 0+330 <[^>]+> +0+3cc <[^>]+> f340 800c ble\.w 0+3e8 <[^>]+> +0+3d0 <[^>]+> f7ff bfae b\.w 0+330 <[^>]+> +0+3d4 <[^>]+> f000 b808 b\.w 0+3e8 <[^>]+> +0+3d8 <[^>]+> f000 f996 bl 0+330 <[^>]+> + 3d8: R_ARM_THM_CALL \.text +0+3dc <[^>]+> f000 f9f2 bl 0+3e8 <[^>]+> + 3dc: R_ARM_THM_CALL \.text +0+3e0 <[^>]+> f000 e996 blx 0+330 <[^>]+> + 3e0: R_ARM_THM_XPC22 \.text +0+3e4 <[^>]+> f000 e9f2 blx 0+3e8 <[^>]+> + 3e4: R_ARM_THM_XPC22 \.text +0+3e8 <[^>]+> 4748 bx r9 +0+3ea <[^>]+> 4780 blx r0 +0+3ec <[^>]+> 47c8 blx r9 +0+3ee <[^>]+> f3c0 8f00 bxj r0 +0+3f2 <[^>]+> f3c9 8f00 bxj r9 +0+3f6 <[^>]+> fab0 f080 clz r0, r0 +0+3fa <[^>]+> fab0 f980 clz r9, r0 +0+3fe <[^>]+> fab9 f089 clz r0, r9 +0+402 <[^>]+> b661 cpsie f +0+404 <[^>]+> b672 cpsid i +0+406 <[^>]+> b664 cpsie a +0+408 <[^>]+> f3af 8620 cpsid\.w f +0+40c <[^>]+> f3af 8440 cpsie\.w i +0+410 <[^>]+> f3af 8680 cpsid\.w a +0+414 <[^>]+> f3af 8540 cpsie i, #0 +0+418 <[^>]+> f3af 8751 cpsid i, #17 +0+41c <[^>]+> f3af 8100 cps #0 +0+420 <[^>]+> f3af 8111 cps #17 +0+424 <[^>]+> 4600 mov r0, r0 +0+426 <[^>]+> 4681 mov r9, r0 +0+428 <[^>]+> 4648 mov r0, r9 +0+42a <[^>]+> ea4f 0000 mov\.w r0, r0 +0+42e <[^>]+> ea4f 0900 mov\.w r9, r0 +0+432 <[^>]+> ea4f 0009 mov\.w r0, r9 +0+436 <[^>]+> b910 cbnz r0, 0+43e <[^>]+> +0+438 <[^>]+> b105 cbz r5, 0+43c <[^>]+> +0+43a <[^>]+> bf00 nop +0+43c <[^>]+> bf10 yield +0+43e <[^>]+> bf20 wfe +0+440 <[^>]+> bf30 wfi +0+442 <[^>]+> bf40 sev +0+444 <[^>]+> f3af 8000 nop\.w +0+448 <[^>]+> f3af 8001 yield\.w +0+44c <[^>]+> f3af 8002 wfe\.w +0+450 <[^>]+> f3af 8003 wfi\.w +0+454 <[^>]+> f3af 9004 sev\.w +0+458 <[^>]+> bf90 nop \{9\} +0+45a <[^>]+> f3af 8081 nop\.w \{129\} +0+45e <[^>]+> bf08 it eq +0+460 <[^>]+> bf00 nop +0+462 <[^>]+> bf18 it ne +0+464 <[^>]+> bf00 nop +0+466 <[^>]+> bf28 it cs +0+468 <[^>]+> bf00 nop +0+46a <[^>]+> bf28 it cs +0+46c <[^>]+> bf00 nop +0+46e <[^>]+> bf38 it cc +0+470 <[^>]+> bf00 nop +0+472 <[^>]+> bf38 it cc +0+474 <[^>]+> bf00 nop +0+476 <[^>]+> bf38 it cc +0+478 <[^>]+> bf00 nop +0+47a <[^>]+> bf48 it mi +0+47c <[^>]+> bf00 nop +0+47e <[^>]+> bf58 it pl +0+480 <[^>]+> bf00 nop +0+482 <[^>]+> bf68 it vs +0+484 <[^>]+> bf00 nop +0+486 <[^>]+> bf78 it vc +0+488 <[^>]+> bf00 nop +0+48a <[^>]+> bf88 it hi +0+48c <[^>]+> bf00 nop +0+48e <[^>]+> bfa8 it ge +0+490 <[^>]+> bf00 nop +0+492 <[^>]+> bfb8 it lt +0+494 <[^>]+> bf00 nop +0+496 <[^>]+> bfc8 it gt +0+498 <[^>]+> bf00 nop +0+49a <[^>]+> bfd8 it le +0+49c <[^>]+> bf00 nop +0+49e <[^>]+> bfe8 it al +0+4a0 <[^>]+> bf00 nop +0+4a2 <[^>]+> bf04 itt eq +0+4a4 <[^>]+> bf00 nop +0+4a6 <[^>]+> bf00 nop +0+4a8 <[^>]+> bf0c ite eq +0+4aa <[^>]+> bf00 nop +0+4ac <[^>]+> bf00 nop +0+4ae <[^>]+> bf02 ittt eq +0+4b0 <[^>]+> bf00 nop +0+4b2 <[^>]+> bf00 nop +0+4b4 <[^>]+> bf00 nop +0+4b6 <[^>]+> bf0a itet eq +0+4b8 <[^>]+> bf00 nop +0+4ba <[^>]+> bf00 nop +0+4bc <[^>]+> bf00 nop +0+4be <[^>]+> bf06 itte eq +0+4c0 <[^>]+> bf00 nop +0+4c2 <[^>]+> bf00 nop +0+4c4 <[^>]+> bf00 nop +0+4c6 <[^>]+> bf0e itee eq +0+4c8 <[^>]+> bf00 nop +0+4ca <[^>]+> bf00 nop +0+4cc <[^>]+> bf00 nop +0+4ce <[^>]+> bf01 itttt eq +0+4d0 <[^>]+> bf00 nop +0+4d2 <[^>]+> bf00 nop +0+4d4 <[^>]+> bf00 nop +0+4d6 <[^>]+> bf00 nop +0+4d8 <[^>]+> bf09 itett eq +0+4da <[^>]+> bf00 nop +0+4dc <[^>]+> bf00 nop +0+4de <[^>]+> bf00 nop +0+4e0 <[^>]+> bf00 nop +0+4e2 <[^>]+> bf05 ittet eq +0+4e4 <[^>]+> bf00 nop +0+4e6 <[^>]+> bf00 nop +0+4e8 <[^>]+> bf00 nop +0+4ea <[^>]+> bf00 nop +0+4ec <[^>]+> bf03 ittte eq +0+4ee <[^>]+> bf00 nop +0+4f0 <[^>]+> bf00 nop +0+4f2 <[^>]+> bf00 nop +0+4f4 <[^>]+> bf00 nop +0+4f6 <[^>]+> bf07 ittee eq +0+4f8 <[^>]+> bf00 nop +0+4fa <[^>]+> bf00 nop +0+4fc <[^>]+> bf00 nop +0+4fe <[^>]+> bf00 nop +0+500 <[^>]+> bf0b itete eq +0+502 <[^>]+> bf00 nop +0+504 <[^>]+> bf00 nop +0+506 <[^>]+> bf00 nop +0+508 <[^>]+> bf00 nop +0+50a <[^>]+> bf0d iteet eq +0+50c <[^>]+> bf00 nop +0+50e <[^>]+> bf00 nop +0+510 <[^>]+> bf00 nop +0+512 <[^>]+> bf00 nop +0+514 <[^>]+> bf0f iteee eq +0+516 <[^>]+> bf00 nop +0+518 <[^>]+> bf00 nop +0+51a <[^>]+> bf00 nop +0+51c <[^>]+> bf00 nop +0+51e <[^>]+> bf1c itt ne +0+520 <[^>]+> bf00 nop +0+522 <[^>]+> bf00 nop +0+524 <[^>]+> bf14 ite ne +0+526 <[^>]+> bf00 nop +0+528 <[^>]+> bf00 nop +0+52a <[^>]+> bf1e ittt ne +0+52c <[^>]+> bf00 nop +0+52e <[^>]+> bf00 nop +0+530 <[^>]+> bf00 nop +0+532 <[^>]+> bf16 itet ne +0+534 <[^>]+> bf00 nop +0+536 <[^>]+> bf00 nop +0+538 <[^>]+> bf00 nop +0+53a <[^>]+> bf1a itte ne +0+53c <[^>]+> bf00 nop +0+53e <[^>]+> bf00 nop +0+540 <[^>]+> bf00 nop +0+542 <[^>]+> bf12 itee ne +0+544 <[^>]+> bf00 nop +0+546 <[^>]+> bf00 nop +0+548 <[^>]+> bf00 nop +0+54a <[^>]+> bf1f itttt ne +0+54c <[^>]+> bf00 nop +0+54e <[^>]+> bf00 nop +0+550 <[^>]+> bf00 nop +0+552 <[^>]+> bf00 nop +0+554 <[^>]+> bf17 itett ne +0+556 <[^>]+> bf00 nop +0+558 <[^>]+> bf00 nop +0+55a <[^>]+> bf00 nop +0+55c <[^>]+> bf00 nop +0+55e <[^>]+> bf1b ittet ne +0+560 <[^>]+> bf00 nop +0+562 <[^>]+> bf00 nop +0+564 <[^>]+> bf00 nop +0+566 <[^>]+> bf00 nop +0+568 <[^>]+> bf1d ittte ne +0+56a <[^>]+> bf00 nop +0+56c <[^>]+> bf00 nop +0+56e <[^>]+> bf00 nop +0+570 <[^>]+> bf00 nop +0+572 <[^>]+> bf19 ittee ne +0+574 <[^>]+> bf00 nop +0+576 <[^>]+> bf00 nop +0+578 <[^>]+> bf00 nop +0+57a <[^>]+> bf00 nop +0+57c <[^>]+> bf15 itete ne +0+57e <[^>]+> bf00 nop +0+580 <[^>]+> bf00 nop +0+582 <[^>]+> bf00 nop +0+584 <[^>]+> bf00 nop +0+586 <[^>]+> bf13 iteet ne +0+588 <[^>]+> bf00 nop +0+58a <[^>]+> bf00 nop +0+58c <[^>]+> bf00 nop +0+58e <[^>]+> bf00 nop +0+590 <[^>]+> bf11 iteee ne +0+592 <[^>]+> bf00 nop +0+594 <[^>]+> bf00 nop +0+596 <[^>]+> bf00 nop +0+598 <[^>]+> bf00 nop +0+59a <[^>]+> f895 1000 ldrb\.w r1, \[r5\] +0+59e <[^>]+> f895 1330 ldrb\.w r1, \[r5, #816\] +0+5a2 <[^>]+> f815 1c30 ldrb\.w r1, \[r5, #-48\] +0+5a6 <[^>]+> f815 1b30 ldrb\.w r1, \[r5, #48\]! +0+5aa <[^>]+> f815 1930 ldrb\.w r1, \[r5, #-48\]! +0+5ae <[^>]+> f815 1f30 ldrb\.w r1, \[r5\], #48 +0+5b2 <[^>]+> f815 1d30 ldrb\.w r1, \[r5\], #-48 +0+5b6 <[^>]+> 5d29 ldrb r1, \[r5, r4\] +0+5b8 <[^>]+> f819 100c ldrb\.w r1, \[r9, ip\] +0+5bc <[^>]+> f89f 10ac ldrb\.w r1, \[pc, #172\] ; 0+66c <[^>]+> +0+5c0 <[^>]+> f81f 102a ldrb\.w r1, \[pc, #-42\] ; 0+59a <[^>]+> +0+5c4 <[^>]+> f995 1000 ldrsb\.w r1, \[r5\] +0+5c8 <[^>]+> f995 1330 ldrsb\.w r1, \[r5, #816\] +0+5cc <[^>]+> f915 1c30 ldrsb\.w r1, \[r5, #-48\] +0+5d0 <[^>]+> f915 1b30 ldrsb\.w r1, \[r5, #48\]! +0+5d4 <[^>]+> f915 1930 ldrsb\.w r1, \[r5, #-48\]! +0+5d8 <[^>]+> f915 1f30 ldrsb\.w r1, \[r5\], #48 +0+5dc <[^>]+> f915 1d30 ldrsb\.w r1, \[r5\], #-48 +0+5e0 <[^>]+> 5729 ldrsb r1, \[r5, r4\] +0+5e2 <[^>]+> f919 100c ldrsb\.w r1, \[r9, ip\] +0+5e6 <[^>]+> f99f 1084 ldrsb\.w r1, \[pc, #132\] ; 0+66c <[^>]+> +0+5ea <[^>]+> f91f 1052 ldrsb\.w r1, \[pc, #-82\] ; 0+59a <[^>]+> +0+5ee <[^>]+> f8b5 1000 ldrh\.w r1, \[r5\] +0+5f2 <[^>]+> f8b5 1330 ldrh\.w r1, \[r5, #816\] +0+5f6 <[^>]+> f835 1c30 ldrh\.w r1, \[r5, #-48\] +0+5fa <[^>]+> f835 1b30 ldrh\.w r1, \[r5, #48\]! +0+5fe <[^>]+> f835 1930 ldrh\.w r1, \[r5, #-48\]! +0+602 <[^>]+> f835 1f30 ldrh\.w r1, \[r5\], #48 +0+606 <[^>]+> f835 1d30 ldrh\.w r1, \[r5\], #-48 +0+60a <[^>]+> 5b29 ldrh r1, \[r5, r4\] +0+60c <[^>]+> f839 100c ldrh\.w r1, \[r9, ip\] +0+610 <[^>]+> f8bf 1058 ldrh\.w r1, \[pc, #88\] ; 0+66c <[^>]+> +0+614 <[^>]+> f83f 107e ldrh\.w r1, \[pc, #-126\] ; 0+59a <[^>]+> +0+618 <[^>]+> f9b5 1000 ldrsh\.w r1, \[r5\] +0+61c <[^>]+> f9b5 1330 ldrsh\.w r1, \[r5, #816\] +0+620 <[^>]+> f935 1c30 ldrsh\.w r1, \[r5, #-48\] +0+624 <[^>]+> f935 1b30 ldrsh\.w r1, \[r5, #48\]! +0+628 <[^>]+> f935 1930 ldrsh\.w r1, \[r5, #-48\]! +0+62c <[^>]+> f935 1f30 ldrsh\.w r1, \[r5\], #48 +0+630 <[^>]+> f935 1d30 ldrsh\.w r1, \[r5\], #-48 +0+634 <[^>]+> 5f29 ldrsh r1, \[r5, r4\] +0+636 <[^>]+> f939 100c ldrsh\.w r1, \[r9, ip\] +0+63a <[^>]+> f9bf 1030 ldrsh\.w r1, \[pc, #48\] ; 0+66c <[^>]+> +0+63e <[^>]+> f93f 10a6 ldrsh\.w r1, \[pc, #-166\] ; 0+59a <[^>]+> +0+642 <[^>]+> f8d5 1000 ldr\.w r1, \[r5\] +0+646 <[^>]+> f8d5 1330 ldr\.w r1, \[r5, #816\] +0+64a <[^>]+> f855 1c30 ldr\.w r1, \[r5, #-48\] +0+64e <[^>]+> f855 1b30 ldr\.w r1, \[r5, #48\]! +0+652 <[^>]+> f855 1930 ldr\.w r1, \[r5, #-48\]! +0+656 <[^>]+> f855 1f30 ldr\.w r1, \[r5\], #48 +0+65a <[^>]+> f855 1d30 ldr\.w r1, \[r5\], #-48 +0+65e <[^>]+> 5929 ldr r1, \[r5, r4\] +0+660 <[^>]+> f859 100c ldr\.w r1, \[r9, ip\] +0+664 <[^>]+> f8df 1004 ldr\.w r1, \[pc, #4\] ; 0+66c <[^>]+> +0+668 <[^>]+> f85f 10d2 ldr\.w r1, \[pc, #-210\] ; 0+59a <[^>]+> +0+66c <[^>]+> f885 1000 strb\.w r1, \[r5\] +0+670 <[^>]+> f885 1330 strb\.w r1, \[r5, #816\] +0+674 <[^>]+> f805 1c30 strb\.w r1, \[r5, #-48\] +0+678 <[^>]+> f805 1b30 strb\.w r1, \[r5, #48\]! +0+67c <[^>]+> f805 1930 strb\.w r1, \[r5, #-48\]! +0+680 <[^>]+> f805 1f30 strb\.w r1, \[r5\], #48 +0+684 <[^>]+> f805 1d30 strb\.w r1, \[r5\], #-48 +0+688 <[^>]+> 5529 strb r1, \[r5, r4\] +0+68a <[^>]+> f809 100c strb\.w r1, \[r9, ip\] +0+68e <[^>]+> f88f 1086 strb\.w r1, \[pc, #134\] ; 0+716 <[^>]+> +0+692 <[^>]+> f80f 1028 strb\.w r1, \[pc, #-40\] ; 0+66c <[^>]+> +0+696 <[^>]+> f8a5 1000 strh\.w r1, \[r5\] +0+69a <[^>]+> f8a5 1330 strh\.w r1, \[r5, #816\] +0+69e <[^>]+> f825 1c30 strh\.w r1, \[r5, #-48\] +0+6a2 <[^>]+> f825 1b30 strh\.w r1, \[r5, #48\]! +0+6a6 <[^>]+> f825 1930 strh\.w r1, \[r5, #-48\]! +0+6aa <[^>]+> f825 1f30 strh\.w r1, \[r5\], #48 +0+6ae <[^>]+> f825 1d30 strh\.w r1, \[r5\], #-48 +0+6b2 <[^>]+> 5329 strh r1, \[r5, r4\] +0+6b4 <[^>]+> f829 100c strh\.w r1, \[r9, ip\] +0+6b8 <[^>]+> f8af 105a strh\.w r1, \[pc, #90\] ; 0+716 <[^>]+> +0+6bc <[^>]+> f82f 1054 strh\.w r1, \[pc, #-84\] ; 0+66c <[^>]+> +0+6c0 <[^>]+> f8c5 1000 str\.w r1, \[r5\] +0+6c4 <[^>]+> f8c5 1330 str\.w r1, \[r5, #816\] +0+6c8 <[^>]+> f845 1c30 str\.w r1, \[r5, #-48\] +0+6cc <[^>]+> f845 1b30 str\.w r1, \[r5, #48\]! +0+6d0 <[^>]+> f845 1930 str\.w r1, \[r5, #-48\]! +0+6d4 <[^>]+> f845 1f30 str\.w r1, \[r5\], #48 +0+6d8 <[^>]+> f845 1d30 str\.w r1, \[r5\], #-48 +0+6dc <[^>]+> 5129 str r1, \[r5, r4\] +0+6de <[^>]+> f849 100c str\.w r1, \[r9, ip\] +0+6e2 <[^>]+> f8cf 1032 str\.w r1, \[pc, #50\] ; 0+716 <[^>]+> +0+6e6 <[^>]+> f84f 107c str\.w r1, \[pc, #-124\] ; 0+66c <[^>]+> +0+6ea <[^>]+> f895 f000 pld \[r5\] +0+6ee <[^>]+> f895 f330 pld \[r5, #816\] +0+6f2 <[^>]+> f815 fc30 pld \[r5, #-48\] +0+6f6 <[^>]+> f815 fb30 pld \[r5, #48\]! +0+6fa <[^>]+> f815 f930 pld \[r5, #-48\]! +0+6fe <[^>]+> f815 ff30 pld \[r5\], #48 +0+702 <[^>]+> f815 fd30 pld \[r5\], #-48 +0+706 <[^>]+> f815 f000 pld \[r5, r0\] +0+70a <[^>]+> f819 f000 pld \[r9, r0\] +0+70e <[^>]+> f89f f006 pld \[pc, #6\] ; 0+716 <[^>]+> +0+712 <[^>]+> f81f f0a8 pld \[pc, #-168\] ; 0+66c <[^>]+> +0+716 <[^>]+> e9d5 2300 ldrd r2, r3, \[r5\] +0+71a <[^>]+> e9d5 230c ldrd r2, r3, \[r5, #48\] +0+71e <[^>]+> e955 230c ldrd r2, r3, \[r5, #-48\] +0+722 <[^>]+> e9c5 2300 strd r2, r3, \[r5\] +0+726 <[^>]+> e9c5 230c strd r2, r3, \[r5, #48\] +0+72a <[^>]+> e945 230c strd r2, r3, \[r5, #-48\] +0+72e <[^>]+> f835 1e00 ldrht r1, \[r5\] +0+732 <[^>]+> f835 1e30 ldrht r1, \[r5, #48\] +0+736 <[^>]+> f915 1e00 ldrsbt r1, \[r5\] +0+73a <[^>]+> f915 1e30 ldrsbt r1, \[r5, #48\] +0+73e <[^>]+> f835 1e00 ldrht r1, \[r5\] +0+742 <[^>]+> f835 1e30 ldrht r1, \[r5, #48\] +0+746 <[^>]+> f935 1e00 ldrsht r1, \[r5\] +0+74a <[^>]+> f935 1e30 ldrsht r1, \[r5, #48\] +0+74e <[^>]+> f855 1e00 ldrt r1, \[r5\] +0+752 <[^>]+> f855 1e30 ldrt r1, \[r5, #48\] +0+756 <[^>]+> e8d4 1f4f ldrexb r1, \[r4\] +0+75a <[^>]+> e8d4 1f5f ldrexh r1, \[r4\] +0+75e <[^>]+> e854 1f00 ldrex r1, \[r4\] +0+762 <[^>]+> e8d4 127f ldrexd r1, r2, \[r4\] +0+766 <[^>]+> e8c4 2f41 strexb r1, r2, \[r4\] +0+76a <[^>]+> e8c4 2f51 strexh r1, r2, \[r4\] +0+76e <[^>]+> e844 2100 strex r1, r2, \[r4\] +0+772 <[^>]+> e8c4 2371 strexd r1, r2, r3, \[r4\] +0+776 <[^>]+> e854 1f81 ldrex r1, \[r4, #516\] +0+77a <[^>]+> e844 2181 strex r1, r2, \[r4, #516\] +0+77e <[^>]+> c80e ldmia r0!, \{r1, r2, r3\} +0+780 <[^>]+> ca07 ldmia r2!, \{r0, r1, r2\} +0+782 <[^>]+> e892 0007 ldmia\.w r2, \{r0, r1, r2\} +0+786 <[^>]+> e899 0007 ldmia\.w r9, \{r0, r1, r2\} +0+78a <[^>]+> e890 0580 ldmia\.w r0, \{r7, r8, sl\} +0+78e <[^>]+> e8b0 0580 ldmia\.w r0!, \{r7, r8, sl\} +0+792 <[^>]+> c00e stmia r0!, \{r1, r2, r3\} +0+794 <[^>]+> c20b stmia r2!, \{r0, r1, r3\} +0+796 <[^>]+> e8a2 000b stmia\.w r2!, \{r0, r1, r3\} +0+79a <[^>]+> e889 0007 stmia\.w r9, \{r0, r1, r2\} +0+79e <[^>]+> e880 0580 stmia\.w r0, \{r7, r8, sl\} +0+7a2 <[^>]+> e8a0 0580 stmia\.w r0!, \{r7, r8, sl\} +0+7a6 <[^>]+> e900 0580 stmdb r0, \{r7, r8, sl\} +0+7aa <[^>]+> e910 0580 ldmdb r0, \{r7, r8, sl\} +0+7ae <[^>]+> fb00 0000 mla r0, r0, r0, r0 +0+7b2 <[^>]+> fb00 0010 mls r0, r0, r0, r0 +0+7b6 <[^>]+> fb00 0900 mla r9, r0, r0, r0 +0+7ba <[^>]+> fb09 0000 mla r0, r9, r0, r0 +0+7be <[^>]+> fb00 0009 mla r0, r0, r9, r0 +0+7c2 <[^>]+> fb00 9000 mla r0, r0, r0, r9 +0+7c6 <[^>]+> 4200 tst r0, r0 +0+7c8 <[^>]+> 4200 tst r0, r0 +0+7ca <[^>]+> 4205 tst r5, r0 +0+7cc <[^>]+> 4228 tst r0, r5 +0+7ce <[^>]+> ea10 4f65 tst\.w r0, r5, asr #17 +0+7d2 <[^>]+> ea10 0f00 tst\.w r0, r0 +0+7d6 <[^>]+> ea19 0f00 tst\.w r9, r0 +0+7da <[^>]+> ea10 0f09 tst\.w r0, r9 +0+7de <[^>]+> f010 0f81 tst\.w r0, #129 ; 0x81 +0+7e2 <[^>]+> f015 0f81 tst\.w r5, #129 ; 0x81 +0+7e6 <[^>]+> ea90 0f00 teq r0, r0 +0+7ea <[^>]+> ea90 0f00 teq r0, r0 +0+7ee <[^>]+> ea95 0f00 teq r5, r0 +0+7f2 <[^>]+> ea90 0f05 teq r0, r5 +0+7f6 <[^>]+> ea90 4f65 teq r0, r5, asr #17 +0+7fa <[^>]+> ea90 0f00 teq r0, r0 +0+7fe <[^>]+> ea99 0f00 teq r9, r0 +0+802 <[^>]+> ea90 0f09 teq r0, r9 +0+806 <[^>]+> f090 0f81 teq r0, #129 ; 0x81 +0+80a <[^>]+> f095 0f81 teq r5, #129 ; 0x81 +0+80e <[^>]+> 4280 cmp r0, r0 +0+810 <[^>]+> 4280 cmp r0, r0 +0+812 <[^>]+> 4285 cmp r5, r0 +0+814 <[^>]+> 42a8 cmp r0, r5 +0+816 <[^>]+> ebb0 4f65 cmp\.w r0, r5, asr #17 +0+81a <[^>]+> ebb0 0f00 cmp\.w r0, r0 +0+81e <[^>]+> 4581 cmp r9, r0 +0+820 <[^>]+> ebb0 0f09 cmp\.w r0, r9 +0+824 <[^>]+> f1b0 0f81 cmp\.w r0, #129 ; 0x81 +0+828 <[^>]+> f1b5 0f81 cmp\.w r5, #129 ; 0x81 +0+82c <[^>]+> 42c0 cmn r0, r0 +0+82e <[^>]+> 42c0 cmn r0, r0 +0+830 <[^>]+> 42c5 cmn r5, r0 +0+832 <[^>]+> 42e8 cmn r0, r5 +0+834 <[^>]+> eb10 4f65 cmn\.w r0, r5, asr #17 +0+838 <[^>]+> eb10 0f00 cmn\.w r0, r0 +0+83c <[^>]+> eb19 0f00 cmn\.w r9, r0 +0+840 <[^>]+> eb10 0f09 cmn\.w r0, r9 +0+844 <[^>]+> f110 0f81 cmn\.w r0, #129 ; 0x81 +0+848 <[^>]+> f115 0f81 cmn\.w r5, #129 ; 0x81 +0+84c <[^>]+> 1c00 adds r0, r0, #0 +0+84e <[^>]+> 4600 mov r0, r0 +0+850 <[^>]+> 1c05 adds r5, r0, #0 +0+852 <[^>]+> 4628 mov r0, r5 +0+854 <[^>]+> ea4f 4065 mov\.w r0, r5, asr #17 +0+858 <[^>]+> ea4f 0000 mov\.w r0, r0 +0+85c <[^>]+> ea5f 0900 movs\.w r9, r0 +0+860 <[^>]+> ea5f 0009 movs\.w r0, r9 +0+864 <[^>]+> f04f 0081 mov\.w r0, #129 ; 0x81 +0+868 <[^>]+> f04f 0581 mov\.w r5, #129 ; 0x81 +0+86c <[^>]+> 43c0 mvns r0, r0 +0+86e <[^>]+> ea6f 0000 mvn\.w r0, r0 +0+872 <[^>]+> 43c5 mvns r5, r0 +0+874 <[^>]+> ea6f 0005 mvn\.w r0, r5 +0+878 <[^>]+> ea6f 4065 mvn\.w r0, r5, asr #17 +0+87c <[^>]+> ea6f 0000 mvn\.w r0, r0 +0+880 <[^>]+> ea7f 0900 mvns\.w r9, r0 +0+884 <[^>]+> ea7f 0009 mvns\.w r0, r9 +0+888 <[^>]+> f06f 0081 mvn\.w r0, #129 ; 0x81 +0+88c <[^>]+> f06f 0581 mvn\.w r5, #129 ; 0x81 +0+890 <[^>]+> f240 0000 movw r0, #0 ; 0x0 +0+894 <[^>]+> f2c0 0000 movt r0, #0 ; 0x0 +0+898 <[^>]+> f240 0900 movw r9, #0 ; 0x0 +0+89c <[^>]+> f249 0000 movw r0, #36864 ; 0x9000 +0+8a0 <[^>]+> f640 0000 movw r0, #2048 ; 0x800 +0+8a4 <[^>]+> f240 5000 movw r0, #1280 ; 0x500 +0+8a8 <[^>]+> f240 0081 movw r0, #129 ; 0x81 +0+8ac <[^>]+> f64f 70ff movw r0, #65535 ; 0xffff +0+8b0 <[^>]+> f3ef 8000 mrs r0, SPSR +0+8b4 <[^>]+> f3ff 8000 mrs r0, CPSR +0+8b8 <[^>]+> f3ef 8900 mrs r9, SPSR +0+8bc <[^>]+> f3ff 8900 mrs r9, CPSR +0+8c0 <[^>]+> f380 8100 msr SPSR_c, r0 +0+8c4 <[^>]+> f390 8100 msr CPSR_c, r0 +0+8c8 <[^>]+> f389 8100 msr SPSR_c, r9 +0+8cc <[^>]+> f380 8200 msr SPSR_x, r0 +0+8d0 <[^>]+> f380 8400 msr SPSR_s, r0 +0+8d4 <[^>]+> f380 8800 msr SPSR_f, r0 +0+8d8 <[^>]+> fb00 f000 mul\.w r0, r0, r0 +0+8dc <[^>]+> fb09 f000 mul\.w r0, r9, r0 +0+8e0 <[^>]+> fb00 f009 mul\.w r0, r0, r9 +0+8e4 <[^>]+> fb00 f000 mul\.w r0, r0, r0 +0+8e8 <[^>]+> fb00 f909 mul\.w r9, r0, r9 +0+8ec <[^>]+> 4345 muls r5, r0 +0+8ee <[^>]+> 4345 muls r5, r0 +0+8f0 <[^>]+> 4368 muls r0, r5 +0+8f2 <[^>]+> fb80 0100 smull r0, r1, r0, r0 +0+8f6 <[^>]+> fba0 0100 umull r0, r1, r0, r0 +0+8fa <[^>]+> fbc0 0100 smlal r0, r1, r0, r0 +0+8fe <[^>]+> fbe0 0100 umlal r0, r1, r0, r0 +0+902 <[^>]+> fb80 9000 smull r9, r0, r0, r0 +0+906 <[^>]+> fb80 0900 smull r0, r9, r0, r0 +0+90a <[^>]+> fb89 0100 smull r0, r1, r9, r0 +0+90e <[^>]+> fb80 0109 smull r0, r1, r0, r9 +0+912 <[^>]+> 4240 negs r0, r0 +0+914 <[^>]+> 4268 negs r0, r5 +0+916 <[^>]+> 4245 negs r5, r0 +0+918 <[^>]+> f1d0 0000 rsbs r0, r0, #0 ; 0x0 +0+91c <[^>]+> f1d0 0500 rsbs r5, r0, #0 ; 0x0 +0+920 <[^>]+> f1d5 0000 rsbs r0, r5, #0 ; 0x0 +0+924 <[^>]+> f1c9 0000 rsb r0, r9, #0 ; 0x0 +0+928 <[^>]+> f1c0 0900 rsb r9, r0, #0 ; 0x0 +0+92c <[^>]+> f1d9 0000 rsbs r0, r9, #0 ; 0x0 +0+930 <[^>]+> f1d0 0900 rsbs r9, r0, #0 ; 0x0 +0+934 <[^>]+> eac0 0000 pkhbt r0, r0, r0 +0+938 <[^>]+> eac0 0900 pkhbt r9, r0, r0 +0+93c <[^>]+> eac9 0000 pkhbt r0, r9, r0 +0+940 <[^>]+> eac0 0009 pkhbt r0, r0, r9 +0+944 <[^>]+> eac0 5000 pkhbt r0, r0, r0, lsl #20 +0+948 <[^>]+> eac0 00c0 pkhbt r0, r0, r0, lsl #3 +0+94c <[^>]+> eac2 0103 pkhbt r1, r2, r3 +0+950 <[^>]+> eac2 4163 pkhtb r1, r2, r3, asr #17 +0+954 <[^>]+> b401 push \{r0\} +0+956 <[^>]+> bc01 pop \{r0\} +0+958 <[^>]+> b502 push \{r1, lr\} +0+95a <[^>]+> bd02 pop \{r1, pc\} +0+95c <[^>]+> e8bd 1f00 ldmia\.w sp!, \{r8, r9, sl, fp, ip\} +0+960 <[^>]+> e8ad 1f00 stmia\.w sp!, \{r8, r9, sl, fp, ip\} +0+964 <[^>]+> fa92 f113 qadd16 r1, r2, r3 +0+968 <[^>]+> fa82 f113 qadd8 r1, r2, r3 +0+96c <[^>]+> faa2 f113 qaddsubx r1, r2, r3 +0+970 <[^>]+> fad2 f113 qsub16 r1, r2, r3 +0+974 <[^>]+> fac2 f113 qsub8 r1, r2, r3 +0+978 <[^>]+> fae2 f113 qsubaddx r1, r2, r3 +0+97c <[^>]+> fa92 f103 sadd16 r1, r2, r3 +0+980 <[^>]+> fa82 f103 sadd8 r1, r2, r3 +0+984 <[^>]+> faa2 f103 saddsubx r1, r2, r3 +0+988 <[^>]+> fad2 f103 ssub16 r1, r2, r3 +0+98c <[^>]+> fac2 f103 ssub8 r1, r2, r3 +0+990 <[^>]+> fae2 f103 ssubaddx r1, r2, r3 +0+994 <[^>]+> fa92 f123 shadd16 r1, r2, r3 +0+998 <[^>]+> fa82 f123 shadd8 r1, r2, r3 +0+99c <[^>]+> faa2 f123 shaddsubx r1, r2, r3 +0+9a0 <[^>]+> fad2 f123 shsub16 r1, r2, r3 +0+9a4 <[^>]+> fac2 f123 shsub8 r1, r2, r3 +0+9a8 <[^>]+> fae2 f123 shsubaddx r1, r2, r3 +0+9ac <[^>]+> fa92 f143 uadd16 r1, r2, r3 +0+9b0 <[^>]+> fa82 f143 uadd8 r1, r2, r3 +0+9b4 <[^>]+> faa2 f143 uaddsubx r1, r2, r3 +0+9b8 <[^>]+> fad2 f143 usub16 r1, r2, r3 +0+9bc <[^>]+> fac2 f143 usub8 r1, r2, r3 +0+9c0 <[^>]+> fae2 f143 usubaddx r1, r2, r3 +0+9c4 <[^>]+> fa92 f163 uhadd16 r1, r2, r3 +0+9c8 <[^>]+> fa82 f163 uhadd8 r1, r2, r3 +0+9cc <[^>]+> faa2 f163 uhaddsubx r1, r2, r3 +0+9d0 <[^>]+> fad2 f163 uhsub16 r1, r2, r3 +0+9d4 <[^>]+> fac2 f163 uhsub8 r1, r2, r3 +0+9d8 <[^>]+> fae2 f163 uhsubaddx r1, r2, r3 +0+9dc <[^>]+> fa92 f153 uqadd16 r1, r2, r3 +0+9e0 <[^>]+> fa82 f153 uqadd8 r1, r2, r3 +0+9e4 <[^>]+> faa2 f153 uqaddsubx r1, r2, r3 +0+9e8 <[^>]+> fad2 f153 uqsub16 r1, r2, r3 +0+9ec <[^>]+> fac2 f153 uqsub8 r1, r2, r3 +0+9f0 <[^>]+> fae2 f153 uqsubaddx r1, r2, r3 +0+9f4 <[^>]+> faa2 f183 sel r1, r2, r3 +0+9f8 <[^>]+> ba00 rev r0, r0 +0+9fa <[^>]+> fa90 f080 rev\.w r0, r0 +0+9fe <[^>]+> ba28 rev r0, r5 +0+a00 <[^>]+> ba05 rev r5, r0 +0+a02 <[^>]+> fa99 f089 rev\.w r0, r9 +0+a06 <[^>]+> fa90 f980 rev\.w r9, r0 +0+a0a <[^>]+> ba40 rev16 r0, r0 +0+a0c <[^>]+> fa90 f090 rev16\.w r0, r0 +0+a10 <[^>]+> ba68 rev16 r0, r5 +0+a12 <[^>]+> ba45 rev16 r5, r0 +0+a14 <[^>]+> fa99 f099 rev16\.w r0, r9 +0+a18 <[^>]+> fa90 f990 rev16\.w r9, r0 +0+a1c <[^>]+> bac0 revsh r0, r0 +0+a1e <[^>]+> fa90 f0b0 revsh\.w r0, r0 +0+a22 <[^>]+> bae8 revsh r0, r5 +0+a24 <[^>]+> bac5 revsh r5, r0 +0+a26 <[^>]+> fa99 f0b9 revsh\.w r0, r9 +0+a2a <[^>]+> fa90 f9b0 revsh\.w r9, r0 +0+a2e <[^>]+> fa90 f0a0 rbit r0, r0 +0+a32 <[^>]+> fa90 f0a0 rbit r0, r0 +0+a36 <[^>]+> fa95 f0a0 rbit r0, r5 +0+a3a <[^>]+> fa90 f5a0 rbit r5, r0 +0+a3e <[^>]+> fa99 f0a0 rbit r0, r9 +0+a42 <[^>]+> fa90 f9a0 rbit r9, r0 +0+a46 <[^>]+> 0440 lsls r0, r0, #17 +0+a48 <[^>]+> 0380 lsls r0, r0, #14 +0+a4a <[^>]+> 0445 lsls r5, r0, #17 +0+a4c <[^>]+> 03a8 lsls r0, r5, #14 +0+a4e <[^>]+> 4080 lsls r0, r0 +0+a50 <[^>]+> 40a8 lsls r0, r5 +0+a52 <[^>]+> 40a8 lsls r0, r5 +0+a54 <[^>]+> ea4f 4949 mov\.w r9, r9, lsl #17 +0+a58 <[^>]+> ea4f 3989 mov\.w r9, r9, lsl #14 +0+a5c <[^>]+> ea5f 4049 movs\.w r0, r9, lsl #17 +0+a60 <[^>]+> ea4f 3980 mov\.w r9, r0, lsl #14 +0+a64 <[^>]+> fa00 f000 lsl\.w r0, r0, r0 +0+a68 <[^>]+> fa09 f909 lsl\.w r9, r9, r9 +0+a6c <[^>]+> fa19 f900 lsls\.w r9, r9, r0 +0+a70 <[^>]+> fa00 f009 lsl\.w r0, r0, r9 +0+a74 <[^>]+> fa00 f005 lsl\.w r0, r0, r5 +0+a78 <[^>]+> fa11 f002 lsls\.w r0, r1, r2 +0+a7c <[^>]+> 0c40 lsrs r0, r0, #17 +0+a7e <[^>]+> 0b80 lsrs r0, r0, #14 +0+a80 <[^>]+> 0c45 lsrs r5, r0, #17 +0+a82 <[^>]+> 0ba8 lsrs r0, r5, #14 +0+a84 <[^>]+> 40c0 lsrs r0, r0 +0+a86 <[^>]+> 40e8 lsrs r0, r5 +0+a88 <[^>]+> 40e8 lsrs r0, r5 +0+a8a <[^>]+> ea4f 4959 mov\.w r9, r9, lsr #17 +0+a8e <[^>]+> ea4f 3999 mov\.w r9, r9, lsr #14 +0+a92 <[^>]+> ea5f 4059 movs\.w r0, r9, lsr #17 +0+a96 <[^>]+> ea4f 3990 mov\.w r9, r0, lsr #14 +0+a9a <[^>]+> fa20 f000 lsr\.w r0, r0, r0 +0+a9e <[^>]+> fa29 f909 lsr\.w r9, r9, r9 +0+aa2 <[^>]+> fa39 f900 lsrs\.w r9, r9, r0 +0+aa6 <[^>]+> fa20 f009 lsr\.w r0, r0, r9 +0+aaa <[^>]+> fa20 f005 lsr\.w r0, r0, r5 +0+aae <[^>]+> fa31 f002 lsrs\.w r0, r1, r2 +0+ab2 <[^>]+> 1440 asrs r0, r0, #17 +0+ab4 <[^>]+> 1380 asrs r0, r0, #14 +0+ab6 <[^>]+> 1445 asrs r5, r0, #17 +0+ab8 <[^>]+> 13a8 asrs r0, r5, #14 +0+aba <[^>]+> 4100 asrs r0, r0 +0+abc <[^>]+> 4128 asrs r0, r5 +0+abe <[^>]+> 4128 asrs r0, r5 +0+ac0 <[^>]+> ea4f 4969 mov\.w r9, r9, asr #17 +0+ac4 <[^>]+> ea4f 39a9 mov\.w r9, r9, asr #14 +0+ac8 <[^>]+> ea5f 4069 movs\.w r0, r9, asr #17 +0+acc <[^>]+> ea4f 39a0 mov\.w r9, r0, asr #14 +0+ad0 <[^>]+> fa40 f000 asr\.w r0, r0, r0 +0+ad4 <[^>]+> fa49 f909 asr\.w r9, r9, r9 +0+ad8 <[^>]+> fa59 f900 asrs\.w r9, r9, r0 +0+adc <[^>]+> fa40 f009 asr\.w r0, r0, r9 +0+ae0 <[^>]+> fa40 f005 asr\.w r0, r0, r5 +0+ae4 <[^>]+> fa51 f002 asrs\.w r0, r1, r2 +0+ae8 <[^>]+> ea5f 4070 movs\.w r0, r0, ror #17 +0+aec <[^>]+> ea5f 30b0 movs\.w r0, r0, ror #14 +0+af0 <[^>]+> ea5f 4570 movs\.w r5, r0, ror #17 +0+af4 <[^>]+> ea5f 30b5 movs\.w r0, r5, ror #14 +0+af8 <[^>]+> 41c0 rors r0, r0 +0+afa <[^>]+> 41e8 rors r0, r5 +0+afc <[^>]+> 41e8 rors r0, r5 +0+afe <[^>]+> ea4f 4979 mov\.w r9, r9, ror #17 +0+b02 <[^>]+> ea4f 39b9 mov\.w r9, r9, ror #14 +0+b06 <[^>]+> ea5f 4079 movs\.w r0, r9, ror #17 +0+b0a <[^>]+> ea4f 39b0 mov\.w r9, r0, ror #14 +0+b0e <[^>]+> fa60 f000 ror\.w r0, r0, r0 +0+b12 <[^>]+> fa69 f909 ror\.w r9, r9, r9 +0+b16 <[^>]+> fa79 f900 rors\.w r9, r9, r0 +0+b1a <[^>]+> fa60 f009 ror\.w r0, r0, r9 +0+b1e <[^>]+> fa60 f005 ror\.w r0, r0, r5 +0+b22 <[^>]+> fa71 f002 rors\.w r0, r1, r2 +0+b26 <[^>]+> f7f0 8000 smi #0 ; 0x0 +0+b2a <[^>]+> f7fd 8bca smi #43981 ; 0xabcd +0+b2e <[^>]+> fb10 0000 smlabb r0, r0, r0, r0 +0+b32 <[^>]+> fb10 0900 smlabb r9, r0, r0, r0 +0+b36 <[^>]+> fb19 0000 smlabb r0, r9, r0, r0 +0+b3a <[^>]+> fb10 0009 smlabb r0, r0, r9, r0 +0+b3e <[^>]+> fb10 9000 smlabb r0, r0, r0, r9 +0+b42 <[^>]+> fb10 0020 smlatb r0, r0, r0, r0 +0+b46 <[^>]+> fb10 0010 smlabt r0, r0, r0, r0 +0+b4a <[^>]+> fb10 0030 smlatt r0, r0, r0, r0 +0+b4e <[^>]+> fb30 0000 smlawb r0, r0, r0, r0 +0+b52 <[^>]+> fb30 0010 smlawt r0, r0, r0, r0 +0+b56 <[^>]+> fb20 0000 smlad r0, r0, r0, r0 +0+b5a <[^>]+> fb20 0010 smladx r0, r0, r0, r0 +0+b5e <[^>]+> fb40 0000 smlsd r0, r0, r0, r0 +0+b62 <[^>]+> fb40 0010 smlsdx r0, r0, r0, r0 +0+b66 <[^>]+> fb50 0000 smmla r0, r0, r0, r0 +0+b6a <[^>]+> fb50 0010 smmlar r0, r0, r0, r0 +0+b6e <[^>]+> fb60 0000 smmls r0, r0, r0, r0 +0+b72 <[^>]+> fb60 0010 smmlsr r0, r0, r0, r0 +0+b76 <[^>]+> fb70 0000 usada8 r0, r0, r0, r0 +0+b7a <[^>]+> fbc0 0080 smlalbb r0, r0, r0, r0 +0+b7e <[^>]+> fbc0 9080 smlalbb r9, r0, r0, r0 +0+b82 <[^>]+> fbc0 0980 smlalbb r0, r9, r0, r0 +0+b86 <[^>]+> fbc9 0080 smlalbb r0, r0, r9, r0 +0+b8a <[^>]+> fbc0 0089 smlalbb r0, r0, r0, r9 +0+b8e <[^>]+> fbc0 00a0 smlaltb r0, r0, r0, r0 +0+b92 <[^>]+> fbc0 0090 smlalbt r0, r0, r0, r0 +0+b96 <[^>]+> fbc0 00b0 smlaltt r0, r0, r0, r0 +0+b9a <[^>]+> fbc0 00c0 smlald r0, r0, r0, r0 +0+b9e <[^>]+> fbc0 00d0 smlaldx r0, r0, r0, r0 +0+ba2 <[^>]+> fbd0 00c0 smlsld r0, r0, r0, r0 +0+ba6 <[^>]+> fbd0 00d0 smlsldx r0, r0, r0, r0 +0+baa <[^>]+> fbe0 0060 umaal r0, r0, r0, r0 +0+bae <[^>]+> fb10 f000 smulbb r0, r0, r0 +0+bb2 <[^>]+> fb10 f900 smulbb r9, r0, r0 +0+bb6 <[^>]+> fb19 f000 smulbb r0, r9, r0 +0+bba <[^>]+> fb10 f009 smulbb r0, r0, r9 +0+bbe <[^>]+> fb10 f020 smultb r0, r0, r0 +0+bc2 <[^>]+> fb10 f010 smulbt r0, r0, r0 +0+bc6 <[^>]+> fb10 f030 smultt r0, r0, r0 +0+bca <[^>]+> fb30 f000 smulwb r0, r0, r0 +0+bce <[^>]+> fb30 f010 smulwt r0, r0, r0 +0+bd2 <[^>]+> fb50 f000 smmul r0, r0, r0 +0+bd6 <[^>]+> fb50 f010 smmulr r0, r0, r0 +0+bda <[^>]+> fb20 f000 smuad r0, r0, r0 +0+bde <[^>]+> fb20 f010 smuadx r0, r0, r0 +0+be2 <[^>]+> fb40 f000 smusd r0, r0, r0 +0+be6 <[^>]+> fb40 f010 smusdx r0, r0, r0 +0+bea <[^>]+> fb70 f000 usad8 r0, r0, r0 +0+bee <[^>]+> f300 0000 ssat r0, #0, r0 +0+bf2 <[^>]+> f300 0000 ssat r0, #0, r0 +0+bf6 <[^>]+> f300 0000 ssat r0, #0, r0 +0+bfa <[^>]+> f300 0900 ssat r9, #0, r0 +0+bfe <[^>]+> f300 0011 ssat r0, #17, r0 +0+c02 <[^>]+> f309 0000 ssat r0, #0, r9 +0+c06 <[^>]+> f300 7000 ssat r0, #0, r0, lsl #28 +0+c0a <[^>]+> f320 00c0 ssat r0, #0, r0, asr #3 +0+c0e <[^>]+> f320 0000 ssat16 r0, #0, r0 +0+c12 <[^>]+> f320 0900 ssat16 r9, #0, r0 +0+c16 <[^>]+> f320 0009 ssat16 r0, #9, r0 +0+c1a <[^>]+> f329 0000 ssat16 r0, #0, r9 +0+c1e <[^>]+> f380 0000 usat r0, #0, r0 +0+c22 <[^>]+> f380 0000 usat r0, #0, r0 +0+c26 <[^>]+> f380 0000 usat r0, #0, r0 +0+c2a <[^>]+> f380 0900 usat r9, #0, r0 +0+c2e <[^>]+> f380 0011 usat r0, #17, r0 +0+c32 <[^>]+> f389 0000 usat r0, #0, r9 +0+c36 <[^>]+> f380 7000 usat r0, #0, r0, lsl #28 +0+c3a <[^>]+> f3a0 00c0 usat r0, #0, r0, asr #3 +0+c3e <[^>]+> f3a0 0000 usat16 r0, #0, r0 +0+c42 <[^>]+> f3a0 0900 usat16 r9, #0, r0 +0+c46 <[^>]+> f3a0 0009 usat16 r0, #9, r0 +0+c4a <[^>]+> f3a9 0000 usat16 r0, #0, r9 +0+c4e <[^>]+> b240 sxtb r0, r0 +0+c50 <[^>]+> b240 sxtb r0, r0 +0+c52 <[^>]+> b245 sxtb r5, r0 +0+c54 <[^>]+> b268 sxtb r0, r5 +0+c56 <[^>]+> fa4f f182 sxtb\.w r1, r2 +0+c5a <[^>]+> fa4f f192 sxtb\.w r1, r2, ror #8 +0+c5e <[^>]+> fa4f f1a2 sxtb\.w r1, r2, ror #16 +0+c62 <[^>]+> fa4f f1b2 sxtb\.w r1, r2, ror #24 +0+c66 <[^>]+> fa2f f182 sxtb16 r1, r2 +0+c6a <[^>]+> fa2f f889 sxtb16 r8, r9 +0+c6e <[^>]+> b211 sxth r1, r2 +0+c70 <[^>]+> fa0f f889 sxth\.w r8, r9 +0+c74 <[^>]+> b2d1 uxtb r1, r2 +0+c76 <[^>]+> fa5f f889 uxtb\.w r8, r9 +0+c7a <[^>]+> fa3f f182 uxtb16 r1, r2 +0+c7e <[^>]+> fa3f f889 uxtb16 r8, r9 +0+c82 <[^>]+> b291 uxth r1, r2 +0+c84 <[^>]+> fa1f f889 uxth\.w r8, r9 +0+c88 <[^>]+> fa40 f080 sxtab r0, r0, r0 +0+c8c <[^>]+> fa40 f080 sxtab r0, r0, r0 +0+c90 <[^>]+> fa40 f990 sxtab r9, r0, r0, ror #8 +0+c94 <[^>]+> fa49 f0a0 sxtab r0, r9, r0, ror #16 +0+c98 <[^>]+> fa40 f0b9 sxtab r0, r0, r9, ror #24 +0+c9c <[^>]+> fa22 f183 sxtab16 r1, r2, r3 +0+ca0 <[^>]+> fa02 f183 sxtah r1, r2, r3 +0+ca4 <[^>]+> fa52 f183 uxtab r1, r2, r3 +0+ca8 <[^>]+> fa32 f183 uxtab16 r1, r2, r3 +0+cac <[^>]+> fa12 f183 uxtah r1, r2, r3 diff --git a/gas/testsuite/gas/arm/thumb32.s b/gas/testsuite/gas/arm/thumb32.s new file mode 100644 index 0000000..7db255a --- /dev/null +++ b/gas/testsuite/gas/arm/thumb32.s @@ -0,0 +1,735 @@ + .text + .thumb + .syntax unified + +encode_thumb32_immediate: + orr r0, r1, #0x00000000 + orr r0, r1, #0x000000a5 + orr r0, r1, #0x00a500a5 + orr r0, r1, #0xa500a500 + orr r0, r1, #0xa5a5a5a5 + + orr r0, r1, #0xa5 << 31 + orr r0, r1, #0xa5 << 30 + orr r0, r1, #0xa5 << 29 + orr r0, r1, #0xa5 << 28 + orr r0, r1, #0xa5 << 27 + orr r0, r1, #0xa5 << 26 + orr r0, r1, #0xa5 << 25 + orr r0, r1, #0xa5 << 24 + orr r0, r1, #0xa5 << 23 + orr r0, r1, #0xa5 << 22 + orr r0, r1, #0xa5 << 21 + orr r0, r1, #0xa5 << 20 + orr r0, r1, #0xa5 << 19 + orr r0, r1, #0xa5 << 18 + orr r0, r1, #0xa5 << 17 + orr r0, r1, #0xa5 << 16 + orr r0, r1, #0xa5 << 15 + orr r0, r1, #0xa5 << 14 + orr r0, r1, #0xa5 << 13 + orr r0, r1, #0xa5 << 12 + orr r0, r1, #0xa5 << 11 + orr r0, r1, #0xa5 << 10 + orr r0, r1, #0xa5 << 9 + orr r0, r1, #0xa5 << 8 + orr r0, r1, #0xa5 << 7 + orr r0, r1, #0xa5 << 6 + orr r0, r1, #0xa5 << 5 + orr r0, r1, #0xa5 << 4 + orr r0, r1, #0xa5 << 3 + orr r0, r1, #0xa5 << 2 + orr r0, r1, #0xa5 << 1 + +add_sub: + adds r0, r0, #0 @ format 1 + adds r5, r0, #0 + adds r0, r5, #0 + adds r0, r0, #5 + + adds r0, #129 @ format 2 + adds r0, r0, #129 + adds r5, #126 + + adds r0, r0, r0 @ format 3 + adds r5, r0, r0 + adds r0, r5, r0 + adds r0, r0, r5 + adds r1, r2, r3 + + add r8, r0 @ format 4 + add r0, r8 + add r0, r8, r0 + add r0, r0, r8 + add r8, r0, r0 @ ... not this one + + add r1, r0 + add r0, r1 + + add r0, pc, #0 @ format 5 + add r5, pc, #0 + add r0, pc, #516 + + add r0, sp, #0 @ format 6 + add r5, sp, #0 + add r0, sp, #516 + + add sp, #0 @ format 7 + add sp, sp, #0 + add sp, #260 + + add.w r0, r0, #0 @ T32 format 1 + adds.w r0, r0, #0 + add.w r9, r0, #0 + add.w r0, r9, #0 + add.w r0, r0, #129 + + add.w r0, r0, r0 @ T32 format 2 + adds.w r0, r0, r0 + add.w r9, r0, r0 + add.w r0, r9, r0 + add.w r0, r0, r9 + + add.w r8, r9, r10 + add.w r8, r9, r10, lsl #17 + add.w r8, r8, r10, lsr #32 + add.w r8, r8, r10, lsr #17 + add.w r8, r9, r10, asr #32 + add.w r8, r9, r10, asr #17 + add.w r8, r9, r10, rrx + add.w r8, r9, r10, ror #17 + + subs r0, r0, #0 @ format 1 + subs r5, r0, #0 + subs r0, r5, #0 + subs r0, r0, #5 + + subs r0, r0, #129 + subs r5, #8 + + subs r0, r0, r0 @ format 3 + subs r5, r0, r0 + subs r0, r5, r0 + subs r0, r0, r5 + + sub sp, #260 @ format 4 + sub sp, sp, #260 + + subs r8, r0 @ T32 format 2 + subs r0, r8 + subs r0, #260 @ T32 format 1 + +arit3: + .macro arit3 op ops opw opsw + \ops r0, r0 + \ops r5, r0 + \ops r0, r5 + \ops r0, r0, r5 + \ops r0, r5, r0 + \op r0, r5, r0 + \op r0, r1, r2 + \op r9, r0, r0 + \op r0, r9, r0 + \op r0, r0, r9 + \opsw r0, r0, r0 + \opw r0, r1, r2, asr #17 + \opw r0, r1, #129 + .endm + + arit3 adc adcs adc.w adcs.w + arit3 and ands and.w ands.w + arit3 bic bics bic.w bics.w + arit3 eor eors eor.w eors.w + arit3 orr orrs orr.w orrs.w + arit3 rsb rsbs rsb.w rsbs.w + arit3 sbc sbcs sbc.w sbcs.w + + .purgem arit3 + +bfc_bfi_bfx: + bfc r0, #0, #1 + bfc r9, #0, #1 + bfi r9, #0, #0, #1 + bfc r0, #21, #1 + bfc r0, #0, #18 + + bfi r0, r0, #0, #1 + bfi r9, r0, #0, #1 + bfi r0, r9, #0, #1 + bfi r0, r0, #21, #1 + bfi r0, r0, #0, #18 + + sbfx r0, r0, #0, #1 + ubfx r9, r0, #0, #1 + sbfx r0, r9, #0, #1 + ubfx r0, r0, #21, #1 + sbfx r0, r0, #0, #18 + + .globl branches +branches: + .macro bra op + \op 1b + \op 1f + .endm +1: + bra beq.n + bra bne.n + bra bcs.n + bra bhs.n + bra bcc.n + bra bul.n + bra blo.n + bra bmi.n + bra bpl.n + bra bvs.n + bra bvc.n + bra bhi.n + bra bls.n + bra bvc.n + bra bhi.n + bra bls.n + bra bge.n + bra blt.n + bra bgt.n + bra ble.n + bra bal.n + bra b.n + @ bl, blx have no short form. + .balign 4 +1: + bra beq + bra bne + bra bcs + bra bhs + bra bcc + bra bul + bra blo + bra bmi + bra bpl + bra bvs + bra bvc + bra bhi + bra bls + bra bvc + bra bhi + bra bls + bra bge + bra blt + bra bgt + bra ble + bra b + bra bl + bra blx + .balign 4 +1: + bx r9 + blx r0 + blx r9 + bxj r0 + bxj r9 + .purgem bra + +clz: + clz r0, r0 + clz r9, r0 + clz r0, r9 + +cps: + cpsie f + cpsid i + cpsie a + cpsid.w f + cpsie.w i + cpsid.w a + cpsie i, #0 + cpsid i, #17 + cps #0 + cps #17 + +cpy: + cpy r0, r0 + cpy r9, r0 + cpy r0, r9 + cpy.w r0, r0 + cpy.w r9, r0 + cpy.w r0, r9 + +czb: + cbnz r0, 2f + cbz r5, 1f + +nop_hint: + nop +1: yield +2: wfe + wfi + sev + + nop.w + yield.w + wfe.w + wfi.w + sev.w + + nop {9} + nop {129} + +it: + .macro itx opc cond n + \opc \cond + .rept \n + nop + .endr + .endm + + itx it eq 1 + itx it ne 1 + itx it cs 1 + itx it hs 1 + itx it cc 1 + itx it ul 1 + itx it lo 1 + itx it mi 1 + itx it pl 1 + itx it vs 1 + itx it vc 1 + itx it hi 1 + itx it ge 1 + itx it lt 1 + itx it gt 1 + itx it le 1 + itx it al 1 + + itx itt eq 2 + itx ite eq 2 + itx ittt eq 3 + itx itet eq 3 + itx itte eq 3 + itx itee eq 3 + itx itttt eq 4 + itx itett eq 4 + itx ittet eq 4 + itx ittte eq 4 + itx ittee eq 4 + itx itete eq 4 + itx iteet eq 4 + itx iteee eq 4 + + itx itt ne 2 + itx ite ne 2 + itx ittt ne 3 + itx itet ne 3 + itx itte ne 3 + itx itee ne 3 + itx itttt ne 4 + itx itett ne 4 + itx ittet ne 4 + itx ittte ne 4 + itx ittee ne 4 + itx itete ne 4 + itx iteet ne 4 + itx iteee ne 4 + + .purgem itx + +ldst: + .macro ls op + \op r1, [r5] + \op r1, [r5, #0x330] + \op r1, [r5, #-0x30] + \op r1, [r5], #0x30 + \op r1, [r5], #-0x30 + \op r1, [r5, #0x30]! + \op r1, [r5, #-0x30]! + \op r1, [r5, r4] + \op r1, [r9, ip] + \op r1, 1f + \op r1, 1b + .endm +1: + ls ldrb + ls ldrsb + ls ldrh + ls ldrsh + ls ldr +1: + ls strb + ls strh + ls str + + pld [r5] + pld [r5, #0x330] + pld [r5, #-0x30] + pld [r5], #0x30 + pld [r5], #-0x30 + pld [r5, #0x30]! + pld [r5, #-0x30]! + pld [r5, r4] + pld [r9, ip] + pld 1f + pld 1b +1: + + ldrd r2, r3, [r5] + ldrd r2, [r5, #0x30] + ldrd r2, [r5, #-0x30] + strd r2, r3, [r5] + strd r2, [r5, #0x30] + strd r2, [r5, #-0x30] + + ldrbt r1, [r5] + ldrbt r1, [r5, #0x30] + ldrsbt r1, [r5] + ldrsbt r1, [r5, #0x30] + ldrht r1, [r5] + ldrht r1, [r5, #0x30] + ldrsht r1, [r5] + ldrsht r1, [r5, #0x30] + ldrt r1, [r5] + ldrt r1, [r5, #0x30] + + .purgem ls + +ldxstx: + ldrexb r1, [r4] + ldrexh r1, [r4] + ldrex r1, [r4] + ldrexd r1, r2, [r4] + + strexb r1, r2, [r4] + strexh r1, r2, [r4] + strex r1, r2, [r4] + strexd r1, r2, r3, [r4] + + ldrex r1, [r4,#516] + strex r1, r2, [r4,#516] + +ldmstm: + ldmia r0!, {r1,r2,r3} + ldmia r2, {r0,r1,r2} + ldmia.w r2, {r0,r1,r2} + ldmia r9, {r0,r1,r2} + ldmia r0, {r7,r8,r10} + ldmia r0!, {r7,r8,r10} + + stmia r0!, {r1,r2,r3} + stmia r2!, {r0,r1,r3} + stmia.w r2!, {r0,r1,r3} + stmia r9, {r0,r1,r2} + stmia r0, {r7,r8,r10} + stmia r0!, {r7,r8,r10} + + ldmdb r0, {r7,r8,r10} + stmdb r0, {r7,r8,r10} + +mlas: + mla r0, r0, r0, r0 + mls r0, r0, r0, r0 + mla r9, r0, r0, r0 + mla r0, r9, r0, r0 + mla r0, r0, r9, r0 + mla r0, r0, r0, r9 + +tst_teq_cmp_cmn_mov_mvn: + .macro mt op ops opw opsw + \ops r0, r0 + \op r0, r0 + \ops r5, r0 + \op r0, r5 + \op r0, r5, asr #17 + \opw r0, r0 + \ops r9, r0 + \opsw r0, r9 + \op r0, #129 + \op r5, #129 + .endm + + mt tst tsts tst.w tsts.w + mt teq teqs teq.w teqs.w + mt cmp cmps cmp.w cmps.w + mt cmn cmns cmn.w cmns.w + mt mov movs mov.w movs.w + mt mvn mvns mvn.w mvns.w + .purgem mt + +mov16: + movw r0, #0 + movt r0, #0 + movw r9, #0 + movw r0, #0x9000 + movw r0, #0x0800 + movw r0, #0x0500 + movw r0, #0x0081 + movw r0, #0xffff + +mrs_msr: + mrs r0, CPSR + mrs r0, SPSR + mrs r9, CPSR_all + mrs r9, SPSR_all + + msr CPSR_c, r0 + msr SPSR_c, r0 + msr CPSR_c, r9 + msr CPSR_x, r0 + msr CPSR_s, r0 + msr CPSR_f, r0 + +mul: + mul r0, r0, r0 + mul r0, r9, r0 + mul r0, r0, r9 + mul r0, r0 + mul r9, r0 + muls r5, r0 + muls r5, r0, r5 + muls r0, r5 + +mull: + smull r0, r1, r0, r0 + umull r0, r1, r0, r0 + smlal r0, r1, r0, r0 + umlal r0, r1, r0, r0 + smull r9, r0, r0, r0 + smull r0, r9, r0, r0 + smull r0, r1, r9, r0 + smull r0, r1, r0, r9 + +neg: + negs r0, r0 + negs r0, r5 + negs r5, r0 + negs.w r0, r0 + negs.w r5, r0 + negs.w r0, r5 + + neg r0, r9 + neg r9, r0 + negs r0, r9 + negs r9, r0 + +pkh: + pkhbt r0, r0, r0 + pkhbt r9, r0, r0 + pkhbt r0, r9, r0 + pkhbt r0, r0, r9 + pkhbt r0, r0, r0, lsl #0x14 + pkhbt r0, r0, r0, lsl #3 + pkhtb r1, r2, r3 + pkhtb r1, r2, r3, asr #0x11 + +push_pop: + push {r0} + pop {r0} + push {r1,lr} + pop {r1,pc} + push {r8,r9,r10,r11,r12} + pop {r8,r9,r10,r11,r12} + +qadd: + qadd16 r1, r2, r3 + qadd8 r1, r2, r3 + qaddsubx r1, r2, r3 + qsub16 r1, r2, r3 + qsub8 r1, r2, r3 + qsubaddx r1, r2, r3 + sadd16 r1, r2, r3 + sadd8 r1, r2, r3 + saddsubx r1, r2, r3 + ssub16 r1, r2, r3 + ssub8 r1, r2, r3 + ssubaddx r1, r2, r3 + shadd16 r1, r2, r3 + shadd8 r1, r2, r3 + shaddsubx r1, r2, r3 + shsub16 r1, r2, r3 + shsub8 r1, r2, r3 + shsubaddx r1, r2, r3 + uadd16 r1, r2, r3 + uadd8 r1, r2, r3 + uaddsubx r1, r2, r3 + usub16 r1, r2, r3 + usub8 r1, r2, r3 + usubaddx r1, r2, r3 + uhadd16 r1, r2, r3 + uhadd8 r1, r2, r3 + uhaddsubx r1, r2, r3 + uhsub16 r1, r2, r3 + uhsub8 r1, r2, r3 + uhsubaddx r1, r2, r3 + uqadd16 r1, r2, r3 + uqadd8 r1, r2, r3 + uqaddsubx r1, r2, r3 + uqsub16 r1, r2, r3 + uqsub8 r1, r2, r3 + uqsubaddx r1, r2, r3 + sel r1, r2, r3 + +rbit_rev: + .macro rx op opw + \op r0, r0 + \opw r0, r0 + \op r0, r5 + \op r5, r0 + \op r0, r9 + \op r9, r0 + .endm + + rx rev rev.w + rx rev16 rev16.w + rx revsh revsh.w + rx rbit rbit.w + + .purgem rx + +shift: + .macro sh op ops opw opsw + \ops r0, #17 @ 16-bit format 1 + \ops r0, r0, #14 + \ops r5, r0, #17 + \ops r0, r5, #14 + \ops r0, r0 @ 16-bit format 2 + \ops r0, r5 + \ops r0, r0, r5 + \op r9, #17 @ 32-bit format 1 + \op r9, r9, #14 + \ops r0, r9, #17 + \op r9, r0, #14 + \opw r0, r0, r0 @ 32-bit format 2 + \op r9, r9 + \ops r9, r0 + \op r0, r9 + \op r0, r5 + \ops r0, r1, r2 + .endm + + sh lsl lsls lsl.w lsls.w + sh lsr lsrs lsr.w lsrs.w + sh asr asrs asr.w asrs.w + sh ror rors ror.w rors.w + + .purgem sh + +smi: + smi #0 + smi #0xabcd + +smla: + smlabb r0, r0, r0, r0 + smlabb r9, r0, r0, r0 + smlabb r0, r9, r0, r0 + smlabb r0, r0, r9, r0 + smlabb r0, r0, r0, r9 + + smlatb r0, r0, r0, r0 + smlabt r0, r0, r0, r0 + smlatt r0, r0, r0, r0 + smlawb r0, r0, r0, r0 + smlawt r0, r0, r0, r0 + smlad r0, r0, r0, r0 + smladx r0, r0, r0, r0 + smlsd r0, r0, r0, r0 + smlsdx r0, r0, r0, r0 + smmla r0, r0, r0, r0 + smmlar r0, r0, r0, r0 + smmls r0, r0, r0, r0 + smmlsr r0, r0, r0, r0 + usada8 r0, r0, r0, r0 + +smlal: + smlalbb r0, r0, r0, r0 + smlalbb r9, r0, r0, r0 + smlalbb r0, r9, r0, r0 + smlalbb r0, r0, r9, r0 + smlalbb r0, r0, r0, r9 + + smlaltb r0, r0, r0, r0 + smlalbt r0, r0, r0, r0 + smlaltt r0, r0, r0, r0 + smlald r0, r0, r0, r0 + smlaldx r0, r0, r0, r0 + smlsld r0, r0, r0, r0 + smlsldx r0, r0, r0, r0 + umaal r0, r0, r0, r0 + +smul: + smulbb r0, r0, r0 + smulbb r9, r0, r0 + smulbb r0, r9, r0 + smulbb r0, r0, r9 + + smultb r0, r0, r0 + smulbt r0, r0, r0 + smultt r0, r0, r0 + smulwb r0, r0, r0 + smulwt r0, r0, r0 + smmul r0, r0, r0 + smmulr r0, r0, r0 + smuad r0, r0, r0 + smuadx r0, r0, r0 + smusd r0, r0, r0 + smusdx r0, r0, r0 + usad8 r0, r0, r0 + +sat: + ssat r0, #1, r0 + ssat r0, #1, r0, lsl #0 + ssat r0, #1, r0, asr #0 + ssat r9, #1, r0 + ssat r0, #18, r0 + ssat r0, #1, r9 + ssat r0, #1, r0, lsl #0x1c + ssat r0, #1, r0, asr #0x03 + + ssat16 r0, #1, r0 + ssat16 r9, #1, r0 + ssat16 r0, #10, r0 + ssat16 r0, #1, r9 + + usat r0, #0, r0 + usat r0, #0, r0, lsl #0 + usat r0, #0, r0, asr #0 + usat r9, #0, r0 + usat r0, #17, r0 + usat r0, #0, r9 + usat r0, #0, r0, lsl #0x1c + usat r0, #0, r0, asr #0x03 + + usat16 r0, #0, r0 + usat16 r9, #0, r0 + usat16 r0, #9, r0 + usat16 r0, #0, r9 + +xt: + sxtb r0, r0 + sxtb r0, r0, ror #0 + sxtb r5, r0 + sxtb r0, r5 + sxtb.w r1, r2 + sxtb r1, r2, ror #8 + sxtb r1, r2, ror #16 + sxtb r1, r2, ror #24 + + sxtb16 r1, r2 + sxtb16 r8, r9 + sxth r1, r2 + sxth r8, r9 + uxtb r1, r2 + uxtb r8, r9 + uxtb16 r1, r2 + uxtb16 r8, r9 + uxth r1, r2 + uxth r8, r9 + +xta: + sxtab r0, r0, r0 + sxtab r0, r0, r0, ror #0 + sxtab r9, r0, r0, ror #8 + sxtab r0, r9, r0, ror #16 + sxtab r0, r0, r9, ror #24 + + sxtab16 r1, r2, r3 + sxtah r1, r2, r3 + uxtab r1, r2, r3 + uxtab16 r1, r2, r3 + uxtah r1, r2, r3 diff --git a/gas/testsuite/gas/arm/thumbv6.d b/gas/testsuite/gas/arm/thumbv6.d index 12860b3..5dc8214 100644 --- a/gas/testsuite/gas/arm/thumbv6.d +++ b/gas/testsuite/gas/arm/thumbv6.d @@ -7,7 +7,7 @@ Disassembly of section .text: 0+000 <[^>]*> b666 * cpsie ai 0+002 <[^>]*> b675 * cpsid af -0+004 <[^>]*> 4623 * cpy r3, r4 +0+004 <[^>]*> 4623 * mov r3, r4 0+006 <[^>]*> ba3a * rev r2, r7 0+008 <[^>]*> ba4d * rev16 r5, r1 0+00a <[^>]*> baf3 * revsh r3, r6 diff --git a/gas/testsuite/gas/arm/vfp-bad.l b/gas/testsuite/gas/arm/vfp-bad.l index 04bb04d..7726e63 100644 --- a/gas/testsuite/gas/arm/vfp-bad.l +++ b/gas/testsuite/gas/arm/vfp-bad.l @@ -1,9 +1,9 @@ [^:]*: Assembler messages: -[^:]*:4: Error: garbage following instruction -- `fstd d0,\[r0\],#8' -[^:]*:5: Error: garbage following instruction -- `fstd d0,\[r0,#-8\]!' -[^:]*:6: Error: garbage following instruction -- `fsts s0,\[r0\],#8' -[^:]*:7: Error: garbage following instruction -- `fsts s0,\[r0,#-8\]!' -[^:]*:8: Error: garbage following instruction -- `fldd d0,\[r0\],#8' -[^:]*:9: Error: garbage following instruction -- `fldd d0,\[r0,#-8\]!' -[^:]*:10: Error: garbage following instruction -- `flds s0,\[r0\],#8' -[^:]*:11: Error: garbage following instruction -- `flds s0,\[r0,#-8\]!' +[^:]*:4: Error: instruction does not support writeback -- `fstd d0,\[r0\],#8' +[^:]*:5: Error: instruction does not support writeback -- `fstd d0,\[r0,#-8\]!' +[^:]*:6: Error: instruction does not support writeback -- `fsts s0,\[r0\],#8' +[^:]*:7: Error: instruction does not support writeback -- `fsts s0,\[r0,#-8\]!' +[^:]*:8: Error: instruction does not support writeback -- `fldd d0,\[r0\],#8' +[^:]*:9: Error: instruction does not support writeback -- `fldd d0,\[r0,#-8\]!' +[^:]*:10: Error: instruction does not support writeback -- `flds s0,\[r0\],#8' +[^:]*:11: Error: instruction does not support writeback -- `flds s0,\[r0,#-8\]!' |