* More opcodes supported by the arm thumb assembler

- Just missing ldr{b,h} and str{b,h}
* Added armthumb_length() function to retrieve opcode length
This commit is contained in:
pancake 2010-10-07 11:20:12 +02:00
parent a8c641a0a6
commit 6b3883cc43
5 changed files with 69 additions and 28 deletions

8
libr/asm/arch/arm/arm.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _INCLUDE_ARMTHUMB_H_
#define _INCLUDE_ARMTHUMB_H_
int armthumb_length(unsigned int ins);
int armthumb_disassemble(char *buf, unsigned long pc, unsigned int ins);
int armass_assemble(const char *str, unsigned long off, int thumb);
#endif

View File

@ -4,6 +4,8 @@
#include <string.h>
#include <stdlib.h>
// TODO: only lo registers accessible in thumb arm
// TODO: add support for ldrb, ldrh, strb, strh
typedef struct {
unsigned long off;
@ -175,6 +177,7 @@ static inline int arm_opcode_cond(ArmOpcode *ao, int delta) {
}
// str, ldr
// TODO: group similar instructions like for non-thumb
static int thumb_assemble(ArmOpcode *ao, const char *str) {
// TODO: Add thumb mode
// mov r, n = 2[r0-7][nn]
@ -243,18 +246,17 @@ static int thumb_assemble(ArmOpcode *ao, const char *str) {
if (!strcmp (ao->a1, "sp")) {
// ldr r0, [sp, n] = a[r0-7][nn]
if (getreg (ao->a2) == -1) {
// ldr r0, [sp, n]
ao->o = 0x98 + (0xf & getreg (ao->a0));
ao->o |= (0xff & getnum (ao->a2)/4)<<8;
} else {
ao->o = 0x58;// + (0xf & getreg (ao->a0));
ao->o |= (0xff & getreg (ao->a2)/4)<<8;
printf("DUnno\n");
}
} else return 0;
} else
if (!strcmp (ao->a1, "pc")) {
// ldr r0, [pc, n] = 4[r0-8][nn*4]
ao->o = 0x40 | (0xf & getreg (ao->a0));
ao->o |= (0xff & getnum (ao->a2)/4)<<8;
if (getreg (ao->a2) == -1) {
ao->o = 0x40 | 8+(0xf & getreg (ao->a0));
ao->o |= (0xff & getnum (ao->a2)/4)<<8;
} else return 0;
} else {
// ldr r0, [rN, rN] = 58[7bits:basereg + 7bits:destreg]
int a0 = getreg (ao->a0);
@ -276,15 +278,44 @@ static int thumb_assemble(ArmOpcode *ao, const char *str) {
// " strb = 8
// str r0, [rN, n] = 6[n*16][7bits:basereg + 7bits:destreg]
// str r0, [rN, rN] = 50[7bits:basereg + 7bits:destreg]
// 0: 6191 str r1, [r2, #24]
// 2: 50d1 str r1, [r2, r3]
getrange (ao->a1);
getrange (ao->a2);
if (!strcmp (ao->a1, "sp")) {
// ldr r0, [sp, n] = a[r0-7][nn]
if (getreg (ao->a2) == -1) {
int ret = getnum (ao->a2);
if (ret%4) {
fprintf (stderr, "ldr index must be aligned to 4");
return 0;
}
ao->o = 0x90 + (0xf & getreg (ao->a0));
ao->o |= (0xff & getnum (ao->a2)/4)<<8;
} else return 0;
} else
if (!strcmp (ao->a1, "pc")) {
return 0;
} else {
// str
int a0 = getreg (ao->a0);
int a1 = getreg (ao->a1);
int a2 = getreg (ao->a2);
if (a2 == -1) {
a2 = getnum (ao->a2)>>1;
ao->o = 0x60; // | (8+(0xf & a0));
ao->o |= (7&a0)<<8;
ao->o |= (7&a1)<<11;
if (a2<0||a2>12) {
fprintf (stderr, "Invalid range in str\n");
return 0;
}
ao->o |= (3&(a2/4))<<14; // XXX: must limit delta in 12
} else {
printf ("DUnno\n");
ao->o = 0x50; // | (8+(0xf & a0));
ao->o |= (7&a0)<<8;
ao->o |= (7&a1)<<11;
ao->o |= (3&a2)<<14;
}
}
} else
@ -483,20 +514,20 @@ int main() {
thisplay("bne 44");
thisplay("and r2,r3");
#endif
// INVALID thisplay("ldr r1, [pc, r2]");
// INVALID thisplay("ldr r1, [sp, r2]");
#if 0
thisplay("ldr r1, [pc, r2]");
thisplay("ldr r1, [pc, 12]");
thisplay("ldr r1, [sp, r2]");
thisplay("ldr r1, [sp, 24]");
#endif
thisplay("ldr r1, [r2, r3]");
#if 0
thisplay("str r1, [pc, r2]");
thisplay("str r1, [pc, 12]");
thisplay("str r1, [sp, r2]");
thisplay("str r1, [sp, 24]");
thisplay("str r1, [r2, r3]");
#endif
// INVALID thisplay("str r1, [pc, 22]");
// INVALID thisplay("str r1, [pc, r2]");
// INVALID thisplay("str r1, [sp, r2]");
thisplay("str r1, [sp, 20]"); // aligned to 4
thisplay("str r1, [r2, 12]"); // OK
thisplay("str r1, [r2, r3]");
return 0;
#if 0
display("mov r0, 33");

View File

@ -78,6 +78,13 @@ static const char* compute_reg_list (unsigned list) {
return tmpbuf;
}
int armthumb_length(unsigned int ins) {
if ((ins & _($1110,$1000,0,0)) == _($1110,0,0,0))
if (ins & _(1,$1000,0,0))
return 4;
return 2;
}
int armthumb_disassemble(char *buf, unsigned long pc, unsigned int ins) {
unsigned int delta, imm, jump, op_code, instr2 = ins >> 16;
const char* op;

View File

@ -3,14 +3,12 @@
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <r_types.h>
#include <r_util.h>
#include <r_lib.h>
#include <r_asm.h>
#include "dis-asm.h"
#include "../arch/arm/arm.h"
static int arm_mode = 0;
static unsigned long Offset = 0;
@ -81,7 +79,6 @@ static int disassemble(struct r_asm_t *a, struct r_asm_aop_t *aop, ut8 *buf, ut6
return aop->inst_len; //(a->bits/8); //aop->inst_len;
}
int armass_assemble(const char *str, unsigned long off, int thumb);
static int assemble(RAsm *a, RAsmAop *aop, const char *buf) {
int op = armass_assemble(buf, a->pc, (a->bits==16)?1:0);
if (op==-1)

View File

@ -7,25 +7,23 @@
#include <r_util.h>
#include <r_lib.h>
#include <r_asm.h>
int armthumb_disassemble(char *buf, unsigned long pc, unsigned int ins); //
#include "../arch/arm/arm.h"
static int disassemble(RAsm *a, RAsmAop *aop, ut8 *buf, ut64 len) {
int *p = (int*)buf; // TODO : endian
aop->buf_asm[0]='\0';
aop->inst_len = armthumb_disassemble (aop->buf_asm, (ut32)a->pc, *p);
if (!aop->inst_len)
strncpy(aop->buf_asm, " (data)", R_ASM_BUFSIZE);
strncpy (aop->buf_asm, " (data)", R_ASM_BUFSIZE);
return aop->inst_len;
}
int armass_assemble(const char *str, unsigned long off);
static int assemble(RAsm *a, RAsmAop *aop, const char *buf) {
int op = armass_assemble(buf, a->pc);
int op = armass_assemble (buf, a->pc, R_TRUE);
if (op==-1)
return -1;
r_mem_copyendian (aop->buf, (void *)&op, 4, a->big_endian);
return (a->bits/8);
r_mem_copyendian (aop->buf, (void *)&op, 2, a->big_endian);
return armthumb_length (op);
}
RAsmPlugin r_asm_plugin_armthumb = {