This is the first patch in a series of changes intended to fix glibc/23296. This bug is a data race in the setting of function descriptors during lazy binding. If a descriptor is updated between the loading of the function target address and the PIC global pointer in another thread, _dl_runtime_resolve() is entered with the new global pointer instead of the expected reloc offset. _dl_runtime_resolve() could handle this situation if we modify the indirect call sequence to preserve the function pointer (descriptor address) in register %r22.
We also change the code to consistently load the function address before the global pointer. There might be still an issue on PA 2.0 hardware due to the out-of-order execution of accesses. Currently, the linker doesn't double word align descriptors. As a result, descriptors can span cache lines and page boundaries. Thus, it might be possible that a function is entered with an incorrect global pointer. This patch slightly improves $$dyncall on Linux. Tested on hppa-unknown-linux-gnu. Committed to trunk and gcc-9 branch. 2019-10-12 John David Anglin <dang...@gcc.gnu.org> * config/pa/lib2funcs.S (__gcc_plt_call): Load branch target to %r21. Load PIC register after branch target. Fix white space. * config/pa/milli64.S ($$dyncall): Separate LINUX and non LINUX implementations. Load PIC register after branch target. Don't clobber function pointer when it points to function descriptor. Use nullification instead of branch in LINUX implementation. Index: config/pa/lib2funcs.S =================================================================== --- config/pa/lib2funcs.S (revision 276920) +++ config/pa/lib2funcs.S (working copy) @@ -55,13 +55,13 @@ ; An inline version of dyncall so we don't have to worry ; about long calls to millicode, PIC and other complexities. bb,>=,n %r22,30,L$foo - depi 0,31,2,%r22 - ldw 4(%r22),%r19 - ldw 0(%r22),%r22 + depi 0,31,2,%r22 + ldw 0(%r22),%r21 + ldw 4(%r22),%r19 L$foo - ldsid (%r22),%r1 - mtsp %r1,%sr0 - ble 0(%sr0,%r22) + ldsid (%r21),%r1 + mtsp %r1,%sr0 + ble 0(%sr0,%r21) copy %r31,%r2 ldw -8(%r30),%r2 Index: config/pa/milli64.S =================================================================== --- config/pa/milli64.S (revision 276920) +++ config/pa/milli64.S (working copy) @@ -222,19 +222,26 @@ .proc .callinfo millicode .entry +#ifdef LINUX + extru,<> %r22,30,1,%r0 ; nullify if plabel bit set + bv,n %r0(%r22) ; branch to target + ldw -2(%r22),%r21 ; load address of target + bv %r0(%r21) ; branch to the real target + ldw 2(%r22),%r19 ; load new LTP value +#else bb,>=,n %r22,30,LREF(1) ; branch if not plabel address - depi 0,31,2,%r22 ; clear the two least significant bits - ldw 4(%r22),%r19 ; load new LTP value - ldw 0(%r22),%r22 ; load address of target + ldw -2(%r22),%r21 ; load address of target to r21 + ldsid (%sr0,%r21),%r1 ; get the "space ident" selected by r21 + ldw 2(%r22),%r19 ; load new LTP value + mtsp %r1,%sr0 ; move that space identifier into sr0 + be 0(%sr0,%r21) ; branch to the real target + stw %r2,-24(%r30) ; save return address into frame marker LSYM(1) -#ifdef LINUX - bv %r0(%r22) ; branch to the real target -#else ldsid (%sr0,%r22),%r1 ; get the "space ident" selected by r22 mtsp %r1,%sr0 ; move that space identifier into sr0 - be 0(%sr0,%r22) ; branch to the real target + be 0(%sr0,%r22) ; branch to the target + stw %r2,-24(%r30) ; save return address into frame marker #endif - stw %r2,-24(%r30) ; save return address into frame marker .exit .procend #endif