aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2007-12-07 06:44:01 +0000
committerIan Lance Taylor <iant@google.com>2007-12-07 06:44:01 +0000
commit4117d76827b3768e9da6ef52f52a59c5ae92bed3 (patch)
tree0e922a8a56fb517fce40ab926e9d1bb98039818a
parenta20d5e98e51d91b66dfccc205d4d27e8850238b2 (diff)
downloadgdb-4117d76827b3768e9da6ef52f52a59c5ae92bed3.zip
gdb-4117d76827b3768e9da6ef52f52a59c5ae92bed3.tar.gz
gdb-4117d76827b3768e9da6ef52f52a59c5ae92bed3.tar.bz2
Fix ehframe header handling for shared libraries.
-rw-r--r--gold/ehframe.cc28
-rw-r--r--gold/ehframe.h3
-rw-r--r--gold/layout.cc4
3 files changed, 30 insertions, 5 deletions
diff --git a/gold/ehframe.cc b/gold/ehframe.cc
index 91a977f..328048b 100644
--- a/gold/ehframe.cc
+++ b/gold/ehframe.cc
@@ -234,8 +234,11 @@ Eh_frame_hdr::do_sized_write(Output_file* of)
template<int size, bool big_endian>
typename elfcpp::Elf_types<size>::Elf_Addr
-Eh_frame_hdr::get_fde_pc(const unsigned char* eh_frame_contents,
- off_t fde_offset, unsigned char fde_encoding)
+Eh_frame_hdr::get_fde_pc(
+ typename elfcpp::Elf_types<size>::Elf_Addr eh_frame_address,
+ const unsigned char* eh_frame_contents,
+ off_t fde_offset,
+ unsigned char fde_encoding)
{
// The FDE starts with a 4 byte length and a 4 byte offset to the
// CIE. The PC follows.
@@ -274,6 +277,22 @@ Eh_frame_hdr::get_fde_pc(const unsigned char* eh_frame_contents,
break;
default:
+ // All other cases were rejected in Eh_frame::read_cie.
+ gold_unreachable();
+ }
+
+ switch (fde_encoding & 0xf0)
+ {
+ case 0:
+ break;
+
+ case elfcpp::DW_EH_PE_pcrel:
+ pc += eh_frame_address + fde_offset + 8;
+ 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();
}
@@ -304,7 +323,8 @@ Eh_frame_hdr::get_fde_addresses(Output_file* of,
++p)
{
typename elfcpp::Elf_types<size>::Elf_Addr fde_pc;
- fde_pc = this->get_fde_pc<size, big_endian>(eh_frame_contents,
+ fde_pc = this->get_fde_pc<size, big_endian>(eh_frame_address,
+ eh_frame_contents,
p->first, p->second);
fde_addresses->push_back(fde_pc, eh_frame_address + p->first);
}
@@ -742,6 +762,8 @@ Eh_frame::read_cie(Sized_relobj<size, big_endian>* object,
case elfcpp::DW_EH_PE_udata8:
break;
default:
+ // We don't expect to see any other cases here, and
+ // we're not prepared to handle them.
return false;
}
++p;
diff --git a/gold/ehframe.h b/gold/ehframe.h
index 12c8c16..5a733e7 100644
--- a/gold/ehframe.h
+++ b/gold/ehframe.h
@@ -131,7 +131,8 @@ class Eh_frame_hdr : public Output_section_data
// Return the PC to which an FDE refers.
template<int size, bool big_endian>
typename elfcpp::Elf_types<size>::Elf_Addr
- get_fde_pc(const unsigned char* eh_frame_contents,
+ get_fde_pc(typename elfcpp::Elf_types<size>::Elf_Addr eh_frame_address,
+ const unsigned char* eh_frame_contents,
off_t fde_offset, unsigned char fde_encoding);
// Convert Fde_offsets to Fde_addresses.
diff --git a/gold/layout.cc b/gold/layout.cc
index 68ebc6b..f5a1f67 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -992,7 +992,9 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
// Find the PT_LOAD segments, and set their addresses and offsets
// and their section's addresses and offsets.
uint64_t addr;
- if (options_.user_set_text_segment_address())
+ if (parameters->output_is_shared())
+ addr = 0;
+ else if (options_.user_set_text_segment_address())
addr = options_.text_segment_address();
else
addr = target->default_text_segment_address();