Пример #1
0
void gadd_sp(int val) {
  if (val == (char) val) {
    o(0xc483);
    g(val);
  } else {
    oad(0xc481, val); // add $xxx, %esp
  }
}
Пример #2
0
/* generate a jump to a fixed address */
void gjmp_addr(int a)
{
    int r;
    r = a - ind - 2;
    if (r == (char)r) {
        g(0xeb);
        g(r);
    } else {
        oad(0xe9, a - ind - 5);
    }
}
Пример #3
0
/* XXX: handle long long case */
ST_FUNC void gen_cvt_ftoi(int t)
{
	int r, r2, size;
	Sym *sym;
	CType ushort_type;

	ushort_type.t = VT_SHORT | VT_UNSIGNED;
	ushort_type.ref = 0;

	gv(RC_FLOAT);
	if (t != VT_INT)
		size = 8;
	else 
		size = 4;

	o(0x2dd9); /* ldcw xxx */
	sym = external_global_sym(TOK___tcc_int_fpu_control, 
		&ushort_type, VT_LVAL);
	greloc(cur_text_section, sym, 
		ind, R_386_32);
	gen_le32(0);

	oad(0xec81, size); /* sub $xxx, %esp */
	if (size == 4)
		o(0x1cdb); /* fistpl */
	else
		o(0x3cdf); /* fistpll */
	o(0x24);
	o(0x2dd9); /* ldcw xxx */
	sym = external_global_sym(TOK___tcc_fpu_control, 
		&ushort_type, VT_LVAL);
	greloc(cur_text_section, sym, 
		ind, R_386_32);
	gen_le32(0);

	r = get_reg(RC_INT);
	o(0x58 + r); /* pop r */
	if (size == 8) {
		if (t == VT_LLONG) {
			vtop->r = r; /* mark reg as used */
			r2 = get_reg(RC_INT);
			o(0x58 + r2); /* pop r2 */
			vtop->r2 = r2;
		} else {
			o(0x04c483); /* add $4, %esp */
		}
	}
	vtop->r = r;
}
Пример #4
0
// Generate a modrm reference. 'op_reg' contains the additional 3
// opcode bits
void gen_modrm(int op_reg, int r, Sym *sym, int c) {
  op_reg = op_reg << 3;
  if ((r & VT_VALMASK) == VT_CONST) {
    // Constant memory reference
    o(0x05 | op_reg);
    gen_addr32(r, sym, c);
  } else if ((r & VT_VALMASK) == VT_LOCAL) {
    // Currently, we use only ebp as base
    if (c == (char) c) {
      // Short reference
      o(0x45 | op_reg);
      g(c);
    } else {
      oad(0x85 | op_reg, c);
    }
  } else {
    g(0x00 | op_reg | (r & VT_VALMASK));
  }
}
Пример #5
0
/* generate a bounded pointer addition */
void gen_bounded_ptr_add(void)
{
    Sym *sym;

    /* prepare fast i386 function call (args in eax and edx) */
    gv2(RC_EAX, RC_EDX);
    /* save all temporary registers */
    vtop -= 2;
    save_regs(0);
    /* do a fast function call */
    sym = external_global_sym(TOK___bound_ptr_add, &func_old_type, 0);
    greloc(cur_text_section, sym, 
           ind + 1, R_386_PC32);
    oad(0xe8, -4);
    /* returned pointer is in eax */
    vtop++;
    vtop->r = TREG_EAX | VT_BOUNDED;
    /* address of bounding function call point */
    vtop->c.ul = (cur_text_section->reloc->data_offset - sizeof(Elf32_Rel)); 
}
Пример #6
0
// Convert fp to int 't' type
// TODO: handle long long case
void gen_cvt_ftoi(int t) {
  int r, r2, size;
  CType ushort_type;

  ushort_type.t = VT_SHORT | VT_UNSIGNED;

  gv(RC_FLOAT);
  if (t != VT_INT) {
    size = 8;
  } else {
    size = 4;
  }

  o(0x2dd9); // ldcw xxx
  greloc(external_global_sym(TOK___tcc_int_fpu_control, &ushort_type, VT_LVAL), 0, 0);
  
  oad(0xec81, size); // sub $xxx, %esp
  if (size == 4)  {
    o(0x1cdb); // fistpl
  } else {
    o(0x3cdf); // fistpll
  }
  o(0x24);
  o(0x2dd9); // ldcw xxx
  greloc(external_global_sym(TOK___tcc_fpu_control, &ushort_type, VT_LVAL), 0, 0);

  r = get_reg(RC_INT);
  o(0x58 + r); // pop r
  if (size == 8) {
    if (t == VT_LLONG) {
      vtop->r = r; // Mark reg as used
      r2 = get_reg(RC_INT);
      o(0x58 + r2); // pop r2
      vtop->r2 = r2;
    } else {
      o(0x04c483); // add $4, %esp
    }
  }
  vtop->r = r;
}
Пример #7
0
/* 'is_jmp' is '1' if it is a jump */
static void gcall_or_jmp(int is_jmp)
{
    int r;
    if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
        /* constant case */
        if (vtop->r & VT_SYM) {
            /* relocation case */
            greloc(cur_text_section, vtop->sym, 
                   ind + 1, R_386_PC32);
        } else {
            /* put an empty PC32 relocation */
            put_elf_reloc(symtab_section, cur_text_section, 
                          ind + 1, R_386_PC32, 0);
        }
        oad(0xe8 + is_jmp, vtop->c.ul - 4); /* call/jmp im */
    } else {
        /* otherwise, indirect call */
        r = gv(RC_INT);
        o(0xff); /* call/jmp *r */
        o(0xd0 + r + (is_jmp << 4));
    }
}
Пример #8
0
// Generate an integer binary operation
void gen_opi(int op) {
  int r, fr, opc, c;

  switch (op) {
    case '+':
    case TOK_ADDC1: // Add with carry generation
      opc = 0;
    gen_op8:
      if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
        // Constant case
        vswap();
        r = gv(RC_INT);
        vswap();
        c = vtop->c.i;
        if (c == (char) c) {
          // Optimize +/- 1 case with inc and dec
          if (op == '+' && c == 1 || op == '-' && c == -1) {
            o(0x40 | r);  // inc r
          } else if (op == '-' && c == 1 || op == '+' && c == -1) {
            o(0x48 | r);  // dec r
          } else {
            o(0x83);
            o(0xc0 | (opc << 3) | r);
            g(c);
          }
        } else {
          o(0x81);
          oad(0xc0 | (opc << 3) | r, c);
        }
      } else {
        gv2(RC_INT, RC_INT);
        r = vtop[-1].r;
        fr = vtop[0].r;
        o((opc << 3) | 0x01);
        o(0xc0 + r + fr * 8); 
      }
      vtop--;
      if (op >= TOK_ULT && op <= TOK_GT) {
        vtop->r = VT_CMP;
        vtop->c.i = op;
      }
      break;
    case '-':
    case TOK_SUBC1: // Subtract with carry generation
      opc = 5;
      goto gen_op8;
    case TOK_ADDC2: // Add with carry use
      opc = 2;
      goto gen_op8;
    case TOK_SUBC2: // Subtract with carry use
      opc = 3;
      goto gen_op8;
    case '&':
      opc = 4;
      goto gen_op8;
    case '^':
      opc = 6;
      goto gen_op8;
    case '|':
      opc = 1;
      goto gen_op8;
    case '*':
      gv2(RC_INT, RC_INT);
      r = vtop[-1].r;
      fr = vtop[0].r;
      vtop--;
      o(0xaf0f); // imul fr, r
      o(0xc0 + fr + r * 8);
      break;
    case TOK_SHL:
      opc = 4;
      goto gen_shift;
    case TOK_SHR:
      opc = 5;
      goto gen_shift;
    case TOK_SAR:
      opc = 7;
    gen_shift:
      opc = 0xc0 | (opc << 3);
      if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
        // Constant case
        vswap();
        r = gv(RC_INT);
        vswap();
        c = vtop->c.i & 0x1f;
        o(0xc1); // shl/shr/sar $xxx, r
        o(opc | r);
        g(c);
      } else {
        // Generate the shift in ecx
        gv2(RC_INT, RC_ECX);
        r = vtop[-1].r;
        o(0xd3); // shl/shr/sar %cl, r
        o(opc | r);
      }
      vtop--;
      break;
    case '/':
    case TOK_UDIV:
    case TOK_PDIV:
    case '%':
    case TOK_UMOD:
    case TOK_UMULL:
      // First operand must be in eax
      // TODO: need better constraint for second operand
      gv2(RC_EAX, RC_ECX);
      r = vtop[-1].r;
      fr = vtop[0].r;
      vtop--;
      save_reg(TREG_EDX);
      if (op == TOK_UMULL) {
        o(0xf7); // mul fr
        o(0xe0 + fr);
        vtop->r2 = TREG_EDX;
        r = TREG_EAX;
      } else {
        if (op == TOK_UDIV || op == TOK_UMOD) {
          o(0xf7d231); // xor %edx, %edx, div fr, %eax
          o(0xf0 + fr);
        } else {
          o(0xf799); // cltd, idiv fr, %eax
          o(0xf8 + fr);
        }
        if (op == '%' || op == TOK_UMOD) {
          r = TREG_EDX;
        } else {
          r = TREG_EAX;
        }
      }
      vtop->r = r;
      break;
    default:
      opc = 7;
      goto gen_op8;
  }
}
Пример #9
0
// Generate function call. The function address is pushed first, then
// all the parameters in call order. This function pops all the
// parameters and the function address.
void gfunc_call(int nb_args) {
  int size, align, r, args_size, i, func_call, v;
  Sym *func_sym;
  
  args_size = 0;
  for (i = 0; i < nb_args; i++) {
    if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
      size = type_size(&vtop->type, &align);
      // Align to stack align size
      size = (size + 3) & ~3;
      // Allocate the necessary size on stack
      oad(0xec81, size); // sub $xxx, %esp
      // Generate structure store
      r = get_reg(RC_INT);
      o(0x89); // mov %esp, r
      o(0xe0 + r);
      vset(&vtop->type, r | VT_LVAL, 0);
      vswap();
      vstore();
      args_size += size;
    } else if (is_float(vtop->type.t)) {
      gv(RC_FLOAT); // Only one float register
      if ((vtop->type.t & VT_BTYPE) == VT_FLOAT) {
        size = 4;
      } else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) {
        size = 8;
      } else {
        size = 12;
      }
      oad(0xec81, size); // sub $xxx, %esp
      if (size == 12) {
        o(0x7cdb);
      } else {
        o(0x5cd9 + size - 4); // fstp[s|l] 0(%esp)
      }
      g(0x24);
      g(0x00);
      args_size += size;
    } else {
      // Simple type (currently always same size)
      // TODO: implicit cast?
      v = vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM);
      if (v == VT_CONST || v == (VT_CONST | VT_SYM)) {
        // Push constant
        if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
          size = 8;
          if (vtop->c.word[1] == (char) vtop->c.word[1]) {
            g(0x6a); // push imm8
            g(vtop->c.word[1]);
          } else {
            g(0x68); // push imm32
            gen_le32(vtop->c.word[1]);
          }
        } else {
          size = 4;
        }
        if ((v & VT_SYM) == 0 && vtop->c.i == (char) vtop->c.i) {
          g(0x6a); // push imm8
          g(vtop->c.i);
        } else {
          g(0x68); // push imm32
          gen_addr32(v, vtop->sym, vtop->c.i);
        }
      } else {
        r = gv(RC_INT);
        if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
          size = 8;
          o(0x50 + vtop->r2); // push r2
        } else {
          size = 4;
        }
        o(0x50 + r); // push r
      }
      args_size += size;
    }
    vtop--;
  }
  save_regs(0); // Save used temporary registers
  func_sym = vtop->type.ref;
  func_call = FUNC_CALL(func_sym->r);

  // fast call case
  if ((func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) ||
    func_call == FUNC_FASTCALLW) {
    int fastcall_nb_regs;
    uint8_t *fastcall_regs_ptr;
    if (func_call == FUNC_FASTCALLW) {
      fastcall_regs_ptr = fastcallw_regs;
      fastcall_nb_regs = 2;
    } else {
      fastcall_regs_ptr = fastcall_regs;
      fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1;
    }
    for (i = 0; i < fastcall_nb_regs; i++) {
      if (args_size <= 0) break;
      o(0x58 + fastcall_regs_ptr[i]); // pop r
      // TODO: incorrect for struct/floats
      args_size -= 4;
    }
  }
  gcall_or_jmp(0);
  if (args_size && func_call != FUNC_STDCALL) gadd_sp(args_size);
  vtop--;
}
Пример #10
0
// Load 'r' from value 'sv'
void load(int r, SValue *sv) {
  int v, t, ft, fc, fr, a;
  SValue v1;

  fr = sv->r;
  ft = sv->type.t;
  fc = sv->c.ul;
  regs_used |= 1 << r;

  v = fr & VT_VALMASK;
  if (fr & VT_LVAL) {
    if (v == VT_LLOCAL) {
      v1.type.t = VT_INT;
      v1.r = VT_LOCAL | VT_LVAL;
      v1.c.ul = fc;
      load(r, &v1);
      fr = r;
    }
    if ((ft & VT_BTYPE) == VT_FLOAT) {
      o(0xd9); // flds
      r = 0;
    } else if ((ft & VT_BTYPE) == VT_DOUBLE) {
      o(0xdd); // fldl
      r = 0;
    } else if ((ft & VT_BTYPE) == VT_LDOUBLE) {
      o(0xdb); // fldt
      r = 5;
    } else if ((ft & VT_TYPE) == VT_BYTE) {
      o(0xbe0f);   // movsbl
    } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) {
      o(0xb60f);   // movzbl
    } else if ((ft & VT_TYPE) == VT_SHORT) {
      o(0xbf0f);   // movswl
    } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) {
      o(0xb70f);   // movzwl
    } else {
      o(0x8b);     // movl
    }
    gen_modrm(r, fr, sv->sym, fc);
  } else {
    if (v == VT_CONST) {
      if (fc == 0 && (fr & VT_SYM) == 0) {
        o(0x33); // xor r, r
        o(0xc0 + r + r * 8);
      } else {
        o(0xb8 + r); // mov $xx, r
        gen_addr32(fr, sv->sym, fc);
      }
    } else if (v == VT_LOCAL) {
      o(0x8d); // lea xxx(%ebp), r
      gen_modrm(r, VT_LOCAL, sv->sym, fc);
    } else if (v == VT_CMP) {
      o(0x0f); // setxx br
      o(fc);
      o(0xc0 + r);
      o(0x0f); // movzx r,br
      o(0xb6);
      o(0xc0 + r + r * 8);
    } else if (v == VT_JMP || v == VT_JMPI) {
      t = v & 1;
      oad(0xb8 + r, t); // mov $1, r
      a = gjmp(0, 0); // jmp after
      gsym(fc);
      oad(0xb8 + r, t ^ 1); // mov $0, r
      gsym(a);
    } else if (v != r) {
      o(0x89);
      o(0xc0 + r + v * 8); // mov v, r
    }
  }
}
Пример #11
0
/* generate an integer binary operation */
void gen_opi(int op)
{
    int r, fr, opc, c;

    switch(op) {
    case '+':
    case TOK_ADDC1: /* add with carry generation */
        opc = 0;
    gen_op8:
        if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
            /* constant case */
            vswap();
            r = gv(RC_INT);
            vswap();
            c = vtop->c.i;
            if (c == (char)c) {
                /* XXX: generate inc and dec for smaller code ? */
                o(0x83);
                o(0xc0 | (opc << 3) | r);
                g(c);
            } else {
                o(0x81);
                oad(0xc0 | (opc << 3) | r, c);
            }
        } else {
            gv2(RC_INT, RC_INT);
            r = vtop[-1].r;
            fr = vtop[0].r;
            o((opc << 3) | 0x01);
            o(0xc0 + r + fr * 8); 
        }
        vtop--;
        if (op >= TOK_ULT && op <= TOK_GT) {
            vtop->r = VT_CMP;
            vtop->c.i = op;
        }
        break;
    case '-':
    case TOK_SUBC1: /* sub with carry generation */
        opc = 5;
        goto gen_op8;
    case TOK_ADDC2: /* add with carry use */
        opc = 2;
        goto gen_op8;
    case TOK_SUBC2: /* sub with carry use */
        opc = 3;
        goto gen_op8;
    case '&':
        opc = 4;
        goto gen_op8;
    case '^':
        opc = 6;
        goto gen_op8;
    case '|':
        opc = 1;
        goto gen_op8;
    case '*':
        gv2(RC_INT, RC_INT);
        r = vtop[-1].r;
        fr = vtop[0].r;
        vtop--;
        o(0xaf0f); /* imul fr, r */
        o(0xc0 + fr + r * 8);
        break;
    case TOK_SHL:
        opc = 4;
        goto gen_shift;
    case TOK_SHR:
        opc = 5;
        goto gen_shift;
    case TOK_SAR:
        opc = 7;
    gen_shift:
        opc = 0xc0 | (opc << 3);
        if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
            /* constant case */
            vswap();
            r = gv(RC_INT);
            vswap();
            c = vtop->c.i & 0x1f;
            o(0xc1); /* shl/shr/sar $xxx, r */
            o(opc | r);
            g(c);
        } else {
            /* we generate the shift in ecx */
            gv2(RC_INT, RC_ECX);
            r = vtop[-1].r;
            o(0xd3); /* shl/shr/sar %cl, r */
            o(opc | r);
        }
        vtop--;
        break;
    case '/':
    case TOK_UDIV:
    case TOK_PDIV:
    case '%':
    case TOK_UMOD:
    case TOK_UMULL:
        /* first operand must be in eax */
        /* XXX: need better constraint for second operand */
        gv2(RC_EAX, RC_ECX);
        r = vtop[-1].r;
        fr = vtop[0].r;
        vtop--;
        save_reg(TREG_EDX);
        if (op == TOK_UMULL) {
            o(0xf7); /* mul fr */
            o(0xe0 + fr);
            vtop->r2 = TREG_EDX;
            r = TREG_EAX;
        } else {
            if (op == TOK_UDIV || op == TOK_UMOD) {
                o(0xf7d231); /* xor %edx, %edx, div fr, %eax */
                o(0xf0 + fr);
            } else {
                o(0xf799); /* cltd, idiv fr, %eax */
                o(0xf8 + fr);
            }
            if (op == '%' || op == TOK_UMOD)
                r = TREG_EDX;
            else
                r = TREG_EAX;
        }
        vtop->r = r;
        break;
    default:
        opc = 7;
        goto gen_op8;
    }
}
Пример #12
0
/* generate function epilog */
void gfunc_epilog(void)
{
    int v, saved_ind;

#ifdef CONFIG_TCC_BCHECK
    if (tcc_state->do_bounds_check
     && func_bound_offset != lbounds_section->data_offset) {
        int saved_ind;
        int *bounds_ptr;
        Sym *sym, *sym_data;
        /* add end of table info */
        bounds_ptr = section_ptr_add(lbounds_section, sizeof(int));
        *bounds_ptr = 0;
        /* generate bound local allocation */
        saved_ind = ind;
        ind = func_sub_sp_offset;
        sym_data = get_sym_ref(&char_pointer_type, lbounds_section, 
                               func_bound_offset, lbounds_section->data_offset);
        greloc(cur_text_section, sym_data,
               ind + 1, R_386_32);
        oad(0xb8, 0); /* mov %eax, xxx */
        sym = external_global_sym(TOK___bound_local_new, &func_old_type, 0);
        greloc(cur_text_section, sym, 
               ind + 1, R_386_PC32);
        oad(0xe8, -4);
        ind = saved_ind;
        /* generate bound check local freeing */
        o(0x5250); /* save returned value, if any */
        greloc(cur_text_section, sym_data,
               ind + 1, R_386_32);
        oad(0xb8, 0); /* mov %eax, xxx */
        sym = external_global_sym(TOK___bound_local_delete, &func_old_type, 0);
        greloc(cur_text_section, sym, 
               ind + 1, R_386_PC32);
        oad(0xe8, -4);
        o(0x585a); /* restore returned value, if any */
    }
#endif
    o(0xc9); /* leave */
    if (func_ret_sub == 0) {
        o(0xc3); /* ret */
    } else {
        o(0xc2); /* ret n */
        g(func_ret_sub);
        g(func_ret_sub >> 8);
    }
    /* align local size to word & save local variables */
    
    v = (-loc + 3) & -4; 
    saved_ind = ind;
    ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
#ifdef TCC_TARGET_PE
    if (v >= 4096) {
        Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0);
        oad(0xb8, v); /* mov stacksize, %eax */
        oad(0xe8, -4); /* call __chkstk, (does the stackframe too) */
        greloc(cur_text_section, sym, ind-4, R_386_PC32);
    } else
