2253 lines · 64.9 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 ONE_SOURCE# define ONE_SOURCE 1#endif #if ONE_SOURCE#include "tccpp.c"#include "tccgen.c"#include "tccdbg.c"#include "tccasm.c"#include "tccelf.c"#include "tccrun.c"#ifdef TCC_TARGET_I386#include "i386-gen.c"#include "i386-link.c"#include "i386-asm.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 "arm64-asm.c"#elif defined(TCC_TARGET_C67)#include "c67-gen.c"#include "c67-link.c"#include "tcccoff.c"#elif defined(TCC_TARGET_X86_64)#include "x86_64-gen.c"#include "x86_64-link.c"#include "i386-asm.c"#elif defined(TCC_TARGET_RISCV64)#include "riscv64-gen.c"#include "riscv64-link.c"#include "riscv64-asm.c"#else#error unknown target#endif#ifdef TCC_TARGET_PE#include "tccpe.c"#endif#ifdef TCC_TARGET_MACHO#include "tccmacho.c"#endif#endif /* ONE_SOURCE */ #include "tcc.h" /********************************************************//* global variables */ /* XXX: get rid of this ASAP (or maybe not) */ST_DATA struct TCCState *tcc_state;TCC_SEM(static tcc_compile_sem);/* an array of pointers to memory to be free'd after errors */ST_DATA void** stk_data;ST_DATA int nb_stk_data;/* option -d<num> (for general development purposes) */ST_DATA int g_debug; /********************************************************/#ifdef _WIN32ST_FUNC char *normalize_slashes(char *path){    char *p;    for (p = path; *p; ++p)        if (*p == '\\')            *p = '/';    return path;} #if defined LIBTCC_AS_DLL && !defined CONFIG_TCCDIRstatic HMODULE tcc_module;BOOL WINAPI DllMain (HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved){    if (DLL_PROCESS_ATTACH == dwReason)        tcc_module = hDll;    return TRUE;}#else#define tcc_module NULL /* NULL means executable itself */#endif #ifndef CONFIG_TCCDIR/* on win32, we suppose the lib and includes are at the location of 'tcc.exe' */static inline char *config_tccdir_w32(char *path){    char *p;    GetModuleFileNameA(tcc_module, path, MAX_PATH);    p = tcc_basename(normalize_slashes(strlwr(path)));    if (p > path)        --p;    *p = 0;    return path;}#define CONFIG_TCCDIR config_tccdir_w32(alloca(MAX_PATH))#endif #ifdef TCC_IS_NATIVEstatic void tcc_add_systemdir(TCCState *s){    char buf[1000];    GetSystemDirectoryA(buf, sizeof buf);    tcc_add_library_path(s, normalize_slashes(buf));}#endif/* for tcc -E : On windows (depending on compiler) a FILE*   must be created by the same module where it is used. */PUB_FUNC FILE *tcc_fopen(const char *f, const char *m) {    return fopen(f, m);}PUB_FUNC int tcc_fclose(FILE *f) {    return fclose(f);}#endif/********************************************************/ PUB_FUNC void tcc_enter_state(TCCState *s1){    if (s1->error_set_jmp_enabled)        return;    WAIT_SEM(&tcc_compile_sem);    tcc_state = s1;} PUB_FUNC void tcc_exit_state(TCCState *s1){    if (s1->error_set_jmp_enabled)        return;    tcc_state = NULL;    POST_SEM(&tcc_compile_sem);} /********************************************************//* copy a string and truncate it. */ST_FUNC char *pstrcpy(char *buf, size_t buf_size, const char *s){    char *q, *q_end;    int c;     if (buf_size > 0) {        q = buf;        q_end = buf + buf_size - 1;        while (q < q_end) {            c = *s++;            if (c == '\0')                break;            *q++ = c;        }        *q = '\0';    }    return buf;} /* strcat and truncate. */ST_FUNC char *pstrcat(char *buf, size_t buf_size, const char *s){    size_t len;    len = strlen(buf);    if (len < buf_size)        pstrcpy(buf + len, buf_size - len, s);    return buf;} ST_FUNC char *pstrncpy(char *out, size_t buf_size, const char *s, size_t num){    if (num >= buf_size)        num = buf_size - 1;    memcpy(out, s, num);    out[num] = '\0';    return out;} /* extract the basename of a file */PUB_FUNC char *tcc_basename(const char *name){    char *p = (char *)strchr(name, 0);    while (p > name && !IS_DIRSEP(p[-1]))        --p;    return p;} /* extract extension part of a file * * (if no extension, return pointer to end-of-string) */PUB_FUNC char *tcc_fileextension (const char *name){    char *b = tcc_basename(name);    char *e = strrchr(b, '.');    return e ? e : strchr(b, 0);} ST_FUNC char *tcc_load_text(int fd){    int len = lseek(fd, 0, SEEK_END);    char *buf = load_data(fd, 0, len + 1);    buf[len] = 0;    return buf;} /* replace *pp by copy of 'str' or NULL */static void tcc_set_str(char **pp, const char *str){    tcc_free(*pp);    *pp = str ? tcc_strdup(str) : NULL;} /* set/append 'str' to *pp (separated by 'sep' unless 0) */static void tcc_concat_str(char **pp, const char *str, int sep){    int l = *pp ? strlen(*pp) + !!sep : 0;    *pp = tcc_realloc(*pp, l + strlen(str) + 1);    if (l && sep) ((*pp)[l - 1] = sep);    strcpy(*pp + l, str);} /********************************************************//* memory management */ /* we'll need the actual versions for a minute */#undef free#undef realloc static void *default_reallocator(void *ptr, unsigned long size){    void *ptr1;    if (size == 0) {        free(ptr);        ptr1 = NULL;    }    else {        ptr1 = realloc(ptr, size);        if (!ptr1) {            fprintf(stderr, "tcc: memory full\n");            exit (1);        }    }    return ptr1;} ST_FUNC void libc_free(void *ptr){    free(ptr);} /* defined to be not used */#define free(p) use_tcc_free(p)#define realloc(p, s) use_tcc_realloc(p, s) /* global so that every tcc_alloc()/tcc_free() call doesn't need to be changed */static void *(*reallocator)(void*, unsigned long) = default_reallocator; LIBTCCAPI void tcc_set_realloc(TCCReallocFunc *my_realloc){    reallocator = my_realloc ? my_realloc : default_reallocator;} /* in case MEM_DEBUG is #defined */#undef tcc_free#undef tcc_malloc#undef tcc_realloc#undef tcc_mallocz#undef tcc_strdup PUB_FUNC void tcc_free(void *ptr){    reallocator(ptr, 0);} PUB_FUNC void *tcc_malloc(unsigned long size){    return reallocator(0, size);} PUB_FUNC void *tcc_realloc(void *ptr, unsigned long size){    return reallocator(ptr, size);} PUB_FUNC void *tcc_mallocz(unsigned long size){    void *ptr;    ptr = tcc_malloc(size);    if (size)        memset(ptr, 0, size);    return ptr;} PUB_FUNC char *tcc_strdup(const char *str){    char *ptr;    ptr = tcc_malloc(strlen(str) + 1);    strcpy(ptr, str);    return ptr;} #ifdef MEM_DEBUG #define MEM_DEBUG_MAGIC1 0xFEEDDEB1#define MEM_DEBUG_MAGIC2 0xFEEDDEB2#define MEM_DEBUG_MAGIC3 0xFEEDDEB3#define MEM_DEBUG_FILE_LEN 40#define MEM_DEBUG_CHECK3(header) \    (((unsigned char *) header->magic3) + header->size)#define MEM_USER_PTR(header) \    ((char *)header + offsetof(mem_debug_header_t, magic3))#define MEM_HEADER_PTR(ptr) \    (mem_debug_header_t *)((char*)ptr - offsetof(mem_debug_header_t, magic3)) struct mem_debug_header {    unsigned magic1;    unsigned size;    struct mem_debug_header *prev;    struct mem_debug_header *next;    int line_num;    char file_name[MEM_DEBUG_FILE_LEN];    unsigned magic2;    ALIGNED(16) unsigned char magic3[4];}; typedef struct mem_debug_header mem_debug_header_t; TCC_SEM(static mem_sem);static mem_debug_header_t *mem_debug_chain;static unsigned mem_cur_size;static unsigned mem_max_size;static int nb_states; static mem_debug_header_t *malloc_check(void *ptr, const char *msg){    mem_debug_header_t * header = MEM_HEADER_PTR(ptr);    if (header->magic1 != MEM_DEBUG_MAGIC1 ||        header->magic2 != MEM_DEBUG_MAGIC2 ||        read32le(MEM_DEBUG_CHECK3(header)) != MEM_DEBUG_MAGIC3 ||        header->size == (unsigned)-1) {        fprintf(stderr, "%s check failed\n", msg);        if (header->magic1 == MEM_DEBUG_MAGIC1)            fprintf(stderr, "%s:%u: block allocated here.\n",                header->file_name, header->line_num);        exit(1);    }    return header;} PUB_FUNC void *tcc_malloc_debug(unsigned long size, const char *file, int line){    int ofs;    mem_debug_header_t *header;    if (!size)        return NULL;    header = tcc_malloc(sizeof(mem_debug_header_t) + size);    header->magic1 = MEM_DEBUG_MAGIC1;    header->magic2 = MEM_DEBUG_MAGIC2;    header->size = size;    write32le(MEM_DEBUG_CHECK3(header), MEM_DEBUG_MAGIC3);    header->line_num = line;    ofs = strlen(file) + 1 - MEM_DEBUG_FILE_LEN;    strcpy(header->file_name, file + (ofs > 0 ? ofs : 0));    WAIT_SEM(&mem_sem);    header->next = mem_debug_chain;    header->prev = NULL;    if (header->next)        header->next->prev = header;    mem_debug_chain = header;    mem_cur_size += size;    if (mem_cur_size > mem_max_size)        mem_max_size = mem_cur_size;    POST_SEM(&mem_sem);    return MEM_USER_PTR(header);} PUB_FUNC void tcc_free_debug(void *ptr){    mem_debug_header_t *header;    if (!ptr)        return;    header = malloc_check(ptr, "tcc_free");    WAIT_SEM(&mem_sem);    mem_cur_size -= header->size;    header->size = (unsigned)-1;    if (header->next)        header->next->prev = header->prev;    if (header->prev)        header->prev->next = header->next;    if (header == mem_debug_chain)        mem_debug_chain = header->next;    POST_SEM(&mem_sem);    tcc_free(header);} PUB_FUNC void *tcc_mallocz_debug(unsigned long size, const char *file, int line){    void *ptr;    ptr = tcc_malloc_debug(size,file,line);    if (size)        memset(ptr, 0, size);    return ptr;} PUB_FUNC void *tcc_realloc_debug(void *ptr, unsigned long size, const char *file, int line){    mem_debug_header_t *header;    int mem_debug_chain_update = 0;     if (!ptr)        return tcc_malloc_debug(size, file, line);    if (!size) {        tcc_free_debug(ptr);        return NULL;    }    header = malloc_check(ptr, "tcc_realloc");    WAIT_SEM(&mem_sem);    mem_cur_size -= header->size;    mem_debug_chain_update = (header == mem_debug_chain);    header = tcc_realloc(header, sizeof(mem_debug_header_t) + size);    header->size = size;    write32le(MEM_DEBUG_CHECK3(header), MEM_DEBUG_MAGIC3);    if (header->next)        header->next->prev = header;    if (header->prev)        header->prev->next = header;    if (mem_debug_chain_update)        mem_debug_chain = header;    mem_cur_size += size;    if (mem_cur_size > mem_max_size)        mem_max_size = mem_cur_size;    POST_SEM(&mem_sem);    return MEM_USER_PTR(header);} PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line){    char *ptr;    ptr = tcc_malloc_debug(strlen(str) + 1, file, line);    strcpy(ptr, str);    return ptr;} PUB_FUNC void tcc_memcheck(int d){    WAIT_SEM(&mem_sem);    nb_states += d;    if (0 == nb_states && mem_cur_size) {        mem_debug_header_t *header = mem_debug_chain;        fflush(stdout);        fprintf(stderr, "MEM_DEBUG: mem_leak= %d bytes, mem_max_size= %d bytes\n",            mem_cur_size, mem_max_size);        while (header) {            fprintf(stderr, "%s:%u: error: %u bytes leaked\n",                header->file_name, header->line_num, header->size);            header = header->next;        }        fflush(stderr);        mem_cur_size = 0;        mem_max_size = 0;        mem_debug_chain = NULL;#if MEM_DEBUG-0 == 2        exit(2);#endif    }    POST_SEM(&mem_sem);} /* restore the debug versions */#define tcc_free(ptr)           tcc_free_debug(ptr)#define tcc_malloc(size)        tcc_malloc_debug(size, __FILE__, __LINE__)#define tcc_mallocz(size)       tcc_mallocz_debug(size, __FILE__, __LINE__)#define tcc_realloc(ptr,size)   tcc_realloc_debug(ptr, size, __FILE__, __LINE__)#define tcc_strdup(str)         tcc_strdup_debug(str, __FILE__, __LINE__) #endif /* MEM_DEBUG */ #ifdef _WIN32# define realpath(file, buf) _fullpath(buf, file, 260)#endif /* for #pragma once */ST_FUNC int normalized_PATHCMP(const char *f1, const char *f2){

Lines 1–500 of 2253.