changeset 92:708f2452d1ae

armdis: full ldr/str decoding implemented
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Sun, 30 Mar 2014 01:47:28 +0000
parents daf69d5edb3f
children 5ebebbc74622
files arm7dis/armdis.c
diffstat 1 files changed, 101 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/arm7dis/armdis.c	Sun Mar 30 00:27:25 2014 +0000
+++ b/arm7dis/armdis.c	Sun Mar 30 01:47:28 2014 +0000
@@ -209,16 +209,63 @@
 		printf("<invalid multiply>\n");
 }
 
+static int
+check_ldr_litpool(off, word, loff, size)
+	unsigned off, word, loff;
+{
+	unsigned litoff, datum;
+
+	/* base reg must be 15 */
+	if (((word >> 16) & 0xF) != 15)
+		return(0);
+	/* must be a load */
+	if (!(word & 0x100000))
+		return(0);
+	/* no writeback allowed */
+	if (word & 0x200000)
+		return(0);
+	/* alignment */
+	if (loff & (size - 1))
+		return(0);
+	/* range */
+	off += 8;
+	if (word & 0x800000)
+		litoff = off + loff;
+	else {
+		if (loff > off)
+			return(0);
+		litoff = off - loff;
+	}
+	if (litoff >= disasm_len)
+		return(0);
+	/* all checks passed, proceed */
+	switch (size) {
+	case 1:
+		datum = filemap[litoff];
+		break;
+	case 2:
+		datum = get_u16(filemap + litoff);
+		break;
+	case 4:
+		datum = get_u32(filemap + litoff);
+		break;
+	}
+	printf("=0x%x\t; via 0x%x\n", datum, litoff);
+	return(1);
+}
+
 static void
 ldr_str_imm_pre(off, word)
 	unsigned off, word;
 {
 	unsigned loff = word & 0xFFF;
 
-	/* check for literal pool fetches will go here */
-	printf("%s%s%s\t%s, [%s", word&0x100000 ? "ldr" : "str",
+	printf("%s%s%s\t%s, ", word&0x100000 ? "ldr" : "str",
 		condition_decode[word>>28], word&0x400000 ? "b" : "",
-		regnames[(word>>12)&0xF], regnames[(word>>16)&0xF]);
+		regnames[(word>>12)&0xF]);
+	if (check_ldr_litpool(off, word, loff, word&0x400000 ? 1 : 4))
+		return;
+	printf("[%s", regnames[(word>>16)&0xF]);
 	if (loff || word&0x200000)
 		printf(", #%s%u", word&0x800000 ? "" : "-", loff);
 	putchar(']');
@@ -287,7 +334,57 @@
 ldr_str_ext(off, word)
 	unsigned off, word;
 {
-	printf("<extended ldr/str>\n");
+	unsigned loff;
+
+	if (!(word&0x01000000) && word&0x200000) {
+		printf("<invalid ldrh/strh: P=0, W=1>\n");
+		return;
+	}
+	if (!(word&0x400000) && word&0xF00) {
+		printf("<invalid ldrh/strh: SBZ!=0>\n");
+		return;
+	}
+	printf("%s%s%s%c\t%s, ", word&0x100000 ? "ldr" : "str",
+		condition_decode[word>>28],
+		word&0x40 ? "s" : "",
+		word&0x20 ? 'h' : 'b',
+		regnames[(word>>12)&0xF]);
+	if (word & 0x400000)
+		loff = ((word & 0xF00) >> 4) | (word & 0xF);
+	switch (word & 0x01400000) {
+	case 0:
+		/* reg post */
+		printf("[%s], %s%s", regnames[(word>>16)&0xF],
+			word&0x800000 ? "" : "-", regnames[word&0xF]);
+		break;
+	case 0x400000:
+		/* imm post */
+		printf("[%s], #%s%u", regnames[(word>>16)&0xF],
+			word&0x800000 ? "" : "-", loff);
+		if (loff >= 10)
+			printf("\t; 0x%x", loff);
+		break;
+	case 0x01000000:
+		/* reg pre */
+		printf("[%s, %s%s]%s", regnames[(word>>16)&0xF],
+			word&0x800000 ? "" : "-", regnames[word&0xF],
+			word&0x200000 ? "!" : "");
+		break;
+	case 0x01400000:
+		/* imm pre */
+		if (check_ldr_litpool(off, word, loff, word&0x20 ? 2 : 1))
+			return;
+		printf("[%s", regnames[(word>>16)&0xF]);
+		if (loff || word&0x200000)
+			printf(", #%s%u", word&0x800000 ? "" : "-", loff);
+		putchar(']');
+		if (word & 0x200000)
+			putchar('!');
+		if (loff >= 10)
+			printf("\t; 0x%x", loff);
+		break;
+	}
+	putchar('\n');
 }
 
 static void