This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Patch committed: Fix -fsplit-stack unwind


The CFI code for the -fsplit-stack support was incomplete.  It did not
correctly unwind throughout the function.  This patch fixes that by
adding the CFI information at the start.  This is probably still not
precisely correct at all times, but it is better.

In 32-bit mode, the exception cleanup routine has to change %ebx when
running in a shared library.  Therefore, it is necessary that the
unwinder restore %ebx to the old value.  This patch implements that in a
simple way, but having the main routine save %ebx with appropriate CFI
information.

Bootstrapped and ran testsuite on x86_64-unknown-linux-gnu.  Committed
to mainline.

Ian


2011-10-28  Ian Lance Taylor  <iant@google.com>

	* config/i386/morestack.S: Correct CFI information to do proper
	returns throughout function.  In 32-bit mode, save %ebx so that it
	is restored on unwind.


Index: config/i386/morestack.S
===================================================================
--- config/i386/morestack.S	(revision 180342)
+++ config/i386/morestack.S	(working copy)
@@ -139,44 +139,68 @@ __morestack:
 	.cfi_lsda 0x1b,.LLSDA1
 #endif
 
-	# Set up a normal backtrace.
-	pushl	%ebp
-	.cfi_def_cfa_offset 8
-	.cfi_offset %ebp, -8
-	movl	%esp, %ebp
-	.cfi_def_cfa_register %ebp
-
 	# We return below with a ret $8.  We will return to a single
 	# return instruction, which will return to the caller of our
 	# caller.  We let the unwinder skip that single return
 	# instruction, and just return to the real caller.
-	.cfi_offset 8, 8
+
+	# Here CFA points just past the return address on the stack,
+	# e.g., on function entry it is %esp + 4.  Later we will
+	# change it to %ebp + 8, as set by .cfi_def_cfa_register and
+	# .cfi_def_cfa_offset above.  The stack looks like this:
+	#	CFA + 12:	stack pointer after two returns
+	#	CFA + 8:	return address of morestack caller's caller
+	#	CFA + 4:	size of parameters
+	#	CFA:		new stack frame size
+	#	CFA - 4:	return address of this function
+	#	CFA - 8:	previous value of %ebp; %ebp points here
+	# We want to set %esp to the stack pointer after the double
+	# return, which is CFA + 12.
+	.cfi_offset 8, 8		# New PC stored at CFA + 8
 	.cfi_escape 0x15, 4, 0x7d	# DW_CFA_val_offset_sf, %esp, 12/-4
+					# i.e., next %esp is CFA + 12
+
+	# Set up a normal backtrace.
+	pushl	%ebp
+	.cfi_def_cfa_offset 8
+	.cfi_offset %ebp, -8
+	movl	%esp,%ebp
+	.cfi_def_cfa_register %ebp
 
 	# In 32-bit mode the parameters are pushed on the stack.  The
 	# argument size is pushed then the new stack frame size is
 	# pushed.
 
+	# Align stack to 16-byte boundary with enough space for saving
+	# registers and passing parameters to functions we call.
+	subl	$40,%esp
+
+	# Because our cleanup code may need to clobber %ebx, we need
+	# to save it here so the unwinder can restore the value used
+	# by the caller.  Note that we don't have to restore the
+	# register, since we don't change it, we just have to save it
+	# for the unwinder.
+	movl	%ebx,-4(%ebp)
+	.cfi_offset %ebx, -12
+
 	# In 32-bit mode the registers %eax, %edx, and %ecx may be
 	# used for parameters, depending on the regparm and fastcall
 	# attributes.
 
-	pushl	%eax
-	pushl	%edx
-	pushl	%ecx
+	movl	%eax,-8(%ebp)
+	movl	%edx,-12(%ebp)
+	movl	%ecx,-16(%ebp)
 
 	call	__morestack_block_signals
 
-	pushl	12(%ebp)		# The size of the parameters.
+	movl	12(%ebp),%eax		# The size of the parameters.
+	movl	%eax,8(%esp)
 	leal	20(%ebp),%eax		# Address of caller's parameters.
-	pushl	%eax
+	movl	%eax,4(%esp)
 	addl	$BACKOFF,8(%ebp)	# Ask for backoff bytes.
 	leal	8(%ebp),%eax		# The address of the new frame size.
-	pushl	%eax
+	movl	%eax,(%esp)
 
-	# Note that %esp is exactly 32 bytes below the CFA -- perfect for
-	# a 16-byte aligned stack.  That said, we still ought to compile
-	# generic-morestack.c with -mpreferred-stack-boundary=2.  FIXME.
 	call	__generic_morestack
 
 	movl	%eax,%esp		# Switch to the new stack.
@@ -191,8 +215,8 @@ __morestack:
 
 	call	__morestack_unblock_signals
 
-	movl	-8(%ebp),%edx		# Restore registers.
-	movl	-12(%ebp),%ecx
+	movl	-12(%ebp),%edx		# Restore registers.
+	movl	-16(%ebp),%ecx
 
 	movl	4(%ebp),%eax		# Increment the return address
 	cmpb	$0xc3,(%eax)		# to skip the ret instruction;
@@ -200,12 +224,12 @@ __morestack:
 	addl	$2,%eax
 1:	inc	%eax
 
-	movl	%eax,-8(%ebp)		# Store return address in an
+	movl	%eax,-12(%ebp)		# Store return address in an
 					# unused slot.
 
-	movl	-4(%ebp),%eax		# Restore the last register.
+	movl	-8(%ebp),%eax		# Restore the last register.
 
-	call	*-8(%ebp)		# Call our caller!
+	call	*-12(%ebp)		# Call our caller!
 
 	# The caller will return here, as predicted.
 
@@ -255,9 +279,13 @@ __morestack:
 	popl	%eax
 
 	.cfi_remember_state
+
+	# We never changed %ebx, so we don't have to actually restore it.
+	.cfi_restore %ebx
+
 	popl	%ebp
 	.cfi_restore %ebp
-	.cfi_def_cfa %esp, 12
+	.cfi_def_cfa %esp, 4
 	ret	$8			# Return to caller, which will
 					# immediately return.  Pop
 					# arguments as we go.
@@ -300,13 +328,6 @@ __morestack:
 	.cfi_lsda 0x1b,.LLSDA1
 #endif
 
-	# Set up a normal backtrace.
-	pushq	%rbp
-	.cfi_def_cfa_offset 16
-	.cfi_offset %rbp, -16
-	movq	%rsp, %rbp
-	.cfi_def_cfa_register %rbp
-
 	# We will return a single return instruction, which will
 	# return to the caller of our caller.  Let the unwinder skip
 	# that single return instruction, and just return to the real
@@ -314,6 +335,13 @@ __morestack:
 	.cfi_offset 16, 0
 	.cfi_escape 0x15, 7, 0x7f	# DW_CFA_val_offset_sf, %esp, 8/-8
 
+	# Set up a normal backtrace.
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+
 	# In 64-bit mode the new stack frame size is passed in r10
         # and the argument size is passed in r11.
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]