aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gold/ChangeLog11
-rw-r--r--gold/ehframe.cc8
-rw-r--r--gold/i386.cc19
-rw-r--r--gold/target.h13
-rw-r--r--gold/x86_64.cc19
5 files changed, 69 insertions, 1 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index 8b8112d..ae36ea2 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,5 +1,16 @@
2011-07-01 Ian Lance Taylor <iant@google.com>
+ PR gold/12525
+ * ehframe.cc (Eh_frame_hdr::get_fde_pc): Handle DW_EH_PE_datarel.
+ Assert if we see DW_EH_PE_indirect.
+ * target.h (Target::ehframe_datarel_base): New function.
+ (Target::do_ehframe_datarel_base): New target function.
+ * i386.cc (Target_i386::do_ehframe_datarel_base): New function.
+ * x86_64.cc (Target_x86_64::do_ehframe_datarel_base): New
+ function.
+
+2011-07-01 Ian Lance Taylor <iant@google.com>
+
PR gold/12571
* options.h (class General_options): Add
--ld-generated-unwind-info.
diff --git a/gold/ehframe.cc b/gold/ehframe.cc
index 80b0035..dad2331 100644
--- a/gold/ehframe.cc
+++ b/gold/ehframe.cc
@@ -266,7 +266,7 @@ Eh_frame_hdr::get_fde_pc(
gold_unreachable();
}
- switch (fde_encoding & 0xf0)
+ switch (fde_encoding & 0x70)
{
case 0:
break;
@@ -275,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;
}
diff --git a/gold/i386.cc b/gold/i386.cc
index 6bec81f..65ff05f 100644
--- a/gold/i386.cc
+++ b/gold/i386.cc
@@ -295,6 +295,10 @@ class Target_i386 : public Sized_target<32, false>
do_can_check_for_function_pointers() const
{ return true; }
+ // Return the base for a DW_EH_PE_datarel encoding.
+ uint64_t
+ do_ehframe_datarel_base() const;
+
// Return whether SYM is call to a non-split function.
bool
do_is_call_to_non_split(const Symbol* sym, unsigned int) const;
@@ -3267,6 +3271,21 @@ Target_i386::do_code_fill(section_size_type length) const
return std::string(nops[length], length);
}
+// Return the value to use for the base of a DW_EH_PE_datarel offset
+// in an FDE. Solaris and SVR4 use DW_EH_PE_datarel because their
+// assembler can not write out the difference between two labels in
+// different sections, so instead of using a pc-relative value they
+// use an offset from the GOT.
+
+uint64_t
+Target_i386::do_ehframe_datarel_base() const
+{
+ gold_assert(this->global_offset_table_ != NULL);
+ Symbol* sym = this->global_offset_table_;
+ Sized_symbol<32>* ssym = static_cast<Sized_symbol<32>*>(sym);
+ return ssym->value();
+}
+
// Return whether SYM should be treated as a call to a non-split
// function. We don't want that to be true of a call to a
// get_pc_thunk function.
diff --git a/gold/target.h b/gold/target.h
index f9b8c04..c2ccc63 100644
--- a/gold/target.h
+++ b/gold/target.h
@@ -276,6 +276,15 @@ class Target
section_may_have_icf_unsafe_pointers(const char* section_name) const
{ return this->do_section_may_have_icf_unsafe_pointers(section_name); }
+ // Return the base to use for the PC value in an FDE when it is
+ // encoded using DW_EH_PE_datarel. This does not appear to be
+ // documented anywhere, but it is target specific. Any use of
+ // DW_EH_PE_datarel in gcc requires defining a special macro
+ // (ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX) to output the value.
+ uint64_t
+ ehframe_datarel_base() const
+ { return this->do_ehframe_datarel_base(); }
+
// Return true if a reference to SYM from a reloc of type R_TYPE
// means that the current function may call an object compiled
// without -fsplit-stack. SYM is known to be defined in an object
@@ -521,6 +530,10 @@ class Target
&& !is_prefix_of(".eh_frame", section_name));
}
+ virtual uint64_t
+ do_ehframe_datarel_base() const
+ { gold_unreachable(); }
+
// Virtual function which may be overridden by the child class. The
// default implementation is that any function not defined by the
// ABI is a call to a non-split function.
diff --git a/gold/x86_64.cc b/gold/x86_64.cc
index 12a5467..8308bf4 100644
--- a/gold/x86_64.cc
+++ b/gold/x86_64.cc
@@ -350,6 +350,10 @@ class Target_x86_64 : public Sized_target<64, false>
do_can_check_for_function_pointers() const
{ return !parameters->options().pie(); }
+ // Return the base for a DW_EH_PE_datarel encoding.
+ uint64_t
+ do_ehframe_datarel_base() const;
+
// Adjust -fsplit-stack code which calls non-split-stack code.
void
do_calls_non_split(Relobj* object, unsigned int shndx,
@@ -3640,6 +3644,21 @@ Target_x86_64::do_reloc_addend(void* arg, unsigned int r_type,
return psymval->value(ti.object, 0);
}
+// Return the value to use for the base of a DW_EH_PE_datarel offset
+// in an FDE. Solaris and SVR4 use DW_EH_PE_datarel because their
+// assembler can not write out the difference between two labels in
+// different sections, so instead of using a pc-relative value they
+// use an offset from the GOT.
+
+uint64_t
+Target_x86_64::do_ehframe_datarel_base() const
+{
+ gold_assert(this->global_offset_table_ != NULL);
+ Symbol* sym = this->global_offset_table_;
+ Sized_symbol<64>* ssym = static_cast<Sized_symbol<64>*>(sym);
+ return ssym->value();
+}
+
// FNOFFSET in section SHNDX in OBJECT is the start of a function
// compiled with -fsplit-stack. The function calls non-split-stack
// code. We have to change the function so that it always ensures