From 638a95a0e1efac11774c54d56d15e2c02612a2d1 Mon Sep 17 00:00:00 2001 From: ian Date: Fri, 28 Oct 2011 22:03:56 +0000 Subject: [PATCH] * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@180633 138bc75d-0d04-0410-961f-82ee72b054a4 --- libgcc/ChangeLog | 6 +++ libgcc/config/i386/morestack.S | 88 ++++++++++++++++++++++++++++-------------- 2 files changed, 64 insertions(+), 30 deletions(-) diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 2ceb1921591..a261e7524cd 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,9 @@ +2011-10-28 Ian Lance Taylor + + * 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. + 2011-10-25 Bernd Schmidt * config/c6x/pr-support.c (__gnu_unwind_24bit): Correct logic for the diff --git a/libgcc/config/i386/morestack.S b/libgcc/config/i386/morestack.S index b09ac76d060..85c20ed7e93 100644 --- a/libgcc/config/i386/morestack.S +++ b/libgcc/config/i386/morestack.S @@ -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. -- 2.11.0