// symtab.cc -- the gold symbol table
+// Copyright 2006, 2007 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.
+
#include "gold.h"
#include <stdint.h>
// Create and return a specially defined symbol. If ONLY_IF_REF is
// true, then only create the symbol if there is a reference to it.
+// If this does not return NULL, it sets *POLDSYM to the existing
+// symbol if there is one. This canonicalizes *PNAME and *PVERSION.
template<int size, bool big_endian>
Sized_symbol<size>*
-Symbol_table::define_special_symbol(const Target* target, const char* name,
- const char* version, bool only_if_ref
+Symbol_table::define_special_symbol(const Target* target, const char** pname,
+ const char** pversion, bool only_if_ref,
+ Sized_symbol<size>** poldsym
ACCEPT_SIZE_ENDIAN)
{
gold_assert(this->size_ == size);
Symbol* oldsym;
Sized_symbol<size>* sym;
+ bool add_to_table = false;
+ typename Symbol_table_type::iterator add_loc = this->table_.end();
if (only_if_ref)
{
- oldsym = this->lookup(name, version);
+ oldsym = this->lookup(*pname, *pversion);
if (oldsym == NULL || !oldsym->is_undefined())
return NULL;
- sym = NULL;
- // Canonicalize NAME and VERSION.
- name = oldsym->name();
- version = oldsym->version();
+ *pname = oldsym->name();
+ *pversion = oldsym->version();
}
else
{
// Canonicalize NAME and VERSION.
Stringpool::Key name_key;
- name = this->namepool_.add(name, &name_key);
+ *pname = this->namepool_.add(*pname, &name_key);
Stringpool::Key version_key = 0;
- if (version != NULL)
- version = this->namepool_.add(version, &version_key);
+ if (*pversion != NULL)
+ *pversion = this->namepool_.add(*pversion, &version_key);
Symbol* const snull = NULL;
std::pair<typename Symbol_table_type::iterator, bool> ins =
// We already have a symbol table entry for NAME/VERSION.
oldsym = ins.first->second;
gold_assert(oldsym != NULL);
- sym = NULL;
}
else
{
// We haven't seen this symbol before.
gold_assert(ins.first->second == NULL);
-
- if (!target->has_make_symbol())
- sym = new Sized_symbol<size>();
- else
- {
- gold_assert(target->get_size() == size);
- gold_assert(target->is_big_endian() ? big_endian : !big_endian);
- typedef Sized_target<size, big_endian> My_target;
- const My_target* sized_target =
- static_cast<const My_target*>(target);
- sym = sized_target->make_symbol();
- if (sym == NULL)
- return NULL;
- }
-
- ins.first->second = sym;
+ add_to_table = true;
+ add_loc = ins.first;
oldsym = NULL;
}
}
- if (oldsym != NULL)
+ if (!target->has_make_symbol())
+ sym = new Sized_symbol<size>();
+ else
{
- gold_assert(sym == NULL);
+ gold_assert(target->get_size() == size);
+ gold_assert(target->is_big_endian() ? big_endian : !big_endian);
+ typedef Sized_target<size, big_endian> My_target;
+ const My_target* sized_target =
+ static_cast<const My_target*>(target);
+ sym = sized_target->make_symbol();
+ if (sym == NULL)
+ return NULL;
+ }
- sym = this->get_sized_symbol SELECT_SIZE_NAME(size) (oldsym
- SELECT_SIZE(size));
- gold_assert(sym->source() == Symbol::FROM_OBJECT);
- const int old_shndx = sym->shndx();
- if (old_shndx != elfcpp::SHN_UNDEF
- && old_shndx != elfcpp::SHN_COMMON
- && !sym->object()->is_dynamic())
- {
- fprintf(stderr, "%s: linker defined: multiple definition of %s\n",
- program_name, name);
- // FIXME: Report old location. Record that we have seen an
- // error.
- return NULL;
- }
+ if (add_to_table)
+ add_loc->second = sym;
+ else
+ gold_assert(oldsym != NULL);
- // Our new definition is going to override the old reference.
- }
+ *poldsym = this->get_sized_symbol SELECT_SIZE_NAME(size) (oldsym
+ SELECT_SIZE(size));
return sym;
}
{
gold_assert(target->get_size() == this->size_);
if (this->size_ == 32)
- return this->do_define_in_output_data<32>(target, name, version, od, value,
- symsize, type, binding,
- visibility, nonvis,
- offset_is_from_end, only_if_ref);
+ {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+ return this->do_define_in_output_data<32>(target, name, version, od,
+ value, symsize, type, binding,
+ visibility, nonvis,
+ offset_is_from_end,
+ only_if_ref);
+#else
+ gold_unreachable();
+#endif
+ }
else if (this->size_ == 64)
- return this->do_define_in_output_data<64>(target, name, version, od, value,
- symsize, type, binding,
- visibility, nonvis,
- offset_is_from_end, only_if_ref);
+ {
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+ return this->do_define_in_output_data<64>(target, name, version, od,
+ value, symsize, type, binding,
+ visibility, nonvis,
+ offset_is_from_end,
+ only_if_ref);
+#else
+ gold_unreachable();
+#endif
+ }
else
gold_unreachable();
}
bool only_if_ref)
{
Sized_symbol<size>* sym;
+ Sized_symbol<size>* oldsym;
if (target->is_big_endian())
- sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) (
- target, name, version, only_if_ref
- SELECT_SIZE_ENDIAN(size, true));
+ {
+#if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
+ sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) (
+ target, &name, &version, only_if_ref, &oldsym
+ SELECT_SIZE_ENDIAN(size, true));
+#else
+ gold_unreachable();
+#endif
+ }
else
- sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) (
- target, name, version, only_if_ref
- SELECT_SIZE_ENDIAN(size, false));
+ {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
+ sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) (
+ target, &name, &version, only_if_ref, &oldsym
+ SELECT_SIZE_ENDIAN(size, false));
+#else
+ gold_unreachable();
+#endif
+ }
if (sym == NULL)
return NULL;
+ gold_assert(version == NULL || oldsym != NULL);
sym->init(name, od, value, symsize, type, binding, visibility, nonvis,
offset_is_from_end);
+ if (oldsym != NULL
+ && Symbol_table::should_override_with_special(oldsym))
+ oldsym->override_with_special(sym);
+
return sym;
}
{
gold_assert(target->get_size() == this->size_);
if (this->size_ == 32)
- return this->do_define_in_output_segment<32>(target, name, version, os,
- value, symsize, type, binding,
- visibility, nonvis,
- offset_base, only_if_ref);
+ {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+ return this->do_define_in_output_segment<32>(target, name, version, os,
+ value, symsize, type,
+ binding, visibility, nonvis,
+ offset_base, only_if_ref);
+#else
+ gold_unreachable();
+#endif
+ }
else if (this->size_ == 64)
- return this->do_define_in_output_segment<64>(target, name, version, os,
- value, symsize, type, binding,
- visibility, nonvis,
- offset_base, only_if_ref);
+ {
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+ return this->do_define_in_output_segment<64>(target, name, version, os,
+ value, symsize, type,
+ binding, visibility, nonvis,
+ offset_base, only_if_ref);
+#else
+ gold_unreachable();
+#endif
+ }
else
gold_unreachable();
}
bool only_if_ref)
{
Sized_symbol<size>* sym;
+ Sized_symbol<size>* oldsym;
if (target->is_big_endian())
sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) (
- target, name, version, only_if_ref
+ target, &name, &version, only_if_ref, &oldsym
SELECT_SIZE_ENDIAN(size, true));
else
sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) (
- target, name, version, only_if_ref
+ target, &name, &version, only_if_ref, &oldsym
SELECT_SIZE_ENDIAN(size, false));
if (sym == NULL)
return NULL;
+ gold_assert(version == NULL || oldsym != NULL);
sym->init(name, os, value, symsize, type, binding, visibility, nonvis,
offset_base);
+ if (oldsym != NULL
+ && Symbol_table::should_override_with_special(oldsym))
+ oldsym->override_with_special(sym);
+
return sym;
}
{
gold_assert(target->get_size() == this->size_);
if (this->size_ == 32)
- return this->do_define_as_constant<32>(target, name, version, value,
- symsize, type, binding, visibility,
- nonvis, only_if_ref);
+ {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+ return this->do_define_as_constant<32>(target, name, version, value,
+ symsize, type, binding,
+ visibility, nonvis, only_if_ref);
+#else
+ gold_unreachable();
+#endif
+ }
else if (this->size_ == 64)
- return this->do_define_as_constant<64>(target, name, version, value,
- symsize, type, binding, visibility,
- nonvis, only_if_ref);
+ {
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+ return this->do_define_as_constant<64>(target, name, version, value,
+ symsize, type, binding,
+ visibility, nonvis, only_if_ref);
+#else
+ gold_unreachable();
+#endif
+ }
else
gold_unreachable();
}
bool only_if_ref)
{
Sized_symbol<size>* sym;
+ Sized_symbol<size>* oldsym;
if (target->is_big_endian())
sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) (
- target, name, version, only_if_ref
+ target, &name, &version, only_if_ref, &oldsym
SELECT_SIZE_ENDIAN(size, true));
else
sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) (
- target, name, version, only_if_ref
+ target, &name, &version, only_if_ref, &oldsym
SELECT_SIZE_ENDIAN(size, false));
if (sym == NULL)
return NULL;
+ gold_assert(version == NULL || oldsym != NULL);
sym->init(name, value, symsize, type, binding, visibility, nonvis);
+ if (oldsym != NULL
+ && Symbol_table::should_override_with_special(oldsym))
+ oldsym->override_with_special(sym);
+
return sym;
}
template<int size, bool big_endian>
void
-Symbol_table::sized_write_globals(const Target*,
+Symbol_table::sized_write_globals(const Target* target,
const Stringpool* sympool,
const Stringpool* dynpool,
Output_file* of) const
}
unsigned int shndx;
+ typename elfcpp::Elf_types<32>::Elf_Addr value = sym->value();
switch (sym->source())
{
case Symbol::FROM_OBJECT:
Object* symobj = sym->object();
if (symobj->is_dynamic())
{
- // FIXME.
+ if (sym->needs_dynsym_value())
+ value = target->dynsym_value(sym);
shndx = elfcpp::SHN_UNDEF;
}
else if (in_shndx == elfcpp::SHN_UNDEF
if (sym_index != -1U)
{
this->sized_write_symbol SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
- sym, shndx, sympool, ps
+ sym, sym->value(), shndx, sympool, ps
SELECT_SIZE_ENDIAN(size, big_endian));
ps += sym_size;
}
gold_assert(dynsym_index < dynamic_count);
unsigned char* pd = dynamic_view + (dynsym_index * sym_size);
this->sized_write_symbol SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
- sym, shndx, dynpool, pd
+ sym, value, shndx, dynpool, pd
SELECT_SIZE_ENDIAN(size, big_endian));
}
}
template<int size, bool big_endian>
void
-Symbol_table::sized_write_symbol(Sized_symbol<size>* sym,
- unsigned int shndx,
- const Stringpool* pool,
- unsigned char* p
- ACCEPT_SIZE_ENDIAN) const
+Symbol_table::sized_write_symbol(
+ Sized_symbol<size>* sym,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ unsigned int shndx,
+ const Stringpool* pool,
+ unsigned char* p
+ ACCEPT_SIZE_ENDIAN) const
{
elfcpp::Sym_write<size, big_endian> osym(p);
osym.put_st_name(pool->get_offset(sym->name()));
- osym.put_st_value(sym->value());
+ osym.put_st_value(value);
osym.put_st_size(sym->symsize());
osym.put_st_info(elfcpp::elf_st_info(sym->binding(), sym->type()));
osym.put_st_other(elfcpp::elf_st_other(sym->visibility(), sym->nonvis()));
// script to restrict this to only the ones needed for implemented
// targets.
+#ifdef HAVE_TARGET_32_LITTLE
template
void
-Symbol_table::add_from_relobj<32, true>(
- Sized_relobj<32, true>* relobj,
+Symbol_table::add_from_relobj<32, false>(
+ Sized_relobj<32, false>* relobj,
const unsigned char* syms,
size_t count,
const char* sym_names,
size_t sym_name_size,
Symbol** sympointers);
+#endif
+#ifdef HAVE_TARGET_32_BIG
template
void
-Symbol_table::add_from_relobj<32, false>(
- Sized_relobj<32, false>* relobj,
+Symbol_table::add_from_relobj<32, true>(
+ Sized_relobj<32, true>* relobj,
const unsigned char* syms,
size_t count,
const char* sym_names,
size_t sym_name_size,
Symbol** sympointers);
+#endif
+#ifdef HAVE_TARGET_64_LITTLE
template
void
-Symbol_table::add_from_relobj<64, true>(
- Sized_relobj<64, true>* relobj,
+Symbol_table::add_from_relobj<64, false>(
+ Sized_relobj<64, false>* relobj,
const unsigned char* syms,
size_t count,
const char* sym_names,
size_t sym_name_size,
Symbol** sympointers);
+#endif
+#ifdef HAVE_TARGET_64_BIG
template
void
-Symbol_table::add_from_relobj<64, false>(
- Sized_relobj<64, false>* relobj,
+Symbol_table::add_from_relobj<64, true>(
+ Sized_relobj<64, true>* relobj,
const unsigned char* syms,
size_t count,
const char* sym_names,
size_t sym_name_size,
Symbol** sympointers);
+#endif
+#ifdef HAVE_TARGET_32_LITTLE
template
void
-Symbol_table::add_from_dynobj<32, true>(
- Sized_dynobj<32, true>* dynobj,
+Symbol_table::add_from_dynobj<32, false>(
+ Sized_dynobj<32, false>* dynobj,
const unsigned char* syms,
size_t count,
const char* sym_names,
const unsigned char* versym,
size_t versym_size,
const std::vector<const char*>* version_map);
+#endif
+#ifdef HAVE_TARGET_32_BIG
template
void
-Symbol_table::add_from_dynobj<32, false>(
- Sized_dynobj<32, false>* dynobj,
+Symbol_table::add_from_dynobj<32, true>(
+ Sized_dynobj<32, true>* dynobj,
const unsigned char* syms,
size_t count,
const char* sym_names,
const unsigned char* versym,
size_t versym_size,
const std::vector<const char*>* version_map);
+#endif
+#ifdef HAVE_TARGET_64_LITTLE
template
void
-Symbol_table::add_from_dynobj<64, true>(
- Sized_dynobj<64, true>* dynobj,
+Symbol_table::add_from_dynobj<64, false>(
+ Sized_dynobj<64, false>* dynobj,
const unsigned char* syms,
size_t count,
const char* sym_names,
const unsigned char* versym,
size_t versym_size,
const std::vector<const char*>* version_map);
+#endif
+#ifdef HAVE_TARGET_64_BIG
template
void
-Symbol_table::add_from_dynobj<64, false>(
- Sized_dynobj<64, false>* dynobj,
+Symbol_table::add_from_dynobj<64, true>(
+ Sized_dynobj<64, true>* dynobj,
const unsigned char* syms,
size_t count,
const char* sym_names,
const unsigned char* versym,
size_t versym_size,
const std::vector<const char*>* version_map);
+#endif
} // End namespace gold.