From b3fbfb385c00f16d9e9ecae3b4298087c5587597 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 20 Sep 2010 18:30:51 +0200 Subject: [PATCH] asm/dasm: Add support for calls/rets (untested) Signed-off-by: Michael Buesch --- assembler/README | 2 ++ assembler/main.c | 49 +++++++++++++++++++++++++++++----------- assembler/parser.y | 55 ++++++++++++++++++++++++++++++++++++++++++++- assembler/scanner.l | 2 ++ disassembler/main.c | 17 +++++++------- 5 files changed, 103 insertions(+), 22 deletions(-) diff --git a/assembler/README b/assembler/README index c64ab01..d9e1362 100644 --- a/assembler/README +++ b/assembler/README @@ -34,7 +34,9 @@ jge | A,B,l | Jump if greater or equal | if(A>=B) PC=l jg | A,B,l | Jump if greater | if(A>B) PC=l jle | A,B,l | Jump if less or equal | if(A<=B) PC=l call | lrX,l | Store PC, call function | lrX=PC; PC=l +calls | l | Store PC, call function | PC->stack; PC=l ret | lrX,lrY | Store PC, ret from func | lrX=PC; PC=lrY +rets | | ret from function | stack->PC jzx | M,S,A,B,l | Jump if zero after shift + mask | jnzx | M,S,A,B,l | Jump if nonzero after shift+msk | jext | E,A,B,l | Jump if External Condition true | if(E) PC=l diff --git a/assembler/main.c b/assembler/main.c index 461b0d8..b262276 100644 --- a/assembler/main.c +++ b/assembler/main.c @@ -482,6 +482,27 @@ static struct code_output * do_assemble_insn(struct assembler_context *ctx, return out; } +static void do_assemble_ret(struct assembler_context *ctx, + struct instruction *insn, + unsigned int opcode) +{ + struct code_output *out; + + /* Get the previous instruction and check whether it + * is a jump instruction. */ + list_for_each_entry_reverse(out, &ctx->output, list) { + /* Search the last insn. */ + if (out->type == OUT_INSN) { + if (out->is_jump_insn) { + asm_warn(ctx, "RET instruction directly after " + "jump instruction. The hardware won't like this."); + } + break; + } + } + do_assemble_insn(ctx, insn, opcode); +} + static unsigned int merge_ext_into_opcode(struct assembler_context *ctx, unsigned int opbase, struct instruction *insn) @@ -855,22 +876,24 @@ static void assemble_instruction(struct assembler_context *ctx, out->is_jump_insn = 1; break; case OP_CALL: + if (ctx->arch != 5) + asm_error(ctx, "'call' instruction is only supported on arch 5"); do_assemble_insn(ctx, insn, 0x002); break; + case OP_CALLS: + if (ctx->arch != 15) + asm_error(ctx, "'calls' instruction is only supported on arch 15"); + do_assemble_insn(ctx, insn, 0x004); + break; case OP_RET: - /* Get the previous instruction and check whether it - * is a jump instruction. */ - list_for_each_entry_reverse(out, &ctx->output, list) { - /* Search the last insn. */ - if (out->type == OUT_INSN) { - if (out->is_jump_insn) { - asm_warn(ctx, "RET instruction directly after " - "jump instruction. The hardware won't like this."); - } - break; - } - } - do_assemble_insn(ctx, insn, 0x003); + if (ctx->arch != 5) + asm_error(ctx, "'ret' instruction is only supported on arch 5"); + do_assemble_ret(ctx, insn, 0x003); + break; + case OP_RETS: + if (ctx->arch != 15) + asm_error(ctx, "'rets' instruction is only supported on arch 15"); + do_assemble_insn(ctx, insn, 0x005); break; case OP_TKIPH: case OP_TKIPHS: diff --git a/assembler/parser.y b/assembler/parser.y index 4ace330..3e83c19 100644 --- a/assembler/parser.y +++ b/assembler/parser.y @@ -43,7 +43,7 @@ extern struct initvals_sect *cur_initvals_sect; %token EQUAL NOT_EQUAL LOGICAL_OR LOGICAL_AND PLUS MINUS MULTIPLY DIVIDE BITW_OR BITW_AND BITW_XOR BITW_NOT LEFTSHIFT RIGHTSHIFT -%token OP_ADD OP_ADDSC OP_ADDC OP_ADDSCC OP_SUB OP_SUBSC OP_SUBC OP_SUBSCC OP_SRA OP_OR OP_AND OP_XOR OP_SR OP_SRX OP_SL OP_RL OP_RR OP_NAND OP_ORX OP_MOV OP_JMP OP_JAND OP_JNAND OP_JS OP_JNS OP_JE OP_JNE OP_JLS OP_JGES OP_JGS OP_JLES OP_JL OP_JGE OP_JG OP_JLE OP_JZX OP_JNZX OP_JEXT OP_JNEXT OP_CALL OP_RET OP_TKIPH OP_TKIPHS OP_TKIPL OP_TKIPLS OP_NAP RAW_CODE +%token OP_ADD OP_ADDSC OP_ADDC OP_ADDSCC OP_SUB OP_SUBSC OP_SUBC OP_SUBSCC OP_SRA OP_OR OP_AND OP_XOR OP_SR OP_SRX OP_SL OP_RL OP_RR OP_NAND OP_ORX OP_MOV OP_JMP OP_JAND OP_JNAND OP_JS OP_JNS OP_JE OP_JNE OP_JLS OP_JGES OP_JGS OP_JLES OP_JL OP_JGE OP_JG OP_JLE OP_JZX OP_JNZX OP_JEXT OP_JNEXT OP_CALL OP_CALLS OP_RET OP_RETS OP_TKIPH OP_TKIPHS OP_TKIPL OP_TKIPLS OP_NAP RAW_CODE %token IVAL_MMIO16 IVAL_MMIO32 IVAL_PHY IVAL_RADIO IVAL_SHM16 IVAL_SHM32 IVAL_TRAM @@ -456,6 +456,13 @@ statement : asmdir { s->u.insn = $1; $$ = s; } + | insn_calls { + struct statement *s = xmalloc(sizeof(struct statement)); + INIT_LIST_HEAD(&s->list); + s->type = STMT_INSN; + s->u.insn = $1; + $$ = s; + } | insn_ret { struct statement *s = xmalloc(sizeof(struct statement)); INIT_LIST_HEAD(&s->list); @@ -463,6 +470,13 @@ statement : asmdir { s->u.insn = $1; $$ = s; } + | insn_rets { + struct statement *s = xmalloc(sizeof(struct statement)); + INIT_LIST_HEAD(&s->list); + s->type = STMT_INSN; + s->u.insn = $1; + $$ = s; + } | insn_tkiph { struct statement *s = xmalloc(sizeof(struct statement)); INIT_LIST_HEAD(&s->list); @@ -922,6 +936,24 @@ insn_call : OP_CALL linkreg COMMA labelref { } ; +insn_calls : OP_CALLS labelref { + struct instruction *insn = xmalloc(sizeof(struct instruction)); + struct operlist *ol = xmalloc(sizeof(struct operlist)); + struct operand *oper_r0 = xmalloc(sizeof(struct operand)); + struct registr *r0 = xmalloc(sizeof(struct registr)); + r0->type = GPR; + r0->nr = 0; + oper_r0->type = OPER_REG; + oper_r0->u.reg = r0; + ol->oper[0] = oper_r0; + ol->oper[1] = oper_r0; + ol->oper[2] = $2; + insn->op = OP_CALLS; + insn->operands = ol; + $$ = insn; + } + ; + insn_ret : OP_RET linkreg COMMA linkreg { struct instruction *insn = xmalloc(sizeof(struct instruction)); struct operlist *ol = xmalloc(sizeof(struct operlist)); @@ -943,6 +975,27 @@ insn_ret : OP_RET linkreg COMMA linkreg { } ; +insn_rets : OP_RETS { + struct instruction *insn = xmalloc(sizeof(struct instruction)); + struct operlist *ol = xmalloc(sizeof(struct operlist)); + struct operand *oper_r0 = xmalloc(sizeof(struct operand)); + struct operand *oper_zero = xmalloc(sizeof(struct operand)); + struct registr *r0 = xmalloc(sizeof(struct registr)); + oper_zero->type = OPER_RAW; + oper_zero->u.raw = 0; + r0->type = GPR; + r0->nr = 0; + oper_r0->type = OPER_REG; + oper_r0->u.reg = r0; + ol->oper[0] = oper_r0; + ol->oper[1] = oper_r0; + ol->oper[2] = oper_zero; + insn->op = OP_RETS; + insn->operands = ol; + $$ = insn; + } + ; + insn_tkiph : OP_TKIPH operlist_2 { struct instruction *insn = xmalloc(sizeof(struct instruction)); struct operlist *ol = $2; diff --git a/assembler/scanner.l b/assembler/scanner.l index 80b204f..436d333 100644 --- a/assembler/scanner.l +++ b/assembler/scanner.l @@ -127,7 +127,9 @@ jext { update_lineinfo(); return OP_JEXT; } jnext { update_lineinfo(); return OP_JNEXT; } call { update_lineinfo(); return OP_CALL; } +calls { update_lineinfo(); return OP_CALLS; } ret { update_lineinfo(); return OP_RET; } +rets { update_lineinfo(); return OP_RETS; } tkiph { update_lineinfo(); return OP_TKIPH; } tkiphs { update_lineinfo(); return OP_TKIPHS; } diff --git a/disassembler/main.c b/disassembler/main.c index ba990ab..86ed1f4 100644 --- a/disassembler/main.c +++ b/disassembler/main.c @@ -515,30 +515,31 @@ static void disasm_constant_opcodes(struct disassembler_context *ctx, stmt->u.insn.operands[2] = str; break; } -//TODO also implement it in the assembler -#if 0 case 0x004: { if (cmdargs.arch != 15) { - dasm_error("arch 15 call instruction found in arch %d binary", + dasm_error("arch 15 'calls' instruction found in arch %d binary", cmdargs.arch); } - stmt->u.insn.name = "call"; + stmt->u.insn.name = "calls"; stmt->u.insn.is_labelref = 0; stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2]; if (stmt->u.insn.bin->operands[0] != 0x1780 || stmt->u.insn.bin->operands[1] != 0x1780) - dasm_warn("r15 call: Invalid first or second argument"); + dasm_warn("r15 calls: Invalid first or second argument"); break; } case 0x005: { if (cmdargs.arch != 15) { - dasm_error("arch 15 ret instruction found in arch %d binary", + dasm_error("arch 15 'rets' instruction found in arch %d binary", cmdargs.arch); } - stmt->u.insn.name = "ret"; + stmt->u.insn.name = "rets"; + if (stmt->u.insn.bin->operands[0] != 0x1780 || + stmt->u.insn.bin->operands[1] != 0x1780 || + stmt->u.insn.bin->operands[2] != 0) + dasm_warn("r15 rets: Invalid argument(s)"); break; } -#endif case 0x1E0: { unsigned int flags, mask; -- 2.31.1