aboutsummaryrefslogtreecommitdiff
path: root/gas/config
diff options
context:
space:
mode:
authorDavid Faust <david.faust@oracle.com>2024-04-25 11:40:31 -0700
committerDavid Faust <david.faust@oracle.com>2024-04-25 13:16:34 -0700
commitdffb4a0784f401c2aa20446abb651a4e19f34a44 (patch)
treeeee62fd09beed5d19910f2ee60ef213345edb382 /gas/config
parentd3c2603167baf9f6fea006f8b747b8186f89b177 (diff)
downloadfsf-binutils-gdb-dffb4a0784f401c2aa20446abb651a4e19f34a44.zip
fsf-binutils-gdb-dffb4a0784f401c2aa20446abb651a4e19f34a44.tar.gz
fsf-binutils-gdb-dffb4a0784f401c2aa20446abb651a4e19f34a44.tar.bz2
bpf: fix calculation when deciding to relax branch
In certain cases we were calculating the jump displacement incorrectly when deciding whether to relax a branch. This meant for some branches, such as a very long backwards conditional branch, relaxation was not done when it should have been. The result was to error later, because the actual jump displacement was too large to fit in the original instruction. This patch fixes up the displacement calculation so that those branches are correctly relaxed and no longer result in an error. In addition, it changes md_convert_frag to install fixups for the JAL instructions in the resulting relaxations rather than encoding the displacement value directly. gas/ * config/tc-bpf.c (relaxed_branch_length): Correct displacement calculation when relaxing. (md_convert_frag): Likewise. Install fixups for JAL instructions resulting from relaxation. * testsuite/gas/bpf/jump-relax-ja-be.d: Correct and expand test. * testsuite/gas/bpf/jump-relax-ja.d: Likewise. * testsuite/gas/bpf/jump-relax-ja.s: Likewise. * testsuite/gas/bpf/jump-relax-jump-be.d: Likewise. * testsuite/gas/bpf/jump-relax-jump.d: Likewise. * testsuite/gas/bpf/jump-relax-jump.s: Likewise.
Diffstat (limited to 'gas/config')
-rw-r--r--gas/config/tc-bpf.c37
1 files changed, 33 insertions, 4 deletions
diff --git a/gas/config/tc-bpf.c b/gas/config/tc-bpf.c
index dfa44ea..effb483 100644
--- a/gas/config/tc-bpf.c
+++ b/gas/config/tc-bpf.c
@@ -434,6 +434,7 @@ relaxed_branch_length (fragS *fragp, asection *sec, int update)
&& sec == S_GET_SEGMENT (fragp->fr_symbol))
{
offsetT val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset;
+ val -= fragp->fr_address + fragp->fr_fix;
/* Convert to 64-bit words, minus one. */
val = (val - 8) / 8;
@@ -578,6 +579,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
&& sec == S_GET_SEGMENT (fragp->fr_symbol))
{
offsetT val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset;
+ val -= fragp->fr_address + fragp->fr_fix;
/* Convert to 64-bit blocks minus one. */
disp_to_target = (val - 8) / 8;
disp_is_known = 1;
@@ -626,15 +628,27 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
{
/* 16-bit disp is known and not in range. Turn the JA
into a JAL with a 32-bit displacement. */
- char bytes[8];
+ char bytes[8] = {0};
bytes[0] = ((BPF_CLASS_JMP32|BPF_CODE_JA|BPF_SRC_K) >> 56) & 0xff;
bytes[1] = (word >> 48) & 0xff;
bytes[2] = 0; /* disp16 high */
bytes[3] = 0; /* disp16 lo */
- encode_int32 ((int32_t) disp_to_target, bytes + 4);
-
write_insn_bytes (buf, bytes);
+
+ /* Install fixup for the JAL. */
+ reloc_howto_type *reloc_howto
+ = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_BPF_DISP32);
+ if (!reloc_howto)
+ abort();
+
+ fixp = fix_new_exp (fragp, buf - (bfd_byte *) fragp->fr_literal,
+ bfd_get_reloc_size (reloc_howto),
+ &exp,
+ reloc_howto->pc_relative,
+ BFD_RELOC_BPF_DISP32);
+ fixp->fx_file = fragp->fr_file;
+ fixp->fx_line = fragp->fr_line;
}
}
else
@@ -731,8 +745,23 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
bytes[1] = 0;
bytes[2] = 0;
bytes[3] = 0;
- encode_int32 ((int32_t) disp_to_target, bytes + 4);
+ encode_int32 ((int32_t) 0, bytes + 4);
write_insn_bytes (buf, bytes);
+
+ /* Install fixup for the JAL. */
+ reloc_howto_type *reloc_howto
+ = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_BPF_DISP32);
+ if (!reloc_howto)
+ abort();
+
+ fixp = fix_new_exp (fragp, buf - (bfd_byte *) fragp->fr_literal,
+ bfd_get_reloc_size (reloc_howto),
+ &exp,
+ reloc_howto->pc_relative,
+ BFD_RELOC_BPF_DISP32);
+ fixp->fx_file = fragp->fr_file;
+ fixp->fx_line = fragp->fr_line;
+
buf += 8;
}
}