X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Fx86_64.cc;h=3cfc064d4b467de85c2c30dd1ac6dfbb4cfe9959;hb=4d625b70fc3fb7facc7159feb8d49b78ac6641f9;hp=c368b039869aae87884f39d52dd43d858703d5d5;hpb=e749cab89d976c723ee01a3dfcfd7ec1a883f890;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/x86_64.cc b/gold/x86_64.cc index c368b03986..3cfc064d4b 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -1,6 +1,6 @@ // x86_64.cc -- x86_64 target support for gold. -// Copyright (C) 2006-2015 Free Software Foundation, Inc. +// Copyright (C) 2006-2016 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. @@ -496,6 +496,21 @@ class Target_x86_64 : public Sized_target const unsigned char* plocal_symbols, Relocatable_relocs*); + // Scan the relocs for --emit-relocs. + void + emit_relocs_scan(Symbol_table* symtab, + Layout* layout, + Sized_relobj_file* object, + unsigned int data_shndx, + unsigned int sh_type, + const unsigned char* prelocs, + size_t reloc_count, + Output_section* output_section, + bool needs_special_offset_handling, + size_t local_symbol_count, + const unsigned char* plocal_syms, + Relocatable_relocs* rr); + // Emit relocations for a section. void relocate_relocs( @@ -505,7 +520,6 @@ class Target_x86_64 : public Sized_target size_t reloc_count, Output_section* 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, section_size_type view_size, @@ -562,6 +576,7 @@ class Target_x86_64 : public Sized_target void do_calls_non_split(Relobj* object, unsigned int shndx, section_offset_type fnoffset, section_size_type fnsize, + const unsigned char* prelocs, size_t reloc_count, unsigned char* view, section_size_type view_size, std::string* from, std::string* to) const; @@ -594,6 +609,11 @@ class Target_x86_64 : public Sized_target unsigned int plt_entry_size() const; + // Return the size of each GOT entry. + unsigned int + got_entry_size() const + { return 8; }; + // Create the GOT section for an incremental update. Output_data_got_base* init_got_plt_for_update(Symbol_table* symtab, @@ -777,11 +797,9 @@ class Target_x86_64 : public Sized_target // Do a relocation. Return false if the caller should not issue // any warnings about this relocation. inline bool - relocate(const Relocate_info*, Target_x86_64*, - Output_section*, - size_t relnum, const elfcpp::Rela&, - unsigned int r_type, const Sized_symbol*, - const Symbol_value*, + relocate(const Relocate_info*, unsigned int, + Target_x86_64*, Output_section*, size_t, const unsigned char*, + const Sized_symbol*, const Symbol_value*, unsigned char*, typename elfcpp::Elf_types::Elf_Addr, section_size_type); @@ -856,14 +874,24 @@ class Target_x86_64 : public Sized_target 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 + // Check if relocation against this symbol is a candidate for + // conversion from + // mov foo@GOTPCREL(%rip), %reg + // to lea foo(%rip), %reg. + static bool + can_convert_mov_to_lea(const Symbol* gsym) { - public: - unsigned int - get_size_for_reloc(unsigned int, Relobj*); - }; + gold_assert(gsym != NULL); + return (gsym->type() != elfcpp::STT_GNU_IFUNC + && !gsym->is_undefined () + && !gsym->is_from_dynobj() + && !gsym->is_preemptible() + && (!parameters->options().shared() + || (gsym->visibility() != elfcpp::STV_DEFAULT + && gsym->visibility() != elfcpp::STV_PROTECTED) + || parameters->options().Bsymbolic()) + && strcmp(gsym->name(), "_DYNAMIC") != 0); + } // Adjust TLS relocation type based on the options and whether this // is a local symbol. @@ -944,10 +972,13 @@ class Target_x86_64 : public Sized_target unsigned int shndx, Output_section* output_section, Symbol* sym, const elfcpp::Rela& reloc) { + unsigned int r_type = elfcpp::elf_r_type(reloc.get_r_info()); this->copy_relocs_.copy_reloc(symtab, layout, symtab->get_sized_symbol(sym), object, shndx, output_section, - reloc, this->rela_dyn_section(layout)); + r_type, reloc.get_r_offset(), + reloc.get_r_addend(), + this->rela_dyn_section(layout)); } // Information about this specific target which we pass to the @@ -1033,7 +1064,8 @@ const Target::Target_info Target_x86_64<64>::x86_64_info = elfcpp::SHF_X86_64_LARGE, // large_common_section_flags NULL, // attributes_section NULL, // attributes_vendor - "_start" // entry_symbol_name + "_start", // entry_symbol_name + 32, // hash_entry_size }; template<> @@ -1060,7 +1092,8 @@ const Target::Target_info Target_x86_64<32>::x86_64_info = elfcpp::SHF_X86_64_LARGE, // large_common_section_flags NULL, // attributes_section NULL, // attributes_vendor - "_start" // entry_symbol_name + "_start", // entry_symbol_name + 32, // hash_entry_size }; // This is called when a new output section is created. This is where @@ -2172,6 +2205,8 @@ Target_x86_64::Scan::get_reference_flags(unsigned int r_type) case elfcpp::R_X86_64_GOT32: case elfcpp::R_X86_64_GOTPCREL64: case elfcpp::R_X86_64_GOTPCREL: + case elfcpp::R_X86_64_GOTPCRELX: + case elfcpp::R_X86_64_REX_GOTPCRELX: case elfcpp::R_X86_64_GOTPLT64: // Absolute in GOT. return Symbol::ABSOLUTE_REF; @@ -2456,10 +2491,33 @@ Target_x86_64::Scan::local(Symbol_table* symtab, case elfcpp::R_X86_64_GOT32: case elfcpp::R_X86_64_GOTPCREL64: case elfcpp::R_X86_64_GOTPCREL: + case elfcpp::R_X86_64_GOTPCRELX: + case elfcpp::R_X86_64_REX_GOTPCRELX: case elfcpp::R_X86_64_GOTPLT64: { - // The symbol requires a GOT entry. + // The symbol requires a GOT section. Output_data_got<64, false>* got = target->got_section(symtab, layout); + + // If the relocation symbol isn't IFUNC, + // and is local, then we will convert + // mov foo@GOTPCREL(%rip), %reg + // to lea foo(%rip), %reg. + // in Relocate::relocate. + if ((r_type == elfcpp::R_X86_64_GOTPCREL + || r_type == elfcpp::R_X86_64_GOTPCRELX + || r_type == elfcpp::R_X86_64_REX_GOTPCRELX) + && reloc.get_r_offset() >= 2 + && !is_ifunc) + { + section_size_type stype; + const unsigned char* view = object->section_contents(data_shndx, + &stype, true); + if (view[reloc.get_r_offset() - 2] == 0x8b) + break; + } + + + // The symbol requires a GOT entry. unsigned int r_sym = elfcpp::elf_r_sym(reloc.get_r_info()); // For a STT_GNU_IFUNC symbol we want the PLT offset. That @@ -2675,6 +2733,8 @@ Target_x86_64::Scan::possible_function_pointer_reloc(unsigned int r_type) case elfcpp::R_X86_64_GOT32: case elfcpp::R_X86_64_GOTPCREL64: case elfcpp::R_X86_64_GOTPCREL: + case elfcpp::R_X86_64_GOTPCRELX: + case elfcpp::R_X86_64_REX_GOTPCRELX: case elfcpp::R_X86_64_GOTPLT64: { return true; @@ -2863,10 +2923,30 @@ Target_x86_64::Scan::global(Symbol_table* symtab, case elfcpp::R_X86_64_GOT32: case elfcpp::R_X86_64_GOTPCREL64: case elfcpp::R_X86_64_GOTPCREL: + case elfcpp::R_X86_64_GOTPCRELX: + case elfcpp::R_X86_64_REX_GOTPCRELX: case elfcpp::R_X86_64_GOTPLT64: { // The symbol requires a GOT entry. Output_data_got<64, false>* got = target->got_section(symtab, layout); + + // If we convert this from + // mov foo@GOTPCREL(%rip), %reg + // to lea foo(%rip), %reg. + // in Relocate::relocate, then there is nothing to do here. + if ((r_type == elfcpp::R_X86_64_GOTPCREL + || r_type == elfcpp::R_X86_64_GOTPCRELX + || r_type == elfcpp::R_X86_64_REX_GOTPCRELX) + && reloc.get_r_offset() >= 2 + && Target_x86_64::can_convert_mov_to_lea(gsym)) + { + section_size_type stype; + const unsigned char* view = object->section_contents(data_shndx, + &stype, true); + if (view[reloc.get_r_offset() - 2] == 0x8b) + break; + } + if (gsym->final_value_is_known()) { // For a STT_GNU_IFUNC symbol we want the PLT address. @@ -2983,7 +3063,12 @@ Target_x86_64::Scan::global(Symbol_table* symtab, case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec case elfcpp::R_X86_64_TPOFF32: // Local-exec { - const bool is_final = gsym->final_value_is_known(); + // For the Initial-Exec model, we can treat undef symbols as final + // when building an executable. + const bool is_final = (gsym->final_value_is_known() || + (r_type == elfcpp::R_X86_64_GOTTPOFF && + gsym->is_undefined() && + parameters->options().output_is_executable())); const tls::Tls_optimization optimized_type = Target_x86_64::optimize_tls_reloc(is_final, r_type); switch (r_type) @@ -3112,15 +3197,16 @@ Target_x86_64::gc_process_relocs(Symbol_table* symtab, size_t local_symbol_count, const unsigned char* plocal_symbols) { + typedef gold::Default_classify_reloc + Classify_reloc; if (sh_type == elfcpp::SHT_REL) { return; } - gold::gc_process_relocs, elfcpp::SHT_RELA, - typename Target_x86_64::Scan, - typename Target_x86_64::Relocatable_size_for_reloc>( + gold::gc_process_relocs, Scan, + Classify_reloc>( symtab, layout, this, @@ -3150,6 +3236,9 @@ Target_x86_64::scan_relocs(Symbol_table* symtab, size_t local_symbol_count, const unsigned char* plocal_symbols) { + typedef gold::Default_classify_reloc + Classify_reloc; + if (sh_type == elfcpp::SHT_REL) { gold_error(_("%s: unsupported REL reloc section"), @@ -3157,8 +3246,7 @@ Target_x86_64::scan_relocs(Symbol_table* symtab, return; } - gold::scan_relocs, elfcpp::SHT_RELA, - typename Target_x86_64::Scan>( + gold::scan_relocs, Scan, Classify_reloc>( symtab, layout, this, @@ -3267,17 +3355,20 @@ template inline bool Target_x86_64::Relocate::relocate( const Relocate_info* relinfo, + unsigned int, Target_x86_64* target, Output_section*, size_t relnum, - const elfcpp::Rela& rela, - unsigned int r_type, + const unsigned char* preloc, const Sized_symbol* gsym, const Symbol_value* psymval, unsigned char* view, typename elfcpp::Elf_types::Elf_Addr address, section_size_type view_size) { + const elfcpp::Rela rela(preloc); + unsigned int r_type = elfcpp::elf_r_type(rela.get_r_info()); + if (this->skip_call_tls_get_addr_) { if ((r_type != elfcpp::R_X86_64_PLT32 @@ -3335,7 +3426,6 @@ Target_x86_64::Relocate::relocate( case elfcpp::R_X86_64_GOT32: case elfcpp::R_X86_64_GOT64: case elfcpp::R_X86_64_GOTPLT64: - case elfcpp::R_X86_64_GOTPCREL: case elfcpp::R_X86_64_GOTPCREL64: if (gsym != NULL) { @@ -3480,11 +3570,41 @@ Target_x86_64::Relocate::relocate( break; case elfcpp::R_X86_64_GOTPCREL: + case elfcpp::R_X86_64_GOTPCRELX: + case elfcpp::R_X86_64_REX_GOTPCRELX: { - 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); + // Convert + // mov foo@GOTPCREL(%rip), %reg + // to lea foo(%rip), %reg. + // if possible. + if (rela.get_r_offset() >= 2 + && view[-2] == 0x8b + && ((gsym == NULL && !psymval->is_ifunc_symbol()) + || (gsym != NULL + && Target_x86_64::can_convert_mov_to_lea(gsym)))) + { + view[-2] = 0x8d; + Relocate_functions::pcrela32(view, object, psymval, addend, + address); + } + else + { + if (gsym != NULL) + { + 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()); + } + typename elfcpp::Elf_types::Elf_Addr value; + value = target->got_plt_section()->address() + got_offset; + Relocate_functions::pcrela32(view, value, addend, address); + } } break; @@ -3779,7 +3899,17 @@ Target_x86_64::Relocate::relocate_tls( break; case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec - if (optimized_type == tls::TLSOPT_TO_LE) + if (gsym != NULL + && gsym->is_undefined() + && parameters->options().output_is_executable()) + { + Target_x86_64::Relocate::tls_ie_to_le(relinfo, relnum, + NULL, rela, + r_type, value, view, + view_size); + break; + } + else if (optimized_type == tls::TLSOPT_TO_LE) { if (tls_segment == NULL) { @@ -4126,7 +4256,8 @@ Target_x86_64::Relocate::tls_ie_to_le( view[-1] = 0x80 | reg | (reg << 3); } - value -= tls_segment->memsz(); + if (tls_segment != NULL) + value -= tls_segment->memsz(); Relocate_functions::rela32(view, value, 0); } @@ -4146,11 +4277,13 @@ Target_x86_64::relocate_section( section_size_type view_size, const Reloc_symbol_changes* reloc_symbol_changes) { + typedef gold::Default_classify_reloc + Classify_reloc; + gold_assert(sh_type == elfcpp::SHT_RELA); - gold::relocate_section, elfcpp::SHT_RELA, - typename Target_x86_64::Relocate, - gold::Default_comdat_behavior>( + gold::relocate_section, Relocate, + gold::Default_comdat_behavior, Classify_reloc>( relinfo, this, prelocs, @@ -4191,84 +4324,50 @@ Target_x86_64::apply_relocation( view_size); } -// Return the size of a relocation while scanning during a relocatable -// link. +// Scan the relocs during a relocatable link. template -unsigned int -Target_x86_64::Relocatable_size_for_reloc::get_size_for_reloc( - unsigned int r_type, - Relobj* object) +void +Target_x86_64::scan_relocatable_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, + Relocatable_relocs* rr) { - switch (r_type) - { - case elfcpp::R_X86_64_NONE: - case elfcpp::R_X86_64_GNU_VTINHERIT: - case elfcpp::R_X86_64_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_PC32_BND: - case elfcpp::R_X86_64_PLT32: - case elfcpp::R_X86_64_PLT32_BND: - 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; + typedef gold::Default_classify_reloc + Classify_reloc; + typedef gold::Default_scan_relocatable_relocs + Scan_relocatable_relocs; - 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: - case elfcpp::R_X86_64_IRELATIVE: - // 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; + gold_assert(sh_type == elfcpp::SHT_RELA); - 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; - } + gold::scan_relocatable_relocs( + symtab, + layout, + object, + data_shndx, + prelocs, + reloc_count, + output_section, + needs_special_offset_handling, + local_symbol_count, + plocal_symbols, + rr); } -// Scan the relocs during a relocatable link. +// Scan the relocs for --emit-relocs. template void -Target_x86_64::scan_relocatable_relocs( +Target_x86_64::emit_relocs_scan( Symbol_table* symtab, Layout* layout, Sized_relobj_file* object, @@ -4279,16 +4378,17 @@ Target_x86_64::scan_relocatable_relocs( Output_section* output_section, bool needs_special_offset_handling, size_t local_symbol_count, - const unsigned char* plocal_symbols, + const unsigned char* plocal_syms, Relocatable_relocs* rr) { - gold_assert(sh_type == elfcpp::SHT_RELA); + typedef gold::Default_classify_reloc + Classify_reloc; + typedef gold::Default_emit_relocs_strategy + Emit_relocs_strategy; - typedef gold::Default_scan_relocatable_relocs Scan_relocatable_relocs; + gold_assert(sh_type == elfcpp::SHT_RELA); - gold::scan_relocatable_relocs( + gold::scan_relocatable_relocs( symtab, layout, object, @@ -4298,7 +4398,7 @@ Target_x86_64::scan_relocatable_relocs( output_section, needs_special_offset_handling, local_symbol_count, - plocal_symbols, + plocal_syms, rr); } @@ -4313,22 +4413,23 @@ Target_x86_64::relocate_relocs( size_t reloc_count, Output_section* 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, section_size_type view_size, unsigned char* reloc_view, section_size_type reloc_view_size) { + typedef gold::Default_classify_reloc + Classify_reloc; + gold_assert(sh_type == elfcpp::SHT_RELA); - gold::relocate_relocs( + gold::relocate_relocs( relinfo, prelocs, reloc_count, output_section, offset_in_output_section, - rr, view, view_address, view_size, @@ -4463,35 +4564,60 @@ Target_x86_64::do_ehframe_datarel_base() const // code. We have to change the function so that it always ensures // that it has enough stack space to run some random function. +static const unsigned char cmp_insn_32[] = { 0x64, 0x3b, 0x24, 0x25 }; +static const unsigned char lea_r10_insn_32[] = { 0x44, 0x8d, 0x94, 0x24 }; +static const unsigned char lea_r11_insn_32[] = { 0x44, 0x8d, 0x9c, 0x24 }; + +static const unsigned char cmp_insn_64[] = { 0x64, 0x48, 0x3b, 0x24, 0x25 }; +static const unsigned char lea_r10_insn_64[] = { 0x4c, 0x8d, 0x94, 0x24 }; +static const unsigned char lea_r11_insn_64[] = { 0x4c, 0x8d, 0x9c, 0x24 }; + template void Target_x86_64::do_calls_non_split(Relobj* object, unsigned int shndx, section_offset_type fnoffset, section_size_type fnsize, + const unsigned char*, + size_t, unsigned char* view, section_size_type view_size, std::string* from, std::string* to) const { + const char* const cmp_insn = reinterpret_cast + (size == 32 ? cmp_insn_32 : cmp_insn_64); + const char* const lea_r10_insn = reinterpret_cast + (size == 32 ? lea_r10_insn_32 : lea_r10_insn_64); + const char* const lea_r11_insn = reinterpret_cast + (size == 32 ? lea_r11_insn_32 : lea_r11_insn_64); + + const size_t cmp_insn_len = + (size == 32 ? sizeof(cmp_insn_32) : sizeof(cmp_insn_64)); + const size_t lea_r10_insn_len = + (size == 32 ? sizeof(lea_r10_insn_32) : sizeof(lea_r10_insn_64)); + const size_t lea_r11_insn_len = + (size == 32 ? sizeof(lea_r11_insn_32) : sizeof(lea_r11_insn_64)); + const size_t nop_len = (size == 32 ? 7 : 8); + // The function starts with a comparison of the stack pointer and a // field in the TCB. This is followed by a jump. // cmp %fs:NN,%rsp - if (this->match_view(view, view_size, fnoffset, "\x64\x48\x3b\x24\x25", 5) - && fnsize > 9) + if (this->match_view(view, view_size, fnoffset, cmp_insn, cmp_insn_len) + && fnsize > nop_len + 1) { // We will call __morestack if the carry flag is set after this // comparison. We turn the comparison into an stc instruction // and some nops. view[fnoffset] = '\xf9'; - this->set_view_to_nop(view, view_size, fnoffset + 1, 8); + this->set_view_to_nop(view, view_size, fnoffset + 1, nop_len); } // lea NN(%rsp),%r10 // lea NN(%rsp),%r11 else if ((this->match_view(view, view_size, fnoffset, - "\x4c\x8d\x94\x24", 4) + lea_r10_insn, lea_r10_insn_len) || this->match_view(view, view_size, fnoffset, - "\x4c\x8d\x9c\x24", 4)) + lea_r11_insn, lea_r11_insn_len)) && fnsize > 8) { // This is loading an offset from the stack pointer for a @@ -4682,7 +4808,8 @@ const Target::Target_info Target_x86_64_nacl<64>::x86_64_nacl_info = elfcpp::SHF_X86_64_LARGE, // large_common_section_flags NULL, // attributes_section NULL, // attributes_vendor - "_start" // entry_symbol_name + "_start", // entry_symbol_name + 32, // hash_entry_size }; template<> @@ -4709,7 +4836,8 @@ const Target::Target_info Target_x86_64_nacl<32>::x86_64_nacl_info = elfcpp::SHF_X86_64_LARGE, // large_common_section_flags NULL, // attributes_section NULL, // attributes_vendor - "_start" // entry_symbol_name + "_start", // entry_symbol_name + 32, // hash_entry_size }; #define NACLMASK 0xe0 // 32-byte alignment mask.