aboutsummaryrefslogtreecommitdiff
path: root/gold/object.cc
diff options
context:
space:
mode:
authorCary Coutant <ccoutant@google.com>2008-05-01 01:23:21 +0000
committerCary Coutant <ccoutant@google.com>2008-05-01 01:23:21 +0000
commite94cf1277329c4eaba3b398b446e693550463c77 (patch)
treec3264396a84db5f5c415e8465cef5d21f58db7cf /gold/object.cc
parent1af5d7ceb5960c714e55c2fdf80c22b52db84738 (diff)
downloadgdb-e94cf1277329c4eaba3b398b446e693550463c77.zip
gdb-e94cf1277329c4eaba3b398b446e693550463c77.tar.gz
gdb-e94cf1277329c4eaba3b398b446e693550463c77.tar.bz2
* layout.cc (Layout::include_section): Refactored check for debug
info section. (Layout::add_comdat): Add new parameters. Change type of signature parameter. Add object and shndx to signatures table. (Layout::find_kept_object): New function. * layout.h: Include <cstring>. (Layout::is_debug_info_section): New function. (Layout::add_comdat): Add new parameters. (Layout::find_kept_object): New function. (Layout::Kept_section): New struct. (Layout::Signatures): Change type of map range. * object.cc (Relobj::output_section_address): New function. (Sized_relobj::include_section_group): Add new parameters. Change calls to Layout::add_comdat. Change to build table of kept comdat groups and table mapping discarded sections to kept sections. (Sized_relobj::include_linkonce_section): Likewise. Add new parameter. (Sized_relobj::do_layout): Change calls to include_section_group and include_linkonce_section. (Sized_relobj::do_finalize_local_symbols): Do not set local symbol value to zero when section is discarded. (Sized_relobj::map_to_kept_section): New function. * object.h (Relobj::output_section_address): New function. (Relobj::Comdat_group): New type. (Relobj::find_comdat_group): New function. (Relobj::Comdat_group_table): New type. (Relobj::Kept_comdat_section): New type. (Relobj::Kept_comdat_section_table): New type. (Relobj::add_comdat_group): New function. (Relobj::set_kept_comdat_section): New function. (Relobj::get_kept_comdat_section): New function. (Relobj::comdat_groups_): New field. (Relobj::kept_comdat_sections_): New field. (Symbol_value::input_value): Update comment. (Sized_relobj::map_to_kept_section) New function. (Sized_relobj::include_linkonce_section): Add new parameter. * target-reloc.h (Comdat_behavior): New type. (get_comdat_behavior): New function. (relocate_section): Add code to map a discarded section to the corresponding kept section when applying a relocation.
Diffstat (limited to 'gold/object.cc')
-rw-r--r--gold/object.cc184
1 files changed, 159 insertions, 25 deletions
diff --git a/gold/object.cc b/gold/object.cc
index 1672225..8f44411 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -230,6 +230,18 @@ Object::handle_gnu_warning_section(const char* name, unsigned int shndx,
return false;
}
+// Class Relobj.
+
+// Return the output address of the input section SHNDX.
+uint64_t
+Relobj::output_section_address(unsigned int shndx) const
+{
+ section_offset_type offset;
+ Output_section* os = this->output_section(shndx, &offset);
+ gold_assert(os != NULL && offset != -1);
+ return os->address() + offset;
+}
+
// Class Sized_relobj.
template<int size, bool big_endian>
@@ -510,10 +522,13 @@ Sized_relobj<size, big_endian>::include_section_group(
Layout* layout,
unsigned int index,
const char* name,
- const elfcpp::Shdr<size, big_endian>& shdr,
+ const unsigned char* shdrs,
+ const char* section_names,
+ section_size_type section_names_size,
std::vector<bool>* omit)
{
// Read the section contents.
+ typename This::Shdr shdr(shdrs + index * This::shdr_size);
const unsigned char* pcon = this->get_view(shdr.get_sh_offset(),
shdr.get_sh_size(), true, false);
const elfcpp::Elf_Word* pword =
@@ -562,12 +577,11 @@ Sized_relobj<size, big_endian>::include_section_group(
return false;
}
- const char* signature = psymnames + sym.get_st_name();
+ std::string signature(psymnames + sym.get_st_name());
// It seems that some versions of gas will create a section group
// associated with a section symbol, and then fail to give a name to
// the section symbol. In such a case, use the name of the section.
- std::string secname;
if (signature[0] == '\0' && sym.get_st_type() == elfcpp::STT_SECTION)
{
bool is_ordinary;
@@ -580,24 +594,40 @@ Sized_relobj<size, big_endian>::include_section_group(
symndx, sym_shndx);
return false;
}
- secname = this->section_name(sym_shndx);
- signature = secname.c_str();
+ typename This::Shdr member_shdr(shdrs + sym_shndx * This::shdr_size);
+ if (member_shdr.get_sh_name() < section_names_size)
+ signature = section_names + member_shdr.get_sh_name();
}
- // Record this section group, and see whether we've already seen one
- // with the same signature.
+ // Record this section group in the layout, and see whether we've already
+ // seen one with the same signature.
+ bool include_group = ((flags & elfcpp::GRP_COMDAT) == 0
+ || layout->add_comdat(this, index, signature, true));
+
+ if (include_group && parameters->options().relocatable())
+ layout->layout_group(symtab, this, index, name, signature.c_str(),
+ shdr, pword);
+
+ Relobj* kept_object = NULL;
+ Comdat_group* kept_group = NULL;
- if ((flags & elfcpp::GRP_COMDAT) == 0
- || layout->add_comdat(signature, true))
+ if (!include_group)
{
- if (parameters->options().relocatable())
- layout->layout_group(symtab, this, index, name, signature, shdr,
- pword);
- return true;
+ // This group is being discarded. Find the object and group
+ // that was kept in its place.
+ unsigned int kept_group_index = 0;
+ kept_object = layout->find_kept_object(signature, &kept_group_index);
+ if (kept_object != NULL)
+ kept_group = kept_object->find_comdat_group(kept_group_index);
+ }
+ else if (flags & elfcpp::GRP_COMDAT)
+ {
+ // This group is being kept. Create the table to map section names
+ // to section indexes and add it to the table of groups.
+ kept_group = new Comdat_group();
+ this->add_comdat_group(index, kept_group);
}
- // This is a duplicate. We want to discard the sections in this
- // group.
size_t count = shdr.get_sh_size() / sizeof(elfcpp::Elf_Word);
for (size_t i = 1; i < count; ++i)
{
@@ -616,10 +646,42 @@ Sized_relobj<size, big_endian>::include_section_group(
this->error(_("invalid section group %u refers to earlier section %u"),
index, secnum);
- (*omit)[secnum] = true;
+ // Get the name of the member section.
+ typename This::Shdr member_shdr(shdrs + secnum * This::shdr_size);
+ if (member_shdr.get_sh_name() >= section_names_size)
+ {
+ // This is an error, but it will be diagnosed eventually
+ // in do_layout, so we don't need to do anything here but
+ // ignore it.
+ continue;
+ }
+ std::string mname(section_names + member_shdr.get_sh_name());
+
+ if (!include_group)
+ {
+ (*omit)[secnum] = true;
+ if (kept_group != NULL)
+ {
+ // Find the corresponding kept section, and store that info
+ // in the discarded section table.
+ Comdat_group::const_iterator p = kept_group->find(mname);
+ if (p != kept_group->end())
+ {
+ Kept_comdat_section* kept =
+ new Kept_comdat_section(kept_object, p->second);
+ this->set_kept_comdat_section(secnum, kept);
+ }
+ }
+ }
+ else if (flags & elfcpp::GRP_COMDAT)
+ {
+ // Add the section to the kept group table.
+ gold_assert(kept_group != NULL);
+ kept_group->insert(std::make_pair(mname, secnum));
+ }
}
- return false;
+ return include_group;
}
// Whether to include a linkonce section in the link. NAME is the
@@ -641,6 +703,7 @@ template<int size, bool big_endian>
bool
Sized_relobj<size, big_endian>::include_linkonce_section(
Layout* layout,
+ unsigned int index,
const char* name,
const elfcpp::Shdr<size, big_endian>&)
{
@@ -658,8 +721,52 @@ Sized_relobj<size, big_endian>::include_linkonce_section(
symname = name + strlen(linkonce_t);
else
symname = strrchr(name, '.') + 1;
- bool include1 = layout->add_comdat(symname, false);
- bool include2 = layout->add_comdat(name, true);
+ std::string sig1(symname);
+ std::string sig2(name);
+ bool include1 = layout->add_comdat(this, index, sig1, false);
+ bool include2 = layout->add_comdat(this, index, sig2, true);
+
+ if (!include2)
+ {
+ // The section is being discarded on the basis of its section
+ // name (i.e., the kept section was also a linkonce section).
+ // In this case, the section index stored with the layout object
+ // is the linkonce section that was kept.
+ unsigned int kept_group_index = 0;
+ Relobj* kept_object = layout->find_kept_object(sig2, &kept_group_index);
+ if (kept_object != NULL)
+ {
+ Kept_comdat_section* kept =
+ new Kept_comdat_section(kept_object, kept_group_index);
+ this->set_kept_comdat_section(index, kept);
+ }
+ }
+ else if (!include1)
+ {
+ // The section is being discarded on the basis of its symbol
+ // name. This means that the corresponding kept section was
+ // part of a comdat group, and it will be difficult to identify
+ // the specific section within that group that corresponds to
+ // 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_group_index = 0;
+ Relobj* kept_object = layout->find_kept_object(sig1, &kept_group_index);
+ if (kept_object != NULL)
+ {
+ Comdat_group* kept_group =
+ kept_object->find_comdat_group(kept_group_index);
+ if (kept_group != NULL && kept_group->size() == 1)
+ {
+ Comdat_group::const_iterator p = kept_group->begin();
+ gold_assert(p != kept_group->end());
+ Kept_comdat_section* kept =
+ new Kept_comdat_section(kept_object, p->second);
+ this->set_kept_comdat_section(index, kept);
+ }
+ }
+ }
+
return include1 && include2;
}
@@ -679,7 +786,8 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
return;
// Get the section headers.
- const unsigned char* pshdrs = sd->section_headers->data();
+ const unsigned char* shdrs = sd->section_headers->data();
+ const unsigned char* pshdrs;
// Get the section names.
const unsigned char* pnamesu = sd->section_names->data();
@@ -691,7 +799,7 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
std::vector<unsigned int> reloc_shndx(shnum, 0);
std::vector<unsigned int> reloc_type(shnum, elfcpp::SHT_NULL);
// Skip the first, dummy, section.
- pshdrs += This::shdr_size;
+ pshdrs = shdrs + This::shdr_size;
for (unsigned int i = 1; i < shnum; ++i, pshdrs += This::shdr_size)
{
typename This::Shdr shdr(pshdrs);
@@ -749,7 +857,7 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
std::vector<unsigned int> eh_frame_sections;
// Skip the first, dummy, section.
- pshdrs = sd->section_headers->data() + This::shdr_size;
+ pshdrs = shdrs + This::shdr_size;
for (unsigned int i = 1; i < shnum; ++i, pshdrs += This::shdr_size)
{
typename This::Shdr shdr(pshdrs);
@@ -784,14 +892,15 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
{
if (shdr.get_sh_type() == elfcpp::SHT_GROUP)
{
- if (!this->include_section_group(symtab, layout, i, name, shdr,
+ if (!this->include_section_group(symtab, layout, i, name, shdrs,
+ pnames, sd->section_names_size,
&omit))
discard = true;
}
else if ((shdr.get_sh_flags() & elfcpp::SHF_GROUP) == 0
&& Layout::is_linkonce(name))
{
- if (!this->include_linkonce_section(layout, name, shdr))
+ if (!this->include_linkonce_section(layout, i, name, shdr))
discard = true;
}
}
@@ -1124,7 +1233,10 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
if (os == NULL)
{
- lv.set_output_value(0);
+ // 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.
continue;
}
else if (mo[shndx].offset == -1)
@@ -1417,6 +1529,28 @@ Sized_relobj<size, big_endian>::get_symbol_location_info(
return false;
}
+// Look for a kept section corresponding to the given discarded section,
+// and return its output address. This is used only for relocations in
+// debugging sections. If we can't find the kept section, return 0.
+
+template<int size, bool big_endian>
+typename Sized_relobj<size, big_endian>::Address
+Sized_relobj<size, big_endian>::map_to_kept_section(
+ unsigned int shndx,
+ bool* found) const
+{
+ Kept_comdat_section *kept = this->get_kept_comdat_section(shndx);
+ if (kept != NULL)
+ {
+ gold_assert(kept->object_ != NULL);
+ *found = true;
+ return (static_cast<Address>
+ (kept->object_->output_section_address(kept->shndx_)));
+ }
+ *found = false;
+ return 0;
+}
+
// Input_objects methods.
// Add a regular relocatable object to the list. Return false if this