public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* DWARF updates for linker relaxation?
@ 2006-07-17 21:32 Bob Wilson
  2006-07-28 23:28 ` Bob Wilson
  0 siblings, 1 reply; 4+ messages in thread
From: Bob Wilson @ 2006-07-17 21:32 UTC (permalink / raw)
  To: binutils

I recently discovered a problem on Xtensa regarding DWARF line numbers and 
linker relaxation.  I'm not sure, but it looks like the same issue may exist for 
SH and possibly other ports that do link-time relaxation.  Before I go too far 
trying to solve this, I'd like to see if anyone has already looked at it, or if 
anyone has suggestions for solutions.

Link-time relaxation for Xtensa may cause some instructions to be deleted.  We 
rely on the assembler's (Xtensa-specific) -link-relax option to produce 
relocations for all text offsets that may change.  The thing we're missing is 
the address offsets in .debug_line sections (e.g., "special opcodes" that 
advance the address by a certain amount).  The assembler does not emit 
relocations for these offsets, and the linker does not adjust them when deleting 
instructions.

This problem went unnoticed for a while, because Tensilica's compiler produces 
its own DWARF that has relocations for the address offsets.  It isn't clear to 
me whether the DWARF generated by the assembler has ever worked with link-time 
relaxation on Xtensa, or if this is a regression caused by some change in the 
assembler.

I've looked around in the code to see if anyone else has dealt with this, and it 
looks like the SH port has code related to this.  See, for example, the 
sh_elf_relax_delete_bytes() function, which appears to be used to delete an 
instruction during linker relaxation.  That function contains this comment: 
"Dwarf line numbers use R_SH_SWITCH32 relocs."  This makes sense to me, since 
those relocs can represent an address offset, and the linker can look for those 
relocs to update the DWARF information.  The problem is that I can't find 
anything in the SH port of the assembler that would cause SWITCH32 relocs to be 
use for DWARF line numbers.  When I run the SH assembler, I don't see any of 
these relocations in the .debug_line section, either.

How do I make this work?  It seems like the obvious approach is to have a hook 
in the assembler to make it use the generic "advance_pc" opcode instead of 
"special opcodes", with relocations on the address offset fields.  The SH code 
mentioned above made me think there might already be code for this somewhere in 
the assembler, but I haven't found it.

Any suggestions?

--Bob

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: DWARF updates for linker relaxation?
  2006-07-17 21:32 DWARF updates for linker relaxation? Bob Wilson
@ 2006-07-28 23:28 ` Bob Wilson
  2006-08-08 10:16   ` Nick Clifton
  0 siblings, 1 reply; 4+ messages in thread
From: Bob Wilson @ 2006-07-28 23:28 UTC (permalink / raw)
  To: binutils

[-- Attachment #1: Type: text/plain, Size: 1515 bytes --]

On Mon, 17 Jul 2006 at 14:32:46 -0700, Bob Wilson wrote:
 > How do I make this work? It seems like the obvious approach is to have a hook
 > in the assembler to make it use the generic "advance_pc" opcode instead of
 > "special opcodes", with relocations on the address offset fields. The SH code
 > mentioned above made me think there might already be code for this somewhere
 > in the assembler, but I haven't found it.
 >
 > Any suggestions?

I didn't get any suggestions or pointers to existing code, so I came up with my 
own solution for this.  It allows a port to specify that DWARF line numbers 
should be specified using the DW_LNS_fixed_advance_pc opcodes.  This allows 
linker relaxation to update the PC offsets, at the expense of slightly larger 
.debug_line sections.

I tested this by building for both i686-pc-linux-gnu and xtensa-elf targets. 
The testsuite passes with no regressions, except for one.  For the xtensa-elf 
target, the lns/lns-common-1 test fails because the expected dump file no longer 
matches.  Is there an easy way to specify an alternate expected dump file? 
Otherwise, I guess I could skip this test for Xtensa targets.

Assuming I get that regression fixed, is this OK?

2006-07-28  Bob Wilson  <bob.wilson@acm.org>

	* dwarf2dbg.c (DWARF2_USE_FIXED_ADVANCE_PC): New.
	(out_sleb128): New.
	(out_fixed_inc_line_addr): New.
	(process_entries): Use out_fixed_inc_line_addr when
	DWARF2_USE_FIXED_ADVANCE_PC is set.
	* config/tc-xtensa.h (DWARF2_USE_FIXED_ADVANCE_PC): Define.


[-- Attachment #2: dwarf-linkrelax.diff --]
[-- Type: text/plain, Size: 4662 bytes --]

Index: dwarf2dbg.c
===================================================================
RCS file: /cvs/src/src/gas/dwarf2dbg.c,v
retrieving revision 1.85
diff -u -p -r1.85 dwarf2dbg.c
--- dwarf2dbg.c	7 Jun 2006 11:27:57 -0000	1.85
+++ dwarf2dbg.c	28 Jul 2006 22:57:04 -0000
@@ -88,6 +88,13 @@
 #define DL_FILES	1
 #define DL_BODY		2
 
+/* If linker relaxation might change offsets in the code, the DWARF special
+   opcodes and variable-length operands cannot be used.  If this macro is
+   nonzero, use the DW_LNS_fixed_advance_pc opcode instead.  */
+#ifndef DWARF2_USE_FIXED_ADVANCE_PC
+# define DWARF2_USE_FIXED_ADVANCE_PC	0
+#endif
+
 /* First special line opcde - leave room for the standard opcodes.
    Note: If you want to change this, you'll have to update the
    "standard_opcode_lengths" table that is emitted below in
@@ -191,11 +198,13 @@ static void out_two (int);
 static void out_four (int);
 static void out_abbrev (int, int);
 static void out_uleb128 (addressT);
+static void out_sleb128 (addressT);
 static offsetT get_frag_fix (fragS *, segT);
 static void out_set_addr (symbolS *);
 static int size_inc_line_addr (int, addressT);
 static void emit_inc_line_addr (int, addressT, char *, int);
 static void out_inc_line_addr (int, addressT);
+static void out_fixed_inc_line_addr (int, symbolS *, symbolS *);
 static void relax_inc_line_addr (int, symbolS *, symbolS *);
 static void process_entries (segT, struct line_entry *);
 static void out_file_list (void);
@@ -746,6 +755,14 @@ out_uleb128 (addressT value)
   output_leb128 (frag_more (sizeof_leb128 (value, 0)), value, 0);
 }
 
+/* Emit a signed "little-endian base 128" number.  */
+
+static void
+out_sleb128 (addressT value)
+{
+  output_leb128 (frag_more (sizeof_leb128 (value, 1)), value, 1);
+}
+
 /* Emit a tuple for .debug_abbrev.  */
 
 static inline void
@@ -979,6 +996,45 @@ out_inc_line_addr (int line_delta, addre
   emit_inc_line_addr (line_delta, addr_delta, frag_more (len), len);
 }
 
+/* Write out an alternative form of line and address skips using
+   DW_LNS_fixed_advance_pc opcodes.  This uses more space than the default
+   line and address information, but it helps support linker relaxation that
+   changes the code offsets.  */
+
+static void
+out_fixed_inc_line_addr (int line_delta, symbolS *to_sym, symbolS *from_sym)
+{
+  expressionS expr;
+
+  /* INT_MAX is a signal that this is actually a DW_LNE_end_sequence.  */
+  if (line_delta == INT_MAX)
+    {
+      out_opcode (DW_LNS_fixed_advance_pc);
+      expr.X_op = O_subtract;
+      expr.X_add_symbol = to_sym;
+      expr.X_op_symbol = from_sym;
+      expr.X_add_number = 0;
+      emit_expr (&expr, 2);
+
+      out_opcode (DW_LNS_extended_op);
+      out_byte (1);
+      out_opcode (DW_LNE_end_sequence);
+      return;
+    }
+
+  out_opcode (DW_LNS_advance_line);
+  out_sleb128 (line_delta);
+
+  out_opcode (DW_LNS_fixed_advance_pc);
+  expr.X_op = O_subtract;
+  expr.X_add_symbol = to_sym;
+  expr.X_op_symbol = from_sym;
+  expr.X_add_number = 0;
+  emit_expr (&expr, 2);
+
+  out_opcode (DW_LNS_copy);
+}
+
 /* Generate a variant frag that we can use to relax address/line
    increments between fragments of the target segment.  */
 
@@ -1129,6 +1185,8 @@ process_entries (segT seg, struct line_e
 	  out_set_addr (lab);
 	  out_inc_line_addr (line_delta, 0);
 	}
+      else if (DWARF2_USE_FIXED_ADVANCE_PC)
+	out_fixed_inc_line_addr (line_delta, lab, last_lab);
       else if (frag == last_frag)
 	out_inc_line_addr (line_delta, frag_ofs - last_frag_ofs);
       else
@@ -1148,7 +1206,12 @@ process_entries (segT seg, struct line_e
   /* Emit a DW_LNE_end_sequence for the end of the section.  */
   frag = last_frag_for_seg (seg);
   frag_ofs = get_frag_fix (frag, seg);
-  if (frag == last_frag)
+  if (DWARF2_USE_FIXED_ADVANCE_PC)
+    {
+      lab = symbol_temp_new (seg, frag_ofs, frag);
+      out_fixed_inc_line_addr (INT_MAX, lab, last_lab);
+    }
+  else if (frag == last_frag)
     out_inc_line_addr (INT_MAX, frag_ofs - last_frag_ofs);
   else
     {
Index: config/tc-xtensa.h
===================================================================
RCS file: /cvs/src/src/gas/config/tc-xtensa.h,v
retrieving revision 1.19
diff -u -p -r1.19 tc-xtensa.h
--- config/tc-xtensa.h	31 Jan 2006 19:36:57 -0000	1.19
+++ config/tc-xtensa.h	28 Jul 2006 22:57:05 -0000
@@ -371,6 +371,9 @@ extern char *xtensa_section_rename (char
 #define MD_APPLY_SYM_VALUE(FIX) 0
 #define SUB_SEGMENT_ALIGN(SEG, FRCHAIN) 0
 
+/* Use line number format that is amenable to linker relaxation.  */
+#define DWARF2_USE_FIXED_ADVANCE_PC (linkrelax != 0)
+
 
 /* Resource reservation info functions.  */
 

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: DWARF updates for linker relaxation?
  2006-07-28 23:28 ` Bob Wilson
