Index: sandbox/linux/seccomp-bpf/codegen.cc |
diff --git a/sandbox/linux/seccomp-bpf/codegen.cc b/sandbox/linux/seccomp-bpf/codegen.cc |
index 3ed06cb4013a68f832a808b26e2d398ef78cab5c..df9676017a07a119e2f53eb25bfd676a191781a2 100644 |
--- a/sandbox/linux/seccomp-bpf/codegen.cc |
+++ b/sandbox/linux/seccomp-bpf/codegen.cc |
@@ -49,7 +49,7 @@ const size_t kBranchRange = std::numeric_limits<uint8_t>::max(); |
const CodeGen::Node CodeGen::kNullNode; |
-CodeGen::CodeGen() : program_(), memos_() { |
+CodeGen::CodeGen() : program_(), equivalent_(), memos_() { |
} |
CodeGen::~CodeGen() { |
@@ -81,11 +81,11 @@ CodeGen::Node CodeGen::AppendInstruction(uint16_t code, |
if (BPF_CLASS(code) == BPF_JMP) { |
CHECK_NE(BPF_JA, BPF_OP(code)) << "CodeGen inserts JAs as needed"; |
- // We need to check |jt| twice because it might get pushed |
- // out-of-range by appending a jump for |jf|. |
- jt = WithinRange(jt, kBranchRange); |
+ // Optimally adding jumps is rather tricky, so we use a quick |
+ // approximation: by artificially reducing |jt|'s range, |jt| will |
+ // stay within its true range even if we add a jump for |jf|. |
+ jt = WithinRange(jt, kBranchRange - 1); |
jf = WithinRange(jf, kBranchRange); |
- jt = WithinRange(jt, kBranchRange); |
return Append(code, k, Offset(jt), Offset(jf)); |
} |
@@ -97,24 +97,26 @@ CodeGen::Node CodeGen::AppendInstruction(uint16_t code, |
// proceeds to the next instruction; so we need to arrange for |
// that to be |jt|. |
jt = WithinRange(jt, 0); |
+ CHECK_EQ(0U, Offset(jt)) << "ICE: Failed to setup next instruction"; |
} |
return Append(code, k, 0, 0); |
} |
CodeGen::Node CodeGen::WithinRange(Node target, size_t range) { |
- if (Offset(target) > range) { |
- // TODO(mdempsky): If |range > 0|, we might be able to reuse an |
- // existing instruction within that range. |
- |
- // TODO(mdempsky): If |target| is a branch or return, it might be |
- // possible to duplicate that instruction rather than jump to it. |
+ // Just use |target| if it's already within range. |
+ if (Offset(target) <= range) { |
+ return target; |
+ } |
- // Fall back to emitting a jump instruction. |
- target = Append(BPF_JMP | BPF_JA, Offset(target), 0, 0); |
+ // Alternatively, look for an equivalent instruction within range. |
+ if (Offset(equivalent_.at(target)) <= range) { |
+ return equivalent_.at(target); |
} |
- CHECK_LE(Offset(target), range) << "ICE: Failed to bring target within range"; |
- return target; |
+ // Otherwise, fall back to emitting a jump instruction. |
+ Node jump = Append(BPF_JMP | BPF_JA, Offset(target), 0, 0); |
+ equivalent_.at(target) = jump; |
+ return jump; |
} |
CodeGen::Node CodeGen::Append(uint16_t code, uint32_t k, size_t jt, size_t jf) { |
@@ -127,8 +129,12 @@ CodeGen::Node CodeGen::Append(uint16_t code, uint32_t k, size_t jt, size_t jf) { |
} |
CHECK_LT(program_.size(), static_cast<size_t>(BPF_MAXINSNS)); |
+ CHECK_EQ(program_.size(), equivalent_.size()); |
+ |
+ Node res = program_.size(); |
program_.push_back(sock_filter{code, jt, jf, k}); |
- return program_.size() - 1; |
+ equivalent_.push_back(res); |
+ return res; |
} |
size_t CodeGen::Offset(Node target) const { |