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
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
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&);
// For each symbol for which we should give a warning, make a note
// on the symbol.
void
- note_warnings(Symbol_table* symtab);
+ note_warnings(Symbol_table* symtab, const Task*);
// Issue a warning for a reference to SYM at RELINFO's location.
template<int size, bool big_endian>
}
void
- set_text(const char* t, off_t l)
+ set_text(const char* t, section_size_type 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
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*
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*
// 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
// symbol, and DYNCOUNT is the number of global dynamic symbols.
// This records the parameters, and returns the new file offset.
off_t
- finalize(unsigned int index, off_t off, off_t dynoff,
+ finalize(const Task*, unsigned int index, off_t off, off_t dynoff,
size_t dyn_global_index, size_t dyncount, Stringpool* pool);
// 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