[libcxx-commits] [PATCH] D105968: [libunwind][CET] Support exception handling stack unwind in CET environment
Fangrui Song via Phabricator via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Aug 7 11:25:59 PDT 2021
MaskRay added a comment.
Have you checked `check-cxxabi` `test/forced_unwind[12].pass.cpp`? Do they pass with CET?
================
Comment at: libunwind/src/UnwindLevel1.c:47
+#if !defined(_LIBUNWIND_CET_ENABLED)
+#define __unw_phase2_resume(cursor, fn) __unw_resume((cursor))
+#elif _LIBUNWIND_CET_ENABLED == 1
----------------
xiongji90 wrote:
> xiongji90 wrote:
> > compnerd wrote:
> > > xiongji90 wrote:
> > > > compnerd wrote:
> > > > > Why does this have to be a macro? Can we just define the function instead?
> > > > Hi, @compnerd
> > > > In previous version, I defined a function the code looks like following:
> > > > void __unw_phase2_resume(cursor, fn) {
> > > > __LIBUNWIND_POP_CET_SSP(...);
> > > > ....
> > > > ....
> > > > __asm__ volatile(....)
> > > > }
> > > > The stack layout looks like following if compiler doesn't do any optimization to __unw_phase2_resume:
> > > > _____________________
> > > > .....user functions
> > > > ______________________
> > > > __cxx_throw
> > > > _______________________
> > > > _Unwind_RaiseException
> > > > _______________________
> > > > unwind_phase2
> > > > _______________________
> > > > __unw_phase2_resume
> > > > ________________________
> > > >
> > > > Under such circumstances, the stack frame for __unw_phase2_resume will be skipped too and we must adjust CET shadow stack for it.
> > > > However, as we can see, the __unw_phase2_resume will never return. I am afraid compiler may directly jump to this function instead of "call" it. If so, there will be no stack frame for __unw_phase2_resume and if compiler uses "jmp" to jump to it instead of calling it, we mustn't adjust CET shadow stack for it.
> > > > In our source code, we can't know whether compiler will do such optimization and we can't decide whether we should adjust CET shadow stack for __unw_phase2_resume. So I used macro here to avoid this problem.
> > > > I used inline asm to jump to __libunwind_Registers_x86_64_jumpto for the same purpose.
> > > > Thanks very much.
> > > I wonder if we can get away with some combination of `noinline`, and pragmas for `no-optimize-sibling-calls`.
> > Hi, @compnerd
> > I think using combination of following:
> > 1. using __attribute__((noinline)) to decorate target functions
> > 2. building source file containing target functions with -fno-optimize-sibling-calls
> > can help us to get away with the issue mentioned above. I only found gcc/clang compiling options for "-fno-optimize-sibling-calls" and didn't find corresponding pragma or attribute, so if we choose to use "-fno-optimize-sibling-calls", tail call optimization for other functions will be disabled too which seems to be overshooting.
> > And if choosing the combination of "noinline" and "-fno-optimize-sibling-calls", we are relying on gcc/clang's implementation which is a implicit dependency, using macro here should be safe to all compilers.
> >
> > Thanks very much.
> Hi, @compnerd
> If you have concern about the macro "unw_phase_resume", I can try to update the patch to use combination of "noinline" and "-fno-optimize-sibling-calls". And do we have any way to use "no-optimize-sibling-calls" to decorate a function? I only found compiling option "-fno-optimize-sibling-calls".
> Thanks very much.
I think using a macro is a right call here, more robust than dancing with -noinline, no-optimize-sibling-calls and using functions and computing how many additional frames are skipped.
================
Comment at: libunwind/src/UnwindLevel1.c:51
+ do { \
+ _LIBUNWIND_POP_CET_SSP(1 + (fn)); \
+ void *cetRegContext = __libunwind_cet_get_registers((cursor)); \
----------------
Question: why is this `1 + (fn)`?
================
Comment at: libunwind/src/UnwindLevel1.c:55
+ __asm__ volatile("push %%edi\n\t" \
+ "sub $4, %%esp\n\t" \
+ "jmp *%%edx\n\t" ::"D"(cetRegContext), \
----------------
Is the calling convention here wrong?
================
Comment at: libunwind/src/UnwindLevel1.c:173
+ unsigned int framesWalked = 0;
// Walk each frame until we reach where search phase said to stop.
----------------
================
Comment at: libunwind/src/UnwindLevel1.c:223
+ framesWalked++;
// If there is a personality routine, tell it we are unwinding.
----------------
https://llvm.org/docs/CodingStandards.html#prefer-preincrement
================
Comment at: libunwind/src/UnwindLevel1.c:287
+ unsigned int framesWalked = 0;
// Walk each frame until we reach where search phase said to stop
----------------
================
Comment at: libunwind/src/cet_unwind.h:20
+ defined(__SHSTK__) && \
+ (defined(_LIBUNWIND_TARGET_I386) || defined(_LIBUNWIND_TARGET_X86_64))
+#define _LIBUNWIND_CET_ENABLED 1
----------------
Since CET is x86 only, `(defined(_LIBUNWIND_TARGET_I386) || defined(_LIBUNWIND_TARGET_X86_64))` can be omitted.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D105968/new/
https://reviews.llvm.org/D105968
More information about the libcxx-commits
mailing list