mirror of
https://github.com/radareorg/radare2-extras.git
synced 2026-11-08 09:10:01 -10:00
[WIP] Apollo Guidance Computer disassembly (#54)
* Implemented basic structure for AGC plugin. Implemented integration into build system and layout, as well as some barebones setup code. Now onto the actual logic :3 * Added basic structure of AGC disassembler The core disassembly logic has been ported over from https://github.com/alfonsokim/apollo-guidance-computer/blob/master/yaAGC/agc_disassembler.c . However, since the disassembler is inherently stateful, we still need to implement either state or port over the whole lib / rewrite it. Or I get to find a different solution for this. * Done some research and gathered some information It seems clear how to get the current address etc. from the data passed to the plugin without resorting to internal state. That way a lot of complexity should be avoidable and implementation gets a lot easier. * Cleaned up logic * Integrated things * Finished integration of disasm plugin. * Worked through the AGC instruction set Gathered info needed for the anal plugin and commented the disassembler components. * Fixed compiler error * Added some constants and fixed errors * Added help file
This commit is contained in:
1 parent
2d7912b5e8
commit
6fa7ca813b
11 files changed
+620
No files matched your search
@@ -0,0 +1,82 @@
|
||||
VERSION=0.10.4
|
||||
HAVE_LIB_YARA=0
|
||||
PREFIX=/usr
|
||||
DESTDIR?=
|
||||
TAR=tar -cvf
|
||||
CZ=xz -f
|
||||
|
||||
DIRS=
|
||||
ifeq ($(HAVE_LIB_YARA),1)
|
||||
DIRS+=yara/yara2
|
||||
DIRS+=yara/yara3
|
||||
DIRS+=libr/asm/p
|
||||
DIRS+=libr/anal/p
|
||||
endif
|
||||
|
||||
help:
|
||||
@echo "Usage make [target] .. Targets:"
|
||||
@echo " all - build everything"
|
||||
@echo " baleful - build baleful r2 plugin"
|
||||
@echo " asm - build armthumb, ppc, psosvm, x86bea, m68k plugins"
|
||||
@echo " anal - build analysis plugins (RAnal)"
|
||||
@echo " debug - build debugger plugins (RDebug)"
|
||||
@echo " dlang - support DLang demangler (RBin)"
|
||||
@echo " yara{2,3} - build yara2 or yara3 r2 plugin"
|
||||
@echo " (target)-install - install given plugin"
|
||||
@echo " (target)-clean - clean given plugin"
|
||||
@echo " install-yara{2,3} - install Yara 2 or 3 from Git"
|
||||
|
||||
baleful:
|
||||
$(MAKE) -C baleful
|
||||
debug unicorn:
|
||||
$(MAKE) -C libr/debug/p
|
||||
anal:
|
||||
$(MAKE) -C libr/anal/p
|
||||
asm:
|
||||
$(MAKE) -C libr/asm/p
|
||||
asm-install:
|
||||
$(MAKE) -C libr/asm/p install DESTDIR=$(DESTDIR)
|
||||
asm-clean:
|
||||
$(MAKE) -C libr/asm/p clean
|
||||
dlang:
|
||||
$(MAKE) -C libr/bin/p
|
||||
dlang-install:
|
||||
$(MAKE) -C libr/bin/p install DESTDIR=$(DESTDIR)
|
||||
yara2 yara3:
|
||||
cd yara/$@ ; ./configure --prefix=$(PREFIX)
|
||||
$(MAKE) -C yara/$@
|
||||
yara2-clean:
|
||||
$(MAKE) -C yara/yara2 clean
|
||||
yara3-clean:
|
||||
$(MAKE) -C yara/yara3 clean
|
||||
baleful-install:
|
||||
$(MAKE) -C baleful install DESTDIR=$(DESTDIR)
|
||||
debug-install unicorn-install:
|
||||
$(MAKE) -C libr/debug/p install DESTDIR=$(DESTDIR)
|
||||
debug-uninstall unicorn-uninstall:
|
||||
$(MAKE) -C libr/debug/p uninstall DESTDIR=$(DESTDIR)
|
||||
yara2-install:
|
||||
$(MAKE) -C yara/yara2 install DESTDIR=$(DESTDIR)
|
||||
yara3-install:
|
||||
$(MAKE) -C yara/yara3 install DESTDIR=$(DESTDIR)
|
||||
|
||||
all:
|
||||
for a in $(DIRS) ; do \
|
||||
( cd $$a ; ./configure --prefix=$(PREFIX) ; $(MAKE) ) ; \
|
||||
done
|
||||
|
||||
clean mrproper install symstall uninstall deinstall:
|
||||
for a in $(DIRS) ; do ( cd $$a ; $(MAKE) $@ ) ; done
|
||||
|
||||
dist:
|
||||
DIR=`basename $$PWD` ; \
|
||||
FILES=`git ls-files | sed -e s,^,radare2-extras-${VERSION}/,` ; \
|
||||
cd .. && mv $${DIR} radare2-extras-${VERSION} && \
|
||||
${TAR} radare2-extras-${VERSION}.tar $${FILES} ; \
|
||||
${CZ} radare2-extras-${VERSION}.tar ; \
|
||||
mv radare2-extras-${VERSION} $${DIR}
|
||||
|
||||
w32dist:
|
||||
@echo TODO: w32dist
|
||||
|
||||
.PHONY: dist all
|
||||
@@ -1,5 +1,6 @@
|
||||
ARCHS=
|
||||
|
||||
ARCHS+=agc.mk
|
||||
ARCHS+=x86_bea.mk
|
||||
#ARCHS+=x86_im.mk
|
||||
ARCHS+=x86_simple.mk
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
OBJ_AGC=anal_agc.o
|
||||
|
||||
STATIC_OBJ+=${OBJ_AGC}
|
||||
TARGET_AGC=anal_agc.${LIBEXT}
|
||||
|
||||
ALL_TARGETS+=${TARGET_AGC}
|
||||
|
||||
${TARGET_AGC}: ${OBJ_AGC}
|
||||
${CC} $(call libname,anal_agc) ${LDFLAGS} \
|
||||
${CFLAGS} -o anal_agc.${LIBEXT} ${OBJ_AGC}
|
||||
@@ -0,0 +1,36 @@
|
||||
#include <r_types.h>
|
||||
#include <r_lib.h>
|
||||
#include <r_util.h>
|
||||
#include <r_anal.h>
|
||||
|
||||
static int agc_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len) {
|
||||
// TODO: get rid of this, we have that in our disassembler already
|
||||
static bool extra_opcode_bit = false;
|
||||
if (!data || len != 2) return -1;
|
||||
op->size = 2;
|
||||
op->type = R_ANAL_OP_TYPE_UNK;
|
||||
|
||||
if (!extra_opcode_bit) {
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
return op->size;
|
||||
}
|
||||
|
||||
RAnalPlugin r_anal_plugin_agc = {
|
||||
.name = "agc",
|
||||
.desc = "AGC code analysis plugin",
|
||||
.license = "LGPL3",
|
||||
.arch = "agc",
|
||||
.bits = 16,
|
||||
.op = &agc_op,
|
||||
};
|
||||
|
||||
#ifndef CORELIB
|
||||
RLibStruct radare_plugin = {
|
||||
.type = R_LIB_TYPE_ANAL,
|
||||
.data = &r_anal_plugin_agc,
|
||||
.version = R2_VERSION
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,350 @@
|
||||
/*
|
||||
Copyright 2003-2006 Ronald S. Burkey <[email protected]>,
|
||||
2008 Onno Hommes
|
||||
2016 Inokentiy Babushkin
|
||||
|
||||
This file is based on the implmentation found in yaAGC, but modified for new
|
||||
purposes.
|
||||
|
||||
This file is part of yaAGC / radare2-extras.
|
||||
yaAGC is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
yaAGC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with yaAGC; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Filename: agc_disassembler.h
|
||||
Purpose: Source file for AGC Disassembler.
|
||||
Contact: Onno Hommes
|
||||
Reference: http://www.ibiblio.org/apollo
|
||||
Mods: 08/31/08 OH. Began.
|
||||
07/12/16 IB. Began refactoring to include in radare2-extras.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include "asm_agc.h"
|
||||
|
||||
/*
|
||||
* We need to find out what the logic behind the modifications done by
|
||||
* ShowAddressContents() is. Since that function performs some lookup
|
||||
* on the internal state of the AGC *simulator*, it is very well possible
|
||||
* we can simplify things a fair bit. This would also mean that we might be
|
||||
* able to reduce the decoding work to interpreting the EXTEND instruction
|
||||
* as a prefix, since that's it's only function as far as we know so far.
|
||||
*
|
||||
* However, if the assembling/disassembling doesn't yield the desired
|
||||
* results, we will be in deep trouble already.
|
||||
*
|
||||
* So far, the best thing to do is to document the functionality of the
|
||||
* different static variables employes:
|
||||
* * sCurrentZ: the current address to be disassembled.
|
||||
* It appears that they are handled differently depending on their value.
|
||||
* For instance, the bank gets computed using them (duh).
|
||||
* * sBank: the memory bank the address maps to.
|
||||
* Memory bank addressing was used because of storage shortage for
|
||||
* adresses, which led to this workaround. Banks have different sizes
|
||||
* (1K or 256 bytes), thus they get used differently in the code.
|
||||
* * sValue: the memory value at the location denoted by the address.
|
||||
* * sErasable: whether the data we access is in erasable memory.
|
||||
* * sFixed: whether we are reading from ROM.
|
||||
*
|
||||
* But why are we using two variables to denote mutually exclusive flags?
|
||||
*
|
||||
* We can get the current address from the RAsm structure pointer passed
|
||||
* to disassemble(). Thus, we can compute erasable and fixed.
|
||||
*
|
||||
* NOP's seem to be encoded in a position-depend way, but that's all we
|
||||
* need to handle specially.
|
||||
*/
|
||||
|
||||
#define SWITCH_MASK 070000
|
||||
#define LOWER_WIDE 07777
|
||||
#define LOWER 01777
|
||||
#define HIGHER 06000
|
||||
|
||||
|
||||
void disasm_instruction(unsigned int address, int value, char *buf, int len) {
|
||||
static bool extra_opcode_bit = false;
|
||||
// distinguish between RW and RO memory
|
||||
bool erasable = false;
|
||||
if (address < 02000)
|
||||
erasable = true;
|
||||
|
||||
// instruction encoding is pretty convoluted, since it doesn't work well with
|
||||
// byte boundaries. Thus, every decoding operation below is about to get proper
|
||||
// documentation to allow for better understanding (to write the ESIL and ANAL
|
||||
// bits still needed).
|
||||
// also see http://www.ibiblio.org/apollo/assembly_language_manual.html
|
||||
|
||||
if (!extra_opcode_bit) {
|
||||
// simple instructions below - encoded as follows: x iii ooo ooo ooo
|
||||
// where x is the odd-parity bit, which is used only by the hardware itself
|
||||
// to determine error conditions. However, yaYUL doesn't emulate it, so things
|
||||
// are shifted one bit to the left. TODO: maybe we should change this?
|
||||
|
||||
// first, special cases that have their own mnemonics
|
||||
if (value == 040000) // i = 100, o = 0
|
||||
// complement the A register (address 0)
|
||||
snprintf(buf, len, "com");
|
||||
else if (value == 020001) // i = 010, o = 0, 1
|
||||
// add the A, L register pair to itself (addresses 0 and 1)
|
||||
snprintf(buf, len, "ddoubl");
|
||||
else if (value == 060000) // i = 110, o = 0
|
||||
// add the A register to itself (address 0o)
|
||||
snprintf(buf, len, "double");
|
||||
else if (value == 052006)
|
||||
// change adressing, see manual
|
||||
snprintf(buf, len, "dtcb");
|
||||
else if (value == 052005)
|
||||
// change adressing, see manual
|
||||
snprintf(buf, len, "dtcf");
|
||||
else if (value == 6) {
|
||||
// set extracode flag for next instruction, and the instruction after that,
|
||||
// if it is an index.
|
||||
snprintf(buf, len, "extend");
|
||||
extra_opcode_bit = true;
|
||||
} else if (value == 4)
|
||||
// disable interrupts
|
||||
snprintf(buf, len, "inhint");
|
||||
else if (!erasable && value == address + 1 && value != 10000)
|
||||
// NOOP's are special:
|
||||
// they are encoded as 10000 + current adress in fixed memory...
|
||||
// (which is a jump to the next instruction)
|
||||
snprintf(buf, len, "noop");
|
||||
else if (erasable && value == 030000)
|
||||
// ...and as a constant value in erasable memory, because the jump method
|
||||
// isn't applicable. Note that this way of encoding it means loading the
|
||||
// accumulator (A) with itself.
|
||||
snprintf(buf, len, "noop");
|
||||
else if (value == 054000)
|
||||
// skip the next instruction if A is overflown
|
||||
snprintf(buf, len, "ovsk");
|
||||
else if (value == 3)
|
||||
// enable interrupts after an inhint
|
||||
snprintf(buf, len, "relint");
|
||||
else if (value == 050017)
|
||||
// resume program from an ISR
|
||||
snprintf(buf, len, "resume");
|
||||
else if (value == 2)
|
||||
// return from subroutine, which is to say, move the Q register
|
||||
// into the Z register.
|
||||
snprintf(buf, len, "return");
|
||||
else if (value == 054005) // essentially a `TS Z`
|
||||
// jump to the address stored in the A register
|
||||
snprintf(buf, len, "tcaa");
|
||||
else if (value == 1) // essentially a `TC L`
|
||||
// convoluted control flow primitive from hell, see manual:
|
||||
// load an instruction in the `A` register, and a return instruction into
|
||||
// the `L` register, call `XLQ` and you will execute the contents of `A`
|
||||
// and return.
|
||||
snprintf(buf, len, "xlq");
|
||||
else if (value == 0) // essentially `TC A`
|
||||
// similar to the above, but with extracode:
|
||||
// load an `EXTEND` instruction into the `A` register, an extracode
|
||||
// instruction into the `L` register, a return instruction into the `Q`
|
||||
// register and call `XXALQ`. This results in the execution of the given
|
||||
// extracode instruction.
|
||||
snprintf(buf, len, "xxalq");
|
||||
else if (value == 022007) // essentially `LXCH 7`
|
||||
// zero the `L` register, by exchanging it's content with the 7th register,
|
||||
// which is hardwired to zero.
|
||||
snprintf(buf, len, "zl");
|
||||
else switch (value & SWITCH_MASK) {
|
||||
// from now on, we have instructions with operands, so switch based on
|
||||
// the first three bits.
|
||||
case 000000: // i = 000, o = address of subroutine
|
||||
// call a subroutine (this can't be nested, because it stores the
|
||||
// current contents of the `Z` register in the `Q` register).
|
||||
snprintf(buf, len, "tc\t%04o", value & LOWER_WIDE);
|
||||
break;
|
||||
case 010000: // i = 001
|
||||
if (!(value & 06000)) // one of the many space-saving tricks employed
|
||||
// weird compare and jump (10 bit address in erasable memory)
|
||||
snprintf(buf, len, "ccs\t%04o",value & LOWER);
|
||||
else
|
||||
// jump to a memory location (12 bit address in fixed memory)
|
||||
snprintf(buf, len, "tcf\t%04o", value & LOWER_WIDE);
|
||||
break;
|
||||
case 020000: // i = 010
|
||||
switch (value & 06000) { // lower bits...
|
||||
case 00000:
|
||||
// add the `A`, `L` register pair to a memory location
|
||||
snprintf(buf, len, "das\t%04o", (value - 1) & LOWER);
|
||||
break;
|
||||
case 02000:
|
||||
// exchange the L register and a memory location
|
||||
snprintf(buf, len, "lxch\t%04o", value & LOWER);
|
||||
break;
|
||||
case 04000:
|
||||
// increment a memory location
|
||||
snprintf(buf, len, "incr\t%04o", value & LOWER);
|
||||
break;
|
||||
case 06000:
|
||||
// add the `A` register to a memory location
|
||||
snprintf(buf, len, "ads\t%04o", value & LOWER);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 030000: // i = 011
|
||||
// move a memory location's contents into the `A` register
|
||||
snprintf(buf, len, "ca\t%04o", value & LOWER_WIDE);
|
||||
break;
|
||||
case 040000: // i = 100
|
||||
// move a memory location's complement into the `A` register
|
||||
snprintf(buf, len, "cs\t%04o", value & LOWER_WIDE);
|
||||
break;
|
||||
case 050000: // i = 101
|
||||
switch (value & HIGHER) { // lower bits again...
|
||||
case 00000:
|
||||
// adds the contents of a memory location to the next
|
||||
// instruction before it is executed, without altering memory
|
||||
snprintf(buf, len, "index\t%04o", value & LOWER);
|
||||
break;
|
||||
case 02000:
|
||||
// exchange double precision int with `A`, `L` register pair
|
||||
snprintf(buf, len, "dxch\t%04o", (value - 1) & LOWER);
|
||||
break;
|
||||
case 04000:
|
||||
// copy the contents of the `A` register to memory, with extra
|
||||
// magic when overflow occured.
|
||||
snprintf(buf, len, "ts\t%04o", value & LOWER);
|
||||
break;
|
||||
case 06000:
|
||||
// exchange an erasable memory location with the `A` register
|
||||
snprintf(buf, len, "xch\t%04o", value & LOWER);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 060000: // i = 110
|
||||
// add a memory location to the `A` register
|
||||
snprintf(buf, len, "ad\t%04o", value & LOWER_WIDE);
|
||||
break;
|
||||
case 070000: // i = 111
|
||||
// logical and between the `A` register and a memory location
|
||||
snprintf(buf, len, "mask\t%04o", value & LOWER_WIDE);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// the previous instruction was an `EXTEND`. This means we will interpret
|
||||
// not three, but four leading bits of our intruction as an opcode. This
|
||||
// was added to the second-generation AGC, after it became clear that three
|
||||
// bits for an opcode are not enough.
|
||||
extra_opcode_bit = false;
|
||||
if (value == 040001) // basically a `DCS A`
|
||||
// bitwise complement of the register pair `A`, `L`
|
||||
snprintf(buf, len, "dcom");
|
||||
else if (value == 050017) //
|
||||
// resume program from an ISR
|
||||
snprintf(buf, len, "resume"); // FIXME: wtf is this here? see manual...
|
||||
else if (value == 070000) // essentially `MP A`
|
||||
// square the contents of register `A`
|
||||
snprintf(buf, len, "square");
|
||||
else if (value == 022007) // essentially `QXCH 7`
|
||||
// zero the `Q` register, by exchanging it's content with the 7th register,
|
||||
// which is hardwired to zero.
|
||||
snprintf(buf, len, "zq");
|
||||
else switch (value & SWITCH_MASK) {
|
||||
case 000000: // i = 000
|
||||
switch (value & 07000) { // lower bits
|
||||
case 00000:
|
||||
// read a 9 bit IO channel into register `A`
|
||||
snprintf(buf, len, "read\t%03o", value & 0777);
|
||||
break;
|
||||
case 01000:
|
||||
// write register `A` into a 9 bit IO channel
|
||||
snprintf(buf, len, "write\t%03o", value & 0777);
|
||||
break;
|
||||
case 02000:
|
||||
// read and bitwise and
|
||||
snprintf(buf, len, "rand\t%03o", value & 0777);
|
||||
break;
|
||||
case 03000:
|
||||
// read and bitwise and with writeback
|
||||
snprintf(buf, len, "wand\t%03o", value & 0777);
|
||||
break;
|
||||
case 04000:
|
||||
// read and bitwise or
|
||||
snprintf(buf, len, "ror\t%03o", value & 0777);
|
||||
break;
|
||||
case 05000:
|
||||
// read and bitwise or with writeback
|
||||
snprintf(buf, len, "wor\t%03o", value & 0777);
|
||||
break;
|
||||
case 06000:
|
||||
// read and xor
|
||||
snprintf(buf, len, "rxor\t%03o", value & 0777);
|
||||
break;
|
||||
case 07000:
|
||||
// noone knows o__O
|
||||
snprintf(buf, len, "edrupt\t%03o", value & 0777);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 010000: // i = 001
|
||||
if (!(value & HIGHER))
|
||||
// divide register pair `A`, `L` by a memory location,
|
||||
// putting the quotient/remainder in `A`, `L`, respectively
|
||||
snprintf(buf, len, "dv\t%04o", value & LOWER);
|
||||
else
|
||||
// branch to a fixed memory location if `A` equals 0
|
||||
snprintf(buf, len, "bzf\t%04o", value & LOWER_WIDE);
|
||||
break;
|
||||
case 020000: // i = 010
|
||||
switch (value & HIGHER) {
|
||||
case 00000:
|
||||
// 1's complement difference between two 2's complement values
|
||||
// of which the first is the register `A`
|
||||
snprintf(buf, len, "msu\t%04o", value & LOWER);
|
||||
break;
|
||||
case 02000:
|
||||
// exchange `Q` register with memory location
|
||||
snprintf(buf, len, "qxch\t%04o", value & LOWER);
|
||||
break;
|
||||
case 04000:
|
||||
// increment positive and decrement negative values at a
|
||||
// memory location, using 1's complement
|
||||
snprintf(buf, len, "aug\t%04o", value & LOWER);
|
||||
break;
|
||||
case 06000:
|
||||
// other way 'round
|
||||
snprintf(buf, len, "dim\t%04o", value & LOWER);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 030000: // i = 011
|
||||
// move a pair of registers into `A` and `L`
|
||||
snprintf(buf, len, "dca\t%04o", (value - 1) & LOWER_WIDE);
|
||||
break;
|
||||
case 040000: // i = 100
|
||||
// move the complement of a pair of registers into `A` and `L`
|
||||
snprintf(buf, len, "dcs\t%04o", (value - 1) & LOWER_WIDE);
|
||||
break;
|
||||
case 050000: // i = 101
|
||||
// see above
|
||||
snprintf(buf, len, "index\t%04o", value & LOWER_WIDE);
|
||||
// reset bit
|
||||
extra_op_code_bit = true;
|
||||
break;
|
||||
case 060000: // i = 110
|
||||
if (!(value & HIGHER))
|
||||
// subtract a memory location from the `A` register
|
||||
snprintf(buf, len, "su\t%04o", value & LOWER);
|
||||
else
|
||||
// branch to a fixed memory location if `A` is equal or less than 0
|
||||
snprintf(buf, len, "bzmf\t%04o", value & LOWER_WIDE);
|
||||
break;
|
||||
case 070000: // i = 111
|
||||
// multiply two single precision values to form a double precision
|
||||
// value, of which one is the accumulator.
|
||||
snprintf(buf, len, "mp\t%04o", value & LOWER_WIDE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef INCLUDED_AGC_H
|
||||
#define INCLUDED_AGC_H
|
||||
|
||||
void disasm_instruction(unsigned int address, int value, char *buf, int len);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,54 @@
|
||||
com=complement the `A` register (address 0)
|
||||
ddoubl=add the A, `L` register pair to itself (addresses 0 and 1)
|
||||
double=add the `A` register to itself (address 0o)
|
||||
dtcb=change adressing, see manual
|
||||
dtcf=change adressing, see manual
|
||||
extend=set extracode flag for next instruction, and the instruction after that, if it is an index.
|
||||
inhint=disable interrupts
|
||||
noop=no operation, but note that this is encoded in a context-sensitive fashion
|
||||
ovsk=skip the next instruction if `A` is overflown
|
||||
relint=enable interrupts after an inhint
|
||||
resume=resume program from an ISR
|
||||
return=return from subroutine, which is to say, move the `Q` register into the `Z` register
|
||||
tcaa=jump to the address stored in the `A` register
|
||||
xlq=execute the content of the `A` register, assuming there is a `return` instruction in `L`
|
||||
xxalq=execute the content of the `L` register as an extracode instruction, assuming there is an `extend` instruction in the `A` register and a `return` instruction in `Q`
|
||||
zl=zero the `L` register
|
||||
tc=call a subroutine, can't be nested
|
||||
ccs=weird compare and jump (10 bit address in erasable memory)
|
||||
tcf=jump to a memory location (12 bit address in fixed memory)
|
||||
das=add the `A`, `L` register pair to a memory location
|
||||
lxch=exchange the `L` register and a memory location
|
||||
incr=increment a memory location
|
||||
ads=add the `A` register to a memory location
|
||||
ca=move a memory location's contents into the `A` register
|
||||
cs=move a memory location's complement into the `A` register
|
||||
index=add a memory location to the next instruction before it is executed, without altering memory
|
||||
dxch=exchange double precision int with `A`, `L` register pair
|
||||
ts=copy the contents of the `A` register to memory, with extra magic when overflow occured.
|
||||
xch=exchange an erasable memory location with the `A` register
|
||||
ad=add a memory location to the `A` register
|
||||
mask=logical and between the `A` register and a memory location
|
||||
dcom=bitwise complement of the register pair `A`, `L`
|
||||
resume=resume program from an ISR
|
||||
square=square the contents of register `A`
|
||||
zq=zero the `Q` register
|
||||
read=read a 9 bit IO channel into register `A`
|
||||
write=write register `A` into a 9 bit IO channel
|
||||
rand=read and bitwise and
|
||||
wand=read and bitwise and with writeback
|
||||
ror=read and bitwise or
|
||||
wor=read and bitwise or with writeback
|
||||
rxor=read and xor
|
||||
edrupt=noone knows o__O
|
||||
dv=divide register pair `A`, `L` by a memory location (double precision), putting the quotient/remainder in `A`, `L`, respectively
|
||||
bzf=branch to a fixed memory location if `A` equals 0
|
||||
msu=1's complement difference between two 2's complement values, of which the first is the register `A`
|
||||
qxch=exchange `Q` register with memory location
|
||||
aug=increment positive and decrement negative values at a memory location, using 1's complement
|
||||
dim=other way 'round compared to `aug`
|
||||
dca=move a pair of registers into `A` and `L`
|
||||
dcs=move the complement of a pair of registers into `A` and `L`
|
||||
su=subtract a memory location from the `A` register
|
||||
bzmf=branch to a fixed memory location if `A` is equal or less than 0
|
||||
mp=multiply two single precision values to form a double precision value, of which one is the accumulator.
|
||||
@@ -1,5 +1,6 @@
|
||||
ARCHS=
|
||||
|
||||
ARCHS+=agc.mk
|
||||
ARCHS+=armthumb.mk
|
||||
ARCHS+=ppc_disasm.mk
|
||||
ARCHS+=psosvm.mk
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
OBJ_AGC=asm_agc.o
|
||||
OBJ_AGC+=../arch/agc/asm_agc.o
|
||||
|
||||
STATIC_OBJ+=${OBJ_AGC}
|
||||
TARGET_AGC=asm_agc.${LIBEXT}
|
||||
|
||||
ALL_TARGETS+=${TARGET_AGC}
|
||||
|
||||
${TARGET_AGC}: ${OBJ_AGC}
|
||||
${CC} $(call libname,asm_armthumb) ${LDFLAGS} \
|
||||
${CFLAGS} -o ${TARGET_AGC} ${OBJ_AGC}
|
||||
@@ -0,0 +1,36 @@
|
||||
#include <r_lib.h>
|
||||
#include <r_asm.h>
|
||||
#include "../arch/agc/asm_agc.h"
|
||||
|
||||
static int disassemble(RAsm *a, RAsmOp *op, const ut8 *buf, int len) {
|
||||
op->buf_asm[0] = 0;
|
||||
disasm_instruction(a->pc,
|
||||
((const ut16 *)buf)[0], op->buf_asm, R_ASM_BUFSIZE);
|
||||
op->size = 2;
|
||||
return op->size;
|
||||
}
|
||||
|
||||
static int assemble(RAsm *a, RAsmOp *op, const char *buf) {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
RAsmPlugin r_asm_plugin_agc = {
|
||||
.name = "agc",
|
||||
.arch = "agc",
|
||||
.bits = 16,
|
||||
.license = "GPL3",
|
||||
.desc = "AGC (Apollo Guidance Computer) disassembly plugin",
|
||||
.init = NULL,
|
||||
.fini = NULL,
|
||||
.disassemble = &disassemble,
|
||||
.assemble = &assemble
|
||||
};
|
||||
|
||||
#ifndef CORELIB
|
||||
struct r_lib_struct_t radare_plugin = {
|
||||
.type = R_LIB_TYPE_ASM,
|
||||
.data = &r_asm_plugin_agc,
|
||||
.version = R2_VERSION
|
||||
};
|
||||
#endif
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
# TEST
|
||||
CC=gcc
|
||||
PREFIX=/usr
|
||||
HOST_OS=linux
|
||||
VERSION=0.10.4
|
||||
LIBDIR=/usr/lib
|
||||
INSTALL_LIB=/usr/bin/install -m 755 -c
|
||||
USEROSTYPE=auto
|
||||
|
||||
HAVE_PKGCFG_UNICORN=0
|
||||
UC_CFLAGS=
|
||||
UC_LDFLAGS=
|
||||
|
||||
R2_CFLAGS=-I/usr/include/libr
|
||||
R2_LDFLAGS=-lr_core -lr_config -lr_cons -lr_io -lr_util -lr_flags -lr_asm -lr_debug -lr_hash -lr_bin -lr_lang -lr_io -lr_anal -lr_parse -lr_bp -lr_egg -lr_reg -lr_search -lr_syscall -lr_socket -lr_fs -lr_magic
|
||||
|
||||
HAVE_LIB_EWF=0
|
||||
EWF_CFLAGS=
|
||||
EWF_LDFLAGS=
|
||||
|
||||
#CFLAGS+=$(R2_CFLAGS)
|
||||
#LDFLAGS+=$(R2_LDFLAGS)
|
||||
|
||||
ifeq ($(HOST_OS),darwin)
|
||||
LIBEXT?=dylib
|
||||
else
|
||||
ifeq ($(HOST_OS),windows)
|
||||
LIBEXT?=dll
|
||||
else
|
||||
LIBEXT?=so
|
||||
endif
|
||||
endif
|
||||
|
||||
Reference in new issue
Block a user