Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

ARM Assembly for eVC with the Mono Jit Macros

, 14 Jul 2007 CPOL
ARM assembly for eVC with the Mono Jit macros
armjitce.zip
ARMJitCE
ArmJit.vcp
ArmJit.vcw
ARMRel
ArmJit.lib
test.exe
ARMV4Rel
ArmJit.lib
test.exe
hidpi.res
libsrc
test.vcp
/*
 * Copyright (c) 2002 Sergey Chaban <serge@wildwestsoftware.com>
 */


#include <stdarg.h>

#include "arm-dis.h"
#include "arm-codegen.h"


static ARMDis* gdisasm = NULL;

static int use_reg_alias = 1;

const static char* cond[] = {
	"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
	"hi", "ls", "ge", "lt", "gt", "le", "", "nv"
};

const static char* ops[] = {
	"and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc",
	"tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn"
};

const static char* shift_types[] = {"lsl", "lsr", "asr", "ror"};

const static char* mul_ops[] = {
	"mul", "mla", "?", "?", "umull", "umlal", "smull", "smlal"
};

const static char* reg_alias[] = {
	"a1", "a2", "a3", "a4",
	"r4", "r5", "r6", "r7", "r8", "r9", "r10",
	"fp", "ip", "sp", "lr", "pc"
};

const static char* msr_fld[] = {"f", "c", "x", "?", "s"};


/* private functions prototypes (to keep compiler happy) */
void chk_out(ARMDis* dis);
void dump_reg(ARMDis* dis, int reg);
void dump_creg(ARMDis* dis, int creg);
void dump_reglist(ARMDis* dis, int reg_list);
void init_gdisasm(void);

void dump_br(ARMDis* dis, ARMInstr i);
void dump_cdp(ARMDis* dis, ARMInstr i);
void dump_cdt(ARMDis* dis, ARMInstr i);
void dump_crt(ARMDis* dis, ARMInstr i);
void dump_dpi(ARMDis* dis, ARMInstr i);
void dump_hxfer(ARMDis* dis, ARMInstr i);
void dump_mrs(ARMDis* dis, ARMInstr i);
void dump_mrt(ARMDis* dis, ARMInstr i);
void dump_msr(ARMDis* dis, ARMInstr i);
void dump_mul(ARMDis* dis, ARMInstr i);
void dump_swi(ARMDis* dis, ARMInstr i);
void dump_swp(ARMDis* dis, ARMInstr i);
void dump_wxfer(ARMDis* dis, ARMInstr i);
void dump_clz(ARMDis* dis, ARMInstr i);


/*
void out(ARMDis* dis, const char* format, ...) {
	va_list arglist;
	va_start(arglist, format);
	fprintf(dis->dis_out, format, arglist);
	va_end(arglist);
}
*/


void chk_out(ARMDis* dis) {
	if (dis != NULL && dis->dis_out == NULL) dis->dis_out = stdout;
}


void armdis_set_output(ARMDis* dis, FILE* f) {
	if (dis != NULL) {
		dis->dis_out = f;
		chk_out(dis);
	}
}

FILE* armdis_get_output(ARMDis* dis) {
	return (dis != NULL ? dis->dis_out : NULL);
}




void dump_reg(ARMDis* dis, int reg) {
	reg &= 0xF;
	if (!use_reg_alias || (reg > 3 && reg < 11)) {
		fprintf(dis->dis_out, "r%d", reg);
	} else {
		fprintf(dis->dis_out, reg_alias[reg]);
	}
}

void dump_creg(ARMDis* dis, int creg) {
	if (dis != NULL) {
		creg &= 0xF;
		fprintf(dis->dis_out, "c%d", creg);
	}
}

void dump_reglist(ARMDis* dis, int reg_list) {
	int i = 0, j, n = 0;
	int m1 = 1, m2, rn;
	while (i < 16) {
		if ((reg_list & m1) != 0) {
			if (n != 0) fprintf(dis->dis_out, ", ");
			n++;
			dump_reg(dis, i);
			for (j = i+1, rn = 0, m2 = m1<<1; j < 16; ++j, m2<<=1) {
				if ((reg_list & m2) != 0) ++rn;
				else break;
			}
			i+=rn;
			if (rn > 1) {
				fprintf(dis->dis_out, "-");
				dump_reg(dis, i);
			} else if (rn == 1) {
				fprintf(dis->dis_out, ", ");
				dump_reg(dis, i);
			}
			m1<<=(rn+1);
			i++;
		} else {
			++i;
			m1<<=1;
		}
	}
}


void dump_br(ARMDis* dis, ARMInstr i) {
	fprintf(dis->dis_out, "b%s%s\t%x\t; %p -> %p",
	    (i.br.link == 1) ? "l" : "",
	    cond[i.br.cond], i.br.offset, dis->pi, (int)dis->pi + 4*2 + ((int)(i.br.offset << 8) >> 6));
}


void dump_dpi(ARMDis* dis, ARMInstr i) {
	fprintf(dis->dis_out, "%s%s", ops[i.dpi.all.opcode], cond[i.dpi.all.cond]);

	if ((i.dpi.all.opcode < ARMOP_TST || i.dpi.all.opcode > ARMOP_CMN) && (i.dpi.all.s != 0)) {
		fprintf(dis->dis_out, "s");
	}

	fprintf(dis->dis_out, "\t");

	if ((i.dpi.all.opcode < ARMOP_TST) || (i.dpi.all.opcode > ARMOP_CMN)) {
		/* for comparison operations Rd is ignored */
		dump_reg(dis, i.dpi.all.rd);
		fprintf(dis->dis_out, ", ");
	}

	if ((i.dpi.all.opcode != ARMOP_MOV) && (i.dpi.all.opcode != ARMOP_MVN)) {
		/* for MOV/MVN Rn is ignored */
		dump_reg(dis, i.dpi.all.rn);
		fprintf(dis->dis_out, ", ");
	}

	if (i.dpi.all.type == 1) {
		/* immediate */
		if (i.dpi.op2_imm.rot != 0) {
			fprintf(dis->dis_out, "#%d, %d\t; 0x%x", i.dpi.op2_imm.imm, i.dpi.op2_imm.rot << 1,
			        ARM_SCALE(i.dpi.op2_imm.imm, (i.dpi.op2_imm.rot << 1)) );
		} else {
			fprintf(dis->dis_out, "#%d\t; 0x%x", i.dpi.op2_imm.imm, i.dpi.op2_imm.imm);
		}
	} else {
		/* reg-reg */
		if (i.dpi.op2_reg.tag == 0) {
			/* op2 is reg shift by imm */
			dump_reg(dis, i.dpi.op2_reg_imm.r2.rm);
			if (i.dpi.op2_reg_imm.imm.shift != 0) {
				fprintf(dis->dis_out, " %s #%d", shift_types[i.dpi.op2_reg_imm.r2.type], i.dpi.op2_reg_imm.imm.shift);
			}
		} else {
			/* op2 is reg shift by reg */
			dump_reg(dis, i.dpi.op2_reg_reg.r2.rm);
			fprintf(dis->dis_out, " %s ", shift_types[i.dpi.op2_reg_reg.r2.type]);
			dump_reg(dis, i.dpi.op2_reg_reg.reg.rs);
		}

	}
}

void dump_wxfer(ARMDis* dis, ARMInstr i) {
	fprintf(dis->dis_out, "%s%s%s%s\t",
		(i.wxfer.all.ls == 0) ? "str" : "ldr",
		cond[i.generic.cond],
		(i.wxfer.all.b == 0) ? "" : "b",
		(i.wxfer.all.ls != 0 && i.wxfer.all.wb != 0) ? "t" : "");
	dump_reg(dis, i.wxfer.all.rd);
	fprintf(dis->dis_out, ", [");
	dump_reg(dis, i.wxfer.all.rn);
	fprintf(dis->dis_out, "%s, ", (i.wxfer.all.p == 0) ? "]" : "");

	if (i.wxfer.all.type == 0) { /* imm */
		fprintf(dis->dis_out, "#%s%d", (i.wxfer.all.u == 0) ? "-" : "", i.wxfer.all.op2_imm);
	} else {
		dump_reg(dis, i.wxfer.op2_reg_imm.r2.rm);
		if (i.wxfer.op2_reg_imm.imm.shift != 0) {
			fprintf(dis->dis_out, " %s #%d", shift_types[i.wxfer.op2_reg_imm.r2.type], i.wxfer.op2_reg_imm.imm.shift);
		}
	}

	if (i.wxfer.all.p != 0) {
		/* close pre-index instr, also check for write-back */
		fprintf(dis->dis_out, "]%s", (i.wxfer.all.wb != 0) ? "!" : "");
	}
}

void dump_hxfer(ARMDis* dis, ARMInstr i) {
	fprintf(dis->dis_out, "%s%s%s%s\t",
		(i.hxfer.ls == 0) ? "str" : "ldr",
		cond[i.generic.cond],
		(i.hxfer.s != 0) ? "s" : "",
		(i.hxfer.h != 0) ? "h" : "b");
	dump_reg(dis, i.hxfer.rd);
	fprintf(dis->dis_out, ", [");
	dump_reg(dis, i.hxfer.rn);
	fprintf(dis->dis_out, "%s, ", (i.hxfer.p == 0) ? "]" : "");

	if (i.hxfer.type != 0) { /* imm */
		fprintf(dis->dis_out, "#%s%d", (i.hxfer.u == 0) ? "-" : "", (i.hxfer.imm_hi << 4) | i.hxfer.rm);
	} else {
		dump_reg(dis, i.hxfer.rm);
	}

	if (i.hxfer.p != 0) {
		/* close pre-index instr, also check for write-back */
		fprintf(dis->dis_out, "]%s", (i.hxfer.wb != 0) ? "!" : "");
	}
}


void dump_mrt(ARMDis* dis, ARMInstr i) {
	fprintf(dis->dis_out, "%s%s%s%s\t", (i.mrt.ls == 0) ? "stm" : "ldm", cond[i.mrt.cond],
	        (i.mrt.u == 0) ? "d" : "i", (i.mrt.p == 0) ? "a" : "b");
	dump_reg(dis, i.mrt.rn);
	fprintf(dis->dis_out, "%s, {", (i.mrt.wb != 0) ? "!" : "");
	dump_reglist(dis, i.mrt.reg_list);
	fprintf(dis->dis_out, "}");
}


void dump_swp(ARMDis* dis, ARMInstr i) {
	fprintf(dis->dis_out, "swp%s%s ", cond[i.swp.cond], (i.swp.b != 0) ? "b" : "");
	dump_reg(dis, i.swp.rd);
	fprintf(dis->dis_out, ", ");
	dump_reg(dis, i.swp.rm);
	fprintf(dis->dis_out, ", [");
	dump_reg(dis, i.swp.rn);
	fprintf(dis->dis_out, "]");
}


void dump_mul(ARMDis* dis, ARMInstr i) {
	fprintf(dis->dis_out, "%s%s%s\t", mul_ops[i.mul.opcode], cond[i.mul.cond], (i.mul.s != 0) ? "s" : "");
	switch (i.mul.opcode) {
	case ARMOP_MUL:
		dump_reg(dis, i.mul.rd);
		fprintf(dis->dis_out, ", ");
		dump_reg(dis, i.mul.rm);
		fprintf(dis->dis_out, ", ");
		dump_reg(dis, i.mul.rs);
		break;
	case ARMOP_MLA:
		dump_reg(dis, i.mul.rd);
		fprintf(dis->dis_out, ", ");
		dump_reg(dis, i.mul.rm);
		fprintf(dis->dis_out, ", ");
		dump_reg(dis, i.mul.rs);
		fprintf(dis->dis_out, ", ");
		dump_reg(dis, i.mul.rn);
		break;
	case ARMOP_UMULL:
	case ARMOP_UMLAL:
	case ARMOP_SMULL:
	case ARMOP_SMLAL:
		dump_reg(dis, i.mul.rd);
		fprintf(dis->dis_out, ", ");
		dump_reg(dis, i.mul.rn);
		fprintf(dis->dis_out, ", ");
		dump_reg(dis, i.mul.rm);
		fprintf(dis->dis_out, ", ");
		dump_reg(dis, i.mul.rs);
		break;
	default:
		fprintf(dis->dis_out, "DCD 0x%x\t; <unknown>", i.raw);
		break;
	}
}


void dump_cdp(ARMDis* dis, ARMInstr i) {
	fprintf(dis->dis_out, "cdp%s\tp%d, %d, ", cond[i.generic.cond], i.cdp.cpn, i.cdp.op);
	dump_creg(dis, i.cdp.crd);
	fprintf(dis->dis_out, ", ");
	dump_creg(dis, i.cdp.crn);
	fprintf(dis->dis_out, ", ");
	dump_creg(dis, i.cdp.crm);

	if (i.cdp.op2 != 0) {
		fprintf(dis->dis_out, ", %d", i.cdp.op2);
	}
}


void dump_cdt(ARMDis* dis, ARMInstr i) {
	fprintf(dis->dis_out, "%s%s%s\tp%d, ", (i.cdt.ls == 0) ? "stc" : "ldc",
	        cond[i.generic.cond], (i.cdt.n != 0) ? "l" : "", i.cdt.cpn);
	dump_creg(dis, i.cdt.crd);
	fprintf(dis->dis_out, ", ");
	dump_reg(dis, i.cdt.rn);

	if (i.cdt.p == 0) {
		fprintf(dis->dis_out, "]");
	}

	if (i.cdt.offs != 0) {
		fprintf(dis->dis_out, ", #%d", i.cdt.offs);
	}

	if (i.cdt.p != 0) {
		fprintf(dis->dis_out, "]%s", (i.cdt.wb != 0) ? "!" : "");
	}
}


void dump_crt(ARMDis* dis, ARMInstr i) {
	fprintf(dis->dis_out, "%s%s\tp%d, %d, ", (i.crt.ls == 0) ? "mrc" : "mcr",
	        cond[i.generic.cond], i.crt.cpn, i.crt.op1);
	dump_reg(dis, i.crt.rd);
	fprintf(dis->dis_out, ", ");
	dump_creg(dis, i.crt.crn);
	fprintf(dis->dis_out, ", ");
	dump_creg(dis, i.crt.crm);

	if (i.crt.op2 != 0) {
		fprintf(dis->dis_out, ", %d", i.crt.op2);
	}
}


void dump_msr(ARMDis* dis, ARMInstr i) {
	fprintf(dis->dis_out, "msr%s\t%spsr_, ", cond[i.generic.cond],
	        (i.msr.all.sel == 0) ? "s" : "c");
	if (i.msr.all.type == 0) {
		/* reg */
		fprintf(dis->dis_out, "%s, ", msr_fld[i.msr.all.fld]);
		dump_reg(dis, i.msr.all.rm);
	} else {
		/* imm */
		fprintf(dis->dis_out, "f, #%d", i.msr.op2_imm.imm << i.msr.op2_imm.rot);
	}
}


void dump_mrs(ARMDis* dis, ARMInstr i) {
	fprintf(dis->dis_out, "mrs%s\t", cond[i.generic.cond]);
	dump_reg(dis, i.mrs.rd);
	fprintf(dis->dis_out, ", %spsr", (i.mrs.sel == 0) ? "s" : "c");
}


void dump_swi(ARMDis* dis, ARMInstr i) {
	fprintf(dis->dis_out, "swi%s\t%d", cond[i.generic.cond], i.swi.num);
}


void dump_clz(ARMDis* dis, ARMInstr i) {
	fprintf(dis->dis_out, "clz%s\t");
	dump_reg(dis, i.clz.rd);
	fprintf(dis->dis_out, ", ");
	dump_reg(dis, i.clz.rm);
	fprintf(dis->dis_out, "\n");
}



