static bfd_boolean
_bfd_aarch64_adrp_p (uint32_t insn)
{
- return ((insn & 0x9f000000) == 0x90000000);
+ return ((insn & AARCH64_ADRP_OP_MASK) == AARCH64_ADRP_OP);
}
+ stub_entry->adrp_offset);
insn = bfd_getl32 (contents + stub_entry->adrp_offset);
- if ((insn & AARCH64_ADRP_OP_MASK) != AARCH64_ADRP_OP)
+ if (!_bfd_aarch64_adrp_p (insn))
abort ();
bfd_signed_vma imm =
# define movz_hw_R0 (0x52c00000)
#endif
+/* Structure to hold payload for _bfd_aarch64_erratum_843419_clear_stub,
+ it is used to identify the stub information to reset. */
+
+struct erratum_843419_branch_to_stub_clear_data
+{
+ bfd_vma adrp_offset;
+ asection *output_section;
+};
+
+/* Clear the erratum information for GEN_ENTRY if the ADRP_OFFSET and
+ section inside IN_ARG matches. The clearing is done by setting the
+ stub_type to none. */
+
+static bfd_boolean
+_bfd_aarch64_erratum_843419_clear_stub (struct bfd_hash_entry *gen_entry,
+ void *in_arg)
+{
+ struct elf_aarch64_stub_hash_entry *stub_entry
+ = (struct elf_aarch64_stub_hash_entry *) gen_entry;
+ struct erratum_843419_branch_to_stub_clear_data *data
+ = (struct erratum_843419_branch_to_stub_clear_data *) in_arg;
+
+ if (stub_entry->target_section != data->output_section
+ || stub_entry->stub_type != aarch64_stub_erratum_843419_veneer
+ || stub_entry->adrp_offset != data->adrp_offset)
+ return TRUE;
+
+ /* Change the stub type instead of removing the entry, removing from the hash
+ table would be slower and we have already reserved the memory for the entry
+ so there wouldn't be much gain. Changing the stub also keeps around a
+ record of what was there before. */
+ stub_entry->stub_type = aarch64_stub_none;
+
+ /* We're done and there could have been only one matching stub at that
+ particular offset, so abort further traversal. */
+ return FALSE;
+}
+
+/* TLS Relaxations may relax an adrp sequence that matches the erratum 843419
+ sequence. In this case the erratum no longer applies and we need to remove
+ the entry from the pending stub generation. This clears matching adrp insn
+ at ADRP_OFFSET in INPUT_SECTION in the stub table defined in GLOBALS. */
+
+static void
+clear_erratum_843419_entry (struct elf_aarch64_link_hash_table *globals,
+ bfd_vma adrp_offset, asection *input_section)
+{
+ if (globals->fix_erratum_843419)
+ {
+ struct erratum_843419_branch_to_stub_clear_data data;
+ data.adrp_offset = adrp_offset;
+ data.output_section = input_section;
+
+ bfd_hash_traverse (&globals->stub_hash_table,
+ _bfd_aarch64_erratum_843419_clear_stub, &data);
+ }
+}
+
/* Handle TLS relaxations. Relaxing is possible for symbols that use
R_AARCH64_TLSDESC_ADR_{PAGE, LD64_LO12_NC, ADD_LO12_NC} during a static
link.
static bfd_reloc_status_type
elfNN_aarch64_tls_relax (struct elf_aarch64_link_hash_table *globals,
- bfd *input_bfd, bfd_byte *contents,
- Elf_Internal_Rela *rel, struct elf_link_hash_entry *h)
+ bfd *input_bfd, asection *input_section,
+ bfd_byte *contents, Elf_Internal_Rela *rel,
+ struct elf_link_hash_entry *h)
{
bfd_boolean is_local = h == NULL;
unsigned int r_type = ELFNN_R_TYPE (rel->r_info);
Where R is x for LP64, and w for ILP32. */
bfd_putl32 (movz_R0, contents + rel->r_offset);
+ /* We have relaxed the adrp into a mov, we may have to clear any
+ pending erratum fixes. */
+ clear_erratum_843419_entry (globals, rel->r_offset, input_section);
return bfd_reloc_continue;
}
else
{
insn = bfd_getl32 (contents + rel->r_offset);
bfd_putl32 (movz_R0 | (insn & 0x1f), contents + rel->r_offset);
+ /* We have relaxed the adrp into a mov, we may have to clear any
+ pending erratum fixes. */
+ clear_erratum_843419_entry (globals, rel->r_offset, input_section);
}
return bfd_reloc_continue;
howto = elfNN_aarch64_howto_from_bfd_reloc (bfd_r_type);
BFD_ASSERT (howto != NULL);
r_type = howto->type;
- r = elfNN_aarch64_tls_relax (globals, input_bfd, contents, rel, h);
+ r = elfNN_aarch64_tls_relax (globals, input_bfd, input_section,
+ contents, rel, h);
unresolved_reloc = 0;
}
else
if (!elfNN_aarch64_output_map_sym (osi, AARCH64_MAP_INSN, addr))
return FALSE;
break;
+ case aarch64_stub_none:
+ break;
default:
abort ();
--- /dev/null
+#source: erratum843419_tls_ie.s
+#as:
+#ld: --fix-cortex-a53-843419 -e0 --section-start .e843419=0x20000000 -Ttext=0x400000 -Tdata=0x40000000
+#objdump: -dr
+#...
+
+Disassembly of section .e843419:
+
+0*20000000 <farbranch>:
+[ ]*20000000: d10043ff sub sp, sp, #0x10
+[ ]*20000004: d28001a7 mov x7, #0xd // #13
+[ ]*20000008: b9000fe7 str w7, \[sp, #12\]
+[ ]*2000000c: 140003fb b 20000ff8 <e843419>
+ ...
+
+0*20000ff8 <e843419>:
+[ ]*20000ff8: d2a00000 movz x0, #0x0, lsl #16
+[ ]*20000ffc: f800c007 stur x7, \[x0, #12\]
+[ ]*20001000: d2800128 mov x8, #0x9 // #9
+[ ]*20001004: f2800208 movk x8, #0x10
+[ ]*20001008: 8b050020 add x0, x1, x5
+[ ]*2000100c: b9400fe7 ldr w7, \[sp, #12\]
+[ ]*20001010: 0b0700e0 add w0, w7, w7
+[ ]*20001014: 910043ff add sp, sp, #0x10
+[ ]*20001018: d65f03c0 ret
+[ ]*2000101c: 00000000 .inst 0x00000000 ; undefined
+[ ]*20001020: 14000400 b 20002020 <e843419\+0x1028>
+[ ]*20001024: d503201f nop
+[ ]*20001028: 00000000 .inst 0x00000000 ; undefined
+[ ]*2000102c: 17fffff7 b 20001008 <e843419\+0x10>
+ ...
+
+Disassembly of section .text:
+
+0*400000 <main>:
+[ ]*400000: d10043ff sub sp, sp, #0x10
+[ ]*400004: d28001a7 mov x7, #0xd // #13
+[ ]*400008: b9000fe7 str w7, \[sp, #12\]
+[ ]*40000c: 14000005 b 400020 <__farbranch_veneer>
+[ ]*400010: d65f03c0 ret
+[ ]*400014: d503201f nop
+[ ]*400018: 14000400 b 401018 <__farbranch_veneer\+0xff8>
+[ ]*40001c: d503201f nop
+
+0*400020 <__farbranch_veneer>:
+[ ]*400020: 900fe010 adrp x16, 20000000 <farbranch>
+[ ]*400024: 91000210 add x16, x16, #0x0
+[ ]*400028: d61f0200 br x16
+ ...