name can be changed. The only requirement is the %s be present. */
#define STUB_ENTRY_NAME "__%s_veneer"
+/* Stub name for a BTI landing stub. */
+#define BTI_STUB_ENTRY_NAME "__%s_bti_veneer"
+
/* The name of the dynamic interpreter. This is put in the .interp
section. */
#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1"
0x00000000,
};
+static const uint32_t aarch64_bti_direct_branch_stub[] =
+{
+ 0xd503245f, /* bti c */
+ 0x14000000, /* b <label> */
+};
+
static const uint32_t aarch64_erratum_835769_stub[] =
{
0x00000000, /* Placeholder for multiply accumulate. */
aarch64_stub_none,
aarch64_stub_adrp_branch,
aarch64_stub_long_branch,
+ aarch64_stub_bti_direct_branch,
aarch64_stub_erratum_835769_veneer,
aarch64_stub_erratum_843419_veneer,
};
/* Destination symbol type */
unsigned char st_type;
+ /* The target is also a stub. */
+ bool double_stub;
+
/* Where this stub is being called from, or, in the case of combined
stub sections, the first input section in the group. */
asection *id_sec;
unsigned int top_index;
asection **input_list;
+ /* True when two stubs are added where one targets the other, happens
+ when BTI stubs are inserted and then the stub layout must not change
+ during elfNN_aarch64_build_stubs. */
+ bool has_double_stub;
+
/* JUMP_SLOT relocs for variant PCS symbols may be present. */
int variant_pcs;
howto, value) == bfd_reloc_ok;
}
-static enum elf_aarch64_stub_type
-aarch64_select_branch_stub (bfd_vma value, bfd_vma place)
-{
- if (aarch64_valid_for_adrp_p (value, place))
- return aarch64_stub_adrp_branch;
- return aarch64_stub_long_branch;
-}
-
/* Determine the type of stub needed, if any, for a call. */
static enum elf_aarch64_stub_type
bfd_vma veneer_entry_loc;
bfd_signed_vma branch_offset = 0;
unsigned int template_size;
+ unsigned int pad_size = 0;
const uint32_t *template;
unsigned int i;
struct bfd_link_info *info;
+ struct elf_aarch64_link_hash_table *htab;
/* Massage our args to the form they really have. */
stub_entry = (struct elf_aarch64_stub_hash_entry *) gen_entry;
info = (struct bfd_link_info *) in_arg;
+ htab = elf_aarch64_hash_table (info);
/* Fail if the target section could not be assigned to an output
section. The user should fix his linker script. */
stub_sec = stub_entry->stub_sec;
+ /* The layout must not change when a stub may be the target of another. */
+ if (htab->has_double_stub)
+ BFD_ASSERT (stub_entry->stub_offset == stub_sec->size);
+
/* Make a note of the offset within the stubs for this entry. */
stub_entry->stub_offset = stub_sec->size;
loc = stub_sec->contents + stub_entry->stub_offset;
/* See if we can relax the stub. */
if (aarch64_valid_for_adrp_p (sym_value, place))
- stub_entry->stub_type = aarch64_select_branch_stub (sym_value, place);
+ {
+ stub_entry->stub_type = aarch64_stub_adrp_branch;
+
+ /* Avoid the relaxation changing the layout. */
+ if (htab->has_double_stub)
+ pad_size = sizeof (aarch64_long_branch_stub)
+ - sizeof (aarch64_adrp_branch_stub);
+ }
}
switch (stub_entry->stub_type)
template = aarch64_long_branch_stub;
template_size = sizeof (aarch64_long_branch_stub);
break;
+ case aarch64_stub_bti_direct_branch:
+ template = aarch64_bti_direct_branch_stub;
+ template_size = sizeof (aarch64_bti_direct_branch_stub);
+ break;
case aarch64_stub_erratum_835769_veneer:
template = aarch64_erratum_835769_stub;
template_size = sizeof (aarch64_erratum_835769_stub);
loc += 4;
}
+ template_size += pad_size;
template_size = (template_size + 7) & ~7;
stub_sec->size += template_size;
BFD_FAIL ();
break;
+ case aarch64_stub_bti_direct_branch:
+ if (!aarch64_relocate (AARCH64_R (JUMP26), stub_bfd, stub_sec,
+ stub_entry->stub_offset + 4, sym_value))
+ BFD_FAIL ();
+ break;
+
case aarch64_stub_erratum_835769_veneer:
veneered_insn_loc = stub_entry->target_section->output_section->vma
+ stub_entry->target_section->output_offset
}
/* As above, but don't actually build the stub. Just bump offset so
- we know stub section sizes. */
+ we know stub section sizes and record the offset for each stub so
+ a stub can target another stub (needed for BTI direct branch stub). */
static bool
aarch64_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
case aarch64_stub_long_branch:
size = sizeof (aarch64_long_branch_stub);
break;
+ case aarch64_stub_bti_direct_branch:
+ size = sizeof (aarch64_bti_direct_branch_stub);
+ break;
case aarch64_stub_erratum_835769_veneer:
size = sizeof (aarch64_erratum_835769_stub);
break;
}
size = (size + 7) & ~7;
+ stub_entry->stub_offset = stub_entry->stub_sec->size;
stub_entry->stub_sec->size += size;
return true;
}
+/* Output is BTI compatible. */
+
+static bool
+elf_aarch64_bti_p (bfd *output_bfd)
+{
+ uint32_t prop = elf_aarch64_tdata (output_bfd)->gnu_and_prop;
+ return prop & GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
+}
+
/* External entry points for sizing and building linker stubs. */
/* Set up various things so that we can make a list of input sections
#undef PREV_SEC
#undef PREV_SEC
+/* True if the inserted stub does not break BTI compatibility. */
+
+static bool
+aarch64_bti_stub_p (struct elf_aarch64_stub_hash_entry *stub_entry)
+{
+ /* Stubs without indirect branch are BTI compatible. */
+ return stub_entry->stub_type != aarch64_stub_adrp_branch
+ && stub_entry->stub_type != aarch64_stub_long_branch;
+}
+
#define AARCH64_BITS(x, pos, n) (((x) >> (pos)) & ((1 << (n)) - 1))
#define AARCH64_RT(insn) AARCH64_BITS (insn, 0, 5)
/* Ignore non-stub sections. */
if (!strstr (section->name, STUB_SUFFIX))
continue;
- section->size = 0;
+
+ /* Add space for a branch. Add 8 bytes to keep section 8 byte aligned,
+ as long branch stubs contain a 64-bit address. */
+ section->size = 8;
}
bfd_hash_traverse (&htab->stub_hash_table, aarch64_size_one_stub, htab);
if (!strstr (section->name, STUB_SUFFIX))
continue;
- /* Add space for a branch. Add 8 bytes to keep section 8 byte aligned,
- as long branch stubs contain a 64-bit address. */
- if (section->size)
- section->size += 8;
+ /* Empty stub section. */
+ if (section->size == 8)
+ section->size = 0;
/* Ensure all stub sections have a size which is a multiple of
4096. This is important in order to ensure that the insertion
struct bfd_link_info *info)
{
struct elf_aarch64_link_hash_table *htab = elf_aarch64_hash_table (info);
+ bool need_bti = elf_aarch64_bti_p (output_bfd);
bfd *input_bfd;
for (input_bfd = info->input_bfds; input_bfd != NULL;
unsigned int r_type, r_indx;
enum elf_aarch64_stub_type stub_type;
struct elf_aarch64_stub_hash_entry *stub_entry;
+ struct elf_aarch64_stub_hash_entry *stub_entry_bti;
asection *sym_sec;
bfd_vma sym_value;
bfd_vma destination;
struct elf_aarch64_link_hash_entry *hash;
const char *sym_name;
char *stub_name;
+ char *stub_name_bti;
const asection *id_sec;
+ const asection *id_sec_bti;
unsigned char st_type;
bfd_size_type len;
/* Always update this stub's target since it may have
changed after layout. */
stub_entry->target_value = sym_value + irela->r_addend;
+
+ if (stub_entry->double_stub)
+ {
+ /* Update the target of both stubs. */
+
+ id_sec_bti = htab->stub_group[sym_sec->id].link_sec;
+ stub_name_bti =
+ elfNN_aarch64_stub_name (id_sec_bti, sym_sec, hash,
+ irela);
+ if (!stub_name_bti)
+ goto error_ret_free_internal;
+ stub_entry_bti =
+ aarch64_stub_hash_lookup (&htab->stub_hash_table,
+ stub_name_bti, false, false);
+ BFD_ASSERT (stub_entry_bti != NULL);
+ free (stub_name_bti);
+ stub_entry_bti->target_value = stub_entry->target_value;
+ stub_entry->target_value = stub_entry_bti->stub_offset;
+ }
continue;
}
snprintf (stub_entry->output_name, len, STUB_ENTRY_NAME,
sym_name);
+ /* A stub with indirect jump may break BTI compatibility, so
+ insert another stub with direct jump near the target then. */
+ if (need_bti && !aarch64_bti_stub_p (stub_entry))
+ {
+ stub_entry->double_stub = true;
+ htab->has_double_stub = true;
+ id_sec_bti = htab->stub_group[sym_sec->id].link_sec;
+ stub_name_bti =
+ elfNN_aarch64_stub_name (id_sec_bti, sym_sec, hash, irela);
+ if (!stub_name_bti)
+ {
+ free (stub_name);
+ goto error_ret_free_internal;
+ }
+
+ stub_entry_bti =
+ aarch64_stub_hash_lookup (&htab->stub_hash_table,
+ stub_name_bti, false, false);
+ if (stub_entry_bti == NULL)
+ stub_entry_bti =
+ _bfd_aarch64_add_stub_entry_in_group (stub_name_bti,
+ sym_sec, htab);
+ if (stub_entry_bti == NULL)
+ {
+ free (stub_name);
+ free (stub_name_bti);
+ goto error_ret_free_internal;
+ }
+
+ stub_entry_bti->target_value = sym_value + irela->r_addend;
+ stub_entry_bti->target_section = sym_sec;
+ stub_entry_bti->stub_type = aarch64_stub_bti_direct_branch;
+ stub_entry_bti->h = hash;
+ stub_entry_bti->st_type = st_type;
+
+ len = sizeof (BTI_STUB_ENTRY_NAME) + strlen (sym_name);
+ stub_entry_bti->output_name = bfd_alloc (htab->stub_bfd, len);
+ if (stub_entry_bti->output_name == NULL)
+ {
+ free (stub_name);
+ free (stub_name_bti);
+ goto error_ret_free_internal;
+ }
+ snprintf (stub_entry_bti->output_name, len,
+ BTI_STUB_ENTRY_NAME, sym_name);
+
+ /* Update the indirect call stub to target the BTI stub. */
+ stub_entry->target_value = 0;
+ stub_entry->target_section = stub_entry_bti->stub_sec;
+ stub_entry->stub_type = stub_type;
+ stub_entry->h = NULL;
+ stub_entry->st_type = STT_FUNC;
+ }
+
*stub_changed = true;
}
if (!elfNN_aarch64_output_map_sym (osi, AARCH64_MAP_DATA, addr + 16))
return false;
break;
+ case aarch64_stub_bti_direct_branch:
+ if (!elfNN_aarch64_output_stub_sym (osi, stub_name, addr,
+ sizeof (aarch64_bti_direct_branch_stub)))
+ return false;
+ if (!elfNN_aarch64_output_map_sym (osi, AARCH64_MAP_INSN, addr))
+ return false;
+ break;
case aarch64_stub_erratum_835769_veneer:
if (!elfNN_aarch64_output_stub_sym (osi, stub_name, addr,
sizeof (aarch64_erratum_835769_stub)))
--- /dev/null
+#name: Check linker stubs with indirect calls handle BTI (shared lib).
+#source: bti-far.s
+#target: [check_shared_lib_support]
+#as: -mabi=lp64
+#ld: -shared -T bti-far.ld
+#objdump: -dr
+
+[^:]*: *file format elf64-.*aarch64
+
+
+Disassembly of section \.plt:
+
+0000000000018000 <\.plt>:
+ 18000: d503245f bti c
+ 18004: a9bf7bf0 stp x16, x30, \[sp, #-16\]!
+ 18008: 900000d0 adrp x16, 30000 <_GLOBAL_OFFSET_TABLE_>
+ 1800c: f9400e11 ldr x17, \[x16, #24\]
+ 18010: 91006210 add x16, x16, #0x18
+ 18014: d61f0220 br x17
+ 18018: d503201f nop
+ 1801c: d503201f nop
+
+0000000000018020 <foo@plt>:
+ 18020: 900000d0 adrp x16, 30000 <_GLOBAL_OFFSET_TABLE_>
+ 18024: f9401211 ldr x17, \[x16, #32\]
+ 18028: 91008210 add x16, x16, #0x20
+ 1802c: d61f0220 br x17
+ 18030: 14000004 b 18040 <__foo_bti_veneer\+0x8>
+ 18034: d503201f nop
+
+0000000000018038 <__foo_bti_veneer>:
+ 18038: d503245f bti c
+ 1803c: 17fffff9 b 18020 <foo@plt>
+
+Disassembly of section \.text:
+
+0000000000020000 <_start>:
+ 20000: 97ffe008 bl 18020 <foo@plt>
+ 20004: 94000007 bl 20020 <___veneer>
+ 20008: 94000001 bl 2000c <baz>
+
+000000000002000c <baz>:
+ 2000c: d65f03c0 ret
+ 20010: 1400000a b 20038 <___veneer\+0x18>
+ 20014: d503201f nop
+
+0000000000020018 <___bti_veneer>:
+ 20018: d503245f bti c
+ 2001c: 17fffffc b 2000c <baz>
+
+0000000000020020 <___veneer>:
+ 20020: 90091910 adrp x16, 12340000 <foo>
+ 20024: 91012210 add x16, x16, #0x48
+ 20028: d61f0200 br x16
+ \.\.\.
+
+Disassembly of section \.far:
+
+0000000012340000 <foo>:
+ 12340000: 9400000c bl 12340030 <___veneer>
+
+0000000012340004 <bar>:
+ 12340004: 9400000b bl 12340030 <___veneer>
+ 12340008: 94000004 bl 12340018 <__foo_veneer>
+ 1234000c: 00000000 udf #0
+ 12340010: 14000010 b 12340050 <___bti_veneer\+0x8>
+ 12340014: d503201f nop
+
+0000000012340018 <__foo_veneer>:
+ 12340018: 90f6e6d0 adrp x16, 18000 <\.plt>
+ 1234001c: 9100e210 add x16, x16, #0x38
+ 12340020: d61f0200 br x16
+ \.\.\.
+
+0000000012340030 <___veneer>:
+ 12340030: 90f6e710 adrp x16, 20000 <_start>
+ 12340034: 91006210 add x16, x16, #0x18
+ 12340038: d61f0200 br x16
+ \.\.\.
+
+0000000012340048 <___bti_veneer>:
+ 12340048: d503245f bti c
+ 1234004c: 17ffffee b 12340004 <bar>