delete *p;
}
+// Return the dynamic object which a symbol refers to.
+
+Dynobj*
+Versions::get_dynobj_for_sym(const Symbol_table* symtab,
+ const Symbol* sym) const
+{
+ if (sym->is_copied_from_dynobj())
+ return symtab->get_copy_source(sym);
+ else
+ {
+ Object* object = sym->object();
+ gold_assert(object->is_dynamic());
+ return static_cast<Dynobj*>(object);
+ }
+}
+
// Record version information for a symbol going into the dynamic
// symbol table.
void
Versions::record_version(const General_options* options,
+ const Symbol_table* symtab,
Stringpool* dynpool, const Symbol* sym)
{
gold_assert(!this->is_finalized_);
Stringpool::Key version_key;
const char* version = dynpool->add(sym->version(), false, &version_key);
- if (!sym->is_from_dynobj())
+ if (!sym->is_from_dynobj() && !sym->is_copied_from_dynobj())
{
if (parameters->output_is_shared())
this->add_def(options, sym, version, version_key);
else
{
// This is a version reference.
-
- Object* object = sym->object();
- gold_assert(object->is_dynamic());
- Dynobj* dynobj = static_cast<Dynobj*>(object);
-
+ Dynobj* dynobj = this->get_dynobj_for_sym(symtab, sym);
this->add_need(dynpool, dynobj->soname(), version, version_key);
}
}
// pointers.
unsigned int
-Versions::version_index(const Stringpool* dynpool, const Symbol* sym) const
+Versions::version_index(const Symbol_table* symtab, const Stringpool* dynpool,
+ const Symbol* sym) const
{
Stringpool::Key version_key;
const char* version = dynpool->find(sym->version(), &version_key);
gold_assert(version != NULL);
Key k;
- if (!sym->is_from_dynobj())
+ if (!sym->is_from_dynobj() && !sym->is_copied_from_dynobj())
{
if (!parameters->output_is_shared())
return elfcpp::VER_NDX_GLOBAL;
}
else
{
- Object* object = sym->object();
- gold_assert(object->is_dynamic());
- Dynobj* dynobj = static_cast<Dynobj*>(object);
+ Dynobj* dynobj = this->get_dynobj_for_sym(symtab, sym);
Stringpool::Key filename_key;
const char* filename = dynpool->find(dynobj->soname(), &filename_key);
template<int size, bool big_endian>
void
-Versions::symbol_section_contents(const Stringpool* dynpool,
+Versions::symbol_section_contents(const Symbol_table* symtab,
+ const Stringpool* dynpool,
unsigned int local_symcount,
const std::vector<Symbol*>& syms,
unsigned char** pp,
if (version == NULL)
version_index = elfcpp::VER_NDX_GLOBAL;
else
- version_index = this->version_index(dynpool, *p);
+ version_index = this->version_index(symtab, dynpool, *p);
elfcpp::Swap<16, big_endian>::writeval(pbuf + (*p)->dynsym_index() * 2,
version_index);
}
template
void
Versions::symbol_section_contents<32, false>(
+ const Symbol_table*,
const Stringpool*,
unsigned int,
const std::vector<Symbol*>&,
template
void
Versions::symbol_section_contents<32, true>(
+ const Symbol_table*,
const Stringpool*,
unsigned int,
const std::vector<Symbol*>&,
template
void
Versions::symbol_section_contents<64, false>(
+ const Symbol_table*,
const Stringpool*,
unsigned int,
const std::vector<Symbol*>&,
template
void
Versions::symbol_section_contents<64, true>(
+ const Symbol_table*,
const Stringpool*,
unsigned int,
const std::vector<Symbol*>&,
// SYM is going into the dynamic symbol table and has a version.
// Record the appropriate version information.
void
- record_version(const General_options*, Stringpool*, const Symbol* sym);
+ record_version(const General_options*, const Symbol_table* symtab,
+ Stringpool*, const Symbol* sym);
// Set the version indexes. DYNSYM_INDEX is the index we should use
// for the next dynamic symbol. We add new dynamic symbols to SYMS
// version section (.gnu.version).
template<int size, bool big_endian>
void
- symbol_section_contents(const Stringpool*, unsigned int local_symcount,
+ symbol_section_contents(const Symbol_table*, const Stringpool*,
+ unsigned int local_symcount,
const std::vector<Symbol*>& syms,
unsigned char**, unsigned int*
ACCEPT_SIZE_ENDIAN) const;
add_need(Stringpool*, const char* filename, const char* name,
Stringpool::Key);
+ // Get the dynamic object to use for SYM.
+ Dynobj*
+ get_dynobj_for_sym(const Symbol_table*, const Symbol* sym) const;
+
// Return the version index to use for SYM.
unsigned int
- version_index(const Stringpool*, const Symbol* sym) const;
+ version_index(const Symbol_table*, const Stringpool*,
+ const Symbol* sym) const;
// We keep a hash table mapping canonicalized name/version pairs to
// a version base.
off_t offset = dynbss_size;
dynbss->set_space_size(dynbss_size + symsize);
- // Define the symbol in the .dynbss section.
- symtab->define_in_output_data(this, ssym->name(), ssym->version(),
- dynbss, offset, symsize, ssym->type(),
- ssym->binding(), ssym->visibility(),
- ssym->nonvis(), false, false);
+ symtab->define_with_copy_reloc(this, ssym, dynbss, offset);
// Add the COPY reloc.
- ssym->set_needs_dynsym_entry();
Reloc_section* rel_dyn = this->rel_dyn_section(layout);
rel_dyn->add_global(ssym, elfcpp::R_386_COPY, dynbss, offset);
}
// Create the version sections. We can't do this until the
// dynamic string table is complete.
- this->create_version_sections(&versions, local_dynamic_count,
+ this->create_version_sections(&versions, symtab, local_dynamic_count,
dynamic_symbols, dynstr);
}
void
Layout::create_version_sections(const Versions* versions,
+ const Symbol_table* symtab,
unsigned int local_symcount,
const std::vector<Symbol*>& dynamic_symbols,
const Output_section* dynstr)
#ifdef HAVE_TARGET_32_BIG
this->sized_create_version_sections
SELECT_SIZE_ENDIAN_NAME(32, true)(
- versions, local_symcount, dynamic_symbols, dynstr
+ versions, symtab, local_symcount, dynamic_symbols, dynstr
SELECT_SIZE_ENDIAN(32, true));
#else
gold_unreachable();
#ifdef HAVE_TARGET_32_LITTLE
this->sized_create_version_sections
SELECT_SIZE_ENDIAN_NAME(32, false)(
- versions, local_symcount, dynamic_symbols, dynstr
+ versions, symtab, local_symcount, dynamic_symbols, dynstr
SELECT_SIZE_ENDIAN(32, false));
#else
gold_unreachable();
#ifdef HAVE_TARGET_64_BIG
this->sized_create_version_sections
SELECT_SIZE_ENDIAN_NAME(64, true)(
- versions, local_symcount, dynamic_symbols, dynstr
+ versions, symtab, local_symcount, dynamic_symbols, dynstr
SELECT_SIZE_ENDIAN(64, true));
#else
gold_unreachable();
#ifdef HAVE_TARGET_64_LITTLE
this->sized_create_version_sections
SELECT_SIZE_ENDIAN_NAME(64, false)(
- versions, local_symcount, dynamic_symbols, dynstr
+ versions, symtab, local_symcount, dynamic_symbols, dynstr
SELECT_SIZE_ENDIAN(64, false));
#else
gold_unreachable();
void
Layout::sized_create_version_sections(
const Versions* versions,
+ const Symbol_table* symtab,
unsigned int local_symcount,
const std::vector<Symbol*>& dynamic_symbols,
const Output_section* dynstr
unsigned char* vbuf;
unsigned int vsize;
versions->symbol_section_contents SELECT_SIZE_ENDIAN_NAME(size, big_endian)(
- &this->dynpool_, local_symcount, dynamic_symbols, &vbuf, &vsize
+ symtab, &this->dynpool_, local_symcount, dynamic_symbols, &vbuf, &vsize
SELECT_SIZE_ENDIAN(size, big_endian));
Output_section_data* vdata = new Output_data_const_buffer(vbuf, vsize, 2);
// Create the version sections.
void
create_version_sections(const Versions*,
+ const Symbol_table*,
unsigned int local_symcount,
const std::vector<Symbol*>& dynamic_symbols,
const Output_section* dynstr);
template<int size, bool big_endian>
void
sized_create_version_sections(const Versions* versions,
+ const Symbol_table*,
unsigned int local_symcount,
const std::vector<Symbol*>& dynamic_symbols,
const Output_section* dynstr
void
Symbol::override_base_with_special(const Symbol* from)
{
+ gold_assert(this->name_ == from->name_ || this->has_alias());
+
this->source_ = from->source_;
switch (from->source_)
{
// Special symbols are always considered to be regular symbols.
this->in_reg_ = true;
+
+ if (from->needs_dynsym_entry_)
+ this->needs_dynsym_entry_ = true;
+ if (from->needs_dynsym_value_)
+ this->needs_dynsym_value_ = true;
+
+ // We shouldn't see these flags. If we do, we need to handle them
+ // somehow.
+ gold_assert(!from->is_target_special_ || this->is_target_special_);
+ gold_assert(!from->is_forwarder_);
+ gold_assert(!from->has_got_offset_);
+ gold_assert(!from->has_plt_offset_);
+ gold_assert(!from->has_warning_);
+ gold_assert(!from->is_copied_from_dynobj_);
}
// Override a symbol with a special symbol.
this->has_got_offset_ = false;
this->has_plt_offset_ = false;
this->has_warning_ = false;
+ this->is_copied_from_dynobj_ = false;
}
// Initialize the fields in the base class Symbol for SYM in OBJECT.
}
}
+// Define CSYM 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.
+
+template<int size>
+void
+Symbol_table::define_with_copy_reloc(const Target* target,
+ Sized_symbol<size>* csym,
+ Output_data* posd, uint64_t value)
+{
+ gold_assert(csym->is_from_dynobj());
+ gold_assert(!csym->is_copied_from_dynobj());
+ Object* object = csym->object();
+ gold_assert(object->is_dynamic());
+ Dynobj* dynobj = static_cast<Dynobj*>(object);
+
+ // Our copied variable has to override any variable in a shared
+ // library.
+ elfcpp::STB binding = csym->binding();
+ if (binding == elfcpp::STB_WEAK)
+ binding = elfcpp::STB_GLOBAL;
+
+ this->define_in_output_data(target, csym->name(), csym->version(),
+ posd, value, csym->symsize(),
+ csym->type(), binding,
+ csym->visibility(), csym->nonvis(),
+ false, false);
+
+ csym->set_is_copied_from_dynobj();
+ csym->set_needs_dynsym_entry();
+
+ this->copied_symbol_dynobjs_[csym] = dynobj;
+
+ // We have now defined all aliases, but we have not entered them all
+ // in the copied_symbol_dynobjs_ map.
+ if (csym->has_alias())
+ {
+ Symbol* sym = csym;
+ while (true)
+ {
+ sym = this->weak_aliases_[sym];
+ if (sym == csym)
+ break;
+ gold_assert(sym->output_data() == posd);
+
+ sym->set_is_copied_from_dynobj();
+ this->copied_symbol_dynobjs_[sym] = dynobj;
+ }
+ }
+}
+
+// SYM is defined using a COPY reloc. Return the dynamic object where
+// the original definition was found.
+
+Dynobj*
+Symbol_table::get_copy_source(const Symbol* sym) const
+{
+ gold_assert(sym->is_copied_from_dynobj());
+ Copied_symbol_dynobjs::const_iterator p =
+ this->copied_symbol_dynobjs_.find(sym);
+ gold_assert(p != this->copied_symbol_dynobjs_.end());
+ return p->second;
+}
+
// Set the dynamic symbol indexes. INDEX is the index of the first
// global dynamic symbol. Pointers to the symbols are stored into the
// vector SYMS. The names are added to DYNPOOL. This returns an
// Record any version information.
if (sym->version() != NULL)
- versions->record_version(options, dynpool, sym);
+ versions->record_version(options, this, dynpool, sym);
}
}
const std::vector<const char*>* version_map);
#endif
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+template
+void
+Symbol_table::define_with_copy_reloc<32>(const Target* target,
+ Sized_symbol<32>* sym,
+ Output_data* posd, uint64_t value);
+#endif
+
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+template
+void
+Symbol_table::define_with_copy_reloc<64>(const Target* target,
+ Sized_symbol<64>* sym,
+ Output_data* posd, uint64_t value);
+#endif
+
#ifdef HAVE_TARGET_32_LITTLE
template
void
size_t relnum, off_t reloffset) const;
#endif
-
} // End namespace gold.
set_has_warning()
{ this->has_warning_ = true; }
+ // Return whether this symbol is defined by a COPY reloc from a
+ // dynamic object.
+ bool
+ is_copied_from_dynobj() const
+ { return this->is_copied_from_dynobj_; }
+
+ // Mark this symbol as defined by a COPY reloc.
+ void
+ set_is_copied_from_dynobj()
+ { this->is_copied_from_dynobj_ = true; }
+
protected:
// Instances of this class should always be created at a specific
// size.
bool needs_dynsym_value_ : 1;
// True if there is a warning for this symbol.
bool has_warning_ : 1;
+ // True if we are using a COPY reloc for this symbol, so that the
+ // real definition lives in a dynamic object.
+ bool is_copied_from_dynobj_ : 1;
};
// The parts of a symbol which are size specific. Using a template
define_symbols(const Layout*, const Target*, int count,
const Define_symbol_in_segment*);
+ // 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.
+ template<int size>
+ void
+ define_with_copy_reloc(const Target*, Sized_symbol<size>* sym,
+ Output_data* posd, uint64_t value);
+
// Look up a symbol.
Symbol*
lookup(const char*, const char* version = NULL) const;
size_t relnum, off_t reloffset) const
{ this->warnings_.issue_warning(sym, relinfo, relnum, reloffset); }
+ // SYM is defined using a COPY reloc. Return the dynamic object
+ // where the original definition was found.
+ Dynobj*
+ get_copy_source(const Symbol* sym) const;
+
// Set the dynamic symbol indexes. INDEX is the index of the first
// global dynamic symbol. Pointers to the symbols are stored into
// the vector. The names are stored into the Stringpool. This
Symbol_table_eq> Symbol_table_type;
// The type of the list of common symbols.
-
typedef std::vector<Symbol*> Commons_type;
+ // A map from symbols with COPY relocs to the dynamic objects where
+ // they are defined.
+ typedef Unordered_map<const Symbol*, Dynobj*> Copied_symbol_dynobjs;
+
// We increment this every time we see a new undefined symbol, for
// use in archive groups.
int saw_undefined_;
-
// The index of the first global symbol in the output file.
unsigned int first_global_index_;
-
// The file offset within the output symtab section where we should
// write the table.
off_t offset_;
-
// The number of global symbols we want to write out.
size_t output_count_;
-
// The file offset of the global dynamic symbols, or 0 if none.
off_t dynamic_offset_;
-
// The index of the first global dynamic symbol.
unsigned int first_dynamic_global_index_;
-
// The number of global dynamic symbols, or 0 if none.
off_t dynamic_count_;
-
// The symbol hash table.
Symbol_table_type table_;
-
// A pool of symbol names. This is used for all global symbols.
// Entries in the hash table point into this pool.
Stringpool namepool_;
-
// Forwarding symbols.
Unordered_map<const Symbol*, Symbol*> forwarders_;
-
// Weak aliases. A symbol in this list points to the next alias.
// The aliases point to each other in a circular list.
Unordered_map<Symbol*, Symbol*> weak_aliases_;
-
// We don't expect there to be very many common symbols, so we keep
// a list of them. When we find a common symbol we add it to this
// list. It is possible that by the time we process the list the
// symbol is no longer a common symbol. It may also have become a
// forwarder.
Commons_type commons_;
-
// Manage symbol warnings.
Warnings warnings_;
+ // When we emit a COPY reloc for a symbol, we define it in an
+ // Output_data. When it's time to emit version information for it,
+ // we need to know the dynamic object in which we found the original
+ // definition. This maps symbols with COPY relocs to the dynamic
+ // object where they were defined.
+ Copied_symbol_dynobjs copied_symbol_dynobjs_;
};
// We inline get_sized_symbol for efficiency.
off_t offset = dynbss_size;
dynbss->set_space_size(dynbss_size + symsize);
- // Define the symbol in the .dynbss section.
- symtab->define_in_output_data(this, ssym->name(), ssym->version(),
- dynbss, offset, symsize, ssym->type(),
- ssym->binding(), ssym->visibility(),
- ssym->nonvis(), false, false);
+ symtab->define_with_copy_reloc(this, ssym, dynbss, offset);
// Add the COPY reloc.
- ssym->set_needs_dynsym_entry();
Reloc_section* rela_dyn = this->rela_dyn_section(layout);
rela_dyn->add_global(ssym, elfcpp::R_X86_64_COPY, dynbss, offset, 0);
}