X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Fx86_64.cc;h=8119983df2ec180fbfc3ff720f923a9dcb43350e;hb=d180bcbd34b9ed5f0062636786ff31c803c2f735;hp=cfc6384cd154b28a534b187209045c0121d7b556;hpb=9dee3b3c89077e7a5dd4720077af0c667534219d;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/x86_64.cc b/gold/x86_64.cc index cfc6384cd1..8119983df2 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -40,6 +40,7 @@ #include "target-select.h" #include "tls.h" #include "freebsd.h" +#include "nacl.h" #include "gc.h" #include "icf.h" @@ -49,6 +50,9 @@ namespace using namespace gold; // A class to handle the PLT data. +// This is an abstract base class that handles most of the linker details +// but does not know the actual contents of PLT entries. The derived +// classes below fill in those details. template class Output_data_plt_x86_64 : public Output_section_data @@ -56,20 +60,23 @@ class Output_data_plt_x86_64 : public Output_section_data public: typedef Output_data_reloc Reloc_section; - Output_data_plt_x86_64(Layout* layout, Output_data_got<64, false>* got, + Output_data_plt_x86_64(Layout* layout, uint64_t addralign, + Output_data_got<64, false>* got, Output_data_space* got_plt, Output_data_space* got_irelative) - : Output_section_data(16), layout_(layout), tlsdesc_rel_(NULL), + : Output_section_data(addralign), layout_(layout), tlsdesc_rel_(NULL), irelative_rel_(NULL), got_(got), got_plt_(got_plt), got_irelative_(got_irelative), count_(0), irelative_count_(0), tlsdesc_got_offset_(-1U), free_list_() { this->init(layout); } - Output_data_plt_x86_64(Layout* layout, Output_data_got<64, false>* got, + Output_data_plt_x86_64(Layout* layout, uint64_t plt_entry_size, + Output_data_got<64, false>* got, Output_data_space* got_plt, Output_data_space* got_irelative, unsigned int plt_count) - : Output_section_data((plt_count + 1) * plt_entry_size, 16, false), + : Output_section_data((plt_count + 1) * plt_entry_size, + plt_entry_size, false), layout_(layout), tlsdesc_rel_(NULL), irelative_rel_(NULL), got_(got), got_plt_(got_plt), got_irelative_(got_irelative), count_(plt_count), irelative_count_(0), tlsdesc_got_offset_(-1U), free_list_() @@ -118,7 +125,10 @@ class Output_data_plt_x86_64 : public Output_section_data // Return the offset of the reserved TLSDESC_PLT entry. unsigned int get_tlsdesc_plt_offset() const - { return (this->count_ + this->irelative_count_ + 1) * plt_entry_size; } + { + return ((this->count_ + this->irelative_count_ + 1) + * this->get_plt_entry_size()); + } // Return the .rela.plt section data. Reloc_section* @@ -145,21 +155,21 @@ class Output_data_plt_x86_64 : public Output_section_data { return this->count_ + this->irelative_count_; } // Return the offset of the first non-reserved PLT entry. - static unsigned int + unsigned int first_plt_entry_offset() - { return plt_entry_size; } + { return this->get_plt_entry_size(); } // Return the size of a PLT entry. - static unsigned int - get_plt_entry_size() - { return plt_entry_size; } + unsigned int + get_plt_entry_size() const + { return this->do_get_plt_entry_size(); } // Reserve a slot in the PLT for an existing symbol in an incremental update. void reserve_slot(unsigned int plt_index) { - this->free_list_.remove((plt_index + 1) * plt_entry_size, - (plt_index + 2) * plt_entry_size); + this->free_list_.remove((plt_index + 1) * this->get_plt_entry_size(), + (plt_index + 2) * this->get_plt_entry_size()); } // Return the PLT address to use for a global symbol. @@ -170,7 +180,74 @@ class Output_data_plt_x86_64 : public Output_section_data uint64_t address_for_local(const Relobj*, unsigned int symndx); + // Add .eh_frame information for the PLT. + void + add_eh_frame(Layout* layout) + { this->do_add_eh_frame(layout); } + protected: + // Fill in the first PLT entry. + void + fill_first_plt_entry(unsigned char* pov, + typename elfcpp::Elf_types::Elf_Addr got_address, + typename elfcpp::Elf_types::Elf_Addr plt_address) + { this->do_fill_first_plt_entry(pov, got_address, plt_address); } + + // Fill in a normal PLT entry. Returns the offset into the entry that + // should be the initial GOT slot value. + unsigned int + fill_plt_entry(unsigned char* pov, + typename elfcpp::Elf_types::Elf_Addr got_address, + typename elfcpp::Elf_types::Elf_Addr plt_address, + unsigned int got_offset, + unsigned int plt_offset, + unsigned int plt_index) + { + return this->do_fill_plt_entry(pov, got_address, plt_address, + got_offset, plt_offset, plt_index); + } + + // Fill in the reserved TLSDESC PLT entry. + void + fill_tlsdesc_entry(unsigned char* pov, + typename elfcpp::Elf_types::Elf_Addr got_address, + typename elfcpp::Elf_types::Elf_Addr plt_address, + typename elfcpp::Elf_types::Elf_Addr got_base, + unsigned int tlsdesc_got_offset, + unsigned int plt_offset) + { + this->do_fill_tlsdesc_entry(pov, got_address, plt_address, got_base, + tlsdesc_got_offset, plt_offset); + } + + virtual unsigned int + do_get_plt_entry_size() const = 0; + + virtual void + do_fill_first_plt_entry(unsigned char* pov, + typename elfcpp::Elf_types::Elf_Addr got_addr, + typename elfcpp::Elf_types::Elf_Addr plt_addr) + = 0; + + virtual unsigned int + do_fill_plt_entry(unsigned char* pov, + typename elfcpp::Elf_types::Elf_Addr got_address, + typename elfcpp::Elf_types::Elf_Addr plt_address, + unsigned int got_offset, + unsigned int plt_offset, + unsigned int plt_index) = 0; + + virtual void + do_fill_tlsdesc_entry(unsigned char* pov, + typename elfcpp::Elf_types::Elf_Addr got_address, + typename elfcpp::Elf_types::Elf_Addr plt_address, + typename elfcpp::Elf_types::Elf_Addr got_base, + unsigned int tlsdesc_got_offset, + unsigned int plt_offset) = 0; + + virtual void + do_add_eh_frame(Layout* layout) = 0; + void do_adjust_output_section(Output_section* os); @@ -179,27 +256,11 @@ class Output_data_plt_x86_64 : public Output_section_data do_print_to_mapfile(Mapfile* mapfile) const { mapfile->print_output_data(this, _("** PLT")); } - private: - // The size of an entry in the PLT. - static const int plt_entry_size = 16; - - // The first entry in the PLT. - // From the AMD64 ABI: "Unlike Intel386 ABI, this ABI uses the same - // procedure linkage table for both programs and shared objects." - static const unsigned char first_plt_entry[plt_entry_size]; - - // Other entries in the PLT for an executable. - static const unsigned char plt_entry[plt_entry_size]; - - // The reserved TLSDESC entry in the PLT for an executable. - static const unsigned char tlsdesc_plt_entry[plt_entry_size]; - - // The .eh_frame unwind information for the PLT. + // The CIE of the .eh_frame unwind information for the PLT. static const int plt_eh_frame_cie_size = 16; - static const int plt_eh_frame_fde_size = 32; static const unsigned char plt_eh_frame_cie[plt_eh_frame_cie_size]; - static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size]; + private: // Set the final size. void set_final_data_size(); @@ -237,6 +298,84 @@ class Output_data_plt_x86_64 : public Output_section_data Free_list free_list_; }; +template +class Output_data_plt_x86_64_standard : public Output_data_plt_x86_64 +{ + public: + Output_data_plt_x86_64_standard(Layout* layout, + Output_data_got<64, false>* got, + Output_data_space* got_plt, + Output_data_space* got_irelative) + : Output_data_plt_x86_64(layout, plt_entry_size, + got, got_plt, got_irelative) + { } + + Output_data_plt_x86_64_standard(Layout* layout, + Output_data_got<64, false>* got, + Output_data_space* got_plt, + Output_data_space* got_irelative, + unsigned int plt_count) + : Output_data_plt_x86_64(layout, plt_entry_size, + got, got_plt, got_irelative, + plt_count) + { } + + protected: + virtual unsigned int + do_get_plt_entry_size() const + { return plt_entry_size; } + + virtual void + do_add_eh_frame(Layout* layout) + { + layout->add_eh_frame_for_plt(this, + this->plt_eh_frame_cie, + this->plt_eh_frame_cie_size, + plt_eh_frame_fde, + plt_eh_frame_fde_size); + } + + virtual void + do_fill_first_plt_entry(unsigned char* pov, + typename elfcpp::Elf_types::Elf_Addr got_addr, + typename elfcpp::Elf_types::Elf_Addr plt_addr); + + virtual unsigned int + do_fill_plt_entry(unsigned char* pov, + typename elfcpp::Elf_types::Elf_Addr got_address, + typename elfcpp::Elf_types::Elf_Addr plt_address, + unsigned int got_offset, + unsigned int plt_offset, + unsigned int plt_index); + + virtual void + do_fill_tlsdesc_entry(unsigned char* pov, + typename elfcpp::Elf_types::Elf_Addr got_address, + typename elfcpp::Elf_types::Elf_Addr plt_address, + typename elfcpp::Elf_types::Elf_Addr got_base, + unsigned int tlsdesc_got_offset, + unsigned int plt_offset); + + private: + // The size of an entry in the PLT. + static const int plt_entry_size = 16; + + // The first entry in the PLT. + // From the AMD64 ABI: "Unlike Intel386 ABI, this ABI uses the same + // procedure linkage table for both programs and shared objects." + static const unsigned char first_plt_entry[plt_entry_size]; + + // Other entries in the PLT for an executable. + static const unsigned char plt_entry[plt_entry_size]; + + // The reserved TLSDESC entry in the PLT for an executable. + static const unsigned char tlsdesc_plt_entry[plt_entry_size]; + + // The .eh_frame unwind information for the PLT. + static const int plt_eh_frame_fde_size = 32; + static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size]; +}; + // The x86_64 target class. // See the ABI at // http://www.x86-64.org/documentation/abi.pdf @@ -252,8 +391,8 @@ class Target_x86_64 : public Sized_target // uses only Elf64_Rela relocation entries with explicit addends." typedef Output_data_reloc Reloc_section; - Target_x86_64() - : Sized_target(&x86_64_info), + Target_x86_64(const Target::Target_info* info = &x86_64_info) + : Sized_target(info), got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL), got_tlsdesc_(NULL), global_offset_table_(NULL), rela_dyn_(NULL), rela_irelative_(NULL), copy_relocs_(elfcpp::R_X86_64_COPY), @@ -268,16 +407,16 @@ class Target_x86_64 : public Sized_target // Scan the relocations to look for symbol adjustments. void gc_process_relocs(Symbol_table* symtab, - Layout* layout, - Sized_relobj_file* 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); + Layout* layout, + Sized_relobj_file* 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); // Scan the relocations to look for symbol adjustments. void @@ -330,15 +469,15 @@ class Target_x86_64 : public Sized_target const unsigned char* plocal_symbols, Relocatable_relocs*); - // Relocate a section during a relocatable link. + // Emit relocations for a section. void - relocate_for_relocatable( + relocate_relocs( const Relocate_info*, unsigned int sh_type, const unsigned char* prelocs, size_t reloc_count, Output_section* output_section, - off_t offset_in_output_section, + typename elfcpp::Elf_types::Elf_Off offset_in_output_section, const Relocatable_relocs*, unsigned char* view, typename elfcpp::Elf_types::Elf_Addr view_address, @@ -439,7 +578,7 @@ class Target_x86_64 : public Sized_target // necessary dynamic relocations. void reserve_local_got_entry(unsigned int got_index, - Sized_relobj* obj, + Sized_relobj* obj, unsigned int r_sym, unsigned int got_type); @@ -477,6 +616,48 @@ class Target_x86_64 : public Sized_target return this->tlsdesc_reloc_info_.size() - 1; } + Output_data_plt_x86_64* + make_data_plt(Layout* layout, + Output_data_got<64, false>* got, + Output_data_space* got_plt, + Output_data_space* got_irelative) + { + return this->do_make_data_plt(layout, got, got_plt, got_irelative); + } + + Output_data_plt_x86_64* + make_data_plt(Layout* layout, + Output_data_got<64, false>* got, + Output_data_space* got_plt, + Output_data_space* got_irelative, + unsigned int plt_count) + { + return this->do_make_data_plt(layout, got, got_plt, got_irelative, + plt_count); + } + + virtual Output_data_plt_x86_64* + do_make_data_plt(Layout* layout, + Output_data_got<64, false>* got, + Output_data_space* got_plt, + Output_data_space* got_irelative) + { + return new Output_data_plt_x86_64_standard(layout, got, got_plt, + got_irelative); + } + + virtual Output_data_plt_x86_64* + do_make_data_plt(Layout* layout, + Output_data_got<64, false>* got, + Output_data_space* got_plt, + Output_data_space* got_irelative, + unsigned int plt_count) + { + return new Output_data_plt_x86_64_standard(layout, got, got_plt, + got_irelative, + plt_count); + } + private: // The class which scans relocations. class Scan @@ -495,7 +676,8 @@ class Target_x86_64 : public Sized_target unsigned int data_shndx, Output_section* output_section, const elfcpp::Rela& reloc, unsigned int r_type, - const elfcpp::Sym& lsym); + const elfcpp::Sym& lsym, + bool is_discarded); inline void global(Symbol_table* symtab, Layout* layout, Target_x86_64* target, @@ -508,22 +690,22 @@ class Target_x86_64 : public Sized_target inline bool local_reloc_may_be_function_pointer(Symbol_table* symtab, Layout* layout, Target_x86_64* target, - Sized_relobj_file* object, - unsigned int data_shndx, - Output_section* output_section, - const elfcpp::Rela& reloc, + Sized_relobj_file* object, + unsigned int data_shndx, + Output_section* output_section, + const elfcpp::Rela& reloc, unsigned int r_type, - const elfcpp::Sym& lsym); + const elfcpp::Sym& lsym); inline bool global_reloc_may_be_function_pointer(Symbol_table* symtab, Layout* layout, - Target_x86_64* target, - Sized_relobj_file* object, - unsigned int data_shndx, - Output_section* output_section, - const elfcpp::Rela& reloc, + Target_x86_64* target, + Sized_relobj_file* object, + unsigned int data_shndx, + Output_section* output_section, + const elfcpp::Rela& reloc, unsigned int r_type, - Symbol* gsym); + Symbol* gsym); private: static void @@ -580,7 +762,7 @@ class Target_x86_64 : public Sized_target // Do a TLS relocation. inline void relocate_tls(const Relocate_info*, Target_x86_64*, - size_t relnum, const elfcpp::Rela&, + size_t relnum, const elfcpp::Rela&, unsigned int r_type, const Sized_symbol*, const Symbol_value*, unsigned char*, typename elfcpp::Elf_types::Elf_Addr, @@ -731,7 +913,7 @@ class Target_x86_64 : public Sized_target // Add a potential copy relocation. void copy_reloc(Symbol_table* symtab, Layout* layout, - Sized_relobj_file* object, + Sized_relobj_file* object, unsigned int shndx, Output_section* output_section, Symbol* sym, const elfcpp::Rela& reloc) { @@ -818,6 +1000,8 @@ const Target::Target_info Target_x86_64<64>::x86_64_info = 0x400000, // default_text_segment_address 0x1000, // abi_pagesize (overridable by -z max-page-size) 0x1000, // common_pagesize (overridable by -z common-page-size) + false, // isolate_execinstr + 0, // rosegment_gap elfcpp::SHN_UNDEF, // small_common_shndx elfcpp::SHN_X86_64_LCOMMON, // large_common_shndx 0, // small_common_section_flags @@ -842,6 +1026,8 @@ const Target::Target_info Target_x86_64<32>::x86_64_info = 0x400000, // default_text_segment_address 0x1000, // abi_pagesize (overridable by -z max-page-size) 0x1000, // common_pagesize (overridable by -z common-page-size) + false, // isolate_execinstr + 0, // rosegment_gap elfcpp::SHN_UNDEF, // small_common_shndx elfcpp::SHN_X86_64_LCOMMON, // large_common_shndx 0, // small_common_section_flags @@ -988,18 +1174,13 @@ Output_data_plt_x86_64::init(Layout* layout) layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA, elfcpp::SHF_ALLOC, this->rel_, ORDER_DYNAMIC_PLT_RELOCS, false); - - // Add unwind information if requested. - if (parameters->options().ld_generated_unwind_info()) - layout->add_eh_frame_for_plt(this, plt_eh_frame_cie, plt_eh_frame_cie_size, - plt_eh_frame_fde, plt_eh_frame_fde_size); } template void Output_data_plt_x86_64::do_adjust_output_section(Output_section* os) { - os->set_entsize(plt_entry_size); + os->set_entsize(this->get_plt_entry_size()); } // Add an entry to the PLT. @@ -1040,7 +1221,7 @@ Output_data_plt_x86_64::add_entry(Symbol_table* symtab, Layout* layout, // Note that when setting the PLT offset for a non-IRELATIVE // entry we skip the initial reserved PLT entry. plt_index = *pcount + offset; - plt_offset = plt_index * plt_entry_size; + plt_offset = plt_index * this->get_plt_entry_size(); ++*pcount; @@ -1057,7 +1238,8 @@ Output_data_plt_x86_64::add_entry(Symbol_table* symtab, Layout* layout, // FIXME: This is probably not correct for IRELATIVE relocs. // For incremental updates, find an available slot. - plt_offset = this->free_list_.allocate(plt_entry_size, plt_entry_size, 0); + plt_offset = this->free_list_.allocate(this->get_plt_entry_size(), + this->get_plt_entry_size(), 0); if (plt_offset == -1) gold_fallback(_("out of patch space (PLT);" " relink with --incremental-full")); @@ -1065,7 +1247,7 @@ Output_data_plt_x86_64::add_entry(Symbol_table* symtab, Layout* layout, // The GOT and PLT entries have a 1-1 correspondance, so the GOT offset // can be calculated from the PLT index, adjusting for the three // reserved entries at the beginning of the GOT. - plt_index = plt_offset / plt_entry_size - 1; + plt_index = plt_offset / this->get_plt_entry_size() - 1; got_offset = (plt_index - offset + reserved) * 8; } @@ -1090,7 +1272,7 @@ Output_data_plt_x86_64::add_local_ifunc_entry( Sized_relobj_file* relobj, unsigned int local_sym_index) { - unsigned int plt_offset = this->irelative_count_ * plt_entry_size; + unsigned int plt_offset = this->irelative_count_ * this->get_plt_entry_size(); ++this->irelative_count_; section_offset_type got_offset = this->got_irelative_->current_data_size(); @@ -1202,8 +1384,8 @@ Output_data_plt_x86_64::address_for_global(const Symbol* gsym) uint64_t offset = 0; if (gsym->type() == elfcpp::STT_GNU_IFUNC && gsym->can_use_relative_reloc(false)) - offset = (this->count_ + 1) * plt_entry_size; - return this->address() + offset; + offset = (this->count_ + 1) * this->get_plt_entry_size(); + return this->address() + offset + gsym->plt_offset(); } // Return the PLT address to use for a local symbol. These are always @@ -1211,9 +1393,12 @@ Output_data_plt_x86_64::address_for_global(const Symbol* gsym) template uint64_t -Output_data_plt_x86_64::address_for_local(const Relobj*, unsigned int) +Output_data_plt_x86_64::address_for_local(const Relobj* object, + unsigned int r_sym) { - return this->address() + (this->count_ + 1) * plt_entry_size; + return (this->address() + + (this->count_ + 1) * this->get_plt_entry_size() + + object->local_plt_offset(r_sym)); } // Set the final size. @@ -1224,14 +1409,14 @@ Output_data_plt_x86_64::set_final_data_size() unsigned int count = this->count_ + this->irelative_count_; if (this->has_tlsdesc_entry()) ++count; - this->set_data_size((count + 1) * plt_entry_size); + this->set_data_size((count + 1) * this->get_plt_entry_size()); } // The first entry in the PLT for an executable. template const unsigned char -Output_data_plt_x86_64::first_plt_entry[plt_entry_size] = +Output_data_plt_x86_64_standard::first_plt_entry[plt_entry_size] = { // From AMD64 ABI Draft 0.98, page 76 0xff, 0x35, // pushq contents of memory address @@ -1241,11 +1426,28 @@ Output_data_plt_x86_64::first_plt_entry[plt_entry_size] = 0x90, 0x90, 0x90, 0x90 // noop (x4) }; +template +void +Output_data_plt_x86_64_standard::do_fill_first_plt_entry( + unsigned char* pov, + typename elfcpp::Elf_types::Elf_Addr got_address, + typename elfcpp::Elf_types::Elf_Addr plt_address) +{ + memcpy(pov, first_plt_entry, plt_entry_size); + // We do a jmp relative to the PC at the end of this instruction. + elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, + (got_address + 8 + - (plt_address + 6))); + elfcpp::Swap<32, false>::writeval(pov + 8, + (got_address + 16 + - (plt_address + 12))); +} + // Subsequent entries in the PLT for an executable. template const unsigned char -Output_data_plt_x86_64::plt_entry[plt_entry_size] = +Output_data_plt_x86_64_standard::plt_entry[plt_entry_size] = { // From AMD64 ABI Draft 0.98, page 76 0xff, 0x25, // jmpq indirect @@ -1256,11 +1458,34 @@ Output_data_plt_x86_64::plt_entry[plt_entry_size] = 0, 0, 0, 0 // replaced with offset to start of .plt }; +template +unsigned int +Output_data_plt_x86_64_standard::do_fill_plt_entry( + unsigned char* pov, + typename elfcpp::Elf_types::Elf_Addr got_address, + typename elfcpp::Elf_types::Elf_Addr plt_address, + unsigned int got_offset, + unsigned int plt_offset, + unsigned int plt_index) +{ + memcpy(pov, plt_entry, plt_entry_size); + elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, + (got_address + got_offset + - (plt_address + plt_offset + + 6))); + + elfcpp::Swap_unaligned<32, false>::writeval(pov + 7, plt_index); + elfcpp::Swap<32, false>::writeval(pov + 12, + - (plt_offset + plt_entry_size)); + + return 6; +} + // The reserved TLSDESC entry in the PLT for an executable. template const unsigned char -Output_data_plt_x86_64::tlsdesc_plt_entry[plt_entry_size] = +Output_data_plt_x86_64_standard::tlsdesc_plt_entry[plt_entry_size] = { // From Alexandre Oliva, "Thread-Local Storage Descriptors for IA32 // and AMD64/EM64T", Version 0.9.4 (2005-10-10). @@ -1272,10 +1497,32 @@ Output_data_plt_x86_64::tlsdesc_plt_entry[plt_entry_size] = 0x40, 0 }; +template +void +Output_data_plt_x86_64_standard::do_fill_tlsdesc_entry( + unsigned char* pov, + typename elfcpp::Elf_types::Elf_Addr got_address, + typename elfcpp::Elf_types::Elf_Addr plt_address, + typename elfcpp::Elf_types::Elf_Addr got_base, + unsigned int tlsdesc_got_offset, + unsigned int plt_offset) +{ + memcpy(pov, tlsdesc_plt_entry, plt_entry_size); + elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, + (got_address + 8 + - (plt_address + plt_offset + + 6))); + elfcpp::Swap_unaligned<32, false>::writeval(pov + 8, + (got_base + + tlsdesc_got_offset + - (plt_address + plt_offset + + 12))); +} + // The .eh_frame unwind information for the PLT. template -const unsigned char +const unsigned char Output_data_plt_x86_64::plt_eh_frame_cie[plt_eh_frame_cie_size] = { 1, // CIE version. @@ -1296,7 +1543,7 @@ Output_data_plt_x86_64::plt_eh_frame_cie[plt_eh_frame_cie_size] = template const unsigned char -Output_data_plt_x86_64::plt_eh_frame_fde[plt_eh_frame_fde_size] = +Output_data_plt_x86_64_standard::plt_eh_frame_fde[plt_eh_frame_fde_size] = { 0, 0, 0, 0, // Replaced with offset to .plt. 0, 0, 0, 0, // Replaced with size of .plt. @@ -1356,15 +1603,8 @@ Output_data_plt_x86_64::do_write(Output_file* of) typename elfcpp::Elf_types::Elf_Addr got_address = this->got_plt_->address(); - memcpy(pov, first_plt_entry, plt_entry_size); - // We do a jmp relative to the PC at the end of this instruction. - elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, - (got_address + 8 - - (plt_address + 6))); - elfcpp::Swap<32, false>::writeval(pov + 8, - (got_address + 16 - - (plt_address + 12))); - pov += plt_entry_size; + this->fill_first_plt_entry(pov, got_address, plt_address); + pov += this->get_plt_entry_size(); unsigned char* got_pov = got_view; @@ -1379,47 +1619,35 @@ Output_data_plt_x86_64::do_write(Output_file* of) memset(got_pov, 0, 16); got_pov += 16; - unsigned int plt_offset = plt_entry_size; + unsigned int plt_offset = this->get_plt_entry_size(); unsigned int got_offset = 24; const unsigned int count = this->count_ + this->irelative_count_; for (unsigned int plt_index = 0; plt_index < count; ++plt_index, - pov += plt_entry_size, + pov += this->get_plt_entry_size(), got_pov += 8, - plt_offset += plt_entry_size, + plt_offset += this->get_plt_entry_size(), got_offset += 8) { // Set and adjust the PLT entry itself. - memcpy(pov, plt_entry, plt_entry_size); - elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, - (got_address + got_offset - - (plt_address + plt_offset - + 6))); - - elfcpp::Swap_unaligned<32, false>::writeval(pov + 7, plt_index); - elfcpp::Swap<32, false>::writeval(pov + 12, - - (plt_offset + plt_entry_size)); + unsigned int lazy_offset = this->fill_plt_entry(pov, + got_address, plt_address, + got_offset, plt_offset, + plt_index); // Set the entry in the GOT. - elfcpp::Swap<64, false>::writeval(got_pov, plt_address + plt_offset + 6); + elfcpp::Swap<64, false>::writeval(got_pov, + plt_address + plt_offset + lazy_offset); } if (this->has_tlsdesc_entry()) { // Set and adjust the reserved TLSDESC PLT entry. unsigned int tlsdesc_got_offset = this->get_tlsdesc_got_offset(); - memcpy(pov, tlsdesc_plt_entry, plt_entry_size); - elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, - (got_address + 8 - - (plt_address + plt_offset - + 6))); - elfcpp::Swap_unaligned<32, false>::writeval(pov + 8, - (got_base - + tlsdesc_got_offset - - (plt_address + plt_offset - + 12))); - pov += plt_entry_size; + this->fill_tlsdesc_entry(pov, got_address, plt_address, got_base, + tlsdesc_got_offset, plt_offset); + pov += this->get_plt_entry_size(); } gold_assert(static_cast(pov - oview) == oview_size); @@ -1440,9 +1668,13 @@ Target_x86_64::make_plt_section(Symbol_table* symtab, Layout* layout) // Create the GOT sections first. this->got_section(symtab, layout); - this->plt_ = new Output_data_plt_x86_64(layout, this->got_, - this->got_plt_, - this->got_irelative_); + this->plt_ = this->make_data_plt(layout, this->got_, this->got_plt_, + this->got_irelative_); + + // Add unwind information if requested. + if (parameters->options().ld_generated_unwind_info()) + this->plt_->add_eh_frame(layout); + layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS, (elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR), @@ -1515,7 +1747,7 @@ template unsigned int Target_x86_64::first_plt_entry_offset() const { - return Output_data_plt_x86_64::first_plt_entry_offset(); + return this->plt_->first_plt_entry_offset(); } // Return the size of each PLT entry. @@ -1524,7 +1756,7 @@ template unsigned int Target_x86_64::plt_entry_size() const { - return Output_data_plt_x86_64::get_plt_entry_size(); + return this->plt_->get_plt_entry_size(); } // Create the GOT and PLT sections for an incremental update. @@ -1581,10 +1813,15 @@ Target_x86_64::init_got_plt_for_update(Symbol_table* symtab, ORDER_NON_RELRO_FIRST, false); // Create the PLT section. - this->plt_ = new Output_data_plt_x86_64(layout, this->got_, - this->got_plt_, - this->got_irelative_, - plt_count); + this->plt_ = this->make_data_plt(layout, this->got_, + this->got_plt_, + this->got_irelative_, + plt_count); + + // Add unwind information if requested. + if (parameters->options().ld_generated_unwind_info()) + this->plt_->add_eh_frame(layout); + layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS, elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR, this->plt_, ORDER_PLT, false); @@ -1667,24 +1904,24 @@ Target_x86_64::reserve_global_got_entry(unsigned int got_index, this->got_, got_offset, 0); else rela_dyn->add_global_relative(gsym, elfcpp::R_X86_64_RELATIVE, - this->got_, got_offset, 0); + this->got_, got_offset, 0, false); } break; case GOT_TYPE_TLS_OFFSET: rela_dyn->add_global_relative(gsym, elfcpp::R_X86_64_TPOFF64, - this->got_, got_offset, 0); + this->got_, got_offset, 0, false); break; case GOT_TYPE_TLS_PAIR: this->got_->reserve_slot(got_index + 1); rela_dyn->add_global_relative(gsym, elfcpp::R_X86_64_DTPMOD64, - this->got_, got_offset, 0); + this->got_, got_offset, 0, false); rela_dyn->add_global_relative(gsym, elfcpp::R_X86_64_DTPOFF64, - this->got_, got_offset + 8, 0); + this->got_, got_offset + 8, 0, false); break; case GOT_TYPE_TLS_DESC: this->got_->reserve_slot(got_index + 1); rela_dyn->add_global_relative(gsym, elfcpp::R_X86_64_TLSDESC, - this->got_, got_offset, 0); + this->got_, got_offset, 0, false); break; default: gold_unreachable(); @@ -1758,7 +1995,7 @@ Target_x86_64::define_tls_base_symbol(Symbol_table* symtab, template void Target_x86_64::reserve_tlsdesc_entries(Symbol_table* symtab, - Layout* layout) + Layout* layout) { if (this->plt_ == NULL) this->make_plt_section(symtab, layout); @@ -1788,7 +2025,7 @@ Target_x86_64::got_mod_index_entry(Symbol_table* symtab, Layout* layout, Output_data_got<64, false>* got = this->got_section(symtab, layout); unsigned int got_offset = got->add_constant(0); rela_dyn->add_local(object, 0, elfcpp::R_X86_64_DTPMOD64, got, - got_offset, 0); + got_offset, 0); got->add_constant(0); this->got_mod_index_offset_ = got_offset; } @@ -1996,10 +2233,10 @@ Target_x86_64::Scan::check_non_pic(Relobj* object, unsigned int r_type, // section. But we can still wind up issuing more than one // error per object file. if (this->issued_non_pic_error_) - return; + return; gold_assert(parameters->options().output_is_position_independent()); object->error(_("requires unsupported dynamic reloc %u; " - "recompile with -fPIC"), + "recompile with -fPIC"), r_type); this->issued_non_pic_error_ = true; return; @@ -2021,7 +2258,7 @@ Target_x86_64::Scan::reloc_needs_plt_for_ifunc( int flags = Scan::get_reference_flags(r_type); if (flags & Symbol::TLS_REF) gold_error(_("%s: unsupported TLS reloc %u for IFUNC symbol"), - object->name().c_str(), r_type); + object->name().c_str(), r_type); return flags != 0; } @@ -2037,8 +2274,12 @@ Target_x86_64::Scan::local(Symbol_table* symtab, Output_section* output_section, const elfcpp::Rela& reloc, unsigned int r_type, - const elfcpp::Sym& lsym) + const elfcpp::Sym& lsym, + bool is_discarded) { + if (is_discarded) + return; + // A local STT_GNU_IFUNC symbol may require a PLT entry. bool is_ifunc = lsym.get_st_type() == elfcpp::STT_GNU_IFUNC; if (is_ifunc && this->reloc_needs_plt_for_ifunc(object, r_type)) @@ -2062,15 +2303,17 @@ Target_x86_64::Scan::local(Symbol_table* symtab, // R_X86_64_RELATIVE relocation so the dynamic loader can // relocate it easily. if (parameters->options().output_is_position_independent()) - { - unsigned int r_sym = elfcpp::elf_r_sym(reloc.get_r_info()); - Reloc_section* rela_dyn = target->rela_dyn_section(layout); + { + unsigned int r_sym = elfcpp::elf_r_sym(reloc.get_r_info()); + Reloc_section* rela_dyn = target->rela_dyn_section(layout); rela_dyn->add_local_relative(object, r_sym, - elfcpp::R_X86_64_RELATIVE, + (size == 32 + ? elfcpp::R_X86_64_RELATIVE64 + : elfcpp::R_X86_64_RELATIVE), output_section, data_shndx, reloc.get_r_offset(), reloc.get_r_addend(), is_ifunc); - } + } break; case elfcpp::R_X86_64_32: @@ -2082,7 +2325,7 @@ Target_x86_64::Scan::local(Symbol_table* symtab, // location. We can't use an R_X86_64_RELATIVE relocation // because that is always a 64-bit relocation. if (parameters->options().output_is_position_independent()) - { + { // Use R_X86_64_RELATIVE relocation for R_X86_64_32 under x32. if (size == 32 && r_type == elfcpp::R_X86_64_32) { @@ -2096,17 +2339,17 @@ Target_x86_64::Scan::local(Symbol_table* symtab, break; } - this->check_non_pic(object, r_type, NULL); + this->check_non_pic(object, r_type, NULL); - Reloc_section* rela_dyn = target->rela_dyn_section(layout); + Reloc_section* rela_dyn = target->rela_dyn_section(layout); unsigned int r_sym = elfcpp::elf_r_sym(reloc.get_r_info()); - if (lsym.get_st_type() != elfcpp::STT_SECTION) + if (lsym.get_st_type() != elfcpp::STT_SECTION) rela_dyn->add_local(object, r_sym, r_type, output_section, data_shndx, reloc.get_r_offset(), reloc.get_r_addend()); - else - { - gold_assert(lsym.get_st_value() == 0); + else + { + gold_assert(lsym.get_st_value() == 0); unsigned int shndx = lsym.get_st_shndx(); bool is_ordinary; shndx = object->adjust_sym_shndx(r_sym, shndx, @@ -2119,8 +2362,8 @@ Target_x86_64::Scan::local(Symbol_table* symtab, r_type, output_section, data_shndx, reloc.get_r_offset(), reloc.get_r_addend()); - } - } + } + } break; case elfcpp::R_X86_64_PC64: @@ -2150,9 +2393,9 @@ Target_x86_64::Scan::local(Symbol_table* symtab, case elfcpp::R_X86_64_GOTPCREL: case elfcpp::R_X86_64_GOTPLT64: { - // The symbol requires a GOT entry. - Output_data_got<64, false>* got = target->got_section(symtab, layout); - unsigned int r_sym = elfcpp::elf_r_sym(reloc.get_r_info()); + // The symbol requires a GOT entry. + Output_data_got<64, false>* got = target->got_section(symtab, layout); + unsigned int r_sym = elfcpp::elf_r_sym(reloc.get_r_info()); // For a STT_GNU_IFUNC symbol we want the PLT offset. That // lets function pointers compare correctly with shared @@ -2162,13 +2405,13 @@ Target_x86_64::Scan::local(Symbol_table* symtab, 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) - { - // If we are generating a shared object, we need to add a - // dynamic relocation for this symbol's GOT entry. - if (parameters->options().output_is_position_independent()) - { - Reloc_section* rela_dyn = target->rela_dyn_section(layout); + if (is_new) + { + // If we are generating a shared object, we need to add a + // dynamic relocation for this symbol's GOT entry. + if (parameters->options().output_is_position_independent()) + { + Reloc_section* rela_dyn = target->rela_dyn_section(layout); // R_X86_64_RELATIVE assumes a 64-bit relocation. if (r_type != elfcpp::R_X86_64_GOT32) { @@ -2178,19 +2421,19 @@ Target_x86_64::Scan::local(Symbol_table* symtab, elfcpp::R_X86_64_RELATIVE, got, got_offset, 0, is_ifunc); } - else - { - this->check_non_pic(object, r_type, NULL); - - gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION); - rela_dyn->add_local( - object, r_sym, r_type, got, - object->local_got_offset(r_sym, GOT_TYPE_STANDARD), 0); - } - } - } - // For GOTPLT64, we'd normally want a PLT section, but since - // we know this is a local symbol, no PLT is needed. + else + { + this->check_non_pic(object, r_type, NULL); + + gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION); + rela_dyn->add_local( + object, r_sym, r_type, got, + object->local_got_offset(r_sym, GOT_TYPE_STANDARD), 0); + } + } + } + // For GOTPLT64, we'd normally want a PLT section, but since + // we know this is a local symbol, no PLT is needed. } break; @@ -2219,50 +2462,50 @@ Target_x86_64::Scan::local(Symbol_table* symtab, { bool output_is_shared = parameters->options().shared(); const tls::Tls_optimization optimized_type - = Target_x86_64::optimize_tls_reloc(!output_is_shared, + = Target_x86_64::optimize_tls_reloc(!output_is_shared, r_type); switch (r_type) { - case elfcpp::R_X86_64_TLSGD: // General-dynamic - if (optimized_type == tls::TLSOPT_NONE) - { - // Create a pair of GOT entries for the module index and - // dtv-relative offset. - Output_data_got<64, false>* got - = target->got_section(symtab, layout); - unsigned int r_sym = elfcpp::elf_r_sym(reloc.get_r_info()); + case elfcpp::R_X86_64_TLSGD: // General-dynamic + if (optimized_type == tls::TLSOPT_NONE) + { + // Create a pair of GOT entries for the module index and + // dtv-relative offset. + Output_data_got<64, false>* got + = target->got_section(symtab, layout); + unsigned int r_sym = elfcpp::elf_r_sym(reloc.get_r_info()); unsigned int shndx = lsym.get_st_shndx(); bool is_ordinary; shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary); if (!is_ordinary) object->error(_("local symbol %u has bad shndx %u"), r_sym, shndx); - else + else got->add_local_pair_with_rel(object, r_sym, shndx, GOT_TYPE_TLS_PAIR, target->rela_dyn_section(layout), - elfcpp::R_X86_64_DTPMOD64, 0); - } - else if (optimized_type != tls::TLSOPT_TO_LE) + elfcpp::R_X86_64_DTPMOD64); + } + else if (optimized_type != tls::TLSOPT_TO_LE) unsupported_reloc_local(object, r_type); - break; + break; - case elfcpp::R_X86_64_GOTPC32_TLSDESC: - target->define_tls_base_symbol(symtab, layout); + case elfcpp::R_X86_64_GOTPC32_TLSDESC: + target->define_tls_base_symbol(symtab, layout); if (optimized_type == tls::TLSOPT_NONE) { - // Create reserved PLT and GOT entries for the resolver. - target->reserve_tlsdesc_entries(symtab, layout); - - // Generate a double GOT entry with an - // R_X86_64_TLSDESC reloc. The R_X86_64_TLSDESC reloc - // is resolved lazily, so the GOT entry needs to be in - // an area in .got.plt, not .got. Call got_section to - // make sure the section has been created. + // Create reserved PLT and GOT entries for the resolver. + target->reserve_tlsdesc_entries(symtab, layout); + + // Generate a double GOT entry with an + // R_X86_64_TLSDESC reloc. The R_X86_64_TLSDESC reloc + // is resolved lazily, so the GOT entry needs to be in + // an area in .got.plt, not .got. Call got_section to + // make sure the section has been created. target->got_section(symtab, layout); - Output_data_got<64, false>* got = target->got_tlsdesc_section(); - unsigned int r_sym = elfcpp::elf_r_sym(reloc.get_r_info()); + Output_data_got<64, false>* got = target->got_tlsdesc_section(); + unsigned int r_sym = elfcpp::elf_r_sym(reloc.get_r_info()); if (!object->local_has_got_offset(r_sym, GOT_TYPE_TLS_DESC)) { unsigned int got_offset = got->add_constant(0); @@ -2283,47 +2526,47 @@ Target_x86_64::Scan::local(Symbol_table* symtab, unsupported_reloc_local(object, r_type); break; - case elfcpp::R_X86_64_TLSDESC_CALL: + case elfcpp::R_X86_64_TLSDESC_CALL: break; - case elfcpp::R_X86_64_TLSLD: // Local-dynamic + case elfcpp::R_X86_64_TLSLD: // Local-dynamic if (optimized_type == tls::TLSOPT_NONE) { - // Create a GOT entry for the module index. - target->got_mod_index_entry(symtab, layout, object); + // Create a GOT entry for the module index. + target->got_mod_index_entry(symtab, layout, object); } else if (optimized_type != tls::TLSOPT_TO_LE) unsupported_reloc_local(object, r_type); break; - case elfcpp::R_X86_64_DTPOFF32: - case elfcpp::R_X86_64_DTPOFF64: + case elfcpp::R_X86_64_DTPOFF32: + case elfcpp::R_X86_64_DTPOFF64: break; - case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec + 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. - Output_data_got<64, false>* got - = target->got_section(symtab, layout); - unsigned int r_sym = elfcpp::elf_r_sym(reloc.get_r_info()); - got->add_local_with_rel(object, r_sym, GOT_TYPE_TLS_OFFSET, + if (optimized_type == tls::TLSOPT_NONE) + { + // Create a GOT entry for the tp-relative offset. + Output_data_got<64, false>* got + = target->got_section(symtab, layout); + unsigned int r_sym = elfcpp::elf_r_sym(reloc.get_r_info()); + got->add_local_with_rel(object, r_sym, GOT_TYPE_TLS_OFFSET, target->rela_dyn_section(layout), elfcpp::R_X86_64_TPOFF64); - } - else if (optimized_type != tls::TLSOPT_TO_LE) - unsupported_reloc_local(object, r_type); - break; + } + else if (optimized_type != tls::TLSOPT_TO_LE) + unsupported_reloc_local(object, r_type); + break; - case elfcpp::R_X86_64_TPOFF32: // Local-exec + case elfcpp::R_X86_64_TPOFF32: // Local-exec layout->set_has_static_tls(); - if (output_is_shared) - unsupported_reloc_local(object, r_type); + if (output_is_shared) + unsupported_reloc_local(object, r_type); break; - default: - gold_unreachable(); + default: + gold_unreachable(); } } break; @@ -2369,7 +2612,7 @@ Target_x86_64::Scan::possible_function_pointer_reloc(unsigned int r_type) case elfcpp::R_X86_64_GOTPCREL: case elfcpp::R_X86_64_GOTPLT64: { - return true; + return true; } } return false; @@ -2396,7 +2639,7 @@ Target_x86_64::Scan::local_reloc_may_be_function_pointer( // not possible to distinguish pointer taken versus a call by looking at // the relocation types. return (parameters->options().shared() - || possible_function_pointer_reloc(r_type)); + || possible_function_pointer_reloc(r_type)); } // For safe ICF, scan a relocation for a global symbol to check if it @@ -2419,10 +2662,10 @@ Target_x86_64::Scan::global_reloc_may_be_function_pointer( // When building a shared library, do not fold symbols whose visibility // is hidden, internal or protected. return ((parameters->options().shared() - && (gsym->visibility() == elfcpp::STV_INTERNAL + && (gsym->visibility() == elfcpp::STV_INTERNAL || gsym->visibility() == elfcpp::STV_PROTECTED || gsym->visibility() == elfcpp::STV_HIDDEN)) - || possible_function_pointer_reloc(r_type)); + || possible_function_pointer_reloc(r_type)); } // Scan a relocation for a global symbol. @@ -2430,14 +2673,14 @@ Target_x86_64::Scan::global_reloc_may_be_function_pointer( template inline void Target_x86_64::Scan::global(Symbol_table* symtab, - Layout* layout, - Target_x86_64* target, - Sized_relobj_file* object, - unsigned int data_shndx, - Output_section* output_section, - const elfcpp::Rela& reloc, - unsigned int r_type, - Symbol* gsym) + Layout* layout, + Target_x86_64* target, + Sized_relobj_file* object, + unsigned int data_shndx, + Output_section* output_section, + const elfcpp::Rela& reloc, + unsigned int r_type, + Symbol* gsym) { // A STT_GNU_IFUNC symbol may require a PLT entry. if (gsym->type() == elfcpp::STT_GNU_IFUNC @@ -2457,26 +2700,27 @@ Target_x86_64::Scan::global(Symbol_table* symtab, case elfcpp::R_X86_64_16: case elfcpp::R_X86_64_8: { - // Make a PLT entry if necessary. - if (gsym->needs_plt_entry()) - { - target->make_plt_entry(symtab, layout, gsym); - // Since this is not a PC-relative relocation, we may be - // 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() && !parameters->options().shared()) - gsym->set_needs_dynsym_value(); - } - // Make a dynamic relocation if necessary. - if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type))) - { - if (gsym->may_need_copy_reloc()) - { - target->copy_reloc(symtab, layout, object, - data_shndx, output_section, gsym, reloc); - } - else if (r_type == elfcpp::R_X86_64_64 + // Make a PLT entry if necessary. + if (gsym->needs_plt_entry()) + { + target->make_plt_entry(symtab, layout, gsym); + // Since this is not a PC-relative relocation, we may be + // 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() && !parameters->options().shared()) + gsym->set_needs_dynsym_value(); + } + // Make a dynamic relocation if necessary. + if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type))) + { + if (gsym->may_need_copy_reloc()) + { + target->copy_reloc(symtab, layout, object, + data_shndx, output_section, gsym, reloc); + } + else if (((size == 64 && r_type == elfcpp::R_X86_64_64) + || (size == 32 && r_type == elfcpp::R_X86_64_32)) && gsym->type() == elfcpp::STT_GNU_IFUNC && gsym->can_use_relative_reloc(false) && !gsym->is_from_dynobj() @@ -2496,25 +2740,25 @@ Target_x86_64::Scan::global(Symbol_table* symtab, reloc.get_r_offset(), reloc.get_r_addend()); } - else if (r_type == elfcpp::R_X86_64_64 - && gsym->can_use_relative_reloc(false)) - { - Reloc_section* rela_dyn = target->rela_dyn_section(layout); + else if (r_type == elfcpp::R_X86_64_64 + && gsym->can_use_relative_reloc(false)) + { + Reloc_section* rela_dyn = target->rela_dyn_section(layout); rela_dyn->add_global_relative(gsym, elfcpp::R_X86_64_RELATIVE, output_section, object, data_shndx, reloc.get_r_offset(), - reloc.get_r_addend()); - } - else - { - this->check_non_pic(object, r_type, gsym); - Reloc_section* rela_dyn = target->rela_dyn_section(layout); - rela_dyn->add_global(gsym, r_type, output_section, object, - data_shndx, reloc.get_r_offset(), - reloc.get_r_addend()); - } - } + reloc.get_r_addend(), false); + } + else + { + this->check_non_pic(object, r_type, gsym); + Reloc_section* rela_dyn = target->rela_dyn_section(layout); + rela_dyn->add_global(gsym, r_type, output_section, object, + data_shndx, reloc.get_r_offset(), + reloc.get_r_addend()); + } + } } break; @@ -2523,26 +2767,26 @@ Target_x86_64::Scan::global(Symbol_table* symtab, case elfcpp::R_X86_64_PC16: case elfcpp::R_X86_64_PC8: { - // Make a PLT entry if necessary. - if (gsym->needs_plt_entry()) - target->make_plt_entry(symtab, layout, gsym); - // Make a dynamic relocation if necessary. - if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type))) - { - if (gsym->may_need_copy_reloc()) - { - target->copy_reloc(symtab, layout, object, - data_shndx, output_section, gsym, reloc); - } - else - { - this->check_non_pic(object, r_type, gsym); - Reloc_section* rela_dyn = target->rela_dyn_section(layout); - rela_dyn->add_global(gsym, r_type, output_section, object, - data_shndx, reloc.get_r_offset(), - reloc.get_r_addend()); - } - } + // Make a PLT entry if necessary. + if (gsym->needs_plt_entry()) + target->make_plt_entry(symtab, layout, gsym); + // Make a dynamic relocation if necessary. + if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type))) + { + if (gsym->may_need_copy_reloc()) + { + target->copy_reloc(symtab, layout, object, + data_shndx, output_section, gsym, reloc); + } + else + { + this->check_non_pic(object, r_type, gsym); + Reloc_section* rela_dyn = target->rela_dyn_section(layout); + rela_dyn->add_global(gsym, r_type, output_section, object, + data_shndx, reloc.get_r_offset(), + reloc.get_r_addend()); + } + } } break; @@ -2552,9 +2796,9 @@ Target_x86_64::Scan::global(Symbol_table* symtab, case elfcpp::R_X86_64_GOTPCREL: case elfcpp::R_X86_64_GOTPLT64: { - // The symbol requires a GOT entry. - Output_data_got<64, false>* got = target->got_section(symtab, layout); - if (gsym->final_value_is_known()) + // The symbol requires a GOT entry. + Output_data_got<64, false>* got = target->got_section(symtab, layout); + if (gsym->final_value_is_known()) { // For a STT_GNU_IFUNC symbol we want the PLT address. if (gsym->type() == elfcpp::STT_GNU_IFUNC) @@ -2562,11 +2806,11 @@ Target_x86_64::Scan::global(Symbol_table* symtab, else got->add_global(gsym, GOT_TYPE_STANDARD); } - else - { - // 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); + else + { + // 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); // Use a GLOB_DAT rather than a RELATIVE reloc if: // @@ -2587,10 +2831,10 @@ Target_x86_64::Scan::global(Symbol_table* symtab, && parameters->options().shared()) || (gsym->type() == elfcpp::STT_GNU_IFUNC && parameters->options().output_is_position_independent())) - got->add_global_with_rel(gsym, GOT_TYPE_STANDARD, rela_dyn, + got->add_global_with_rel(gsym, GOT_TYPE_STANDARD, rela_dyn, elfcpp::R_X86_64_GLOB_DAT); - else - { + else + { // For a STT_GNU_IFUNC symbol we want to write the PLT // offset into the GOT, so that function pointer // comparisons work correctly. @@ -2606,20 +2850,20 @@ Target_x86_64::Scan::global(Symbol_table* symtab, && !parameters->options().shared()) gsym->set_needs_dynsym_value(); } - if (is_new) + if (is_new) { unsigned int got_off = gsym->got_offset(GOT_TYPE_STANDARD); rela_dyn->add_global_relative(gsym, elfcpp::R_X86_64_RELATIVE, - got, got_off, 0); + got, got_off, 0, false); } - } - } - // For GOTPLT64, we also need a PLT entry (but only if the - // symbol is not fully resolved). - if (r_type == elfcpp::R_X86_64_GOTPLT64 - && !gsym->final_value_is_known()) - target->make_plt_entry(symtab, layout, gsym); + } + } + // For GOTPLT64, we also need a PLT entry (but only if the + // symbol is not fully resolved). + if (r_type == elfcpp::R_X86_64_GOTPLT64 + && !gsym->final_value_is_known()) + target->make_plt_entry(symtab, layout, gsym); } break; @@ -2632,8 +2876,8 @@ Target_x86_64::Scan::global(Symbol_table* symtab, // if the symbol is defined in the output file and is protected // or hidden. if (gsym->is_defined() - && !gsym->is_from_dynobj() - && !gsym->is_preemptible()) + && !gsym->is_from_dynobj() + && !gsym->is_preemptible()) break; target->make_plt_entry(symtab, layout, gsym); break; @@ -2676,27 +2920,27 @@ Target_x86_64::Scan::global(Symbol_table* symtab, { const bool is_final = gsym->final_value_is_known(); const tls::Tls_optimization optimized_type - = Target_x86_64::optimize_tls_reloc(is_final, r_type); + = Target_x86_64::optimize_tls_reloc(is_final, r_type); switch (r_type) { - case elfcpp::R_X86_64_TLSGD: // General-dynamic + case elfcpp::R_X86_64_TLSGD: // General-dynamic if (optimized_type == tls::TLSOPT_NONE) { - // Create a pair of GOT entries for the module index and - // dtv-relative offset. - Output_data_got<64, false>* got - = target->got_section(symtab, layout); - got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR, + // Create a pair of GOT entries for the module index and + // dtv-relative offset. + Output_data_got<64, false>* got + = target->got_section(symtab, layout); + got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR, target->rela_dyn_section(layout), elfcpp::R_X86_64_DTPMOD64, elfcpp::R_X86_64_DTPOFF64); } else if (optimized_type == tls::TLSOPT_TO_IE) { - // Create a GOT entry for the tp-relative offset. - Output_data_got<64, false>* got - = target->got_section(symtab, layout); - got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET, + // Create a GOT entry for the tp-relative offset. + Output_data_got<64, false>* got + = target->got_section(symtab, layout); + got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET, target->rela_dyn_section(layout), elfcpp::R_X86_64_TPOFF64); } @@ -2704,30 +2948,30 @@ Target_x86_64::Scan::global(Symbol_table* symtab, unsupported_reloc_global(object, r_type, gsym); break; - case elfcpp::R_X86_64_GOTPC32_TLSDESC: - target->define_tls_base_symbol(symtab, layout); + case elfcpp::R_X86_64_GOTPC32_TLSDESC: + target->define_tls_base_symbol(symtab, layout); if (optimized_type == tls::TLSOPT_NONE) { - // Create reserved PLT and GOT entries for the resolver. - target->reserve_tlsdesc_entries(symtab, layout); - - // Create a double GOT entry with an R_X86_64_TLSDESC - // reloc. The R_X86_64_TLSDESC reloc is resolved - // lazily, so the GOT entry needs to be in an area in - // .got.plt, not .got. Call got_section to make sure - // the section has been created. + // Create reserved PLT and GOT entries for the resolver. + target->reserve_tlsdesc_entries(symtab, layout); + + // Create a double GOT entry with an R_X86_64_TLSDESC + // reloc. The R_X86_64_TLSDESC reloc is resolved + // lazily, so the GOT entry needs to be in an area in + // .got.plt, not .got. Call got_section to make sure + // the section has been created. target->got_section(symtab, layout); - Output_data_got<64, false>* got = target->got_tlsdesc_section(); + Output_data_got<64, false>* got = target->got_tlsdesc_section(); Reloc_section* rt = target->rela_tlsdesc_section(layout); - got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_DESC, rt, + got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_DESC, rt, elfcpp::R_X86_64_TLSDESC, 0); } else if (optimized_type == tls::TLSOPT_TO_IE) { - // Create a GOT entry for the tp-relative offset. - Output_data_got<64, false>* got - = target->got_section(symtab, layout); - got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET, + // Create a GOT entry for the tp-relative offset. + Output_data_got<64, false>* got + = target->got_section(symtab, layout); + got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET, target->rela_dyn_section(layout), elfcpp::R_X86_64_TPOFF64); } @@ -2735,46 +2979,46 @@ Target_x86_64::Scan::global(Symbol_table* symtab, unsupported_reloc_global(object, r_type, gsym); break; - case elfcpp::R_X86_64_TLSDESC_CALL: + case elfcpp::R_X86_64_TLSDESC_CALL: break; - case elfcpp::R_X86_64_TLSLD: // Local-dynamic + case elfcpp::R_X86_64_TLSLD: // Local-dynamic if (optimized_type == tls::TLSOPT_NONE) { - // Create a GOT entry for the module index. - target->got_mod_index_entry(symtab, layout, object); + // Create a GOT entry for the module index. + target->got_mod_index_entry(symtab, layout, object); } else if (optimized_type != tls::TLSOPT_TO_LE) unsupported_reloc_global(object, r_type, gsym); break; - case elfcpp::R_X86_64_DTPOFF32: - case elfcpp::R_X86_64_DTPOFF64: + case elfcpp::R_X86_64_DTPOFF32: + case elfcpp::R_X86_64_DTPOFF64: break; - case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec + 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. - Output_data_got<64, false>* got - = target->got_section(symtab, layout); - got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET, + if (optimized_type == tls::TLSOPT_NONE) + { + // Create a GOT entry for the tp-relative offset. + Output_data_got<64, false>* got + = target->got_section(symtab, layout); + got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET, target->rela_dyn_section(layout), elfcpp::R_X86_64_TPOFF64); - } - else if (optimized_type != tls::TLSOPT_TO_LE) - unsupported_reloc_global(object, r_type, gsym); - break; + } + else if (optimized_type != tls::TLSOPT_TO_LE) + unsupported_reloc_global(object, r_type, gsym); + break; - case elfcpp::R_X86_64_TPOFF32: // Local-exec + case elfcpp::R_X86_64_TPOFF32: // Local-exec layout->set_has_static_tls(); - if (parameters->options().shared()) - unsupported_reloc_local(object, r_type); + if (parameters->options().shared()) + unsupported_reloc_global(object, r_type, gsym); break; - default: - gold_unreachable(); + default: + gold_unreachable(); } } break; @@ -2784,7 +3028,7 @@ Target_x86_64::Scan::global(Symbol_table* symtab, default: gold_error(_("%s: unsupported reloc %u against global symbol %s"), object->name().c_str(), r_type, - gsym->demangled_name().c_str()); + gsym->demangled_name().c_str()); break; } } @@ -2810,7 +3054,7 @@ Target_x86_64::gc_process_relocs(Symbol_table* symtab, } gold::gc_process_relocs, elfcpp::SHT_RELA, - typename Target_x86_64::Scan, + typename Target_x86_64::Scan, typename Target_x86_64::Relocatable_size_for_reloc>( symtab, layout, @@ -2823,7 +3067,7 @@ Target_x86_64::gc_process_relocs(Symbol_table* symtab, needs_special_offset_handling, local_symbol_count, plocal_symbols); - + } // Scan relocations for a section. @@ -2877,7 +3121,7 @@ Target_x86_64::do_finalize_sections( : this->plt_->rela_plt()); layout->add_target_dynamic_tags(false, this->got_plt_, rel_plt, this->rela_dyn_, true, false); - + // Fill in some more dynamic tags. Output_data_dynamic* const odyn = layout->dynamic_data(); if (odyn != NULL) @@ -2972,7 +3216,7 @@ Target_x86_64::Relocate::relocate( if (this->skip_call_tls_get_addr_) { if ((r_type != elfcpp::R_X86_64_PLT32 - && r_type != elfcpp::R_X86_64_PC32) + && r_type != elfcpp::R_X86_64_PC32) || gsym == NULL || strcmp(gsym->name(), "__tls_get_addr") != 0) { @@ -2993,8 +3237,7 @@ Target_x86_64::Relocate::relocate( if (gsym != NULL && gsym->use_plt_offset(Scan::get_reference_flags(r_type))) { - symval.set_output_value(target->plt_address_for_global(gsym) - + gsym->plt_offset()); + symval.set_output_value(target->plt_address_for_global(gsym)); psymval = &symval; } else if (gsym == NULL && psymval->is_ifunc_symbol()) @@ -3002,8 +3245,7 @@ Target_x86_64::Relocate::relocate( unsigned int r_sym = elfcpp::elf_r_sym(rela.get_r_info()); if (object->local_has_plt_offset(r_sym)) { - symval.set_output_value(target->plt_address_for_local(object, r_sym) - + object->local_plt_offset(r_sym)); + symval.set_output_value(target->plt_address_for_local(object, r_sym)); psymval = &symval; } } @@ -3024,17 +3266,17 @@ Target_x86_64::Relocate::relocate( case elfcpp::R_X86_64_GOTPCREL: case elfcpp::R_X86_64_GOTPCREL64: if (gsym != NULL) - { - gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD)); - got_offset = gsym->got_offset(GOT_TYPE_STANDARD) - target->got_size(); - } + { + gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD)); + got_offset = gsym->got_offset(GOT_TYPE_STANDARD) - target->got_size(); + } else - { - unsigned int r_sym = elfcpp::elf_r_sym(rela.get_r_info()); - gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD)); - got_offset = (object->local_got_offset(r_sym, GOT_TYPE_STANDARD) - - target->got_size()); - } + { + unsigned int r_sym = elfcpp::elf_r_sym(rela.get_r_info()); + gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD)); + got_offset = (object->local_got_offset(r_sym, GOT_TYPE_STANDARD) + - target->got_size()); + } have_got_offset = true; break; @@ -3055,7 +3297,7 @@ Target_x86_64::Relocate::relocate( case elfcpp::R_X86_64_PC64: Relocate_functions::pcrela64(view, object, psymval, addend, - address); + address); break; case elfcpp::R_X86_64_32: @@ -3098,7 +3340,7 @@ Target_x86_64::Relocate::relocate( case elfcpp::R_X86_64_PLT32: gold_assert(gsym == NULL - || gsym->has_plt_offset() + || gsym->has_plt_offset() || gsym->final_value_is_known() || (gsym->is_defined() && !gsym->is_from_dynobj() @@ -3112,9 +3354,9 @@ Target_x86_64::Relocate::relocate( case elfcpp::R_X86_64_PLTOFF64: { - gold_assert(gsym); - gold_assert(gsym->has_plt_offset() - || gsym->final_value_is_known()); + gold_assert(gsym); + gold_assert(gsym->has_plt_offset() + || gsym->final_value_is_known()); typename elfcpp::Elf_types::Elf_Addr got_address; got_address = target->got_section(NULL, NULL)->address(); Relocate_functions::rela64(view, object, psymval, @@ -3128,7 +3370,7 @@ Target_x86_64::Relocate::relocate( case elfcpp::R_X86_64_GOTPC32: { - gold_assert(gsym); + gold_assert(gsym); typename elfcpp::Elf_types::Elf_Addr value; value = target->got_plt_section()->address(); Relocate_functions::pcrela32(view, value, addend, address); @@ -3145,7 +3387,7 @@ Target_x86_64::Relocate::relocate( case elfcpp::R_X86_64_GOTPC64: { - gold_assert(gsym); + gold_assert(gsym); typename elfcpp::Elf_types::Elf_Addr value; value = target->got_plt_section()->address(); Relocate_functions::pcrela64(view, value, addend, address); @@ -3163,19 +3405,19 @@ Target_x86_64::Relocate::relocate( case elfcpp::R_X86_64_GOTPCREL: { - gold_assert(have_got_offset); - typename elfcpp::Elf_types::Elf_Addr value; - value = target->got_plt_section()->address() + got_offset; - Relocate_functions::pcrela32(view, value, addend, address); + gold_assert(have_got_offset); + typename elfcpp::Elf_types::Elf_Addr value; + value = target->got_plt_section()->address() + got_offset; + Relocate_functions::pcrela32(view, value, addend, address); } break; case elfcpp::R_X86_64_GOTPCREL64: { - gold_assert(have_got_offset); - typename elfcpp::Elf_types::Elf_Addr value; - value = target->got_plt_section()->address() + got_offset; - Relocate_functions::pcrela64(view, value, addend, address); + gold_assert(have_got_offset); + typename elfcpp::Elf_types::Elf_Addr value; + value = target->got_plt_section()->address() + got_offset; + Relocate_functions::pcrela64(view, value, addend, address); } break; @@ -3203,7 +3445,7 @@ Target_x86_64::Relocate::relocate( case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec case elfcpp::R_X86_64_TPOFF32: // Local-exec this->relocate_tls(relinfo, target, relnum, rela, r_type, gsym, psymval, - view, address, view_size); + view, address, view_size); break; case elfcpp::R_X86_64_SIZE32: @@ -3275,40 +3517,40 @@ Target_x86_64::Relocate::relocate_tls( break; } else - { - unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE - ? GOT_TYPE_TLS_OFFSET - : GOT_TYPE_TLS_PAIR); - unsigned int got_offset; - if (gsym != NULL) - { - gold_assert(gsym->has_got_offset(got_type)); - got_offset = gsym->got_offset(got_type) - target->got_size(); - } - else - { - unsigned int r_sym = elfcpp::elf_r_sym(rela.get_r_info()); - gold_assert(object->local_has_got_offset(r_sym, got_type)); - got_offset = (object->local_got_offset(r_sym, got_type) - - target->got_size()); - } - if (optimized_type == tls::TLSOPT_TO_IE) - { - value = target->got_plt_section()->address() + got_offset; - this->tls_gd_to_ie(relinfo, relnum, tls_segment, rela, r_type, - value, view, address, view_size); - break; - } - else if (optimized_type == tls::TLSOPT_NONE) - { - // Relocate the field with the offset of the pair of GOT - // entries. + { + unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE + ? GOT_TYPE_TLS_OFFSET + : GOT_TYPE_TLS_PAIR); + unsigned int got_offset; + if (gsym != NULL) + { + gold_assert(gsym->has_got_offset(got_type)); + got_offset = gsym->got_offset(got_type) - target->got_size(); + } + else + { + unsigned int r_sym = elfcpp::elf_r_sym(rela.get_r_info()); + gold_assert(object->local_has_got_offset(r_sym, got_type)); + got_offset = (object->local_got_offset(r_sym, got_type) + - target->got_size()); + } + if (optimized_type == tls::TLSOPT_TO_IE) + { value = target->got_plt_section()->address() + got_offset; - Relocate_functions::pcrela32(view, value, addend, + this->tls_gd_to_ie(relinfo, relnum, tls_segment, rela, r_type, + value, view, address, view_size); + break; + } + else if (optimized_type == tls::TLSOPT_NONE) + { + // Relocate the field with the offset of the pair of GOT + // entries. + value = target->got_plt_section()->address() + got_offset; + Relocate_functions::pcrela32(view, value, addend, address); - break; - } - } + break; + } + } gold_error_at_location(relinfo, relnum, rela.get_r_offset(), _("unsupported reloc %u"), r_type); break; @@ -3329,16 +3571,16 @@ Target_x86_64::Relocate::relocate_tls( return; } this->tls_desc_gd_to_le(relinfo, relnum, tls_segment, - rela, r_type, value, view, - view_size); + rela, r_type, value, view, + view_size); break; } else - { - unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE - ? GOT_TYPE_TLS_OFFSET - : GOT_TYPE_TLS_DESC); - unsigned int got_offset = 0; + { + unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE + ? GOT_TYPE_TLS_OFFSET + : GOT_TYPE_TLS_DESC); + unsigned int got_offset = 0; if (r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC && optimized_type == tls::TLSOPT_NONE) { @@ -3348,45 +3590,45 @@ Target_x86_64::Relocate::relocate_tls( got_offset = (target->got_size() + target->got_plt_section()->data_size()); } - if (gsym != NULL) - { - gold_assert(gsym->has_got_offset(got_type)); - got_offset += gsym->got_offset(got_type) - target->got_size(); - } - else - { - unsigned int r_sym = elfcpp::elf_r_sym(rela.get_r_info()); - gold_assert(object->local_has_got_offset(r_sym, got_type)); - got_offset += (object->local_got_offset(r_sym, got_type) + if (gsym != NULL) + { + gold_assert(gsym->has_got_offset(got_type)); + got_offset += gsym->got_offset(got_type) - target->got_size(); + } + else + { + unsigned int r_sym = elfcpp::elf_r_sym(rela.get_r_info()); + gold_assert(object->local_has_got_offset(r_sym, got_type)); + got_offset += (object->local_got_offset(r_sym, got_type) - target->got_size()); - } - if (optimized_type == tls::TLSOPT_TO_IE) - { + } + if (optimized_type == tls::TLSOPT_TO_IE) + { if (tls_segment == NULL) { gold_assert(parameters->errors()->error_count() > 0 || issue_undefined_symbol_error(gsym)); return; } - value = target->got_plt_section()->address() + got_offset; - this->tls_desc_gd_to_ie(relinfo, relnum, tls_segment, - rela, r_type, value, view, address, - view_size); - break; - } - else if (optimized_type == tls::TLSOPT_NONE) - { - if (r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC) - { - // Relocate the field with the offset of the pair of GOT - // entries. - value = target->got_plt_section()->address() + got_offset; - Relocate_functions::pcrela32(view, value, addend, + value = target->got_plt_section()->address() + got_offset; + this->tls_desc_gd_to_ie(relinfo, relnum, tls_segment, + rela, r_type, value, view, address, + view_size); + break; + } + else if (optimized_type == tls::TLSOPT_NONE) + { + if (r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC) + { + // Relocate the field with the offset of the pair of GOT + // entries. + value = target->got_plt_section()->address() + got_offset; + Relocate_functions::pcrela32(view, value, addend, address); - } - break; - } - } + } + break; + } + } gold_error_at_location(relinfo, relnum, rela.get_r_offset(), _("unsupported reloc %u"), r_type); break; @@ -3398,7 +3640,7 @@ Target_x86_64::Relocate::relocate_tls( optimized_type = tls::TLSOPT_NONE; } if (optimized_type == tls::TLSOPT_TO_LE) - { + { if (tls_segment == NULL) { gold_assert(parameters->errors()->error_count() > 0 @@ -3408,19 +3650,19 @@ Target_x86_64::Relocate::relocate_tls( this->tls_ld_to_le(relinfo, relnum, tls_segment, rela, r_type, value, view, view_size); break; - } + } else if (optimized_type == tls::TLSOPT_NONE) - { - // Relocate the field with the offset of the GOT entry for - // the module index. - unsigned int got_offset; - got_offset = (target->got_mod_index_entry(NULL, NULL, NULL) + { + // Relocate the field with the offset of the GOT entry for + // the module index. + unsigned int got_offset; + got_offset = (target->got_mod_index_entry(NULL, NULL, NULL) - target->got_size()); value = target->got_plt_section()->address() + got_offset; - Relocate_functions::pcrela32(view, value, addend, + Relocate_functions::pcrela32(view, value, addend, address); - break; - } + break; + } gold_error_at_location(relinfo, relnum, rela.get_r_offset(), _("unsupported reloc %u"), r_type); break; @@ -3476,29 +3718,29 @@ Target_x86_64::Relocate::relocate_tls( break; } else if (optimized_type == tls::TLSOPT_NONE) - { - // Relocate the field with the offset of the GOT entry for - // the tp-relative offset of the symbol. - unsigned int got_offset; - if (gsym != NULL) - { - gold_assert(gsym->has_got_offset(GOT_TYPE_TLS_OFFSET)); - got_offset = (gsym->got_offset(GOT_TYPE_TLS_OFFSET) - - target->got_size()); - } - else - { - unsigned int r_sym = elfcpp::elf_r_sym(rela.get_r_info()); - gold_assert(object->local_has_got_offset(r_sym, - GOT_TYPE_TLS_OFFSET)); - got_offset = (object->local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET) - - target->got_size()); - } + { + // Relocate the field with the offset of the GOT entry for + // the tp-relative offset of the symbol. + unsigned int got_offset; + if (gsym != NULL) + { + gold_assert(gsym->has_got_offset(GOT_TYPE_TLS_OFFSET)); + got_offset = (gsym->got_offset(GOT_TYPE_TLS_OFFSET) + - target->got_size()); + } + else + { + unsigned int r_sym = elfcpp::elf_r_sym(rela.get_r_info()); + gold_assert(object->local_has_got_offset(r_sym, + GOT_TYPE_TLS_OFFSET)); + got_offset = (object->local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET) + - target->got_size()); + } value = target->got_plt_section()->address() + got_offset; - Relocate_functions::pcrela32(view, value, addend, + Relocate_functions::pcrela32(view, value, addend, address); - break; - } + break; + } gold_error_at_location(relinfo, relnum, rela.get_r_offset(), _("unsupported reloc type %u"), r_type); @@ -3533,19 +3775,37 @@ Target_x86_64::Relocate::tls_gd_to_ie( typename elfcpp::Elf_types::Elf_Addr address, section_size_type view_size) { - // .byte 0x66; leaq foo@tlsgd(%rip),%rdi; - // .word 0x6666; rex64; call __tls_get_addr - // ==> movq %fs:0,%rax; addq x@gottpoff(%rip),%rax + // For SIZE == 64: + // .byte 0x66; leaq foo@tlsgd(%rip),%rdi; + // .word 0x6666; rex64; call __tls_get_addr + // ==> movq %fs:0,%rax; addq x@gottpoff(%rip),%rax + // For SIZE == 32: + // leaq foo@tlsgd(%rip),%rdi; + // .word 0x6666; rex64; call __tls_get_addr + // ==> movl %fs:0,%eax; addq x@gottpoff(%rip),%rax - tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -4); tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 12); - tls::check_tls(relinfo, relnum, rela.get_r_offset(), - (memcmp(view - 4, "\x66\x48\x8d\x3d", 4) == 0)); - tls::check_tls(relinfo, relnum, rela.get_r_offset(), - (memcmp(view + 4, "\x66\x66\x48\xe8", 4) == 0)); + (memcmp(view + 4, "\x66\x66\x48\xe8", 4) == 0)); - memcpy(view - 4, "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0\0", 16); + if (size == 64) + { + tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, + -4); + tls::check_tls(relinfo, relnum, rela.get_r_offset(), + (memcmp(view - 4, "\x66\x48\x8d\x3d", 4) == 0)); + memcpy(view - 4, "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0\0", + 16); + } + else + { + tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, + -3); + tls::check_tls(relinfo, relnum, rela.get_r_offset(), + (memcmp(view - 3, "\x48\x8d\x3d", 3) == 0)); + memcpy(view - 3, "\x64\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0\0", + 15); + } const elfcpp::Elf_Xword addend = rela.get_r_addend(); Relocate_functions::pcrela32(view + 8, value, addend - 8, @@ -3571,19 +3831,38 @@ Target_x86_64::Relocate::tls_gd_to_le( unsigned char* view, section_size_type view_size) { - // .byte 0x66; leaq foo@tlsgd(%rip),%rdi; - // .word 0x6666; rex64; call __tls_get_addr - // ==> movq %fs:0,%rax; leaq x@tpoff(%rax),%rax + // For SIZE == 64: + // .byte 0x66; leaq foo@tlsgd(%rip),%rdi; + // .word 0x6666; rex64; call __tls_get_addr + // ==> movq %fs:0,%rax; leaq x@tpoff(%rax),%rax + // For SIZE == 32: + // leaq foo@tlsgd(%rip),%rdi; + // .word 0x6666; rex64; call __tls_get_addr + // ==> movl %fs:0,%eax; leaq x@tpoff(%rax),%rax - tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -4); tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 12); - tls::check_tls(relinfo, relnum, rela.get_r_offset(), - (memcmp(view - 4, "\x66\x48\x8d\x3d", 4) == 0)); - tls::check_tls(relinfo, relnum, rela.get_r_offset(), - (memcmp(view + 4, "\x66\x66\x48\xe8", 4) == 0)); + (memcmp(view + 4, "\x66\x66\x48\xe8", 4) == 0)); - memcpy(view - 4, "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0\0", 16); + if (size == 64) + { + tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, + -4); + tls::check_tls(relinfo, relnum, rela.get_r_offset(), + (memcmp(view - 4, "\x66\x48\x8d\x3d", 4) == 0)); + memcpy(view - 4, "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0\0", + 16); + } + else + { + tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, + -3); + tls::check_tls(relinfo, relnum, rela.get_r_offset(), + (memcmp(view - 3, "\x48\x8d\x3d", 3) == 0)); + + memcpy(view - 3, "\x64\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0\0", + 15); + } value -= tls_segment->memsz(); Relocate_functions::rela32(view + 8, value, 0); @@ -3615,7 +3894,7 @@ Target_x86_64::Relocate::tls_desc_gd_to_ie( tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3); tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4); tls::check_tls(relinfo, relnum, rela.get_r_offset(), - view[-3] == 0x48 && view[-2] == 0x8d && view[-1] == 0x05); + view[-3] == 0x48 && view[-2] == 0x8d && view[-1] == 0x05); view[-2] = 0x8b; const elfcpp::Elf_Xword addend = rela.get_r_addend(); Relocate_functions::pcrela32(view, value, addend, address); @@ -3627,7 +3906,7 @@ Target_x86_64::Relocate::tls_desc_gd_to_ie( gold_assert(r_type == elfcpp::R_X86_64_TLSDESC_CALL); tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 2); tls::check_tls(relinfo, relnum, rela.get_r_offset(), - view[0] == 0xff && view[1] == 0x10); + view[0] == 0xff && view[1] == 0x10); view[0] = 0x66; view[1] = 0x90; } @@ -3654,7 +3933,7 @@ Target_x86_64::Relocate::tls_desc_gd_to_le( tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3); tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4); tls::check_tls(relinfo, relnum, rela.get_r_offset(), - view[-3] == 0x48 && view[-2] == 0x8d && view[-1] == 0x05); + view[-3] == 0x48 && view[-2] == 0x8d && view[-1] == 0x05); view[-2] = 0xc7; view[-1] = 0xc0; value -= tls_segment->memsz(); @@ -3667,7 +3946,7 @@ Target_x86_64::Relocate::tls_desc_gd_to_le( gold_assert(r_type == elfcpp::R_X86_64_TLSDESC_CALL); tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 2); tls::check_tls(relinfo, relnum, rela.get_r_offset(), - view[0] == 0xff && view[1] == 0x10); + view[0] == 0xff && view[1] == 0x10); view[0] = 0x66; view[1] = 0x90; } @@ -3686,18 +3965,25 @@ Target_x86_64::Relocate::tls_ld_to_le( section_size_type view_size) { // leaq foo@tlsld(%rip),%rdi; call __tls_get_addr@plt; + // For SIZE == 64: // ... leq foo@dtpoff(%rax),%reg // ==> .word 0x6666; .byte 0x66; movq %fs:0,%rax ... leaq x@tpoff(%rax),%rdx + // For SIZE == 32: + // ... leq foo@dtpoff(%rax),%reg + // ==> nopl 0x0(%rax); movl %fs:0,%eax ... leaq x@tpoff(%rax),%rdx tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3); tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 9); tls::check_tls(relinfo, relnum, rela.get_r_offset(), - view[-3] == 0x48 && view[-2] == 0x8d && view[-1] == 0x3d); + view[-3] == 0x48 && view[-2] == 0x8d && view[-1] == 0x3d); tls::check_tls(relinfo, relnum, rela.get_r_offset(), view[4] == 0xe8); - memcpy(view - 3, "\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0\0", 12); + if (size == 64) + memcpy(view - 3, "\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0\0", 12); + else + memcpy(view - 3, "\x0f\x1f\x40\x00\x64\x8b\x04\x25\0\0\0\0", 12); // The next reloc should be a PLT32 reloc against __tls_get_addr. // We can skip it. @@ -3737,7 +4023,7 @@ Target_x86_64::Relocate::tls_ie_to_le( { // movq if (op1 == 0x4c) - view[-3] = 0x49; + view[-3] = 0x49; view[-2] = 0xc7; view[-1] = 0xc0 | reg; } @@ -3745,7 +4031,7 @@ Target_x86_64::Relocate::tls_ie_to_le( { // Special handling for %rsp. if (op1 == 0x4c) - view[-3] = 0x49; + view[-3] = 0x49; view[-2] = 0x81; view[-1] = 0xc0 | reg; } @@ -3753,7 +4039,7 @@ Target_x86_64::Relocate::tls_ie_to_le( { // addq if (op1 == 0x4c) - view[-3] = 0x4d; + view[-3] = 0x4d; view[-2] = 0x8d; view[-1] = 0x80 | reg | (reg << 3); } @@ -3781,7 +4067,8 @@ Target_x86_64::relocate_section( gold_assert(sh_type == elfcpp::SHT_RELA); gold::relocate_section, elfcpp::SHT_RELA, - typename Target_x86_64::Relocate>( + typename Target_x86_64::Relocate, + gold::Default_comdat_behavior>( relinfo, this, prelocs, @@ -3935,13 +4222,13 @@ Target_x86_64::scan_relocatable_relocs( template void -Target_x86_64::relocate_for_relocatable( +Target_x86_64::relocate_relocs( const Relocate_info* relinfo, unsigned int sh_type, const unsigned char* prelocs, size_t reloc_count, Output_section* output_section, - off_t offset_in_output_section, + typename elfcpp::Elf_types::Elf_Off offset_in_output_section, const Relocatable_relocs* rr, unsigned char* view, typename elfcpp::Elf_types::Elf_Addr view_address, @@ -3951,7 +4238,7 @@ Target_x86_64::relocate_for_relocatable( { gold_assert(sh_type == elfcpp::SHT_RELA); - gold::relocate_for_relocatable( + gold::relocate_relocs( relinfo, prelocs, reloc_count, @@ -3975,7 +4262,7 @@ uint64_t Target_x86_64::do_dynsym_value(const Symbol* gsym) const { gold_assert(gsym->is_from_dynobj() && gsym->has_plt_offset()); - return this->plt_address_for_global(gsym) + gsym->plt_offset(); + return this->plt_address_for_global(gsym); } // Return a string used to fill a code section with nops to take up @@ -3992,7 +4279,7 @@ Target_x86_64::do_code_fill(section_size_type length) const jmp[0] = 0xe9; elfcpp::Swap_unaligned<32, false>::writeval(jmp + 1, length - 5); return (std::string(reinterpret_cast(&jmp[0]), 5) - + std::string(length - 5, static_cast(0x90))); + + std::string(length - 5, static_cast(0x90))); } // Nop sequences of various lengths. @@ -4000,47 +4287,47 @@ Target_x86_64::do_code_fill(section_size_type length) const const char nop2[2] = { '\x66', '\x90' }; // xchg %ax %ax const char nop3[3] = { '\x0f', '\x1f', '\x00' }; // nop (%rax) const char nop4[4] = { '\x0f', '\x1f', '\x40', // nop 0(%rax) - '\x00'}; + '\x00'}; const char nop5[5] = { '\x0f', '\x1f', '\x44', // nop 0(%rax,%rax,1) '\x00', '\x00' }; const char nop6[6] = { '\x66', '\x0f', '\x1f', // nopw 0(%rax,%rax,1) - '\x44', '\x00', '\x00' }; + '\x44', '\x00', '\x00' }; const char nop7[7] = { '\x0f', '\x1f', '\x80', // nopl 0L(%rax) - '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00' }; const char nop8[8] = { '\x0f', '\x1f', '\x84', // nopl 0L(%rax,%rax,1) - '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00' }; const char nop9[9] = { '\x66', '\x0f', '\x1f', // nopw 0L(%rax,%rax,1) - '\x84', '\x00', '\x00', + '\x84', '\x00', '\x00', '\x00', '\x00', '\x00' }; const char nop10[10] = { '\x66', '\x2e', '\x0f', // nopw %cs:0L(%rax,%rax,1) - '\x1f', '\x84', '\x00', + '\x1f', '\x84', '\x00', '\x00', '\x00', '\x00', '\x00' }; const char nop11[11] = { '\x66', '\x66', '\x2e', // data16 - '\x0f', '\x1f', '\x84', // nopw %cs:0L(%rax,%rax,1) + '\x0f', '\x1f', '\x84', // nopw %cs:0L(%rax,%rax,1) '\x00', '\x00', '\x00', '\x00', '\x00' }; const char nop12[12] = { '\x66', '\x66', '\x66', // data16; data16 - '\x2e', '\x0f', '\x1f', // nopw %cs:0L(%rax,%rax,1) + '\x2e', '\x0f', '\x1f', // nopw %cs:0L(%rax,%rax,1) '\x84', '\x00', '\x00', '\x00', '\x00', '\x00' }; const char nop13[13] = { '\x66', '\x66', '\x66', // data16; data16; data16 - '\x66', '\x2e', '\x0f', // nopw %cs:0L(%rax,%rax,1) + '\x66', '\x2e', '\x0f', // nopw %cs:0L(%rax,%rax,1) '\x1f', '\x84', '\x00', '\x00', '\x00', '\x00', - '\x00' }; + '\x00' }; const char nop14[14] = { '\x66', '\x66', '\x66', // data16; data16; data16 - '\x66', '\x66', '\x2e', // data16 + '\x66', '\x66', '\x2e', // data16 '\x0f', '\x1f', '\x84', // nopw %cs:0L(%rax,%rax,1) '\x00', '\x00', '\x00', - '\x00', '\x00' }; + '\x00', '\x00' }; const char nop15[15] = { '\x66', '\x66', '\x66', // data16; data16; data16 - '\x66', '\x66', '\x66', // data16; data16 + '\x66', '\x66', '\x66', // data16; data16 '\x2e', '\x0f', '\x1f', // nopw %cs:0L(%rax,%rax,1) '\x84', '\x00', '\x00', - '\x00', '\x00', '\x00' }; + '\x00', '\x00', '\x00' }; const char* nops[16] = { NULL, @@ -4149,7 +4436,8 @@ Target_x86_64::do_calls_non_split(Relobj* object, unsigned int shndx, *to = "__morestack_non_split"; } -// The selector for x86_64 object files. +// The selector for x86_64 object files. Note this is never instantiated +// directly. It's only used in Target_selector_x86_64_nacl, below. template class Target_selector_x86_64 : public Target_selector_freebsd @@ -4157,9 +4445,9 @@ class Target_selector_x86_64 : public Target_selector_freebsd public: Target_selector_x86_64() : Target_selector_freebsd(elfcpp::EM_X86_64, size, false, - (size == 64 + (size == 64 ? "elf64-x86-64" : "elf32-x86-64"), - (size == 64 + (size == 64 ? "elf64-x86-64-freebsd" : "elf32-x86-64-freebsd"), (size == 64 ? "elf_x86_64" : "elf32_x86_64")) @@ -4171,7 +4459,359 @@ public: }; -Target_selector_x86_64<64> target_selector_x86_64; -Target_selector_x86_64<32> target_selector_x32; +// NaCl variant. It uses different PLT contents. + +template +class Output_data_plt_x86_64_nacl : public Output_data_plt_x86_64 +{ + public: + Output_data_plt_x86_64_nacl(Layout* layout, + Output_data_got<64, false>* got, + Output_data_space* got_plt, + Output_data_space* got_irelative) + : Output_data_plt_x86_64(layout, plt_entry_size, + got, got_plt, got_irelative) + { } + + Output_data_plt_x86_64_nacl(Layout* layout, + Output_data_got<64, false>* got, + Output_data_space* got_plt, + Output_data_space* got_irelative, + unsigned int plt_count) + : Output_data_plt_x86_64(layout, plt_entry_size, + got, got_plt, got_irelative, + plt_count) + { } + + protected: + virtual unsigned int + do_get_plt_entry_size() const + { return plt_entry_size; } + + virtual void + do_add_eh_frame(Layout* layout) + { + layout->add_eh_frame_for_plt(this, + this->plt_eh_frame_cie, + this->plt_eh_frame_cie_size, + plt_eh_frame_fde, + plt_eh_frame_fde_size); + } + + virtual void + do_fill_first_plt_entry(unsigned char* pov, + typename elfcpp::Elf_types::Elf_Addr got_addr, + typename elfcpp::Elf_types::Elf_Addr plt_addr); + + virtual unsigned int + do_fill_plt_entry(unsigned char* pov, + typename elfcpp::Elf_types::Elf_Addr got_address, + typename elfcpp::Elf_types::Elf_Addr plt_address, + unsigned int got_offset, + unsigned int plt_offset, + unsigned int plt_index); + + virtual void + do_fill_tlsdesc_entry(unsigned char* pov, + typename elfcpp::Elf_types::Elf_Addr got_address, + typename elfcpp::Elf_types::Elf_Addr plt_address, + typename elfcpp::Elf_types::Elf_Addr got_base, + unsigned int tlsdesc_got_offset, + unsigned int plt_offset); + + private: + // The size of an entry in the PLT. + static const int plt_entry_size = 64; + + // The first entry in the PLT. + static const unsigned char first_plt_entry[plt_entry_size]; + + // Other entries in the PLT for an executable. + static const unsigned char plt_entry[plt_entry_size]; + + // The reserved TLSDESC entry in the PLT for an executable. + static const unsigned char tlsdesc_plt_entry[plt_entry_size]; + + // The .eh_frame unwind information for the PLT. + static const int plt_eh_frame_fde_size = 32; + static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size]; +}; + +template +class Target_x86_64_nacl : public Target_x86_64 +{ + public: + Target_x86_64_nacl() + : Target_x86_64(&x86_64_nacl_info) + { } + + virtual Output_data_plt_x86_64* + do_make_data_plt(Layout* layout, + Output_data_got<64, false>* got, + Output_data_space* got_plt, + Output_data_space* got_irelative) + { + return new Output_data_plt_x86_64_nacl(layout, got, got_plt, + got_irelative); + } + + virtual Output_data_plt_x86_64* + do_make_data_plt(Layout* layout, + Output_data_got<64, false>* got, + Output_data_space* got_plt, + Output_data_space* got_irelative, + unsigned int plt_count) + { + return new Output_data_plt_x86_64_nacl(layout, got, got_plt, + got_irelative, + plt_count); + } + + private: + static const Target::Target_info x86_64_nacl_info; +}; + +template<> +const Target::Target_info Target_x86_64_nacl<64>::x86_64_nacl_info = +{ + 64, // size + false, // is_big_endian + elfcpp::EM_X86_64, // machine_code + false, // has_make_symbol + false, // has_resolve + true, // has_code_fill + true, // is_default_stack_executable + true, // can_icf_inline_merge_sections + '\0', // wrap_char + "/lib64/ld-nacl-x86-64.so.1", // dynamic_linker + 0x20000, // default_text_segment_address + 0x10000, // abi_pagesize (overridable by -z max-page-size) + 0x10000, // common_pagesize (overridable by -z common-page-size) + true, // isolate_execinstr + 0x10000000, // rosegment_gap + elfcpp::SHN_UNDEF, // small_common_shndx + elfcpp::SHN_X86_64_LCOMMON, // large_common_shndx + 0, // small_common_section_flags + elfcpp::SHF_X86_64_LARGE, // large_common_section_flags + NULL, // attributes_section + NULL // attributes_vendor +}; + +template<> +const Target::Target_info Target_x86_64_nacl<32>::x86_64_nacl_info = +{ + 32, // size + false, // is_big_endian + elfcpp::EM_X86_64, // machine_code + false, // has_make_symbol + false, // has_resolve + true, // has_code_fill + true, // is_default_stack_executable + true, // can_icf_inline_merge_sections + '\0', // wrap_char + "/lib/ld-nacl-x86-64.so.1", // dynamic_linker + 0x20000, // default_text_segment_address + 0x10000, // abi_pagesize (overridable by -z max-page-size) + 0x10000, // common_pagesize (overridable by -z common-page-size) + true, // isolate_execinstr + 0x10000000, // rosegment_gap + elfcpp::SHN_UNDEF, // small_common_shndx + elfcpp::SHN_X86_64_LCOMMON, // large_common_shndx + 0, // small_common_section_flags + elfcpp::SHF_X86_64_LARGE, // large_common_section_flags + NULL, // attributes_section + NULL // attributes_vendor +}; + +#define NACLMASK 0xe0 // 32-byte alignment mask. + +// The first entry in the PLT. + +template +const unsigned char +Output_data_plt_x86_64_nacl::first_plt_entry[plt_entry_size] = +{ + 0xff, 0x35, // pushq contents of memory address + 0, 0, 0, 0, // replaced with address of .got + 8 + 0x4c, 0x8b, 0x1d, // mov GOT+16(%rip), %r11 + 0, 0, 0, 0, // replaced with address of .got + 16 + 0x41, 0x83, 0xe3, NACLMASK, // and $-32, %r11d + 0x4d, 0x01, 0xfb, // add %r15, %r11 + 0x41, 0xff, 0xe3, // jmpq *%r11 + + // 9-byte nop sequence to pad out to the next 32-byte boundary. + 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopl %cs:0x0(%rax,%rax,1) + + // 32 bytes of nop to pad out to the standard size + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // excess data32 prefixes + 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1) + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // excess data32 prefixes + 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1) + 0x66, // excess data32 prefix + 0x90 // nop +}; + +template +void +Output_data_plt_x86_64_nacl::do_fill_first_plt_entry( + unsigned char* pov, + typename elfcpp::Elf_types::Elf_Addr got_address, + typename elfcpp::Elf_types::Elf_Addr plt_address) +{ + memcpy(pov, first_plt_entry, plt_entry_size); + elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, + (got_address + 8 + - (plt_address + 2 + 4))); + elfcpp::Swap_unaligned<32, false>::writeval(pov + 9, + (got_address + 16 + - (plt_address + 9 + 4))); +} + +// Subsequent entries in the PLT. + +template +const unsigned char +Output_data_plt_x86_64_nacl::plt_entry[plt_entry_size] = +{ + 0x4c, 0x8b, 0x1d, // mov name@GOTPCREL(%rip),%r11 + 0, 0, 0, 0, // replaced with address of symbol in .got + 0x41, 0x83, 0xe3, NACLMASK, // and $-32, %r11d + 0x4d, 0x01, 0xfb, // add %r15, %r11 + 0x41, 0xff, 0xe3, // jmpq *%r11 + + // 15-byte nop sequence to pad out to the next 32-byte boundary. + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // excess data32 prefixes + 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1) + + // Lazy GOT entries point here (32-byte aligned). + 0x68, // pushq immediate + 0, 0, 0, 0, // replaced with index into relocation table + 0xe9, // jmp relative + 0, 0, 0, 0, // replaced with offset to start of .plt0 + + // 22 bytes of nop to pad out to the standard size. + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // excess data32 prefixes + 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1) + 0x0f, 0x1f, 0x80, 0, 0, 0, 0, // nopl 0x0(%rax) +}; + +template +unsigned int +Output_data_plt_x86_64_nacl::do_fill_plt_entry( + unsigned char* pov, + typename elfcpp::Elf_types::Elf_Addr got_address, + typename elfcpp::Elf_types::Elf_Addr plt_address, + unsigned int got_offset, + unsigned int plt_offset, + unsigned int plt_index) +{ + memcpy(pov, plt_entry, plt_entry_size); + elfcpp::Swap_unaligned<32, false>::writeval(pov + 3, + (got_address + got_offset + - (plt_address + plt_offset + + 3 + 4))); + + elfcpp::Swap_unaligned<32, false>::writeval(pov + 33, plt_index); + elfcpp::Swap_unaligned<32, false>::writeval(pov + 38, + - (plt_offset + 38 + 4)); + + return 32; +} + +// The reserved TLSDESC entry in the PLT. + +template +const unsigned char +Output_data_plt_x86_64_nacl::tlsdesc_plt_entry[plt_entry_size] = +{ + 0xff, 0x35, // pushq x(%rip) + 0, 0, 0, 0, // replaced with address of linkmap GOT entry (at PLTGOT + 8) + 0x4c, 0x8b, 0x1d, // mov y(%rip),%r11 + 0, 0, 0, 0, // replaced with offset of reserved TLSDESC_GOT entry + 0x41, 0x83, 0xe3, NACLMASK, // and $-32, %r11d + 0x4d, 0x01, 0xfb, // add %r15, %r11 + 0x41, 0xff, 0xe3, // jmpq *%r11 + + // 41 bytes of nop to pad out to the standard size. + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // excess data32 prefixes + 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1) + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // excess data32 prefixes + 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1) + 0x66, 0x66, // excess data32 prefixes + 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1) +}; + +template +void +Output_data_plt_x86_64_nacl::do_fill_tlsdesc_entry( + unsigned char* pov, + typename elfcpp::Elf_types::Elf_Addr got_address, + typename elfcpp::Elf_types::Elf_Addr plt_address, + typename elfcpp::Elf_types::Elf_Addr got_base, + unsigned int tlsdesc_got_offset, + unsigned int plt_offset) +{ + memcpy(pov, tlsdesc_plt_entry, plt_entry_size); + elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, + (got_address + 8 + - (plt_address + plt_offset + + 2 + 4))); + elfcpp::Swap_unaligned<32, false>::writeval(pov + 9, + (got_base + + tlsdesc_got_offset + - (plt_address + plt_offset + + 9 + 4))); +} + +// The .eh_frame unwind information for the PLT. + +template +const unsigned char +Output_data_plt_x86_64_nacl::plt_eh_frame_fde[plt_eh_frame_fde_size] = +{ + 0, 0, 0, 0, // Replaced with offset to .plt. + 0, 0, 0, 0, // Replaced with size of .plt. + 0, // Augmentation size. + elfcpp::DW_CFA_def_cfa_offset, 16, // DW_CFA_def_cfa_offset: 16. + elfcpp::DW_CFA_advance_loc + 6, // Advance 6 to __PLT__ + 6. + elfcpp::DW_CFA_def_cfa_offset, 24, // DW_CFA_def_cfa_offset: 24. + elfcpp::DW_CFA_advance_loc + 58, // Advance 58 to __PLT__ + 64. + elfcpp::DW_CFA_def_cfa_expression, // DW_CFA_def_cfa_expression. + 13, // Block length. + elfcpp::DW_OP_breg7, 8, // Push %rsp + 8. + elfcpp::DW_OP_breg16, 0, // Push %rip. + elfcpp::DW_OP_const1u, 63, // Push 0x3f. + elfcpp::DW_OP_and, // & (%rip & 0x3f). + elfcpp::DW_OP_const1u, 37, // Push 0x25. + elfcpp::DW_OP_ge, // >= ((%rip & 0x3f) >= 0x25) + elfcpp::DW_OP_lit3, // Push 3. + elfcpp::DW_OP_shl, // << (((%rip & 0x3f) >= 0x25) << 3) + elfcpp::DW_OP_plus, // + ((((%rip&0x3f)>=0x25)<<3)+%rsp+8 + elfcpp::DW_CFA_nop, // Align to 32 bytes. + elfcpp::DW_CFA_nop +}; + +// The selector for x86_64-nacl object files. + +template +class Target_selector_x86_64_nacl + : public Target_selector_nacl, + Target_x86_64_nacl > +{ + public: + Target_selector_x86_64_nacl() + : Target_selector_nacl, + Target_x86_64_nacl >("x86-64", + size == 64 + ? "elf64-x86-64-nacl" + : "elf32-x86-64-nacl", + size == 64 + ? "elf_x86_64_nacl" + : "elf32_x86_64_nacl") + { } +}; + +Target_selector_x86_64_nacl<64> target_selector_x86_64; +Target_selector_x86_64_nacl<32> target_selector_x32; } // End anonymous namespace.