aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
Diffstat (limited to 'bfd')
-rw-r--r--bfd/ChangeLog41
-rw-r--r--bfd/bfd-in.h4
-rw-r--r--bfd/bfd-in2.h4
-rw-r--r--bfd/elfnn-aarch64.c438
-rw-r--r--bfd/elfxx-aarch64.c29
-rw-r--r--bfd/elfxx-aarch64.h13
6 files changed, 516 insertions, 13 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 5d3013a..9e78a49 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,44 @@
+2015-04-01 Tejas Belagod <tejas.belagod@arm.com>
+ Marcus Shawcroft <marcus.shawcroft@arm.com>
+ Jiong Wang <jiong.wang@arm.com>
+
+ * bfd-in.h (bfd_elf64_aarch64_set_options)
+ (bfd_elf32_aarch64_set_options): Add parameter.
+ * bfd-in2.h: Regenerated.
+ * elfnn-aarch64.c (aarch64_erratum_843419_stub)
+ (_bfd_aarch64_adrp_p, _bfd_aarch64_erratum_843419_sequence_p)
+ (_bfd_aarch64_erratum_843419_stub_name)
+ (_bfd_aarch64_erratum_843419_fixup)
+ (_bfd_aarch64_erratum_843419_scan)
+ (_bfd_aarch64_erratum_843419_branch_to_stub)
+ (_bfd_aarch64_erratum_843419_p): Define.
+ (enum elf_aarch64_stub_type): Define
+ aarch64_stub_erratum_843419_veneer.
+ (struct elf_aarch64_stub_hash_entry): Define adrp_offset.
+ (struct elf_aarch64_link_hash_table): Define fix_erratum_843419
+ and fix_erratum_843419_adr.
+ (stub_hash_newfunc): Initialize adrp_offset;
+ (_bfd_aarch64_add_stub_entry_after): Define.
+ (aarch64_map_one_stub, aarch64_build_one_stub)
+ (aarch64_size_one_stub): Handle
+ aarch64_stub_erratum_843419_veneer.
+ (_bfd_aarch64_resize_stubs): Round stub section size.
+ (elfNN_aarch64_size_stubs): Add scan for 843419.
+ (bfd_elfNN_aarch64_set_options): Add parameter. Initialize
+ fix_erratum_843419 and fix_erratum_843419_adr.
+ (struct erratum_835769_branch_to_stub_data): Add info.
+ (elfNN_aarch64_write_section): Initialise info. Handle 843419.
+ (elfNN_aarch64_size_dynamic_sections): Handle 843419.
+ * elfxx-aarch64.c (_bfd_aarch64_decode_adrp_imm)
+ (_bfd_aarch64_sign_extend): Define.
+ (reencode_adr_imm): Remove static. Rename to:
+ (_bfd_aarch64_reencode_adr_imm): Define.
+ (_bfd_aarch64_elf_put_addend): Call _bfd_aarch64_reencode_adr_imm.
+ * elfxx-aarch64.h (AARCH64_ADR_OP, AARCH64_ADRP_OP)
+ (AARCH64_ADRP_OP_MASK, _bfd_aarch64_sign_extend)
+ (_bfd_aarch64_decode_adrp_imm, _bfd_aarch64_reencode_adr_imm):
+ Define.
+
2015-04-01 H.J. Lu <hongjiu.lu@intel.com>
* configure: Regenerated.
diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h
index cbd0465..1f8a72c 100644
--- a/bfd/bfd-in.h
+++ b/bfd/bfd-in.h
@@ -934,10 +934,10 @@ extern void bfd_elf32_aarch64_init_maps
(bfd *);
extern void bfd_elf64_aarch64_set_options
- (bfd *, struct bfd_link_info *, int, int, int, int);
+ (bfd *, struct bfd_link_info *, int, int, int, int, int);
extern void bfd_elf32_aarch64_set_options
- (bfd *, struct bfd_link_info *, int, int, int, int);
+ (bfd *, struct bfd_link_info *, int, int, int, int, int);
/* ELF AArch64 mapping symbol support. */
#define BFD_AARCH64_SPECIAL_SYM_TYPE_MAP (1 << 0)
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index e170dd9..81def3f 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -941,10 +941,10 @@ extern void bfd_elf32_aarch64_init_maps
(bfd *);
extern void bfd_elf64_aarch64_set_options
- (bfd *, struct bfd_link_info *, int, int, int, int);
+ (bfd *, struct bfd_link_info *, int, int, int, int, int);
extern void bfd_elf32_aarch64_set_options
- (bfd *, struct bfd_link_info *, int, int, int, int);
+ (bfd *, struct bfd_link_info *, int, int, int, int, int);
/* ELF AArch64 mapping symbol support. */
#define BFD_AARCH64_SPECIAL_SYM_TYPE_MAP (1 << 0)
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index e0e4915..85cf856 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -1640,6 +1640,12 @@ static const uint32_t aarch64_erratum_835769_stub[] =
0x14000000, /* b <label> */
};
+static const uint32_t aarch64_erratum_843419_stub[] =
+{
+ 0x00000000, /* Placeholder for LDR instruction. */
+ 0x14000000, /* b <label> */
+};
+
/* Section name for stubs is the associated section name plus this
string. */
#define STUB_SUFFIX ".stub"
@@ -1650,6 +1656,7 @@ enum elf_aarch64_stub_type
aarch64_stub_adrp_branch,
aarch64_stub_long_branch,
aarch64_stub_erratum_835769_veneer,
+ aarch64_stub_erratum_843419_veneer,
};
struct elf_aarch64_stub_hash_entry
@@ -1688,6 +1695,9 @@ struct elf_aarch64_stub_hash_entry
/* The instruction which caused this stub to be generated (only valid for
erratum 835769 workaround stubs at present). */
uint32_t veneered_insn;
+
+ /* In an erratum 843419 workaround stub, the ADRP instruction offset. */
+ bfd_vma adrp_offset;
};
/* Used to build a map of a section. This is required for mixed-endian
@@ -1836,6 +1846,12 @@ struct elf_aarch64_link_hash_table
/* Fix erratum 835769. */
int fix_erratum_835769;
+ /* Fix erratum 843419. */
+ int fix_erratum_843419;
+
+ /* Enable ADRP->ADR rewrite for erratum 843419 workaround. */
+ int fix_erratum_843419_adr;
+
/* The number of bytes in the initial entry in the PLT. */
bfd_size_type plt_header_size;
@@ -1957,6 +1973,7 @@ stub_hash_newfunc (struct bfd_hash_entry *entry,
/* Initialize the local fields. */
eh = (struct elf_aarch64_stub_hash_entry *) entry;
+ eh->adrp_offset = 0;
eh->stub_sec = NULL;
eh->stub_offset = 0;
eh->target_value = 0;
@@ -2399,6 +2416,34 @@ _bfd_aarch64_add_stub_entry_in_group (const char *stub_name,
return stub_entry;
}
+/* Add a new stub entry in the final stub section to the stub hash.
+ Not all fields of the new stub entry are initialised. */
+
+static struct elf_aarch64_stub_hash_entry *
+_bfd_aarch64_add_stub_entry_after (const char *stub_name,
+ asection *link_section,
+ struct elf_aarch64_link_hash_table *htab)
+{
+ asection *stub_sec;
+ struct elf_aarch64_stub_hash_entry *stub_entry;
+
+ stub_sec = _bfd_aarch64_get_stub_for_link_section (link_section, htab);
+ stub_entry = aarch64_stub_hash_lookup (&htab->stub_hash_table, stub_name,
+ TRUE, FALSE);
+ if (stub_entry == NULL)
+ {
+ (*_bfd_error_handler) (_("cannot create stub entry %s"), stub_name);
+ return NULL;
+ }
+
+ stub_entry->stub_sec = stub_sec;
+ stub_entry->stub_offset = 0;
+ stub_entry->id_sec = link_section;
+
+ return stub_entry;
+}
+
+
static bfd_boolean
aarch64_build_one_stub (struct bfd_hash_entry *gen_entry,
void *in_arg ATTRIBUTE_UNUSED)
@@ -2455,6 +2500,10 @@ aarch64_build_one_stub (struct bfd_hash_entry *gen_entry,
template = aarch64_erratum_835769_stub;
template_size = sizeof (aarch64_erratum_835769_stub);
break;
+ case aarch64_stub_erratum_843419_veneer:
+ template = aarch64_erratum_843419_stub;
+ template_size = sizeof (aarch64_erratum_843419_stub);
+ break;
default:
abort ();
}
@@ -2506,6 +2555,12 @@ aarch64_build_one_stub (struct bfd_hash_entry *gen_entry,
stub_sec->contents + stub_entry->stub_offset + 4);
break;
+ case aarch64_stub_erratum_843419_veneer:
+ if (aarch64_relocate (AARCH64_R (JUMP26), stub_bfd, stub_sec,
+ stub_entry->stub_offset + 4, sym_value + 4))
+ BFD_FAIL ();
+ break;
+
default:
abort ();
}
@@ -2537,6 +2592,9 @@ aarch64_size_one_stub (struct bfd_hash_entry *gen_entry,
case aarch64_stub_erratum_835769_veneer:
size = sizeof (aarch64_erratum_835769_stub);
break;
+ case aarch64_stub_erratum_843419_veneer:
+ size = sizeof (aarch64_erratum_843419_stub);
+ break;
default:
abort ();
}
@@ -3001,7 +3059,7 @@ _bfd_aarch64_erratum_835769_stub_name (unsigned num_fixes)
return stub_name;
}
-/* Scan for cortex-a53 erratum 835769 sequence.
+/* Scan for Cortex-A53 erratum 835769 sequence.
Return TRUE else FALSE on abnormal termination. */
@@ -3091,6 +3149,82 @@ _bfd_aarch64_erratum_835769_scan (bfd *input_bfd,
}
+/* Test if instruction INSN is ADRP. */
+
+static bfd_boolean
+_bfd_aarch64_adrp_p (uint32_t insn)
+{
+ return ((insn & 0x9f000000) == 0x90000000);
+}
+
+
+/* Helper predicate to look for cortex-a53 erratum 843419 sequence 1. */
+
+static bfd_boolean
+_bfd_aarch64_erratum_843419_sequence_p (uint32_t insn_1, uint32_t insn_2,
+ uint32_t insn_3)
+{
+ uint32_t rt;
+ uint32_t rt2;
+ bfd_boolean pair;
+ bfd_boolean load;
+
+ return (aarch64_mem_op_p (insn_2, &rt, &rt2, &pair, &load)
+ && (!pair
+ || (pair && !load))
+ && AARCH64_LDST_UIMM (insn_3)
+ && AARCH64_RN (insn_3) == AARCH64_RD (insn_1));
+}
+
+
+/* Test for the presence of Cortex-A53 erratum 843419 instruction sequence.
+
+ Return TRUE if section CONTENTS at offset I contains one of the
+ erratum 843419 sequences, otherwise return FALSE. If a sequence is
+ seen set P_VENEER_I to the offset of the final LOAD/STORE
+ instruction in the sequence.
+ */
+
+static bfd_boolean
+_bfd_aarch64_erratum_843419_p (bfd_byte *contents, bfd_vma vma,
+ bfd_vma i, bfd_vma span_end,
+ bfd_vma *p_veneer_i)
+{
+ uint32_t insn_1 = bfd_getl32 (contents + i);
+
+ if (!_bfd_aarch64_adrp_p (insn_1))
+ return FALSE;
+
+ if (span_end < i + 12)
+ return FALSE;
+
+ uint32_t insn_2 = bfd_getl32 (contents + i + 4);
+ uint32_t insn_3 = bfd_getl32 (contents + i + 8);
+
+ if ((vma & 0xfff) != 0xff8 && (vma & 0xfff) != 0xffc)
+ return FALSE;
+
+ if (_bfd_aarch64_erratum_843419_sequence_p (insn_1, insn_2, insn_3))
+ {
+ *p_veneer_i = i + 8;
+ return TRUE;
+ }
+
+ if (span_end < i + 16)
+ return FALSE;
+
+ uint32_t insn_4 = bfd_getl32 (contents + i + 12);
+
+ if (_bfd_aarch64_erratum_843419_sequence_p (insn_1, insn_2, insn_4))
+ {
+ *p_veneer_i = i + 12;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
/* Resize all stub sections. */
static void
@@ -3119,9 +3253,174 @@ _bfd_aarch64_resize_stubs (struct elf_aarch64_link_hash_table *htab)
if (section->size)
section->size += 4;
+
+ /* Ensure all stub sections have a size which is a multiple of
+ 4096. This is important in order to ensure that the insertion
+ of stub sections does not in itself move existing code around
+ in such a way that new errata sequences are created. */
+ if (htab->fix_erratum_843419)
+ if (section->size)
+ section->size = BFD_ALIGN (section->size, 0x1000);
}
}
+
+/* Construct an erratum 843419 workaround stub name.
+ */
+
+static char *
+_bfd_aarch64_erratum_843419_stub_name (asection *input_section,
+ bfd_vma offset)
+{
+ const bfd_size_type len = 8 + 4 + 1 + 8 + 1 + 16 + 1;
+ char *stub_name = bfd_malloc (len);
+
+ if (stub_name != NULL)
+ snprintf (stub_name, len, "e843419@%04x_%08x_%" BFD_VMA_FMT "x",
+ input_section->owner->id,
+ input_section->id,
+ offset);
+ return stub_name;
+}
+
+/* Build a stub_entry structure describing an 843419 fixup.
+
+ The stub_entry constructed is populated with the bit pattern INSN
+ of the instruction located at OFFSET within input SECTION.
+
+ Returns TRUE on success. */
+
+static bfd_boolean
+_bfd_aarch64_erratum_843419_fixup (uint32_t insn,
+ bfd_vma adrp_offset,
+ bfd_vma ldst_offset,
+ asection *section,
+ struct bfd_link_info *info)
+{
+ struct elf_aarch64_link_hash_table *htab = elf_aarch64_hash_table (info);
+ char *stub_name;
+ struct elf_aarch64_stub_hash_entry *stub_entry;
+
+ stub_name = _bfd_aarch64_erratum_843419_stub_name (section, ldst_offset);
+ stub_entry = aarch64_stub_hash_lookup (&htab->stub_hash_table, stub_name,
+ FALSE, FALSE);
+ if (stub_entry)
+ {
+ free (stub_name);
+ return TRUE;
+ }
+
+ /* We always place an 843419 workaround veneer in the stub section
+ attached to the input section in which an erratum sequence has
+ been found. This ensures that later in the link process (in
+ elfNN_aarch64_write_section) when we copy the veneered
+ instruction from the input section into the stub section the
+ copied instruction will have had any relocations applied to it.
+ If we placed workaround veneers in any other stub section then we
+ could not assume that all relocations have been processed on the
+ corresponding input section at the point we output the stub
+ section.
+ */
+
+ stub_entry = _bfd_aarch64_add_stub_entry_after (stub_name, section, htab);
+ if (stub_entry == NULL)
+ {
+ free (stub_name);
+ return FALSE;
+ }
+
+ stub_entry->adrp_offset = adrp_offset;
+ stub_entry->target_value = ldst_offset;
+ stub_entry->target_section = section;
+ stub_entry->stub_type = aarch64_stub_erratum_843419_veneer;
+ stub_entry->veneered_insn = insn;
+ stub_entry->output_name = stub_name;
+
+ return TRUE;
+}
+
+
+/* Scan an input section looking for the signature of erratum 843419.
+
+ Scans input SECTION in INPUT_BFD looking for erratum 843419
+ signatures, for each signature found a stub_entry is created
+ describing the location of the erratum for subsequent fixup.
+
+ Return TRUE on successful scan, FALSE on failure to scan.
+ */
+
+static bfd_boolean
+_bfd_aarch64_erratum_843419_scan (bfd *input_bfd, asection *section,
+ struct bfd_link_info *info)
+{
+ struct elf_aarch64_link_hash_table *htab = elf_aarch64_hash_table (info);
+
+ if (htab == NULL)
+ return TRUE;
+
+ if (elf_section_type (section) != SHT_PROGBITS
+ || (elf_section_flags (section) & SHF_EXECINSTR) == 0
+ || (section->flags & SEC_EXCLUDE) != 0
+ || (section->sec_info_type == SEC_INFO_TYPE_JUST_SYMS)
+ || (section->output_section == bfd_abs_section_ptr))
+ return TRUE;
+
+ do
+ {
+ bfd_byte *contents = NULL;
+ struct _aarch64_elf_section_data *sec_data;
+ unsigned int span;
+
+ if (elf_section_data (section)->this_hdr.contents != NULL)
+ contents = elf_section_data (section)->this_hdr.contents;
+ else if (! bfd_malloc_and_get_section (input_bfd, section, &contents))
+ return FALSE;
+
+ sec_data = elf_aarch64_section_data (section);
+
+ qsort (sec_data->map, sec_data->mapcount,
+ sizeof (elf_aarch64_section_map), elf_aarch64_compare_mapping);
+
+ for (span = 0; span < sec_data->mapcount; span++)
+ {
+ unsigned int span_start = sec_data->map[span].vma;
+ unsigned int span_end = ((span == sec_data->mapcount - 1)
+ ? sec_data->map[0].vma + section->size
+ : sec_data->map[span + 1].vma);
+ unsigned int i;
+ char span_type = sec_data->map[span].type;
+
+ if (span_type == 'd')
+ continue;
+
+ for (i = span_start; i + 8 < span_end; i += 4)
+ {
+ bfd_vma vma = (section->output_section->vma
+ + section->output_offset
+ + i);
+ bfd_vma veneer_i;
+
+ if (_bfd_aarch64_erratum_843419_p
+ (contents, vma, i, span_end, &veneer_i))
+ {
+ uint32_t insn = bfd_getl32 (contents + veneer_i);
+
+ if (!_bfd_aarch64_erratum_843419_fixup (insn, i, veneer_i,
+ section, info))
+ return FALSE;
+ }
+ }
+ }
+
+ if (elf_section_data (section)->this_hdr.contents == NULL)
+ free (contents);
+ }
+ while (0);
+
+ return TRUE;
+}
+
+
/* Determine and set the size of the stub section for a final link.
The basic idea here is to examine all the relocations looking for
@@ -3167,6 +3466,8 @@ elfNN_aarch64_size_stubs (bfd *output_bfd,
group_sections (htab, stub_group_size, stubs_always_before_branch);
+ (*htab->layout_sections_again) ();
+
if (htab->fix_erratum_835769)
{
bfd *input_bfd;
@@ -3177,7 +3478,29 @@ elfNN_aarch64_size_stubs (bfd *output_bfd,
&num_erratum_835769_fixes))
return FALSE;
- stub_changed = TRUE;
+ _bfd_aarch64_resize_stubs (htab);
+ (*htab->layout_sections_again) ();
+ }
+
+ if (htab->fix_erratum_843419)
+ {
+ bfd *input_bfd;
+
+ for (input_bfd = info->input_bfds;
+ input_bfd != NULL;
+ input_bfd = input_bfd->link.next)
+ {
+ asection *section;
+
+ for (section = input_bfd->sections;
+ section != NULL;
+ section = section->next)
+ if (!_bfd_aarch64_erratum_843419_scan (input_bfd, section, info))
+ return FALSE;
+ }
+
+ _bfd_aarch64_resize_stubs (htab);
+ (*htab->layout_sections_again) ();
}
while (1)
@@ -3582,13 +3905,16 @@ bfd_elfNN_aarch64_set_options (struct bfd *output_bfd,
struct bfd_link_info *link_info,
int no_enum_warn,
int no_wchar_warn, int pic_veneer,
- int fix_erratum_835769)
+ int fix_erratum_835769,
+ int fix_erratum_843419)
{
struct elf_aarch64_link_hash_table *globals;
globals = elf_aarch64_hash_table (link_info);
globals->pic_veneer = pic_veneer;
globals->fix_erratum_835769 = fix_erratum_835769;
+ globals->fix_erratum_843419 = fix_erratum_843419;
+ globals->fix_erratum_843419_adr = TRUE;
BFD_ASSERT (is_aarch64_elf (output_bfd));
elf_aarch64_tdata (output_bfd)->no_enum_size_warning = no_enum_warn;
@@ -3924,6 +4250,7 @@ symbol_tlsdesc_got_offset (bfd *input_bfd, struct elf_link_hash_entry *h,
struct erratum_835769_branch_to_stub_data
{
+ struct bfd_link_info *info;
asection *output_section;
bfd_byte *contents;
};
@@ -3976,6 +4303,87 @@ make_branch_to_erratum_835769_stub (struct bfd_hash_entry *gen_entry,
return TRUE;
}
+
+static bfd_boolean
+_bfd_aarch64_erratum_843419_branch_to_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_835769_branch_to_stub_data *data
+ = (struct erratum_835769_branch_to_stub_data *) in_arg;
+ struct bfd_link_info *info;
+ struct elf_aarch64_link_hash_table *htab;
+ bfd_byte *contents;
+ asection *section;
+ bfd *abfd;
+ bfd_vma place;
+ uint32_t insn;
+
+ info = data->info;
+ contents = data->contents;
+ section = data->output_section;
+
+ htab = elf_aarch64_hash_table (info);
+
+ if (stub_entry->target_section != section
+ || stub_entry->stub_type != aarch64_stub_erratum_843419_veneer)
+ return TRUE;
+
+ insn = bfd_getl32 (contents + stub_entry->target_value);
+ bfd_putl32 (insn,
+ stub_entry->stub_sec->contents + stub_entry->stub_offset);
+
+ place = (section->output_section->vma + section->output_offset
+ + stub_entry->adrp_offset);
+ insn = bfd_getl32 (contents + stub_entry->adrp_offset);
+
+ if ((insn & AARCH64_ADRP_OP_MASK) != AARCH64_ADRP_OP)
+ abort ();
+
+ bfd_signed_vma imm =
+ (_bfd_aarch64_sign_extend
+ ((bfd_vma) _bfd_aarch64_decode_adrp_imm (insn) << 12, 33)
+ - (place & 0xfff));
+
+ if (htab->fix_erratum_843419_adr
+ && (imm >= AARCH64_MIN_ADRP_IMM && imm <= AARCH64_MAX_ADRP_IMM))
+ {
+ insn = (_bfd_aarch64_reencode_adr_imm (AARCH64_ADR_OP, imm)
+ | AARCH64_RT (insn));
+ bfd_putl32 (insn, contents + stub_entry->adrp_offset);
+ }
+ else
+ {
+ bfd_vma veneered_insn_loc;
+ bfd_vma veneer_entry_loc;
+ bfd_signed_vma branch_offset;
+ uint32_t branch_insn;
+
+ veneered_insn_loc = stub_entry->target_section->output_section->vma
+ + stub_entry->target_section->output_offset
+ + stub_entry->target_value;
+ veneer_entry_loc = stub_entry->stub_sec->output_section->vma
+ + stub_entry->stub_sec->output_offset
+ + stub_entry->stub_offset;
+ branch_offset = veneer_entry_loc - veneered_insn_loc;
+
+ abfd = stub_entry->target_section->owner;
+ if (!aarch64_valid_branch_p (veneer_entry_loc, veneered_insn_loc))
+ (*_bfd_error_handler)
+ (_("%B: error: Erratum 843419 stub out "
+ "of range (input file too large)"), abfd);
+
+ branch_insn = 0x14000000;
+ branch_offset >>= 2;
+ branch_offset &= 0x3ffffff;
+ branch_insn |= branch_offset;
+ bfd_putl32 (branch_insn, contents + stub_entry->target_value);
+ }
+ return TRUE;
+}
+
+
static bfd_boolean
elfNN_aarch64_write_section (bfd *output_bfd ATTRIBUTE_UNUSED,
struct bfd_link_info *link_info,
@@ -3994,12 +4402,24 @@ elfNN_aarch64_write_section (bfd *output_bfd ATTRIBUTE_UNUSED,
{
struct erratum_835769_branch_to_stub_data data;
+ data.info = link_info;
data.output_section = sec;
data.contents = contents;
bfd_hash_traverse (&globals->stub_hash_table,
make_branch_to_erratum_835769_stub, &data);
}
+ if (globals->fix_erratum_843419)
+ {
+ struct erratum_835769_branch_to_stub_data data;
+
+ data.info = link_info;
+ data.output_section = sec;
+ data.contents = contents;
+ bfd_hash_traverse (&globals->stub_hash_table,
+ _bfd_aarch64_erratum_843419_branch_to_stub, &data);
+ }
+
return FALSE;
}
@@ -6461,6 +6881,14 @@ aarch64_map_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
if (!elfNN_aarch64_output_map_sym (osi, AARCH64_MAP_INSN, addr))
return FALSE;
break;
+ case aarch64_stub_erratum_843419_veneer:
+ if (!elfNN_aarch64_output_stub_sym (osi, stub_name, addr,
+ sizeof (aarch64_erratum_843419_stub)))
+ return FALSE;
+ if (!elfNN_aarch64_output_map_sym (osi, AARCH64_MAP_INSN, addr))
+ return FALSE;
+ break;
+
default:
abort ();
}
@@ -7161,8 +7589,8 @@ elfNN_aarch64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
}
/* Init mapping symbols information to use later to distingush between
- code and data while scanning for erratam 835769. */
- if (htab->fix_erratum_835769)
+ code and data while scanning for errata. */
+ if (htab->fix_erratum_835769 || htab->fix_erratum_843419)
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
{
if (!is_aarch64_elf (ibfd))
diff --git a/bfd/elfxx-aarch64.c b/bfd/elfxx-aarch64.c
index b513a54..db9d4fa 100644
--- a/bfd/elfxx-aarch64.c
+++ b/bfd/elfxx-aarch64.c
@@ -25,6 +25,26 @@
#define MASK(n) ((1u << (n)) - 1)
+/* Sign-extend VALUE, which has the indicated number of BITS. */
+
+bfd_signed_vma
+_bfd_aarch64_sign_extend (bfd_vma value, int bits)
+{
+ if (value & ((bfd_vma) 1 << (bits - 1)))
+ /* VALUE is negative. */
+ value |= ((bfd_vma) - 1) << bits;
+
+ return value;
+}
+
+/* Decode the IMM field of ADRP. */
+
+uint32_t
+_bfd_aarch64_decode_adrp_imm (uint32_t insn)
+{
+ return (((insn >> 5) & MASK (19)) << 2) | ((insn >> 29) & MASK (2));
+}
+
/* Reencode the imm field of add immediate. */
static inline uint32_t
reencode_add_imm (uint32_t insn, uint32_t imm)
@@ -32,9 +52,10 @@ reencode_add_imm (uint32_t insn, uint32_t imm)
return (insn & ~(MASK (12) << 10)) | ((imm & MASK (12)) << 10);
}
-/* Reencode the imm field of adr. */
-static inline uint32_t
-reencode_adr_imm (uint32_t insn, uint32_t imm)
+/* Reencode the IMM field of ADR. */
+
+uint32_t
+_bfd_aarch64_reencode_adr_imm (uint32_t insn, uint32_t imm)
{
return (insn & ~((MASK (2) << 29) | (MASK (19) << 5)))
| ((imm & MASK (2)) << 29) | ((imm & (MASK (19) << 2)) << 3);
@@ -220,7 +241,7 @@ _bfd_aarch64_elf_put_addend (bfd *abfd,
case BFD_RELOC_AARCH64_ADR_LO21_PCREL:
case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL:
- contents = reencode_adr_imm (contents, addend);
+ contents = _bfd_aarch64_reencode_adr_imm (contents, addend);
break;
case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC:
diff --git a/bfd/elfxx-aarch64.h b/bfd/elfxx-aarch64.h
index 612b036..1c9ceda 100644
--- a/bfd/elfxx-aarch64.h
+++ b/bfd/elfxx-aarch64.h
@@ -26,6 +26,19 @@
#define PG(x) ((x) & ~ (bfd_vma) 0xfff)
#define PG_OFFSET(x) ((x) & (bfd_vma) 0xfff)
+#define AARCH64_ADR_OP 0x10000000
+#define AARCH64_ADRP_OP 0x90000000
+#define AARCH64_ADRP_OP_MASK 0x9F000000
+
+extern bfd_signed_vma
+_bfd_aarch64_sign_extend (bfd_vma, int);
+
+extern uint32_t
+_bfd_aarch64_decode_adrp_imm (uint32_t);
+
+extern uint32_t
+_bfd_aarch64_reencode_adr_imm (uint32_t, uint32_t);
+
extern bfd_reloc_status_type
_bfd_aarch64_elf_put_addend (bfd *, bfd_byte *, bfd_reloc_code_real_type,
reloc_howto_type *, bfd_signed_vma);