Commit 39228c27ed3f677a95b46380a8d31602b5777e1a

aph 2009-06-16T18:00:47

2009-06-16 Wim Lewis <wiml@hhhh.org> * src/powerpc/ffi.c: Avoid clobbering cr3 and cr4, which are supposed to be callee-saved. * src/powerpc/sysv.S (small_struct_return_value): Fix overrun of return buffer for odd-size structs.

diff --git a/libffi/ChangeLog b/libffi/ChangeLog
index 8275975..3d94b9c 100644
--- a/libffi/ChangeLog
+++ b/libffi/ChangeLog
@@ -1,3 +1,10 @@
+2009-06-16  Wim Lewis  <wiml@hhhh.org>
+
+	* src/powerpc/ffi.c: Avoid clobbering cr3 and cr4, which are
+	supposed to be callee-saved.
+	* src/powerpc/sysv.S (small_struct_return_value): Fix overrun of
+	return buffer for odd-size structs.
+
 2009-06-16  Andreas Tobler  <a.tobler@schweiz.org>
 
 	PR libffi/40444
diff --git a/libffi/src/powerpc/ffi.c b/libffi/src/powerpc/ffi.c
index a0426f4..fbbfbe2 100644
--- a/libffi/src/powerpc/ffi.c
+++ b/libffi/src/powerpc/ffi.c
@@ -43,11 +43,12 @@ enum {
   FLAG_RETURNS_64BITS   = 1 << (31-28),
 
   FLAG_RETURNS_128BITS  = 1 << (31-27), /* cr6  */
-
-  FLAG_SYSV_SMST_R4     = 1 << (31-16), /* cr4, use r4 for FFI_SYSV 8 byte
+  FLAG_SYSV_SMST_R4     = 1 << (31-26), /* use r4 for FFI_SYSV 8 byte
 					   structs.  */
-  FLAG_SYSV_SMST_R3     = 1 << (31-15), /* cr3, use r3 for FFI_SYSV 4 byte
+  FLAG_SYSV_SMST_R3     = 1 << (31-25), /* use r3 for FFI_SYSV 4 byte
 					   structs.  */
+  /* Bits (31-24) through (31-19) store shift value for SMST */
+
   FLAG_ARG_NEEDS_COPY   = 1 << (31- 7),
   FLAG_FP_ARGUMENTS     = 1 << (31- 6), /* cr1.eq; specified by ABI */
   FLAG_4_GPR_ARGUMENTS  = 1 << (31- 5),
@@ -685,14 +686,14 @@ ffi_prep_cif_machdep (ffi_cif *cif)
 	      if (size <= 4)
 		{
 		  flags |= FLAG_SYSV_SMST_R3;
-		  flags |= 8 * (4 - size) << 4;
+		  flags |= 8 * (4 - size) << 8;
 		  break;
 		}
 	      /* These structs are returned in r3 and r4. See above.   */
 	      if  (size <= 8)
 		{
-		  flags |= FLAG_SYSV_SMST_R4;
-		  flags |= 8 * (8 - size) << 4;
+		  flags |= FLAG_SYSV_SMST_R3 | FLAG_SYSV_SMST_R4;
+		  flags |= 8 * (8 - size) << 8;
 		  break;
 		}
 	    }
diff --git a/libffi/src/powerpc/sysv.S b/libffi/src/powerpc/sysv.S
index c06311f..96ea22b 100644
--- a/libffi/src/powerpc/sysv.S
+++ b/libffi/src/powerpc/sysv.S
@@ -136,29 +136,18 @@ L(float_return_value):
 	b	L(done_return_value)
 
 L(small_struct_return_value):
-	mtcrf	0x10,%r31	/* cr3  */
-	bt-	15,L(smst_one_register)
-	mtcrf	0x08,%r31	/* cr4  */
-	bt-	16,L(smst_two_register)
-	b       L(done_return_value)
-
-L(smst_one_register):
-	rlwinm  %r5,%r31,5+23,32-5,31 /* Extract the value to shift.  */
-	slw	%r3,%r3,%r5
-	stw	%r3,0(%r30)
-	b	L(done_return_value)
-L(smst_two_register):
-	rlwinm  %r5,%r31,5+23,32-5,31 /* Extract the value to shift.  */
-	cmpwi	%r5,0
-	subfic	%r9,%r5,32
-	slw	%r29,%r3,%r5
-	srw	%r9,%r4,%r9
-	beq-	L(smst_8byte)
-	or	%r3,%r9,%r29
-	slw	%r4,%r4,%r5
-L(smst_8byte):
-	stw	%r3,0(%r30)
-	stw	%r4,4(%r30)
+	extrwi	%r6,%r31,2,19         /* number of bytes padding = shift/8 */
+	mtcrf	0x02,%r31	      /* copy flags to cr[24:27] (cr6) */
+	extrwi	%r5,%r31,5,19         /* r5 <- number of bits of padding */
+	subfic  %r6,%r6,4             /* r6 <- number of useful bytes in r3 */
+	bf-	25,L(done_return_value) /* struct in r3 ? if not, done. */
+/* smst_one_register: */
+	slw	%r3,%r3,%r5           /* Left-justify value in r3 */
+	mtxer	%r6                   /* move byte count to XER ... */
+	stswx	%r3,0,%r30            /* ... and store that many bytes */
+	bf+	26,L(done_return_value)  /* struct in r3:r4 ? */
+	add	%r6,%r6,%r30          /* adjust pointer */
+	stswi	%r4,%r6,4             /* store last four bytes */
 	b	L(done_return_value)
 
 .LFE1: