capstone-engine / capstone

Capstone disassembly/disassembler framework for ARM, ARM64 (ARMv8), Alpha, BPF, Ethereum VM, HPPA, LoongArch, M68K, M680X, Mips, MOS65XX, PPC, RISC-V(rv32G/rv64G), SH, Sparc, SystemZ, TMS320C64X, TriCore, Webassembly, XCore and X86.
http://www.capstone-engine.org
7.6k stars 1.56k forks source link

How to compute the effective address of a memory operand on ARM? #1013

Open 10110111 opened 7 years ago

10110111 commented 7 years ago

I'm a bit confused by all the fields in cs_arm_op for ARM_OP_MEM. At first I thought the calculation would be something like

op.mem.base+op.mem.disp+doShift(op.mem.index*op.mem.scale, op.shift)

but it appears that for an instruction like 82 f6 11 e7 ldr pc, [r1, -r2, lsl #13] we have op.mem.scale==1 and op.subtracted==1. So, what is the generally correct procedure to calculate the effective address? What are some examples of instructions where op.subtracted==0 and op.mem.scale==-1?

10110111 commented 7 years ago

OK, I've found some. But this doesn't actually make any sense:

B2 00 11 E1    ldrh   r0, [r1, -r2]    ; scale=-1, subtracted=true
02 00 11 E7    ldr    r0, [r1, -r2]    ; scale=+1, subtracted=true

I do recognize that the first of these instructions has Addressing Mode 3, while the second one has Addressing Mode 2. But shouldn't Capstone give some more intuitive results? I'd suppose in both cases here scale should be -1, and subtracted=false, since the memory read is not subtracted from r0, and the index register r2 is scaled by -1.

catenacyber commented 6 years ago

see #1163 subtracted does not refer to the index register, but to an immediate (0 in your cases)

10110111 commented 6 years ago

@catenacyber In ldr pc, [r1, -r2, lsl #13] there's no immediate other than shift count, yet op.subtracted==1. Seems to contradict your claim.

catenacyber commented 6 years ago

@10110111 my mistake. This looks like

diff --git a/arch/ARM/ARMInstPrinter.c b/arch/ARM/ARMInstPrinter.c
index af23c456..d8da4c4d 100644
--- a/arch/ARM/ARMInstPrinter.c
+++ b/arch/ARM/ARMInstPrinter.c
@@ -1032,7 +1032,7 @@ static void printAM3PreOrOffsetIndexOp(MCInst *MI, unsigned Op, SStream *O,
                if (MI->csh->detail) {
                        MI->flat_insn->detail->arm.operands[MI->flat_insn->detail->arm.op_count].mem.index = MCOperand_getReg(MO2);
                        if (sign == ARM_AM_sub) {
-                               MI->flat_insn->detail->arm.operands[MI->flat_insn->detail->arm.op_count].mem.scale = -1;
+                               MI->flat_insn->detail->arm.operands[MI->flat_insn->detail->arm.op_count].mem.scale = 1;
                                MI->flat_insn->detail->arm.operands[MI->flat_insn->detail->arm.op_count].subtracted = true;
                        }
                }

could be a reasonable patch