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
set_is_copied_from_dynobj()
{ this->is_copied_from_dynobj_ = true; }
- // Mark this symbol as needing its value written to the GOT even when
- // the value is subject to dynamic relocation (e.g., when the target
- // uses a RELATIVE relocation for the GOT entry).
- void
- set_needs_value_in_got()
- { this->needs_value_in_got_ = true; }
-
- // Return whether this symbol needs its value written to the GOT even
- // when the value is subject to dynamic relocation.
- bool
- needs_value_in_got() const
- { return this->needs_value_in_got_; }
-
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
// 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;
- // True if the static value should be written to the GOT even
- // when the final value is subject to dynamic relocation.
- bool needs_value_in_got_ : 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();
// 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
template<int size>
void
define_with_copy_reloc(const Target*, Sized_symbol<size>* sym,
- Output_data* posd, uint64_t value);
+ 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*
// 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
// 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_;
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