/* 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)
/* 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,
/* 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. */
#endif
#endif
+#ifdef TE_LINUX
+#define FPU_DEFAULT FPU_ARCH_FPA
+#endif
+
+#ifdef TE_NetBSD
+#ifdef OBJ_ELF
+#define FPU_DEFAULT FPU_ARCH_VFP /* Soft-float, but VFP order. */
+#else
+/* Legacy a.out format. */
+#define FPU_DEFAULT FPU_ARCH_FPA /* Soft-float, but FPA order. */
+#endif
+#endif
+
/* For backwards compatibility we default to the FPA. */
#ifndef FPU_DEFAULT
#define FPU_DEFAULT FPU_ARCH_FPA
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
struct asm_psr
{
- const char * template;
- boolean cpsr;
+ const char *template;
+ bfd_boolean cpsr;
unsigned long field;
};
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
unsigned long regno;
};
-static const struct vfp_reg vfp_regs[] =
+static const struct vfp_reg vfp_regs[] =
{
{"fpsid", 0x00000000},
{"FPSID", 0x00000000},
#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[] =
{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[] =
{
{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. */
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. */
static void do_mav_binops_3b PARAMS ((char *));
static void do_mav_binops_3c PARAMS ((char *));
static void do_mav_binops_3d PARAMS ((char *));
-static void do_mav_triple PARAMS ((char *, int, enum arm_reg_type,
+static void do_mav_triple PARAMS ((char *, int, enum arm_reg_type,
enum arm_reg_type,
enum arm_reg_type));
static void do_mav_triple_4a PARAMS ((char *));
static void do_mav_triple_5f PARAMS ((char *));
static void do_mav_triple_5g PARAMS ((char *));
static void do_mav_triple_5h PARAMS ((char *));
-static void do_mav_quad PARAMS ((char *, int, enum arm_reg_type,
+static void do_mav_quad PARAMS ((char *, int, enum arm_reg_type,
enum arm_reg_type,
enum arm_reg_type,
enum arm_reg_type));
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
{"strh", 0xe00000b0, 3, ARM_EXT_V4, do_ldstv4},
/* ARM Architecture 4T. */
- /* Note: bx (and blx) are required on V5, even if the processor does
+ /* 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},
{"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},
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));
#ifdef OBJ_ELF
-static void arm_s_section PARAMS ((int));
static void s_arm_elf_cons PARAMS ((int));
#endif
{ "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 },
#ifdef OBJ_ELF
- { "section", arm_s_section, 0 },
- { "section.s", arm_s_section, 0 },
- { "sect", arm_s_section, 0 },
- { "sect.s", arm_s_section, 0 },
{ "word", s_arm_elf_cons, 4 },
{ "long", s_arm_elf_cons, 4 },
- { "file", dwarf2_directive_file, 0 },
- { "loc", dwarf2_directive_loc, 0 },
#else
{ "word", cons, 4},
#endif
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:
*/
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));
-/* Next literal pool number. */
-int lit_pool_num = 1;
+static literal_pool *
+find_literal_pool ()
+{
+ literal_pool * pool;
-symbolS * current_poolP = NULL;
+ 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;
+ }
+
+ /* 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 ++;
+ }
+
+ /* 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++;
}
- 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;
}
S_SET_SEGMENT (symbolP, segment);
S_SET_VALUE (symbolP, valu);
- symbol_clear_list_pointers(symbolP);
+ symbol_clear_list_pointers (symbolP);
symbol_set_frag (symbolP, frag);
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.
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. */
/* 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 ();
}
#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
-}
-
-#ifdef OBJ_ELF
-static void
-arm_s_section (ignore)
- int ignore;
-{
- s_ltorg (0);
-
- obj_elf_section (ignore);
-}
-#endif
-
static void
opcode_select (width)
int width;
thumb_mode = 0;
if (!need_pass_2)
- frag_align (2, 0, 0);
+ frag_align (2, 0, 0);
- record_alignment (now_seg, 1);
+ record_alignment (now_seg, 1);
}
break;
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;
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;
}
else /* [Rn] */
{
- skip_whitespace (str);
+ skip_whitespace (str);
- if (* str == '!')
- {
- str ++;
- inst.instruction |= WRITE_BACK;
- }
+ if (* str == '!')
+ {
+ str ++;
+ inst.instruction |= WRITE_BACK;
+ }
inst.instruction |= INDEX_UP | HWOFFSET_IMM;
pre_inc = 1;
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;
}
/* 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
- {
- /* This must be is BLX <target address>, no condition allowed. */
- if (inst.instruction != COND_ALWAYS)
- {
- inst.error = BAD_COND;
- return;
- }
+ 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
+ {
+ /* 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);
+ }
+}
+
+/* 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. */
+
+static void
+do_t_blx (str)
+ 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)
+ {
+ /* It's BLX(2). The .instruction was zapped with rm & is final. */
+ inst.size = 2;
+ }
+ else
+ {
+ /* 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;
+ }
+
+ 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. */
+
+static void
+do_bkpt (str)
+ char * str;
+{
+ expressionS expr;
+ unsigned long number;
+
+ 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
+ /* As a convenience we allow 'bkpt' without an operand. */
+ && expr.X_op != O_absent))
+ {
+ 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;
+ }
+
+ /* 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);
+}
+
+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;
- inst.instruction = 0xfafffffe;
+ if ((number = check_iwmmxt_insn (str, check_waligni, 7)) == (unsigned long) FAIL)
+ return;
- /* 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.instruction |= ((number & 0x7) << 20);
+ 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. */
+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_t_blx (str)
+do_iwmmxt_word_addr (str)
char * str;
{
- char * mystr = str;
- int rm;
+ int op = (inst.instruction & 0x300) >> 8;
+ int reg;
- skip_whitespace (mystr);
- inst.instruction = 0x4780;
+ inst.instruction &= ~0x300;
+ inst.instruction |= (op & 1) << 22 | (op & 2) << 7;
- /* 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;
+ skip_whitespace (str);
- if (rm != FAIL)
+ 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)
{
- /* It's BLX(2). The .instruction was zapped with rm & is final. */
- inst.size = 2;
+ if (! inst.error)
+ inst.error = BAD_ARGS;
}
else
- {
- /* 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;
+ end_of_line (str);
- inst.reloc.type = BFD_RELOC_THUMB_PCREL_BLX;
- inst.reloc.pc_rel = 1;
+ if (wc_register (reg))
+ {
+ inst.instruction |= 0xf0000100;
+ inst.instruction &= ~0x00400000;
}
-
- 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. */
-
static void
-do_bkpt (str)
- char * str;
+do_iwmmxt_wrwr (str)
+ char * str;
{
- expressionS expr;
- unsigned long number;
+ check_iwmmxt_insn (str, check_wrwr, 0);
+
+ return;
+}
- skip_whitespace (str);
+static void
+do_iwmmxt_wrwrwcg (str)
+ char * str;
+{
+ check_iwmmxt_insn (str, check_wrwrwcg, 0);
- /* Allow optional leading '#'. */
- if (is_immediate_prefix (* str))
- str++;
+ return;
+}
- memset (& expr, '\0', sizeof (expr));
+static void
+do_iwmmxt_wrwrwr (str)
+ char * str;
+{
+ check_iwmmxt_insn (str, check_wrwrwr, 0);
- if (my_get_expression (& expr, & str) || (expr.X_op != O_constant))
- {
- inst.error = _("bad or missing expression");
- return;
- }
+ return;
+}
- number = expr.X_add_number;
+static void
+do_iwmmxt_wshufh (str)
+ char * str;
+{
+ unsigned long number;
- /* Check it fits a 16 bit unsigned. */
- if (number != (number & 0xffff))
- {
- inst.error = _("immediate value out of range");
- return;
- }
+ if ((number = check_iwmmxt_insn (str, check_wshufh, 0xff)) == (unsigned long) FAIL)
+ return;
- /* Top 12 of 16 bits to bits 19:8. */
- inst.instruction |= (number & 0xfff0) << 4;
+ inst.instruction |= ((number & 0xf0) << 16) | (number & 0xf);
+ return;
+}
- /* Bottom 4 of 16 bits to bits 3:0. */
- inst.instruction |= number & 0xf;
+static void
+do_iwmmxt_wzero (str)
+ char * str;
+{
+ if (check_iwmmxt_insn (str, check_wr, 0) == (unsigned long) FAIL)
+ return;
- end_of_line (str);
+ inst.instruction |= ((inst.instruction & 0xf) << 12) | ((inst.instruction & 0xf) << 16);
+ return;
}
/* Xscale multiply-accumulate (argument parse)
|| (rn = ld_mode_required_here (& str)) == FAIL)
{
if (!inst.error)
- inst.error = BAD_ARGS;
+ inst.error = BAD_ARGS;
return;
}
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)
return 0;
}
-/* We handle all bad expressions here, so that we can report the faulty
+/* We handle all bad expressions here, so that we can report the faulty
instruction in the error message. */
void
md_operand (expr)
end_of_line (str);
return;
}
-
+
value = validate_immediate (~ inst.reloc.exp.X_add_number);
if (value != FAIL)
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;
/* Mark it. */
*--p = 0;
- for (vreg = vfp_regs + 0;
+ for (vreg = vfp_regs + 0;
vreg < vfp_regs + sizeof (vfp_regs) / sizeof (struct vfp_reg);
vreg++)
{
/* Sanity check -- should have raised a parse error above. */
if (count == 0 || count > 32)
- abort();
+ abort ();
/* Final test -- the registers must be consecutive. */
while (count--)
/* Sanity check -- should have raised a parse error above. */
if (count == 0 || count > 16)
- abort();
+ abort ();
/* Final test -- the registers must be consecutive. */
while (count--)
}
static void
-vfp_sp_ldstm(str, ldstm_type)
+vfp_sp_ldstm (str, ldstm_type)
char *str;
enum vfp_ldstm_type ldstm_type;
{
}
static void
-vfp_dp_ldstm(str, ldstm_type)
+vfp_dp_ldstm (str, ldstm_type)
char *str;
enum vfp_ldstm_type ldstm_type;
{
int offset = inst.reloc.exp.X_add_number;
if (subtract)
- offset = -offset;
+ offset = - offset;
if (offset < 0)
{
- offset = -offset;
+ offset = - offset;
subtract = 1;
/* Quick check, in case offset is MIN_INT. */
return;
}
}
- else
+ /* 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)
/* Restore the start point. */
*str = start;
-
+
/* 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;
}
REG_TYPE_MVFX);
}
-/* cfmvsc32<cond> DSPSC,MVFX[15:0]. */
+/* cfmvsc32<cond> DSPSC,MVFX[15:0]. */
static void
do_mav_dspsc_1 (str)
char * str;
*p = c;
return 0;
}
-
+
static void
set_constant_flonums ()
{
}
}
+#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 ()
{
}
else if (mfpu_opt == -1)
{
+#if !(defined (TE_LINUX) || defined (TE_NetBSD))
+ /* 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)
/* 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);
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)
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);
}
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);
{
as_bad_where (fixP->fx_file, fixP->fx_line,
_("unable to compute ADRL instructions for PC offset of 0x%lx"),
- value);
+ (long) value);
break;
}
value = fixP->fx_offset;
#endif
value += diff;
+
if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff))
as_bad_where (fixP->fx_file, fixP->fx_line,
_("branch with link out of range"));
newval = (newval & 0xf800) | ((value & 0x7fffff) >> 12);
newval2 = (newval2 & 0xf800) | ((value & 0xfff) >> 1);
if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
- /* Remove bit zero of the adjusted offset. Bit zero can only be
- set if the upper insn is at a half-word boundary, since the
- destination address, an ARM instruction, must always be on a
- word boundary. The semantics of the BLX (1) instruction, however,
- are that bit zero in the offset must always be zero, and the
- corresponding bit one in the target address will be set from bit
- one of the source address. */
- newval2 &= ~1;
+ /* For a BLX instruction, make sure that the relocation is rounded up
+ to a word boundary. This follows the semantics of the instruction
+ which specifies that bit 1 of the target address will come from bit
+ 1 of the base address. */
+ newval2 = (newval2 + 1) & ~ 1;
md_number_to_chars (buf, newval, THUMB_SIZE);
md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
}
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))
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
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;
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;
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
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:
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:
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;
}
#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)
{
#if 0
arm_align (2, 0);
#endif
- listing_prev_line (); /* Defined in listing.h. */
/* Align the previous label if needed. */
if (last_label_seen != NULL)
/* md_parse_option
Invocation line includes a switch not recognized by the base assembler.
- See if it's a processor-specific option.
+ See if it's a processor-specific option.
This routine is somewhat complicated by the need for backwards
compatibility (since older releases of gcc can't be changed).
-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
*/
-CONST char * md_shortopts = "m:k";
+const char * md_shortopts = "m:k";
#ifdef ARM_BI_ENDIAN
#define OPTION_EB (OPTION_MD_BASE + 0)
char *deprecated; /* If non-null, print this message. */
};
-struct arm_option_table arm_opts[] =
+struct arm_option_table arm_opts[] =
{
{"k", N_("generate PIC code"), &pic_code, 1, NULL},
{"mthumb", N_("assemble Thumb code"), &thumb_mode, 1, NULL},
{"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. */
{"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},
{NULL, 0, 0}
};
-
+
struct arm_arch_option_table
{
char *name;
{
{"maverick", ARM_CEXT_MAVERICK},
{"xscale", ARM_CEXT_XSCALE},
+ {"iwmmxt", ARM_CEXT_IWMMXT},
{NULL, 0}
};
#endif
case 'a':
- /* Listing option. Just ignore these, we don't support additional
+ /* Listing option. Just ignore these, we don't support additional
ones. */
return 0;
for (lopt = arm_long_opts; lopt->option != NULL; lopt++)
{
- /* These options are expected to have an argument. */
+ /* These options are expected to have an argument. */
if (c == lopt->option[0]
&& arg != NULL
- && strncmp (arg, lopt->option + 1,
+ && strncmp (arg, lopt->option + 1,
strlen (lopt->option + 1)) == 0)
{
#if WARN_DEPRECATED
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);
- listing_prev_line ();
+ 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
lsl r3, r3, #2
ldr r2, [r3, r2]
mov pc, r2
-
+
.Lbbb: .word .Lxxx
.Lccc: .word .Lyyy
..etc...
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
THUMB_SET_FUNC (sym, 1);
- label_is_thumb_function_name = false;
+ label_is_thumb_function_name = FALSE;
}
}
as_bad (_("%s: unexpected function type: %d"),
S_GET_NAME (sym), S_GET_STORAGE_CLASS (sym));
}
- else switch (S_GET_STORAGE_CLASS (sym))
+ else switch (S_GET_STORAGE_CLASS (sym))
{
case C_EXT:
S_SET_STORAGE_CLASS (sym, C_THUMBEXT);
return name;
}
-boolean
+#if defined OBJ_COFF || defined OBJ_ELF
+void
arm_validate_fix (fixP)
fixS * fixP;
{
&& ! THUMB_IS_FUNC (fixP->fx_addsy))
{
fixP->fx_addsy = find_real_start (fixP->fx_addsy);
- return true;
}
+}
+#endif
+
+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 false;
+ return generic_force_reloc (fixp);
}
#ifdef OBJ_COFF
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;
{
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
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;
|| 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;
}
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 ()
{
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 = arm_noop;
noop_size = sizeof (arm_noop);
}
-
+
if (bytes & (noop_size - 1))
{
fix = bytes & (noop_size - 1);
bytes -= noop_size;
fix += noop_size;
}
-
+
fragP->fr_fix += fix;
fragP->fr_var = noop_size;
}
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,