X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-arm.c;h=484acb5b6ac6a385cf442d9b99aad27c666779f8;hb=10a9829174397471ff95856c94aac352190ca7b9;hp=a6bbba1e0766ab082e3e07e4f20dca984741b829;hpb=5a38dc70b43becf6e5865c90d5dcaf254f5af0e1;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index a6bbba1e07..484acb5b6a 100644 --- a/gas/config/tc-arm.c +++ b/gas/config/tc-arm.c @@ -1,5 +1,5 @@ /* tc-arm.c -- Assemble for the ARM - Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 + Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) Modified by David Taylor (dtaylor@armltd.co.uk) @@ -59,6 +59,7 @@ /* Co-processor space extensions. */ #define ARM_CEXT_XSCALE 0x00800000 /* Allow MIA etc. */ #define ARM_CEXT_MAVERICK 0x00400000 /* Use Cirrus/DSP coprocessor. */ +#define ARM_CEXT_IWMMXT 0x00200000 /* Intel Wireless MMX technology coprocessor. */ /* Architectures are the sum of the base and extensions. The ARM ARM (rev E) defines the following: ARMv3, ARMv3M, ARMv4xM, ARMv4, ARMv4TxM, ARMv4T, @@ -84,6 +85,7 @@ /* Processors with specific extensions in the co-processor space. */ #define ARM_ARCH_XSCALE (ARM_ARCH_V5TE | ARM_CEXT_XSCALE) +#define ARM_ARCH_IWMMXT (ARM_ARCH_XSCALE | ARM_CEXT_IWMMXT) /* Some useful combinations: */ #define ARM_ANY 0x0000ffff /* Any basic core. */ @@ -144,11 +146,11 @@ static unsigned long cpu_variant; static int target_oabi = 0; /* Flags stored in private area of BFD structure. */ -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 uses_apcs_26 = FALSE; +static int atpcs = FALSE; +static int support_interwork = FALSE; +static int uses_apcs_float = 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 @@ -342,8 +344,8 @@ static const struct asm_cond conds[] = struct asm_psr { - const char * template; - boolean cpsr; + const char *template; + bfd_boolean cpsr; unsigned long field; }; @@ -360,143 +362,172 @@ struct asm_psr 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}, + {"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}, + {"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 @@ -543,6 +574,10 @@ struct reg_entry #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. */ /* Integer Register Numbers. */ static const struct reg_entry rn_table[] = @@ -562,6 +597,40 @@ static const struct reg_entry rn_table[] = {NULL, 0} }; +#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}, {"wr1", 0x1 | WR_PREFIX}, + { "wr2", 0x2 | WR_PREFIX}, {"wr3", 0x3 | WR_PREFIX}, + { "wr4", 0x4 | WR_PREFIX}, {"wr5", 0x5 | WR_PREFIX}, + { "wr6", 0x6 | WR_PREFIX}, {"wr7", 0x7 | WR_PREFIX}, + { "wr8", 0x8 | WR_PREFIX}, {"wr9", 0x9 | WR_PREFIX}, + { "wr10", 0xa | WR_PREFIX}, {"wr11", 0xb | WR_PREFIX}, + { "wr12", 0xc | WR_PREFIX}, {"wr13", 0xd | WR_PREFIX}, + { "wr14", 0xe | WR_PREFIX}, {"wr15", 0xf | WR_PREFIX}, + { "wcid", 0x0 | WC_PREFIX}, {"wcon", 0x1 | WC_PREFIX}, + {"wcssf", 0x2 | WC_PREFIX}, {"wcasf", 0x3 | WC_PREFIX}, + {"wcgr0", 0x8 | WC_PREFIX}, {"wcgr1", 0x9 | WC_PREFIX}, + {"wcgr2", 0xa | WC_PREFIX}, {"wcgr3", 0xb | WC_PREFIX}, + + { "wR0", 0x0 | WR_PREFIX}, {"wR1", 0x1 | WR_PREFIX}, + { "wR2", 0x2 | WR_PREFIX}, {"wR3", 0x3 | WR_PREFIX}, + { "wR4", 0x4 | WR_PREFIX}, {"wR5", 0x5 | WR_PREFIX}, + { "wR6", 0x6 | WR_PREFIX}, {"wR7", 0x7 | WR_PREFIX}, + { "wR8", 0x8 | WR_PREFIX}, {"wR9", 0x9 | WR_PREFIX}, + { "wR10", 0xa | WR_PREFIX}, {"wR11", 0xb | WR_PREFIX}, + { "wR12", 0xc | WR_PREFIX}, {"wR13", 0xd | WR_PREFIX}, + { "wR14", 0xe | WR_PREFIX}, {"wR15", 0xf | WR_PREFIX}, + { "wCID", 0x0 | WC_PREFIX}, {"wCon", 0x1 | WC_PREFIX}, + {"wCSSF", 0x2 | WC_PREFIX}, {"wCASF", 0x3 | WC_PREFIX}, + {"wCGR0", 0x8 | WC_PREFIX}, {"wCGR1", 0x9 | WC_PREFIX}, + {"wCGR2", 0xa | WC_PREFIX}, {"wCGR3", 0xb | WC_PREFIX}, + {NULL, 0} +}; + /* Co-processor Numbers. */ static const struct reg_entry cp_table[] = { @@ -690,6 +759,7 @@ struct reg_map all_reg_maps[] = {mav_mvdx_table, 15, NULL, N_("Maverick MVFX 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. */ @@ -708,8 +778,9 @@ enum arm_reg_type REG_TYPE_MVDX = 9, REG_TYPE_MVAX = 10, REG_TYPE_DSPSC = 11, + REG_TYPE_IWMMXT = 12, - REG_TYPE_MAX = 12 + REG_TYPE_MAX = 13 }; /* Functions called by parser. */ @@ -938,6 +1009,31 @@ static symbolS * find_real_start PARAMS ((symbolS *)); static bfd_reloc_code_real_type arm_parse_reloc PARAMS ((void)); #endif +static int wreg_required_here PARAMS ((char **, int, enum wreg_type)); +static void do_iwmmxt_byte_addr PARAMS ((char *)); +static void do_iwmmxt_tandc PARAMS ((char *)); +static void do_iwmmxt_tbcst PARAMS ((char *)); +static void do_iwmmxt_textrc PARAMS ((char *)); +static void do_iwmmxt_textrm PARAMS ((char *)); +static void do_iwmmxt_tinsr PARAMS ((char *)); +static void do_iwmmxt_tmcr PARAMS ((char *)); +static void do_iwmmxt_tmcrr PARAMS ((char *)); +static void do_iwmmxt_tmia PARAMS ((char *)); +static void do_iwmmxt_tmovmsk PARAMS ((char *)); +static void do_iwmmxt_tmrc PARAMS ((char *)); +static void do_iwmmxt_tmrrc PARAMS ((char *)); +static void do_iwmmxt_torc PARAMS ((char *)); +static void do_iwmmxt_waligni PARAMS ((char *)); +static void do_iwmmxt_wmov PARAMS ((char *)); +static void do_iwmmxt_word_addr PARAMS ((char *)); +static void do_iwmmxt_wrwr PARAMS ((char *)); +static void do_iwmmxt_wrwrwcg PARAMS ((char *)); +static void do_iwmmxt_wrwrwr PARAMS ((char *)); +static void do_iwmmxt_wshufh PARAMS ((char *)); +static void do_iwmmxt_wzero PARAMS ((char *)); +static int cp_byte_address_offset PARAMS ((char **)); +static int cp_byte_address_required_here PARAMS ((char **)); + /* ARM instructions take 4bytes in the object file, Thumb instructions take 2: */ #define INSN_SIZE 4 @@ -1728,6 +1824,170 @@ static const struct asm_opcode insns[] = {"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}, @@ -2061,9 +2321,6 @@ static void s_code PARAMS ((int)); static void s_force_thumb PARAMS ((int)); static void s_thumb_func PARAMS ((int)); static void s_thumb_set PARAMS ((int)); -static void arm_s_text PARAMS ((int)); -static void arm_s_data PARAMS ((int)); -static void arm_s_section PARAMS ((int)); #ifdef OBJ_ELF static void s_arm_elf_cons PARAMS ((int)); #endif @@ -2085,17 +2342,10 @@ const pseudo_typeS md_pseudo_table[] = { "even", s_even, 0 }, { "ltorg", s_ltorg, 0 }, { "pool", s_ltorg, 0 }, - /* Allow for the effect of section changes. */ - { "text", arm_s_text, 0 }, - { "data", arm_s_data, 0 }, - { "section", arm_s_section, 0 }, - { "section.s", arm_s_section, 0 }, - { "sect", arm_s_section, 0 }, - { "sect.s", arm_s_section, 0 }, #ifdef OBJ_ELF { "word", s_arm_elf_cons, 4 }, { "long", s_arm_elf_cons, 4 }, - { "file", dwarf2_directive_file, 0 }, + { "file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0 }, { "loc", dwarf2_directive_loc, 0 }, #else { "word", cons, 4}, @@ -2111,6 +2361,9 @@ static int arm_parse_extension PARAMS ((char *, int *)); static int arm_parse_cpu PARAMS ((char *)); static int arm_parse_arch PARAMS ((char *)); static int arm_parse_fpu PARAMS ((char *)); +#if defined OBJ_COFF || defined OBJ_ELF +static void arm_add_note PARAMS ((const char *, const char *, unsigned int)); +#endif /* Stuff needed to resolve the label ambiguity As: @@ -2123,75 +2376,132 @@ static int arm_parse_fpu PARAMS ((char *)); */ symbolS * last_label_seen; -static int label_is_thumb_function_name = false; +static int label_is_thumb_function_name = FALSE; -/* Literal stuff. */ +/* Literal Pool stuff. */ #define MAX_LITERAL_POOL_SIZE 1024 -typedef struct literalS +/* Literal pool structure. Held on a per-section + and per-sub-section basis. */ +typedef struct literal_pool { - struct expressionS exp; - struct arm_it * inst; -} literalT; + 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; -literalT literals[MAX_LITERAL_POOL_SIZE]; +/* Pointer to a linked list of literal pools. */ +literal_pool * list_of_pools = NULL; -/* Next free entry in the pool. */ -int next_literal_pool_place = 0; +static literal_pool * find_literal_pool PARAMS ((void)); +static literal_pool * find_or_make_literal_pool PARAMS ((void)); + +static literal_pool * +find_literal_pool () +{ + literal_pool * pool; + + for (pool = list_of_pools; pool != NULL; pool = pool->next) + { + if (pool->section == now_seg + && pool->sub_section == now_subseg) + break; + } + + return pool; +} + +static literal_pool * +find_or_make_literal_pool () +{ + /* Next literal pool ID number. */ + static unsigned int latest_pool_num = 1; + literal_pool * pool; + + pool = find_literal_pool (); + + if (pool == NULL) + { + /* Create a new pool. */ + pool = (literal_pool *) xmalloc (sizeof (* pool)); + if (! pool) + return NULL; + + pool->next_free_entry = 0; + pool->section = now_seg; + pool->sub_section = now_subseg; + pool->next = list_of_pools; + pool->symbol = NULL; + + /* Add it to the list. */ + list_of_pools = pool; + } -/* Next literal pool number. */ -int lit_pool_num = 1; + /* 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 ++; + } -symbolS * current_poolP = NULL; + /* Done. */ + return pool; +} +/* Add the literal in the global 'inst' + structure to the relevent literal pool. */ static int add_to_lit_pool () { - int lit_count = 0; + literal_pool * pool; + unsigned int entry; - if (current_poolP == NULL) - current_poolP = symbol_create (FAKE_LABEL_NAME, undefined_section, - (valueT) 0, &zero_address_frag); + pool = find_or_make_literal_pool (); - /* Check if this literal value is already in the pool: */ - while (lit_count < next_literal_pool_place) + /* Check if this literal value is already in the pool. */ + for (entry = 0; entry < pool->next_free_entry; entry ++) { - if (literals[lit_count].exp.X_op == inst.reloc.exp.X_op - && inst.reloc.exp.X_op == O_constant - && (literals[lit_count].exp.X_add_number + 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) - && literals[lit_count].exp.X_unsigned == inst.reloc.exp.X_unsigned) + && (pool->literals[entry].X_unsigned + == inst.reloc.exp.X_unsigned)) break; - if (literals[lit_count].exp.X_op == inst.reloc.exp.X_op - && inst.reloc.exp.X_op == O_symbol - && (literals[lit_count].exp.X_add_number + 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) - && (literals[lit_count].exp.X_add_symbol + && (pool->literals[entry].X_add_symbol == inst.reloc.exp.X_add_symbol) - && (literals[lit_count].exp.X_op_symbol + && (pool->literals[entry].X_op_symbol == inst.reloc.exp.X_op_symbol)) - break; - - lit_count++; + break; } - if (lit_count == next_literal_pool_place) /* New entry. */ + /* Do we need to create a new entry? */ + if (entry == pool->next_free_entry) { - if (next_literal_pool_place >= MAX_LITERAL_POOL_SIZE) + if (entry >= MAX_LITERAL_POOL_SIZE) { inst.error = _("literal pool overflow"); return FAIL; } - literals[next_literal_pool_place].exp = inst.reloc.exp; - lit_count = next_literal_pool_place++; + pool->literals[entry] = inst.reloc.exp; + pool->next_free_entry += 1; } - inst.reloc.exp.X_op = O_symbol; - inst.reloc.exp.X_add_number = (lit_count) * 4 - 8; - inst.reloc.exp.X_add_symbol = current_poolP; + 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 SUCCESS; } @@ -2353,10 +2663,14 @@ static void s_ltorg (ignored) int ignored ATTRIBUTE_UNUSED; { - int lit_count = 0; + unsigned int entry; + literal_pool * pool; char sym_name[20]; - if (current_poolP == NULL) + pool = find_literal_pool (); + if (pool == NULL + || pool->symbol == NULL + || pool->next_free_entry == 0) return; /* Align pool as you have word accesses. @@ -2366,24 +2680,25 @@ s_ltorg (ignored) record_alignment (now_seg, 2); - sprintf (sym_name, "$$lit_\002%x", lit_pool_num++); + sprintf (sym_name, "$$lit_\002%x", pool->id); - symbol_locate (current_poolP, sym_name, now_seg, + symbol_locate (pool->symbol, sym_name, now_seg, (valueT) frag_now_fix (), frag_now); - symbol_table_insert (current_poolP); + symbol_table_insert (pool->symbol); - ARM_SET_THUMB (current_poolP, thumb_mode); + ARM_SET_THUMB (pool->symbol, thumb_mode); #if defined OBJ_COFF || defined OBJ_ELF - ARM_SET_INTERWORK (current_poolP, support_interwork); + ARM_SET_INTERWORK (pool->symbol, support_interwork); #endif - while (lit_count < next_literal_pool_place) + for (entry = 0; entry < pool->next_free_entry; entry ++) /* First output the expression in the instruction to the pool. */ - emit_expr (&(literals[lit_count++].exp), 4); /* .word */ + emit_expr (&(pool->literals[entry]), 4); /* .word */ - next_literal_pool_place = 0; - current_poolP = NULL; + /* Mark the pool as empty. */ + pool->next_free_entry = 0; + pool->symbol = NULL; } /* Same as s_align_ptwo but align 0 => align 2. */ @@ -2452,7 +2767,7 @@ s_thumb_func (ignore) /* The following label is the name/address of the start of a Thumb function. We need to know this for the interworking support. */ - label_is_thumb_function_name = true; + label_is_thumb_function_name = TRUE; demand_empty_rest_of_line (); } @@ -2550,55 +2865,6 @@ s_thumb_set (equiv) #endif } -/* If we change section we must dump the literal pool first. */ - -static void -arm_s_text (ignore) - int ignore; -{ - if (now_seg != text_section) - s_ltorg (0); - -#ifdef OBJ_ELF - obj_elf_text (ignore); -#else - s_text (ignore); -#endif -} - -static void -arm_s_data (ignore) - int ignore; -{ - if (flag_readonly_data_in_text) - { - if (now_seg != text_section) - s_ltorg (0); - } - else if (now_seg != data_section) - s_ltorg (0); - -#ifdef OBJ_ELF - obj_elf_data (ignore); -#else - s_data (ignore); -#endif -} - -static void -arm_s_section (ignore) - int ignore; -{ - s_ltorg (0); - -#ifdef OBJ_ELF - obj_elf_section (ignore); -#endif -#ifdef OBJ_COFF - obj_coff_section (ignore); -#endif -} - static void opcode_select (width) int width; @@ -2736,6 +3002,57 @@ reg_required_here (str, shift) 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 (str, shift, reg_type) + 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; +} + static const struct asm_psr * arm_psr_parse (ccp) register char ** ccp; @@ -3073,6 +3390,144 @@ cp_address_required_here (str, wb_ok) return SUCCESS; } +static int +cp_byte_address_offset (str) + char ** str; +{ + int offset; + + skip_whitespace (* str); + + if (! is_immediate_prefix (**str)) + { + inst.error = _("immediate expression expected"); + return FAIL; + } + + (*str)++; + + if (my_get_expression (& inst.reloc.exp, str)) + return FAIL; + + if (inst.reloc.exp.X_op == O_constant) + { + offset = inst.reloc.exp.X_add_number; + + if (offset > 255 || offset < -255) + { + inst.error = _("offset too large"); + return FAIL; + } + + if (offset >= 0) + inst.instruction |= INDEX_UP; + else + offset = -offset; + + inst.instruction |= offset; + } + else + inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM_S2; + + return SUCCESS; +} + +static int +cp_byte_address_required_here (str) + char ** str; +{ + char * p = * str; + int pre_inc = 0; + int write_back = 0; + + if (*p == '[') + { + int reg; + + p++; + skip_whitespace (p); + + if ((reg = reg_required_here (& p, 16)) == FAIL) + return FAIL; + + skip_whitespace (p); + + 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']'[!] */ + + if (skip_past_comma (& p) == FAIL) + { + inst.error = _("pre-indexed expression expected"); + return FAIL; + } + + pre_inc = PRE_INDEX; + + if (cp_byte_address_offset (& p) == FAIL) + return FAIL; + + skip_whitespace (p); + + if (*p++ != ']') + { + inst.error = _("missing ]"); + return FAIL; + } + + skip_whitespace (p); + + if (*p == '!') + { + if (reg == REG_PC) + { + inst.error = _("pc may not be used with write-back"); + return FAIL; + } + + 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_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; + } + + inst.instruction |= write_back | pre_inc; + *str = p; + return SUCCESS; +} + static void do_empty (str) char * str; @@ -3926,9 +4381,12 @@ do_t_bkpt (str) str ++; memset (& expr, '\0', sizeof (expr)); - if (my_get_expression (& expr, & str) || (expr.X_op != O_constant)) + 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)) { - inst.error = _("bad or missing expression"); + inst.error = _("bad expression"); return; } @@ -4108,9 +4566,12 @@ do_bkpt (str) memset (& expr, '\0', sizeof (expr)); - if (my_get_expression (& expr, & str) || (expr.X_op != O_constant)) + 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)) { - inst.error = _("bad or missing expression"); + inst.error = _("bad expression"); return; } @@ -4132,6 +4593,449 @@ do_bkpt (str) end_of_line (str); } +static unsigned long check_iwmmxt_insn PARAMS ((char *, enum iwmmxt_insn_type, int)); + +/* Parse INSN_TYPE insn STR having a possible IMMEDIATE_SIZE immediate. */ + +static unsigned long +check_iwmmxt_insn (str, insn_type, immediate_size) + 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; + } +} + +static void +do_iwmmxt_byte_addr (str) + char * str; +{ + 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)) + { + inst.instruction |= 0xf0000100; + inst.instruction &= ~0x00400000; + } +} + +static void +do_iwmmxt_tandc (str) + char * str; +{ + int reg; + + reg = check_iwmmxt_insn (str, check_rd, 0); + + if (reg != REG_PC && !inst.error) + inst.error = _("only r15 allowed here"); + return; +} + +static void +do_iwmmxt_tbcst (str) + char * str; +{ + check_iwmmxt_insn (str, check_tbcst, 0); + + return; +} + +static void +do_iwmmxt_textrc (str) + char * str; +{ + unsigned long number; + + if ((number = check_iwmmxt_insn (str, check_textrc, 7)) == (unsigned long) FAIL) + return; + + inst.instruction |= number & 0x7; + return; +} + +static void +do_iwmmxt_textrm (str) + char * str; +{ + unsigned long number; + + if ((number = check_iwmmxt_insn (str, check_textrm, 7)) == (unsigned long) FAIL) + return; + + inst.instruction |= number & 0x7; +} + +static void +do_iwmmxt_tinsr (str) + char * str; +{ + unsigned long number; + + if ((number = check_iwmmxt_insn (str, check_tinsr, 7)) == (unsigned long) FAIL) + return; + + inst.instruction |= number & 0x7; + return; +} + +static void +do_iwmmxt_tmcr (str) + char * str; +{ + check_iwmmxt_insn (str, check_tmcr, 0); + + return; +} + +static void +do_iwmmxt_tmcrr (str) + char * str; +{ + check_iwmmxt_insn (str, check_tmcrr, 0); + + return; +} + +static void +do_iwmmxt_tmia (str) + char * str; +{ + check_iwmmxt_insn (str, check_tmia, 0); + + return; +} + +static void +do_iwmmxt_tmovmsk (str) + char * str; +{ + check_iwmmxt_insn (str, check_tmovmsk, 0); + + return; +} + +static void +do_iwmmxt_tmrc (str) + char * str; +{ + check_iwmmxt_insn (str, check_tmrc, 0); + + return; +} + +static void +do_iwmmxt_tmrrc (str) + char * str; +{ + check_iwmmxt_insn (str, check_tmrrc, 0); + + return; +} + +static void +do_iwmmxt_torc (str) + char * str; +{ + check_iwmmxt_insn (str, check_rd, 0); + return; +} + +static void +do_iwmmxt_waligni (str) + char * str; +{ + unsigned long number; + + if ((number = check_iwmmxt_insn (str, check_waligni, 7)) == (unsigned long) FAIL) + return; + + inst.instruction |= ((number & 0x7) << 20); + return; +} + +static void +do_iwmmxt_wmov (str) + char * str; +{ + if (check_iwmmxt_insn (str, check_wrwr, 0) == (unsigned long) FAIL) + return; + + inst.instruction |= ((inst.instruction >> 16) & 0xf); + return; +} + +static void +do_iwmmxt_word_addr (str) + char * str; +{ + 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_address_required_here (& str, CP_WB_OK) == FAIL) + { + if (! inst.error) + inst.error = BAD_ARGS; + } + else + end_of_line (str); + + if (wc_register (reg)) + { + inst.instruction |= 0xf0000100; + inst.instruction &= ~0x00400000; + } +} + +static void +do_iwmmxt_wrwr (str) + char * str; +{ + check_iwmmxt_insn (str, check_wrwr, 0); + + return; +} + +static void +do_iwmmxt_wrwrwcg (str) + char * str; +{ + check_iwmmxt_insn (str, check_wrwrwcg, 0); + + return; +} + +static void +do_iwmmxt_wrwrwr (str) + char * str; +{ + check_iwmmxt_insn (str, check_wrwrwr, 0); + + return; +} + +static void +do_iwmmxt_wshufh (str) + char * str; +{ + unsigned long number; + + if ((number = check_iwmmxt_insn (str, check_wshufh, 0xff)) == (unsigned long) FAIL) + return; + + inst.instruction |= ((number & 0xf0) << 16) | (number & 0xf); + return; +} + +static void +do_iwmmxt_wzero (str) + char * str; +{ + if (check_iwmmxt_insn (str, check_wr, 0) == (unsigned long) FAIL) + return; + + inst.instruction |= ((inst.instruction & 0xf) << 12) | ((inst.instruction & 0xf) << 16); + return; +} + /* Xscale multiply-accumulate (argument parse) MIAcc acc0,Rm,Rs MIAPHcc acc0,Rm,Rs @@ -4440,7 +5344,7 @@ my_get_float_expression (str) return -1; } -/* Return true if anything in the expression is a bignum. */ +/* Return TRUE if anything in the expression is a bignum. */ static int walk_no_bignums (sp) @@ -5763,6 +6667,31 @@ do_ldmstm (str) inst.instruction |= LDM_TYPE_2_OR_3; } + 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); return; @@ -9157,6 +10086,54 @@ build_arm_ops_hsh () } } +#if defined OBJ_ELF || defined OBJ_COFF + +#ifdef OBJ_ELF +#define arm_Note Elf_External_Note +#else +typedef struct +{ + unsigned char namesz[4]; /* Size of entry's owner string. */ + unsigned char descsz[4]; /* Size of the note descriptor. */ + unsigned char type[4]; /* Interpretation of the descriptor. */ + char name[1]; /* Start of the name+desc data. */ +} arm_Note; +#endif + +/* The description is kept to a fix sized in order to make updating + it and merging it easier. */ +#define ARM_NOTE_DESCRIPTION_LENGTH 8 + +static void +arm_add_note (name, description, type) + const char * name; + const char * description; + unsigned int type; +{ + arm_Note note ATTRIBUTE_UNUSED; + char * p; + unsigned int name_len; + + name_len = (strlen (name) + 1 + 3) & ~3; + + p = frag_more (sizeof (note.namesz)); + md_number_to_chars (p, (valueT) name_len, sizeof (note.namesz)); + + p = frag_more (sizeof (note.descsz)); + md_number_to_chars (p, (valueT) ARM_NOTE_DESCRIPTION_LENGTH, sizeof (note.descsz)); + + p = frag_more (sizeof (note.type)); + md_number_to_chars (p, (valueT) type, sizeof (note.type)); + + p = frag_more (name_len); + strcpy (p, name); + + p = frag_more (ARM_NOTE_DESCRIPTION_LENGTH); + strncpy (p, description, ARM_NOTE_DESCRIPTION_LENGTH); + frag_align (2, 0, 0); +} +#endif + void md_begin () { @@ -9244,6 +10221,13 @@ md_begin () /* 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 & ARM_CEXT_MAVERICK) + { + flags ^= F_SOFT_FLOAT; + flags |= EF_ARM_MAVERICK_FLOAT; + } +#endif bfd_set_private_flags (stdoutput, flags); @@ -9283,13 +10267,17 @@ md_begin () break; default: - mach = bfd_mach_arm_4; + mach = bfd_mach_arm_unknown; break; } /* Catch special cases. */ - if (cpu_variant & ARM_CEXT_XSCALE) + 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) @@ -9309,6 +10297,59 @@ md_begin () else if (cpu_variant & ARM_EXT_V3M) mach = bfd_mach_arm_3M; +#if 0 /* Suppressed - for now. */ +#if defined (OBJ_ELF) || defined (OBJ_COFF) + + /* Create a .note section to fully identify this arm binary. */ + +#define NOTE_ARCH_STRING "arch: " + +#if defined OBJ_COFF && ! defined NT_VERSION +#define NT_VERSION 1 +#define NT_ARCH 2 +#endif + + { + segT current_seg = now_seg; + subsegT current_subseg = now_subseg; + asection * arm_arch; + const char * arch_string; + + arm_arch = bfd_make_section_old_way (stdoutput, ARM_NOTE_SECTION); + +#ifdef OBJ_COFF + bfd_set_section_flags (stdoutput, arm_arch, + SEC_DATA | SEC_ALLOC | SEC_LOAD | SEC_LINK_ONCE \ + | SEC_HAS_CONTENTS); +#endif + arm_arch->output_section = arm_arch; + subseg_set (arm_arch, 0); + + switch (mach) + { + default: + case bfd_mach_arm_unknown: arch_string = "unknown"; break; + case bfd_mach_arm_2: arch_string = "armv2"; break; + case bfd_mach_arm_2a: arch_string = "armv2a"; break; + case bfd_mach_arm_3: arch_string = "armv3"; break; + case bfd_mach_arm_3M: arch_string = "armv3M"; break; + case bfd_mach_arm_4: arch_string = "armv4"; break; + case bfd_mach_arm_4T: arch_string = "armv4t"; break; + case bfd_mach_arm_5: arch_string = "armv5"; break; + case bfd_mach_arm_5T: arch_string = "armv5t"; break; + case bfd_mach_arm_5TE: arch_string = "armv5te"; break; + case bfd_mach_arm_XScale: arch_string = "XScale"; break; + case bfd_mach_arm_ep9312: arch_string = "ep9312"; break; + case bfd_mach_arm_iWMMXt: arch_string = "iWMMXt"; break; + } + + arm_add_note (NOTE_ARCH_STRING, arch_string, NT_ARCH); + + subseg_set (current_seg, current_subseg); + } +#endif +#endif /* Suppressed code. */ + bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach); } @@ -9649,12 +10690,14 @@ md_apply_fix3 (fixP, valP, seg) newimm |= (temp & 0xfffff000); md_number_to_chars (buf, (valueT) newimm, INSN_SIZE); + fixP->fx_done = 1; break; case BFD_RELOC_ARM_ADRL_IMMEDIATE: { unsigned int highpart = 0; unsigned int newinsn = 0xe1a00000; /* nop. */ + newimm = validate_immediate (value); temp = md_chars_to_number (buf, INSN_SIZE); @@ -9679,7 +10722,7 @@ md_apply_fix3 (fixP, valP, seg) { as_bad_where (fixP->fx_file, fixP->fx_line, _("unable to compute ADRL instructions for PC offset of 0x%lx"), - value); + (long) value); break; } @@ -10007,10 +11050,6 @@ md_apply_fix3 (fixP, valP, seg) break; #endif - case BFD_RELOC_ARM_GOTPC: - md_number_to_chars (buf, value, 4); - break; - case BFD_RELOC_ARM_CP_OFF_IMM: sign = value >= 0; if (value < -1023 || value > 1023 || (value & 3)) @@ -10023,6 +11062,18 @@ md_apply_fix3 (fixP, valP, seg) 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; + case BFD_RELOC_ARM_THUMB_OFFSET: newval = md_chars_to_number (buf, THUMB_SIZE); /* Exactly what ranges, and where the offset is inserted depends @@ -10045,7 +11096,8 @@ md_apply_fix3 (fixP, valP, seg) if ((value + 2) & ~0x3fe) as_bad_where (fixP->fx_file, fixP->fx_line, - _("invalid offset, value too big (0x%08lX)"), value); + _("invalid offset, value too big (0x%08lX)"), + (long) value); /* Round up, since pc will be rounded down. */ newval |= (value + 2) >> 2; @@ -10054,28 +11106,32 @@ md_apply_fix3 (fixP, valP, seg) case 9: /* SP load/store. */ if (value & ~0x3fc) as_bad_where (fixP->fx_file, fixP->fx_line, - _("invalid offset, value too big (0x%08lX)"), value); + _("invalid offset, value too big (0x%08lX)"), + (long) value); newval |= value >> 2; break; case 6: /* Word load/store. */ if (value & ~0x7c) as_bad_where (fixP->fx_file, fixP->fx_line, - _("invalid offset, value too big (0x%08lX)"), value); + _("invalid offset, value too big (0x%08lX)"), + (long) value); newval |= value << 4; /* 6 - 2. */ break; case 7: /* Byte load/store. */ if (value & ~0x1f) as_bad_where (fixP->fx_file, fixP->fx_line, - _("invalid offset, value too big (0x%08lX)"), value); + _("invalid offset, value too big (0x%08lX)"), + (long) value); newval |= value << 6; break; case 8: /* Halfword load/store. */ if (value & ~0x3e) as_bad_where (fixP->fx_file, fixP->fx_line, - _("invalid offset, value too big (0x%08lX)"), value); + _("invalid offset, value too big (0x%08lX)"), + (long) value); newval |= value << 5; /* 6 - 1. */ break; @@ -10254,10 +11310,10 @@ tc_gen_reloc (section, fixp) case BFD_RELOC_ARM_LITERAL: case BFD_RELOC_ARM_HWLITERAL: - /* If this is called then the a literal has been referenced across - a section boundary - possibly due to an implicit dump. */ + /* If this is called then the a literal has + been referenced across a section boundary. */ as_bad_where (fixp->fx_file, fixp->fx_line, - _("literal referenced across section boundary (Implicit dump?)")); + _("literal referenced across section boundary")); return NULL; #ifdef OBJ_ELF @@ -10270,8 +11326,7 @@ tc_gen_reloc (section, fixp) case BFD_RELOC_ARM_IMMEDIATE: as_bad_where (fixp->fx_file, fixp->fx_line, - _("internal relocation (type %d) not fixed up (IMMEDIATE)"), - fixp->fx_r_type); + _("internal relocation (type: IMMEDIATE) not fixed up")); return NULL; case BFD_RELOC_ARM_ADRL_IMMEDIATE: @@ -10281,8 +11336,7 @@ tc_gen_reloc (section, fixp) case BFD_RELOC_ARM_OFFSET_IMM: as_bad_where (fixp->fx_file, fixp->fx_line, - _("internal_relocation (type %d) not fixed up (OFFSET_IMM)"), - fixp->fx_r_type); + _("internal_relocation (type: OFFSET_IMM) not fixed up")); return NULL; default: @@ -10291,8 +11345,6 @@ tc_gen_reloc (section, fixp) switch (fixp->fx_r_type) { - case BFD_RELOC_ARM_IMMEDIATE: type = "IMMEDIATE"; break; - case BFD_RELOC_ARM_OFFSET_IMM: type = "OFFSET_IMM"; 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_SWI: type = "SWI"; break; @@ -10312,7 +11364,7 @@ tc_gen_reloc (section, fixp) } #ifdef OBJ_ELF - if (code == BFD_RELOC_32_PCREL + if ((code == BFD_RELOC_32_PCREL || code == BFD_RELOC_32) && GOT_symbol && fixp->fx_addsy == GOT_symbol) { @@ -10505,7 +11557,7 @@ md_assemble (str) -mthumb Start in Thumb mode -mthumb-interwork Code supports ARM/Thumb interworking - For now we will also provide support for + For now we will also provide support for: -mapcs-32 32-bit Program counter -mapcs-26 26-bit Program counter @@ -10680,6 +11732,7 @@ struct arm_option_table arm_opts[] = {"mstrongarm1110", NULL, &legacy_cpu, ARM_ARCH_V4, 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")}, /* Architecture variants -- don't add any more to this list either. */ @@ -10784,6 +11837,8 @@ static struct arm_cpu_option_table arm_cpus[] = {"arm1020e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2}, /* ??? XSCALE is really an architecture. */ {"xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2}, + /* ??? iwmmxt is not a processor. */ + {"iwmmxt", ARM_ARCH_IWMMXT, FPU_ARCH_VFP_V2}, {"i80200", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2}, /* Maverick */ {"ep9312", ARM_ARCH_V4T | ARM_CEXT_MAVERICK, FPU_NONE}, @@ -10833,6 +11888,7 @@ static struct arm_arch_extension_table arm_extensions[] = { {"maverick", ARM_CEXT_MAVERICK}, {"xscale", ARM_CEXT_XSCALE}, + {"iwmmxt", ARM_CEXT_IWMMXT}, {NULL, 0} }; @@ -11210,12 +12266,14 @@ cons_fix_new_arm (frag, where, size, exp) void arm_cleanup () { - if (current_poolP == NULL) - return; + literal_pool * pool; - /* Put it at the end of text section. */ - subseg_set (text_section, 0); - s_ltorg (0); + 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); + s_ltorg (0); + } } void @@ -11276,7 +12334,7 @@ arm_frob_label (sym) THUMB_SET_FUNC (sym, 1); - label_is_thumb_function_name = false; + label_is_thumb_function_name = FALSE; } } @@ -11380,7 +12438,8 @@ arm_canonicalize_symbol_name (name) return name; } -boolean +#if defined OBJ_COFF || defined OBJ_ELF +void arm_validate_fix (fixP) fixS * fixP; { @@ -11394,10 +12453,33 @@ arm_validate_fix (fixP) && ! THUMB_IS_FUNC (fixP->fx_addsy)) { fixP->fx_addsy = find_real_start (fixP->fx_addsy); - return true; } +} +#endif - return false; +int +arm_force_relocation (fixp) + 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 @@ -11407,7 +12489,7 @@ arm_validate_fix (fixP) be resolved before the binbary is emitted, so it is safe to say that it is adjustable. */ -boolean +bfd_boolean arm_fix_adjustable (fixP) fixS * fixP; { @@ -11416,6 +12498,7 @@ arm_fix_adjustable (fixP) 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 @@ -11430,20 +12513,13 @@ arm_fix_adjustable (fixP) addresses also ought to have their bottom bit set (assuming that they reside in Thumb code), but at the moment they will not. */ -boolean +bfd_boolean arm_fix_adjustable (fixP) fixS * fixP; { if (fixP->fx_addsy == NULL) return 1; - /* Prevent all adjustments to global symbols. */ - if (S_IS_EXTERN (fixP->fx_addsy)) - return 0; - - if (S_IS_WEAK (fixP->fx_addsy)) - return 0; - if (THUMB_IS_FUNC (fixP->fx_addsy) && fixP->fx_subsy == NULL) return 0; @@ -11453,6 +12529,12 @@ arm_fix_adjustable (fixP) || 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) + return 0; + return 1; } @@ -11483,21 +12565,6 @@ armelf_frob_symbol (symp, puntp) elf_frob_symbol (symp, puntp); } -int -arm_force_relocation (fixp) - struct fix * fixp; -{ - if ( fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT - || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY - || fixp->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH - || fixp->fx_r_type == BFD_RELOC_ARM_PCREL_BLX - || fixp->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX - || fixp->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23) - return 1; - - return 0; -} - static bfd_reloc_code_real_type arm_parse_reloc () {