Improve access scanner
Detect Sancov table accesses via static displacements, not just PC-relative
Explicitly skip instructions with no memory operand
Skip instructions whose effective address relies on (non-PC) register values
@@ -5,7 +5,7 @@ use std::collections::BTreeSet;
use std::convert::TryInto;
use anyhow::{format_err, Result};
-use iced_x86::{Decoder, DecoderOptions, Instruction, Mnemonic, OpKind};
+use iced_x86::{Decoder, DecoderOptions, Instruction, Mnemonic, OpKind, Register};
/// Size of padding inserted (on Window) between `__start_` delimiter symbols
/// and the first entry of the delimited table's array.
@@ -337,9 +337,30 @@ impl SancovInlineAccessScanner {
decoder.set_ip(va);
let mut inst = Instruction::default();
+
while decoder.can_decode() {
decoder.decode_out(&mut inst);
+ // If no memory operand, there is no table access.
+ if !inst.op_kinds().any(|o| o == OpKind::Memory) {
+ continue;
+ }
+
+ // Skip any memory access that is not PC-relative or absolute.
+ if !inst.is_ip_rel_memory_operand() {
+ if inst.memory_base() != Register::None {
+ continue;
+ }
+
+ if inst.memory_index() != Register::None {
+ continue;
+ }
+
+ if inst.segment_prefix() != Register::None {
+ continue;
+ }
+ }
+
match inst.op_code().mnemonic() {
Mnemonic::Add | Mnemonic::Inc => {
// These may be 8-bit counter updates, check further.
@@ -402,8 +423,7 @@ impl SancovInlineAccessScanner {
}
}
- if inst.is_ip_rel_memory_operand() {
- // When relative, `memory_displacement64()` returns a VA.
+ // Even when PC-relative, `memory_displacement64()` returns a VA.
let accessed = inst
.memory_displacement64()
.checked_sub(self.base)
@@ -420,7 +440,6 @@ impl SancovInlineAccessScanner {
self.offsets.insert(offset);
}
}
- }
Ok(())
}
