From 5be1b787276d2adbe85ae7febc709ca517b62f08 Mon Sep 17 00:00:00 2001 From: "Jose E. Marchesi" Date: Thu, 17 Aug 2023 09:38:37 +0200 Subject: [PATCH] bpf: gas: consolidate handling of immediate overflows This commit changes the BPF GAS port in order to handle immediate overflows the same way than the clang BPF assembler: - For an immediate field of N bits, any written number (positive or negative) whose two's complement encoding fit in N its is accepted. This means that -2 is the same than 0xffffffe. It is up to the instructions to decide how to interpret the encoded value. - Immediate fields in jump instructions are no longer relaxed. Relaxing to jump instructions with wider range is only performed when expressions are involved. - The manual is updated to document this, and testsuite adapted accordingly. Tested in x86_64-linux-gnu host, bpf-unknown-none target. gas/ChangeLog: 2023-08-17 Jose E. Marchesi * config/tc-bpf.c (check_immediate_overflow): New function. (encode_insn): Use check_immediate_overflow. (md_assemble): Do not relax instructions with constant disp16 fields. * doc/c-bpf.texi (BPF Instructions): Add note about how numerical literal values are interpreted for instruction immediate operands. * testsuite/gas/bpf/disp16-overflow.s: Adapt accordingly. * testsuite/gas/bpf/jump-relax-jump.s: Likewise. * testsuite/gas/bpf/jump-relax-jump.d: Likewise. * testsuite/gas/bpf/jump-relax-jump-be.d: Likewise. * testsuite/gas/bpf/jump-relax-ja.s: Likewise. * testsuite/gas/bpf/jump-relax-ja.d: Likewise. * testsuite/gas/bpf/jump-relax-ja-be.d: Likewise. * testsuite/gas/bpf/disp16-overflow-relax.l: Likewise. * testsuite/gas/bpf/imm32-overflow.s: Likewise. * testsuite/gas/bpf/disp32-overflow.s: Likewise. * testsuite/gas/bpf/disp16-overflow.l: Likewise. * testsuite/gas/bpf/disp32-overflow.l: Likewise. * testsuite/gas/bpf/imm32-overflow.l: Likewise. * testsuite/gas/bpf/offset16-overflow.l: Likewise. --- gas/ChangeLog | 23 ++++++++++ gas/config/tc-bpf.c | 43 ++++++++++++++----- gas/config/tc-sparc.c | 2 +- gas/doc/c-bpf.texi | 8 ++++ gas/testsuite/gas/bpf/disp16-overflow-relax.l | 6 ++- gas/testsuite/gas/bpf/disp16-overflow-relax.s | 4 +- gas/testsuite/gas/bpf/disp16-overflow.l | 4 +- gas/testsuite/gas/bpf/disp16-overflow.s | 2 +- gas/testsuite/gas/bpf/disp32-overflow.l | 4 +- gas/testsuite/gas/bpf/disp32-overflow.s | 4 +- gas/testsuite/gas/bpf/imm32-overflow.l | 4 +- gas/testsuite/gas/bpf/imm32-overflow.s | 6 +-- gas/testsuite/gas/bpf/jump-relax-ja-be.d | 6 +-- gas/testsuite/gas/bpf/jump-relax-ja.d | 6 +-- gas/testsuite/gas/bpf/jump-relax-ja.s | 4 -- gas/testsuite/gas/bpf/jump-relax-jump-be.d | 12 ++---- gas/testsuite/gas/bpf/jump-relax-jump.d | 12 ++---- gas/testsuite/gas/bpf/jump-relax-jump.s | 5 --- gas/testsuite/gas/bpf/offset16-overflow.l | 4 +- gas/testsuite/gas/bpf/offset16-overflow.s | 4 +- 20 files changed, 96 insertions(+), 67 deletions(-) diff --git a/gas/ChangeLog b/gas/ChangeLog index 26d7dc1623b..3339c4cadd3 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,26 @@ +2023-08-17 Jose E. Marchesi + + * config/tc-bpf.c (check_immediate_overflow): New function. + (encode_insn): Use check_immediate_overflow. + (md_assemble): Do not relax instructions with + constant disp16 fields. + * doc/c-bpf.texi (BPF Instructions): Add note about how numerical + literal values are interpreted for instruction immediate operands. + * testsuite/gas/bpf/disp16-overflow.s: Adapt accordingly. + * testsuite/gas/bpf/jump-relax-jump.s: Likewise. + * testsuite/gas/bpf/jump-relax-jump.d: Likewise. + * testsuite/gas/bpf/jump-relax-jump-be.d: Likewise. + * testsuite/gas/bpf/jump-relax-ja.s: Likewise. + * testsuite/gas/bpf/jump-relax-ja.d: Likewise. + * testsuite/gas/bpf/jump-relax-ja-be.d: Likewise. + * testsuite/gas/bpf/disp16-overflow-relax.l: Likewise. + * testsuite/gas/bpf/imm32-overflow.s: Likewise. + * testsuite/gas/bpf/disp32-overflow.s: Likewise. + * testsuite/gas/bpf/disp16-overflow.l: Likewise. + * testsuite/gas/bpf/disp32-overflow.l: Likewise. + * testsuite/gas/bpf/imm32-overflow.l: Likewise. + * testsuite/gas/bpf/offset16-overflow.l: Likewise. + 2023-07-30 Jose E. Marchesi * config/tc-bpf.h (elf_tc_final_processing): Define. diff --git a/gas/config/tc-bpf.c b/gas/config/tc-bpf.c index b4566d89ddf..cdde05c9139 100644 --- a/gas/config/tc-bpf.c +++ b/gas/config/tc-bpf.c @@ -286,6 +286,26 @@ signed_overflow (offsetT value, unsigned bits) return (value < -lim || value >= lim); } +/* Return non-zero if the two's complement encoding of VALUE would + overflow an immediate field of width BITS bits. */ + +static bool +immediate_overflow (int64_t value, unsigned bits) +{ + if (value < 0) + return signed_overflow (value, bits); + else + { + valueT lim; + + if (bits >= sizeof (valueT) * 8) + return false; + + lim = (valueT) 1 << bits; + return ((valueT) value >= lim); + } +} + /* Functions concerning relocs. */ @@ -379,7 +399,7 @@ tc_gen_reloc (asection *sec ATTRIBUTE_UNUSED, fixS *fixP) #define RELAX_BRANCH_UNCOND(i) (((i) & 1) != 0) -/* Compute the length of a branch seuqence, and adjust the stored +/* Compute the length of a branch sequence, and adjust the stored length accordingly. If FRAG is NULL, the worst-case length is returned. */ @@ -854,7 +874,8 @@ 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, int relaxed) +encode_insn (struct bpf_insn *insn, char *bytes, + int relaxed ATTRIBUTE_UNUSED) { uint8_t src, dst; @@ -911,8 +932,8 @@ encode_insn (struct bpf_insn *insn, char *bytes, int relaxed) { 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")); + if (immediate_overflow (imm, 32)) + as_bad (_("immediate out of range, shall fit in 32 bits")); else encode_int32 (insn->imm32.X_add_number, bytes + 4); } @@ -921,8 +942,8 @@ encode_insn (struct bpf_insn *insn, char *bytes, int relaxed) { 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")); + if (immediate_overflow (disp, 32)) + as_bad (_("pc-relative offset out of range, shall fit in 32 bits")); else encode_int32 (insn->disp32.X_add_number, bytes + 4); } @@ -931,8 +952,8 @@ encode_insn (struct bpf_insn *insn, char *bytes, int relaxed) { 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")); + if (immediate_overflow (offset, 16)) + as_bad (_("pc-relative offset out of range, shall fit in 16 bits")); else encode_int16 (insn->offset16.X_add_number, bytes + 2); } @@ -941,8 +962,8 @@ encode_insn (struct bpf_insn *insn, char *bytes, int relaxed) { 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")); + if (immediate_overflow (disp, 16)) + as_bad (_("pc-relative offset out of range, shall fit in 16 bits")); else encode_int16 (insn->disp16.X_add_number, bytes + 2); } @@ -1517,7 +1538,7 @@ md_assemble (char *str ATTRIBUTE_UNUSED) break; } insn.has_disp16 = 1; - insn.is_relaxable = 1; + insn.is_relaxable = (insn.disp16.X_op != O_constant); p += 4; } else if (strncmp (p, "%d32", 4) == 0) diff --git a/gas/config/tc-sparc.c b/gas/config/tc-sparc.c index c273bd75c08..8c23b65ca8b 100644 --- a/gas/config/tc-sparc.c +++ b/gas/config/tc-sparc.c @@ -844,7 +844,7 @@ struct pop_entry pop_table[] = { { "hix", BFD_RELOC_SPARC_HIX22, F_POP_V9 }, { "lox", BFD_RELOC_SPARC_LOX10, F_POP_V9 }, - { "hi", BFD_RELOC_HI22, F_POP_PCREL }, + { "hi"5, BFD_RELOC_HI22, F_POP_PCREL }, { "lo", BFD_RELOC_LO10, F_POP_PCREL }, { "pc22", BFD_RELOC_SPARC_PC22, F_POP_PCREL }, { "pc10", BFD_RELOC_SPARC_PC10, F_POP_PCREL }, diff --git a/gas/doc/c-bpf.texi b/gas/doc/c-bpf.texi index 6b43c77d5a0..75372de4ef4 100644 --- a/gas/doc/c-bpf.texi +++ b/gas/doc/c-bpf.texi @@ -172,6 +172,14 @@ Signed 32-bit immediate. Signed 64-bit immediate. @end table +@noindent +Note that the assembler allows to express the value for an immediate +using any numerical literal whose two's complement encoding fits in +the immediate field. For example, @code{-2}, @code{0xfffffffe} and +@code{4294967294} all denote the same encoded 32-bit immediate, whose +value may be then interpreted by different instructions as either as a +negative or a positive number. + @subsection Arithmetic instructions The destination register in these instructions act like an diff --git a/gas/testsuite/gas/bpf/disp16-overflow-relax.l b/gas/testsuite/gas/bpf/disp16-overflow-relax.l index ca572cbd0ff..935a8abaed3 100644 --- a/gas/testsuite/gas/bpf/disp16-overflow-relax.l +++ b/gas/testsuite/gas/bpf/disp16-overflow-relax.l @@ -1,3 +1,5 @@ .*: 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 +.*:1: Error: pc-relative offset out of range, shall fit in 16 bits +.*:2: Error: pc-relative offset out of range, shall fit in 16 bits +.*:3: Error: pc-relative offset out of range, shall fit in 16 bits +.*:4: Error: pc-relative offset out of range, shall fit in 16 bits diff --git a/gas/testsuite/gas/bpf/disp16-overflow-relax.s b/gas/testsuite/gas/bpf/disp16-overflow-relax.s index 3953992ad07..05d505caaae 100644 --- a/gas/testsuite/gas/bpf/disp16-overflow-relax.s +++ b/gas/testsuite/gas/bpf/disp16-overflow-relax.s @@ -1,4 +1,4 @@ - jeq %r1,%r2,2147483647 + jeq %r1,%r2,2147483647 ; Overflows. jlt %r3,%r4,2147483648 ; Overflows. - jge %r5,10,-2147483648 + jge %r5,10,-2147483648 ; Overflows. ja -2147483649 ; Overflows. diff --git a/gas/testsuite/gas/bpf/disp16-overflow.l b/gas/testsuite/gas/bpf/disp16-overflow.l index 6404b1b2076..1fd0f94d0e2 100644 --- a/gas/testsuite/gas/bpf/disp16-overflow.l +++ b/gas/testsuite/gas/bpf/disp16-overflow.l @@ -1,3 +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 +.*:2: Error: pc-relative offset out of range, shall fit in 16 bits +.*:4: Error: 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 index ab66753af7d..4a8fd9fcf1c 100644 --- a/gas/testsuite/gas/bpf/disp16-overflow.s +++ b/gas/testsuite/gas/bpf/disp16-overflow.s @@ -1,4 +1,4 @@ ja 32767 - jeq %r1,%r2,32768 ; Overflows + jeq %r1,%r2,65536 ; Overflows jlt %r3,%r4,-32768 jge %r5,10,-32769 ; Overflows diff --git a/gas/testsuite/gas/bpf/disp32-overflow.l b/gas/testsuite/gas/bpf/disp32-overflow.l index 8a6b6479f07..40a20dd88fb 100644 --- a/gas/testsuite/gas/bpf/disp32-overflow.l +++ b/gas/testsuite/gas/bpf/disp32-overflow.l @@ -1,3 +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 +.*:2: Error: pc-relative offset out of range, shall fit in 32 bits +.*:4: Error: 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 index 03a0d97e6c6..11128a20dff 100644 --- a/gas/testsuite/gas/bpf/disp32-overflow.s +++ b/gas/testsuite/gas/bpf/disp32-overflow.s @@ -1,4 +1,4 @@ call -2147483648 call -2147483649 ; This overflows. - call 2147483647 - call 2147483648 ; This overflows. + call 4294967295 + call 4294967296 ; This overflows. diff --git a/gas/testsuite/gas/bpf/imm32-overflow.l b/gas/testsuite/gas/bpf/imm32-overflow.l index f6691c49cd5..4e5ac5ae06f 100644 --- a/gas/testsuite/gas/bpf/imm32-overflow.l +++ b/gas/testsuite/gas/bpf/imm32-overflow.l @@ -1,3 +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 +.*:2: Error: immediate out of range, shall fit in 32 bits +.*:4: Error: 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 index 5cb858cee05..b2ab43d2e7a 100644 --- a/gas/testsuite/gas/bpf/imm32-overflow.s +++ b/gas/testsuite/gas/bpf/imm32-overflow.s @@ -1,4 +1,4 @@ add %r1, 2147483647 - or %r2, 2147483648 ; This overflows. - xor %r3, -2147483648 - sub %r4, -2147483649 ; This overflows. + or %r2, 4294967296 ; This overflows. + xor %r3, 4294967295 + sub %r4, 4294967296 ; This overflows. diff --git a/gas/testsuite/gas/bpf/jump-relax-ja-be.d b/gas/testsuite/gas/bpf/jump-relax-ja-be.d index 08b85a97b45..5f07847e90c 100644 --- a/gas/testsuite/gas/bpf/jump-relax-ja-be.d +++ b/gas/testsuite/gas/bpf/jump-relax-ja-be.d @@ -13,7 +13,5 @@ Disassembly of section .text: 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 ff ff 7f ff jal -32769 - 28: 06 00 00 00 00 00 80 00 jal 32768 - 30: 06 00 00 00 00 00 80 01 jal 32769 - 38: 06 00 00 00 00 00 80 01 jal 32769 + 20: 06 00 00 00 00 00 80 01 jal 32769 + 28: 06 00 00 00 00 00 80 01 jal 32769 diff --git a/gas/testsuite/gas/bpf/jump-relax-ja.d b/gas/testsuite/gas/bpf/jump-relax-ja.d index 6b50973915d..ed3aa6bad4e 100644 --- a/gas/testsuite/gas/bpf/jump-relax-ja.d +++ b/gas/testsuite/gas/bpf/jump-relax-ja.d @@ -13,7 +13,5 @@ Disassembly of section .text: 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 ff 7f ff ff jal -32769 - 28: 06 00 00 00 00 80 00 00 jal 32768 - 30: 06 00 00 00 01 80 00 00 jal 32769 - 38: 06 00 00 00 01 80 00 00 jal 32769 + 20: 06 00 00 00 01 80 00 00 jal 32769 + 28: 06 00 00 00 01 80 00 00 jal 32769 diff --git a/gas/testsuite/gas/bpf/jump-relax-ja.s b/gas/testsuite/gas/bpf/jump-relax-ja.s index 8be3d7a4288..1faf67909eb 100644 --- a/gas/testsuite/gas/bpf/jump-relax-ja.s +++ b/gas/testsuite/gas/bpf/jump-relax-ja.s @@ -9,10 +9,6 @@ ;; The following instruction has an undefined symbol as a ;; target. It is not to be relaxed. ja undefined + 10 - ;; The following instructions are relaxed to JAL instructions - ;; so they can fit their displacements. - ja -32769 - ja 32768 ;; The following instructions refer to a defined symbol that ;; is not on reach. They shall be relaxed to a JAL. ja tail diff --git a/gas/testsuite/gas/bpf/jump-relax-jump-be.d b/gas/testsuite/gas/bpf/jump-relax-jump-be.d index 5626d568734..0cacdb38fc9 100644 --- a/gas/testsuite/gas/bpf/jump-relax-jump-be.d +++ b/gas/testsuite/gas/bpf/jump-relax-jump-be.d @@ -11,15 +11,9 @@ Disassembly of section .text: 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 + 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 ff ff 7f ff jal -32769 + 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 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 + 40: 06 00 00 00 00 00 80 01 jal 32769 diff --git a/gas/testsuite/gas/bpf/jump-relax-jump.d b/gas/testsuite/gas/bpf/jump-relax-jump.d index cd46ea7024e..dd31ba5f4e4 100644 --- a/gas/testsuite/gas/bpf/jump-relax-jump.d +++ b/gas/testsuite/gas/bpf/jump-relax-jump.d @@ -11,15 +11,9 @@ Disassembly of section .text: 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: 3d 21 01 00 00 00 00 00 jge %r1,%r2,1 + 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 ff 7f ff ff jal -32769 + 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 00 80 00 00 jal 32768 - 48: 1d 21 01 00 00 00 00 00 jeq %r1,%r2,1 - 50: 05 00 01 00 00 00 00 00 ja 1 - 58: 06 00 00 00 01 80 00 00 jal 32769 - 60: 2d 21 01 00 00 00 00 00 jgt %r1,%r2,1 - 68: 05 00 01 00 00 00 00 00 ja 1 - 70: 06 00 00 00 01 80 00 00 jal 32769 + 40: 06 00 00 00 01 80 00 00 jal 32769 diff --git a/gas/testsuite/gas/bpf/jump-relax-jump.s b/gas/testsuite/gas/bpf/jump-relax-jump.s index dabbab84f7c..3ee7c873320 100644 --- a/gas/testsuite/gas/bpf/jump-relax-jump.s +++ b/gas/testsuite/gas/bpf/jump-relax-jump.s @@ -5,11 +5,6 @@ ;; The following instruction refers to a defined symbol that ;; is on reach, so it should not be relaxed. jle %r1, %r2, 1b - ;; The following instructions are relaxed to sequences - ;; involving unconditional jumps, so they can fi their - ;; displacements. - jge %r1, %r2, -32769 - jgt %r1, %r2, 32768 ;; The following instructions refer to a defined symbol that ;; is not on reach. They shall be relaxed. jeq %r1, %r2, tail diff --git a/gas/testsuite/gas/bpf/offset16-overflow.l b/gas/testsuite/gas/bpf/offset16-overflow.l index 6404b1b2076..1fd0f94d0e2 100644 --- a/gas/testsuite/gas/bpf/offset16-overflow.l +++ b/gas/testsuite/gas/bpf/offset16-overflow.l @@ -1,3 +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 +.*:2: Error: pc-relative offset out of range, shall fit in 16 bits +.*:4: Error: 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 index da9f633a337..ebd8e05c09e 100644 --- a/gas/testsuite/gas/bpf/offset16-overflow.s +++ b/gas/testsuite/gas/bpf/offset16-overflow.s @@ -1,4 +1,4 @@ - ldxh %r2, [%r1 + 32767] - ldxw %r2, [%r1 + 32768] ; This overflows + ldxh %r2, [%r1 + 65535] + ldxw %r2, [%r1 + 65536] ; This overflows stxw [%r2 - 32768], %r1 stxdw [%r2 - 32769], %r1 ; This overflows -- 2.30.2