summaryrefslogtreecommitdiff
path: root/ld/testsuite/ld-arm/stm32l4xx-fix-ldm.s
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/testsuite/ld-arm/stm32l4xx-fix-ldm.s
parentc6056a744af028824797e769ddb71927740be88a (diff)
downloadbinutils-gdb-a504d23a83d115b1b29a5b1fbfaeb2b09bc0e22c.tar.gz
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/testsuite/ld-arm/stm32l4xx-fix-ldm.s')
-rw-r--r--ld/testsuite/ld-arm/stm32l4xx-fix-ldm.s147
1 files changed, 147 insertions, 0 deletions
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 00000000000..2f36c3e6f36
--- /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}