X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-arm.c;h=d6cd3acc12018d8fee40a11624e2df904f5aa081;hb=1256987795a7f61826c0e5cc2ee023a579bb0a80;hp=8c405a87b11c8e5a8f1960d95d727fe985469440;hpb=74db7efbe3a09c00e5f4f5b99862f173258938f6;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index 8c405a87b1..d6cd3acc12 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-2013 Free Software Foundation, Inc. + Copyright (C) 1994-2015 Free Software Foundation, Inc. Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) Modified by David Taylor (dtaylor@armltd.co.uk) Cirrus coprocessor mods by Aldy Hernandez (aldyh@redhat.com) @@ -137,6 +137,8 @@ static int fix_v4bx = FALSE; /* Warn on using deprecated features. */ static int warn_on_deprecated = TRUE; +/* Understand CodeComposer Studio assembly syntax. */ +bfd_boolean codecomposer_syntax = 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 @@ -166,80 +168,99 @@ static const arm_feature_set fpu_endian_pure = FPU_ARCH_ENDIAN_PURE; static const arm_feature_set cpu_default = CPU_DEFAULT; #endif -static const arm_feature_set arm_ext_v1 = ARM_FEATURE (ARM_EXT_V1, 0); -static const arm_feature_set arm_ext_v2 = ARM_FEATURE (ARM_EXT_V1, 0); -static const arm_feature_set arm_ext_v2s = ARM_FEATURE (ARM_EXT_V2S, 0); -static const arm_feature_set arm_ext_v3 = ARM_FEATURE (ARM_EXT_V3, 0); -static const arm_feature_set arm_ext_v3m = ARM_FEATURE (ARM_EXT_V3M, 0); -static const arm_feature_set arm_ext_v4 = ARM_FEATURE (ARM_EXT_V4, 0); -static const arm_feature_set arm_ext_v4t = ARM_FEATURE (ARM_EXT_V4T, 0); -static const arm_feature_set arm_ext_v5 = ARM_FEATURE (ARM_EXT_V5, 0); +static const arm_feature_set arm_ext_v1 = ARM_FEATURE_CORE_LOW (ARM_EXT_V1); +static const arm_feature_set arm_ext_v2 = ARM_FEATURE_CORE_LOW (ARM_EXT_V1); +static const arm_feature_set arm_ext_v2s = ARM_FEATURE_CORE_LOW (ARM_EXT_V2S); +static const arm_feature_set arm_ext_v3 = ARM_FEATURE_CORE_LOW (ARM_EXT_V3); +static const arm_feature_set arm_ext_v3m = ARM_FEATURE_CORE_LOW (ARM_EXT_V3M); +static const arm_feature_set arm_ext_v4 = ARM_FEATURE_CORE_LOW (ARM_EXT_V4); +static const arm_feature_set arm_ext_v4t = ARM_FEATURE_CORE_LOW (ARM_EXT_V4T); +static const arm_feature_set arm_ext_v5 = ARM_FEATURE_CORE_LOW (ARM_EXT_V5); static const arm_feature_set arm_ext_v4t_5 = - ARM_FEATURE (ARM_EXT_V4T | ARM_EXT_V5, 0); -static const arm_feature_set arm_ext_v5t = ARM_FEATURE (ARM_EXT_V5T, 0); -static const arm_feature_set arm_ext_v5e = ARM_FEATURE (ARM_EXT_V5E, 0); -static const arm_feature_set arm_ext_v5exp = ARM_FEATURE (ARM_EXT_V5ExP, 0); -static const arm_feature_set arm_ext_v5j = ARM_FEATURE (ARM_EXT_V5J, 0); -static const arm_feature_set arm_ext_v6 = ARM_FEATURE (ARM_EXT_V6, 0); -static const arm_feature_set arm_ext_v6k = ARM_FEATURE (ARM_EXT_V6K, 0); -static const arm_feature_set arm_ext_v6t2 = ARM_FEATURE (ARM_EXT_V6T2, 0); -static const arm_feature_set arm_ext_v6m = ARM_FEATURE (ARM_EXT_V6M, 0); -static const arm_feature_set arm_ext_v6_notm = ARM_FEATURE (ARM_EXT_V6_NOTM, 0); -static const arm_feature_set arm_ext_v6_dsp = ARM_FEATURE (ARM_EXT_V6_DSP, 0); -static const arm_feature_set arm_ext_barrier = ARM_FEATURE (ARM_EXT_BARRIER, 0); -static const arm_feature_set arm_ext_msr = ARM_FEATURE (ARM_EXT_THUMB_MSR, 0); -static const arm_feature_set arm_ext_div = ARM_FEATURE (ARM_EXT_DIV, 0); -static const arm_feature_set arm_ext_v7 = ARM_FEATURE (ARM_EXT_V7, 0); -static const arm_feature_set arm_ext_v7a = ARM_FEATURE (ARM_EXT_V7A, 0); -static const arm_feature_set arm_ext_v7r = ARM_FEATURE (ARM_EXT_V7R, 0); -static const arm_feature_set arm_ext_v7m = ARM_FEATURE (ARM_EXT_V7M, 0); -static const arm_feature_set arm_ext_v8 = ARM_FEATURE (ARM_EXT_V8, 0); + ARM_FEATURE_CORE_LOW (ARM_EXT_V4T | ARM_EXT_V5); +static const arm_feature_set arm_ext_v5t = ARM_FEATURE_CORE_LOW (ARM_EXT_V5T); +static const arm_feature_set arm_ext_v5e = ARM_FEATURE_CORE_LOW (ARM_EXT_V5E); +static const arm_feature_set arm_ext_v5exp = ARM_FEATURE_CORE_LOW (ARM_EXT_V5ExP); +static const arm_feature_set arm_ext_v5j = ARM_FEATURE_CORE_LOW (ARM_EXT_V5J); +static const arm_feature_set arm_ext_v6 = ARM_FEATURE_CORE_LOW (ARM_EXT_V6); +static const arm_feature_set arm_ext_v6k = ARM_FEATURE_CORE_LOW (ARM_EXT_V6K); +static const arm_feature_set arm_ext_v6t2 = ARM_FEATURE_CORE_LOW (ARM_EXT_V6T2); +static const arm_feature_set arm_ext_v6m = ARM_FEATURE_CORE_LOW (ARM_EXT_V6M); +static const arm_feature_set arm_ext_v6_notm = + ARM_FEATURE_CORE_LOW (ARM_EXT_V6_NOTM); +static const arm_feature_set arm_ext_v6_dsp = + ARM_FEATURE_CORE_LOW (ARM_EXT_V6_DSP); +static const arm_feature_set arm_ext_barrier = + ARM_FEATURE_CORE_LOW (ARM_EXT_BARRIER); +static const arm_feature_set arm_ext_msr = + ARM_FEATURE_CORE_LOW (ARM_EXT_THUMB_MSR); +static const arm_feature_set arm_ext_div = ARM_FEATURE_CORE_LOW (ARM_EXT_DIV); +static const arm_feature_set arm_ext_v7 = ARM_FEATURE_CORE_LOW (ARM_EXT_V7); +static const arm_feature_set arm_ext_v7a = ARM_FEATURE_CORE_LOW (ARM_EXT_V7A); +static const arm_feature_set arm_ext_v7r = ARM_FEATURE_CORE_LOW (ARM_EXT_V7R); +static const arm_feature_set arm_ext_v7m = ARM_FEATURE_CORE_LOW (ARM_EXT_V7M); +static const arm_feature_set arm_ext_v8 = ARM_FEATURE_CORE_LOW (ARM_EXT_V8); static const arm_feature_set arm_ext_m = - ARM_FEATURE (ARM_EXT_V6M | ARM_EXT_OS | ARM_EXT_V7M, 0); -static const arm_feature_set arm_ext_mp = ARM_FEATURE (ARM_EXT_MP, 0); -static const arm_feature_set arm_ext_sec = ARM_FEATURE (ARM_EXT_SEC, 0); -static const arm_feature_set arm_ext_os = ARM_FEATURE (ARM_EXT_OS, 0); -static const arm_feature_set arm_ext_adiv = ARM_FEATURE (ARM_EXT_ADIV, 0); -static const arm_feature_set arm_ext_virt = ARM_FEATURE (ARM_EXT_VIRT, 0); + ARM_FEATURE_CORE_LOW (ARM_EXT_V6M | ARM_EXT_OS | ARM_EXT_V7M); +static const arm_feature_set arm_ext_mp = ARM_FEATURE_CORE_LOW (ARM_EXT_MP); +static const arm_feature_set arm_ext_sec = ARM_FEATURE_CORE_LOW (ARM_EXT_SEC); +static const arm_feature_set arm_ext_os = ARM_FEATURE_CORE_LOW (ARM_EXT_OS); +static const arm_feature_set arm_ext_adiv = ARM_FEATURE_CORE_LOW (ARM_EXT_ADIV); +static const arm_feature_set arm_ext_virt = ARM_FEATURE_CORE_LOW (ARM_EXT_VIRT); +static const arm_feature_set arm_ext_pan = ARM_FEATURE_CORE_HIGH (ARM_EXT2_PAN); static const arm_feature_set arm_arch_any = ARM_ANY; -static const arm_feature_set arm_arch_full = ARM_FEATURE (-1, -1); +static const arm_feature_set arm_arch_full = ARM_FEATURE (-1, -1, -1); static const arm_feature_set arm_arch_t2 = ARM_ARCH_THUMB2; static const arm_feature_set arm_arch_none = ARM_ARCH_NONE; static const arm_feature_set arm_arch_v6m_only = ARM_ARCH_V6M_ONLY; static const arm_feature_set arm_cext_iwmmxt2 = - ARM_FEATURE (0, ARM_CEXT_IWMMXT2); + ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT2); static const arm_feature_set arm_cext_iwmmxt = - ARM_FEATURE (0, ARM_CEXT_IWMMXT); + ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT); static const arm_feature_set arm_cext_xscale = - ARM_FEATURE (0, ARM_CEXT_XSCALE); + ARM_FEATURE_COPROC (ARM_CEXT_XSCALE); static const arm_feature_set arm_cext_maverick = - ARM_FEATURE (0, ARM_CEXT_MAVERICK); -static const arm_feature_set fpu_fpa_ext_v1 = ARM_FEATURE (0, FPU_FPA_EXT_V1); -static const arm_feature_set fpu_fpa_ext_v2 = ARM_FEATURE (0, FPU_FPA_EXT_V2); + ARM_FEATURE_COPROC (ARM_CEXT_MAVERICK); +static const arm_feature_set fpu_fpa_ext_v1 = + ARM_FEATURE_COPROC (FPU_FPA_EXT_V1); +static const arm_feature_set fpu_fpa_ext_v2 = + ARM_FEATURE_COPROC (FPU_FPA_EXT_V2); static const arm_feature_set fpu_vfp_ext_v1xd = - ARM_FEATURE (0, FPU_VFP_EXT_V1xD); -static const arm_feature_set fpu_vfp_ext_v1 = ARM_FEATURE (0, FPU_VFP_EXT_V1); -static const arm_feature_set fpu_vfp_ext_v2 = ARM_FEATURE (0, FPU_VFP_EXT_V2); -static const arm_feature_set fpu_vfp_ext_v3xd = ARM_FEATURE (0, FPU_VFP_EXT_V3xD); -static const arm_feature_set fpu_vfp_ext_v3 = ARM_FEATURE (0, FPU_VFP_EXT_V3); + ARM_FEATURE_COPROC (FPU_VFP_EXT_V1xD); +static const arm_feature_set fpu_vfp_ext_v1 = + ARM_FEATURE_COPROC (FPU_VFP_EXT_V1); +static const arm_feature_set fpu_vfp_ext_v2 = + ARM_FEATURE_COPROC (FPU_VFP_EXT_V2); +static const arm_feature_set fpu_vfp_ext_v3xd = + ARM_FEATURE_COPROC (FPU_VFP_EXT_V3xD); +static const arm_feature_set fpu_vfp_ext_v3 = + ARM_FEATURE_COPROC (FPU_VFP_EXT_V3); static const arm_feature_set fpu_vfp_ext_d32 = - ARM_FEATURE (0, FPU_VFP_EXT_D32); -static const arm_feature_set fpu_neon_ext_v1 = ARM_FEATURE (0, FPU_NEON_EXT_V1); + ARM_FEATURE_COPROC (FPU_VFP_EXT_D32); +static const arm_feature_set fpu_neon_ext_v1 = + ARM_FEATURE_COPROC (FPU_NEON_EXT_V1); static const arm_feature_set fpu_vfp_v3_or_neon_ext = - ARM_FEATURE (0, FPU_NEON_EXT_V1 | FPU_VFP_EXT_V3); -static const arm_feature_set fpu_vfp_fp16 = ARM_FEATURE (0, FPU_VFP_EXT_FP16); -static const arm_feature_set fpu_neon_ext_fma = ARM_FEATURE (0, FPU_NEON_EXT_FMA); -static const arm_feature_set fpu_vfp_ext_fma = ARM_FEATURE (0, FPU_VFP_EXT_FMA); + ARM_FEATURE_COPROC (FPU_NEON_EXT_V1 | FPU_VFP_EXT_V3); +static const arm_feature_set fpu_vfp_fp16 = + ARM_FEATURE_COPROC (FPU_VFP_EXT_FP16); +static const arm_feature_set fpu_neon_ext_fma = + ARM_FEATURE_COPROC (FPU_NEON_EXT_FMA); +static const arm_feature_set fpu_vfp_ext_fma = + ARM_FEATURE_COPROC (FPU_VFP_EXT_FMA); static const arm_feature_set fpu_vfp_ext_armv8 = - ARM_FEATURE (0, FPU_VFP_EXT_ARMV8); + ARM_FEATURE_COPROC (FPU_VFP_EXT_ARMV8); +static const arm_feature_set fpu_vfp_ext_armv8xd = + ARM_FEATURE_COPROC (FPU_VFP_EXT_ARMV8xD); static const arm_feature_set fpu_neon_ext_armv8 = - ARM_FEATURE (0, FPU_NEON_EXT_ARMV8); + ARM_FEATURE_COPROC (FPU_NEON_EXT_ARMV8); static const arm_feature_set fpu_crypto_ext_armv8 = - ARM_FEATURE (0, FPU_CRYPTO_EXT_ARMV8); + ARM_FEATURE_COPROC (FPU_CRYPTO_EXT_ARMV8); static const arm_feature_set crc_ext_armv8 = - ARM_FEATURE (0, CRC_EXT_ARMV8); + ARM_FEATURE_COPROC (CRC_EXT_ARMV8); +static const arm_feature_set fpu_neon_ext_v8_1 = + ARM_FEATURE_COPROC (FPU_NEON_EXT_ARMV8 | FPU_NEON_EXT_RDMA); static int mfloat_abi_opt = -1; /* Record user cpu selection for object attributes. */ @@ -247,12 +268,13 @@ static arm_feature_set selected_cpu = ARM_ARCH_NONE; /* Must be long enough to hold any of the names in arm_cpus. */ static char selected_cpu_name[16]; +extern FLONUM_TYPE generic_floating_point_number; + /* Return if no cpu was selected on command-line. */ static bfd_boolean no_cpu_selected (void) { - return selected_cpu.core == arm_arch_none.core - && selected_cpu.coproc == arm_arch_none.coproc; + return ARM_FEATURE_EQUAL (selected_cpu, arm_arch_none); } #ifdef OBJ_ELF @@ -628,6 +650,7 @@ struct asm_opcode #define LITERAL_MASK 0xf000f000 #define OPCODE_MASK 0xfe1fffff #define V4_STR_BIT 0x00000020 +#define VLDR_VMOV_SAME 0x0040f000 #define T2_SUBS_PC_LR 0xf3de8f00 @@ -790,11 +813,21 @@ typedef struct literal_pool struct dwarf2_line_info locs [MAX_LITERAL_POOL_SIZE]; #endif struct literal_pool * next; + unsigned int alignment; } literal_pool; /* Pointer to a linked list of literal pools. */ literal_pool * list_of_pools = NULL; +typedef enum asmfunc_states +{ + OUTSIDE_ASMFUNC, + WAITING_ASMFUNC_NAME, + WAITING_ENDASMFUNC +} asmfunc_states; + +static asmfunc_states asmfunc_state = OUTSIDE_ASMFUNC; + #ifdef OBJ_ELF # define now_it seg_info (now_seg)->tc_segment_info_data.current_it #else @@ -853,7 +886,7 @@ static void it_fsm_post_encode (void); /* This array holds the chars that always start a comment. If the pre-processor is disabled, these aren't very useful. */ -const char comment_chars[] = "@"; +char arm_comment_chars[] = "@"; /* This array holds the chars that only start a comment at the beginning of a line. If the line seems to have the form '# 123 filename' @@ -864,7 +897,7 @@ const char comment_chars[] = "@"; /* Also note that comments like this one will always work. */ const char line_comment_chars[] = "#"; -const char line_separator_chars[] = ";"; +char arm_line_separator_chars[] = ";"; /* Chars that can be used to separate mant from exp in floating point numbers. */ @@ -2615,13 +2648,12 @@ static void mapping_state_2 (enum mstate state, int max_chars); /* Set the mapping state to STATE. Only call this when about to emit some STATE bytes to the file. */ +#define TRANSITION(from, to) (mapstate == (from) && state == (to)) void mapping_state (enum mstate state) { enum mstate mapstate = seg_info (now_seg)->tc_segment_info_data.mapstate; -#define TRANSITION(from, to) (mapstate == (from) && state == (to)) - if (mapstate == state) /* The mapping symbol has already been emitted. There is nothing else to do. */ @@ -2644,24 +2676,10 @@ mapping_state (enum mstate state) record_alignment (now_seg, state == MAP_ARM ? 2 : 1); if (TRANSITION (MAP_UNDEFINED, MAP_DATA)) - /* This case will be evaluated later in the next else. */ + /* This case will be evaluated later. */ return; - else if (TRANSITION (MAP_UNDEFINED, MAP_ARM) - || TRANSITION (MAP_UNDEFINED, MAP_THUMB)) - { - /* Only add the symbol if the offset is > 0: - if we're at the first frag, check it's size > 0; - if we're not at the first frag, then for sure - the offset is > 0. */ - struct frag * const frag_first = seg_info (now_seg)->frchainP->frch_root; - const int add_symbol = (frag_now != frag_first) || (frag_now_fix () > 0); - - if (add_symbol) - make_mapping_symbol (MAP_DATA, (valueT) 0, frag_first); - } mapping_state_2 (state, 0); -#undef TRANSITION } /* Same as mapping_state, but MAX_CHARS bytes have already been @@ -2680,9 +2698,20 @@ mapping_state_2 (enum mstate state, int max_chars) There is nothing else to do. */ return; + if (TRANSITION (MAP_UNDEFINED, MAP_ARM) + || TRANSITION (MAP_UNDEFINED, MAP_THUMB)) + { + struct frag * const frag_first = seg_info (now_seg)->frchainP->frch_root; + const int add_symbol = (frag_now != frag_first) || (frag_now_fix () > 0); + + if (add_symbol) + make_mapping_symbol (MAP_DATA, (valueT) 0, frag_first); + } + seg_info (now_seg)->tc_segment_info_data.mapstate = state; make_mapping_symbol (state, (valueT) frag_now_fix () - max_chars, frag_now); } +#undef TRANSITION #else #define mapping_state(x) ((void)0) #define mapping_state_2(x, y) ((void)0) @@ -3012,6 +3041,104 @@ s_even (int ignore ATTRIBUTE_UNUSED) demand_empty_rest_of_line (); } +/* Directives: CodeComposer Studio. */ + +/* .ref (for CodeComposer Studio syntax only). */ +static void +s_ccs_ref (int unused ATTRIBUTE_UNUSED) +{ + if (codecomposer_syntax) + ignore_rest_of_line (); + else + as_bad (_(".ref pseudo-op only available with -mccs flag.")); +} + +/* If name is not NULL, then it is used for marking the beginning of a + function, wherease if it is NULL then it means the function end. */ +static void +asmfunc_debug (const char * name) +{ + static const char * last_name = NULL; + + if (name != NULL) + { + gas_assert (last_name == NULL); + last_name = name; + + if (debug_type == DEBUG_STABS) + stabs_generate_asm_func (name, name); + } + else + { + gas_assert (last_name != NULL); + + if (debug_type == DEBUG_STABS) + stabs_generate_asm_endfunc (last_name, last_name); + + last_name = NULL; + } +} + +static void +s_ccs_asmfunc (int unused ATTRIBUTE_UNUSED) +{ + if (codecomposer_syntax) + { + switch (asmfunc_state) + { + case OUTSIDE_ASMFUNC: + asmfunc_state = WAITING_ASMFUNC_NAME; + break; + + case WAITING_ASMFUNC_NAME: + as_bad (_(".asmfunc repeated.")); + break; + + case WAITING_ENDASMFUNC: + as_bad (_(".asmfunc without function.")); + break; + } + demand_empty_rest_of_line (); + } + else + as_bad (_(".asmfunc pseudo-op only available with -mccs flag.")); +} + +static void +s_ccs_endasmfunc (int unused ATTRIBUTE_UNUSED) +{ + if (codecomposer_syntax) + { + switch (asmfunc_state) + { + case OUTSIDE_ASMFUNC: + as_bad (_(".endasmfunc without a .asmfunc.")); + break; + + case WAITING_ASMFUNC_NAME: + as_bad (_(".endasmfunc without function.")); + break; + + case WAITING_ENDASMFUNC: + asmfunc_state = OUTSIDE_ASMFUNC; + asmfunc_debug (NULL); + break; + } + demand_empty_rest_of_line (); + } + else + as_bad (_(".endasmfunc pseudo-op only available with -mccs flag.")); +} + +static void +s_ccs_def (int name) +{ + if (codecomposer_syntax) + s_globl (name); + else + as_bad (_(".def pseudo-op only available with -mccs flag.")); +} + /* Directives: Literal pools. */ static literal_pool * @@ -3050,6 +3177,7 @@ find_or_make_literal_pool (void) pool->sub_section = now_subseg; pool->next = list_of_pools; pool->symbol = NULL; + pool->alignment = 2; /* Add it to the list. */ list_of_pools = pool; @@ -3071,33 +3199,74 @@ find_or_make_literal_pool (void) structure to the relevant literal pool. */ static int -add_to_lit_pool (void) +add_to_lit_pool (unsigned int nbytes) { +#define PADDING_SLOT 0x1 +#define LIT_ENTRY_SIZE_MASK 0xFF literal_pool * pool; - unsigned int entry; + unsigned int entry, pool_size = 0; + bfd_boolean padding_slot_p = FALSE; + unsigned imm1 = 0; + unsigned imm2 = 0; + + if (nbytes == 8) + { + imm1 = inst.operands[1].imm; + imm2 = (inst.operands[1].regisimm ? inst.operands[1].reg + : inst.reloc.exp.X_unsigned ? 0 + : ((bfd_int64_t) inst.operands[1].imm) >> 32); + if (target_big_endian) + { + imm1 = imm2; + imm2 = inst.operands[1].imm; + } + } pool = find_or_make_literal_pool (); /* Check if this literal value is already in the pool. */ for (entry = 0; entry < pool->next_free_entry; entry ++) { - if ((pool->literals[entry].X_op == inst.reloc.exp.X_op) - && (inst.reloc.exp.X_op == O_constant) - && (pool->literals[entry].X_add_number - == inst.reloc.exp.X_add_number) - && (pool->literals[entry].X_unsigned - == inst.reloc.exp.X_unsigned)) + if (nbytes == 4) + { + if ((pool->literals[entry].X_op == inst.reloc.exp.X_op) + && (inst.reloc.exp.X_op == O_constant) + && (pool->literals[entry].X_add_number + == inst.reloc.exp.X_add_number) + && (pool->literals[entry].X_md == nbytes) + && (pool->literals[entry].X_unsigned + == inst.reloc.exp.X_unsigned)) + break; + + if ((pool->literals[entry].X_op == inst.reloc.exp.X_op) + && (inst.reloc.exp.X_op == O_symbol) + && (pool->literals[entry].X_add_number + == inst.reloc.exp.X_add_number) + && (pool->literals[entry].X_add_symbol + == inst.reloc.exp.X_add_symbol) + && (pool->literals[entry].X_op_symbol + == inst.reloc.exp.X_op_symbol) + && (pool->literals[entry].X_md == nbytes)) + break; + } + else if ((nbytes == 8) + && !(pool_size & 0x7) + && ((entry + 1) != pool->next_free_entry) + && (pool->literals[entry].X_op == O_constant) + && (pool->literals[entry].X_add_number == (offsetT) imm1) + && (pool->literals[entry].X_unsigned + == inst.reloc.exp.X_unsigned) + && (pool->literals[entry + 1].X_op == O_constant) + && (pool->literals[entry + 1].X_add_number == (offsetT) imm2) + && (pool->literals[entry + 1].X_unsigned + == inst.reloc.exp.X_unsigned)) break; - if ((pool->literals[entry].X_op == inst.reloc.exp.X_op) - && (inst.reloc.exp.X_op == O_symbol) - && (pool->literals[entry].X_add_number - == inst.reloc.exp.X_add_number) - && (pool->literals[entry].X_add_symbol - == inst.reloc.exp.X_add_symbol) - && (pool->literals[entry].X_op_symbol - == inst.reloc.exp.X_op_symbol)) + padding_slot_p = ((pool->literals[entry].X_md >> 8) == PADDING_SLOT); + if (padding_slot_p && (nbytes == 4)) break; + + pool_size += 4; } /* Do we need to create a new entry? */ @@ -3109,7 +3278,64 @@ add_to_lit_pool (void) return FAIL; } - pool->literals[entry] = inst.reloc.exp; + if (nbytes == 8) + { + /* For 8-byte entries, we align to an 8-byte boundary, + and split it into two 4-byte entries, because on 32-bit + host, 8-byte constants are treated as big num, thus + saved in "generic_bignum" which will be overwritten + by later assignments. + + We also need to make sure there is enough space for + the split. + + We also check to make sure the literal operand is a + constant number. */ + if (!(inst.reloc.exp.X_op == O_constant + || inst.reloc.exp.X_op == O_big)) + { + inst.error = _("invalid type for literal pool"); + return FAIL; + } + else if (pool_size & 0x7) + { + if ((entry + 2) >= MAX_LITERAL_POOL_SIZE) + { + inst.error = _("literal pool overflow"); + return FAIL; + } + + pool->literals[entry] = inst.reloc.exp; + pool->literals[entry].X_add_number = 0; + pool->literals[entry++].X_md = (PADDING_SLOT << 8) | 4; + pool->next_free_entry += 1; + pool_size += 4; + } + else if ((entry + 1) >= MAX_LITERAL_POOL_SIZE) + { + inst.error = _("literal pool overflow"); + return FAIL; + } + + pool->literals[entry] = inst.reloc.exp; + pool->literals[entry].X_op = O_constant; + pool->literals[entry].X_add_number = imm1; + pool->literals[entry].X_unsigned = inst.reloc.exp.X_unsigned; + pool->literals[entry++].X_md = 4; + pool->literals[entry] = inst.reloc.exp; + pool->literals[entry].X_op = O_constant; + pool->literals[entry].X_add_number = imm2; + pool->literals[entry].X_unsigned = inst.reloc.exp.X_unsigned; + pool->literals[entry].X_md = 4; + pool->alignment = 3; + pool->next_free_entry += 1; + } + else + { + pool->literals[entry] = inst.reloc.exp; + pool->literals[entry].X_md = 4; + } + #ifdef OBJ_ELF /* PR ld/12974: Record the location of the first source line to reference this entry in the literal pool. If it turns out during linking that the @@ -3120,14 +3346,45 @@ add_to_lit_pool (void) #endif pool->next_free_entry += 1; } + else if (padding_slot_p) + { + pool->literals[entry] = inst.reloc.exp; + pool->literals[entry].X_md = nbytes; + } inst.reloc.exp.X_op = O_symbol; - inst.reloc.exp.X_add_number = ((int) entry) * 4; + inst.reloc.exp.X_add_number = pool_size; inst.reloc.exp.X_add_symbol = pool->symbol; return SUCCESS; } +bfd_boolean +tc_start_label_without_colon (char unused1 ATTRIBUTE_UNUSED, const char * rest) +{ + bfd_boolean ret = TRUE; + + if (codecomposer_syntax && asmfunc_state == WAITING_ASMFUNC_NAME) + { + const char *label = rest; + + while (!is_end_of_line[(int) label[-1]]) + --label; + + if (*label == '.') + { + as_bad (_("Invalid label '%s'"), label); + ret = FALSE; + } + + asmfunc_debug (label); + + asmfunc_state = WAITING_ENDASMFUNC; + } + + return ret; +} + /* Can't use symbol_new here, so have to create a symbol and then at a later date assign it a value. Thats what these functions do. */ @@ -3138,7 +3395,7 @@ symbol_locate (symbolS * symbolP, valueT valu, /* Symbol value. */ fragS * frag) /* Associated fragment. */ { - unsigned int name_length; + size_t name_length; char * preserved_copy_of_name; name_length = strlen (name) + 1; /* +1 for \0. */ @@ -3179,7 +3436,6 @@ symbol_locate (symbolS * symbolP, #endif /* DEBUG_SYMS */ } - static void s_ltorg (int ignored ATTRIBUTE_UNUSED) { @@ -3193,15 +3449,17 @@ s_ltorg (int ignored ATTRIBUTE_UNUSED) || pool->next_free_entry == 0) return; - mapping_state (MAP_DATA); - /* Align pool as you have word accesses. Only make a frag if we have to. */ if (!need_pass_2) - frag_align (2, 0, 0); + frag_align (pool->alignment, 0, 0); record_alignment (now_seg, 2); +#ifdef OBJ_ELF + seg_info (now_seg)->tc_segment_info_data.mapstate = MAP_DATA; + make_mapping_symbol (MAP_DATA, (valueT) frag_now_fix (), frag_now); +#endif sprintf (sym_name, "$$lit_\002%x", pool->id); symbol_locate (pool->symbol, sym_name, now_seg, @@ -3221,7 +3479,8 @@ s_ltorg (int ignored ATTRIBUTE_UNUSED) dwarf2_gen_line_info (frag_now_fix (), pool->locs + entry); #endif /* First output the expression in the instruction to the pool. */ - emit_expr (&(pool->literals[entry]), 4); /* .word */ + emit_expr (&(pool->literals[entry]), + pool->literals[entry].X_md & LIT_ENTRY_SIZE_MASK); } /* Mark the pool as empty. */ @@ -3316,7 +3575,8 @@ s_arm_elf_cons (int nbytes) memcpy (base, save_buf, p - base); offset = nbytes - size; - p = frag_more ((int) nbytes); + p = frag_more (nbytes); + memset (p, 0, nbytes); fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size, &exp, 0, (enum bfd_reloc_code_real) reloc); } @@ -4134,15 +4394,24 @@ s_arm_unwind_save (int arch_v6) s_arm_unwind_save_fpa (reg->number); return; - case REG_TYPE_RN: s_arm_unwind_save_core (); return; + case REG_TYPE_RN: + s_arm_unwind_save_core (); + return; + case REG_TYPE_VFD: if (arch_v6) s_arm_unwind_save_vfp_armv6 (); else s_arm_unwind_save_vfp (); return; - case REG_TYPE_MMXWR: s_arm_unwind_save_mmxwr (); return; - case REG_TYPE_MMXWCG: s_arm_unwind_save_mmxwcg (); return; + + case REG_TYPE_MMXWR: + s_arm_unwind_save_mmxwr (); + return; + + case REG_TYPE_MMXWCG: + s_arm_unwind_save_mmxwcg (); + return; default: as_bad (_(".unwind_save does not support this kind of register")); @@ -4477,6 +4746,13 @@ const pseudo_typeS md_pseudo_table[] = #ifdef TE_PE {"secrel32", pe_directive_secrel, 0}, #endif + + /* These are for compatibility with CodeComposer Studio. */ + {"ref", s_ccs_ref, 0}, + {"def", s_ccs_def, 0}, + {"asmfunc", s_ccs_asmfunc, 0}, + {"endasmfunc", s_ccs_endasmfunc, 0}, + { 0, 0, 0 } }; @@ -4515,28 +4791,31 @@ parse_immediate (char **str, int *val, int min, int max, instructions. Puts the result directly in inst.operands[i]. */ static int -parse_big_immediate (char **str, int i) +parse_big_immediate (char **str, int i, expressionS *in_exp, + bfd_boolean allow_symbol_p) { expressionS exp; + expressionS *exp_p = in_exp ? in_exp : &exp; char *ptr = *str; - my_get_expression (&exp, &ptr, GE_OPT_PREFIX_BIG); + my_get_expression (exp_p, &ptr, GE_OPT_PREFIX_BIG); - if (exp.X_op == O_constant) + if (exp_p->X_op == O_constant) { - inst.operands[i].imm = exp.X_add_number & 0xffffffff; + inst.operands[i].imm = exp_p->X_add_number & 0xffffffff; /* If we're on a 64-bit host, then a 64-bit number can be returned using O_constant. We have to be careful not to break compilation for 32-bit X_add_number, though. */ - if ((exp.X_add_number & ~(offsetT)(0xffffffffU)) != 0) + if ((exp_p->X_add_number & ~(offsetT)(0xffffffffU)) != 0) { - /* X >> 32 is illegal if sizeof (exp.X_add_number) == 4. */ - inst.operands[i].reg = ((exp.X_add_number >> 16) >> 16) & 0xffffffff; + /* X >> 32 is illegal if sizeof (exp_p->X_add_number) == 4. */ + inst.operands[i].reg = (((exp_p->X_add_number >> 16) >> 16) + & 0xffffffff); inst.operands[i].regisimm = 1; } } - else if (exp.X_op == O_big - && LITTLENUM_NUMBER_OF_BITS * exp.X_add_number > 32) + else if (exp_p->X_op == O_big + && LITTLENUM_NUMBER_OF_BITS * exp_p->X_add_number > 32) { unsigned parts = 32 / LITTLENUM_NUMBER_OF_BITS, j, idx = 0; @@ -4549,7 +4828,7 @@ parse_big_immediate (char **str, int i) PR 11972: Bignums can now be sign-extended to the size of a .octa so check that the out of range bits are all zero or all one. */ - if (LITTLENUM_NUMBER_OF_BITS * exp.X_add_number > 64) + if (LITTLENUM_NUMBER_OF_BITS * exp_p->X_add_number > 64) { LITTLENUM_TYPE m = -1; @@ -4557,7 +4836,7 @@ parse_big_immediate (char **str, int i) && generic_bignum[parts * 2] != m) return FAIL; - for (j = parts * 2 + 1; j < (unsigned) exp.X_add_number; j++) + for (j = parts * 2 + 1; j < (unsigned) exp_p->X_add_number; j++) if (generic_bignum[j] != generic_bignum[j-1]) return FAIL; } @@ -4572,7 +4851,7 @@ parse_big_immediate (char **str, int i) << (LITTLENUM_NUMBER_OF_BITS * j); inst.operands[i].regisimm = 1; } - else + else if (!(exp_p->X_op == O_symbol && allow_symbol_p)) return FAIL; *str = ptr; @@ -4645,7 +4924,9 @@ parse_fpa_immediate (char ** str) { /* FIXME: 5 = X_PRECISION, should be #define'd where we can use it. Ditto for 15. */ - if (gen_to_words (words, 5, (long) 15) == 0) +#define X_PRECISION 5 +#define E_PRECISION 15L + if (gen_to_words (words, X_PRECISION, E_PRECISION) == 0) { for (i = 0; i < NUM_FLOAT_VALS; i++) { @@ -4681,6 +4962,41 @@ is_quarter_float (unsigned imm) return (imm & 0x7ffff) == 0 && ((imm & 0x7e000000) ^ bs) == 0; } + +/* Detect the presence of a floating point or integer zero constant, + i.e. #0.0 or #0. */ + +static bfd_boolean +parse_ifimm_zero (char **in) +{ + int error_code; + + if (!is_immediate_prefix (**in)) + return FALSE; + + ++*in; + + /* Accept #0x0 as a synonym for #0. */ + if (strncmp (*in, "0x", 2) == 0) + { + int val; + if (parse_immediate (in, &val, 0, 0, TRUE) == FAIL) + return FALSE; + return TRUE; + } + + error_code = atof_generic (in, ".", EXP_CHARS, + &generic_floating_point_number); + + if (!error_code + && generic_floating_point_number.sign == '+' + && (generic_floating_point_number.low + > generic_floating_point_number.leader)) + return TRUE; + + return FALSE; +} + /* Parse an 8-bit "quarter-precision" floating point number of the form: 0baBbbbbbc defgh000 00000000 00000000. The zero and minus-zero cases need special handling, since they can't be @@ -5165,10 +5481,12 @@ parse_address_main (char **str, int i, int group_relocations, inst.operands[i].reg = REG_PC; inst.operands[i].isreg = 1; inst.operands[i].preind = 1; - } - /* Otherwise a load-constant pseudo op, no special treatment needed here. */ - if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX)) + if (my_get_expression (&inst.reloc.exp, &p, GE_OPT_PREFIX_BIG)) + return PARSE_OPERAND_FAIL; + } + else if (parse_big_immediate (&p, i, &inst.reloc.exp, + /*allow_symbol_p=*/TRUE)) return PARSE_OPERAND_FAIL; *str = p; @@ -5469,7 +5787,7 @@ parse_psr (char **str, bfd_boolean lhs) /* PR gas/12698: If the user has specified -march=all then m_profile will be TRUE, but we want to ignore it in this case as we are building for any CPU type, including non-m variants. */ - if (selected_cpu.core == arm_arch_any.core) + if (ARM_FEATURE_CORE_EQUAL (selected_cpu, arm_arch_any)) m_profile = FALSE; /* CPSR's and SPSR's can now be lowercase. This is just a convenience @@ -5998,7 +6316,8 @@ parse_neon_mov (char **str, int *which_operand) Case 10: VMOV.F32 , # Case 11: VMOV.F64
, # */ inst.operands[i].immisfloat = 1; - else if (parse_big_immediate (&ptr, i) == SUCCESS) + else if (parse_big_immediate (&ptr, i, NULL, /*allow_symbol_p=*/FALSE) + == SUCCESS) /* Case 2: VMOV.
, # Case 3: VMOV.
, # */ ; @@ -6151,6 +6470,7 @@ enum operand_parse_code OP_RNDQ_I0, /* Neon D or Q reg, or immediate zero. */ OP_RVSD_I0, /* VFP S or D reg, or immediate zero. */ + OP_RSVD_FI0, /* VFP S or D reg, or floating point immediate zero. */ OP_RR_RNSC, /* ARM reg or Neon scalar. */ OP_RNSDQ_RNSC, /* Vector S, D or Q reg, or Neon scalar. */ OP_RNDQ_RNSC, /* Neon D or Q reg, or Neon scalar. */ @@ -6434,6 +6754,22 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) po_reg_or_goto (REG_TYPE_VFSD, try_imm0); break; + case OP_RSVD_FI0: + { + po_reg_or_goto (REG_TYPE_VFSD, try_ifimm0); + break; + try_ifimm0: + if (parse_ifimm_zero (&str)) + inst.operands[i].imm = 0; + else + { + inst.error + = _("only floating point zero is allowed as immediate value"); + goto failure; + } + } + break; + case OP_RR_RNSC: { po_scalar_or_goto (8, try_rr); @@ -6483,7 +6819,8 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) try_immbig: /* There's a possibility of getting a 64-bit immediate here, so we need special handling. */ - if (parse_big_immediate (&str, i) == FAIL) + if (parse_big_immediate (&str, i, NULL, /*allow_symbol_p=*/FALSE) + == FAIL) { inst.error = _("immediate value is out of range"); goto failure; @@ -6719,7 +7056,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) val = parse_reg_list (&str); if (*str == '^') { - inst.operands[1].writeback = 1; + inst.operands[i].writeback = 1; str++; } break; @@ -6935,12 +7272,12 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb) #define warn_deprecated_sp(reg) \ do \ if (warn_on_deprecated && reg == REG_SP) \ - as_warn (_("use of r13 is deprecated")); \ + as_tsktsk (_("use of r13 is deprecated")); \ while (0) /* Functions for operand encoding. ARM, then Thumb. */ -#define rotate_left(v, n) (v << n | v >> (32 - n)) +#define rotate_left(v, n) (v << (n & 31) | v >> ((32 - n) & 31)) /* If VAL can be encoded in the immediate field of an ARM instruction, return the encoded form. Otherwise, return FAIL. */ @@ -7167,7 +7504,7 @@ encode_arm_addr_mode_2 (int i, bfd_boolean is_t) if (warn_on_deprecated && !is_load && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v7)) - as_warn (_("use of PC in this instruction is deprecated")); + as_tsktsk (_("use of PC in this instruction is deprecated")); } if (inst.reloc.type == BFD_RELOC_UNUSED) @@ -7224,70 +7561,251 @@ encode_arm_addr_mode_3 (int i, bfd_boolean is_t) } } -/* inst.operands[i] was set up by parse_address. Encode it into an - ARM-format instruction. Reject all forms which cannot be encoded - into a coprocessor load/store instruction. If wb_ok is false, - reject use of writeback; if unind_ok is false, reject use of - unindexed addressing. If reloc_override is not 0, use it instead - of BFD_ARM_CP_OFF_IMM, unless the initial relocation is a group one - (in which case it is preserved). */ +/* Write immediate bits [7:0] to the following locations: -static int -encode_arm_cp_address (int i, int wb_ok, int unind_ok, int reloc_override) -{ - inst.instruction |= inst.operands[i].reg << 16; + |28/24|23 19|18 16|15 4|3 0| + | a |x x x x x|b c d|x x x x x x x x x x x x|e f g h| - gas_assert (!(inst.operands[i].preind && inst.operands[i].postind)); + This function is used by VMOV/VMVN/VORR/VBIC. */ - if (!inst.operands[i].preind && !inst.operands[i].postind) /* unindexed */ - { - gas_assert (!inst.operands[i].writeback); - if (!unind_ok) - { - inst.error = _("instruction does not support unindexed addressing"); - return FAIL; - } - inst.instruction |= inst.operands[i].imm; - inst.instruction |= INDEX_UP; - return SUCCESS; - } +static void +neon_write_immbits (unsigned immbits) +{ + inst.instruction |= immbits & 0xf; + inst.instruction |= ((immbits >> 4) & 0x7) << 16; + inst.instruction |= ((immbits >> 7) & 0x1) << (thumb_mode ? 28 : 24); +} - if (inst.operands[i].preind) - inst.instruction |= PRE_INDEX; +/* Invert low-order SIZE bits of XHI:XLO. */ - if (inst.operands[i].writeback) - { - if (inst.operands[i].reg == REG_PC) - { - inst.error = _("pc may not be used with write-back"); - return FAIL; - } - if (!wb_ok) - { - inst.error = _("instruction does not support writeback"); - return FAIL; - } - inst.instruction |= WRITE_BACK; - } +static void +neon_invert_size (unsigned *xlo, unsigned *xhi, int size) +{ + unsigned immlo = xlo ? *xlo : 0; + unsigned immhi = xhi ? *xhi : 0; - if (reloc_override) - inst.reloc.type = (bfd_reloc_code_real_type) reloc_override; - else if ((inst.reloc.type < BFD_RELOC_ARM_ALU_PC_G0_NC - || inst.reloc.type > BFD_RELOC_ARM_LDC_SB_G2) - && inst.reloc.type != BFD_RELOC_ARM_LDR_PC_G0) + switch (size) { - if (thumb_mode) - inst.reloc.type = BFD_RELOC_ARM_T32_CP_OFF_IMM; - else - inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM; - } - - /* Prefer + for zero encoded value. */ - if (!inst.operands[i].negative) - inst.instruction |= INDEX_UP; + case 8: + immlo = (~immlo) & 0xff; + break; - return SUCCESS; -} + case 16: + immlo = (~immlo) & 0xffff; + break; + + case 64: + immhi = (~immhi) & 0xffffffff; + /* fall through. */ + + case 32: + immlo = (~immlo) & 0xffffffff; + break; + + default: + abort (); + } + + if (xlo) + *xlo = immlo; + + if (xhi) + *xhi = immhi; +} + +/* True if IMM has form 0bAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD for bits + A, B, C, D. */ + +static int +neon_bits_same_in_bytes (unsigned imm) +{ + return ((imm & 0x000000ff) == 0 || (imm & 0x000000ff) == 0x000000ff) + && ((imm & 0x0000ff00) == 0 || (imm & 0x0000ff00) == 0x0000ff00) + && ((imm & 0x00ff0000) == 0 || (imm & 0x00ff0000) == 0x00ff0000) + && ((imm & 0xff000000) == 0 || (imm & 0xff000000) == 0xff000000); +} + +/* For immediate of above form, return 0bABCD. */ + +static unsigned +neon_squash_bits (unsigned imm) +{ + return (imm & 0x01) | ((imm & 0x0100) >> 7) | ((imm & 0x010000) >> 14) + | ((imm & 0x01000000) >> 21); +} + +/* Compress quarter-float representation to 0b...000 abcdefgh. */ + +static unsigned +neon_qfloat_bits (unsigned imm) +{ + return ((imm >> 19) & 0x7f) | ((imm >> 24) & 0x80); +} + +/* Returns CMODE. IMMBITS [7:0] is set to bits suitable for inserting into + the instruction. *OP is passed as the initial value of the op field, and + may be set to a different value depending on the constant (i.e. + "MOV I64, 0bAAAAAAAABBBB..." which uses OP = 1 despite being MOV not + MVN). If the immediate looks like a repeated pattern then also + try smaller element sizes. */ + +static int +neon_cmode_for_move_imm (unsigned immlo, unsigned immhi, int float_p, + unsigned *immbits, int *op, int size, + enum neon_el_type type) +{ + /* Only permit float immediates (including 0.0/-0.0) if the operand type is + float. */ + if (type == NT_float && !float_p) + return FAIL; + + if (type == NT_float && is_quarter_float (immlo) && immhi == 0) + { + if (size != 32 || *op == 1) + return FAIL; + *immbits = neon_qfloat_bits (immlo); + return 0xf; + } + + if (size == 64) + { + if (neon_bits_same_in_bytes (immhi) + && neon_bits_same_in_bytes (immlo)) + { + if (*op == 1) + return FAIL; + *immbits = (neon_squash_bits (immhi) << 4) + | neon_squash_bits (immlo); + *op = 1; + return 0xe; + } + + if (immhi != immlo) + return FAIL; + } + + if (size >= 32) + { + if (immlo == (immlo & 0x000000ff)) + { + *immbits = immlo; + return 0x0; + } + else if (immlo == (immlo & 0x0000ff00)) + { + *immbits = immlo >> 8; + return 0x2; + } + else if (immlo == (immlo & 0x00ff0000)) + { + *immbits = immlo >> 16; + return 0x4; + } + else if (immlo == (immlo & 0xff000000)) + { + *immbits = immlo >> 24; + return 0x6; + } + else if (immlo == ((immlo & 0x0000ff00) | 0x000000ff)) + { + *immbits = (immlo >> 8) & 0xff; + return 0xc; + } + else if (immlo == ((immlo & 0x00ff0000) | 0x0000ffff)) + { + *immbits = (immlo >> 16) & 0xff; + return 0xd; + } + + if ((immlo & 0xffff) != (immlo >> 16)) + return FAIL; + immlo &= 0xffff; + } + + if (size >= 16) + { + if (immlo == (immlo & 0x000000ff)) + { + *immbits = immlo; + return 0x8; + } + else if (immlo == (immlo & 0x0000ff00)) + { + *immbits = immlo >> 8; + return 0xa; + } + + if ((immlo & 0xff) != (immlo >> 8)) + return FAIL; + immlo &= 0xff; + } + + if (immlo == (immlo & 0x000000ff)) + { + /* Don't allow MVN with 8-bit immediate. */ + if (*op == 1) + return FAIL; + *immbits = immlo; + return 0xe; + } + + return FAIL; +} + +/* Returns TRUE if double precision value V may be cast + to single precision without loss of accuracy. */ + +static bfd_boolean +is_double_a_single (long int v) +{ + int exp = (int) (v >> 52) & 0x7FF; + long int mantissa = (v & 0xFFFFFFFFFFFFFl); + + return (exp == 0 || exp == 0x7FF + || (exp >= 1023 - 126 && exp <= 1023 + 127)) + && (mantissa & 0x1FFFFFFFl) == 0; +} + +/* Returns a double precision value casted to single precision + (ignoring the least significant bits in exponent and mantissa). */ + +static int +double_to_single (long int v) +{ + int sign = (int) ((v >> 63) & 1l); + int exp = (int) (v >> 52) & 0x7FF; + long int mantissa = (v & 0xFFFFFFFFFFFFFl); + + if (exp == 0x7FF) + exp = 0xFF; + else + { + exp = exp - 1023 + 127; + if (exp >= 0xFF) + { + /* Infinity. */ + exp = 0x7F; + mantissa = 0; + } + else if (exp < 0) + { + /* No denormalized numbers. */ + exp = 0; + mantissa = 0; + } + } + mantissa >>= 29; + return (sign << 31) | (exp << 23) | mantissa; +} + +enum lit_type +{ + CONST_THUMB, + CONST_ARM, + CONST_VEC +}; + +static void do_vfp_nsyn_opcode (const char *); /* inst.reloc.exp describes an "=expr" load pseudo-operation. Determine whether it can be performed with a move instruction; if @@ -7299,9 +7817,11 @@ encode_arm_cp_address (int i, int wb_ok, int unind_ok, int reloc_override) inst.operands[i] describes the destination register. */ static bfd_boolean -move_or_literal_pool (int i, bfd_boolean thumb_p, bfd_boolean mode_3) +move_or_literal_pool (int i, enum lit_type t, bfd_boolean mode_3) { unsigned long tbit; + bfd_boolean thumb_p = (t == CONST_THUMB); + bfd_boolean arm_p = (t == CONST_ARM); if (thumb_p) tbit = (inst.instruction > 0xffff) ? THUMB2_LOAD_BIT : THUMB_LOAD_BIT; @@ -7313,52 +7833,197 @@ move_or_literal_pool (int i, bfd_boolean thumb_p, bfd_boolean mode_3) inst.error = _("invalid pseudo operation"); return TRUE; } - if (inst.reloc.exp.X_op != O_constant && inst.reloc.exp.X_op != O_symbol) + + if (inst.reloc.exp.X_op != O_constant + && inst.reloc.exp.X_op != O_symbol + && inst.reloc.exp.X_op != O_big) { inst.error = _("constant expression expected"); return TRUE; } - if (inst.reloc.exp.X_op == O_constant) + + if (inst.reloc.exp.X_op == O_constant + || inst.reloc.exp.X_op == O_big) { - if (thumb_p) + offsetT v; + + if (inst.reloc.exp.X_op == O_big) { - if (!unified_syntax && (inst.reloc.exp.X_add_number & ~0xFF) == 0) + LITTLENUM_TYPE w[X_PRECISION]; + LITTLENUM_TYPE * l; + + if (inst.reloc.exp.X_add_number == -1) { - /* This can be done with a mov(1) instruction. */ - inst.instruction = T_OPCODE_MOV_I8 | (inst.operands[i].reg << 8); - inst.instruction |= inst.reloc.exp.X_add_number; - return TRUE; + gen_to_words (w, X_PRECISION, E_PRECISION); + l = w; + /* FIXME: Should we check words w[2..5] ? */ } + else + l = generic_bignum; + + v = ((l[1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS) + | (l[0] & LITTLENUM_MASK); } else + v = inst.reloc.exp.X_add_number; + + if (!inst.operands[i].issingle) { - int value = encode_arm_immediate (inst.reloc.exp.X_add_number); - if (value != FAIL) + if (thumb_p) { - /* This can be done with a mov instruction. */ - inst.instruction &= LITERAL_MASK; - inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT); - inst.instruction |= value & 0xfff; - return TRUE; + if ((v & ~0xFF) == 0) + { + /* This can be done with a mov(1) instruction. */ + inst.instruction = T_OPCODE_MOV_I8 | (inst.operands[i].reg << 8); + inst.instruction |= v; + return TRUE; + } + + if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_arch_t2) + && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2)) + { + /* Check if on thumb2 it can be done with a mov.w or mvn.w instruction. */ + unsigned int newimm; + bfd_boolean isNegated; + + newimm = encode_thumb32_immediate (v); + if (newimm != (unsigned int) FAIL) + isNegated = FALSE; + else + { + newimm = encode_thumb32_immediate (~ v); + if (newimm != (unsigned int) FAIL) + isNegated = TRUE; + } + + if (newimm != (unsigned int) FAIL) + { + inst.instruction = 0xf04f0000 | (inst.operands[i].reg << 8); + inst.instruction |= (isNegated?0x200000:0); + inst.instruction |= (newimm & 0x800) << 15; + inst.instruction |= (newimm & 0x700) << 4; + inst.instruction |= (newimm & 0x0ff); + return TRUE; + } + else if ((v & ~0xFFFF) == 0 || (v & ~0xFFFF0000) == 0) + { + /* The number may be loaded with a movw/movt instruction. */ + int imm; + + if ((inst.reloc.exp.X_add_number & ~0xFFFF) == 0) + { + inst.instruction= 0xf2400000; + imm = v; + } + else + { + inst.instruction = 0xf2c00000; + imm = v >> 16; + } + + inst.instruction |= (inst.operands[i].reg << 8); + inst.instruction |= (imm & 0xf000) << 4; + inst.instruction |= (imm & 0x0800) << 15; + inst.instruction |= (imm & 0x0700) << 4; + inst.instruction |= (imm & 0x00ff); + return TRUE; + } + } + } + else if (arm_p) + { + int value = encode_arm_immediate (v); + + if (value != FAIL) + { + /* This can be done with a mov instruction. */ + inst.instruction &= LITERAL_MASK; + inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT); + inst.instruction |= value & 0xfff; + return TRUE; + } + + value = encode_arm_immediate (~ v); + if (value != FAIL) + { + /* This can be done with a mvn instruction. */ + inst.instruction &= LITERAL_MASK; + inst.instruction |= INST_IMMEDIATE | (OPCODE_MVN << DATA_OP_SHIFT); + inst.instruction |= value & 0xfff; + return TRUE; + } + } + else if (t == CONST_VEC) + { + int op = 0; + unsigned immbits = 0; + unsigned immlo = inst.operands[1].imm; + unsigned immhi = inst.operands[1].regisimm + ? inst.operands[1].reg + : inst.reloc.exp.X_unsigned + ? 0 + : ((bfd_int64_t)((int) immlo)) >> 32; + int cmode = neon_cmode_for_move_imm (immlo, immhi, FALSE, &immbits, + &op, 64, NT_invtype); + + if (cmode == FAIL) + { + neon_invert_size (&immlo, &immhi, 64); + op = !op; + cmode = neon_cmode_for_move_imm (immlo, immhi, FALSE, &immbits, + &op, 64, NT_invtype); + } + + if (cmode != FAIL) + { + inst.instruction = (inst.instruction & VLDR_VMOV_SAME) + | (1 << 23) + | (cmode << 8) + | (op << 5) + | (1 << 4); + + /* Fill other bits in vmov encoding for both thumb and arm. */ + if (thumb_mode) + inst.instruction |= (0x7 << 29) | (0xF << 24); + else + inst.instruction |= (0xF << 28) | (0x1 << 25); + neon_write_immbits (immbits); + return TRUE; + } } + } - value = encode_arm_immediate (~inst.reloc.exp.X_add_number); - if (value != FAIL) + if (t == CONST_VEC) + { + /* Check if vldr Rx, =constant could be optimized to vmov Rx, #constant. */ + if (inst.operands[i].issingle + && is_quarter_float (inst.operands[1].imm) + && ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v3xd)) { - /* This can be done with a mvn instruction. */ - inst.instruction &= LITERAL_MASK; - inst.instruction |= INST_IMMEDIATE | (OPCODE_MVN << DATA_OP_SHIFT); - inst.instruction |= value & 0xfff; + inst.operands[1].imm = + neon_qfloat_bits (v); + do_vfp_nsyn_opcode ("fconsts"); return TRUE; } + else if (!inst.operands[1].issingle + && ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v3)) + { + if (is_double_a_single (v) + && is_quarter_float (double_to_single (v))) + { + inst.operands[1].imm = + neon_qfloat_bits (double_to_single (v)); + do_vfp_nsyn_opcode ("fconstd"); + return TRUE; + } + } } } - if (add_to_lit_pool () == FAIL) - { - inst.error = _("literal pool insertion failed"); - return TRUE; - } + if (add_to_lit_pool ((!inst.operands[i].isvec + || inst.operands[i].issingle) ? 4 : 8) == FAIL) + return TRUE; + inst.operands[1].reg = REG_PC; inst.operands[1].isreg = 1; inst.operands[1].preind = 1; @@ -7371,6 +8036,83 @@ move_or_literal_pool (int i, bfd_boolean thumb_p, bfd_boolean mode_3) return FALSE; } +/* inst.operands[i] was set up by parse_address. Encode it into an + ARM-format instruction. Reject all forms which cannot be encoded + into a coprocessor load/store instruction. If wb_ok is false, + reject use of writeback; if unind_ok is false, reject use of + unindexed addressing. If reloc_override is not 0, use it instead + of BFD_ARM_CP_OFF_IMM, unless the initial relocation is a group one + (in which case it is preserved). */ + +static int +encode_arm_cp_address (int i, int wb_ok, int unind_ok, int reloc_override) +{ + if (!inst.operands[i].isreg) + { + /* PR 18256 */ + if (! inst.operands[0].isvec) + { + inst.error = _("invalid co-processor operand"); + return FAIL; + } + if (move_or_literal_pool (0, CONST_VEC, /*mode_3=*/FALSE)) + return SUCCESS; + } + + inst.instruction |= inst.operands[i].reg << 16; + + gas_assert (!(inst.operands[i].preind && inst.operands[i].postind)); + + if (!inst.operands[i].preind && !inst.operands[i].postind) /* unindexed */ + { + gas_assert (!inst.operands[i].writeback); + if (!unind_ok) + { + inst.error = _("instruction does not support unindexed addressing"); + return FAIL; + } + inst.instruction |= inst.operands[i].imm; + inst.instruction |= INDEX_UP; + return SUCCESS; + } + + if (inst.operands[i].preind) + inst.instruction |= PRE_INDEX; + + if (inst.operands[i].writeback) + { + if (inst.operands[i].reg == REG_PC) + { + inst.error = _("pc may not be used with write-back"); + return FAIL; + } + if (!wb_ok) + { + inst.error = _("instruction does not support writeback"); + return FAIL; + } + inst.instruction |= WRITE_BACK; + } + + if (reloc_override) + inst.reloc.type = (bfd_reloc_code_real_type) reloc_override; + else if ((inst.reloc.type < BFD_RELOC_ARM_ALU_PC_G0_NC + || inst.reloc.type > BFD_RELOC_ARM_LDC_SB_G2) + && inst.reloc.type != BFD_RELOC_ARM_LDR_PC_G0) + { + if (thumb_mode) + inst.reloc.type = BFD_RELOC_ARM_T32_CP_OFF_IMM; + else + inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM; + } + + /* Prefer + for zero encoded value. */ + if (!inst.operands[i].negative) + inst.instruction |= INDEX_UP; + + return SUCCESS; +} + /* Functions for instruction encoding, sorted by sub-architecture. First some generics; their names are taken from the conventional bit positions for register arguments in ARM format instructions. */ @@ -7419,7 +8161,7 @@ check_obsolete (const arm_feature_set *feature, const char *msg) { if (ARM_CPU_IS_ANY (cpu_variant)) { - as_warn ("%s", msg); + as_tsktsk ("%s", msg); return TRUE; } else if (ARM_CPU_HAS_FEATURE (cpu_variant, *feature)) @@ -7447,7 +8189,7 @@ do_rd_rm_rn (void) _("swp{b} use is obsoleted for ARMv8 and later")) && warn_on_deprecated && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6)) - as_warn (_("swp{b} use is deprecated for ARMv6 and ARMv7")); + as_tsktsk (_("swp{b} use is deprecated for ARMv6 and ARMv7")); } inst.instruction |= inst.operands[0].reg << 12; @@ -7765,19 +8507,19 @@ struct deprecated_coproc_regs_s static struct deprecated_coproc_regs_s deprecated_coproc_regs[] = { {15, 0, 7, 10, 5, /* CP15DMB. */ - ARM_FEATURE (ARM_EXT_V8, 0), ARM_FEATURE (0, 0), + ARM_FEATURE_CORE_LOW (ARM_EXT_V8), ARM_ARCH_NONE, DEPR_ACCESS_V8, NULL}, {15, 0, 7, 10, 4, /* CP15DSB. */ - ARM_FEATURE (ARM_EXT_V8, 0), ARM_FEATURE (0, 0), + ARM_FEATURE_CORE_LOW (ARM_EXT_V8), ARM_ARCH_NONE, DEPR_ACCESS_V8, NULL}, {15, 0, 7, 5, 4, /* CP15ISB. */ - ARM_FEATURE (ARM_EXT_V8, 0), ARM_FEATURE (0, 0), + ARM_FEATURE_CORE_LOW (ARM_EXT_V8), ARM_ARCH_NONE, DEPR_ACCESS_V8, NULL}, {14, 6, 1, 0, 0, /* TEEHBR. */ - ARM_FEATURE (ARM_EXT_V8, 0), ARM_FEATURE (0, 0), + ARM_FEATURE_CORE_LOW (ARM_EXT_V8), ARM_ARCH_NONE, DEPR_ACCESS_V8, NULL}, {14, 6, 0, 0, 0, /* TEECR. */ - ARM_FEATURE (ARM_EXT_V8, 0), ARM_FEATURE (0, 0), + ARM_FEATURE_CORE_LOW (ARM_EXT_V8), ARM_ARCH_NONE, DEPR_ACCESS_V8, NULL}, }; @@ -7824,7 +8566,7 @@ do_co_reg (void) if (! ARM_CPU_IS_ANY (cpu_variant) && warn_on_deprecated && ARM_CPU_HAS_FEATURE (cpu_variant, r->deprecated)) - as_warn ("%s", r->dep_msg); + as_tsktsk ("%s", r->dep_msg); } } @@ -8101,7 +8843,7 @@ do_ldst (void) { inst.instruction |= inst.operands[0].reg << 12; if (!inst.operands[1].isreg) - if (move_or_literal_pool (0, /*thumb_p=*/FALSE, /*mode_3=*/FALSE)) + if (move_or_literal_pool (0, CONST_ARM, /*mode_3=*/FALSE)) return; encode_arm_addr_mode_2 (1, /*is_t=*/FALSE); check_ldr_r15_aligned (); @@ -8134,7 +8876,7 @@ do_ldstv4 (void) constraint (inst.operands[0].reg == REG_PC, BAD_PC); inst.instruction |= inst.operands[0].reg << 12; if (!inst.operands[1].isreg) - if (move_or_literal_pool (0, /*thumb_p=*/FALSE, /*mode_3=*/TRUE)) + if (move_or_literal_pool (0, CONST_ARM, /*mode_3=*/TRUE)) return; encode_arm_addr_mode_3 (1, /*is_t=*/FALSE); } @@ -8212,8 +8954,6 @@ do_mov16 (void) } } -static void do_vfp_nsyn_opcode (const char *); - static int do_vfp_nsyn_mrs (void) { @@ -8470,6 +9210,8 @@ do_pli (void) static void do_push_pop (void) { + constraint (inst.operands[0].writeback, + _("push/pop do not support {reglist}^")); inst.operands[1] = inst.operands[0]; memset (&inst.operands[0], 0, sizeof inst.operands[0]); inst.operands[0].isreg = 1; @@ -8547,7 +9289,7 @@ do_setend (void) { if (warn_on_deprecated && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8)) - as_warn (_("setend use is deprecated for ARMv8")); + as_tsktsk (_("setend use is deprecated for ARMv8")); if (inst.operands[0].imm) inst.instruction |= 0x200; @@ -8595,6 +9337,24 @@ do_swi (void) inst.reloc.pc_rel = 0; } +static void +do_setpan (void) +{ + constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_pan), + _("selected processor does not support SETPAN instruction")); + + inst.instruction |= ((inst.operands[0].imm & 1) << 9); +} + +static void +do_t_setpan (void) +{ + constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_pan), + _("selected processor does not support SETPAN instruction")); + + inst.instruction |= (inst.operands[0].imm << 3); +} + /* ARM V5E (El Segundo) signed-multiply-accumulate (argument parse) SMLAxy{cond} Rd,Rm,Rs,Rn SMLAWy{cond} Rd,Rm,Rs,Rn @@ -10678,7 +11438,7 @@ do_t_ldst (void) { if (opcode <= 0xffff) inst.instruction = THUMB_OP32 (opcode); - if (move_or_literal_pool (0, /*thumb_p=*/TRUE, /*mode_3=*/FALSE)) + if (move_or_literal_pool (0, CONST_THUMB, /*mode_3=*/FALSE)) return; } if (inst.operands[1].isreg @@ -10784,7 +11544,7 @@ do_t_ldst (void) inst.instruction = THUMB_OP16 (inst.instruction); if (!inst.operands[1].isreg) - if (move_or_literal_pool (0, /*thumb_p=*/TRUE, /*mode_3=*/FALSE)) + if (move_or_literal_pool (0, CONST_THUMB, /*mode_3=*/FALSE)) return; constraint (!inst.operands[1].preind @@ -10990,7 +11750,7 @@ do_t_mov_cmp (void) if ((Rn == REG_SP || Rn == REG_PC) && (Rm == REG_SP || Rm == REG_PC)) { - as_warn (_("Use of r%u as a source register is " + as_tsktsk (_("Use of r%u as a source register is " "deprecated when r%u is the destination " "register."), Rm, Rn); } @@ -11267,7 +12027,8 @@ do_t_mvn_tst (void) || inst.operands[1].shifted || Rn > 7 || Rm > 7) narrow = FALSE; - else if (inst.instruction == T_MNEM_cmn) + else if (inst.instruction == T_MNEM_cmn + || inst.instruction == T_MNEM_tst) narrow = TRUE; else if (THUMB_SETS_FLAGS (inst.instruction)) narrow = !in_it_block (); @@ -11351,7 +12112,8 @@ do_t_mrs (void) /* PR gas/12698: The constraint is only applied for m_profile. If the user has specified -march=all, we want to ignore it as we are building for any CPU type, including non-m variants. */ - bfd_boolean m_profile = selected_cpu.core != arm_arch_any.core; + bfd_boolean m_profile = + !ARM_FEATURE_CORE_EQUAL (selected_cpu, arm_arch_any); constraint ((flags != 0) && m_profile, _("selected processor does " "not support requested special purpose register")); } @@ -11391,7 +12153,8 @@ do_t_msr (void) /* PR gas/12698: The constraint is only applied for m_profile. If the user has specified -march=all, we want to ignore it as we are building for any CPU type, including non-m variants. */ - bfd_boolean m_profile = selected_cpu.core != arm_arch_any.core; + bfd_boolean m_profile = + !ARM_FEATURE_CORE_EQUAL (selected_cpu, arm_arch_any); constraint (((ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6_dsp) && (bits & ~(PSR_s | PSR_f)) != 0) || (!ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6_dsp) @@ -11671,12 +12434,11 @@ do_t_push_pop (void) _("expression too complex")); mask = inst.operands[0].imm; - if ((mask & ~0xff) == 0) + if (inst.size_req != 4 && (mask & ~0xff) == 0) inst.instruction = THUMB_OP16 (inst.instruction) | mask; - else if ((inst.instruction == T_MNEM_push - && (mask & ~0xff) == 1 << REG_LR) - || (inst.instruction == T_MNEM_pop - && (mask & ~0xff) == 1 << REG_PC)) + else if (inst.size_req != 4 + && (mask & ~0xff) == (1 << (inst.instruction == T_MNEM_push + ? REG_LR : REG_PC))) { inst.instruction = THUMB_OP16 (inst.instruction); inst.instruction |= THUMB_PP_PC_LR; @@ -11814,7 +12576,7 @@ do_t_setend (void) { if (warn_on_deprecated && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8)) - as_warn (_("setend use is deprecated for ARMv8")); + as_tsktsk (_("setend use is deprecated for ARMv8")); set_it_insn_type (OUTSIDE_IT_INSN); if (inst.operands[0].imm) @@ -12309,6 +13071,8 @@ struct neon_tab_entry X(vqdmull, 0x0800d00, N_INV, 0x0800b40), \ X(vqdmulh, 0x0000b00, N_INV, 0x0800c40), \ X(vqrdmulh, 0x1000b00, N_INV, 0x0800d40), \ + X(vqrdmlah, 0x3000b10, N_INV, 0x0800e40), \ + X(vqrdmlsh, 0x3000c10, N_INV, 0x0800f40), \ X(vshl, 0x0000400, N_INV, 0x0800510), \ X(vqshl, 0x0000410, N_INV, 0x0800710), \ X(vand, 0x0000110, N_INV, 0x0800030), \ @@ -13542,8 +14306,12 @@ do_neon_shl_imm (void) { enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL); struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_KEY | N_I_ALL); + int imm = inst.operands[2].imm; + + constraint (imm < 0 || (unsigned)imm >= et.size, + _("immediate out of range for shift")); NEON_ENCODE (IMMED, inst); - neon_imm_shift (FALSE, 0, neon_quad (rs), et, inst.operands[2].imm); + neon_imm_shift (FALSE, 0, neon_quad (rs), et, imm); } else { @@ -13574,10 +14342,12 @@ do_neon_qshl_imm (void) { enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL); struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_SU_ALL | N_KEY); + int imm = inst.operands[2].imm; + constraint (imm < 0 || (unsigned)imm >= et.size, + _("immediate out of range for shift")); NEON_ENCODE (IMMED, inst); - neon_imm_shift (TRUE, et.type == NT_unsigned, neon_quad (rs), et, - inst.operands[2].imm); + neon_imm_shift (TRUE, et.type == NT_unsigned, neon_quad (rs), et, imm); } else { @@ -13592,270 +14362,79 @@ do_neon_qshl_imm (void) inst.operands[1].reg = tmp; NEON_ENCODE (INTEGER, inst); neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size); - } -} - -static void -do_neon_rshl (void) -{ - enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL); - struct neon_type_el et = neon_check_type (3, rs, - N_EQK, N_EQK, N_SU_ALL | N_KEY); - unsigned int tmp; - - tmp = inst.operands[2].reg; - inst.operands[2].reg = inst.operands[1].reg; - inst.operands[1].reg = tmp; - neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size); -} - -static int -neon_cmode_for_logic_imm (unsigned immediate, unsigned *immbits, int size) -{ - /* Handle .I8 pseudo-instructions. */ - if (size == 8) - { - /* Unfortunately, this will make everything apart from zero out-of-range. - FIXME is this the intended semantics? There doesn't seem much point in - accepting .I8 if so. */ - immediate |= immediate << 8; - size = 16; - } - - if (size >= 32) - { - if (immediate == (immediate & 0x000000ff)) - { - *immbits = immediate; - return 0x1; - } - else if (immediate == (immediate & 0x0000ff00)) - { - *immbits = immediate >> 8; - return 0x3; - } - else if (immediate == (immediate & 0x00ff0000)) - { - *immbits = immediate >> 16; - return 0x5; - } - else if (immediate == (immediate & 0xff000000)) - { - *immbits = immediate >> 24; - return 0x7; - } - if ((immediate & 0xffff) != (immediate >> 16)) - goto bad_immediate; - immediate &= 0xffff; - } - - if (immediate == (immediate & 0x000000ff)) - { - *immbits = immediate; - return 0x9; - } - else if (immediate == (immediate & 0x0000ff00)) - { - *immbits = immediate >> 8; - return 0xb; - } - - bad_immediate: - first_error (_("immediate value out of range")); - return FAIL; -} - -/* True if IMM has form 0bAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD for bits - A, B, C, D. */ - -static int -neon_bits_same_in_bytes (unsigned imm) -{ - return ((imm & 0x000000ff) == 0 || (imm & 0x000000ff) == 0x000000ff) - && ((imm & 0x0000ff00) == 0 || (imm & 0x0000ff00) == 0x0000ff00) - && ((imm & 0x00ff0000) == 0 || (imm & 0x00ff0000) == 0x00ff0000) - && ((imm & 0xff000000) == 0 || (imm & 0xff000000) == 0xff000000); -} - -/* For immediate of above form, return 0bABCD. */ - -static unsigned -neon_squash_bits (unsigned imm) -{ - return (imm & 0x01) | ((imm & 0x0100) >> 7) | ((imm & 0x010000) >> 14) - | ((imm & 0x01000000) >> 21); + } } -/* Compress quarter-float representation to 0b...000 abcdefgh. */ - -static unsigned -neon_qfloat_bits (unsigned imm) +static void +do_neon_rshl (void) { - return ((imm >> 19) & 0x7f) | ((imm >> 24) & 0x80); -} + enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL); + struct neon_type_el et = neon_check_type (3, rs, + N_EQK, N_EQK, N_SU_ALL | N_KEY); + unsigned int tmp; -/* Returns CMODE. IMMBITS [7:0] is set to bits suitable for inserting into - the instruction. *OP is passed as the initial value of the op field, and - may be set to a different value depending on the constant (i.e. - "MOV I64, 0bAAAAAAAABBBB..." which uses OP = 1 despite being MOV not - MVN). If the immediate looks like a repeated pattern then also - try smaller element sizes. */ + tmp = inst.operands[2].reg; + inst.operands[2].reg = inst.operands[1].reg; + inst.operands[1].reg = tmp; + neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size); +} static int -neon_cmode_for_move_imm (unsigned immlo, unsigned immhi, int float_p, - unsigned *immbits, int *op, int size, - enum neon_el_type type) +neon_cmode_for_logic_imm (unsigned immediate, unsigned *immbits, int size) { - /* Only permit float immediates (including 0.0/-0.0) if the operand type is - float. */ - if (type == NT_float && !float_p) - return FAIL; - - if (type == NT_float && is_quarter_float (immlo) && immhi == 0) - { - if (size != 32 || *op == 1) - return FAIL; - *immbits = neon_qfloat_bits (immlo); - return 0xf; - } - - if (size == 64) + /* Handle .I8 pseudo-instructions. */ + if (size == 8) { - if (neon_bits_same_in_bytes (immhi) - && neon_bits_same_in_bytes (immlo)) - { - if (*op == 1) - return FAIL; - *immbits = (neon_squash_bits (immhi) << 4) - | neon_squash_bits (immlo); - *op = 1; - return 0xe; - } - - if (immhi != immlo) - return FAIL; + /* Unfortunately, this will make everything apart from zero out-of-range. + FIXME is this the intended semantics? There doesn't seem much point in + accepting .I8 if so. */ + immediate |= immediate << 8; + size = 16; } if (size >= 32) { - if (immlo == (immlo & 0x000000ff)) - { - *immbits = immlo; - return 0x0; - } - else if (immlo == (immlo & 0x0000ff00)) - { - *immbits = immlo >> 8; - return 0x2; - } - else if (immlo == (immlo & 0x00ff0000)) + if (immediate == (immediate & 0x000000ff)) { - *immbits = immlo >> 16; - return 0x4; + *immbits = immediate; + return 0x1; } - else if (immlo == (immlo & 0xff000000)) + else if (immediate == (immediate & 0x0000ff00)) { - *immbits = immlo >> 24; - return 0x6; + *immbits = immediate >> 8; + return 0x3; } - else if (immlo == ((immlo & 0x0000ff00) | 0x000000ff)) + else if (immediate == (immediate & 0x00ff0000)) { - *immbits = (immlo >> 8) & 0xff; - return 0xc; + *immbits = immediate >> 16; + return 0x5; } - else if (immlo == ((immlo & 0x00ff0000) | 0x0000ffff)) + else if (immediate == (immediate & 0xff000000)) { - *immbits = (immlo >> 16) & 0xff; - return 0xd; + *immbits = immediate >> 24; + return 0x7; } - - if ((immlo & 0xffff) != (immlo >> 16)) - return FAIL; - immlo &= 0xffff; + if ((immediate & 0xffff) != (immediate >> 16)) + goto bad_immediate; + immediate &= 0xffff; } - if (size >= 16) + if (immediate == (immediate & 0x000000ff)) { - if (immlo == (immlo & 0x000000ff)) - { - *immbits = immlo; - return 0x8; - } - else if (immlo == (immlo & 0x0000ff00)) - { - *immbits = immlo >> 8; - return 0xa; - } - - if ((immlo & 0xff) != (immlo >> 8)) - return FAIL; - immlo &= 0xff; + *immbits = immediate; + return 0x9; } - - if (immlo == (immlo & 0x000000ff)) + else if (immediate == (immediate & 0x0000ff00)) { - /* Don't allow MVN with 8-bit immediate. */ - if (*op == 1) - return FAIL; - *immbits = immlo; - return 0xe; + *immbits = immediate >> 8; + return 0xb; } + bad_immediate: + first_error (_("immediate value out of range")); return FAIL; } -/* Write immediate bits [7:0] to the following locations: - - |28/24|23 19|18 16|15 4|3 0| - | a |x x x x x|b c d|x x x x x x x x x x x x|e f g h| - - This function is used by VMOV/VMVN/VORR/VBIC. */ - -static void -neon_write_immbits (unsigned immbits) -{ - inst.instruction |= immbits & 0xf; - inst.instruction |= ((immbits >> 4) & 0x7) << 16; - inst.instruction |= ((immbits >> 7) & 0x1) << 24; -} - -/* Invert low-order SIZE bits of XHI:XLO. */ - -static void -neon_invert_size (unsigned *xlo, unsigned *xhi, int size) -{ - unsigned immlo = xlo ? *xlo : 0; - unsigned immhi = xhi ? *xhi : 0; - - switch (size) - { - case 8: - immlo = (~immlo) & 0xff; - break; - - case 16: - immlo = (~immlo) & 0xffff; - break; - - case 64: - immhi = (~immhi) & 0xffffffff; - /* fall through. */ - - case 32: - immlo = (~immlo) & 0xffffffff; - break; - - default: - abort (); - } - - if (xlo) - *xlo = immlo; - - if (xhi) - *xhi = immhi; -} - static void do_neon_logic (void) { @@ -14665,13 +15244,20 @@ do_vfp_nsyn_cvt_fpv8 (enum neon_cvt_flavour flavour, int sz, op; int rm; + /* Targets like FPv5-SP-D16 don't support FP v8 instructions with + D register operands. */ + if (flavour == neon_cvt_flavour_s32_f64 + || flavour == neon_cvt_flavour_u32_f64) + constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8), + _(BAD_FPU)); + set_it_insn_type (OUTSIDE_IT_INSN); switch (flavour) { case neon_cvt_flavour_s32_f64: sz = 1; - op = 0; + op = 1; break; case neon_cvt_flavour_s32_f32: sz = 0; @@ -14929,11 +15515,21 @@ do_neon_cvttb_1 (bfd_boolean t) } else if (neon_check_type (2, rs, N_F16, N_F64 | N_VFP).type != NT_invtype) { + /* The VCVTB and VCVTT instructions with D-register operands + don't work for SP only targets. */ + constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8), + _(BAD_FPU)); + inst.error = NULL; do_neon_cvttb_2 (t, /*to=*/TRUE, /*is_double=*/TRUE); } else if (neon_check_type (2, rs, N_F64 | N_VFP, N_F16).type != NT_invtype) { + /* The VCVTB and VCVTT instructions with D-register operands + don't work for SP only targets. */ + constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8), + _(BAD_FPU)); + inst.error = NULL; do_neon_cvttb_2 (t, /*to=*/FALSE, /*is_double=*/TRUE); } @@ -15702,7 +16298,7 @@ do_neon_ldr_str (void) if (thumb_mode) inst.error = _("Use of PC here is UNPREDICTABLE"); else if (warn_on_deprecated) - as_warn (_("Use of PC here is deprecated")); + as_tsktsk (_("Use of PC here is deprecated")); } if (inst.operands[0].issingle) @@ -15783,6 +16379,8 @@ do_neon_ld_st_interleave (void) typebits = typetable[idx]; constraint (typebits == -1, _("bad list type for instruction")); + constraint (((inst.instruction >> 8) & 3) && et.size == 64, + _("bad element type for instruction")); inst.instruction &= ~0xf00; inst.instruction |= typebits << 8; @@ -16058,6 +16656,12 @@ do_neon_ldx_stx (void) static void do_vfp_nsyn_fpv8 (enum neon_shape rs) { + /* Targets like FPv5-SP-D16 don't support FP v8 instructions with + D register operands. */ + if (neon_shape_class[rs] == SC_DOUBLE) + constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8), + _(BAD_FPU)); + NEON_ENCODE (FPV8, inst); if (rs == NS_FFF) @@ -16103,6 +16707,12 @@ do_vrint_1 (enum neon_cvt_mode mode) if (rs == NS_NULL) return; + /* Targets like FPv5-SP-D16 don't support FP v8 instructions with + D register operands. */ + if (neon_shape_class[rs] == SC_DOUBLE) + constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8), + _(BAD_FPU)); + et = neon_check_type (2, rs, N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP); if (et.type != NT_invtype) { @@ -16715,7 +17325,7 @@ opcode_lookup (char **str) } if (warn_on_deprecated && unified_syntax) - as_warn (_("conditional infixes are deprecated in unified syntax")); + as_tsktsk (_("conditional infixes are deprecated in unified syntax")); affix = base + (opcode->tag - OT_odd_infix_0); cond = (const struct asm_cond *) hash_find_n (arm_cond_hsh, affix, 2); gas_assert (cond); @@ -16801,7 +17411,7 @@ opcode_lookup (char **str) if (warn_on_deprecated && unified_syntax && (opcode->tag == OT_cinfix3 || opcode->tag == OT_cinfix3_deprecated)) - as_warn (_("conditional infixes are deprecated in unified syntax")); + as_tsktsk (_("conditional infixes are deprecated in unified syntax")); inst.cond = cond->value; return opcode; @@ -17110,6 +17720,9 @@ static const struct depr_insn_mask depr_it_insns[] = { { 0x4800, 0xf800, N_("Literal loads") }, { 0x4478, 0xf478, N_("Hi-register ADD, MOV, CMP, BX, BLX using pc") }, { 0x4487, 0xfc87, N_("Hi-register ADD, MOV, CMP using pc") }, + /* NOTE: 0x00dd is not the real encoding, instead, it is the 'tvalue' + field in asm_opcode. 'tvalue' is used at the stage this check happen. */ + { 0x00dd, 0x7fff, N_("ADD/SUB sp, sp #imm") }, { 0, 0, NULL } }; @@ -17128,7 +17741,7 @@ it_fsm_post_encode (void) { if (inst.instruction >= 0x10000) { - as_warn (_("IT blocks containing 32-bit Thumb instructions are " + as_tsktsk (_("IT blocks containing 32-bit Thumb instructions are " "deprecated in ARMv8")); now_it.warn_deprecated = TRUE; } @@ -17140,7 +17753,7 @@ it_fsm_post_encode (void) { if ((inst.instruction & p->mask) == p->pattern) { - as_warn (_("IT blocks containing 16-bit Thumb instructions " + as_tsktsk (_("IT blocks containing 16-bit Thumb instructions " "of the following class are deprecated in ARMv8: " "%s"), p->description); now_it.warn_deprecated = TRUE; @@ -17153,7 +17766,7 @@ it_fsm_post_encode (void) if (now_it.block_length > 1) { - as_warn (_("IT blocks containing more than one conditional " + as_tsktsk (_("IT blocks containing more than one conditional " "instruction are deprecated in ARMv8")); now_it.warn_deprecated = TRUE; } @@ -17217,7 +17830,7 @@ md_assemble (char *str) } if (warn_on_deprecated && opcode->tag == OT_cinfix3_deprecated) - as_warn (_("s suffix on comparison instruction is deprecated")); + as_tsktsk (_("s suffix on comparison instruction is deprecated")); /* The value which unconditional instructions should have in place of the condition field. */ @@ -17300,9 +17913,9 @@ md_assemble (char *str) /* Many Thumb-2 instructions also have Thumb-1 variants, so explicitly set those bits when Thumb-2 32-bit instructions are seen. ie. anything other than bl/blx and v6-M instructions. - This is overly pessimistic for relaxable instructions. */ - if (((inst.size == 4 && (inst.instruction & 0xf800e800) != 0xf000e800) - || inst.relax) + The impact of relaxable instructions will be considered later after we + finish all relaxation. */ + if ((inst.size == 4 && (inst.instruction & 0xf800e800) != 0xf000e800) && !(ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_msr) || ARM_CPU_HAS_FEATURE (*opcode->tvariant, arm_ext_barrier))) ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used, @@ -17790,8 +18403,8 @@ static const struct asm_cond conds[] = }; #define UL_BARRIER(L,U,CODE,FEAT) \ - { L, CODE, ARM_FEATURE (FEAT, 0) }, \ - { U, CODE, ARM_FEATURE (FEAT, 0) } + { L, CODE, ARM_FEATURE_CORE_LOW (FEAT) }, \ + { U, CODE, ARM_FEATURE_CORE_LOW (FEAT) } static struct asm_barrier_opt barrier_opt_names[] = { @@ -18447,6 +19060,13 @@ static const struct asm_opcode insns[] = TCE("hvc", 1400070, f7e08000, 1, (EXPi), hvc, t_hvc), TCE("eret", 160006e, f3de8f00, 0, (), noargs, noargs), +#undef ARM_VARIANT +#define ARM_VARIANT & arm_ext_pan +#undef THUMB_VARIANT +#define THUMB_VARIANT & arm_ext_pan + + TUF("setpan", 1100000, b610, 1, (I7), setpan, t_setpan), + #undef ARM_VARIANT #define ARM_VARIANT & arm_ext_v6t2 #undef THUMB_VARIANT @@ -18581,9 +19201,9 @@ static const struct asm_opcode insns[] = /* FP for ARMv8. */ #undef ARM_VARIANT -#define ARM_VARIANT & fpu_vfp_ext_armv8 +#define ARM_VARIANT & fpu_vfp_ext_armv8xd #undef THUMB_VARIANT -#define THUMB_VARIANT & fpu_vfp_ext_armv8 +#define THUMB_VARIANT & fpu_vfp_ext_armv8xd nUF(vseleq, _vseleq, 3, (RVSD, RVSD, RVSD), vsel), nUF(vselvs, _vselvs, 3, (RVSD, RVSD, RVSD), vsel), @@ -19215,8 +19835,8 @@ static const struct asm_opcode insns[] = nCE(vnmul, _vnmul, 3, (RVSD, RVSD, RVSD), vfp_nsyn_nmul), nCE(vnmla, _vnmla, 3, (RVSD, RVSD, RVSD), vfp_nsyn_nmul), nCE(vnmls, _vnmls, 3, (RVSD, RVSD, RVSD), vfp_nsyn_nmul), - nCE(vcmp, _vcmp, 2, (RVSD, RVSD_I0), vfp_nsyn_cmp), - nCE(vcmpe, _vcmpe, 2, (RVSD, RVSD_I0), vfp_nsyn_cmp), + nCE(vcmp, _vcmp, 2, (RVSD, RSVD_FI0), vfp_nsyn_cmp), + nCE(vcmpe, _vcmpe, 2, (RVSD, RSVD_FI0), vfp_nsyn_cmp), NCE(vpush, 0, 1, (VRSDLST), vfp_nsyn_push), NCE(vpop, 0, 1, (VRSDLST), vfp_nsyn_pop), NCE(vcvtz, 0, 2, (RVSD, RVSD), vfp_nsyn_cvtz), @@ -19352,6 +19972,11 @@ static const struct asm_opcode insns[] = NUF(vrecpsq, 0000f10, 3, (RNQ, oRNQ, RNQ), neon_step), NUF(vrsqrts, 0200f10, 3, (RNDQ, oRNDQ, RNDQ), neon_step), NUF(vrsqrtsq, 0200f10, 3, (RNQ, oRNQ, RNQ), neon_step), + /* ARM v8.1 extension. */ + nUF(vqrdmlah, _vqrdmlah, 3, (RNDQ, oRNDQ, RNDQ_RNSC), neon_qdmulh), + nUF(vqrdmlahq, _vqrdmlah, 3, (RNQ, oRNQ, RNDQ_RNSC), neon_qdmulh), + nUF(vqrdmlsh, _vqrdmlsh, 3, (RNDQ, oRNDQ, RNDQ_RNSC), neon_qdmulh), + nUF(vqrdmlshq, _vqrdmlsh, 3, (RNQ, oRNQ, RNDQ_RNSC), neon_qdmulh), /* Two address, int/float. Types S8 S16 S32 F32. */ NUF(vabsq, 1b10300, 2, (RNQ, RNQ), neon_abs_neg), @@ -20136,6 +20761,11 @@ md_convert_frag (bfd *abfd, segT asec ATTRIBUTE_UNUSED, fragS *fragp) fixp->fx_file = fragp->fr_file; fixp->fx_line = fragp->fr_line; fragp->fr_fix += fragp->fr_var; + + /* Set whether we use thumb-2 ISA based on final relaxation results. */ + if (thumb_mode && fragp->fr_var == 4 && no_cpu_selected () + && !ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_arch_t2)) + ARM_MERGE_FEATURE_SETS (arm_arch_used, thumb_arch_used, arm_ext_v6t2); } /* Return the size of a relaxable immediate operand instruction. @@ -20476,7 +21106,8 @@ arm_handle_align (fragS * fragP) if (fragP->tc_frag_data.thumb_mode & (~ MODE_RECORDED)) { - if (ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6t2)) + if (ARM_CPU_HAS_FEATURE (selected_cpu_name[0] + ? selected_cpu : arm_arch_none, arm_ext_v6t2)) { narrow_noop = thumb_noop[1][target_big_endian]; noop = wide_thumb_noop[target_big_endian]; @@ -20490,7 +21121,9 @@ arm_handle_align (fragS * fragP) } else { - noop = arm_noop[ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6k) != 0] + noop = arm_noop[ARM_CPU_HAS_FEATURE (selected_cpu_name[0] + ? selected_cpu : arm_arch_none, + arm_ext_v6k) != 0] [target_big_endian]; noop_size = 4; #ifdef OBJ_ELF @@ -20585,27 +21218,29 @@ arm_init_frag (fragS * fragP, int max_chars ATTRIBUTE_UNUSED) void arm_init_frag (fragS * fragP, int max_chars) { + int frag_thumb_mode; + /* If the current ARM vs THUMB mode has not already been recorded into this frag then do so now. */ if ((fragP->tc_frag_data.thumb_mode & MODE_RECORDED) == 0) - { - fragP->tc_frag_data.thumb_mode = thumb_mode | MODE_RECORDED; + fragP->tc_frag_data.thumb_mode = thumb_mode | MODE_RECORDED; - /* Record a mapping symbol for alignment frags. We will delete this - later if the alignment ends up empty. */ - switch (fragP->fr_type) - { - case rs_align: - case rs_align_test: - case rs_fill: - mapping_state_2 (MAP_DATA, max_chars); - break; - case rs_align_code: - mapping_state_2 (thumb_mode ? MAP_THUMB : MAP_ARM, max_chars); - break; - default: - break; - } + frag_thumb_mode = fragP->tc_frag_data.thumb_mode ^ MODE_RECORDED; + + /* Record a mapping symbol for alignment frags. We will delete this + later if the alignment ends up empty. */ + switch (fragP->fr_type) + { + case rs_align: + case rs_align_test: + case rs_fill: + mapping_state_2 (MAP_DATA, max_chars); + break; + case rs_align_code: + mapping_state_2 (frag_thumb_mode ? MAP_THUMB : MAP_ARM, max_chars); + break; + default: + break; } } @@ -20839,7 +21474,7 @@ start_unwind_section (const segT text_seg, int idx) /* Start an unwind table entry. HAVE_DATA is nonzero if we have additional personality routine data. Returns zero, or the index table value for - and inline entry. */ + an inline entry. */ static valueT create_unwind_entry (int have_data) @@ -20910,7 +21545,12 @@ create_unwind_entry (int have_data) } else { - gas_assert (unwind.personality_index == -1); + /* PR 16765: Missing or misplaced unwind directives can trigger this. */ + if (unwind.personality_index != -1) + { + as_bad (_("attempt to recreate an unwind entry")); + return 1; + } /* An extra byte is required for the opcode count. */ size = unwind.opcode_count + 1; @@ -21017,11 +21657,19 @@ int tc_arm_regname_to_dw2regnum (char *regname) { int reg = arm_reg_parse (®name, REG_TYPE_RN); + if (reg != FAIL) + return reg; - if (reg == FAIL) - return -1; + /* PR 16694: Allow VFP registers as well. */ + reg = arm_reg_parse (®name, REG_TYPE_VFS); + if (reg != FAIL) + return 64 + reg; - return reg; + reg = arm_reg_parse (®name, REG_TYPE_VFD); + if (reg != FAIL) + return reg + 256; + + return -1; } #ifdef TE_PE @@ -21167,6 +21815,51 @@ md_pcrel_from_section (fixS * fixP, segT seg) } } +static bfd_boolean flag_warn_syms = TRUE; + +bfd_boolean +arm_tc_equal_in_insn (int c ATTRIBUTE_UNUSED, char * name) +{ + /* PR 18347 - Warn if the user attempts to create a symbol with the same + name as an ARM instruction. Whilst strictly speaking it is allowed, it + does mean that the resulting code might be very confusing to the reader. + Also this warning can be triggered if the user omits an operand before + an immediate address, eg: + + LDR =foo + + GAS treats this as an assignment of the value of the symbol foo to a + symbol LDR, and so (without this code) it will not issue any kind of + warning or error message. + + Note - ARM instructions are case-insensitive but the strings in the hash + table are all stored in lower case, so we must first ensure that name is + lower case too. */ + if (flag_warn_syms && arm_ops_hsh) + { + char * nbuf = strdup (name); + char * p; + + for (p = nbuf; *p; p++) + *p = TOLOWER (*p); + if (hash_find (arm_ops_hsh, nbuf) != NULL) + { + static struct hash_control * already_warned = NULL; + + if (already_warned == NULL) + already_warned = hash_new (); + /* Only warn about the symbol once. To keep the code + simple we let hash_insert do the lookup for us. */ + if (hash_insert (already_warned, name, NULL) == NULL) + as_warn (_("[-mwarn-syms]: Assignment makes a symbol match an ARM instruction: %s"), name); + } + else + free (nbuf); + } + + return FALSE; +} + /* Under ELF we need to default _GLOBAL_OFFSET_TABLE. Otherwise we have no need to default values of symbols. */ @@ -22216,7 +22909,7 @@ md_apply_fix (fixS * fixP, case BFD_RELOC_8: if (fixP->fx_done || !seg->use_rela_p) - md_number_to_chars (buf, value, 1); + *buf = value; break; case BFD_RELOC_16: @@ -22229,9 +22922,6 @@ md_apply_fix (fixS * fixP, case BFD_RELOC_ARM_THM_TLS_CALL: case BFD_RELOC_ARM_TLS_DESCSEQ: case BFD_RELOC_ARM_THM_TLS_DESCSEQ: - S_SET_THREAD_LOCAL (fixP->fx_addsy); - break; - case BFD_RELOC_ARM_TLS_GOTDESC: case BFD_RELOC_ARM_TLS_GD32: case BFD_RELOC_ARM_TLS_LE32: @@ -22239,12 +22929,10 @@ md_apply_fix (fixS * fixP, case BFD_RELOC_ARM_TLS_LDM32: case BFD_RELOC_ARM_TLS_LDO32: S_SET_THREAD_LOCAL (fixP->fx_addsy); - /* fall through */ + break; case BFD_RELOC_ARM_GOT32: case BFD_RELOC_ARM_GOTOFF: - if (fixP->fx_done || !seg->use_rela_p) - md_number_to_chars (buf, 0, 4); break; case BFD_RELOC_ARM_GOT_PREL: @@ -22993,9 +23681,9 @@ void cons_fix_new_arm (fragS * frag, int where, int size, - expressionS * exp) + expressionS * exp, + bfd_reloc_code_real_type reloc) { - bfd_reloc_code_real_type type; int pcrel = 0; /* Pick a reloc. @@ -23003,17 +23691,17 @@ cons_fix_new_arm (fragS * frag, switch (size) { case 1: - type = BFD_RELOC_8; + reloc = BFD_RELOC_8; break; case 2: - type = BFD_RELOC_16; + reloc = BFD_RELOC_16; break; case 4: default: - type = BFD_RELOC_32; + reloc = BFD_RELOC_32; break; case 8: - type = BFD_RELOC_64; + reloc = BFD_RELOC_64; break; } @@ -23021,11 +23709,11 @@ cons_fix_new_arm (fragS * frag, if (exp->X_op == O_secrel) { exp->X_op = O_symbol; - type = BFD_RELOC_32_SECREL; + reloc = BFD_RELOC_32_SECREL; } #endif - fix_new_exp (frag, where, (int) size, exp, pcrel, type); + fix_new_exp (frag, where, size, exp, pcrel, reloc); } #if defined (OBJ_COFF) @@ -23516,6 +24204,8 @@ md_begin (void) mcpu_cpu_opt = &cpu_default; selected_cpu = cpu_default; } + else if (no_cpu_selected ()) + selected_cpu = cpu_default; #else if (mcpu_cpu_opt) selected_cpu = *mcpu_cpu_opt; @@ -23663,6 +24353,7 @@ md_begin (void) -mthumb-interwork Code supports ARM/Thumb interworking -m[no-]warn-deprecated Warn about deprecated features + -m[no-]warn-syms Warn when symbols match instructions For now we will also provide support for: @@ -23731,6 +24422,7 @@ struct option md_longopts[] = {NULL, no_argument, NULL, 0} }; + size_t md_longopts_size = sizeof (md_longopts); struct arm_option_table @@ -23765,6 +24457,8 @@ struct arm_option_table arm_opts[] = {"mwarn-deprecated", NULL, &warn_on_deprecated, 1, NULL}, {"mno-warn-deprecated", N_("do not warn on use of deprecated feature"), &warn_on_deprecated, 0, NULL}, + {"mwarn-syms", N_("warn about symbols that match instruction names [default]"), (int *) (& flag_warn_syms), TRUE, NULL}, + {"mno-warn-syms", N_("disable warnings about symobls that match instructions"), (int *) (& flag_warn_syms), FALSE, NULL}, {NULL, NULL, NULL, 0, NULL} }; @@ -23995,27 +24689,28 @@ static const struct arm_cpu_option_table arm_cpus[] = ARM_CPU_OPT ("arm1176jzf-s", ARM_ARCH_V6ZK, FPU_ARCH_VFP_V2, NULL), ARM_CPU_OPT ("cortex-a5", ARM_ARCH_V7A_MP_SEC, FPU_NONE, "Cortex-A5"), - ARM_CPU_OPT ("cortex-a7", ARM_ARCH_V7A_IDIV_MP_SEC_VIRT, - FPU_ARCH_NEON_VFP_V4, + ARM_CPU_OPT ("cortex-a7", ARM_ARCH_V7VE, FPU_ARCH_NEON_VFP_V4, "Cortex-A7"), ARM_CPU_OPT ("cortex-a8", ARM_ARCH_V7A_SEC, - ARM_FEATURE (0, FPU_VFP_V3 + ARM_FEATURE_COPROC (FPU_VFP_V3 | FPU_NEON_EXT_V1), "Cortex-A8"), ARM_CPU_OPT ("cortex-a9", ARM_ARCH_V7A_MP_SEC, - ARM_FEATURE (0, FPU_VFP_V3 + ARM_FEATURE_COPROC (FPU_VFP_V3 | FPU_NEON_EXT_V1), "Cortex-A9"), - ARM_CPU_OPT ("cortex-a12", ARM_ARCH_V7A_IDIV_MP_SEC_VIRT, - FPU_ARCH_NEON_VFP_V4, + ARM_CPU_OPT ("cortex-a12", ARM_ARCH_V7VE, FPU_ARCH_NEON_VFP_V4, "Cortex-A12"), - ARM_CPU_OPT ("cortex-a15", ARM_ARCH_V7A_IDIV_MP_SEC_VIRT, - FPU_ARCH_NEON_VFP_V4, + ARM_CPU_OPT ("cortex-a15", ARM_ARCH_V7VE, FPU_ARCH_NEON_VFP_V4, "Cortex-A15"), + ARM_CPU_OPT ("cortex-a17", ARM_ARCH_V7VE, FPU_ARCH_NEON_VFP_V4, + "Cortex-A17"), ARM_CPU_OPT ("cortex-a53", ARM_ARCH_V8A, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8, "Cortex-A53"), ARM_CPU_OPT ("cortex-a57", ARM_ARCH_V8A, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8, "Cortex-A57"), + ARM_CPU_OPT ("cortex-a72", ARM_ARCH_V8A, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8, + "Cortex-A72"), ARM_CPU_OPT ("cortex-r4", ARM_ARCH_V7R, FPU_NONE, "Cortex-R4"), ARM_CPU_OPT ("cortex-r4f", ARM_ARCH_V7R, FPU_ARCH_VFP_V3D16, "Cortex-R4F"), @@ -24024,11 +24719,15 @@ static const struct arm_cpu_option_table arm_cpus[] = ARM_CPU_OPT ("cortex-r7", ARM_ARCH_V7R_IDIV, FPU_ARCH_VFP_V3D16, "Cortex-R7"), + ARM_CPU_OPT ("cortex-m7", ARM_ARCH_V7EM, FPU_NONE, "Cortex-M7"), ARM_CPU_OPT ("cortex-m4", ARM_ARCH_V7EM, FPU_NONE, "Cortex-M4"), ARM_CPU_OPT ("cortex-m3", ARM_ARCH_V7M, FPU_NONE, "Cortex-M3"), ARM_CPU_OPT ("cortex-m1", ARM_ARCH_V6SM, FPU_NONE, "Cortex-M1"), ARM_CPU_OPT ("cortex-m0", ARM_ARCH_V6SM, FPU_NONE, "Cortex-M0"), ARM_CPU_OPT ("cortex-m0plus", ARM_ARCH_V6SM, FPU_NONE, "Cortex-M0+"), + ARM_CPU_OPT ("exynos-m1", ARM_ARCH_V8A, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8, + "Samsung " \ + "Exynos M1"), /* ??? XSCALE is really an architecture. */ ARM_CPU_OPT ("xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL), /* ??? iwmmxt is not a processor. */ @@ -24036,11 +24735,20 @@ static const struct arm_cpu_option_table arm_cpus[] = ARM_CPU_OPT ("iwmmxt2", ARM_ARCH_IWMMXT2,FPU_ARCH_VFP_V2, NULL), ARM_CPU_OPT ("i80200", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL), /* Maverick */ - ARM_CPU_OPT ("ep9312", ARM_FEATURE (ARM_AEXT_V4T, ARM_CEXT_MAVERICK), + ARM_CPU_OPT ("ep9312", ARM_FEATURE_LOW (ARM_AEXT_V4T, ARM_CEXT_MAVERICK), FPU_ARCH_MAVERICK, "ARM920T"), /* Marvell processors. */ - ARM_CPU_OPT ("marvell-pj4", ARM_FEATURE (ARM_AEXT_V7A | ARM_EXT_MP | ARM_EXT_SEC, 0), + ARM_CPU_OPT ("marvell-pj4", ARM_FEATURE_CORE_LOW (ARM_AEXT_V7A | ARM_EXT_MP + | ARM_EXT_SEC), FPU_ARCH_VFP_V3D16, NULL), + ARM_CPU_OPT ("marvell-whitney", ARM_FEATURE_CORE_LOW (ARM_AEXT_V7A | ARM_EXT_MP + | ARM_EXT_SEC), + FPU_ARCH_NEON_VFP_V4, NULL), + /* APM X-Gene family. */ + ARM_CPU_OPT ("xgene1", ARM_ARCH_V8A, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8, + "APM X-Gene 1"), + ARM_CPU_OPT ("xgene2", ARM_ARCH_V8A, FPU_ARCH_CRYPTO_NEON_VFP_ARMV8, + "APM X-Gene 2"), { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE, NULL } }; @@ -24091,6 +24799,7 @@ static const struct arm_arch_option_table arm_archs[] = /* The official spelling of the ARMv7 profile variants is the dashed form. Accept the non-dashed form for compatibility with old toolchains. */ ARM_ARCH_OPT ("armv7a", ARM_ARCH_V7A, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv7ve", ARM_ARCH_V7VE, FPU_ARCH_VFP), ARM_ARCH_OPT ("armv7r", ARM_ARCH_V7R, FPU_ARCH_VFP), ARM_ARCH_OPT ("armv7m", ARM_ARCH_V7M, FPU_ARCH_VFP), ARM_ARCH_OPT ("armv7-a", ARM_ARCH_V7A, FPU_ARCH_VFP), @@ -24098,6 +24807,7 @@ static const struct arm_arch_option_table arm_archs[] = ARM_ARCH_OPT ("armv7-m", ARM_ARCH_V7M, FPU_ARCH_VFP), ARM_ARCH_OPT ("armv7e-m", ARM_ARCH_V7EM, FPU_ARCH_VFP), ARM_ARCH_OPT ("armv8-a", ARM_ARCH_V8A, FPU_ARCH_VFP), + ARM_ARCH_OPT ("armv8.1-a", ARM_ARCH_V8_1A, FPU_ARCH_VFP), ARM_ARCH_OPT ("xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP), ARM_ARCH_OPT ("iwmmxt", ARM_ARCH_IWMMXT, FPU_ARCH_VFP), ARM_ARCH_OPT ("iwmmxt2", ARM_ARCH_IWMMXT2,FPU_ARCH_VFP), @@ -24110,40 +24820,57 @@ struct arm_option_extension_value_table { char *name; size_t name_len; - const arm_feature_set value; + const arm_feature_set merge_value; + const arm_feature_set clear_value; const arm_feature_set allowed_archs; }; /* The following table must be in alphabetical order with a NULL last entry. */ -#define ARM_EXT_OPT(N, V, AA) { N, sizeof (N) - 1, V, AA } +#define ARM_EXT_OPT(N, M, C, AA) { N, sizeof (N) - 1, M, C, AA } static const struct arm_option_extension_value_table arm_extensions[] = { - ARM_EXT_OPT ("crc", ARCH_CRC_ARMV8, ARM_FEATURE (ARM_EXT_V8, 0)), + ARM_EXT_OPT ("crc", ARCH_CRC_ARMV8, ARM_FEATURE_COPROC (CRC_EXT_ARMV8), + ARM_FEATURE_CORE_LOW (ARM_EXT_V8)), ARM_EXT_OPT ("crypto", FPU_ARCH_CRYPTO_NEON_VFP_ARMV8, - ARM_FEATURE (ARM_EXT_V8, 0)), - ARM_EXT_OPT ("fp", FPU_ARCH_VFP_ARMV8, - ARM_FEATURE (ARM_EXT_V8, 0)), - ARM_EXT_OPT ("idiv", ARM_FEATURE (ARM_EXT_ADIV | ARM_EXT_DIV, 0), - ARM_FEATURE (ARM_EXT_V7A | ARM_EXT_V7R, 0)), - ARM_EXT_OPT ("iwmmxt",ARM_FEATURE (0, ARM_CEXT_IWMMXT), ARM_ANY), - ARM_EXT_OPT ("iwmmxt2", - ARM_FEATURE (0, ARM_CEXT_IWMMXT2), ARM_ANY), - ARM_EXT_OPT ("maverick", - ARM_FEATURE (0, ARM_CEXT_MAVERICK), ARM_ANY), - ARM_EXT_OPT ("mp", ARM_FEATURE (ARM_EXT_MP, 0), - ARM_FEATURE (ARM_EXT_V7A | ARM_EXT_V7R, 0)), + ARM_FEATURE_COPROC (FPU_CRYPTO_ARMV8), + ARM_FEATURE_CORE_LOW (ARM_EXT_V8)), + ARM_EXT_OPT ("fp", FPU_ARCH_VFP_ARMV8, ARM_FEATURE_COPROC (FPU_VFP_ARMV8), + ARM_FEATURE_CORE_LOW (ARM_EXT_V8)), + ARM_EXT_OPT ("idiv", ARM_FEATURE_CORE_LOW (ARM_EXT_ADIV | ARM_EXT_DIV), + ARM_FEATURE_CORE_LOW (ARM_EXT_ADIV | ARM_EXT_DIV), + ARM_FEATURE_CORE_LOW (ARM_EXT_V7A | ARM_EXT_V7R)), + ARM_EXT_OPT ("iwmmxt",ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT), + ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT), ARM_ANY), + ARM_EXT_OPT ("iwmmxt2", ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT2), + ARM_FEATURE_COPROC (ARM_CEXT_IWMMXT2), ARM_ANY), + ARM_EXT_OPT ("maverick", ARM_FEATURE_COPROC (ARM_CEXT_MAVERICK), + ARM_FEATURE_COPROC (ARM_CEXT_MAVERICK), ARM_ANY), + ARM_EXT_OPT ("mp", ARM_FEATURE_CORE_LOW (ARM_EXT_MP), + ARM_FEATURE_CORE_LOW (ARM_EXT_MP), + ARM_FEATURE_CORE_LOW (ARM_EXT_V7A | ARM_EXT_V7R)), ARM_EXT_OPT ("simd", FPU_ARCH_NEON_VFP_ARMV8, - ARM_FEATURE (ARM_EXT_V8, 0)), - ARM_EXT_OPT ("os", ARM_FEATURE (ARM_EXT_OS, 0), - ARM_FEATURE (ARM_EXT_V6M, 0)), - ARM_EXT_OPT ("sec", ARM_FEATURE (ARM_EXT_SEC, 0), - ARM_FEATURE (ARM_EXT_V6K | ARM_EXT_V7A, 0)), - ARM_EXT_OPT ("virt", ARM_FEATURE (ARM_EXT_VIRT | ARM_EXT_ADIV - | ARM_EXT_DIV, 0), - ARM_FEATURE (ARM_EXT_V7A, 0)), - ARM_EXT_OPT ("xscale",ARM_FEATURE (0, ARM_CEXT_XSCALE), ARM_ANY), - { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE } + ARM_FEATURE_COPROC (FPU_NEON_ARMV8), + ARM_FEATURE_CORE_LOW (ARM_EXT_V8)), + ARM_EXT_OPT ("os", ARM_FEATURE_CORE_LOW (ARM_EXT_OS), + ARM_FEATURE_CORE_LOW (ARM_EXT_OS), + ARM_FEATURE_CORE_LOW (ARM_EXT_V6M)), + ARM_EXT_OPT ("pan", ARM_FEATURE_CORE_HIGH (ARM_EXT2_PAN), + ARM_FEATURE (ARM_EXT_V8, ARM_EXT2_PAN, 0), + ARM_FEATURE_CORE_LOW (ARM_EXT_V8)), + ARM_EXT_OPT ("sec", ARM_FEATURE_CORE_LOW (ARM_EXT_SEC), + ARM_FEATURE_CORE_LOW (ARM_EXT_SEC), + ARM_FEATURE_CORE_LOW (ARM_EXT_V6K | ARM_EXT_V7A)), + ARM_EXT_OPT ("virt", ARM_FEATURE_CORE_LOW (ARM_EXT_VIRT | ARM_EXT_ADIV + | ARM_EXT_DIV), + ARM_FEATURE_CORE_LOW (ARM_EXT_VIRT), + ARM_FEATURE_CORE_LOW (ARM_EXT_V7A)), + ARM_EXT_OPT ("rdma", FPU_ARCH_NEON_VFP_ARMV8, + ARM_FEATURE_COPROC (FPU_NEON_ARMV8 | FPU_NEON_EXT_RDMA), + ARM_FEATURE_CORE_LOW (ARM_EXT_V8)), + ARM_EXT_OPT ("xscale",ARM_FEATURE_COPROC (ARM_CEXT_XSCALE), + ARM_FEATURE_COPROC (ARM_CEXT_XSCALE), ARM_ANY), + { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE, ARM_ARCH_NONE } }; #undef ARM_EXT_OPT @@ -24191,11 +24918,14 @@ static const struct arm_option_fpu_value_table arm_fpus[] = {"vfpv4", FPU_ARCH_VFP_V4}, {"vfpv4-d16", FPU_ARCH_VFP_V4D16}, {"fpv4-sp-d16", FPU_ARCH_VFP_V4_SP_D16}, + {"fpv5-d16", FPU_ARCH_VFP_V5D16}, + {"fpv5-sp-d16", FPU_ARCH_VFP_V5_SP_D16}, {"neon-vfpv4", FPU_ARCH_NEON_VFP_V4}, {"fp-armv8", FPU_ARCH_VFP_ARMV8}, {"neon-fp-armv8", FPU_ARCH_NEON_VFP_ARMV8}, {"crypto-neon-fp-armv8", FPU_ARCH_CRYPTO_NEON_VFP_ARMV8}, + {"neon-fp-armv8.1", FPU_ARCH_NEON_VFP_ARMV8_1}, {NULL, ARM_ARCH_NONE} }; @@ -24318,9 +25048,9 @@ arm_parse_extension (char *str, const arm_feature_set **opt_p) /* Add or remove the extension. */ if (adding_value) - ARM_MERGE_FEATURE_SETS (*ext_set, *ext_set, opt->value); + ARM_MERGE_FEATURE_SETS (*ext_set, *ext_set, opt->merge_value); else - ARM_CLEAR_FEATURE (*ext_set, *ext_set, opt->value); + ARM_CLEAR_FEATURE (*ext_set, *ext_set, opt->clear_value); break; } @@ -24506,6 +25236,15 @@ arm_parse_it_mode (char * str) return ret; } +static bfd_boolean +arm_ccs_mode (char * unused ATTRIBUTE_UNUSED) +{ + codecomposer_syntax = TRUE; + arm_comment_chars[0] = ';'; + arm_line_separator_chars[0] = 0; + return TRUE; +} + struct arm_long_option_table arm_long_opts[] = { {"mcpu=", N_("\t assemble for CPU "), @@ -24522,6 +25261,8 @@ struct arm_long_option_table arm_long_opts[] = #endif {"mimplicit-it=", N_("\t controls implicit insertion of IT instructions"), arm_parse_it_mode, NULL}, + {"mccs", N_("\t\t\t TI CodeComposer Studio syntax compatibility mode"), + arm_ccs_mode, NULL}, {NULL, NULL, 0, NULL} }; @@ -24670,7 +25411,7 @@ static const cpu_arch_ver_table cpu_arch_ver[] = {11, ARM_ARCH_V6M}, {12, ARM_ARCH_V6SM}, {8, ARM_ARCH_V6T2}, - {10, ARM_ARCH_V7A_IDIV_MP_SEC_VIRT}, + {10, ARM_ARCH_V7VE}, {10, ARM_ARCH_V7R}, {10, ARM_ARCH_V7M}, {14, ARM_ARCH_V8A}, @@ -24697,7 +25438,7 @@ aeabi_set_attribute_string (int tag, const char *value) } /* Set the public EABI object attributes. */ -static void +void aeabi_set_public_attributes (void) { int arch; @@ -24720,6 +25461,8 @@ aeabi_set_public_attributes (void) if (ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_arch_any)) ARM_MERGE_FEATURE_SETS (flags, flags, arm_ext_v4t); + selected_cpu = flags; + /* Allow the user to override the reported architecture. */ if (object_arch) { @@ -24803,8 +25546,10 @@ aeabi_set_public_attributes (void) ARM_CPU_HAS_FEATURE (flags, arm_arch_t2) ? 2 : 1); /* Tag_VFP_arch. */ - if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_armv8)) - aeabi_set_attribute_int (Tag_VFP_arch, 7); + if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_armv8xd)) + aeabi_set_attribute_int (Tag_VFP_arch, + ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_d32) + ? 7 : 8); else if (ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_fma)) aeabi_set_attribute_int (Tag_VFP_arch, ARM_CPU_HAS_FEATURE (flags, fpu_vfp_ext_d32) @@ -25040,9 +25785,10 @@ s_arm_arch_extension (int ignored ATTRIBUTE_UNUSED) } if (adding_value) - ARM_MERGE_FEATURE_SETS (selected_cpu, selected_cpu, opt->value); + ARM_MERGE_FEATURE_SETS (selected_cpu, selected_cpu, + opt->merge_value); else - ARM_CLEAR_FEATURE (selected_cpu, selected_cpu, opt->value); + ARM_CLEAR_FEATURE (selected_cpu, selected_cpu, opt->clear_value); mcpu_cpu_opt = &selected_cpu; ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt); @@ -25172,14 +25918,18 @@ arm_convert_symbolic_attribute (const char *name) } -/* Apply sym value for relocations only in the case that - they are for local symbols and you have the respective - architectural feature for blx and simple switches. */ +/* Apply sym value for relocations only in the case that they are for + local symbols in the same segment as the fixup and you have the + respective architectural feature for blx and simple switches. */ int -arm_apply_sym_value (struct fix * fixP) +arm_apply_sym_value (struct fix * fixP, segT this_seg) { if (fixP->fx_addsy && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v5t) + /* PR 17444: If the local symbol is in a different section then a reloc + will always be generated for it, so applying the symbol value now + will result in a double offset being stored in the relocation. */ + && (S_GET_SEGMENT (fixP->fx_addsy) == this_seg) && !S_FORCE_RELOC (fixP->fx_addsy, TRUE)) { switch (fixP->fx_r_type) @@ -25193,7 +25943,7 @@ arm_apply_sym_value (struct fix * fixP) case BFD_RELOC_ARM_PCREL_CALL: case BFD_RELOC_THUMB_PCREL_BLX: if (THUMB_IS_FUNC (fixP->fx_addsy)) - return 1; + return 1; break; default: