aboutsummaryrefslogtreecommitdiff
path: root/gold/ehframe.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gold/ehframe.cc')
-rw-r--r--gold/ehframe.cc71
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_);
}