#endif
    {
        o(0xe58955);  /* push %ebp, mov %esp, %ebp */
        o(0xec81);  /* sub esp, stacksize */
        gen_le32(v);
#if FUNC_PROLOG_SIZE == 10
        o(0x90);  /* adjust to FUNC_PROLOG_SIZE */
#endif
    }
    ind = saved_ind;
}
Пример #13
0
/* generate function prolog of type 't' */
void gfunc_prolog(CType *func_type)
{
    int addr, align, size, func_call, fastcall_nb_regs;
    int param_index, param_addr;
    uint8_t *fastcall_regs_ptr;
    Sym *sym;
    CType *type;

    sym = func_type->ref;
    func_call = FUNC_CALL(sym->r);
    addr = 8;
    loc = 0;
    if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) {
        fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1;
        fastcall_regs_ptr = fastcall_regs;
    } else if (func_call == FUNC_FASTCALLW) {
        fastcall_nb_regs = 2;
        fastcall_regs_ptr = fastcallw_regs;
    } else {
        fastcall_nb_regs = 0;
        fastcall_regs_ptr = NULL;
    }
    param_index = 0;

    ind += FUNC_PROLOG_SIZE;
    func_sub_sp_offset = ind;
    /* if the function returns a structure, then add an
       implicit pointer parameter */
    func_vt = sym->type;
    if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
        /* XXX: fastcall case ? */
        func_vc = addr;
        addr += 4;
        param_index++;
    }
    /* define parameters */
    while ((sym = sym->next) != NULL) {
        type = &sym->type;
        size = type_size(type, &align);
        size = (size + 3) & ~3;
#ifdef FUNC_STRUCT_PARAM_AS_PTR
        /* structs are passed as pointer */
        if ((type->t & VT_BTYPE) == VT_STRUCT) {
            size = 4;
        }
#endif
        if (param_index < fastcall_nb_regs) {
            /* save FASTCALL register */
            loc -= 4;
            o(0x89);     /* movl */
            gen_modrm(fastcall_regs_ptr[param_index], VT_LOCAL, NULL, loc);
            param_addr = loc;
        } else {
            param_addr = addr;
            addr += size;
        }
        sym_push(sym->v & ~SYM_FIELD, type,
                 VT_LOCAL | lvalue_type(type->t), param_addr);
        param_index++;
    }
    func_ret_sub = 0;
    /* pascal type call ? */
    if (func_call == FUNC_STDCALL)
        func_ret_sub = addr - 8;

    /* leave some room for bound checking code */
    if (tcc_state->do_bounds_check) {
        oad(0xb8, 0); /* lbound section pointer */
        oad(0xb8, 0); /* call to function */
        func_bound_offset = lbounds_section->data_offset;
    }
}
Пример #14
0
/* Generate function call. The function address is pushed first, then
   all the parameters in call order. This functions pops all the
   parameters and the function address. */
