📄 tcc.c
字号:
/* * TCC - Tiny C Compiler * * Copyright (c) 2001, 2002, 2003 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 _GNU_SOURCE#include "config.h"#include <stdlib.h>#include <stdio.h>#include <stdarg.h>#include <string.h>#include <errno.h>#include <math.h>#include <unistd.h>#include <signal.h>#include <unistd.h>#include <fcntl.h>#include <setjmp.h>#include <time.h>#ifdef WIN32#include <sys/timeb.h>#endif#ifndef WIN32#include <sys/time.h>#include <sys/ucontext.h>#endif#include "elf.h"#include "stab.h"#ifndef CONFIG_TCC_STATIC#include <dlfcn.h>#endif#include "libtcc.h"/* parser debug *///#define PARSE_DEBUG/* preprocessor debug *///#define PP_DEBUG/* include file debug *///#define INC_DEBUG//#define MEM_DEBUG/* assembler debug *///#define ASM_DEBUG/* target selection *///#define TCC_TARGET_I386 /* i386 code generator *//* default target is I386 */#if !defined(TCC_TARGET_I386)#define TCC_TARGET_I386#endif#if !defined(WIN32) && !defined(TCC_UCLIBC)#define CONFIG_TCC_BCHECK /* enable bound checking code */#endif/* define it to include assembler support */#define CONFIG_TCC_ASM/* path to find crt1.o, crti.o and crtn.o. Only needed when generating executables or dlls */#define CONFIG_TCC_CRT_PREFIX "/usr/lib"#define INCLUDE_STACK_SIZE 32#define IFDEF_STACK_SIZE 64#define VSTACK_SIZE 64#define STRING_MAX_SIZE 1024#define TOK_HASH_SIZE 2048 /* must be a power of two */#define TOK_ALLOC_INCR 512 /* must be a power of two */#define TOK_STR_ALLOC_INCR_BITS 6#define TOK_STR_ALLOC_INCR (1 << TOK_STR_ALLOC_INCR_BITS)#define TOK_MAX_SIZE 4 /* token max size in int unit when stored in string *//* token symbol management */typedef struct TokenSym { struct TokenSym *hash_next; struct Sym *sym_define; /* direct pointer to define */ struct Sym *sym_label; /* direct pointer to label */ struct Sym *sym_struct; /* direct pointer to structure */ struct Sym *sym_identifier; /* direct pointer to identifier */ int tok; /* token number */ int len; char str[1];} TokenSym;typedef struct CString { int size; /* size in bytes */ void *data; /* either 'char *' or 'int *' */ int size_allocated; void *data_allocated; /* if non NULL, data has been malloced */} CString;/* type definition */typedef struct CType { int t; struct Sym *ref;} CType;/* constant value */typedef union CValue { long double ld; double d; float f; int i; unsigned int ui; unsigned int ul; /* address (should be unsigned long on 64 bit cpu) */ long long ll; unsigned long long ull; struct CString *cstr; void *ptr; int tab[1];} CValue;/* value on stack */typedef struct SValue { CType type; /* type */ unsigned short r; /* register + flags */ unsigned short r2; /* second register, used for 'long long' type. If not used, set to VT_CONST */ CValue c; /* constant, if VT_CONST */ struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST) */} SValue;/* symbol management */typedef struct Sym { int v; /* symbol token */ int r; /* associated register */ int c; /* associated number */ CType type; /* associated type */ struct Sym *next; /* next related symbol */ struct Sym *prev; /* prev symbol in stack */ struct Sym *prev_tok; /* previous symbol for this token */} Sym;/* section definition *//* XXX: use directly ELF structure for parameters ? *//* special flag to indicate that the section should not be linked to the other ones */#define SHF_PRIVATE 0x80000000typedef struct Section { unsigned long data_offset; /* current data offset */ unsigned char *data; /* section data */ unsigned long data_allocated; /* used for realloc() handling */ int sh_name; /* elf section name (only used during output) */ int sh_num; /* elf section number */ int sh_type; /* elf section type */ int sh_flags; /* elf section flags */ int sh_info; /* elf section info */ int sh_addralign; /* elf section alignment */ int sh_entsize; /* elf entry size */ unsigned long sh_size; /* section size (only used during output) */ unsigned long sh_addr; /* address at which the section is relocated */ unsigned long sh_offset; /* address at which the section is relocated */ int nb_hashed_syms; /* used to resize the hash table */ struct Section *link; /* link to another section */ struct Section *reloc; /* corresponding section for relocation, if any */ struct Section *hash; /* hash table for symbols */ struct Section *next; char name[1]; /* section name */} Section;typedef struct DLLReference { int level; char name[1];} DLLReference;/* GNUC attribute definition */typedef struct AttributeDef { int aligned; Section *section; unsigned char func_call; /* FUNC_CDECL or FUNC_STDCALL */} AttributeDef;#define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */#define SYM_FIELD 0x20000000 /* struct/union field symbol space */#define SYM_FIRST_ANOM (1 << (31 - VT_STRUCT_SHIFT)) /* first anonymous sym *//* stored in 'Sym.c' field */#define FUNC_NEW 1 /* ansi function prototype */#define FUNC_OLD 2 /* old function prototype */#define FUNC_ELLIPSIS 3 /* ansi function prototype with ... *//* stored in 'Sym.r' field */#define FUNC_CDECL 0 /* standard c call */#define FUNC_STDCALL 1 /* pascal c call *//* field 'Sym.t' for macros */#define MACRO_OBJ 0 /* object like macro */#define MACRO_FUNC 1 /* function like macro *//* field 'Sym.r' for C labels */#define LABEL_DEFINED 0 /* label is defined */#define LABEL_FORWARD 1 /* label is forward defined */#define LABEL_DECLARED 2 /* label is declared but never used *//* type_decl() types */#define TYPE_ABSTRACT 1 /* type without variable */#define TYPE_DIRECT 2 /* type with variable */#define IO_BUF_SIZE 8192typedef struct BufferedFile { uint8_t *buf_ptr; uint8_t *buf_end; int fd; int line_num; /* current line number - here to simplify code */ int ifndef_macro; /* #ifndef macro / #endif search */ int ifndef_macro_saved; /* saved ifndef_macro */ int *ifdef_stack_ptr; /* ifdef_stack value at the start of the file */ char inc_type; /* type of include */ char inc_filename[512]; /* filename specified by the user */ char filename[1024]; /* current filename - here to simplify code */ unsigned char buffer[IO_BUF_SIZE + 1]; /* extra size for CH_EOB char */} BufferedFile;#define CH_EOB '\\' /* end of buffer or '\0' char in file */#define CH_EOF (-1) /* end of file *//* parsing state (used to save parser state to reparse part of the source several times) */typedef struct ParseState { int *macro_ptr; int line_num; int tok; CValue tokc;} ParseState;/* used to record tokens */typedef struct TokenString { int *str; int len; int allocated_len; int last_line_num;} TokenString;/* include file cache, used to find files faster and also to eliminate inclusion if the include file is protected by #ifndef ... #endif */typedef struct CachedInclude { int ifndef_macro; char type; /* '"' or '>' to give include type */ char filename[1]; /* path specified in #include */} CachedInclude;/* parser */static struct BufferedFile *file;static int ch, tok;static CValue tokc;static CString tokcstr; /* current parsed string, if any *//* additional informations about token */static int tok_flags;#define TOK_FLAG_BOL 0x0001 /* beginning of line before */#define TOK_FLAG_BOF 0x0002 /* beginning of file before */#define TOK_FLAG_ENDIF 0x0004 /* a endif was found matching starting #ifdef */static int *macro_ptr, *macro_ptr_allocated;static int *unget_saved_macro_ptr;static int unget_saved_buffer[TOK_MAX_SIZE + 1];static int unget_buffer_enabled;static int parse_flags;#define PARSE_FLAG_PREPROCESS 0x0001 /* activate preprocessing */#define PARSE_FLAG_TOK_NUM 0x0002 /* return numbers instead of TOK_PPNUM */#define PARSE_FLAG_LINEFEED 0x0004 /* line feed is returned as a token. line feed is also returned at eof */ static Section *text_section, *data_section, *bss_section; /* predefined sections */static Section *cur_text_section; /* current section where function code is generated *//* bound check related sections */static Section *bounds_section; /* contains global data bound description */static Section *lbounds_section; /* contains local data bound description *//* symbol sections */static Section *symtab_section, *strtab_section;/* debug sections */static Section *stab_section, *stabstr_section;/* loc : local variable index ind : output code index rsym: return symbol anon_sym: anonymous symbol index*/static int rsym, anon_sym, ind, loc;/* expression generation modifiers */static int const_wanted; /* true if constant wanted */static int nocode_wanted; /* true if no code generation wanted for an expression */static int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */static CType func_vt; /* current function return type (used by return instruction) */static int func_vc;static int last_line_num, last_ind, func_ind; /* debug last line number and pc */static int tok_ident;static TokenSym **table_ident;static TokenSym *hash_ident[TOK_HASH_SIZE];static char token_buf[STRING_MAX_SIZE + 1];static char *funcname;static Sym *global_stack, *local_stack;static Sym *define_stack;static Sym *global_label_stack, *local_label_stack;static SValue vstack[VSTACK_SIZE], *vtop;/* some predefined types */static CType char_pointer_type, func_old_type, int_type;/* true if isid(c) || isnum(c) */static unsigned char isidnum_table[256];/* compile with debug symbol (and use them if error during execution) */static int do_debug = 0;/* compile with built-in memory and bounds checker */static int do_bounds_check = 0;/* display benchmark infos */#if !defined(LIBTCC)static int do_bench = 0;#endifstatic int total_lines;static int total_bytes;/* use GNU C extensions */static int gnu_ext = 1;/* use Tiny C extensions */static int tcc_ext = 1;/* max number of callers shown if error */static int num_callers = 6;static const char **rt_bound_error_msg;/* XXX: get rid of this ASAP */static struct TCCState *tcc_state;/* give the path of the tcc libraries */static const char *tcc_lib_path = CONFIG_TCC_LIBDIR "/tcc";struct TCCState { int output_type; BufferedFile **include_stack_ptr; int *ifdef_stack_ptr; /* include file handling */ char **include_paths; int nb_include_paths; char **sysinclude_paths; int nb_sysinclude_paths; CachedInclude **cached_includes; int nb_cached_includes; char **library_paths; int nb_library_paths; /* array of all loaded dlls (including those referenced by loaded dlls) */ DLLReference **loaded_dlls; int nb_loaded_dlls; /* sections */ Section **sections; int nb_sections; /* number of sections, including first dummy section */ /* got handling */ Section *got; Section *plt; unsigned long *got_offsets; int nb_got_offsets; /* give the correspondance from symtab indexes to dynsym indexes */ int *symtab_to_dynsym; /* temporary dynamic symbol sections (for dll loading) */ Section *dynsymtab_section; /* exported dynamic symbol section */ Section *dynsym; int nostdinc; /* if true, no standard headers are added */ int nostdlib; /* if true, no standard libraries are added */ /* if true, static linking is performed */ int static_link; /* if true, all symbols are exported */ int rdynamic; /* if true, only link in referenced objects from archive */ int alacarte_link; /* warning switches */ int warn_write_strings; int warn_unsupported; int warn_error; int warn_none; /* error handling */ void *error_opaque; void (*error_func)(void *opaque, const char *msg); int error_set_jmp_enabled; jmp_buf error_jmp_buf; int nb_errors; /* tiny assembler state */ Sym *asm_labels; /* see include_stack_ptr */ BufferedFile *include_stack[INCLUDE_STACK_SIZE]; /* see ifdef_stack_ptr */ int ifdef_stack[IFDEF_STACK_SIZE];};/* The current value can be: */#define VT_VALMASK 0x00ff#define VT_CONST 0x00f0 /* constant in vc (must be first non register value) */#define VT_LLOCAL 0x00f1 /* lvalue, offset on stack */#define VT_LOCAL 0x00f2 /* offset on stack */#define VT_CMP 0x00f3 /* the value is stored in processor flags (in vc) */#define VT_JMP 0x00f4 /* value is the consequence of jmp true (even) */#define VT_JMPI 0x00f5 /* value is the consequence of jmp false (odd) */#define VT_LVAL 0x0100 /* var is an lvalue */#define VT_SYM 0x0200 /* a symbol value is added */#define VT_MUSTCAST 0x0400 /* value must be casted to be correct (used for char/short stored in integer registers) */#define VT_MUSTBOUND 0x0800 /* bound checking must be done before dereferencing value */#define VT_BOUNDED 0x8000 /* value is bounded. The address of the bounding function call point is in vc */#define VT_LVAL_BYTE 0x1000 /* lvalue is a byte */#define VT_LVAL_SHORT 0x2000 /* lvalue is a short */#define VT_LVAL_UNSIGNED 0x4000 /* lvalue is unsigned */#define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED)/* types */#define VT_INT 0 /* integer type */#define VT_BYTE 1 /* signed byte type */#define VT_SHORT 2 /* short type */#define VT_VOID 3 /* void type */#define VT_PTR 4 /* pointer */#define VT_ENUM 5 /* enum definition */#define VT_FUNC 6 /* function type */#define VT_STRUCT 7 /* struct/union definition */#define VT_FLOAT 8 /* IEEE float */#define VT_DOUBLE 9 /* IEEE double */#define VT_LDOUBLE 10 /* IEEE long double */#define VT_BOOL 11 /* ISOC99 boolean type */#define VT_LLONG 12 /* 64 bit integer */#define VT_LONG 13 /* long integer (NEVER USED as type, only during parsing) */#define VT_BTYPE 0x000f /* mask for basic type */#define VT_UNSIGNED 0x0010 /* unsigned type */#define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */#define VT_BITFIELD 0x0040 /* bitfield modifier */#define VT_CONSTANT 0x0800 /* const modifier */#define VT_VOLATILE 0x1000 /* volatile modifier *//* storage */#define VT_EXTERN 0x00000080 /* extern definition */#define VT_STATIC 0x00000100 /* static variable */#define VT_TYPEDEF 0x00000200 /* typedef definition */#define VT_INLINE 0x00000400 /* inline definition */#define VT_STRUCT_SHIFT 16 /* shift for bitfield shift values *//* type mask (except storage) */#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -