// symtab.cc -- the gold symbol table
-// Copyright (C) 2006-2016 Free Software Foundation, Inc.
+// Copyright (C) 2006-2017 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
// Class Symbol.
-// Initialize fields in Symbol. This initializes everything except u_
-// and source_.
+// Initialize fields in Symbol. This initializes everything except
+// u1_, u2_ and source_.
void
Symbol::init_fields(const char* name, const char* version,
this->undef_binding_weak_ = false;
this->is_predefined_ = false;
this->is_protected_ = false;
+ this->non_zero_localentry_ = false;
}
// Return the demangled version of the symbol's name, but only
{
this->init_fields(name, version, sym.get_st_type(), sym.get_st_bind(),
sym.get_st_visibility(), sym.get_st_nonvis());
- this->u_.from_object.object = object;
- this->u_.from_object.shndx = st_shndx;
+ this->u1_.object = object;
+ this->u2_.shndx = st_shndx;
this->is_ordinary_shndx_ = is_ordinary;
this->source_ = FROM_OBJECT;
this->in_reg_ = !object->is_dynamic();
bool is_predefined)
{
this->init_fields(name, version, type, binding, visibility, nonvis);
- this->u_.in_output_data.output_data = od;
- this->u_.in_output_data.offset_is_from_end = offset_is_from_end;
+ this->u1_.output_data = od;
+ this->u2_.offset_is_from_end = offset_is_from_end;
this->source_ = IN_OUTPUT_DATA;
this->in_reg_ = true;
this->in_real_elf_ = true;
bool is_predefined)
{
this->init_fields(name, version, type, binding, visibility, nonvis);
- this->u_.in_output_segment.output_segment = os;
- this->u_.in_output_segment.offset_base = offset_base;
+ this->u1_.output_segment = os;
+ this->u2_.offset_base = offset_base;
this->source_ = IN_OUTPUT_SEGMENT;
this->in_reg_ = true;
this->in_real_elf_ = true;
{
gold_assert(this->is_common());
this->source_ = IN_OUTPUT_DATA;
- this->u_.in_output_data.output_data = od;
- this->u_.in_output_data.offset_is_from_end = false;
+ this->u1_.output_data = od;
+ this->u2_.offset_is_from_end = false;
}
// Initialize the fields in Sized_symbol for SYM in OBJECT.
{
case FROM_OBJECT:
{
- unsigned int shndx = this->u_.from_object.shndx;
+ unsigned int shndx = this->u2_.shndx;
if (shndx != elfcpp::SHN_UNDEF && this->is_ordinary_shndx_)
{
- gold_assert(!this->u_.from_object.object->is_dynamic());
- gold_assert(this->u_.from_object.object->pluginobj() == NULL);
- Relobj* relobj = static_cast<Relobj*>(this->u_.from_object.object);
+ gold_assert(!this->u1_.object->is_dynamic());
+ gold_assert(this->u1_.object->pluginobj() == NULL);
+ Relobj* relobj = static_cast<Relobj*>(this->u1_.object);
return relobj->output_section(shndx);
}
return NULL;
}
case IN_OUTPUT_DATA:
- return this->u_.in_output_data.output_data->output_section();
+ return this->u1_.output_data->output_section();
case IN_OUTPUT_SEGMENT:
case IS_CONSTANT:
break;
case IS_CONSTANT:
this->source_ = IN_OUTPUT_DATA;
- this->u_.in_output_data.output_data = os;
- this->u_.in_output_data.offset_is_from_end = false;
+ this->u1_.output_data = os;
+ this->u2_.offset_is_from_end = false;
break;
case IN_OUTPUT_SEGMENT:
case IS_UNDEFINED:
{
gold_assert(this->is_predefined_);
this->source_ = IN_OUTPUT_SEGMENT;
- this->u_.in_output_segment.output_segment = os;
- this->u_.in_output_segment.offset_base = base;
+ this->u1_.output_segment = os;
+ this->u2_.offset_base = base;
}
// Set the symbol to undefined. This is used for pre-defined
const char* name = sym_names + st_name;
if (!parameters->options().relocatable()
- && strcmp (name, "__gnu_lto_slim") == 0)
+ && name[0] == '_'
+ && name[1] == '_'
+ && strcmp (name + (name[2] == '_'), "__gnu_lto_slim") == 0)
gold_info(_("%s: plugin needed to handle lto object"),
relobj->name().c_str());
Sized_symbol<size>*
Symbol_table::define_special_symbol(const char** pname, const char** pversion,
bool only_if_ref,
+ elfcpp::STV visibility,
Sized_symbol<size>** poldsym,
- bool* resolve_oldsym)
+ bool* resolve_oldsym, bool is_forced_local)
{
*resolve_oldsym = false;
*poldsym = NULL;
// the version script.
std::string v;
bool is_default_version = false;
- if (*pversion == NULL)
+ if (!is_forced_local && *pversion == NULL)
{
bool is_global;
if (this->version_script_.get_symbol_version(*pname, &v, &is_global))
oldsym = this->lookup(*pname, *pversion);
if (oldsym == NULL && is_default_version)
oldsym = this->lookup(*pname, NULL);
- if (oldsym == NULL || !oldsym->is_undefined())
+ if (oldsym == NULL)
return NULL;
+ if (!oldsym->is_undefined())
+ {
+ // Skip if the old definition is from a regular object.
+ if (!oldsym->is_from_dynobj())
+ return NULL;
+
+ // If the symbol has hidden or internal visibility, ignore
+ // definition and reference from a dynamic object.
+ if ((visibility == elfcpp::STV_HIDDEN
+ || visibility == elfcpp::STV_INTERNAL)
+ && !oldsym->in_reg())
+ return NULL;
+ }
*pname = oldsym->name();
if (is_default_version)
Sized_symbol<size>* sym;
Sized_symbol<size>* oldsym;
bool resolve_oldsym;
+ const bool is_forced_local = binding == elfcpp::STB_LOCAL;
if (parameters->target().is_big_endian())
{
#if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
sym = this->define_special_symbol<size, true>(&name, &version,
- only_if_ref, &oldsym,
- &resolve_oldsym);
+ only_if_ref,
+ visibility,
+ &oldsym,
+ &resolve_oldsym,
+ is_forced_local);
#else
gold_unreachable();
#endif
{
#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
sym = this->define_special_symbol<size, false>(&name, &version,
- only_if_ref, &oldsym,
- &resolve_oldsym);
+ only_if_ref,
+ visibility,
+ &oldsym,
+ &resolve_oldsym,
+ is_forced_local);
#else
gold_unreachable();
#endif
if (oldsym == NULL)
{
- if (binding == elfcpp::STB_LOCAL
- || this->version_script_.symbol_is_local(name))
+ if (is_forced_local || this->version_script_.symbol_is_local(name))
this->force_local(sym);
else if (version != NULL)
sym->set_is_default();
else
{
if (defined == PREDEFINED
- && (binding == elfcpp::STB_LOCAL
- || this->version_script_.symbol_is_local(name)))
+ && (is_forced_local || this->version_script_.symbol_is_local(name)))
this->force_local(oldsym);
delete sym;
return oldsym;
Sized_symbol<size>* sym;
Sized_symbol<size>* oldsym;
bool resolve_oldsym;
+ const bool is_forced_local = binding == elfcpp::STB_LOCAL;
if (parameters->target().is_big_endian())
{
#if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
sym = this->define_special_symbol<size, true>(&name, &version,
- only_if_ref, &oldsym,
- &resolve_oldsym);
+ only_if_ref,
+ visibility,
+ &oldsym,
+ &resolve_oldsym,
+ is_forced_local);
#else
gold_unreachable();
#endif
{
#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
sym = this->define_special_symbol<size, false>(&name, &version,
- only_if_ref, &oldsym,
- &resolve_oldsym);
+ only_if_ref,
+ visibility,
+ &oldsym,
+ &resolve_oldsym,
+ is_forced_local);
#else
gold_unreachable();
#endif
if (oldsym == NULL)
{
- if (binding == elfcpp::STB_LOCAL
- || this->version_script_.symbol_is_local(name))
+ if (is_forced_local || this->version_script_.symbol_is_local(name))
this->force_local(sym);
else if (version != NULL)
sym->set_is_default();
return sym;
else
{
- if (binding == elfcpp::STB_LOCAL
- || this->version_script_.symbol_is_local(name))
+ if (is_forced_local || this->version_script_.symbol_is_local(name))
this->force_local(oldsym);
delete sym;
return oldsym;
Sized_symbol<size>* sym;
Sized_symbol<size>* oldsym;
bool resolve_oldsym;
+ const bool is_forced_local = binding == elfcpp::STB_LOCAL;
if (parameters->target().is_big_endian())
{
#if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
sym = this->define_special_symbol<size, true>(&name, &version,
- only_if_ref, &oldsym,
- &resolve_oldsym);
+ only_if_ref,
+ visibility,
+ &oldsym,
+ &resolve_oldsym,
+ is_forced_local);
#else
gold_unreachable();
#endif
{
#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
sym = this->define_special_symbol<size, false>(&name, &version,
- only_if_ref, &oldsym,
- &resolve_oldsym);
+ only_if_ref,
+ visibility,
+ &oldsym,
+ &resolve_oldsym,
+ is_forced_local);
#else
gold_unreachable();
#endif
if ((version == NULL
|| name != version
|| value != 0)
- && (binding == elfcpp::STB_LOCAL
- || this->version_script_.symbol_is_local(name)))
+ && (is_forced_local || this->version_script_.symbol_is_local(name)))
this->force_local(sym);
else if (version != NULL
&& (name != version || value != 0))
return sym;
else
{
- if (binding == elfcpp::STB_LOCAL
- || this->version_script_.symbol_is_local(name))
+ if (is_forced_local || this->version_script_.symbol_is_local(name))
this->force_local(oldsym);
delete sym;
return oldsym;
{
#if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
sym = this->define_special_symbol<size, true>(&name, &version,
- false, &oldsym,
- &resolve_oldsym);
+ false,
+ elfcpp::STV_DEFAULT,
+ &oldsym,
+ &resolve_oldsym,
+ false);
#else
gold_unreachable();
#endif
{
#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
sym = this->define_special_symbol<size, false>(&name, &version,
- false, &oldsym,
- &resolve_oldsym);
+ false,
+ elfcpp::STV_DEFAULT,
+ &oldsym,
+ &resolve_oldsym,
+ false);
#else
gold_unreachable();
#endif
}
// Set the dynamic symbol indexes. INDEX is the index of the first
-// global dynamic symbol. Pointers to the symbols are stored into the
-// vector SYMS. The names are added to DYNPOOL. This returns an
-// updated dynamic symbol index.
+// global dynamic symbol. Pointers to the global symbols are stored
+// into the vector SYMS. The names are added to DYNPOOL.
+// This returns an updated dynamic symbol index.
unsigned int
Symbol_table::set_dynsym_indexes(unsigned int index,
+ unsigned int* pforced_local_count,
std::vector<Symbol*>* syms,
Stringpool* dynpool,
Versions* versions)
{
std::vector<Symbol*> as_needed_sym;
+ // First process all the symbols which have been forced to be local,
+ // as they must appear before all global symbols.
+ unsigned int forced_local_count = 0;
+ for (Forced_locals::iterator p = this->forced_locals_.begin();
+ p != this->forced_locals_.end();
+ ++p)
+ {
+ Symbol* sym = *p;
+ gold_assert(sym->is_forced_local());
+ if (sym->has_dynsym_index())
+ continue;
+ if (!sym->should_add_dynsym_entry(this))
+ sym->set_dynsym_index(-1U);
+ else
+ {
+ sym->set_dynsym_index(index);
+ ++index;
+ ++forced_local_count;
+ dynpool->add(sym->name(), false, NULL);
+ }
+ }
+ *pforced_local_count = forced_local_count;
+
// Allow a target to set dynsym indexes.
if (parameters->target().has_custom_set_dynsym_indexes())
{
++p)
{
Symbol* sym = p->second;
+ if (sym->is_forced_local())
+ continue;
if (!sym->should_add_dynsym_entry(this))
sym->set_dynsym_index(-1U);
else
{
Symbol* sym = p->second;
+ if (sym->is_forced_local())
+ continue;
+
// Note that SYM may already have a dynamic symbol index, since
// some symbols appear more than once in the symbol table, with
// and without a version.
// Set the final values for all the symbols. The index of the first
// global symbol in the output file is *PLOCAL_SYMCOUNT. Record the
// file offset OFF. Add their names to POOL. Return the new file
-// offset. Update *PLOCAL_SYMCOUNT if necessary.
+// offset. Update *PLOCAL_SYMCOUNT if necessary. DYNOFF and
+// DYN_GLOBAL_INDEX refer to the start of the symbols that will be
+// written from the global symbol table in Symtab::write_globals(),
+// which will include forced-local symbols. DYN_GLOBAL_INDEX is
+// not necessarily the same as the sh_info field for the .dynsym
+// section, which will point to the first real global symbol.
off_t
Symbol_table::finalize(off_t off, off_t dynoff, size_t dyn_global_index,
break;
case Symbol::IN_OUTPUT_SEGMENT:
- shndx = elfcpp::SHN_ABS;
+ {
+ Output_segment* oseg = sym->output_segment();
+ Output_section* osect = oseg->first_section();
+ if (osect == NULL)
+ shndx = elfcpp::SHN_ABS;
+ else
+ shndx = osect->out_shndx();
+ }
break;
case Symbol::IS_CONSTANT: