diff options
author | Ian Lance Taylor <ian@airs.com> | 2011-07-01 22:05:01 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@airs.com> | 2011-07-01 22:05:01 +0000 |
commit | 07a60597350488f098508ee67717d549a8a0b579 (patch) | |
tree | 2476e48897011f57f41615892bdffda825fde6b2 /gold/ehframe.cc | |
parent | a931db6a07ac9ae2fec6c31c6d037716050292c5 (diff) | |
download | gdb-07a60597350488f098508ee67717d549a8a0b579.zip gdb-07a60597350488f098508ee67717d549a8a0b579.tar.gz gdb-07a60597350488f098508ee67717d549a8a0b579.tar.bz2 |
PR gold/12571
* options.h (class General_options): Add
--ld-generated-unwind-info.
* ehframe.cc (Fde::write): Add address parameter. Change all
callers. If associated with PLT, fill in address and size.
(Cie::set_output_offset): Only add merge mapping if there is an
object.
(Cie::write): Add address parameter. Change all callers.
(Eh_frame::add_ehframe_for_plt): New function.
* ehframe.h (class Fde): Update declarations. Move shndx_ and
input_offset_ fields into union u_, with new plt field.
(Fde::Fde): Adjust for new union field.
(Fde::Fde) [Output_data version]: New constructor.
(Fde::add_mapping): Only add merge mapping if there is an object.
(class Cie): Update declarations.
(class Eh_frame): Declare add_ehframe_for_plt.
* layout.cc (Layout::layout_eh_frame): Break out code into
make_eh_frame_section, and call it.
(Layout::make_eh_frame_section): New function.
(Layout::add_eh_frame_for_plt): New function.
* layout.h (class Layout): Update declarations.
* merge.cc (Merge_map::add_mapping): Add assertion.
* i386.cc: Include "dwarf.h".
(class Output_data_plt_i386): Make first_plt_entry,
dyn_first_plt_entry, exec_plt_entry, and dyn_plt_entry const. Add
plt_eh_frame_cie_size, plt_eh_frame_fde_size, plt_eh_frame_cie,
and plt_eh_frame_fde.
(Output_data_plt_i386::Output_data_plt_i386): Align to 16-byte
boundary. Call add_eh_frame_for_plt if appropriate.
* x86_64.cc: Include "dwarf.h".
(class Output_data_plt_x86_64): Align to 16-byte boundary. Make
first_plt_entry, plt_entry and tlsdesc_plt_entry const. Add
plt_eh_frame_cie_size, plt_eh_frame_fde_size, plt_eh_frame_cie,
and plt_eh_frame_fde.
(Output_data_plt_x86_64::init): Call add_eh_frame_for_plt if
appropriate.
Diffstat (limited to 'gold/ehframe.cc')
-rw-r--r-- | gold/ehframe.cc | 71 |
1 files changed, 60 insertions, 11 deletions
diff --git a/gold/ehframe.cc b/gold/ehframe.cc index fbeb8a3..80b0035 100644 --- a/gold/ehframe.cc +++ b/gold/ehframe.cc @@ -1,6 +1,6 @@ // ehframe.cc -- handle exception frame sections for gold -// Copyright 2006, 2007, 2008, 2010 Free Software Foundation, Inc. +// Copyright 2006, 2007, 2008, 2010, 2011 Free Software Foundation, Inc. // Written by Ian Lance Taylor <iant@google.com>. // This file is part of gold. @@ -321,14 +321,16 @@ 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. ADDRALIGN is the required alignment. 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<int size, bool big_endian> section_offset_type Fde::write(unsigned char* oview, section_offset_type offset, - unsigned int addralign, section_offset_type cie_offset, - unsigned char fde_encoding, Eh_frame_hdr* eh_frame_hdr) + 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); @@ -355,6 +357,24 @@ 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<int32_t>(poffset); + off_t psize = plt->data_size(); + uint32_t upsize = static_cast<uint32_t>(psize); + if (static_cast<uint64_t>(static_cast<int64_t>(spoffset)) != poffset + || static_cast<off_t>(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)); @@ -389,8 +409,12 @@ Cie::set_output_offset(section_offset_type output_offset, // 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); @@ -415,7 +439,8 @@ Cie::set_output_offset(section_offset_type output_offset, template<int size, bool big_endian> section_offset_type Cie::write(unsigned char* oview, section_offset_type offset, - unsigned int addralign, Eh_frame_hdr* eh_frame_hdr) + uint64_t address, unsigned int addralign, + Eh_frame_hdr* eh_frame_hdr) { gold_assert((offset & (addralign - 1)) == 0); @@ -448,7 +473,7 @@ Cie::write(unsigned char* oview, section_offset_type offset, for (std::vector<Fde*>::const_iterator p = this->fdes_.begin(); p != this->fdes_.end(); ++p) - offset = (*p)->write<size, big_endian>(oview, offset, addralign, + offset = (*p)->write<size, big_endian>(oview, offset, address, addralign, cie_offset, fde_encoding, eh_frame_hdr); @@ -994,6 +1019,29 @@ Eh_frame::read_fde(Sized_relobj_file<size, big_endian>* 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 @@ -1113,18 +1161,19 @@ template<int size, bool big_endian> 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<size, big_endian>(oview, o, addralign, + o = (*p)->write<size, big_endian>(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<size, big_endian>(oview, o, addralign, + o = (*p)->write<size, big_endian>(oview, o, address, addralign, this->eh_frame_hdr_); } |