DWARF line number table problem when .byte is used for prefix (x86)

H.J. Lu hjl.tools@gmail.com
Wed Sep 1 01:27:00 GMT 2010
On Tue, Aug 31, 2010 at 6:04 PM, Cary Coutant <ccoutant@google.com> wrote:
> In the following test program, which I've reduced from gcc-generated
> code, ".byte 0x66" is used as a nop prefix for the leaq instruction in
> order to pad the TLS GD sequence to make room for a possible linker
> transformation (the exact code sequence, which I've chopped in half
> here, is given in Ulrich's "ELF Handling for Thread-Local Storage"
> document).
>
>        .file   "test.cc"
>        .section        .debug_abbrev,"",@progbits
> .Ldebug_abbrev0:
>        .section        .debug_info,"",@progbits
> .Ldebug_info0:
>        .section        .debug_line,"",@progbits
> .Ldebug_line0:
>        .text
> .Ltext0:
> foo:
> .LFB5133:
>        .file 1 "test.cc"
>        .loc 1 41 0
>        pushq   %rbp
> .LCFI96:
>        movq    %rsp, %rbp
> .LCFI97:
>        pushq   %rbx
>        subq    $40, %rsp
>        movq    %rdi, -40(%rbp)
> .LBB13:
>        .loc 1 41 0
>        .byte   0x66
>        leaq    bar@TLSGD(%rip), %rdi
>        ret
> .LFE5133:
>        .size   foo, .-foo
>
> The problem here is that gas assembles this with the line number table
> entry pointing to the byte after the 0x66 instead of the 0x66 itself:
>
> $ objdump -d test.o
> [...]
> 0000000000000000 <foo>:
>   0:   55                      push   %rbp
>   1:   48 89 e5                mov    %rsp,%rbp
>   4:   53                      push   %rbx
>   5:   48 83 ec 28             sub    $0x28,%rsp
>   9:   48 89 7d d8             mov    %rdi,-0x28(%rbp)
>   d:   66 48 8d 3d 00 00 00    lea    0x0(%rip),%rdi        # 15 <foo+0x15>
>  14:   00
>  15:   c3                      retq
>
> $ readelf -wl test.o
> [...]
>  Line Number Statements:
>  Extended opcode 2: set Address to 0x0
>  Advance Line by 40 to 41
>  Copy
>  Special opcode 201: advance Address by 14 to 0xe and Line by 0 to 41
>  Advance PC by 8 to 0x16
>  Extended opcode 1: End of Sequence
>
> Notice the row at address 0xe, placed just after the 0x66 prefix.
>
> The result of this is that when gdb tries to set a breakpoint just
> after the prologue, it ends up setting the breakpoint in the middle of
> the instruction (because x86 executes the 0x66 as a prefix rather than
> a single-byte NOP).
>
> If I remove the ".byte 0x66" and replace the "leaq" with "word leaq",
> the same object code gets generated, but the line number info is now
> correct:
>
> $ readelf -wl test.o
> [...]
>  Line Number Statements:
>  Extended opcode 2: set Address to 0x0
>  Advance Line by 40 to 41
>  Copy
>  Special opcode 187: advance Address by 13 to 0xd and Line by 0 to 41
>  Advance PC by 9 to 0x16
>  Extended opcode 1: End of Sequence
>
> Is this a gcc bug or a gas bug (or both)?

It is

http://sourceware.org/bugzilla/show_bug.cgi?id=11802

I think it is a gcc bug.

> We could change i386.md in gcc to use the mnemonic "word" prefix
> instead of ".byte 0x66" (or, alternatively, generate a real 1-byte NOP
> instead of using the prefix byte). Or we could change gas to call
> dwarf2_emit_insn() from cons_worker() to make sure that the location
> information gets processed at the right point.
>
> (Note that the same TLS sequence also uses a ".word 0x6666" prefix
> that probably ought to be changed as well, if we're changing what gcc
> emits. The difference there is that we'll never see a ".loc" opcode
> just before that, so I suspect it'll never actually trigger this
> problem.)
>


-- 
H.J.



More information about the Binutils mailing list