void armdis_decode(ARMDis* dis, void* p, int size) {
	int i;
	arminstr_t* pi = (arminstr_t*)p;
	ARMInstr instr;

	if (dis == NULL) return;

	chk_out(dis);

	size/=sizeof(arminstr_t);

	for (i=0; i<size; ++i) {
		fprintf(dis->dis_out, "%p:\t%08x\t", pi, *pi);
		dis->pi = pi;
		instr.raw = *pi++;

		if ((instr.raw & ARM_BR_MASK) == ARM_BR_TAG) {
			dump_br(dis, instr);
		} else if ((instr.raw & ARM_SWP_MASK) == ARM_SWP_TAG) {
			dump_swp(dis, instr);
		} else if ((instr.raw & ARM_MUL_MASK) == ARM_MUL_TAG) {
			dump_mul(dis, instr);
		} else if ((instr.raw & ARM_CLZ_MASK) == ARM_CLZ_TAG) {
			dump_clz(dis, instr);
		} else if ((instr.raw & ARM_WXFER_MASK) == ARM_WXFER_TAG) {
			dump_wxfer(dis, instr);
		} else if ((instr.raw & ARM_HXFER_MASK) == ARM_HXFER_TAG) {
			dump_hxfer(dis, instr);
		} else if ((instr.raw & ARM_DPI_MASK) == ARM_DPI_TAG) {
			dump_dpi(dis, instr);
		} else if ((instr.raw & ARM_MRT_MASK) == ARM_MRT_TAG) {
			dump_mrt(dis, instr);
		} else if ((instr.raw & ARM_CDP_MASK) == ARM_CDP_TAG) {
			dump_cdp(dis, instr);
		} else if ((instr.raw & ARM_CDT_MASK) == ARM_CDT_TAG) {
			dump_cdt(dis, instr);
		} else if ((instr.raw & ARM_CRT_MASK) == ARM_CRT_TAG) {
			dump_crt(dis, instr);
		} else if ((instr.raw & ARM_MSR_MASK) == ARM_MSR_TAG) {
			dump_msr(dis, instr);
		} else if ((instr.raw & ARM_MRS_MASK) == ARM_MRS_TAG) {
			dump_mrs(dis, instr);
		} else if ((instr.raw & ARM_SWI_MASK) == ARM_SWI_TAG) {
			dump_swi(dis, instr);
		} else {
			fprintf(dis->dis_out, "DCD 0x%x\t; <unknown>", instr.raw);
		}

		fprintf(dis->dis_out, "\n");
	}
}


void armdis_open(ARMDis* dis, const char* dump_name) {
	if (dis != NULL && dump_name != NULL) {
		armdis_set_output(dis, fopen(dump_name, "w"));
	}
}


void armdis_close(ARMDis* dis) {
	if (dis->dis_out != NULL && dis->dis_out != stdout && dis->dis_out != stderr) {
		fclose(dis->dis_out);
		dis->dis_out = NULL;
	}
}


void armdis_dump(ARMDis* dis, const char* dump_name, void* p, int size) {
	armdis_open(dis, dump_name);
	armdis_decode(dis, p, size);
	armdis_close(dis);
}


void armdis_init(ARMDis* dis) {
	if (dis != NULL) {
		/* set to stdout */
		armdis_set_output(dis, NULL);
	}
}




void init_gdisasm() {
	if (gdisasm == NULL) {
		gdisasm = (ARMDis*)malloc(sizeof(ARMDis));
		armdis_init(gdisasm);
	}
}

void _armdis_set_output(FILE* f) {
	init_gdisasm();
	armdis_set_output(gdisasm, f);
}

FILE* _armdis_get_output() {
	init_gdisasm();
	return armdis_get_output(gdisasm);
}

void _armdis_decode(void* p, int size) {
	init_gdisasm();
	armdis_decode(gdisasm, p, size);
}

void _armdis_open(const char* dump_name) {
	init_gdisasm();
	armdis_open(gdisasm, dump_name);
}

void _armdis_close() {
	init_gdisasm();
	armdis_close(gdisasm);
}

void _armdis_dump(const char* dump_name, void* p, int size) {
	init_gdisasm();
	armdis_dump(gdisasm, dump_name, p, size);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Sjoerd_B

Netherlands Netherlands
Sjoerd Bakker was a 6510 (C64) machine language editor for a Dutch computer magazine in the mid eighties of the previous century.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141223.1 | Last Updated 14 Jul 2007
Article Copyright 2007 by Sjoerd_B
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid