[Dwarf-Discuss] Location list entries for caller-saved registers at time of call

David Stenberg david.stenberg at ericsson.com
Fri Dec 7 04:36:39 PST 2018


On tor, 2018-12-06 at 17:47 -0800, Cary Coutant via Dwarf-Discuss
wrote:
> But we're getting sidetracked from the OP's question: Does GCC in
> fact
> subtract one from the upper bound of a location list entry for a
> variable contained in a caller-saved register? I can think of no
> reason why it should do this. If the compiled code does something
> like
> this:
> 
>     A: promote variable X into caller-save register R
>        ...
>        call f
>     B: ...
>        spill register R back to X
>     C: ...
> 
> The location list entry for x should show it live in register R in
> the
> range [A..C). The call should not interrupt the range.
> 
> It sounds like David has an example where the range list entry shows
> x
> in register R in the range [A..B-1), then presumably again for
> [B..C),
> leaving [B-1..B) uncovered. That would be a bug, in my opinion.
> 
> David, can you show us an example?

In the following example I used GCC 7.3.0, and compiled the below
listed C code using `-O1 -gstrict-dwarf -gdwarf-5'.

  extern int get();
  extern void set(int);
  
  int main() {
    int local = get();
    set(local);
    local = 123;
    return local;
  }

This produces the following location list for `local':

    0000000c 000000000000000e 0000000000000014 (DW_OP_reg0 (rax))
    00000011 0000000000000015 000000000000001f (DW_OP_const1u: 123;    
                                                DW_OP_stack_value)

   9:   e8 00 00 00 00          callq  e <main+0xe>
   e:   89 c7                   mov    %eax,%edi
  10:   e8 00 00 00 00          callq  15 <main+0x15>
  15:   b8 7b 00 00 00          mov    $0x7b,%eax

As seen, there is a one-byte gap at the end of the call instruction to
set().

As far as I have understood it, GCC emits a location list like this
because it knows that the producer will subtract one from the return
address when doing virtual unwinding. In this way, GDB will print the
variable as "<optimized out>" when unwinding from set() to main(), even
though it does not have knowledge of whether or not RAX is caller-
saved.

If we instead use Clang, there is no gap in the location list for the
same code:

    [0x0000000000000008, 0x000000000000000f): DW_OP_reg0 RAX
    [0x000000000000000f, 0x0000000000000016): DW_OP_consts +123,
                                              DW_OP_stack_value)

   3:   e8 00 00 00 00          callq  8 <main+0x8>
   8:   89 c7                   mov    %eax,%edi
   a:   e8 00 00 00 00          callq  f <main+0xf>
   f:   b8 7b 00 00 00          mov    $0x7b,%eax

When debugging the Clang-built binary in GDB, when unwinding from set()
to main(), `local' will be evaluated using the value RAX has in set(),
rather then being printed as "<optimized out>".

Best regards,
David


More information about the Dwarf-Discuss mailing list