This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [RFC] powerpc: restore TOC when static longjmp to shared object
Em 23-05-2018 06:26, Alexander Monakov escreveu:
On Tue, 22 May 2018, Rogerio Alves wrote:
I've attached patch v2 to this email with the fixes suggested by Adhemerval.
Why was it necessary to change the prototype of lbar(), and does the testcase
still demonstrate the issue with that change (does it fail without the patch)?
Yes it fails without the patch.
The change on lbar() prototype was made only because glibc is being
compiled with and it give me an error due a -Werror=strict-prototypes.
But lbar(void) works fine but, you don't have a segmentation fault.
The problem is that if you have a parameter area on the stack
alloca/memset will set TOC to 0x0 and lbar() prototype doesn't mean "no
parameters" in C it means "any arguments" - C Standard, subclause
6.7.6.3, paragraph 14 [ISO/IEC 9899:2011] - so the compiler ends up
creating a parameter area for the function.
This code works if you use lbar(void) or if you don't have a parameter
save area on stack:
lbar() - Segmentation fault
lbar(void) - Works (no arguments).
lbar(int a, int b, int c, int d, int e, int f, int g) - Works (less than
8 parameters, use registers, no parameter saving area)
lbar(int a, int b, int c, int d, int e, int f, int g, int h, int i) -
Segmentation fault
Note that as soon as gcc is capable of optimizing out the alloca-memset code
in the testcase, it will no longer serve the purpose (maybe it's alread > capable, when preparing the testcase I only checked -O0 IIRC). Surely
there
are more direct and robust ways of checking that TOC is correctly restored?
I've tested with -O3 here and get the same problem here. If
alloca/memset is optimized out or removed from the code the problem
doesn't happens but, that's only if the caller stack frame doesn't
change if don't, when longjmp execute you still have a valid TOC on the
stack.
But described in https://sourceware.org/bugzilla/show_bug.cgi?id=269
"In this (simple) case the appl calls [bsd]_setjmp() which transfers to
__setjmp. Both are in libc.so. So by the time __setjmp() gets control
libc.so's TOC is already loaded. In this case we need to reach back
into the callers frame and retrieve the callers TOC from the TOC save
area. But in the static case the TOC is not saved and has not changed.
In GLIBC sysdeps/powerpc/powerpc64/setjmp.S is built 4 times (static,
shared, profiled, and a special version (rtld-setjmp) for the dynamic
linker. In the SHARED case (libc.so), external calls to setjmp will
save the TOC on the stack, but internal libc calls will not. So the
trick is to do the correct thing for each case."
So your test has a example of a code that use a static function to call
a longjmp that was set on a shared object called via (static) dlopen. In
that case we should have to restore it to caller frame as the jump area
is in shared object but, since longjmp is inside static compiled unit
TOC is not restored.
I don't think that alloca/memset should destroy the caller stack like is
happening but, also I think we have to restore TOC to the caller frame
after the longjmp in that case also. I don't know if there's any other
more direct and robust ways to checking if TOC is correctly restored. I
can't think in anything easier than always restore.
Rogerio
Alexander