Powerpc_relobj(const std::string& name, Input_file* input_file, off_t offset,
const typename elfcpp::Ehdr<size, big_endian>& ehdr)
: Sized_relobj_file<size, big_endian>(name, input_file, offset, ehdr),
- special_(0), opd_valid_(false), opd_ent_(), access_from_map_()
+ special_(0), has_small_toc_reloc_(false), opd_valid_(false),
+ opd_ent_(), access_from_map_(), has14_(), stub_table_()
{ }
~Powerpc_relobj()
toc_base_offset() const
{ return 0x8000; }
+ void
+ set_has_small_toc_reloc()
+ { has_small_toc_reloc_ = true; }
+
+ bool
+ has_small_toc_reloc() const
+ { return has_small_toc_reloc_; }
+
void
set_has_14bit_branch(unsigned int shndx)
{
// For 32-bit the .got2 section shdnx, for 64-bit the .opd section shndx.
unsigned int special_;
+ // For 64-bit, whether this object uses small model relocs to access
+ // the toc.
+ bool has_small_toc_reloc_;
+
// Set at the start of gc_process_relocs, when we know opd_ent_
// vector is valid. The flag could be made atomic and set in
// do_read_relocs with memory_order_release and then tested with
return;
to = symval.value(this->object_, 0);
}
+ to += this->addend_;
if (stub_table == NULL)
stub_table = this->object_->stub_table(this->shndx_);
gold_assert(stub_table != NULL);
unsupported_reloc_local(object, r_type);
break;
}
+
+ switch (r_type)
+ {
+ case elfcpp::R_POWERPC_GOT_TLSLD16:
+ case elfcpp::R_POWERPC_GOT_TLSGD16:
+ case elfcpp::R_POWERPC_GOT_TPREL16:
+ case elfcpp::R_POWERPC_GOT_DTPREL16:
+ case elfcpp::R_POWERPC_GOT16:
+ case elfcpp::R_PPC64_GOT16_DS:
+ case elfcpp::R_PPC64_TOC16:
+ case elfcpp::R_PPC64_TOC16_DS:
+ ppc_object->set_has_small_toc_reloc();
+ default:
+ break;
+ }
}
// Report an unsupported relocation against a global symbol.
unsupported_reloc_global(object, r_type, gsym);
break;
}
+
+ switch (r_type)
+ {
+ case elfcpp::R_POWERPC_GOT_TLSLD16:
+ case elfcpp::R_POWERPC_GOT_TLSGD16:
+ case elfcpp::R_POWERPC_GOT_TPREL16:
+ case elfcpp::R_POWERPC_GOT_DTPREL16:
+ case elfcpp::R_POWERPC_GOT16:
+ case elfcpp::R_PPC64_GOT16_DS:
+ case elfcpp::R_PPC64_TOC16:
+ case elfcpp::R_PPC64_TOC16_DS:
+ ppc_object->set_has_small_toc_reloc();
+ default:
+ break;
+ }
}
// Process relocations for gc.
}
}
+// Sort linker created .got section first (for the header), then input
+// sections belonging to files using small model code.
+
+template<bool big_endian>
+class Sort_toc_sections
+{
+ public:
+ bool
+ operator()(const Output_section::Input_section& is1,
+ const Output_section::Input_section& is2) const
+ {
+ if (!is1.is_input_section() && is2.is_input_section())
+ return true;
+ bool small1
+ = (is1.is_input_section()
+ && (static_cast<const Powerpc_relobj<64, big_endian>*>(is1.relobj())
+ ->has_small_toc_reloc()));
+ bool small2
+ = (is2.is_input_section()
+ && (static_cast<const Powerpc_relobj<64, big_endian>*>(is2.relobj())
+ ->has_small_toc_reloc()));
+ return small1 && !small2;
+ }
+};
+
// Finalize the sections.
template<int size, bool big_endian>
// need to mess with the relaxation machinery checkpointing.
this->got_section(symtab, layout);
this->make_brlt_section(layout);
+
+ if (parameters->options().toc_sort())
+ {
+ Output_section* os = this->got_->output_section();
+ if (os != NULL && os->input_sections().size() > 1)
+ std::stable_sort(os->input_sections().begin(),
+ os->input_sections().end(),
+ Sort_toc_sections<big_endian>());
+ }
}
}
case elfcpp::R_POWERPC_GOT_DTPREL16_HA:
case elfcpp::R_POWERPC_GOT16_HA:
case elfcpp::R_PPC64_TOC16_HA:
- if (!parameters->options().no_toc_optimize())
+ if (parameters->options().toc_optimize())
{
Insn* iview = reinterpret_cast<Insn*>(view - 2 * big_endian);
Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
case elfcpp::R_PPC64_GOT16_LO_DS:
case elfcpp::R_PPC64_TOC16_LO:
case elfcpp::R_PPC64_TOC16_LO_DS:
- if (!parameters->options().no_toc_optimize())
+ if (parameters->options().toc_optimize())
{
Insn* iview = reinterpret_cast<Insn*>(view - 2 * big_endian);
Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
{
public:
Target_selector_powerpc()
- : Target_selector(elfcpp::EM_NONE, size, big_endian,
+ : Target_selector(size == 64 ? elfcpp::EM_PPC64 : elfcpp::EM_PPC,
+ size, big_endian,
(size == 64
? (big_endian ? "elf64-powerpc" : "elf64-powerpcle")
: (big_endian ? "elf32-powerpc" : "elf32-powerpcle")),
: (big_endian ? "elf32ppc" : "elf32lppc")))
{ }
- virtual Target*
- do_recognize(Input_file*, off_t, int machine, int, int)
- {
- switch (size)
- {
- case 64:
- if (machine != elfcpp::EM_PPC64)
- return NULL;
- break;
-
- case 32:
- if (machine != elfcpp::EM_PPC)
- return NULL;
- break;
-
- default:
- return NULL;
- }
-
- return this->instantiate_target();
- }
-
virtual Target*
do_instantiate_target()
{ return new Target_powerpc<size, big_endian>(); }