X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Fehframe.cc;h=c9feb28793d50b43f4eb551ee4226d4eb3a39071;hb=2106ed9baf1098a5d76469ecde30813065c46c68;hp=c711bac5f05c69c98889f2e2b45b83bff4f3b12d;hpb=9860cbcfb60bdae2f9800e6a6ea5f21ef1507d08;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/ehframe.cc b/gold/ehframe.cc index c711bac5f0..c9feb28793 100644 --- a/gold/ehframe.cc +++ b/gold/ehframe.cc @@ -1,6 +1,6 @@ // ehframe.cc -- handle exception frame sections for gold -// Copyright (C) 2006-2014 Free Software Foundation, Inc. +// Copyright (C) 2006-2020 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. @@ -412,7 +412,7 @@ Cie::~Cie() section_offset_type Cie::set_output_offset(section_offset_type output_offset, unsigned int addralign, - Merge_map* merge_map) + Output_section_data *output_data) { size_t length = this->contents_.length(); @@ -422,8 +422,9 @@ Cie::set_output_offset(section_offset_type output_offset, if (this->object_ != NULL) { // Add a mapping so that relocations are applied correctly. - merge_map->add_mapping(this->object_, this->shndx_, this->input_offset_, - length, output_offset); + this->object_->add_merge_mapping(output_data, this->shndx_, + this->input_offset_, length, + output_offset); } length = align_address(length, addralign); @@ -432,7 +433,7 @@ Cie::set_output_offset(section_offset_type output_offset, p != this->fdes_.end(); ++p) { - (*p)->add_mapping(output_offset + length, merge_map); + (*p)->add_mapping(output_offset + length, output_data); size_t fde_length = (*p)->length(); fde_length = align_address(fde_length, addralign); @@ -531,7 +532,6 @@ Eh_frame::Eh_frame() eh_frame_hdr_(NULL), cie_offsets_(), unmergeable_cie_offsets_(), - merge_map_(), mappings_are_done_(false), final_data_size_(0) { @@ -567,7 +567,7 @@ Eh_frame::skip_leb128(const unsigned char** pp, const unsigned char* pend) // section. template -bool +Eh_frame::Eh_frame_section_disposition Eh_frame::add_ehframe_input_section( Sized_relobj_file* object, const unsigned char* symbols, @@ -584,7 +584,7 @@ Eh_frame::add_ehframe_input_section( &contents_len, false); if (contents_len == 0) - return false; + return EH_EMPTY_SECTION; // If this is the marker section for the end of the data, then // return false to force it to be handled as an ordinary input @@ -592,7 +592,7 @@ Eh_frame::add_ehframe_input_section( // of unrecognized .eh_frame sections. if (contents_len == 4 && elfcpp::Swap<32, big_endian>::readval(pcontents) == 0) - return false; + return EH_END_MARKER_SECTION; New_cies new_cies; if (!this->do_add_ehframe_input_section(object, symbols, symbols_size, @@ -609,7 +609,7 @@ Eh_frame::add_ehframe_input_section( ++p) delete p->first; - return false; + return EH_UNRECOGNIZED_SECTION; } // Now that we know we are using this section, record any new CIEs @@ -624,7 +624,7 @@ Eh_frame::add_ehframe_input_section( this->unmergeable_cie_offsets_.push_back(p->first); } - return true; + return EH_OPTIMIZABLE_SECTION; } // The bulk of the implementation of add_ehframe_input_section. @@ -958,8 +958,8 @@ Eh_frame::read_cie(Sized_relobj_file* object, // know for sure that we are doing a special mapping for this // input section, but that's OK--if we don't do a special // mapping, nobody will ever ask for the mapping we add here. - this->merge_map_.add_mapping(object, shndx, (pcie - 8) - pcontents, - pcieend - (pcie - 8), -1); + object->add_merge_mapping(this, shndx, (pcie - 8) - pcontents, + pcieend - (pcie - 8), -1); } // Record this CIE plus the offset in the input section. @@ -992,13 +992,68 @@ Eh_frame::read_fde(Sized_relobj_file* object, return false; Cie* cie = pcie->second; + int pc_size = 0; + switch (cie->fde_encoding() & 7) + { + case elfcpp::DW_EH_PE_udata2: + pc_size = 2; + break; + case elfcpp::DW_EH_PE_udata4: + pc_size = 4; + break; + case elfcpp::DW_EH_PE_udata8: + gold_assert(size == 64); + pc_size = 8; + break; + case elfcpp::DW_EH_PE_absptr: + pc_size = size == 32 ? 4 : 8; + break; + default: + // All other cases were rejected in Eh_frame::read_cie. + gold_unreachable(); + } + // The FDE should start with a reloc to the start of the code which // it describes. if (relocs->advance(pfde - pcontents) > 0) return false; - if (relocs->next_offset() != pfde - pcontents) - return false; + { + // In an object produced by a relocatable link, gold may have + // discarded a COMDAT group in the previous link, but not the + // corresponding FDEs. In that case, gold will have discarded + // the relocations, so the FDE will have a non-relocatable zero + // (regardless of whether the PC encoding is absolute, pc-relative, + // or data-relative) instead of a pointer to the start of the code. + + uint64_t pc_value = 0; + switch (pc_size) + { + case 2: + pc_value = elfcpp::Swap<16, big_endian>::readval(pfde); + break; + case 4: + pc_value = elfcpp::Swap<32, big_endian>::readval(pfde); + break; + case 8: + pc_value = elfcpp::Swap_unaligned<64, big_endian>::readval(pfde); + break; + default: + gold_unreachable(); + } + + if (pc_value == 0) + { + // This FDE applies to a discarded function. We + // can discard this FDE. + object->add_merge_mapping(this, shndx, (pfde - 8) - pcontents, + pfdeend - (pfde - 8), -1); + return true; + } + + // Otherwise, reject the FDE. + return false; + } unsigned int symndx = relocs->next_symndx(); if (symndx == -1U) @@ -1010,6 +1065,8 @@ Eh_frame::read_fde(Sized_relobj_file* object, // pointer to a PC relative offset when generating a shared library. relocs->advance(pfdeend - pcontents); + // Find the section index for code that this FDE describes. + // If we have discarded the section, we can also discard the FDE. unsigned int fde_shndx; const int sym_size = elfcpp::Elf_sizes::sym_size; if (symndx >= symbols_size / sym_size) @@ -1018,16 +1075,38 @@ Eh_frame::read_fde(Sized_relobj_file* object, bool is_ordinary; fde_shndx = object->adjust_sym_shndx(symndx, sym.get_st_shndx(), &is_ordinary); + bool is_discarded = (is_ordinary + && fde_shndx != elfcpp::SHN_UNDEF + && fde_shndx < object->shnum() + && !object->is_section_included(fde_shndx)); + + // Fetch the address range field from the FDE. The offset and size + // of the field depends on the PC encoding given in the CIE, but + // it is always an absolute value. If the address range is 0, this + // FDE corresponds to a function that was discarded during optimization + // (too late to discard the corresponding FDE). + uint64_t address_range = 0; + switch (pc_size) + { + case 2: + address_range = elfcpp::Swap<16, big_endian>::readval(pfde + 2); + break; + case 4: + address_range = elfcpp::Swap<32, big_endian>::readval(pfde + 4); + break; + case 8: + address_range = elfcpp::Swap_unaligned<64, big_endian>::readval(pfde + 8); + break; + default: + gold_unreachable(); + } - if (is_ordinary - && fde_shndx != elfcpp::SHN_UNDEF - && fde_shndx < object->shnum() - && !object->is_section_included(fde_shndx)) + if (is_discarded || address_range == 0) { - // This FDE applies to a section which we are discarding. We + // This FDE applies to a discarded function. We // can discard this FDE. - this->merge_map_.add_mapping(object, shndx, (pfde - 8) - pcontents, - pfdeend - (pfde - 8), -1); + object->add_merge_mapping(this, shndx, (pfde - 8) - pcontents, + pfdeend - (pfde - 8), -1); return true; } @@ -1064,6 +1143,33 @@ Eh_frame::add_ehframe_for_plt(Output_data* plt, const unsigned char* cie_data, this->final_data_size_ += align_address(fde_length + 8, this->addralign()); } +// Remove all post-map unwind information for a PLT. + +void +Eh_frame::remove_ehframe_for_plt(Output_data* plt, + const unsigned char* cie_data, + size_t cie_length) +{ + if (!this->mappings_are_done_) + return; + + Cie cie(NULL, 0, 0, elfcpp::DW_EH_PE_pcrel | elfcpp::DW_EH_PE_sdata4, "", + cie_data, cie_length); + Cie_offsets::iterator find_cie = this->cie_offsets_.find(&cie); + gold_assert (find_cie != this->cie_offsets_.end()); + Cie* pcie = *find_cie; + + while (pcie->fde_count() != 0) + { + const Fde* fde = pcie->last_fde(); + if (!fde->post_map(plt)) + break; + size_t length = fde->length(); + this->final_data_size_ -= align_address(length + 8, this->addralign()); + pcie->remove_fde(); + } +} + // Return the number of FDEs. unsigned int @@ -1107,14 +1213,14 @@ Eh_frame::set_final_data_size() ++p) output_offset = (*p)->set_output_offset(output_offset, this->addralign(), - &this->merge_map_); + this); for (Cie_offsets::iterator p = this->cie_offsets_.begin(); p != this->cie_offsets_.end(); ++p) output_offset = (*p)->set_output_offset(output_offset, this->addralign(), - &this->merge_map_); + this); this->mappings_are_done_ = true; this->final_data_size_ = output_offset - output_start; @@ -1130,16 +1236,7 @@ Eh_frame::do_output_offset(const Relobj* object, unsigned int shndx, section_offset_type offset, section_offset_type* poutput) const { - return this->merge_map_.get_output_offset(object, shndx, offset, poutput); -} - -// Return whether this is the merge section for an input section. - -bool -Eh_frame::do_is_merge_section_for(const Relobj* object, - unsigned int shndx) const -{ - return this->merge_map_.is_merge_section_for(object, shndx); + return object->merge_output_offset(shndx, offset, poutput); } // Write the data to the output file. @@ -1215,7 +1312,7 @@ Eh_frame::do_sized_write(unsigned char* oview) #ifdef HAVE_TARGET_32_LITTLE template -bool +Eh_frame::Eh_frame_section_disposition Eh_frame::add_ehframe_input_section<32, false>( Sized_relobj_file<32, false>* object, const unsigned char* symbols, @@ -1229,7 +1326,7 @@ Eh_frame::add_ehframe_input_section<32, false>( #ifdef HAVE_TARGET_32_BIG template -bool +Eh_frame::Eh_frame_section_disposition Eh_frame::add_ehframe_input_section<32, true>( Sized_relobj_file<32, true>* object, const unsigned char* symbols, @@ -1243,7 +1340,7 @@ Eh_frame::add_ehframe_input_section<32, true>( #ifdef HAVE_TARGET_64_LITTLE template -bool +Eh_frame::Eh_frame_section_disposition Eh_frame::add_ehframe_input_section<64, false>( Sized_relobj_file<64, false>* object, const unsigned char* symbols, @@ -1257,7 +1354,7 @@ Eh_frame::add_ehframe_input_section<64, false>( #ifdef HAVE_TARGET_64_BIG template -bool +Eh_frame::Eh_frame_section_disposition Eh_frame::add_ehframe_input_section<64, true>( Sized_relobj_file<64, true>* object, const unsigned char* symbols,