// 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>
this->symsize_ = symsize;
}
+// Return true if the final value of this symbol is known at link
+// time.
+
+bool
+Symbol::final_value_is_known() const
+{
+ // If we are not generating an executable, then no final values are
+ // known, since they will change at runtime.
+ if (!parameters->output_is_executable())
+ return false;
+
+ // If the symbol is not from an object file, then it is defined, and
+ // known.
+ if (this->source_ != FROM_OBJECT)
+ return true;
+
+ // If the symbol is from a dynamic object, then the final value is
+ // not known.
+ if (this->object()->is_dynamic())
+ return false;
+
+ // If the symbol is not undefined (it is defined or common), then
+ // the final value is known.
+ if (!this->is_undefined())
+ return true;
+
+ // If the symbol is undefined, then whether the final value is known
+ // depends on whether we are doing a static link. If we are doing a
+ // dynamic link, then the final value could be filled in at runtime.
+ // This could reasonably be the case for a weak undefined symbol.
+ return parameters->doing_static_link();
+}
+
// Class Symbol_table.
Symbol_table::Symbol_table()
- : size_(0), saw_undefined_(0), offset_(0), table_(), namepool_(),
+ : saw_undefined_(0), offset_(0), table_(), namepool_(),
forwarders_(), commons_(), warnings_()
{
}
size_t sym_name_size,
Symbol** sympointers)
{
- // We take the size from the first object we see.
- if (this->get_size() == 0)
- this->set_size(size);
-
- if (size != this->get_size() || size != relobj->target()->get_size())
- {
- fprintf(stderr, _("%s: %s: mixing 32-bit and 64-bit ELF objects\n"),
- program_name, relobj->name().c_str());
- gold_exit(false);
- }
+ gold_assert(size == relobj->target()->get_size());
+ gold_assert(size == parameters->get_size());
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
size_t versym_size,
const std::vector<const char*>* version_map)
{
- // We take the size from the first object we see.
- if (this->get_size() == 0)
- this->set_size(size);
-
- if (size != this->get_size() || size != dynobj->target()->get_size())
- {
- fprintf(stderr, _("%s: %s: mixing 32-bit and 64-bit ELF objects\n"),
- program_name, dynobj->name().c_str());
- gold_exit(false);
- }
+ gold_assert(size == dynobj->target()->get_size());
+ gold_assert(size == parameters->get_size());
if (versym != NULL && versym_size / 2 < count)
{
Sized_symbol<size>** poldsym
ACCEPT_SIZE_ENDIAN)
{
- gold_assert(this->size_ == size);
-
Symbol* oldsym;
Sized_symbol<size>* sym;
bool add_to_table = false;
bool offset_is_from_end,
bool only_if_ref)
{
- gold_assert(target->get_size() == this->size_);
- if (this->size_ == 32)
+ if (parameters->get_size() == 32)
{
#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
return this->do_define_in_output_data<32>(target, name, version, od,
gold_unreachable();
#endif
}
- else if (this->size_ == 64)
+ else if (parameters->get_size() == 64)
{
#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
return this->do_define_in_output_data<64>(target, name, version, od,
Sized_symbol<size>* sym;
Sized_symbol<size>* oldsym;
- if (target->is_big_endian())
+ if (parameters->is_big_endian())
{
#if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) (
if (sym == NULL)
return NULL;
- gold_assert(version == NULL);
+ gold_assert(version == NULL || oldsym != NULL);
sym->init(name, od, value, symsize, type, binding, visibility, nonvis,
offset_is_from_end);
Symbol::Segment_offset_base offset_base,
bool only_if_ref)
{
- gold_assert(target->get_size() == this->size_);
- if (this->size_ == 32)
+ if (parameters->get_size() == 32)
{
#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
return this->do_define_in_output_segment<32>(target, name, version, os,
gold_unreachable();
#endif
}
- else if (this->size_ == 64)
+ else if (parameters->get_size() == 64)
{
#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
return this->do_define_in_output_segment<64>(target, name, version, os,
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, &oldsym
- SELECT_SIZE_ENDIAN(size, true));
+ if (parameters->is_big_endian())
+ {
+#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, &oldsym
- 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);
+ gold_assert(version == NULL || oldsym != NULL);
sym->init(name, os, value, symsize, type, binding, visibility, nonvis,
offset_base);
elfcpp::STB binding, elfcpp::STV visibility,
unsigned char nonvis, bool only_if_ref)
{
- gold_assert(target->get_size() == this->size_);
- if (this->size_ == 32)
+ if (parameters->get_size() == 32)
{
#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
return this->do_define_as_constant<32>(target, name, version, value,
gold_unreachable();
#endif
}
- else if (this->size_ == 64)
+ else if (parameters->get_size() == 64)
{
#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
return this->do_define_as_constant<64>(target, name, version, value,
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, &oldsym
- SELECT_SIZE_ENDIAN(size, true));
+ if (parameters->is_big_endian())
+ {
+#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, &oldsym
- 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);
+ gold_assert(version == NULL || oldsym != NULL);
sym->init(name, value, symsize, type, binding, visibility, nonvis);
if (oldsym != NULL
this->first_dynamic_global_index_ = dyn_global_index;
this->dynamic_count_ = dyncount;
- if (this->size_ == 32)
- ret = this->sized_finalize<32>(index, off, pool);
- else if (this->size_ == 64)
- ret = this->sized_finalize<64>(index, off, pool);
+ if (parameters->get_size() == 32)
+ {
+#if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_32_LITTLE)
+ ret = this->sized_finalize<32>(index, off, pool);
+#else
+ gold_unreachable();
+#endif
+ }
+ else if (parameters->get_size() == 64)
+ {
+#if defined(HAVE_TARGET_64_BIG) || defined(HAVE_TARGET_64_LITTLE)
+ ret = this->sized_finalize<64>(index, off, pool);
+#else
+ gold_unreachable();
+#endif
+ }
else
gold_unreachable();
Symbol_table::write_globals(const Target* target, const Stringpool* sympool,
const Stringpool* dynpool, Output_file* of) const
{
- if (this->size_ == 32)
+ if (parameters->get_size() == 32)
{
- if (target->is_big_endian())
- this->sized_write_globals<32, true>(target, sympool, dynpool, of);
+ if (parameters->is_big_endian())
+ {
+#ifdef HAVE_TARGET_32_BIG
+ this->sized_write_globals<32, true>(target, sympool, dynpool, of);
+#else
+ gold_unreachable();
+#endif
+ }
else
- this->sized_write_globals<32, false>(target, sympool, dynpool, of);
+ {
+#ifdef HAVE_TARGET_32_LITTLE
+ this->sized_write_globals<32, false>(target, sympool, dynpool, of);
+#else
+ gold_unreachable();
+#endif
+ }
}
- else if (this->size_ == 64)
+ else if (parameters->get_size() == 64)
{
- if (target->is_big_endian())
- this->sized_write_globals<64, true>(target, sympool, dynpool, of);
+ if (parameters->is_big_endian())
+ {
+#ifdef HAVE_TARGET_64_BIG
+ this->sized_write_globals<64, true>(target, sympool, dynpool, of);
+#else
+ gold_unreachable();
+#endif
+ }
else
- this->sized_write_globals<64, false>(target, sympool, dynpool, of);
+ {
+#ifdef HAVE_TARGET_64_LITTLE
+ this->sized_write_globals<64, false>(target, sympool, dynpool, of);
+#else
+ gold_unreachable();
+#endif
+ }
}
else
gold_unreachable();
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()));
// Write out a section symbol. Return the update offset.
void
-Symbol_table::write_section_symbol(const Target* target,
- const Output_section *os,
+Symbol_table::write_section_symbol(const Output_section *os,
Output_file* of,
off_t offset) const
{
- if (this->size_ == 32)
+ if (parameters->get_size() == 32)
{
- if (target->is_big_endian())
- this->sized_write_section_symbol<32, true>(os, of, offset);
+ if (parameters->is_big_endian())
+ {
+#ifdef HAVE_TARGET_32_BIG
+ this->sized_write_section_symbol<32, true>(os, of, offset);
+#else
+ gold_unreachable();
+#endif
+ }
else
- this->sized_write_section_symbol<32, false>(os, of, offset);
+ {
+#ifdef HAVE_TARGET_32_LITTLE
+ this->sized_write_section_symbol<32, false>(os, of, offset);
+#else
+ gold_unreachable();
+#endif
+ }
}
- else if (this->size_ == 64)
+ else if (parameters->get_size() == 64)
{
- if (target->is_big_endian())
- this->sized_write_section_symbol<64, true>(os, of, offset);
+ if (parameters->is_big_endian())
+ {
+#ifdef HAVE_TARGET_64_BIG
+ this->sized_write_section_symbol<64, true>(os, of, offset);
+#else
+ gold_unreachable();
+#endif
+ }
else
- this->sized_write_section_symbol<64, false>(os, of, offset);
+ {
+#ifdef HAVE_TARGET_64_LITTLE
+ this->sized_write_section_symbol<64, false>(os, of, offset);
+#else
+ gold_unreachable();
+#endif
+ }
}
else
gold_unreachable();
Task_locker_obj<Object> tl(*p->second.object);
const unsigned char* c;
off_t len;
- c = p->second.object->section_contents(p->second.shndx, &len);
+ c = p->second.object->section_contents(p->second.shndx, &len,
+ false);
p->second.set_text(reinterpret_cast<const char*>(c), len);
}
}