// aarch64.cc -- aarch64 target support for gold.
-// Copyright (C) 2014-2015 Free Software Foundation, Inc.
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
// Written by Jing Yu <jingyu@google.com> and Han Shen <shenhan@google.com>.
// This file is part of gold.
aarch64_ra(Insntype insn)
{ 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; }
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 multiplied 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; }
{ this->erratum_address_ = addr; }
// Comparator used to group Erratum_stubs in a set by (obj, shndx,
- // sh_offset). We do not include 'type' in the calculation, becuase there is
+ // sh_offset). We do not include 'type' in the calculation, because there is
// at most one stub type at (obj, shndx, sh_offset).
bool
operator<(const Erratum_stub<size, big_endian>& k) const
AArch64_address erratum_address_;
}; // 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;
if (aarch64_valid_for_adrp_p(location, dest))
return ST_ADRP_BRANCH;
- if (parameters->options().output_is_position_independent()
- && parameters->options().output_is_executable())
+ // Always use PC-relative addressing in case of -shared or -pie.
+ if (parameters->options().output_is_position_independent())
return ST_LONG_BRANCH_PCREL;
+ // This saves 2 insns per stub, compared to ST_LONG_BRANCH_PCREL.
+ // But is only applicable to non-shared or non-pie.
return ST_LONG_BRANCH_ABS;
}
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>&,
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 & ((1u << 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>
const unsigned char* pshdrs, Output_file* of,
typename Sized_relobj_file<size, big_endian>::Views* pviews)
{
- // Call parent to relocate sections.
- Sized_relobj_file<size, big_endian>::do_relocate_sections(symtab, layout,
- pshdrs, of, pviews);
+ // Relocate the section data.
+ this->relocate_section_range(symtab, layout, pshdrs, of, pviews,
+ 1, this->shnum() - 1);
// We do not generate stubs if doing a relocatable link.
if (parameters->options().relocatable())
// Find the first mapping symbol record within section shndx.
typename Mapping_symbol_info::const_iterator p =
this->mapping_symbol_info_.lower_bound(section_start);
- if (p == this->mapping_symbol_info_.end() || p->first.shndx_ != shndx)
- gold_warning(_("cannot scan executable section %u of %s for Cortex-A53 "
- "erratum because it has no mapping symbols."),
- shndx, this->name().c_str());
while (p != this->mapping_symbol_info_.end() &&
p->first.shndx_ == shndx)
{
const unsigned char* plocal_symbols,
Relocatable_relocs*);
+ // Scan the relocs for --emit-relocs.
+ void
+ emit_relocs_scan(Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_syms,
+ Relocatable_relocs* rr);
+
// Relocate a section during a relocatable link.
void
relocate_relocs(
size_t reloc_count,
Output_section* output_section,
typename elfcpp::Elf_types<size>::Elf_Off offset_in_output_section,
- const Relocatable_relocs*,
unsigned char* view,
typename elfcpp::Elf_types<size>::Elf_Addr view_address,
section_size_type view_size,
// Do a relocation. Return false if the caller should not issue
// any warnings about this relocation.
inline bool
- relocate(const Relocate_info<size, big_endian>*, Target_aarch64*,
- Output_section*,
- size_t relnum, const elfcpp::Rela<size, big_endian>&,
- unsigned int r_type, const Sized_symbol<size>*,
- const Symbol_value<size>*,
+ relocate(const Relocate_info<size, big_endian>*, unsigned int,
+ Target_aarch64*, Output_section*, size_t, const unsigned char*,
+ const Sized_symbol<size>*, const Symbol_value<size>*,
unsigned char*, typename elfcpp::Elf_types<size>::Elf_Addr,
section_size_type);
}; // End of class Relocate
- // A class which returns the size required for a relocation type,
- // used while scanning relocs during a relocatable link.
- class Relocatable_size_for_reloc
- {
- public:
- unsigned int
- get_size_for_reloc(unsigned int, Relobj*);
- };
-
// Adjust TLS relocation type based on the options and whether this
// is a local symbol.
static tls::Tls_optimization
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(
unsigned int shndx, Output_section* output_section,
Symbol* sym, const elfcpp::Rela<size, big_endian>& reloc)
{
+ unsigned int r_type = elfcpp::elf_r_type<size>(reloc.get_r_info());
this->copy_relocs_.copy_reloc(symtab, layout,
symtab->get_sized_symbol<size>(sym),
object, shndx, output_section,
- reloc, this->rela_dyn_section(layout));
+ r_type, reloc.get_r_offset(),
+ reloc.get_r_addend(),
+ this->rela_dyn_section(layout));
}
// Information about this specific target which we pass to the
'\0', // wrap_char
"/lib/ld.so.1", // program interpreter
0x400000, // default_text_segment_address
- 0x1000, // abi_pagesize (overridable by -z max-page-size)
+ 0x10000, // abi_pagesize (overridable by -z max-page-size)
0x1000, // common_pagesize (overridable by -z common-page-size)
false, // isolate_execinstr
0, // rosegment_gap
0, // large_common_section_flags
NULL, // attributes_section
NULL, // attributes_vendor
- "_start" // entry_symbol_name
+ "_start", // entry_symbol_name
+ 32, // hash_entry_size
};
template<>
'\0', // wrap_char
"/lib/ld.so.1", // program interpreter
0x400000, // default_text_segment_address
- 0x1000, // abi_pagesize (overridable by -z max-page-size)
+ 0x10000, // abi_pagesize (overridable by -z max-page-size)
0x1000, // common_pagesize (overridable by -z common-page-size)
false, // isolate_execinstr
0, // rosegment_gap
0, // large_common_section_flags
NULL, // attributes_section
NULL, // attributes_vendor
- "_start" // entry_symbol_name
+ "_start", // entry_symbol_name
+ 32, // hash_entry_size
};
template<>
'\0', // wrap_char
"/lib/ld.so.1", // program interpreter
0x400000, // default_text_segment_address
- 0x1000, // abi_pagesize (overridable by -z max-page-size)
+ 0x10000, // abi_pagesize (overridable by -z max-page-size)
0x1000, // common_pagesize (overridable by -z common-page-size)
false, // isolate_execinstr
0, // rosegment_gap
0, // large_common_section_flags
NULL, // attributes_section
NULL, // attributes_vendor
- "_start" // entry_symbol_name
+ "_start", // entry_symbol_name
+ 32, // hash_entry_size
};
template<>
'\0', // wrap_char
"/lib/ld.so.1", // program interpreter
0x400000, // default_text_segment_address
- 0x1000, // abi_pagesize (overridable by -z max-page-size)
+ 0x10000, // abi_pagesize (overridable by -z max-page-size)
0x1000, // common_pagesize (overridable by -z common-page-size)
false, // isolate_execinstr
0, // rosegment_gap
0, // large_common_section_flags
NULL, // attributes_section
NULL, // attributes_vendor
- "_start" // entry_symbol_name
+ "_start", // entry_symbol_name
+ 32, // hash_entry_size
};
// Get the GOT section, creating it if necessary.
if (!is_defined_in_discarded_section)
{
typedef Sized_relobj_file<size, big_endian> ObjType;
+ if (psymval->is_section_symbol())
+ symval.set_is_section_symbol();
typename ObjType::Compute_final_local_value_status status =
object->compute_final_local_value(r_sym, psymval, &symval,
relinfo->symtab);
static_cast<Valtype>(val | (immed << doffset)));
}
+ public:
+
// Update selected bits in text.
template<int valsize>
: This::STATUS_OVERFLOW);
}
- public:
-
// Construct a B insn. Note, although we group it here with other relocation
// operation, there is actually no 'relocation' involved here.
static inline void
typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>
Reloc_section;
- Output_data_got_aarch64<size, big_endian>* got =
- target->got_section(symtab, layout);
unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
// A local STT_GNU_IFUNC symbol may require a PLT entry.
switch (r_type)
{
+ case elfcpp::R_AARCH64_NONE:
+ break;
+
case elfcpp::R_AARCH64_ABS32:
case elfcpp::R_AARCH64_ABS16:
if (parameters->options().output_is_position_independent())
case elfcpp::R_AARCH64_PREL16:
break;
+ case elfcpp::R_AARCH64_ADR_GOT_PAGE:
+ case elfcpp::R_AARCH64_LD64_GOT_LO12_NC:
+ case elfcpp::R_AARCH64_LD64_GOTPAGE_LO15:
+ // The above relocations are used to access GOT entries.
+ {
+ Output_data_got_aarch64<size, big_endian>* got =
+ target->got_section(symtab, layout);
+ bool is_new = false;
+ // This symbol requires a GOT entry.
+ if (is_ifunc)
+ is_new = got->add_local_plt(object, r_sym, GOT_TYPE_STANDARD);
+ else
+ is_new = got->add_local(object, r_sym, GOT_TYPE_STANDARD);
+ if (is_new && parameters->options().output_is_position_independent())
+ target->rela_dyn_section(layout)->
+ add_local_relative(object,
+ r_sym,
+ elfcpp::R_AARCH64_RELATIVE,
+ got,
+ object->local_got_offset(r_sym,
+ GOT_TYPE_STANDARD),
+ 0,
+ false);
+ }
+ break;
+
+ case elfcpp::R_AARCH64_MOVW_UABS_G0: // 263
+ case elfcpp::R_AARCH64_MOVW_UABS_G0_NC: // 264
+ case elfcpp::R_AARCH64_MOVW_UABS_G1: // 265
+ case elfcpp::R_AARCH64_MOVW_UABS_G1_NC: // 266
+ case elfcpp::R_AARCH64_MOVW_UABS_G2: // 267
+ case elfcpp::R_AARCH64_MOVW_UABS_G2_NC: // 268
+ case elfcpp::R_AARCH64_MOVW_UABS_G3: // 269
+ case elfcpp::R_AARCH64_MOVW_SABS_G0: // 270
+ case elfcpp::R_AARCH64_MOVW_SABS_G1: // 271
+ case elfcpp::R_AARCH64_MOVW_SABS_G2: // 272
+ if (parameters->options().output_is_position_independent())
+ {
+ gold_error(_("%s: unsupported reloc %u in pos independent link."),
+ object->name().c_str(), r_type);
+ }
+ break;
+
case elfcpp::R_AARCH64_LD_PREL_LO19: // 273
case elfcpp::R_AARCH64_ADR_PREL_LO21: // 274
case elfcpp::R_AARCH64_ADR_PREL_PG_HI21: // 275
// Create a GOT entry for the tp-relative offset.
if (!parameters->doing_static_link())
{
+ Output_data_got_aarch64<size, big_endian>* got =
+ target->got_section(symtab, layout);
got->add_local_with_rel(object, r_sym, GOT_TYPE_TLS_OFFSET,
target->rela_dyn_section(layout),
elfcpp::R_AARCH64_TLS_TPREL64);
else if (!object->local_has_got_offset(r_sym,
GOT_TYPE_TLS_OFFSET))
{
+ Output_data_got_aarch64<size, big_endian>* got =
+ target->got_section(symtab, layout);
got->add_local(object, r_sym, GOT_TYPE_TLS_OFFSET);
unsigned int got_offset =
object->local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET);
}
gold_assert(tlsopt == tls::TLSOPT_NONE);
+ Output_data_got_aarch64<size, big_endian>* got =
+ target->got_section(symtab, layout);
got->add_local_pair_with_rel(object,r_sym, data_shndx,
GOT_TYPE_TLS_PAIR,
target->rela_dyn_section(layout),
switch (r_type)
{
+ case elfcpp::R_AARCH64_NONE:
+ break;
+
case elfcpp::R_AARCH64_ABS16:
case elfcpp::R_AARCH64_ABS32:
case elfcpp::R_AARCH64_ABS64:
}
break;
+ case elfcpp::R_AARCH64_MOVW_UABS_G0: // 263
+ case elfcpp::R_AARCH64_MOVW_UABS_G0_NC: // 264
+ case elfcpp::R_AARCH64_MOVW_UABS_G1: // 265
+ case elfcpp::R_AARCH64_MOVW_UABS_G1_NC: // 266
+ case elfcpp::R_AARCH64_MOVW_UABS_G2: // 267
+ case elfcpp::R_AARCH64_MOVW_UABS_G2_NC: // 268
+ case elfcpp::R_AARCH64_MOVW_UABS_G3: // 269
+ case elfcpp::R_AARCH64_MOVW_SABS_G0: // 270
+ case elfcpp::R_AARCH64_MOVW_SABS_G1: // 271
+ case elfcpp::R_AARCH64_MOVW_SABS_G2: // 272
+ if (parameters->options().output_is_position_independent())
+ {
+ gold_error(_("%s: unsupported reloc %u in pos independent link."),
+ object->name().c_str(), r_type);
+ }
+ break;
+
case elfcpp::R_AARCH64_LD_PREL_LO19: // 273
case elfcpp::R_AARCH64_ADR_PREL_LO21: // 274
case elfcpp::R_AARCH64_ADR_PREL_PG_HI21: // 275
case elfcpp::R_AARCH64_ADR_GOT_PAGE:
case elfcpp::R_AARCH64_LD64_GOT_LO12_NC:
+ case elfcpp::R_AARCH64_LD64_GOTPAGE_LO15:
{
- // This pair of relocations is used to access a specific GOT entry.
+ // The above relocations are used to access GOT entries.
// Note a GOT entry is an *address* to a symbol.
// The symbol requires a GOT entry
Output_data_got_aarch64<size, big_endian>* got =
size_t local_symbol_count,
const unsigned char* plocal_symbols)
{
+ typedef Target_aarch64<size, big_endian> Aarch64;
+ typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+ Classify_reloc;
+
if (sh_type == elfcpp::SHT_REL)
{
return;
}
- gold::gc_process_relocs<
- size, big_endian,
- Target_aarch64<size, big_endian>,
- elfcpp::SHT_RELA,
- typename Target_aarch64<size, big_endian>::Scan,
- typename Target_aarch64<size, big_endian>::Relocatable_size_for_reloc>(
+ gold::gc_process_relocs<size, big_endian, Aarch64, Scan, Classify_reloc>(
symtab,
layout,
this,
size_t local_symbol_count,
const unsigned char* plocal_symbols)
{
+ typedef Target_aarch64<size, big_endian> Aarch64;
+ typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+ Classify_reloc;
+
if (sh_type == elfcpp::SHT_REL)
{
gold_error(_("%s: unsupported REL reloc section"),
object->name().c_str());
return;
}
- gold::scan_relocs<size, big_endian, Target_aarch64, elfcpp::SHT_RELA, Scan>(
+
+ gold::scan_relocs<size, big_endian, Aarch64, Scan, Classify_reloc>(
symtab,
layout,
this,
inline bool
Target_aarch64<size, big_endian>::Relocate::relocate(
const Relocate_info<size, big_endian>* relinfo,
+ unsigned int,
Target_aarch64<size, big_endian>* target,
Output_section* ,
size_t relnum,
- const elfcpp::Rela<size, big_endian>& rela,
- unsigned int r_type,
+ const unsigned char* preloc,
const Sized_symbol<size>* gsym,
const Symbol_value<size>* psymval,
unsigned char* view,
typedef AArch64_relocate_functions<size, big_endian> Reloc;
+ const elfcpp::Rela<size, big_endian> rela(preloc);
+ unsigned int r_type = elfcpp::elf_r_type<size>(rela.get_r_info());
const AArch64_reloc_property* reloc_property =
aarch64_reloc_property_table->get_reloc_property(r_type);
break;
case elfcpp::R_AARCH64_ABS64:
+ if (!parameters->options().apply_dynamic_relocs()
+ && parameters->options().output_is_position_independent()
+ && gsym != NULL
+ && gsym->needs_dynamic_reloc(reloc_property->reference_flags())
+ && !gsym->can_use_relative_reloc(false))
+ // We have generated an absolute dynamic relocation, so do not
+ // apply the relocation statically. (Works around bugs in older
+ // Android dynamic linkers.)
+ break;
reloc_status = Reloc::template rela_ua<64>(
view, object, psymval, addend, reloc_property);
break;
case elfcpp::R_AARCH64_ABS32:
+ if (!parameters->options().apply_dynamic_relocs()
+ && parameters->options().output_is_position_independent()
+ && gsym != NULL
+ && gsym->needs_dynamic_reloc(reloc_property->reference_flags()))
+ // We have generated an absolute dynamic relocation, so do not
+ // apply the relocation statically. (Works around bugs in older
+ // Android dynamic linkers.)
+ break;
reloc_status = Reloc::template rela_ua<32>(
view, object, psymval, addend, reloc_property);
break;
case elfcpp::R_AARCH64_ABS16:
+ if (!parameters->options().apply_dynamic_relocs()
+ && parameters->options().output_is_position_independent()
+ && gsym != NULL
+ && gsym->needs_dynamic_reloc(reloc_property->reference_flags()))
+ // We have generated an absolute dynamic relocation, so do not
+ // apply the relocation statically. (Works around bugs in older
+ // Android dynamic linkers.)
+ break;
reloc_status = Reloc::template rela_ua<16>(
view, object, psymval, addend, reloc_property);
break;
view, object, psymval, addend, address, reloc_property);
break;
+ case elfcpp::R_AARCH64_MOVW_UABS_G0:
+ case elfcpp::R_AARCH64_MOVW_UABS_G0_NC:
+ case elfcpp::R_AARCH64_MOVW_UABS_G1:
+ case elfcpp::R_AARCH64_MOVW_UABS_G1_NC:
+ case elfcpp::R_AARCH64_MOVW_UABS_G2:
+ case elfcpp::R_AARCH64_MOVW_UABS_G2_NC:
+ case elfcpp::R_AARCH64_MOVW_UABS_G3:
+ reloc_status = Reloc::template rela_general<32>(
+ view, object, psymval, addend, reloc_property);
+ break;
+ case elfcpp::R_AARCH64_MOVW_SABS_G0:
+ case elfcpp::R_AARCH64_MOVW_SABS_G1:
+ case elfcpp::R_AARCH64_MOVW_SABS_G2:
+ reloc_status = Reloc::movnz(view, psymval->value(object, addend),
+ reloc_property);
+ break;
+
case elfcpp::R_AARCH64_LD_PREL_LO19:
reloc_status = Reloc::template pcrela_general<32>(
view, object, psymval, addend, address, reloc_property);
// Return false to stop further processing this reloc.
return false;
}
- // Fallthrough
+ // Fall through.
case elfcpp::R_AARCH64_JUMP26:
if (Reloc::maybe_apply_stub(r_type, relinfo, rela, view, address,
gsym, psymval, object,
target->stub_group_size_))
break;
- // Fallthrough
+ // Fall through.
case elfcpp::R_AARCH64_TSTBR14:
case elfcpp::R_AARCH64_CONDBR19:
reloc_status = Reloc::template pcrela_general<32>(
view, value, addend, reloc_property);
break;
+ case elfcpp::R_AARCH64_LD64_GOTPAGE_LO15:
+ {
+ gold_assert(have_got_offset);
+ value = target->got_->address() + got_base + got_offset + addend -
+ Reloc::Page(target->got_->address() + got_base);
+ if ((value & 7) != 0)
+ reloc_status = Reloc::STATUS_OVERFLOW;
+ else
+ reloc_status = Reloc::template reloc_common<32>(
+ view, value, reloc_property);
+ break;
+ }
+
case elfcpp::R_AARCH64_TLSGD_ADR_PAGE21:
case elfcpp::R_AARCH64_TLSGD_ADD_LO12_NC:
case elfcpp::R_AARCH64_TLSLD_ADR_PAGE21:
}
if (tlsopt == tls::TLSOPT_TO_IE)
{
- if (tls_segment == NULL)
- {
- gold_assert(parameters->errors()->error_count() > 0
- || issue_undefined_symbol_error(gsym));
- return aarch64_reloc_funcs::STATUS_BAD_RELOC;
- }
return tls_desc_gd_to_ie(relinfo, target, rela, r_type,
view, psymval, got_entry_address,
address);
section_size_type view_size,
const Reloc_symbol_changes* reloc_symbol_changes)
{
- gold_assert(sh_type == elfcpp::SHT_RELA);
+ typedef Target_aarch64<size, big_endian> Aarch64;
typedef typename Target_aarch64<size, big_endian>::Relocate AArch64_relocate;
- gold::relocate_section<size, big_endian, Target_aarch64, elfcpp::SHT_RELA,
- AArch64_relocate, gold::Default_comdat_behavior>(
+ typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+ Classify_reloc;
+
+ gold_assert(sh_type == elfcpp::SHT_RELA);
+
+ gold::relocate_section<size, big_endian, Aarch64, AArch64_relocate,
+ gold::Default_comdat_behavior, Classify_reloc>(
relinfo,
this,
prelocs,
reloc_symbol_changes);
}
-// Return the size of a relocation while scanning during a relocatable
-// link.
-
-template<int size, bool big_endian>
-unsigned int
-Target_aarch64<size, big_endian>::Relocatable_size_for_reloc::
-get_size_for_reloc(
- unsigned int ,
- Relobj* )
-{
- // We will never support SHT_REL relocations.
- gold_unreachable();
- return 0;
-}
-
// Scan the relocs during a relocatable link.
template<int size, bool big_endian>
const unsigned char* plocal_symbols,
Relocatable_relocs* rr)
{
- gold_assert(sh_type == elfcpp::SHT_RELA);
+ typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+ Classify_reloc;
+ typedef gold::Default_scan_relocatable_relocs<Classify_reloc>
+ Scan_relocatable_relocs;
- typedef gold::Default_scan_relocatable_relocs<elfcpp::SHT_RELA,
- Relocatable_size_for_reloc> Scan_relocatable_relocs;
+ gold_assert(sh_type == elfcpp::SHT_RELA);
- gold::scan_relocatable_relocs<size, big_endian, elfcpp::SHT_RELA,
- Scan_relocatable_relocs>(
+ gold::scan_relocatable_relocs<size, big_endian, Scan_relocatable_relocs>(
symtab,
layout,
object,
rr);
}
+// Scan the relocs for --emit-relocs.
+
+template<int size, bool big_endian>
+void
+Target_aarch64<size, big_endian>::emit_relocs_scan(
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_syms,
+ Relocatable_relocs* rr)
+{
+ typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+ Classify_reloc;
+ typedef gold::Default_emit_relocs_strategy<Classify_reloc>
+ Emit_relocs_strategy;
+
+ gold_assert(sh_type == elfcpp::SHT_RELA);
+
+ gold::scan_relocatable_relocs<size, big_endian, Emit_relocs_strategy>(
+ symtab,
+ layout,
+ object,
+ data_shndx,
+ prelocs,
+ reloc_count,
+ output_section,
+ needs_special_offset_handling,
+ local_symbol_count,
+ plocal_syms,
+ rr);
+}
+
// Relocate a section during a relocatable link.
template<int size, bool big_endian>
size_t reloc_count,
Output_section* output_section,
typename elfcpp::Elf_types<size>::Elf_Off offset_in_output_section,
- const Relocatable_relocs* rr,
unsigned char* view,
typename elfcpp::Elf_types<size>::Elf_Addr view_address,
section_size_type view_size,
unsigned char* reloc_view,
section_size_type reloc_view_size)
{
+ typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+ Classify_reloc;
+
gold_assert(sh_type == elfcpp::SHT_RELA);
- gold::relocate_relocs<size, big_endian, elfcpp::SHT_RELA>(
+ gold::relocate_relocs<size, big_endian, Classify_reloc>(
relinfo,
prelocs,
reloc_count,
output_section,
offset_in_output_section,
- rr,
view,
view_address,
view_size,
typename elfcpp::Swap<32,big_endian>::Valtype insn2)
{
uint32_t rt;
- uint32_t rt2;
+ uint32_t rt2 = 0;
uint32_t rn;
uint32_t rm;
uint32_t ra;
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);
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
// "span_start + offset + BPI".
section_size_type erratum_insn_offset = span_start + offset + BPI;
Address erratum_address = output_address + offset + BPI;
- gold_warning(_("Erratum 835769 found and fixed at \"%s\", "
+ gold_info(_("Erratum 835769 found and fixed at \"%s\", "
"section %d, offset 0x%08x."),
relobj->name().c_str(), shndx,
(unsigned int)(span_start + offset));
}
if (do_report)
{
- gold_warning(_("Erratum 843419 found and fixed at \"%s\", "
- "section %d, offset 0x%08x."),
- relobj->name().c_str(), shndx,
- (unsigned int)(span_start + offset));
unsigned int erratum_insn_offset =
span_start + offset + insn_offset;
Address erratum_address =
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);
}
}