1821 lines · 60.7 KB · C
RawDownload
/* *  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 */ #ifndef _TCC_H#define _TCC_H #define _GNU_SOURCE#define _DARWIN_C_SOURCE#include "config.h" #include <stdarg.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <errno.h>#include <math.h>#include <fcntl.h>#include <setjmp.h>#include <time.h> #ifndef _WIN32# define WIN32_LEAN_AND_MEAN 1# include <unistd.h># include <sys/time.h># ifndef CONFIG_TCC_STATIC#  include <dlfcn.h># endif/* XXX: need to define this to use them in non ISOC99 context */extern float strtof (const char *__nptr, char **__endptr);extern long double strtold (const char *__nptr, char **__endptr);#endif #ifdef _WIN32# define WIN32_LEAN_AND_MEAN# include <windows.h># include <io.h> /* open, close etc. */# include <direct.h> /* getcwd */# ifdef __GNUC__#  include <stdint.h># endif# define inline __inline# define snprintf _snprintf# define vsnprintf _vsnprintf# ifndef __GNUC__#  define strtold (long double)strtod#  define strtof (float)strtod#  define strtoll _strtoi64#  define strtoull _strtoui64# endif# ifdef LIBTCC_AS_DLL#  define LIBTCCAPI __declspec(dllexport)#  define PUB_FUNC LIBTCCAPI# endif# define inp next_inp /* inp is an intrinsic on msvc/mingw */# ifdef _MSC_VER#  pragma warning (disable : 4244)  // conversion from 'uint64_t' to 'int', possible loss of data#  pragma warning (disable : 4267)  // conversion from 'size_t' to 'int', possible loss of data#  pragma warning (disable : 4996)  // The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name#  pragma warning (disable : 4018)  // signed/unsigned mismatch#  pragma warning (disable : 4146)  // unary minus operator applied to unsigned type, result still unsigned#  define ssize_t intptr_t#  ifdef _X86_#   define __i386__ 1#  endif#  ifdef _AMD64_#   define __x86_64__ 1#  endif# endif# undef CONFIG_TCC_STATIC#endif #ifndef O_BINARY# define O_BINARY 0#endif #ifndef offsetof#define offsetof(type, field) ((size_t) &((type *)0)->field)#endif #ifndef countof#define countof(tab) (sizeof(tab) / sizeof((tab)[0]))#endif #ifdef _MSC_VER# define NORETURN __declspec(noreturn)# define ALIGNED(x) __declspec(align(x))# define PRINTF_LIKE(x,y)#else# define NORETURN __attribute__((noreturn))# define ALIGNED(x) __attribute__((aligned(x)))# define PRINTF_LIKE(x,y) __attribute__ ((format (printf, (x), (y))))#endif /* gnu headers use to #define __attribute__ to empty for non-gcc compilers */#ifdef __TINYC__# undef __attribute__#endif #ifdef _WIN32# define IS_DIRSEP(c) (c == '/' || c == '\\')# define IS_ABSPATH(p) (IS_DIRSEP(p[0]) || (p[0] && p[1] == ':' && IS_DIRSEP(p[2])))# define PATHCMP stricmp# define PATHSEP ";"#else# define IS_DIRSEP(c) (c == '/')# define IS_ABSPATH(p) IS_DIRSEP(p[0])# define PATHCMP strcmp# define PATHSEP ":"#endif /* -------------------------------------------- */ /* parser debug *//* #define PARSE_DEBUG *//* preprocessor debug *//* #define PP_DEBUG *//* include file debug *//* #define INC_DEBUG *//* memory leak debug (only for single threaded usage) *//* #define MEM_DEBUG *//* assembler debug *//* #define ASM_DEBUG */ /* target selection *//* #define TCC_TARGET_I386   *//* i386 code generator *//* #define TCC_TARGET_X86_64 *//* x86-64 code generator *//* #define TCC_TARGET_ARM    *//* ARMv4 code generator *//* #define TCC_TARGET_ARM64  *//* ARMv8 code generator *//* #define TCC_TARGET_C67    *//* TMS320C67xx code generator *//* #define TCC_TARGET_RISCV64 *//* risc-v code generator */ /* default target is I386 */#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_ARM) && \    !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_C67) && \    !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_RISCV64)# if defined __x86_64__#  define TCC_TARGET_X86_64# elif defined __arm__#  define TCC_TARGET_ARM#  define TCC_ARM_EABI#  define TCC_ARM_VFP#  define TCC_ARM_HARDFLOAT# elif defined __aarch64__#  define TCC_TARGET_ARM64# elif defined __riscv#  define TCC_TARGET_RISCV64# else#  define TCC_TARGET_I386# endif# ifdef _WIN32#  define TCC_TARGET_PE 1# endif#endif /* only native compiler supports -run */#if defined _WIN32 == defined TCC_TARGET_PE# if defined __i386__ && defined TCC_TARGET_I386#  define TCC_IS_NATIVE# elif defined __x86_64__ && defined TCC_TARGET_X86_64#  define TCC_IS_NATIVE# elif defined __arm__ && defined TCC_TARGET_ARM#  define TCC_IS_NATIVE# elif defined __aarch64__ && defined TCC_TARGET_ARM64#  define TCC_IS_NATIVE# elif defined __riscv && defined __LP64__ && defined TCC_TARGET_RISCV64#  define TCC_IS_NATIVE# endif#endif #if defined TCC_IS_NATIVE && !defined CONFIG_TCCBOOT# define CONFIG_TCC_BACKTRACE# if (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 || \      defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64 || \      defined TCC_TARGET_RISCV64) \  && !defined TCC_UCLIBC && !defined TCC_MUSL# define CONFIG_TCC_BCHECK /* enable bound checking code */# endif#endif #if defined TCC_TARGET_PE || defined TCC_TARGET_MACHO# define ELF_OBJ_ONLY /* create elf .o but native executables */#endif /* ------------ path configuration ------------ */ #ifndef CONFIG_SYSROOT# define CONFIG_SYSROOT ""#endif#ifndef CONFIG_TCCDIR# define CONFIG_TCCDIR "/usr/local/lib/tcc"#endif#ifndef CONFIG_LDDIR# define CONFIG_LDDIR "lib"#endif#ifdef CONFIG_TRIPLET# define USE_TRIPLET(s) s "/" CONFIG_TRIPLET# define ALSO_TRIPLET(s) USE_TRIPLET(s) ":" s#else# define USE_TRIPLET(s) s# define ALSO_TRIPLET(s) s#endif /* path to find crt1.o, crti.o and crtn.o */#ifndef CONFIG_TCC_CRTPREFIX# define CONFIG_TCC_CRTPREFIX USE_TRIPLET(CONFIG_SYSROOT "/usr/" CONFIG_LDDIR)#endif #ifndef CONFIG_USR_INCLUDE# define CONFIG_USR_INCLUDE "/usr/include"#endif /* Below: {B} is substituted by CONFIG_TCCDIR (rsp. -B option) */ /* system include paths */#ifndef CONFIG_TCC_SYSINCLUDEPATHS# if defined TCC_TARGET_PE || defined _WIN32#  define CONFIG_TCC_SYSINCLUDEPATHS "{B}/include"PATHSEP"{B}/include/winapi"# else#  define CONFIG_TCC_SYSINCLUDEPATHS \        "{B}/include" \    ":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/local/include") \    ":" ALSO_TRIPLET(CONFIG_SYSROOT CONFIG_USR_INCLUDE)# endif#endif /* library search paths */#ifndef CONFIG_TCC_LIBPATHS# ifdef TCC_TARGET_PE#  define CONFIG_TCC_LIBPATHS "{B}/lib"# else#  define CONFIG_TCC_LIBPATHS \        ALSO_TRIPLET(CONFIG_SYSROOT "/usr/" CONFIG_LDDIR) \    ":" ALSO_TRIPLET(CONFIG_SYSROOT "/" CONFIG_LDDIR) \    ":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/local/" CONFIG_LDDIR)# endif#endif /* name of ELF interpreter */#ifndef CONFIG_TCC_ELFINTERP# if defined __FreeBSD__#  define CONFIG_TCC_ELFINTERP "/libexec/ld-elf.so.1"# elif defined __FreeBSD_kernel__#  if defined(TCC_TARGET_X86_64)#   define CONFIG_TCC_ELFINTERP "/lib/ld-kfreebsd-x86-64.so.1"#  else#   define CONFIG_TCC_ELFINTERP "/lib/ld.so.1"#  endif# elif defined __DragonFly__#  define CONFIG_TCC_ELFINTERP "/usr/libexec/ld-elf.so.2"# elif defined __NetBSD__#  define CONFIG_TCC_ELFINTERP "/usr/libexec/ld.elf_so"# elif defined __GNU__#  define CONFIG_TCC_ELFINTERP "/lib/ld.so"# elif defined(TCC_TARGET_PE)#  define CONFIG_TCC_ELFINTERP "-"# elif defined(TCC_UCLIBC)#  define CONFIG_TCC_ELFINTERP "/lib/ld-uClibc.so.0" /* is there a uClibc for x86_64 ? */# elif defined TCC_TARGET_ARM64#  if defined(TCC_MUSL)#   define CONFIG_TCC_ELFINTERP "/lib/ld-musl-aarch64.so.1"#  else#   define CONFIG_TCC_ELFINTERP "/lib/ld-linux-aarch64.so.1"#  endif# elif defined(TCC_TARGET_X86_64)#  if defined(TCC_MUSL)#   define CONFIG_TCC_ELFINTERP "/lib/ld-musl-x86_64.so.1"#  else#   define CONFIG_TCC_ELFINTERP "/lib64/ld-linux-x86-64.so.2"#  endif# elif defined(TCC_TARGET_RISCV64)#  define CONFIG_TCC_ELFINTERP "/lib/ld-linux-riscv64-lp64d.so.1"# elif !defined(TCC_ARM_EABI)#  if defined(TCC_MUSL)#   if defined(TCC_TARGET_I386)#     define CONFIG_TCC_ELFINTERP "/lib/ld-musl-i386.so.1"#    else#     define CONFIG_TCC_ELFINTERP "/lib/ld-musl-arm.so.1"#    endif#  else#   define CONFIG_TCC_ELFINTERP "/lib/ld-linux.so.2"#  endif# endif#endif /* var elf_interp dans *-gen.c */#ifdef CONFIG_TCC_ELFINTERP# define DEFAULT_ELFINTERP(s) CONFIG_TCC_ELFINTERP#else# define DEFAULT_ELFINTERP(s) default_elfinterp(s)#endif /* (target specific) libtcc1.a */#ifndef TCC_LIBTCC1# define TCC_LIBTCC1 "libtcc1.a"#endif /* library to use with CONFIG_USE_LIBGCC instead of libtcc1.a */#if defined CONFIG_USE_LIBGCC && !defined TCC_LIBGCC#define TCC_LIBGCC USE_TRIPLET(CONFIG_SYSROOT "/" CONFIG_LDDIR) "/libgcc_s.so.1"#endif /* -------------------------------------------- */ #include "libtcc.h"#include "elf.h"#include "stab.h" /* -------------------------------------------- */ #ifndef PUB_FUNC /* functions used by tcc.c but not in libtcc.h */# define PUB_FUNC#endif #ifndef ONE_SOURCE# define ONE_SOURCE 1#endif /* support using libtcc from threads */#define CONFIG_TCC_SEMLOCK #if ONE_SOURCE#define ST_INLN static inline#define ST_FUNC static#define ST_DATA static#else#define ST_INLN#define ST_FUNC#define ST_DATA extern#endif #ifdef TCC_PROFILE /* profile all functions */# define static#endif /* -------------------------------------------- *//* include the target specific definitions */ #define TARGET_DEFS_ONLY#ifdef TCC_TARGET_I386# include "i386-gen.c"# include "i386-link.c"#elif defined TCC_TARGET_X86_64# include "x86_64-gen.c"# include "x86_64-link.c"#elif defined TCC_TARGET_ARM# include "arm-gen.c"# include "arm-link.c"# include "arm-asm.c"#elif defined TCC_TARGET_ARM64# include "arm64-gen.c"# include "arm64-link.c"# include "arm-asm.c"#elif defined TCC_TARGET_C67# define TCC_TARGET_COFF# include "coff.h"# include "c67-gen.c"# include "c67-link.c"#elif defined(TCC_TARGET_RISCV64)# include "riscv64-gen.c"# include "riscv64-link.c"# include "riscv64-asm.c"#else#error unknown target#endif#undef TARGET_DEFS_ONLY /* -------------------------------------------- */ #if PTR_SIZE == 8# define ELFCLASSW ELFCLASS64# define ElfW(type) Elf##64##_##type# define ELFW(type) ELF##64##_##type# define ElfW_Rel ElfW(Rela)# define SHT_RELX SHT_RELA# define REL_SECTION_FMT ".rela%s"#else# define ELFCLASSW ELFCLASS32# define ElfW(type) Elf##32##_##type# define ELFW(type) ELF##32##_##type# define ElfW_Rel ElfW(Rel)# define SHT_RELX SHT_REL# define REL_SECTION_FMT ".rel%s"#endif/* target address type */#define addr_t ElfW(Addr)#define ElfSym ElfW(Sym) #if PTR_SIZE == 8 && !defined TCC_TARGET_PE# define LONG_SIZE 8#else# define LONG_SIZE 4#endif /* -------------------------------------------- */ #define INCLUDE_STACK_SIZE  32#define IFDEF_STACK_SIZE    64#define VSTACK_SIZE         256#define STRING_MAX_SIZE     1024#define TOKSTR_MAX_SIZE     256#define PACK_STACK_SIZE     8 #define TOK_HASH_SIZE       16384 /* must be a power of two */#define TOK_ALLOC_INCR      512  /* must be a power of two */#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; #ifdef TCC_TARGET_PEtypedef unsigned short nwchar_t;#elsetypedef int nwchar_t;#endif typedef struct CString {    int size; /* size in bytes */    void *data; /* either 'char *' or 'nwchar_t *' */    int size_allocated;} CString; /* type definition */typedef struct CType {    int t;    struct Sym *ref;} CType; /* constant value */typedef union CValue {    long double ld;    double d;    float f;    uint64_t i;    struct {        const void *data;        int size;    } str;    int tab[LDOUBLE_SIZE/4];} 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 */    union {      struct { int jtrue, jfalse; }; /* forward jmps */      CValue c;         /* constant, if VT_CONST */    };    union {      struct { unsigned short cmp_op, cmp_r; }; /* VT_CMP operation */      struct Sym *sym;  /* symbol, if (VT_SYM | VT_CONST), or if */    };                  /* result of unary() for an identifier. */ } SValue; /* symbol attributes */struct SymAttr {    unsigned short    aligned     : 5, /* alignment as log2+1 (0 == unspecified) */    packed      : 1,    weak        : 1,    visibility  : 2,    dllexport   : 1,    nodecorate  : 1,    dllimport   : 1,    addrtaken   : 1,    xxxx        : 3; /* not used */}; /* function attributes or temporary attributes for parsing */struct FuncAttr {    unsigned

Lines 1–500 of 1821.