powerpc help needed: Defining hidden alias for __sigsetjmp
Commit Message
I'm trying to create a hidden alias for __sigsetjmp on powerpc. The
problem is that powerpc uses the generic <setjmp.h> wrapper, which has a
libc_hidden_proto for it, but the implementation of that redirect never
happens.
I came up with the attached patch. It adds a definition of the hidden
redirect to libc.so, as expected. But in addition to that, I get this
ABI difference on powerpc32:
-GLIBC_2.3.4 __longjmp F
This does not happen on powerpc64.
I really can't explain that. Any ideas?
Florian
Comments
On Nov 14 2016, Florian Weimer <fweimer@redhat.com> wrote:
> I came up with the attached patch. It adds a definition of the hidden
> redirect to libc.so, as expected. But in addition to that, I get this ABI
> difference on powerpc32:
>
> -GLIBC_2.3.4 __longjmp F
Are you sure this is the only change you did? setjmp.* does not contain
anything related to longjmp. I couldn't reproduce that.
Andreas.
On 11/14/2016 04:37 PM, Andreas Schwab wrote:
> On Nov 14 2016, Florian Weimer <fweimer@redhat.com> wrote:
>
>> I came up with the attached patch. It adds a definition of the hidden
>> redirect to libc.so, as expected. But in addition to that, I get this ABI
>> difference on powerpc32:
>>
>> -GLIBC_2.3.4 __longjmp F
>
> Are you sure this is the only change you did? setjmp.* does not contain
> anything related to longjmp. I couldn't reproduce that.
Thanks. It only happens in conjunction with this patch:
<https://sourceware.org/ml/libc-alpha/2016-11/msg00465.html>
This patch adds a reference to __longjmp to libc.so. With it,
libc_pic.os has this:
8296: 00017024 492 FUNC GLOBAL HIDDEN 2
__longjmp@@GLIBC_2.3.4
9342: 00017210 184 FUNC GLOBAL DEFAULT 2 __longjmp@GLIBC_2.0
And libc.so has this:
5208: 00039c04 492 FUNC LOCAL DEFAULT 11
__longjmp@@GLIBC_2.3.4
5758: 00039df0 184 FUNC LOCAL DEFAULT 11 __longjmp@GLIBC_2.0
It turns out that libc.map lists _longjmp only, based on the entry in
sysdeps/powerpc/Versions.
setjmp/__longjmp.os has:
11: 00000000 492 FUNC GLOBAL DEFAULT 1 __vmx__longjmp
14: 000001ec 184 FUNC GLOBAL DEFAULT 1 __novmx__longjmp
15: 00000000 492 FUNC GLOBAL DEFAULT 1
__longjmp@@GLIBC_2.3.4
16: 000001ec 184 FUNC GLOBAL DEFAULT 1 __longjmp@GLIBC_2.0
setjmp/longjmp.os has:
21: 00000000 116 FUNC GLOBAL DEFAULT 1 __vmx__libc_longjmp
22: 00000000 116 FUNC GLOBAL DEFAULT 1
__vmx__libc_siglongjmp
23: 00000000 116 FUNC WEAK DEFAULT 1 __vmx_longjmp
24: 00000000 116 FUNC WEAK DEFAULT 1 __vmxlongjmp
25: 00000000 116 FUNC WEAK DEFAULT 1 __vmxsiglongjmp
30: 00000000 116 FUNC GLOBAL HIDDEN 1
__GI___vmx__libc_longjmp
31: 00000000 116 FUNC GLOBAL DEFAULT 1
__libc_longjmp@@GLIBC_PRIVATE
32: 00000000 116 FUNC GLOBAL DEFAULT 1
__libc_siglongjmp@@GLIBC_PRIVATE
33: 00000000 116 FUNC WEAK DEFAULT 1
_longjmp@@GLIBC_2.3.4
34: 00000000 116 FUNC WEAK DEFAULT 1 longjmp@@GLIBC_2.3.4
35: 00000000 116 FUNC WEAK DEFAULT 1
siglongjmp@@GLIBC_2.3.4
So the __GI_* aliases are missing there, too.
The internal reference to __longjmp seems to cause ld to drop the
exported symbol version. Adding __longjmp to sysdeps/powerpc/Versions
does not change this. Neither does adding
libc_hidden_ver (__vmx__libc_longjmp, __longjmp)
to sysdeps/powerpc/longjmp.c. Okay, that's because the definition comes
from sysdeps/powerpc/powerpc32/fpu/__longjmp-common.S. But changing
that file to contain:
versioned_symbol (libc, __vmx__longjmp, __longjmp, GLIBC_2_3_4);
# define __longjmp_symbol __vmx__longjmp
# include "__longjmp-common.S"
libc_hidden_ver (__vmx__libc_longjmp, __longjmp)
does not help, either.
Maybe this is relevant. __longjmp is declared *hidden*:
extern void __longjmp (__jmp_buf __env, int __val)
__attribute__ ((__noreturn__)) attribute_hidden;
So maybe that's why a reference to it causes ld to drop the export.
I wonder if this indeed the root cause. It would mean this is a
spurious ABI addition. Can we drop __longjmp from the ABI in this way?
Or do we have to fix this up using a powerpc-specific alias?
This happens on no other architecture for which we have abilist files.
It was introduced into the abilist file here:
commit 0741d64c9140aa205f9df8ebee80ca0bcb018445
Author: Andreas Schwab <schwab@linux-m68k.org>
Date: Tue May 1 01:12:54 2012 +0200
Update powerpc ABI data
Thanks,
Florian
On Nov 14 2016, Florian Weimer <fweimer@redhat.com> wrote:
> This patch adds a reference to __longjmp to libc.so. With it, libc_pic.os
> has this:
>
> 8296: 00017024 492 FUNC GLOBAL HIDDEN 2
> __longjmp@@GLIBC_2.3.4
> 9342: 00017210 184 FUNC GLOBAL DEFAULT 2 __longjmp@GLIBC_2.0
>
> And libc.so has this:
>
> 5208: 00039c04 492 FUNC LOCAL DEFAULT 11
> __longjmp@@GLIBC_2.3.4
> 5758: 00039df0 184 FUNC LOCAL DEFAULT 11 __longjmp@GLIBC_2.0
>
> It turns out that libc.map lists _longjmp only, based on the entry in
> sysdeps/powerpc/Versions.
So it looks like a linker bug that the symbol was exported before,
probably related to the fact that it is a default version. But it is
also a bug that __longjmp has a version in the first place.
> setjmp/__longjmp.os has:
>
> 11: 00000000 492 FUNC GLOBAL DEFAULT 1 __vmx__longjmp
> 14: 000001ec 184 FUNC GLOBAL DEFAULT 1 __novmx__longjmp
> 15: 00000000 492 FUNC GLOBAL DEFAULT 1
> __longjmp@@GLIBC_2.3.4
> 16: 000001ec 184 FUNC GLOBAL DEFAULT 1 __longjmp@GLIBC_2.0
>
> setjmp/longjmp.os has:
>
> 21: 00000000 116 FUNC GLOBAL DEFAULT 1 __vmx__libc_longjmp
> 22: 00000000 116 FUNC GLOBAL DEFAULT 1
> __vmx__libc_siglongjmp
> 23: 00000000 116 FUNC WEAK DEFAULT 1 __vmx_longjmp
> 24: 00000000 116 FUNC WEAK DEFAULT 1 __vmxlongjmp
> 25: 00000000 116 FUNC WEAK DEFAULT 1 __vmxsiglongjmp
> 30: 00000000 116 FUNC GLOBAL HIDDEN 1
> __GI___vmx__libc_longjmp
> 31: 00000000 116 FUNC GLOBAL DEFAULT 1
> __libc_longjmp@@GLIBC_PRIVATE
> 32: 00000000 116 FUNC GLOBAL DEFAULT 1
> __libc_siglongjmp@@GLIBC_PRIVATE
> 33: 00000000 116 FUNC WEAK DEFAULT 1
> _longjmp@@GLIBC_2.3.4
> 34: 00000000 116 FUNC WEAK DEFAULT 1 longjmp@@GLIBC_2.3.4
> 35: 00000000 116 FUNC WEAK DEFAULT 1
> siglongjmp@@GLIBC_2.3.4
The version is coming from sysdeps/powerpc/powerpc32/fpu/__longjmp.S,
and was added in commit 5c76ff279f. Clearly this was a genuine error,
and the versioned alias in sysdeps/powerpc/powerpc32/__longjmp.S has
later been removed in commit 9b9ef82358 (without fixing the fpu
version).
> So the __GI_* aliases are missing there, too.
There is no hidden_proto for __longjmp, only attribute_hidden, so this
is correct. It is already an internal-only function.
> I wonder if this indeed the root cause. It would mean this is a spurious
> ABI addition. Can we drop __longjmp from the ABI in this way? Or do we
> have to fix this up using a powerpc-specific alias?
I'm not sure. Nobody should be using __longjmp, it's not declared or
used in any public header.
> This happens on no other architecture for which we have abilist files. It
> was introduced into the abilist file here:
>
> commit 0741d64c9140aa205f9df8ebee80ca0bcb018445
> Author: Andreas Schwab <schwab@linux-m68k.org>
> Date: Tue May 1 01:12:54 2012 +0200
>
> Update powerpc ABI data
It's unfortunate that Jakub didn't fix the fpu version back in 2004.
Andreas.
On 11/15/2016 10:06 AM, Andreas Schwab wrote:
> On Nov 14 2016, Florian Weimer <fweimer@redhat.com> wrote:
>
>> This patch adds a reference to __longjmp to libc.so. With it, libc_pic.os
>> has this:
>>
>> 8296: 00017024 492 FUNC GLOBAL HIDDEN 2
>> __longjmp@@GLIBC_2.3.4
>> 9342: 00017210 184 FUNC GLOBAL DEFAULT 2 __longjmp@GLIBC_2.0
>>
>> And libc.so has this:
>>
>> 5208: 00039c04 492 FUNC LOCAL DEFAULT 11
>> __longjmp@@GLIBC_2.3.4
>> 5758: 00039df0 184 FUNC LOCAL DEFAULT 11 __longjmp@GLIBC_2.0
>>
>> It turns out that libc.map lists _longjmp only, based on the entry in
>> sysdeps/powerpc/Versions.
>
> So it looks like a linker bug that the symbol was exported before,
> probably related to the fact that it is a default version. But it is
> also a bug that __longjmp has a version in the first place.
I've asked for clarification of the linker behavior:
<https://sourceware.org/ml/binutils/2016-11/msg00180.html>
From the binutils perspective, it may work as designed. It may be a
mismatch between the assembler (which does not know about a mere
reference to a hidden symbol), and the C/C++ source, where visibility
attributes are supported on declarations (and declarations in one
translation unit are not supposed to affect how other translation units
are compiled/linked).
>> ABI addition. Can we drop __longjmp from the ABI in this way? Or do we
>> have to fix this up using a powerpc-specific alias?
>
> I'm not sure. Nobody should be using __longjmp, it's not declared or
> used in any public header.
I don't see a reference in codesearch.debian.org (the existing ones are
definitions in other libcs). I don't have ppc RPMs indexed in my symbol
database, unfortunately.
I suspect this is something for the powerpc maintainers to decide.
Thanks,
Florian
powerpc: Add hidden definition for __sigsetjmp
2016-11-14 Florian Weimer <fweimer@redhat.com>
* sysdeps/powerpc/powerpc64/setjmp-common.S (__GI___sigsetjmp):
Define.
* sysdeps/powerpc/powerpc32/setjmp.S (__sigsetjmp): Add hidden
definition.
@@ -32,6 +32,7 @@ versioned_symbol (libc, __vmx__sigsetjmp, __sigsetjmp, GLIBC_2_3_4)
# define __sigsetjmp_symbol __vmx__sigsetjmp
# define __sigjmp_save_symbol __vmx__sigjmp_save
# include "setjmp-common.S"
+libc_hidden_ver (__vmx__sigsetjmp, __sigsetjmp)
# if defined SHARED && SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4)
# define __NO_VMX__
@@ -31,6 +31,7 @@ versioned_symbol (libc, __vmx__sigsetjmp, __sigsetjmp, GLIBC_2_3_4)
# define __sigsetjmp_symbol __vmx__sigsetjmp
# define __sigjmp_save_symbol __vmx__sigjmp_save
# include "setjmp-common.S"
+libc_hidden_ver (__vmx__sigsetjmp, __sigsetjmp)
# if defined SHARED && SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4)
# define __NO_VMX__
@@ -232,3 +232,14 @@ L(no_vmx):
blr
#endif
END (__sigsetjmp_symbol)
+
+#if defined SHARED && !IS_IN (rtld) && !defined __NO_VMX__
+/* When called from within libc we need a special version of __sigsetjmp
+ that saves r2 since the call won't go via a plt call stub. See
+ bugz #269. */
+ENTRY (__GI___sigsetjmp)
+ std r2,FRAME_TOC_SAVE(r1) /* Save the callers TOC in the save area. */
+ CALL_MCOUNT 1
+ b JUMPTARGET (GLUE(__sigsetjmp_symbol,_ent))
+END (__GI___sigsetjmp)
+#endif