Optimise away eh_frame advance_loc 0

These can be generated when multiple cfi directives are emitted for an
instruction and the insn frag is closed off between directives, as
happens when listings are enabled.  No doubt the advance_loc of zero
could be avoided by backtracking over frags in dw2gencfi.c before
calling cfi_add_advance_loc, but that seems like more work than
cleaning up afterwards as this patch does.

Noticed when looking at the testcase in PR25125.

	PR 25125
	* dw2gencfi.c (output_cfi_insn): Don't output DW_CFA_advance_loc+0.
	* ehopt.c (eh_frame_estimate_size_before_relax): Return -1 for
	an advance_loc of zero.
	(eh_frame_relax_frag): Translate fr_subtype of 7 to size -1.
	(eh_frame_convert_frag): Handle fr_subtype of 7.  Abort on
	unexpected fr_subtype.
This commit is contained in:
Alan Modra 2019-10-26 18:38:26 +10:30
parent 30baf67b65
commit 6f69abb049
3 changed files with 28 additions and 4 deletions

View File

@ -1,3 +1,13 @@
2019-10-26 Alan Modra <amodra@gmail.com>
PR 25125
* dw2gencfi.c (output_cfi_insn): Don't output DW_CFA_advance_loc+0.
* ehopt.c (eh_frame_estimate_size_before_relax): Return -1 for
an advance_loc of zero.
(eh_frame_relax_frag): Translate fr_subtype of 7 to size -1.
(eh_frame_convert_frag): Handle fr_subtype of 7. Abort on
unexpected fr_subtype.
2019-10-25 Alan Modra <amodra@gmail.com> 2019-10-25 Alan Modra <amodra@gmail.com>
PR gas/25125 PR gas/25125

View File

@ -1598,7 +1598,9 @@ output_cfi_insn (struct cfi_insn_data *insn)
addressT delta = S_GET_VALUE (to) - S_GET_VALUE (from); addressT delta = S_GET_VALUE (to) - S_GET_VALUE (from);
addressT scaled = delta / DWARF2_LINE_MIN_INSN_LENGTH; addressT scaled = delta / DWARF2_LINE_MIN_INSN_LENGTH;
if (scaled <= 0x3F) if (scaled == 0)
;
else if (scaled <= 0x3F)
out_one (DW_CFA_advance_loc + scaled); out_one (DW_CFA_advance_loc + scaled);
else if (scaled <= 0xFF) else if (scaled <= 0xFF)
{ {

View File

@ -482,7 +482,9 @@ eh_frame_estimate_size_before_relax (fragS *frag)
gas_assert (ca > 0); gas_assert (ca > 0);
diff /= ca; diff /= ca;
if (diff < 0x40) if (diff == 0)
ret = -1;
else if (diff < 0x40)
ret = 0; ret = 0;
else if (diff < 0x100) else if (diff < 0x100)
ret = 1; ret = 1;
@ -491,7 +493,7 @@ eh_frame_estimate_size_before_relax (fragS *frag)
else else
ret = 4; ret = 4;
frag->fr_subtype = (frag->fr_subtype & ~7) | ret; frag->fr_subtype = (frag->fr_subtype & ~7) | (ret & 7);
return ret; return ret;
} }
@ -506,6 +508,8 @@ eh_frame_relax_frag (fragS *frag)
int oldsize, newsize; int oldsize, newsize;
oldsize = frag->fr_subtype & 7; oldsize = frag->fr_subtype & 7;
if (oldsize == 7)
oldsize = -1;
newsize = eh_frame_estimate_size_before_relax (frag); newsize = eh_frame_estimate_size_before_relax (frag);
return newsize - oldsize; return newsize - oldsize;
} }
@ -548,9 +552,17 @@ eh_frame_convert_frag (fragS *frag)
md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 2); md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 2);
break; break;
default: case 4:
md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 4); md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 4);
break; break;
case 7:
gas_assert (diff == 0);
frag->fr_fix -= 8;
break;
default:
abort ();
} }
frag->fr_fix += frag->fr_subtype & 7; frag->fr_fix += frag->fr_subtype & 7;