[committed]

Message ID 3be749b8-9ff2-61bb-12f3-acf31e98a568@bell.net
State New
Headers show
Series
  • [committed]
Related show

Commit Message

John David Anglin Oct. 12, 2019, 8:10 p.m.
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  <danglin@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.

Patch

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