Exemple #1
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));
  }
}
Exemple #2
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--;
}
Exemple #3
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
    }
  }
}
Exemple #4
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 */
        }
    }
}