This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: [RFC][ARM][AARCH64] Set DWARF2_LINE_MIN_INSN_LENGTH to 1
- From: Nicholas Clifton <nickc at redhat dot com>
- To: Renlin Li <renlin dot li at arm dot com>, "binutils at sourceware dot org" <binutils at sourceware dot org>
- Cc: Marcus Shawcroft <Marcus dot Shawcroft at arm dot com>
- Date: Wed, 01 Apr 2015 17:01:17 +0100
- Subject: Re: [RFC][ARM][AARCH64] Set DWARF2_LINE_MIN_INSN_LENGTH to 1
- Authentication-results: sourceware.org; auth=none
- References: <55158759 dot 8090300 at arm dot com>
Hi Renlin,
If any cases left the last frag unaligned(size of the frag) to
DWARF2_LINE_MIN_INSN_LENGTH, and assembled with -gdwarf-2 flag,
The following error will be triggered.
'''Error: unaligned opcodes detected in executable segment'''.
For the following code snippet;
.text
ret
.byte 0xf --> data in .text section, minimum size is different.
I do not think that this is a bug. The assembler is correctly reporting
that the user has created a code section that ends not on a code
alignment boundary. It does appear however that this kind of thing is
expected to work. (See eg gas/testsuite/gas/elf/section7.s). So maybe
a solution is needed.
Setting DWARF2_LINE_MIN_INSN_LENGTH to 1 seems wrong to me. For the
normal case we want to use a dwarf insn length that matches the
architecture's insn length. So instead, how about the attached patch?
It changes the dwarf2dbg.c code so that it computes a maximum allowable
value for DWARF2_LINE_MIN_INSN_LENGTH automatically, using the target
supplied value as a starting point, but reducing it if necessary to
support pathological assembly programming.
What do you think ?
Cheers
Nick
diff --git a/gas/dwarf2dbg.c b/gas/dwarf2dbg.c
index e67c992..4724f31 100644
--- a/gas/dwarf2dbg.c
+++ b/gas/dwarf2dbg.c
@@ -143,6 +143,7 @@
bytes). This value should be rather too small than too big. */
# define DWARF2_LINE_MIN_INSN_LENGTH 1
#endif
+static unsigned int dwarf2_line_min_insn_length = 1;
/* Flag that indicates the initial value of the is_stmt_start flag. */
#define DWARF2_LINE_DEFAULT_IS_STMT 1
@@ -869,20 +870,100 @@ out_set_addr (symbolS *sym)
emit_expr (&exp, sizeof_address);
}
-static void scale_addr_delta (addressT *);
+/* Compute the maximum possible value for the minimum instruction length.
+ Normally this will be the value DWARF2_LINE_MIN_INSN_LENGTH set by the
+ target. But if the assembly source includes non-instruction bytes in
+ a code section then it may need to be smaller. For an example see:
+ gas/testsuite/gas/elf/dwarf2-5.s. */
+
+static void
+compute_line_min_insn_length (void)
+{
+ struct line_seg *s;
+
+ dwarf2_line_min_insn_length = DWARF2_LINE_MIN_INSN_LENGTH;
+
+ if (dwarf2_line_min_insn_length == 1 || DWARF2_USE_FIXED_ADVANCE_PC)
+ return;
+
+ for (s = all_segs; s; s = s->next)
+ {
+ segT seg = s->seg;
+ struct line_entry * e;
+ symbolS * lab;
+ fragS * last_frag = NULL;
+ fragS * frag;
+ addressT last_frag_ofs = 0;
+ addressT frag_ofs;
+
+ if (! SEG_NORMAL (seg))
+ continue;
+
+ e = s->head->head;
+
+ while (e)
+ {
+ lab = e->label;
+ frag = symbol_get_frag (lab);
+ frag_ofs = S_GET_VALUE (lab);
+
+ if (frag == last_frag)
+ {
+ addressT delta = frag_ofs - last_frag_ofs;
+
+ if ((delta % dwarf2_line_min_insn_length) != 0)
+ {
+ do
+ {
+ dwarf2_line_min_insn_length >>= 1;
+ }
+ while (delta % dwarf2_line_min_insn_length != 0);
+
+ if (dwarf2_line_min_insn_length == 1)
+ return;
+ }
+ }
+
+ last_frag = frag;
+ last_frag_ofs = frag_ofs;
+ e = e->next;
+ }
+
+ frag = last_frag_for_seg (seg);
+ if (frag == last_frag)
+ {
+ addressT delta;
+
+ frag_ofs = get_frag_fix (frag, seg);
+ delta = frag_ofs - last_frag_ofs;
+
+ if ((delta % dwarf2_line_min_insn_length) != 0)
+ {
+ do
+ {
+ dwarf2_line_min_insn_length >>= 1;
+ }
+ while (delta % dwarf2_line_min_insn_length != 0);
+ }
+ }
+ }
+}
static void
scale_addr_delta (addressT *addr_delta)
{
static int printed_this = 0;
- if (DWARF2_LINE_MIN_INSN_LENGTH > 1)
+
+ if (dwarf2_line_min_insn_length > 1)
{
- if (*addr_delta % DWARF2_LINE_MIN_INSN_LENGTH != 0 && !printed_this)
+ if (*addr_delta % dwarf2_line_min_insn_length != 0 && !printed_this)
{
+ /* FIXME: If this warning is triggered then the code in
+ compute_line_min_insn_length () above has failed. */
as_bad("unaligned opcodes detected in executable segment");
printed_this = 1;
}
- *addr_delta /= DWARF2_LINE_MIN_INSN_LENGTH;
+ *addr_delta /= dwarf2_line_min_insn_length;
}
}
@@ -1173,9 +1254,9 @@ relax_inc_line_addr (int line_delta, symbolS *to_sym, symbolS *from_sym)
sized address delta. */
if (DWARF2_USE_FIXED_ADVANCE_PC)
max_chars = size_fixed_inc_line_addr (line_delta,
- -DWARF2_LINE_MIN_INSN_LENGTH);
+ - dwarf2_line_min_insn_length);
else
- max_chars = size_inc_line_addr (line_delta, -DWARF2_LINE_MIN_INSN_LENGTH);
+ max_chars = size_inc_line_addr (line_delta, - dwarf2_line_min_insn_length);
frag_var (rs_dwarf2dbg, max_chars, max_chars, 1,
make_expr_symbol (&exp), line_delta, NULL);
@@ -1538,8 +1619,10 @@ out_debug_line (segT line_seg)
emit_expr (&exp, sizeof_offset);
symbol_set_value_now (prologue_start);
+ compute_line_min_insn_length ();
+
/* Parameters of the state machine. */
- out_byte (DWARF2_LINE_MIN_INSN_LENGTH);
+ out_byte (dwarf2_line_min_insn_length);
out_byte (DWARF2_LINE_DEFAULT_IS_STMT);
out_byte (DWARF2_LINE_BASE);
out_byte (DWARF2_LINE_RANGE);
diff --git a/gas/testsuite/gas/elf/elf.exp b/gas/testsuite/gas/elf/elf.exp
index 47b5a21..cfe7c47 100644
--- a/gas/testsuite/gas/elf/elf.exp
+++ b/gas/testsuite/gas/elf/elf.exp
@@ -200,6 +200,7 @@ if { [is_elf_format] } then {
run_dump_test "dwarf2-2"
run_dump_test "dwarf2-3"
run_dump_test "dwarf2-4"
+ gas_test "dwarf2-5.s" "-gdwarf-2" "" "DWARF2: non-aligned code sections"
run_dump_test "bad-section-flag"
run_dump_test "bad-size"
run_dump_test "bad-group"
--- /dev/null 2015-04-01 08:58:06.478958567 +0100
+++ gas/testsuite/gas/elf/dwarf2-5.s 2015-04-01 16:30:07.001070045 +0100
@@ -0,0 +1,16 @@
+# When the following is assembled with -gdwarf-2 enabled the assembler used to
+# report:
+#
+# dwarf2-5.s: Assembler messages:
+# dwarf2-5.s: Error: unaligned opcodes detected in executable segment
+#
+# This indicates that the target concerned had an instruction size greater than 1.
+# This should now be fixed by dwarf2dbg.c:compute_line_min_insn_length().
+
+ .text
+ nop
+ .byte 0xf
+
+ .data
+ .byte 2
+