// object.cc -- support for an object file for linking in gold
-// Copyright (C) 2006-2017 Free Software Foundation, Inc.
+// Copyright (C) 2006-2018 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
local_plt_offsets_(),
kept_comdat_sections_(),
has_eh_frame_(false),
- discarded_eh_frame_shndx_(-1U),
is_deferred_layout_(false),
deferred_layout_(),
deferred_layout_relocs_(),
{
elfcpp::Elf_Word sh_type = shdr->get_sh_type();
return ((sh_type == elfcpp::SHT_PROGBITS
- || sh_type == elfcpp::SHT_X86_64_UNWIND)
+ || sh_type == parameters->target().unwind_section_type())
&& (shdr->get_sh_flags() & elfcpp::SHF_ALLOC) != 0);
}
{
(*omit)[shndx] = true;
- if (is_comdat)
- {
- Relobj* kept_object = kept_section->object();
- if (kept_section->is_comdat())
- {
- // Find the corresponding kept section, and store
- // that info in the discarded section table.
- unsigned int kept_shndx;
- uint64_t kept_size;
- if (kept_section->find_comdat_section(mname, &kept_shndx,
- &kept_size))
- {
- // We don't keep a mapping for this section if
- // it has a different size. The mapping is only
- // used for relocation processing, and we don't
- // want to treat the sections as similar if the
- // sizes are different. Checking the section
- // size is the approach used by the GNU linker.
- if (kept_size == member_shdr.get_sh_size())
- this->set_kept_comdat_section(shndx, kept_object,
- kept_shndx);
- }
- }
- else
- {
- // The existing section is a linkonce section. Add
- // a mapping if there is exactly one section in the
- // group (which is true when COUNT == 2) and if it
- // is the same size.
- if (count == 2
- && (kept_section->linkonce_size()
- == member_shdr.get_sh_size()))
- this->set_kept_comdat_section(shndx, kept_object,
- kept_section->shndx());
- }
- }
+ // Store a mapping from this section to the Kept_section
+ // information for the group. This mapping is used for
+ // relocation processing and diagnostics.
+ // If the kept section is a linkonce section, we don't
+ // bother with it unless the comdat group contains just
+ // a single section, making it easy to match up.
+ if (is_comdat
+ && (kept_section->is_comdat() || count == 2))
+ this->set_kept_comdat_section(shndx, true, symndx,
+ member_shdr.get_sh_size(),
+ kept_section);
}
}
// that the kept section is another linkonce section. If it is
// the same size, record it as the section which corresponds to
// this one.
- if (kept2->object() != NULL
- && !kept2->is_comdat()
- && kept2->linkonce_size() == sh_size)
- this->set_kept_comdat_section(index, kept2->object(), kept2->shndx());
+ if (kept2->object() != NULL && !kept2->is_comdat())
+ this->set_kept_comdat_section(index, false, 0, sh_size, kept2);
}
else if (!include1)
{
// this linkonce section. We'll handle the simple case where
// the group has only one member section. Otherwise, it's not
// worth the effort.
- unsigned int kept_shndx;
- uint64_t kept_size;
- if (kept1->object() != NULL
- && kept1->is_comdat()
- && kept1->find_single_comdat_section(&kept_shndx, &kept_size)
- && kept_size == sh_size)
- this->set_kept_comdat_section(index, kept1->object(), kept_shndx);
+ if (kept1->object() != NULL && kept1->is_comdat())
+ this->set_kept_comdat_section(index, false, 0, sh_size, kept1);
}
else
{
unsigned int shndx,
const char* name,
const typename This::Shdr& shdr,
+ unsigned int sh_type,
unsigned int reloc_shndx,
unsigned int reloc_type)
{
off_t offset;
- Output_section* os = layout->layout(this, shndx, name, shdr,
- reloc_shndx, reloc_type, &offset);
+ Output_section* os = layout->layout(this, shndx, name, shdr, sh_type,
+ reloc_shndx, reloc_type, &offset);
this->output_sections()[shndx] = os;
if (offset == -1)
&offset);
this->output_sections()[shndx] = os;
if (os == NULL || offset == -1)
- {
- // An object can contain at most one section holding exception
- // frame information.
- gold_assert(this->discarded_eh_frame_shndx_ == -1U);
- this->discarded_eh_frame_shndx_ = shndx;
- this->section_offsets()[shndx] = invalid_address;
- }
+ this->section_offsets()[shndx] = invalid_address;
else
this->section_offsets()[shndx] = convert_types<Address, off_t>(offset);
Layout* layout,
Read_symbols_data* sd)
{
+ const unsigned int unwind_section_type =
+ parameters->target().unwind_section_type();
const unsigned int shnum = this->shnum();
/* Should this function be called twice? */
for (unsigned int i = 1; i < shnum; ++i, pshdrs += This::shdr_size)
{
typename This::Shdr shdr(pshdrs);
+ const unsigned int sh_name = shdr.get_sh_name();
+ unsigned int sh_type = shdr.get_sh_type();
- if (shdr.get_sh_name() >= section_names_size)
+ if (sh_name >= section_names_size)
{
this->error(_("bad section name offset for section %u: %lu"),
- i, static_cast<unsigned long>(shdr.get_sh_name()));
+ i, static_cast<unsigned long>(sh_name));
return;
}
- const char* name = pnames + shdr.get_sh_name();
+ const char* name = pnames + sh_name;
if (!is_pass_two)
{
bool discard = omit[i];
if (!discard)
{
- if (shdr.get_sh_type() == elfcpp::SHT_GROUP)
+ if (sh_type == elfcpp::SHT_GROUP)
{
if (!this->include_section_group(symtab, layout, i, name,
shdrs, pnames,
Incremental_inputs* incremental_inputs = layout->incremental_inputs();
if (incremental_inputs != NULL
&& !discard
- && can_incremental_update(shdr.get_sh_type()))
+ && can_incremental_update(sh_type))
{
off_t sh_size = shdr.get_sh_size();
section_size_type uncompressed_size;
{
if (this->is_section_name_included(name)
|| layout->keep_input_section (this, name)
- || shdr.get_sh_type() == elfcpp::SHT_INIT_ARRAY
- || shdr.get_sh_type() == elfcpp::SHT_FINI_ARRAY)
+ || sh_type == elfcpp::SHT_INIT_ARRAY
+ || sh_type == elfcpp::SHT_FINI_ARRAY)
{
symtab->gc()->worklist().push_back(Section_id(this, i));
}
// reloc sections and process them later. Garbage collection is
// not triggered when relocatable code is desired.
if (emit_relocs
- && (shdr.get_sh_type() == elfcpp::SHT_REL
- || shdr.get_sh_type() == elfcpp::SHT_RELA))
+ && (sh_type == elfcpp::SHT_REL
+ || sh_type == elfcpp::SHT_RELA))
{
reloc_sections.push_back(i);
continue;
}
- if (relocatable && shdr.get_sh_type() == elfcpp::SHT_GROUP)
+ if (relocatable && sh_type == elfcpp::SHT_GROUP)
continue;
// The .eh_frame section is special. It holds exception frame
// sections so that the exception frame reader can reliably
// determine which sections are being discarded, and discard the
// corresponding information.
- if (!relocatable
- && strcmp(name, ".eh_frame") == 0
- && this->check_eh_frame_flags(&shdr))
+ if (this->check_eh_frame_flags(&shdr)
+ && strcmp(name, ".eh_frame") == 0)
{
- if (is_pass_one)
+ // If the target has a special unwind section type, let's
+ // canonicalize it here.
+ sh_type = unwind_section_type;
+ if (!relocatable)
{
- if (this->is_deferred_layout())
- out_sections[i] = reinterpret_cast<Output_section*>(2);
+ if (is_pass_one)
+ {
+ if (this->is_deferred_layout())
+ out_sections[i] = reinterpret_cast<Output_section*>(2);
+ else
+ out_sections[i] = reinterpret_cast<Output_section*>(1);
+ out_section_offsets[i] = invalid_address;
+ }
+ else if (this->is_deferred_layout())
+ this->deferred_layout_.push_back(
+ Deferred_layout(i, name, sh_type, pshdrs,
+ reloc_shndx[i], reloc_type[i]));
else
- out_sections[i] = reinterpret_cast<Output_section*>(1);
- out_section_offsets[i] = invalid_address;
+ eh_frame_sections.push_back(i);
+ continue;
}
- else if (this->is_deferred_layout())
- this->deferred_layout_.push_back(Deferred_layout(i, name,
- pshdrs,
- reloc_shndx[i],
- reloc_type[i]));
- else
- eh_frame_sections.push_back(i);
- continue;
}
if (is_pass_two && parameters->options().gc_sections())
&& this->is_deferred_layout()
&& (shdr.get_sh_flags() & elfcpp::SHF_ALLOC))
{
- this->deferred_layout_.push_back(Deferred_layout(i, name,
+ this->deferred_layout_.push_back(Deferred_layout(i, name, sh_type,
pshdrs,
reloc_shndx[i],
reloc_type[i]));
{
// When garbage collection is switched on the actual layout
// only happens in the second call.
- this->layout_section(layout, i, name, shdr, reloc_shndx[i],
+ this->layout_section(layout, i, name, shdr, sh_type, reloc_shndx[i],
reloc_type[i]);
// When generating a .gdb_index section, we do additional
// 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));
+ Deferred_layout(i, name, shdr.get_sh_type(), pshdr, 0,
+ elfcpp::SHT_NULL));
out_sections[i] = reinterpret_cast<Output_section*>(2);
out_section_offsets[i] = invalid_address;
continue;
continue;
this->layout_section(layout, deferred->shndx_, deferred->name_.c_str(),
- shdr, deferred->reloc_shndx_,
+ shdr, shdr.get_sh_type(), deferred->reloc_shndx_,
deferred->reloc_type_);
}
// Decide whether this symbol should go into the output file.
if (is_ordinary
- && ((shndx < shnum && out_sections[shndx] == NULL)
- || shndx == this->discarded_eh_frame_shndx_))
+ && shndx < shnum
+ && (out_sections[shndx] == NULL
+ || (out_sections[shndx]->order() == ORDER_EHFRAME
+ && out_section_offsets[shndx] == invalid_address)))
{
+ // This is either a discarded section or an optimized .eh_frame
+ // section.
lv.set_no_output_symtab_entry();
gold_assert(!lv.needs_output_dynsym_entry());
continue;
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)
// This is a SHF_MERGE section or one which otherwise
// requires special handling.
- if (shndx == this->discarded_eh_frame_shndx_)
+ if (os->order() == ORDER_EHFRAME)
{
- // This local symbol belongs to a discarded .eh_frame
- // section. Just treat it like the case in which
+ // This local symbol belongs to a discarded or optimized
+ // .eh_frame section. Just treat it like the case in which
// os == NULL above.
gold_assert(this->has_eh_frame_);
return This::CFLV_DISCARDED;
{
// 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()));
+ uint64_t value =
+ os->output_address(this, shndx, lv_in->input_value());
+ if (relocatable)
+ value -= os->address();
+ lv_out->set_output_value(value);
}
else if (!os->find_starting_output_address(this, shndx, &start))
{
os->find_relaxed_input_section(this, shndx);
if (posd != NULL)
{
- lv_out->set_output_value(posd->address());
+ uint64_t value = posd->address();
+ if (relocatable)
+ value -= os->address();
+ lv_out->set_output_value(value);
}
else
lv_out->set_output_value(os->address());
{
// We have to consider the addend to determine the
// value to use in a relocation. START is the start
- // of this input section.
+ // 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(),
- start);
+ adjusted_start);
lv_out->set_merged_symbol_value(msv);
}
}
+ secoffset
+ lv_in->input_value());
else
- lv_out->set_output_value(os->address()
+ lv_out->set_output_value((relocatable ? 0 : os->address())
+ secoffset
+ lv_in->input_value());
}
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,
- out_sections, out_offsets,
- symtab);
+ relocatable, out_sections,
+ out_offsets, symtab);
}
// Finalize the local symbols. Here we set the final value in
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());
Symbol_value<size>* lv = &this->local_values_[i];
Compute_final_local_value_status cflv_status =
- this->compute_final_local_value_internal(i, lv, lv, out_sections,
- out_offsets, symtab);
+ this->compute_final_local_value_internal(i, lv, lv, relocatable,
+ out_sections, out_offsets,
+ symtab);
switch (cflv_status)
{
case CFLV_OK:
elfcpp::Sym<size, big_endian> isym(psyms);
Symbol_value<size>& lv(this->local_values_[i]);
- typename elfcpp::Elf_types<size>::Elf_Addr sym_value = lv.value(this, 0);
bool is_ordinary;
unsigned int st_shndx = this->adjust_sym_shndx(i, isym.get_st_shndx(),
gold_assert(st_shndx < out_sections.size());
if (out_sections[st_shndx] == NULL)
continue;
- // In relocatable object files symbol values are section relative.
- if (parameters->options().relocatable())
- sym_value -= out_sections[st_shndx]->address();
st_shndx = out_sections[st_shndx]->out_shndx();
if (st_shndx >= elfcpp::SHN_LORESERVE)
{
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(sym_value);
+ osym.put_st_value(lv.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());
gold_assert(isym.get_st_name() < strtab_size);
const char* name = pnames + isym.get_st_name();
osym.put_st_name(dynpool->get_offset(name));
- osym.put_st_value(sym_value);
+ osym.put_st_value(lv.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());
typename Sized_relobj_file<size, big_endian>::Address
Sized_relobj_file<size, big_endian>::map_to_kept_section(
unsigned int shndx,
- bool* found) const
+ std::string& section_name,
+ bool* pfound) const
{
- Relobj* kept_object;
- unsigned int kept_shndx;
- if (this->get_kept_comdat_section(shndx, &kept_object, &kept_shndx))
- {
- Sized_relobj_file<size, big_endian>* kept_relobj =
- static_cast<Sized_relobj_file<size, big_endian>*>(kept_object);
- Output_section* os = kept_relobj->output_section(kept_shndx);
- Address offset = kept_relobj->get_output_section_offset(kept_shndx);
- if (os != NULL && offset != invalid_address)
+ Kept_section* kept_section;
+ bool is_comdat;
+ uint64_t sh_size;
+ unsigned int symndx;
+ bool found = false;
+
+ if (this->get_kept_comdat_section(shndx, &is_comdat, &symndx, &sh_size,
+ &kept_section))
+ {
+ Relobj* kept_object = kept_section->object();
+ unsigned int kept_shndx = 0;
+ if (!kept_section->is_comdat())
+ {
+ // The kept section is a linkonce section.
+ if (sh_size == kept_section->linkonce_size())
+ found = true;
+ }
+ else
{
- *found = true;
- return os->address() + offset;
+ if (is_comdat)
+ {
+ // Find the corresponding kept section.
+ // Since we're using this mapping for relocation processing,
+ // we don't want to match sections unless they have the same
+ // size.
+ uint64_t kept_size;
+ if (kept_section->find_comdat_section(section_name, &kept_shndx,
+ &kept_size))
+ {
+ if (sh_size == kept_size)
+ found = true;
+ }
+ }
+ else
+ {
+ uint64_t kept_size;
+ if (kept_section->find_single_comdat_section(&kept_shndx,
+ &kept_size)
+ && sh_size == kept_size)
+ found = true;
+ }
+ }
+
+ if (found)
+ {
+ Sized_relobj_file<size, big_endian>* kept_relobj =
+ static_cast<Sized_relobj_file<size, big_endian>*>(kept_object);
+ Output_section* os = kept_relobj->output_section(kept_shndx);
+ Address offset = kept_relobj->get_output_section_offset(kept_shndx);
+ if (os != NULL && offset != invalid_address)
+ {
+ *pfound = true;
+ return os->address() + offset;
+ }
}
}
- *found = false;
+ *pfound = false;
return 0;
}
+// Look for a kept section corresponding to the given discarded section,
+// and return its object file.
+
+template<int size, bool big_endian>
+Relobj*
+Sized_relobj_file<size, big_endian>::find_kept_section_object(
+ unsigned int shndx, unsigned int *symndx_p) const
+{
+ Kept_section* kept_section;
+ bool is_comdat;
+ uint64_t sh_size;
+ if (this->get_kept_comdat_section(shndx, &is_comdat, symndx_p, &sh_size,
+ &kept_section))
+ return kept_section->object();
+ return NULL;
+}
+
+// Return the name of symbol SYMNDX.
+
+template<int size, bool big_endian>
+const char*
+Sized_relobj_file<size, big_endian>::get_symbol_name(unsigned int symndx)
+{
+ if (this->symtab_shndx_ == 0)
+ return NULL;
+
+ section_size_type symbols_size;
+ const unsigned char* symbols = this->section_contents(this->symtab_shndx_,
+ &symbols_size,
+ false);
+
+ unsigned int symbol_names_shndx =
+ this->adjust_shndx(this->section_link(this->symtab_shndx_));
+ section_size_type names_size;
+ const unsigned char* symbol_names_u =
+ this->section_contents(symbol_names_shndx, &names_size, false);
+ const char* symbol_names = reinterpret_cast<const char*>(symbol_names_u);
+
+ const unsigned char* p = symbols + symndx * This::sym_size;
+
+ if (p >= symbols + symbols_size)
+ return NULL;
+
+ elfcpp::Sym<size, big_endian> sym(p);
+
+ return symbol_names + sym.get_st_name();
+}
+
// Get symbol counts.
template<int size, bool big_endian>