2124 lines · 61.2 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 */ #if !defined ONE_SOURCE || ONE_SOURCE#include "tccpp.c"#include "tccgen.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 "arm-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 CONFIG_TCC_ASM#include "tccasm.c"#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; #ifdef MEM_DEBUGstatic int nb_states;#endif /********************************************************/#ifdef _WIN32ST_FUNC char *normalize_slashes(char *path){    char *p;    for (p = path; *p; ++p)        if (*p == '\\')            *p = '/';    return path;} static HMODULE tcc_module; /* on win32, we suppose the lib and includes are at the location of 'tcc.exe' */static void tcc_set_lib_path_w32(TCCState *s){    char path[1024], *p;    GetModuleFileNameA(tcc_module, path, sizeof path);    p = tcc_basename(normalize_slashes(strlwr(path)));    if (p > path)        --p;    *p = 0;    tcc_set_lib_path(s, path);} #ifdef TCC_TARGET_PEstatic void tcc_add_systemdir(TCCState *s){    char buf[1000];    GetSystemDirectory(buf, sizeof buf);    tcc_add_library_path(s, normalize_slashes(buf));}#endif #ifdef LIBTCC_AS_DLLBOOL WINAPI DllMain (HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved){    if (DLL_PROCESS_ATTACH == dwReason)        tcc_module = hDll;    return TRUE;}#endif#endif /********************************************************/#ifndef CONFIG_TCC_SEMLOCK#define WAIT_SEM()#define POST_SEM()#elif defined _WIN32static int tcc_sem_init;static CRITICAL_SECTION tcc_cr;static void wait_sem(void){    if (!tcc_sem_init)        InitializeCriticalSection(&tcc_cr), tcc_sem_init = 1;    EnterCriticalSection(&tcc_cr);}#define WAIT_SEM() wait_sem()#define POST_SEM() LeaveCriticalSection(&tcc_cr);#elif defined __APPLE__/* Half-compatible MacOS doesn't have non-shared (process local)   semaphores.  Use the dispatch framework for lightweight locks.  */#include <dispatch/dispatch.h>static int tcc_sem_init;static dispatch_semaphore_t tcc_sem;static void wait_sem(void){    if (!tcc_sem_init)      tcc_sem = dispatch_semaphore_create(1), tcc_sem_init = 1;    dispatch_semaphore_wait(tcc_sem, DISPATCH_TIME_FOREVER);}#define WAIT_SEM() wait_sem()#define POST_SEM() dispatch_semaphore_signal(tcc_sem)#else#include <semaphore.h>static int tcc_sem_init;static sem_t tcc_sem;static void wait_sem(void){    if (!tcc_sem_init)        sem_init(&tcc_sem, 0, 1), tcc_sem_init = 1;    while (sem_wait (&tcc_sem) < 0 && errno == EINTR);}#define WAIT_SEM() wait_sem()#define POST_SEM() sem_post(&tcc_sem)#endif /********************************************************//* 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, const char *in, size_t num){    memcpy(out, in, num);    out[num] = '\0';    return out;} /* extract the basename of a file */PUB_FUNC char *tcc_basename(const char *name){    char *p = 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);} /********************************************************//* memory management */ #undef free#undef malloc#undef realloc #ifndef MEM_DEBUG PUB_FUNC void tcc_free(void *ptr){    free(ptr);} PUB_FUNC void *tcc_malloc(unsigned long size){    void *ptr;    ptr = malloc(size);    if (!ptr && size)        _tcc_error("memory full (malloc)");    return ptr;} PUB_FUNC void *tcc_mallocz(unsigned long size){    void *ptr;    ptr = tcc_malloc(size);    if (size)        memset(ptr, 0, size);    return ptr;} PUB_FUNC void *tcc_realloc(void *ptr, unsigned long size){    void *ptr1;    ptr1 = realloc(ptr, size);    if (!ptr1 && size)        _tcc_error("memory full (realloc)");    return ptr1;} PUB_FUNC char *tcc_strdup(const char *str){    char *ptr;    ptr = tcc_malloc(strlen(str) + 1);    strcpy(ptr, str);    return ptr;} #else #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) \    ((mem_debug_header_t*)((char*)header + header->size))->magic3#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 + 1];    unsigned magic2;    ALIGNED(16) unsigned magic3;}; typedef struct mem_debug_header mem_debug_header_t; static mem_debug_header_t *mem_debug_chain;static unsigned mem_cur_size;static unsigned mem_max_size; 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 ||        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;     header = malloc(sizeof(mem_debug_header_t) + size);    if (!header)        _tcc_error("memory full (malloc)");     header->magic1 = MEM_DEBUG_MAGIC1;    header->magic2 = MEM_DEBUG_MAGIC2;    header->size = size;    MEM_DEBUG_CHECK3(header) = MEM_DEBUG_MAGIC3;    header->line_num = line;    ofs = strlen(file) - MEM_DEBUG_FILE_LEN;    strncpy(header->file_name, file + (ofs > 0 ? ofs : 0), MEM_DEBUG_FILE_LEN);    header->file_name[MEM_DEBUG_FILE_LEN] = 0;     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;     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");    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;    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);    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);    header = malloc_check(ptr, "tcc_realloc");    mem_cur_size -= header->size;    mem_debug_chain_update = (header == mem_debug_chain);    header = realloc(header, sizeof(mem_debug_header_t) + size);    if (!header)        _tcc_error("memory full (realloc)");    header->size = size;    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;    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(void){    if (mem_cur_size) {        mem_debug_header_t *header = mem_debug_chain;        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;        }#if MEM_DEBUG-0 == 2        exit(2);#endif    }}#endif /* MEM_DEBUG */ #define free(p) use_tcc_free(p)#define malloc(s) use_tcc_malloc(s)#define realloc(p, s) use_tcc_realloc(p, s) /********************************************************//* dynarrays */ ST_FUNC void dynarray_add(void *ptab, int *nb_ptr, void *data){    int nb, nb_alloc;    void **pp;     nb = *nb_ptr;    pp = *(void ***)ptab;    /* every power of two we double array size */    if ((nb & (nb - 1)) == 0) {        if (!nb)            nb_alloc = 1;        else            nb_alloc = nb * 2;        pp = tcc_realloc(pp, nb_alloc * sizeof(void *));        *(void***)ptab = pp;    }    pp[nb++] = data;    *nb_ptr = nb;} ST_FUNC void dynarray_reset(void *pp, int *n){    void **p;    for (p = *(void***)pp; *n; ++p, --*n)        if (*p)            tcc_free(*p);    tcc_free(*(void**)pp);    *(void**)pp = NULL;} static void tcc_split_path(TCCState *s, void *p_ary, int *p_nb_ary, const char *in){    const char *p;    do {        int c;        CString str;         cstr_new(&str);        for (p = in; c = *p, c != '\0' && c != PATHSEP[0]; ++p) {            if (c == '{' && p[1] && p[2] == '}') {                c = p[1], p += 2;                if (c == 'B')                    cstr_cat(&str, s->tcc_lib_path, -1);                if (c == 'f' && file) {                    /* substitute current file's dir */                    const char *f = file->true_filename;                    const char *b = tcc_basename(f);                    if (b > f)                        cstr_cat(&str, f, b - f - 1);                    else                        cstr_cat(&str, ".", 1);                }            } else {                cstr_ccat(&str, c);            }        }        if (str.size) {            cstr_ccat(&str, '\0');            dynarray_add(p_ary, p_nb_ary, tcc_strdup(str.data));        }        cstr_free(&str);        in = p+1;    } while (*p);} /********************************************************/ static void strcat_vprintf(char *buf, int buf_size, const char *fmt, va_list ap){    int len;

Lines 1–500 of 2124.