From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 46353 invoked by alias); 30 Aug 2019 09:02:54 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 46328 invoked by uid 89); 30 Aug 2019 09:02:53 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-17.6 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,HTML_MESSAGE autolearn=ham version=3.3.1 spammy=bx, landing X-HELO: foss.arm.com Received: from foss.arm.com (HELO foss.arm.com) (217.140.110.172) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 30 Aug 2019 09:02:48 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 4A33F344; Fri, 30 Aug 2019 02:02:47 -0700 (PDT) Received: from [10.2.206.47] (e120808-lin.cambridge.arm.com [10.2.206.47]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 7970C3F718; Fri, 30 Aug 2019 02:02:46 -0700 (PDT) Subject: Re: [ARM/FDPIC v5 06/21] [ARM] FDPIC: Add support for c++ exceptions To: Christophe Lyon , "gcc-patches@gcc.gnu.org" References: <20190515124006.25840-1-christophe.lyon@st.com> <20190515124006.25840-7-christophe.lyon@st.com> Cc: libstdc++@gcc.gnu.org, ian@airs.com From: Kyrill Tkachov Message-ID: <597c97c0-16a5-f886-3d1a-8e2f0b089259@foss.arm.com> Date: Fri, 30 Aug 2019 09:31:00 -0000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.7.1 MIME-Version: 1.0 In-Reply-To: <20190515124006.25840-7-christophe.lyon@st.com> Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit X-SW-Source: 2019-08/txt/msg02052.txt.bz2 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  >         Mickaël Guêné > >         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(ptr); > -- > 2.6.3 >