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.
This commit is contained in:
David Faust 2024-04-25 11:40:31 -07:00
parent d3c2603167
commit dffb4a0784
7 changed files with 95 additions and 43 deletions

View File

@ -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;
}
}

View File

@ -8,10 +8,14 @@
Disassembly of section .text:
0+ <.*>:
0: 05 00 80 00 00 00 00 00 ja -32768
8: 05 00 7f ff 00 00 00 00 ja 32767
10: 05 00 ff fd 00 00 00 00 ja -3
18: 05 00 00 00 00 00 00 00 ja 0
0: 05 00 80 00 00 00 00 00 ja -32768
8: 05 00 7f ff 00 00 00 00 ja 32767
10: 05 00 ff fd 00 00 00 00 ja -3
18: 05 00 00 00 00 00 00 00 ja 0
18: R_BPF_GNU_64_16 undefined
20: 06 00 00 00 00 00 80 01 jal 32769
28: 06 00 00 00 00 00 80 01 jal 32769
20: 06 00 00 00 00 00 80 00 jal 32768
28: 05 00 7f ff 00 00 00 00 ja 32767
...
0+40028 <tail>:
40028: 06 00 00 00 ff ff 7f fa jal -32774

View File

@ -8,10 +8,14 @@
Disassembly of section .text:
0+ <.*>:
0: 05 00 00 80 00 00 00 00 ja -32768
8: 05 00 ff 7f 00 00 00 00 ja 32767
10: 05 00 fd ff 00 00 00 00 ja -3
18: 05 00 00 00 00 00 00 00 ja 0
0: 05 00 00 80 00 00 00 00 ja -32768
8: 05 00 ff 7f 00 00 00 00 ja 32767
10: 05 00 fd ff 00 00 00 00 ja -3
18: 05 00 00 00 00 00 00 00 ja 0
18: R_BPF_GNU_64_16 undefined
20: 06 00 00 00 01 80 00 00 jal 32769
28: 06 00 00 00 01 80 00 00 jal 32769
20: 06 00 00 00 00 80 00 00 jal 32768
28: 05 00 ff 7f 00 00 00 00 ja 32767
...
0+40028 <tail>:
40028: 06 00 00 00 fa 7f ff ff jal -32774

View File

@ -4,13 +4,18 @@
1: ja -32768
ja 32767
/* The following instruction refers to a defined symbol that
is on reach, so it should not be relaxed. */
is in reach, so it should not be relaxed. */
ja 1b
/* The following instruction has an undefined symbol as a
target. It is not to be relaxed. */
ja undefined + 10
/* The following instructions refer to a defined symbol that
is not on reach. They shall be relaxed to a JAL. */
/* The following instruction refers to a defined symbol that
is not in reach, so it shall be relaxed to JAL. */
ja tail
tail = .text + 262160
/* Now the symbol is in reach, and the following instruction
shall not be relaxed. */
ja tail
.space 262136
tail = .
/* The jump back is too large and shall be relaxed. */
ja 1b

View File

@ -8,12 +8,16 @@
Disassembly of section .text:
0+ <.*>:
0: 1d 12 80 00 00 00 00 00 jeq %r1,%r2,-32768
8: ad 12 7f ff 00 00 00 00 jlt %r1,%r2,32767
10: bd 12 ff fd 00 00 00 00 jle %r1,%r2,-3
18: 1d 12 00 01 00 00 00 00 jeq %r1,%r2,1
20: 05 00 00 01 00 00 00 00 ja 1
28: 06 00 00 00 00 00 80 01 jal 32769
30: 2d 12 00 01 00 00 00 00 jgt %r1,%r2,1
38: 05 00 00 01 00 00 00 00 ja 1
40: 06 00 00 00 00 00 80 01 jal 32769
0: 1d 12 80 00 00 00 00 00 jeq %r1,%r2,-32768
8: ad 12 7f ff 00 00 00 00 jlt %r1,%r2,32767
10: bd 12 ff fd 00 00 00 00 jle %r1,%r2,-3
18: 1d 12 00 01 00 00 00 00 jeq %r1,%r2,1
20: 05 00 00 01 00 00 00 00 ja 1
28: 06 00 00 00 00 00 80 00 jal 32768
30: 2d 12 7f ff 00 00 00 00 jgt %r1,%r2,32767
...
0+40030 <tail>:
40030: 55 10 00 01 00 00 00 00 jne %r1,0,1
40038: 05 00 00 01 00 00 00 00 ja 1
40040: 06 00 00 00 ff ff 7f f7 jal -32777

View File

@ -8,12 +8,16 @@
Disassembly of section .text:
0+ <.*>:
0: 1d 21 00 80 00 00 00 00 jeq %r1,%r2,-32768
8: ad 21 ff 7f 00 00 00 00 jlt %r1,%r2,32767
10: bd 21 fd ff 00 00 00 00 jle %r1,%r2,-3
18: 1d 21 01 00 00 00 00 00 jeq %r1,%r2,1
20: 05 00 01 00 00 00 00 00 ja 1
28: 06 00 00 00 01 80 00 00 jal 32769
30: 2d 21 01 00 00 00 00 00 jgt %r1,%r2,1
38: 05 00 01 00 00 00 00 00 ja 1
40: 06 00 00 00 01 80 00 00 jal 32769
0: 1d 21 00 80 00 00 00 00 jeq %r1,%r2,-32768
8: ad 21 ff 7f 00 00 00 00 jlt %r1,%r2,32767
10: bd 21 fd ff 00 00 00 00 jle %r1,%r2,-3
18: 1d 21 01 00 00 00 00 00 jeq %r1,%r2,1
20: 05 00 01 00 00 00 00 00 ja 1
28: 06 00 00 00 00 80 00 00 jal 32768
30: 2d 21 ff 7f 00 00 00 00 jgt %r1,%r2,32767
...
0+40030 <tail>:
40030: 55 01 01 00 00 00 00 00 jne %r1,0,1
40038: 05 00 01 00 00 00 00 00 ja 1
40040: 06 00 00 00 f7 7f ff ff jal -32777

View File

@ -2,11 +2,13 @@
fix in the jump 16-bit signed displacement operand. */
1: jeq %r1, %r2, -32768
jlt %r1, %r2, 32767
/* The following instruction refers to a defined symbol that
is on reach, so it should not be relaxed. */
/* The following instructions refer to defined symbols that
are in reach, so they should not be relaxed. */
jle %r1, %r2, 1b
/* The following instructions refer to a defined symbol that
is not on reach. They shall be relaxed. */
jeq %r1, %r2, tail
tail = .text + 262160
jgt %r1, %r2, tail
/* The following instructions refers to defined symbols that
are not in reach, so they shall be relaxied. */
.space 262136
tail = .
jne %r1, 0, 1b