Пример #1
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;
}
Пример #2
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;
}
Пример #3
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)); 
}
Пример #4
0
/* patch pointer addition in vtop so that pointer dereferencing is
   also tested */
void gen_bounded_ptr_deref(void)
{
    int func;
    int size, align;
    Elf32_Rel *rel;
    Sym *sym;

    size = 0;
    /* XXX: put that code in generic part of tcc */
    if (!is_float(vtop->type.t)) {
        if (vtop->r & VT_LVAL_BYTE)
            size = 1;
        else if (vtop->r & VT_LVAL_SHORT)
            size = 2;
    }
    if (!size)
        size = type_size(&vtop->type, &align);
    switch(size) {
    case  1: func = TOK___bound_ptr_indir1; break;
    case  2: func = TOK___bound_ptr_indir2; break;
    case  4: func = TOK___bound_ptr_indir4; break;
    case  8: func = TOK___bound_ptr_indir8; break;
    case 12: func = TOK___bound_ptr_indir12; break;
    case 16: func = TOK___bound_ptr_indir16; break;
    default:
        error("unhandled size when derefencing bounded pointer");
        func = 0;
        break;
    }

    /* patch relocation */
    /* XXX: find a better solution ? */
    rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.ul);
    sym = external_global_sym(func, &func_old_type, 0);
    if (!sym->c)
        put_extern_sym(sym, NULL, 0, 0);
    rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info));
}
Пример #5
0
void gcode(void) {
  int i, n, t, r, stacksize, addr, pc, disp, rel, errs, more, func_start;
  Branch *b, *bn;

  // Generate function prolog
  func_start = cur_text_section->data_offset;
  if (!func_naked) {
    // Align local size to word
    stacksize = (-loc + 3) & -4;

    if (stacksize >= 4096) {
      // Generate stack guard since parameters can cross page boundary
      Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0);
      gen(0xb8); // mov stacksize, %eax
      genword(stacksize);
      gen(0xe8);  // call __chkstk, (does the stackframe too)
      put_reloc(cur_text_section, sym, cur_text_section->data_offset, R_386_PC32);
      genword(-4);
    } else {
      if (do_debug || loc || !func_noargs) {
        gen(0x55); // push %ebp
        gen(0x89); // mov %esp, %ebp
        gen(0xe5);
      }
      if (stacksize > 0) {
        if (stacksize == (char) stacksize) {
          gen(0x83);  // sub esp, stacksize
          gen(0xec);
          gen(stacksize);
        } else {
          gen(0x81);  // sub esp, stacksize
          gen(0xec);
          genword(stacksize);
        }
      }
    }
    
    // Save callee-saved registers used by function.
    for (r = 0; r < NB_REGS; ++r) {
      if ((reg_classes[r] & RC_SAVE) && (regs_used & (1 << r))) {
        gen(0x50 + r); // push r
      }
    }
  }

  // Optimize jumps
  more = 1;
  while (more) {
    more = 0;

    for (i = 0; i < br; ++i) {
      b = branch + i;
      if (b->type == CodeLabel) b->target = 0;
      if (b->type != CodeJump) continue;

      t = skip_nops(b->target, 1);
      if (branch[t].type == CodeJump && !branch[t].param && b->target != branch[t].target) {
        // Eliminate jump to jump
        b->target = branch[t].target;
        more = 1;
        continue;
      }

      // Find next non-nop
      n = i + 1;
      while (branch[n].type == CodeNop || branch[n].type == CodeLine) n++;
      bn = branch + n;
      if (b->ind != bn->ind) continue;

      if (!b->param && bn->type == CodeJump) {
        // Eliminate dead jump instruction
        bn->type = CodeNop;
        more = 1;
        continue;
      }

      if (b->target > i && b->target <= n) {
        // Eliminate jump to next instruction
        b->type = CodeNop;
        more = 1;
        continue;
      }
      
      t = skip_nops(n + 1, 0);
      if (bn->type == CodeJump && !bn->param && b->target == t && bn->ind == branch[t].ind) {
        // Optimize inverted jump
        if (b->param) b->param ^= 1;
        b->target = bn->target;
        bn->type = CodeNop;
        more = 1;
        continue;
      }
    }

    // Eliminate unused labels
    for (i = 0; i < br; ++i) {
      b = branch + i;
      if (b->type == CodeJump) branch[b->target].target++;
    }
    for (i = 0; i < br; ++i) {
      b = branch + i;
      if (b->type == CodeLabel && !b->target && !b->sym) {
        // Remove label with no references
        b->type = CodeNop;
        more = 1;
      }
    }
  }

  // Assign addresses to branch points, assuming only long jumps
  addr = cur_text_section->data_offset;
  pc = 0;
  for (i = 0; i < br; ++i) {
    b = branch + i;
    addr += b->ind - pc;
    b->addr = addr;
    switch (b->type) {
      case CodeJump:
        addr += 5;
        if (b->param != 0) addr++;
        break;
        
      case CodeAlign:
        // Use convervative estimate for short/long jump estimation
        addr += b->param - 1;
        break;
    }
    pc = b->ind;
  }
  
  // Find jumps which can be encoded as short jumps
  for (i = 0; i < br; ++i) {
    b = branch + i;
    if (b->type == CodeJump) {
      disp = branch[b->target].addr - b->addr - 2;
      if (b->param) disp--;
      if (disp == (char) disp) b->type = CodeShortJump;
    }
  }

  // Assign final addresses to branch points
  addr = cur_text_section->data_offset;
  pc = 0;
  for (i = 0; i < br; ++i) {
    b = branch + i;
    addr += b->ind - pc;
    b->addr = addr;
    switch (b->type) {
      case CodeJump:
        addr += 5;
        if (b->param) addr++;
        break;

      case CodeShortJump:
        addr += 2;
        break;
      
      case CodeAlign:
        addr = (addr + b->param - 1) & -b->param;
        break;
    }
    pc = b->ind;
  }

  // Generate code blocks
  pc = 0;
  errs = 0;
  for (i = 0; i < br; ++i) {
    b = branch + i;
    
    // Output code block before branch point
    if (b->ind != pc) {
      genblk(code + pc, b->ind - pc);
      pc = b->ind;
    }

    switch (b->type) {
      case CodeLabel:
        // Export label if symbol defined
        if (b->sym) {
          put_extern_sym_ex(b->sym, cur_text_section, b->addr, 0, 0);
          sym_free(b->sym);
        }
        break;

      case CodeJump:
        // Generate long jump instruction
        if (branch[b->target].type != CodeLabel) {
          printf("internal error: jump %d to non-label %d\n", i, b->target);
          errs++;
        }
        if (b->param > 0xff) error("invalid displacement");
        if (b->param == 0) {
          gen(0xe9);
          genword(branch[b->target].addr - (b->addr + 5));
        } else {
          gen(0x0f);
          gen(b->param - 0x10);
          genword(branch[b->target].addr - (b->addr + 6));
        }
        break;

      case CodeShortJump:
        // Generate short jump instruction
        if (branch[b->target].type != CodeLabel) {
          printf("internal error: jump %d to non-label %d\n", i, b->target);
          errs++;
        }
        if (b->param == 0) {
          gen(0xeb);
        } else {
          gen(b->param - 0x20);
        }
        gen(branch[b->target].addr - (b->addr + 2));
        break;

      case CodeReloc:
        if (b->param) {
          rel = R_386_PC32;
        } else {
          rel = R_386_32;
        }
        put_elf_reloc(symtab_section, cur_text_section, b->addr, rel, b->target);
        break;
        
      case CodeAlign:
        i = addr;
        while (i & (b->param - 1)) {
          gen(b->target);
          i++;
        }
        break;

      case CodeLine:
        put_stabn(N_SLINE, 0, b->target, b->addr - func_start);
        break;
    }
  }

  // Generate function epilog
  if (!func_naked) {
    // Restore callee-saved registers used by function.
    for (r = NB_REGS; r >= 0; --r) {
      if ((reg_classes[r] & RC_SAVE) && (regs_used & (1 << r))) {
        gen(0x58 + r); // pop r
      }
    }

    if (do_debug || loc || !func_noargs) gen(0xc9); // leave

    // Generate return
    if (func_ret_sub == 0) {
      gen(0xc3); // ret
    } else {
      gen(0xc2); // ret n
      gen(func_ret_sub);
      gen(func_ret_sub >> 8);
    }
  }

#ifdef DEBUG_BRANCH
  printf("\nbranch table for %s\n", func_name);
  printf(" #   t targ parm    ind      addr\n");
  printf("---- - ---- ----- -------- --------\n");
  for (i = 0; i < br; ++i) {
    b = branch + i;
    printf("%04d %c %04d %04x %08x %08x", i, "SLJjRANlE"[b->type], b->target, b->param, b->ind, b->addr);
    if (branch[i].sym) {
      printf(" sym=%s", get_tok_str(b->sym->v, NULL));
    }
    printf("\n");
  }
  printf("\n");
#endif

  if (errs) error("internal error: code generation");
}
Пример #6
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;
}