icedland / iced

Blazing fast and correct x86/x64 disassembler, assembler, decoder, encoder for Rust, .NET, Java, Python, Lua
MIT License
2.95k stars 232 forks source link

Bad operand access for `sub rax, rax` #613

Closed susitsm closed 1 month ago

susitsm commented 1 month ago

Printing the instruction info for sub rax, rax

fn sub_rax_rax_operand_access() {
    let data = &[0x48, 0x29, 0xc0]; // sub rax, rax
    let mut decoder = iced_x86::Decoder::new(64, data, 0);
    let ins = decoder.decode();
    println!("{ins:?}");
    let mut factory = InstructionInfoFactory::new();
    let info = factory.info(&ins);
    println!("{info:#?}");
}

gives the following results:

Instruction { next_rip: 3, mem_displ: 0, flags1: 786432, immediate: 0, code: Sub_rm64_r64, mem_base_reg: None, mem_index_reg: None, regs: [RAX, RAX, None, None], op_kinds: [Register, Register, Register, Register], scale: Scale1, displ_size: 0, len: 3, pad: 0 }
InstructionInfo {
    used_registers: [
        RAX:Write,
    ],
    used_memory_locations: [],
    op_accesses: [
        Write,
        None,
        None,
        None,
        None,
    ],
}

Any sub reg1, reg2 will give the same result when reg1 == reg2. This seems to be because implied access in flags1 contains ImpliedAccess::Clear_rflags for the instruction.

Would love to fix it in a PR, but I don't know much about the info table in iced. Is there any resource I can turn to?

susitsm commented 1 month ago

I just realized this is a simplification like xor rax, rax since the result will always be 0

wtfsck commented 1 month ago

iced has some special cases like that since it's obvious that if you execute eg. 'xor rax,rax' (or more likely 'xor eax,eax') you're not reading eax/rax, you're writing to it (clearing it in this case).