mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-03 05:12:28 +08:00
* 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.
This commit is contained in:
@ -1,3 +1,45 @@
|
|||||||
|
2008-04-30 Cary Coutant <ccoutant@google.com>
|
||||||
|
|
||||||
|
* 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.
|
||||||
|
|
||||||
2008-04-30 Craig Silverstein <csilvers@google.com>
|
2008-04-30 Craig Silverstein <csilvers@google.com>
|
||||||
|
|
||||||
* dwarf_reader.cc (next_generation_count): New static var.
|
* dwarf_reader.cc (next_generation_count): New static var.
|
||||||
|
@ -192,11 +192,7 @@ Layout::include_section(Sized_relobj<size, big_endian>*, const char* name,
|
|||||||
if (parameters->options().strip_debug()
|
if (parameters->options().strip_debug()
|
||||||
&& (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
|
&& (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
|
||||||
{
|
{
|
||||||
// Debugging sections can only be recognized by name.
|
if (is_debug_info_section(name))
|
||||||
if (is_prefix_of(".debug", name)
|
|
||||||
|| is_prefix_of(".gnu.linkonce.wi.", name)
|
|
||||||
|| is_prefix_of(".line", name)
|
|
||||||
|| is_prefix_of(".stab", name))
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (parameters->options().strip_debug_gdb()
|
if (parameters->options().strip_debug_gdb()
|
||||||
@ -2770,11 +2766,12 @@ Layout::output_section_name(const char* name, size_t* plen)
|
|||||||
// want a linkonce signature to block another linkonce signature.
|
// want a linkonce signature to block another linkonce signature.
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Layout::add_comdat(const char* signature, bool group)
|
Layout::add_comdat(Relobj* object, unsigned int shndx,
|
||||||
|
const std::string& signature, bool group)
|
||||||
{
|
{
|
||||||
std::string sig(signature);
|
Kept_section kept(object, shndx, group);
|
||||||
std::pair<Signatures::iterator, bool> ins(
|
std::pair<Signatures::iterator, bool> ins(
|
||||||
this->signatures_.insert(std::make_pair(sig, group)));
|
this->signatures_.insert(std::make_pair(signature, kept)));
|
||||||
|
|
||||||
if (ins.second)
|
if (ins.second)
|
||||||
{
|
{
|
||||||
@ -2782,7 +2779,7 @@ Layout::add_comdat(const char* signature, bool group)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ins.first->second)
|
if (ins.first->second.group_)
|
||||||
{
|
{
|
||||||
// We've already seen a real section group with this signature.
|
// We've already seen a real section group with this signature.
|
||||||
return false;
|
return false;
|
||||||
@ -2792,7 +2789,7 @@ Layout::add_comdat(const char* signature, bool group)
|
|||||||
// This is a real section group, and we've already seen a
|
// This is a real section group, and we've already seen a
|
||||||
// linkonce section with this signature. Record that we've seen
|
// linkonce section with this signature. Record that we've seen
|
||||||
// a section group, and don't include this section group.
|
// a section group, and don't include this section group.
|
||||||
ins.first->second = true;
|
ins.first->second.group_ = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -2804,6 +2801,20 @@ Layout::add_comdat(const char* signature, bool group)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find the given comdat signature, and return the object and section
|
||||||
|
// index of the kept group.
|
||||||
|
Relobj*
|
||||||
|
Layout::find_kept_object(const std::string& signature,
|
||||||
|
unsigned int* pshndx) const
|
||||||
|
{
|
||||||
|
Signatures::const_iterator p = this->signatures_.find(signature);
|
||||||
|
if (p == this->signatures_.end())
|
||||||
|
return NULL;
|
||||||
|
if (pshndx != NULL)
|
||||||
|
*pshndx = p->second.shndx_;
|
||||||
|
return p->second.object_;
|
||||||
|
}
|
||||||
|
|
||||||
// Store the allocated sections into the section list.
|
// Store the allocated sections into the section list.
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#ifndef GOLD_LAYOUT_H
|
#ifndef GOLD_LAYOUT_H
|
||||||
#define GOLD_LAYOUT_H
|
#define GOLD_LAYOUT_H
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@ -212,12 +213,29 @@ class Layout
|
|||||||
is_linkonce(const char* name)
|
is_linkonce(const char* name)
|
||||||
{ return strncmp(name, ".gnu.linkonce", sizeof(".gnu.linkonce") - 1) == 0; }
|
{ return strncmp(name, ".gnu.linkonce", sizeof(".gnu.linkonce") - 1) == 0; }
|
||||||
|
|
||||||
|
// Return true if a section is a debugging section.
|
||||||
|
static inline bool
|
||||||
|
is_debug_info_section(const char* name)
|
||||||
|
{
|
||||||
|
// Debugging sections can only be recognized by name.
|
||||||
|
return (strncmp(name, ".debug", sizeof(".debug") - 1) == 0
|
||||||
|
|| strncmp(name, ".gnu.linkonce.wi.",
|
||||||
|
sizeof(".gnu.linkonce.wi.") - 1) == 0
|
||||||
|
|| strncmp(name, ".line", sizeof(".line") - 1) == 0
|
||||||
|
|| strncmp(name, ".stab", sizeof(".stab") - 1) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
// Record the signature of a comdat section, and return whether to
|
// Record the signature of a comdat section, and return whether to
|
||||||
// include it in the link. The GROUP parameter is true for a
|
// include it in the link. The GROUP parameter is true for a
|
||||||
// section group signature, false for a signature derived from a
|
// section group signature, false for a signature derived from a
|
||||||
// .gnu.linkonce section.
|
// .gnu.linkonce section.
|
||||||
bool
|
bool
|
||||||
add_comdat(const char*, bool group);
|
add_comdat(Relobj*, unsigned int, const std::string&, bool group);
|
||||||
|
|
||||||
|
// Find the given comdat signature, and return the object and section
|
||||||
|
// index of the kept group.
|
||||||
|
Relobj*
|
||||||
|
find_kept_object(const std::string&, unsigned int*) const;
|
||||||
|
|
||||||
// Finalize the layout after all the input sections have been added.
|
// Finalize the layout after all the input sections have been added.
|
||||||
off_t
|
off_t
|
||||||
@ -550,7 +568,19 @@ class Layout
|
|||||||
segment_precedes(const Output_segment* seg1, const Output_segment* seg2);
|
segment_precedes(const Output_segment* seg1, const Output_segment* seg2);
|
||||||
|
|
||||||
// A mapping used for group signatures.
|
// A mapping used for group signatures.
|
||||||
typedef Unordered_map<std::string, bool> Signatures;
|
struct Kept_section
|
||||||
|
{
|
||||||
|
Kept_section()
|
||||||
|
: object_(NULL), shndx_(0), group_(false)
|
||||||
|
{ }
|
||||||
|
Kept_section(Relobj* object, unsigned int shndx, bool group)
|
||||||
|
: object_(object), shndx_(shndx), group_(group)
|
||||||
|
{ }
|
||||||
|
Relobj* object_;
|
||||||
|
unsigned int shndx_;
|
||||||
|
bool group_;
|
||||||
|
};
|
||||||
|
typedef Unordered_map<std::string, Kept_section> Signatures;
|
||||||
|
|
||||||
// Mapping from input section name/type/flags to output section. We
|
// Mapping from input section name/type/flags to output section. We
|
||||||
// use canonicalized strings here.
|
// use canonicalized strings here.
|
||||||
|
184
gold/object.cc
184
gold/object.cc
@ -230,6 +230,18 @@ Object::handle_gnu_warning_section(const char* name, unsigned int shndx,
|
|||||||
return false;
|
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.
|
// Class Sized_relobj.
|
||||||
|
|
||||||
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
||||||
@ -510,10 +522,13 @@ Sized_relobj<size, big_endian>::include_section_group(
|
|||||||
Layout* layout,
|
Layout* layout,
|
||||||
unsigned int index,
|
unsigned int index,
|
||||||
const char* name,
|
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)
|
std::vector<bool>* omit)
|
||||||
{
|
{
|
||||||
// Read the section contents.
|
// Read the section contents.
|
||||||
|
typename This::Shdr shdr(shdrs + index * This::shdr_size);
|
||||||
const unsigned char* pcon = this->get_view(shdr.get_sh_offset(),
|
const unsigned char* pcon = this->get_view(shdr.get_sh_offset(),
|
||||||
shdr.get_sh_size(), true, false);
|
shdr.get_sh_size(), true, false);
|
||||||
const elfcpp::Elf_Word* pword =
|
const elfcpp::Elf_Word* pword =
|
||||||
@ -562,12 +577,11 @@ Sized_relobj<size, big_endian>::include_section_group(
|
|||||||
return false;
|
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
|
// 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
|
// 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.
|
// 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)
|
if (signature[0] == '\0' && sym.get_st_type() == elfcpp::STT_SECTION)
|
||||||
{
|
{
|
||||||
bool is_ordinary;
|
bool is_ordinary;
|
||||||
@ -580,24 +594,40 @@ Sized_relobj<size, big_endian>::include_section_group(
|
|||||||
symndx, sym_shndx);
|
symndx, sym_shndx);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
secname = this->section_name(sym_shndx);
|
typename This::Shdr member_shdr(shdrs + sym_shndx * This::shdr_size);
|
||||||
signature = secname.c_str();
|
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
|
// Record this section group in the layout, and see whether we've already
|
||||||
// with the same signature.
|
// seen one with the same signature.
|
||||||
|
bool include_group = ((flags & elfcpp::GRP_COMDAT) == 0
|
||||||
|
|| layout->add_comdat(this, index, signature, true));
|
||||||
|
|
||||||
if ((flags & elfcpp::GRP_COMDAT) == 0
|
if (include_group && parameters->options().relocatable())
|
||||||
|| layout->add_comdat(signature, true))
|
layout->layout_group(symtab, this, index, name, signature.c_str(),
|
||||||
|
shdr, pword);
|
||||||
|
|
||||||
|
Relobj* kept_object = NULL;
|
||||||
|
Comdat_group* kept_group = NULL;
|
||||||
|
|
||||||
|
if (!include_group)
|
||||||
{
|
{
|
||||||
if (parameters->options().relocatable())
|
// This group is being discarded. Find the object and group
|
||||||
layout->layout_group(symtab, this, index, name, signature, shdr,
|
// that was kept in its place.
|
||||||
pword);
|
unsigned int kept_group_index = 0;
|
||||||
return true;
|
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);
|
size_t count = shdr.get_sh_size() / sizeof(elfcpp::Elf_Word);
|
||||||
for (size_t i = 1; i < count; ++i)
|
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"),
|
this->error(_("invalid section group %u refers to earlier section %u"),
|
||||||
index, secnum);
|
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
|
// Whether to include a linkonce section in the link. NAME is the
|
||||||
@ -641,6 +703,7 @@ template<int size, bool big_endian>
|
|||||||
bool
|
bool
|
||||||
Sized_relobj<size, big_endian>::include_linkonce_section(
|
Sized_relobj<size, big_endian>::include_linkonce_section(
|
||||||
Layout* layout,
|
Layout* layout,
|
||||||
|
unsigned int index,
|
||||||
const char* name,
|
const char* name,
|
||||||
const elfcpp::Shdr<size, big_endian>&)
|
const elfcpp::Shdr<size, big_endian>&)
|
||||||
{
|
{
|
||||||
@ -658,8 +721,52 @@ Sized_relobj<size, big_endian>::include_linkonce_section(
|
|||||||
symname = name + strlen(linkonce_t);
|
symname = name + strlen(linkonce_t);
|
||||||
else
|
else
|
||||||
symname = strrchr(name, '.') + 1;
|
symname = strrchr(name, '.') + 1;
|
||||||
bool include1 = layout->add_comdat(symname, false);
|
std::string sig1(symname);
|
||||||
bool include2 = layout->add_comdat(name, true);
|
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;
|
return include1 && include2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -679,7 +786,8 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Get the section headers.
|
// 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.
|
// Get the section names.
|
||||||
const unsigned char* pnamesu = sd->section_names->data();
|
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_shndx(shnum, 0);
|
||||||
std::vector<unsigned int> reloc_type(shnum, elfcpp::SHT_NULL);
|
std::vector<unsigned int> reloc_type(shnum, elfcpp::SHT_NULL);
|
||||||
// Skip the first, dummy, section.
|
// 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)
|
for (unsigned int i = 1; i < shnum; ++i, pshdrs += This::shdr_size)
|
||||||
{
|
{
|
||||||
typename This::Shdr shdr(pshdrs);
|
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;
|
std::vector<unsigned int> eh_frame_sections;
|
||||||
|
|
||||||
// Skip the first, dummy, section.
|
// 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)
|
for (unsigned int i = 1; i < shnum; ++i, pshdrs += This::shdr_size)
|
||||||
{
|
{
|
||||||
typename This::Shdr shdr(pshdrs);
|
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 (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))
|
&omit))
|
||||||
discard = true;
|
discard = true;
|
||||||
}
|
}
|
||||||
else if ((shdr.get_sh_flags() & elfcpp::SHF_GROUP) == 0
|
else if ((shdr.get_sh_flags() & elfcpp::SHF_GROUP) == 0
|
||||||
&& Layout::is_linkonce(name))
|
&& Layout::is_linkonce(name))
|
||||||
{
|
{
|
||||||
if (!this->include_linkonce_section(layout, name, shdr))
|
if (!this->include_linkonce_section(layout, i, name, shdr))
|
||||||
discard = true;
|
discard = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1124,7 +1233,10 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
|
|||||||
|
|
||||||
if (os == NULL)
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
else if (mo[shndx].offset == -1)
|
else if (mo[shndx].offset == -1)
|
||||||
@ -1417,6 +1529,28 @@ Sized_relobj<size, big_endian>::get_symbol_location_info(
|
|||||||
return false;
|
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.
|
// Input_objects methods.
|
||||||
|
|
||||||
// Add a regular relocatable object to the list. Return false if this
|
// Add a regular relocatable object to the list. Return false if this
|
||||||
|
@ -561,6 +561,8 @@ class Relobj : public Object
|
|||||||
Relobj(const std::string& name, Input_file* input_file, off_t offset = 0)
|
Relobj(const std::string& name, Input_file* input_file, off_t offset = 0)
|
||||||
: Object(name, input_file, false, offset),
|
: Object(name, input_file, false, offset),
|
||||||
map_to_output_(),
|
map_to_output_(),
|
||||||
|
comdat_groups_(),
|
||||||
|
kept_comdat_sections_(),
|
||||||
map_to_relocatable_relocs_(NULL),
|
map_to_relocatable_relocs_(NULL),
|
||||||
object_merge_map_(NULL),
|
object_merge_map_(NULL),
|
||||||
relocs_must_follow_section_writes_(false)
|
relocs_must_follow_section_writes_(false)
|
||||||
@ -647,6 +649,10 @@ class Relobj : public Object
|
|||||||
this->map_to_output_[shndx].offset = off;
|
this->map_to_output_[shndx].offset = off;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the output address of the input section SHNDX.
|
||||||
|
uint64_t
|
||||||
|
output_section_address(unsigned int shndx) const;
|
||||||
|
|
||||||
// Return true if we need to wait for output sections to be written
|
// Return true if we need to wait for output sections to be written
|
||||||
// before we can apply relocations. This is true if the object has
|
// before we can apply relocations. This is true if the object has
|
||||||
// any relocations for sections which require special handling, such
|
// any relocations for sections which require special handling, such
|
||||||
@ -684,6 +690,24 @@ class Relobj : public Object
|
|||||||
return (*this->map_to_relocatable_relocs_)[reloc_shndx];
|
return (*this->map_to_relocatable_relocs_)[reloc_shndx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Information needed to keep track of kept comdat groups. This is
|
||||||
|
// simply a map from the section name to its section index. This may
|
||||||
|
// not be a one-to-one mapping, but we ignore that possibility since
|
||||||
|
// this is used only to attempt to handle stray relocations from
|
||||||
|
// non-comdat debug sections that refer to comdat loadable sections.
|
||||||
|
typedef Unordered_map<std::string, unsigned int> Comdat_group;
|
||||||
|
|
||||||
|
// Find a comdat group table given its group section SHNDX.
|
||||||
|
Comdat_group*
|
||||||
|
find_comdat_group(unsigned int shndx) const
|
||||||
|
{
|
||||||
|
Comdat_group_table::const_iterator p =
|
||||||
|
this->comdat_groups_.find(shndx);
|
||||||
|
if (p != this->comdat_groups_.end())
|
||||||
|
return p->second;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// What we need to know to map an input section to an output
|
// What we need to know to map an input section to an output
|
||||||
// section. We keep an array of these, one for each input section,
|
// section. We keep an array of these, one for each input section,
|
||||||
@ -698,6 +722,23 @@ class Relobj : public Object
|
|||||||
section_offset_type offset;
|
section_offset_type offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// A map from group section index to the table of group members.
|
||||||
|
typedef std::map<unsigned int, Comdat_group*> Comdat_group_table;
|
||||||
|
|
||||||
|
// To keep track of discarded comdat sections, we need to map a member
|
||||||
|
// section index to the object and section index of the corresponding
|
||||||
|
// kept section.
|
||||||
|
struct Kept_comdat_section
|
||||||
|
{
|
||||||
|
Kept_comdat_section(Relobj* object, unsigned int shndx)
|
||||||
|
: object_(object), shndx_(shndx)
|
||||||
|
{ }
|
||||||
|
Relobj* object_;
|
||||||
|
unsigned int shndx_;
|
||||||
|
};
|
||||||
|
typedef std::map<unsigned int, Kept_comdat_section*>
|
||||||
|
Kept_comdat_section_table;
|
||||||
|
|
||||||
// Read the relocs--implemented by child class.
|
// Read the relocs--implemented by child class.
|
||||||
virtual void
|
virtual void
|
||||||
do_read_relocs(Read_relocs_data*) = 0;
|
do_read_relocs(Read_relocs_data*) = 0;
|
||||||
@ -745,6 +786,30 @@ class Relobj : public Object
|
|||||||
map_to_output() const
|
map_to_output() const
|
||||||
{ return this->map_to_output_; }
|
{ return this->map_to_output_; }
|
||||||
|
|
||||||
|
// Record a new comdat group whose group section index is SHNDX.
|
||||||
|
void
|
||||||
|
add_comdat_group(unsigned int shndx, Comdat_group* group)
|
||||||
|
{ this->comdat_groups_[shndx] = group; }
|
||||||
|
|
||||||
|
// Record a mapping from discarded section SHNDX to the corresponding
|
||||||
|
// kept section.
|
||||||
|
void
|
||||||
|
set_kept_comdat_section(unsigned int shndx, Kept_comdat_section* kept)
|
||||||
|
{
|
||||||
|
this->kept_comdat_sections_[shndx] = kept;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the kept section corresponding to the discarded section SHNDX.
|
||||||
|
Kept_comdat_section*
|
||||||
|
get_kept_comdat_section(unsigned int shndx) const
|
||||||
|
{
|
||||||
|
Kept_comdat_section_table::const_iterator p =
|
||||||
|
this->kept_comdat_sections_.find(shndx);
|
||||||
|
if (p == this->kept_comdat_sections_.end())
|
||||||
|
return NULL;
|
||||||
|
return p->second;
|
||||||
|
}
|
||||||
|
|
||||||
// Set the size of the relocatable relocs array.
|
// Set the size of the relocatable relocs array.
|
||||||
void
|
void
|
||||||
size_relocatable_relocs()
|
size_relocatable_relocs()
|
||||||
@ -762,6 +827,10 @@ class Relobj : public Object
|
|||||||
private:
|
private:
|
||||||
// Mapping from input sections to output section.
|
// Mapping from input sections to output section.
|
||||||
std::vector<Map_to_output> map_to_output_;
|
std::vector<Map_to_output> map_to_output_;
|
||||||
|
// Table of kept comdat groups.
|
||||||
|
Comdat_group_table comdat_groups_;
|
||||||
|
// Table mapping discarded comdat sections to corresponding kept sections.
|
||||||
|
Kept_comdat_section_table kept_comdat_sections_;
|
||||||
// Mapping from input section index to the information recorded for
|
// Mapping from input section index to the information recorded for
|
||||||
// the relocations. This is only used for a relocatable link.
|
// the relocations. This is only used for a relocatable link.
|
||||||
std::vector<Relocatable_relocs*>* map_to_relocatable_relocs_;
|
std::vector<Relocatable_relocs*>* map_to_relocatable_relocs_;
|
||||||
@ -927,7 +996,7 @@ class Symbol_value
|
|||||||
{ this->u_.value = value; }
|
{ this->u_.value = value; }
|
||||||
|
|
||||||
// Return the input value. This is only called by
|
// Return the input value. This is only called by
|
||||||
// finalize_local_symbols.
|
// finalize_local_symbols and (in special cases) relocate_section.
|
||||||
Value
|
Value
|
||||||
input_value() const
|
input_value() const
|
||||||
{ return this->u_.value; }
|
{ return this->u_.value; }
|
||||||
@ -1288,6 +1357,12 @@ class Sized_relobj : public Relobj
|
|||||||
get_symbol_location_info(unsigned int shndx, off_t offset,
|
get_symbol_location_info(unsigned int shndx, off_t offset,
|
||||||
Symbol_location_info* info);
|
Symbol_location_info* info);
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
Address
|
||||||
|
map_to_kept_section(unsigned int shndx, bool* found) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Read the symbols.
|
// Read the symbols.
|
||||||
void
|
void
|
||||||
@ -1421,12 +1496,12 @@ class Sized_relobj : public Relobj
|
|||||||
// Whether to include a section group in the link.
|
// Whether to include a section group in the link.
|
||||||
bool
|
bool
|
||||||
include_section_group(Symbol_table*, Layout*, unsigned int, const char*,
|
include_section_group(Symbol_table*, Layout*, unsigned int, const char*,
|
||||||
const elfcpp::Shdr<size, big_endian>&,
|
const unsigned char*, const char *, section_size_type,
|
||||||
std::vector<bool>*);
|
std::vector<bool>*);
|
||||||
|
|
||||||
// Whether to include a linkonce section in the link.
|
// Whether to include a linkonce section in the link.
|
||||||
bool
|
bool
|
||||||
include_linkonce_section(Layout*, const char*,
|
include_linkonce_section(Layout*, unsigned int, const char*,
|
||||||
const elfcpp::Shdr<size, big_endian>&);
|
const elfcpp::Shdr<size, big_endian>&);
|
||||||
|
|
||||||
// Views and sizes when relocating.
|
// Views and sizes when relocating.
|
||||||
|
@ -119,6 +119,31 @@ scan_relocs(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Behavior for relocations to discarded comdat sections.
|
||||||
|
|
||||||
|
enum Comdat_behavior
|
||||||
|
{
|
||||||
|
CB_UNDETERMINED, // Not yet determined -- need to look at section name.
|
||||||
|
CB_PRETEND, // Attempt to map to the corresponding kept section.
|
||||||
|
CB_IGNORE, // Ignore the relocation.
|
||||||
|
CB_WARNING // Print a warning.
|
||||||
|
};
|
||||||
|
|
||||||
|
// Decide what the linker should do for relocations that refer to discarded
|
||||||
|
// comdat sections. This decision is based on the name of the section being
|
||||||
|
// relocated.
|
||||||
|
|
||||||
|
inline Comdat_behavior
|
||||||
|
get_comdat_behavior(const char* name)
|
||||||
|
{
|
||||||
|
if (Layout::is_debug_info_section(name))
|
||||||
|
return CB_PRETEND;
|
||||||
|
if (strcmp(name, ".eh_frame") == 0
|
||||||
|
|| strcmp(name, ".gcc_except_table") == 0)
|
||||||
|
return CB_IGNORE;
|
||||||
|
return CB_WARNING;
|
||||||
|
}
|
||||||
|
|
||||||
// This function implements the generic part of relocation processing.
|
// This function implements the generic part of relocation processing.
|
||||||
// The template parameter Relocate must be a class type which provides
|
// The template parameter Relocate must be a class type which provides
|
||||||
// a single function, relocate(), which implements the machine
|
// a single function, relocate(), which implements the machine
|
||||||
@ -159,6 +184,8 @@ relocate_section(
|
|||||||
Sized_relobj<size, big_endian>* object = relinfo->object;
|
Sized_relobj<size, big_endian>* object = relinfo->object;
|
||||||
unsigned int local_count = object->local_symbol_count();
|
unsigned int local_count = object->local_symbol_count();
|
||||||
|
|
||||||
|
Comdat_behavior comdat_behavior = CB_UNDETERMINED;
|
||||||
|
|
||||||
for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
|
for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
|
||||||
{
|
{
|
||||||
Reltype reloc(prelocs);
|
Reltype reloc(prelocs);
|
||||||
@ -187,6 +214,44 @@ relocate_section(
|
|||||||
{
|
{
|
||||||
sym = NULL;
|
sym = NULL;
|
||||||
psymval = object->local_symbol(r_sym);
|
psymval = object->local_symbol(r_sym);
|
||||||
|
|
||||||
|
// If the local symbol belongs to a section we are discarding,
|
||||||
|
// and that section is a debug section, try to find the
|
||||||
|
// corresponding kept section and map this symbol to its
|
||||||
|
// counterpart in the kept section.
|
||||||
|
bool is_ordinary;
|
||||||
|
unsigned int shndx = psymval->input_shndx(&is_ordinary);
|
||||||
|
if (is_ordinary
|
||||||
|
&& shndx != elfcpp::SHN_UNDEF
|
||||||
|
&& !object->is_section_included(shndx))
|
||||||
|
{
|
||||||
|
if (comdat_behavior == CB_UNDETERMINED)
|
||||||
|
{
|
||||||
|
const char* name =
|
||||||
|
object->section_name(relinfo->data_shndx).c_str();
|
||||||
|
comdat_behavior = get_comdat_behavior(name);
|
||||||
|
}
|
||||||
|
if (comdat_behavior == CB_PRETEND)
|
||||||
|
{
|
||||||
|
bool found;
|
||||||
|
typename elfcpp::Elf_types<size>::Elf_Addr value =
|
||||||
|
object->map_to_kept_section(shndx, &found);
|
||||||
|
if (found)
|
||||||
|
symval.set_output_value(value + psymval->input_value());
|
||||||
|
else
|
||||||
|
symval.set_output_value(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (comdat_behavior == CB_WARNING)
|
||||||
|
gold_warning_at_location(relinfo, i, offset,
|
||||||
|
_("Relocation refers to discarded "
|
||||||
|
"comdat section"));
|
||||||
|
symval.set_output_value(0);
|
||||||
|
}
|
||||||
|
symval.set_no_output_symtab_entry();
|
||||||
|
psymval = &symval;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user