[PATCH] Fix ffi powerpc64 unwind info

Jakub Jelinek jakub@redhat.com
Fri Nov 24 22:18:00 GMT 2006


Hi!

When libgcj.so is linked with an anonymous version script which hides all
the symbols which aren't part of the libgcj.so ABI (e.g. GC_*, ffi_*, fdlibm
symbols, etc.; will post such a patch soon), invokethrow test fails on
ppc64.  The reason for this is no explicit unwind info for the r2 (TOC)
register.  ffi_call_LINUX64 explicitely saves this register, but doesn't
mention that in the unwind info.  Unwinding on ppc64 implicitly 
adds a rule to restore r2 if the instruction at RA is ld %r2, 40(%r1)
(that's what the linker replaces nops after bl instructions with it
it calls something which (maybe) needs a different TOC pointer.
When ffi_call symbol is exported out of libgcj.so, unwinding sort of works
fine, eventhough %r2 in ffi_call_LINUX64 and ffi_call is wrong, there are no
catch regions in those and as all calls to ffi_call in that case are
followed by ld %r2, 40(%r1), TOC register is correctly unwinded at least
in ffi_call caller and above.  But when ffi_call is hidden within
libgcj.so (and ffi_call_LINUX64 is hidden there too, which is the case for
several years no), r2 will be wrong even in ffi_call caller when unwinding
and as _Jv_Throw has try { ffi_call (...); } catch (...) { ... } construct
around it, invokethrow test crashes.

Attached are two possible fixes, one doesn't chance the code at all,
just adds CFA expression where r2 is saved, the other moves ld %r2, 40(%r1)
instruction around to force the implicit unwinder behavior.

Ok for head?  Which one?

	Jakub
-------------- next part --------------
2006-11-24  Jakub Jelinek  <jakub@redhat.com>

	* src/powerpc/linux64.S (ffi_call_LINUX64): Add DW_CFA_expression
	for r2.

--- libffi/src/powerpc/linux64.S.jj	2006-08-02 20:55:10.000000000 +0200
+++ libffi/src/powerpc/linux64.S	2006-11-24 21:38:16.000000000 +0100
@@ -47,12 +47,13 @@ ffi_call_LINUX64:
 	std	%r0, 16(%r1)
 
 	mr	%r28, %r1	/* our AP.  */
-	stdux	%r1, %r1, %r4
 .LCFI0:
+	stdux	%r1, %r1, %r4
 	mr	%r31, %r5	/* flags, */
 	mr	%r30, %r6	/* rvalue, */
 	mr	%r29, %r7	/* function address.  */
 	std	%r2, 40(%r1)
+.LCFI1:
 
 	/* Call ffi_prep_args64.  */
 	mr	%r4, %r1
@@ -159,8 +160,6 @@ ffi_call_LINUX64:
 	.uleb128 0x0	 # Augmentation size
 	.byte	0x2	 # DW_CFA_advance_loc1
 	.byte	.LCFI0-.LFB1
-	.byte	0xd	 # DW_CFA_def_cfa_register
-	.uleb128 0x1c
 	.byte	0x11	 # DW_CFA_offset_extended_sf
 	.uleb128 0x41
 	.sleb128 -2
@@ -172,7 +171,16 @@ ffi_call_LINUX64:
 	.uleb128 0x3
 	.byte	0x9c	 # DW_CFA_offset, column 0x1c
 	.uleb128 0x4
-	.align 3
+	.byte	0xd	 # DW_CFA_def_cfa_register
+	.uleb128 0x1c
+	.byte	0x2	 # DW_CFA_advance_loc1
+	.byte	.LCFI1-.LCFI0
+	.byte	0x10	 # DW_CFA_expression
+	.uleb128 0x2
+	.uleb128 2f-1f
+1:	.byte	0x71	 # DW_OP_breg1
+	.sleb128 40
+2:	.align 3
 .LEFDE1:
 #endif
 
-------------- next part --------------
2006-11-24  Jakub Jelinek  <jakub@redhat.com>

	* src/powerpc/linux64.S (ffi_call_LINUX64): Move restore of r2
	immediately after bctrl instruction.

--- libffi/src/powerpc/linux64.S.jj	2006-08-02 20:55:10.000000000 +0200
+++ libffi/src/powerpc/linux64.S	2006-11-24 21:57:06.000000000 +0100
@@ -47,8 +47,8 @@ ffi_call_LINUX64:
 	std	%r0, 16(%r1)
 
 	mr	%r28, %r1	/* our AP.  */
-	stdux	%r1, %r1, %r4
 .LCFI0:
+	stdux	%r1, %r1, %r4
 	mr	%r31, %r5	/* flags, */
 	mr	%r30, %r6	/* rvalue, */
 	mr	%r29, %r7	/* function address.  */
@@ -100,6 +100,10 @@ ffi_call_LINUX64:
 	/* Make the call.  */
 	bctrl
 
+	/* This must follow the call immediately, the unwinder
+	   uses this to find out if r2 has been saved or not.  */
+	ld	%r2, 40(%r1)
+
 	/* Now, deal with the return value.  */
 	mtcrf	0x01, %r31
 	bt-	30, .Ldone_return_value
@@ -109,7 +113,6 @@ ffi_call_LINUX64:
 
 .Ldone_return_value:
 	/* Restore the registers we used and return.  */
-	ld	%r2, 40(%r1)
 	mr	%r1, %r28
 	ld	%r0, 16(%r28)
 	ld	%r28, -32(%r1)


More information about the Gcc-patches mailing list