Skip to content

Commit e34307d

Browse files
committed
Put callx register into dst field
The mailing list discussion at https://mailarchive.ietf.org/arch/msg/bpf/Vx1H3ViPUWoGKNssCO22lOIjyXU/ agreed that inst.dst is where to put the register to use going forward and clang v.19 will do so but earlier versions of clang used inst.imm. Signed-off-by: Dave Thaler <[email protected]>
1 parent 687873f commit e34307d

File tree

4 files changed

+24
-8
lines changed

4 files changed

+24
-8
lines changed

external/bpf_conformance

src/asm_marshal.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,9 @@ struct MarshalVisitor {
180180
}
181181

182182
vector<ebpf_inst> operator()(Callx const& b) {
183-
// callx is defined to have the source register in 'imm' not in 'src'.
183+
// callx is defined to have the register in 'dst' not in 'src'.
184184
return {
185-
ebpf_inst{.opcode = static_cast<uint8_t>(INST_OP_CALL | INST_SRC_REG), .dst = 0, .src = 0, .offset = 0, .imm = b.func.v}};
185+
ebpf_inst{.opcode = static_cast<uint8_t>(INST_OP_CALL | INST_SRC_REG), .dst = b.func.v, .src = 0, .offset = 0}};
186186
}
187187

188188
vector<ebpf_inst> operator()(Exit const& b) {

src/asm_unmarshal.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -406,10 +406,18 @@ struct Unmarshaller {
406406
}
407407

408408
auto makeCallx(ebpf_inst inst, pc_t pc) const {
409-
// callx puts the register number in the 'imm' field rather than the 'src' field.
410-
if (inst.imm < 0 || inst.imm > R10_STACK_POINTER)
409+
// callx puts the register number in the 'dst' field rather than the 'src' field.
410+
if (inst.dst > R10_STACK_POINTER)
411411
throw InvalidInstruction(pc, "Bad register");
412-
return Callx{(uint8_t)inst.imm};
412+
if (inst.imm != 0) {
413+
// Clang prior to v19 put the register number into the 'imm' field.
414+
if (inst.dst > 0)
415+
throw InvalidInstruction(pc, make_opcode_message("Nonzero imm for", inst.opcode));
416+
if (inst.imm < 0 || inst.imm > R10_STACK_POINTER)
417+
throw InvalidInstruction(pc, "Bad register");
418+
return Callx{(uint8_t)inst.imm};
419+
}
420+
return Callx{inst.dst};
413421
}
414422

415423
auto makeJmp(ebpf_inst inst, const vector<ebpf_inst>& insts, pc_t pc) -> Instruction {

src/test/test_marshal.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,19 @@ TEST_CASE("disasm_marshal", "[disasm][marshal]") {
177177
oss << "0: Bad instruction op 0x" << std::hex << INST_OP_CALLX << std::endl;
178178
check_unmarshal_fail(ebpf_inst{.opcode = INST_OP_CALLX}, oss.str().c_str());
179179

180-
// Test callx with support. Note that callx puts the register number in 'imm' not 'src'.
180+
// Test callx with support. Note that callx puts the register number in 'dst' not 'src'.
181181
ebpf_platform_t platform = g_ebpf_platform_linux;
182182
platform.callx = true;
183183
compare_marshal_unmarshal(Callx{8}, false, &platform);
184-
check_unmarshal_fail(ebpf_inst{.opcode = /* 0x8d */ INST_OP_CALLX, .imm = 11}, "0: Bad register\n", &platform);
184+
ebpf_inst callx{.opcode = INST_OP_CALLX, .dst = 8};
185+
compare_unmarshal_marshal(callx, callx, &platform);
186+
check_unmarshal_fail({.opcode = INST_OP_CALLX, .dst = 11}, "0: Bad register\n", &platform);
187+
check_unmarshal_fail({.opcode = INST_OP_CALLX, .dst = 8, .imm = 8}, "0: Nonzero imm for op 0x8d\n", &platform);
188+
189+
// clang prior to v19 put the register into 'imm' instead of 'dst' so we treat it as equivalent.
190+
compare_unmarshal_marshal(ebpf_inst{.opcode = /* 0x8d */ INST_OP_CALLX, .imm = 8}, callx, &platform);
191+
check_unmarshal_fail({.opcode = INST_OP_CALLX, .imm = 11}, "0: Bad register\n", &platform);
192+
check_unmarshal_fail({.opcode = INST_OP_CALLX, .imm = -1}, "0: Bad register\n", &platform);
185193
}
186194

187195
SECTION("Exit") { compare_marshal_unmarshal(Exit{}); }

0 commit comments

Comments
 (0)