This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
DWARF line number table problem when .byte is used for prefix (x86)
- From: Cary Coutant <ccoutant at google dot com>
- To: Binutils <binutils at sourceware dot org>
- Date: Tue, 31 Aug 2010 18:04:52 -0700
- Subject: DWARF line number table problem when .byte is used for prefix (x86)
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)?
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.)
-cary