X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Fsparc.cc;h=6db3b1014be26c633c9abe0e1ad96f1a44b62bb0;hb=d180bcbd34b9ed5f0062636786ff31c803c2f735;hp=eb238f9b1c1dc5a0f640f44ecf89004b2da1f55f;hpb=a4d851453b4050a60b36dac130aad4b4b490a2c0;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/sparc.cc b/gold/sparc.cc index eb238f9b1c..6db3b1014b 100644 --- a/gold/sparc.cc +++ b/gold/sparc.cc @@ -66,20 +66,20 @@ class Target_sparc : public Sized_target { } - // Process the relocations to determine unreferenced sections for + // Process the relocations to determine unreferenced sections for // garbage collection. 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 @@ -131,20 +131,22 @@ class Target_sparc : 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(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, - const Relocatable_relocs*, - 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); + relocate_relocs(const Relocate_info*, + unsigned int sh_type, + const unsigned char* prelocs, + 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, + unsigned char* reloc_view, + section_size_type reloc_view_size); + // Return whether SYM is defined by the ABI. bool do_is_defined_by_abi(const Symbol* sym) const @@ -236,7 +238,8 @@ class Target_sparc : 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_sparc* target, @@ -248,24 +251,24 @@ class Target_sparc : public Sized_target inline bool local_reloc_may_be_function_pointer(Symbol_table* , Layout* , - Target_sparc* , - Sized_relobj_file* , - unsigned int , - Output_section* , - const elfcpp::Rela& , + Target_sparc* , + Sized_relobj_file* , + unsigned int , + Output_section* , + const elfcpp::Rela& , unsigned int , - const elfcpp::Sym&) + const elfcpp::Sym&) { return false; } inline bool global_reloc_may_be_function_pointer(Symbol_table* , Layout* , - Target_sparc* , - Sized_relobj_file* , - unsigned int , - Output_section* , - const elfcpp::Rela& , - unsigned int , Symbol*) + Target_sparc* , + Sized_relobj_file* , + unsigned int , + Output_section* , + const elfcpp::Rela& , + unsigned int , Symbol*) { return false; } @@ -326,13 +329,19 @@ class Target_sparc : public Sized_target // Do a TLS relocation. inline void relocate_tls(const Relocate_info*, Target_sparc* target, - 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, section_size_type); + inline void + relax_call(Target_sparc* target, + unsigned char* view, + const elfcpp::Rela& rela, + section_size_type view_size); + // Ignore the next relocation which should be R_SPARC_TLS_GD_ADD bool ignore_gd_add_; @@ -402,7 +411,7 @@ class Target_sparc : public Sized_target // Copy a relocation against a global symbol. 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) { @@ -467,6 +476,8 @@ Target::Target_info Target_sparc<32, true>::sparc_info = 0x00010000, // default_text_segment_address 64 * 1024, // abi_pagesize (overridable by -z max-page-size) 8 * 1024, // common_pagesize (overridable by -z common-page-size) + false, // isolate_execinstr + 0, // rosegment_gap elfcpp::SHN_UNDEF, // small_common_shndx elfcpp::SHN_UNDEF, // large_common_shndx 0, // small_common_section_flags @@ -491,6 +502,8 @@ Target::Target_info Target_sparc<64, true>::sparc_info = 0x100000, // default_text_segment_address 64 * 1024, // abi_pagesize (overridable by -z max-page-size) 8 * 1024, // common_pagesize (overridable by -z common-page-size) + false, // isolate_execinstr + 0, // rosegment_gap elfcpp::SHN_UNDEF, // small_common_shndx elfcpp::SHN_UNDEF, // large_common_shndx 0, // small_common_section_flags @@ -1607,7 +1620,7 @@ Output_data_plt_sparc::address_for_global(const Symbol* gsym) if (gsym->type() == elfcpp::STT_GNU_IFUNC && gsym->can_use_relative_reloc(false)) offset = plt_index_to_offset(this->count_ + 4); - return this->address() + offset; + return this->address() + offset + gsym->plt_offset(); } // Return the PLT address to use for a local symbol. These are always @@ -1616,10 +1629,12 @@ Output_data_plt_sparc::address_for_global(const Symbol* gsym) template uint64_t Output_data_plt_sparc::address_for_local( - const Relobj*, - unsigned int) + const Relobj* object, + unsigned int r_sym) { - return this->address() + plt_index_to_offset(this->count_ + 4); + return (this->address() + + plt_index_to_offset(this->count_ + 4) + + object->local_plt_offset(r_sym)); } static const unsigned int sparc_nop = 0x01000000; @@ -2212,7 +2227,7 @@ Target_sparc::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; } @@ -2229,8 +2244,12 @@ Target_sparc::Scan::local( 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; + bool is_ifunc = lsym.get_st_type() == elfcpp::STT_GNU_IFUNC; unsigned int orig_r_type = r_type; r_type &= 0xff; @@ -2259,14 +2278,14 @@ Target_sparc::Scan::local( // an R_SPARC_RELATIVE relocation so the dynamic loader can // relocate it easily. if (parameters->options().output_is_position_independent()) - { - Reloc_section* rela_dyn = target->rela_dyn_section(layout); - unsigned int r_sym = elfcpp::elf_r_sym(reloc.get_r_info()); - rela_dyn->add_local_relative(object, r_sym, elfcpp::R_SPARC_RELATIVE, + { + Reloc_section* rela_dyn = target->rela_dyn_section(layout); + unsigned int r_sym = elfcpp::elf_r_sym(reloc.get_r_info()); + rela_dyn->add_local_relative(object, r_sym, elfcpp::R_SPARC_RELATIVE, output_section, data_shndx, reloc.get_r_offset(), reloc.get_r_addend(), is_ifunc); - } + } break; case elfcpp::R_SPARC_HIX22: @@ -2295,26 +2314,26 @@ Target_sparc::Scan::local( // executable), we need to create a dynamic relocation for // this location. if (parameters->options().output_is_position_independent()) - { - 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); + unsigned int r_sym = elfcpp::elf_r_sym(reloc.get_r_info()); check_non_pic(object, r_type); - if (lsym.get_st_type() != elfcpp::STT_SECTION) - { - rela_dyn->add_local(object, r_sym, orig_r_type, output_section, + if (lsym.get_st_type() != elfcpp::STT_SECTION) + { + rela_dyn->add_local(object, r_sym, orig_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); rela_dyn->add_symbolless_local_addend(object, r_sym, orig_r_type, output_section, data_shndx, reloc.get_r_offset(), reloc.get_r_addend()); - } - } + } + } break; case elfcpp::R_SPARC_WDISP30: @@ -2342,9 +2361,9 @@ Target_sparc::Scan::local( case elfcpp::R_SPARC_GOT13: case elfcpp::R_SPARC_GOT22: { - // The symbol requires a GOT entry. - Output_data_got* got; - unsigned int r_sym; + // The symbol requires a GOT entry. + Output_data_got* got; + unsigned int r_sym; got = target->got_section(symtab, layout); r_sym = elfcpp::elf_r_sym(reloc.get_r_info()); @@ -2391,7 +2410,7 @@ Target_sparc::Scan::local( { bool output_is_shared = parameters->options().shared(); const tls::Tls_optimization optimized_type - = optimize_tls_reloc(!output_is_shared, r_type); + = optimize_tls_reloc(!output_is_shared, r_type); switch (r_type) { case elfcpp::R_SPARC_TLS_GD_HI22: // Global-dynamic @@ -2400,11 +2419,11 @@ Target_sparc::Scan::local( case elfcpp::R_SPARC_TLS_GD_CALL: if (optimized_type == tls::TLSOPT_NONE) { - // Create a pair of GOT entries for the module index and - // dtv-relative offset. - Output_data_got* got - = target->got_section(symtab, layout); - unsigned int r_sym = elfcpp::elf_r_sym(reloc.get_r_info()); + // Create a pair of GOT entries for the module index and + // dtv-relative offset. + Output_data_got* 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); @@ -2412,14 +2431,13 @@ Target_sparc::Scan::local( object->error(_("local symbol %u has bad shndx %u"), r_sym, shndx); else - got->add_local_pair_with_rel(object, r_sym, + got->add_local_pair_with_rel(object, r_sym, lsym.get_st_shndx(), GOT_TYPE_TLS_PAIR, target->rela_dyn_section(layout), (size == 64 ? elfcpp::R_SPARC_TLS_DTPMOD64 - : elfcpp::R_SPARC_TLS_DTPMOD32), - 0); + : elfcpp::R_SPARC_TLS_DTPMOD32)); if (r_type == elfcpp::R_SPARC_TLS_GD_CALL) generate_tls_call(symtab, layout, target); } @@ -2484,11 +2502,11 @@ Target_sparc::Scan::local( layout->set_has_static_tls(); if (output_is_shared) { - // We need to create a dynamic relocation. - gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION); - unsigned int r_sym = elfcpp::elf_r_sym(reloc.get_r_info()); - Reloc_section* rela_dyn = target->rela_dyn_section(layout); - rela_dyn->add_symbolless_local_addend(object, r_sym, r_type, + // We need to create a dynamic relocation. + gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION); + unsigned int r_sym = elfcpp::elf_r_sym(reloc.get_r_info()); + Reloc_section* rela_dyn = target->rela_dyn_section(layout); + rela_dyn->add_symbolless_local_addend(object, r_sym, r_type, output_section, data_shndx, reloc.get_r_offset(), 0); } @@ -2590,8 +2608,8 @@ Target_sparc::Scan::global( // 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; @@ -2659,24 +2677,24 @@ Target_sparc::Scan::global( case elfcpp::R_SPARC_6: case elfcpp::R_SPARC_5: { - // 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))) - { + // 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))) + { unsigned int r_off = reloc.get_r_offset(); // The assembler can sometimes emit unaligned relocations - // for dwarf2 cfi directives. + // for dwarf2 cfi directives. switch (r_type) { case elfcpp::R_SPARC_16: @@ -2705,11 +2723,11 @@ Target_sparc::Scan::global( break; } - if (gsym->may_need_copy_reloc()) - { - target->copy_reloc(symtab, layout, object, - data_shndx, output_section, gsym, reloc); - } + 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_SPARC_64) || (size == 32 && r_type == elfcpp::R_SPARC_32)) && gsym->type() == elfcpp::STT_GNU_IFUNC @@ -2731,19 +2749,19 @@ Target_sparc::Scan::global( reloc.get_r_offset(), reloc.get_r_addend()); } - else if ((r_type == elfcpp::R_SPARC_32 + else if ((r_type == elfcpp::R_SPARC_32 || r_type == elfcpp::R_SPARC_64) - && gsym->can_use_relative_reloc(false)) - { - Reloc_section* rela_dyn = target->rela_dyn_section(layout); - rela_dyn->add_global_relative(gsym, elfcpp::R_SPARC_RELATIVE, + && gsym->can_use_relative_reloc(false)) + { + Reloc_section* rela_dyn = target->rela_dyn_section(layout); + rela_dyn->add_global_relative(gsym, elfcpp::R_SPARC_RELATIVE, output_section, object, data_shndx, reloc.get_r_offset(), reloc.get_r_addend(), is_ifunc); - } - else - { - Reloc_section* rela_dyn = target->rela_dyn_section(layout); + } + else + { + Reloc_section* rela_dyn = target->rela_dyn_section(layout); check_non_pic(object, r_type); if (gsym->is_from_dynobj() @@ -2759,8 +2777,8 @@ Target_sparc::Scan::global( object, data_shndx, reloc.get_r_offset(), reloc.get_r_addend()); - } - } + } + } } break; @@ -2768,8 +2786,8 @@ Target_sparc::Scan::global( case elfcpp::R_SPARC_GOTDATA_OP_HIX22: case elfcpp::R_SPARC_GOTDATA_OP_LOX10: if (gsym->is_defined() - && !gsym->is_from_dynobj() - && !gsym->is_preemptible() + && !gsym->is_from_dynobj() + && !gsym->is_preemptible() && !is_ifunc) { // We will optimize this into a GOT relative relocation @@ -2780,11 +2798,11 @@ Target_sparc::Scan::global( case elfcpp::R_SPARC_GOT13: case elfcpp::R_SPARC_GOT22: { - // The symbol requires a GOT entry. - Output_data_got* got; + // The symbol requires a GOT entry. + Output_data_got* got; got = target->got_section(symtab, layout); - if (gsym->final_value_is_known()) + if (gsym->final_value_is_known()) { // For a STT_GNU_IFUNC symbol we want the PLT address. if (gsym->type() == elfcpp::STT_GNU_IFUNC) @@ -2792,10 +2810,10 @@ Target_sparc::Scan::global( else got->add_global(gsym, GOT_TYPE_STANDARD); } - else - { - // If this symbol is not fully resolved, we need to add a - // GOT entry with a dynamic relocation. + else + { + // If this symbol is not fully resolved, we need to add a + // GOT entry with a dynamic relocation. bool is_ifunc = gsym->type() == elfcpp::STT_GNU_IFUNC; // Use a GLOB_DAT rather than a RELATIVE reloc if: @@ -2810,10 +2828,10 @@ Target_sparc::Scan::global( // // 3) This is a STT_GNU_IFUNC symbol in position dependent // code, again so that function address comparisons work. - Reloc_section* rela_dyn = target->rela_dyn_section(layout); - if (gsym->is_from_dynobj() - || gsym->is_undefined() - || gsym->is_preemptible() + Reloc_section* rela_dyn = target->rela_dyn_section(layout); + if (gsym->is_from_dynobj() + || gsym->is_undefined() + || gsym->is_preemptible() || (gsym->visibility() == elfcpp::STV_PROTECTED && parameters->options().shared()) || (gsym->type() == elfcpp::STT_GNU_IFUNC @@ -2832,8 +2850,8 @@ Target_sparc::Scan::global( got->add_global_with_rel(gsym, GOT_TYPE_STANDARD, rela_dyn, r_type); } - else if (!gsym->has_got_offset(GOT_TYPE_STANDARD)) - { + else if (!gsym->has_got_offset(GOT_TYPE_STANDARD)) + { unsigned int off = got->add_constant(0); gsym->set_got_offset(GOT_TYPE_STANDARD, off); @@ -2848,7 +2866,7 @@ Target_sparc::Scan::global( rela_dyn->add_global_relative(gsym, elfcpp::R_SPARC_RELATIVE, got, off, 0, is_ifunc); } - } + } } break; @@ -2875,7 +2893,7 @@ Target_sparc::Scan::global( { const bool is_final = gsym->final_value_is_known(); const tls::Tls_optimization optimized_type - = optimize_tls_reloc(is_final, r_type); + = optimize_tls_reloc(is_final, r_type); switch (r_type) { case elfcpp::R_SPARC_TLS_GD_HI22: // Global-dynamic @@ -2884,11 +2902,11 @@ Target_sparc::Scan::global( case elfcpp::R_SPARC_TLS_GD_CALL: if (optimized_type == tls::TLSOPT_NONE) { - // Create a pair of GOT entries for the module index and - // dtv-relative offset. - Output_data_got* 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* got + = target->got_section(symtab, layout); + got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR, target->rela_dyn_section(layout), (size == 64 ? elfcpp::R_SPARC_TLS_DTPMOD64 @@ -2903,10 +2921,10 @@ Target_sparc::Scan::global( } else if (optimized_type == tls::TLSOPT_TO_IE) { - // Create a GOT entry for the tp-relative offset. - Output_data_got* 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* got + = target->got_section(symtab, layout); + got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET, target->rela_dyn_section(layout), (size == 64 ? elfcpp::R_SPARC_TLS_TPOFF64 : @@ -3184,7 +3202,7 @@ Target_sparc::Relocate::relocate( { elfcpp::Elf_Xword value; - value = target->plt_address_for_global(gsym) + gsym->plt_offset(); + value = target->plt_address_for_global(gsym); symval.set_output_value(value); @@ -3195,8 +3213,7 @@ Target_sparc::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; } } @@ -3229,16 +3246,16 @@ Target_sparc::Relocate::relocate( case elfcpp::R_SPARC_GOT13: case elfcpp::R_SPARC_GOT22: if (gsym != NULL) - { - gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD)); - got_offset = gsym->got_offset(GOT_TYPE_STANDARD); - } + { + gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD)); + got_offset = gsym->got_offset(GOT_TYPE_STANDARD); + } 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); - } + { + 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); + } break; default: @@ -3262,7 +3279,7 @@ Target_sparc::Relocate::relocate( if (rela.get_r_offset() & 0x1) { // The assembler can sometimes emit unaligned relocations - // for dwarf2 cfi directives. + // for dwarf2 cfi directives. Reloc::ua16(view, object, psymval, addend); } else @@ -3276,7 +3293,7 @@ Target_sparc::Relocate::relocate( if (rela.get_r_offset() & 0x3) { // The assembler can sometimes emit unaligned relocations - // for dwarf2 cfi directives. + // for dwarf2 cfi directives. Reloc::ua32(view, object, psymval, addend); } else @@ -3304,6 +3321,8 @@ Target_sparc::Relocate::relocate( case elfcpp::R_SPARC_WDISP30: case elfcpp::R_SPARC_WPLT30: Reloc::wdisp30(view, object, psymval, addend, address); + if (target->may_relax()) + relax_call(target, view, rela, view_size); break; case elfcpp::R_SPARC_WDISP22: @@ -3427,7 +3446,7 @@ Target_sparc::Relocate::relocate( if (rela.get_r_offset() & 0x7) { // The assembler can sometimes emit unaligned relocations - // for dwarf2 cfi directives. + // for dwarf2 cfi directives. Reloc::ua64(view, object, psymval, addend); } else @@ -3641,22 +3660,22 @@ Target_sparc::Relocate::relocate_tls( break; } else - { - unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE - ? GOT_TYPE_TLS_OFFSET - : GOT_TYPE_TLS_PAIR); - if (gsym != NULL) - { - gold_assert(gsym->has_got_offset(got_type)); - value = gsym->got_offset(got_type); - } - else - { - unsigned int r_sym = elfcpp::elf_r_sym(rela.get_r_info()); - gold_assert(object->local_has_got_offset(r_sym, got_type)); - value = object->local_got_offset(r_sym, got_type); - } - if (optimized_type == tls::TLSOPT_TO_IE) + { + unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE + ? GOT_TYPE_TLS_OFFSET + : GOT_TYPE_TLS_PAIR); + if (gsym != NULL) + { + gold_assert(gsym->has_got_offset(got_type)); + value = gsym->got_offset(got_type); + } + else + { + unsigned int r_sym = elfcpp::elf_r_sym(rela.get_r_info()); + gold_assert(object->local_has_got_offset(r_sym, got_type)); + value = object->local_got_offset(r_sym, got_type); + } + if (optimized_type == tls::TLSOPT_TO_IE) { Insntype* wv = reinterpret_cast(view); Insntype val; @@ -3721,10 +3740,10 @@ Target_sparc::Relocate::relocate_tls( elfcpp::Swap<32, true>::writeval(wv, 0x9001c008); break; } - break; + break; } - else if (optimized_type == tls::TLSOPT_NONE) - { + else if (optimized_type == tls::TLSOPT_NONE) + { switch (r_type) { case elfcpp::R_SPARC_TLS_GD_HI22: @@ -3751,8 +3770,8 @@ Target_sparc::Relocate::relocate_tls( break; } break; - } - } + } + } gold_error_at_location(relinfo, relnum, rela.get_r_offset(), _("unsupported reloc %u"), r_type); @@ -3781,10 +3800,10 @@ Target_sparc::Relocate::relocate_tls( 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; + { + // 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); switch (r_type) @@ -3812,8 +3831,8 @@ Target_sparc::Relocate::relocate_tls( } break; } - break; - } + break; + } gold_error_at_location(relinfo, relnum, rela.get_r_offset(), _("unsupported reloc %u"), r_type); @@ -3954,6 +3973,150 @@ Target_sparc::Relocate::relocate_tls( } } +// Relax a call instruction. + +template +inline void +Target_sparc::Relocate::relax_call( + Target_sparc* target, + unsigned char* view, + const elfcpp::Rela& rela, + section_size_type view_size) +{ + typedef typename elfcpp::Swap<32, true>::Valtype Insntype; + Insntype *wv = reinterpret_cast(view); + Insntype call_insn, delay_insn, set_insn; + uint32_t op3, reg, off; + + // This code tries to relax call instructions that meet + // certain criteria. + // + // The first criteria is that the call must be such that the return + // address which the call writes into %o7 is unused. Two sequences + // meet this criteria, and are used to implement tail calls. + // + // Leaf function tail call: + // + // or %o7, %g0, %ANY_REG + // call FUNC + // or %ANY_REG, %g0, %o7 + // + // Non-leaf function tail call: + // + // call FUNC + // restore + // + // The second criteria is that the call destination is close. If + // the displacement can fit in a signed 22-bit immediate field of a + // pre-V9 branch, we can do it. If we are generating a 64-bit + // object or a 32-bit object with ELF machine type EF_SPARC32PLUS, + // and the displacement fits in a signed 19-bit immediate field, + // then we can use a V9 branch. + + // Make sure the delay instruction can be safely accessed. + if (rela.get_r_offset() + 8 > view_size) + return; + + call_insn = elfcpp::Swap<32, true>::readval(wv); + delay_insn = elfcpp::Swap<32, true>::readval(wv + 1); + + // Make sure it is really a call instruction. + if (((call_insn >> 30) & 0x3) != 1) + return; + + if (((delay_insn >> 30) & 0x3) != 2) + return; + + // Accept only a restore or an integer arithmetic operation whose + // sole side effect is to write the %o7 register (and perhaps set + // the condition codes, which are considered clobbered across + // function calls). + // + // For example, we don't want to match a tagged addition or + // subtraction. We also don't want to match something like a + // divide. + // + // Specifically we accept add{,cc}, and{,cc}, or{,cc}, + // xor{,cc}, sub{,cc}, andn{,cc}, orn{,cc}, and xnor{,cc}. + + op3 = (delay_insn >> 19) & 0x3f; + reg = (delay_insn >> 25) & 0x1f; + if (op3 != 0x3d + && ((op3 & 0x28) != 0 || reg != 15)) + return; + + // For non-restore instructions, make sure %o7 isn't + // an input. + if (op3 != 0x3d) + { + // First check RS1 + reg = (delay_insn >> 14) & 0x15; + if (reg == 15) + return; + + // And if non-immediate, check RS2 + if (((delay_insn >> 13) & 1) == 0) + { + reg = (delay_insn & 0x1f); + if (reg == 15) + return; + } + } + + // Now check the branch distance. We are called after the + // call has been relocated, so we just have to peek at the + // offset contained in the instruction. + off = call_insn & 0x3fffffff; + if ((off & 0x3fe00000) != 0 + && (off & 0x3fe00000) != 0x3fe00000) + return; + + if ((size == 64 || target->elf_machine_ == elfcpp::EM_SPARC32PLUS) + && ((off & 0x3c0000) == 0 + || (off & 0x3c0000) == 0x3c0000)) + { + // ba,pt %xcc, FUNC + call_insn = 0x10680000 | (off & 0x07ffff); + } + else + { + // ba FUNC + call_insn = 0x10800000 | (off & 0x3fffff); + } + elfcpp::Swap<32, true>::writeval(wv, call_insn); + + // See if we can NOP out the delay slot instruction. We peek + // at the instruction before the call to make sure we're dealing + // with exactly the: + // + // or %o7, %g0, %ANY_REG + // call + // or %ANY_REG, %g0, %o7 + // + // case. Otherwise this might be a tricky piece of hand written + // assembler calculating %o7 in some non-trivial way, and therefore + // we can't be sure that NOP'ing out the delay slot is safe. + if (op3 == 0x02 + && rela.get_r_offset() >= 4) + { + if ((delay_insn & ~(0x1f << 14)) != 0x9e100000) + return; + + set_insn = elfcpp::Swap<32, true>::readval(wv - 1); + if ((set_insn & ~(0x1f << 25)) != 0x8013c000) + return; + + reg = (set_insn >> 25) & 0x1f; + if (reg == 0 || reg == 15) + return; + if (reg != ((delay_insn >> 14) & 0x1f)) + return; + + // All tests pass, nop it out. + elfcpp::Swap<32, true>::writeval(wv + 1, sparc_nop); + } +} + // Relocate section data. template @@ -3976,7 +4139,7 @@ Target_sparc::relocate_section( gold_assert(sh_type == elfcpp::SHT_RELA); gold::relocate_section( + Sparc_relocate, gold::Default_comdat_behavior>( relinfo, this, prelocs, @@ -4041,17 +4204,17 @@ Target_sparc::scan_relocatable_relocs( rr); } -// Relocate a section during a relocatable link. +// Emit relocations for a section. template void -Target_sparc::relocate_for_relocatable( +Target_sparc::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, @@ -4061,7 +4224,7 @@ Target_sparc::relocate_for_relocatable( { gold_assert(sh_type == elfcpp::SHT_RELA); - gold::relocate_for_relocatable( + gold::relocate_relocs( relinfo, prelocs, reloc_count, @@ -4103,7 +4266,7 @@ Target_sparc::do_make_elf_object( elfcpp::Elf_Half machine = ehdr.get_e_machine(); elfcpp::Elf_Word flags = ehdr.get_e_flags(); elfcpp::Elf_Word omm, mm; - + switch (machine) { case elfcpp::EM_SPARC32PLUS: @@ -4194,7 +4357,8 @@ public: (size == 64 ? "elf64_sparc" : "elf32_sparc")) { } - Target* do_recognize(int machine, int, int) + virtual Target* + do_recognize(Input_file*, off_t, int machine, int, int) { switch (size) { @@ -4216,7 +4380,8 @@ public: return this->instantiate_target(); } - Target* do_instantiate_target() + virtual Target* + do_instantiate_target() { return new Target_sparc(); } };