void gfunc_call(int nb_args)
{
    int size, align, r, args_size, i, func_call;
    Sym *func_sym;
    
    args_size = 0;
    for(i = 0;i < nb_args; i++) {
        if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
            size = type_size(&vtop->type, &align);
            /* align to stack align size */
            size = (size + 3) & ~3;
            /* allocate the necessary size on stack */
            oad(0xec81, size); /* sub $xxx, %esp */
            /* generate structure store */
            r = get_reg(RC_INT);
            o(0x89); /* mov %esp, r */
            o(0xe0 + r);
            vset(&vtop->type, r | VT_LVAL, 0);
            vswap();
            vstore();
            args_size += size;
        } else if (is_float(vtop->type.t)) {
            gv(RC_FLOAT); /* only one float register */
            if ((vtop->type.t & VT_BTYPE) == VT_FLOAT)
                size = 4;
            else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
                size = 8;
            else
                size = 12;
            oad(0xec81, size); /* sub $xxx, %esp */
            if (size == 12)
                o(0x7cdb);
            else
                o(0x5cd9 + size - 4); /* fstp[s|l] 0(%esp) */
            g(0x24);
            g(0x00);
            args_size += size;
        } else {
            /* simple type (currently always same size) */
            /* XXX: implicit cast ? */
            r = gv(RC_INT);
            if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
                size = 8;
                o(0x50 + vtop->r2); /* push r */
            } else {
                size = 4;
            }
            o(0x50 + r); /* push r */
            args_size += size;
        }
        vtop--;
    }
    save_regs(0); /* save used temporary registers */
    func_sym = vtop->type.ref;
    func_call = FUNC_CALL(func_sym->r);
    /* fast call case */
    if ((func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) ||
        func_call == FUNC_FASTCALLW) {
        int fastcall_nb_regs;
        uint8_t *fastcall_regs_ptr;
        if (func_call == FUNC_FASTCALLW) {
            fastcall_regs_ptr = fastcallw_regs;
            fastcall_nb_regs = 2;
        } else {
            fastcall_regs_ptr = fastcall_regs;
            fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1;
        }
        for(i = 0;i < fastcall_nb_regs; i++) {
            if (args_size <= 0)
                break;
            o(0x58 + fastcall_regs_ptr[i]); /* pop r */
            /* XXX: incorrect for struct/floats */
            args_size -= 4;
        }
    }
    gcall_or_jmp(0);
    if (args_size && func_call != FUNC_STDCALL)
        gadd_sp(args_size);
    vtop--;
}
Пример #15
0
/* load 'r' from value 'sv' */
void load(int r, SValue *sv)
{
    int v, t, ft, fc, fr;
    SValue v1;

    fr = sv->r;
    ft = sv->type.t;
    fc = sv->c.ul;

    v = fr & VT_VALMASK;
    if (fr & VT_LVAL) {
        if (v == VT_LLOCAL) {
            v1.type.t = VT_INT;
            v1.r = VT_LOCAL | VT_LVAL;
            v1.c.ul = fc;
            load(r, &v1);
            fr = r;
        }
        if ((ft & VT_BTYPE) == VT_FLOAT) {
            o(0xd9); /* flds */
            r = 0;
        } else if ((ft & VT_BTYPE) == VT_DOUBLE) {
            o(0xdd); /* fldl */
            r = 0;
        } else if ((ft & VT_BTYPE) == VT_LDOUBLE) {
            o(0xdb); /* fldt */
            r = 5;
        } else if ((ft & VT_TYPE) == VT_BYTE) {
            o(0xbe0f);   /* movsbl */
        } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) {
            o(0xb60f);   /* movzbl */
        } else if ((ft & VT_TYPE) == VT_SHORT) {
            o(0xbf0f);   /* movswl */
        } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) {
            o(0xb70f);   /* movzwl */
        } else {
            o(0x8b);     /* movl */
        }
        gen_modrm(r, fr, sv->sym, fc);
    } else {
        if (v == VT_CONST) {
            o(0xb8 + r); /* mov $xx, r */
            gen_addr32(fr, sv->sym, fc);
        } else if (v == VT_LOCAL) {
            o(0x8d); /* lea xxx(%ebp), r */
            gen_modrm(r, VT_LOCAL, sv->sym, fc);
        } else if (v == VT_CMP) {
            oad(0xb8 + r, 0); /* mov $0, r */
            o(0x0f); /* setxx %br */
            o(fc);
            o(0xc0 + r);
        } else if (v == VT_JMP || v == VT_JMPI) {
            t = v & 1;
            oad(0xb8 + r, t); /* mov $1, r */
            o(0x05eb); /* jmp after */
            gsym(fc);
            oad(0xb8 + r, t ^ 1); /* mov $0, r */
        } else if (v != r) {
            o(0x89);
            o(0xc0 + r + v * 8); /* mov v, r */
        }
    }
}