b43-asm: Fix the reverse search for JMPs before RETs
[b43-tools.git] / assembler / main.c
index 1dac1c7cafa146068c38d027f82f41a1dcaf0a9a..3f207baf1ed69e412d4f5a6be1c48e05a52c6607 100644 (file)
@@ -470,6 +470,9 @@ static unsigned int merge_external_jmp_into_opcode(struct assembler_context *ctx
                                                   unsigned int opbase,
                                                   struct instruction *insn)
 {
+       struct operand *fake;
+       struct registr *fake_reg;
+       struct operand *target;
        struct operlist *ol;
        unsigned int cond;
        unsigned int opcode;
@@ -480,9 +483,21 @@ static unsigned int merge_external_jmp_into_opcode(struct assembler_context *ctx
        if (cond & ~0xFF)
                asm_error(ctx, "External jump condition value too big (> 0xFF)");
        opcode |= cond;
-       ol->oper[0] = ol->oper[1];
-       ol->oper[1] = ol->oper[2];
-       ol->oper[2] = ol->oper[3];
+       target = ol->oper[1];
+       memset(ol->oper, 0, sizeof(ol->oper));
+
+       /* This instruction has two fake r0 operands
+        * at position 0 and 1. */
+       fake = xmalloc(sizeof(*fake));
+       fake_reg = xmalloc(sizeof(*fake_reg));
+       fake->type = OPER_REG;
+       fake->u.reg = fake_reg;
+       fake_reg->type = GPR;
+       fake_reg->nr = 0;
+
+       ol->oper[0] = fake;
+       ol->oper[1] = fake;
+       ol->oper[2] = target;
 
        return opcode;
 }
@@ -801,13 +816,16 @@ static void assemble_instruction(struct assembler_context *ctx,
                do_assemble_insn(ctx, insn, 0x002);
                break;
        case OP_RET:
-               if (!list_empty(&ctx->output)) {
-                       /* Get the previous instruction and check whether it
-                        * is a jump instruction. */
-                       out = list_entry(ctx->output.prev, struct code_output, list);
-                       if (out->is_jump_insn) {
-                               asm_error(ctx, "RET instruction directly after "
-                                         "jump instruction. The hardware won't like this.");
+               /* 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_error(ctx, "RET instruction directly after "
+                                                 "jump instruction. The hardware won't like this.");
+                               }
+                               break;
                        }
                }
                do_assemble_insn(ctx, insn, 0x003);