#include #include #include #include #include #include "dis.h" #include "dis_syn.h" /* * Another World script disassembler * Only DOS version are supported */ #define MSG_USAGE "usage: disasm [-a | -i | -u] [-p] OBJECT OUTFILE\n" #define MSG_OPENERR "can't open file %s.\n" #define MSG_WRITEERR "can't create file %s.\n" #define MSG_INVALIDOP "invalid opcode 0x%X\n" #define MSG_INVALIDJMP "invalid jump opcode %u\n" char *input, *output; FILE *fp; uint8_t *code; uint16_t codesize; uint16_t pc, adr; struct labelinfo label[MAX_LABEL]; int labelnum; bool printcode; bool printadr; void (*printlabel)(int); void (*printopcode)(uint16_t, uint16_t, uint16_t, uint16_t, uint16_t, int); static uint8_t ubyte() { return code[pc++]; } static uint16_t uword() { return (ubyte() << 8) | ubyte(); } static int addlabel(uint16_t adr, int type) { for(int i = 0; i < labelnum; i++) { if(label[i].adr == adr) return i; } label[labelnum].adr = adr; label[labelnum].type = type; ++labelnum; return labelnum - 1; } static void fndlabel() { for(int i = 0; i < labelnum; i++) { if(label[i].adr == pc) { printlabel(i); return; } } printlabel(-1); } static void step() { adr = pc; if(printcode) fndlabel(); uint8_t op = ubyte(); uint16_t x = -1, y = -1, z = -1, w = -1; int label = -666; if(op & 0x80) { /* spr */ w = (((op << 8) | ubyte()) << 1) & 0x7FFF; x = ubyte(); y = ubyte(); } else if(op & 0x40) { /* spr */ w = (uword() << 1) & 0x7FFF; x = ubyte(); if((op & 48) == 0) x = (x << 8) | ubyte(); else if((op & 48) == 48) x = x + 256; y = ubyte(); if((op & 12) == 0) y = (y << 8) | ubyte(); if((op & 3) == 1 || (op & 3) == 2) z = ubyte(); else z = 64; } else { switch(op) { case 0x0: /* seti */ x = ubyte(); y = uword(); break; case 0x1: /* set */ x = ubyte(); y = ubyte(); break; case 0x2: /* add */ x = ubyte(); y = ubyte(); break; case 0x3: /* addi */ x = ubyte(); y = uword(); break; case 0x4: /* jsr */ x = uword(); label = addlabel(x, LT_CALL); break; case 0x5: /* return */ break; case 0x6: /* break */ break; case 0x7: /* jmp */ x = uword(); label = addlabel(x, LT_JUMP); break; case 0x8: /* setvec */ x = ubyte(); y = uword(); label = addlabel(y, LT_VEC); break; case 0x9: /* dbra */ x = ubyte(); y = uword(); label = addlabel(y, LT_JUMP); break; case 0xA: /* si */ w = ubyte(); x = ubyte(); if(w & 0x80) y = ubyte(); else if(w & 0x40) y = uword(); else y = ubyte(); if((w & 7) > 5) { printf(MSG_INVALIDJMP, w & 0x7); exit(1); } z = uword(); label = addlabel(z, LT_JUMP); break; case 0xB: /* fade */ x = uword() >> 8; break; case 0xC: /* vec */ x = ubyte(); y = ubyte(); z = ubyte(); break; case 0xD: /* setws */ x = ubyte(); break; case 0xE: /* clr */ x = ubyte(); y = ubyte(); break; case 0xF: /* copy */ x = ubyte(); y = ubyte(); break; case 0x10: /* show */ x = ubyte(); break; case 0x11: /* bigend */ break; case 0x12: /* text */ z = uword(); x = ubyte(); y = ubyte(); w = ubyte(); break; case 0x13: /* sub */ x = ubyte(); y = ubyte(); break; case 0x14: /* andi */ x = ubyte(); y = uword(); break; case 0x15: /* ori */ x = ubyte(); y = uword(); break; case 0x16: /* lsl */ x = ubyte(); y = uword(); break; case 0x17: /* lsr */ x = ubyte(); y = uword(); break; case 0x18: /* play */ z = uword(); x = ubyte(); y = ubyte(); w = ubyte(); break; case 0x19: /* load */ x = uword(); break; case 0x1A: /* song */ x = uword(); y = uword(); z = ubyte(); break; default: printf(MSG_INVALIDOP, op); exit(1); } } if(printcode) printopcode(op, x, y, z, w, label); } static void readarg(int argc, char **argv) { if(argc < 3) goto error; printadr = false; printlabel = aw_printlabel; printopcode = aw_printopcode; int i = 1; while((i < argc) && (argv[i][0] == '-')) { if(strcmp("-a", argv[i]) == 0) { printlabel = aw_printlabel; printopcode = aw_printopcode; } else if(strcmp("-i", argv[i]) == 0) { printlabel = intel_printlabel; printopcode = intel_printopcode; } else if(strcmp("-u", argv[i]) == 0) { printlabel = att_printlabel; printopcode = att_printopcode; } else if(strcmp("-p", argv[i]) == 0) { printadr = true; } else { goto error; } ++i; } if((argc - i) != 2) goto error; input = argv[i]; output = argv[i + 1]; return; error: printf(MSG_USAGE); exit(1); } int main(int argc, char **argv) { readarg(argc, argv); if((fp = fopen(input, "r")) == NULL) { printf(MSG_OPENERR, input); exit(1); } fseek(fp, 0, SEEK_END); codesize = ftell(fp); fseek(fp, 0, SEEK_SET); code = malloc(codesize); fread(code, codesize, 1, fp); fclose(fp); if((fp = fopen(output, "w")) == NULL) { printf(MSG_WRITEERR, output); exit(1); } labelnum = 0; pc = 0; printcode = false; while(pc < codesize) step(); /* read labels */ pc = 0; printcode = true; while(pc < codesize) step(); /* print code */ fclose(fp); free(code); return 0; }