FreeCalypso > hg > freecalypso-reveng
diff arm7dis/armdis.c @ 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 |
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