bool needs_special_offset_handling,
unsigned char* view,
elfcpp::Elf_types<64>::Elf_Addr view_address,
- off_t view_size);
+ section_size_type view_size);
+
+ // Scan the relocs during a relocatable link.
+ void
+ scan_relocatable_relocs(const General_options& options,
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj<64, false>* 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_symbols,
+ Relocatable_relocs*);
+
+ // Relocate a section during a relocatable link.
+ void
+ relocate_for_relocatable(const Relocate_info<64, false>*,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ off_t offset_in_output_section,
+ const Relocatable_relocs*,
+ unsigned char* view,
+ elfcpp::Elf_types<64>::Elf_Addr view_address,
+ section_size_type view_size,
+ unsigned char* reloc_view,
+ section_size_type reloc_view_size);
// Return a string used to fill a code section with nops.
std::string
- do_code_fill(off_t length);
+ do_code_fill(section_size_type length);
// Return whether SYM is defined by the ABI.
bool
{ return strcmp(sym->name(), "__tls_get_addr") == 0; }
// Return the size of the GOT section.
- off_t
+ section_size_type
got_size()
{
gold_assert(this->got_ != NULL);
unsigned int r_type, const Sized_symbol<64>*,
const Symbol_value<64>*,
unsigned char*, elfcpp::Elf_types<64>::Elf_Addr,
- off_t);
+ section_size_type);
private:
// Do a TLS relocation.
size_t relnum, const elfcpp::Rela<64, false>&,
unsigned int r_type, const Sized_symbol<64>*,
const Symbol_value<64>*,
- unsigned char*, elfcpp::Elf_types<64>::Elf_Addr, off_t);
+ unsigned char*, elfcpp::Elf_types<64>::Elf_Addr,
+ section_size_type);
// Do a TLS General-Dynamic to Local-Exec transition.
inline void
const elfcpp::Rela<64, false>&, unsigned int r_type,
elfcpp::Elf_types<64>::Elf_Addr value,
unsigned char* view,
- off_t view_size);
+ section_size_type view_size);
// Do a TLS General-Dynamic to Local-Exec transition.
inline void
const elfcpp::Rela<64, false>&, unsigned int r_type,
elfcpp::Elf_types<64>::Elf_Addr value,
unsigned char* view,
- off_t view_size);
+ section_size_type view_size);
// Do a TLS Local-Dynamic to Local-Exec transition.
inline void
const elfcpp::Rela<64, false>&, unsigned int r_type,
elfcpp::Elf_types<64>::Elf_Addr value,
unsigned char* view,
- off_t view_size);
+ section_size_type view_size);
// Do a TLS Initial-Exec to Local-Exec transition.
static inline void
const elfcpp::Rela<64, false>&, unsigned int r_type,
elfcpp::Elf_types<64>::Elf_Addr value,
unsigned char* view,
- off_t view_size);
+ section_size_type view_size);
// This is set if we should skip the next reloc, which should be a
// PLT32 reloc against ___tls_get_addr.
bool skip_call_tls_get_addr_;
};
+ // 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
this->got_plt_->set_current_data_size(3 * 8);
// Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT.
- symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_", NULL,
+ symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
this->got_plt_,
0, 0, elfcpp::STT_OBJECT,
elfcpp::STB_LOCAL,
++this->count_;
- off_t got_offset = this->got_plt_->current_data_size();
+ section_offset_type got_offset = this->got_plt_->current_data_size();
// Every PLT entry needs a GOT entry which points back to the PLT
// entry (this will be changed by the dynamic linker, normally
Output_data_plt_x86_64::do_write(Output_file* of)
{
const off_t offset = this->offset();
- const off_t oview_size = this->data_size();
+ const section_size_type oview_size =
+ convert_to_section_size_type(this->data_size());
unsigned char* const oview = of->get_output_view(offset, oview_size);
const off_t got_file_offset = this->got_plt_->offset();
- const off_t got_size = this->got_plt_->data_size();
+ const section_size_type got_size =
+ convert_to_section_size_type(this->got_plt_->data_size());
unsigned char* const got_view = of->get_output_view(got_file_offset,
got_size);
elfcpp::Swap<64, false>::writeval(got_pov, plt_address + plt_offset + 6);
}
- gold_assert(pov - oview == oview_size);
- gold_assert(got_pov - got_view == got_size);
+ gold_assert(static_cast<section_size_type>(pov - oview) == oview_size);
+ gold_assert(static_cast<section_size_type>(got_pov - got_view) == got_size);
of->write_output_view(offset, oview_size, oview);
of->write_output_view(got_file_offset, got_size, got_view);
if (align > dynbss->addralign())
dynbss->set_space_alignment(align);
- off_t dynbss_size = dynbss->current_data_size();
+ section_size_type dynbss_size = dynbss->current_data_size();
dynbss_size = align_address(dynbss_size, align);
- off_t offset = dynbss_size;
+ section_size_type offset = dynbss_size;
dynbss->set_current_data_size(dynbss_size + symsize);
- symtab->define_with_copy_reloc(this, ssym, dynbss, offset);
+ symtab->define_with_copy_reloc(ssym, dynbss, offset);
// Add the COPY reloc.
Reloc_section* rela_dyn = this->rela_dyn_section(layout);
break;
case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
+ layout->set_has_static_tls();
if (optimized_type == tls::TLSOPT_NONE)
{
// Create a GOT entry for the tp-relative offset.
break;
case elfcpp::R_X86_64_TPOFF32: // Local-exec
+ layout->set_has_static_tls();
if (output_is_shared)
unsupported_reloc_local(object, r_type);
break;
// taking the address of a function. In that case we need to
// set the entry in the dynamic symbol table to the address of
// the PLT entry.
- if (gsym->is_from_dynobj())
+ if (gsym->is_from_dynobj() && !parameters->output_is_shared())
gsym->set_needs_dynsym_value();
}
// Make a dynamic relocation if necessary.
- if (gsym->needs_dynamic_reloc(true, false))
+ if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF))
{
if (target->may_need_copy_reloc(gsym))
{
if (gsym->needs_plt_entry())
target->make_plt_entry(symtab, layout, gsym);
// Make a dynamic relocation if necessary.
- bool is_function_call = (gsym->type() == elfcpp::STT_FUNC);
- if (gsym->needs_dynamic_reloc(false, is_function_call))
+ int flags = Symbol::NON_PIC_REF;
+ if (gsym->type() == elfcpp::STT_FUNC)
+ flags |= Symbol::FUNCTION_CALL;
+ if (gsym->needs_dynamic_reloc(flags))
{
if (target->may_need_copy_reloc(gsym))
{
// If this symbol is not fully resolved, we need to add a
// dynamic relocation for it.
Reloc_section* rela_dyn = target->rela_dyn_section(layout);
- if (gsym->is_from_dynobj() || gsym->is_preemptible())
+ if (gsym->is_from_dynobj()
+ || gsym->is_undefined()
+ || gsym->is_preemptible())
got->add_global_with_rela(gsym, rela_dyn,
elfcpp::R_X86_64_GLOB_DAT);
else
break;
case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
+ layout->set_has_static_tls();
if (optimized_type == tls::TLSOPT_NONE)
{
// Create a GOT entry for the tp-relative offset.
break;
case elfcpp::R_X86_64_TPOFF32: // Local-exec
+ layout->set_has_static_tls();
if (parameters->output_is_shared())
unsupported_reloc_local(object, r_type);
break;
const Symbol_value<64>* psymval,
unsigned char* view,
elfcpp::Elf_types<64>::Elf_Addr address,
- off_t view_size)
+ section_size_type view_size)
{
if (this->skip_call_tls_get_addr_)
{
if (gsym != NULL
&& (gsym->is_from_dynobj()
|| (parameters->output_is_shared()
- && gsym->is_preemptible()))
+ && (gsym->is_undefined() || gsym->is_preemptible())))
&& gsym->has_plt_offset())
{
symval.set_output_value(target->plt_section()->address()
case elfcpp::R_X86_64_PLT32:
gold_assert(gsym == NULL
|| gsym->has_plt_offset()
- || gsym->final_value_is_known());
+ || gsym->final_value_is_known()
+ || (gsym->is_defined()
+ && !gsym->is_from_dynobj()
+ && !gsym->is_preemptible()));
// Note: while this code looks the same as for R_X86_64_PC32, it
// behaves differently because psymval was set to point to
// the PLT entry, rather than the symbol, in Scan::global().
const Symbol_value<64>* psymval,
unsigned char* view,
elfcpp::Elf_types<64>::Elf_Addr address,
- off_t view_size)
+ section_size_type view_size)
{
Output_segment* tls_segment = relinfo->layout->tls_segment();
unsigned int,
elfcpp::Elf_types<64>::Elf_Addr value,
unsigned char* view,
- off_t view_size)
+ section_size_type view_size)
{
// .byte 0x66; leaq foo@tlsgd(%rip),%rdi;
// .word 0x6666; rex64; call __tls_get_addr
unsigned int,
elfcpp::Elf_types<64>::Elf_Addr value,
unsigned char* view,
- off_t view_size)
+ section_size_type view_size)
{
// .byte 0x66; leaq foo@tlsgd(%rip),%rdi;
// .word 0x6666; rex64; call __tls_get_addr
unsigned int,
elfcpp::Elf_types<64>::Elf_Addr,
unsigned char* view,
- off_t view_size)
+ section_size_type view_size)
{
// leaq foo@tlsld(%rip),%rdi; call __tls_get_addr@plt;
// ... leq foo@dtpoff(%rax),%reg
unsigned int,
elfcpp::Elf_types<64>::Elf_Addr value,
unsigned char* view,
- off_t view_size)
+ section_size_type view_size)
{
// We need to examine the opcodes to figure out which instruction we
// are looking at.
bool needs_special_offset_handling,
unsigned char* view,
elfcpp::Elf_types<64>::Elf_Addr address,
- off_t view_size)
+ section_size_type view_size)
{
gold_assert(sh_type == elfcpp::SHT_RELA);
view_size);
}
+// Return the size of a relocation while scanning during a relocatable
+// link.
+
+unsigned int
+Target_x86_64::Relocatable_size_for_reloc::get_size_for_reloc(
+ unsigned int r_type,
+ Relobj* object)
+{
+ switch (r_type)
+ {
+ case elfcpp::R_X86_64_NONE:
+ case elfcpp::R_386_GNU_VTINHERIT:
+ case elfcpp::R_386_GNU_VTENTRY:
+ case elfcpp::R_X86_64_TLSGD: // Global-dynamic
+ case elfcpp::R_X86_64_GOTPC32_TLSDESC: // Global-dynamic (from ~oliva url)
+ case elfcpp::R_X86_64_TLSDESC_CALL:
+ case elfcpp::R_X86_64_TLSLD: // Local-dynamic
+ case elfcpp::R_X86_64_DTPOFF32:
+ case elfcpp::R_X86_64_DTPOFF64:
+ case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
+ case elfcpp::R_X86_64_TPOFF32: // Local-exec
+ return 0;
+
+ case elfcpp::R_X86_64_64:
+ case elfcpp::R_X86_64_PC64:
+ case elfcpp::R_X86_64_GOTOFF64:
+ case elfcpp::R_X86_64_GOTPC64:
+ case elfcpp::R_X86_64_PLTOFF64:
+ case elfcpp::R_X86_64_GOT64:
+ case elfcpp::R_X86_64_GOTPCREL64:
+ case elfcpp::R_X86_64_GOTPCREL:
+ case elfcpp::R_X86_64_GOTPLT64:
+ return 8;
+
+ case elfcpp::R_X86_64_32:
+ case elfcpp::R_X86_64_32S:
+ case elfcpp::R_X86_64_PC32:
+ case elfcpp::R_X86_64_PLT32:
+ case elfcpp::R_X86_64_GOTPC32:
+ case elfcpp::R_X86_64_GOT32:
+ return 4;
+
+ case elfcpp::R_X86_64_16:
+ case elfcpp::R_X86_64_PC16:
+ return 2;
+
+ case elfcpp::R_X86_64_8:
+ case elfcpp::R_X86_64_PC8:
+ return 1;
+
+ case elfcpp::R_X86_64_COPY:
+ case elfcpp::R_X86_64_GLOB_DAT:
+ case elfcpp::R_X86_64_JUMP_SLOT:
+ case elfcpp::R_X86_64_RELATIVE:
+ // These are outstanding tls relocs, which are unexpected when linking
+ case elfcpp::R_X86_64_TPOFF64:
+ case elfcpp::R_X86_64_DTPMOD64:
+ case elfcpp::R_X86_64_TLSDESC:
+ object->error(_("unexpected reloc %u in object file"), r_type);
+ return 0;
+
+ case elfcpp::R_X86_64_SIZE32:
+ case elfcpp::R_X86_64_SIZE64:
+ default:
+ object->error(_("unsupported reloc %u against local symbol"), r_type);
+ return 0;
+ }
+}
+
+// Scan the relocs during a relocatable link.
+
+void
+Target_x86_64::scan_relocatable_relocs(const General_options& options,
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj<64, false>* 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_symbols,
+ Relocatable_relocs* rr)
+{
+ gold_assert(sh_type == elfcpp::SHT_RELA);
+
+ typedef gold::Default_scan_relocatable_relocs<elfcpp::SHT_RELA,
+ Relocatable_size_for_reloc> Scan_relocatable_relocs;
+
+ gold::scan_relocatable_relocs<64, false, Target_x86_64, elfcpp::SHT_RELA,
+ Scan_relocatable_relocs>(
+ options,
+ symtab,
+ layout,
+ object,
+ data_shndx,
+ prelocs,
+ reloc_count,
+ output_section,
+ needs_special_offset_handling,
+ local_symbol_count,
+ plocal_symbols,
+ rr);
+}
+
+// Relocate a section during a relocatable link.
+
+void
+Target_x86_64::relocate_for_relocatable(
+ const Relocate_info<64, false>* relinfo,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ off_t offset_in_output_section,
+ const Relocatable_relocs* rr,
+ unsigned char* view,
+ elfcpp::Elf_types<64>::Elf_Addr view_address,
+ section_size_type view_size,
+ unsigned char* reloc_view,
+ section_size_type reloc_view_size)
+{
+ gold_assert(sh_type == elfcpp::SHT_RELA);
+
+ gold::relocate_for_relocatable<64, false, Target_x86_64, elfcpp::SHT_RELA>(
+ relinfo,
+ prelocs,
+ reloc_count,
+ output_section,
+ offset_in_output_section,
+ rr,
+ view,
+ view_address,
+ view_size,
+ reloc_view,
+ reloc_view_size);
+}
+
// Return the value to use for a dynamic which requires special
// treatment. This is how we support equality comparisons of function
// pointers across shared library boundaries, as described in the
// the specified length.
std::string
-Target_x86_64::do_code_fill(off_t length)
+Target_x86_64::do_code_fill(section_size_type length)
{
if (length >= 16)
{