[RFC] powerpc: restore TOC when static longjmp to shared object

Rogerio Alves rcardoso@linux.vnet.ibm.com
Tue May 15 17:29:00 GMT 2018


Hi, everyone

I was trying to fix a issue related to setjmp/longjmp on powerpc64 
"ppc64 setjmp/longjmp not fully interoperable with static dlopen":

https://sourceware.org/bugzilla/show_bug.cgi?id=21895

The code sent by the person who reports this problem on bugzilla #21895 
uses a static dlopen to a function declared in a shared lib, this 
function foo() calls setjmp and a static function inside a static 
compiled file calls the longjmp. So the problem is in that case it's not 
restoring the r2 (TOC) to the frame as the code who calls the longjmp is 
compiled as static but, as setjmp is called inside a shared object file 
it will fails once it tries to retrieve the TOC pointer from the memory:

0x3fffb7fb0954 <foo+96>         ld      r2,24(r1)
Segmentation fault

The problem is that TOC is not being restored to the frame after the 
longjmp.  I find out those lines at 
sysdeps/powerpc/powerpc64/__longjmp-common.S:

#if defined SHARED && !IS_IN (rtld)
        std r2,FRAME_TOC_SAVE(r1)       /* Restore the callers TOC save 
area.  */
#endif
/*     std r2,FRAME_TOC_SAVE(r1)       Restore the TOC save area.  */


As described on bugzilla #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."

Since the function who calls the longjmp is a static function in a 
static compiled file it will not restore the TOC. But, the function that 
setjmp is a function inside a share object called via dlopen.

One simple solution would be always restore the TOC pointer by uncomment 
the line bellow:

/*     std r2,FRAME_TOC_SAVE(r1)       Restore the TOC save area.  */

Or maybe we can check if we have a valid TOC pointer before restore it, 
instead #if defined SHARED.

However, I am not sure if this is something that we should work on. 
First of all, as far I known, glibc is deprecating the static dlopen. 
Also, on the code attached on bug #21895, after call setjmp function the 
code calls a alloca and a memset function and those function are 
destroying the caller stack somehow. Then when longjmp executes it gets 
a segmentation fault since alloca/memset destroyed the caller stack.

I would like to request for comments on this matter: Should we fix/work 
this? Is feasible to change longjmp to always restore TOC pointer? Any 
suggestions?

Regards

--
Rogerio Alves
Software Engineer - IBM



More information about the Libc-alpha mailing list