Expected behavior of __builtin_return_address() with inlining?

Hi,
I am trying to understand what should be the expected behavior of __builtin_return_address(0)
when inlining has happened.

So, the GCC doc from https://gcc.gnu.org/onlinedocs/gcc/Return-Address.html says:
(I used GCC doc because I could not find equivalent Clang/LLVM builtin doc)
  When inlining the expected behavior is that the function returns the address of the function
  that is returned to. To work around this behavior use the noinline function attribute.

I wrote the following test case to verify this behavior:
  /* test.c */
  long foo() {
    return (long)__builtin_return_address(0);
  }
  inline long bar() {
    return foo();
  }
  long foobar() {
    return bar();
  }
  /* end test.c */

My interpretation of the GCC doc is that, if foo() is inlined into bar(), then __builtin_return_address(0)
will return &bar, instead of the instruction address of the call to foo().

I compiled with GCC 4.8.2 and Clang 3.8.0, and I got the following result:

  # clang 3.8.0 trunk 253253
  # clang -S -O2 test.c
  foo:
    movq (%rsp), %rax
    retq
  foobar:
    movq (%rsp), %rax
    retq
  # end assembly

  # GCC 4.8.2-19ubuntu1
  # gcc -S -O2 test.c
  foo:
    movq (%rsp), %rax
    ret
  bar:
    movq (%rsp), %rax
    ret
  foobar:
    movq (%rsp), %rax
    ret
  # end assembly

So with both compilers, an inlined __builtin_return_address(0) seems to produce the return address of the
function containing the callsite where the inlined function is expanded.

Maybe I misunderstood the documentation regarding the inlined __builtin_return_address()? Please help,

- Gao

Hi,
I am trying to understand what should be the expected behavior of
__builtin_return_address(0)
when inlining has happened.

So, the GCC doc from
https://gcc.gnu.org/onlinedocs/gcc/Return-Address.html says:
(I used GCC doc because I could not find equivalent Clang/LLVM builtin doc)
  When inlining the expected behavior is that the function returns the
address of the function
  that is returned to. To work around this behavior use the noinline
function attribute.

I wrote the following test case to verify this behavior:
  /* test.c */
  long foo() {
    return (long)__builtin_return_address(0);
  }
  inline long bar() {
    return foo();
  }
  long foobar() {
    return bar();
  }
  /* end test.c */

My interpretation of the GCC doc is that, if foo() is inlined into bar(),
then __builtin_return_address(0)
will return &bar, instead of the instruction address of the call to foo().

I think the wording "the function that is returned to" is referring to the
function that is dynamically returned to, not anything at source level.
It's more like "if you were to say `asm("ret")`, where would you return to"

Also see: See http://llvm.org/docs/LangRef.html#llvm-returnaddress-intrinsic

The "current function" is pretty much "whatever the backend sees". That
seems like the only reasonable way to define it.

-- Sean Silva

Hey Sean,

Thanks for the explanation. The LLVM IR doc does clarify things for me. The part

that I got confused is not really about what is “the function that is returned to”:

the GCC doc explicitly mentions it should be the address of "the function that is

returned to", i.e., &bar in my example; whereas the observed behavior from the

compiler is more like the return address as if the builtin was placed inside "the

function that is returned to", i.e.,

long bar() { return __builtin_return_address(0); }

Reading the old thread from https://gcc.gnu.org/ml/gcc/2002-06/msg00335.html seems

to indicate that the GCC doc is intended as an after-the-fact description of what the

compiler does, rather than a description of behavior which the compiler should be

changed to conform to. I am therefore inclined to believe that the GCC doc is inaccurate

in capturing the behavior of the compiler. The clang LangRef.html says,

"Note that calling this intrinsic does not prevent function inlining or other

aggressive transformations, so the value returned may not be that of the obvious

source-language caller."

And I believe it is consistent with the observed behavior from the compiler.

Thanks!

  • Gao