#include "gold.h"
#include "elfcpp.h"
#include "target.h"
#include "object.h"
#include "symtab.h"
namespace gold
{
inline void
Symbol::override_version(const char* version)
{
if (version == NULL)
{
this->version_ = version;
}
else
{
gold_assert(this->version_ == version || this->version_ == NULL);
this->version_ = version;
}
}
template<int size, bool big_endian>
void
Symbol::override_base(const elfcpp::Sym<size, big_endian>& sym,
unsigned int st_shndx, bool is_ordinary,
Object* object, const char* version)
{
gold_assert(this->source_ == FROM_OBJECT);
this->u_.from_object.object = object;
this->override_version(version);
this->u_.from_object.shndx = st_shndx;
this->is_ordinary_shndx_ = is_ordinary;
this->type_ = sym.get_st_type();
this->binding_ = sym.get_st_bind();
this->visibility_ = sym.get_st_visibility();
this->nonvis_ = sym.get_st_nonvis();
if (object->is_dynamic())
this->in_dyn_ = true;
else
this->in_reg_ = true;
}
template<int size>
template<bool big_endian>
void
Sized_symbol<size>::override(const elfcpp::Sym<size, big_endian>& sym,
unsigned st_shndx, bool is_ordinary,
Object* object, const char* version)
{
this->override_base(sym, st_shndx, is_ordinary, object, version);
this->value_ = sym.get_st_value();
this->symsize_ = sym.get_st_size();
}
template<int size, bool big_endian>
void
Symbol_table::override(Sized_symbol<size>* tosym,
const elfcpp::Sym<size, big_endian>& fromsym,
unsigned int st_shndx, bool is_ordinary,
Object* object, const char* version)
{
tosym->override(fromsym, st_shndx, is_ordinary, object, version);
if (tosym->has_alias())
{
Symbol* sym = this->weak_aliases_[tosym];
gold_assert(sym != NULL);
Sized_symbol<size>* ssym = this->get_sized_symbol<size>(sym);
do
{
ssym->override(fromsym, st_shndx, is_ordinary, object, version);
sym = this->weak_aliases_[ssym];
gold_assert(sym != NULL);
ssym = this->get_sized_symbol<size>(sym);
}
while (ssym != tosym);
}
}
static const int global_or_weak_shift = 0;
static const unsigned int global_flag = 0 << global_or_weak_shift;
static const unsigned int weak_flag = 1 << global_or_weak_shift;
static const int regular_or_dynamic_shift = 1;
static const unsigned int regular_flag = 0 << regular_or_dynamic_shift;
static const unsigned int dynamic_flag = 1 << regular_or_dynamic_shift;
static const int def_undef_or_common_shift = 2;
static const unsigned int def_flag = 0 << def_undef_or_common_shift;
static const unsigned int undef_flag = 1 << def_undef_or_common_shift;
static const unsigned int common_flag = 2 << def_undef_or_common_shift;
static unsigned int
symbol_to_bits(elfcpp::STB binding, bool is_dynamic,
unsigned int shndx, bool is_ordinary, elfcpp::STT type)
{
unsigned int bits;
switch (binding)
{
case elfcpp::STB_GLOBAL:
bits = global_flag;
break;
case elfcpp::STB_WEAK:
bits = weak_flag;
break;
case elfcpp::STB_LOCAL:
gold_error(_("invalid STB_LOCAL symbol in external symbols"));
bits = global_flag;
default:
gold_error(_("unsupported symbol binding"));
bits = global_flag;
}
if (is_dynamic)
bits |= dynamic_flag;
else
bits |= regular_flag;
switch (shndx)
{
case elfcpp::SHN_UNDEF:
bits |= undef_flag;
break;
case elfcpp::SHN_COMMON:
if (!is_ordinary)
bits |= common_flag;
break;
default:
if (type == elfcpp::STT_COMMON)
bits |= common_flag;
else
bits |= def_flag;
break;
}
return bits;
}
template<int size, bool big_endian>
void
Symbol_table::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* object, const char* version)
{
if (object->target()->has_resolve())
{
Sized_target<size, big_endian>* sized_target;
sized_target = object->sized_target<size, big_endian>();
sized_target->resolve(to, sym, object, version);
return;
}
if (!object->is_dynamic())
{
to->set_in_reg();
}
else
{
to->set_in_dyn();
}
unsigned int frombits = symbol_to_bits(sym.get_st_bind(),
object->is_dynamic(),
st_shndx, is_ordinary,
sym.get_st_type());
bool adjust_common_sizes;
if (Symbol_table::should_override(to, frombits, object,
&adjust_common_sizes))
{
typename Sized_symbol<size>::Size_type tosize = to->symsize();
this->override(to, sym, st_shndx, is_ordinary, object, version);
if (adjust_common_sizes && tosize > to->symsize())
to->set_symsize(tosize);
}
else
{
if (adjust_common_sizes && sym.get_st_size() > to->symsize())
to->set_symsize(sym.get_st_size());
}
bool to_is_ordinary;
if (parameters->options().detect_odr_violations()
&& sym.get_st_bind() == elfcpp::STB_WEAK
&& to->binding() == elfcpp::STB_WEAK
&& orig_st_shndx != elfcpp::SHN_UNDEF
&& to->shndx(&to_is_ordinary) != elfcpp::SHN_UNDEF
&& to_is_ordinary
&& sym.get_st_size() != 0
&& to->symsize() != 0
&& (sym.get_st_type() != to->type()
|| sym.get_st_size() != to->symsize())
&& to->name()[0] == '_' && to->name()[1] == 'Z')
{
Symbol_location fromloc
= { object, orig_st_shndx, sym.get_st_value() };
Symbol_location toloc = { to->object(), to->shndx(&to_is_ordinary),
to->value() };
this->candidate_odr_violations_[to->name()].insert(fromloc);
this->candidate_odr_violations_[to->name()].insert(toloc);
}
}
bool
Symbol_table::should_override(const Symbol* to, unsigned int frombits,
Object* object, bool* adjust_common_sizes)
{
*adjust_common_sizes = false;
unsigned int tobits;
if (to->source() == Symbol::IS_UNDEFINED)
tobits = symbol_to_bits(to->binding(), false, elfcpp::SHN_UNDEF, true,
to->type());
else if (to->source() != Symbol::FROM_OBJECT)
tobits = symbol_to_bits(to->binding(), false, elfcpp::SHN_ABS, false,
to->type());
else
{
bool is_ordinary;
unsigned int shndx = to->shndx(&is_ordinary);
tobits = symbol_to_bits(to->binding(),
to->object()->is_dynamic(),
shndx,
is_ordinary,
to->type());
}
enum
{
DEF = global_flag | regular_flag | def_flag,
WEAK_DEF = weak_flag | regular_flag | def_flag,
DYN_DEF = global_flag | dynamic_flag | def_flag,
DYN_WEAK_DEF = weak_flag | dynamic_flag | def_flag,
UNDEF = global_flag | regular_flag | undef_flag,
WEAK_UNDEF = weak_flag | regular_flag | undef_flag,
DYN_UNDEF = global_flag | dynamic_flag | undef_flag,
DYN_WEAK_UNDEF = weak_flag | dynamic_flag | undef_flag,
COMMON = global_flag | regular_flag | common_flag,
WEAK_COMMON = weak_flag | regular_flag | common_flag,
DYN_COMMON = global_flag | dynamic_flag | common_flag,
DYN_WEAK_COMMON = weak_flag | dynamic_flag | common_flag
};
switch (tobits * 16 + frombits)
{
case DEF * 16 + DEF:
if ((to->source() == Symbol::FROM_OBJECT && to->object()->just_symbols())
|| object->just_symbols())
return false;
gold_error(_("%s: multiple definition of %s"),
object != NULL ? object->name().c_str() : _("command line"),
to->demangled_name().c_str());
gold_error(_("%s: previous definition here"),
(to->source() == Symbol::FROM_OBJECT
? to->object()->name().c_str()
: _("command line")));
return false;
case WEAK_DEF * 16 + DEF:
return true;
case DYN_DEF * 16 + DEF:
case DYN_WEAK_DEF * 16 + DEF:
return true;
case UNDEF * 16 + DEF:
case WEAK_UNDEF * 16 + DEF:
case DYN_UNDEF * 16 + DEF:
case DYN_WEAK_UNDEF * 16 + DEF:
return true;
case COMMON * 16 + DEF:
case WEAK_COMMON * 16 + DEF:
case DYN_COMMON * 16 + DEF:
case DYN_WEAK_COMMON * 16 + DEF:
return true;
case DEF * 16 + WEAK_DEF:
case WEAK_DEF * 16 + WEAK_DEF:
return false;
case DYN_DEF * 16 + WEAK_DEF:
case DYN_WEAK_DEF * 16 + WEAK_DEF:
return true;
case UNDEF * 16 + WEAK_DEF:
case WEAK_UNDEF * 16 + WEAK_DEF:
case DYN_UNDEF * 16 + WEAK_DEF:
case DYN_WEAK_UNDEF * 16 + WEAK_DEF:
return true;
case COMMON * 16 + WEAK_DEF:
case WEAK_COMMON * 16 + WEAK_DEF:
return false;
case DYN_COMMON * 16 + WEAK_DEF:
case DYN_WEAK_COMMON * 16 + WEAK_DEF:
return true;
case DEF * 16 + DYN_DEF:
case WEAK_DEF * 16 + DYN_DEF:
case DYN_DEF * 16 + DYN_DEF:
case DYN_WEAK_DEF * 16 + DYN_DEF:
return false;
case UNDEF * 16 + DYN_DEF:
case WEAK_UNDEF * 16 + DYN_DEF:
case DYN_UNDEF * 16 + DYN_DEF:
case DYN_WEAK_UNDEF * 16 + DYN_DEF:
return true;
case COMMON * 16 + DYN_DEF:
case WEAK_COMMON * 16 + DYN_DEF:
case DYN_COMMON * 16 + DYN_DEF:
case DYN_WEAK_COMMON * 16 + DYN_DEF:
return false;
case DEF * 16 + DYN_WEAK_DEF:
case WEAK_DEF * 16 + DYN_WEAK_DEF:
case DYN_DEF * 16 + DYN_WEAK_DEF:
case DYN_WEAK_DEF * 16 + DYN_WEAK_DEF:
return false;
case UNDEF * 16 + DYN_WEAK_DEF:
case WEAK_UNDEF * 16 + DYN_WEAK_DEF:
case DYN_UNDEF * 16 + DYN_WEAK_DEF:
case DYN_WEAK_UNDEF * 16 + DYN_WEAK_DEF:
return true;
case COMMON * 16 + DYN_WEAK_DEF:
case WEAK_COMMON * 16 + DYN_WEAK_DEF:
case DYN_COMMON * 16 + DYN_WEAK_DEF:
case DYN_WEAK_COMMON * 16 + DYN_WEAK_DEF:
return false;
case DEF * 16 + UNDEF:
case WEAK_DEF * 16 + UNDEF:
case DYN_DEF * 16 + UNDEF:
case DYN_WEAK_DEF * 16 + UNDEF:
case UNDEF * 16 + UNDEF:
return false;
case WEAK_UNDEF * 16 + UNDEF:
case DYN_UNDEF * 16 + UNDEF:
case DYN_WEAK_UNDEF * 16 + UNDEF:
return true;
case COMMON * 16 + UNDEF:
case WEAK_COMMON * 16 + UNDEF:
case DYN_COMMON * 16 + UNDEF:
case DYN_WEAK_COMMON * 16 + UNDEF:
return false;
case DEF * 16 + WEAK_UNDEF:
case WEAK_DEF * 16 + WEAK_UNDEF:
case DYN_DEF * 16 + WEAK_UNDEF:
case DYN_WEAK_DEF * 16 + WEAK_UNDEF:
case UNDEF * 16 + WEAK_UNDEF:
case WEAK_UNDEF * 16 + WEAK_UNDEF:
case DYN_UNDEF * 16 + WEAK_UNDEF:
case DYN_WEAK_UNDEF * 16 + WEAK_UNDEF:
case COMMON * 16 + WEAK_UNDEF:
case WEAK_COMMON * 16 + WEAK_UNDEF:
case DYN_COMMON * 16 + WEAK_UNDEF:
case DYN_WEAK_COMMON * 16 + WEAK_UNDEF:
return false;
case DEF * 16 + DYN_UNDEF:
case WEAK_DEF * 16 + DYN_UNDEF:
case DYN_DEF * 16 + DYN_UNDEF:
case DYN_WEAK_DEF * 16 + DYN_UNDEF:
case UNDEF * 16 + DYN_UNDEF:
case WEAK_UNDEF * 16 + DYN_UNDEF:
case DYN_UNDEF * 16 + DYN_UNDEF:
case DYN_WEAK_UNDEF * 16 + DYN_UNDEF:
case COMMON * 16 + DYN_UNDEF:
case WEAK_COMMON * 16 + DYN_UNDEF:
case DYN_COMMON * 16 + DYN_UNDEF:
case DYN_WEAK_COMMON * 16 + DYN_UNDEF:
return false;
case DEF * 16 + DYN_WEAK_UNDEF:
case WEAK_DEF * 16 + DYN_WEAK_UNDEF:
case DYN_DEF * 16 + DYN_WEAK_UNDEF:
case DYN_WEAK_DEF * 16 + DYN_WEAK_UNDEF:
case UNDEF * 16 + DYN_WEAK_UNDEF:
case WEAK_UNDEF * 16 + DYN_WEAK_UNDEF:
case DYN_UNDEF * 16 + DYN_WEAK_UNDEF:
case DYN_WEAK_UNDEF * 16 + DYN_WEAK_UNDEF:
case COMMON * 16 + DYN_WEAK_UNDEF:
case WEAK_COMMON * 16 + DYN_WEAK_UNDEF:
case DYN_COMMON * 16 + DYN_WEAK_UNDEF:
case DYN_WEAK_COMMON * 16 + DYN_WEAK_UNDEF:
return false;
case DEF * 16 + COMMON:
return false;
case WEAK_DEF * 16 + COMMON:
case DYN_DEF * 16 + COMMON:
case DYN_WEAK_DEF * 16 + COMMON:
return true;
case UNDEF * 16 + COMMON:
case WEAK_UNDEF * 16 + COMMON:
case DYN_UNDEF * 16 + COMMON:
case DYN_WEAK_UNDEF * 16 + COMMON:
return true;
case COMMON * 16 + COMMON:
*adjust_common_sizes = true;
return false;
case WEAK_COMMON * 16 + COMMON:
return true;
case DYN_COMMON * 16 + COMMON:
case DYN_WEAK_COMMON * 16 + COMMON:
*adjust_common_sizes = true;
return true;
case DEF * 16 + WEAK_COMMON:
case WEAK_DEF * 16 + WEAK_COMMON:
case DYN_DEF * 16 + WEAK_COMMON:
case DYN_WEAK_DEF * 16 + WEAK_COMMON:
return false;
case UNDEF * 16 + WEAK_COMMON:
case WEAK_UNDEF * 16 + WEAK_COMMON:
case DYN_UNDEF * 16 + WEAK_COMMON:
case DYN_WEAK_UNDEF * 16 + WEAK_COMMON:
return true;
case COMMON * 16 + WEAK_COMMON:
case WEAK_COMMON * 16 + WEAK_COMMON:
case DYN_COMMON * 16 + WEAK_COMMON:
case DYN_WEAK_COMMON * 16 + WEAK_COMMON:
return false;
case DEF * 16 + DYN_COMMON:
case WEAK_DEF * 16 + DYN_COMMON:
case DYN_DEF * 16 + DYN_COMMON:
case DYN_WEAK_DEF * 16 + DYN_COMMON:
return false;
case UNDEF * 16 + DYN_COMMON:
case WEAK_UNDEF * 16 + DYN_COMMON:
case DYN_UNDEF * 16 + DYN_COMMON:
case DYN_WEAK_UNDEF * 16 + DYN_COMMON:
return true;
case COMMON * 16 + DYN_COMMON:
case WEAK_COMMON * 16 + DYN_COMMON:
case DYN_COMMON * 16 + DYN_COMMON:
case DYN_WEAK_COMMON * 16 + DYN_COMMON:
*adjust_common_sizes = true;
return false;
case DEF * 16 + DYN_WEAK_COMMON:
case WEAK_DEF * 16 + DYN_WEAK_COMMON:
case DYN_DEF * 16 + DYN_WEAK_COMMON:
case DYN_WEAK_DEF * 16 + DYN_WEAK_COMMON:
return false;
case UNDEF * 16 + DYN_WEAK_COMMON:
case WEAK_UNDEF * 16 + DYN_WEAK_COMMON:
case DYN_UNDEF * 16 + DYN_WEAK_COMMON:
case DYN_WEAK_UNDEF * 16 + DYN_WEAK_COMMON:
return true;
case COMMON * 16 + DYN_WEAK_COMMON:
case WEAK_COMMON * 16 + DYN_WEAK_COMMON:
case DYN_COMMON * 16 + DYN_WEAK_COMMON:
case DYN_WEAK_COMMON * 16 + DYN_WEAK_COMMON:
*adjust_common_sizes = true;
return false;
default:
gold_unreachable();
}
}
bool
Symbol_table::should_override_with_special(const Symbol* to)
{
bool adjust_common_sizes;
unsigned int frombits = global_flag | regular_flag | def_flag;
bool ret = Symbol_table::should_override(to, frombits, NULL,
&adjust_common_sizes);
gold_assert(!adjust_common_sizes);
return ret;
}
void
Symbol::override_base_with_special(const Symbol* from)
{
gold_assert(this->name_ == from->name_ || this->has_alias());
this->source_ = from->source_;
switch (from->source_)
{
case FROM_OBJECT:
this->u_.from_object = from->u_.from_object;
break;
case IN_OUTPUT_DATA:
this->u_.in_output_data = from->u_.in_output_data;
break;
case IN_OUTPUT_SEGMENT:
this->u_.in_output_segment = from->u_.in_output_segment;
break;
case IS_CONSTANT:
case IS_UNDEFINED:
break;
default:
gold_unreachable();
break;
}
this->override_version(from->version_);
this->type_ = from->type_;
this->binding_ = from->binding_;
this->visibility_ = from->visibility_;
this->nonvis_ = from->nonvis_;
this->in_reg_ = true;
if (from->needs_dynsym_entry_)
this->needs_dynsym_entry_ = true;
if (from->needs_dynsym_value_)
this->needs_dynsym_value_ = true;
gold_assert(!from->is_target_special_ || this->is_target_special_);
gold_assert(!from->is_forwarder_);
gold_assert(!from->has_plt_offset_);
gold_assert(!from->has_warning_);
gold_assert(!from->is_copied_from_dynobj_);
gold_assert(!from->is_forced_local_);
}
template<int size>
void
Sized_symbol<size>::override_with_special(const Sized_symbol<size>* from)
{
this->override_base_with_special(from);
this->value_ = from->value_;
this->symsize_ = from->symsize_;
}
template<int size>
void
Symbol_table::override_with_special(Sized_symbol<size>* tosym,
const Sized_symbol<size>* fromsym)
{
tosym->override_with_special(fromsym);
if (tosym->has_alias())
{
Symbol* sym = this->weak_aliases_[tosym];
gold_assert(sym != NULL);
Sized_symbol<size>* ssym = this->get_sized_symbol<size>(sym);
do
{
ssym->override_with_special(fromsym);
sym = this->weak_aliases_[ssym];
gold_assert(sym != NULL);
ssym = this->get_sized_symbol<size>(sym);
}
while (ssym != tosym);
}
if (tosym->binding() == elfcpp::STB_LOCAL)
this->force_local(tosym);
}
#ifdef HAVE_TARGET_32_LITTLE
template
void
Symbol_table::resolve<32, false>(
Sized_symbol<32>* to,
const elfcpp::Sym<32, false>& sym,
unsigned int st_shndx,
bool is_ordinary,
unsigned int orig_st_shndx,
Object* object,
const char* version);
#endif
#ifdef HAVE_TARGET_32_BIG
template
void
Symbol_table::resolve<32, true>(
Sized_symbol<32>* to,
const elfcpp::Sym<32, true>& sym,
unsigned int st_shndx,
bool is_ordinary,
unsigned int orig_st_shndx,
Object* object,
const char* version);
#endif
#ifdef HAVE_TARGET_64_LITTLE
template
void
Symbol_table::resolve<64, false>(
Sized_symbol<64>* to,
const elfcpp::Sym<64, false>& sym,
unsigned int st_shndx,
bool is_ordinary,
unsigned int orig_st_shndx,
Object* object,
const char* version);
#endif
#ifdef HAVE_TARGET_64_BIG
template
void
Symbol_table::resolve<64, true>(
Sized_symbol<64>* to,
const elfcpp::Sym<64, true>& sym,
unsigned int st_shndx,
bool is_ordinary,
unsigned int orig_st_shndx,
Object* object,
const char* version);
#endif
#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
template
void
Symbol_table::override_with_special<32>(Sized_symbol<32>*,
const Sized_symbol<32>*);
#endif
#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
template
void
Symbol_table::override_with_special<64>(Sized_symbol<64>*,
const Sized_symbol<64>*);
#endif
}