use crate::bpf::{Insn, BPF_ABS, BPF_LD};
pub fn dedup_loads(insns: &mut Vec<Insn>) {
if insns.is_empty() {
return;
}
let load_mask = BPF_LD | BPF_ABS;
let mut i = 0;
while i + 1 < insns.len() {
let cur = insns[i];
let nxt = insns[i + 1];
let is_load = |insn: Insn| (insn.code & 0xf8) == load_mask;
if is_load(cur)
&& is_load(nxt)
&& cur.code == nxt.code
&& cur.k == nxt.k
&& cur.jt == 0
&& cur.jf == 0
{
insns.remove(i + 1);
adjust_jumps(insns, i + 1);
} else {
i += 1;
}
}
}
fn adjust_jumps(insns: &mut [Insn], removed_idx: usize) {
let bpf_jmp = 0x05u16;
for (src, insn) in insns.iter_mut().enumerate() {
if (insn.code & 0x07) != bpf_jmp {
continue;
}
let adjust = |field: &mut u8, src: usize| {
let target = src + 1 + *field as usize;
if target > removed_idx {
*field -= 1;
}
};
let is_ja = (insn.code & 0xf0) == 0x00; if is_ja {
let target = src + 1 + insn.k as usize;
if target > removed_idx {
insn.k -= 1;
}
} else {
adjust(&mut insn.jt, src);
adjust(&mut insn.jf, src);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::bpf::Insn;
#[test]
fn dedup_removes_repeated_load() {
let ldh = Insn::ldh_abs(12);
let jeq = Insn::jeq_k(0x0800, 0, 1);
let mut insns = vec![ldh, jeq, ldh, Insn::jeq_k(0x86dd, 0, 1)];
dedup_loads(&mut insns);
}
}