diff options
author | Christophe Monat <christophe.monat@st.com> | 2016-05-09 15:10:37 +0200 |
---|---|---|
committer | Christophe Lyon <christophe.lyon@linaro.org> | 2016-05-09 15:10:37 +0200 |
commit | 9239bbd3a6bf901dba1c0170622c50c78f6d1096 (patch) | |
tree | 9f383c10b9859fc9d8221e8b9b05ce3121d1597b /bfd/elf32-arm.c | |
parent | 73597c183c78ed0bea291897de6d8867ec640208 (diff) | |
download | gdb-9239bbd3a6bf901dba1c0170622c50c78f6d1096.zip gdb-9239bbd3a6bf901dba1c0170622c50c78f6d1096.tar.gz gdb-9239bbd3a6bf901dba1c0170622c50c78f6d1096.tar.bz2 |
[ARM/STM32L4XX] PR 20030: --fix-stm32l4xx-629360 fails to create vldm/vpop veneers for double-precision registers
bfd/
PR ld/20030
* elf32-arm.c (is_thumb2_vldm): Account for T1 (DP) encoding.
(stm32l4xx_need_create_replacing_stub): Rename ambiguous nb_regs
to nb_words.
(create_instruction_vldmia): Add is_dp to disambiguate SP/DP
encoding.
(create_instruction_vldmdb): Likewise.
(stm32l4xx_create_replacing_stub_vldm): is_dp detects DP encoding,
uses it to re-encode.
ld/
PR ld/20030
* testsuite/ld-arm/arm-elf.exp: Run new stm32l4xx-fix-vldm-dp
tests. Fix misnamed stm32l4xx-fix-all.
* testsuite/ld-arm/stm32l4xx-fix-vldm-dp.s: New tests for multiple
loads with DP registers.
* testsuite/ld-arm/stm32l4xx-fix-vldm-dp.d: New reference file.
* testsuite/ld-arm/stm32l4xx-fix-vldm.s: Add missing comment.
* testsuite/ld-arm/stm32l4xx-fix-all.s: Add tests for multiple
loads with DP registers.
* testsuite/ld-arm/stm32l4xx-fix-all.d: Update reference.
Diffstat (limited to 'bfd/elf32-arm.c')
-rw-r--r-- | bfd/elf32-arm.c | 101 |
1 files changed, 56 insertions, 45 deletions
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c index 61deb9e..d65837c 100644 --- a/bfd/elf32-arm.c +++ b/bfd/elf32-arm.c @@ -7442,18 +7442,21 @@ is_thumb2_vldm (const insn32 insn) { /* A6.5 Extension register load or store instruction A7.7.229 - We look only for the 32-bit registers case since the DP (64-bit - registers) are not supported for STM32L4XX + We look for SP 32-bit and DP 64-bit registers. + Encoding T1 VLDM{mode}<c> <Rn>{!}, <list> + <list> is consecutive 64-bit registers + 1110 - 110P - UDW1 - rrrr - vvvv - 1011 - iiii - iiii Encoding T2 VLDM{mode}<c> <Rn>{!}, <list> <list> is consecutive 32-bit registers 1110 - 110P - UDW1 - rrrr - vvvv - 1010 - iiii - iiii if P==0 && U==1 && W==1 && Rn=1101 VPOP if PUW=010 || PUW=011 || PUW=101 VLDM. */ return - ((insn & 0xfe100f00) == 0xec100a00) + (((insn & 0xfe100f00) == 0xec100b00) || + ((insn & 0xfe100f00) == 0xec100a00)) && /* (IA without !). */ (((((insn << 7) >> 28) & 0xd) == 0x4) - /* (IA with !), includes VPOP (when reg number is SP). */ + /* (IA with !), includes VPOP (when reg number is SP). */ || ((((insn << 7) >> 28) & 0xd) == 0x5) /* (DB with !). */ || ((((insn << 7) >> 28) & 0xd) == 0x9)); @@ -7470,19 +7473,19 @@ static bfd_boolean stm32l4xx_need_create_replacing_stub (const insn32 insn, bfd_arm_stm32l4xx_fix stm32l4xx_fix) { - int nb_regs = 0; + int nb_words = 0; /* The field encoding the register list is the same for both LDMIA and LDMDB encodings. */ if (is_thumb2_ldmia (insn) || is_thumb2_ldmdb (insn)) - nb_regs = popcount (insn & 0x0000ffff); + nb_words = popcount (insn & 0x0000ffff); else if (is_thumb2_vldm (insn)) - nb_regs = (insn & 0xff); + nb_words = (insn & 0xff); /* DEFAULT mode accounts for the real bug condition situation, ALL mode inserts stubs for each LDM/VLDM instruction (testing). */ return - (stm32l4xx_fix == BFD_ARM_STM32L4XX_FIX_DEFAULT) ? nb_regs > 8 : + (stm32l4xx_fix == BFD_ARM_STM32L4XX_FIX_DEFAULT) ? nb_words > 8 : (stm32l4xx_fix == BFD_ARM_STM32L4XX_FIX_ALL) ? TRUE : FALSE; } @@ -16432,30 +16435,31 @@ create_instruction_sub (int target_reg, int source_reg, int value) } static inline bfd_vma -create_instruction_vldmia (int base_reg, int wback, int num_regs, +create_instruction_vldmia (int base_reg, int is_dp, int wback, int num_words, int first_reg) { /* A8.8.332 VLDM (A8-922) - VLMD{MODE} Rn{!}, {list} (Encoding T2). */ - bfd_vma patched_inst = 0xec900a00 + VLMD{MODE} Rn{!}, {list} (Encoding T1 or T2). */ + bfd_vma patched_inst = (is_dp ? 0xec900b00 : 0xec900a00) | (/*W=*/wback << 21) | (base_reg << 16) - | (num_regs & 0x000000ff) - | (((unsigned)first_reg>>1) & 0x0000000f) << 12 + | (num_words & 0x000000ff) + | (((unsigned)first_reg >> 1) & 0x0000000f) << 12 | (first_reg & 0x00000001) << 22; return patched_inst; } static inline bfd_vma -create_instruction_vldmdb (int base_reg, int num_regs, int first_reg) +create_instruction_vldmdb (int base_reg, int is_dp, int num_words, + int first_reg) { /* A8.8.332 VLDM (A8-922) - VLMD{MODE} Rn!, {} (Encoding T2). */ - bfd_vma patched_inst = 0xed300a00 + VLMD{MODE} Rn!, {} (Encoding T1 or T2). */ + bfd_vma patched_inst = (is_dp ? 0xed300b00 : 0xed300a00) | (base_reg << 16) - | (num_regs & 0x000000ff) - | (((unsigned)first_reg>>1) & 0x0000000f) << 12 + | (num_words & 0x000000ff) + | (((unsigned)first_reg >>1 ) & 0x0000000f) << 12 | (first_reg & 0x00000001) << 22; return patched_inst; @@ -16935,15 +16939,15 @@ stm32l4xx_create_replacing_stub_vldm (struct elf32_arm_link_hash_table * htab, const bfd_byte *const initial_insn_addr, bfd_byte *const base_stub_contents) { - int num_regs = ((unsigned int)initial_insn << 24) >> 24; + int num_words = ((unsigned int) initial_insn << 24) >> 24; bfd_byte *current_stub_contents = base_stub_contents; BFD_ASSERT (is_thumb2_vldm (initial_insn)); /* In BFD_ARM_STM32L4XX_FIX_ALL mode we may have to deal with - smaller than 8 registers load sequences that do not cause the + smaller than 8 words load sequences that do not cause the hardware issue. */ - if (num_regs <= 8) + if (num_words <= 8) { /* Untouched instruction. */ current_stub_contents = @@ -16958,28 +16962,30 @@ stm32l4xx_create_replacing_stub_vldm (struct elf32_arm_link_hash_table * htab, } else { + bfd_boolean is_dp = /* DP encoding. */ + (initial_insn & 0xfe100f00) == 0xec100b00; bfd_boolean is_ia_nobang = /* (IA without !). */ (((initial_insn << 7) >> 28) & 0xd) == 0x4; bfd_boolean is_ia_bang = /* (IA with !) - includes VPOP. */ (((initial_insn << 7) >> 28) & 0xd) == 0x5; bfd_boolean is_db_bang = /* (DB with !). */ (((initial_insn << 7) >> 28) & 0xd) == 0x9; - int base_reg = ((unsigned int)initial_insn << 12) >> 28; + int base_reg = ((unsigned int) initial_insn << 12) >> 28; /* d = UInt (Vd:D);. */ - int first_reg = ((((unsigned int)initial_insn << 16) >> 28) << 1) + int first_reg = ((((unsigned int) initial_insn << 16) >> 28) << 1) | (((unsigned int)initial_insn << 9) >> 31); - /* Compute the number of 8-register chunks needed to split. */ - int chunks = (num_regs%8) ? (num_regs/8 + 1) : (num_regs/8); + /* Compute the number of 8-words chunks needed to split. */ + int chunks = (num_words % 8) ? (num_words / 8 + 1) : (num_words / 8); int chunk; /* The test coverage has been done assuming the following hypothesis that exactly one of the previous is_ predicates is true. */ - BFD_ASSERT ((is_ia_nobang ^ is_ia_bang ^ is_db_bang) && - !(is_ia_nobang & is_ia_bang & is_db_bang)); + BFD_ASSERT ( (is_ia_nobang ^ is_ia_bang ^ is_db_bang) + && !(is_ia_nobang & is_ia_bang & is_db_bang)); - /* We treat the cutting of the register in one pass for all + /* We treat the cutting of the words in one pass for all cases, then we emit the adjustments: vldm rx, {...} @@ -16992,29 +16998,34 @@ stm32l4xx_create_replacing_stub_vldm (struct elf32_arm_link_hash_table * htab, vldmd rx!, {...} -> vldmb rx!, {8_words_or_less} for each needed 8_word. */ - for (chunk = 0; chunk<chunks; ++chunk) + for (chunk = 0; chunk < chunks; ++chunk) { + bfd_vma new_insn = 0; + if (is_ia_nobang || is_ia_bang) { - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_vldmia - (base_reg, - /*wback= . */1, - chunks - (chunk + 1) ? - 8 : num_regs - chunk * 8, - first_reg + chunk * 8)); + new_insn = create_instruction_vldmia + (base_reg, + is_dp, + /*wback= . */1, + chunks - (chunk + 1) ? + 8 : num_words - chunk * 8, + first_reg + chunk * 8); } else if (is_db_bang) { - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_vldmdb - (base_reg, - chunks - (chunk + 1) ? - 8 : num_regs - chunk * 8, - first_reg + chunk * 8)); + new_insn = create_instruction_vldmdb + (base_reg, + is_dp, + chunks - (chunk + 1) ? + 8 : num_words - chunk * 8, + first_reg + chunk * 8); } + + if (new_insn) + current_stub_contents = + push_thumb2_insn32 (htab, output_bfd, current_stub_contents, + new_insn); } /* Only this case requires the base register compensation @@ -17024,7 +17035,7 @@ stm32l4xx_create_replacing_stub_vldm (struct elf32_arm_link_hash_table * htab, current_stub_contents = push_thumb2_insn32 (htab, output_bfd, current_stub_contents, create_instruction_sub - (base_reg, base_reg, 4*num_regs)); + (base_reg, base_reg, 4*num_words)); } /* B initial_insn_addr+4. */ |