From: Nick Clifton Date: Wed, 13 Jun 2001 11:49:41 +0000 (+0000) Subject: Merge in patches from mainline X-Git-Tag: binutils-2_11_1~7 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=958ec91cefedc92bda1e86dce5a1e5290efefb50;p=thirdparty%2Fbinutils-gdb.git Merge in patches from mainline --- diff --git a/gas/ChangeLog b/gas/ChangeLog index 105e8875e41..0386e0990bd 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,32 @@ +2001-06-13 Nick Clifton + + Merge from mainline: + 2001-05-11 Nick Clifton + * config/tc-arm.c (arm_handle_align): When truncating an aligned + block, ensure that the low order bits of the alignment are + preserved. + 2001-05-06 Nick Clifton + * config/tc-arm.h (MAX_MEM_FOR_RS_ALIGN_CODE): Define. + * config/tc-arm.c (arm_handle_align): Do not insert more than + MAX_MEM_FOR_RS_ALIGN_CODE bytes. + (arm_frag_align_code): Use MAX_MEM_FOR_RS_ALIGN_CODE. + 2001-04-26 Nick Clifton + * config/tc-arm.c (arm_handle_align): New Function: Generate + no-op filled alignment frags. + (arm_frag_align_code): New Function: Create a code alignment frag. + (arm_init_frag): New Function: Initialse the target dependent + parts of a frag. + * config/tc-arm.h (TC_FRAG_TYPE): Define. + (TC_FRAG_INIT): Define. + (HANDLE_ALIGN): Define. + (md_do_align): Define. + 2001-03-12 Nick Clifton + * config/tc-arm.c (md_begin): Always set machine type based on + cpu_variant. + 2001-03-06 Nick Clifton + * config/tc-arm.c (md_apply_fix3): Clear bit zero of offset in + BLX(1) instruction. + 2001-06-12 Nick Clifton * doc/as.texinfo (Infix Ops): Document that comparison and diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index f88d1ff6fb9..fa5c85a4e96 100644 --- a/gas/config/tc-arm.c +++ b/gas/config/tc-arm.c @@ -1279,12 +1279,23 @@ add_to_lit_pool () == inst.reloc.exp.X_add_number) && literals[lit_count].exp.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 + == inst.reloc.exp.X_add_number) + && (literals[lit_count].exp.X_add_symbol + == inst.reloc.exp.X_add_symbol) + && (literals[lit_count].exp.X_op_symbol + == inst.reloc.exp.X_op_symbol)) + break; + lit_count++; } if (lit_count == next_literal_pool_place) /* New entry. */ { - if (next_literal_pool_place > MAX_LITERAL_POOL_SIZE) + if (next_literal_pool_place >= MAX_LITERAL_POOL_SIZE) { inst.error = _("Literal Pool Overflow"); return FAIL; @@ -6513,29 +6524,26 @@ md_begin () } /* Catch special cases. */ - if (cpu_variant != (FPU_DEFAULT | CPU_DEFAULT)) + if (cpu_variant & ARM_EXT_XSCALE) + mach = bfd_mach_arm_XScale; + else if (cpu_variant & ARM_EXT_V5E) + mach = bfd_mach_arm_5TE; + else if (cpu_variant & ARM_EXT_V5) + { + if (cpu_variant & ARM_EXT_THUMB) + mach = bfd_mach_arm_5T; + else + mach = bfd_mach_arm_5; + } + else if (cpu_variant & ARM_EXT_HALFWORD) { - if (cpu_variant & ARM_EXT_XSCALE) - mach = bfd_mach_arm_XScale; - else if (cpu_variant & ARM_EXT_V5E) - mach = bfd_mach_arm_5TE; - else if (cpu_variant & ARM_EXT_V5) - { - if (cpu_variant & ARM_EXT_THUMB) - mach = bfd_mach_arm_5T; - else - mach = bfd_mach_arm_5; - } - else if (cpu_variant & ARM_EXT_HALFWORD) - { - if (cpu_variant & ARM_EXT_THUMB) - mach = bfd_mach_arm_4T; - else - mach = bfd_mach_arm_4; - } - else if (cpu_variant & ARM_EXT_LONGMUL) - mach = bfd_mach_arm_3M; + if (cpu_variant & ARM_EXT_THUMB) + mach = bfd_mach_arm_4T; + else + mach = bfd_mach_arm_4; } + else if (cpu_variant & ARM_EXT_LONGMUL) + mach = bfd_mach_arm_3M; bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach); } @@ -7149,6 +7157,15 @@ md_apply_fix3 (fixP, val, seg) 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; md_number_to_chars (buf, newval, THUMB_SIZE); md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE); } @@ -8418,7 +8435,38 @@ arm_frob_label (sym) ARM_SET_INTERWORK (sym, support_interwork); #endif - if (label_is_thumb_function_name) + /* Note - do not allow local symbols (.Lxxx) to be labeled + as Thumb functions. This is because these labels, whilst + they exist inside Thumb code, are not the entry points for + possible ARM->Thumb calls. Also, these labels can be used + as part of a computed goto or switch statement. eg gcc + can generate code that looks like this: + + ldr r2, [pc, .Laaa] + lsl r3, r3, #2 + ldr r2, [r3, r2] + mov pc, r2 + + .Lbbb: .word .Lxxx + .Lccc: .word .Lyyy + ..etc... + .Laaa: .word Lbbb + + The first instruction loads the address of the jump table. + The second instruction converts a table index into a byte offset. + The third instruction gets the jump address out of the table. + The fourth instruction performs the jump. + + If the address stored at .Laaa is that of a symbol which has the + Thumb_Func bit set, then the linker will arrange for this address + to have the bottom bit set, which in turn would mean that the + address computation performed by the third instruction would end + up with the bottom bit set. Since the ARM is capable of unaligned + word loads, the instruction would then load the incorrect address + out of the jump table, and chaos would ensue. */ + if (label_is_thumb_function_name + && (S_GET_NAME (sym)[0] != '.' || S_GET_NAME (sym)[1] != 'L') + && (bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0) { /* When the address of a Thumb function is taken the bottom bit of that address should be set. This will allow @@ -8743,3 +8791,102 @@ s_arm_elf_cons (nbytes) } #endif /* OBJ_ELF */ + +/* This is called from HANDLE_ALIGN in write.c. Fill in the contents + of an rs_align_code fragment. */ + +void +arm_handle_align (fragP) + fragS *fragP; +{ + static char const arm_noop[4] = { 0x00, 0x00, 0xa0, 0xe1 }; + static char const thumb_noop[2] = { 0xc0, 0x46 }; + static char const arm_bigend_noop[4] = { 0xe1, 0xa0, 0x00, 0x00 }; + static char const thumb_bigend_noop[2] = { 0x46, 0xc0 }; + + int bytes, fix, noop_size; + char * p; + const char * noop; + + if (fragP->fr_type != rs_align_code) + return; + + bytes = fragP->fr_next->fr_address - fragP->fr_address - fragP->fr_fix; + p = fragP->fr_literal + fragP->fr_fix; + fix = 0; + + if (bytes > MAX_MEM_FOR_RS_ALIGN_CODE) + bytes &= MAX_MEM_FOR_RS_ALIGN_CODE; + + if (fragP->tc_frag_data) + { + if (target_big_endian) + noop = thumb_bigend_noop; + else + noop = thumb_noop; + noop_size = sizeof (thumb_noop); + } + else + { + if (target_big_endian) + noop = arm_bigend_noop; + else + noop = arm_noop; + noop_size = sizeof (arm_noop); + } + + if (bytes & (noop_size - 1)) + { + fix = bytes & (noop_size - 1); + memset (p, 0, fix); + p += fix; + bytes -= fix; + } + + while (bytes >= noop_size) + { + memcpy (p, noop, noop_size); + p += noop_size; + bytes -= noop_size; + fix += noop_size; + } + + fragP->fr_fix += fix; + fragP->fr_var = noop_size; +} + +/* Called from md_do_align. Used to create an alignment + frag in a code section. */ + +void +arm_frag_align_code (n, max) + int n; + int max; +{ + char * p; + + /* We assume that there will never be a requirment + to support alignments greater than 32 bytes. */ + if (max > MAX_MEM_FOR_RS_ALIGN_CODE) + as_fatal (_("alignments greater than 32 bytes not supported in .text sections.")); + + p = frag_var (rs_align_code, + MAX_MEM_FOR_RS_ALIGN_CODE, + 1, + (relax_substateT) max, + (symbolS *) NULL, + (offsetT) n, + (char *) NULL); + *p = 0; + +} + +/* Perform target specific initialisation of a frag. */ + +void +arm_init_frag (fragP) + fragS *fragP; +{ + /* Record whether this frag is in an ARM or a THUMB area. */ + fragP->tc_frag_data = thumb_mode; +} diff --git a/gas/config/tc-arm.h b/gas/config/tc-arm.h index 7060333a5b1..8de5704efae 100644 --- a/gas/config/tc-arm.h +++ b/gas/config/tc-arm.h @@ -214,3 +214,23 @@ void armelf_frob_symbol PARAMS ((symbolS *, int *)); #ifdef OBJ_ELF #define DWARF2_LINE_MIN_INSN_LENGTH 2 #endif + +#define MAX_MEM_FOR_RS_ALIGN_CODE 31 + +/* For frags in code sections we need to record whether they contain + ARM code or THUMB code. This is that if they have to be aligned, + they can contain the correct type of no-op instruction. */ +#define TC_FRAG_TYPE int +#define TC_FRAG_INIT(fragp) arm_init_frag (fragp) +extern void arm_init_frag PARAMS ((struct frag *)); + +#define HANDLE_ALIGN(fragp) arm_handle_align (fragp) +extern void arm_handle_align PARAMS ((struct frag *)); + +#define md_do_align(N, FILL, LEN, MAX, LABEL) \ + if (FILL == NULL && (N) != 0 && ! need_pass_2 && subseg_text_p (now_seg)) \ + { \ + arm_frag_align_code (N, MAX); \ + goto LABEL; \ + } +extern void arm_frag_align_code PARAMS ((int, int));