8a5e3e08a6
Target::new_output_section. (Layout::attach_allocated_section_to_segment): Put large section sections in a separate load segment with the large segment flag set. (Layout::segment_precedes): Sort large data segments after other load segments. (align_file_offset): New static function. (Layout::set_segment_offsets): Use align_file_offset. * output.h (class Output_section): Add is_small_section_ and is_large_section_ fields. (Output_section::is_small_section): New function. (Output_section::set_is_small_section): New function. (Output_section::is_large_section): New function. (Output_section::set_is_large_section): New function. (Output_section::is_large_data_section): New function. (class Output_segment): Add is_large_data_segment_ field. (Output_segment::is_large_data_segment): New function. (Output_segment::set_is_large_data_segment): New function. * output.cc (Output_section::Output_section): Initialize new fields. (Output_segment::Output_segment): Likewise. (Output_segment::add_output_section): Add assertion that large data sections always go in large data segments. Force small data sections to the end of the list of data sections. Force small BSS sections to the start of the list of BSS sections. For large BSS sections to the end of the list of BSS sections. * symtab.h (class Symbol): Declare is_common_shndx. (Symbol::is_defined): Check Symbol::is_common_shndx. (Symbol::is_common): Likewise. (class Symbol_table): Define enum Commons_section_type. Update declarations. Add small_commons_ and large_commons_ fields. * symtab.cc (Symbol::is_common_shndx): New function. (Symbol_table::Symbol_table): Initialize new fields. (Symbol_table::add_from_object): Put small and large common symbols in the right list. (Symbol_table::sized_finalized_symbol): Check Symbol::is_common_shndx. (Symbol_table::sized_write_globals): Likewise. * common.cc (Symbol_table::do_allocate_commons): Allocate new common symbol lists. Don't call do_allocate_commons_list if the list is empty. (Symbol_table::do_allocate_commons_list): Remove is_tls parameter. Add comons_section_type parameter. Change all callers. Handle small and large common symbols. * object.cc (Sized_relobj::do_finalize_local_symbols): Check Symbol::is_common_shndx. * resolve.cc (symbol_to_bits): Likewise. * target.h (Target::small_common_shndx): New function. (Target::small_common_section_flags): New function. (Target::large_common_shndx): New function. (Target::large_common_section_flags): New function. (Target::new_output_section): New function. (Target::Target_info): Add small_common_shndx, large_common_shndx, small_common_section_flags, and large_common_section_flags fields. (Target::do_new_output_section): New virtual function. * arm.cc (Target_arm::arm_info): Initialize new fields. * i386.cc (Target_i386::i386_info): Likewise. * powerpc.cc (Target_powerpc::powerpc_info) [all versions]: Likewise. * sparc.c (Target_sparc::sparc_info) [all versions]: Likewise. * x86_64.cc (Target_x86_64::x86_64_info): Likewise. (Target_x86_64::do_new_output_section): New function. * configure.ac: Define conditional MCMODEL_MEDIUM. * testsuite/Makefile.am (check_PROGRAMS): Add large. (large_SOURCES, large_CFLAGS, large_DEPENDENCIES): Define. (large_LDFLAGS): Define. * testsuite/large.c: New file. * testsuite/testfile.cc (Target_test::test_target_info): Initialize new fields. * configure, testsuite/Makefile.in: Rebuild.
1696 lines
53 KiB
C++
1696 lines
53 KiB
C++
// symtab.h -- the gold symbol table -*- C++ -*-
|
|
|
|
// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
|
// Written by Ian Lance Taylor <iant@google.com>.
|
|
|
|
// This file is part of gold.
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
|
// MA 02110-1301, USA.
|
|
|
|
// Symbol_table
|
|
// The symbol table.
|
|
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "gc.h"
|
|
#include "elfcpp.h"
|
|
#include "parameters.h"
|
|
#include "stringpool.h"
|
|
#include "object.h"
|
|
|
|
#ifndef GOLD_SYMTAB_H
|
|
#define GOLD_SYMTAB_H
|
|
|
|
namespace gold
|
|
{
|
|
|
|
class Mapfile;
|
|
class Object;
|
|
class Relobj;
|
|
template<int size, bool big_endian>
|
|
class Sized_relobj;
|
|
template<int size, bool big_endian>
|
|
class Sized_pluginobj;
|
|
class Dynobj;
|
|
template<int size, bool big_endian>
|
|
class Sized_dynobj;
|
|
class Versions;
|
|
class Version_script_info;
|
|
class Input_objects;
|
|
class Output_data;
|
|
class Output_section;
|
|
class Output_segment;
|
|
class Output_file;
|
|
class Output_symtab_xindex;
|
|
class Garbage_collection;
|
|
|
|
// The base class of an entry in the symbol table. The symbol table
|
|
// can have a lot of entries, so we don't want this class to big.
|
|
// Size dependent fields can be found in the template class
|
|
// Sized_symbol. Targets may support their own derived classes.
|
|
|
|
class Symbol
|
|
{
|
|
public:
|
|
// Because we want the class to be small, we don't use any virtual
|
|
// functions. But because symbols can be defined in different
|
|
// places, we need to classify them. This enum is the different
|
|
// sources of symbols we support.
|
|
enum Source
|
|
{
|
|
// Symbol defined in a relocatable or dynamic input file--this is
|
|
// the most common case.
|
|
FROM_OBJECT,
|
|
// Symbol defined in an Output_data, a special section created by
|
|
// the target.
|
|
IN_OUTPUT_DATA,
|
|
// Symbol defined in an Output_segment, with no associated
|
|
// section.
|
|
IN_OUTPUT_SEGMENT,
|
|
// Symbol value is constant.
|
|
IS_CONSTANT,
|
|
// Symbol is undefined.
|
|
IS_UNDEFINED
|
|
};
|
|
|
|
// When the source is IN_OUTPUT_SEGMENT, we need to describe what
|
|
// the offset means.
|
|
enum Segment_offset_base
|
|
{
|
|
// From the start of the segment.
|
|
SEGMENT_START,
|
|
// From the end of the segment.
|
|
SEGMENT_END,
|
|
// From the filesz of the segment--i.e., after the loaded bytes
|
|
// but before the bytes which are allocated but zeroed.
|
|
SEGMENT_BSS
|
|
};
|
|
|
|
// Return the symbol name.
|
|
const char*
|
|
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*
|
|
version() const
|
|
{ return this->version_; }
|
|
|
|
// Return whether this version is the default for this symbol name
|
|
// (eg, "foo@@V2" is a default version; "foo@V1" is not). Only
|
|
// meaningful for versioned symbols.
|
|
bool
|
|
is_default() const
|
|
{
|
|
gold_assert(this->version_ != NULL);
|
|
return this->is_def_;
|
|
}
|
|
|
|
// Set that this version is the default for this symbol name.
|
|
void
|
|
set_is_default()
|
|
{ this->is_def_ = true; }
|
|
|
|
// Return the symbol source.
|
|
Source
|
|
source() const
|
|
{ return this->source_; }
|
|
|
|
// Return the object with which this symbol is associated.
|
|
Object*
|
|
object() const
|
|
{
|
|
gold_assert(this->source_ == FROM_OBJECT);
|
|
return this->u_.from_object.object;
|
|
}
|
|
|
|
// Return the index of the section in the input relocatable or
|
|
// dynamic object file.
|
|
unsigned int
|
|
shndx(bool* is_ordinary) const
|
|
{
|
|
gold_assert(this->source_ == FROM_OBJECT);
|
|
*is_ordinary = this->is_ordinary_shndx_;
|
|
return this->u_.from_object.shndx;
|
|
}
|
|
|
|
// Return the output data section with which this symbol is
|
|
// associated, if the symbol was specially defined with respect to
|
|
// an output data section.
|
|
Output_data*
|
|
output_data() const
|
|
{
|
|
gold_assert(this->source_ == IN_OUTPUT_DATA);
|
|
return this->u_.in_output_data.output_data;
|
|
}
|
|
|
|
// If this symbol was defined with respect to an output data
|
|
// section, return whether the value is an offset from end.
|
|
bool
|
|
offset_is_from_end() const
|
|
{
|
|
gold_assert(this->source_ == IN_OUTPUT_DATA);
|
|
return this->u_.in_output_data.offset_is_from_end;
|
|
}
|
|
|
|
// Return the output segment with which this symbol is associated,
|
|
// if the symbol was specially defined with respect to an output
|
|
// segment.
|
|
Output_segment*
|
|
output_segment() const
|
|
{
|
|
gold_assert(this->source_ == IN_OUTPUT_SEGMENT);
|
|
return this->u_.in_output_segment.output_segment;
|
|
}
|
|
|
|
// If this symbol was defined with respect to an output segment,
|
|
// return the offset base.
|
|
Segment_offset_base
|
|
offset_base() const
|
|
{
|
|
gold_assert(this->source_ == IN_OUTPUT_SEGMENT);
|
|
return this->u_.in_output_segment.offset_base;
|
|
}
|
|
|
|
// Return the symbol binding.
|
|
elfcpp::STB
|
|
binding() const
|
|
{ return this->binding_; }
|
|
|
|
// Return the symbol type.
|
|
elfcpp::STT
|
|
type() const
|
|
{ return this->type_; }
|
|
|
|
// Return the symbol visibility.
|
|
elfcpp::STV
|
|
visibility() const
|
|
{ return this->visibility_; }
|
|
|
|
// Set the visibility.
|
|
void
|
|
set_visibility(elfcpp::STV visibility)
|
|
{ this->visibility_ = visibility; }
|
|
|
|
// Override symbol visibility.
|
|
void
|
|
override_visibility(elfcpp::STV);
|
|
|
|
// Return the non-visibility part of the st_other field.
|
|
unsigned char
|
|
nonvis() const
|
|
{ return this->nonvis_; }
|
|
|
|
// Return whether this symbol is a forwarder. This will never be
|
|
// true of a symbol found in the hash table, but may be true of
|
|
// symbol pointers attached to object files.
|
|
bool
|
|
is_forwarder() const
|
|
{ return this->is_forwarder_; }
|
|
|
|
// Mark this symbol as a forwarder.
|
|
void
|
|
set_forwarder()
|
|
{ this->is_forwarder_ = true; }
|
|
|
|
// Return whether this symbol has an alias in the weak aliases table
|
|
// in Symbol_table.
|
|
bool
|
|
has_alias() const
|
|
{ return this->has_alias_; }
|
|
|
|
// Mark this symbol as having an alias.
|
|
void
|
|
set_has_alias()
|
|
{ this->has_alias_ = true; }
|
|
|
|
// Return whether this symbol needs an entry in the dynamic symbol
|
|
// table.
|
|
bool
|
|
needs_dynsym_entry() const
|
|
{
|
|
return (this->needs_dynsym_entry_
|
|
|| (this->in_reg() && this->in_dyn()));
|
|
}
|
|
|
|
// Mark this symbol as needing an entry in the dynamic symbol table.
|
|
void
|
|
set_needs_dynsym_entry()
|
|
{ this->needs_dynsym_entry_ = true; }
|
|
|
|
// Return whether this symbol should be added to the dynamic symbol
|
|
// table.
|
|
bool
|
|
should_add_dynsym_entry() const;
|
|
|
|
// Return whether this symbol has been seen in a regular object.
|
|
bool
|
|
in_reg() const
|
|
{ return this->in_reg_; }
|
|
|
|
// Mark this symbol as having been seen in a regular object.
|
|
void
|
|
set_in_reg()
|
|
{ this->in_reg_ = true; }
|
|
|
|
// Return whether this symbol has been seen in a dynamic object.
|
|
bool
|
|
in_dyn() const
|
|
{ return this->in_dyn_; }
|
|
|
|
// Mark this symbol as having been seen in a dynamic object.
|
|
void
|
|
set_in_dyn()
|
|
{ this->in_dyn_ = true; }
|
|
|
|
// Return whether this symbol has been seen in a real ELF object.
|
|
// (IN_REG will return TRUE if the symbol has been seen in either
|
|
// a real ELF object or an object claimed by a plugin.)
|
|
bool
|
|
in_real_elf() const
|
|
{ return this->in_real_elf_; }
|
|
|
|
// Mark this symbol as having been seen in a real ELF object.
|
|
void
|
|
set_in_real_elf()
|
|
{ this->in_real_elf_ = true; }
|
|
|
|
// Return the index of this symbol in the output file symbol table.
|
|
// A value of -1U means that this symbol is not going into the
|
|
// output file. This starts out as zero, and is set to a non-zero
|
|
// value by Symbol_table::finalize. It is an error to ask for the
|
|
// symbol table index before it has been set.
|
|
unsigned int
|
|
symtab_index() const
|
|
{
|
|
gold_assert(this->symtab_index_ != 0);
|
|
return this->symtab_index_;
|
|
}
|
|
|
|
// Set the index of the symbol in the output file symbol table.
|
|
void
|
|
set_symtab_index(unsigned int index)
|
|
{
|
|
gold_assert(index != 0);
|
|
this->symtab_index_ = index;
|
|
}
|
|
|
|
// Return whether this symbol already has an index in the output
|
|
// file symbol table.
|
|
bool
|
|
has_symtab_index() const
|
|
{ return this->symtab_index_ != 0; }
|
|
|
|
// Return the index of this symbol in the dynamic symbol table. A
|
|
// value of -1U means that this symbol is not going into the dynamic
|
|
// symbol table. This starts out as zero, and is set to a non-zero
|
|
// during Layout::finalize. It is an error to ask for the dynamic
|
|
// symbol table index before it has been set.
|
|
unsigned int
|
|
dynsym_index() const
|
|
{
|
|
gold_assert(this->dynsym_index_ != 0);
|
|
return this->dynsym_index_;
|
|
}
|
|
|
|
// Set the index of the symbol in the dynamic symbol table.
|
|
void
|
|
set_dynsym_index(unsigned int index)
|
|
{
|
|
gold_assert(index != 0);
|
|
this->dynsym_index_ = index;
|
|
}
|
|
|
|
// Return whether this symbol already has an index in the dynamic
|
|
// symbol table.
|
|
bool
|
|
has_dynsym_index() const
|
|
{ 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(unsigned int got_type) const
|
|
{ return this->got_offsets_.get_offset(got_type) != -1U; }
|
|
|
|
// Return the offset into the GOT section of this symbol.
|
|
unsigned int
|
|
got_offset(unsigned int got_type) const
|
|
{
|
|
unsigned int got_offset = this->got_offsets_.get_offset(got_type);
|
|
gold_assert(got_offset != -1U);
|
|
return got_offset;
|
|
}
|
|
|
|
// Set the GOT offset of this symbol.
|
|
void
|
|
set_got_offset(unsigned int got_type, unsigned int got_offset)
|
|
{ this->got_offsets_.set_offset(got_type, got_offset); }
|
|
|
|
// Return whether this symbol has an entry in the PLT section.
|
|
bool
|
|
has_plt_offset() const
|
|
{ return this->has_plt_offset_; }
|
|
|
|
// Return the offset into the PLT section of this symbol.
|
|
unsigned int
|
|
plt_offset() const
|
|
{
|
|
gold_assert(this->has_plt_offset());
|
|
return this->plt_offset_;
|
|
}
|
|
|
|
// Set the PLT offset of this symbol.
|
|
void
|
|
set_plt_offset(unsigned int plt_offset)
|
|
{
|
|
this->has_plt_offset_ = true;
|
|
this->plt_offset_ = plt_offset;
|
|
}
|
|
|
|
// Return whether this dynamic symbol needs a special value in the
|
|
// dynamic symbol table.
|
|
bool
|
|
needs_dynsym_value() const
|
|
{ return this->needs_dynsym_value_; }
|
|
|
|
// Set that this dynamic symbol needs a special value in the dynamic
|
|
// symbol table.
|
|
void
|
|
set_needs_dynsym_value()
|
|
{
|
|
gold_assert(this->object()->is_dynamic());
|
|
this->needs_dynsym_value_ = true;
|
|
}
|
|
|
|
// Return true if the final value of this symbol is known at link
|
|
// time.
|
|
bool
|
|
final_value_is_known() const;
|
|
|
|
// Return true if SHNDX represents a common symbol. This depends on
|
|
// the target.
|
|
static bool
|
|
is_common_shndx(unsigned int shndx);
|
|
|
|
// Return whether this is a defined symbol (not undefined or
|
|
// common).
|
|
bool
|
|
is_defined() const
|
|
{
|
|
bool is_ordinary;
|
|
if (this->source_ != FROM_OBJECT)
|
|
return this->source_ != IS_UNDEFINED;
|
|
unsigned int shndx = this->shndx(&is_ordinary);
|
|
return (is_ordinary
|
|
? shndx != elfcpp::SHN_UNDEF
|
|
: !Symbol::is_common_shndx(shndx));
|
|
}
|
|
|
|
// Return true if this symbol is from a dynamic object.
|
|
bool
|
|
is_from_dynobj() const
|
|
{
|
|
return this->source_ == FROM_OBJECT && this->object()->is_dynamic();
|
|
}
|
|
|
|
// Return whether this is an undefined symbol.
|
|
bool
|
|
is_undefined() const
|
|
{
|
|
bool is_ordinary;
|
|
return ((this->source_ == FROM_OBJECT
|
|
&& this->shndx(&is_ordinary) == elfcpp::SHN_UNDEF
|
|
&& is_ordinary)
|
|
|| this->source_ == IS_UNDEFINED);
|
|
}
|
|
|
|
// Return whether this is a weak undefined symbol.
|
|
bool
|
|
is_weak_undefined() const
|
|
{ return this->is_undefined() && this->binding() == elfcpp::STB_WEAK; }
|
|
|
|
// Return whether this is an absolute symbol.
|
|
bool
|
|
is_absolute() const
|
|
{
|
|
bool is_ordinary;
|
|
return ((this->source_ == FROM_OBJECT
|
|
&& this->shndx(&is_ordinary) == elfcpp::SHN_ABS
|
|
&& !is_ordinary)
|
|
|| this->source_ == IS_CONSTANT);
|
|
}
|
|
|
|
// Return whether this is a common symbol.
|
|
bool
|
|
is_common() const
|
|
{
|
|
if (this->type_ == elfcpp::STT_COMMON)
|
|
return true;
|
|
if (this->source_ != FROM_OBJECT)
|
|
return false;
|
|
bool is_ordinary;
|
|
unsigned int shndx = this->shndx(&is_ordinary);
|
|
return !is_ordinary && Symbol::is_common_shndx(shndx);
|
|
}
|
|
|
|
// Return whether this symbol can be seen outside this object.
|
|
bool
|
|
is_externally_visible() const
|
|
{
|
|
return (this->visibility_ == elfcpp::STV_DEFAULT
|
|
|| this->visibility_ == elfcpp::STV_PROTECTED);
|
|
}
|
|
|
|
// Return true if this symbol can be preempted by a definition in
|
|
// another link unit.
|
|
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());
|
|
|
|
// It doesn't make sense to ask whether an undefined symbol
|
|
// is preemptible.
|
|
gold_assert(!this->is_undefined());
|
|
|
|
// If a symbol does not have default visibility, it can not be
|
|
// seen outside this link unit and therefore is not preemptible.
|
|
if (this->visibility_ != elfcpp::STV_DEFAULT)
|
|
return false;
|
|
|
|
// If this symbol has been forced to be a local symbol by a
|
|
// version script, then it is not visible outside this link unit
|
|
// and is not preemptible.
|
|
if (this->is_forced_local_)
|
|
return false;
|
|
|
|
// If we are not producing a shared library, then nothing is
|
|
// preemptible.
|
|
if (!parameters->options().shared())
|
|
return false;
|
|
|
|
// If the user used -Bsymbolic, then nothing is preemptible.
|
|
if (parameters->options().Bsymbolic())
|
|
return false;
|
|
|
|
// If the user used -Bsymbolic-functions, then functions are not
|
|
// preemptible. We explicitly check for not being STT_OBJECT,
|
|
// rather than for being STT_FUNC, because that is what the GNU
|
|
// linker does.
|
|
if (this->type() != elfcpp::STT_OBJECT
|
|
&& parameters->options().Bsymbolic_functions())
|
|
return false;
|
|
|
|
// Otherwise the symbol is preemptible.
|
|
return true;
|
|
}
|
|
|
|
// 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. If we're doing a
|
|
// static link, we don't create PLT entries.
|
|
bool
|
|
needs_plt_entry() const
|
|
{
|
|
// An undefined symbol from an executable does not need a PLT entry.
|
|
if (this->is_undefined() && !parameters->options().shared())
|
|
return false;
|
|
|
|
return (!parameters->doing_static_link()
|
|
&& this->type() == elfcpp::STT_FUNC
|
|
&& (this->is_from_dynobj()
|
|
|| this->is_undefined()
|
|
|| this->is_preemptible()));
|
|
}
|
|
|
|
// When determining whether a reference to a symbol needs a dynamic
|
|
// relocation, we need to know several things about the reference.
|
|
// These flags may be or'ed together.
|
|
enum Reference_flags
|
|
{
|
|
// Reference to the symbol's absolute address.
|
|
ABSOLUTE_REF = 1,
|
|
// A non-PIC reference.
|
|
NON_PIC_REF = 2,
|
|
// A function call.
|
|
FUNCTION_CALL = 4
|
|
};
|
|
|
|
// 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(int flags) const
|
|
{
|
|
// No dynamic relocations in a static link!
|
|
if (parameters->doing_static_link())
|
|
return false;
|
|
|
|
// A reference to an undefined symbol from an executable should be
|
|
// statically resolved to 0, and does not need a dynamic relocation.
|
|
// This matches gnu ld behavior.
|
|
if (this->is_undefined() && !parameters->options().shared())
|
|
return false;
|
|
|
|
// A reference to an absolute symbol does not need a dynamic relocation.
|
|
if (this->is_absolute())
|
|
return false;
|
|
|
|
// An absolute reference within a position-independent output file
|
|
// will need a dynamic relocation.
|
|
if ((flags & ABSOLUTE_REF)
|
|
&& parameters->options().output_is_position_independent())
|
|
return true;
|
|
|
|
// A function call that can branch to a local PLT entry does not need
|
|
// a dynamic relocation. A non-pic pc-relative function call in a
|
|
// shared library cannot use a PLT entry.
|
|
if ((flags & FUNCTION_CALL)
|
|
&& this->has_plt_offset()
|
|
&& !((flags & NON_PIC_REF) && parameters->options().shared()))
|
|
return false;
|
|
|
|
// A reference to any PLT entry in a non-position-independent executable
|
|
// does not need a dynamic relocation.
|
|
if (!parameters->options().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_undefined()
|
|
|| this->is_preemptible())
|
|
return true;
|
|
|
|
// For all other cases, return FALSE.
|
|
return false;
|
|
}
|
|
|
|
// Whether we should use the PLT offset associated with a symbol for
|
|
// a relocation. IS_NON_PIC_REFERENCE is true if this is a non-PIC
|
|
// reloc--the same set of relocs for which we would pass NON_PIC_REF
|
|
// to the needs_dynamic_reloc function.
|
|
|
|
bool
|
|
use_plt_offset(bool is_non_pic_reference) const
|
|
{
|
|
// If the symbol doesn't have a PLT offset, then naturally we
|
|
// don't want to use it.
|
|
if (!this->has_plt_offset())
|
|
return false;
|
|
|
|
// If we are going to generate a dynamic relocation, then we will
|
|
// wind up using that, so no need to use the PLT entry.
|
|
if (this->needs_dynamic_reloc(FUNCTION_CALL
|
|
| (is_non_pic_reference
|
|
? NON_PIC_REF
|
|
: 0)))
|
|
return false;
|
|
|
|
// If the symbol is from a dynamic object, we need to use the PLT
|
|
// entry.
|
|
if (this->is_from_dynobj())
|
|
return true;
|
|
|
|
// If we are generating a shared object, and this symbol is
|
|
// undefined or preemptible, we need to use the PLT entry.
|
|
if (parameters->options().shared()
|
|
&& (this->is_undefined() || this->is_preemptible()))
|
|
return true;
|
|
|
|
// If this is a weak undefined symbol, we need to use the PLT
|
|
// entry; the symbol may be defined by a library loaded at
|
|
// runtime.
|
|
if (this->is_weak_undefined())
|
|
return true;
|
|
|
|
// Otherwise we can use the regular definition.
|
|
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_undefined()
|
|
|| this->is_preemptible())
|
|
return false;
|
|
|
|
// For all other cases, return TRUE.
|
|
return true;
|
|
}
|
|
|
|
// Return the output section where this symbol is defined. Return
|
|
// NULL if the symbol has an absolute value.
|
|
Output_section*
|
|
output_section() const;
|
|
|
|
// Set the symbol's output section. This is used for symbols
|
|
// defined in scripts. This should only be called after the symbol
|
|
// table has been finalized.
|
|
void
|
|
set_output_section(Output_section*);
|
|
|
|
// Return whether there should be a warning for references to this
|
|
// symbol.
|
|
bool
|
|
has_warning() const
|
|
{ return this->has_warning_; }
|
|
|
|
// Mark this symbol as having a warning.
|
|
void
|
|
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; }
|
|
|
|
// Return whether this symbol is forced to visibility STB_LOCAL
|
|
// by a "local:" entry in a version script.
|
|
bool
|
|
is_forced_local() const
|
|
{ return this->is_forced_local_; }
|
|
|
|
// Mark this symbol as forced to STB_LOCAL visibility.
|
|
void
|
|
set_is_forced_local()
|
|
{ this->is_forced_local_ = true; }
|
|
|
|
protected:
|
|
// Instances of this class should always be created at a specific
|
|
// size.
|
|
Symbol()
|
|
{ memset(this, 0, sizeof *this); }
|
|
|
|
// Initialize the general fields.
|
|
void
|
|
init_fields(const char* name, const char* version,
|
|
elfcpp::STT type, elfcpp::STB binding,
|
|
elfcpp::STV visibility, unsigned char nonvis);
|
|
|
|
// Initialize fields from an ELF symbol in OBJECT. ST_SHNDX is the
|
|
// section index, IS_ORDINARY is whether it is a normal section
|
|
// index rather than a special code.
|
|
template<int size, bool big_endian>
|
|
void
|
|
init_base_object(const char *name, const char* version, Object* object,
|
|
const elfcpp::Sym<size, big_endian>&, unsigned int st_shndx,
|
|
bool is_ordinary);
|
|
|
|
// Initialize fields for an Output_data.
|
|
void
|
|
init_base_output_data(const char* name, const char* version, Output_data*,
|
|
elfcpp::STT, elfcpp::STB, elfcpp::STV,
|
|
unsigned char nonvis, bool offset_is_from_end);
|
|
|
|
// Initialize fields for an Output_segment.
|
|
void
|
|
init_base_output_segment(const char* name, const char* version,
|
|
Output_segment* os, elfcpp::STT type,
|
|
elfcpp::STB binding, elfcpp::STV visibility,
|
|
unsigned char nonvis,
|
|
Segment_offset_base offset_base);
|
|
|
|
// Initialize fields for a constant.
|
|
void
|
|
init_base_constant(const char* name, const char* version, elfcpp::STT type,
|
|
elfcpp::STB binding, elfcpp::STV visibility,
|
|
unsigned char nonvis);
|
|
|
|
// Initialize fields for an undefined symbol.
|
|
void
|
|
init_base_undefined(const char* name, const char* version, elfcpp::STT type,
|
|
elfcpp::STB binding, elfcpp::STV visibility,
|
|
unsigned char nonvis);
|
|
|
|
// Override existing symbol.
|
|
template<int size, bool big_endian>
|
|
void
|
|
override_base(const elfcpp::Sym<size, big_endian>&, unsigned int st_shndx,
|
|
bool is_ordinary, Object* object, const char* version);
|
|
|
|
// Override existing symbol with a special symbol.
|
|
void
|
|
override_base_with_special(const Symbol* from);
|
|
|
|
// Override symbol version.
|
|
void
|
|
override_version(const char* version);
|
|
|
|
// 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&);
|
|
|
|
// Symbol name (expected to point into a Stringpool).
|
|
const char* name_;
|
|
// Symbol version (expected to point into a Stringpool). This may
|
|
// be NULL.
|
|
const char* version_;
|
|
|
|
union
|
|
{
|
|
// This struct is used if SOURCE_ == FROM_OBJECT.
|
|
struct
|
|
{
|
|
// Object in which symbol is defined, or in which it was first
|
|
// seen.
|
|
Object* object;
|
|
// Section number in object_ in which symbol is defined.
|
|
unsigned int shndx;
|
|
} from_object;
|
|
|
|
// This struct is used if SOURCE_ == IN_OUTPUT_DATA.
|
|
struct
|
|
{
|
|
// Output_data in which symbol is defined. Before
|
|
// Layout::finalize the symbol's value is an offset within the
|
|
// Output_data.
|
|
Output_data* output_data;
|
|
// True if the offset is from the end, false if the offset is
|
|
// from the beginning.
|
|
bool offset_is_from_end;
|
|
} in_output_data;
|
|
|
|
// This struct is used if SOURCE_ == IN_OUTPUT_SEGMENT.
|
|
struct
|
|
{
|
|
// Output_segment in which the symbol is defined. Before
|
|
// Layout::finalize the symbol's value is an offset.
|
|
Output_segment* output_segment;
|
|
// The base to use for the offset before Layout::finalize.
|
|
Segment_offset_base offset_base;
|
|
} in_output_segment;
|
|
} u_;
|
|
|
|
// The index of this symbol in the output file. If the symbol is
|
|
// not going into the output file, this value is -1U. This field
|
|
// starts as always holding zero. It is set to a non-zero value by
|
|
// Symbol_table::finalize.
|
|
unsigned int symtab_index_;
|
|
|
|
// The index of this symbol in the dynamic symbol table. If the
|
|
// symbol is not going into the dynamic symbol table, this value is
|
|
// -1U. This field starts as always holding zero. It is set to a
|
|
// non-zero value during Layout::finalize.
|
|
unsigned int dynsym_index_;
|
|
|
|
// If this symbol has an entry in the GOT section (has_got_offset_
|
|
// is true), this holds the offset from the start of the GOT section.
|
|
// A symbol may have more than one GOT offset (e.g., when mixing
|
|
// modules compiled with two different TLS models), but will usually
|
|
// have at most one.
|
|
Got_offset_list got_offsets_;
|
|
|
|
// 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.
|
|
unsigned int plt_offset_;
|
|
|
|
// Symbol type (bits 0 to 3).
|
|
elfcpp::STT type_ : 4;
|
|
// Symbol binding (bits 4 to 7).
|
|
elfcpp::STB binding_ : 4;
|
|
// Symbol visibility (bits 8 to 9).
|
|
elfcpp::STV visibility_ : 2;
|
|
// Rest of symbol st_other field (bits 10 to 15).
|
|
unsigned int nonvis_ : 6;
|
|
// The type of symbol (bits 16 to 18).
|
|
Source source_ : 3;
|
|
// True if this symbol always requires special target-specific
|
|
// handling (bit 19).
|
|
bool is_target_special_ : 1;
|
|
// True if this is the default version of the symbol (bit 20).
|
|
bool is_def_ : 1;
|
|
// True if this symbol really forwards to another symbol. This is
|
|
// used when we discover after the fact that two different entries
|
|
// in the hash table really refer to the same symbol. This will
|
|
// never be set for a symbol found in the hash table, but may be set
|
|
// for a symbol found in the list of symbols attached to an Object.
|
|
// It forwards to the symbol found in the forwarders_ map of
|
|
// Symbol_table (bit 21).
|
|
bool is_forwarder_ : 1;
|
|
// True if the symbol has an alias in the weak_aliases table in
|
|
// Symbol_table (bit 22).
|
|
bool has_alias_ : 1;
|
|
// True if this symbol needs to be in the dynamic symbol table (bit
|
|
// 23).
|
|
bool needs_dynsym_entry_ : 1;
|
|
// True if we've seen this symbol in a regular object (bit 24).
|
|
bool in_reg_ : 1;
|
|
// True if we've seen this symbol in a dynamic object (bit 25).
|
|
bool in_dyn_ : 1;
|
|
// True if the symbol has an entry in the PLT section (bit 26).
|
|
bool has_plt_offset_ : 1;
|
|
// True if this is a dynamic symbol which needs a special value in
|
|
// the dynamic symbol table (bit 27).
|
|
bool needs_dynsym_value_ : 1;
|
|
// True if there is a warning for this symbol (bit 28).
|
|
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 (bit 29).
|
|
bool is_copied_from_dynobj_ : 1;
|
|
// True if this symbol was forced to local visibility by a version
|
|
// script (bit 30).
|
|
bool is_forced_local_ : 1;
|
|
// True if the field u_.from_object.shndx is an ordinary section
|
|
// index, not one of the special codes from SHN_LORESERVE to
|
|
// SHN_HIRESERVE (bit 31).
|
|
bool is_ordinary_shndx_ : 1;
|
|
// True if we've seen this symbol in a real ELF object.
|
|
bool in_real_elf_ : 1;
|
|
};
|
|
|
|
// The parts of a symbol which are size specific. Using a template
|
|
// derived class like this helps us use less space on a 32-bit system.
|
|
|
|
template<int size>
|
|
class Sized_symbol : public Symbol
|
|
{
|
|
public:
|
|
typedef typename elfcpp::Elf_types<size>::Elf_Addr Value_type;
|
|
typedef typename elfcpp::Elf_types<size>::Elf_WXword Size_type;
|
|
|
|
Sized_symbol()
|
|
{ }
|
|
|
|
// Initialize fields from an ELF symbol in OBJECT. ST_SHNDX is the
|
|
// section index, IS_ORDINARY is whether it is a normal section
|
|
// index rather than a special code.
|
|
template<bool big_endian>
|
|
void
|
|
init_object(const char *name, const char* version, Object* object,
|
|
const elfcpp::Sym<size, big_endian>&, unsigned int st_shndx,
|
|
bool is_ordinary);
|
|
|
|
// Initialize fields for an Output_data.
|
|
void
|
|
init_output_data(const char* name, const char* version, Output_data*,
|
|
Value_type value, Size_type symsize, elfcpp::STT,
|
|
elfcpp::STB, elfcpp::STV, unsigned char nonvis,
|
|
bool offset_is_from_end);
|
|
|
|
// Initialize fields for an Output_segment.
|
|
void
|
|
init_output_segment(const char* name, const char* version, Output_segment*,
|
|
Value_type value, Size_type symsize, elfcpp::STT,
|
|
elfcpp::STB, elfcpp::STV, unsigned char nonvis,
|
|
Segment_offset_base offset_base);
|
|
|
|
// Initialize fields for a constant.
|
|
void
|
|
init_constant(const char* name, const char* version, Value_type value,
|
|
Size_type symsize, elfcpp::STT, elfcpp::STB, elfcpp::STV,
|
|
unsigned char nonvis);
|
|
|
|
// Initialize fields for an undefined symbol.
|
|
void
|
|
init_undefined(const char* name, const char* version, elfcpp::STT,
|
|
elfcpp::STB, elfcpp::STV, unsigned char nonvis);
|
|
|
|
// Override existing symbol.
|
|
template<bool big_endian>
|
|
void
|
|
override(const elfcpp::Sym<size, big_endian>&, unsigned int st_shndx,
|
|
bool is_ordinary, Object* object, const char* version);
|
|
|
|
// Override existing symbol with a special symbol.
|
|
void
|
|
override_with_special(const Sized_symbol<size>*);
|
|
|
|
// Return the symbol's value.
|
|
Value_type
|
|
value() const
|
|
{ return this->value_; }
|
|
|
|
// Return the symbol's size (we can't call this 'size' because that
|
|
// is a template parameter).
|
|
Size_type
|
|
symsize() const
|
|
{ return this->symsize_; }
|
|
|
|
// Set the symbol size. This is used when resolving common symbols.
|
|
void
|
|
set_symsize(Size_type symsize)
|
|
{ this->symsize_ = symsize; }
|
|
|
|
// Set the symbol value. This is called when we store the final
|
|
// values of the symbols into the symbol table.
|
|
void
|
|
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&);
|
|
|
|
// Symbol value. Before Layout::finalize this is the offset in the
|
|
// input section. This is set to the final value during
|
|
// Layout::finalize.
|
|
Value_type value_;
|
|
// Symbol size.
|
|
Size_type symsize_;
|
|
};
|
|
|
|
// A struct describing a symbol defined by the linker, where the value
|
|
// of the symbol is defined based on an output section. This is used
|
|
// for symbols defined by the linker, like "_init_array_start".
|
|
|
|
struct Define_symbol_in_section
|
|
{
|
|
// The symbol name.
|
|
const char* name;
|
|
// The name of the output section with which this symbol should be
|
|
// associated. If there is no output section with that name, the
|
|
// symbol will be defined as zero.
|
|
const char* output_section;
|
|
// The offset of the symbol within the output section. This is an
|
|
// offset from the start of the output section, unless start_at_end
|
|
// is true, in which case this is an offset from the end of the
|
|
// output section.
|
|
uint64_t value;
|
|
// The size of the symbol.
|
|
uint64_t size;
|
|
// The symbol type.
|
|
elfcpp::STT type;
|
|
// The symbol binding.
|
|
elfcpp::STB binding;
|
|
// The symbol visibility.
|
|
elfcpp::STV visibility;
|
|
// The rest of the st_other field.
|
|
unsigned char nonvis;
|
|
// If true, the value field is an offset from the end of the output
|
|
// section.
|
|
bool offset_is_from_end;
|
|
// If true, this symbol is defined only if we see a reference to it.
|
|
bool only_if_ref;
|
|
};
|
|
|
|
// A struct describing a symbol defined by the linker, where the value
|
|
// of the symbol is defined based on a segment. This is used for
|
|
// symbols defined by the linker, like "_end". We describe the
|
|
// segment with which the symbol should be associated by its
|
|
// characteristics. If no segment meets these characteristics, the
|
|
// symbol will be defined as zero. If there is more than one segment
|
|
// which meets these characteristics, we will use the first one.
|
|
|
|
struct Define_symbol_in_segment
|
|
{
|
|
// The symbol name.
|
|
const char* name;
|
|
// The segment type where the symbol should be defined, typically
|
|
// PT_LOAD.
|
|
elfcpp::PT segment_type;
|
|
// Bitmask of segment flags which must be set.
|
|
elfcpp::PF segment_flags_set;
|
|
// Bitmask of segment flags which must be clear.
|
|
elfcpp::PF segment_flags_clear;
|
|
// The offset of the symbol within the segment. The offset is
|
|
// calculated from the position set by offset_base.
|
|
uint64_t value;
|
|
// The size of the symbol.
|
|
uint64_t size;
|
|
// The symbol type.
|
|
elfcpp::STT type;
|
|
// The symbol binding.
|
|
elfcpp::STB binding;
|
|
// The symbol visibility.
|
|
elfcpp::STV visibility;
|
|
// The rest of the st_other field.
|
|
unsigned char nonvis;
|
|
// The base from which we compute the offset.
|
|
Symbol::Segment_offset_base offset_base;
|
|
// If true, this symbol is defined only if we see a reference to it.
|
|
bool only_if_ref;
|
|
};
|
|
|
|
// This class manages warnings. Warnings are a GNU extension. When
|
|
// we see a section named .gnu.warning.SYM in an object file, and if
|
|
// we wind using the definition of SYM from that object file, then we
|
|
// will issue a warning for any relocation against SYM from a
|
|
// different object file. The text of the warning is the contents of
|
|
// the section. This is not precisely the definition used by the old
|
|
// GNU linker; the old GNU linker treated an occurrence of
|
|
// .gnu.warning.SYM as defining a warning symbol. A warning symbol
|
|
// would trigger a warning on any reference. However, it was
|
|
// inconsistent in that a warning in a dynamic object only triggered
|
|
// if there was no definition in a regular object. This linker is
|
|
// different in that we only issue a warning if we use the symbol
|
|
// definition from the same object file as the warning section.
|
|
|
|
class Warnings
|
|
{
|
|
public:
|
|
Warnings()
|
|
: warnings_()
|
|
{ }
|
|
|
|
// 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,
|
|
const std::string& warning);
|
|
|
|
// For each symbol for which we should give a warning, make a note
|
|
// on the symbol.
|
|
void
|
|
note_warnings(Symbol_table* symtab);
|
|
|
|
// Issue a warning for a reference to SYM at RELINFO's location.
|
|
template<int size, bool big_endian>
|
|
void
|
|
issue_warning(const Symbol* sym, const Relocate_info<size, big_endian>*,
|
|
size_t relnum, off_t reloffset) const;
|
|
|
|
private:
|
|
Warnings(const Warnings&);
|
|
Warnings& operator=(const Warnings&);
|
|
|
|
// What we need to know to get the warning text.
|
|
struct Warning_location
|
|
{
|
|
// The object the warning is in.
|
|
Object* object;
|
|
// The warning text.
|
|
std::string text;
|
|
|
|
Warning_location()
|
|
: object(NULL), text()
|
|
{ }
|
|
|
|
void
|
|
set(Object* o, const std::string& t)
|
|
{
|
|
this->object = o;
|
|
this->text = t;
|
|
}
|
|
};
|
|
|
|
// A mapping from warning symbol names (canonicalized in
|
|
// Symbol_table's namepool_ field) to warning information.
|
|
typedef Unordered_map<const char*, Warning_location> Warning_table;
|
|
|
|
Warning_table warnings_;
|
|
};
|
|
|
|
// The main linker symbol table.
|
|
|
|
class Symbol_table
|
|
{
|
|
public:
|
|
// 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, const Version_script_info& version_script);
|
|
|
|
~Symbol_table();
|
|
|
|
void
|
|
set_gc(Garbage_collection* gc)
|
|
{ this->gc_ = gc; }
|
|
|
|
Garbage_collection*
|
|
gc()
|
|
{ return this->gc_; }
|
|
|
|
// During garbage collection, this keeps undefined symbols.
|
|
void
|
|
gc_mark_undef_symbols();
|
|
|
|
// During garbage collection, this ensures externally visible symbols
|
|
// are not treated as garbage while building shared objects.
|
|
void
|
|
gc_mark_symbol_for_shlib(Symbol* sym);
|
|
|
|
// During garbage collection, this keeps sections that correspond to
|
|
// symbols seen in dynamic objects.
|
|
inline void
|
|
gc_mark_dyn_syms(Symbol* sym);
|
|
|
|
// Add COUNT external symbols from the relocatable object RELOBJ to
|
|
// the symbol table. SYMS is the symbols, SYMNDX_OFFSET is the
|
|
// offset in the symbol table of the first symbol, SYM_NAMES is
|
|
// their names, SYM_NAME_SIZE is the size of SYM_NAMES. This sets
|
|
// SYMPOINTERS to point to the symbols in the symbol table. It sets
|
|
// *DEFINED to the number of defined symbols.
|
|
template<int size, bool big_endian>
|
|
void
|
|
add_from_relobj(Sized_relobj<size, big_endian>* relobj,
|
|
const unsigned char* syms, size_t count,
|
|
size_t symndx_offset, const char* sym_names,
|
|
size_t sym_name_size,
|
|
typename Sized_relobj<size, big_endian>::Symbols*,
|
|
size_t* defined);
|
|
|
|
// Add one external symbol from the plugin object OBJ to the symbol table.
|
|
// Returns a pointer to the resolved symbol in the symbol table.
|
|
template<int size, bool big_endian>
|
|
Symbol*
|
|
add_from_pluginobj(Sized_pluginobj<size, big_endian>* obj,
|
|
const char* name, const char* ver,
|
|
elfcpp::Sym<size, big_endian>* sym);
|
|
|
|
// Add COUNT dynamic symbols from the dynamic object DYNOBJ to the
|
|
// symbol table. SYMS is the symbols. SYM_NAMES is their names.
|
|
// SYM_NAME_SIZE is the size of SYM_NAMES. The other parameters are
|
|
// symbol version data.
|
|
template<int size, bool big_endian>
|
|
void
|
|
add_from_dynobj(Sized_dynobj<size, big_endian>* dynobj,
|
|
const unsigned char* syms, size_t count,
|
|
const char* sym_names, size_t sym_name_size,
|
|
const unsigned char* versym, size_t versym_size,
|
|
const std::vector<const char*>*,
|
|
typename Sized_relobj<size, big_endian>::Symbols*,
|
|
size_t* defined);
|
|
|
|
// Define a special symbol based on an Output_data. It is a
|
|
// multiple definition error if this symbol is already defined.
|
|
Symbol*
|
|
define_in_output_data(const char* name, const char* version,
|
|
Output_data*, uint64_t value, uint64_t symsize,
|
|
elfcpp::STT type, elfcpp::STB binding,
|
|
elfcpp::STV visibility, unsigned char nonvis,
|
|
bool offset_is_from_end, bool only_if_ref);
|
|
|
|
// Define a special symbol based on an Output_segment. It is a
|
|
// multiple definition error if this symbol is already defined.
|
|
Symbol*
|
|
define_in_output_segment(const char* name, const char* version,
|
|
Output_segment*, uint64_t value, uint64_t symsize,
|
|
elfcpp::STT type, elfcpp::STB binding,
|
|
elfcpp::STV visibility, unsigned char nonvis,
|
|
Symbol::Segment_offset_base, bool only_if_ref);
|
|
|
|
// Define a special symbol with a constant value. It is a multiple
|
|
// definition error if this symbol is already defined.
|
|
Symbol*
|
|
define_as_constant(const char* name, const char* version,
|
|
uint64_t value, uint64_t symsize, elfcpp::STT type,
|
|
elfcpp::STB binding, elfcpp::STV visibility,
|
|
unsigned char nonvis, bool only_if_ref,
|
|
bool force_override);
|
|
|
|
// Define a set of symbols in output sections. If ONLY_IF_REF is
|
|
// true, only define them if they are referenced.
|
|
void
|
|
define_symbols(const Layout*, int count, const Define_symbol_in_section*,
|
|
bool only_if_ref);
|
|
|
|
// Define a set of symbols in output segments. If ONLY_IF_REF is
|
|
// true, only defined them if they are referenced.
|
|
void
|
|
define_symbols(const Layout*, int count, const Define_symbol_in_segment*,
|
|
bool only_if_ref);
|
|
|
|
// 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(Sized_symbol<size>* sym, Output_data* posd,
|
|
typename elfcpp::Elf_types<size>::Elf_Addr);
|
|
|
|
// Look up a symbol.
|
|
Symbol*
|
|
lookup(const char*, const char* version = NULL) const;
|
|
|
|
// Return the real symbol associated with the forwarder symbol FROM.
|
|
Symbol*
|
|
resolve_forwards(const Symbol* from) const;
|
|
|
|
// Return the sized version of a symbol in this table.
|
|
template<int size>
|
|
Sized_symbol<size>*
|
|
get_sized_symbol(Symbol*) const;
|
|
|
|
template<int size>
|
|
const Sized_symbol<size>*
|
|
get_sized_symbol(const Symbol*) const;
|
|
|
|
// Return the count of undefined symbols seen.
|
|
int
|
|
saw_undefined() const
|
|
{ return this->saw_undefined_; }
|
|
|
|
// Allocate the common symbols
|
|
void
|
|
allocate_commons(Layout*, Mapfile*);
|
|
|
|
// Add a warning for symbol NAME in object OBJ. WARNING is the text
|
|
// of the warning.
|
|
void
|
|
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*
|
|
canonicalize_name(const char* name)
|
|
{ return this->namepool_.add(name, true, NULL); }
|
|
|
|
// Possibly issue a warning for a reference to SYM at LOCATION which
|
|
// is in OBJ.
|
|
template<int size, bool big_endian>
|
|
void
|
|
issue_warning(const Symbol* sym,
|
|
const Relocate_info<size, big_endian>* relinfo,
|
|
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;
|
|
|
|
// Add any undefined symbols named on the command line to the symbol
|
|
// table.
|
|
void
|
|
add_undefined_symbols_from_command_line();
|
|
|
|
// 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(unsigned int index, std::vector<Symbol*>*,
|
|
Stringpool*, Versions*);
|
|
|
|
// Finalize the symbol table after we have set the final addresses
|
|
// of all the input sections. This sets the final symbol indexes,
|
|
// values and adds the names to *POOL. *PLOCAL_SYMCOUNT is the
|
|
// index of the first global symbol. OFF is the file offset of the
|
|
// global symbol table, DYNOFF is the offset of the globals in the
|
|
// dynamic symbol table, DYN_GLOBAL_INDEX is the index of the first
|
|
// global dynamic symbol, and DYNCOUNT is the number of global
|
|
// dynamic symbols. This records the parameters, and returns the
|
|
// new file offset. It updates *PLOCAL_SYMCOUNT if it created any
|
|
// local symbols.
|
|
off_t
|
|
finalize(off_t off, off_t dynoff, size_t dyn_global_index, size_t dyncount,
|
|
Stringpool* pool, unsigned int *plocal_symcount);
|
|
|
|
// Write out the global symbols.
|
|
void
|
|
write_globals(const Stringpool*, const Stringpool*,
|
|
Output_symtab_xindex*, Output_symtab_xindex*,
|
|
Output_file*) const;
|
|
|
|
// Write out a section symbol. Return the updated offset.
|
|
void
|
|
write_section_symbol(const Output_section*, Output_symtab_xindex*,
|
|
Output_file*, off_t) const;
|
|
|
|
// Dump statistical information to stderr.
|
|
void
|
|
print_stats() const;
|
|
|
|
// Return the version script information.
|
|
const Version_script_info&
|
|
version_script() const
|
|
{ return version_script_; }
|
|
|
|
private:
|
|
Symbol_table(const Symbol_table&);
|
|
Symbol_table& operator=(const Symbol_table&);
|
|
|
|
// The type of the list of common symbols.
|
|
typedef std::vector<Symbol*> Commons_type;
|
|
|
|
// The type of the symbol hash table.
|
|
|
|
typedef std::pair<Stringpool::Key, Stringpool::Key> Symbol_table_key;
|
|
|
|
struct Symbol_table_hash
|
|
{
|
|
size_t
|
|
operator()(const Symbol_table_key&) const;
|
|
};
|
|
|
|
struct Symbol_table_eq
|
|
{
|
|
bool
|
|
operator()(const Symbol_table_key&, const Symbol_table_key&) const;
|
|
};
|
|
|
|
typedef Unordered_map<Symbol_table_key, Symbol*, Symbol_table_hash,
|
|
Symbol_table_eq> Symbol_table_type;
|
|
|
|
// Make FROM a forwarder symbol to TO.
|
|
void
|
|
make_forwarder(Symbol* from, Symbol* to);
|
|
|
|
// Add a symbol.
|
|
template<int size, bool big_endian>
|
|
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,
|
|
unsigned int st_shndx, bool is_ordinary,
|
|
unsigned int orig_st_shndx);
|
|
|
|
// Define a default symbol.
|
|
template<int size, bool big_endian>
|
|
void
|
|
define_default_version(Sized_symbol<size>*, bool,
|
|
Symbol_table_type::iterator);
|
|
|
|
// Resolve symbols.
|
|
template<int size, bool big_endian>
|
|
void
|
|
resolve(Sized_symbol<size>* to,
|
|
const elfcpp::Sym<size, big_endian>& sym,
|
|
unsigned int st_shndx, bool is_ordinary,
|
|
unsigned int orig_st_shndx,
|
|
Object*, const char* version);
|
|
|
|
template<int size, bool big_endian>
|
|
void
|
|
resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from);
|
|
|
|
// Record that a symbol is forced to be local by a version script or
|
|
// by visibility.
|
|
void
|
|
force_local(Symbol*);
|
|
|
|
// Adjust NAME and *NAME_KEY for wrapping.
|
|
const char*
|
|
wrap_symbol(Object* object, const char*, Stringpool::Key* name_key);
|
|
|
|
// Whether we should override a symbol, based on flags in
|
|
// resolve.cc.
|
|
static bool
|
|
should_override(const Symbol*, unsigned int, Object*, bool*);
|
|
|
|
// Override a symbol.
|
|
template<int size, bool big_endian>
|
|
void
|
|
override(Sized_symbol<size>* tosym,
|
|
const elfcpp::Sym<size, big_endian>& fromsym,
|
|
unsigned int st_shndx, bool is_ordinary,
|
|
Object* object, const char* version);
|
|
|
|
// Whether we should override a symbol with a special symbol which
|
|
// is automatically defined by the linker.
|
|
static bool
|
|
should_override_with_special(const Symbol*);
|
|
|
|
// Override a symbol with a special symbol.
|
|
template<int size>
|
|
void
|
|
override_with_special(Sized_symbol<size>* tosym,
|
|
const Sized_symbol<size>* fromsym);
|
|
|
|
// Record all weak alias sets for a dynamic object.
|
|
template<int size>
|
|
void
|
|
record_weak_aliases(std::vector<Sized_symbol<size>*>*);
|
|
|
|
// Define a special symbol.
|
|
template<int size, bool big_endian>
|
|
Sized_symbol<size>*
|
|
define_special_symbol(const char** pname, const char** pversion,
|
|
bool only_if_ref, Sized_symbol<size>** poldsym,
|
|
bool* resolve_oldsym);
|
|
|
|
// Define a symbol in an Output_data, sized version.
|
|
template<int size>
|
|
Sized_symbol<size>*
|
|
do_define_in_output_data(const char* name, const char* version, Output_data*,
|
|
typename elfcpp::Elf_types<size>::Elf_Addr value,
|
|
typename elfcpp::Elf_types<size>::Elf_WXword ssize,
|
|
elfcpp::STT type, elfcpp::STB binding,
|
|
elfcpp::STV visibility, unsigned char nonvis,
|
|
bool offset_is_from_end, bool only_if_ref);
|
|
|
|
// Define a symbol in an Output_segment, sized version.
|
|
template<int size>
|
|
Sized_symbol<size>*
|
|
do_define_in_output_segment(
|
|
const char* name, const char* version, Output_segment* os,
|
|
typename elfcpp::Elf_types<size>::Elf_Addr value,
|
|
typename elfcpp::Elf_types<size>::Elf_WXword ssize,
|
|
elfcpp::STT type, elfcpp::STB binding,
|
|
elfcpp::STV visibility, unsigned char nonvis,
|
|
Symbol::Segment_offset_base offset_base, bool only_if_ref);
|
|
|
|
// Define a symbol as a constant, sized version.
|
|
template<int size>
|
|
Sized_symbol<size>*
|
|
do_define_as_constant(
|
|
const char* name, const char* version,
|
|
typename elfcpp::Elf_types<size>::Elf_Addr value,
|
|
typename elfcpp::Elf_types<size>::Elf_WXword ssize,
|
|
elfcpp::STT type, elfcpp::STB binding,
|
|
elfcpp::STV visibility, unsigned char nonvis,
|
|
bool only_if_ref, bool force_override);
|
|
|
|
// Add any undefined symbols named on the command line to the symbol
|
|
// table, sized version.
|
|
template<int size>
|
|
void
|
|
do_add_undefined_symbols_from_command_line();
|
|
|
|
// Types of common symbols.
|
|
|
|
enum Commons_section_type
|
|
{
|
|
COMMONS_NORMAL,
|
|
COMMONS_TLS,
|
|
COMMONS_SMALL,
|
|
COMMONS_LARGE
|
|
};
|
|
|
|
// Allocate the common symbols, sized version.
|
|
template<int size>
|
|
void
|
|
do_allocate_commons(Layout*, Mapfile*);
|
|
|
|
// Allocate the common symbols from one list.
|
|
template<int size>
|
|
void
|
|
do_allocate_commons_list(Layout*, Commons_section_type, Commons_type*,
|
|
Mapfile*);
|
|
|
|
// 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
|
|
sized_finalize(off_t, Stringpool*, unsigned int*);
|
|
|
|
// Finalize a symbol. Return whether it should be added to the
|
|
// symbol table.
|
|
template<int size>
|
|
bool
|
|
sized_finalize_symbol(Symbol*);
|
|
|
|
// Add a symbol the final symtab by setting its index.
|
|
template<int size>
|
|
void
|
|
add_to_final_symtab(Symbol*, Stringpool*, unsigned int* pindex, off_t* poff);
|
|
|
|
// Write globals specialized for size and endianness.
|
|
template<int size, bool big_endian>
|
|
void
|
|
sized_write_globals(const Stringpool*, const Stringpool*,
|
|
Output_symtab_xindex*, Output_symtab_xindex*,
|
|
Output_file*) const;
|
|
|
|
// Write out a symbol to P.
|
|
template<int size, bool big_endian>
|
|
void
|
|
sized_write_symbol(Sized_symbol<size>*,
|
|
typename elfcpp::Elf_types<size>::Elf_Addr value,
|
|
unsigned int shndx,
|
|
const Stringpool*, unsigned char* p) const;
|
|
|
|
// Possibly warn about an undefined symbol from a dynamic object.
|
|
void
|
|
warn_about_undefined_dynobj_symbol(Symbol*) const;
|
|
|
|
// Write out a section symbol, specialized for size and endianness.
|
|
template<int size, bool big_endian>
|
|
void
|
|
sized_write_section_symbol(const Output_section*, Output_symtab_xindex*,
|
|
Output_file*, off_t) const;
|
|
|
|
// The type of the list of symbols which have been forced local.
|
|
typedef std::vector<Symbol*> Forced_locals;
|
|
|
|
// 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.
|
|
unsigned int 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.
|
|
unsigned int 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_;
|
|
// This is like the commons_ field, except that it holds TLS common
|
|
// symbols.
|
|
Commons_type tls_commons_;
|
|
// This is for small common symbols.
|
|
Commons_type small_commons_;
|
|
// This is for large common symbols.
|
|
Commons_type large_commons_;
|
|
// A list of symbols which have been forced to be local. We don't
|
|
// expect there to be very many of them, so we keep a list of them
|
|
// rather than walking the whole table to find them.
|
|
Forced_locals forced_locals_;
|
|
// 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_;
|
|
// Information parsed from the version script, if any.
|
|
const Version_script_info& version_script_;
|
|
Garbage_collection* gc_;
|
|
};
|
|
|
|
// We inline get_sized_symbol for efficiency.
|
|
|
|
template<int size>
|
|
Sized_symbol<size>*
|
|
Symbol_table::get_sized_symbol(Symbol* sym) const
|
|
{
|
|
gold_assert(size == parameters->target().get_size());
|
|
return static_cast<Sized_symbol<size>*>(sym);
|
|
}
|
|
|
|
template<int size>
|
|
const Sized_symbol<size>*
|
|
Symbol_table::get_sized_symbol(const Symbol* sym) const
|
|
{
|
|
gold_assert(size == parameters->target().get_size());
|
|
return static_cast<const Sized_symbol<size>*>(sym);
|
|
}
|
|
|
|
} // End namespace gold.
|
|
|
|
#endif // !defined(GOLD_SYMTAB_H)
|