+ }
+
+ if (!is_pass_two)
+ layout->layout_gnu_stack(seen_gnu_stack, gnu_stack_flags, this);
+
+ // Handle the .eh_frame sections after the other sections.
+ gold_assert(!is_pass_one || eh_frame_sections.empty());
+ for (std::vector<unsigned int>::const_iterator p = eh_frame_sections.begin();
+ p != eh_frame_sections.end();
+ ++p)
+ {
+ unsigned int i = *p;
+ const unsigned char* pshdr;
+ pshdr = section_headers_data + i * This::shdr_size;
+ typename This::Shdr shdr(pshdr);
+
+ this->layout_eh_frame_section(layout,
+ symbols_data,
+ symbols_size,
+ symbol_names_data,
+ symbol_names_size,
+ i,
+ shdr,
+ reloc_shndx[i],
+ reloc_type[i]);
+ }
+
+ // When doing a relocatable link handle the reloc sections at the
+ // end. Garbage collection and Identical Code Folding is not
+ // turned on for relocatable code.
+ if (emit_relocs)
+ this->size_relocatable_relocs();
+
+ gold_assert(!is_two_pass || reloc_sections.empty());
+
+ for (std::vector<unsigned int>::const_iterator p = reloc_sections.begin();
+ p != reloc_sections.end();
+ ++p)
+ {
+ unsigned int i = *p;
+ const unsigned char* pshdr;
+ pshdr = section_headers_data + i * This::shdr_size;
+ typename This::Shdr shdr(pshdr);
+
+ unsigned int data_shndx = this->adjust_shndx(shdr.get_sh_info());
+ if (data_shndx >= shnum)
+ {
+ // We already warned about this above.
+ continue;
+ }
+
+ Output_section* data_section = out_sections[data_shndx];
+ if (data_section == reinterpret_cast<Output_section*>(2))
+ {
+ if (is_pass_two)
+ continue;
+ // The layout for the data section was deferred, so we need
+ // to defer the relocation section, too.
+ const char* name = pnames + shdr.get_sh_name();
+ this->deferred_layout_relocs_.push_back(
+ Deferred_layout(i, name, pshdr, 0, elfcpp::SHT_NULL));
+ out_sections[i] = reinterpret_cast<Output_section*>(2);
+ out_section_offsets[i] = invalid_address;
+ continue;
+ }
+ if (data_section == NULL)
+ {
+ out_sections[i] = NULL;
+ out_section_offsets[i] = invalid_address;
+ continue;
+ }
+
+ Relocatable_relocs* rr = new Relocatable_relocs();
+ this->set_relocatable_relocs(i, rr);
+
+ Output_section* os = layout->layout_reloc(this, i, shdr, data_section,
+ rr);
+ out_sections[i] = os;
+ out_section_offsets[i] = invalid_address;
+ }
+
+ // When building a .gdb_index section, scan the .debug_info and
+ // .debug_types sections.
+ gold_assert(!is_pass_one
+ || (debug_info_sections.empty() && debug_types_sections.empty()));
+ for (std::vector<unsigned int>::const_iterator p
+ = debug_info_sections.begin();
+ p != debug_info_sections.end();
+ ++p)
+ {
+ unsigned int i = *p;
+ layout->add_to_gdb_index(false, this, symbols_data, symbols_size,
+ i, reloc_shndx[i], reloc_type[i]);
+ }
+ for (std::vector<unsigned int>::const_iterator p
+ = debug_types_sections.begin();
+ p != debug_types_sections.end();
+ ++p)
+ {
+ unsigned int i = *p;
+ layout->add_to_gdb_index(true, this, symbols_data, symbols_size,
+ i, reloc_shndx[i], reloc_type[i]);
+ }
+
+ if (is_pass_two)
+ {
+ delete[] gc_sd->section_headers_data;
+ delete[] gc_sd->section_names_data;
+ delete[] gc_sd->symbols_data;
+ delete[] gc_sd->symbol_names_data;
+ this->set_symbols_data(NULL);
+ }
+ else
+ {
+ delete sd->section_headers;
+ sd->section_headers = NULL;
+ delete sd->section_names;
+ sd->section_names = NULL;
+ }
+}
+
+// Layout sections whose layout was deferred while waiting for
+// input files from a plugin.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::do_layout_deferred_sections(Layout* layout)
+{
+ typename std::vector<Deferred_layout>::iterator deferred;
+
+ for (deferred = this->deferred_layout_.begin();
+ deferred != this->deferred_layout_.end();
+ ++deferred)
+ {
+ typename This::Shdr shdr(deferred->shdr_data_);
+
+ if (!parameters->options().relocatable()
+ && deferred->name_ == ".eh_frame"
+ && this->check_eh_frame_flags(&shdr))
+ {
+ // Checking is_section_included is not reliable for
+ // .eh_frame sections, because they do not have an output
+ // section. This is not a problem normally because we call
+ // layout_eh_frame_section unconditionally, but when
+ // deferring sections that is not true. We don't want to
+ // keep all .eh_frame sections because that will cause us to
+ // keep all sections that they refer to, which is the wrong
+ // way around. Instead, the eh_frame code will discard
+ // .eh_frame sections that refer to discarded sections.
+
+ // Reading the symbols again here may be slow.
+ Read_symbols_data sd;
+ this->base_read_symbols(&sd);
+ this->layout_eh_frame_section(layout,
+ sd.symbols->data(),
+ sd.symbols_size,
+ sd.symbol_names->data(),
+ sd.symbol_names_size,
+ deferred->shndx_,
+ shdr,
+ deferred->reloc_shndx_,
+ deferred->reloc_type_);
+ continue;
+ }
+
+ // If the section is not included, it is because the garbage collector
+ // decided it is not needed. Avoid reverting that decision.
+ if (!this->is_section_included(deferred->shndx_))
+ continue;
+
+ this->layout_section(layout, deferred->shndx_, deferred->name_.c_str(),
+ shdr, deferred->reloc_shndx_,
+ deferred->reloc_type_);
+ }
+
+ this->deferred_layout_.clear();
+
+ // Now handle the deferred relocation sections.
+
+ Output_sections& out_sections(this->output_sections());
+ std::vector<Address>& out_section_offsets(this->section_offsets());
+
+ for (deferred = this->deferred_layout_relocs_.begin();
+ deferred != this->deferred_layout_relocs_.end();
+ ++deferred)
+ {
+ unsigned int shndx = deferred->shndx_;
+ typename This::Shdr shdr(deferred->shdr_data_);
+ unsigned int data_shndx = this->adjust_shndx(shdr.get_sh_info());
+
+ Output_section* data_section = out_sections[data_shndx];
+ if (data_section == NULL)
+ {
+ out_sections[shndx] = NULL;
+ out_section_offsets[shndx] = invalid_address;
+ continue;
+ }
+
+ Relocatable_relocs* rr = new Relocatable_relocs();
+ this->set_relocatable_relocs(shndx, rr);
+
+ Output_section* os = layout->layout_reloc(this, shndx, shdr,
+ data_section, rr);
+ out_sections[shndx] = os;
+ out_section_offsets[shndx] = invalid_address;
+ }
+}
+
+// Add the symbols to the symbol table.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::do_add_symbols(Symbol_table* symtab,
+ Read_symbols_data* sd,
+ Layout*)
+{
+ if (sd->symbols == NULL)
+ {
+ gold_assert(sd->symbol_names == NULL);
+ return;
+ }
+
+ const int sym_size = This::sym_size;
+ size_t symcount = ((sd->symbols_size - sd->external_symbols_offset)
+ / sym_size);
+ if (symcount * sym_size != sd->symbols_size - sd->external_symbols_offset)
+ {
+ this->error(_("size of symbols is not multiple of symbol size"));
+ return;
+ }
+
+ this->symbols_.resize(symcount);
+
+ const char* sym_names =
+ reinterpret_cast<const char*>(sd->symbol_names->data());
+ symtab->add_from_relobj(this,
+ sd->symbols->data() + sd->external_symbols_offset,
+ symcount, this->local_symbol_count_,
+ sym_names, sd->symbol_names_size,
+ &this->symbols_,
+ &this->defined_count_);
+
+ delete sd->symbols;
+ sd->symbols = NULL;
+ delete sd->symbol_names;
+ sd->symbol_names = NULL;
+}
+
+// Find out if this object, that is a member of a lib group, should be included
+// in the link. We check every symbol defined by this object. If the symbol
+// table has a strong undefined reference to that symbol, we have to include
+// the object.
+
+template<int size, bool big_endian>
+Archive::Should_include
+Sized_relobj_file<size, big_endian>::do_should_include_member(
+ Symbol_table* symtab,
+ Layout* layout,
+ Read_symbols_data* sd,
+ std::string* why)
+{
+ char* tmpbuf = NULL;
+ size_t tmpbuflen = 0;
+ const char* sym_names =
+ reinterpret_cast<const char*>(sd->symbol_names->data());
+ const unsigned char* syms =
+ sd->symbols->data() + sd->external_symbols_offset;
+ const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+ size_t symcount = ((sd->symbols_size - sd->external_symbols_offset)
+ / sym_size);
+
+ const unsigned char* p = syms;
+
+ for (size_t i = 0; i < symcount; ++i, p += sym_size)
+ {
+ elfcpp::Sym<size, big_endian> sym(p);
+ unsigned int st_shndx = sym.get_st_shndx();
+ if (st_shndx == elfcpp::SHN_UNDEF)
+ continue;
+
+ unsigned int st_name = sym.get_st_name();
+ const char* name = sym_names + st_name;
+ Symbol* symbol;
+ Archive::Should_include t = Archive::should_include_member(symtab,
+ layout,
+ name,
+ &symbol, why,
+ &tmpbuf,
+ &tmpbuflen);
+ if (t == Archive::SHOULD_INCLUDE_YES)
+ {
+ if (tmpbuf != NULL)
+ free(tmpbuf);
+ return t;
+ }
+ }
+ if (tmpbuf != NULL)
+ free(tmpbuf);
+ return Archive::SHOULD_INCLUDE_UNKNOWN;
+}
+
+// Iterate over global defined symbols, calling a visitor class V for each.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::do_for_all_global_symbols(
+ Read_symbols_data* sd,
+ Library_base::Symbol_visitor_base* v)
+{
+ const char* sym_names =
+ reinterpret_cast<const char*>(sd->symbol_names->data());
+ const unsigned char* syms =
+ sd->symbols->data() + sd->external_symbols_offset;
+ const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+ size_t symcount = ((sd->symbols_size - sd->external_symbols_offset)
+ / sym_size);
+ const unsigned char* p = syms;
+
+ for (size_t i = 0; i < symcount; ++i, p += sym_size)
+ {
+ elfcpp::Sym<size, big_endian> sym(p);
+ if (sym.get_st_shndx() != elfcpp::SHN_UNDEF)
+ v->visit(sym_names + sym.get_st_name());
+ }
+}
+
+// Return whether the local symbol SYMNDX has a PLT offset.
+
+template<int size, bool big_endian>
+bool
+Sized_relobj_file<size, big_endian>::local_has_plt_offset(
+ unsigned int symndx) const
+{
+ typename Local_plt_offsets::const_iterator p =
+ this->local_plt_offsets_.find(symndx);
+ return p != this->local_plt_offsets_.end();
+}
+
+// Get the PLT offset of a local symbol.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_relobj_file<size, big_endian>::do_local_plt_offset(
+ unsigned int symndx) const
+{
+ typename Local_plt_offsets::const_iterator p =
+ this->local_plt_offsets_.find(symndx);
+ gold_assert(p != this->local_plt_offsets_.end());
+ return p->second;
+}
+
+// Set the PLT offset of a local symbol.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::set_local_plt_offset(
+ unsigned int symndx, unsigned int plt_offset)
+{
+ std::pair<typename Local_plt_offsets::iterator, bool> ins =
+ this->local_plt_offsets_.insert(std::make_pair(symndx, plt_offset));
+ gold_assert(ins.second);
+}
+
+// First pass over the local symbols. Here we add their names to
+// *POOL and *DYNPOOL, and we store the symbol value in
+// THIS->LOCAL_VALUES_. This function is always called from a
+// singleton thread. This is followed by a call to
+// finalize_local_symbols.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::do_count_local_symbols(Stringpool* pool,
+ Stringpool* dynpool)
+{
+ gold_assert(this->symtab_shndx_ != -1U);
+ if (this->symtab_shndx_ == 0)
+ {
+ // This object has no symbols. Weird but legal.
+ return;
+ }
+
+ // Read the symbol table section header.
+ const unsigned int symtab_shndx = this->symtab_shndx_;
+ typename This::Shdr symtabshdr(this,
+ this->elf_file_.section_header(symtab_shndx));
+ gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
+
+ // Read the local symbols.
+ const int sym_size = This::sym_size;
+ const unsigned int loccount = this->local_symbol_count_;
+ gold_assert(loccount == symtabshdr.get_sh_info());
+ off_t locsize = loccount * sym_size;
+ const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
+ locsize, true, true);
+
+ // Read the symbol names.
+ const unsigned int strtab_shndx =
+ this->adjust_shndx(symtabshdr.get_sh_link());
+ section_size_type strtab_size;
+ const unsigned char* pnamesu = this->section_contents(strtab_shndx,
+ &strtab_size,
+ true);
+ const char* pnames = reinterpret_cast<const char*>(pnamesu);
+
+ // Loop over the local symbols.
+
+ const Output_sections& out_sections(this->output_sections());
+ unsigned int shnum = this->shnum();
+ unsigned int count = 0;
+ unsigned int dyncount = 0;
+ // Skip the first, dummy, symbol.
+ psyms += sym_size;
+ bool strip_all = parameters->options().strip_all();
+ bool discard_all = parameters->options().discard_all();
+ bool discard_locals = parameters->options().discard_locals();
+ for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size)
+ {
+ elfcpp::Sym<size, big_endian> sym(psyms);
+
+ Symbol_value<size>& lv(this->local_values_[i]);
+
+ bool is_ordinary;
+ unsigned int shndx = this->adjust_sym_shndx(i, sym.get_st_shndx(),
+ &is_ordinary);
+ lv.set_input_shndx(shndx, is_ordinary);
+
+ if (sym.get_st_type() == elfcpp::STT_SECTION)
+ lv.set_is_section_symbol();
+ else if (sym.get_st_type() == elfcpp::STT_TLS)
+ lv.set_is_tls_symbol();
+ else if (sym.get_st_type() == elfcpp::STT_GNU_IFUNC)
+ lv.set_is_ifunc_symbol();
+
+ // Save the input symbol value for use in do_finalize_local_symbols().
+ lv.set_input_value(sym.get_st_value());
+
+ // Decide whether this symbol should go into the output file.
+
+ if ((shndx < shnum && out_sections[shndx] == NULL)
+ || shndx == this->discarded_eh_frame_shndx_)
+ {
+ lv.set_no_output_symtab_entry();
+ gold_assert(!lv.needs_output_dynsym_entry());
+ continue;
+ }
+
+ if (sym.get_st_type() == elfcpp::STT_SECTION
+ || !this->adjust_local_symbol(&lv))
+ {
+ lv.set_no_output_symtab_entry();
+ gold_assert(!lv.needs_output_dynsym_entry());
+ continue;
+ }
+
+ if (sym.get_st_name() >= strtab_size)
+ {
+ this->error(_("local symbol %u section name out of range: %u >= %u"),
+ i, sym.get_st_name(),
+ static_cast<unsigned int>(strtab_size));
+ lv.set_no_output_symtab_entry();
+ continue;
+ }
+
+ const char* name = pnames + sym.get_st_name();
+
+ // If needed, add the symbol to the dynamic symbol table string pool.
+ if (lv.needs_output_dynsym_entry())
+ {
+ dynpool->add(name, true, NULL);
+ ++dyncount;
+ }
+
+ if (strip_all
+ || (discard_all && lv.may_be_discarded_from_output_symtab()))
+ {
+ lv.set_no_output_symtab_entry();
+ continue;
+ }
+
+ // If --discard-locals option is used, discard all temporary local
+ // symbols. These symbols start with system-specific local label
+ // prefixes, typically .L for ELF system. We want to be compatible
+ // with GNU ld so here we essentially use the same check in
+ // bfd_is_local_label(). The code is different because we already
+ // know that:
+ //
+ // - the symbol is local and thus cannot have global or weak binding.
+ // - the symbol is not a section symbol.
+ // - the symbol has a name.
+ //
+ // We do not discard a symbol if it needs a dynamic symbol entry.
+ if (discard_locals
+ && sym.get_st_type() != elfcpp::STT_FILE
+ && !lv.needs_output_dynsym_entry()
+ && lv.may_be_discarded_from_output_symtab()
+ && parameters->target().is_local_label_name(name))
+ {
+ lv.set_no_output_symtab_entry();
+ continue;
+ }
+
+ // Discard the local symbol if -retain_symbols_file is specified
+ // and the local symbol is not in that file.
+ if (!parameters->options().should_retain_symbol(name))
+ {
+ lv.set_no_output_symtab_entry();
+ continue;
+ }
+
+ // Add the symbol to the symbol table string pool.
+ pool->add(name, true, NULL);
+ ++count;
+ }
+
+ this->output_local_symbol_count_ = count;
+ this->output_local_dynsym_count_ = dyncount;
+}
+
+// Compute the final value of a local symbol.
+
+template<int size, bool big_endian>
+typename Sized_relobj_file<size, big_endian>::Compute_final_local_value_status
+Sized_relobj_file<size, big_endian>::compute_final_local_value_internal(
+ unsigned int r_sym,
+ const Symbol_value<size>* lv_in,
+ Symbol_value<size>* lv_out,
+ bool relocatable,
+ const Output_sections& out_sections,
+ const std::vector<Address>& out_offsets,
+ const Symbol_table* symtab)
+{
+ // We are going to overwrite *LV_OUT, if it has a merged symbol value,
+ // we may have a memory leak.
+ gold_assert(lv_out->has_output_value());
+
+ bool is_ordinary;
+ unsigned int shndx = lv_in->input_shndx(&is_ordinary);
+
+ // Set the output symbol value.
+
+ if (!is_ordinary)
+ {
+ if (shndx == elfcpp::SHN_ABS || Symbol::is_common_shndx(shndx))
+ lv_out->set_output_value(lv_in->input_value());
+ else
+ {
+ this->error(_("unknown section index %u for local symbol %u"),
+ shndx, r_sym);
+ lv_out->set_output_value(0);
+ return This::CFLV_ERROR;
+ }
+ }
+ else
+ {
+ if (shndx >= this->shnum())
+ {
+ this->error(_("local symbol %u section index %u out of range"),
+ r_sym, shndx);
+ lv_out->set_output_value(0);
+ return This::CFLV_ERROR;
+ }
+
+ Output_section* os = out_sections[shndx];
+ Address secoffset = out_offsets[shndx];
+ if (symtab->is_section_folded(this, shndx))
+ {
+ gold_assert(os == NULL && secoffset == invalid_address);
+ // Get the os of the section it is folded onto.
+ Section_id folded = symtab->icf()->get_folded_section(this,
+ shndx);
+ gold_assert(folded.first != NULL);
+ Sized_relobj_file<size, big_endian>* folded_obj = reinterpret_cast
+ <Sized_relobj_file<size, big_endian>*>(folded.first);
+ os = folded_obj->output_section(folded.second);
+ gold_assert(os != NULL);
+ secoffset = folded_obj->get_output_section_offset(folded.second);
+
+ // This could be a relaxed input section.
+ if (secoffset == invalid_address)
+ {
+ const Output_relaxed_input_section* relaxed_section =
+ os->find_relaxed_input_section(folded_obj, folded.second);
+ gold_assert(relaxed_section != NULL);
+ secoffset = relaxed_section->address() - os->address();
+ }
+ }
+
+ if (os == NULL)
+ {
+ // This local symbol belongs to a section we are discarding.
+ // In some cases when applying relocations later, we will
+ // attempt to match it to the corresponding kept section,
+ // so we leave the input value unchanged here.
+ return This::CFLV_DISCARDED;
+ }
+ else if (secoffset == invalid_address)
+ {
+ uint64_t start;
+
+ // This is a SHF_MERGE section or one which otherwise
+ // requires special handling.
+ if (shndx == this->discarded_eh_frame_shndx_)
+ {
+ // This local symbol belongs to a discarded .eh_frame
+ // section. Just treat it like the case in which
+ // os == NULL above.
+ gold_assert(this->has_eh_frame_);
+ return This::CFLV_DISCARDED;
+ }
+ else if (!lv_in->is_section_symbol())
+ {
+ // This is not a section symbol. We can determine
+ // the final value now.
+ lv_out->set_output_value(
+ os->output_address(this, shndx, lv_in->input_value()));
+ }
+ else if (!os->find_starting_output_address(this, shndx, &start))
+ {
+ // This is a section symbol, but apparently not one in a
+ // merged section. First check to see if this is a relaxed
+ // input section. If so, use its address. Otherwise just
+ // use the start of the output section. This happens with
+ // relocatable links when the input object has section
+ // symbols for arbitrary non-merge sections.
+ const Output_section_data* posd =
+ os->find_relaxed_input_section(this, shndx);
+ if (posd != NULL)
+ {
+ Address relocatable_link_adjustment =
+ relocatable ? os->address() : 0;
+ lv_out->set_output_value(posd->address()
+ - relocatable_link_adjustment);
+ }
+ else
+ lv_out->set_output_value(os->address());
+ }
+ else
+ {
+ // We have to consider the addend to determine the
+ // value to use in a relocation. START is the start
+ // of this input section. If we are doing a relocatable
+ // link, use offset from start output section instead of
+ // address.
+ Address adjusted_start =
+ relocatable ? start - os->address() : start;
+ Merged_symbol_value<size>* msv =
+ new Merged_symbol_value<size>(lv_in->input_value(),
+ adjusted_start);
+ lv_out->set_merged_symbol_value(msv);
+ }
+ }
+ else if (lv_in->is_tls_symbol()
+ || (lv_in->is_section_symbol()
+ && (os->flags() & elfcpp::SHF_TLS)))
+ lv_out->set_output_value(os->tls_offset()
+ + secoffset
+ + lv_in->input_value());
+ else
+ lv_out->set_output_value((relocatable ? 0 : os->address())
+ + secoffset
+ + lv_in->input_value());
+ }
+ return This::CFLV_OK;
+}
+
+// Compute final local symbol value. R_SYM is the index of a local
+// symbol in symbol table. LV points to a symbol value, which is
+// expected to hold the input value and to be over-written by the
+// final value. SYMTAB points to a symbol table. Some targets may want
+// to know would-be-finalized local symbol values in relaxation.
+// Hence we provide this method. Since this method updates *LV, a
+// callee should make a copy of the original local symbol value and
+// use the copy instead of modifying an object's local symbols before
+// everything is finalized. The caller should also free up any allocated
+// memory in the return value in *LV.
+template<int size, bool big_endian>
+typename Sized_relobj_file<size, big_endian>::Compute_final_local_value_status
+Sized_relobj_file<size, big_endian>::compute_final_local_value(
+ unsigned int r_sym,
+ const Symbol_value<size>* lv_in,
+ Symbol_value<size>* lv_out,
+ const Symbol_table* symtab)
+{
+ // This is just a wrapper of compute_final_local_value_internal.
+ const bool relocatable = parameters->options().relocatable();
+ const Output_sections& out_sections(this->output_sections());
+ const std::vector<Address>& out_offsets(this->section_offsets());
+ return this->compute_final_local_value_internal(r_sym, lv_in, lv_out,
+ relocatable, out_sections,
+ out_offsets, symtab);
+}
+
+// Finalize the local symbols. Here we set the final value in
+// THIS->LOCAL_VALUES_ and set their output symbol table indexes.
+// This function is always called from a singleton thread. The actual
+// output of the local symbols will occur in a separate task.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_relobj_file<size, big_endian>::do_finalize_local_symbols(
+ unsigned int index,
+ off_t off,
+ Symbol_table* symtab)
+{
+ gold_assert(off == static_cast<off_t>(align_address(off, size >> 3)));
+
+ const unsigned int loccount = this->local_symbol_count_;
+ this->local_symbol_offset_ = off;
+
+ const bool relocatable = parameters->options().relocatable();
+ const Output_sections& out_sections(this->output_sections());
+ const std::vector<Address>& out_offsets(this->section_offsets());
+
+ for (unsigned int i = 1; i < loccount; ++i)
+ {
+ Symbol_value<size>* lv = &this->local_values_[i];
+
+ Compute_final_local_value_status cflv_status =
+ this->compute_final_local_value_internal(i, lv, lv, relocatable,
+ out_sections, out_offsets,
+ symtab);
+ switch (cflv_status)
+ {
+ case CFLV_OK:
+ if (!lv->is_output_symtab_index_set())
+ {
+ lv->set_output_symtab_index(index);
+ ++index;
+ }
+ break;
+ case CFLV_DISCARDED:
+ case CFLV_ERROR:
+ // Do nothing.
+ break;
+ default:
+ gold_unreachable();
+ }
+ }
+ return index;
+}
+
+// Set the output dynamic symbol table indexes for the local variables.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_relobj_file<size, big_endian>::do_set_local_dynsym_indexes(
+ unsigned int index)
+{
+ const unsigned int loccount = this->local_symbol_count_;
+ for (unsigned int i = 1; i < loccount; ++i)
+ {
+ Symbol_value<size>& lv(this->local_values_[i]);
+ if (lv.needs_output_dynsym_entry())
+ {
+ lv.set_output_dynsym_index(index);
+ ++index;
+ }
+ }
+ return index;
+}
+
+// Set the offset where local dynamic symbol information will be stored.
+// Returns the count of local symbols contributed to the symbol table by
+// this object.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_relobj_file<size, big_endian>::do_set_local_dynsym_offset(off_t off)
+{
+ gold_assert(off == static_cast<off_t>(align_address(off, size >> 3)));
+ this->local_dynsym_offset_ = off;
+ return this->output_local_dynsym_count_;
+}
+
+// If Symbols_data is not NULL get the section flags from here otherwise
+// get it from the file.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_relobj_file<size, big_endian>::do_section_flags(unsigned int shndx)
+{
+ Symbols_data* sd = this->get_symbols_data();
+ if (sd != NULL)
+ {
+ const unsigned char* pshdrs = sd->section_headers_data
+ + This::shdr_size * shndx;
+ typename This::Shdr shdr(pshdrs);
+ return shdr.get_sh_flags();
+ }
+ // If sd is NULL, read the section header from the file.
+ return this->elf_file_.section_flags(shndx);
+}
+
+// Get the section's ent size from Symbols_data. Called by get_section_contents
+// in icf.cc
+
+template<int size, bool big_endian>
+uint64_t
+Sized_relobj_file<size, big_endian>::do_section_entsize(unsigned int shndx)
+{
+ Symbols_data* sd = this->get_symbols_data();
+ gold_assert(sd != NULL);
+
+ const unsigned char* pshdrs = sd->section_headers_data
+ + This::shdr_size * shndx;
+ typename This::Shdr shdr(pshdrs);
+ return shdr.get_sh_entsize();
+}
+
+// Write out the local symbols.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::write_local_symbols(
+ Output_file* of,
+ const Stringpool* sympool,
+ const Stringpool* dynpool,
+ Output_symtab_xindex* symtab_xindex,
+ Output_symtab_xindex* dynsym_xindex,
+ off_t symtab_off)
+{
+ const bool strip_all = parameters->options().strip_all();
+ if (strip_all)
+ {
+ if (this->output_local_dynsym_count_ == 0)
+ return;
+ this->output_local_symbol_count_ = 0;
+ }
+
+ gold_assert(this->symtab_shndx_ != -1U);
+ if (this->symtab_shndx_ == 0)
+ {
+ // This object has no symbols. Weird but legal.
+ return;
+ }
+
+ // Read the symbol table section header.
+ const unsigned int symtab_shndx = this->symtab_shndx_;
+ typename This::Shdr symtabshdr(this,
+ this->elf_file_.section_header(symtab_shndx));
+ gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
+ const unsigned int loccount = this->local_symbol_count_;
+ gold_assert(loccount == symtabshdr.get_sh_info());
+
+ // Read the local symbols.
+ const int sym_size = This::sym_size;
+ off_t locsize = loccount * sym_size;
+ const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
+ locsize, true, false);
+
+ // Read the symbol names.
+ const unsigned int strtab_shndx =
+ this->adjust_shndx(symtabshdr.get_sh_link());
+ section_size_type strtab_size;
+ const unsigned char* pnamesu = this->section_contents(strtab_shndx,
+ &strtab_size,
+ false);
+ const char* pnames = reinterpret_cast<const char*>(pnamesu);
+
+ // Get views into the output file for the portions of the symbol table
+ // and the dynamic symbol table that we will be writing.
+ off_t output_size = this->output_local_symbol_count_ * sym_size;
+ unsigned char* oview = NULL;
+ if (output_size > 0)
+ oview = of->get_output_view(symtab_off + this->local_symbol_offset_,
+ output_size);
+
+ off_t dyn_output_size = this->output_local_dynsym_count_ * sym_size;
+ unsigned char* dyn_oview = NULL;
+ if (dyn_output_size > 0)
+ dyn_oview = of->get_output_view(this->local_dynsym_offset_,
+ dyn_output_size);
+
+ const Output_sections out_sections(this->output_sections());
+
+ gold_assert(this->local_values_.size() == loccount);
+
+ unsigned char* ov = oview;
+ unsigned char* dyn_ov = dyn_oview;
+ psyms += sym_size;
+ for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size)
+ {
+ elfcpp::Sym<size, big_endian> isym(psyms);
+
+ Symbol_value<size>& lv(this->local_values_[i]);
+
+ bool is_ordinary;
+ unsigned int st_shndx = this->adjust_sym_shndx(i, isym.get_st_shndx(),
+ &is_ordinary);
+ if (is_ordinary)
+ {
+ gold_assert(st_shndx < out_sections.size());
+ if (out_sections[st_shndx] == NULL)
+ continue;
+ st_shndx = out_sections[st_shndx]->out_shndx();
+ if (st_shndx >= elfcpp::SHN_LORESERVE)
+ {
+ if (lv.has_output_symtab_entry())
+ symtab_xindex->add(lv.output_symtab_index(), st_shndx);
+ if (lv.has_output_dynsym_entry())
+ dynsym_xindex->add(lv.output_dynsym_index(), st_shndx);
+ st_shndx = elfcpp::SHN_XINDEX;
+ }
+ }
+
+ // Write the symbol to the output symbol table.
+ if (lv.has_output_symtab_entry())
+ {
+ elfcpp::Sym_write<size, big_endian> osym(ov);
+
+ gold_assert(isym.get_st_name() < strtab_size);
+ const char* name = pnames + isym.get_st_name();
+ osym.put_st_name(sympool->get_offset(name));
+ osym.put_st_value(this->local_values_[i].value(this, 0));
+ osym.put_st_size(isym.get_st_size());
+ osym.put_st_info(isym.get_st_info());
+ osym.put_st_other(isym.get_st_other());
+ osym.put_st_shndx(st_shndx);
+
+ ov += sym_size;
+ }