Skip to content
This repository was archived by the owner on Jan 10, 2025. It is now read-only.

Commit 410a627

Browse files
authored
Fix - PQR 64 unsigned sign extension (#642)
* Formats parameters and arguments of emit_product_quotient_remainder(). * Removes sign extension of the immediate values in unsigned PQR instructions.
1 parent ba886be commit 410a627

File tree

3 files changed

+72
-25
lines changed

3 files changed

+72
-25
lines changed

Diff for: src/interpreter.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> {
403403
ebpf::LMUL32_REG if self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] = (self.reg[dst] as u32).wrapping_mul(self.reg[src] as u32) as u64,
404404
ebpf::LMUL64_IMM if self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] = self.reg[dst].wrapping_mul(insn.imm as u64),
405405
ebpf::LMUL64_REG if self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] = self.reg[dst].wrapping_mul(self.reg[src]),
406-
ebpf::UHMUL64_IMM if self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] = (self.reg[dst] as u128).wrapping_mul(insn.imm as u64 as u128).wrapping_shr(64) as u64,
406+
ebpf::UHMUL64_IMM if self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] = (self.reg[dst] as u128).wrapping_mul(insn.imm as u32 as u128).wrapping_shr(64) as u64,
407407
ebpf::UHMUL64_REG if self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] = (self.reg[dst] as u128).wrapping_mul(self.reg[src] as u128).wrapping_shr(64) as u64,
408408
ebpf::SHMUL64_IMM if self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] = (self.reg[dst] as i64 as i128).wrapping_mul(insn.imm as i128).wrapping_shr(64) as u64,
409409
ebpf::SHMUL64_REG if self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] = (self.reg[dst] as i64 as i128).wrapping_mul(self.reg[src] as i64 as i128).wrapping_shr(64) as u64,
@@ -415,7 +415,7 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> {
415415
self.reg[dst] = (self.reg[dst] as u32 / self.reg[src] as u32) as u64;
416416
},
417417
ebpf::UDIV64_IMM if self.executable.get_sbpf_version().enable_pqr() => {
418-
self.reg[dst] /= insn.imm as u64;
418+
self.reg[dst] /= insn.imm as u32 as u64;
419419
}
420420
ebpf::UDIV64_REG if self.executable.get_sbpf_version().enable_pqr() => {
421421
throw_error!(DivideByZero; self, self.reg[src], u64);
@@ -429,7 +429,7 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> {
429429
self.reg[dst] = (self.reg[dst] as u32 % self.reg[src] as u32) as u64;
430430
},
431431
ebpf::UREM64_IMM if self.executable.get_sbpf_version().enable_pqr() => {
432-
self.reg[dst] %= insn.imm as u64;
432+
self.reg[dst] %= insn.imm as u32 as u64;
433433
}
434434
ebpf::UREM64_REG if self.executable.get_sbpf_version().enable_pqr() => {
435435
throw_error!(DivideByZero; self, self.reg[src], u64);

Diff for: src/jit.rs

+47-10
Original file line numberDiff line numberDiff line change
@@ -509,12 +509,24 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> {
509509
}
510510
},
511511
ebpf::MUL32_IMM | ebpf::DIV32_IMM | ebpf::MOD32_IMM if !self.executable.get_sbpf_version().enable_pqr() =>
512-
self.emit_product_quotient_remainder(OperandSize::S32, (insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MOD, (insn.opc & ebpf::BPF_ALU_OP_MASK) != ebpf::BPF_MUL, (insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MUL, dst, dst, Some(insn.imm)),
512+
self.emit_product_quotient_remainder(
513+
OperandSize::S32,
514+
(insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MOD,
515+
(insn.opc & ebpf::BPF_ALU_OP_MASK) != ebpf::BPF_MUL,
516+
(insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MUL,
517+
dst, dst, Some(insn.imm),
518+
),
513519
ebpf::LD_1B_REG if self.executable.get_sbpf_version().move_memory_instruction_classes() => {
514520
self.emit_address_translation(Some(dst), Value::RegisterPlusConstant64(src, insn.off as i64, true), 1, None);
515521
},
516522
ebpf::MUL32_REG | ebpf::DIV32_REG | ebpf::MOD32_REG if !self.executable.get_sbpf_version().enable_pqr() =>
517-
self.emit_product_quotient_remainder(OperandSize::S32, (insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MOD, (insn.opc & ebpf::BPF_ALU_OP_MASK) != ebpf::BPF_MUL, (insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MUL, src, dst, None),
523+
self.emit_product_quotient_remainder(
524+
OperandSize::S32,
525+
(insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MOD,
526+
(insn.opc & ebpf::BPF_ALU_OP_MASK) != ebpf::BPF_MUL,
527+
(insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MUL,
528+
src, dst, None,
529+
),
518530
ebpf::LD_2B_REG if self.executable.get_sbpf_version().move_memory_instruction_classes() => {
519531
self.emit_address_translation(Some(dst), Value::RegisterPlusConstant64(src, insn.off as i64, true), 2, None);
520532
},
@@ -594,15 +606,27 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> {
594606
}
595607
ebpf::SUB64_REG => self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x29, src, dst, 0, None)),
596608
ebpf::MUL64_IMM | ebpf::DIV64_IMM | ebpf::MOD64_IMM if !self.executable.get_sbpf_version().enable_pqr() =>
597-
self.emit_product_quotient_remainder(OperandSize::S64, (insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MOD, (insn.opc & ebpf::BPF_ALU_OP_MASK) != ebpf::BPF_MUL, (insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MUL, dst, dst, Some(insn.imm)),
609+
self.emit_product_quotient_remainder(
610+
OperandSize::S64,
611+
(insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MOD,
612+
(insn.opc & ebpf::BPF_ALU_OP_MASK) != ebpf::BPF_MUL,
613+
(insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MUL,
614+
dst, dst, Some(insn.imm),
615+
),
598616
ebpf::ST_1B_IMM if self.executable.get_sbpf_version().move_memory_instruction_classes() => {
599617
self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 1, Some(Value::Constant64(insn.imm, true)));
600618
},
601619
ebpf::ST_2B_IMM if self.executable.get_sbpf_version().move_memory_instruction_classes() => {
602620
self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 2, Some(Value::Constant64(insn.imm, true)));
603621
},
604622
ebpf::MUL64_REG | ebpf::DIV64_REG | ebpf::MOD64_REG if !self.executable.get_sbpf_version().enable_pqr() =>
605-
self.emit_product_quotient_remainder(OperandSize::S64, (insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MOD, (insn.opc & ebpf::BPF_ALU_OP_MASK) != ebpf::BPF_MUL, (insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MUL, src, dst, None),
623+
self.emit_product_quotient_remainder(
624+
OperandSize::S64,
625+
(insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MOD,
626+
(insn.opc & ebpf::BPF_ALU_OP_MASK) != ebpf::BPF_MUL,
627+
(insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MUL,
628+
src, dst, None,
629+
),
606630
ebpf::ST_1B_REG if self.executable.get_sbpf_version().move_memory_instruction_classes() => {
607631
self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 1, Some(Value::Register(src)));
608632
},
@@ -651,26 +675,30 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> {
651675
ebpf::UDIV32_IMM | ebpf::UDIV64_IMM | ebpf::UREM32_IMM | ebpf::UREM64_IMM |
652676
ebpf::SDIV32_IMM | ebpf::SDIV64_IMM | ebpf::SREM32_IMM | ebpf::SREM64_IMM
653677
if self.executable.get_sbpf_version().enable_pqr() => {
678+
let signed = insn.opc & (1 << 7) != 0;
679+
let mut imm = insn.imm;
680+
if !signed {
681+
imm &= u32::MAX as i64;
682+
}
654683
self.emit_product_quotient_remainder(
655684
if insn.opc & (1 << 4) != 0 { OperandSize::S64 } else { OperandSize::S32 },
656685
insn.opc & (1 << 5) != 0,
657686
insn.opc & (1 << 6) != 0,
658-
insn.opc & (1 << 7) != 0,
659-
dst, dst, Some(insn.imm),
687+
signed,
688+
dst, dst, Some(imm),
660689
)
661690
}
662691
ebpf::LMUL32_REG | ebpf::LMUL64_REG | ebpf::UHMUL64_REG | ebpf::SHMUL64_REG |
663692
ebpf::UDIV32_REG | ebpf::UDIV64_REG | ebpf::UREM32_REG | ebpf::UREM64_REG |
664693
ebpf::SDIV32_REG | ebpf::SDIV64_REG | ebpf::SREM32_REG | ebpf::SREM64_REG
665-
if self.executable.get_sbpf_version().enable_pqr() => {
694+
if self.executable.get_sbpf_version().enable_pqr() =>
666695
self.emit_product_quotient_remainder(
667696
if insn.opc & (1 << 4) != 0 { OperandSize::S64 } else { OperandSize::S32 },
668697
insn.opc & (1 << 5) != 0,
669698
insn.opc & (1 << 6) != 0,
670699
insn.opc & (1 << 7) != 0,
671700
src, dst, None,
672-
)
673-
}
701+
),
674702

675703
// BPF_JMP class
676704
ebpf::JA => {
@@ -1272,7 +1300,16 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> {
12721300
}
12731301

12741302
#[allow(clippy::too_many_arguments)]
1275-
fn emit_product_quotient_remainder(&mut self, size: OperandSize, alt_dst: bool, division: bool, signed: bool, src: u8, dst: u8, imm: Option<i64>) {
1303+
fn emit_product_quotient_remainder(
1304+
&mut self,
1305+
size: OperandSize,
1306+
alt_dst: bool,
1307+
division: bool,
1308+
signed: bool,
1309+
src: u8,
1310+
dst: u8,
1311+
imm: Option<i64>,
1312+
) {
12761313
// LMUL UHMUL SHMUL UDIV SDIV UREM SREM
12771314
// ALU F7/4 F7/4 F7/5 F7/6 F7/7 F7/6 F7/7
12781315
// src-in REGISTER_SCRATCH REGISTER_SCRATCH REGISTER_SCRATCH REGISTER_SCRATCH REGISTER_SCRATCH REGISTER_SCRATCH REGISTER_SCRATCH

Diff for: tests/execution.rs

+22-12
Original file line numberDiff line numberDiff line change
@@ -701,9 +701,9 @@ fn test_be64() {
701701
#[test]
702702
fn test_pqr() {
703703
let mut prog = [0; 48];
704-
prog[0] = ebpf::MOV64_IMM;
704+
prog[0] = ebpf::MOV32_IMM;
705705
prog[8] = ebpf::HOR64_IMM;
706-
prog[16] = ebpf::MOV64_IMM;
706+
prog[16] = ebpf::MOV32_IMM;
707707
prog[17] = 1; // dst = R1
708708
prog[24] = ebpf::HOR64_IMM;
709709
prog[25] = 1; // dst = R1
@@ -716,21 +716,31 @@ fn test_pqr() {
716716
(ebpf::UDIV64_IMM, 13u64, 4u64, 3u64),
717717
(ebpf::UREM32_IMM, 13u64, 4u64, 1u64),
718718
(ebpf::UREM64_IMM, 13u64, 4u64, 1u64),
719-
(ebpf::UHMUL64_IMM, 13u64, u64::MAX, 12u64),
720-
(ebpf::UDIV32_IMM, 13u64, u64::MAX, 0u64),
721-
(ebpf::UDIV64_IMM, 13u64, u64::MAX, 0u64),
722-
(ebpf::UREM32_IMM, 13u64, u64::MAX, 13u64),
723-
(ebpf::UREM64_IMM, 13u64, u64::MAX, 13u64),
719+
(ebpf::UHMUL64_IMM, 13u64, u32::MAX as u64, 0u64),
720+
(ebpf::UDIV32_IMM, 13u64, u32::MAX as u64, 0u64),
721+
(ebpf::UDIV64_IMM, 13u64, u32::MAX as u64, 0u64),
722+
(ebpf::UREM32_IMM, 13u64, u32::MAX as u64, 13u64),
723+
(ebpf::UREM64_IMM, 13u64, u32::MAX as u64, 13u64),
724724
(ebpf::UHMUL64_IMM, u64::MAX, 4u64, 3u64),
725725
(ebpf::UDIV32_IMM, u64::MAX, 4u64, (u32::MAX / 4) as u64),
726726
(ebpf::UDIV64_IMM, u64::MAX, 4u64, u64::MAX / 4),
727727
(ebpf::UREM32_IMM, u64::MAX, 4u64, 3u64),
728728
(ebpf::UREM64_IMM, u64::MAX, 4u64, 3u64),
729-
(ebpf::UHMUL64_IMM, u64::MAX, u64::MAX, u64::MAX - 1),
730-
(ebpf::UDIV32_IMM, u64::MAX, u64::MAX, 1u64),
731-
(ebpf::UDIV64_IMM, u64::MAX, u64::MAX, 1u64),
732-
(ebpf::UREM32_IMM, u64::MAX, u64::MAX, 0u64),
733-
(ebpf::UREM64_IMM, u64::MAX, u64::MAX, 0u64),
729+
(
730+
ebpf::UHMUL64_IMM,
731+
u64::MAX,
732+
u32::MAX as u64,
733+
u32::MAX as u64 - 1,
734+
),
735+
(ebpf::UDIV32_IMM, u64::MAX, u32::MAX as u64, 1u64),
736+
(
737+
ebpf::UDIV64_IMM,
738+
u64::MAX,
739+
u32::MAX as u64,
740+
u32::MAX as u64 + 2,
741+
),
742+
(ebpf::UREM32_IMM, u64::MAX, u32::MAX as u64, 0u64),
743+
(ebpf::UREM64_IMM, u64::MAX, u32::MAX as u64, 0u64),
734744
(
735745
ebpf::LMUL32_IMM,
736746
13i64 as u64,

0 commit comments

Comments
 (0)