template<int size, bool big_endian>
class Sized_dynobj;
class Versions;
+class Input_objects;
class Output_data;
class Output_section;
class Output_segment;
name() const
{ return this->name_; }
+ // Return the (ANSI) demangled version of the name, if
+ // parameters.demangle() is true. Otherwise, return the name. This
+ // is intended to be used only for logging errors, so it's not
+ // super-efficient.
+ std::string
+ demangled_name() const;
+
// Return the symbol version. This will return NULL for an
// unversioned symbol.
const char*
{ return this->dynsym_index_ != 0; }
// Return whether this symbol has an entry in the GOT section.
+ // For a TLS symbol, this GOT entry will hold its tp-relative offset.
bool
has_got_offset() const
{ return this->has_got_offset_; }
this->got_offset_ = got_offset;
}
+ // Return whether this TLS symbol has an entry in the GOT section for
+ // its module index or, if NEED_PAIR is true, has a pair of entries
+ // for its module index and dtv-relative offset.
+ bool
+ has_tls_got_offset(bool need_pair) const
+ {
+ return (this->has_tls_mod_got_offset_
+ && (!need_pair || this->has_tls_pair_got_offset_));
+ }
+
+ // Return the offset into the GOT section for this symbol's TLS module
+ // index or, if NEED_PAIR is true, for the pair of entries for the
+ // module index and dtv-relative offset.
+ unsigned int
+ tls_got_offset(bool need_pair) const
+ {
+ gold_assert(this->has_tls_got_offset(need_pair));
+ return this->tls_mod_got_offset_;
+ }
+
+ // Set the GOT offset of this symbol.
+ void
+ set_tls_got_offset(unsigned int got_offset, bool have_pair)
+ {
+ this->has_tls_mod_got_offset_ = true;
+ this->has_tls_pair_got_offset_ = have_pair;
+ this->tls_mod_got_offset_ = got_offset;
+ }
+
// Return whether this symbol has an entry in the PLT section.
bool
has_plt_offset() const
bool
is_preemptible() const
{
+ // It doesn't make sense to ask whether a symbol defined in
+ // another object is preemptible.
+ gold_assert(!this->is_from_dynobj());
+
return (this->visibility_ != elfcpp::STV_INTERNAL
&& this->visibility_ != elfcpp::STV_HIDDEN
&& this->visibility_ != elfcpp::STV_PROTECTED
+ && parameters->output_is_shared()
&& !parameters->symbolic());
}
+ // Return true if this symbol is a function that needs a PLT entry.
+ // If the symbol is defined in a dynamic object or if it is subject
+ // to pre-emption, we need to make a PLT entry.
+ bool
+ needs_plt_entry() const
+ {
+ return (this->type() == elfcpp::STT_FUNC
+ && (this->is_from_dynobj() || this->is_preemptible()));
+ }
+
+ // Given a direct absolute or pc-relative static relocation against
+ // the global symbol, this function returns whether a dynamic relocation
+ // is needed.
+
+ bool
+ needs_dynamic_reloc(bool is_absolute_ref, bool is_function_call) const
+ {
+ // An absolute reference within a position-independent output file
+ // will need a dynamic relocaion.
+ if (is_absolute_ref && parameters->output_is_position_independent())
+ return true;
+
+ // A function call that can branch to a local PLT entry does not need
+ // a dynamic relocation.
+ if (is_function_call && this->has_plt_offset())
+ return false;
+
+ // A reference to any PLT entry in a non-position-independent executable
+ // does not need a dynamic relocation.
+ if (!parameters->output_is_position_independent()
+ && this->has_plt_offset())
+ return false;
+
+ // A reference to a symbol defined in a dynamic object or to a
+ // symbol that is preemptible will need a dynamic relocation.
+ if (this->is_from_dynobj() || this->is_preemptible())
+ return true;
+
+ // For all other cases, return FALSE.
+ return false;
+ }
+
+ // Given a direct absolute static relocation against
+ // the global symbol, where a dynamic relocation is needed, this
+ // function returns whether a relative dynamic relocation can be used.
+ // The caller must determine separately whether the static relocation
+ // is compatible with a relative relocation.
+
+ bool
+ can_use_relative_reloc(bool is_function_call) const
+ {
+ // A function call that can branch to a local PLT entry can
+ // use a RELATIVE relocation.
+ if (is_function_call && this->has_plt_offset())
+ return true;
+
+ // A reference to a symbol defined in a dynamic object or to a
+ // symbol that is preemptible can not use a RELATIVE relocaiton.
+ if (this->is_from_dynobj() || this->is_preemptible())
+ return false;
+
+ // For all other cases, return TRUE.
+ return true;
+ }
+
// Return whether there should be a warning for references to this
// symbol.
bool
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.
void
override_base_with_special(const Symbol* from);
+ // Allocate a common symbol by giving it a location in the output
+ // file.
+ void
+ allocate_base_common(Output_data*);
+
private:
Symbol(const Symbol&);
Symbol& operator=(const Symbol&);
// If this symbol has an entry in the GOT section (has_got_offset_
// is true), this is the offset from the start of the GOT section.
+ // For a TLS symbol, if has_tls_tpoff_got_offset_ is true, this
+ // serves as the GOT offset for the GOT entry that holds its
+ // TP-relative offset.
unsigned int got_offset_;
+ // If this is a TLS symbol and has an entry in the GOT section
+ // for a module index or a pair of entries (module index,
+ // dtv-relative offset), these are the offsets from the start
+ // of the GOT section.
+ unsigned int tls_mod_got_offset_;
+ unsigned int tls_pair_got_offset_;
+
// If this symbol has an entry in the PLT section (has_plt_offset_
// is true), then this is the offset from the start of the PLT
// section.
// True if we've seen this symbol in a dynamic object.
bool in_dyn_ : 1;
// True if the symbol has an entry in the GOT section.
+ // For a TLS symbol, this GOT entry will hold its tp-relative offset.
bool has_got_offset_ : 1;
+ // True if the symbol has an entry in the GOT section for its
+ // module index.
+ bool has_tls_mod_got_offset_ : 1;
+ // True if the symbol has a pair of entries in the GOT section for its
+ // module index and dtv-relative offset.
+ bool has_tls_pair_got_offset_ : 1;
// True if the symbol has an entry in the PLT section.
bool has_plt_offset_ : 1;
// True if this is a dynamic symbol which needs a special value in
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
set_value(Value_type value)
{ this->value_ = value; }
+ // Allocate a common symbol by giving it a location in the output
+ // file.
+ void
+ allocate_common(Output_data*, Value_type value);
+
private:
Sized_symbol(const Sized_symbol&);
Sized_symbol& operator=(const Sized_symbol&);
: warnings_()
{ }
- // Add a warning for symbol NAME in section SHNDX in object OBJ.
+ // Add a warning for symbol NAME in object OBJ. WARNING is the text
+ // of the warning.
void
add_warning(Symbol_table* symtab, const char* name, Object* obj,
- unsigned int shndx);
+ const std::string& warning);
// For each symbol for which we should give a warning, make a note
// on the symbol.
{
// The object the warning is in.
Object* object;
- // The index of the warning section.
- unsigned int shndx;
- // The warning text if we have already loaded it.
+ // The warning text.
std::string text;
Warning_location()
- : object(NULL), shndx(0), text()
+ : object(NULL), text()
{ }
void
- set(Object* o, unsigned int s)
+ set(Object* o, const std::string& t)
{
this->object = o;
- this->shndx = s;
+ this->text = t;
}
-
- void
- set_text(const char* t, off_t l)
- { this->text.assign(t, l); }
};
// A mapping from warning symbol names (canonicalized in
- // Symbol_table's namepool_ field) to
+ // Symbol_table's namepool_ field) to warning information.
typedef Unordered_map<const char*, Warning_location> Warning_table;
Warning_table warnings_;
class Symbol_table
{
public:
- Symbol_table();
+ // COUNT is an estimate of how many symbosl will be inserted in the
+ // symbol table. It's ok to put 0 if you don't know; a correct
+ // guess will just save some CPU by reducing hashtable resizes.
+ Symbol_table(unsigned int count);
~Symbol_table();
add_from_relobj(Sized_relobj<size, big_endian>* relobj,
const unsigned char* syms, size_t count,
const char* sym_names, size_t sym_name_size,
- Symbol** sympointers);
+ typename Sized_relobj<size, big_endian>::Symbols*);
// Add COUNT dynamic symbols from the dynamic object DYNOBJ to the
// symbol table. SYMS is the symbols. SYM_NAMES is their names.
// Define a set of symbols in output segments.
void
define_symbols(const Layout*, const Target*, int count,
- const Define_symbol_in_segment*);
+ 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,
+ typename elfcpp::Elf_types<size>::Elf_Addr);
// Look up a symbol.
Symbol*
void
allocate_commons(const General_options&, Layout*);
- // Add a warning for symbol NAME in section SHNDX in object OBJ.
+ // Add a warning for symbol NAME in object OBJ. WARNING is the text
+ // of the warning.
void
- add_warning(const char* name, Object* obj, unsigned int shndx)
- { this->warnings_.add_warning(this, name, obj, shndx); }
+ add_warning(const char* name, Object* obj, const std::string& warning)
+ { this->warnings_.add_warning(this, name, obj, warning); }
// Canonicalize a symbol name for use in the hash table.
const char*
size_t relnum, off_t reloffset) const
{ this->warnings_.issue_warning(sym, relinfo, relnum, reloffset); }
+ // Check candidate_odr_violations_ to find symbols with the same name
+ // but apparently different definitions (different source-file/line-no).
+ void
+ detect_odr_violations(const Task*, const char* output_file_name) const;
+
+ // 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
// returns an updated dynamic symbol index.
unsigned int
- set_dynsym_indexes(const General_options*, const Target*, unsigned int index,
+ set_dynsym_indexes(const Target*, unsigned int index,
std::vector<Symbol*>*, Stringpool*, Versions*);
// Finalize the symbol table after we have set the final addresses
// Write out the global symbols.
void
- write_globals(const Target*, const Stringpool*, const Stringpool*,
+ write_globals(const Input_objects*, const Stringpool*, const Stringpool*,
Output_file*) const;
// Write out a section symbol. Return the updated offset.
void
write_section_symbol(const Output_section*, Output_file*, off_t) const;
+ // Dump statistical information to stderr.
+ void
+ print_stats() const;
+
private:
Symbol_table(const Symbol_table&);
Symbol_table& operator=(const Symbol_table&);
Sized_symbol<size>*
add_from_object(Object*, const char *name, Stringpool::Key name_key,
const char *version, Stringpool::Key version_key,
- bool def, const elfcpp::Sym<size, big_endian>& sym);
+ bool def, const elfcpp::Sym<size, big_endian>& sym,
+ const elfcpp::Sym<size, big_endian>& orig_sym);
// Resolve symbols.
template<int size, bool big_endian>
void
resolve(Sized_symbol<size>* to,
const elfcpp::Sym<size, big_endian>& sym,
+ const elfcpp::Sym<size, big_endian>& orig_sym,
Object*, const char* version);
template<int size, bool big_endian>
void
do_allocate_commons(const General_options&, Layout*);
+ // Implement detect_odr_violations.
+ template<int size, bool big_endian>
+ void
+ sized_detect_odr_violations() const;
+
// Finalize symbols specialized for size.
template<int size>
off_t
// Write globals specialized for size and endianness.
template<int size, bool big_endian>
void
- sized_write_globals(const Target*, const Stringpool*, const Stringpool*,
- Output_file*) const;
+ sized_write_globals(const Input_objects*, const Stringpool*,
+ const Stringpool*, Output_file*) const;
// Write out a symbol to P.
template<int size, bool big_endian>
const Stringpool*, unsigned char* p
ACCEPT_SIZE_ENDIAN) const;
+ // Possibly warn about an undefined symbol from a dynamic object.
+ void
+ warn_about_undefined_dynobj_symbol(const Input_objects*, Symbol*) const;
+
// Write out a section symbol, specialized for size and endianness.
template<int size, bool big_endian>
void
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;
+
+ // A map from symbol name (as a pointer into the namepool) to all
+ // the locations the symbols is (weakly) defined (and certain other
+ // conditions are met). This map will be used later to detect
+ // possible One Definition Rule (ODR) violations.
+ struct Symbol_location
+ {
+ Object* object; // Object where the symbol is defined.
+ unsigned int shndx; // Section-in-object where the symbol is defined.
+ off_t offset; // Offset-in-section where the symbol is defined.
+ bool operator==(const Symbol_location& that) const
+ {
+ return (this->object == that.object
+ && this->shndx == that.shndx
+ && this->offset == that.offset);
+ }
+ };
+
+ struct Symbol_location_hash
+ {
+ size_t operator()(const Symbol_location& loc) const
+ { return reinterpret_cast<uintptr_t>(loc.object) ^ loc.offset ^ loc.shndx; }
+ };
+
+ typedef Unordered_map<const char*,
+ Unordered_set<Symbol_location, Symbol_location_hash> >
+ Odr_map;
+
// 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_;
+ // Manage potential One Definition Rule (ODR) violations.
+ Odr_map candidate_odr_violations_;
+
+ // 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.