aboutsummaryrefslogtreecommitdiff
path: root/ld
diff options
context:
space:
mode:
authorLaurent Alfonsi <laurent.alfonsi@st.com>2015-10-27 13:20:33 +0000
committerNick Clifton <nickc@redhat.com>2015-10-27 13:20:33 +0000
commita504d23a83d115b1b29a5b1fbfaeb2b09bc0e22c (patch)
tree08cb61808c609c54d47090c2f8226fd649d3eea3 /ld
parentc6056a744af028824797e769ddb71927740be88a (diff)
downloadfsf-binutils-gdb-a504d23a83d115b1b29a5b1fbfaeb2b09bc0e22c.zip
fsf-binutils-gdb-a504d23a83d115b1b29a5b1fbfaeb2b09bc0e22c.tar.gz
fsf-binutils-gdb-a504d23a83d115b1b29a5b1fbfaeb2b09bc0e22c.tar.bz2
Add --fix-stm32l4xx-629360 to the ARM linker to enable a link-time workaround for a bug in the bus matrix / memory controller for some of the STM32 Cortex-M4 based products (STM32L4xx).
bfd * bfd-in2.h: Regenerate. * bfd-in.h (bfd_arm_stm32l4xx_fix): New enum. Specify how STM32L4XX instruction scanning should be done. (bfd_elf32_arm_set_stm32l4xx_fix) (bfd_elf32_arm_stm32l4xx_erratum_scan) (bfd_elf32_arm_stm32l4xx_fix_veneer_locations): Add prototypes. (bfd_elf32_arm_set_target_relocs): Add stm32l4xx fix type argument to prototype. * elf32-arm.c (STM32L4XX_ERRATUM_VENEER_SECTION_NAME) (STM32L4XX_ERRATUM_VENEER_ENTRY_NAME): Define macros. (elf32_stm32l4xx_erratum_type): New enum. (elf32_stm32l4xx_erratum_list): New struct. List of veneers or jumps to veneers. (_arm_elf_section_data): Add stm32l4xx_erratumcount, stm32l4xx_erratumlist. (elf32_arm_link_hash_table): Add stm32l4xx_erratum_glue_size, stm32l4xx_fix and num_stm32l4xx_fixes fields. (ctz): New function. (popcount): New function. (elf32_arm_link_hash_table_create): Initialize stm32l4xx_fix. (put_thumb2_insn): New function. (STM32L4XX_ERRATUM_LDM_VENEER_SIZE): Define. Size of a veneer for LDM instructions. (STM32L4XX_ERRATUM_VLDM_VENEER_SIZE): Define. Size of a veneer for VLDM instructions. (bfd_elf32_arm_allocate_interworking_sections): Initialise erratum glue section. (record_stm32l4xx_erratum_veneer) : New function. Create a single veneer, and its associated symbols. (bfd_elf32_arm_add_glue_sections_to_bfd): Add STM32L4XX erratum glue. (bfd_elf32_arm_set_stm32l4xx_fix): New function. Set the type of erratum workaround required. (bfd_elf32_arm_stm32l4xx_fix_veneer_locations): New function. Find out where veneers and branches to veneers have been placed in virtual memory after layout. (is_thumb2_ldmia): New function. (is_thumb2_ldmdb): Likewise. (is_thumb2_vldm ): Likewise. (stm32l4xx_need_create_replacing_stub): New function. Decide if a veneer must be emitted. (bfd_elf32_arm_stm32l4xx_erratum_scan): Scan the sections of an input BFD for potential erratum-triggering insns. Record results. (bfd_elf32_arm_set_target_relocs): Set stm32l4xx_fix field in global hash table. (elf32_arm_size_dynamic_sections): Collect glue information. (create_instruction_branch_absolute): New function. (create_instruction_ldmia): Likewise. (create_instruction_ldmdb): Likewise. (create_instruction_mov): Likewise. (create_instruction_sub): Likewise. (create_instruction_vldmia): Likewise. (create_instruction_vldmdb): Likewise. (create_instruction_udf_w): Likewise. (create_instruction_udf): Likewise. (push_thumb2_insn32): Likewise. (push_thumb2_insn16): Likewise. (stm32l4xx_fill_stub_udf): Likewise. (stm32l4xx_create_replacing_stub_ldmia): New function. Expands the replacing stub for ldmia instructions. (stm32l4xx_create_replacing_stub_ldmdb): Likewise for ldmdb. (stm32l4xx_create_replacing_stub_vldm): Likewise for vldm. (stm32l4xx_create_replacing_stub): New function. Dispatches the stub emission to the appropriate functions. (elf32_arm_write_section): Output veneers, and branches to veneers. ld * ld.texinfo: Description of the STM32L4xx erratum workaround. * emultempl/armelf.em (stm32l4xx_fix): New. (arm_elf_before_allocation): Choose the type of fix, scan for erratum. (gld${EMULATION_NAME}_finish): Fix veneer locations. (arm_elf_create_output_section_statements): Propagate stm32l4xx_fix value. (PARSE_AND_LIST_PROLOGUE): Define OPTION_STM32L4XX_FIX. (PARSE_AND_LIST_LONGOPTS): Add entry for handling --fix-stm32l4xx-629360. (PARSE_AND_LIST_OPTION): Add entry for helping on --fix-stm32l4xx-629360. (PARSE_AND_LIST_ARGS_CASES): Treat OPTION_STM32L4XX_FIX. tests * ld-arm/arm-elf.exp (armelftests_common): Add STM32L4XX tests. * ld-arm/stm32l4xx-cannot-fix-far-ldm.d: New. * ld-arm/stm32l4xx-cannot-fix-far-ldm.s: Likewise. * ld-arm/stm32l4xx-cannot-fix-it-block.d: Likewise. * ld-arm/stm32l4xx-cannot-fix-it-block.s: Likewise. * ld-arm/stm32l4xx-fix-all.d: Likewise. * ld-arm/stm32l4xx-fix-all.s: Likewise. * ld-arm/stm32l4xx-fix-it-block.d: Likewise. * ld-arm/stm32l4xx-fix-it-block.s: Likewise. * ld-arm/stm32l4xx-fix-ldm.d: Likewise. * ld-arm/stm32l4xx-fix-ldm.s: Likewise. * ld-arm/stm32l4xx-fix-vldm.d: Likewise. * ld-arm/stm32l4xx-fix-vldm.s: Likewise.
Diffstat (limited to 'ld')
-rw-r--r--ld/ChangeLog19
-rw-r--r--ld/NEWS3
-rw-r--r--ld/emultempl/armelf.em32
-rw-r--r--ld/ld.texinfo42
-rw-r--r--ld/testsuite/ChangeLog18
-rw-r--r--ld/testsuite/ld-arm/arm-elf.exp18
-rw-r--r--ld/testsuite/ld-arm/stm32l4xx-cannot-fix-far-ldm.d25
-rw-r--r--ld/testsuite/ld-arm/stm32l4xx-cannot-fix-far-ldm.s27
-rw-r--r--ld/testsuite/ld-arm/stm32l4xx-cannot-fix-it-block.d16
-rw-r--r--ld/testsuite/ld-arm/stm32l4xx-cannot-fix-it-block.s16
-rw-r--r--ld/testsuite/ld-arm/stm32l4xx-fix-all.d83
-rw-r--r--ld/testsuite/ld-arm/stm32l4xx-fix-all.s22
-rw-r--r--ld/testsuite/ld-arm/stm32l4xx-fix-it-block.d189
-rw-r--r--ld/testsuite/ld-arm/stm32l4xx-fix-it-block.s92
-rw-r--r--ld/testsuite/ld-arm/stm32l4xx-fix-ldm.d174
-rw-r--r--ld/testsuite/ld-arm/stm32l4xx-fix-ldm.s147
-rw-r--r--ld/testsuite/ld-arm/stm32l4xx-fix-vldm.d49
-rw-r--r--ld/testsuite/ld-arm/stm32l4xx-fix-vldm.s26
18 files changed, 996 insertions, 2 deletions
diff --git a/ld/ChangeLog b/ld/ChangeLog
index bef7b26..359fc19 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,22 @@
+2015-10-27 Laurent Alfonsi <laurent.alfonsi@st.com>
+ Christophe Monat <christophe.monat@st.com>
+
+ * ld.texinfo: Add description of the STM32L4xx erratum
+ workaround.
+ * NEWS: Mention the new feature.
+ * emultempl/armelf.em (stm32l4xx_fix): New.
+ (arm_elf_before_allocation): Choose the type of fix, scan for
+ erratum.
+ (gld${EMULATION_NAME}_finish): Fix veneer locations.
+ (arm_elf_create_output_section_statements): Propagate
+ stm32l4xx_fix value.
+ (PARSE_AND_LIST_PROLOGUE): Define OPTION_STM32L4XX_FIX.
+ (PARSE_AND_LIST_LONGOPTS): Add entry for handling
+ --fix-stm32l4xx-629360.
+ (PARSE_AND_LIST_OPTION): Add entry for helping on
+ --fix-stm32l4xx-629360.
+ (PARSE_AND_LIST_ARGS_CASES): Treat OPTION_STM32L4XX_FIX.
+
2015-10-27 Alan Modra <amodra@gmail.com>
PR ld/19175
diff --git a/ld/NEWS b/ld/NEWS
index 89288d9..154c066 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,4 +1,7 @@
-*- text -*-
+* Add --fix-stm32l4xx-629360 to the ARM linker to enable a link-time
+ workaround for a bug in the bus matrix / memory controller for some of
+ the STM32 Cortex-M4 based products (STM32L4xx)
* Add a configure option --enable-compressed-debug-sections={all,ld} to
decide whether DWARF debug sections should be compressed by default.
diff --git a/ld/emultempl/armelf.em b/ld/emultempl/armelf.em
index 408d605..b03aed4 100644
--- a/ld/emultempl/armelf.em
+++ b/ld/emultempl/armelf.em
@@ -35,6 +35,7 @@ static char * target2_type = "${TARGET2_TYPE}";
static int fix_v4bx = 0;
static int use_blx = 0;
static bfd_arm_vfp11_fix vfp11_denorm_fix = BFD_ARM_VFP11_FIX_DEFAULT;
+static bfd_arm_stm32l4xx_fix stm32l4xx_fix = BFD_ARM_STM32L4XX_FIX_NONE;
static int fix_cortex_a8 = -1;
static int no_enum_size_warning = 0;
static int no_wchar_size_warning = 0;
@@ -62,6 +63,10 @@ arm_elf_before_allocation (void)
due to architecture version. */
bfd_elf32_arm_set_vfp11_fix (link_info.output_bfd, &link_info);
+ /* Choose type of STM32L4XX erratum fix, or warn if specified fix is
+ unnecessary due to architecture version. */
+ bfd_elf32_arm_set_stm32l4xx_fix (link_info.output_bfd, &link_info);
+
/* Auto-select Cortex-A8 erratum fix if it wasn't explicitly specified. */
bfd_elf32_arm_set_cortex_a8_fix (link_info.output_bfd, &link_info);
@@ -77,7 +82,9 @@ arm_elf_before_allocation (void)
if (!bfd_elf32_arm_process_before_allocation (is->the_bfd,
&link_info)
- || !bfd_elf32_arm_vfp11_erratum_scan (is->the_bfd, &link_info))
+ || !bfd_elf32_arm_vfp11_erratum_scan (is->the_bfd, &link_info)
+ || !bfd_elf32_arm_stm32l4xx_erratum_scan (is->the_bfd,
+ &link_info))
/* xgettext:c-format */
einfo (_("Errors encountered processing file %s"), is->filename);
}
@@ -380,6 +387,10 @@ gld${EMULATION_NAME}_finish (void)
/* Figure out where VFP11 erratum veneers (and the labels returning
from same) have been placed. */
bfd_elf32_arm_vfp11_fix_veneer_locations (is->the_bfd, &link_info);
+
+ /* Figure out where STM32L4XX erratum veneers (and the labels returning
+ from them) have been placed. */
+ bfd_elf32_arm_stm32l4xx_fix_veneer_locations (is->the_bfd, &link_info);
}
}
@@ -468,7 +479,8 @@ arm_elf_create_output_section_statements (void)
bfd_elf32_arm_set_target_relocs (link_info.output_bfd, &link_info,
target1_is_rel,
target2_type, fix_v4bx, use_blx,
- vfp11_denorm_fix, no_enum_size_warning,
+ vfp11_denorm_fix, stm32l4xx_fix,
+ no_enum_size_warning,
no_wchar_size_warning,
pic_veneer, fix_cortex_a8,
fix_arm1176);
@@ -539,6 +551,7 @@ PARSE_AND_LIST_PROLOGUE='
#define OPTION_FIX_ARM1176 317
#define OPTION_NO_FIX_ARM1176 318
#define OPTION_LONG_PLT 319
+#define OPTION_STM32L4XX_FIX 320
'
PARSE_AND_LIST_SHORTOPTS=p
@@ -554,6 +567,7 @@ PARSE_AND_LIST_LONGOPTS='
{ "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},
+ { "fix-stm32l4xx-629360", optional_argument, NULL, OPTION_STM32L4XX_FIX},
{ "no-enum-size-warning", no_argument, NULL, OPTION_NO_ENUM_SIZE_WARNING},
{ "pic-veneer", no_argument, NULL, OPTION_PIC_VENEER},
{ "stub-group-size", required_argument, NULL, OPTION_STUBGROUP_SIZE },
@@ -576,6 +590,7 @@ PARSE_AND_LIST_OPTIONS='
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, _(" --fix-stm32l4xx-629360 Specify how to fix STM32L4XX 629360 erratum\n"));
fprintf (file, _(" --no-enum-size-warning Don'\''t warn about objects with incompatible\n"
" enum sizes\n"));
fprintf (file, _(" --no-wchar-size-warning Don'\''t warn about objects with incompatible\n"
@@ -645,6 +660,19 @@ PARSE_AND_LIST_ARGS_CASES='
einfo (_("Unrecognized VFP11 fix type '\''%s'\''.\n"), optarg);
break;
+ case OPTION_STM32L4XX_FIX:
+ if (!optarg)
+ stm32l4xx_fix = BFD_ARM_STM32L4XX_FIX_DEFAULT;
+ else if (strcmp (optarg, "none") == 0)
+ stm32l4xx_fix = BFD_ARM_STM32L4XX_FIX_NONE;
+ else if (strcmp (optarg, "default") == 0)
+ stm32l4xx_fix = BFD_ARM_STM32L4XX_FIX_DEFAULT;
+ else if (strcmp (optarg, "all") == 0)
+ stm32l4xx_fix = BFD_ARM_STM32L4XX_FIX_ALL;
+ else
+ einfo (_("Unrecognized STM32L4XX fix type '\''%s'\''.\n"), optarg);
+ break;
+
case OPTION_NO_ENUM_SIZE_WARNING:
no_enum_size_warning = 1;
break;
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index 0c3a551..8374ccf 100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -6681,6 +6681,48 @@ Further information is available in the ``ARM1176JZ-S and ARM1176JZF-S
Programmer Advice Notice'' available on the ARM documentation website at:
http://infocenter.arm.com/.
+@cindex STM32L4xx erratum workaround
+@kindex --fix-stm32l4xx-629360
+
+The @samp{--fix-stm32l4xx-629360} switch enables a link-time
+workaround for a bug in the bus matrix / memory controller for some of
+the STM32 Cortex-M4 based products (STM32L4xx). When accessing
+off-chip memory via the affected bus for bus reads of 9 words or more,
+the bus can generate corrupt data and/or abort. These are only
+core-initiated accesses (not DMA), and might affect any access:
+integer loads such as LDM, POP and floating-point loads such as VLDM,
+VPOP. Stores are not affected.
+
+The bug can be avoided by splitting memory accesses into the
+necessary chunks to keep bus reads below 8 words.
+
+The workaround is not enabled by default, this is equivalent to use
+@samp{--fix-stm32l4xx-629360=none}. If you know you are using buggy
+STM32L4xx hardware, you can enable the workaround by specifying the
+linker option @samp{--fix-stm32l4xx-629360}, or the equivalent
+@samp{--fix-stm32l4xx-629360=default}.
+
+If the workaround is enabled, instructions are scanned for
+potentially-troublesome sequences, and a veneer is created for each
+such sequence which may trigger the erratum. The veneer consists in a
+replacement sequence emulating the behaviour of the original one and a
+branch back to the subsequent instruction. The original instruction is
+then replaced with a branch to the veneer.
+
+The workaround does not always preserve the memory access order for
+the LDMDB instruction, when the instruction loads the PC.
+
+The workaround is not able to handle problematic instructions when
+they are in the middle of an IT block, since a branch is not allowed
+there. In that case, the linker reports a warning and no replacement
+occurs.
+
+The workaround is not able to replace problematic instructions with a
+PC-relative branch instruction if the @samp{.text} section is too
+large. In that case, when the branch that replaces the original code
+cannot be encoded, the linker reports a warning and no replacement
+occurs.
+
@cindex NO_ENUM_SIZE_WARNING
@kindex --no-enum-size-warning
The @option{--no-enum-size-warning} switch prevents the linker from
diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog
index 4e412d6..6981d70 100644
--- a/ld/testsuite/ChangeLog
+++ b/ld/testsuite/ChangeLog
@@ -1,3 +1,21 @@
+2015-10-27 Laurent Alfonsi <laurent.alfonsi@st.com>
+ Christophe Monat <christophe.monat@st.com>
+
+ * ld-arm/arm-elf.exp (armelftests_common): Add STM32L4XX
+ tests.
+ * ld-arm/stm32l4xx-cannot-fix-far-ldm.d: New.
+ * ld-arm/stm32l4xx-cannot-fix-far-ldm.s: Likewise.
+ * ld-arm/stm32l4xx-cannot-fix-it-block.d: Likewise.
+ * ld-arm/stm32l4xx-cannot-fix-it-block.s: Likewise.
+ * ld-arm/stm32l4xx-fix-all.d: Likewise.
+ * ld-arm/stm32l4xx-fix-all.s: Likewise.
+ * ld-arm/stm32l4xx-fix-it-block.d: Likewise.
+ * ld-arm/stm32l4xx-fix-it-block.s: Likewise.
+ * ld-arm/stm32l4xx-fix-ldm.d: Likewise.
+ * ld-arm/stm32l4xx-fix-ldm.s: Likewise.
+ * ld-arm/stm32l4xx-fix-vldm.d: Likewise.
+ * ld-arm/stm32l4xx-fix-vldm.s: Likewise.
+
2015-10-27 Alan Modra <amodra@gmail.com>
* ld-gc/pr19161.d: xfail hppa-*-*.
diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp
index 882f5cb..1d9b1c8 100644
--- a/ld/testsuite/ld-arm/arm-elf.exp
+++ b/ld/testsuite/ld-arm/arm-elf.exp
@@ -159,6 +159,22 @@ set armelftests_common {
"-EL --vfp11-denorm-fix=scalar -Ttext=0x8000" "" "-EL -mfpu=vfpxd" {vfp11-fix-none.s}
{{objdump -dr vfp11-fix-none.d}}
"vfp11-fix-none"}
+ {"STM32L4XX erratum fix LDM"
+ "-EL --fix-stm32l4xx-629360 -Ttext=0x8000" "" "-EL -mcpu=cortex-m4 -mfpu=fpv4-sp-d16" {stm32l4xx-fix-ldm.s}
+ {{objdump -dr stm32l4xx-fix-ldm.d}}
+ "stm32l4xx-fix-ldm"}
+ {"STM32L4XX erratum fix VLDM"
+ "-EL --fix-stm32l4xx-629360 -Ttext=0x8000" "" "-EL -mcpu=cortex-m4 -mfpu=fpv4-sp-d16" {stm32l4xx-fix-vldm.s}
+ {{objdump -dr stm32l4xx-fix-vldm.d}}
+ "stm32l4xx-fix-vldm"}
+ {"STM32L4XX erratum fix ALL"
+ "-EL --fix-stm32l4xx-629360=all -Ttext=0x8000" "" "-EL -mcpu=cortex-m4 -mfpu=fpv4-sp-d16" {stm32l4xx-fix-all.s}
+ {{objdump -dr stm32l4xx-fix-all.d}}
+ "stm32l4xx-fix-vldm-all"}
+ {"STM32L4XX erratum fix in IT context"
+ "-EL --fix-stm32l4xx-629360 -Ttext=0x8000" "" "-EL -mcpu=cortex-m4 -mfpu=fpv4-sp-d16" {stm32l4xx-fix-it-block.s}
+ {{objdump -dr stm32l4xx-fix-it-block.d}}
+ "stm32l4xx-fix-it-block"}
{"Unwinding and -gc-sections" "-gc-sections" "" "" {gc-unwind.s}
{{objdump -sj.data gc-unwind.d}}
"gc-unwind"}
@@ -905,3 +921,5 @@ if { ![istarget "arm*-*-nacl*"] } {
run_dump_test "unresolved-2"
run_dump_test "gc-hidden-1"
run_dump_test "protected-data"
+run_dump_test "stm32l4xx-cannot-fix-it-block"
+run_dump_test "stm32l4xx-cannot-fix-far-ldm"
diff --git a/ld/testsuite/ld-arm/stm32l4xx-cannot-fix-far-ldm.d b/ld/testsuite/ld-arm/stm32l4xx-cannot-fix-far-ldm.d
new file mode 100644
index 0000000..a7674d5
--- /dev/null
+++ b/ld/testsuite/ld-arm/stm32l4xx-cannot-fix-far-ldm.d
@@ -0,0 +1,25 @@
+#source: stm32l4xx-cannot-fix-far-ldm.s
+#as:-EL -mcpu=cortex-m4 -mfpu=fpv4-sp-d16
+#ld:-EL --fix-stm32l4xx-629360 -Ttext=0x80000
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: STM32L4XX erratum : LDM cannot be patched when LDM is too far from veneer section
+#warning: .*Cannot create STM32L4XX veneer. Jump out of range by 24 bytes. Cannot encode branch instruction.*
+
+# Test the `LDM*' instructions when too far from the veneer section
+# They cannot, thus should not, be patched
+
+.*: +file format .*arm.*
+
+Disassembly of section \.text:
+00080000 <__stm32l4xx_veneer_0> 4607[[:space:]]+mov[[:space:]]+r7, r0
+00080002 <__stm32l4xx_veneer_0\+0x2> e8b7 007e[[:space:]]+ldmia\.w[[:space:]]+r7\!, {r1, r2, r3, r4, r5, r6}
+00080006 <__stm32l4xx_veneer_0\+0x6> e897 0380[[:space:]]+ldmia\.w[[:space:]]+r7, {r7, r8, r9}
+0008000a <__stm32l4xx_veneer_0\+0xa> f3ff 978b[[:space:]]+b\.w[[:space:]]+0107ff24 <__stm32l4xx_veneer_0_r>
+0008000e <__stm32l4xx_veneer_0\+0xe> de00[[:space:]]+udf[[:space:]]+#0
+ \.\.\.
+ \.\.\.
+0107ff20 <_start\+0xffff00> f400 906e[[:space:]]+b\.w[[:space:]]+00080000 <__stm32l4xx_veneer_0>
+ \.\.\.
+01080024 <__stm32l4xx_veneer_0_r\+0x100> e899 03fe[[:space:]]+ldmia\.w[[:space:]]+r9, {r1, r2, r3, r4, r5, r6, r7, r8, r9}
+01080028 <__stm32l4xx_veneer_1_r> bf00[[:space:]]+nop
+
diff --git a/ld/testsuite/ld-arm/stm32l4xx-cannot-fix-far-ldm.s b/ld/testsuite/ld-arm/stm32l4xx-cannot-fix-far-ldm.s
new file mode 100644
index 0000000..7ba9a16
--- /dev/null
+++ b/ld/testsuite/ld-arm/stm32l4xx-cannot-fix-far-ldm.s
@@ -0,0 +1,27 @@
+ .syntax unified
+ .cpu cortex-m4
+ .fpu fpv4-sp-d16
+ .text
+ .align 1
+ .thumb
+ .thumb_func
+ .global _start
+_start:
+ .space 0xFFFF00
+
+ @ Multiple load, case #2
+ @ ldm rx, {...} ->
+ @ mov ry, rx where ry is the lowest register from upper_list
+ @ ldm ry!, { lower_list }
+ @ ldm ry, { upper_list }
+ ldm.w r0, {r1-r9}
+
+ .space 0x100
+
+ @ Check that the linker never generates a wrong branch
+ @ ldm rx, {...} -> ldm rx, {...}
+ @ Emit a warning during the link phase and keep the same instruction
+
+ ldm.w r9, {r1-r9}
+
+ nop
diff --git a/ld/testsuite/ld-arm/stm32l4xx-cannot-fix-it-block.d b/ld/testsuite/ld-arm/stm32l4xx-cannot-fix-it-block.d
new file mode 100644
index 0000000..9b689f1
--- /dev/null
+++ b/ld/testsuite/ld-arm/stm32l4xx-cannot-fix-it-block.d
@@ -0,0 +1,16 @@
+#source: stm32l4xx-cannot-fix-it-block.s
+#as:-EL -mcpu=cortex-m4 -mfpu=fpv4-sp-d16
+#ld:-EL --fix-stm32l4xx-629360 -Ttext=0x8000
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: STM32L4XX erratum : LDM cannot be patched when not last in IT block
+#warning: .*multiple load detected in non-last IT block instruction.*
+
+# Test the `LDM*' instructions when non-last in IT block
+# They cannot, thus should not, be patched
+
+.*: +file format .*arm.*
+
+Disassembly of section \.text:
+00008000 \<_start\> bf04[[:space:]]+itt[[:space:]]+eq
+00008002 \<_start\+0x2\> e899 03fe[[:space:]]+ldmiaeq\.w[[:space:]]+r9, {r1, r2, r3, r4, r5, r6, r7, r8, r9}
+00008006 \<_start\+0x6\> f3af 8000[[:space:]]+nopeq\.w
diff --git a/ld/testsuite/ld-arm/stm32l4xx-cannot-fix-it-block.s b/ld/testsuite/ld-arm/stm32l4xx-cannot-fix-it-block.s
new file mode 100644
index 0000000..9c16388
--- /dev/null
+++ b/ld/testsuite/ld-arm/stm32l4xx-cannot-fix-it-block.s
@@ -0,0 +1,16 @@
+ .syntax unified
+ .cpu cortex-m4
+ .fpu fpv4-sp-d16
+ .text
+ .align 1
+ .thumb
+ .thumb_func
+ .global _start
+_start:
+ @ Create a situation where a multiple-load that should be
+ @ patched cannot be, due to its belonging to an IT block
+ @ but not in last position, which is the only position
+ @ when a branch is valid in a IT block
+ itt eq
+ ldmeq.w r9, {r1-r9}
+ nop.w
diff --git a/ld/testsuite/ld-arm/stm32l4xx-fix-all.d b/ld/testsuite/ld-arm/stm32l4xx-fix-all.d
new file mode 100644
index 0000000..59f3ed1
--- /dev/null
+++ b/ld/testsuite/ld-arm/stm32l4xx-fix-all.d
@@ -0,0 +1,83 @@
+
+.*: file format elf32-littlearm.*
+
+
+Disassembly of section \.text:
+
+00008000 <__stm32l4xx_veneer_0>:
+ 8000: e899 01fe ldmia\.w r9, {r1, r2, r3, r4, r5, r6, r7, r8}
+ 8004: f000 b84a b\.w 809c <__stm32l4xx_veneer_0_r>
+ 8008: f7f0 a000 udf\.w #0
+ 800c: f7f0 a000 udf\.w #0
+
+00008010 <__stm32l4xx_veneer_1>:
+ 8010: e8b9 01fe ldmia\.w r9!, {r1, r2, r3, r4, r5, r6, r7, r8}
+ 8014: f000 b844 b\.w 80a0 <__stm32l4xx_veneer_1_r>
+ 8018: f7f0 a000 udf\.w #0
+ 801c: f7f0 a000 udf\.w #0
+
+00008020 <__stm32l4xx_veneer_2>:
+ 8020: e919 01fe ldmdb r9, {r1, r2, r3, r4, r5, r6, r7, r8}
+ 8024: f000 b83e b\.w 80a4 <__stm32l4xx_veneer_2_r>
+ 8028: f7f0 a000 udf\.w #0
+ 802c: f7f0 a000 udf\.w #0
+
+00008030 <__stm32l4xx_veneer_3>:
+ 8030: e939 01fe ldmdb r9!, {r1, r2, r3, r4, r5, r6, r7, r8}
+ 8034: f000 b838 b\.w 80a8 <__stm32l4xx_veneer_3_r>
+ 8038: f7f0 a000 udf\.w #0
+ 803c: f7f0 a000 udf\.w #0
+
+00008040 <__stm32l4xx_veneer_4>:
+ 8040: e8bd 01fe ldmia\.w sp!, {r1, r2, r3, r4, r5, r6, r7, r8}
+ 8044: f000 b832 b\.w 80ac <__stm32l4xx_veneer_4_r>
+ 8048: f7f0 a000 udf\.w #0
+ 804c: f7f0 a000 udf\.w #0
+
+00008050 <__stm32l4xx_veneer_5>:
+ 8050: ecd9 0a08 vldmia r9, {s1-s8}
+ 8054: f000 b82c b\.w 80b0 <__stm32l4xx_veneer_5_r>
+ 8058: f7f0 a000 udf\.w #0
+ 805c: f7f0 a000 udf\.w #0
+ 8060: f7f0 a000 udf\.w #0
+ 8064: f7f0 a000 udf\.w #0
+
+00008068 <__stm32l4xx_veneer_6>:
+ 8068: ecf6 4a08 vldmia r6!, {s9-s16}
+ 806c: f000 b822 b\.w 80b4 <__stm32l4xx_veneer_6_r>
+ 8070: f7f0 a000 udf\.w #0
+ 8074: f7f0 a000 udf\.w #0
+ 8078: f7f0 a000 udf\.w #0
+ 807c: f7f0 a000 udf\.w #0
+
+00008080 <__stm32l4xx_veneer_7>:
+ 8080: ecfd 0a08 vpop {s1-s8}
+ 8084: f000 b818 b\.w 80b8 <__stm32l4xx_veneer_7_r>
+ 8088: f7f0 a000 udf\.w #0
+ 808c: f7f0 a000 udf\.w #0
+ 8090: f7f0 a000 udf\.w #0
+ 8094: f7f0 a000 udf\.w #0
+
+00008098 <_start>:
+ 8098: f7ff bfb2 b\.w 8000 <__stm32l4xx_veneer_0>
+
+0000809c <__stm32l4xx_veneer_0_r>:
+ 809c: f7ff bfb8 b\.w 8010 <__stm32l4xx_veneer_1>
+
+000080a0 <__stm32l4xx_veneer_1_r>:
+ 80a0: f7ff bfbe b\.w 8020 <__stm32l4xx_veneer_2>
+
+000080a4 <__stm32l4xx_veneer_2_r>:
+ 80a4: f7ff bfc4 b\.w 8030 <__stm32l4xx_veneer_3>
+
+000080a8 <__stm32l4xx_veneer_3_r>:
+ 80a8: f7ff bfca b\.w 8040 <__stm32l4xx_veneer_4>
+
+000080ac <__stm32l4xx_veneer_4_r>:
+ 80ac: f7ff bfd0 b\.w 8050 <__stm32l4xx_veneer_5>
+
+000080b0 <__stm32l4xx_veneer_5_r>:
+ 80b0: f7ff bfda b\.w 8068 <__stm32l4xx_veneer_6>
+
+000080b4 <__stm32l4xx_veneer_6_r>:
+ 80b4: f7ff bfe4 b\.w 8080 <__stm32l4xx_veneer_7>
diff --git a/ld/testsuite/ld-arm/stm32l4xx-fix-all.s b/ld/testsuite/ld-arm/stm32l4xx-fix-all.s
new file mode 100644
index 0000000..0c18266
--- /dev/null
+++ b/ld/testsuite/ld-arm/stm32l4xx-fix-all.s
@@ -0,0 +1,22 @@
+ .syntax unified
+ .cpu cortex-m4
+ .fpu fpv4-sp-d16
+ .text
+ .align 1
+ .thumb
+ .thumb_func
+ .global _start
+_start:
+ @ All LDM treatments for word acces <= 8 go through the same
+ @ replication code, but decoding may vary
+ ldm.w r9, {r1-r8}
+ ldm.w r9!, {r1-r8}
+ ldmdb.w r9, {r1-r8}
+ ldmdb.w r9!, {r1-r8}
+ pop {r1-r8}
+
+ @ All VLDM treatments for word acces <= 8 go through the same
+ @ replication code, but decoding may vary
+ vldm r9, {s1-s8}
+ vldm r6!, {s9-s16}
+ vpop {s1-s8}
diff --git a/ld/testsuite/ld-arm/stm32l4xx-fix-it-block.d b/ld/testsuite/ld-arm/stm32l4xx-fix-it-block.d
new file mode 100644
index 0000000..97bb34d
--- /dev/null
+++ b/ld/testsuite/ld-arm/stm32l4xx-fix-it-block.d
@@ -0,0 +1,189 @@
+
+.*: file format elf32-littlearm.*
+
+
+Disassembly of section \.text:
+
+00008000 <__stm32l4xx_veneer_0>:
+ 8000: e8b9 007e ldmia\.w r9!, {r1, r2, r3, r4, r5, r6}
+ 8004: e899 0380 ldmia\.w r9, {r7, r8, r9}
+ 8008: f000 b875 b\.w 80f6 <__stm32l4xx_veneer_0_r>
+ 800c: f7f0 a000 udf\.w #0
+
+00008010 <__stm32l4xx_veneer_1>:
+ 8010: e8b9 007e ldmia\.w r9!, {r1, r2, r3, r4, r5, r6}
+ 8014: e899 0380 ldmia\.w r9, {r7, r8, r9}
+ 8018: f000 b872 b\.w 8100 <__stm32l4xx_veneer_1_r>
+ 801c: f7f0 a000 udf\.w #0
+
+00008020 <__stm32l4xx_veneer_2>:
+ 8020: e8b9 007e ldmia\.w r9!, {r1, r2, r3, r4, r5, r6}
+ 8024: e899 0380 ldmia\.w r9, {r7, r8, r9}
+ 8028: f000 b86f b\.w 810a <__stm32l4xx_veneer_2_r>
+ 802c: f7f0 a000 udf\.w #0
+
+00008030 <__stm32l4xx_veneer_3>:
+ 8030: e8b9 007e ldmia\.w r9!, {r1, r2, r3, r4, r5, r6}
+ 8034: e899 0380 ldmia\.w r9, {r7, r8, r9}
+ 8038: f000 b86e b\.w 8118 <__stm32l4xx_veneer_3_r>
+ 803c: f7f0 a000 udf\.w #0
+
+00008040 <__stm32l4xx_veneer_4>:
+ 8040: e8b9 007e ldmia\.w r9!, {r1, r2, r3, r4, r5, r6}
+ 8044: e899 0380 ldmia\.w r9, {r7, r8, r9}
+ 8048: f000 b86d b\.w 8126 <__stm32l4xx_veneer_4_r>
+ 804c: f7f0 a000 udf\.w #0
+
+00008050 <__stm32l4xx_veneer_5>:
+ 8050: e8b9 007e ldmia\.w r9!, {r1, r2, r3, r4, r5, r6}
+ 8054: e899 0380 ldmia\.w r9, {r7, r8, r9}
+ 8058: f000 b86c b\.w 8134 <__stm32l4xx_veneer_5_r>
+ 805c: f7f0 a000 udf\.w #0
+
+00008060 <__stm32l4xx_veneer_6>:
+ 8060: e8b9 007e ldmia\.w r9!, {r1, r2, r3, r4, r5, r6}
+ 8064: e899 0380 ldmia\.w r9, {r7, r8, r9}
+ 8068: f000 b86b b\.w 8142 <__stm32l4xx_veneer_6_r>
+ 806c: f7f0 a000 udf\.w #0
+
+00008070 <__stm32l4xx_veneer_7>:
+ 8070: e8b9 007e ldmia\.w r9!, {r1, r2, r3, r4, r5, r6}
+ 8074: e899 0380 ldmia\.w r9, {r7, r8, r9}
+ 8078: f000 b86c b\.w 8154 <__stm32l4xx_veneer_7_r>
+ 807c: f7f0 a000 udf\.w #0
+
+00008080 <__stm32l4xx_veneer_8>:
+ 8080: e8b9 007e ldmia\.w r9!, {r1, r2, r3, r4, r5, r6}
+ 8084: e899 0380 ldmia\.w r9, {r7, r8, r9}
+ 8088: f000 b86d b\.w 8166 <__stm32l4xx_veneer_8_r>
+ 808c: f7f0 a000 udf\.w #0
+
+00008090 <__stm32l4xx_veneer_9>:
+ 8090: e8b9 007e ldmia\.w r9!, {r1, r2, r3, r4, r5, r6}
+ 8094: e899 0380 ldmia\.w r9, {r7, r8, r9}
+ 8098: f000 b86e b\.w 8178 <__stm32l4xx_veneer_9_r>
+ 809c: f7f0 a000 udf\.w #0
+
+000080a0 <__stm32l4xx_veneer_a>:
+ 80a0: e8b9 007e ldmia\.w r9!, {r1, r2, r3, r4, r5, r6}
+ 80a4: e899 0380 ldmia\.w r9, {r7, r8, r9}
+ 80a8: f000 b86f b\.w 818a <__stm32l4xx_veneer_a_r>
+ 80ac: f7f0 a000 udf\.w #0
+
+000080b0 <__stm32l4xx_veneer_b>:
+ 80b0: e8b9 007e ldmia\.w r9!, {r1, r2, r3, r4, r5, r6}
+ 80b4: e899 0380 ldmia\.w r9, {r7, r8, r9}
+ 80b8: f000 b870 b\.w 819c <__stm32l4xx_veneer_b_r>
+ 80bc: f7f0 a000 udf\.w #0
+
+000080c0 <__stm32l4xx_veneer_c>:
+ 80c0: e8b9 007e ldmia\.w r9!, {r1, r2, r3, r4, r5, r6}
+ 80c4: e899 0380 ldmia\.w r9, {r7, r8, r9}
+ 80c8: f000 b871 b\.w 81ae <__stm32l4xx_veneer_c_r>
+ 80cc: f7f0 a000 udf\.w #0
+
+000080d0 <__stm32l4xx_veneer_d>:
+ 80d0: e8b9 007e ldmia\.w r9!, {r1, r2, r3, r4, r5, r6}
+ 80d4: e899 0380 ldmia\.w r9, {r7, r8, r9}
+ 80d8: f000 b872 b\.w 81c0 <__stm32l4xx_veneer_d_r>
+ 80dc: f7f0 a000 udf\.w #0
+
+000080e0 <__stm32l4xx_veneer_e>:
+ 80e0: e8b9 007e ldmia\.w r9!, {r1, r2, r3, r4, r5, r6}
+ 80e4: e899 0380 ldmia\.w r9, {r7, r8, r9}
+ 80e8: f000 b873 b\.w 81d2 <__stm32l4xx_veneer_e_r>
+ 80ec: f7f0 a000 udf\.w #0
+
+000080f0 <_start>:
+ 80f0: bf08 it eq
+ 80f2: f7ff bf85 beq\.w 8000 <__stm32l4xx_veneer_0>
+
+000080f6 <__stm32l4xx_veneer_0_r>:
+ 80f6: bf04 itt eq
+ 80f8: f3af 8000 nopeq\.w
+ 80fc: f7ff bf88 beq\.w 8010 <__stm32l4xx_veneer_1>
+
+00008100 <__stm32l4xx_veneer_1_r>:
+ 8100: bf0c ite eq
+ 8102: f3af 8000 nopeq\.w
+ 8106: f7ff bf8b bne\.w 8020 <__stm32l4xx_veneer_2>
+
+0000810a <__stm32l4xx_veneer_2_r>:
+ 810a: bf02 ittt eq
+ 810c: f3af 8000 nopeq\.w
+ 8110: f3af 8000 nopeq\.w
+ 8114: f7ff bf8c beq\.w 8030 <__stm32l4xx_veneer_3>
+
+00008118 <__stm32l4xx_veneer_3_r>:
+ 8118: bf0a itet eq
+ 811a: f3af 8000 nopeq\.w
+ 811e: f3af 8000 nopne\.w
+ 8122: f7ff bf8d beq\.w 8040 <__stm32l4xx_veneer_4>
+
+00008126 <__stm32l4xx_veneer_4_r>:
+ 8126: bf06 itte eq
+ 8128: f3af 8000 nopeq\.w
+ 812c: f3af 8000 nopeq\.w
+ 8130: f7ff bf8e bne\.w 8050 <__stm32l4xx_veneer_5>
+
+00008134 <__stm32l4xx_veneer_5_r>:
+ 8134: bf0e itee eq
+ 8136: f3af 8000 nopeq\.w
+ 813a: f3af 8000 nopne\.w
+ 813e: f7ff bf8f bne\.w 8060 <__stm32l4xx_veneer_6>
+
+00008142 <__stm32l4xx_veneer_6_r>:
+ 8142: bf01 itttt eq
+ 8144: f3af 8000 nopeq\.w
+ 8148: f3af 8000 nopeq\.w
+ 814c: f3af 8000 nopeq\.w
+ 8150: f7ff bf8e beq\.w 8070 <__stm32l4xx_veneer_7>
+
+00008154 <__stm32l4xx_veneer_7_r>:
+ 8154: bf03 ittte eq
+ 8156: f3af 8000 nopeq\.w
+ 815a: f3af 8000 nopeq\.w
+ 815e: f3af 8000 nopeq\.w
+ 8162: f7ff bf8d bne\.w 8080 <__stm32l4xx_veneer_8>
+
+00008166 <__stm32l4xx_veneer_8_r>:
+ 8166: bf05 ittet eq
+ 8168: f3af 8000 nopeq\.w
+ 816c: f3af 8000 nopeq\.w
+ 8170: f3af 8000 nopne\.w
+ 8174: f7ff bf8c beq\.w 8090 <__stm32l4xx_veneer_9>
+
+00008178 <__stm32l4xx_veneer_9_r>:
+ 8178: bf07 ittee eq
+ 817a: f3af 8000 nopeq\.w
+ 817e: f3af 8000 nopeq\.w
+ 8182: f3af 8000 nopne\.w
+ 8186: f7ff bf8b bne\.w 80a0 <__stm32l4xx_veneer_a>
+
+0000818a <__stm32l4xx_veneer_a_r>:
+ 818a: bf09 itett eq
+ 818c: f3af 8000 nopeq\.w
+ 8190: f3af 8000 nopne\.w
+ 8194: f3af 8000 nopeq\.w
+ 8198: f7ff bf8a beq\.w 80b0 <__stm32l4xx_veneer_b>
+
+0000819c <__stm32l4xx_veneer_b_r>:
+ 819c: bf0b itete eq
+ 819e: f3af 8000 nopeq\.w
+ 81a2: f3af 8000 nopne\.w
+ 81a6: f3af 8000 nopeq\.w
+ 81aa: f7ff bf89 bne\.w 80c0 <__stm32l4xx_veneer_c>
+
+000081ae <__stm32l4xx_veneer_c_r>:
+ 81ae: bf0d iteet eq
+ 81b0: f3af 8000 nopeq\.w
+ 81b4: f3af 8000 nopne\.w
+ 81b8: f3af 8000 nopne\.w
+ 81bc: f7ff bf88 beq\.w 80d0 <__stm32l4xx_veneer_d>
+
+000081c0 <__stm32l4xx_veneer_d_r>:
+ 81c0: bf0f iteee eq
+ 81c2: f3af 8000 nopeq\.w
+ 81c6: f3af 8000 nopne\.w
+ 81ca: f3af 8000 nopne\.w
+ 81ce: f7ff bf87 bne\.w 80e0 <__stm32l4xx_veneer_e>
diff --git a/ld/testsuite/ld-arm/stm32l4xx-fix-it-block.s b/ld/testsuite/ld-arm/stm32l4xx-fix-it-block.s
new file mode 100644
index 0000000..567c0b6
--- /dev/null
+++ b/ld/testsuite/ld-arm/stm32l4xx-fix-it-block.s
@@ -0,0 +1,92 @@
+ .syntax unified
+ .cpu cortex-m4
+ .fpu fpv4-sp-d16
+ .text
+ .align 1
+ .thumb
+ .thumb_func
+ .global _start
+_start:
+ @ Create a situation where a multiple-load that should be
+ @ patched belongs to an IT block in the position where it can
+ @ be, that is the last position in the IT block.
+ @ Mostly to cover the IT detection logic.
+ @ Tests correspond to LDM CASE #1.
+ it eq
+ ldmeq.w r9, {r1-r9}
+
+ itt eq
+ nop.w
+ ldmeq.w r9, {r1-r9}
+
+ ite eq
+ nop.w
+ ldmne.w r9, {r1-r9}
+
+ ittt eq
+ nop.w
+ nop.w
+ ldmeq.w r9, {r1-r9}
+
+ itet eq
+ nop.w
+ nop.w
+ ldmeq.w r9, {r1-r9}
+
+ itte eq
+ nop.w
+ nop.w
+ ldmne.w r9, {r1-r9}
+
+ itee eq
+ nop.w
+ nop.w
+ ldmne.w r9, {r1-r9}
+
+ itttt eq
+ nop.w
+ nop.w
+ nop.w
+ ldmeq.w r9, {r1-r9}
+
+ ittte eq
+ nop.w
+ nop.w
+ nop.w
+ ldmne.w r9, {r1-r9}
+
+ ittet eq
+ nop.w
+ nop.w
+ nop.w
+ ldmeq.w r9, {r1-r9}
+
+ ittee eq
+ nop.w
+ nop.w
+ nop.w
+ ldmne.w r9, {r1-r9}
+
+ itett eq
+ nop.w
+ nop.w
+ nop.w
+ ldmeq.w r9, {r1-r9}
+
+ itete eq
+ nop.w
+ nop.w
+ nop.w
+ ldmne.w r9, {r1-r9}
+
+ iteet eq
+ nop.w
+ nop.w
+ nop.w
+ ldmeq.w r9, {r1-r9}
+
+ iteee eq
+ nop.w
+ nop.w
+ nop.w
+ ldmne.w r9, {r1-r9}
diff --git a/ld/testsuite/ld-arm/stm32l4xx-fix-ldm.d b/ld/testsuite/ld-arm/stm32l4xx-fix-ldm.d
new file mode 100644
index 0000000..260415d
--- /dev/null
+++ b/ld/testsuite/ld-arm/stm32l4xx-fix-ldm.d
@@ -0,0 +1,174 @@
+
+.*: file format elf32-littlearm.*
+
+
+Disassembly of section \.text:
+
+00008000 <__stm32l4xx_veneer_0>:
+ 8000: e8b9 007e ldmia\.w r9!, {r1, r2, r3, r4, r5, r6}
+ 8004: e899 0380 ldmia\.w r9, {r7, r8, r9}
+ 8008: f000 b88c b\.w 8124 <__stm32l4xx_veneer_0_r>
+ 800c: f7f0 a000 udf\.w #0
+
+00008010 <__stm32l4xx_veneer_1>:
+ 8010: e8b9 007e ldmia\.w r9!, {r1, r2, r3, r4, r5, r6}
+ 8014: e899 8380 ldmia\.w r9, {r7, r8, r9, pc}
+ 8018: f7f0 a000 udf\.w #0
+ 801c: f7f0 a000 udf\.w #0
+
+00008020 <__stm32l4xx_veneer_2>:
+ 8020: 4607 mov r7, r0
+ 8022: e8b7 007e ldmia\.w r7!, {r1, r2, r3, r4, r5, r6}
+ 8026: e897 0380 ldmia\.w r7, {r7, r8, r9}
+ 802a: f000 b87f b\.w 812c <__stm32l4xx_veneer_2_r>
+ 802e: de00 udf #0
+
+00008030 <__stm32l4xx_veneer_3>:
+ 8030: 460f mov r7, r1
+ 8032: e8b7 007e ldmia\.w r7!, {r1, r2, r3, r4, r5, r6}
+ 8036: e897 0380 ldmia\.w r7, {r7, r8, r9}
+ 803a: f000 b879 b\.w 8130 <__stm32l4xx_veneer_3_r>
+ 803e: de00 udf #0
+
+00008040 <__stm32l4xx_veneer_4>:
+ 8040: 4607 mov r7, r0
+ 8042: e8b7 007e ldmia\.w r7!, {r1, r2, r3, r4, r5, r6}
+ 8046: e897 8380 ldmia\.w r7, {r7, r8, r9, pc}
+ 804a: de00 udf #0
+ 804c: f7f0 a000 udf\.w #0
+
+00008050 <__stm32l4xx_veneer_5>:
+ 8050: 460f mov r7, r1
+ 8052: e8b7 007e ldmia\.w r7!, {r1, r2, r3, r4, r5, r6}
+ 8056: e897 8380 ldmia\.w r7, {r7, r8, r9, pc}
+ 805a: de00 udf #0
+ 805c: f7f0 a000 udf\.w #0
+
+00008060 <__stm32l4xx_veneer_6>:
+ 8060: e8b0 007e ldmia\.w r0!, {r1, r2, r3, r4, r5, r6}
+ 8064: e8b0 0380 ldmia\.w r0!, {r7, r8, r9}
+ 8068: f000 b868 b\.w 813c <__stm32l4xx_veneer_6_r>
+ 806c: f7f0 a000 udf\.w #0
+
+00008070 <__stm32l4xx_veneer_7>:
+ 8070: e8b0 007e ldmia\.w r0!, {r1, r2, r3, r4, r5, r6}
+ 8074: e8b0 8380 ldmia\.w r0!, {r7, r8, r9, pc}
+ 8078: f7f0 a000 udf\.w #0
+ 807c: f7f0 a000 udf\.w #0
+
+00008080 <__stm32l4xx_veneer_8>:
+ 8080: e931 0380 ldmdb r1!, {r7, r8, r9}
+ 8084: e911 007e ldmdb r1, {r1, r2, r3, r4, r5, r6}
+ 8088: f000 b85c b\.w 8144 <__stm32l4xx_veneer_8_r>
+ 808c: f7f0 a000 udf\.w #0
+
+00008090 <__stm32l4xx_veneer_9>:
+ 8090: 4651 mov r1, sl
+ 8092: e931 0380 ldmdb r1!, {r7, r8, r9}
+ 8096: e911 007e ldmdb r1, {r1, r2, r3, r4, r5, r6}
+ 809a: f000 b855 b\.w 8148 <__stm32l4xx_veneer_9_r>
+ 809e: de00 udf #0
+
+000080a0 <__stm32l4xx_veneer_a>:
+ 80a0: 4649 mov r1, r9
+ 80a2: e931 0380 ldmdb r1!, {r7, r8, r9}
+ 80a6: e911 007e ldmdb r1, {r1, r2, r3, r4, r5, r6}
+ 80aa: f000 b84f b\.w 814c <__stm32l4xx_veneer_a_r>
+ 80ae: de00 udf #0
+
+000080b0 <__stm32l4xx_veneer_b>:
+ 80b0: f1a9 0928 sub\.w r9, r9, #40 ; 0x28
+ 80b4: e8b9 007e ldmia\.w r9!, {r1, r2, r3, r4, r5, r6}
+ 80b8: e899 8380 ldmia\.w r9, {r7, r8, r9, pc}
+ 80bc: f7f0 a000 udf\.w #0
+
+000080c0 <__stm32l4xx_veneer_c>:
+ 80c0: f1a1 0728 sub\.w r7, r1, #40 ; 0x28
+ 80c4: e8b7 007e ldmia\.w r7!, {r1, r2, r3, r4, r5, r6}
+ 80c8: e897 8380 ldmia\.w r7, {r7, r8, r9, pc}
+ 80cc: f7f0 a000 udf\.w #0
+
+000080d0 <__stm32l4xx_veneer_d>:
+ 80d0: f1a0 0728 sub\.w r7, r0, #40 ; 0x28
+ 80d4: e8b7 007e ldmia\.w r7!, {r1, r2, r3, r4, r5, r6}
+ 80d8: e897 8380 ldmia\.w r7, {r7, r8, r9, pc}
+ 80dc: f7f0 a000 udf\.w #0
+
+000080e0 <__stm32l4xx_veneer_e>:
+ 80e0: e930 0380 ldmdb r0!, {r7, r8, r9}
+ 80e4: e930 007e ldmdb r0!, {r1, r2, r3, r4, r5, r6}
+ 80e8: f000 b838 b\.w 815c <__stm32l4xx_veneer_e_r>
+ 80ec: f7f0 a000 udf\.w #0
+
+000080f0 <__stm32l4xx_veneer_f>:
+ 80f0: f1a0 0028 sub\.w r0, r0, #40 ; 0x28
+ 80f4: 4607 mov r7, r0
+ 80f6: e8b7 007e ldmia\.w r7!, {r1, r2, r3, r4, r5, r6}
+ 80fa: e897 8380 ldmia\.w r7, {r7, r8, r9, pc}
+ 80fe: de00 udf #0
+
+00008100 <__stm32l4xx_veneer_10>:
+ 8100: e8bd 007f ldmia\.w sp!, {r0, r1, r2, r3, r4, r5, r6}
+ 8104: e8bd 0380 ldmia\.w sp!, {r7, r8, r9}
+ 8108: f000 b82c b\.w 8164 <__stm32l4xx_veneer_10_r>
+ 810c: f7f0 a000 udf\.w #0
+
+00008110 <__stm32l4xx_veneer_11>:
+ 8110: e8bd 007f ldmia\.w sp!, {r0, r1, r2, r3, r4, r5, r6}
+ 8114: e8bd 8380 ldmia\.w sp!, {r7, r8, r9, pc}
+ 8118: f7f0 a000 udf\.w #0
+ 811c: f7f0 a000 udf\.w #0
+
+00008120 <_start>:
+ 8120: f7ff bf6e b\.w 8000 <__stm32l4xx_veneer_0>
+
+00008124 <__stm32l4xx_veneer_0_r>:
+ 8124: f7ff bf74 b\.w 8010 <__stm32l4xx_veneer_1>
+
+00008128 <__stm32l4xx_veneer_1_r>:
+ 8128: f7ff bf7a b\.w 8020 <__stm32l4xx_veneer_2>
+
+0000812c <__stm32l4xx_veneer_2_r>:
+ 812c: f7ff bf80 b\.w 8030 <__stm32l4xx_veneer_3>
+
+00008130 <__stm32l4xx_veneer_3_r>:
+ 8130: f7ff bf86 b\.w 8040 <__stm32l4xx_veneer_4>
+
+00008134 <__stm32l4xx_veneer_4_r>:
+ 8134: f7ff bf8c b\.w 8050 <__stm32l4xx_veneer_5>
+
+00008138 <__stm32l4xx_veneer_5_r>:
+ 8138: f7ff bf92 b\.w 8060 <__stm32l4xx_veneer_6>
+
+0000813c <__stm32l4xx_veneer_6_r>:
+ 813c: f7ff bf98 b\.w 8070 <__stm32l4xx_veneer_7>
+
+00008140 <__stm32l4xx_veneer_7_r>:
+ 8140: f7ff bf9e b\.w 8080 <__stm32l4xx_veneer_8>
+
+00008144 <__stm32l4xx_veneer_8_r>:
+ 8144: f7ff bfa4 b\.w 8090 <__stm32l4xx_veneer_9>
+
+00008148 <__stm32l4xx_veneer_9_r>:
+ 8148: f7ff bfaa b\.w 80a0 <__stm32l4xx_veneer_a>
+
+0000814c <__stm32l4xx_veneer_a_r>:
+ 814c: f7ff bfb0 b\.w 80b0 <__stm32l4xx_veneer_b>
+
+00008150 <__stm32l4xx_veneer_b_r>:
+ 8150: f7ff bfb6 b\.w 80c0 <__stm32l4xx_veneer_c>
+
+00008154 <__stm32l4xx_veneer_c_r>:
+ 8154: f7ff bfbc b\.w 80d0 <__stm32l4xx_veneer_d>
+
+00008158 <__stm32l4xx_veneer_d_r>:
+ 8158: f7ff bfc2 b\.w 80e0 <__stm32l4xx_veneer_e>
+
+0000815c <__stm32l4xx_veneer_e_r>:
+ 815c: f7ff bfc8 b\.w 80f0 <__stm32l4xx_veneer_f>
+
+00008160 <__stm32l4xx_veneer_f_r>:
+ 8160: f7ff bfce b\.w 8100 <__stm32l4xx_veneer_10>
+
+00008164 <__stm32l4xx_veneer_10_r>:
+ 8164: f7ff bfd4 b\.w 8110 <__stm32l4xx_veneer_11>
diff --git a/ld/testsuite/ld-arm/stm32l4xx-fix-ldm.s b/ld/testsuite/ld-arm/stm32l4xx-fix-ldm.s
new file mode 100644
index 0000000..2f36c3e
--- /dev/null
+++ b/ld/testsuite/ld-arm/stm32l4xx-fix-ldm.s
@@ -0,0 +1,147 @@
+ .syntax unified
+ .cpu cortex-m4
+ .fpu fpv4-sp-d16
+ .text
+ .align 1
+ .thumb
+ .thumb_func
+ .global _start
+_start:
+ @ LDM CASE #1 (used when rx is in upper_list)
+ @ ldm rx, {...} ->
+ @ ldm rx!, {lower_list}
+ @ ldm rx, {upper_list}
+ @ b.w
+ ldm.w r9, {r1-r9}
+
+ @ LDM CASE #1 bis (used when rx is in upper_list and pc is
+ @ in reglist)
+ @ ldm rx, {...} ->
+ @ ldm rx!, {lower_list}
+ @ ldm rx, {upper_list}
+ ldm.w r9, {r1-r9, pc}
+
+ @ LDM CASE #2 (used when rx is not in upper_list)
+ @ ldm rx, {...} ->
+ @ mov ry, rx where ry is the lowest register from upper_list
+ @ ldm ry!, {lower_list}
+ @ ldm ry, {upper_list}
+ @ b.w
+ ldm.w r0, {r1-r9}
+
+ @ LDM CASE #2 bis (used when rx is in lower_list)
+ @ ldm rx, {...} ->
+ @ mov ry, rx where ry is the lowest register from upper_list
+ @ ldm ry!, {lower_list}
+ @ ldm ry, {upper_list}
+ @ b.w
+ ldm.w r1, {r1-r9}
+
+ @ LDM CASE #2 ter (used when rx is not in upper_list and pc is
+ @ in reglist)
+ @ ldm rx, {...} ->
+ @ mov ry, rx where ry is the lowest register from upper_list
+ @ ldm ry!, {lower_list}
+ @ ldm ry, {upper_list}
+ ldm.w r0, {r1-r9, pc}
+
+ @ LDM CASE #2 quater (used when rx is in lower_list and pc is
+ @ in reglist)
+ @ ldm rx, {...} ->
+ @ mov ry, rx where ry is the lowest register from upper_list
+ @ ldm ry!, {lower_list}
+ @ ldm ry, {upper_list}
+ ldm.w r1, {r1-r9, pc}
+
+ @ LDM CASE #3 (used when rx is not in upper_list)
+ @ ldm rx, {...} ->
+ @ ldm rx!, {lower_list}
+ @ ldm rx!, {upper_list}
+ @ b.w
+ @ Write-back variant are unpredictable when rx appears also in
+ @ the loaded registers
+ ldm.w r0!, {r1-r9}
+
+ @ LDM CASE #3 bis (used when rx is not in upper_list and pc is
+ @ in reglist)
+ @ ldm rx, {...} ->
+ @ ldm rx!, {lower_list}
+ @ ldm rx!, {upper_list}
+ ldm.w r0!, {r1-r9, pc}
+
+ @ LDM CASE #4 (used when pc is not in reglist and rx is in
+ @ lower_list)
+ @ ldmb rx, {...} ->
+ @ ldmb rx!, {upper_list}
+ @ ldmb rx, {lower_list}
+ ldmdb.w r1, {r1-r9}
+
+ @ LDM CASE #5 (used when pc is not in reglist and rx is not in
+ @ lower_list)
+ @ It looks like it this mean that it could be in upper_list or not
+ @ ldmdb rx, {...} ->
+ @ mov ry, rx where ry is the lowest register from lower_list
+ @ ldmdb ry!, {upper_list}
+ @ ldmdb ry , {lower_list}
+ @ b.w
+ ldmdb.w sl, {r1-r9}
+
+ @ LDM CASE #5 bis (used when pc is not in reglist and rx is in
+ @ upper_list)
+ @ ldmdb rx, {...} ->
+ @ mov ry, rx where ry is the lowest register from lower_list
+ @ ldmdb ry!, {upper_list}
+ @ ldmdb ry , {lower_list}
+ @ b.w
+ ldmdb.w r9, {r1-r9}
+
+ @ LDM CASE #6 (used when pc is in reglist and rx is in
+ @ upper_list)
+ @ ldmdb rx, {...} ->
+ @ sub rx, rx, #size (lower_list + upper_list)
+ @ ldm rx!, {lower_list}
+ @ ldm rx, {upper_list}
+ @ This case reverses the load order
+ ldmdb.w r9, {r1-r9, pc}
+
+ @ LDM CASE #6 bis (used when pc is in reglist and rx is in
+ @ lower_list)
+ @ ldmdb rx, {...} ->
+ @ sub rx, rx, #size (lower_list + upper_list)
+ @ ldm rx!, {lower_list}
+ @ ldm rx, {upper_list}
+ ldmdb.w r1, {r1-r9, pc}
+
+ @ LDM CASE #7 (used when pc is in reglist and rx is not in
+ @ upper_list)
+ @ ldmdb rx, {...} ->
+ @ sub ry, rx, #size (lower_list + upper_list) where ry is the lowest
+ @ register of the upper list
+ @ ldm ry!, {lower_list}
+ @ ldm ry , {upper_list}
+ @ This case reverses the load order
+ ldmdb.w r0, {r1-r9, pc}
+
+ @ LDM CASE #8 (used when pc is in not in reglist)
+ @ ldmdb rx!, {...} ->
+ @ ldm rx!, {upper_list}
+ @ ldm rx!, {lower_list}
+ @ b.w
+ ldmdb.w r0!, {r1-r9}
+
+ @ LDM CASE #9 (Used when pc is in reglist)
+ @ ldmdb rx!, {...} ->
+ @ sub rx, rx, #size (lower_list + upper_list)
+ @ mov ry, rx where ry is the lowest register from upper_list
+ @ ldm ry!, {lower_list}
+ @ ldm ry , {upper_list}
+ ldmdb.w r0!, {r1-r9, pc}
+
+ @ POP CASE #1 (list does not include pc)
+ @ pop {...} -> pop {lower_list} pop {upper_list}
+ @ b.w
+ pop {r0-r9}
+
+ @ POP CASE #2 (list includes PC)
+ @ pop {...} -> pop {lower_list} pop {upper_list}
+ pop {r0-r9, pc}
diff --git a/ld/testsuite/ld-arm/stm32l4xx-fix-vldm.d b/ld/testsuite/ld-arm/stm32l4xx-fix-vldm.d
new file mode 100644
index 0000000..49d7bee
--- /dev/null
+++ b/ld/testsuite/ld-arm/stm32l4xx-fix-vldm.d
@@ -0,0 +1,49 @@
+
+.*: file format elf32-littlearm.*
+
+
+Disassembly of section \.text:
+
+00008000 <__stm32l4xx_veneer_0>:
+ 8000: ecf9 0a08 vldmia r9!, {s1-s8}
+ 8004: ecf9 4a08 vldmia r9!, {s9-s16}
+ 8008: ecf9 8a08 vldmia r9!, {s17-s24}
+ 800c: ecf9 ca07 vldmia r9!, {s25-s31}
+ 8010: f1a9 097c sub\.w r9, r9, #124 ; 0x7c
+ 8014: f000 b826 b\.w 8064 <__stm32l4xx_veneer_0_r>
+
+00008018 <__stm32l4xx_veneer_1>:
+ 8018: ecf6 4a08 vldmia r6!, {s9-s16}
+ 801c: ecf6 8a08 vldmia r6!, {s17-s24}
+ 8020: ecf6 ca05 vldmia r6!, {s25-s29}
+ 8024: f000 b820 b\.w 8068 <__stm32l4xx_veneer_1_r>
+ 8028: f7f0 a000 udf\.w #0
+ 802c: f7f0 a000 udf\.w #0
+
+00008030 <__stm32l4xx_veneer_2>:
+ 8030: ecfd 0a08 vpop {s1-s8}
+ 8034: ecfd 4a01 vpop {s9}
+ 8038: f000 b818 b\.w 806c <__stm32l4xx_veneer_2_r>
+ 803c: f7f0 a000 udf\.w #0
+ 8040: f7f0 a000 udf\.w #0
+ 8044: f7f0 a000 udf\.w #0
+
+00008048 <__stm32l4xx_veneer_3>:
+ 8048: ed7b 0a08 vldmdb fp!, {s1-s8}
+ 804c: ed7b 4a08 vldmdb fp!, {s9-s16}
+ 8050: ed7b 8a08 vldmdb fp!, {s17-s24}
+ 8054: ed7b ca07 vldmdb fp!, {s25-s31}
+ 8058: f000 b80a b\.w 8070 <__stm32l4xx_veneer_3_r>
+ 805c: f7f0 a000 udf\.w #0
+
+00008060 <_start>:
+ 8060: f7ff bfce b\.w 8000 <__stm32l4xx_veneer_0>
+
+00008064 <__stm32l4xx_veneer_0_r>:
+ 8064: f7ff bfd8 b\.w 8018 <__stm32l4xx_veneer_1>
+
+00008068 <__stm32l4xx_veneer_1_r>:
+ 8068: f7ff bfe2 b\.w 8030 <__stm32l4xx_veneer_2>
+
+0000806c <__stm32l4xx_veneer_2_r>:
+ 806c: f7ff bfec b\.w 8048 <__stm32l4xx_veneer_3>
diff --git a/ld/testsuite/ld-arm/stm32l4xx-fix-vldm.s b/ld/testsuite/ld-arm/stm32l4xx-fix-vldm.s
new file mode 100644
index 0000000..94aa66e
--- /dev/null
+++ b/ld/testsuite/ld-arm/stm32l4xx-fix-vldm.s
@@ -0,0 +1,26 @@
+ .syntax unified
+ .cpu cortex-m4
+ .fpu fpv4-sp-d16
+ .text
+ .align 1
+ .thumb
+ .thumb_func
+ .global _start
+_start:
+ @ VLDM CASE #1
+ @ vldm rx, {...}
+ @ -> vldm rx!, {8_words_or_less} for each
+ @ -> sub rx, rx, #size (list)
+ vldm r9, {s1-s31}
+
+ @ VLDM CASE #2
+ @ vldm rx!, {...}
+ @ -> vldm rx!, {8_words_or_less} for each needed 8_word
+ @ This also handles vpop instruction (when rx is sp)
+ vldm r6!, {s9-s29}
+ @ Explicit VPOP test
+ vpop {s1-s9}
+
+ @ vldmd rx!, {...}
+ @ -> vldmb rx!, {8_words_or_less} for each needed 8_word
+ vldmdb r11!, {s1-s31}