+ lr_new = calloc(1, sizeof(*lr_new));
+ lr_new->i = op_i;
+ lr_new->next = lr->next;
+ lr->next = lr_new;
+}
+
+static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
+{
+ struct parsed_op *po = &ops[i];
+ struct parsed_data *pd;
+ char label[NAMELEN], *p;
+ int len, j, l;
+
+ p = strchr(po->operand[0].name, '[');
+ if (p == NULL)
+ return NULL;
+
+ len = p - po->operand[0].name;
+ strncpy(label, po->operand[0].name, len);
+ label[len] = 0;
+
+ for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
+ if (IS(g_func_pd[j].label, label)) {
+ pd = &g_func_pd[j];
+ break;
+ }
+ }
+ if (pd == NULL)
+ //ferr(po, "label '%s' not parsed?\n", label);
+ return NULL;
+
+ if (pd->type != OPT_OFFSET)
+ ferr(po, "label '%s' with non-offset data?\n", label);
+
+ // find all labels, link
+ for (j = 0; j < pd->count; j++) {
+ for (l = 0; l < opcnt; l++) {
+ if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
+ add_label_ref(&g_label_refs[l], i);
+ pd->d[j].bt_i = l;
+ break;
+ }
+ }
+ }
+
+ return pd;
+}
+
+static void clear_labels(int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (g_labels[i] != NULL) {
+ free(g_labels[i]);
+ g_labels[i] = NULL;
+ }
+ }
+}
+
+static void resolve_branches_parse_calls(int opcnt)
+{
+ const struct parsed_proto *pp_c;
+ struct parsed_proto *pp;
+ struct parsed_data *pd;
+ struct parsed_op *po;
+ const char *tmpname;
+ int i, l, ret;
+
+ for (i = 0; i < opcnt; i++)
+ {
+ po = &ops[i];
+ po->bt_i = -1;
+ po->btj = NULL;
+
+ if (po->op == OP_CALL) {
+ pp = NULL;
+
+ if (po->operand[0].type == OPT_LABEL) {
+ tmpname = opr_name(po, 0);
+ if (IS_START(tmpname, "loc_"))
+ ferr(po, "call to loc_*\n");
+ pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
+ if (!g_header_mode && pp_c == NULL)
+ ferr(po, "proto_parse failed for call '%s'\n", tmpname);
+
+ if (pp_c != NULL) {
+ pp = proto_clone(pp_c);
+ my_assert_not(pp, NULL);
+ }
+ }
+ else if (po->datap != NULL) {
+ pp = calloc(1, sizeof(*pp));
+ my_assert_not(pp, NULL);
+
+ ret = parse_protostr(po->datap, pp);
+ if (ret < 0)
+ ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
+ free(po->datap);
+ po->datap = NULL;
+ }
+
+ if (pp != NULL) {
+ if (pp->is_fptr)
+ check_func_pp(po, pp, "fptr var call");
+ if (pp->is_noreturn)
+ po->flags |= OPF_TAIL;
+ }
+ po->pp = pp;
+ continue;
+ }
+
+ if (!(po->flags & OPF_JMP) || po->op == OP_RET)
+ continue;
+
+ if (po->operand[0].type == OPT_REGMEM) {
+ pd = try_resolve_jumptab(i, opcnt);
+ if (pd == NULL)
+ goto tailcall;
+
+ po->btj = pd;
+ continue;
+ }
+
+ for (l = 0; l < opcnt; l++) {
+ if (g_labels[l] != NULL
+ && IS(po->operand[0].name, g_labels[l]))
+ {
+ if (l == i + 1 && po->op == OP_JMP) {
+ // yet another alignment type..
+ po->flags |= OPF_RMD|OPF_DONE;
+ break;
+ }
+ add_label_ref(&g_label_refs[l], i);
+ po->bt_i = l;
+ break;
+ }
+ }
+
+ if (po->bt_i != -1 || (po->flags & OPF_RMD))
+ continue;
+
+ if (po->operand[0].type == OPT_LABEL)
+ // assume tail call
+ goto tailcall;
+
+ ferr(po, "unhandled branch\n");
+
+tailcall:
+ po->op = OP_CALL;
+ po->flags |= OPF_TAIL;
+ if (i > 0 && ops[i - 1].op == OP_POP)
+ po->flags |= OPF_ATAIL;
+ i--; // reprocess
+ }