@ 2006-08-08 10:16   ` Nick Clifton
  2006-08-09  0:12     ` Bob Wilson
  0 siblings, 1 reply; 4+ messages in thread
From: Nick Clifton @ 2006-08-08 10:16 UTC (permalink / raw)
  To: Bob Wilson; +Cc: binutils

Hi Bob,

> I didn't get any suggestions or pointers to existing code,

Sorry about that.  I have been very behind in answering binutils email 
recently. :-(

> I tested this by building for both i686-pc-linux-gnu and xtensa-elf 
> targets. The testsuite passes with no regressions, except for one.  For 
> the xtensa-elf target, the lns/lns-common-1 test fails because the 
> expected dump file no longer matches.  Is there an easy way to specify 
> an alternate expected dump file?

Yes.  Edit the lns.exp file and an explicit entry for the xtensa port.  eg:

   if { ![istarget ia64*-*-*] && ![istarget i370-*-*]
        && ![istarget i960-*-*] && ![istarget or32-*-*]
        && ![istarget s390*-*-*] } {
      if {[istarget xtensa-*-*]} {
        run_dump_test "lns-common-1-xtensa"
      } else {
        run_dump_test "lns-common-1"
      }
    }

Then create an "lns-common-1-xtensa.d" file containing the correct 
regexps and also this line at the start:

   # source lns-common-1.s


> Assuming I get that regression fixed, is this OK?
> 
> 2006-07-28  Bob Wilson  <bob.wilson@acm.org>
> 
>     * dwarf2dbg.c (DWARF2_USE_FIXED_ADVANCE_PC): New.
>     (out_sleb128): New.
>     (out_fixed_inc_line_addr): New.
>     (process_entries): Use out_fixed_inc_line_addr when
>     DWARF2_USE_FIXED_ADVANCE_PC is set.
>     * config/tc-xtensa.h (DWARF2_USE_FIXED_ADVANCE_PC): Define.

Approved - please apply.

Cheers
   Nick

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: DWARF updates for linker relaxation?
  2006-08-08 10:16   ` Nick Clifton
@ 2006-08-09  0:12     ` Bob Wilson
  0 siblings, 0 replies; 4+ messages in thread
From: Bob Wilson @ 2006-08-09  0:12 UTC (permalink / raw)
  To: Nick Clifton; +Cc: binutils

[-- Attachment #1: Type: text/plain, Size: 1402 bytes --]

Nick Clifton wrote:
> Sorry about that.  I have been very behind in answering binutils email 
> recently. :-(

That's OK -- I don't think there was any existing code to start from.  I have no 
idea what the comments in the SH code were referring to, but I'm pretty sure GAS 
is not generating relocs for DWARF line numbers on SH.

>> I tested this by building for both i686-pc-linux-gnu and xtensa-elf 
>> targets. The testsuite passes with no regressions, except for one.  
>> For the xtensa-elf target, the lns/lns-common-1 test fails because the 
>> expected dump file no longer matches.  Is there an easy way to specify 
>> an alternate expected dump file?
> 
> Yes.  Edit the lns.exp file and an explicit entry for the xtensa port.  eg:
 > [ example removed ]

Thanks -- my DejaGNU skills are pretty minimal, and you saved me a bunch of time 
trying to figure out how to do this.  Here is the testsuite change that I have 
applied along with the previous patch.  I named the file with a "-alt" suffix 
instead of "-xtensa", because other targets may someday need to use this style 
of DWARF line numbers and so it's really not Xtensa-specific.  I verified that 
there are no unexpected failures for both xtensa-elf and i686-pc-linux-gnu builds.

2006-08-08  Bob Wilson  <bob.wilson@acm.org>

	* gas/lns/lns-common-1-alt.d: New file.
	* gas/lns/lns.exp: Use lns-common-1-alt.d for xtensa targets.


[-- Attachment #2: gas-dwarf2-test.diff --]
[-- Type: text/plain, Size: 1855 bytes --]

Index: testsuite/gas/lns/lns.exp
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/lns/lns.exp,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- testsuite/gas/lns/lns.exp	21 Sep 2005 06:55:49 -0000	1.2
+++ testsuite/gas/lns/lns.exp	8 Aug 2006 19:09:34 -0000	1.3
@@ -23,5 +23,10 @@
 # defined a macro...
 if { ![istarget ia64*-*-*] && ![istarget i370-*-*] && ![istarget i960-*-*]
      && ![istarget or32-*-*] && ![istarget s390*-*-*] } {
-  run_dump_test "lns-common-1"
+  # Use alternate file for targets using DW_LNS_fixed_advance_pc opcodes.
+  if { [istarget xtensa-*-*] } {
+    run_dump_test "lns-common-1-alt"
+  } else {
+    run_dump_test "lns-common-1"
+  }
 }
--- /dev/null	2006-05-30 18:33:22.000000000 -0700
+++ testsuite/gas/lns/lns-common-1-alt.d	2006-08-08 11:26:27.000000000 -0700
@@ -0,0 +1,39 @@
+#source: lns-common-1.s
+#readelf: -wl
+#name: lns-common-1
+Dump of debug contents of section \.debug_line:
+#...
+  Initial value of 'is_stmt':  1
+#...
+ Line Number Statements:
+  Extended opcode 2: set Address to .*
+  Copy
+  Set column to 3
+  Advance Line by 1 to 2
+  Advance PC by fixed size amount .* to .*
+  Copy
+  Set prologue_end to true
+  Advance Line by 1 to 3
+  Advance PC by fixed size amount .* to .*
+  Copy
+  Set column to 0
+  Set epilogue_begin to true
+  Advance Line by 1 to 4
+  Advance PC by fixed size amount .* to .*
+  Copy
+  Set ISA to 1
+  Set basic block
+  Advance Line by 1 to 5
+  Advance PC by fixed size amount .* to .*
+  Copy
+  Set is_stmt to 0
+  Advance Line by 1 to 6
+  Advance PC by fixed size amount .* to .*
+  Copy
+  Set is_stmt to 1
+  Advance Line by 1 to 7
+  Advance PC by fixed size amount .* to .*
+  Copy
+  Advance PC by fixed size amount .* to .*
+  Extended opcode 1: End of Sequence
+#...

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2006-08-08 19:20 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-07-17 21:32 DWARF updates for linker relaxation? Bob Wilson
2006-07-28 23:28 ` Bob Wilson
2006-08-08 10:16   ` Nick Clifton
2006-08-09  0:12     ` Bob Wilson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).