diff options
-rw-r--r-- | bfd/ChangeLog | 41 | ||||
-rw-r--r-- | bfd/bfd-in.h | 4 | ||||
-rw-r--r-- | bfd/bfd-in2.h | 4 | ||||
-rw-r--r-- | bfd/elfnn-aarch64.c | 438 | ||||
-rw-r--r-- | bfd/elfxx-aarch64.c | 29 | ||||
-rw-r--r-- | bfd/elfxx-aarch64.h | 13 | ||||
-rw-r--r-- | ld/ChangeLog | 9 | ||||
-rw-r--r-- | ld/emultempl/aarch64elf.em | 11 | ||||
-rw-r--r-- | ld/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | ld/testsuite/ld-aarch64/aarch64-elf.exp | 1 | ||||
-rw-r--r-- | ld/testsuite/ld-aarch64/erratum843419.d | 69 | ||||
-rw-r--r-- | ld/testsuite/ld-aarch64/erratum843419.s | 84 |
12 files changed, 695 insertions, 14 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); diff --git a/ld/ChangeLog b/ld/ChangeLog index 6082e28..ac1abae 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,12 @@ +2015-04-01 Tejas Belagod <tejas.belagod@arm.com> + + * emultempl/aarch64elf.em + (aarch64_elf_create_output_section_statements): Add parameter in + bfd_elf${ELFSIZE}_aarch64_set_options call. + (OPTION_FIX_ERRATUM_843419): Define. + (PARSE_AND_LIST_LONGOPTS): Add fix-cortex-a53-843419. + (PARSE_AND_LIST_ARGS_CASES): Add OPTION_FIX_ERRATUM_843419. + 2015-04-01 Chen Gang <gang.chen.5i5j@gmail.com> * emulparams/elf32_tic6x_le.sh: Skip OTHER_BSS_SECTIONS for diff --git a/ld/emultempl/aarch64elf.em b/ld/emultempl/aarch64elf.em index 75f04a7..313263a 100644 --- a/ld/emultempl/aarch64elf.em +++ b/ld/emultempl/aarch64elf.em @@ -31,6 +31,7 @@ static int no_enum_size_warning = 0; static int no_wchar_size_warning = 0; static int pic_veneer = 0; static int fix_erratum_835769 = 0; +static int fix_erratum_843419 = 0; static void gld${EMULATION_NAME}_before_parse (void) @@ -303,7 +304,8 @@ aarch64_elf_create_output_section_statements (void) 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); + pic_veneer, + fix_erratum_835769, fix_erratum_843419); stub_file = lang_add_input_file ("linker stubs", lang_input_file_is_fake_enum, @@ -353,6 +355,7 @@ PARSE_AND_LIST_PROLOGUE=' #define OPTION_STUBGROUP_SIZE 311 #define OPTION_NO_WCHAR_SIZE_WARNING 312 #define OPTION_FIX_ERRATUM_835769 313 +#define OPTION_FIX_ERRATUM_843419 314 ' PARSE_AND_LIST_SHORTOPTS=p @@ -364,6 +367,7 @@ PARSE_AND_LIST_LONGOPTS=' { "stub-group-size", required_argument, NULL, OPTION_STUBGROUP_SIZE }, { "no-wchar-size-warning", no_argument, NULL, OPTION_NO_WCHAR_SIZE_WARNING}, { "fix-cortex-a53-835769", no_argument, NULL, OPTION_FIX_ERRATUM_835769}, + { "fix-cortex-a53-843419", no_argument, NULL, OPTION_FIX_ERRATUM_843419}, ' PARSE_AND_LIST_OPTIONS=' @@ -382,6 +386,7 @@ PARSE_AND_LIST_OPTIONS=' the linker should choose suitable defaults.\n" )); fprintf (file, _(" --fix-cortex-a53-835769 Fix erratum 835769\n")); + fprintf (file, _(" --fix-cortex-a53-843419 Fix erratum 843419\n")); ' PARSE_AND_LIST_ARGS_CASES=' @@ -405,6 +410,10 @@ PARSE_AND_LIST_ARGS_CASES=' fix_erratum_835769 = 1; break; + case OPTION_FIX_ERRATUM_843419: + fix_erratum_843419 = 1; + break; + case OPTION_STUBGROUP_SIZE: { const char *end; diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index b35ab3f..2b8d345 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2015-04-01 Tejas Belagod <tejas.belagod@arm.com> + + * ld-aarch64/aarch64-elf.exp: Add erratum843419 test. + * ld-aarch64/erratum843419.d: New. + * ld-aarch64/erratum843419.s: New. + 2015-04-01 H.J. Lu <hongjiu.lu@intel.com> PR ld/18176 diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp index a7ce3f2..895b1b2 100644 --- a/ld/testsuite/ld-aarch64/aarch64-elf.exp +++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp @@ -46,6 +46,7 @@ set aarch64elftests { } run_ld_link_tests $aarch64elftests +run_dump_test "erratum843419" # Relocation Tests run_dump_test "weak-undefined" diff --git a/ld/testsuite/ld-aarch64/erratum843419.d b/ld/testsuite/ld-aarch64/erratum843419.d new file mode 100644 index 0000000..4be8f9e --- /dev/null +++ b/ld/testsuite/ld-aarch64/erratum843419.d @@ -0,0 +1,69 @@ +#source: erratum843419.s +#as: +#ld: --fix-cortex-a53-835769 --fix-cortex-a53-843419 -e0 --section-start .e843419=0x20000000 --section-start .e835769=0x3000000 -Ttext=0x400000 -Tdata=0x40000000 +#objdump: -dr +#... + +Disassembly of section .e843419: + +0000000020000000 <e843419>: + 20000000: d10043ff sub sp, sp, #0x10 + 20000004: d28001a7 mov x7, #0xd // #13 + 20000008: b9000fe7 str w7, \[sp,#12\] + 2000000c: 140003fb b 20000ff8 <e843419_1> + ... + +0000000020000ff8 <e843419_1>: + 20000ff8: 90100000 adrp x0, 40000000 <[_a-zA-z0-9]+> + 20000ffc: f800c007 stur x7, \[x0,#12\] + 20001000: d2800128 mov x8, #0x9 // #9 + 20001004: 14000008 b 20001024 <e843419@0002_00000013_1004> + 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: 14000005 b 2000102c <__e835769_veneer> + 2000101c: d65f03c0 ret + 20001020: 14000400 b 20002020 <__e835769_veneer\+0xff4> + +0000000020001024 <e843419@0002_00000013_1004>: + 20001024: f9000008 str x8, \[x0\] + 20001028: 17fffff8 b 20001008 <e843419_1\+0x10> + +000000002000102c <__e835769_veneer>: + 2000102c: f0f17ff0 adrp x16, 3000000 <e835769> + 20001030: 91000210 add x16, x16, #0x0 + 20001034: d61f0200 br x16 + ... + +Disassembly of section .e835769: + +0000000003000000 <e835769>: + 3000000: b8408c87 ldr w7, \[x4,#8\]! + 3000004: 1b017c06 mul w6, w0, w1 + 3000008: f9400084 ldr x4, \[x4\] + 300000c: 14000004 b 300001c <__erratum_835769_veneer_0> + 3000010: aa0503e0 mov x0, x5 + 3000014: d65f03c0 ret + 3000018: 14000400 b 3001018 <__erratum_835769_veneer_0\+0xffc> + +000000000300001c <__erratum_835769_veneer_0>: + 300001c: 9b031845 madd x5, x2, x3, x6 + 3000020: 17fffffc b 3000010 <e835769\+0x10> + ... + +Disassembly of section .text: + +0000000000400000 <main>: + 400000: d10043ff sub sp, sp, #0x10 + 400004: d28001a7 mov x7, #0xd // #13 + 400008: b9000fe7 str w7, \[sp,#12\] + 40000c: 14000003 b 400018 <__e843419_veneer> + 400010: d65f03c0 ret + 400014: 14000400 b 401014 <__e843419_veneer\+0xffc> + +0000000000400018 <__e843419_veneer>: + 400018: 900fe010 adrp x16, 20000000 <e843419> + 40001c: 91000210 add x16, x16, #0x0 + 400020: d61f0200 br x16 + ... diff --git a/ld/testsuite/ld-aarch64/erratum843419.s b/ld/testsuite/ld-aarch64/erratum843419.s new file mode 100644 index 0000000..35c21ae --- /dev/null +++ b/ld/testsuite/ld-aarch64/erratum843419.s @@ -0,0 +1,84 @@ + + .comm data0,4,4 + .text + .align 2 + .global main + .type main, %function +main: + sub sp, sp, #16 + mov x7, 13 + str w7, [sp,12] + b e843419 + ret + .size main, .-main + + .section .e843419, "xa" + .align 2 + .global e843419 + .type e843419, %function +e843419: + sub sp, sp, #16 + mov x7, 13 + str w7, [sp,12] + b e843419_1 + .fill 4072,1,0 +e843419_1: + adrp x0, data0 + str x7, [x0,12] + mov x8, 9 + str x8, [x0, :lo12:data0] + + add x0, x1, x5 + ldr w7, [sp,12] + add w0, w7, w7 + add sp, sp, 16 + b e835769 + ret + .size e843419, .-e843419 + + .section .e835769, "xa" + .align 2 + .global e835769 + .type e835769, %function +e835769: + ldr w7, [x4,8]! + mul w6, w0, w1 + ldr x4, [x4] + madd x5, x2, x3, x6 + mov x0, x5 + ret + .size e835769, .-e835769 + +# --- + + + + + +# --- + + .data +data0: + .fill 8,1,255 + .balign 512 + .fill 4,1,255 + # double word access that crosses a 64 bit boundary +data1: + .fill 2,1,255 + + # word access that crosses a 64 boundary +data2: + .fill 2,1,255 + +data5: + .fill 4,1,255 + + # double word access that crosses a 128 boundary +data3: + .fill 2,1,255 + + # word access that crosses a 128 bit boundary +data4: + .fill 2,1,255 +data6: + .fill 496,1,255 |