X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Fehframe.cc;h=dad23319913d836a0d98b6528c335ef045e56238;hb=e0d08d4b30212f2eb03b8d1da8262d48e636bd71;hp=80fd859a0dec822333759d9cdb1236f34f4b7a16;hpb=1cac254c18ff7ebf94d1f949b2c65ecc447a2ebf;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/ehframe.cc b/gold/ehframe.cc index 80fd859a0d..dad2331991 100644 --- a/gold/ehframe.cc +++ b/gold/ehframe.cc @@ -1,6 +1,6 @@ // ehframe.cc -- handle exception frame sections for gold -// Copyright 2006, 2007 Free Software Foundation, Inc. +// Copyright 2006, 2007, 2008, 2010, 2011 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. @@ -104,51 +104,36 @@ Eh_frame_hdr::set_final_data_size() this->set_data_size(data_size); } -// Write the data to the flie. +// Write the data to the file. void Eh_frame_hdr::do_write(Output_file* of) { - if (parameters->get_size() == 32) + switch (parameters->size_and_endianness()) { - if (!parameters->is_big_endian()) - { #ifdef HAVE_TARGET_32_LITTLE - this->do_sized_write<32, false>(of); -#else - gold_unreachable(); + case Parameters::TARGET_32_LITTLE: + this->do_sized_write<32, false>(of); + break; #endif - } - else - { #ifdef HAVE_TARGET_32_BIG - this->do_sized_write<32, true>(of); -#else - gold_unreachable(); + case Parameters::TARGET_32_BIG: + this->do_sized_write<32, true>(of); + break; #endif - } - } - else if (parameters->get_size() == 64) - { - if (!parameters->is_big_endian()) - { #ifdef HAVE_TARGET_64_LITTLE - this->do_sized_write<64, false>(of); -#else - gold_unreachable(); + case Parameters::TARGET_64_LITTLE: + this->do_sized_write<64, false>(of); + break; #endif - } - else - { #ifdef HAVE_TARGET_64_BIG - this->do_sized_write<64, true>(of); -#else - gold_unreachable(); + case Parameters::TARGET_64_BIG: + this->do_sized_write<64, true>(of); + break; #endif - } + default: + gold_unreachable(); } - else - gold_unreachable(); } // Write the data to the file with the right endianness. @@ -281,7 +266,7 @@ Eh_frame_hdr::get_fde_pc( gold_unreachable(); } - switch (fde_encoding & 0xf0) + switch (fde_encoding & 0x70) { case 0: break; @@ -290,12 +275,18 @@ Eh_frame_hdr::get_fde_pc( pc += eh_frame_address + fde_offset + 8; break; + case elfcpp::DW_EH_PE_datarel: + pc += parameters->target().ehframe_datarel_base(); + break; + default: // If other cases arise, then we have to handle them, or we have // to reject them by returning false in Eh_frame::read_cie. gold_unreachable(); } + gold_assert((fde_encoding & elfcpp::DW_EH_PE_indirect) == 0); + return pc; } @@ -336,21 +327,30 @@ Eh_frame_hdr::get_fde_addresses(Output_file* of, // Write the FDE to OVIEW starting at OFFSET. CIE_OFFSET is the // offset of the CIE in OVIEW. FDE_ENCODING is the encoding, from the -// CIE. Record the FDE pc for EH_FRAME_HDR. Return the new offset. +// CIE. ADDRALIGN is the required alignment. ADDRESS is the virtual +// address of OVIEW. Record the FDE pc for EH_FRAME_HDR. Return the +// new offset. template section_offset_type Fde::write(unsigned char* oview, section_offset_type offset, + uint64_t address, unsigned int addralign, section_offset_type cie_offset, unsigned char fde_encoding, Eh_frame_hdr* eh_frame_hdr) { + gold_assert((offset & (addralign - 1)) == 0); + size_t length = this->contents_.length(); + // We add 8 when getting the aligned length to account for the + // length word and the CIE offset. + size_t aligned_full_length = align_address(length + 8, addralign); + // Write the length of the FDE as a 32-bit word. The length word // does not include the four bytes of the length word itself, but it // does include the offset to the CIE. elfcpp::Swap<32, big_endian>::writeval(oview + offset, - length + 4); + aligned_full_length - 4); // Write the offset to the CIE as a 32-bit word. This is the // difference between the address of the offset word itself and the @@ -363,11 +363,32 @@ Fde::write(unsigned char* oview, section_offset_type offset, // will later be applied to the FDE data. memcpy(oview + offset + 8, this->contents_.data(), length); + // If this FDE is associated with a PLT, fill in the PLT's address + // and size. + if (this->object_ == NULL) + { + gold_assert(memcmp(oview + offset + 8, "\0\0\0\0\0\0\0\0", 8) == 0); + Output_data* plt = this->u_.from_linker.plt; + uint64_t poffset = plt->address() - (address + offset + 8); + int32_t spoffset = static_cast(poffset); + off_t psize = plt->data_size(); + uint32_t upsize = static_cast(psize); + if (static_cast(static_cast(spoffset)) != poffset + || static_cast(upsize) != psize) + gold_warning(_("overflow in PLT unwind data; " + "unwinding through PLT may fail")); + elfcpp::Swap<32, big_endian>::writeval(oview + offset + 8, spoffset); + elfcpp::Swap<32, big_endian>::writeval(oview + offset + 12, upsize); + } + + if (aligned_full_length > length + 8) + memset(oview + offset + length + 8, 0, aligned_full_length - (length + 8)); + // Tell the exception frame header about this FDE. if (eh_frame_hdr != NULL) eh_frame_hdr->record_fde(offset, fde_encoding); - return offset + length + 8; + return offset + aligned_full_length; } // Class Cie. @@ -390,12 +411,18 @@ Cie::set_output_offset(section_offset_type output_offset, Merge_map* merge_map) { size_t length = this->contents_.length(); - gold_assert((length & (addralign - 1)) == 0); + // Add 4 for length and 4 for zero CIE identifier tag. length += 8; - merge_map->add_mapping(this->object_, this->shndx_, this->input_offset_, - length, 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); + } + + length = align_address(length, addralign); for (std::vector::const_iterator p = this->fdes_.begin(); p != this->fdes_.end(); @@ -404,7 +431,7 @@ Cie::set_output_offset(section_offset_type output_offset, (*p)->add_mapping(output_offset + length, merge_map); size_t fde_length = (*p)->length(); - gold_assert((fde_length & (addralign - 1)) == 0); + fde_length = align_address(fde_length, addralign); length += fde_length; } @@ -412,35 +439,49 @@ Cie::set_output_offset(section_offset_type output_offset, } // Write the CIE to OVIEW starting at OFFSET. EH_FRAME_HDR is for FDE -// recording. Return the new offset. +// recording. Round up the bytes to ADDRALIGN. Return the new +// offset. template section_offset_type Cie::write(unsigned char* oview, section_offset_type offset, + uint64_t address, unsigned int addralign, Eh_frame_hdr* eh_frame_hdr) { + gold_assert((offset & (addralign - 1)) == 0); + section_offset_type cie_offset = offset; size_t length = this->contents_.length(); + // We add 8 when getting the aligned length to account for the + // length word and the CIE tag. + size_t aligned_full_length = align_address(length + 8, addralign); + // Write the length of the CIE as a 32-bit word. The length word // does not include the four bytes of the length word itself. - elfcpp::Swap<32, big_endian>::writeval(oview + offset, length + 4); + elfcpp::Swap<32, big_endian>::writeval(oview + offset, + aligned_full_length - 4); // Write the tag which marks this as a CIE: a 32-bit zero. elfcpp::Swap<32, big_endian>::writeval(oview + offset + 4, 0); // Write out the CIE data. memcpy(oview + offset + 8, this->contents_.data(), length); - offset += length + 8; + + if (aligned_full_length > length + 8) + memset(oview + offset + length + 8, 0, aligned_full_length - (length + 8)); + + offset += aligned_full_length; // Write out the associated FDEs. unsigned char fde_encoding = this->fde_encoding_; for (std::vector::const_iterator p = this->fdes_.begin(); p != this->fdes_.end(); ++p) - offset = (*p)->write(oview, offset, cie_offset, - fde_encoding, eh_frame_hdr); + offset = (*p)->write(oview, offset, address, addralign, + cie_offset, fde_encoding, + eh_frame_hdr); return offset; } @@ -477,7 +518,9 @@ Eh_frame::Eh_frame() eh_frame_hdr_(NULL), cie_offsets_(), unmergeable_cie_offsets_(), - merge_map_() + merge_map_(), + mappings_are_done_(false), + final_data_size_(0) { } @@ -513,7 +556,7 @@ Eh_frame::skip_leb128(const unsigned char** pp, const unsigned char* pend) template bool Eh_frame::add_ehframe_input_section( - Sized_relobj* object, + Sized_relobj_file* object, const unsigned char* symbols, section_size_type symbols_size, const unsigned char* symbol_names, @@ -545,7 +588,8 @@ Eh_frame::add_ehframe_input_section( reloc_type, pcontents, contents_len, &new_cies)) { - this->eh_frame_hdr_->found_unrecognized_eh_frame_section(); + if (this->eh_frame_hdr_ != NULL) + this->eh_frame_hdr_->found_unrecognized_eh_frame_section(); for (New_cies::iterator p = new_cies.begin(); p != new_cies.end(); @@ -575,7 +619,7 @@ Eh_frame::add_ehframe_input_section( template bool Eh_frame::do_add_ehframe_input_section( - Sized_relobj* object, + Sized_relobj_file* object, const unsigned char* symbols, section_size_type symbols_size, const unsigned char* symbol_names, @@ -662,7 +706,7 @@ Eh_frame::do_add_ehframe_input_section( template bool -Eh_frame::read_cie(Sized_relobj* object, +Eh_frame::read_cie(Sized_relobj_file* object, unsigned int shndx, const unsigned char* symbols, section_size_type symbols_size, @@ -670,7 +714,7 @@ Eh_frame::read_cie(Sized_relobj* object, section_size_type symbol_names_size, const unsigned char* pcontents, const unsigned char* pcie, - const unsigned char *pcieend, + const unsigned char* pcieend, Track_relocs* relocs, Offsets_to_cie* cies, New_cies* new_cies) @@ -916,14 +960,14 @@ Eh_frame::read_cie(Sized_relobj* object, template bool -Eh_frame::read_fde(Sized_relobj* object, +Eh_frame::read_fde(Sized_relobj_file* object, unsigned int shndx, const unsigned char* symbols, section_size_type symbols_size, const unsigned char* pcontents, unsigned int offset, const unsigned char* pfde, - const unsigned char *pfdeend, + const unsigned char* pfdeend, Track_relocs* relocs, Offsets_to_cie* cies) { @@ -959,9 +1003,12 @@ Eh_frame::read_fde(Sized_relobj* object, if (symndx >= symbols_size / sym_size) return false; elfcpp::Sym sym(symbols + symndx * sym_size); - fde_shndx = sym.get_st_shndx(); + bool is_ordinary; + fde_shndx = object->adjust_sym_shndx(symndx, sym.get_st_shndx(), + &is_ordinary); - if (fde_shndx != elfcpp::SHN_UNDEF + if (is_ordinary + && fde_shndx != elfcpp::SHN_UNDEF && fde_shndx < object->shnum() && !object->is_section_included(fde_shndx)) { @@ -978,6 +1025,29 @@ Eh_frame::read_fde(Sized_relobj* object, return true; } +// Add unwind information for a PLT. + +void +Eh_frame::add_ehframe_for_plt(Output_data* plt, const unsigned char* cie_data, + size_t cie_length, const unsigned char* fde_data, + size_t fde_length) +{ + 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); + Cie* pcie; + if (find_cie != this->cie_offsets_.end()) + pcie = *find_cie; + else + { + pcie = new Cie(cie); + this->cie_offsets_.insert(pcie); + } + + Fde* fde = new Fde(plt, fde_data, fde_length); + pcie->add_fde(fde); +} + // Return the number of FDEs. unsigned int @@ -1001,6 +1071,15 @@ Eh_frame::fde_count() const void Eh_frame::set_final_data_size() { + // We can be called more than once if Layout::set_segment_offsets + // finds a better mapping. We don't want to add all the mappings + // again. + if (this->mappings_are_done_) + { + this->set_data_size(this->final_data_size_); + return; + } + section_offset_type output_offset = 0; for (Unmergeable_cie_offsets::iterator p = @@ -1018,6 +1097,9 @@ Eh_frame::set_final_data_size() this->addralign(), &this->merge_map_); + this->mappings_are_done_ = true; + this->final_data_size_ = output_offset; + gold_assert((output_offset & (this->addralign() - 1)) == 0); this->set_data_size(output_offset); } @@ -1050,46 +1132,31 @@ Eh_frame::do_write(Output_file* of) const off_t oview_size = this->data_size(); unsigned char* const oview = of->get_output_view(offset, oview_size); - if (parameters->get_size() == 32) + switch (parameters->size_and_endianness()) { - if (!parameters->is_big_endian()) - { #ifdef HAVE_TARGET_32_LITTLE - this->do_sized_write<32, false>(oview); -#else - gold_unreachable(); + case Parameters::TARGET_32_LITTLE: + this->do_sized_write<32, false>(oview); + break; #endif - } - else - { #ifdef HAVE_TARGET_32_BIG - this->do_sized_write<32, true>(oview); -#else - gold_unreachable(); + case Parameters::TARGET_32_BIG: + this->do_sized_write<32, true>(oview); + break; #endif - } - } - else if (parameters->get_size() == 64) - { - if (!parameters->is_big_endian()) - { #ifdef HAVE_TARGET_64_LITTLE - this->do_sized_write<64, false>(oview); -#else - gold_unreachable(); + case Parameters::TARGET_64_LITTLE: + this->do_sized_write<64, false>(oview); + break; #endif - } - else - { #ifdef HAVE_TARGET_64_BIG - this->do_sized_write<64, true>(oview); -#else - gold_unreachable(); + case Parameters::TARGET_64_BIG: + this->do_sized_write<64, true>(oview); + break; #endif - } + default: + gold_unreachable(); } - else - gold_unreachable(); of->write_output_view(offset, oview_size, oview); } @@ -1100,23 +1167,27 @@ template void Eh_frame::do_sized_write(unsigned char* oview) { + uint64_t address = this->address(); + unsigned int addralign = this->addralign(); section_offset_type o = 0; for (Unmergeable_cie_offsets::iterator p = this->unmergeable_cie_offsets_.begin(); p != this->unmergeable_cie_offsets_.end(); ++p) - o = (*p)->write(oview, o, this->eh_frame_hdr_); + o = (*p)->write(oview, o, address, addralign, + this->eh_frame_hdr_); for (Cie_offsets::iterator p = this->cie_offsets_.begin(); p != this->cie_offsets_.end(); ++p) - o = (*p)->write(oview, o, this->eh_frame_hdr_); + o = (*p)->write(oview, o, address, addralign, + this->eh_frame_hdr_); } #ifdef HAVE_TARGET_32_LITTLE template bool Eh_frame::add_ehframe_input_section<32, false>( - Sized_relobj<32, false>* object, + Sized_relobj_file<32, false>* object, const unsigned char* symbols, section_size_type symbols_size, const unsigned char* symbol_names, @@ -1130,7 +1201,7 @@ Eh_frame::add_ehframe_input_section<32, false>( template bool Eh_frame::add_ehframe_input_section<32, true>( - Sized_relobj<32, true>* object, + Sized_relobj_file<32, true>* object, const unsigned char* symbols, section_size_type symbols_size, const unsigned char* symbol_names, @@ -1144,7 +1215,7 @@ Eh_frame::add_ehframe_input_section<32, true>( template bool Eh_frame::add_ehframe_input_section<64, false>( - Sized_relobj<64, false>* object, + Sized_relobj_file<64, false>* object, const unsigned char* symbols, section_size_type symbols_size, const unsigned char* symbol_names, @@ -1158,7 +1229,7 @@ Eh_frame::add_ehframe_input_section<64, false>( template bool Eh_frame::add_ehframe_input_section<64, true>( - Sized_relobj<64, true>* object, + Sized_relobj_file<64, true>* object, const unsigned char* symbols, section_size_type symbols_size, const unsigned char* symbol_names,