diff options
author | Cary Coutant <ccoutant@google.com> | 2014-11-25 13:55:42 -0800 |
---|---|---|
committer | Cary Coutant <ccoutant@google.com> | 2014-11-25 16:14:15 -0800 |
commit | 9ec85a27138aefcd3fc35ddbd7727f384fe299b1 (patch) | |
tree | dc1f26e559c637ca906fda7200694e428641a16f | |
parent | bd30b2c856c9ae1fc3559d80fc8c8ccdf65e5fce (diff) | |
download | binutils-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/ChangeLog | 9 | ||||
-rw-r--r-- | gold/object.cc | 20 | ||||
-rw-r--r-- | gold/object.h | 7 |
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. |