From 02d7cd4495b617a9dc356b4f5140a74d020df6f5 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sat, 2 Jul 2011 00:03:25 +0000 Subject: [PATCH] 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. --- gold/ChangeLog | 11 +++++++++++ gold/ehframe.cc | 8 +++++++- gold/i386.cc | 19 +++++++++++++++++++ gold/target.h | 13 +++++++++++++ gold/x86_64.cc | 19 +++++++++++++++++++ 5 files changed, 69 insertions(+), 1 deletion(-) diff --git a/gold/ChangeLog b/gold/ChangeLog index 8b8112dc320..ae36ea22a1a 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,14 @@ +2011-07-01 Ian Lance Taylor + + 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 PR gold/12571 diff --git a/gold/ehframe.cc b/gold/ehframe.cc index 80b00358d22..dad23319913 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 6bec81f0507..65ff05f5f56 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*>(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 f9b8c045929..c2ccc638c94 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 12a5467f3f5..8308bf4ba7a 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*>(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 -- 2.30.2