X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Fsparc.cc;h=e73970afd779c3af6336947a739d7de71ac068b7;hb=b0ee49d21ba0c4b7f9817db01dc247255eebd516;hp=57659cc8ae48bd98ab38ce940a4a154337f551ee;hpb=43819297ce3e76908a840fa66159ca83c1560fe5;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/sparc.cc b/gold/sparc.cc index 57659cc8ae..e73970afd7 100644 --- a/gold/sparc.cc +++ b/gold/sparc.cc @@ -1,6 +1,6 @@ // sparc.cc -- sparc target support for gold. -// Copyright 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. +// Copyright (C) 2008-2020 Free Software Foundation, Inc. // Written by David S. Miller . // This file is part of gold. @@ -62,10 +62,14 @@ class Target_sparc : public Sized_target copy_relocs_(elfcpp::R_SPARC_COPY), got_mod_index_offset_(-1U), tls_get_addr_sym_(NULL), elf_machine_(sparc_info.machine_code), elf_flags_(0), - elf_flags_set_(false) + elf_flags_set_(false), register_syms_() { } + // Make a new symbol table entry. + Sized_symbol* + make_symbol(const char*, elfcpp::STT, Object*, unsigned int, uint64_t); + // Process the relocations to determine unreferenced sections for // garbage collection. void @@ -131,6 +135,21 @@ class Target_sparc : 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(const Relocate_info*, @@ -140,7 +159,6 @@ class Target_sparc : public Sized_target 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, @@ -150,13 +168,7 @@ class Target_sparc : public Sized_target // Return whether SYM is defined by the ABI. bool do_is_defined_by_abi(const Symbol* sym) const - { - // XXX Really need to support this better... - if (sym->type() == elfcpp::STT_SPARC_REGISTER) - return 1; - - return strcmp(sym->name(), "___tls_get_addr") == 0; - } + { return strcmp(sym->name(), "___tls_get_addr") == 0; } // Return the PLT address to use for a global symbol. uint64_t @@ -217,7 +229,7 @@ class Target_sparc : public Sized_target const elfcpp::Ehdr& ehdr); void - do_adjust_elf_header(unsigned char* view, int len) const; + do_adjust_elf_header(unsigned char* view, int len); private: @@ -316,13 +328,10 @@ class Target_sparc : 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_sparc*, - Output_section*, size_t relnum, - const elfcpp::Rela&, - unsigned int r_type, const Sized_symbol*, - const Symbol_value*, - unsigned char*, - typename elfcpp::Elf_types::Elf_Addr, + relocate(const Relocate_info*, unsigned int, + Target_sparc*, Output_section*, size_t, const unsigned char*, + const Sized_symbol*, const Symbol_value*, + unsigned char*, typename elfcpp::Elf_types::Elf_Addr, section_size_type); private: @@ -349,15 +358,6 @@ class Target_sparc : public Sized_target unsigned char *reloc_adjust_addr_; }; - // A class which returns the size required for a relocation type, - // used while scanning relocs during a relocatable link. - class Relocatable_size_for_reloc - { - public: - unsigned int - get_size_for_reloc(unsigned int, Relobj*); - }; - // Get the GOT section, creating it if necessary. Output_data_got* got_section(Symbol_table*, Layout*); @@ -415,10 +415,13 @@ class Target_sparc : 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 @@ -436,6 +439,16 @@ class Target_sparc : public Sized_target GOT_TYPE_TLS_PAIR = 2, // GOT entry for TLS module/offset pair }; + struct Register_symbol + { + Register_symbol() + : name(NULL), shndx(0), obj(NULL) + { } + const char* name; + unsigned int shndx; + Object* obj; + }; + // The GOT section. Output_data_got* got_; // The PLT section. @@ -456,6 +469,8 @@ class Target_sparc : public Sized_target elfcpp::Elf_Word elf_flags_; // Whether elf_flags_ has been set for the first time yet bool elf_flags_set_; + // STT_SPARC_REGISTER symbols (%g2, %g3, %g6, %g7). + Register_symbol register_syms_[4]; }; template<> @@ -482,7 +497,9 @@ Target::Target_info Target_sparc<32, true>::sparc_info = 0, // large_common_section_flags NULL, // attributes_section NULL, // attributes_vendor - "_start" // entry_symbol_name + "_start", // entry_symbol_name + 32, // hash_entry_size + elfcpp::SHT_PROGBITS, // unwind_section_type }; template<> @@ -491,7 +508,7 @@ Target::Target_info Target_sparc<64, true>::sparc_info = 64, // size true, // is_big_endian elfcpp::EM_SPARCV9, // machine_code - false, // has_make_symbol + true, // has_make_symbol false, // has_resolve false, // has_code_fill true, // is_default_stack_executable @@ -509,7 +526,9 @@ Target::Target_info Target_sparc<64, true>::sparc_info = 0, // large_common_section_flags NULL, // attributes_section NULL, // attributes_vendor - "_start" // entry_symbol_name + "_start", // entry_symbol_name + 32, // hash_entry_size + elfcpp::SHT_PROGBITS, // unwind_section_type }; // We have to take care here, even when operating in little-endian @@ -1107,13 +1126,12 @@ public: // R_SPARC_GOTDATA_OP_HIX22: @gdopoff(Symbol + Addend) >> 10 static inline void gdop_hix22(unsigned char* view, - typename elfcpp::Elf_types::Elf_Addr value, - typename elfcpp::Elf_types::Elf_Addr addend) + typename elfcpp::Elf_types::Elf_Addr value) { typedef typename elfcpp::Swap<32, true>::Valtype Valtype; Valtype* wv = reinterpret_cast(view); Valtype val = elfcpp::Swap<32, true>::readval(wv); - int32_t reloc = static_cast(value + addend); + int32_t reloc = static_cast(value); val &= ~0x3fffff; @@ -1170,13 +1188,12 @@ public: // R_SPARC_GOTDATA_OP_LOX10: (@gdopoff(Symbol + Addend) & 0x3ff) | 0x1c00 static inline void gdop_lox10(unsigned char* view, - typename elfcpp::Elf_types::Elf_Addr value, - typename elfcpp::Elf_types::Elf_Addr addend) + typename elfcpp::Elf_types::Elf_Addr value) { typedef typename elfcpp::Swap<32, true>::Valtype Valtype; Valtype* wv = reinterpret_cast(view); Valtype val = elfcpp::Swap<32, true>::readval(wv); - int32_t reloc = static_cast(value + addend); + int32_t reloc = static_cast(value); if (reloc < 0) reloc = (reloc & 0x3ff) | 0x1c00; @@ -2135,6 +2152,7 @@ Target_sparc::Scan::check_non_pic(Relobj* object, unsigned int case elfcpp::R_SPARC_RELATIVE: case elfcpp::R_SPARC_IRELATIVE: case elfcpp::R_SPARC_COPY: + case elfcpp::R_SPARC_32: case elfcpp::R_SPARC_64: case elfcpp::R_SPARC_GLOB_DAT: case elfcpp::R_SPARC_JMP_SLOT: @@ -2277,7 +2295,9 @@ Target_sparc::Scan::local( // apply the link-time value, so we flag the location with // an R_SPARC_RELATIVE relocation so the dynamic loader can // relocate it easily. - if (parameters->options().output_is_position_independent()) + if (parameters->options().output_is_position_independent() + && ((size == 64 && r_type == elfcpp::R_SPARC_64) + || (size == 32 && r_type == elfcpp::R_SPARC_32))) { Reloc_section* rela_dyn = target->rela_dyn_section(layout); unsigned int r_sym = elfcpp::elf_r_sym(reloc.get_r_info()); @@ -2285,8 +2305,9 @@ Target_sparc::Scan::local( output_section, data_shndx, reloc.get_r_offset(), reloc.get_r_addend(), is_ifunc); + break; } - break; + // Fall through. case elfcpp::R_SPARC_HIX22: case elfcpp::R_SPARC_LOX10: @@ -2634,7 +2655,8 @@ Target_sparc::Scan::global( // Make a dynamic relocation if necessary. if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type))) { - if (gsym->may_need_copy_reloc()) + if (parameters->options().output_is_executable() + && gsym->may_need_copy_reloc()) { target->copy_reloc(symtab, layout, object, data_shndx, output_section, gsym, @@ -2723,7 +2745,8 @@ Target_sparc::Scan::global( break; } - if (gsym->may_need_copy_reloc()) + if (!parameters->options().output_is_position_independent() + && gsym->may_need_copy_reloc()) { target->copy_reloc(symtab, layout, object, data_shndx, output_section, gsym, reloc); @@ -2749,8 +2772,8 @@ Target_sparc::Scan::global( reloc.get_r_offset(), reloc.get_r_addend()); } - else if ((r_type == elfcpp::R_SPARC_32 - || r_type == elfcpp::R_SPARC_64) + else if (((size == 64 && r_type == elfcpp::R_SPARC_64) + || (size == 32 && r_type == elfcpp::R_SPARC_32)) && gsym->can_use_relative_reloc(false)) { Reloc_section* rela_dyn = target->rela_dyn_section(layout); @@ -2794,6 +2817,7 @@ Target_sparc::Scan::global( // and code transform the GOT load into an addition. break; } + // Fall through. case elfcpp::R_SPARC_GOT10: case elfcpp::R_SPARC_GOT13: case elfcpp::R_SPARC_GOT22: @@ -3016,6 +3040,68 @@ Target_sparc::Scan::global( } } +// Make a new symbol table entry. +// STT_SPARC_REGISTER symbols require special handling, +// so we intercept these symbols and keep track of them separately. +// We will resolve register symbols here and output them at symbol +// finalization time. + +template +Sized_symbol* +Target_sparc::make_symbol(const char* name, + elfcpp::STT type, + Object* object, + unsigned int shndx, + uint64_t value) +{ + // REGISTER symbols are used only on SPARC-64. + if (size == 64 && type == elfcpp::STT_SPARC_REGISTER) + { + // Ignore REGISTER symbols in dynamic objects. + if (object->is_dynamic()) + return NULL; + // Only registers 2, 3, 6, and 7 can be declared global. + int reg = value; + switch (reg) + { + case 2: case 3: + reg -= 2; + break; + case 6: case 7: + reg -= 4; + break; + default: + gold_error(_("%s: only registers %%g[2367] can be declared " + "using STT_REGISTER"), + object->name().c_str()); + return NULL; + } + Register_symbol& rsym = this->register_syms_[reg]; + if (rsym.name == NULL) + { + rsym.name = name; + rsym.shndx = shndx; + rsym.obj = object; + } + else + { + if (strcmp(rsym.name, name) != 0) + { + gold_error(_("%s: register %%g%d declared as '%s'; " + "previously declared as '%s' in %s"), + object->name().c_str(), + static_cast(value), + *name ? name : "#scratch", + *rsym.name ? rsym.name : "#scratch", + rsym.obj->name().c_str()); + return NULL; + } + } + return NULL; + } + return new Sized_symbol(); +} + // Process relocations for gc. template @@ -3035,9 +3121,10 @@ Target_sparc::gc_process_relocs( { typedef Target_sparc Sparc; typedef typename Target_sparc::Scan Scan; + typedef gold::Default_classify_reloc + Classify_reloc; - gold::gc_process_relocs( + gold::gc_process_relocs( symtab, layout, this, @@ -3069,7 +3156,8 @@ Target_sparc::scan_relocs( const unsigned char* plocal_symbols) { typedef Target_sparc Sparc; - typedef typename Target_sparc::Scan Scan; + typedef gold::Default_classify_reloc + Classify_reloc; if (sh_type == elfcpp::SHT_REL) { @@ -3078,7 +3166,7 @@ Target_sparc::scan_relocs( return; } - gold::scan_relocs( + gold::scan_relocs( symtab, layout, this, @@ -3156,6 +3244,27 @@ Target_sparc::do_finalize_sections( symtab->define_symbols(layout, 2, syms, layout->script_options()->saw_sections_clause()); } + + for (int reg = 0; reg < 4; ++reg) + { + Register_symbol& rsym = this->register_syms_[reg]; + if (rsym.name != NULL) + { + int value = reg < 3 ? reg + 2 : reg + 4; + Sized_symbol* sym = new Sized_symbol(); + if (rsym.shndx == elfcpp::SHN_UNDEF) + sym->init_undefined(rsym.name, NULL, value, + elfcpp::STT_SPARC_REGISTER, elfcpp::STB_GLOBAL, + elfcpp::STV_DEFAULT, 0); + else + sym->init_constant(rsym.name, NULL, value, 0, + elfcpp::STT_SPARC_REGISTER, elfcpp::STB_GLOBAL, + elfcpp::STV_DEFAULT, 0, false); + symtab->add_target_global_symbol(sym); + layout->add_target_specific_dynamic_tag(elfcpp::DT_SPARC_REGISTER, + value); + } + } } // Perform a relocation. @@ -3164,17 +3273,19 @@ template inline bool Target_sparc::Relocate::relocate( const Relocate_info* relinfo, + unsigned int, Target_sparc* 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()); bool orig_is_ifunc = psymval->is_ifunc_symbol(); r_type &= 0xff; @@ -3242,10 +3353,11 @@ Target_sparc::Relocate::relocate( && !gsym->is_preemptible() && !orig_is_ifunc)) { - got_offset = psymval->value(object, 0) - target->got_address(); + got_offset = psymval->value(object, addend) - target->got_address(); gdop_valid = true; break; } + // Fall through. case elfcpp::R_SPARC_GOT10: case elfcpp::R_SPARC_GOT13: case elfcpp::R_SPARC_GOT22: @@ -3361,6 +3473,13 @@ Target_sparc::Relocate::relocate( Reloc::lo10(view, object, psymval, addend); break; + case elfcpp::R_SPARC_GOTDATA_OP_LOX10: + if (gdop_valid) + { + Reloc::gdop_lox10(view, got_offset); + break; + } + // Fall through. case elfcpp::R_SPARC_GOT10: Reloc::lo10(view, got_offset, addend); break; @@ -3379,13 +3498,6 @@ Target_sparc::Relocate::relocate( } break; - case elfcpp::R_SPARC_GOTDATA_OP_LOX10: - if (gdop_valid) - { - Reloc::gdop_lox10(view, got_offset, addend); - break; - } - /* Fall through. */ case elfcpp::R_SPARC_GOT13: Reloc::rela32_13(view, got_offset, addend); break; @@ -3393,10 +3505,10 @@ Target_sparc::Relocate::relocate( case elfcpp::R_SPARC_GOTDATA_OP_HIX22: if (gdop_valid) { - Reloc::gdop_hix22(view, got_offset, addend); + Reloc::gdop_hix22(view, got_offset); break; } - /* Fall through. */ + // Fall through. case elfcpp::R_SPARC_GOT22: Reloc::hi22(view, got_offset, addend); break; @@ -3620,7 +3732,7 @@ Target_sparc::Relocate::relocate_tls( const bool is_final = (gsym == NULL - ? !parameters->options().output_is_position_independent() + ? !parameters->options().shared() : gsym->final_value_is_known()); const tls::Tls_optimization optimized_type = optimize_tls_reloc(is_final, r_type); @@ -4054,7 +4166,7 @@ Target_sparc::Relocate::relax_call( if (op3 != 0x3d) { // First check RS1 - reg = (delay_insn >> 14) & 0x15; + reg = (delay_insn >> 14) & 0x1f; if (reg == 15) return; @@ -4139,11 +4251,13 @@ Target_sparc::relocate_section( { typedef Target_sparc Sparc; typedef typename Target_sparc::Relocate Sparc_relocate; + typedef gold::Default_classify_reloc + Classify_reloc; gold_assert(sh_type == elfcpp::SHT_RELA); - gold::relocate_section( + gold::relocate_section( relinfo, this, prelocs, @@ -4156,20 +4270,6 @@ Target_sparc::relocate_section( reloc_symbol_changes); } -// Return the size of a relocation while scanning during a relocatable -// link. - -template -unsigned int -Target_sparc::Relocatable_size_for_reloc::get_size_for_reloc( - unsigned int, - Relobj*) -{ - // We are always SHT_RELA, so we should never get here. - gold_unreachable(); - return 0; -} - // Scan the relocs during a relocatable link. template @@ -4188,13 +4288,14 @@ Target_sparc::scan_relocatable_relocs( const unsigned char* plocal_symbols, Relocatable_relocs* rr) { - gold_assert(sh_type == elfcpp::SHT_RELA); + typedef gold::Default_classify_reloc + Classify_reloc; + typedef gold::Default_scan_relocatable_relocs + Scan_relocatable_relocs; - 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, @@ -4208,6 +4309,45 @@ Target_sparc::scan_relocatable_relocs( rr); } +// Scan the relocs for --emit-relocs. + +template +void +Target_sparc::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) +{ + typedef gold::Default_classify_reloc + Classify_reloc; + typedef gold::Default_emit_relocs_strategy + Emit_relocs_strategy; + + gold_assert(sh_type == elfcpp::SHT_RELA); + + gold::scan_relocatable_relocs( + symtab, + layout, + object, + data_shndx, + prelocs, + reloc_count, + output_section, + needs_special_offset_handling, + local_symbol_count, + plocal_syms, + rr); +} + // Emit relocations for a section. template @@ -4219,22 +4359,23 @@ Target_sparc::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, @@ -4339,7 +4480,7 @@ template void Target_sparc::do_adjust_elf_header( unsigned char* view, - int len) const + int len) { elfcpp::Ehdr_write oehdr(view);