[PATCH] PR8541; X86: Handle unwind.init and eh.return intrinsics.
Dimitry Andric
dimitry at andric.com
Wed May 15 07:17:36 PDT 2013
On 2013-05-15 14:36, Pasi Parviainen wrote:
> On 15.5.2013 14:54, Dimitry Andric wrote:
>> On 2013-05-15 02:20, Pasi Parviainen wrote:
...
>>> So considering previous point, workaround used in FreeBSD is also
>>> flawed, since it is trashing return values on non-eh.return epilogues :)
>>
>> Interesting, but we do not seem to see any effect of such thrashing in
>> FreeBSD. It seems that in the relevant cases, libgcc always returns via
>> __builtin_eh_return()? E.g., would the non-eh.return cases not go via a
>> different code path?
>
> Yes, the common code path would be trough __builtin_eh_return. But when
> unwinder encounters some exceptional situation/failure, it will return a
> reason code for it. So, now instead of a proper reason code, client of
> unwinder interface will get a more or less random value and this breaks
> API contract between unwinder and its client.
Hmm, you are quite right, apparently. Take for example the libgcc
function _Unwind_ForcedUnwind():
_Unwind_Reason_Code
_Unwind_ForcedUnwind (struct _Unwind_Exception *exc,
_Unwind_Stop_Fn stop, void * stop_argument)
{
struct _Unwind_Context this_context, cur_context;
_Unwind_Reason_Code code;
[...]
code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context);
if (code != _URC_INSTALL_CONTEXT)
return code;
uw_install_context (&this_context, &cur_context);
}
The uw_install_context macro eventually calls __builtin_eh_return. With
gcc, the produced assembly goes like this (modified slightly to improve
readability):
_Unwind_ForcedUnwind:
pushq %rbp
movq %rsp, %rbp
movq %rax, -56(%rbp)
movq %rdx, -48(%rbp)
leaq -304(%rbp), %rax
movq %rbx, -40(%rbp)
movq %r12, -32(%rbp)
movq %r13, -24(%rbp)
movq %r14, -16(%rbp)
movq %r15, -8(%rbp)
subq $592, %rsp
[...]
call _Unwind_ForcedUnwind_Phase2
cmpl $7, %eax # 7 is _URC_INSTALL_CONTEXT
je .L612
movq -40(%rbp), %rbx # restores just a few regs
movq -32(%rbp), %r12
movq -24(%rbp), %r13
movq -16(%rbp), %r14
movq -8(%rbp), %r15
leave
ret # non-eh return
.L612:
movq -584(%rbp), %rsi
movq -576(%rbp), %rdi
call uw_install_context_1
movq %rax, %rcx
movq -392(%rbp), %rax
movq %rax, 8(%rbp,%rcx)
leaq 8(%rbp,%rcx), %rcx
movq -56(%rbp), %rax # restores most regs
movq -48(%rbp), %rdx
movq -40(%rbp), %rbx
movq -32(%rbp), %r12
movq -24(%rbp), %r13
movq -16(%rbp), %r14
movq -8(%rbp), %r15
movq 0(%rbp), %rbp
movq %rcx, %rsp
ret # eh return
With clang, and our clobber hack, it goes like this:
_Unwind_ForcedUnwind: # @_Unwind_ForcedUnwind
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
pushq %rdx
pushq %rax
subq $488, %rsp # imm = 0x1E8
[...]
callq _Unwind_ForcedUnwind_Phase2
cmpl $7, %eax # 7 is _URC_INSTALL_CONTEXT
je .LBB17_2
addq $488, %rsp # imm = 0x1E8
popq %rax # restores most regs, and clobbers %eax!
popq %rdx
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
ret # non-eh return
.LBB17_2:
leaq -296(%rbp), %rdi
leaq -536(%rbp), %rsi
callq uw_install_context_1
movq %rax, %rcx
movq -384(%rbp), %rsi
movq %rsi, 8(%rbp,%rcx)
leaq 8(%rbp,%rcx), %rcx
addq $488, %rsp # imm = 0x1E8
popq %rax # restores most regs
popq %rdx
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
movq %rcx, %rsp
ret # eh_return, addr: %rcx
So clearly, clang restores too much in the non-eh case, and clobbers the
return value from _Unwind_ForcedUnwind_Phase2().
I am not sure if there is a way to force it to restore all registers
just in the eh_return case, except by using your patch. :-)
-Dimitry
More information about the llvm-commits
mailing list