Message ID | 20190515124006.25840-7-christophe.lyon@st.com |
---|---|
State | Superseded |
Headers | show |
Series | FDPIC ABI for ARM | expand |
As Richard mentioned in an earlier post the generic libgcc and libstdc++ changes will need approval from the relevant maintainers. CC'ing the libstdc++ list and the libgcc maintainer. On 5/15/19 1:39 PM, Christophe Lyon wrote: > The main difference with existing support is that function addresses > are function descriptor addresses instead. This means that all code > dealing with function pointers now has to cope with function > descriptors instead. > > For the same reason, Linux kernel helpers can no longer be called by > dereferencing their address, so we implement wrappers that directly > call the kernel helpers. > > When restoring a function address, we also have to restore the FDPIC > register value (r9). > > 2019-XX-XX Christophe Lyon <christophe.lyon@st.com> > Mickaël Guêné <mickael.guene@st.com> > > gcc/ > * ginclude/unwind-arm-common.h (unwinder_cache): Add reserved5 > field. > (FDPIC_REGNUM): New define. > > libgcc/ > * config/arm/linux-atomic.c (__kernel_cmpxchg): Add FDPIC support. > (__kernel_dmb): Likewise. > (__fdpic_cmpxchg): New function. > (__fdpic_dmb): New function. > * config/arm/unwind-arm.h (FDPIC_REGNUM): New define. > (gnu_Unwind_Find_got): New function. > (_Unwind_decode_typeinfo_ptr): Add FDPIC support. > * unwind-arm-common.inc (UCB_PR_GOT): New. > (funcdesc_t): New struct. > (get_eit_entry): Add FDPIC support. > (unwind_phase2): Likewise. > (unwind_phase2_forced): Likewise. > (__gnu_Unwind_RaiseException): Likewise. > (__gnu_Unwind_Resume): Likewise. > (__gnu_Unwind_Backtrace): Likewise. > * unwind-pe.h (read_encoded_value_with_base): Likewise. > > libstdc++/ > * libsupc++/eh_personality.cc (get_ttype_entry): Add FDPIC > support. > > Change-Id: I64b81cfaf390a05f2fd121f44ba1912cb4b47cae > > diff --git a/gcc/ginclude/unwind-arm-common.h > b/gcc/ginclude/unwind-arm-common.h > index 6df783e..d4eb03e 100644 > --- a/gcc/ginclude/unwind-arm-common.h > +++ b/gcc/ginclude/unwind-arm-common.h > @@ -91,7 +91,7 @@ extern "C" { > _uw reserved2; /* Personality routine address */ > _uw reserved3; /* Saved callsite address */ > _uw reserved4; /* Forced unwind stop arg */ > - _uw reserved5; > + _uw reserved5; /* Personality routine GOT value in FDPIC > mode. */ > } > unwinder_cache; > /* Propagation barrier cache (valid after phase 1): */ > diff --git a/libgcc/config/arm/linux-atomic.c > b/libgcc/config/arm/linux-atomic.c > index 06a6d46..565f829 100644 > --- a/libgcc/config/arm/linux-atomic.c > +++ b/libgcc/config/arm/linux-atomic.c > @@ -25,11 +25,62 @@ see the files COPYING3 and COPYING.RUNTIME > respectively. If not, see > > /* Kernel helper for compare-and-exchange. */ > typedef int (__kernel_cmpxchg_t) (int oldval, int newval, int *ptr); > -#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *) 0xffff0fc0) > + > +#define STR(X) #X > +#define XSTR(X) STR(X) > + > +#define KERNEL_CMPXCHG 0xffff0fc0 > + > +#if __FDPIC__ > +/* Non-FDPIC ABIs call __kernel_cmpxchg directly by dereferencing its > + address, but under FDPIC we would generate a broken call > + sequence. That's why we have to implement __kernel_cmpxchg and > + __kernel_dmb here: this way, the FDPIC call sequence works. */ > +#define __kernel_cmpxchg __fdpic_cmpxchg > +#else > +#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *) KERNEL_CMPXCHG) > +#endif > > /* Kernel helper for memory barrier. */ > typedef void (__kernel_dmb_t) (void); > -#define __kernel_dmb (*(__kernel_dmb_t *) 0xffff0fa0) > + > +#define KERNEL_DMB 0xffff0fa0 > + > +#if __FDPIC__ > +#define __kernel_dmb __fdpic_dmb > +#else > +#define __kernel_dmb (*(__kernel_dmb_t *) KERNEL_DMB) > +#endif > + > +#if __FDPIC__ > +static int __fdpic_cmpxchg (int oldval, int newval, int *ptr) > +{ > + int result; > + > + asm volatile ( > + "ldr ip, 1f\n\t" > + "bx ip\n\t" > + "1:\n\t" > + ".word " XSTR(KERNEL_CMPXCHG) "\n\t" > + : "=r" (result) > + : "r" (oldval) , "r" (newval), "r" (ptr) > + : "r3", "memory"); > + /* The result is actually returned by the kernel helper, we need > + this to avoid a warning. */ > + return result; > +} > + > +static void __fdpic_dmb (void) > +{ > + asm volatile ( > + "ldr ip, 1f\n\t" > + "bx ip\n\t" > + "1:\n\t" > + ".word " XSTR(KERNEL_DMB) "\n\t" > + ); > +} > + > +#endif > > /* Note: we implement byte, short and int versions of atomic > operations using > the above kernel helpers; see linux-atomic-64bit.c for "long long" > (64-bit) > diff --git a/libgcc/config/arm/unwind-arm.h > b/libgcc/config/arm/unwind-arm.h > index 43c5379..2bf320a 100644 > --- a/libgcc/config/arm/unwind-arm.h > +++ b/libgcc/config/arm/unwind-arm.h > @@ -33,9 +33,33 @@ > /* Use IP as a scratch register within the personality routine. */ > #define UNWIND_POINTER_REG 12 > > +#define FDPIC_REGNUM 9 > + > +#define STR(x) #x > +#define XSTR(x) STR(x) > + > #ifdef __cplusplus > extern "C" { > #endif > +_Unwind_Ptr __attribute__((weak)) __gnu_Unwind_Find_got (_Unwind_Ptr); > + > +static inline _Unwind_Ptr gnu_Unwind_Find_got (_Unwind_Ptr ptr) > +{ > + _Unwind_Ptr res; > + > + if (__gnu_Unwind_Find_got) > + res = __gnu_Unwind_Find_got (ptr); > + else > + { > + asm volatile ("mov %[result], r" XSTR(FDPIC_REGNUM) > + : [result]"=r" (res) > + : > + :); > + } > + > + return res; > +} > + > /* Decode an R_ARM_TARGET2 relocation. */ > static inline _Unwind_Word > _Unwind_decode_typeinfo_ptr (_Unwind_Word base __attribute__ > ((unused)), > @@ -48,7 +72,12 @@ extern "C" { > if (!tmp) > return 0; > > -#if (defined(linux) && !defined(__uClinux__)) || defined(__NetBSD__) \ > +#if __FDPIC__ > + /* For FDPIC, we store the offset of the GOT entry. */ > + /* So, first get GOT from dynamic linker and then use indirect > access. */ > + tmp += gnu_Unwind_Find_got (ptr); > + tmp = *(_Unwind_Word *) tmp; > +#elif (defined(linux) && !defined(__uClinux__)) || defined(__NetBSD__) \ > || defined(__FreeBSD__) || defined(__fuchsia__) > /* Pc-relative indirect. */ > #define _GLIBCXX_OVERRIDE_TTYPE_ENCODING (DW_EH_PE_pcrel | > DW_EH_PE_indirect) > diff --git a/libgcc/unwind-arm-common.inc b/libgcc/unwind-arm-common.inc > index fd572fe..0bacc11 100644 > --- a/libgcc/unwind-arm-common.inc > +++ b/libgcc/unwind-arm-common.inc > @@ -62,6 +62,7 @@ __gnu_Unwind_Find_exidx (_Unwind_Ptr, int *); > #define UCB_PR_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved2) > #define UCB_SAVED_CALLSITE_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved3) > #define UCB_FORCED_STOP_ARG(ucbp) ((ucbp)->unwinder_cache.reserved4) > +#define UCB_PR_GOT(ucbp) ((ucbp)->unwinder_cache.reserved5) > > /* Unwind descriptors. */ > > @@ -85,6 +86,16 @@ typedef struct __EIT_entry > _uw content; > } __EIT_entry; > > +#ifdef __FDPIC__ > + > +/* Only used in FDPIC case. */ > +struct funcdesc_t > +{ > + unsigned int ptr; > + unsigned int got; > +}; > +#endif > + > /* Assembly helper functions. */ > > /* Restore core register state. Never returns. */ > @@ -259,7 +270,21 @@ get_eit_entry (_Unwind_Control_Block *ucbp, _uw > return_address) > { > /* One of the predefined standard routines. */ > _uw idx = (*(_uw *) ucbp->pr_cache.ehtp >> 24) & 0xf; > +#if __FDPIC__ > + { > + struct funcdesc_t *funcdesc > + = (struct funcdesc_t *) __gnu_unwind_get_pr_addr (idx); > + if (funcdesc) > + { > + UCB_PR_ADDR (ucbp) = funcdesc->ptr; > + UCB_PR_GOT (ucbp) = funcdesc->got; > + } > + else > + UCB_PR_ADDR (ucbp) = 0; > + } > +#else > UCB_PR_ADDR (ucbp) = __gnu_unwind_get_pr_addr (idx); > +#endif > if (UCB_PR_ADDR (ucbp) == 0) > { > /* Failed */ > @@ -270,6 +295,10 @@ get_eit_entry (_Unwind_Control_Block *ucbp, _uw > return_address) > { > /* Execute region offset to PR */ > UCB_PR_ADDR (ucbp) = selfrel_offset31 (ucbp->pr_cache.ehtp); > +#if __FDPIC__ > + UCB_PR_GOT (ucbp) > + = (unsigned int) gnu_Unwind_Find_got ((_Unwind_Ptr) > UCB_PR_ADDR (ucbp)); > +#endif > } > return _URC_OK; > } > @@ -291,14 +320,29 @@ unwind_phase2 (_Unwind_Control_Block * ucbp, > phase2_vrs * vrs) > UCB_SAVED_CALLSITE_ADDR (ucbp) = VRS_PC(vrs); > > /* Call the pr to decide what to do. */ > +#if __FDPIC__ > + { > + volatile struct funcdesc_t funcdesc; > + funcdesc.ptr = UCB_PR_ADDR (ucbp); > + funcdesc.got = UCB_PR_GOT (ucbp); > + pr_result = ((personality_routine) &funcdesc) > + (_US_UNWIND_FRAME_STARTING, ucbp, (_Unwind_Context *) vrs); > + } > +#else > pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) > (_US_UNWIND_FRAME_STARTING, ucbp, (_Unwind_Context *) vrs); > +#endif > } > while (pr_result == _URC_CONTINUE_UNWIND); > > if (pr_result != _URC_INSTALL_CONTEXT) > abort(); > > +#if __FDPIC__ > + /* r9 could have been lost due to PLT jump. Restore correct value. */ > + vrs->core.r[FDPIC_REGNUM] = gnu_Unwind_Find_got (VRS_PC (vrs)); > +#endif > + > uw_restore_core_regs (vrs, &vrs->core); > } > > @@ -346,8 +390,18 @@ unwind_phase2_forced (_Unwind_Control_Block > *ucbp, phase2_vrs *entry_vrs, > next_vrs = saved_vrs; > > /* Call the pr to decide what to do. */ > +#if __FDPIC__ > + { > + volatile struct funcdesc_t funcdesc; > + funcdesc.ptr = UCB_PR_ADDR (ucbp); > + funcdesc.got = UCB_PR_GOT (ucbp); > + pr_result = ((personality_routine) &funcdesc) > + (action, ucbp, (void *) &next_vrs); > + } > +#else > pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) > (action, ucbp, (void *) &next_vrs); > +#endif > > saved_vrs.prev_sp = VRS_SP (&next_vrs); > } > @@ -384,6 +438,11 @@ unwind_phase2_forced (_Unwind_Control_Block > *ucbp, phase2_vrs *entry_vrs, > return _URC_FAILURE; > } > > +#if __FDPIC__ > + /* r9 could have been lost due to PLT jump. Restore correct value. */ > + saved_vrs.core.r[FDPIC_REGNUM] = gnu_Unwind_Find_got (VRS_PC > (&saved_vrs)); > +#endif > + > uw_restore_core_regs (&saved_vrs, &saved_vrs.core); > } > > @@ -429,8 +488,18 @@ __gnu_Unwind_RaiseException > (_Unwind_Control_Block * ucbp, > return _URC_FAILURE; > > /* Call the pr to decide what to do. */ > +#if __FDPIC__ > + { > + volatile struct funcdesc_t funcdesc; > + funcdesc.ptr = UCB_PR_ADDR (ucbp); > + funcdesc.got = UCB_PR_GOT (ucbp); > + pr_result = ((personality_routine) &funcdesc) > + (_US_VIRTUAL_UNWIND_FRAME, ucbp, (void *) &saved_vrs); > + } > +#else > pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) > (_US_VIRTUAL_UNWIND_FRAME, ucbp, (void *) &saved_vrs); > +#endif > } > while (pr_result == _URC_CONTINUE_UNWIND); > > @@ -488,13 +557,27 @@ __gnu_Unwind_Resume (_Unwind_Control_Block * > ucbp, phase2_vrs * entry_vrs) > } > > /* Call the cached PR. */ > +#if __FDPIC__ > + { > + volatile struct funcdesc_t funcdesc; > + funcdesc.ptr = UCB_PR_ADDR (ucbp); > + funcdesc.got = UCB_PR_GOT (ucbp); > + pr_result = ((personality_routine) &funcdesc) > + (_US_UNWIND_FRAME_RESUME, ucbp, (_Unwind_Context *) entry_vrs); > + } > +#else > pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) > (_US_UNWIND_FRAME_RESUME, ucbp, (_Unwind_Context *) entry_vrs); > +#endif > > switch (pr_result) > { > case _URC_INSTALL_CONTEXT: > /* Upload the registers to enter the landing pad. */ > +#if __FDPIC__ > + /* r9 could have been lost due to PLT jump. Restore correct > value. */ > + entry_vrs->core.r[FDPIC_REGNUM] = gnu_Unwind_Find_got (VRS_PC > (entry_vrs)); > +#endif > uw_restore_core_regs (entry_vrs, &entry_vrs->core); > > case _URC_CONTINUE_UNWIND: > @@ -586,9 +669,20 @@ __gnu_Unwind_Backtrace(_Unwind_Trace_Fn trace, > void * trace_argument, > } > > /* Call the pr to decide what to do. */ > +#if __FDPIC__ > + { > + volatile struct funcdesc_t funcdesc; > + funcdesc.ptr = UCB_PR_ADDR (ucbp); > + funcdesc.got = UCB_PR_GOT (ucbp); > + code = ((personality_routine) &funcdesc) > + (_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, > + ucbp, (void *) &saved_vrs); > + } > +#else > code = ((personality_routine) UCB_PR_ADDR (ucbp)) > (_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, > ucbp, (void *) &saved_vrs); > +#endif > } > while (code != _URC_END_OF_STACK > && code != _URC_FAILURE); > diff --git a/libgcc/unwind-pe.h b/libgcc/unwind-pe.h > index 4ed1c66..1c9dae5 100644 > --- a/libgcc/unwind-pe.h > +++ b/libgcc/unwind-pe.h > @@ -262,10 +262,27 @@ read_encoded_value_with_base (unsigned char > encoding, _Unwind_Ptr base, > > if (result != 0) > { > +#if __FDPIC__ > + /* FDPIC relative addresses imply taking the GOT address > + into account. */ > + if ((encoding & DW_EH_PE_pcrel) && (encoding & > DW_EH_PE_indirect)) > + { > + result += gnu_Unwind_Find_got ((_Unwind_Ptr) u); > + result = *(_Unwind_Internal_Ptr *) result; > + } > + else > + { > + result += ((encoding & 0x70) == DW_EH_PE_pcrel > + ? (_Unwind_Internal_Ptr) u : base); > + if (encoding & DW_EH_PE_indirect) > + result = *(_Unwind_Internal_Ptr *) result; > + } > +#else > result += ((encoding & 0x70) == DW_EH_PE_pcrel > ? (_Unwind_Internal_Ptr) u : base); > if (encoding & DW_EH_PE_indirect) > result = *(_Unwind_Internal_Ptr *) result; > +#endif > } > } > > diff --git a/libstdc++-v3/libsupc++/eh_personality.cc > b/libstdc++-v3/libsupc++/eh_personality.cc > index 35e4e46..1528ab9 100644 > --- a/libstdc++-v3/libsupc++/eh_personality.cc > +++ b/libstdc++-v3/libsupc++/eh_personality.cc > @@ -93,7 +93,15 @@ get_ttype_entry (lsda_header_info *info, _uleb128_t i) > _Unwind_Ptr ptr; > > i *= size_of_encoded_value (info->ttype_encoding); > - read_encoded_value_with_base (info->ttype_encoding, info->ttype_base, > + read_encoded_value_with_base ( > +#if __FDPIC__ > + /* Force these flags to nake sure to > + take the GOT into account. */ > + (DW_EH_PE_pcrel | DW_EH_PE_indirect), > +#else > + info->ttype_encoding, > +#endif > + info->ttype_base, > info->TType - i, &ptr); > > return reinterpret_cast<const std::type_info *>(ptr); > -- > 2.6.3 >
On 30/08/19 10:02 +0100, Kyrill Tkachov wrote: >As Richard mentioned in an earlier post the generic libgcc and >libstdc++ changes will need approval from the relevant maintainers. > >CC'ing the libstdc++ list and the libgcc maintainer. The libstdc++ change is OK for trunk. >On 5/15/19 1:39 PM, Christophe Lyon wrote: >>The main difference with existing support is that function addresses >>are function descriptor addresses instead. This means that all code >>dealing with function pointers now has to cope with function >>descriptors instead. >> >>For the same reason, Linux kernel helpers can no longer be called by >>dereferencing their address, so we implement wrappers that directly >>call the kernel helpers. >> >>When restoring a function address, we also have to restore the FDPIC >>register value (r9). >> >>2019-XX-XX Christophe Lyon <christophe.lyon@st.com> >> Mickaël Guêné <mickael.guene@st.com> >> >> gcc/ >> * ginclude/unwind-arm-common.h (unwinder_cache): Add reserved5 >> field. >> (FDPIC_REGNUM): New define. >> >> libgcc/ >> * config/arm/linux-atomic.c (__kernel_cmpxchg): Add FDPIC support. >> (__kernel_dmb): Likewise. >> (__fdpic_cmpxchg): New function. >> (__fdpic_dmb): New function. >> * config/arm/unwind-arm.h (FDPIC_REGNUM): New define. >> (gnu_Unwind_Find_got): New function. >> (_Unwind_decode_typeinfo_ptr): Add FDPIC support. >> * unwind-arm-common.inc (UCB_PR_GOT): New. >> (funcdesc_t): New struct. >> (get_eit_entry): Add FDPIC support. >> (unwind_phase2): Likewise. >> (unwind_phase2_forced): Likewise. >> (__gnu_Unwind_RaiseException): Likewise. >> (__gnu_Unwind_Resume): Likewise. >> (__gnu_Unwind_Backtrace): Likewise. >> * unwind-pe.h (read_encoded_value_with_base): Likewise. >> >> libstdc++/ >> * libsupc++/eh_personality.cc (get_ttype_entry): Add FDPIC >> support. >> >>Change-Id: I64b81cfaf390a05f2fd121f44ba1912cb4b47cae >> >>diff --git a/gcc/ginclude/unwind-arm-common.h >>b/gcc/ginclude/unwind-arm-common.h >>index 6df783e..d4eb03e 100644 >>--- a/gcc/ginclude/unwind-arm-common.h >>+++ b/gcc/ginclude/unwind-arm-common.h >>@@ -91,7 +91,7 @@ extern "C" { >> _uw reserved2; /* Personality routine address */ >> _uw reserved3; /* Saved callsite address */ >> _uw reserved4; /* Forced unwind stop arg */ >>- _uw reserved5; >>+ _uw reserved5; /* Personality routine GOT value in FDPIC >>mode. */ >> } >> unwinder_cache; >> /* Propagation barrier cache (valid after phase 1): */ >>diff --git a/libgcc/config/arm/linux-atomic.c >>b/libgcc/config/arm/linux-atomic.c >>index 06a6d46..565f829 100644 >>--- a/libgcc/config/arm/linux-atomic.c >>+++ b/libgcc/config/arm/linux-atomic.c >>@@ -25,11 +25,62 @@ see the files COPYING3 and COPYING.RUNTIME >>respectively. If not, see >> >> /* Kernel helper for compare-and-exchange. */ >> typedef int (__kernel_cmpxchg_t) (int oldval, int newval, int *ptr); >>-#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *) 0xffff0fc0) >>+ >>+#define STR(X) #X >>+#define XSTR(X) STR(X) >>+ >>+#define KERNEL_CMPXCHG 0xffff0fc0 >>+ >>+#if __FDPIC__ >>+/* Non-FDPIC ABIs call __kernel_cmpxchg directly by dereferencing its >>+ address, but under FDPIC we would generate a broken call >>+ sequence. That's why we have to implement __kernel_cmpxchg and >>+ __kernel_dmb here: this way, the FDPIC call sequence works. */ >>+#define __kernel_cmpxchg __fdpic_cmpxchg >>+#else >>+#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *) KERNEL_CMPXCHG) >>+#endif >> >> /* Kernel helper for memory barrier. */ >> typedef void (__kernel_dmb_t) (void); >>-#define __kernel_dmb (*(__kernel_dmb_t *) 0xffff0fa0) >>+ >>+#define KERNEL_DMB 0xffff0fa0 >>+ >>+#if __FDPIC__ >>+#define __kernel_dmb __fdpic_dmb >>+#else >>+#define __kernel_dmb (*(__kernel_dmb_t *) KERNEL_DMB) >>+#endif >>+ >>+#if __FDPIC__ >>+static int __fdpic_cmpxchg (int oldval, int newval, int *ptr) >>+{ >>+ int result; >>+ >>+ asm volatile ( >>+ "ldr ip, 1f\n\t" >>+ "bx ip\n\t" >>+ "1:\n\t" >>+ ".word " XSTR(KERNEL_CMPXCHG) "\n\t" >>+ : "=r" (result) >>+ : "r" (oldval) , "r" (newval), "r" (ptr) >>+ : "r3", "memory"); >>+ /* The result is actually returned by the kernel helper, we need >>+ this to avoid a warning. */ >>+ return result; >>+} >>+ >>+static void __fdpic_dmb (void) >>+{ >>+ asm volatile ( >>+ "ldr ip, 1f\n\t" >>+ "bx ip\n\t" >>+ "1:\n\t" >>+ ".word " XSTR(KERNEL_DMB) "\n\t" >>+ ); >>+} >>+ >>+#endif >> >> /* Note: we implement byte, short and int versions of atomic >>operations using >> the above kernel helpers; see linux-atomic-64bit.c for "long >>long" (64-bit) >>diff --git a/libgcc/config/arm/unwind-arm.h >>b/libgcc/config/arm/unwind-arm.h >>index 43c5379..2bf320a 100644 >>--- a/libgcc/config/arm/unwind-arm.h >>+++ b/libgcc/config/arm/unwind-arm.h >>@@ -33,9 +33,33 @@ >> /* Use IP as a scratch register within the personality routine. */ >> #define UNWIND_POINTER_REG 12 >> >>+#define FDPIC_REGNUM 9 >>+ >>+#define STR(x) #x >>+#define XSTR(x) STR(x) >>+ >> #ifdef __cplusplus >> extern "C" { >> #endif >>+_Unwind_Ptr __attribute__((weak)) __gnu_Unwind_Find_got (_Unwind_Ptr); >>+ >>+static inline _Unwind_Ptr gnu_Unwind_Find_got (_Unwind_Ptr ptr) >>+{ >>+ _Unwind_Ptr res; >>+ >>+ if (__gnu_Unwind_Find_got) >>+ res = __gnu_Unwind_Find_got (ptr); >>+ else >>+ { >>+ asm volatile ("mov %[result], r" XSTR(FDPIC_REGNUM) >>+ : [result]"=r" (res) >>+ : >>+ :); >>+ } >>+ >>+ return res; >>+} >>+ >> /* Decode an R_ARM_TARGET2 relocation. */ >> static inline _Unwind_Word >> _Unwind_decode_typeinfo_ptr (_Unwind_Word base __attribute__ >>((unused)), >>@@ -48,7 +72,12 @@ extern "C" { >> if (!tmp) >> return 0; >> >>-#if (defined(linux) && !defined(__uClinux__)) || defined(__NetBSD__) \ >>+#if __FDPIC__ >>+ /* For FDPIC, we store the offset of the GOT entry. */ >>+ /* So, first get GOT from dynamic linker and then use >>indirect access. */ >>+ tmp += gnu_Unwind_Find_got (ptr); >>+ tmp = *(_Unwind_Word *) tmp; >>+#elif (defined(linux) && !defined(__uClinux__)) || defined(__NetBSD__) \ >> || defined(__FreeBSD__) || defined(__fuchsia__) >> /* Pc-relative indirect. */ >> #define _GLIBCXX_OVERRIDE_TTYPE_ENCODING (DW_EH_PE_pcrel | >>DW_EH_PE_indirect) >>diff --git a/libgcc/unwind-arm-common.inc b/libgcc/unwind-arm-common.inc >>index fd572fe..0bacc11 100644 >>--- a/libgcc/unwind-arm-common.inc >>+++ b/libgcc/unwind-arm-common.inc >>@@ -62,6 +62,7 @@ __gnu_Unwind_Find_exidx (_Unwind_Ptr, int *); >> #define UCB_PR_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved2) >> #define UCB_SAVED_CALLSITE_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved3) >> #define UCB_FORCED_STOP_ARG(ucbp) ((ucbp)->unwinder_cache.reserved4) >>+#define UCB_PR_GOT(ucbp) ((ucbp)->unwinder_cache.reserved5) >> >> /* Unwind descriptors. */ >> >>@@ -85,6 +86,16 @@ typedef struct __EIT_entry >> _uw content; >> } __EIT_entry; >> >>+#ifdef __FDPIC__ >>+ >>+/* Only used in FDPIC case. */ >>+struct funcdesc_t >>+{ >>+ unsigned int ptr; >>+ unsigned int got; >>+}; >>+#endif >>+ >> /* Assembly helper functions. */ >> >> /* Restore core register state. Never returns. */ >>@@ -259,7 +270,21 @@ get_eit_entry (_Unwind_Control_Block *ucbp, _uw >>return_address) >> { >> /* One of the predefined standard routines. */ >> _uw idx = (*(_uw *) ucbp->pr_cache.ehtp >> 24) & 0xf; >>+#if __FDPIC__ >>+ { >>+ struct funcdesc_t *funcdesc >>+ = (struct funcdesc_t *) __gnu_unwind_get_pr_addr (idx); >>+ if (funcdesc) >>+ { >>+ UCB_PR_ADDR (ucbp) = funcdesc->ptr; >>+ UCB_PR_GOT (ucbp) = funcdesc->got; >>+ } >>+ else >>+ UCB_PR_ADDR (ucbp) = 0; >>+ } >>+#else >> UCB_PR_ADDR (ucbp) = __gnu_unwind_get_pr_addr (idx); >>+#endif >> if (UCB_PR_ADDR (ucbp) == 0) >> { >> /* Failed */ >>@@ -270,6 +295,10 @@ get_eit_entry (_Unwind_Control_Block *ucbp, _uw >>return_address) >> { >> /* Execute region offset to PR */ >> UCB_PR_ADDR (ucbp) = selfrel_offset31 (ucbp->pr_cache.ehtp); >>+#if __FDPIC__ >>+ UCB_PR_GOT (ucbp) >>+ = (unsigned int) gnu_Unwind_Find_got ((_Unwind_Ptr) >>UCB_PR_ADDR (ucbp)); >>+#endif >> } >> return _URC_OK; >> } >>@@ -291,14 +320,29 @@ unwind_phase2 (_Unwind_Control_Block * ucbp, >>phase2_vrs * vrs) >> UCB_SAVED_CALLSITE_ADDR (ucbp) = VRS_PC(vrs); >> >> /* Call the pr to decide what to do. */ >>+#if __FDPIC__ >>+ { >>+ volatile struct funcdesc_t funcdesc; >>+ funcdesc.ptr = UCB_PR_ADDR (ucbp); >>+ funcdesc.got = UCB_PR_GOT (ucbp); >>+ pr_result = ((personality_routine) &funcdesc) >>+ (_US_UNWIND_FRAME_STARTING, ucbp, (_Unwind_Context *) vrs); >>+ } >>+#else >> pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) >> (_US_UNWIND_FRAME_STARTING, ucbp, (_Unwind_Context *) vrs); >>+#endif >> } >> while (pr_result == _URC_CONTINUE_UNWIND); >> >> if (pr_result != _URC_INSTALL_CONTEXT) >> abort(); >> >>+#if __FDPIC__ >>+ /* r9 could have been lost due to PLT jump. Restore correct value. */ >>+ vrs->core.r[FDPIC_REGNUM] = gnu_Unwind_Find_got (VRS_PC (vrs)); >>+#endif >>+ >> uw_restore_core_regs (vrs, &vrs->core); >> } >> >>@@ -346,8 +390,18 @@ unwind_phase2_forced (_Unwind_Control_Block >>*ucbp, phase2_vrs *entry_vrs, >> next_vrs = saved_vrs; >> >> /* Call the pr to decide what to do. */ >>+#if __FDPIC__ >>+ { >>+ volatile struct funcdesc_t funcdesc; >>+ funcdesc.ptr = UCB_PR_ADDR (ucbp); >>+ funcdesc.got = UCB_PR_GOT (ucbp); >>+ pr_result = ((personality_routine) &funcdesc) >>+ (action, ucbp, (void *) &next_vrs); >>+ } >>+#else >> pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) >> (action, ucbp, (void *) &next_vrs); >>+#endif >> >> saved_vrs.prev_sp = VRS_SP (&next_vrs); >> } >>@@ -384,6 +438,11 @@ unwind_phase2_forced (_Unwind_Control_Block >>*ucbp, phase2_vrs *entry_vrs, >> return _URC_FAILURE; >> } >> >>+#if __FDPIC__ >>+ /* r9 could have been lost due to PLT jump. Restore correct value. */ >>+ saved_vrs.core.r[FDPIC_REGNUM] = gnu_Unwind_Find_got (VRS_PC >>(&saved_vrs)); >>+#endif >>+ >> uw_restore_core_regs (&saved_vrs, &saved_vrs.core); >> } >> >>@@ -429,8 +488,18 @@ __gnu_Unwind_RaiseException >>(_Unwind_Control_Block * ucbp, >> return _URC_FAILURE; >> >> /* Call the pr to decide what to do. */ >>+#if __FDPIC__ >>+ { >>+ volatile struct funcdesc_t funcdesc; >>+ funcdesc.ptr = UCB_PR_ADDR (ucbp); >>+ funcdesc.got = UCB_PR_GOT (ucbp); >>+ pr_result = ((personality_routine) &funcdesc) >>+ (_US_VIRTUAL_UNWIND_FRAME, ucbp, (void *) &saved_vrs); >>+ } >>+#else >> pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) >> (_US_VIRTUAL_UNWIND_FRAME, ucbp, (void *) &saved_vrs); >>+#endif >> } >> while (pr_result == _URC_CONTINUE_UNWIND); >> >>@@ -488,13 +557,27 @@ __gnu_Unwind_Resume (_Unwind_Control_Block * >>ucbp, phase2_vrs * entry_vrs) >> } >> >> /* Call the cached PR. */ >>+#if __FDPIC__ >>+ { >>+ volatile struct funcdesc_t funcdesc; >>+ funcdesc.ptr = UCB_PR_ADDR (ucbp); >>+ funcdesc.got = UCB_PR_GOT (ucbp); >>+ pr_result = ((personality_routine) &funcdesc) >>+ (_US_UNWIND_FRAME_RESUME, ucbp, (_Unwind_Context *) entry_vrs); >>+ } >>+#else >> pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) >> (_US_UNWIND_FRAME_RESUME, ucbp, (_Unwind_Context *) entry_vrs); >>+#endif >> >> switch (pr_result) >> { >> case _URC_INSTALL_CONTEXT: >> /* Upload the registers to enter the landing pad. */ >>+#if __FDPIC__ >>+ /* r9 could have been lost due to PLT jump. Restore correct >>value. */ >>+ entry_vrs->core.r[FDPIC_REGNUM] = gnu_Unwind_Find_got (VRS_PC >>(entry_vrs)); >>+#endif >> uw_restore_core_regs (entry_vrs, &entry_vrs->core); >> >> case _URC_CONTINUE_UNWIND: >>@@ -586,9 +669,20 @@ __gnu_Unwind_Backtrace(_Unwind_Trace_Fn trace, >>void * trace_argument, >> } >> >> /* Call the pr to decide what to do. */ >>+#if __FDPIC__ >>+ { >>+ volatile struct funcdesc_t funcdesc; >>+ funcdesc.ptr = UCB_PR_ADDR (ucbp); >>+ funcdesc.got = UCB_PR_GOT (ucbp); >>+ code = ((personality_routine) &funcdesc) >>+ (_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, >>+ ucbp, (void *) &saved_vrs); >>+ } >>+#else >> code = ((personality_routine) UCB_PR_ADDR (ucbp)) >> (_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, >> ucbp, (void *) &saved_vrs); >>+#endif >> } >> while (code != _URC_END_OF_STACK >> && code != _URC_FAILURE); >>diff --git a/libgcc/unwind-pe.h b/libgcc/unwind-pe.h >>index 4ed1c66..1c9dae5 100644 >>--- a/libgcc/unwind-pe.h >>+++ b/libgcc/unwind-pe.h >>@@ -262,10 +262,27 @@ read_encoded_value_with_base (unsigned char >>encoding, _Unwind_Ptr base, >> >> if (result != 0) >> { >>+#if __FDPIC__ >>+ /* FDPIC relative addresses imply taking the GOT address >>+ into account. */ >>+ if ((encoding & DW_EH_PE_pcrel) && (encoding & >>DW_EH_PE_indirect)) >>+ { >>+ result += gnu_Unwind_Find_got ((_Unwind_Ptr) u); >>+ result = *(_Unwind_Internal_Ptr *) result; >>+ } >>+ else >>+ { >>+ result += ((encoding & 0x70) == DW_EH_PE_pcrel >>+ ? (_Unwind_Internal_Ptr) u : base); >>+ if (encoding & DW_EH_PE_indirect) >>+ result = *(_Unwind_Internal_Ptr *) result; >>+ } >>+#else >> result += ((encoding & 0x70) == DW_EH_PE_pcrel >> ? (_Unwind_Internal_Ptr) u : base); >> if (encoding & DW_EH_PE_indirect) >> result = *(_Unwind_Internal_Ptr *) result; >>+#endif >> } >> } >> >>diff --git a/libstdc++-v3/libsupc++/eh_personality.cc >>b/libstdc++-v3/libsupc++/eh_personality.cc >>index 35e4e46..1528ab9 100644 >>--- a/libstdc++-v3/libsupc++/eh_personality.cc >>+++ b/libstdc++-v3/libsupc++/eh_personality.cc >>@@ -93,7 +93,15 @@ get_ttype_entry (lsda_header_info *info, _uleb128_t i) >> _Unwind_Ptr ptr; >> >> i *= size_of_encoded_value (info->ttype_encoding); >>- read_encoded_value_with_base (info->ttype_encoding, info->ttype_base, >>+ read_encoded_value_with_base ( >>+#if __FDPIC__ >>+ /* Force these flags to nake sure to >>+ take the GOT into account. */ >>+ (DW_EH_PE_pcrel | DW_EH_PE_indirect), >>+#else >>+ info->ttype_encoding, >>+#endif >>+ info->ttype_base, >> info->TType - i, &ptr); >> >> return reinterpret_cast<const std::type_info *>(ptr); >>-- >>2.6.3 >>
diff --git a/gcc/ginclude/unwind-arm-common.h b/gcc/ginclude/unwind-arm-common.h index 6df783e..d4eb03e 100644 --- a/gcc/ginclude/unwind-arm-common.h +++ b/gcc/ginclude/unwind-arm-common.h @@ -91,7 +91,7 @@ extern "C" { _uw reserved2; /* Personality routine address */ _uw reserved3; /* Saved callsite address */ _uw reserved4; /* Forced unwind stop arg */ - _uw reserved5; + _uw reserved5; /* Personality routine GOT value in FDPIC mode. */ } unwinder_cache; /* Propagation barrier cache (valid after phase 1): */ diff --git a/libgcc/config/arm/linux-atomic.c b/libgcc/config/arm/linux-atomic.c index 06a6d46..565f829 100644 --- a/libgcc/config/arm/linux-atomic.c +++ b/libgcc/config/arm/linux-atomic.c @@ -25,11 +25,62 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see /* Kernel helper for compare-and-exchange. */ typedef int (__kernel_cmpxchg_t) (int oldval, int newval, int *ptr); -#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *) 0xffff0fc0) + +#define STR(X) #X +#define XSTR(X) STR(X) + +#define KERNEL_CMPXCHG 0xffff0fc0 + +#if __FDPIC__ +/* Non-FDPIC ABIs call __kernel_cmpxchg directly by dereferencing its + address, but under FDPIC we would generate a broken call + sequence. That's why we have to implement __kernel_cmpxchg and + __kernel_dmb here: this way, the FDPIC call sequence works. */ +#define __kernel_cmpxchg __fdpic_cmpxchg +#else +#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *) KERNEL_CMPXCHG) +#endif /* Kernel helper for memory barrier. */ typedef void (__kernel_dmb_t) (void); -#define __kernel_dmb (*(__kernel_dmb_t *) 0xffff0fa0) + +#define KERNEL_DMB 0xffff0fa0 + +#if __FDPIC__ +#define __kernel_dmb __fdpic_dmb +#else +#define __kernel_dmb (*(__kernel_dmb_t *) KERNEL_DMB) +#endif + +#if __FDPIC__ +static int __fdpic_cmpxchg (int oldval, int newval, int *ptr) +{ + int result; + + asm volatile ( + "ldr ip, 1f\n\t" + "bx ip\n\t" + "1:\n\t" + ".word " XSTR(KERNEL_CMPXCHG) "\n\t" + : "=r" (result) + : "r" (oldval) , "r" (newval), "r" (ptr) + : "r3", "memory"); + /* The result is actually returned by the kernel helper, we need + this to avoid a warning. */ + return result; +} + +static void __fdpic_dmb (void) +{ + asm volatile ( + "ldr ip, 1f\n\t" + "bx ip\n\t" + "1:\n\t" + ".word " XSTR(KERNEL_DMB) "\n\t" + ); +} + +#endif /* Note: we implement byte, short and int versions of atomic operations using the above kernel helpers; see linux-atomic-64bit.c for "long long" (64-bit) diff --git a/libgcc/config/arm/unwind-arm.h b/libgcc/config/arm/unwind-arm.h index 43c5379..2bf320a 100644 --- a/libgcc/config/arm/unwind-arm.h +++ b/libgcc/config/arm/unwind-arm.h @@ -33,9 +33,33 @@ /* Use IP as a scratch register within the personality routine. */ #define UNWIND_POINTER_REG 12 +#define FDPIC_REGNUM 9 + +#define STR(x) #x +#define XSTR(x) STR(x) + #ifdef __cplusplus extern "C" { #endif +_Unwind_Ptr __attribute__((weak)) __gnu_Unwind_Find_got (_Unwind_Ptr); + +static inline _Unwind_Ptr gnu_Unwind_Find_got (_Unwind_Ptr ptr) +{ + _Unwind_Ptr res; + + if (__gnu_Unwind_Find_got) + res = __gnu_Unwind_Find_got (ptr); + else + { + asm volatile ("mov %[result], r" XSTR(FDPIC_REGNUM) + : [result]"=r" (res) + : + :); + } + + return res; +} + /* Decode an R_ARM_TARGET2 relocation. */ static inline _Unwind_Word _Unwind_decode_typeinfo_ptr (_Unwind_Word base __attribute__ ((unused)), @@ -48,7 +72,12 @@ extern "C" { if (!tmp) return 0; -#if (defined(linux) && !defined(__uClinux__)) || defined(__NetBSD__) \ +#if __FDPIC__ + /* For FDPIC, we store the offset of the GOT entry. */ + /* So, first get GOT from dynamic linker and then use indirect access. */ + tmp += gnu_Unwind_Find_got (ptr); + tmp = *(_Unwind_Word *) tmp; +#elif (defined(linux) && !defined(__uClinux__)) || defined(__NetBSD__) \ || defined(__FreeBSD__) || defined(__fuchsia__) /* Pc-relative indirect. */ #define _GLIBCXX_OVERRIDE_TTYPE_ENCODING (DW_EH_PE_pcrel | DW_EH_PE_indirect) diff --git a/libgcc/unwind-arm-common.inc b/libgcc/unwind-arm-common.inc index fd572fe..0bacc11 100644 --- a/libgcc/unwind-arm-common.inc +++ b/libgcc/unwind-arm-common.inc @@ -62,6 +62,7 @@ __gnu_Unwind_Find_exidx (_Unwind_Ptr, int *); #define UCB_PR_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved2) #define UCB_SAVED_CALLSITE_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved3) #define UCB_FORCED_STOP_ARG(ucbp) ((ucbp)->unwinder_cache.reserved4) +#define UCB_PR_GOT(ucbp) ((ucbp)->unwinder_cache.reserved5) /* Unwind descriptors. */ @@ -85,6 +86,16 @@ typedef struct __EIT_entry _uw content; } __EIT_entry; +#ifdef __FDPIC__ + +/* Only used in FDPIC case. */ +struct funcdesc_t +{ + unsigned int ptr; + unsigned int got; +}; +#endif + /* Assembly helper functions. */ /* Restore core register state. Never returns. */ @@ -259,7 +270,21 @@ get_eit_entry (_Unwind_Control_Block *ucbp, _uw return_address) { /* One of the predefined standard routines. */ _uw idx = (*(_uw *) ucbp->pr_cache.ehtp >> 24) & 0xf; +#if __FDPIC__ + { + struct funcdesc_t *funcdesc + = (struct funcdesc_t *) __gnu_unwind_get_pr_addr (idx); + if (funcdesc) + { + UCB_PR_ADDR (ucbp) = funcdesc->ptr; + UCB_PR_GOT (ucbp) = funcdesc->got; + } + else + UCB_PR_ADDR (ucbp) = 0; + } +#else UCB_PR_ADDR (ucbp) = __gnu_unwind_get_pr_addr (idx); +#endif if (UCB_PR_ADDR (ucbp) == 0) { /* Failed */ @@ -270,6 +295,10 @@ get_eit_entry (_Unwind_Control_Block *ucbp, _uw return_address) { /* Execute region offset to PR */ UCB_PR_ADDR (ucbp) = selfrel_offset31 (ucbp->pr_cache.ehtp); +#if __FDPIC__ + UCB_PR_GOT (ucbp) + = (unsigned int) gnu_Unwind_Find_got ((_Unwind_Ptr) UCB_PR_ADDR (ucbp)); +#endif } return _URC_OK; } @@ -291,14 +320,29 @@ unwind_phase2 (_Unwind_Control_Block * ucbp, phase2_vrs * vrs) UCB_SAVED_CALLSITE_ADDR (ucbp) = VRS_PC(vrs); /* Call the pr to decide what to do. */ +#if __FDPIC__ + { + volatile struct funcdesc_t funcdesc; + funcdesc.ptr = UCB_PR_ADDR (ucbp); + funcdesc.got = UCB_PR_GOT (ucbp); + pr_result = ((personality_routine) &funcdesc) + (_US_UNWIND_FRAME_STARTING, ucbp, (_Unwind_Context *) vrs); + } +#else pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) (_US_UNWIND_FRAME_STARTING, ucbp, (_Unwind_Context *) vrs); +#endif } while (pr_result == _URC_CONTINUE_UNWIND); if (pr_result != _URC_INSTALL_CONTEXT) abort(); +#if __FDPIC__ + /* r9 could have been lost due to PLT jump. Restore correct value. */ + vrs->core.r[FDPIC_REGNUM] = gnu_Unwind_Find_got (VRS_PC (vrs)); +#endif + uw_restore_core_regs (vrs, &vrs->core); } @@ -346,8 +390,18 @@ unwind_phase2_forced (_Unwind_Control_Block *ucbp, phase2_vrs *entry_vrs, next_vrs = saved_vrs; /* Call the pr to decide what to do. */ +#if __FDPIC__ + { + volatile struct funcdesc_t funcdesc; + funcdesc.ptr = UCB_PR_ADDR (ucbp); + funcdesc.got = UCB_PR_GOT (ucbp); + pr_result = ((personality_routine) &funcdesc) + (action, ucbp, (void *) &next_vrs); + } +#else pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) (action, ucbp, (void *) &next_vrs); +#endif saved_vrs.prev_sp = VRS_SP (&next_vrs); } @@ -384,6 +438,11 @@ unwind_phase2_forced (_Unwind_Control_Block *ucbp, phase2_vrs *entry_vrs, return _URC_FAILURE; } +#if __FDPIC__ + /* r9 could have been lost due to PLT jump. Restore correct value. */ + saved_vrs.core.r[FDPIC_REGNUM] = gnu_Unwind_Find_got (VRS_PC (&saved_vrs)); +#endif + uw_restore_core_regs (&saved_vrs, &saved_vrs.core); } @@ -429,8 +488,18 @@ __gnu_Unwind_RaiseException (_Unwind_Control_Block * ucbp, return _URC_FAILURE; /* Call the pr to decide what to do. */ +#if __FDPIC__ + { + volatile struct funcdesc_t funcdesc; + funcdesc.ptr = UCB_PR_ADDR (ucbp); + funcdesc.got = UCB_PR_GOT (ucbp); + pr_result = ((personality_routine) &funcdesc) + (_US_VIRTUAL_UNWIND_FRAME, ucbp, (void *) &saved_vrs); + } +#else pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) (_US_VIRTUAL_UNWIND_FRAME, ucbp, (void *) &saved_vrs); +#endif } while (pr_result == _URC_CONTINUE_UNWIND); @@ -488,13 +557,27 @@ __gnu_Unwind_Resume (_Unwind_Control_Block * ucbp, phase2_vrs * entry_vrs) } /* Call the cached PR. */ +#if __FDPIC__ + { + volatile struct funcdesc_t funcdesc; + funcdesc.ptr = UCB_PR_ADDR (ucbp); + funcdesc.got = UCB_PR_GOT (ucbp); + pr_result = ((personality_routine) &funcdesc) + (_US_UNWIND_FRAME_RESUME, ucbp, (_Unwind_Context *) entry_vrs); + } +#else pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) (_US_UNWIND_FRAME_RESUME, ucbp, (_Unwind_Context *) entry_vrs); +#endif switch (pr_result) { case _URC_INSTALL_CONTEXT: /* Upload the registers to enter the landing pad. */ +#if __FDPIC__ + /* r9 could have been lost due to PLT jump. Restore correct value. */ + entry_vrs->core.r[FDPIC_REGNUM] = gnu_Unwind_Find_got (VRS_PC (entry_vrs)); +#endif uw_restore_core_regs (entry_vrs, &entry_vrs->core); case _URC_CONTINUE_UNWIND: @@ -586,9 +669,20 @@ __gnu_Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument, } /* Call the pr to decide what to do. */ +#if __FDPIC__ + { + volatile struct funcdesc_t funcdesc; + funcdesc.ptr = UCB_PR_ADDR (ucbp); + funcdesc.got = UCB_PR_GOT (ucbp); + code = ((personality_routine) &funcdesc) + (_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, + ucbp, (void *) &saved_vrs); + } +#else code = ((personality_routine) UCB_PR_ADDR (ucbp)) (_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, ucbp, (void *) &saved_vrs); +#endif } while (code != _URC_END_OF_STACK && code != _URC_FAILURE); diff --git a/libgcc/unwind-pe.h b/libgcc/unwind-pe.h index 4ed1c66..1c9dae5 100644 --- a/libgcc/unwind-pe.h +++ b/libgcc/unwind-pe.h @@ -262,10 +262,27 @@ read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base, if (result != 0) { +#if __FDPIC__ + /* FDPIC relative addresses imply taking the GOT address + into account. */ + if ((encoding & DW_EH_PE_pcrel) && (encoding & DW_EH_PE_indirect)) + { + result += gnu_Unwind_Find_got ((_Unwind_Ptr) u); + result = *(_Unwind_Internal_Ptr *) result; + } + else + { + result += ((encoding & 0x70) == DW_EH_PE_pcrel + ? (_Unwind_Internal_Ptr) u : base); + if (encoding & DW_EH_PE_indirect) + result = *(_Unwind_Internal_Ptr *) result; + } +#else result += ((encoding & 0x70) == DW_EH_PE_pcrel ? (_Unwind_Internal_Ptr) u : base); if (encoding & DW_EH_PE_indirect) result = *(_Unwind_Internal_Ptr *) result; +#endif } } diff --git a/libstdc++-v3/libsupc++/eh_personality.cc b/libstdc++-v3/libsupc++/eh_personality.cc index 35e4e46..1528ab9 100644 --- a/libstdc++-v3/libsupc++/eh_personality.cc +++ b/libstdc++-v3/libsupc++/eh_personality.cc @@ -93,7 +93,15 @@ get_ttype_entry (lsda_header_info *info, _uleb128_t i) _Unwind_Ptr ptr; i *= size_of_encoded_value (info->ttype_encoding); - read_encoded_value_with_base (info->ttype_encoding, info->ttype_base, + read_encoded_value_with_base ( +#if __FDPIC__ + /* Force these flags to nake sure to + take the GOT into account. */ + (DW_EH_PE_pcrel | DW_EH_PE_indirect), +#else + info->ttype_encoding, +#endif + info->ttype_base, info->TType - i, &ptr); return reinterpret_cast<const std::type_info *>(ptr);