Example #1
0
/* NOTE: the same name space as C labels is used to avoid using too
   much memory when storing labels in TokenStrings */
static void asm_new_label1(TCCState *s1, int label, int is_local,
                           int sh_num, int value)
{
    Sym *sym;

    sym = label_find(label);
    if (sym) {
        if (sym->r) {
            /* the label is already defined */
            if (!is_local) {
                tcc_error("assembler label '%s' already defined", 
                      get_tok_str(label, NULL));
            } else {
                /* redefinition of local labels is possible */
                goto new_label;
            }
        }
    } else {
    new_label:
        sym = label_push(&s1->asm_labels, label, 0);
        sym->type.t = VT_STATIC | VT_VOID;
    }
    sym->r = sh_num;
    sym->jnext = value;
}
Example #2
0
char* get_sym_str(Sym* sym)
{
  static char name[256];
  char* symname;
  
  symname = get_tok_str(sym->v, NULL);
  
  name[0] = 0;
  /* if static, add prefix */
#if 0
  if(sym->type.t & VT_STATICLOCAL) {
    strcpy(name, "__local_");
  }
  else
#endif
  if(sym->type.t & VT_STATIC) {
    //fprintf(stderr,"sym %s type 0x%x current_fn %s token %d\n",symname,sym->type.t,current_fn,sym->v);
    if((sym->type.t & VT_STATICLOCAL) && current_fn[0] != 0 && !((sym->type.t & VT_BTYPE) == VT_FUNC))
      sprintf(name, "%s_FUNC_%s_", static_prefix, current_fn);
    else
      strcpy(name, static_prefix);
#if 0
    for(int i = 0; i < labels; i++) {
      if(strcmp(label[i].name, symname) == 0)
        strcpy(name, "__local_");
    }
#endif
  }
    
  /* add symbol name */
  strcat(name, symname);

  //fprintf(stderr,"symbol %s type 0x%x\n", name, sym->type.t);
  return name;
}
Example #3
0
static void asm_expr_unary(TCCState *s1, ExprValue *pe)
{
    Sym *sym;
    int op, n, label;
    const char *p;

    switch(tok) {
    case TOK_PPNUM:
        p = tokc.cstr->data;
        n = strtoul(p, (char **)&p, 0);
        if (*p == 'b' || *p == 'f') {
            /* backward or forward label */
            label = asm_get_local_label_name(s1, n);
            sym = label_find(label);
            if (*p == 'b') {
                /* backward : find the last corresponding defined label */
                if (sym && sym->r == 0)
                    sym = sym->prev_tok;
                if (!sym)
                    tcc_error("local label '%d' not found backward", n);
            } else {
                /* forward */
                if (!sym || sym->r) {
                    /* if the last label is defined, then define a new one */
                    sym = label_push(&s1->asm_labels, label, 0);
                    sym->type.t = VT_STATIC | VT_VOID;
                }
            }
            pe->v = 0;
            pe->sym = sym;
        } else if (*p == '\0') {
            pe->v = n;
            pe->sym = NULL;
        } else {
            tcc_error("invalid number syntax");
        }
        next();
        break;
    case '+':
        next();
        asm_expr_unary(s1, pe);
        break;
    case '-':
    case '~':
        op = tok;
        next();
        asm_expr_unary(s1, pe);
        if (pe->sym)
            tcc_error("invalid operation with label");
        if (op == '-')
            pe->v = -pe->v;
        else
            pe->v = ~pe->v;
        break;
    case TOK_CCHAR:
    case TOK_LCHAR:
	pe->v = tokc.i;
	pe->sym = NULL;
	next();
	break;
    case '(':
        next();
        asm_expr(s1, pe);
        skip(')');
        break;
    default:
        if (tok >= TOK_IDENT) {
            /* label case : if the label was not found, add one */
            sym = label_find(tok);
            if (!sym) {
                sym = label_push(&s1->asm_labels, tok, 0);
                /* NOTE: by default, the symbol is global */
                sym->type.t = VT_VOID;
            }
            if (sym->r == SHN_ABS) {
                /* if absolute symbol, no need to put a symbol value */
                pe->v = sym->jnext;
                pe->sym = NULL;
            } else {
                pe->v = 0;
                pe->sym = sym;
            }
            next();
        } else {
            tcc_error("bad expression syntax [%s]", get_tok_str(tok, &tokc));
        }
        break;
    }
}
Example #4
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");
}
Example #5
0
double float_eval(exp_tree_t *t, double val)
{
	int i;
	double result = 0.0;
	double (*fp)(double);
	int v;
	hashtab_t *function_dispatch_table = new_hashtab();
	struct fts {
		char *key;
		double (*val)(double);
	} function_table[] = {
		{ "arccos", &acos },
		{ "arcsin", &asin },
		{ "arctan", &atan },
		/* XXX: arccsc, arcsec, arccot */
		{ "cos", &cos},
		{ "cot", &my_cot },
		{ "csc", &my_csc },
		{ "ln", &log },
		/* n.b. this is by design; base-10 logarithms = shit */
		{ "log", &log },
		{ "sin", &sin },
		{ "sqrt", &sqrt },
		{ "tan", &tan },
		{ "sec", &my_sec },
		{ "D", &give_a_nan }
	};

	/*
 	 * Register functions
	 */
	for (i = 0; i < sizeof(function_table) / sizeof(struct fts); ++i) {
		hashtab_insert(function_dispatch_table, 
			       function_table[i].key,
			       (void *)function_table[i].val);
	}
	

	#define children_reduce_infix(operator) \
		for (i = 1, result = float_eval(t->child[0], val); i < t->child_count; ++i) \
			result = result operator float_eval(t->child[i], val);

	#define children_reduce_prefix(operator) \
		for (i = 1, result = float_eval(t->child[0], val); i < t->child_count; ++i) \
			result = operator ( result , float_eval(t->child[i], val) );

	switch (t->head_type) {
		case NEGATIVE: return -float_eval(t->child[0], val);
		case ADD: children_reduce_infix(+); break;
		case SUB: children_reduce_infix(-); break;
		case MULT: children_reduce_infix(*); break;
		case DIV: children_reduce_infix(/); break;

		case EXP: children_reduce_prefix(powf); break;

		case FUNC: {
			fp = hashtab_lookup(function_dispatch_table,
				            get_tok_str(*(t->tok)));
			if (!fp) {
				fprintf(stderr, "error: FLOATEVAL: uncoded function: %s\n", get_tok_str(*(t->tok)));
				exit(1);
			}
			result = fp(float_eval(t->child[0], val));
		}
		break;

		case VARIABLE: {
			if (!strcmp(get_tok_str(*(t->tok)), "e"))
				result = 2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466391932003059921817413596629043572900334295260595630738132328627943490763233829880753195251019011573834187930702154089149934884167509244761460668082264800168477411853742345442437107539077744992069551702761838606261331384583000752044933826560297606737113200709328709127443747047230696977209310141692836819025515108657463772111252389784425056953696770785449969967946864454905987931636889230098793127736178215424999229576351482208269895193668033182528869398496465105820939239829488793320362509443117301238197068416140397019837679320683282376464804295311802328782509819455815301756717361332069811250996181881593041690351598888519345807273866738589422879228499892086805825749279610484198444363463244968487560233624827041978623209002160990235304369941849146314093431738143640546253152096183690888707016768396424378140592714563549061303107208510383750510115747704171898610687396965521267154688957035035;
			else
				/* 
				 * Provided value + some variation based
				 * on the first letter of the variable
				 */
				result = val + (float)(1.0 * (*get_tok_str(*(t->tok)) % 5));
		}
		break;

		case NUMBER: {
			sscanf(get_tok_str(*(t->tok)), "%d", &v);
			result = (double)v;
		}
		break;
	}

	return result;
}