* Initial working basic block conditional decompilation
- Only 'test' opcode for x86 is currently supported (just for testing) - analysis backend generates RAnalValue's for each argument - compiles a cmp+cjmp into a RAnalCond class - de/serializes the RAnalCond into an evaluable string - Make anal api more stable * Fix a memory leak in anal_bb * Reassign anal->reg into dbg->reg - Replicate dbg->reg into dbg->anal->reg - Such nasty cascade assignation..
This commit is contained in:
parent
a580ff4fa8
commit
e36ef11025
|
@ -11,7 +11,7 @@ foo: pre libr_anal.${EXT_SO} libr_anal.${EXT_AR} plugins
|
|||
include ${STATIC_ANAL_PLUGINS}
|
||||
#STATIC_OBJS=$(subst ..,p/..,$(subst anal_,p/anal_,$(STATIC_OBJ)))
|
||||
STATIC_OBJS=$(subst ../ar,p/../ar,$(subst anal_,p/anal_,$(STATIC_OBJ)))
|
||||
OBJ=${STATIC_OBJS} ctx.o reflines.o ref.o aop.o fcn.o bb.o var.o anal.o cond.o
|
||||
OBJ=${STATIC_OBJS} ctx.o reflines.o ref.o aop.o fcn.o bb.o var.o anal.o cond.o value.o
|
||||
|
||||
pre:
|
||||
if [ ! -e libr_anal.${EXT_SO} ]; then rm -f ${STATIC_OBJS} ; fi
|
||||
|
|
|
@ -7,9 +7,7 @@
|
|||
#include <r_list.h>
|
||||
|
||||
R_API RAnalOp *r_anal_aop_new() {
|
||||
RAnalOp *aop;
|
||||
|
||||
aop = R_NEW (RAnalOp);
|
||||
RAnalOp *aop = R_NEW (RAnalOp);
|
||||
if (aop) {
|
||||
memset (aop, 0, sizeof (RAnalOp));
|
||||
aop->mnemonic = NULL;
|
||||
|
@ -26,10 +24,16 @@ R_API RList *r_anal_aop_list_new() {
|
|||
return list;
|
||||
}
|
||||
|
||||
R_API void r_anal_aop_free(void *aop) {
|
||||
if (aop)
|
||||
free (((RAnalOp*)aop)->mnemonic);
|
||||
free (aop);
|
||||
R_API void r_anal_aop_free(void *_aop) {
|
||||
if (_aop) {
|
||||
RAnalOp *aop = _aop;
|
||||
r_anal_value_free (aop->src[0]);
|
||||
r_anal_value_free (aop->src[1]);
|
||||
r_anal_value_free (aop->src[2]);
|
||||
r_anal_value_free (aop->dst);
|
||||
free (aop->mnemonic);
|
||||
free (aop);
|
||||
}
|
||||
}
|
||||
|
||||
R_API int r_anal_aop(RAnal *anal, RAnalOp *aop, ut64 addr, const ut8 *data, int len) {
|
||||
|
|
|
@ -42,7 +42,7 @@ R_API void r_anal_bb_free(void *_bb) {
|
|||
}
|
||||
|
||||
R_API int r_anal_bb(RAnal *anal, RAnalBlock *bb, ut64 addr, ut8 *buf, ut64 len, int head) {
|
||||
RAnalOp *aop;
|
||||
RAnalOp *aop = NULL;
|
||||
int oplen, idx = 0;
|
||||
|
||||
if (bb->addr == -1)
|
||||
|
@ -65,13 +65,7 @@ R_API int r_anal_bb(RAnal *anal, RAnalBlock *bb, ut64 addr, ut8 *buf, ut64 len,
|
|||
if (head) bb->type = R_ANAL_BB_TYPE_HEAD;
|
||||
switch (aop->type) {
|
||||
case R_ANAL_OP_TYPE_CMP:
|
||||
bb->cond = r_anal_cond_new ();
|
||||
// TODO fill conditional information
|
||||
//bb->cond->type = 0; // UNKNOWN
|
||||
bb->cond->arg[0] = r_anal_value_new_from_aop(aop, 0);
|
||||
bb->cond->arg[1] = r_anal_value_new_from_aop(aop, 1);
|
||||
// bb->src = { 0,0,0,0,0 }
|
||||
// bb->dst = { 0,0,0,0,0 }
|
||||
bb->cond = r_anal_cond_new_from_aop (aop);
|
||||
break;
|
||||
case R_ANAL_OP_TYPE_CJMP:
|
||||
if (bb->cond) {
|
||||
|
@ -81,18 +75,23 @@ R_API int r_anal_bb(RAnal *anal, RAnalBlock *bb, ut64 addr, ut8 *buf, ut64 len,
|
|||
bb->fail = aop->fail;
|
||||
bb->jump = aop->jump;
|
||||
bb->type |= R_ANAL_BB_TYPE_BODY;
|
||||
r_anal_aop_free (aop);
|
||||
return R_ANAL_RET_END;
|
||||
case R_ANAL_OP_TYPE_JMP:
|
||||
bb->jump = aop->jump;
|
||||
bb->type |= R_ANAL_BB_TYPE_BODY;
|
||||
r_anal_aop_free (aop);
|
||||
return R_ANAL_RET_END;
|
||||
case R_ANAL_OP_TYPE_UJMP:
|
||||
bb->type |= R_ANAL_BB_TYPE_FOOT;
|
||||
r_anal_aop_free (aop);
|
||||
return R_ANAL_RET_END;
|
||||
case R_ANAL_OP_TYPE_RET:
|
||||
bb->type |= R_ANAL_BB_TYPE_LAST;
|
||||
r_anal_aop_free (aop);
|
||||
return R_ANAL_RET_END;
|
||||
}
|
||||
r_anal_aop_free (aop);
|
||||
}
|
||||
return bb->size;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,19 @@ R_API char *r_anal_cond_to_string(RAnalCond *cond) {
|
|||
return out;
|
||||
}
|
||||
|
||||
R_API RAnalCond *r_anal_cond_new_from_aop(RAnalOp *op) {
|
||||
RAnalCond *cond;
|
||||
if (!(cond = r_anal_cond_new()))
|
||||
return NULL;
|
||||
//v->reg[0] = op->src[0];
|
||||
//v->reg[1] = op->src[1];
|
||||
cond->arg[0] = op->src[0];
|
||||
op->src[0] = NULL;
|
||||
// TODO: moar!
|
||||
//cond->arg[1] = op->src[1];
|
||||
return cond;
|
||||
}
|
||||
|
||||
R_API RAnalCond *r_anal_cond_new_from_string(const char *str) {
|
||||
RAnalCond *cond = R_NEW (RAnalCond);
|
||||
// TODO: find '<','=','>','!'...
|
||||
|
|
|
@ -114,11 +114,20 @@ static int aop(RAnal *anal, RAnalOp *aop, ut64 addr, const ut8 *data, int len) {
|
|||
"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" };
|
||||
int src = buf[1]&7;
|
||||
int dst = (buf[1]&0x38)>>3;
|
||||
aop->src[0] = r_reg_get (anal->reg, testregs[src%8], R_REG_TYPE_GPR);
|
||||
aop->src[1] = r_reg_get (anal->reg, testregs[dst%8], R_REG_TYPE_GPR);
|
||||
if (aop->src[0] == aop->src[1])
|
||||
aop->src[0] = r_anal_value_new ();
|
||||
aop->src[0]->reg = r_reg_get (anal->reg, testregs[src%8], R_REG_TYPE_GPR);
|
||||
aop->src[1] = r_anal_value_new ();
|
||||
aop->src[1]->reg = r_reg_get (anal->reg, testregs[dst%8], R_REG_TYPE_GPR);
|
||||
aop->src[2] = NULL;
|
||||
//eprintf ("REGZ (%s)\n", anal->reg);
|
||||
//eprintf ("REG IZ: (%s)\n", testregs[src%8]);
|
||||
//eprintf ("REG IZ: %p (%s)\n", aop->src[0], aop->src[0]->reg->name);
|
||||
if (aop->src[0]->reg == aop->src[1]->reg) {
|
||||
//eprintf ("fruity\n");
|
||||
r_anal_value_free (aop->src[1]);
|
||||
aop->src[1] = NULL;
|
||||
// eprintf ("0x%"PFMT64x": (%02x) %d %d\n", addr, buf[1], src, dst);
|
||||
}
|
||||
//eprintf ("0x%"PFMT64x": (%02x) %d %d\n", addr, buf[1], src, dst);
|
||||
} else if (buf[1]<0xc0) { // test [eax+delta], eax
|
||||
/* not yet supported */
|
||||
}
|
||||
|
|
|
@ -22,25 +22,21 @@ R_API void r_anal_value_free(RAnalValue *value) {
|
|||
R_API st64 r_anal_value_eval(RAnalValue *value) {
|
||||
/* OMFG TODO.. this is done by r_num_shit */
|
||||
// r_num_math (anal->num, ...);
|
||||
#warning TODO r_anal_value_eval
|
||||
return 0LL;
|
||||
}
|
||||
|
||||
R_API char *r_anal_value_to_string (RAnalValue *value) {
|
||||
char *out = r_str_new ("");
|
||||
if (value->memref) out = r_str_concat (out, "[");
|
||||
if (value->mul) out = r_str_concatf (out, "%d*", value->mul);
|
||||
if (value->regbase) out = r_str_concatf (out, "%s+", value->regbase->name);
|
||||
if (value->regdelta) out = r_str_concatf (out, "%s+", value->regdelta->name);
|
||||
if (value->base!=0) out = r_str_concatf (out, "0x%"PFMT64x, value->base);
|
||||
if (value->delta>0) out = r_str_concatf (out, "+%d", value->delta);
|
||||
else if (value->delta<0) out = r_str_concatf (out, "%d", value->delta);
|
||||
if (value->memref) out = r_str_concat (out, "]");
|
||||
if (value) {
|
||||
if (value->memref) out = r_str_concat (out, "[");
|
||||
if (value->mul) out = r_str_concatf (out, "%d*", value->mul);
|
||||
if (value->reg) out = r_str_concatf (out, "%s", value->reg->name);
|
||||
if (value->regdelta) out = r_str_concatf (out, "+%s", value->regdelta->name);
|
||||
if (value->base!=0) out = r_str_concatf (out, "0x%"PFMT64x, value->base);
|
||||
if (value->delta>0) out = r_str_concatf (out, "+%d", value->delta);
|
||||
else if (value->delta<0) out = r_str_concatf (out, "%d", value->delta);
|
||||
if (value->memref) out = r_str_concat (out, "]");
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
R_API RAnalValue *r_anal_value_new_from_aop(RAnalOp *op, int idx) {
|
||||
RAnalValue *v = R_NEW (RAnalValue);
|
||||
if (idx<0 || idx> sizeof(op->arg) || !op->arg[idx])
|
||||
return NULL;
|
||||
TODO
|
||||
return v;
|
||||
}
|
||||
|
|
|
@ -36,22 +36,22 @@ static char *r_core_anal_graph_label(RCore *core, struct r_anal_bb_t *bb, int op
|
|||
return NULL;
|
||||
for(i=j=0;cmdstr[i];i++,j++) {
|
||||
switch(cmdstr[i]) {
|
||||
case 0x1b:
|
||||
/* skip ansi chars */
|
||||
for(i++;cmdstr[i]&&cmdstr[i]!='m'&&cmdstr[i]!='H'&&cmdstr[i]!='J';i++);
|
||||
j--;
|
||||
break;
|
||||
case '"':
|
||||
str[j]='\\';
|
||||
str[++j]='"';
|
||||
break;
|
||||
case '\n':
|
||||
case '\r':
|
||||
str[j]='\\';
|
||||
str[++j]='l';
|
||||
break;
|
||||
default:
|
||||
str[j]=cmdstr[i];
|
||||
case 0x1b:
|
||||
/* skip ansi chars */
|
||||
for(i++;cmdstr[i]&&cmdstr[i]!='m'&&cmdstr[i]!='H'&&cmdstr[i]!='J';i++);
|
||||
j--;
|
||||
break;
|
||||
case '"':
|
||||
str[j]='\\';
|
||||
str[++j]='"';
|
||||
break;
|
||||
case '\n':
|
||||
case '\r':
|
||||
str[j]='\\';
|
||||
str[++j]='l';
|
||||
break;
|
||||
default:
|
||||
str[j]=cmdstr[i];
|
||||
}
|
||||
}
|
||||
str[j]='\0';
|
||||
|
@ -170,9 +170,7 @@ R_API int r_core_anal_bb_list(RCore *core, int rad) {
|
|||
r_cons_printf ("0x%08"PFMT64x" ", bbi->jump);
|
||||
r_cons_printf ("0x%08"PFMT64x" ", bbi->fail);
|
||||
|
||||
if (bbi->type == R_ANAL_BB_TYPE_NULL)
|
||||
r_cons_printf ("n");
|
||||
else {
|
||||
if (bbi->type != R_ANAL_BB_TYPE_NULL) {
|
||||
if ((bbi->type & R_ANAL_BB_TYPE_BODY))
|
||||
r_cons_printf ("b");
|
||||
if ((bbi->type & R_ANAL_BB_TYPE_FOOT))
|
||||
|
@ -181,7 +179,7 @@ R_API int r_core_anal_bb_list(RCore *core, int rad) {
|
|||
r_cons_printf ("h");
|
||||
if ((bbi->type & R_ANAL_BB_TYPE_LAST))
|
||||
r_cons_printf ("l");
|
||||
}
|
||||
} else r_cons_printf ("n");
|
||||
|
||||
if ((bbi->diff == R_ANAL_DIFF_MATCH))
|
||||
r_cons_printf (" m");
|
||||
|
@ -216,7 +214,9 @@ R_API int r_core_anal_bb_list(RCore *core, int rad) {
|
|||
else if ((bbi->diff == R_ANAL_DIFF_UNMATCH))
|
||||
r_cons_printf ("unmatch");
|
||||
else r_cons_printf ("new");
|
||||
r_cons_printf ("\n");
|
||||
|
||||
r_cons_printf (" cond=\"%s\"\n", bbi->cond?
|
||||
r_anal_cond_to_string (bbi->cond):"none");
|
||||
}
|
||||
}
|
||||
r_cons_flush ();
|
||||
|
@ -226,7 +226,6 @@ R_API int r_core_anal_bb_list(RCore *core, int rad) {
|
|||
R_API int r_core_anal_bb_seek(RCore *core, ut64 addr) {
|
||||
struct r_anal_bb_t *bbi;
|
||||
RListIter *iter;
|
||||
|
||||
r_list_foreach (core->anal->bbs, iter, bbi)
|
||||
if (addr >= bbi->addr && addr < bbi->addr+bbi->size)
|
||||
return r_core_seek (core, bbi->addr, R_FALSE);
|
||||
|
@ -252,7 +251,7 @@ R_API int r_core_anal_fcn(RCore *core, ut64 at, ut64 from, int depth) {
|
|||
if (from == refi->addr)
|
||||
return R_FALSE;
|
||||
}
|
||||
if (!(ref = r_anal_ref_new())) {
|
||||
if (!(ref = r_anal_ref_new ())) {
|
||||
eprintf ("Error: new (xref)\n");
|
||||
return R_ANAL_RET_ERROR;
|
||||
}
|
||||
|
@ -338,10 +337,7 @@ R_API int r_core_anal_fcn_list(RCore *core, int rad) {
|
|||
RListIter *iter, *iter2;
|
||||
|
||||
r_list_foreach (core->anal->fcns, iter, fcni)
|
||||
if (rad) {
|
||||
r_cons_printf ("af+ 0x%08"PFMT64x" %"PFMT64d" %s (%c)\n",
|
||||
fcni->addr, fcni->size, fcni->name, fcni->diff?fcni->diff:'n');
|
||||
} else {
|
||||
if (!rad) {
|
||||
r_cons_printf ("[0x%08"PFMT64x"] size=%"PFMT64d" name=%s",
|
||||
fcni->addr, fcni->size, fcni->name);
|
||||
r_cons_printf (" diff=%s", fcni->diff=='m'?"match": fcni->diff=='u'?"unmatch": "new");
|
||||
|
@ -359,7 +355,8 @@ R_API int r_core_anal_fcn_list(RCore *core, int rad) {
|
|||
r_anal_var_type_to_str (core->anal, vari->type));
|
||||
}
|
||||
r_cons_newline ();
|
||||
}
|
||||
} else r_cons_printf ("af+ 0x%08"PFMT64x" %"PFMT64d" %s (%c)\n",
|
||||
fcni->addr, fcni->size, fcni->name, fcni->diff?fcni->diff:'n');
|
||||
r_cons_flush ();
|
||||
return R_TRUE;
|
||||
}
|
||||
|
@ -392,7 +389,6 @@ R_API int r_core_anal_graph(RCore *core, ut64 addr, int opts) {
|
|||
R_API int r_core_anal_graph_fcn(RCore *core, char *fname, int opts) {
|
||||
RListIter *iter;
|
||||
RAnalFcn *fcni;
|
||||
|
||||
r_list_foreach (core->anal->fcns, iter, fcni)
|
||||
if (!strcmp (fname, fcni->name))
|
||||
return r_core_anal_graph (core, fcni->addr, opts);
|
||||
|
|
|
@ -149,8 +149,8 @@ static void r_print_disasm(RPrint *p, RCore *core, ut64 addr, ut8 *buf, int len,
|
|||
stackptr += analop.stackptr;
|
||||
}
|
||||
if (show_bytes) {
|
||||
char pad[64];
|
||||
char *str, *extra = " ";
|
||||
char *str, pad[64];
|
||||
const char *extra = " ";
|
||||
if (!flag) {
|
||||
str = strdup (asmop.buf_hex);
|
||||
if (strlen (str) > nb) {
|
||||
|
@ -499,6 +499,7 @@ static void cmd_reg(RCore *core, const char *str) {
|
|||
r_cons_printf ("%s\n", core->dbg->reg_profile);
|
||||
else eprintf ("No register profile defined. Try 'dr.'\n");
|
||||
} else r_reg_set_profile (core->dbg->reg, str+2);
|
||||
core->anal->reg = core->dbg->reg;
|
||||
break;
|
||||
case 't':
|
||||
for (i=0; (name=r_reg_get_type (i));i++)
|
||||
|
|
|
@ -114,7 +114,7 @@ static int config_asm_bits_callback(void *user, void *data) {
|
|||
RConfigNode *node = (RConfigNode *) data;
|
||||
int ret = r_asm_set_bits (core->assembler, node->i_value);
|
||||
if (ret == R_FALSE) {
|
||||
struct r_asm_plugin_t *h = core->assembler->cur;
|
||||
RAsmPlugin *h = core->assembler->cur;
|
||||
if (h) {
|
||||
eprintf ("Cannot set bits %"PFMT64d" to '%s'\n",
|
||||
node->i_value, h->name);
|
||||
|
|
|
@ -7,6 +7,7 @@ static ut64 num_callback(RNum *userptr, const char *str, int *ok) {
|
|||
RCore *core = (RCore *)userptr; // XXX ?
|
||||
RFlagItem *flag;
|
||||
RAnalOp aop;
|
||||
ut64 ret;
|
||||
|
||||
if (str[0]=='$') {
|
||||
/* analyze opcode */
|
||||
|
@ -46,11 +47,11 @@ static ut64 num_callback(RNum *userptr, const char *str, int *ok) {
|
|||
case '?': return core->num->value;
|
||||
}
|
||||
}
|
||||
|
||||
flag = r_flag_get (core->flags, str);
|
||||
if (flag) *ok = R_TRUE;
|
||||
else *ok = R_FALSE;
|
||||
return (flag)?flag->offset:0LL;
|
||||
if ( (flag = r_flag_get (core->flags, str)) ) {
|
||||
ret = flag->offset;
|
||||
*ok = R_TRUE;
|
||||
} else *ok = ret = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
R_API RCore *r_core_new() {
|
||||
|
@ -158,7 +159,7 @@ R_API int r_core_init(RCore *core) {
|
|||
core->flags = r_flag_new ();
|
||||
core->dbg = r_debug_new (R_TRUE);
|
||||
core->dbg->anal = core->anal; // XXX: dupped instance.. can cause lost pointerz
|
||||
core->dbg->anal->reg = core->anal->reg; // XXX: dupped instance.. can cause lost pointerz
|
||||
// core->dbg->anal->reg = core->anal->reg; // XXX: dupped instance.. can cause lost pointerz
|
||||
core->sign->printf = r_cons_printf;
|
||||
core->io->printf = r_cons_printf;
|
||||
core->dbg->printf = r_cons_printf;
|
||||
|
|
|
@ -33,6 +33,7 @@ R_API int r_debug_use(RDebug *dbg, const char *str) {
|
|||
if (h->reg_profile) {
|
||||
free (dbg->reg_profile);
|
||||
dbg->reg_profile = dbg->h->reg_profile ();
|
||||
dbg->anal->reg = dbg->reg;
|
||||
r_reg_set_profile_string (dbg->reg, dbg->reg_profile);
|
||||
}
|
||||
return R_TRUE;
|
||||
|
|
|
@ -132,6 +132,17 @@ typedef struct r_anal_t {
|
|||
struct list_head anals; // XXX: use RList here
|
||||
} RAnal;
|
||||
|
||||
// mul*value+regbase+regidx+delta
|
||||
typedef struct r_anal_value_t {
|
||||
int memref; // is memory reference? or value?
|
||||
ut64 base ; // numeric address
|
||||
int delta; // numeric delta
|
||||
int mul; // multiplier (reg*4+base)
|
||||
// TODO: add multiplier
|
||||
RRegisterItem *reg; // register index used (-1 if no reg)
|
||||
RRegisterItem *regdelta; // register index used (-1 if no reg)
|
||||
} RAnalValue;
|
||||
|
||||
typedef struct r_anal_aop_t {
|
||||
char *mnemonic; /* mnemonic */
|
||||
ut64 addr; /* address */
|
||||
|
@ -147,23 +158,11 @@ typedef struct r_anal_aop_t {
|
|||
st64 ref; /* reference to memory */ /* XXX signed? */
|
||||
ut64 value; /* reference to value */ /* XXX signed? */
|
||||
st64 stackptr; /* stack pointer */
|
||||
RRegisterItem *src[3];
|
||||
RRegisterItem *dst;
|
||||
RAnalValue *src[3];
|
||||
RAnalValue *dst;
|
||||
int refptr;
|
||||
} RAnalOp;
|
||||
|
||||
//mov 0x8175780(,%eax,4),%eax
|
||||
// value+regbase+regidx+delta
|
||||
typedef struct r_anal_value_t {
|
||||
int memref; // is memory reference? or value?
|
||||
ut64 base ; // numeric address
|
||||
int delta; // numeric delta
|
||||
int mul; // multiplier (reg*4+base)
|
||||
// TODO: add multiplier
|
||||
RRegisterItem *regbase; // register index used (-1 if no reg)
|
||||
RRegisterItem *regdelta; // register index used (-1 if no reg)
|
||||
} RAnalValue;
|
||||
|
||||
#define R_ANAL_COND_SINGLE(x) (!x->arg[1] || x->arg[0]==x->arg[1])
|
||||
|
||||
typedef struct r_anal_cond_t {
|
||||
|
@ -314,7 +313,14 @@ R_API int r_anal_var_access_add(RAnal *anal, RAnalVar *var, ut64 from, int set);
|
|||
R_API int r_anal_var_access_del(RAnal *anal, RAnalVar *var, ut64 from);
|
||||
R_API RAnalVarAccess *r_anal_var_access_get(RAnal *anal, RAnalVar *var, ut64 from);
|
||||
|
||||
R_API RAnalValue *r_anal_value_new();
|
||||
R_API RAnalValue *r_anal_value_new_from_string(const char *str);
|
||||
R_API st64 r_anal_value_eval(RAnalValue *value);
|
||||
R_API char *r_anal_value_to_string (RAnalValue *value);
|
||||
R_API void r_anal_value_free(RAnalValue *value);
|
||||
|
||||
R_API RAnalCond *r_anal_cond_new();
|
||||
R_API RAnalCond *r_anal_cond_new_from_aop(RAnalOp *op);
|
||||
#define r_anal_cond_free(x) free(x);
|
||||
R_API int r_anal_cond_eval(RAnalCond *cond);
|
||||
R_API char *r_anal_cond_to_string(RAnalCond *cond);
|
||||
|
|
|
@ -176,11 +176,11 @@ static void emit_while_end (const char *labelback) {
|
|||
#if SYNTAX_ATT
|
||||
rcc_printf (" pop %%"R_AX"\n");
|
||||
rcc_printf (" cmp $0, %%"R_AX"\n"); // XXX MUST SUPPORT != 0 COMPARE HERE
|
||||
rcc_printf (" jnz %s\n", labelback);
|
||||
rcc_printf (" bne %s\n", labelback);
|
||||
#else
|
||||
rcc_printf (" pop "R_AX"\n");
|
||||
rcc_printf (" test "R_AX", "R_AX"\n"); // XXX MUST SUPPORT != 0 COMPARE HERE
|
||||
rcc_printf (" jnz %s\n", labelback);
|
||||
rcc_printf (" cmp "R_AX", $0\n"); // XXX MUST SUPPORT != 0 COMPARE HERE
|
||||
rcc_printf (" bne %s\n", labelback);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue