+ Symbol* oldsym;
+ Sized_symbol<size>* sym;
+
+ if (only_if_ref)
+ {
+ oldsym = this->lookup(name, NULL);
+ if (oldsym == NULL)
+ return NULL;
+ sym = NULL;
+
+ // Canonicalize NAME.
+ name = oldsym->name();
+ }
+ else
+ {
+ // Canonicalize NAME.
+ name = this->namepool_.add(name);
+
+ Symbol* const snull = NULL;
+ const char* const vnull = NULL;
+ std::pair<typename Symbol_table_type::iterator, bool> ins =
+ this->table_.insert(std::make_pair(std::make_pair(name, vnull),
+ snull));
+
+ if (!ins.second)
+ {
+ // We already have a symbol table entry for NAME.
+ oldsym = ins.first->second;
+ assert(oldsym != NULL);
+ sym = NULL;
+ }
+ else
+ {
+ // We haven't seen this symbol before.
+ assert(ins.first->second == NULL);
+
+ if (!target->has_make_symbol())
+ sym = new Sized_symbol<size>();
+ else
+ {
+ assert(target->get_size() == size);
+ assert(target->is_big_endian() ? big_endian : !big_endian);
+ typedef Sized_target<size, big_endian> My_target;
+ My_target* sized_target = static_cast<My_target*>(target);
+ sym = sized_target->make_symbol();
+ if (sym == NULL)
+ return NULL;
+ }
+
+ ins.first->second = sym;
+ oldsym = NULL;
+ }
+ }
+
+ if (oldsym != NULL)
+ {
+ assert(sym == NULL);
+
+ sym = this->get_sized_symbol SELECT_SIZE_NAME (oldsym
+ SELECT_SIZE(size));
+ assert(sym->source() == Symbol::FROM_OBJECT);
+ const int old_shnum = sym->shnum();
+ if (old_shnum != elfcpp::SHN_UNDEF
+ && old_shnum != 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;
+ }
+
+ // Our new definition is going to override the old reference.
+ }
+
+ return sym;
+}
+
+// Define a symbol based on an Output_data.
+
+void
+Symbol_table::define_in_output_data(Target* target, const char* name,
+ Output_data* od,
+ 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)
+{
+ assert(target->get_size() == this->size_);
+ if (this->size_ == 32)
+ this->do_define_in_output_data<32>(target, name, od, value, symsize,
+ type, binding, visibility, nonvis,
+ offset_is_from_end, only_if_ref);
+ else if (this->size_ == 64)
+ this->do_define_in_output_data<64>(target, name, od, value, symsize,
+ type, binding, visibility, nonvis,
+ offset_is_from_end, only_if_ref);
+ else
+ abort();
+}
+
+// Define a symbol in an Output_data, sized version.
+
+template<int size>
+void
+Symbol_table::do_define_in_output_data(
+ Target* target,
+ const char* name,
+ Output_data* od,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ typename elfcpp::Elf_types<size>::Elf_WXword symsize,
+ elfcpp::STT type,
+ elfcpp::STB binding,
+ elfcpp::STV visibility,
+ unsigned char nonvis,
+ bool offset_is_from_end,
+ bool only_if_ref)
+{
+ Sized_symbol<size>* sym;
+
+ if (target->is_big_endian())
+ sym = this->define_special_symbol<size, true>(target, name, only_if_ref);
+ else
+ sym = this->define_special_symbol<size, false>(target, name, only_if_ref);
+
+ if (sym == NULL)
+ return;
+
+ sym->init(name, od, value, symsize, type, binding, visibility, nonvis,
+ offset_is_from_end);
+}
+
+// Define a symbol based on an Output_segment.
+
+void
+Symbol_table::define_in_output_segment(Target* target, const char* name,
+ Output_segment* os,
+ uint64_t value, uint64_t symsize,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility,
+ unsigned char nonvis,
+ Symbol::Segment_offset_base offset_base,
+ bool only_if_ref)
+{
+ assert(target->get_size() == this->size_);
+ if (this->size_ == 32)
+ this->do_define_in_output_segment<32>(target, name, os, value, symsize,
+ type, binding, visibility, nonvis,
+ offset_base, only_if_ref);
+ else if (this->size_ == 64)
+ this->do_define_in_output_segment<64>(target, name, os, value, symsize,
+ type, binding, visibility, nonvis,
+ offset_base, only_if_ref);
+ else
+ abort();
+}
+
+// Define a symbol in an Output_segment, sized version.
+
+template<int size>
+void
+Symbol_table::do_define_in_output_segment(
+ Target* target,
+ const char* name,
+ Output_segment* os,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ typename elfcpp::Elf_types<size>::Elf_WXword symsize,
+ elfcpp::STT type,
+ elfcpp::STB binding,
+ elfcpp::STV visibility,
+ unsigned char nonvis,
+ Symbol::Segment_offset_base offset_base,
+ bool only_if_ref)
+{
+ Sized_symbol<size>* sym;
+
+ if (target->is_big_endian())
+ sym = this->define_special_symbol<size, true>(target, name, only_if_ref);
+ else
+ sym = this->define_special_symbol<size, false>(target, name, only_if_ref);
+
+ if (sym == NULL)
+ return;
+
+ sym->init(name, os, value, symsize, type, binding, visibility, nonvis,
+ offset_base);
+}
+
+// Define a special symbol with a constant value. It is a multiple
+// definition error if this symbol is already defined.
+
+void
+Symbol_table::define_as_constant(Target* target, const char* name,
+ uint64_t value, uint64_t symsize,
+ elfcpp::STT type, elfcpp::STB binding,
+ elfcpp::STV visibility, unsigned char nonvis,
+ bool only_if_ref)
+{
+ assert(target->get_size() == this->size_);
+ if (this->size_ == 32)
+ this->do_define_as_constant<32>(target, name, value, symsize,
+ type, binding, visibility, nonvis,
+ only_if_ref);
+ else if (this->size_ == 64)
+ this->do_define_as_constant<64>(target, name, value, symsize,
+ type, binding, visibility, nonvis,
+ only_if_ref);
+ else
+ abort();
+}
+
+// Define a symbol as a constant, sized version.
+
+template<int size>
+void
+Symbol_table::do_define_as_constant(
+ Target* target,
+ const char* name,
+ typename elfcpp::Elf_types<size>::Elf_Addr value,
+ typename elfcpp::Elf_types<size>::Elf_WXword symsize,
+ elfcpp::STT type,
+ elfcpp::STB binding,
+ elfcpp::STV visibility,
+ unsigned char nonvis,
+ bool only_if_ref)
+{
+ Sized_symbol<size>* sym;
+
+ if (target->is_big_endian())
+ sym = this->define_special_symbol<size, true>(target, name, only_if_ref);
+ else
+ sym = this->define_special_symbol<size, false>(target, name, only_if_ref);
+
+ if (sym == NULL)
+ return;
+
+ sym->init(name, value, symsize, type, binding, visibility, nonvis);
+}
+
+// Define a set of symbols in output sections.
+
+void
+Symbol_table::define_symbols(const Layout* layout, Target* target, int count,
+ const Define_symbol_in_section* p)
+{
+ for (int i = 0; i < count; ++i, ++p)
+ {
+ Output_section* os = layout->find_output_section(p->output_section);
+ if (os != NULL)
+ this->define_in_output_data(target, p->name, os, p->value, p->size,
+ p->type, p->binding, p->visibility,
+ p->nonvis, p->offset_is_from_end,
+ p->only_if_ref);
+ else
+ this->define_as_constant(target, p->name, 0, p->size, p->type,
+ p->binding, p->visibility, p->nonvis,
+ p->only_if_ref);
+ }
+}
+
+// Define a set of symbols in output segments.
+
+void
+Symbol_table::define_symbols(const Layout* layout, Target* target, int count,
+ const Define_symbol_in_segment* p)
+{
+ for (int i = 0; i < count; ++i, ++p)
+ {
+ Output_segment* os = layout->find_output_segment(p->segment_type,
+ p->segment_flags_set,
+ p->segment_flags_clear);
+ if (os != NULL)
+ this->define_in_output_segment(target, p->name, os, p->value, p->size,
+ p->type, p->binding, p->visibility,
+ p->nonvis, p->offset_base,
+ p->only_if_ref);
+ else
+ this->define_as_constant(target, p->name, 0, p->size, p->type,
+ p->binding, p->visibility, p->nonvis,
+ p->only_if_ref);