// arm.cc -- arm target support for gold.
-// Copyright (C) 2009-2015 Free Software Foundation, Inc.
+// Copyright (C) 2009-2020 Free Software Foundation, Inc.
// Written by Doug Kwan <dougkwan@google.com> based on the i386 code
// by Ian Lance Taylor <iant@google.com>.
// This file also contains borrowed and adapted code from
class Output_data_plt_arm;
template<bool big_endian>
-class Output_data_plt_arm_standard;
+class Output_data_plt_arm_short;
+
+template<bool big_endian>
+class Output_data_plt_arm_long;
template<bool big_endian>
class Stub_table;
// Target::do_select_as_default_target() hook so that we do not spend time
// building the table if we are not linking ARM objects.
//
-// An alternative is to to process the information in arm-reloc.def in
+// An alternative is to process the information in arm-reloc.def in
// compilation time and generate a representation of it in PODs only. That
// way we can avoid initialization when the linker starts.
// Name of key. This is mainly for debugging.
std::string
- name() const;
+ name() const ATTRIBUTE_UNUSED;
private:
// Stub type.
// bits. The default handling of relocatable relocation cannot process these
// relocations. So we have to extend the default code.
-template<bool big_endian, int sh_type, typename Classify_reloc>
+template<bool big_endian, typename Classify_reloc>
class Arm_scan_relocatable_relocs :
- public Default_scan_relocatable_relocs<sh_type, Classify_reloc>
+ public Default_scan_relocatable_relocs<Classify_reloc>
{
public:
// Return the strategy to use for a local symbol which is a section
inline Relocatable_relocs::Reloc_strategy
local_section_strategy(unsigned int r_type, Relobj*)
{
- if (sh_type == elfcpp::SHT_RELA)
+ if (Classify_reloc::sh_type == elfcpp::SHT_RELA)
return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA;
else
{
stub_tables_(), stub_factory_(Stub_factory::get_instance()),
should_force_pic_veneer_(false),
arm_input_section_map_(), attributes_section_data_(NULL),
- fix_cortex_a8_(false), cortex_a8_relocs_info_()
+ fix_cortex_a8_(false), cortex_a8_relocs_info_(),
+ target1_reloc_(elfcpp::R_ARM_ABS32),
+ // This can be any reloc type but usually is R_ARM_GOT_PREL.
+ target2_reloc_(elfcpp::R_ARM_GOT_PREL)
{ }
// Whether we force PCI branch veneers.
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<32, 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);
+
// Emit relocations for a section.
void
relocate_relocs(const Relocate_info<32, big_endian>*,
Output_section* output_section,
typename elfcpp::Elf_types<32>::Elf_Off
offset_in_output_section,
- const Relocatable_relocs*,
unsigned char* view,
Arm_address view_address,
section_size_type view_size,
rel_irelative_section(Layout*);
// Map platform-specific reloc types
- static unsigned int
- get_real_reloc_type(unsigned int r_type);
+ unsigned int
+ get_real_reloc_type(unsigned int r_type) const;
//
// Methods to support stub-generations.
// as the default.
gold_assert(arm_reloc_property_table == NULL);
arm_reloc_property_table = new Arm_reloc_property_table();
+ if (parameters->options().user_set_target1_rel())
+ {
+ // FIXME: This is not strictly compatible with ld, which allows both
+ // --target1-abs and --target-rel to be given.
+ if (parameters->options().user_set_target1_abs())
+ gold_error(_("Cannot use both --target1-abs and --target1-rel."));
+ else
+ this->target1_reloc_ = elfcpp::R_ARM_REL32;
+ }
+ // We don't need to handle --target1-abs because target1_reloc_ is set
+ // to elfcpp::R_ARM_ABS32 in the member initializer list.
+
+ if (parameters->options().user_set_target2())
+ {
+ const char* target2 = parameters->options().target2();
+ if (strcmp(target2, "rel") == 0)
+ this->target2_reloc_ = elfcpp::R_ARM_REL32;
+ else if (strcmp(target2, "abs") == 0)
+ this->target2_reloc_ = elfcpp::R_ARM_ABS32;
+ else if (strcmp(target2, "got-rel") == 0)
+ this->target2_reloc_ = elfcpp::R_ARM_GOT_PREL;
+ else
+ gold_unreachable();
+ }
}
// Virtual function which is set to return true by a target if
Output_data_space* got_irelative)
{
gold_assert(got_plt != NULL && got_irelative != NULL);
- return new Output_data_plt_arm_standard<big_endian>(
+ if (parameters->options().long_plt())
+ return new Output_data_plt_arm_long<big_endian>(
+ layout, got, got_plt, got_irelative);
+ else
+ return new Output_data_plt_arm_short<big_endian>(
layout, got, got_plt, got_irelative);
}
// Do a relocation. Return false if the caller should not issue
// any warnings about this relocation.
inline bool
- relocate(const Relocate_info<32, big_endian>*, Target_arm*,
- Output_section*, size_t relnum,
- const elfcpp::Rel<32, big_endian>&,
- unsigned int r_type, const Sized_symbol<32>*,
- const Symbol_value<32>*,
- unsigned char*, Arm_address,
- section_size_type);
+ relocate(const Relocate_info<32, big_endian>*, unsigned int,
+ Target_arm*, Output_section*, size_t, const unsigned char*,
+ const Sized_symbol<32>*, const Symbol_value<32>*,
+ unsigned char*, Arm_address, section_size_type);
// Return whether we want to pass flag NON_PIC_REF for this
// reloc. This means the relocation type accesses a symbol not via
};
- // A class which returns the size required for a relocation type,
- // used while scanning relocs during a relocatable link.
- class Relocatable_size_for_reloc
+ // A class for inquiring about properties of a relocation,
+ // used while scanning relocs during a relocatable link and
+ // garbage collection.
+ class Classify_reloc :
+ public gold::Default_classify_reloc<elfcpp::SHT_REL, 32, big_endian>
{
public:
- unsigned int
+ typedef typename Reloc_types<elfcpp::SHT_REL, 32, big_endian>::Reloc
+ Reltype;
+
+ // Return the explicit addend of the relocation (return 0 for SHT_REL).
+ static typename elfcpp::Elf_types<32>::Elf_Swxword
+ get_r_addend(const Reltype*)
+ { return 0; }
+
+ // Return the size of the addend of the relocation (only used for SHT_REL).
+ static unsigned int
get_size_for_reloc(unsigned int, Relobj*);
};
unsigned int shndx, Output_section* output_section,
Symbol* sym, const elfcpp::Rel<32, big_endian>& reloc)
{
+ unsigned int r_type = elfcpp::elf_r_type<32>(reloc.get_r_info());
this->copy_relocs_.copy_reloc(symtab, layout,
symtab->get_sized_symbol<32>(sym),
- object, shndx, output_section, reloc,
+ object, shndx, output_section,
+ r_type, reloc.get_r_offset(), 0,
this->rel_dyn_section(layout));
}
bool fix_cortex_a8_;
// Map addresses to relocs for Cortex-A8 erratum.
Cortex_a8_relocs_info cortex_a8_relocs_info_;
+ // What R_ARM_TARGET1 maps to. It can be R_ARM_REL32 or R_ARM_ABS32.
+ unsigned int target1_reloc_;
+ // What R_ARM_TARGET2 maps to. It should be one of R_ARM_REL32, R_ARM_ABS32
+ // and R_ARM_GOT_PREL.
+ unsigned int target2_reloc_;
};
template<bool big_endian>
0, // large_common_section_flags
".ARM.attributes", // attributes_section
"aeabi", // attributes_vendor
- "_start" // entry_symbol_name
+ "_start", // entry_symbol_name
+ 32, // hash_entry_size
+ elfcpp::SHT_PROGBITS, // unwind_section_type
};
// Arm relocate functions class
const Symbol_value<32>* psymval, Arm_address address,
Arm_address thumb_bit);
- // R_ARM_THM_JUMP6: S + A – P
+ // R_ARM_THM_JUMP6: S + A - P
static inline typename This::Status
thm_jump6(unsigned char* view,
const Sized_relobj_file<32, big_endian>* object,
typedef typename elfcpp::Swap<16, big_endian>::Valtype Reltype;
Valtype* wv = reinterpret_cast<Valtype*>(view);
Valtype val = elfcpp::Swap<16, big_endian>::readval(wv);
- // bit[9]:bit[7:3]:’0’ (mask: 0x02f8)
+ // bit[9]:bit[7:3]:'0' (mask: 0x02f8)
Reltype addend = (((val & 0x0200) >> 3) | ((val & 0x00f8) >> 2));
Reltype x = (psymval->value(object, addend) - address);
val = (val & 0xfd07) | ((x & 0x0040) << 3) | ((val & 0x003e) << 2);
: This::STATUS_OKAY);
}
- // R_ARM_THM_JUMP8: S + A – P
+ // R_ARM_THM_JUMP8: S + A - P
static inline typename This::Status
thm_jump8(unsigned char* view,
const Sized_relobj_file<32, big_endian>* object,
: This::STATUS_OKAY);
}
- // R_ARM_THM_JUMP11: S + A – P
+ // R_ARM_THM_JUMP11: S + A - P
static inline typename This::Status
thm_jump11(unsigned char* view,
const Sized_relobj_file<32, big_endian>* object,
{
const Stub_template* stub_template = this->stub_template();
const Insn_template* insns = stub_template->insns();
+ const bool enable_be8 = parameters->options().be8();
- // FIXME: We do not handle BE8 encoding yet.
unsigned char* pov = view;
for (size_t i = 0; i < stub_template->insn_count(); i++)
{
switch (insns[i].type())
{
case Insn_template::THUMB16_TYPE:
- elfcpp::Swap<16, big_endian>::writeval(pov, insns[i].data() & 0xffff);
+ if (enable_be8)
+ elfcpp::Swap<16, false>::writeval(pov, insns[i].data() & 0xffff);
+ else
+ elfcpp::Swap<16, big_endian>::writeval(pov,
+ insns[i].data() & 0xffff);
break;
case Insn_template::THUMB16_SPECIAL_TYPE:
- elfcpp::Swap<16, big_endian>::writeval(
- pov,
- this->thumb16_special(i));
+ if (enable_be8)
+ elfcpp::Swap<16, false>::writeval(pov, this->thumb16_special(i));
+ else
+ elfcpp::Swap<16, big_endian>::writeval(pov,
+ this->thumb16_special(i));
break;
case Insn_template::THUMB32_TYPE:
{
uint32_t hi = (insns[i].data() >> 16) & 0xffff;
uint32_t lo = insns[i].data() & 0xffff;
- elfcpp::Swap<16, big_endian>::writeval(pov, hi);
- elfcpp::Swap<16, big_endian>::writeval(pov + 2, lo);
+ if (enable_be8)
+ {
+ elfcpp::Swap<16, false>::writeval(pov, hi);
+ elfcpp::Swap<16, false>::writeval(pov + 2, lo);
+ }
+ else
+ {
+ elfcpp::Swap<16, big_endian>::writeval(pov, hi);
+ elfcpp::Swap<16, big_endian>::writeval(pov + 2, lo);
+ }
}
break;
case Insn_template::ARM_TYPE:
+ if (enable_be8)
+ elfcpp::Swap<32, false>::writeval(pov, insns[i].data());
+ else
+ elfcpp::Swap<32, big_endian>::writeval(pov, insns[i].data());
+ break;
case Insn_template::DATA_TYPE:
elfcpp::Swap<32, big_endian>::writeval(pov, insns[i].data());
break;
// This is a bit ugly but we want to avoid using a templated class for
// big and little endianities.
bool may_use_blx;
- bool should_force_pic_veneer;
+ bool should_force_pic_veneer = parameters->options().pic_veneer();
bool thumb2;
bool thumb_only;
if (parameters->target().is_big_endian())
const Target_arm<true>* big_endian_target =
Target_arm<true>::default_target();
may_use_blx = big_endian_target->may_use_v5t_interworking();
- should_force_pic_veneer = big_endian_target->should_force_pic_veneer();
+ should_force_pic_veneer |= big_endian_target->should_force_pic_veneer();
thumb2 = big_endian_target->using_thumb2();
thumb_only = big_endian_target->using_thumb_only();
}
const Target_arm<false>* little_endian_target =
Target_arm<false>::default_target();
may_use_blx = little_endian_target->may_use_v5t_interworking();
- should_force_pic_veneer = little_endian_target->should_force_pic_veneer();
+ should_force_pic_veneer |=
+ little_endian_target->should_force_pic_veneer();
thumb2 = little_endian_target->using_thumb2();
thumb_only = little_endian_target->using_thumb_only();
}
Output_file* of,
typename Sized_relobj_file<32, big_endian>::Views* pviews)
{
- // Call parent to relocate sections.
- Sized_relobj_file<32, 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())
section_address,
section_size);
}
+ // BE8 swapping
+ if (parameters->options().be8())
+ {
+ section_size_type span_start, span_end;
+ elfcpp::Shdr<32, big_endian>
+ shdr(pshdrs + i * elfcpp::Elf_sizes<32>::shdr_size);
+ Mapping_symbol_position section_start(i, 0);
+ typename Mapping_symbols_info::const_iterator p =
+ this->mapping_symbols_info_.lower_bound(section_start);
+ unsigned char* view = (*pviews)[i].view;
+ Arm_address view_address = (*pviews)[i].address;
+ section_size_type view_size = (*pviews)[i].view_size;
+ while (p != this->mapping_symbols_info_.end()
+ && p->first.first == i)
+ {
+ typename Mapping_symbols_info::const_iterator next =
+ this->mapping_symbols_info_.upper_bound(p->first);
+
+ // Only swap arm or thumb code.
+ if ((p->second == 'a') || (p->second == 't'))
+ {
+ Output_section* os = this->output_section(i);
+ gold_assert(os != NULL);
+ Arm_address section_address =
+ this->simple_input_section_output_address(i, os);
+ span_start = convert_to_section_size_type(p->first.second);
+ if (next != this->mapping_symbols_info_.end()
+ && next->first.first == i)
+ span_end =
+ convert_to_section_size_type(next->first.second);
+ else
+ span_end =
+ convert_to_section_size_type(shdr.get_sh_size());
+ unsigned char* section_view =
+ view + (section_address - view_address);
+ uint64_t section_size = this->section_size(i);
+
+ gold_assert(section_address >= view_address
+ && ((section_address + section_size)
+ <= (view_address + view_size)));
+
+ // Set Output view for swapping
+ unsigned char *oview = section_view + span_start;
+ unsigned int index = 0;
+ if (p->second == 'a')
+ {
+ while (index + 3 < (span_end - span_start))
+ {
+ typedef typename elfcpp::Swap<32, big_endian>
+ ::Valtype Valtype;
+ Valtype* wv =
+ reinterpret_cast<Valtype*>(oview+index);
+ uint32_t val = elfcpp::Swap<32, false>::readval(wv);
+ elfcpp::Swap<32, true>::writeval(wv, val);
+ index += 4;
+ }
+ }
+ else if (p->second == 't')
+ {
+ while (index + 1 < (span_end - span_start))
+ {
+ typedef typename elfcpp::Swap<16, big_endian>
+ ::Valtype Valtype;
+ Valtype* wv =
+ reinterpret_cast<Valtype*>(oview+index);
+ uint16_t val = elfcpp::Swap<16, false>::readval(wv);
+ elfcpp::Swap<16, true>::writeval(wv, val);
+ index += 2;
+ }
+ }
+ }
+ p = next;
+ }
+ }
}
}
do_first_plt_entry_offset() const
{ return sizeof(first_plt_entry); }
- // Return the size of a PLT entry.
- virtual unsigned int
- do_get_plt_entry_size() const
- { return sizeof(plt_entry); }
-
virtual void
do_fill_first_plt_entry(unsigned char* pov,
Arm_address got_address,
Arm_address plt_address);
- virtual void
- do_fill_plt_entry(unsigned char* pov,
- Arm_address got_address,
- Arm_address plt_address,
- unsigned int got_offset,
- unsigned int plt_offset);
-
private:
// Template for the first PLT entry.
static const uint32_t first_plt_entry[5];
-
- // Template for subsequent PLT entries.
- static const uint32_t plt_entry[3];
};
// ARM PLTs.
{
// Write first PLT entry. All but the last word are constants.
const size_t num_first_plt_words = (sizeof(first_plt_entry)
- / sizeof(plt_entry[0]));
+ / sizeof(first_plt_entry[0]));
for (size_t i = 0; i < num_first_plt_words - 1; i++)
- elfcpp::Swap<32, big_endian>::writeval(pov + i * 4, first_plt_entry[i]);
+ {
+ if (parameters->options().be8())
+ {
+ elfcpp::Swap<32, false>::writeval(pov + i * 4,
+ first_plt_entry[i]);
+ }
+ else
+ {
+ elfcpp::Swap<32, big_endian>::writeval(pov + i * 4,
+ first_plt_entry[i]);
+ }
+ }
// Last word in first PLT entry is &GOT[0] - .
elfcpp::Swap<32, big_endian>::writeval(pov + 16,
got_address - (plt_address + 16));
}
// Subsequent entries in the PLT.
+// This class generates short (12-byte) entries, for displacements up to 2^28.
template<bool big_endian>
-const uint32_t Output_data_plt_arm_standard<big_endian>::plt_entry[3] =
+class Output_data_plt_arm_short : public Output_data_plt_arm_standard<big_endian>
+{
+ public:
+ Output_data_plt_arm_short(Layout* layout,
+ Arm_output_data_got<big_endian>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_data_plt_arm_standard<big_endian>(layout, got, got_plt, got_irelative)
+ { }
+
+ protected:
+ // Return the size of a PLT entry.
+ virtual unsigned int
+ do_get_plt_entry_size() const
+ { return sizeof(plt_entry); }
+
+ virtual void
+ do_fill_plt_entry(unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset);
+
+ private:
+ // Template for subsequent PLT entries.
+ static const uint32_t plt_entry[3];
+};
+
+template<bool big_endian>
+const uint32_t Output_data_plt_arm_short<big_endian>::plt_entry[3] =
{
0xe28fc600, // add ip, pc, #0xNN00000
0xe28cca00, // add ip, ip, #0xNN000
template<bool big_endian>
void
-Output_data_plt_arm_standard<big_endian>::do_fill_plt_entry(
+Output_data_plt_arm_short<big_endian>::do_fill_plt_entry(
unsigned char* pov,
Arm_address got_address,
Arm_address plt_address,
{
int32_t offset = ((got_address + got_offset)
- (plt_address + plt_offset + 8));
+ if (offset < 0 || offset > 0x0fffffff)
+ gold_error(_("PLT offset too large, try linking with --long-plt"));
- gold_assert(offset >= 0 && offset < 0x0fffffff);
uint32_t plt_insn0 = plt_entry[0] | ((offset >> 20) & 0xff);
- elfcpp::Swap<32, big_endian>::writeval(pov, plt_insn0);
uint32_t plt_insn1 = plt_entry[1] | ((offset >> 12) & 0xff);
- elfcpp::Swap<32, big_endian>::writeval(pov + 4, plt_insn1);
uint32_t plt_insn2 = plt_entry[2] | (offset & 0xfff);
- elfcpp::Swap<32, big_endian>::writeval(pov + 8, plt_insn2);
+
+ if (parameters->options().be8())
+ {
+ elfcpp::Swap<32, false>::writeval(pov, plt_insn0);
+ elfcpp::Swap<32, false>::writeval(pov + 4, plt_insn1);
+ elfcpp::Swap<32, false>::writeval(pov + 8, plt_insn2);
+ }
+ else
+ {
+ elfcpp::Swap<32, big_endian>::writeval(pov, plt_insn0);
+ elfcpp::Swap<32, big_endian>::writeval(pov + 4, plt_insn1);
+ elfcpp::Swap<32, big_endian>::writeval(pov + 8, plt_insn2);
+ }
+}
+
+// This class generates long (16-byte) entries, for arbitrary displacements.
+
+template<bool big_endian>
+class Output_data_plt_arm_long : public Output_data_plt_arm_standard<big_endian>
+{
+ public:
+ Output_data_plt_arm_long(Layout* layout,
+ Arm_output_data_got<big_endian>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_data_plt_arm_standard<big_endian>(layout, got, got_plt, got_irelative)
+ { }
+
+ protected:
+ // Return the size of a PLT entry.
+ virtual unsigned int
+ do_get_plt_entry_size() const
+ { return sizeof(plt_entry); }
+
+ virtual void
+ do_fill_plt_entry(unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset);
+
+ private:
+ // Template for subsequent PLT entries.
+ static const uint32_t plt_entry[4];
+};
+
+template<bool big_endian>
+const uint32_t Output_data_plt_arm_long<big_endian>::plt_entry[4] =
+{
+ 0xe28fc200, // add ip, pc, #0xN0000000
+ 0xe28cc600, // add ip, ip, #0xNN00000
+ 0xe28cca00, // add ip, ip, #0xNN000
+ 0xe5bcf000, // ldr pc, [ip, #0xNNN]!
+};
+
+template<bool big_endian>
+void
+Output_data_plt_arm_long<big_endian>::do_fill_plt_entry(
+ unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset)
+{
+ int32_t offset = ((got_address + got_offset)
+ - (plt_address + plt_offset + 8));
+
+ uint32_t plt_insn0 = plt_entry[0] | (offset >> 28);
+ uint32_t plt_insn1 = plt_entry[1] | ((offset >> 20) & 0xff);
+ uint32_t plt_insn2 = plt_entry[2] | ((offset >> 12) & 0xff);
+ uint32_t plt_insn3 = plt_entry[3] | (offset & 0xfff);
+
+ if (parameters->options().be8())
+ {
+ elfcpp::Swap<32, false>::writeval(pov, plt_insn0);
+ elfcpp::Swap<32, false>::writeval(pov + 4, plt_insn1);
+ elfcpp::Swap<32, false>::writeval(pov + 8, plt_insn2);
+ elfcpp::Swap<32, false>::writeval(pov + 12, plt_insn3);
+ }
+ else
+ {
+ elfcpp::Swap<32, big_endian>::writeval(pov, plt_insn0);
+ elfcpp::Swap<32, big_endian>::writeval(pov + 4, plt_insn1);
+ elfcpp::Swap<32, big_endian>::writeval(pov + 8, plt_insn2);
+ elfcpp::Swap<32, big_endian>::writeval(pov + 12, plt_insn3);
+ }
}
// Write out the PLT. This uses the hand-coded instructions above,
if (is_discarded)
return;
- r_type = get_real_reloc_type(r_type);
+ r_type = target->get_real_reloc_type(r_type);
// A local STT_GNU_IFUNC symbol may require a PLT entry.
bool is_ifunc = lsym.get_st_type() == elfcpp::STT_GNU_IFUNC;
&& this->reloc_needs_plt_for_ifunc(object, r_type))
target->make_plt_entry(symtab, layout, gsym);
- r_type = get_real_reloc_type(r_type);
+ r_type = target->get_real_reloc_type(r_type);
switch (r_type)
{
case elfcpp::R_ARM_NONE:
typedef Target_arm<big_endian> Arm;
typedef typename Target_arm<big_endian>::Scan Scan;
- gold::gc_process_relocs<32, big_endian, Arm, elfcpp::SHT_REL, Scan,
- typename Target_arm::Relocatable_size_for_reloc>(
+ gold::gc_process_relocs<32, big_endian, Arm, Scan, Classify_reloc>(
symtab,
layout,
this,
size_t local_symbol_count,
const unsigned char* plocal_symbols)
{
- typedef typename Target_arm<big_endian>::Scan Scan;
if (sh_type == elfcpp::SHT_RELA)
{
gold_error(_("%s: unsupported RELA reloc section"),
return;
}
- gold::scan_relocs<32, big_endian, Target_arm, elfcpp::SHT_REL, Scan>(
+ gold::scan_relocs<32, big_endian, Target_arm, Scan, Classify_reloc>(
symtab,
layout,
this,
inline bool
Target_arm<big_endian>::Relocate::relocate(
const Relocate_info<32, big_endian>* relinfo,
+ unsigned int,
Target_arm* target,
Output_section* output_section,
size_t relnum,
- const elfcpp::Rel<32, big_endian>& rel,
- unsigned int r_type,
+ const unsigned char* preloc,
const Sized_symbol<32>* gsym,
const Symbol_value<32>* psymval,
unsigned char* view,
typedef Arm_relocate_functions<big_endian> Arm_relocate_functions;
- r_type = get_real_reloc_type(r_type);
+ const elfcpp::Rel<32, big_endian> rel(preloc);
+ unsigned int r_type = elfcpp::elf_r_type<32>(rel.get_r_info());
+ r_type = target->get_real_reloc_type(r_type);
const Arm_reloc_property* reloc_property =
arm_reloc_property_table->get_implemented_static_reloc_property(r_type);
if (reloc_property == NULL)
}
}
- gold::relocate_section<32, big_endian, Target_arm, elfcpp::SHT_REL,
- Arm_relocate, gold::Default_comdat_behavior>(
+ gold::relocate_section<32, big_endian, Target_arm, Arm_relocate,
+ gold::Default_comdat_behavior, Classify_reloc>(
relinfo,
this,
prelocs,
template<bool big_endian>
unsigned int
-Target_arm<big_endian>::Relocatable_size_for_reloc::get_size_for_reloc(
+Target_arm<big_endian>::Classify_reloc::get_size_for_reloc(
unsigned int r_type,
Relobj* object)
{
- r_type = get_real_reloc_type(r_type);
+ Target_arm<big_endian>* arm_target =
+ Target_arm<big_endian>::default_target();
+ r_type = arm_target->get_real_reloc_type(r_type);
const Arm_reloc_property* arp =
arm_reloc_property_table->get_implemented_static_reloc_property(r_type);
if (arp != NULL)
const unsigned char* plocal_symbols,
Relocatable_relocs* rr)
{
- gold_assert(sh_type == elfcpp::SHT_REL);
+ typedef Arm_scan_relocatable_relocs<big_endian, Classify_reloc>
+ Scan_relocatable_relocs;
- typedef Arm_scan_relocatable_relocs<big_endian, elfcpp::SHT_REL,
- Relocatable_size_for_reloc> Scan_relocatable_relocs;
+ gold_assert(sh_type == elfcpp::SHT_REL);
- gold::scan_relocatable_relocs<32, big_endian, elfcpp::SHT_REL,
- Scan_relocatable_relocs>(
+ gold::scan_relocatable_relocs<32, big_endian, Scan_relocatable_relocs>(
symtab,
layout,
object,
rr);
}
+// Scan the relocs for --emit-relocs.
+
+template<bool big_endian>
+void
+Target_arm<big_endian>::emit_relocs_scan(Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<32, 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_REL, 32, big_endian>
+ Classify_reloc;
+ typedef gold::Default_emit_relocs_strategy<Classify_reloc>
+ Emit_relocs_strategy;
+
+ gold_assert(sh_type == elfcpp::SHT_REL);
+
+ gold::scan_relocatable_relocs<32, 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);
+}
+
// Emit relocations for a section.
template<bool big_endian>
size_t reloc_count,
Output_section* output_section,
typename elfcpp::Elf_types<32>::Elf_Off offset_in_output_section,
- const Relocatable_relocs* rr,
unsigned char* view,
Arm_address view_address,
section_size_type view_size,
{
gold_assert(sh_type == elfcpp::SHT_REL);
- gold::relocate_relocs<32, big_endian, elfcpp::SHT_REL>(
+ gold::relocate_relocs<32, big_endian, Classify_reloc>(
relinfo,
prelocs,
reloc_count,
output_section,
offset_in_output_section,
- rr,
view,
view_address,
view_size,
//
template<bool big_endian>
unsigned int
-Target_arm<big_endian>::get_real_reloc_type(unsigned int r_type)
+Target_arm<big_endian>::get_real_reloc_type(unsigned int r_type) const
{
switch (r_type)
{
case elfcpp::R_ARM_TARGET1:
- // This is either R_ARM_ABS32 or R_ARM_REL32;
- return elfcpp::R_ARM_ABS32;
+ return this->target1_reloc_;
case elfcpp::R_ARM_TARGET2:
- // This can be any reloc type but usually is R_ARM_GOT_PREL
- return elfcpp::R_ARM_GOT_PREL;
+ return this->target2_reloc_;
default:
return r_type;
e_ident[elfcpp::EI_OSABI] = 0;
e_ident[elfcpp::EI_ABIVERSION] = 0;
- // FIXME: Do EF_ARM_BE8 adjustment.
+ // Do EF_ARM_BE8 adjustment.
+ if (parameters->options().be8() && !big_endian)
+ gold_error("BE8 images only valid in big-endian mode.");
+ if (parameters->options().be8())
+ {
+ flags |= elfcpp::EF_ARM_BE8;
+ this->set_processor_specific_flags(flags);
+ }
// If we're working in EABI_VER5, set the hard/soft float ABI flags
// as appropriate.
}
elfcpp::Ehdr_write<32, big_endian> oehdr(view);
oehdr.put_e_ident(e_ident);
+ oehdr.put_e_flags(this->processor_specific_flags());
}
// do_make_elf_object to override the same function in the base class.
{
case 0:
// Integer divide allowed if instruction contained in
- // archetecture.
+ // architecture.
if (arch == elfcpp::TAG_CPU_ARCH_V7 && (profile == 'R' || profile == 'M'))
return true;
else if (arch >= elfcpp::TAG_CPU_ARCH_V7E_M)
if (in_attr[elfcpp::Tag_MPextension_use].int_value()
!= in_attr[i].int_value())
{
- gold_error(_("%s has has both the current and legacy "
+ gold_error(_("%s has both the current and legacy "
"Tag_MPextension_use attributes"),
name);
}
const Symbol_value<32> *psymval;
bool is_defined_in_discarded_section;
unsigned int shndx;
+ const Symbol* gsym = NULL;
if (r_sym < local_count)
{
sym = NULL;
if (!is_defined_in_discarded_section)
{
typedef Sized_relobj_file<32, big_endian> ObjType;
+ if (psymval->is_section_symbol())
+ symval.set_is_section_symbol();
typename ObjType::Compute_final_local_value_status status =
arm_object->compute_final_local_value(r_sym, psymval, &symval,
relinfo->symtab);
}
else
{
- const Symbol* gsym;
gsym = arm_object->global_symbol(r_sym);
gold_assert(gsym != NULL);
if (gsym->is_forwarder())
Symbol_value<32> symval2;
if (is_defined_in_discarded_section)
{
+ std::string name = arm_object->section_name(relinfo->data_shndx);
+
if (comdat_behavior == CB_UNDETERMINED)
- {
- std::string name = arm_object->section_name(relinfo->data_shndx);
comdat_behavior = default_comdat_behavior.get(name.c_str());
- }
+
if (comdat_behavior == CB_PRETEND)
{
// FIXME: This case does not work for global symbols.
// script.
bool found;
typename elfcpp::Elf_types<32>::Elf_Addr value =
- arm_object->map_to_kept_section(shndx, &found);
+ arm_object->map_to_kept_section(shndx, name, &found);
if (found)
symval2.set_output_value(value + psymval->input_value());
else
}
else
{
- if (comdat_behavior == CB_WARNING)
- gold_warning_at_location(relinfo, i, offset,
- _("relocation refers to discarded "
- "section"));
+ if (comdat_behavior == CB_ERROR)
+ issue_discarded_error(relinfo, i, offset, r_sym, gsym);
symval2.set_output_value(0);
}
symval2.set_no_output_symtab_entry();
elfcpp::Rel_write<32, big_endian> reloc_write(reloc_buffer);
reloc_write.put_r_offset(reloc_offset);
reloc_write.put_r_info(elfcpp::elf_r_info<32>(0, r_type));
- elfcpp::Rel<32, big_endian> rel(reloc_buffer);
- relocate.relocate(relinfo, this, output_section,
- this->fake_relnum_for_stubs, rel, r_type,
+ relocate.relocate(relinfo, elfcpp::SHT_REL, this, output_section,
+ this->fake_relnum_for_stubs, reloc_buffer,
NULL, &symval, view + reloc_offset,
address + reloc_offset, reloc_size);
}
Arm_address target = (pc_for_insn + offset) | (is_blx ? 0 : 1);
- // Add a new stub if destination address in in the same page.
+ // Add a new stub if destination address is in the same page.
if (((address + i) & ~0xfffU) == (target & ~0xfffU))
{
Cortex_a8_stub* stub =
// branch to the stub. We use the THUMB-2 encoding here.
upper_insn = 0xf000U;
lower_insn = 0xb800U;
- // Fall through
+ // Fall through.
case arm_stub_a8_veneer_b:
case arm_stub_a8_veneer_bl:
case arm_stub_a8_veneer_blx:
const Task* task)
{
// We need to look at all the input sections in output in ascending
- // order of of output address. We do that by building a sorted list
+ // order of output address. We do that by building a sorted list
// of output sections by addresses. Then we looks at the output sections
// in order. The input sections in an output section are already sorted
// by addresses within the output section.
0, // large_common_section_flags
".ARM.attributes", // attributes_section
"aeabi", // attributes_vendor
- "_start" // entry_symbol_name
+ "_start", // entry_symbol_name
+ 32, // hash_entry_size
+ elfcpp::SHT_PROGBITS, // unwind_section_type
};
template<bool big_endian>