X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Fehframe.cc;h=c9feb28793d50b43f4eb551ee4226d4eb3a39071;hb=2106ed9baf1098a5d76469ecde30813065c46c68;hp=57eb031fafc5eb114e066cd0ee5dcdd6b0daee77;hpb=fc5a9bd57cbb974b8fc3aeb9a15d644cd9103451;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/ehframe.cc b/gold/ehframe.cc index 57eb031faf..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-2016 Free Software Foundation, Inc. +// Copyright (C) 2006-2020 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. @@ -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) @@ -1031,23 +1086,18 @@ Eh_frame::read_fde(Sized_relobj_file* object, // FDE corresponds to a function that was discarded during optimization // (too late to discard the corresponding FDE). uint64_t address_range = 0; - int pc_size = cie->fde_encoding() & 7; - if (pc_size == elfcpp::DW_EH_PE_absptr) - pc_size = size == 32 ? elfcpp::DW_EH_PE_udata4 : elfcpp::DW_EH_PE_udata8; switch (pc_size) { - case elfcpp::DW_EH_PE_udata2: + case 2: address_range = elfcpp::Swap<16, big_endian>::readval(pfde + 2); break; - case elfcpp::DW_EH_PE_udata4: + case 4: address_range = elfcpp::Swap<32, big_endian>::readval(pfde + 4); break; - case elfcpp::DW_EH_PE_udata8: - gold_assert(size == 64); + case 8: address_range = elfcpp::Swap_unaligned<64, big_endian>::readval(pfde + 8); break; default: - // All other cases were rejected in Eh_frame::read_cie. gold_unreachable(); } @@ -1093,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