aboutsummaryrefslogtreecommitdiff
path: root/gold/object.cc
diff options
context:
space:
mode:
authorCary Coutant <ccoutant@gmail.com>2018-04-02 16:12:10 -0700
committerCary Coutant <ccoutant@gmail.com>2018-04-02 19:07:04 -0700
commitbce5a025d2ed7eda2c5bbb85bd9b33333ca5d556 (patch)
tree92912c522de8e45805825292a4a94e50f753584c /gold/object.cc
parent8849a5e9edda5f00d727490c7bb8be3c616742ae (diff)
downloadfsf-binutils-gdb-bce5a025d2ed7eda2c5bbb85bd9b33333ca5d556.zip
fsf-binutils-gdb-bce5a025d2ed7eda2c5bbb85bd9b33333ca5d556.tar.gz
fsf-binutils-gdb-bce5a025d2ed7eda2c5bbb85bd9b33333ca5d556.tar.bz2
Fix problem where mixed section types can cause internal error during a -r link.
During a -r (or --emit-relocs) link, if two sections had the same name but different section types, gold would put relocations for both sections into the same relocation section even though the data sections remained separate. For .eh_frame sections, when one section is PROGBITS and another is X86_64_UNWIND, we really should be using the UNWIND section type and combining the sections anyway. For other sections, we should be creating one relocation section for each output data section. gold/ PR gold/23016 * incremental.cc (can_incremental_update): Check for unwind section type. * layout.h (Layout::layout): Add sh_type parameter. * layout.cc (Layout::layout): Likewise. (Layout::layout_reloc): Create new output reloc section if data section does not already have one. (Layout::layout_eh_frame): Check for unwind section type. (Layout::make_eh_frame_section): Use unwind section type for .eh_frame and .eh_frame_hdr. * object.h (Sized_relobj_file::Shdr_write): New typedef. (Sized_relobj_file::layout_section): Add sh_type parameter. (Sized_relobj_file::Deferred_layout::Deferred_layout): Add sh_type parameter. * object.cc (Sized_relobj_file::check_eh_frame_flags): Check for unwind section type. (Sized_relobj_file::layout_section): Add sh_type parameter; pass it to Layout::layout. (Sized_relobj_file::do_layout): Make local copy of sh_type. Force .eh_frame sections to unwind section type. Pass sh_type to layout_section. (Sized_relobj_file<size, big_endian>::do_layout_deferred_sections): Pass sh_type to layout_section. * output.cc (Output_section::Output_section): Initialize reloc_section_. * output.h (Output_section::reloc_section): New method. (Output_section::set_reloc_section): New method. (Output_section::reloc_section_): New data member. * target.h (Target::unwind_section_type): New method. (Target::Target_info::unwind_section_type): New data member. * aarch64.cc (aarch64_info): Add unwind_section_type. * arm.cc (arm_info, arm_nacl_info): Likewise. * i386.cc (i386_info, i386_nacl_info, iamcu_info): Likewise. * mips.cc (mips_info, mips_nacl_info): Likewise. * powerpc.cc (powerpc_info): Likewise. * s390.cc (s390_info): Likewise. * sparc.cc (sparc_info): Likewise. * tilegx.cc (tilegx_info): Likewise. * x86_64.cc (x86_64_info, x86_64_nacl_info): Likewise. * testsuite/Makefile.am (pr23016_1, pr23016_2): New test cases. * testsuite/Makefile.in: Regenerate. * testsuite/testfile.cc: Add unwind_section_type. * testsuite/pr23016_1.sh: New test script. * testsuite/pr23016_1a.s: New source file. * testsuite/pr23016_1b.s: New source file. * testsuite/pr23016_2.sh: New test script. * testsuite/pr23016_2a.s: New source file. * testsuite/pr23016_2b.s: New source file.
Diffstat (limited to 'gold/object.cc')
-rw-r--r--gold/object.cc76
1 files changed, 43 insertions, 33 deletions
diff --git a/gold/object.cc b/gold/object.cc
index 0c8f7e2..0dbb0cb 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -574,7 +574,7 @@ Sized_relobj_file<size, big_endian>::check_eh_frame_flags(
{
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);
}
@@ -1252,12 +1252,13 @@ Sized_relobj_file<size, big_endian>::layout_section(
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)
@@ -1337,6 +1338,8 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
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? */
@@ -1522,15 +1525,17 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
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)
{
@@ -1568,7 +1573,7 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
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,
@@ -1588,7 +1593,7 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
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;
@@ -1610,8 +1615,8 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
{
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));
}
@@ -1632,14 +1637,14 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
// 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
@@ -1648,26 +1653,30 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
// 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())
@@ -1731,7 +1740,7 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
&& 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]));
@@ -1760,7 +1769,7 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
{
// 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
@@ -1838,7 +1847,8 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
// 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;
@@ -1949,7 +1959,7 @@ Sized_relobj_file<size, big_endian>::do_layout_deferred_sections(Layout* layout)
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_);
}