aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJose E. Marchesi <jose.marchesi@oracle.com>2023-07-30 21:01:03 +0200
committerJose E. Marchesi <jose.marchesi@oracle.com>2023-07-30 21:08:14 +0200
commit0346042938539324a5052cc09023c1fe426e8b31 (patch)
treea23d300951c394601cb51ceeef7719a8788b962c
parent82be476a08a2d6ee787af9a463386fab5dd85fdd (diff)
downloadbinutils-0346042938539324a5052cc09023c1fe426e8b31.zip
binutils-0346042938539324a5052cc09023c1fe426e8b31.tar.gz
binutils-0346042938539324a5052cc09023c1fe426e8b31.tar.bz2
bpf: gas: add field overflow checking to the BPF assembler
This patch makes the BPF assembler to throughfully check for overflow in immediates. This includes relaxed instructions. Tested in bpf-unknown-none. gas/ChangeLog: 2023-07-30 Jose E. Marchesi <jose.marchesi@oracle.com> * config/tc-bpf.c (signed_overflow): Copy function from tc-aarch64.c. (encode_insn): Check for overflow in constant immediates. (add_relaxed_insn): Pass relax argument to encode_insn. (add_fixed_insn): Likewise. * testsuite/gas/bpf/disp16-overflow.d: New file. * testsuite/gas/bpf/disp16-overflow.s: Likewise. * testsuite/gas/bpf/disp16-overflow.l: Likewise. * testsuite/gas/bpf/disp32-overflow.d: Likewise. * testsuite/gas/bpf/disp32-overflow.s: Likewise. * testsuite/gas/bpf/disp32-overflow.l: Likewise. * testsuite/gas/bpf/imm32-overflow.d: Likewise. * testsuite/gas/bpf/imm32-overflow.s: Likewise. * testsuite/gas/bpf/imm32-overflow.l: Likewise. * testsuite/gas/bpf/offset16-overflow.d: Likewise. * testsuite/gas/bpf/offset16-overflow.s: Likewise. * testsuite/gas/bpf/offset16-overflow.l: Likewise. * testsuite/gas/bpf/disp16-overflow-relax.d: Likewise. * testsuite/gas/bpf/disp16-overflow-relax.l: Likewise. * testsuite/gas/bpf/disp16-overflow-relax.s: Likewise. * testsuite/gas/bpf/jump-relax-jump-be.d: New file. * testsuite/gas/bpf/bpf.exp: Run new tests.
-rw-r--r--gas/ChangeLog25
-rw-r--r--gas/config/tc-bpf.c63
-rw-r--r--gas/testsuite/gas/bpf/bpf.exp7
-rw-r--r--gas/testsuite/gas/bpf/disp16-overflow-relax.d3
-rw-r--r--gas/testsuite/gas/bpf/disp16-overflow-relax.l3
-rw-r--r--gas/testsuite/gas/bpf/disp16-overflow-relax.s4
-rw-r--r--gas/testsuite/gas/bpf/disp16-overflow.d3
-rw-r--r--gas/testsuite/gas/bpf/disp16-overflow.l3
-rw-r--r--gas/testsuite/gas/bpf/disp16-overflow.s4
-rw-r--r--gas/testsuite/gas/bpf/disp32-overflow.d3
-rw-r--r--gas/testsuite/gas/bpf/disp32-overflow.l3
-rw-r--r--gas/testsuite/gas/bpf/disp32-overflow.s4
-rw-r--r--gas/testsuite/gas/bpf/imm32-overflow.d3
-rw-r--r--gas/testsuite/gas/bpf/imm32-overflow.l3
-rw-r--r--gas/testsuite/gas/bpf/imm32-overflow.s4
-rw-r--r--gas/testsuite/gas/bpf/jump-relax-jump-be.d25
-rw-r--r--gas/testsuite/gas/bpf/offset16-overflow.d3
-rw-r--r--gas/testsuite/gas/bpf/offset16-overflow.l3
-rw-r--r--gas/testsuite/gas/bpf/offset16-overflow.s4
19 files changed, 162 insertions, 8 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 1f3735d..ab139a9 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,28 @@
+2023-07-30 Jose E. Marchesi <jose.marchesi@oracle.com>
+
+ * config/tc-bpf.c (signed_overflow): Copy function from
+ tc-aarch64.c.
+ (encode_insn): Check for overflow in constant immediates.
+ (add_relaxed_insn): Pass relax argument to encode_insn.
+ (add_fixed_insn): Likewise.
+ * testsuite/gas/bpf/disp16-overflow.d: New file.
+ * testsuite/gas/bpf/disp16-overflow.s: Likewise.
+ * testsuite/gas/bpf/disp16-overflow.l: Likewise.
+ * testsuite/gas/bpf/disp32-overflow.d: Likewise.
+ * testsuite/gas/bpf/disp32-overflow.s: Likewise.
+ * testsuite/gas/bpf/disp32-overflow.l: Likewise.
+ * testsuite/gas/bpf/imm32-overflow.d: Likewise.
+ * testsuite/gas/bpf/imm32-overflow.s: Likewise.
+ * testsuite/gas/bpf/imm32-overflow.l: Likewise.
+ * testsuite/gas/bpf/offset16-overflow.d: Likewise.
+ * testsuite/gas/bpf/offset16-overflow.s: Likewise.
+ * testsuite/gas/bpf/offset16-overflow.l: Likewise.
+ * testsuite/gas/bpf/disp16-overflow-relax.d: Likewise.
+ * testsuite/gas/bpf/disp16-overflow-relax.l: Likewise.
+ * testsuite/gas/bpf/disp16-overflow-relax.s: Likewise.
+ * testsuite/gas/bpf/jump-relax-jump-be.d: New file.
+ * testsuite/gas/bpf/bpf.exp: Run new tests.
+
2023-07-28 Jose E. Marchesi <jose.marchesi@oracle.com>
PR gas/30690
diff --git a/gas/config/tc-bpf.c b/gas/config/tc-bpf.c
index 230e499..7e1bd5d 100644
--- a/gas/config/tc-bpf.c
+++ b/gas/config/tc-bpf.c
@@ -272,6 +272,20 @@ md_section_align (segT segment, valueT size)
return ((size + (1 << align) - 1) & -(1 << align));
}
+/* Return non-zero if the indicated VALUE has overflowed the maximum
+ range expressible by an signed number with the indicated number of
+ BITS. */
+
+static bool
+signed_overflow (offsetT value, unsigned bits)
+{
+ offsetT lim;
+ if (bits >= sizeof (offsetT) * 8)
+ return false;
+ lim = (offsetT) 1 << (bits - 1);
+ return (value < -lim || value >= lim);
+}
+
/* Functions concerning relocs. */
@@ -549,6 +563,11 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
disp_is_known = 1;
}
+ /* The displacement should fit in a signed 32-bit number. */
+ if (disp_is_known && signed_overflow (disp_to_target, 32))
+ as_bad_where (fragp->fr_file, fragp->fr_line,
+ _("signed instruction operand out of range, shall fit in 32 bits"));
+
/* Now relax particular jump instructions. */
if (code == BPF_CODE_JA)
{
@@ -835,7 +854,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
immediates are encoded as zeroes. */
static void
-encode_insn (struct bpf_insn *insn, char *bytes)
+encode_insn (struct bpf_insn *insn, char *bytes, int relaxed)
{
uint8_t src, dst;
@@ -889,16 +908,44 @@ encode_insn (struct bpf_insn *insn, char *bytes)
/* Now the immediates that are known to be constant. */
if (insn->has_imm32 && insn->imm32.X_op == O_constant)
- encode_int32 (insn->imm32.X_add_number, bytes + 4);
+ {
+ int64_t imm = insn->imm32.X_add_number;
+
+ if (signed_overflow (imm, 32))
+ as_bad (_("signed immediate out of range, shall fit in 32 bits"));
+ else
+ encode_int32 (insn->imm32.X_add_number, bytes + 4);
+ }
if (insn->has_disp32 && insn->disp32.X_op == O_constant)
- encode_int32 (insn->disp32.X_add_number, bytes + 4);
+ {
+ int64_t disp = insn->disp32.X_add_number;
+
+ if (signed_overflow (disp, 32))
+ as_bad (_("signed pc-relative offset out of range, shall fit in 32 bits"));
+ else
+ encode_int32 (insn->disp32.X_add_number, bytes + 4);
+ }
if (insn->has_offset16 && insn->offset16.X_op == O_constant)
- encode_int16 (insn->offset16.X_add_number, bytes + 2);
+ {
+ int64_t offset = insn->offset16.X_add_number;
+
+ if (signed_overflow (offset, 16))
+ as_bad (_("signed pc-relative offset out of range, shall fit in 16 bits"));
+ else
+ encode_int16 (insn->offset16.X_add_number, bytes + 2);
+ }
if (insn->has_disp16 && insn->disp16.X_op == O_constant)
- encode_int16 (insn->disp16.X_add_number, bytes + 2);
+ {
+ int64_t disp = insn->disp16.X_add_number;
+
+ if (!relaxed && signed_overflow (disp, 16))
+ as_bad (_("signed pc-relative offset out of range, shall fit in 16 bits"));
+ else
+ encode_int16 (insn->disp16.X_add_number, bytes + 2);
+ }
if (insn->has_imm64 && insn->imm64.X_op == O_constant)
{
@@ -1105,7 +1152,7 @@ add_fixed_insn (struct bpf_insn *insn)
/* First encode the known parts of the instruction, including
opcodes and constant immediates, and write them to the frag. */
- encode_insn (insn, bytes);
+ encode_insn (insn, bytes, 0 /* relax */);
for (i = 0; i < insn->size; ++i)
md_number_to_chars (this_frag + i, (valueT) bytes[i], 1);
@@ -1136,7 +1183,7 @@ add_relaxed_insn (struct bpf_insn *insn, expressionS *exp)
/* First encode the known parts of the instruction, including
opcodes and constant immediates, and write them to the frag. */
- encode_insn (insn, bytes);
+ encode_insn (insn, bytes, 1 /* relax */);
for (i = 0; i < insn->size; ++i)
md_number_to_chars (this_frag + i, (valueT) bytes[i], 1);
@@ -1555,7 +1602,7 @@ md_assemble (char *str ATTRIBUTE_UNUSED)
#undef PARSE_ERROR
/* Generate the frags and fixups for the parsed instruction. */
- if (do_relax && insn.is_relaxable)
+ if (do_relax && isa_spec >= BPF_V4 && insn.is_relaxable)
{
expressionS *relaxable_exp = NULL;
diff --git a/gas/testsuite/gas/bpf/bpf.exp b/gas/testsuite/gas/bpf/bpf.exp
index 6e6a000..80f5a1d 100644
--- a/gas/testsuite/gas/bpf/bpf.exp
+++ b/gas/testsuite/gas/bpf/bpf.exp
@@ -65,4 +65,11 @@ if {[istarget bpf*-*-*]} {
run_dump_test jump-relax-ja-be
run_dump_test jump-relax-jump-be
+
+ # Overflow tests
+ run_dump_test offset16-overflow
+ run_dump_test disp16-overflow
+ run_dump_test disp16-overflow-relax
+ run_dump_test disp32-overflow
+ run_dump_test imm32-overflow
}
diff --git a/gas/testsuite/gas/bpf/disp16-overflow-relax.d b/gas/testsuite/gas/bpf/disp16-overflow-relax.d
new file mode 100644
index 0000000..051e2fa
--- /dev/null
+++ b/gas/testsuite/gas/bpf/disp16-overflow-relax.d
@@ -0,0 +1,3 @@
+#as: -EL -misa-spec=v4
+#source: disp16-overflow-relax.s
+#error_output: disp16-overflow-relax.l
diff --git a/gas/testsuite/gas/bpf/disp16-overflow-relax.l b/gas/testsuite/gas/bpf/disp16-overflow-relax.l
new file mode 100644
index 0000000..ca572cb
--- /dev/null
+++ b/gas/testsuite/gas/bpf/disp16-overflow-relax.l
@@ -0,0 +1,3 @@
+.*: Assembler messages:
+.*:2: Error: signed instruction operand out of range, shall fit in 32 bits
+.*:4: Error: signed instruction operand out of range, shall fit in 32 bits
diff --git a/gas/testsuite/gas/bpf/disp16-overflow-relax.s b/gas/testsuite/gas/bpf/disp16-overflow-relax.s
new file mode 100644
index 0000000..3953992
--- /dev/null
+++ b/gas/testsuite/gas/bpf/disp16-overflow-relax.s
@@ -0,0 +1,4 @@
+ jeq %r1,%r2,2147483647
+ jlt %r3,%r4,2147483648 ; Overflows.
+ jge %r5,10,-2147483648
+ ja -2147483649 ; Overflows.
diff --git a/gas/testsuite/gas/bpf/disp16-overflow.d b/gas/testsuite/gas/bpf/disp16-overflow.d
new file mode 100644
index 0000000..5a0094f
--- /dev/null
+++ b/gas/testsuite/gas/bpf/disp16-overflow.d
@@ -0,0 +1,3 @@
+#as: -EL -mno-relax
+#source: disp16-overflow.s
+#error_output: disp16-overflow.l
diff --git a/gas/testsuite/gas/bpf/disp16-overflow.l b/gas/testsuite/gas/bpf/disp16-overflow.l
new file mode 100644
index 0000000..6404b1b
--- /dev/null
+++ b/gas/testsuite/gas/bpf/disp16-overflow.l
@@ -0,0 +1,3 @@
+.*: Assembler messages:
+.*:2: Error: signed pc-relative offset out of range, shall fit in 16 bits
+.*:4: Error: signed pc-relative offset out of range, shall fit in 16 bits
diff --git a/gas/testsuite/gas/bpf/disp16-overflow.s b/gas/testsuite/gas/bpf/disp16-overflow.s
new file mode 100644
index 0000000..ab66753
--- /dev/null
+++ b/gas/testsuite/gas/bpf/disp16-overflow.s
@@ -0,0 +1,4 @@
+ ja 32767
+ jeq %r1,%r2,32768 ; Overflows
+ jlt %r3,%r4,-32768
+ jge %r5,10,-32769 ; Overflows
diff --git a/gas/testsuite/gas/bpf/disp32-overflow.d b/gas/testsuite/gas/bpf/disp32-overflow.d
new file mode 100644
index 0000000..09fa189
--- /dev/null
+++ b/gas/testsuite/gas/bpf/disp32-overflow.d
@@ -0,0 +1,3 @@
+#as: -EL
+#source: disp32-overflow.s
+#error_output: disp32-overflow.l
diff --git a/gas/testsuite/gas/bpf/disp32-overflow.l b/gas/testsuite/gas/bpf/disp32-overflow.l
new file mode 100644
index 0000000..8a6b647
--- /dev/null
+++ b/gas/testsuite/gas/bpf/disp32-overflow.l
@@ -0,0 +1,3 @@
+.*: Assembler messages:
+.*:2: Error: signed pc-relative offset out of range, shall fit in 32 bits
+.*:4: Error: signed pc-relative offset out of range, shall fit in 32 bits
diff --git a/gas/testsuite/gas/bpf/disp32-overflow.s b/gas/testsuite/gas/bpf/disp32-overflow.s
new file mode 100644
index 0000000..03a0d97
--- /dev/null
+++ b/gas/testsuite/gas/bpf/disp32-overflow.s
@@ -0,0 +1,4 @@
+ call -2147483648
+ call -2147483649 ; This overflows.
+ call 2147483647
+ call 2147483648 ; This overflows.
diff --git a/gas/testsuite/gas/bpf/imm32-overflow.d b/gas/testsuite/gas/bpf/imm32-overflow.d
new file mode 100644
index 0000000..c8e35a9
--- /dev/null
+++ b/gas/testsuite/gas/bpf/imm32-overflow.d
@@ -0,0 +1,3 @@
+#as: -EL
+#source: imm32-overflow.s
+#error_output: imm32-overflow.l
diff --git a/gas/testsuite/gas/bpf/imm32-overflow.l b/gas/testsuite/gas/bpf/imm32-overflow.l
new file mode 100644
index 0000000..f6691c4
--- /dev/null
+++ b/gas/testsuite/gas/bpf/imm32-overflow.l
@@ -0,0 +1,3 @@
+.*: Assembler messages:
+.*:2: Error: signed immediate out of range, shall fit in 32 bits
+.*:4: Error: signed immediate out of range, shall fit in 32 bits
diff --git a/gas/testsuite/gas/bpf/imm32-overflow.s b/gas/testsuite/gas/bpf/imm32-overflow.s
new file mode 100644
index 0000000..5cb858c
--- /dev/null
+++ b/gas/testsuite/gas/bpf/imm32-overflow.s
@@ -0,0 +1,4 @@
+ add %r1, 2147483647
+ or %r2, 2147483648 ; This overflows.
+ xor %r3, -2147483648
+ sub %r4, -2147483649 ; This overflows.
diff --git a/gas/testsuite/gas/bpf/jump-relax-jump-be.d b/gas/testsuite/gas/bpf/jump-relax-jump-be.d
new file mode 100644
index 0000000..5626d56
--- /dev/null
+++ b/gas/testsuite/gas/bpf/jump-relax-jump-be.d
@@ -0,0 +1,25 @@
+#as: -EB -mdialect=normal
+#objdump: -dr -M dec
+#source: jump-relax-jump.s
+#name: Relaxation of conditional branch instructions, big-endian
+
+.*: +file format .*bpf.*
+
+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: 3d 12 00 01 00 00 00 00 jge %r1,%r2,1
+ 20: 05 00 00 01 00 00 00 00 ja 1
+ 28: 06 00 00 00 ff ff 7f ff 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 00 jal 32768
+ 48: 1d 12 00 01 00 00 00 00 jeq %r1,%r2,1
+ 50: 05 00 00 01 00 00 00 00 ja 1
+ 58: 06 00 00 00 00 00 80 01 jal 32769
+ 60: 2d 12 00 01 00 00 00 00 jgt %r1,%r2,1
+ 68: 05 00 00 01 00 00 00 00 ja 1
+ 70: 06 00 00 00 00 00 80 01 jal 32769
diff --git a/gas/testsuite/gas/bpf/offset16-overflow.d b/gas/testsuite/gas/bpf/offset16-overflow.d
new file mode 100644
index 0000000..102edca
--- /dev/null
+++ b/gas/testsuite/gas/bpf/offset16-overflow.d
@@ -0,0 +1,3 @@
+#as: -EL
+#source: offset16-overflow.s
+#error_output: offset16-overflow.l
diff --git a/gas/testsuite/gas/bpf/offset16-overflow.l b/gas/testsuite/gas/bpf/offset16-overflow.l
new file mode 100644
index 0000000..6404b1b
--- /dev/null
+++ b/gas/testsuite/gas/bpf/offset16-overflow.l
@@ -0,0 +1,3 @@
+.*: Assembler messages:
+.*:2: Error: signed pc-relative offset out of range, shall fit in 16 bits
+.*:4: Error: signed pc-relative offset out of range, shall fit in 16 bits
diff --git a/gas/testsuite/gas/bpf/offset16-overflow.s b/gas/testsuite/gas/bpf/offset16-overflow.s
new file mode 100644
index 0000000..da9f633
--- /dev/null
+++ b/gas/testsuite/gas/bpf/offset16-overflow.s
@@ -0,0 +1,4 @@
+ ldxh %r2, [%r1 + 32767]
+ ldxw %r2, [%r1 + 32768] ; This overflows
+ stxw [%r2 - 32768], %r1
+ stxdw [%r2 - 32769], %r1 ; This overflows