diff options
-rw-r--r-- | gold/ChangeLog | 11 | ||||
-rw-r--r-- | gold/ehframe.cc | 8 | ||||
-rw-r--r-- | gold/i386.cc | 19 | ||||
-rw-r--r-- | gold/target.h | 13 | ||||
-rw-r--r-- | gold/x86_64.cc | 19 |
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 |