2016-03-03 Cary Coutant gold/ PR gold/19019 * layout.h (Layout::add_target_specific_dynamic_tag): New function. * layout.cc (Layout::add_target_specific_dynamic_tag): New function. * mips.cc (Target_mips::make_symbol): Adjust function signature. * sparc.cc (Target_sparc::Target_sparc): Initialize register_syms_. (Target_sparc::do_is_defined_by_abi): Remove test for STT_SPARC_REGISTER. (Target_sparc::Register_symbol): New struct type. (Target_sparc::register_syms_): New data member. (Target_sparc<64, true>::sparc_info): Set has_make_symbol to true. (Target_sparc::make_symbol): New function. (Target_sparc::do_finalize_sections): Add register symbols and new dynamic table entries. * symtab.h (Sized_symbol::init_undefined): Add value parameter. (Symbol_table::add_target_global_symbol): New function. (Symbol_table::target_symbols_): New data member. * symtab.cc (Sized_symbol::init_undefined): Add value parameter. (Symbol_table::Symbol_table): Initialize target_symbols_. (Symbol_table::add_from_object): Pass additional parameters to Target::make_symbol. (Symbol_table::define_special_symbol): Likewise. (Symbol_table::add_undefined_symbol_from_command_line): Pass 0 for undefined symbol value. (Symbol_table::set_dynsym_indexes): Process target-specific symbols. (Symbol_table::sized_finalize): Likewise. (Symbol_table::sized_write_globals): Likewise. * target.h (Sized_target::make_symbol): Add name, st_type, object, st_shndx, and value parameters. commit 8524f199166d5e54fab6974113067f1853f946d8 Author: Cary Coutant Date: Thu Feb 4 16:55:39 2016 -0800 Add support for STT_SPARC_REGISTER symbols. diff --git a/gold/layout.cc b/gold/layout.cc index 90337e7..376051d 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -4724,6 +4724,15 @@ Layout::add_target_dynamic_tags(bool use_rel, const Output_data* plt_got, } } +void +Layout::add_target_specific_dynamic_tag(elfcpp::DT tag, unsigned int val) +{ + Output_data_dynamic* odyn = this->dynamic_data_; + if (odyn == NULL) + return; + odyn->add_constant(tag, val); +} + // Finish the .dynamic section and PT_DYNAMIC segment. void diff --git a/gold/layout.h b/gold/layout.h index 5fad4f3..c369fef 100644 --- a/gold/layout.h +++ b/gold/layout.h @@ -902,6 +902,10 @@ class Layout const Output_data_reloc_generic* dyn_rel, bool add_debug, bool dynrel_includes_plt); + // Add a target-specific dynamic tag with constant value. + void + add_target_specific_dynamic_tag(elfcpp::DT tag, unsigned int val); + // Compute and write out the build ID if needed. void write_build_id(Output_file*, unsigned char*, size_t) const; diff --git a/gold/mips.cc b/gold/mips.cc index 6c4f379..6f66fe9 100644 --- a/gold/mips.cc +++ b/gold/mips.cc @@ -3079,7 +3079,7 @@ class Target_mips : public Sized_target // Make a new symbol table entry for the Mips target. Sized_symbol* - make_symbol() const + make_symbol(const char*, elfcpp::STT, Object*, unsigned int, uint64_t) { return new Mips_symbol(); } // Process the relocations to determine unreferenced sections for diff --git a/gold/sparc.cc b/gold/sparc.cc index c97c32c..10a5031 100644 --- a/gold/sparc.cc +++ b/gold/sparc.cc @@ -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 @@ -164,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 @@ -441,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. @@ -461,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<> @@ -497,7 +507,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 @@ -3023,6 +3033,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 @@ -3165,6 +3237,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. diff --git a/gold/symtab.cc b/gold/symtab.cc index 156c876..a53f6c9 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -285,11 +285,12 @@ Sized_symbol::init_constant(const char* name, const char* version, template void Sized_symbol::init_undefined(const char* name, const char* version, - elfcpp::STT type, elfcpp::STB binding, - elfcpp::STV visibility, unsigned char nonvis) + Value_type value, elfcpp::STT type, + elfcpp::STB binding, elfcpp::STV visibility, + unsigned char nonvis) { this->init_base_undefined(name, version, type, binding, visibility, nonvis); - this->value_ = 0; + this->value_ = value; this->symsize_ = 0; } @@ -565,7 +566,8 @@ Symbol_table::Symbol_table(unsigned int count, : saw_undefined_(0), offset_(0), table_(count), namepool_(), forwarders_(), commons_(), tls_commons_(), small_commons_(), large_commons_(), forced_locals_(), warnings_(), - version_script_(version_script), gc_(NULL), icf_(NULL) + version_script_(version_script), gc_(NULL), icf_(NULL), + target_symbols_() { namepool_.reserve(count); } @@ -1058,7 +1060,8 @@ Symbol_table::add_from_object(Object* object, ret = new Sized_symbol(); else { - ret = target->make_symbol(); + ret = target->make_symbol(name, sym.get_st_type(), object, + st_shndx, sym.get_st_value()); if (ret == NULL) { // This means that we don't want a symbol table @@ -1858,7 +1861,8 @@ Symbol_table::define_special_symbol(const char** pname, const char** pversion, { Sized_target* sized_target = parameters->sized_target(); - sym = sized_target->make_symbol(); + sym = sized_target->make_symbol(*pname, elfcpp::STT_NOTYPE, + NULL, elfcpp::SHN_UNDEF, 0); if (sym == NULL) return NULL; } @@ -2437,7 +2441,7 @@ Symbol_table::add_undefined_symbol_from_command_line(const char* name) gold_assert(oldsym == NULL); - sym->init_undefined(name, version, elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL, + sym->init_undefined(name, version, 0, elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL, elfcpp::STV_DEFAULT, 0); ++this->saw_undefined_; } @@ -2534,6 +2538,17 @@ Symbol_table::set_dynsym_indexes(unsigned int index, // symbols. index = versions->finalize(this, index, syms); + // Process target-specific symbols. + for (std::vector::iterator p = this->target_symbols_.begin(); + p != this->target_symbols_.end(); + ++p) + { + (*p)->set_dynsym_index(index); + ++index; + syms->push_back(*p); + dynpool->add((*p)->name(), false, NULL); + } + return index; } @@ -2639,6 +2654,14 @@ Symbol_table::sized_finalize(off_t off, Stringpool* pool, this->add_to_final_symtab(sym, pool, &index, &off); } + // Now do target-specific symbols. + for (std::vector::iterator p = this->target_symbols_.begin(); + p != this->target_symbols_.end(); + ++p) + { + this->add_to_final_symtab(*p, pool, &index, &off); + } + this->output_count_ = index - orig_index; return off; @@ -3108,6 +3131,54 @@ Symbol_table::sized_write_globals(const Stringpool* sympool, } } + // Write the target-specific symbols. + for (std::vector::const_iterator p = this->target_symbols_.begin(); + p != this->target_symbols_.end(); + ++p) + { + Sized_symbol* sym = static_cast*>(*p); + + unsigned int sym_index = sym->symtab_index(); + unsigned int dynsym_index; + if (dynamic_view == NULL) + dynsym_index = -1U; + else + dynsym_index = sym->dynsym_index(); + + unsigned int shndx; + switch (sym->source()) + { + case Symbol::IS_CONSTANT: + shndx = elfcpp::SHN_ABS; + break; + case Symbol::IS_UNDEFINED: + shndx = elfcpp::SHN_UNDEF; + break; + default: + gold_unreachable(); + } + + if (sym_index != -1U) + { + sym_index -= first_global_index; + gold_assert(sym_index < output_count); + unsigned char* ps = psyms + (sym_index * sym_size); + this->sized_write_symbol(sym, sym->value(), shndx, + sym->binding(), sympool, + ps); + } + + if (dynsym_index != -1U) + { + dynsym_index -= first_dynamic_global_index; + gold_assert(dynsym_index < dynamic_count); + unsigned char* pd = dynamic_view + (dynsym_index * sym_size); + this->sized_write_symbol(sym, sym->value(), shndx, + sym->binding(), dynpool, + pd); + } + } + of->write_output_view(this->offset_, oview_size, psyms); if (dynamic_view != NULL) of->write_output_view(this->dynamic_offset_, dynamic_size, dynamic_view); diff --git a/gold/symtab.h b/gold/symtab.h index 764ef46..5cee458 100644 --- a/gold/symtab.h +++ b/gold/symtab.h @@ -1113,8 +1113,8 @@ class Sized_symbol : public Symbol // Initialize fields for an undefined symbol. void - init_undefined(const char* name, const char* version, elfcpp::STT, - elfcpp::STB, elfcpp::STV, unsigned char nonvis); + init_undefined(const char* name, const char* version, Value_type value, + elfcpp::STT, elfcpp::STB, elfcpp::STV, unsigned char nonvis); // Override existing symbol. template @@ -1481,6 +1481,12 @@ class Symbol_table define_symbols(const Layout*, int count, const Define_symbol_in_segment*, bool only_if_ref); + // Add a target-specific global symbol. + // (Used by SPARC backend to add STT_SPARC_REGISTER symbols.) + void + add_target_global_symbol(Symbol* sym) + { this->target_symbols_.push_back(sym); } + // Define SYM using a COPY reloc. POSD is the Output_data where the // symbol should be defined--typically a .dyn.bss section. VALUE is // the offset within POSD. @@ -1951,6 +1957,8 @@ class Symbol_table const Version_script_info& version_script_; Garbage_collection* gc_; Icf* icf_; + // Target-specific symbols, if any. + std::vector target_symbols_; }; // We inline get_sized_symbol for efficiency. diff --git a/gold/target.h b/gold/target.h index d20044e..8e801e1 100644 --- a/gold/target.h +++ b/gold/target.h @@ -834,7 +834,7 @@ class Sized_target : public Target // symbol table. This will only be called if has_make_symbol() // returns true. virtual Sized_symbol* - make_symbol() const + make_symbol(const char*, elfcpp::STT, Object*, unsigned int, uint64_t) { gold_unreachable(); } // Resolve a symbol for the target. This should be overridden by a