diff options
author | Han Shen <shenhan@google.com> | 2015-11-17 16:29:47 -0800 |
---|---|---|
committer | Han Shen <shenhan@google.com> | 2015-11-19 17:29:00 -0800 |
commit | 8bfb6b2bf11cfbc445239158ec28d0988f8fa947 (patch) | |
tree | 64baf9be2b2d76eb0d3d83ec6acf3d5ddd452b64 /binutils-2.25/gold/aarch64.cc | |
parent | 932d71b859239e834651fdee549dc661cda82fe8 (diff) | |
download | toolchain_binutils-8bfb6b2bf11cfbc445239158ec28d0988f8fa947.tar.gz toolchain_binutils-8bfb6b2bf11cfbc445239158ec28d0988f8fa947.tar.bz2 toolchain_binutils-8bfb6b2bf11cfbc445239158ec28d0988f8fa947.zip |
Create an unified binutils source tree for both Android and ChromiumOS.
About source code - The base version of this binutils is newer than that
of aosp/binutils-2.25, it is based on the binutils that is used to build
google products and ChromiumOS. And it contains *all* local Android
patches as well as all patches that are cherry-picked from upstream for
aosp/binutils-2.25 tree (up to Nov. 5 - 932d71b85). You may find the
detailed development history for this binutils tree here -
https://chromium.googlesource.com/chromiumos/third_party/binutils/+log/unification
(This CL is a combination of all the CLs in it. After this CL is
submitted the tree will be identical to
https://chromium.googlesource.com/chromiumos/third_party/binutils/+log/unification
at 2865a3615d80bd5f82d14d7e0484e84dc052596a)
About testing - We tested this binutils for both ChromiumOS and
Android. For android, we tested building N4, N5X, N6, N7, N9 using new
binutils, we also did a full-build of toolchain (by build.py) and built
a N5X image; for ChromiumOS - it passed ChromiumOS toolchain release
tests on all 4 platforms (x86, x86_64, arm32 and arm64).
Change-Id: I2bb2cf579f9458d0a8bc9612331dc7d5043e3d82
Diffstat (limited to 'binutils-2.25/gold/aarch64.cc')
-rw-r--r-- | binutils-2.25/gold/aarch64.cc | 199 |
1 files changed, 172 insertions, 27 deletions
diff --git a/binutils-2.25/gold/aarch64.cc b/binutils-2.25/gold/aarch64.cc index 49481945..41533896 100644 --- a/binutils-2.25/gold/aarch64.cc +++ b/binutils-2.25/gold/aarch64.cc @@ -103,6 +103,10 @@ public: { return aarch64_bits(insn, 10, 5); } static bool + is_adr(const Insntype insn) + { return (insn & 0x9F000000) == 0x10000000; } + + static bool is_adrp(const Insntype insn) { return (insn & 0x9F000000) == 0x90000000; } @@ -126,6 +130,39 @@ public: aarch64_rt2(const Insntype insn) { return aarch64_bits(insn, 10, 5); } + // Encode imm21 into adr. Signed imm21 is in the range of [-1M, 1M). + static Insntype + aarch64_adr_encode_imm(Insntype adr, int imm21) + { + gold_assert(is_adr(adr)); + gold_assert(-(1 << 20) <= imm21 && imm21 < (1 << 20)); + const int mask19 = (1 << 19) - 1; + const int mask2 = 3; + adr &= ~((mask19 << 5) | (mask2 << 29)); + adr |= ((imm21 & mask2) << 29) | (((imm21 >> 2) & mask19) << 5); + return adr; + } + + // Retrieve encoded adrp 33-bit signed imm value. This value is obtained by + // 21-bit signed imm encoded in the insn multiplied by 4k (page size) and + // 64-bit sign-extended, resulting in [-4G, 4G) with 12-lsb being 0. + static int64_t + aarch64_adrp_decode_imm(const Insntype adrp) + { + const int mask19 = (1 << 19) - 1; + const int mask2 = 3; + gold_assert(is_adrp(adrp)); + // 21-bit imm encoded in adrp. + uint64_t imm = ((adrp >> 29) & mask2) | (((adrp >> 5) & mask19) << 2); + // Retrieve msb of 21-bit-signed imm for sign extension. + uint64_t msbt = (imm >> 20) & 1; + // Real value is imm multipled by 4k. Value now has 33-bit information. + int64_t value = imm << 12; + // Sign extend to 64-bit by repeating msbt 31 (64-33) times and merge it + // with value. + return ((((uint64_t)(1) << 32) - msbt) << 33) | value; + } + static bool aarch64_b(const Insntype insn) { return (insn & 0xFC000000) == 0x14000000; } @@ -1020,6 +1057,34 @@ private: }; // End of "Erratum_stub". +// Erratum sub class to wrap additional info needed by 843419. In fixing this +// erratum, we may choose to replace 'adrp' with 'adr', in this case, we need +// adrp's code position (two or three insns before erratum insn itself). + +template<int size, bool big_endian> +class E843419_stub : public Erratum_stub<size, big_endian> +{ +public: + typedef typename AArch64_insn_utilities<big_endian>::Insntype Insntype; + + E843419_stub(AArch64_relobj<size, big_endian>* relobj, + unsigned int shndx, unsigned int sh_offset, + unsigned int adrp_sh_offset) + : Erratum_stub<size, big_endian>(relobj, ST_E_843419, shndx, sh_offset), + adrp_sh_offset_(adrp_sh_offset) + {} + + unsigned int + adrp_sh_offset() const + { return this->adrp_sh_offset_; } + +private: + // Section offset of "adrp". (We do not need a "adrp_shndx_" field, because we + // can can obtain it from its parent.) + const unsigned int adrp_sh_offset_; +}; + + template<int size, bool big_endian> const int Erratum_stub<size, big_endian>::STUB_ADDR_ALIGN = 4; @@ -1755,6 +1820,13 @@ class AArch64_relobj : public Sized_relobj_file<size, big_endian> void fix_errata(typename Sized_relobj_file<size, big_endian>::Views* pviews); + // Try to fix erratum 843419 in an optimized way. Return true if patch is + // applied. + bool + try_fix_erratum_843419_optimized( + The_erratum_stub*, + typename Sized_relobj_file<size, big_endian>::View_size&); + // Whether a section needs to be scanned for relocation stubs. bool section_needs_reloc_stub_scanning(const elfcpp::Shdr<size, big_endian>&, @@ -1892,18 +1964,75 @@ AArch64_relobj<size, big_endian>::fix_errata( Insntype insn_to_fix = ip[0]; stub->update_erratum_insn(insn_to_fix); - // Replace the erratum insn with a branch-to-stub. - AArch64_address stub_address = - stub_table->erratum_stub_address(stub); - unsigned int b_offset = stub_address - stub->erratum_address(); - AArch64_relocate_functions<size, big_endian>::construct_b( - pview.view + stub->sh_offset(), b_offset & 0xfffffff); + // First try to see if erratum is 843419 and if it can be fixed + // without using branch-to-stub. + if (!try_fix_erratum_843419_optimized(stub, pview)) + { + // Replace the erratum insn with a branch-to-stub. + AArch64_address stub_address = + stub_table->erratum_stub_address(stub); + unsigned int b_offset = stub_address - stub->erratum_address(); + AArch64_relocate_functions<size, big_endian>::construct_b( + pview.view + stub->sh_offset(), b_offset & 0xfffffff); + } ++p; } } } +// This is an optimization for 843419. This erratum requires the sequence begin +// with 'adrp', when final value calculated by adrp fits in adr, we can just +// replace 'adrp' with 'adr', so we save 2 jumps per occurrence. (Note, however, +// in this case, we do not delete the erratum stub (too late to do so), it is +// merely generated without ever being called.) + +template<int size, bool big_endian> +bool +AArch64_relobj<size, big_endian>::try_fix_erratum_843419_optimized( + The_erratum_stub* stub, + typename Sized_relobj_file<size, big_endian>::View_size& pview) +{ + if (stub->type() != ST_E_843419) + return false; + + typedef AArch64_insn_utilities<big_endian> Insn_utilities; + typedef typename elfcpp::Swap<32,big_endian>::Valtype Insntype; + E843419_stub<size, big_endian>* e843419_stub = + reinterpret_cast<E843419_stub<size, big_endian>*>(stub); + AArch64_address pc = pview.address + e843419_stub->adrp_sh_offset(); + Insntype* adrp_view = reinterpret_cast<Insntype*>( + pview.view + e843419_stub->adrp_sh_offset()); + Insntype adrp_insn = adrp_view[0]; + gold_assert(Insn_utilities::is_adrp(adrp_insn)); + // Get adrp 33-bit signed imm value. + int64_t adrp_imm = Insn_utilities:: + aarch64_adrp_decode_imm(adrp_insn); + // adrp - final value transferred to target register is calculated as: + // PC[11:0] = Zeros(12) + // adrp_dest_value = PC + adrp_imm; + int64_t adrp_dest_value = (pc & ~((1 << 12) - 1)) + adrp_imm; + // adr -final value transferred to target register is calucalted as: + // PC + adr_imm + // So we have: + // PC + adr_imm = adrp_dest_value + // ==> + // adr_imm = adrp_dest_value - PC + int64_t adr_imm = adrp_dest_value - pc; + // Check if imm fits in adr (21-bit signed). + if (-(1 << 20) <= adr_imm && adr_imm < (1 << 20)) + { + // Convert 'adrp' into 'adr'. + Insntype adr_insn = adrp_insn & ((1 << 31) - 1); + adr_insn = Insn_utilities:: + aarch64_adr_encode_imm(adr_insn, adr_imm); + elfcpp::Swap<32, big_endian>::writeval(adrp_view, adr_insn); + return true; + } + return false; +} + + // Relocate sections. template<int size, bool big_endian> @@ -2767,9 +2896,8 @@ class Target_aarch64 : public Sized_target<size, big_endian> } // Return the addend to use for a target specific relocation. - typename elfcpp::Elf_types<size>::Elf_Addr - do_reloc_addend(void* arg, unsigned int r_type, - typename elfcpp::Elf_types<size>::Elf_Addr addend) const; + uint64_t + do_reloc_addend(void* arg, unsigned int r_type, uint64_t addend) const; // Return the PLT section. uint64_t @@ -3168,14 +3296,16 @@ class Target_aarch64 : public Sized_target<size, big_endian> return this->plt_; } - // Helper method to create erratum stubs for ST_E_843419 and ST_E_835769. + // Helper method to create erratum stubs for ST_E_843419 and ST_E_835769. For + // ST_E_843419, we need an additional field for adrp offset. void create_erratum_stub( AArch64_relobj<size, big_endian>* relobj, unsigned int shndx, section_size_type erratum_insn_offset, Address erratum_address, typename Insn_utilities::Insntype erratum_insn, - int erratum_type); + int erratum_type, + unsigned int e843419_adrp_offset=0); // Return whether this is a 3-insn erratum sequence. bool is_erratum_843419_sequence( @@ -5457,10 +5587,9 @@ Target_aarch64<size, big_endian>::new_stub_table( template<int size, bool big_endian> -typename elfcpp::Elf_types<size>::Elf_Addr +uint64_t Target_aarch64<size, big_endian>::do_reloc_addend( - void* arg, unsigned int r_type, - typename elfcpp::Elf_types<size>::Elf_Addr) const + void* arg, unsigned int r_type, uint64_t) const { gold_assert(r_type == elfcpp::R_AARCH64_TLSDESC); uintptr_t intarg = reinterpret_cast<uintptr_t>(arg); @@ -5514,16 +5643,14 @@ Target_aarch64<size, big_endian>::define_tls_base_symbol( Output_segment* tls_segment = layout->tls_segment(); if (tls_segment != NULL) { - bool is_exec = parameters->options().output_is_executable(); + // _TLS_MODULE_BASE_ always points to the beginning of tls segment. symtab->define_in_output_segment("_TLS_MODULE_BASE_", NULL, Symbol_table::PREDEFINED, tls_segment, 0, 0, elfcpp::STT_TLS, elfcpp::STB_LOCAL, elfcpp::STV_HIDDEN, 0, - (is_exec - ? Symbol::SEGMENT_END - : Symbol::SEGMENT_START), + Symbol::SEGMENT_START, true); } this->tls_base_symbol_defined_ = true; @@ -5614,6 +5741,8 @@ Target_aarch64<size, big_endian>::optimize_tls_reloc(bool is_final, case elfcpp::R_AARCH64_TLSLD_ADD_LO12_NC: case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G1: case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC: + case elfcpp::R_AARCH64_TLSLD_ADD_DTPREL_HI12: + case elfcpp::R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC: // These are Local-Dynamic, which refer to local symbols in the // dynamic TLS block. Since we know that we generating an // executable, we can switch to Local-Exec. @@ -5962,6 +6091,8 @@ Target_aarch64<size, big_endian>::Scan::local( case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G1: case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC: + case elfcpp::R_AARCH64_TLSLD_ADD_DTPREL_HI12: + case elfcpp::R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC: break; case elfcpp::R_AARCH64_TLSDESC_ADR_PAGE21: @@ -6286,7 +6417,9 @@ Target_aarch64<size, big_endian>::Scan::global( break; case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G1: - case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC: // Other local dynamic + case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC: + case elfcpp::R_AARCH64_TLSLD_ADD_DTPREL_HI12: + case elfcpp::R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC: // Other local dynamic break; case elfcpp::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: @@ -6852,6 +6985,8 @@ Target_aarch64<size, big_endian>::Relocate::relocate( case elfcpp::R_AARCH64_TLSLD_ADD_LO12_NC: case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G1: case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC: + case elfcpp::R_AARCH64_TLSLD_ADD_DTPREL_HI12: + case elfcpp::R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC: case elfcpp::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: case elfcpp::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G2: @@ -7049,7 +7184,9 @@ Target_aarch64<size, big_endian>::Relocate::relocate_tls( break; case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G1: - case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC: // Other local-dynamic + case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC: + case elfcpp::R_AARCH64_TLSLD_ADD_DTPREL_HI12: + case elfcpp::R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC: // Other local-dynamic { AArch64_address value = psymval->value(object, 0); if (tlsopt == tls::TLSOPT_TO_LE) @@ -7060,9 +7197,6 @@ Target_aarch64<size, big_endian>::Relocate::relocate_tls( || issue_undefined_symbol_error(gsym)); return aarch64_reloc_funcs::STATUS_BAD_RELOC; } - // If building executable, _TLS_MODULE_BASE_ points to segment - // end. Thus we must subtract it from value. - value -= tls_segment->memsz(); } switch (r_type) { @@ -7072,6 +7206,8 @@ Target_aarch64<size, big_endian>::Relocate::relocate_tls( break; case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC: + case elfcpp::R_AARCH64_TLSLD_ADD_DTPREL_HI12: + case elfcpp::R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC: return aarch64_reloc_funcs::template rela_general<32>( view, value, addend, reloc_property); break; @@ -7867,7 +8003,8 @@ Target_aarch64<size, big_endian>::create_erratum_stub( section_size_type erratum_insn_offset, Address erratum_address, typename Insn_utilities::Insntype erratum_insn, - int erratum_type) + int erratum_type, + unsigned int e843419_adrp_offset) { gold_assert(erratum_type == ST_E_843419 || erratum_type == ST_E_835769); The_stub_table* stub_table = relobj->stub_table(shndx); @@ -7877,8 +8014,15 @@ Target_aarch64<size, big_endian>::create_erratum_stub( erratum_insn_offset) == NULL) { const int BPI = AArch64_insn_utilities<big_endian>::BYTES_PER_INSN; - The_erratum_stub* stub = new The_erratum_stub( - relobj, erratum_type, shndx, erratum_insn_offset); + The_erratum_stub* stub; + if (erratum_type == ST_E_835769) + stub = new The_erratum_stub(relobj, erratum_type, shndx, + erratum_insn_offset); + else if (erratum_type == ST_E_843419) + stub = new E843419_stub<size, big_endian>( + relobj, shndx, erratum_insn_offset, e843419_adrp_offset); + else + gold_unreachable(); stub->set_erratum_insn(erratum_insn); stub->set_erratum_address(erratum_address); // For erratum ST_E_843419 and ST_E_835769, the destination address is @@ -8023,7 +8167,8 @@ Target_aarch64<size, big_endian>::scan_erratum_843419_span( output_address + offset + insn_offset; create_erratum_stub(relobj, shndx, erratum_insn_offset, erratum_address, - erratum_insn, ST_E_843419); + erratum_insn, ST_E_843419, + span_start + offset); } } |