This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]