in net/bpf_jit_comp_64.c [658:791]
static int emit_compare_and_branch(const u8 code, const u8 dst, u8 src,
const s32 imm, bool is_imm, int branch_dst,
struct jit_ctx *ctx)
{
bool use_cbcond = (sparc64_elf_hwcap & AV_SPARC_CBCOND) != 0;
const u8 tmp = bpf2sparc[TMP_REG_1];
branch_dst = ctx->offset[branch_dst];
if (!is_simm10(branch_dst - ctx->idx) ||
BPF_OP(code) == BPF_JSET)
use_cbcond = false;
if (is_imm) {
bool fits = true;
if (use_cbcond) {
if (!is_simm5(imm))
fits = false;
} else if (!is_simm13(imm)) {
fits = false;
}
if (!fits) {
ctx->tmp_1_used = true;
emit_loadimm_sext(imm, tmp, ctx);
src = tmp;
is_imm = false;
}
}
if (!use_cbcond) {
u32 br_opcode;
if (BPF_OP(code) == BPF_JSET) {
if (is_imm)
emit_btsti(dst, imm, ctx);
else
emit_btst(dst, src, ctx);
} else {
if (is_imm)
emit_cmpi(dst, imm, ctx);
else
emit_cmp(dst, src, ctx);
}
switch (BPF_OP(code)) {
case BPF_JEQ:
br_opcode = BE;
break;
case BPF_JGT:
br_opcode = BGU;
break;
case BPF_JLT:
br_opcode = BLU;
break;
case BPF_JGE:
br_opcode = BGEU;
break;
case BPF_JLE:
br_opcode = BLEU;
break;
case BPF_JSET:
case BPF_JNE:
br_opcode = BNE;
break;
case BPF_JSGT:
br_opcode = BG;
break;
case BPF_JSLT:
br_opcode = BL;
break;
case BPF_JSGE:
br_opcode = BGE;
break;
case BPF_JSLE:
br_opcode = BLE;
break;
default:
/* Make sure we dont leak kernel information to the
* user.
*/
return -EFAULT;
}
emit_branch(br_opcode, ctx->idx, branch_dst, ctx);
emit_nop(ctx);
} else {
u32 cbcond_opcode;
switch (BPF_OP(code)) {
case BPF_JEQ:
cbcond_opcode = CBCONDE;
break;
case BPF_JGT:
cbcond_opcode = CBCONDGU;
break;
case BPF_JLT:
cbcond_opcode = CBCONDLU;
break;
case BPF_JGE:
cbcond_opcode = CBCONDGEU;
break;
case BPF_JLE:
cbcond_opcode = CBCONDLEU;
break;
case BPF_JNE:
cbcond_opcode = CBCONDNE;
break;
case BPF_JSGT:
cbcond_opcode = CBCONDG;
break;
case BPF_JSLT:
cbcond_opcode = CBCONDL;
break;
case BPF_JSGE:
cbcond_opcode = CBCONDGE;
break;
case BPF_JSLE:
cbcond_opcode = CBCONDLE;
break;
default:
/* Make sure we dont leak kernel information to the
* user.
*/
return -EFAULT;
}
cbcond_opcode |= CBCOND_OP;
if (is_imm)
emit_cbcondi(cbcond_opcode, ctx->idx, branch_dst,
dst, imm, ctx);
else
emit_cbcond(cbcond_opcode, ctx->idx, branch_dst,
dst, src, ctx);
}
return 0;
}