From 01f470d7d9f7d44e25af75152560357a3a273607 Mon Sep 17 00:00:00 2001 From: Paul Brook Date: Wed, 20 Feb 2008 15:17:56 +0000 Subject: [PATCH] 2008-02-20 Paul Brook ld/ * emultempl/armelf.em (OPTION_FIX_V4BX_INTERWORKING): Define. (PARSE_AND_LIST_LONGOPTS): Add fix-v4bx-interworking. (PARSE_AND_LIST_OPTIONS): Ditto. (PARSE_AND_LIST_ARGS_CASES): Handle OPTION_FIX_V4BX_INTERWORKING. * emulparams/armelf.sh (OTHER_TEXT_SECTIONS): Add .v4_bx. * emulparams/armelf_linux.sh (OTHER_TEXT_SECTIONS): Ditto. * emulparams/armnto.sh (OTHER_TEXT_SECTIONS): Ditto. * ld.texinfo: Document --fix-v4bx-interworking. ld/testsuite/ * ld-arm/armv4-bx.d: New test. * ld-arm/armv4-bx.s: New test. * ld-arm/arm.ld: Add .v4bx. * ld-arm/arm-elf.exp: Add armv4-bx. gas/testsuite/ * gas/arm/thumb.d: Exclude EABI targets. * gas/arm/arch4t.d: Exclude EABI targts. * gas/arm/v4bx.d: New test. * gas/arm/v4bx.s: New test. * gas/arm/thumb-eabi.d: New test. * gas/arm/arch4t-eabi.d: New test. gas/ * config/tc-arm.c (fix_v4bx): New variable. (do_bx): Generate V4BX relocations. (md_assemble): Allow bx on v4 codes when fix_v4bx. (md_apply_fix): Handle BFD_RELOC_ARM_V4BX. (tc_gen_reloc): Ditto. (OPTION_FIX_V4BX): Define. (md_longopts): Add fix-v4bx. (md_parse_option): Handle OPTION_FIX_V4BX. (md_show_usage): Document --fix-v4bx. * doc/c-arm.texi: Document --fix-v4bx. bfd/ * reloc.c: Add BFD_RELOC_ARM_V4BX. * elf32-arm.c (elf32_arm_reloc_map): Add BFD_RELOC_ARM_V4BX. (ARM_BX_GLUE_SECTION_NAME, ARM_BX_GLUE_SECTION_NAME): Define. (elf32_arm_link_hash_table): Add bx_glue_size and bx_glue_offset. Update comment for fix_v4bx. (elf32_arm_link_hash_table_create): Zero bx_glue_size and bx_glue_offset. (ARM_BX_VENEER_SIZE, armbx1_tst_insn, armbx2_moveq_insn, armbx3_bx_insn): New. (bfd_elf32_arm_allocate_interworking_sections): Allocate BX veneer section. (bfd_elf32_arm_add_glue_sections_to_bfd): Ditto. (bfd_elf32_arm_process_before_allocation): Record BX veneers. (record_arm_bx_glue, elf32_arm_bx_glue): New functions. (elf32_arm_final_link_relocate): Handle BX veneers. (elf32_arm_output_arch_local_syms): Output mapping symbol for .v4_bx. * bfd-in2.h: Regenerate. * libbfd.h: Regenerate. --- bfd/bfd-in2.h | 3 + bfd/elf32-arm.c | 208 ++++++++++++++++++++-- bfd/libbfd.h | 1 + bfd/reloc.c | 5 + gas/config/tc-arm.c | 42 ++++- gas/doc/c-arm.texi | 5 + gas/testsuite/gas/arm/{arch4t.d => arch4t-eabi.d} | 6 +- gas/testsuite/gas/arm/arch4t.d | 2 + gas/testsuite/gas/arm/{thumb.d => thumb-eabi.d} | 7 +- gas/testsuite/gas/arm/thumb.d | 3 +- gas/testsuite/gas/arm/v4bx.d | 10 ++ gas/testsuite/gas/arm/v4bx.s | 4 + ld/emulparams/armelf.sh | 2 +- ld/emulparams/armelf_linux.sh | 2 +- ld/emulparams/armnto.sh | 2 +- ld/emultempl/armelf.em | 7 + ld/ld.texinfo | 15 ++ ld/testsuite/ld-arm/arm-elf.exp | 3 + ld/testsuite/ld-arm/arm.ld | 1 + ld/testsuite/ld-arm/armv4-bx.d | 19 ++ ld/testsuite/ld-arm/armv4-bx.s | 8 + 21 files changed, 331 insertions(+), 24 deletions(-) copy gas/testsuite/gas/arm/{arch4t.d => arch4t-eabi.d} (90%) copy gas/testsuite/gas/arm/{thumb.d => thumb-eabi.d} (98%) create mode 100644 gas/testsuite/gas/arm/v4bx.d create mode 100644 gas/testsuite/gas/arm/v4bx.s create mode 100644 ld/testsuite/ld-arm/armv4-bx.d create mode 100644 ld/testsuite/ld-arm/armv4-bx.s diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 858bb29d9..c1b5341ab 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -3089,6 +3089,9 @@ pc-relative or some form of GOT-indirect relocation. */ BFD_RELOC_ARM_LDC_SB_G1, BFD_RELOC_ARM_LDC_SB_G2, +/* Annotation of BX instructions. */ + BFD_RELOC_ARM_V4BX, + /* These relocs are only used within the ARM assembler. They are not (at present) written to any object files. */ BFD_RELOC_ARM_IMMEDIATE, diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c index ec887038a..7218ba8c3 100644 --- a/bfd/elf32-arm.c +++ b/bfd/elf32-arm.c @@ -1773,7 +1773,8 @@ static const struct elf32_arm_reloc_map elf32_arm_reloc_map[] = {BFD_RELOC_ARM_LDRS_SB_G2, R_ARM_LDRS_SB_G2}, {BFD_RELOC_ARM_LDC_SB_G0, R_ARM_LDC_SB_G0}, {BFD_RELOC_ARM_LDC_SB_G1, R_ARM_LDC_SB_G1}, - {BFD_RELOC_ARM_LDC_SB_G2, R_ARM_LDC_SB_G2} + {BFD_RELOC_ARM_LDC_SB_G2, R_ARM_LDC_SB_G2}, + {BFD_RELOC_ARM_V4BX, R_ARM_V4BX} }; static reloc_howto_type * @@ -1904,6 +1905,9 @@ typedef unsigned short int insn16; #define VFP11_ERRATUM_VENEER_SECTION_NAME ".vfp11_veneer" #define VFP11_ERRATUM_VENEER_ENTRY_NAME "__vfp11_veneer_%x" +#define ARM_BX_GLUE_SECTION_NAME ".v4_bx" +#define ARM_BX_GLUE_ENTRY_NAME "__bx_r%d" + /* The name of the dynamic interpreter. This is put in the .interp section. */ #define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" @@ -2171,6 +2175,13 @@ struct elf32_arm_link_hash_table /* The size in bytes of the section containing the ARM-to-Thumb glue. */ bfd_size_type arm_glue_size; + /* The size in bytes of section containing the ARMv4 BX veneers. */ + bfd_size_type bx_glue_size; + + /* Offsets of ARMv4 BX veneers. Bit1 set if present, and Bit0 set when + veneer has been populated. */ + bfd_vma bx_glue_offset[15]; + /* The size in bytes of the section containing glue for VFP11 erratum veneers. */ bfd_size_type vfp11_erratum_glue_size; @@ -2188,7 +2199,9 @@ struct elf32_arm_link_hash_table /* The relocation to use for R_ARM_TARGET2 relocations. */ int target2_reloc; - /* Nonzero to fix BX instructions for ARMv4 targets. */ + /* 0 = Ignore R_ARM_V4BX. + 1 = Convert BX to MOV PC. + 2 = Generate v4 interworing stubs. */ int fix_v4bx; /* Nonzero if the ARM/Thumb BLX instructions are available for use. */ @@ -2469,6 +2482,8 @@ elf32_arm_link_hash_table_create (bfd *abfd) ret->srelplt2 = NULL; ret->thumb_glue_size = 0; ret->arm_glue_size = 0; + ret->bx_glue_size = 0; + memset (ret->bx_glue_offset, 0, sizeof(ret->bx_glue_offset)); ret->vfp11_fix = BFD_ARM_VFP11_FIX_NONE; ret->vfp11_erratum_glue_size = 0; ret->num_vfp11_fixes = 0; @@ -2626,6 +2641,11 @@ static const insn32 t2a3_b_insn = 0xea000000; #define VFP11_ERRATUM_VENEER_SIZE 8 +#define ARM_BX_VENEER_SIZE 12 +static const insn32 armbx1_tst_insn = 0xe3100001; +static const insn32 armbx2_moveq_insn = 0x01a0f000; +static const insn32 armbx3_bx_insn = 0xe12fff10; + #ifndef ELFARM_NABI_C_INCLUDED bfd_boolean bfd_elf32_arm_allocate_interworking_sections (struct bfd_link_info * info) @@ -2684,6 +2704,21 @@ bfd_elf32_arm_allocate_interworking_sections (struct bfd_link_info * info) s->contents = foo; } + if (globals->bx_glue_size != 0) + { + BFD_ASSERT (globals->bfd_of_glue_owner != NULL); + + s = bfd_get_section_by_name (globals->bfd_of_glue_owner, + ARM_BX_GLUE_SECTION_NAME); + + BFD_ASSERT (s != NULL); + + foo = bfd_alloc (globals->bfd_of_glue_owner, globals->bx_glue_size); + + BFD_ASSERT (s->size == globals->bx_glue_size); + s->contents = foo; + } + return TRUE; } @@ -2835,6 +2870,64 @@ record_thumb_to_arm_glue (struct bfd_link_info *link_info, } +/* Allocate space for ARMv4 BX veneers. */ + +static void +record_arm_bx_glue (struct bfd_link_info * link_info, int reg) +{ + asection * s; + struct elf32_arm_link_hash_table *globals; + char *tmp_name; + struct elf_link_hash_entry *myh; + struct bfd_link_hash_entry *bh; + bfd_vma val; + + /* BX PC does not need a veneer. */ + if (reg == 15) + return; + + globals = elf32_arm_hash_table (link_info); + + BFD_ASSERT (globals != NULL); + BFD_ASSERT (globals->bfd_of_glue_owner != NULL); + + /* Check if this veneer has already been allocated. */ + if (globals->bx_glue_offset[reg]) + return; + + s = bfd_get_section_by_name + (globals->bfd_of_glue_owner, ARM_BX_GLUE_SECTION_NAME); + + BFD_ASSERT (s != NULL); + + /* Add symbol for veneer. */ + tmp_name = bfd_malloc ((bfd_size_type) strlen (ARM_BX_GLUE_ENTRY_NAME) + 1); + + BFD_ASSERT (tmp_name); + + sprintf (tmp_name, ARM_BX_GLUE_ENTRY_NAME, reg); + + myh = elf_link_hash_lookup + (&(globals)->root, tmp_name, FALSE, FALSE, FALSE); + + BFD_ASSERT (myh == NULL); + + bh = NULL; + val = globals->bx_glue_size; + _bfd_generic_link_add_one_symbol (link_info, globals->bfd_of_glue_owner, + tmp_name, BSF_FUNCTION | BSF_LOCAL, s, val, + NULL, TRUE, FALSE, &bh); + + myh = (struct elf_link_hash_entry *) bh; + myh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC); + myh->forced_local = 1; + + s->size += ARM_BX_VENEER_SIZE; + globals->bx_glue_offset[reg] = globals->bx_glue_size | 2; + globals->bx_glue_size += ARM_BX_VENEER_SIZE; +} + + /* Add an entry to the code/data map for section SEC. */ static void @@ -3058,6 +3151,24 @@ bfd_elf32_arm_add_glue_sections_to_bfd (bfd *abfd, sec->gc_mark = 1; } + sec = bfd_get_section_by_name (abfd, ARM_BX_GLUE_SECTION_NAME); + + if (sec == NULL) + { + flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_CODE | SEC_READONLY); + + sec = bfd_make_section_with_flags (abfd, + ARM_BX_GLUE_SECTION_NAME, + flags); + + if (sec == NULL + || !bfd_set_section_alignment (abfd, sec, 2)) + return FALSE; + + sec->gc_mark = 1; + } + return TRUE; } @@ -3177,7 +3288,8 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd, && r_type != R_ARM_CALL && r_type != R_ARM_JUMP24 && r_type != R_ARM_THM_CALL - && r_type != R_ARM_THM_JUMP24) + && r_type != R_ARM_THM_JUMP24 + && (r_type != R_ARM_V4BX || globals->fix_v4bx < 2)) continue; /* Get the section contents if we haven't done so already. */ @@ -3194,6 +3306,15 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd, } } + if (r_type == R_ARM_V4BX) + { + int reg; + + reg = bfd_get_32 (abfd, contents + irel->r_offset) & 0xf; + record_arm_bx_glue (link_info, reg); + continue; + } + /* If the relocation is not against a symbol it cannot concern us. */ h = NULL; @@ -4332,6 +4453,43 @@ elf32_arm_to_thumb_export_stub (struct elf_link_hash_entry *h, void * inf) return TRUE; } +/* Populate ARMv4 BX veneers. Returns the absolute adress of the veneer. */ + +static bfd_vma +elf32_arm_bx_glue (struct bfd_link_info * info, int reg) +{ + bfd_byte *p; + bfd_vma glue_addr; + asection *s; + struct elf32_arm_link_hash_table *globals; + + globals = elf32_arm_hash_table (info); + + BFD_ASSERT (globals != NULL); + BFD_ASSERT (globals->bfd_of_glue_owner != NULL); + + s = bfd_get_section_by_name (globals->bfd_of_glue_owner, + ARM_BX_GLUE_SECTION_NAME); + BFD_ASSERT (s != NULL); + BFD_ASSERT (s->contents != NULL); + BFD_ASSERT (s->output_section != NULL); + + BFD_ASSERT (globals->bx_glue_offset[reg] & 2); + + glue_addr = globals->bx_glue_offset[reg] & ~(bfd_vma)3; + + if ((globals->bx_glue_offset[reg] & 1) == 0) + { + p = s->contents + glue_addr; + bfd_put_32 (globals->obfd, armbx1_tst_insn + (reg << 16), p); + bfd_put_32 (globals->obfd, armbx2_moveq_insn + reg, p + 4); + bfd_put_32 (globals->obfd, armbx3_bx_insn + reg, p + 8); + globals->bx_glue_offset[reg] |= 1; + } + + return glue_addr + s->output_section->vma + s->output_offset; +} + /* Generate Arm stubs for exported Thumb symbols. */ static void elf32_arm_begin_write_processing (bfd *abfd ATTRIBUTE_UNUSED, @@ -5710,18 +5868,32 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, case R_ARM_V4BX: if (globals->fix_v4bx) - { - bfd_vma insn = bfd_get_32 (input_bfd, hit_data); + { + bfd_vma insn = bfd_get_32 (input_bfd, hit_data); - /* Ensure that we have a BX instruction. */ - BFD_ASSERT ((insn & 0x0ffffff0) == 0x012fff10); + /* Ensure that we have a BX instruction. */ + BFD_ASSERT ((insn & 0x0ffffff0) == 0x012fff10); - /* Preserve Rm (lowest four bits) and the condition code - (highest four bits). Other bits encode MOV PC,Rm. */ - insn = (insn & 0xf000000f) | 0x01a0f000; + if (globals->fix_v4bx == 2 && (insn & 0xf) != 0xf) + { + /* Branch to veneer. */ + bfd_vma glue_addr; + glue_addr = elf32_arm_bx_glue (info, insn & 0xf); + glue_addr -= input_section->output_section->vma + + input_section->output_offset + + rel->r_offset + 8; + insn = (insn & 0xf0000000) | 0x0a000000 + | ((glue_addr >> 2) & 0x00ffffff); + } + else + { + /* Preserve Rm (lowest four bits) and the condition code + (highest four bits). Other bits encode MOV PC,Rm. */ + insn = (insn & 0xf000000f) | 0x01a0f000; + } - bfd_put_32 (input_bfd, insn, hit_data); - } + bfd_put_32 (input_bfd, insn, hit_data); + } return bfd_reloc_ok; case R_ARM_MOVW_ABS_NC: @@ -9732,6 +9904,18 @@ elf32_arm_output_arch_local_syms (bfd *output_bfd, } } + /* ARMv4 BX veneers. */ + if (htab->bx_glue_size > 0) + { + osi.sec = bfd_get_section_by_name (htab->bfd_of_glue_owner, + ARM_BX_GLUE_SECTION_NAME); + + osi.sec_shndx = _bfd_elf_section_from_bfd_section + (output_bfd, osi.sec->output_section); + + elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_ARM, 0); + } + /* Finally, output mapping symbols for the PLT. */ if (!htab->splt || htab->splt->size == 0) return TRUE; diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 4d83a4cbd..cb6544a00 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -1282,6 +1282,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_ARM_LDC_SB_G0", "BFD_RELOC_ARM_LDC_SB_G1", "BFD_RELOC_ARM_LDC_SB_G2", + "BFD_RELOC_ARM_V4BX", "BFD_RELOC_ARM_IMMEDIATE", "BFD_RELOC_ARM_ADRL_IMMEDIATE", "BFD_RELOC_ARM_T32_IMMEDIATE", diff --git a/bfd/reloc.c b/bfd/reloc.c index f413ced71..027ede0bf 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -2925,6 +2925,11 @@ ENUMDOC ARM group relocations. ENUM + BFD_RELOC_ARM_V4BX +ENUMDOC + Annotation of BX instructions. + +ENUM BFD_RELOC_ARM_IMMEDIATE ENUMX BFD_RELOC_ARM_ADRL_IMMEDIATE diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index 412db5f7b..4d8eb42ba 100644 --- a/gas/config/tc-arm.c +++ b/gas/config/tc-arm.c @@ -143,6 +143,7 @@ static int atpcs = FALSE; static int support_interwork = FALSE; static int uses_apcs_float = FALSE; static int pic_code = FALSE; +static int fix_v4bx = 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 @@ -6760,10 +6761,23 @@ do_blx (void) static void do_bx (void) { + bfd_boolean want_reloc; + if (inst.operands[0].reg == REG_PC) as_tsktsk (_("use of r15 in bx in ARM mode is not really useful")); inst.instruction |= inst.operands[0].reg; + /* Output R_ARM_V4BX relocations if is an EABI object that looks like + it is for ARMv4t or earlier. */ + want_reloc = !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v5); + if (object_arch && !ARM_CPU_HAS_FEATURE (*object_arch, arm_ext_v5)) + want_reloc = TRUE; + + if (EF_ARM_EABI_VERSION (meabi_flags) < EF_ARM_EABI_VER4) + want_reloc = FALSE; + + if (want_reloc) + inst.reloc.type = BFD_RELOC_ARM_V4BX; } @@ -14272,9 +14286,15 @@ md_assemble (char *str) } else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1)) { + bfd_boolean is_bx; + + /* bx is allowed on v5 cores, and sometimes on v4 cores. */ + is_bx = (opcode->aencode == do_bx); + /* Check that this instruction is supported for this CPU. */ - if (!opcode->avariant || - !ARM_CPU_HAS_FEATURE (cpu_variant, *opcode->avariant)) + if (!(is_bx && fix_v4bx) + && !(opcode->avariant && + ARM_CPU_HAS_FEATURE (cpu_variant, *opcode->avariant))) { as_bad (_("selected processor does not support `%s'"), str); return; @@ -14296,8 +14316,7 @@ md_assemble (char *str) opcode->aencode (); /* Arm mode bx is marked as both v4T and v5 because it's still required on a hypothetical non-thumb v5 core. */ - if (ARM_CPU_HAS_FEATURE (*opcode->avariant, arm_ext_v4t) - || ARM_CPU_HAS_FEATURE (*opcode->avariant, arm_ext_v5)) + if (is_bx) ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used, arm_ext_v4t); else ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used, @@ -18969,6 +18988,11 @@ md_apply_fix (fixS * fixP, } break; + case BFD_RELOC_ARM_V4BX: + /* This will need to go in the object file. */ + fixP->fx_done = 0; + break; + case BFD_RELOC_UNUSED: default: as_bad_where (fixP->fx_file, fixP->fx_line, @@ -19119,6 +19143,7 @@ tc_gen_reloc (asection *section, fixS *fixp) case BFD_RELOC_ARM_LDC_SB_G0: case BFD_RELOC_ARM_LDC_SB_G1: case BFD_RELOC_ARM_LDC_SB_G2: + case BFD_RELOC_ARM_V4BX: code = fixp->fx_r_type; break; @@ -19806,6 +19831,7 @@ const char * md_shortopts = "m:k"; #define OPTION_EL (OPTION_MD_BASE + 1) #endif #endif +#define OPTION_FIX_V4BX (OPTION_MD_BASE + 2) struct option md_longopts[] = { @@ -19815,6 +19841,7 @@ struct option md_longopts[] = #ifdef OPTION_EL {"EL", no_argument, NULL, OPTION_EL}, #endif + {"fix-v4bx", no_argument, NULL, OPTION_FIX_V4BX}, {NULL, no_argument, NULL, 0} }; @@ -20430,6 +20457,10 @@ md_parse_option (int c, char * arg) break; #endif + case OPTION_FIX_V4BX: + fix_v4bx = TRUE; + break; + case 'a': /* Listing option. Just ignore these, we don't support additional ones. */ @@ -20527,6 +20558,9 @@ md_show_usage (FILE * fp) fprintf (fp, _("\ -EL assemble code for a little-endian cpu\n")); #endif + + fprintf (fp, _("\ + --fix-v4bx Allow BX in ARMv4 code\n")); } diff --git a/gas/doc/c-arm.texi b/gas/doc/c-arm.texi index 404c8ef1b..ef5dcc09c 100644 --- a/gas/doc/c-arm.texi +++ b/gas/doc/c-arm.texi @@ -276,6 +276,11 @@ be marked as being encoded for a little-endian processor. This option specifies that the output of the assembler should be marked as position-independent code (PIC). +@cindex @code{--fix-v4bx} command line option, ARM +@item --fix-v4bx +Allow @code{BX} instructions in ARMv4 code. This is intended for use with +the linker option of the same name. + @end table diff --git a/gas/testsuite/gas/arm/arch4t.d b/gas/testsuite/gas/arm/arch4t-eabi.d similarity index 90% copy from gas/testsuite/gas/arm/arch4t.d copy to gas/testsuite/gas/arm/arch4t-eabi.d index f7e343f03..dfab64d4e 100644 --- a/gas/testsuite/gas/arm/arch4t.d +++ b/gas/testsuite/gas/arm/arch4t-eabi.d @@ -1,12 +1,16 @@ -# name: ARM architecture 4t instructions +# name: ARM architecture 4t instructions (EABI) # as: -march=armv4t # objdump: -dr --prefix-addresses --show-raw-insn +# source: arch4t.s +# target: *-*-*eabi *-*-symbianelf .*: +file format .*arm.* Disassembly of section .text: 0+00 <[^>]+> e12fff10 ? bx r0 +.*: R_ARM_V4BX.* 0+04 <[^>]+> 012fff11 ? bxeq r1 +.*: R_ARM_V4BX.* 0+08 <[^>]+> e15f30b8 ? ldrh r3, \[pc, #-8\] ; 0+08 <[^>]+> 0+0c <[^>]+> e1d540f0 ? ldrsh r4, \[r5\] 0+10 <[^>]+> e19140d3 ? ldrsb r4, \[r1, r3\] diff --git a/gas/testsuite/gas/arm/arch4t.d b/gas/testsuite/gas/arm/arch4t.d index f7e343f03..4ec95f402 100644 --- a/gas/testsuite/gas/arm/arch4t.d +++ b/gas/testsuite/gas/arm/arch4t.d @@ -1,6 +1,8 @@ # name: ARM architecture 4t instructions # as: -march=armv4t # objdump: -dr --prefix-addresses --show-raw-insn +# EABI targets have their own variant. +# not-target: *-*-*eabi *-*-symbianelf .*: +file format .*arm.* diff --git a/gas/testsuite/gas/arm/thumb.d b/gas/testsuite/gas/arm/thumb-eabi.d similarity index 98% copy from gas/testsuite/gas/arm/thumb.d copy to gas/testsuite/gas/arm/thumb-eabi.d index 7f9b253a4..3c7b4aeac 100644 --- a/gas/testsuite/gas/arm/thumb.d +++ b/gas/testsuite/gas/arm/thumb-eabi.d @@ -1,8 +1,8 @@ -# name: Thumb instructions +# name: Thumb instructions (EABI) # as: -mcpu=arm7t # objdump: -dr --prefix-addresses --show-raw-insn -# The arm-aout and arm-pe ports do not support Thumb branch relocations. -# not-target: *-*-*aout* *-*-pe +# source: thumb.s +# target: *-*-*eabi *-*-symbianelf .*: +file format .*arm.* @@ -126,6 +126,7 @@ Disassembly of section \.text: 0+0ec <[^>]+> ebfffffc bl 0+0e4 <[^>]+> 0+0f0 <[^>]+> eb00000f bl 0+134 <[^>]+> 0+0f4 <[^>]+> e12fff10 bx r0 +.*: R_ARM_V4BX.* 0+0f8 <[^>]+> ef123456 (swi|svc) 0x00123456 0+0fc <[^>]+> a004 add r0, pc, #16 \(adr r0, 0+110 <[^>]+>\) 0+0fe <[^>]+> e77f b.n 0+000 <[^>]+> diff --git a/gas/testsuite/gas/arm/thumb.d b/gas/testsuite/gas/arm/thumb.d index 7f9b253a4..1d3ac9f17 100644 --- a/gas/testsuite/gas/arm/thumb.d +++ b/gas/testsuite/gas/arm/thumb.d @@ -2,7 +2,8 @@ # as: -mcpu=arm7t # objdump: -dr --prefix-addresses --show-raw-insn # The arm-aout and arm-pe ports do not support Thumb branch relocations. -# not-target: *-*-*aout* *-*-pe +# EABI targets have their own variant. +# not-target: *-*-*aout* *-*-pe *-*-*eabi *-*-symbianelf .*: +file format .*arm.* diff --git a/gas/testsuite/gas/arm/v4bx.d b/gas/testsuite/gas/arm/v4bx.d new file mode 100644 index 000000000..d37c25bf5 --- /dev/null +++ b/gas/testsuite/gas/arm/v4bx.d @@ -0,0 +1,10 @@ +# objdump: -dr --prefix-addresses --show-raw-insn +# as: -meabi=4 --fix-v4bx +# This test is only valid on ELF based ports. +#not-target: *-*-*coff *-*-pe *-*-wince *-*-*aout* *-*-netbsd *-*-riscix* + +.*: +file format .*arm.* + +Disassembly of section .text: +0+00 <[^>]+> e12fff1e bx lr + 0: R_ARM_V4BX \*ABS\* diff --git a/gas/testsuite/gas/arm/v4bx.s b/gas/testsuite/gas/arm/v4bx.s new file mode 100644 index 000000000..fecedccb9 --- /dev/null +++ b/gas/testsuite/gas/arm/v4bx.s @@ -0,0 +1,4 @@ + .arch armv4 + .text +foo: + bx lr diff --git a/ld/emulparams/armelf.sh b/ld/emulparams/armelf.sh index ba9fdbe3f..a3c317f49 100644 --- a/ld/emulparams/armelf.sh +++ b/ld/emulparams/armelf.sh @@ -6,7 +6,7 @@ LITTLE_OUTPUT_FORMAT="elf32-littlearm" TEXT_START_ADDR=0x8000 TEMPLATE_NAME=elf32 EXTRA_EM_FILE=armelf -OTHER_TEXT_SECTIONS='*(.glue_7t) *(.glue_7) *(.vfp11_veneer)' +OTHER_TEXT_SECTIONS='*(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx)' OTHER_BSS_SYMBOLS='__bss_start__ = .;' OTHER_BSS_END_SYMBOLS='_bss_end__ = . ; __bss_end__ = . ;' OTHER_END_SYMBOLS='__end__ = . ;' diff --git a/ld/emulparams/armelf_linux.sh b/ld/emulparams/armelf_linux.sh index e7f301fd3..338d2eb37 100644 --- a/ld/emulparams/armelf_linux.sh +++ b/ld/emulparams/armelf_linux.sh @@ -11,7 +11,7 @@ GENERATE_SHLIB_SCRIPT=yes GENERATE_PIE_SCRIPT=yes DATA_START_SYMBOLS='__data_start = . ;'; -OTHER_TEXT_SECTIONS='*(.glue_7t) *(.glue_7) *(.vfp11_veneer)' +OTHER_TEXT_SECTIONS='*(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx)' OTHER_BSS_SYMBOLS='__bss_start__ = .;' OTHER_BSS_END_SYMBOLS='_bss_end__ = . ; __bss_end__ = . ;' OTHER_END_SYMBOLS='__end__ = . ;' diff --git a/ld/emulparams/armnto.sh b/ld/emulparams/armnto.sh index ae0b4bea5..f89f14f55 100644 --- a/ld/emulparams/armnto.sh +++ b/ld/emulparams/armnto.sh @@ -6,7 +6,7 @@ LITTLE_OUTPUT_FORMAT="elf32-littlearm" TEXT_START_ADDR=0x00100000 TEMPLATE_NAME=elf32 EXTRA_EM_FILE=armelf -OTHER_TEXT_SECTIONS='*(.glue_7t) *(.glue_7) *(.vfp11_veneer)' +OTHER_TEXT_SECTIONS='*(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx)' OTHER_BSS_SYMBOLS='__bss_start__ = .;' OTHER_BSS_END_SYMBOLS='_bss_end__ = . ; __bss_end__ = . ;' OTHER_END_SYMBOLS='__end__ = . ;' diff --git a/ld/emultempl/armelf.em b/ld/emultempl/armelf.em index 7d0320d85..29e9902cb 100644 --- a/ld/emultempl/armelf.em +++ b/ld/emultempl/armelf.em @@ -264,6 +264,7 @@ PARSE_AND_LIST_PROLOGUE=' #define OPTION_VFP11_DENORM_FIX 308 #define OPTION_NO_ENUM_SIZE_WARNING 309 #define OPTION_PIC_VENEER 310 +#define OPTION_FIX_V4BX_INTERWORKING 311 ' PARSE_AND_LIST_SHORTOPTS=p @@ -276,6 +277,7 @@ PARSE_AND_LIST_LONGOPTS=' { "target1-abs", no_argument, NULL, OPTION_TARGET1_ABS}, { "target2", required_argument, NULL, OPTION_TARGET2}, { "fix-v4bx", no_argument, NULL, OPTION_FIX_V4BX}, + { "fix-v4bx-interworking", no_argument, NULL, OPTION_FIX_V4BX_INTERWORKING}, { "use-blx", no_argument, NULL, OPTION_USE_BLX}, { "vfp11-denorm-fix", required_argument, NULL, OPTION_VFP11_DENORM_FIX}, { "no-enum-size-warning", no_argument, NULL, OPTION_NO_ENUM_SIZE_WARNING}, @@ -289,6 +291,7 @@ PARSE_AND_LIST_OPTIONS=' fprintf (file, _(" --target1=abs Interpret R_ARM_TARGET1 as R_ARM_ABS32\n")); fprintf (file, _(" --target2= Specify definition of R_ARM_TARGET2\n")); fprintf (file, _(" --fix-v4bx Rewrite BX rn as MOV pc, rn for ARMv4\n")); + fprintf (file, _(" --fix-v4bx-interworking Rewrite BX rn branch to ARMv4 interworking veneer\n")); fprintf (file, _(" --use-blx Enable use of BLX instructions\n")); fprintf (file, _(" --vfp11-denorm-fix Specify how to fix VFP11 denorm erratum\n")); fprintf (file, _(" --no-enum-size-warning Don'\''t warn about objects with incompatible" @@ -325,6 +328,10 @@ PARSE_AND_LIST_ARGS_CASES=' fix_v4bx = 1; break; + case OPTION_FIX_V4BX_INTERWORKING: + fix_v4bx = 2; + break; + case OPTION_USE_BLX: use_blx = 1; break; diff --git a/ld/ld.texinfo b/ld/ld.texinfo index 00081da94..cda834afe 100644 --- a/ld/ld.texinfo +++ b/ld/ld.texinfo @@ -5584,6 +5584,21 @@ linker, which causes v4t @code{BX rM} instructions to be rewritten as In the former case, the switch should not be used, and @samp{R_ARM_V4BX} relocations are ignored. +@cindex FIX_V4BX_INTERWORKING +@kindex --fix-v4bx-interworking +Replace @code{BX rM} instructions identified by @samp{R_ARM_V4BX} +relocations with a branch to the following veneer: + +@smallexample +TST rM, #1 +MOVEQ PC, rM +BX Rn +@end smallexample + +This allows generation of libraries/applications that work on ARMv4 cores +and are still interworking safe. Note that the above veneer clobbers the +condition flags, so may cause incorrect progrm behavior in rare cases. + @cindex USE_BLX @kindex --use-blx The @samp{--use-blx} switch enables the linker to use ARM/Thumb diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp index 889796811..3f2b69c1a 100644 --- a/ld/testsuite/ld-arm/arm-elf.exp +++ b/ld/testsuite/ld-arm/arm-elf.exp @@ -173,6 +173,9 @@ set armelftests { {"callweak" "-static -T arm.ld" "" {callweak.s} {{objdump -dr callweak.d}} "callweak"} + {"ARMv4 interworking" "-static -T arm.ld --fix-v4bx-interworking" "--fix-v4bx -meabi=4" {armv4-bx.s} + {{objdump -d armv4-bx.d}} + "armv4-bx"} } run_ld_link_tests $armelftests diff --git a/ld/testsuite/ld-arm/arm.ld b/ld/testsuite/ld-arm/arm.ld index c9e01e65a..cb73fb3b1 100644 --- a/ld/testsuite/ld-arm/arm.ld +++ b/ld/testsuite/ld-arm/arm.ld @@ -11,6 +11,7 @@ SECTIONS *(.text) *(.after) *(.glue_7) + *(.v4_bx) } =0 . = 0x9000; .got : { *(.got) *(.got.plt)} diff --git a/ld/testsuite/ld-arm/armv4-bx.d b/ld/testsuite/ld-arm/armv4-bx.d new file mode 100644 index 000000000..095b38740 --- /dev/null +++ b/ld/testsuite/ld-arm/armv4-bx.d @@ -0,0 +1,19 @@ + +.*: .*file format elf32-(big|little)arm + +Disassembly of section \.text: + +00008000 <_start>: + 8000: ea000001 b 800c \<__bx_r14\> + 8004: ea000003 b 8018 \<__bx_r0\> + 8008: 0a000002 beq 8018 \<__bx_r0\> + +0000800c <__bx_r14>: + 800c: e31e0001 tst lr, #1 ; 0x1 + 8010: 01a0f00e moveq pc, lr + 8014: e12fff1e bx lr + +00008018 <__bx_r0>: + 8018: e3100001 tst r0, #1 ; 0x1 + 801c: 01a0f000 moveq pc, r0 + 8020: e12fff10 bx r0 diff --git a/ld/testsuite/ld-arm/armv4-bx.s b/ld/testsuite/ld-arm/armv4-bx.s new file mode 100644 index 000000000..ef863570a --- /dev/null +++ b/ld/testsuite/ld-arm/armv4-bx.s @@ -0,0 +1,8 @@ +.text +.arch armv4 +.global _start +.type _start, %function +_start: +bx lr +bx r0 +bxeq r0 -- 2.11.4.GIT