/* * TCC - Tiny C Compiler * * Copyright (c) 2001-2004 Fabrice Bellard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define USING_GLOBALS#include "tcc.h" /********************************************************//* global variables */ /* loc : local variable index ind : output code index rsym: return symbol anon_sym: anonymous symbol index*/ST_DATA int rsym, anon_sym, ind, loc; ST_DATA Sym *global_stack;ST_DATA Sym *local_stack;ST_DATA Sym *define_stack;ST_DATA Sym *global_label_stack;ST_DATA Sym *local_label_stack; static Sym *sym_free_first;static void **sym_pools;static int nb_sym_pools; static Sym *all_cleanups, *pending_gotos;static int local_scope;ST_DATA char debug_modes; ST_DATA SValue *vtop;static SValue _vstack[1 + VSTACK_SIZE];#define vstack (_vstack + 1) ST_DATA int nocode_wanted; /* no code generation wanted */#define NODATA_WANTED (nocode_wanted > 0) /* no static data output wanted either */#define DATA_ONLY_WANTED 0x80000000 /* ON outside of functions and for static initializers */ /* no code output after unconditional jumps such as with if (0) ... */#define CODE_OFF_BIT 0x20000000#define CODE_OFF() if(!nocode_wanted)(nocode_wanted |= CODE_OFF_BIT)#define CODE_ON() (nocode_wanted &= ~CODE_OFF_BIT) /* no code output when parsing sizeof()/typeof() etc. (using nocode_wanted++/--) */#define NOEVAL_MASK 0x0000FFFF#define NOEVAL_WANTED (nocode_wanted & NOEVAL_MASK) /* no code output when parsing constant expressions */#define CONST_WANTED_BIT 0x00010000#define CONST_WANTED_MASK 0x0FFF0000#define CONST_WANTED (nocode_wanted & CONST_WANTED_MASK) ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */ST_DATA CType func_vt; /* current function return type (used by return instruction) */ST_DATA int func_var; /* true if current function is variadic (used by return instruction) */ST_DATA int func_vc; /* stack address for implicit struct return storage */ST_DATA int func_ind; /* function start address */static int func_old;ST_DATA const char *funcname;ST_DATA CType int_type, func_old_type, char_type, char_pointer_type;static CString initstr; #if PTR_SIZE == 4#define VT_SIZE_T (VT_INT | VT_UNSIGNED)#define VT_PTRDIFF_T VT_INT#elif LONG_SIZE == 4#define VT_SIZE_T (VT_LLONG | VT_UNSIGNED)#define VT_PTRDIFF_T VT_LLONG#else#define VT_SIZE_T (VT_LONG | VT_LLONG | VT_UNSIGNED)#define VT_PTRDIFF_T (VT_LONG | VT_LLONG)#endif static struct switch_t { struct case_t { int64_t v1, v2; int ind, line; } **p; int n; /* list of case ranges */ int def_sym; /* default symbol */ int nocode_wanted; int *bsym; struct scope *scope; struct switch_t *prev; SValue sv;} *cur_switch; /* current switch */ #define MAX_TEMP_LOCAL_VARIABLE_NUMBER 8/*list of temporary local variables on the stack in current function. */static struct temp_local_variable { int location; //offset on stack. Svalue.c.i short size; short align;} arr_temp_local_vars[MAX_TEMP_LOCAL_VARIABLE_NUMBER];static int nb_temp_local_vars; static struct scope { struct scope *prev; struct { int loc, locorig, num; } vla; struct { Sym *s; int n; } cl; int *bsym, *csym; Sym *lstk, *llstk;} *cur_scope, *loop_scope, *root_scope; typedef struct { Section *sec; int local_offset; Sym *flex_array_ref;} init_params; #if 1#define precedence_parserstatic void init_prec(void);#endif static void block(int flags);#define STMT_EXPR 1#define STMT_COMPOUND 2 static void gen_cast(CType *type);static void gen_cast_s(int t);static inline CType *pointed_type(CType *type);static int is_compatible_types(CType *type1, CType *type2);static int parse_btype(CType *type, AttributeDef *ad, int ignore_label);static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td);static void parse_expr_type(CType *type);static void init_putv(init_params *p, CType *type, unsigned long c);static void decl_initializer(init_params *p, CType *type, unsigned long c, int flags);static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope);static int decl(int l);static void expr_eq(void);static void vpush_type_size(CType *type, int *a);static int is_compatible_unqualified_types(CType *type1, CType *type2);static inline int64_t expr_const64(void);static void vpush64(int ty, unsigned long long v);static void vpush(CType *type);static int gvtst(int inv, int t);static void gen_inline_functions(TCCState *s);static void free_inline_functions(TCCState *s);static void skip_or_save_block(TokenString **str);static void gv_dup(void);static int get_temp_local_var(int size,int align,int *r2);static void cast_error(CType *st, CType *dt);static void end_switch(void);static void do_Static_assert(void); /* ------------------------------------------------------------------------- *//* Automagical code suppression */ /* Clear 'nocode_wanted' at forward label if it was used */ST_FUNC void gsym(int t){ if (t) { gsym_addr(t, ind); CODE_ON(); }} /* Clear 'nocode_wanted' if current pc is a label */static int gind(){ int t = ind; CODE_ON(); if (debug_modes) tcc_tcov_block_begin(tcc_state); return t;} /* Set 'nocode_wanted' after unconditional (backwards) jump */static void gjmp_addr_acs(int t){ gjmp_addr(t); CODE_OFF();} /* Set 'nocode_wanted' after unconditional (forwards) jump */static int gjmp_acs(int t){ t = gjmp(t); CODE_OFF(); return t;} /* These are #undef'd at the end of this file */#define gjmp_addr gjmp_addr_acs#define gjmp gjmp_acs/* ------------------------------------------------------------------------- */ ST_INLN int is_float(int t){ int bt = t & VT_BTYPE; return bt == VT_LDOUBLE || bt == VT_DOUBLE || bt == VT_FLOAT || bt == VT_QFLOAT;} static inline int is_integer_btype(int bt){ return bt == VT_BYTE || bt == VT_BOOL || bt == VT_SHORT || bt == VT_INT || bt == VT_LLONG;} static int btype_size(int bt){ return bt == VT_BYTE || bt == VT_BOOL ? 1 : bt == VT_SHORT ? 2 : bt == VT_INT ? 4 : bt == VT_LLONG ? 8 : bt == VT_PTR ? PTR_SIZE : 0;} /* returns function return register from type */static int R_RET(int t){ if (!is_float(t)) return REG_IRET;#ifdef TCC_TARGET_X86_64 if ((t & VT_BTYPE) == VT_LDOUBLE) return TREG_ST0;#elif defined TCC_TARGET_RISCV64 if ((t & VT_BTYPE) == VT_LDOUBLE) return REG_IRET;#endif return REG_FRET;} /* returns 2nd function return register, if any */static int R2_RET(int t){ t &= VT_BTYPE;#if PTR_SIZE == 4 if (t == VT_LLONG) return REG_IRE2;#elif defined TCC_TARGET_X86_64 if (t == VT_QLONG) return REG_IRE2; if (t == VT_QFLOAT) return REG_FRE2;#elif defined TCC_TARGET_RISCV64 if (t == VT_LDOUBLE) return REG_IRE2;#endif return VT_CONST;} /* returns true for two-word types */#define USING_TWO_WORDS(t) (R2_RET(t) != VT_CONST) /* put function return registers to stack value */static void PUT_R_RET(SValue *sv, int t){ sv->r = R_RET(t), sv->r2 = R2_RET(t);} /* returns function return register class for type t */static int RC_RET(int t){ return reg_classes[R_RET(t)] & ~(RC_FLOAT | RC_INT);} /* returns generic register class for type t */static int RC_TYPE(int t){ if (!is_float(t)) return RC_INT;#ifdef TCC_TARGET_X86_64 if ((t & VT_BTYPE) == VT_LDOUBLE) return RC_ST0; if ((t & VT_BTYPE) == VT_QFLOAT) return RC_FRET;#elif defined TCC_TARGET_RISCV64 if ((t & VT_BTYPE) == VT_LDOUBLE) return RC_INT;#endif return RC_FLOAT;} /* returns 2nd register class corresponding to t and rc */static int RC2_TYPE(int t, int rc){ if (!USING_TWO_WORDS(t)) return 0;#ifdef RC_IRE2 if (rc == RC_IRET) return RC_IRE2;#endif#ifdef RC_FRE2 if (rc == RC_FRET) return RC_FRE2;#endif if (rc & RC_FLOAT) return RC_FLOAT; return RC_INT;} /* we use our own 'finite' function to avoid potential problems with non standard math libs *//* XXX: endianness dependent */ST_FUNC int ieee_finite(double d){ int p[4]; memcpy(p, &d, sizeof(double)); return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31;} ST_FUNC void test_lvalue(void){ if (!(vtop->r & VT_LVAL)) expect("lvalue");} ST_FUNC void check_vstack(void){ if (vtop != vstack - 1) tcc_error("internal compiler error: vstack leak (%d)", (int)(vtop - vstack + 1));} #if 0/* dump 'b' vstack entries starting with 'a' */void pv (const char *lbl, int a, int b){ int i; for (i = a; i < a + b; ++i) { SValue *p = &vtop[-i]; printf("%s vtop[-%d] : type.t:%04x r:%04x r2:%04x c.i:%d\n", lbl, i, p->type.t, p->r, p->r2, (int)p->c.i); }} /* dump symbols on stack from s ... last */static inline void psyms(const char *msg, Sym *s, Sym *last){ printf("%-8s scope v c r type.t\n", msg); while (s && s != last) { printf(" %8x %08x %08x %08x %08x %s\n", s->sym_scope, s->v, s->c, s->r, s->type.t, get_tok_str(s->v, 0)); s = s->prev; }} static void type_to_str(char *buf, int buf_size, CType *type, const char *varstr); /* print type */static void ptype(const char *msg, CType *type, int v){ char buf[500]; type_to_str(buf, sizeof(buf), type, (v & ~SYM_FIELD) ? get_tok_str(v, NULL) : NULL); printf("%s : %s;\n", msg, buf);}#endif /* ------------------------------------------------------------------------- *//* initialize vstack and types. This must be done also for tcc -E */ST_FUNC void tccgen_init(TCCState *s1){ vtop = vstack - 1; memset(vtop, 0, sizeof *vtop); /* define some often used types */ int_type.t = VT_INT; char_type.t = VT_BYTE; if (s1->char_is_unsigned) char_type.t |= VT_UNSIGNED; char_pointer_type = char_type; mk_pointer(&char_pointer_type); func_old_type.t = VT_FUNC; func_old_type.ref = sym_push(SYM_FIELD, &int_type, 0, 0); func_old_type.ref->f.func_call = FUNC_CDECL; func_old_type.ref->f.func_type = FUNC_OLD;#ifdef precedence_parser init_prec();#endif cstr_new(&initstr);} ST_FUNC int tccgen_compile(TCCState *s1){ funcname = ""; func_ind = -1; anon_sym = SYM_FIRST_ANOM; nocode_wanted = DATA_ONLY_WANTED; /* no code outside of functions */ debug_modes = (s1->do_debug ? 1 : 0) | s1->test_coverage << 1; global_expr = 0; tcc_debug_start(s1); tcc_tcov_start (s1);#ifdef TCC_TARGET_ARM arm_init(s1);#endif#ifdef INC_DEBUG printf("%s: **** new file\n", file->filename);#endif parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | PARSE_FLAG_TOK_STR; next(); decl(VT_CONST); gen_inline_functions(s1); check_vstack(); /* end of translation unit info */#if TCC_EH_FRAME tcc_eh_frame_end(s1);#endif tcc_debug_end(s1); tcc_tcov_end(s1); return 0;} ST_FUNC void tccgen_finish(TCCState *s1){ tcc_debug_end(s1); /* just in case of errors: free memory */ free_inline_functions(s1); sym_pop(&global_stack, NULL, 0); sym_pop(&local_stack, NULL, 0); /* free preprocessor macros */ free_defines(NULL); /* free sym_pools */ dynarray_reset(&sym_pools, &nb_sym_pools); cstr_free(&initstr); dynarray_reset(&stk_data, &nb_stk_data); while (cur_switch) end_switch(); local_scope = 0; loop_scope = NULL; all_cleanups = NULL; pending_gotos = NULL; nb_temp_local_vars = 0; global_label_stack = NULL; local_label_stack = NULL; cur_text_section = NULL; sym_free_first = NULL;} /* ------------------------------------------------------------------------- */ST_FUNC ElfSym *elfsym(Sym *s){ if (!s || !s->c) return NULL; return &((ElfSym *)symtab_section->data)[s->c];} /* apply storage attributes to Elf symbol */ST_FUNC void update_storage(Sym *sym){ ElfSym *esym; int sym_bind, old_sym_bind; esym = elfsym(sym); if (!esym) return; if (sym->a.visibility) esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) | sym->a.visibility; if (sym->type.t & (VT_STATIC | VT_INLINE)) sym_bind = STB_LOCAL; else if (sym->a.weak) sym_bind = STB_WEAK; else sym_bind = STB_GLOBAL; old_sym_bind = ELFW(ST_BIND)(esym->st_info); if (sym_bind != old_sym_bind) { esym->st_info = ELFW(ST_INFO)(sym_bind, ELFW(ST_TYPE)(esym->st_info)); } #ifdef TCC_TARGET_PE if (sym->a.dllimport) esym->st_other |= ST_PE_IMPORT; if (sym->a.dllexport) esym->st_other |= ST_PE_EXPORT;#endif #if 0 printf("storage %s: bind=%c vis=%d exp=%d imp=%d\n", get_tok_str(sym->v, NULL), sym_bind == STB_WEAK ? 'w' : sym_bind == STB_LOCAL ? 'l' : 'g', sym->a.visibility,Lines 1–500 of 9001. Load more
/* * TCC - Tiny C Compiler * * Copyright (c) 2001-2004 Fabrice Bellard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define USING_GLOBALS #include "tcc.h" /********************************************************/ /* global variables */ /* loc : local variable index ind : output code index rsym: return symbol anon_sym: anonymous symbol index */ ST_DATA int rsym, anon_sym, ind, loc; ST_DATA Sym *global_stack; ST_DATA Sym *local_stack; ST_DATA Sym *define_stack; ST_DATA Sym *global_label_stack; ST_DATA Sym *local_label_stack; static Sym *sym_free_first; static void **sym_pools; static int nb_sym_pools; static Sym *all_cleanups, *pending_gotos; static int local_scope; ST_DATA char debug_modes; ST_DATA SValue *vtop; static SValue _vstack[1 + VSTACK_SIZE]; #define vstack (_vstack + 1) ST_DATA int nocode_wanted; /* no code generation wanted */ #define NODATA_WANTED (nocode_wanted > 0) /* no static data output wanted either */ #define DATA_ONLY_WANTED 0x80000000 /* ON outside of functions and for static initializers */ /* no code output after unconditional jumps such as with if (0) ... */ #define CODE_OFF_BIT 0x20000000 #define CODE_OFF() if(!nocode_wanted)(nocode_wanted |= CODE_OFF_BIT) #define CODE_ON() (nocode_wanted &= ~CODE_OFF_BIT) /* no code output when parsing sizeof()/typeof() etc. (using nocode_wanted++/--) */ #define NOEVAL_MASK 0x0000FFFF #define NOEVAL_WANTED (nocode_wanted & NOEVAL_MASK) /* no code output when parsing constant expressions */ #define CONST_WANTED_BIT 0x00010000 #define CONST_WANTED_MASK 0x0FFF0000 #define CONST_WANTED (nocode_wanted & CONST_WANTED_MASK) ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */ ST_DATA CType func_vt; /* current function return type (used by return instruction) */ ST_DATA int func_var; /* true if current function is variadic (used by return instruction) */ ST_DATA int func_vc; /* stack address for implicit struct return storage */ ST_DATA int func_ind; /* function start address */ static int func_old; ST_DATA const char *funcname; ST_DATA CType int_type, func_old_type, char_type, char_pointer_type; static CString initstr; #if PTR_SIZE == 4 #define VT_SIZE_T (VT_INT | VT_UNSIGNED) #define VT_PTRDIFF_T VT_INT #elif LONG_SIZE == 4 #define VT_SIZE_T (VT_LLONG | VT_UNSIGNED) #define VT_PTRDIFF_T VT_LLONG #else #define VT_SIZE_T (VT_LONG | VT_LLONG | VT_UNSIGNED) #define VT_PTRDIFF_T (VT_LONG | VT_LLONG) #endif static struct switch_t { struct case_t { int64_t v1, v2; int ind, line; } **p; int n; /* list of case ranges */ int def_sym; /* default symbol */ int nocode_wanted; int *bsym; struct scope *scope; struct switch_t *prev; SValue sv; } *cur_switch; /* current switch */ #define MAX_TEMP_LOCAL_VARIABLE_NUMBER 8 /*list of temporary local variables on the stack in current function. */ static struct temp_local_variable { int location; //offset on stack. Svalue.c.i short size; short align; } arr_temp_local_vars[MAX_TEMP_LOCAL_VARIABLE_NUMBER]; static int nb_temp_local_vars; static struct scope { struct scope *prev; struct { int loc, locorig, num; } vla; struct { Sym *s; int n; } cl; int *bsym, *csym; Sym *lstk, *llstk; } *cur_scope, *loop_scope, *root_scope; typedef struct { Section *sec; int local_offset; Sym *flex_array_ref; } init_params; #if 1 #define precedence_parser static void init_prec(void); #endif static void block(int flags); #define STMT_EXPR 1 #define STMT_COMPOUND 2 static void gen_cast(CType *type); static void gen_cast_s(int t); static inline CType *pointed_type(CType *type); static int is_compatible_types(CType *type1, CType *type2); static int parse_btype(CType *type, AttributeDef *ad, int ignore_label); static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td); static void parse_expr_type(CType *type); static void init_putv(init_params *p, CType *type, unsigned long c); static void decl_initializer(init_params *p, CType *type, unsigned long c, int flags); static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope); static int decl(int l); static void expr_eq(void); static void vpush_type_size(CType *type, int *a); static int is_compatible_unqualified_types(CType *type1, CType *type2); static inline int64_t expr_const64(void); static void vpush64(int ty, unsigned long long v); static void vpush(CType *type); static int gvtst(int inv, int t); static void gen_inline_functions(TCCState *s); static void free_inline_functions(TCCState *s); static void skip_or_save_block(TokenString **str); static void gv_dup(void); static int get_temp_local_var(int size,int align,int *r2); static void cast_error(CType *st, CType *dt); static void end_switch(void); static void do_Static_assert(void); /* ------------------------------------------------------------------------- */ /* Automagical code suppression */ /* Clear 'nocode_wanted' at forward label if it was used */ ST_FUNC void gsym(int t) { if (t) { gsym_addr(t, ind); CODE_ON(); } } /* Clear 'nocode_wanted' if current pc is a label */ static int gind() { int t = ind; CODE_ON(); if (debug_modes) tcc_tcov_block_begin(tcc_state); return t; } /* Set 'nocode_wanted' after unconditional (backwards) jump */ static void gjmp_addr_acs(int t) { gjmp_addr(t); CODE_OFF(); } /* Set 'nocode_wanted' after unconditional (forwards) jump */ static int gjmp_acs(int t) { t = gjmp(t); CODE_OFF(); return t; } /* These are #undef'd at the end of this file */ #define gjmp_addr gjmp_addr_acs #define gjmp gjmp_acs /* ------------------------------------------------------------------------- */ ST_INLN int is_float(int t) { int bt = t & VT_BTYPE; return bt == VT_LDOUBLE || bt == VT_DOUBLE || bt == VT_FLOAT || bt == VT_QFLOAT; } static inline int is_integer_btype(int bt) { return bt == VT_BYTE || bt == VT_BOOL || bt == VT_SHORT || bt == VT_INT || bt == VT_LLONG; } static int btype_size(int bt) { return bt == VT_BYTE || bt == VT_BOOL ? 1 : bt == VT_SHORT ? 2 : bt == VT_INT ? 4 : bt == VT_LLONG ? 8 : bt == VT_PTR ? PTR_SIZE : 0; } /* returns function return register from type */ static int R_RET(int t) { if (!is_float(t)) return REG_IRET; #ifdef TCC_TARGET_X86_64 if ((t & VT_BTYPE) == VT_LDOUBLE) return TREG_ST0; #elif defined TCC_TARGET_RISCV64 if ((t & VT_BTYPE) == VT_LDOUBLE) return REG_IRET; #endif return REG_FRET; } /* returns 2nd function return register, if any */ static int R2_RET(int t) { t &= VT_BTYPE; #if PTR_SIZE == 4 if (t == VT_LLONG) return REG_IRE2; #elif defined TCC_TARGET_X86_64 if (t == VT_QLONG) return REG_IRE2; if (t == VT_QFLOAT) return REG_FRE2; #elif defined TCC_TARGET_RISCV64 if (t == VT_LDOUBLE) return REG_IRE2; #endif return VT_CONST; } /* returns true for two-word types */ #define USING_TWO_WORDS(t) (R2_RET(t) != VT_CONST) /* put function return registers to stack value */ static void PUT_R_RET(SValue *sv, int t) { sv->r = R_RET(t), sv->r2 = R2_RET(t); } /* returns function return register class for type t */ static int RC_RET(int t) { return reg_classes[R_RET(t)] & ~(RC_FLOAT | RC_INT); } /* returns generic register class for type t */ static int RC_TYPE(int t) { if (!is_float(t)) return RC_INT; #ifdef TCC_TARGET_X86_64 if ((t & VT_BTYPE) == VT_LDOUBLE) return RC_ST0; if ((t & VT_BTYPE) == VT_QFLOAT) return RC_FRET; #elif defined TCC_TARGET_RISCV64 if ((t & VT_BTYPE) == VT_LDOUBLE) return RC_INT; #endif return RC_FLOAT; } /* returns 2nd register class corresponding to t and rc */ static int RC2_TYPE(int t, int rc) { if (!USING_TWO_WORDS(t)) return 0; #ifdef RC_IRE2 if (rc == RC_IRET) return RC_IRE2; #endif #ifdef RC_FRE2 if (rc == RC_FRET) return RC_FRE2; #endif if (rc & RC_FLOAT) return RC_FLOAT; return RC_INT; } /* we use our own 'finite' function to avoid potential problems with non standard math libs */ /* XXX: endianness dependent */ ST_FUNC int ieee_finite(double d) { int p[4]; memcpy(p, &d, sizeof(double)); return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31; } ST_FUNC void test_lvalue(void) { if (!(vtop->r & VT_LVAL)) expect("lvalue"); } ST_FUNC void check_vstack(void) { if (vtop != vstack - 1) tcc_error("internal compiler error: vstack leak (%d)", (int)(vtop - vstack + 1)); } #if 0 /* dump 'b' vstack entries starting with 'a' */ void pv (const char *lbl, int a, int b) { int i; for (i = a; i < a + b; ++i) { SValue *p = &vtop[-i]; printf("%s vtop[-%d] : type.t:%04x r:%04x r2:%04x c.i:%d\n", lbl, i, p->type.t, p->r, p->r2, (int)p->c.i); } } /* dump symbols on stack from s ... last */ static inline void psyms(const char *msg, Sym *s, Sym *last) { printf("%-8s scope v c r type.t\n", msg); while (s && s != last) { printf(" %8x %08x %08x %08x %08x %s\n", s->sym_scope, s->v, s->c, s->r, s->type.t, get_tok_str(s->v, 0)); s = s->prev; } } static void type_to_str(char *buf, int buf_size, CType *type, const char *varstr); /* print type */ static void ptype(const char *msg, CType *type, int v) { char buf[500]; type_to_str(buf, sizeof(buf), type, (v & ~SYM_FIELD) ? get_tok_str(v, NULL) : NULL); printf("%s : %s;\n", msg, buf); } #endif /* ------------------------------------------------------------------------- */ /* initialize vstack and types. This must be done also for tcc -E */ ST_FUNC void tccgen_init(TCCState *s1) { vtop = vstack - 1; memset(vtop, 0, sizeof *vtop); /* define some often used types */ int_type.t = VT_INT; char_type.t = VT_BYTE; if (s1->char_is_unsigned) char_type.t |= VT_UNSIGNED; char_pointer_type = char_type; mk_pointer(&char_pointer_type); func_old_type.t = VT_FUNC; func_old_type.ref = sym_push(SYM_FIELD, &int_type, 0, 0); func_old_type.ref->f.func_call = FUNC_CDECL; func_old_type.ref->f.func_type = FUNC_OLD; #ifdef precedence_parser init_prec(); #endif cstr_new(&initstr); } ST_FUNC int tccgen_compile(TCCState *s1) { funcname = ""; func_ind = -1; anon_sym = SYM_FIRST_ANOM; nocode_wanted = DATA_ONLY_WANTED; /* no code outside of functions */ debug_modes = (s1->do_debug ? 1 : 0) | s1->test_coverage << 1; global_expr = 0; tcc_debug_start(s1); tcc_tcov_start (s1); #ifdef TCC_TARGET_ARM arm_init(s1); #endif #ifdef INC_DEBUG printf("%s: **** new file\n", file->filename); #endif parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | PARSE_FLAG_TOK_STR; next(); decl(VT_CONST); gen_inline_functions(s1); check_vstack(); /* end of translation unit info */ #if TCC_EH_FRAME tcc_eh_frame_end(s1); #endif tcc_debug_end(s1); tcc_tcov_end(s1); return 0; } ST_FUNC void tccgen_finish(TCCState *s1) { tcc_debug_end(s1); /* just in case of errors: free memory */ free_inline_functions(s1); sym_pop(&global_stack, NULL, 0); sym_pop(&local_stack, NULL, 0); /* free preprocessor macros */ free_defines(NULL); /* free sym_pools */ dynarray_reset(&sym_pools, &nb_sym_pools); cstr_free(&initstr); dynarray_reset(&stk_data, &nb_stk_data); while (cur_switch) end_switch(); local_scope = 0; loop_scope = NULL; all_cleanups = NULL; pending_gotos = NULL; nb_temp_local_vars = 0; global_label_stack = NULL; local_label_stack = NULL; cur_text_section = NULL; sym_free_first = NULL; } /* ------------------------------------------------------------------------- */ ST_FUNC ElfSym *elfsym(Sym *s) { if (!s || !s->c) return NULL; return &((ElfSym *)symtab_section->data)[s->c]; } /* apply storage attributes to Elf symbol */ ST_FUNC void update_storage(Sym *sym) { ElfSym *esym; int sym_bind, old_sym_bind; esym = elfsym(sym); if (!esym) return; if (sym->a.visibility) esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) | sym->a.visibility; if (sym->type.t & (VT_STATIC | VT_INLINE)) sym_bind = STB_LOCAL; else if (sym->a.weak) sym_bind = STB_WEAK; else sym_bind = STB_GLOBAL; old_sym_bind = ELFW(ST_BIND)(esym->st_info); if (sym_bind != old_sym_bind) { esym->st_info = ELFW(ST_INFO)(sym_bind, ELFW(ST_TYPE)(esym->st_info)); } #ifdef TCC_TARGET_PE if (sym->a.dllimport) esym->st_other |= ST_PE_IMPORT; if (sym->a.dllexport) esym->st_other |= ST_PE_EXPORT; #endif #if 0 printf("storage %s: bind=%c vis=%d exp=%d imp=%d\n", get_tok_str(sym->v, NULL), sym_bind == STB_WEAK ? 'w' : sym_bind == STB_LOCAL ? 'l' : 'g', sym->a.visibility,