+/*
+ * ia32rtools
+ * (C) notaz, 2013,2014
+ *
+ * This work is licensed under the terms of 3-clause BSD license.
+ * See COPYING file in the top-level directory.
+ */
+
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
OPF_ATAIL = (1 << 14), /* tail call with reused arg frame */
OPF_32BIT = (1 << 15), /* 32bit division */
OPF_LOCK = (1 << 16), /* op has lock prefix */
+ OPF_VAPUSH = (1 << 17), /* vararg ptr push (as call arg) */
};
enum op_op {
unsigned int size_mismatch:1; // type override differs from C
unsigned int size_lt:1; // type override is larger than C
unsigned int had_ds:1; // had ds: prefix
+ const struct parsed_proto *pp; // for OPT_LABEL
int reg;
unsigned int val;
- char name[256];
+ char name[112];
};
struct parsed_op {
int cc_scratch; // scratch storage during analysis
int bt_i; // branch target for branches
struct parsed_data *btj;// branch targets for jumptables
- struct parsed_proto *pp;
+ struct parsed_proto *pp;// parsed_proto for OP_CALL
void *datap;
+ int asmln;
};
// datap:
static int g_ida_func_attr;
static int g_allow_regfunc;
#define ferr(op_, fmt, ...) do { \
- printf("error:%s:#%zd: '%s': " fmt, g_func, (op_) - ops, \
+ printf("%s:%d: error: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
dump_op(op_), ##__VA_ARGS__); \
fcloseall(); \
exit(1); \
} while (0)
#define fnote(op_, fmt, ...) \
- printf("error:%s:#%zd: '%s': " fmt, g_func, (op_) - ops, \
+ printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
dump_op(op_), ##__VA_ARGS__)
#define MAX_REGS 8
"LONG", "HIMC",
};
static const char *word_types[] = {
- "uint16_t", "int16_t", "_WORD",
+ "uint16_t", "int16_t", "_WORD", "WORD",
"unsigned __int16", "__int16",
};
static const char *byte_types[] = {
"uint8_t", "int8_t", "char",
"unsigned __int8", "__int8", "BYTE", "_BYTE",
"CHAR", "_UNKNOWN",
+ // structures.. deal the same as with _UNKNOWN for now
+ "CRITICAL_SECTION",
};
const char *n;
int i;
return 0;
}
+static char *default_cast_to(char *buf, size_t buf_size,
+ struct parsed_opr *opr)
+{
+ buf[0] = 0;
+
+ if (!opr->is_ptr)
+ return buf;
+ if (opr->pp == NULL || opr->pp->type.name == NULL
+ || opr->pp->is_fptr)
+ {
+ snprintf(buf, buf_size, "%s", "(void *)");
+ return buf;
+ }
+
+ snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
+ return buf;
+}
+
static enum opr_type lmod_from_directive(const char *d)
{
if (IS(d, "dd"))
if (wordc_in == 2) {
if (IS(words[w], "offset")) {
opr->type = OPT_OFFSET;
+ opr->lmod = OPLM_DWORD;
strcpy(opr->name, words[w + 1]);
- return wordc;
+ pp = proto_parse(g_fhdr, opr->name, 1);
+ goto do_label;
}
if (IS(words[w], "(offset")) {
p = strchr(words[w + 1], ')');
}
opr->is_array = pp->type.is_array;
}
+ opr->pp = pp;
if (opr->lmod == OPLM_UNSPEC)
guess_lmod_from_name(opr);
op->pfo = op_table[i].pfo;
op->pfo_inv = op_table[i].pfo_inv;
op->regmask_src = op->regmask_dst = 0;
+ op->asmln = asmln;
for (opr = 0; opr < op_table[i].minopr; opr++) {
regmask = regmask_ind = 0;
return pp;
}
-static int try_resolve_const(int i, const struct parsed_opr *opr,
- int magic, unsigned int *val)
+// find an instruction that changed opr before i op
+// *op_i must be set to -1
+static int resolve_origin(int i, const struct parsed_opr *opr,
+ int magic, int *op_i)
{
struct label_ref *lr;
int ret = 0;
if (g_labels[i][0] != 0) {
lr = &g_label_refs[i];
for (; lr != NULL; lr = lr->next)
- ret |= try_resolve_const(lr->i, opr, magic, val);
+ ret |= resolve_origin(lr->i, opr, magic, op_i);
if (i > 0 && LAST_OP(i - 1))
return ret;
}
continue;
if (!is_opr_modified(opr, &ops[i]))
continue;
+
+ if (*op_i >= 0) {
+ if (*op_i == i)
+ return 1;
+ // XXX: could check if the other op does the same
+ return -1;
+ }
+
+ *op_i = i;
+ return 1;
+ }
+}
+
+static int try_resolve_const(int i, const struct parsed_opr *opr,
+ int magic, unsigned int *val)
+{
+ int s_i = -1;
+ int ret = 0;
+
+ ret = resolve_origin(i, opr, magic, &s_i);
+ if (ret == 1) {
+ i = s_i;
if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
return -1;
*val = ops[i].operand[1].val;
return 1;
}
+
+ return -1;
}
static int collect_call_args_r(struct parsed_op *po, int i,
struct parsed_proto *pp_tmp;
struct label_ref *lr;
int need_to_save_current;
+ int save_args;
int ret = 0;
- int j;
+ char buf[32];
+ int j, k;
if (i < 0) {
ferr(po, "dead label encountered\n");
pp->arg[arg].datap = &ops[j];
need_to_save_current = 0;
+ save_args = 0;
if (!need_op_saving) {
ret = scan_for_mod(&ops[j], j + 1, i, 1);
need_to_save_current = (ret >= 0);
ops[j].flags &= ~OPF_RMD;
if (ops[j].argnum == 0) {
ops[j].argnum = arg + 1;
- *save_arg_vars |= 1 << arg;
+ save_args |= 1 << arg;
}
else if (ops[j].argnum < arg + 1)
ferr(&ops[j], "argnum conflict (%d<%d) for '%s'\n",
ops[j].flags &= ~OPF_RSAVE;
+ // check for __VALIST
+ if (!pp->is_unresolved && g_func_pp->is_vararg
+ && IS(pp->arg[arg].type.name, "__VALIST"))
+ {
+ snprintf(buf, sizeof(buf), "arg_%X",
+ g_func_pp->argc_stack * 4);
+ k = -1;
+ ret = resolve_origin(j, &ops[j].operand[0], magic + 1, &k);
+ if (ret == 1 && k >= 0 && ops[k].op == OP_LEA
+ && strstr(ops[k].operand[1].name, buf))
+ {
+ ops[k].flags |= OPF_RMD;
+ ops[j].flags |= OPF_RMD | OPF_VAPUSH;
+ save_args &= ~(1 << arg);
+ }
+ }
+
+ *save_arg_vars |= save_args;
+
+ // tracking reg usage
+ if (!(ops[j].flags & OPF_VAPUSH)
+ && ops[j].operand[0].type == OPT_REG)
+ {
+ *regmask |= 1 << ops[j].operand[0].reg;
+ }
+
arg++;
if (!pp->is_unresolved) {
// next arg
break;
}
magic = (magic & 0xffffff) | (arg << 24);
-
- // tracking reg usage
- if (ops[j].operand[0].type == OPT_REG)
- *regmask |= 1 << ops[j].operand[0].reg;
}
}
if (g_func_pp == NULL)
ferr(ops, "proto_parse failed for '%s'\n", funcn);
- fprintf(fout, "%s ", g_func_pp->ret_type.name);
- output_pp_attrs(fout, g_func_pp, g_ida_func_attr & IDAFA_NORETURN);
- fprintf(fout, "%s(", g_func_pp->name);
-
for (i = 0; i < g_func_pp->argc; i++) {
- if (i > 0)
- fprintf(fout, ", ");
- if (g_func_pp->arg[i].fptr != NULL) {
- // func pointer..
- pp = g_func_pp->arg[i].fptr;
- fprintf(fout, "%s (", pp->ret_type.name);
- output_pp_attrs(fout, pp, 0);
- fprintf(fout, "*a%d)(", i + 1);
- for (j = 0; j < pp->argc; j++) {
- if (j > 0)
- fprintf(fout, ", ");
- if (pp->arg[j].fptr)
- ferr(ops, "nested fptr\n");
- fprintf(fout, "%s", pp->arg[j].type.name);
- }
- if (pp->is_vararg) {
- if (j > 0)
- fprintf(fout, ", ");
- fprintf(fout, "...");
- }
- fprintf(fout, ")");
- }
- else if (g_func_pp->arg[i].type.is_retreg) {
- fprintf(fout, "u32 *r_%s", g_func_pp->arg[i].reg);
- }
- else {
- fprintf(fout, "%s a%d", g_func_pp->arg[i].type.name, i + 1);
- }
if (g_func_pp->arg[i].reg != NULL) {
reg = char_array_i(regs_r32,
ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
regmask_arg |= 1 << reg;
}
}
- if (g_func_pp->is_vararg) {
- if (i > 0)
- fprintf(fout, ", ");
- fprintf(fout, "...");
- }
-
- fprintf(fout, ")\n{\n");
// pass1:
// - handle ebp/esp frame, remove ops related to it
// indirect call
pp_c = resolve_icall(i, opcnt, &l);
if (pp_c != NULL) {
+ if (!pp_c->is_func && !pp_c->is_fptr)
+ ferr(po, "call to non-func: %s\n", pp_c->name);
pp = proto_clone(pp_c);
my_assert_not(pp, NULL);
if (l)
pfomask = 1 << po->pfo;
}
- if (tmp_op->op == OP_ADD && po->pfo == PFO_C)
- need_tmp64 = 1;
+ if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
+ propagate_lmod(tmp_op, &tmp_op->operand[0],
+ &tmp_op->operand[1]);
+ if (tmp_op->operand[0].lmod == OPLM_DWORD)
+ need_tmp64 = 1;
+ }
}
if (pfomask) {
tmp_op->pfomask |= pfomask;
else if (po->op == OP_MUL
|| (po->op == OP_IMUL && po->operand_cnt == 1))
{
- need_tmp64 = 1;
+ if (po->operand[0].lmod == OPLM_DWORD)
+ need_tmp64 = 1;
}
else if (po->op == OP_CALL) {
pp = po->pp;
}
}
}
-
- // declare indirect funcs
- if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
- if (pp->name[0] != 0) {
- memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
- memcpy(pp->name, "i_", 2);
-
- // might be declared already
- found = 0;
- for (j = 0; j < i; j++) {
- if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
- if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
- found = 1;
- break;
- }
- }
- }
- if (found)
- continue;
- }
- else
- snprintf(pp->name, sizeof(pp->name), "icall%d", i);
-
- fprintf(fout, " %s (", pp->ret_type.name);
- output_pp_attrs(fout, pp, 0);
- fprintf(fout, "*%s)(", pp->name);
- for (j = 0; j < pp->argc; j++) {
- if (j > 0)
- fprintf(fout, ", ");
- fprintf(fout, "%s a%d", pp->arg[j].type.name, j + 1);
+ }
+ else if (po->op == OP_MOV && po->operand[0].pp != NULL
+ && po->operand[1].pp != NULL)
+ {
+ // <var> = offset <something>
+ if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
+ && !IS_START(po->operand[1].name, "off_"))
+ {
+ if (!po->operand[0].pp->is_fptr)
+ ferr(po, "%s not declared as fptr when it should be\n",
+ po->operand[0].name);
+ if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
+ pp_print(buf1, sizeof(buf1), po->operand[0].pp);
+ pp_print(buf2, sizeof(buf2), po->operand[1].pp);
+ fnote(po, "var: %s\n", buf1);
+ fnote(po, "func: %s\n", buf2);
+ ferr(po, "^ mismatch\n");
}
- fprintf(fout, ");\n");
}
}
else if (po->op == OP_RET && !IS(g_func_pp->ret_type.name, "void"))
}
}
+ // output starts here
+
+ // define userstack size
+ if (g_func_pp->is_userstack) {
+ fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
+ fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
+ fprintf(fout, "#endif\n");
+ }
+
+ // the function itself
+ fprintf(fout, "%s ", g_func_pp->ret_type.name);
+ output_pp_attrs(fout, g_func_pp, g_ida_func_attr & IDAFA_NORETURN);
+ fprintf(fout, "%s(", g_func_pp->name);
+
+ for (i = 0; i < g_func_pp->argc; i++) {
+ if (i > 0)
+ fprintf(fout, ", ");
+ if (g_func_pp->arg[i].fptr != NULL) {
+ // func pointer..
+ pp = g_func_pp->arg[i].fptr;
+ fprintf(fout, "%s (", pp->ret_type.name);
+ output_pp_attrs(fout, pp, 0);
+ fprintf(fout, "*a%d)(", i + 1);
+ for (j = 0; j < pp->argc; j++) {
+ if (j > 0)
+ fprintf(fout, ", ");
+ if (pp->arg[j].fptr)
+ ferr(ops, "nested fptr\n");
+ fprintf(fout, "%s", pp->arg[j].type.name);
+ }
+ if (pp->is_vararg) {
+ if (j > 0)
+ fprintf(fout, ", ");
+ fprintf(fout, "...");
+ }
+ fprintf(fout, ")");
+ }
+ else if (g_func_pp->arg[i].type.is_retreg) {
+ fprintf(fout, "u32 *r_%s", g_func_pp->arg[i].reg);
+ }
+ else {
+ fprintf(fout, "%s a%d", g_func_pp->arg[i].type.name, i + 1);
+ }
+ }
+ if (g_func_pp->is_vararg) {
+ if (i > 0)
+ fprintf(fout, ", ");
+ fprintf(fout, "...");
+ }
+
+ fprintf(fout, ")\n{\n");
+
+ // declare indirect functions
+ for (i = 0; i < opcnt; i++) {
+ po = &ops[i];
+ if (po->flags & OPF_RMD)
+ continue;
+
+ if (po->op == OP_CALL) {
+ pp = po->pp;
+ if (pp == NULL)
+ ferr(po, "NULL pp\n");
+
+ if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
+ if (pp->name[0] != 0) {
+ memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
+ memcpy(pp->name, "i_", 2);
+
+ // might be declared already
+ found = 0;
+ for (j = 0; j < i; j++) {
+ if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
+ if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
+ found = 1;
+ break;
+ }
+ }
+ }
+ if (found)
+ continue;
+ }
+ else
+ snprintf(pp->name, sizeof(pp->name), "icall%d", i);
+
+ fprintf(fout, " %s (", pp->ret_type.name);
+ output_pp_attrs(fout, pp, 0);
+ fprintf(fout, "*%s)(", pp->name);
+ for (j = 0; j < pp->argc; j++) {
+ if (j > 0)
+ fprintf(fout, ", ");
+ fprintf(fout, "%s a%d", pp->arg[j].type.name, j + 1);
+ }
+ fprintf(fout, ");\n");
+ }
+ }
+ }
// output LUTs/jumptables
for (i = 0; i < g_func_pd_cnt; i++) {
}
if (g_func_pp->is_userstack) {
- fprintf(fout, " u32 fake_sf[1024];\n");
- fprintf(fout, " u32 *esp = &fake_sf[1024];\n");
+ fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
+ fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
had_decl = 1;
}
assert_operand_cnt(2);
propagate_lmod(po, &po->operand[0], &po->operand[1]);
out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
+ default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
fprintf(fout, " %s = %s;", buf1,
out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
- po->operand[0].is_ptr ? "(void *)" : "", 0));
+ buf3, 0));
break;
case OP_LEA:
out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
fprintf(fout, " %s = %s;",
out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
- out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], "", 0));
- fprintf(fout, " %s = tmp;",
- out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]));
+ out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
+ default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
+ fprintf(fout, " %s = %stmp;",
+ out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
+ default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
snprintf(g_comment, sizeof(g_comment), "xchg");
break;
ferr(po, "TODO\n");
}
else {
- fprintf(fout, " eax = %sedi; esi %c= %d;",
+ fprintf(fout, " eax = %sesi; esi %c= %d;",
lmod_cast_u_ptr(po, po->operand[0].lmod),
(po->flags & OPF_DF) ? '-' : '+',
lmod_bytes(po, po->operand[0].lmod));
if (pfomask & (1 << PFO_C)) {
// ugh..
fprintf(fout,
- " cond_c = %sedi < %sesi;\n", buf1, buf1);
+ " cond_c = %sesi < %sedi;\n", buf1, buf1);
pfomask &= ~(1 << PFO_C);
}
fprintf(fout,
- " cond_z = (%sedi == %sesi); edi %c= %d, esi %c= %d;\n",
+ " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
buf1, buf1, l, j, l, j);
fprintf(fout,
" if (cond_z %s 0) break;\n",
}
else {
fprintf(fout,
- " cond_z = (%sedi = %sesi); edi %c= %d; esi %c= %d;",
+ " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
buf1, buf1, l, j, l, j);
strcpy(g_comment, "cmps");
}
(po->flags & OPF_REPZ) ? "e" : "ne");
}
else {
- fprintf(fout, " cond_z = (%seax = %sedi); edi %c= %d;",
+ fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
lmod_cast_u(po, po->operand[0].lmod),
lmod_cast_u_ptr(po, po->operand[0].lmod), l, j);
strcpy(g_comment, "scas");
assert_operand_cnt(2);
propagate_lmod(po, &po->operand[0], &po->operand[1]);
if (pfomask & (1 << PFO_C)) {
- fprintf(fout, " tmp64 = (u64)%s + %s;\n",
- out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]),
- out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
- fprintf(fout, " cond_c = tmp64 >> 32;\n");
- fprintf(fout, " %s = (u32)tmp64;",
- out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
- strcat(g_comment, "add64");
+ out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
+ out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
+ if (po->operand[0].lmod == OPLM_DWORD) {
+ fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
+ fprintf(fout, " cond_c = tmp64 >> 32;\n");
+ fprintf(fout, " %s = (u32)tmp64;",
+ out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
+ strcat(g_comment, "add64");
+ }
+ else {
+ fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
+ buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
+ fprintf(fout, " %s += %s;",
+ out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
+ buf2);
+ }
pfomask &= ~(1 << PFO_C);
output_std_flags(fout, po, &pfomask, buf1);
last_arith_dst = &po->operand[0];
// fallthrough
case OP_MUL:
assert_operand_cnt(1);
- strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
- fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
- out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
- fprintf(fout, " edx = tmp64 >> 32;\n");
- fprintf(fout, " eax = tmp64;");
+ switch (po->operand[0].lmod) {
+ case OPLM_DWORD:
+ strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
+ fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
+ out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
+ fprintf(fout, " edx = tmp64 >> 32;\n");
+ fprintf(fout, " eax = tmp64;");
+ break;
+ case OPLM_BYTE:
+ strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
+ fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
+ out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
+ buf1, 0));
+ break;
+ default:
+ ferr(po, "TODO: unhandled mul type\n");
+ break;
+ }
last_arith_dst = NULL;
delayed_flag_op = NULL;
break;
fprintf(fout, " {\n");
}
- if (pp->is_fptr && !pp->is_arg)
+ if (pp->is_fptr && !pp->is_arg) {
fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
"(void *)", 0));
+ if (pp->is_unresolved)
+ fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
+ buf3, asmfn, po->asmln, pp->name);
+ }
fprintf(fout, "%s", buf3);
if (strstr(pp->ret_type.name, "int64")) {
tmp_op = pp->arg[arg].datap;
if (tmp_op == NULL)
ferr(po, "parsed_op missing for arg%d\n", arg);
- if (tmp_op->argnum != 0) {
+
+ if (tmp_op->flags & OPF_VAPUSH) {
+ fprintf(fout, "ap");
+ }
+ else if (tmp_op->argnum != 0) {
fprintf(fout, "%ss_a%d", cast, tmp_op->argnum);
}
else {
}
if (pp->is_unresolved) {
- snprintf(buf2, sizeof(buf2), " unresoved %dreg",
+ snprintf(buf2, sizeof(buf2), " unresolved %dreg",
pp->argc_reg);
strcat(g_comment, buf2);
}
fprintf(fout, " %s = %s;", buf1,
out_src_opr(buf2, sizeof(buf2),
tmp_op, &tmp_op->operand[0],
- po->operand[0].is_ptr ? "(void *)" : "", 0));
+ default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
break;
}
else if (g_func_pp->is_userstack) {
parse_op(&ops[pi], words, wordc);
if (sctproto != NULL) {
- if (ops[pi].op == OP_CALL)
+ if (ops[pi].op == OP_CALL || ops[pi].op == OP_JMP)
ops[pi].datap = sctproto;
sctproto = NULL;
}