[llvm-dev] X86 llvm.frameaddress/returnaddress

Todd Mortimer via llvm-dev llvm-dev at lists.llvm.org
Fri Nov 17 07:44:33 PST 2017


Hello,

The llvm.frameaddress and llvm.returnaddress intrinsics seem broken on
64 bit X86 with -fomit-frame-pointer when given an argument greater than
zero.

We recently found on OpenBSD that code calling __builtin_return_address
and __builtin_frame_address with arguments greater than zero can
segfault if RBP has been allocated as a general purpose register
somewhere up the stack. Specifically, we found that chromium calls
backtrace(), and the library we were using to implement that function
was just using __builtin_return_address and __builtin_frame_address to
walk the stack backwards. The compiled code ended up something like
this:

     5bf:       48 8b 4d 00             mov    0x0(%rbp),%rcx
     5c3:       48 8b 09                mov    (%rcx),%rcx
     5c6:       48 8b 09                mov    (%rcx),%rcx
     5c9:       48 8b 09                mov    (%rcx),%rcx
     5cc:       48 83 39 00             cmpq   $0x0,(%rcx)

This works fine when %rbp is always holding a frame pointer, but is
unpredictable when it does not. In our case, C++ code in Chromium had
used %rbp for data, so segfaulted when dereferencing.

I see in the implementation of X86TargetLowering::LowerFRAMEADDR that
there is some special handling when MF.getTarget().getMCAsmInfo()->usesWindowsCFI()
is true, and it is commented to the effect that depth > 0 makes no sense
when unwind info is needed. Should the same logic be applied when given
-fomit-frame-pointer, or just in general on 64 bit X86 where unwind
tables are required anyway? I realize that the documentation for the
llvm.frameaddress and llvm.returnaddress intrinsics are explicit that
the return value may be wrong when the argument is > 0, but in cases
where we know it will be unreliable / unstable, it might be useful to
limit the output to something that doesn't possibly cause runtime
failures?

Todd




More information about the llvm-dev mailing list