/* All GNU_PROPERTY_AARCH64_FEATURE_1_AND properties. */
uint32_t gnu_and_prop;
- /* Zero to warn when linking objects with incompatible
- GNU_PROPERTY_AARCH64_FEATURE_1_BTI. */
- int no_bti_warn;
-
- /* PLT type based on security. */
- aarch64_plt_type plt_type;
+ /* Software protections options. */
+ struct aarch64_protection_opts sw_protections;
};
#define elf_aarch64_tdata(bfd) \
int fix_erratum_835769,
erratum_84319_opts fix_erratum_843419,
int no_apply_dynamic_relocs,
- aarch64_bti_pac_info bp_info)
+ const aarch64_protection_opts *sw_protections)
{
struct elf_aarch64_link_hash_table *globals;
elf_aarch64_tdata (output_bfd)->no_enum_size_warning = no_enum_warn;
elf_aarch64_tdata (output_bfd)->no_wchar_size_warning = no_wchar_warn;
- switch (bp_info.bti_type)
- {
- case BTI_WARN:
- elf_aarch64_tdata (output_bfd)->no_bti_warn = 0;
- elf_aarch64_tdata (output_bfd)->gnu_and_prop
- |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
- break;
+ /* Note: gnu_property_aarch64_feature_1_and was initialized to 0 by
+ bfd_zalloc(). */
+ if (sw_protections->plt_type & PLT_BTI)
+ elf_aarch64_tdata (output_bfd)->gnu_and_prop
+ |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
- default:
- break;
- }
- elf_aarch64_tdata (output_bfd)->plt_type = bp_info.plt_type;
- setup_plt_values (link_info, bp_info.plt_type);
+ elf_aarch64_tdata (output_bfd)->sw_protections = *sw_protections;
+
+ setup_plt_values (link_info, sw_protections->plt_type);
}
static bfd_vma
&& !add_dynamic_entry (DT_AARCH64_VARIANT_PCS, 0))
return false;
- if ((elf_aarch64_tdata (output_bfd)->plt_type == PLT_BTI_PAC)
+ aarch64_plt_type plt_type
+ = elf_aarch64_tdata (output_bfd)->sw_protections.plt_type;
+ if ((plt_type == PLT_BTI_PAC)
&& (!add_dynamic_entry (DT_AARCH64_BTI_PLT, 0)
|| !add_dynamic_entry (DT_AARCH64_PAC_PLT, 0)))
return false;
- else if ((elf_aarch64_tdata (output_bfd)->plt_type == PLT_BTI)
+ else if ((plt_type == PLT_BTI)
&& !add_dynamic_entry (DT_AARCH64_BTI_PLT, 0))
return false;
- else if ((elf_aarch64_tdata (output_bfd)->plt_type == PLT_PAC)
+ else if ((plt_type == PLT_PAC)
&& !add_dynamic_entry (DT_AARCH64_PAC_PLT, 0))
return false;
}
/* First instruction in BTI enabled PLT stub is a BTI
instruction so skip it. */
- if (elf_aarch64_tdata (output_bfd)->plt_type & PLT_BTI
+ if (elf_aarch64_tdata (output_bfd)->sw_protections.plt_type & PLT_BTI
&& elf_elfheader (output_bfd)->e_type == ET_EXEC)
plt_entry = plt_entry + 4;
/* First instruction in BTI enabled PLT stub is a BTI
instruction so skip it. */
bfd_byte *plt0_entry = htab->root.splt->contents;
- if (elf_aarch64_tdata (output_bfd)->plt_type & PLT_BTI)
+ if (elf_aarch64_tdata (output_bfd)->sw_protections.plt_type & PLT_BTI)
plt0_entry = plt0_entry + 4;
/* Fill in the top 21 bits for this: ADRP x16, PLT_GOT + n * 8.
const bfd_byte *entry = elfNN_aarch64_tlsdesc_small_plt_entry;
htab->tlsdesc_plt_entry_size = PLT_TLSDESC_ENTRY_SIZE;
- aarch64_plt_type type = elf_aarch64_tdata (output_bfd)->plt_type;
+ aarch64_plt_type type
+ = elf_aarch64_tdata (output_bfd)->sw_protections.plt_type;
if (type == PLT_BTI || type == PLT_BTI_PAC)
{
entry = elfNN_aarch64_tlsdesc_small_plt_bti_entry;
asymbol **dynsyms,
asymbol **ret)
{
- elf_aarch64_tdata (abfd)->plt_type = get_plt_type (abfd);
+ elf_aarch64_tdata (abfd)->sw_protections.plt_type = get_plt_type (abfd);
return _bfd_elf_get_synthetic_symtab (abfd, symcount, syms,
dynsymcount, dynsyms, ret);
}
size_t plt0_size = PLT_ENTRY_SIZE;
size_t pltn_size = PLT_SMALL_ENTRY_SIZE;
- if (elf_aarch64_tdata (plt->owner)->plt_type == PLT_BTI_PAC)
+ aarch64_plt_type plt_type
+ = elf_aarch64_tdata (plt->owner)->sw_protections.plt_type;
+ if (plt_type == PLT_BTI_PAC)
{
if (elf_elfheader (plt->owner)->e_type == ET_EXEC)
pltn_size = PLT_BTI_PAC_SMALL_ENTRY_SIZE;
else
pltn_size = PLT_PAC_SMALL_ENTRY_SIZE;
}
- else if (elf_aarch64_tdata (plt->owner)->plt_type == PLT_BTI)
+ else if (plt_type == PLT_BTI)
{
if (elf_elfheader (plt->owner)->e_type == ET_EXEC)
pltn_size = PLT_BTI_SMALL_ENTRY_SIZE;
}
- else if (elf_aarch64_tdata (plt->owner)->plt_type == PLT_PAC)
+ else if (plt_type == PLT_PAC)
{
pltn_size = PLT_PAC_SMALL_ENTRY_SIZE;
}
static bfd *
elfNN_aarch64_link_setup_gnu_properties (struct bfd_link_info *info)
{
- uint32_t prop = elf_aarch64_tdata (info->output_bfd)->gnu_and_prop;
+ struct elf_aarch64_obj_tdata * tdata = elf_aarch64_tdata (info->output_bfd);
+ uint32_t prop = tdata->gnu_and_prop;
bfd *pbfd = _bfd_aarch64_elf_link_setup_gnu_properties (info, &prop);
- elf_aarch64_tdata (info->output_bfd)->gnu_and_prop = prop;
- elf_aarch64_tdata (info->output_bfd)->plt_type
+ tdata->gnu_and_prop = prop;
+ tdata->sw_protections.plt_type
|= (prop & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) ? PLT_BTI : 0;
- setup_plt_values (info, elf_aarch64_tdata (info->output_bfd)->plt_type);
+ setup_plt_values (info, tdata->sw_protections.plt_type);
return pbfd;
}
uint32_t prop
= elf_aarch64_tdata (info->output_bfd)->gnu_and_prop;
- /* If output has been marked with BTI using command line argument, give out
- warning if necessary. */
/* Properties are merged per type, hence only check for warnings when merging
GNU_PROPERTY_AARCH64_FEATURE_1_AND. */
- if (((aprop && aprop->pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND)
- || (bprop && bprop->pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND))
- && (prop & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)
- && (!elf_aarch64_tdata (info->output_bfd)->no_bti_warn))
+ if ((aprop && aprop->pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND)
+ || (bprop && bprop->pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND))
{
- if ((aprop && !(aprop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_BTI))
- || !aprop)
- {
- _bfd_error_handler (_("%pB: warning: BTI turned on by -z force-bti when "
- "all inputs do not have BTI in NOTE section."),
- abfd);
- }
- if ((bprop && !(bprop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_BTI))
- || !bprop)
+ const aarch64_protection_opts *sw_protections
+ = &elf_aarch64_tdata (info->output_bfd)->sw_protections;
+ aarch64_bti_report bti_report = sw_protections->bti_report;
+
+ /* If output has been marked with BTI using command line argument, give
+ out warning if necessary. */
+ if ((prop & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)
+ && (bti_report != BTI_NONE))
{
- _bfd_error_handler (_("%pB: warning: BTI turned on by -z force-bti when "
- "all inputs do not have BTI in NOTE section."),
- bbfd);
+ if ((aprop && !(aprop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_BTI))
+ || !aprop)
+ _bfd_aarch64_elf_check_bti_report (bti_report, abfd);
+ if ((bprop && !(bprop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_BTI))
+ || !bprop)
+ _bfd_aarch64_elf_check_bti_report (bti_report, bbfd);
}
}
return property_corrupt;
}
prop = _bfd_elf_get_property (abfd, type, datasz);
- /* Combine properties of the same type. */
+ /* Merge AArch64 feature properties together if they are declared in
+ different AARCH64_FEATURE_1_AND properties. */
prop->u.number |= bfd_h_get_32 (abfd, ptr);
prop->pr_kind = property_number;
break;
}
}
}
+
+/* Check AArch64 BTI report. */
+void
+_bfd_aarch64_elf_check_bti_report (aarch64_bti_report bti_report, bfd *ebfd)
+{
+ if (bti_report == BTI_NONE)
+ return;
+
+ const char *log_level = (bti_report == BTI_WARN ? "warning" : "error");
+
+ const char *msg = _("%pB: %s: BTI turned on by -z force-bti on the output "
+ "when all inputs do not have BTI in NOTE section.");
+
+ _bfd_error_handler (msg, ebfd, log_level);
+}
\ No newline at end of file
typedef enum
{
PLT_NORMAL = 0x0, /* Normal plts. */
- PLT_BTI = 0x1, /* plts with bti. */
+ PLT_BTI = 0x1, /* plts with BTI. */
PLT_PAC = 0x2, /* plts with pointer authentication. */
PLT_BTI_PAC = PLT_BTI | PLT_PAC
} aarch64_plt_type;
-/* To indicate if BTI is enabled with/without warning. */
+/* Indicates whether the linker should generate warnings/errors when input
+ objects are missing BTI markings and the output has BTI markings. */
typedef enum
{
- BTI_NONE = 0, /* BTI is not enabled. */
- BTI_WARN = 1, /* BTI is enabled with -z force-bti. */
-} aarch64_enable_bti_type;
-
-/* A structure to encompass all information coming from BTI or PAC
- related command line options. This involves the "PLT_TYPE" to determine
- which version of PLTs to pick and "BTI_TYPE" to determine if
- BTI should be turned on with any warnings. */
-typedef struct
+ BTI_NONE = 0, /* Does not emit any warning/error messages. */
+ BTI_WARN = 1, /* Emit warning when the input objects are missing BTI
+ markings and output have BTI marking. */
+ BTI_ERROR = 2, /* Emit error when the input objects are missing BTI
+ markings and output have BTI marking. */
+} aarch64_bti_report;
+
+/* A structure to encompass all information about software protections coming
+ from BTI or PAC related command line options. */
+struct aarch64_protection_opts
{
+ /* PLT type to use depending on the selected software proctections. */
aarch64_plt_type plt_type;
- aarch64_enable_bti_type bti_type;
-} aarch64_bti_pac_info;
+
+ /* Report level for BTI issues. */
+ aarch64_bti_report bti_report;
+};
+typedef struct aarch64_protection_opts aarch64_protection_opts;
/* An enum to define what kind of erratum fixes we should apply. This gives the
user a bit more control over the sequences we generate. */
extern void bfd_elf64_aarch64_set_options
(bfd *, struct bfd_link_info *, int, int, int, int, erratum_84319_opts, int,
- aarch64_bti_pac_info);
+ const aarch64_protection_opts *);
extern void bfd_elf32_aarch64_set_options
(bfd *, struct bfd_link_info *, int, int, int, int, erratum_84319_opts, int,
- aarch64_bti_pac_info);
+ const aarch64_protection_opts *);
/* AArch64 stub generation support for ELF64. Called from the linker. */
extern int elf64_aarch64_setup_section_lists
elf_property *, elf_property *,
uint32_t);
+extern void
+_bfd_aarch64_elf_check_bti_report (aarch64_bti_report, bfd *);
+
extern void
_bfd_aarch64_elf_link_fixup_gnu_properties (struct bfd_link_info *,
elf_property_list **);
static int fix_erratum_835769 = 0;
static erratum_84319_opts fix_erratum_843419 = ERRAT_NONE;
static int no_apply_dynamic_relocs = 0;
-static aarch64_plt_type plt_type = PLT_NORMAL;
-static aarch64_enable_bti_type bti_type = BTI_NONE;
+static aarch64_protection_opts sw_protections = {
+ .plt_type = PLT_NORMAL,
+ .bti_report = BTI_WARN,
+};
+
+#define COMPILE_TIME_STRLEN(s) \
+ (sizeof(s) - 1)
static void
gld${EMULATION_NAME}_before_parse (void)
return;
}
- aarch64_bti_pac_info bp_info;
- bp_info.plt_type = plt_type;
- bp_info.bti_type = bti_type;
-
bfd_elf${ELFSIZE}_aarch64_set_options (link_info.output_bfd, &link_info,
no_enum_size_warning,
no_wchar_size_warning,
pic_veneer,
fix_erratum_835769, fix_erratum_843419,
no_apply_dynamic_relocs,
- bp_info);
+ &sw_protections);
stub_file = lang_add_input_file ("linker stubs",
lang_input_file_is_fake_enum,
ldlang_add_file (stub_file);
}
+static bool
+aarch64_parse_bti_report_option (const char *optarg)
+{
+ #define BTI_REPORT "bti-report"
+ #define BTI_REPORT_LEN COMPILE_TIME_STRLEN (BTI_REPORT)
+
+ if (strncmp (optarg, BTI_REPORT, BTI_REPORT_LEN) != 0)
+ return false;
+
+ if (strlen (optarg) == BTI_REPORT_LEN
+ || strcmp (optarg + BTI_REPORT_LEN, "=warning") == 0)
+ sw_protections.bti_report = BTI_WARN;
+ else if (strcmp (optarg + BTI_REPORT_LEN, "=none") == 0)
+ sw_protections.bti_report = BTI_NONE;
+ else if (strcmp (optarg + BTI_REPORT_LEN, "=error") == 0)
+ sw_protections.bti_report = BTI_ERROR;
+ else
+ einfo (_("%X%P: error: unrecognized value '-z %s'\n"), optarg);
+
+ return true;
+
+ #undef BTI_REPORT
+ #undef BTI_REPORT_LEN
+}
EOF
# Define some shell vars to insert bits of code into the standard elf
instruction into an ADR. As such the workaround will always use a\n\
veneer and this will give you both a performance and size overhead.\n"));
fprintf (file, _(" --no-apply-dynamic-relocs Do not apply link-time values for dynamic relocations\n"));
- fprintf (file, _(" -z force-bti Turn on Branch Target Identification mechanism and generate PLTs with BTI. Generate warnings for missing BTI on inputs\n"));
- fprintf (file, _(" -z pac-plt Protect PLTs with Pointer Authentication.\n"));
+ fprintf (file, _("\
+ -z force-bti Turn on Branch Target Identification mechanism and generate PLTs with BTI.\n\
+ Generate warnings for missing BTI markings on inputs\n"));
+ fprintf (file, _("\
+ -z bti-report[=none|warning|error] Emit warning/error on mismatch of BTI marking between input objects and ouput.\n\
+ none: Does not emit any warning/error messages.\n\
+ warning (default): Emit warning when the input objects are missing BTI markings\n\
+ and output has BTI marking.\n\
+ error: Emit error when the input objects are missing BTI markings\n\
+ and output has BTI marking.\n"));
+ fprintf (file, _("\
+ -z pac-plt Protect PLTs with Pointer Authentication.\n"));
'
PARSE_AND_LIST_ARGS_CASE_Z_AARCH64='
- else if (strcmp (optarg, "force-bti") == 0)
- {
- plt_type |= PLT_BTI;
- bti_type = BTI_WARN;
- }
- else if (strcmp (optarg, "pac-plt") == 0)
- plt_type |= PLT_PAC;
+ else if (strcmp (optarg, "force-bti") == 0)
+ sw_protections.plt_type |= PLT_BTI;
+ else if (aarch64_parse_bti_report_option (optarg))
+ {}
+ else if (strcmp (optarg, "pac-plt") == 0)
+ sw_protections.plt_type |= PLT_PAC;
'
PARSE_AND_LIST_ARGS_CASE_Z="$PARSE_AND_LIST_ARGS_CASE_Z $PARSE_AND_LIST_ARGS_CASE_Z_AARCH64"