summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCary Coutant <ccoutant@google.com>2014-11-25 13:55:42 -0800
committerCary Coutant <ccoutant@google.com>2014-11-25 16:14:15 -0800
commit9ec85a27138aefcd3fc35ddbd7727f384fe299b1 (patch)
treedc1f26e559c637ca906fda7200694e428641a16f
parentbd30b2c856c9ae1fc3559d80fc8c8ccdf65e5fce (diff)
downloadbinutils-9ec85a27138aefcd3fc35ddbd7727f384fe299b1.tar.gz
binutils-9ec85a27138aefcd3fc35ddbd7727f384fe299b1.tar.bz2
binutils-9ec85a27138aefcd3fc35ddbd7727f384fe299b1.zip
Fix corrupted .eh_frame section with LTO and --gc-sections.
Backport from trunk: When --gc-sections is turned on during an LTO link, the .eh_frame sections from deferred files are processed before those from the replacement files. As a result, the section end-cap from crtendS.o is placed ahead of the .eh_frame data from the replacement files. This patch fixes the bug by skipping the layout of the deferred sections during GC pass 2. gold/ PR gold/17639 * object.cc (Sized_relobj_file): Initialize is_deferred_layout_. (Sized_relobj_file::do_layout): Handle deferred sections properly during GC pass 1. Don't add reloc sections to deferred list twice. * object.h (Sized_relobj_file::is_deferred_layout): New function. (Sized_relobj_file::is_deferred_layout_): New data member.
-rw-r--r--gold/ChangeLog9
-rw-r--r--gold/object.cc20
-rw-r--r--gold/object.h7
3 files changed, 30 insertions, 6 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index ff5d5afc77a..141a465185c 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,12 @@
+2014-11-25 Cary Coutant <ccoutant@google.com>
+
+ PR gold/17639
+ * object.cc (Sized_relobj_file): Initialize is_deferred_layout_.
+ (Sized_relobj_file::do_layout): Handle deferred sections properly
+ during GC pass 1. Don't add reloc sections to deferred list twice.
+ * object.h (Sized_relobj_file::is_deferred_layout): New function.
+ (Sized_relobj_file::is_deferred_layout_): New data member.
+
2014-11-21 Alan Modra <amodra@gmail.com>
* powerpc.cc (Target_powerpc::Relocate::relocate): Correct test
diff --git a/gold/object.cc b/gold/object.cc
index 6ab84cef70f..e357ddf8707 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -430,6 +430,7 @@ Sized_relobj_file<size, big_endian>::Sized_relobj_file(
kept_comdat_sections_(),
has_eh_frame_(false),
discarded_eh_frame_shndx_(-1U),
+ is_deferred_layout_(false),
deferred_layout_(),
deferred_layout_relocs_(),
compressed_sections_()
@@ -1430,6 +1431,7 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
{
parameters->options().plugins()->add_deferred_layout_object(this);
this->deferred_layout_.reserve(num_sections_to_defer);
+ this->is_deferred_layout_ = true;
}
// Whether we've seen a .note.GNU-stack section.
@@ -1590,10 +1592,13 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
{
if (is_pass_one)
{
- out_sections[i] = reinterpret_cast<Output_section*>(1);
+ 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 (should_defer_layout)
+ else if (this->is_deferred_layout())
this->deferred_layout_.push_back(Deferred_layout(i, name,
pshdrs,
reloc_shndx[i],
@@ -1658,11 +1663,12 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
}
// Defer layout here if input files are claimed by plugins. When gc
- // is turned on this function is called twice. For the second call
- // should_defer_layout should be false.
- if (should_defer_layout && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC))
+ // is turned on this function is called twice; we only want to do this
+ // on the first pass.
+ if (!is_pass_two
+ && this->is_deferred_layout()
+ && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC))
{
- gold_assert(!is_pass_two);
this->deferred_layout_.push_back(Deferred_layout(i, name,
pshdrs,
reloc_shndx[i],
@@ -1764,6 +1770,8 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
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();
diff --git a/gold/object.h b/gold/object.h
index 754b1d26b89..cf45ec53e47 100644
--- a/gold/object.h
+++ b/gold/object.h
@@ -2202,6 +2202,10 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
Symbol_value<size>* lv_out,
const Symbol_table* symtab);
+ // Return true if the layout for this object was deferred.
+ bool is_deferred_layout() const
+ { return this->is_deferred_layout_; }
+
protected:
typedef typename Sized_relobj<size, big_endian>::Output_sections
Output_sections;
@@ -2740,6 +2744,9 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
// If this object has a GNU style .eh_frame section that is discarded in
// output, record the index here. Otherwise it is -1U.
unsigned int discarded_eh_frame_shndx_;
+ // True if the layout of this object was deferred, waiting for plugin
+ // replacement files.
+ bool is_deferred_layout_;
// The list of sections whose layout was deferred.
std::vector<Deferred_layout> deferred_layout_;
// The list of relocation sections whose layout was deferred.