diff options
Diffstat (limited to 'libgcc')
-rw-r--r-- | libgcc/ChangeLog | 20 | ||||
-rw-r--r-- | libgcc/config/arm/linux-atomic.c | 55 | ||||
-rw-r--r-- | libgcc/config/arm/unwind-arm.h | 31 | ||||
-rw-r--r-- | libgcc/unwind-arm-common.inc | 94 | ||||
-rw-r--r-- | libgcc/unwind-pe.h | 17 |
5 files changed, 214 insertions, 3 deletions
diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index bb41129..8f29b5e 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,6 +1,26 @@ 2019-09-10 Christophe Lyon <christophe.lyon@st.com> Mickaël Guêné <mickael.guene@st.com> + * 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. + +2019-09-10 Christophe Lyon <christophe.lyon@st.com> + Mickaël Guêné <mickael.guene@st.com> + * libgcc/crtstuff.c: Add support for FDPIC. 2019-09-10 Christophe Lyon <christophe.lyon@st.com> 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 } } |