aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2019-10-26 18:38:26 +1030
committerAlan Modra <amodra@gmail.com>2019-10-26 20:19:28 +1030
commit6f69abb0498286297936a178ba81c7e445aa4437 (patch)
tree7a5d73d08dad01d2423566cffb48b48cda5971a1 /gas
parent30baf67b6505d903bf678f9a0ba3645eb337ce49 (diff)
downloadfsf-binutils-gdb-6f69abb0498286297936a178ba81c7e445aa4437.zip
fsf-binutils-gdb-6f69abb0498286297936a178ba81c7e445aa4437.tar.gz
fsf-binutils-gdb-6f69abb0498286297936a178ba81c7e445aa4437.tar.bz2
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.
Diffstat (limited to 'gas')
-rw-r--r--gas/ChangeLog10
-rw-r--r--gas/dw2gencfi.c4
-rw-r--r--gas/ehopt.c18
3 files changed, 28 insertions, 4 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 8b78037..f900c26 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -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>
PR gas/25125
diff --git a/gas/dw2gencfi.c b/gas/dw2gencfi.c
index 388123f..b01e4c4 100644
--- a/gas/dw2gencfi.c
+++ b/gas/dw2gencfi.c
@@ -1598,7 +1598,9 @@ output_cfi_insn (struct cfi_insn_data *insn)
addressT delta = S_GET_VALUE (to) - S_GET_VALUE (from);
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);
else if (scaled <= 0xFF)
{
diff --git a/gas/ehopt.c b/gas/ehopt.c
index 207e799..bf65602 100644
--- a/gas/ehopt.c
+++ b/gas/ehopt.c
@@ -482,7 +482,9 @@ eh_frame_estimate_size_before_relax (fragS *frag)
gas_assert (ca > 0);
diff /= ca;
- if (diff < 0x40)
+ if (diff == 0)
+ ret = -1;
+ else if (diff < 0x40)
ret = 0;
else if (diff < 0x100)
ret = 1;
@@ -491,7 +493,7 @@ eh_frame_estimate_size_before_relax (fragS *frag)
else
ret = 4;
- frag->fr_subtype = (frag->fr_subtype & ~7) | ret;
+ frag->fr_subtype = (frag->fr_subtype & ~7) | (ret & 7);
return ret;
}
@@ -506,6 +508,8 @@ eh_frame_relax_frag (fragS *frag)
int oldsize, newsize;
oldsize = frag->fr_subtype & 7;
+ if (oldsize == 7)
+ oldsize = -1;
newsize = eh_frame_estimate_size_before_relax (frag);
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);
break;
- default:
+ case 4:
md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 4);
break;
+
+ case 7:
+ gas_assert (diff == 0);
+ frag->fr_fix -= 8;
+ break;
+
+ default:
+ abort ();
}
frag->fr_fix += frag->fr_subtype & 7;