libtcc: new LIBTCCAPI tcc_set_options(TCCState*, const char*str)

This replaces       -> use instead:
-----------------------------------
- tcc_set_linker    -> tcc_set_options(s, "-Wl,...");
- tcc_set_warning   -> tcc_set_options(s, "-W...");
- tcc_enable_debug  -> tcc_set_options(s, "-g");

parse_args is moved to libtcc.c (now tcc_parse_args).

Also some cleanups:
- reorder TCCState members
- add some comments here and there
- do not use argv's directly, make string copies
- use const char* in tcc_set_linker
- tccpe: use fd instead of fp

tested with -D MEM_DEBUG: 0 bytes left
master
grischka 2013-02-12 19:13:28 +01:00
parent 829655949b
commit 05108a3b0a
12 changed files with 909 additions and 987 deletions

View File

@ -4,7 +4,8 @@ User interface:
- -MD/-MF (automatically generate dependencies for make) - -MD/-MF (automatically generate dependencies for make)
- -pthread option (same as -D_REENTRANT -lpthread) (Henry Kroll III) - -pthread option (same as -D_REENTRANT -lpthread) (Henry Kroll III)
- -m32/-m64 to re-exec cross compiler (Henry Kroll III) - -m32/-m64 to re-exec cross compiler (Henry Kroll III)
- Mimic all GNU -option forms supported by ld (Kirill Smelkov) - -Wl, Mimic all GNU -option forms supported by ld (Kirill Smelkov)
- new LIBTCCAPI tcc_set_options() (grischka)
Platforms: Platforms:
- Many improvements for x86-64 target (Shinichiro Hamaji, Michael Matz, grischka) - Many improvements for x86-64 target (Shinichiro Hamaji, Michael Matz, grischka)

649
libtcc.c
View File

@ -197,8 +197,8 @@ PUB_FUNC char *tcc_fileextension (const char *name)
#undef realloc #undef realloc
#ifdef MEM_DEBUG #ifdef MEM_DEBUG
int mem_cur_size; ST_DATA int mem_cur_size;
int mem_max_size; ST_DATA int mem_max_size;
unsigned malloc_usable_size(void*); unsigned malloc_usable_size(void*);
#endif #endif
@ -261,7 +261,7 @@ PUB_FUNC char *tcc_strdup(const char *str)
PUB_FUNC void tcc_memstats(void) PUB_FUNC void tcc_memstats(void)
{ {
#ifdef MEM_DEBUG #ifdef MEM_DEBUG
printf("memory in use: %d\n", mem_cur_size); printf("memory: %d bytes, max = %d bytes\n", mem_cur_size, mem_max_size);
#endif #endif
} }
@ -272,7 +272,7 @@ PUB_FUNC void tcc_memstats(void)
/********************************************************/ /********************************************************/
/* dynarrays */ /* dynarrays */
PUB_FUNC void dynarray_add(void ***ptab, int *nb_ptr, void *data) ST_FUNC void dynarray_add(void ***ptab, int *nb_ptr, void *data)
{ {
int nb, nb_alloc; int nb, nb_alloc;
void **pp; void **pp;
@ -292,7 +292,7 @@ PUB_FUNC void dynarray_add(void ***ptab, int *nb_ptr, void *data)
*nb_ptr = nb; *nb_ptr = nb;
} }
PUB_FUNC void dynarray_reset(void *pp, int *n) ST_FUNC void dynarray_reset(void *pp, int *n)
{ {
void **p; void **p;
for (p = *(void***)pp; *n; ++p, --*n) for (p = *(void***)pp; *n; ++p, --*n)
@ -860,10 +860,10 @@ LIBTCCAPI void tcc_undefine_symbol(TCCState *s1, const char *sym)
define_undef(s); define_undef(s);
} }
/* cleanup all static data used during compilation */
static void tcc_cleanup(void) static void tcc_cleanup(void)
{ {
int i, n; int i, n;
if (NULL == tcc_state) if (NULL == tcc_state)
return; return;
tcc_state = NULL; tcc_state = NULL;
@ -915,18 +915,23 @@ LIBTCCAPI TCCState *tcc_new(void)
define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL); define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL);
define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL); define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL);
/* define __TINYC__ 92X */
sscanf(TCC_VERSION, "%d.%d.%d", &a, &b, &c);
sprintf(buffer, "%d", a*10000 + b*100 + c);
tcc_define_symbol(s, "__TINYC__", buffer);
/* standard defines */ /* standard defines */
tcc_define_symbol(s, "__STDC__", NULL); tcc_define_symbol(s, "__STDC__", NULL);
tcc_define_symbol(s, "__STDC_VERSION__", "199901L"); tcc_define_symbol(s, "__STDC_VERSION__", "199901L");
/* target defines */
#if defined(TCC_TARGET_I386) #if defined(TCC_TARGET_I386)
tcc_define_symbol(s, "__i386__", NULL); tcc_define_symbol(s, "__i386__", NULL);
tcc_define_symbol(s, "__i386", NULL); tcc_define_symbol(s, "__i386", NULL);
tcc_define_symbol(s, "i386", NULL); tcc_define_symbol(s, "i386", NULL);
#endif #elif defined(TCC_TARGET_X86_64)
#if defined(TCC_TARGET_X86_64)
tcc_define_symbol(s, "__x86_64__", NULL); tcc_define_symbol(s, "__x86_64__", NULL);
#endif #elif defined(TCC_TARGET_ARM)
#if defined(TCC_TARGET_ARM)
tcc_define_symbol(s, "__ARM_ARCH_4__", NULL); tcc_define_symbol(s, "__ARM_ARCH_4__", NULL);
tcc_define_symbol(s, "__arm_elf__", NULL); tcc_define_symbol(s, "__arm_elf__", NULL);
tcc_define_symbol(s, "__arm_elf", NULL); tcc_define_symbol(s, "__arm_elf", NULL);
@ -936,34 +941,31 @@ LIBTCCAPI TCCState *tcc_new(void)
tcc_define_symbol(s, "arm", NULL); tcc_define_symbol(s, "arm", NULL);
tcc_define_symbol(s, "__APCS_32__", NULL); tcc_define_symbol(s, "__APCS_32__", NULL);
#endif #endif
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
tcc_define_symbol(s, "_WIN32", NULL); tcc_define_symbol(s, "_WIN32", NULL);
#ifdef TCC_TARGET_X86_64 # ifdef TCC_TARGET_X86_64
tcc_define_symbol(s, "_WIN64", NULL); tcc_define_symbol(s, "_WIN64", NULL);
#endif # endif
#else #else
tcc_define_symbol(s, "__unix__", NULL); tcc_define_symbol(s, "__unix__", NULL);
tcc_define_symbol(s, "__unix", NULL); tcc_define_symbol(s, "__unix", NULL);
tcc_define_symbol(s, "unix", NULL); tcc_define_symbol(s, "unix", NULL);
#if defined(__FreeBSD__) # if defined(__linux)
#define str(s) #s
tcc_define_symbol(s, "__FreeBSD__", str( __FreeBSD__));
#undef str
#endif
#if defined(__FreeBSD_kernel__)
tcc_define_symbol(s, "__FreeBSD_kernel__", NULL);
#endif
#if defined(__linux)
tcc_define_symbol(s, "__linux__", NULL); tcc_define_symbol(s, "__linux__", NULL);
tcc_define_symbol(s, "__linux", NULL); tcc_define_symbol(s, "__linux", NULL);
# endif
# if defined(__FreeBSD__)
# define str(s) #s
tcc_define_symbol(s, "__FreeBSD__", str( __FreeBSD__));
# undef str
# endif
# if defined(__FreeBSD_kernel__)
tcc_define_symbol(s, "__FreeBSD_kernel__", NULL);
# endif
#endif #endif
#endif
/* tiny C specific defines */
sscanf(TCC_VERSION, "%d.%d.%d", &a, &b, &c);
sprintf(buffer, "%d", a*10000 + b*100 + c);
tcc_define_symbol(s, "__TINYC__", buffer);
/* tiny C & gcc defines */ /* TinyCC & gcc defines */
#if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64 #if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64
tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long long"); tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long long");
tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long long"); tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long long");
@ -978,11 +980,10 @@ LIBTCCAPI TCCState *tcc_new(void)
tcc_define_symbol(s, "__WCHAR_TYPE__", "int"); tcc_define_symbol(s, "__WCHAR_TYPE__", "int");
#endif #endif
#ifndef TCC_TARGET_PE
/* glibc defines */ /* glibc defines */
tcc_define_symbol(s, "__REDIRECT(name, proto, alias)", "name proto __asm__ (#alias)"); tcc_define_symbol(s, "__REDIRECT(name, proto, alias)", "name proto __asm__ (#alias)");
tcc_define_symbol(s, "__REDIRECT_NTH(name, proto, alias)", "name proto __asm__ (#alias) __THROW"); tcc_define_symbol(s, "__REDIRECT_NTH(name, proto, alias)", "name proto __asm__ (#alias) __THROW");
#ifndef TCC_TARGET_PE
/* default library paths */ /* default library paths */
tcc_add_library_path(s, CONFIG_TCC_LIBPATHS); tcc_add_library_path(s, CONFIG_TCC_LIBPATHS);
/* paths for crt objects */ /* paths for crt objects */
@ -1010,16 +1011,15 @@ LIBTCCAPI TCCState *tcc_new(void)
".dynhashtab", SHF_PRIVATE); ".dynhashtab", SHF_PRIVATE);
s->alacarte_link = 1; s->alacarte_link = 1;
s->nocommon = 1; s->nocommon = 1;
s->section_align = ELF_PAGE_SIZE;
#ifdef CHAR_IS_UNSIGNED #ifdef CHAR_IS_UNSIGNED
s->char_is_unsigned = 1; s->char_is_unsigned = 1;
#endif #endif
/* enable this if you want symbols with leading underscore on windows: */ /* enable this if you want symbols with leading underscore on windows: */
#if defined(TCC_TARGET_PE) && 0 #if 0 //def TCC_TARGET_PE
s->leading_underscore = 1; s->leading_underscore = 1;
#endif #endif
if (s->section_align == 0)
s->section_align = ELF_PAGE_SIZE;
#ifdef TCC_TARGET_I386 #ifdef TCC_TARGET_I386
s->seg_size = 32; s->seg_size = 32;
#endif #endif
@ -1060,16 +1060,25 @@ LIBTCCAPI void tcc_delete(TCCState *s1)
dynarray_reset(&s1->include_paths, &s1->nb_include_paths); dynarray_reset(&s1->include_paths, &s1->nb_include_paths);
dynarray_reset(&s1->sysinclude_paths, &s1->nb_sysinclude_paths); dynarray_reset(&s1->sysinclude_paths, &s1->nb_sysinclude_paths);
tcc_free(s1->tcc_lib_path);
tcc_free(s1->soname);
tcc_free(s1->rpath);
tcc_free(s1->init_symbol);
tcc_free(s1->fini_symbol);
tcc_free(s1->outfile);
tcc_free(s1->deps_outfile);
dynarray_reset(&s1->files, &s1->nb_files);
dynarray_reset(&s1->target_deps, &s1->nb_target_deps); dynarray_reset(&s1->target_deps, &s1->nb_target_deps);
tcc_free(s1->tcc_lib_path); #ifdef TCC_IS_NATIVE
# ifdef HAVE_SELINUX
#ifdef HAVE_SELINUX
munmap (s1->write_mem, s1->mem_size); munmap (s1->write_mem, s1->mem_size);
munmap (s1->runtime_mem, s1->mem_size); munmap (s1->runtime_mem, s1->mem_size);
#else # else
tcc_free(s1->runtime_mem); tcc_free(s1->runtime_mem);
# endif
#endif #endif
tcc_free(s1); tcc_free(s1);
} }
@ -1236,7 +1245,6 @@ static int tcc_add_library_internal(TCCState *s, const char *fmt,
return -1; return -1;
} }
#ifndef TCC_TARGET_PE
/* find and load a dll. Return non zero if not found */ /* find and load a dll. Return non zero if not found */
/* XXX: add '-rpath' option support ? */ /* XXX: add '-rpath' option support ? */
ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags) ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags)
@ -1244,7 +1252,6 @@ ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags)
return tcc_add_library_internal(s, "%s/%s", filename, flags, return tcc_add_library_internal(s, "%s/%s", filename, flags,
s->library_paths, s->nb_library_paths); s->library_paths, s->nb_library_paths);
} }
#endif
ST_FUNC int tcc_add_crt(TCCState *s, const char *filename) ST_FUNC int tcc_add_crt(TCCState *s, const char *filename)
{ {
@ -1276,11 +1283,15 @@ LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname)
LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, const void *val) LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, const void *val)
{ {
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
pe_putimport(s, 0, name, (uintptr_t)val); /* On x86_64 'val' might not be reachable with a 32bit offset.
So it is handled here as if it were in a DLL. */
pe_putimport(s, 0, name, (uintptr_t)val);
#else #else
add_elf_sym(symtab_section, (uintptr_t)val, 0, /* XXX: Same problem on linux but currently "solved" elsewhere
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, via the rather dirty 'runtime_plt_and_got' hack. */
SHN_ABS, name); add_elf_sym(symtab_section, (uintptr_t)val, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
SHN_ABS, name);
#endif #endif
return 0; return 0;
} }
@ -1341,6 +1352,12 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type)
return 0; return 0;
} }
LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path)
{
tcc_free(s->tcc_lib_path);
s->tcc_lib_path = tcc_strdup(path);
}
#define WD_ALL 0x0001 /* warning is activated when using -Wall */ #define WD_ALL 0x0001 /* warning is activated when using -Wall */
#define FD_INVERT 0x0002 /* invert value before storing */ #define FD_INVERT 0x0002 /* invert value before storing */
@ -1382,14 +1399,8 @@ ST_FUNC int set_flag(TCCState *s, const FlagDef *flags, int nb_flags,
return 0; return 0;
} }
/* enable debug */
LIBTCCAPI void tcc_enable_debug(TCCState *s)
{
s->do_debug = 1;
}
/* set/reset a warning */ /* set/reset a warning */
LIBTCCAPI int tcc_set_warning(TCCState *s, const char *warning_name, int value) static int tcc_set_warning(TCCState *s, const char *warning_name, int value)
{ {
int i; int i;
const FlagDef *p; const FlagDef *p;
@ -1414,30 +1425,28 @@ static const FlagDef flag_defs[] = {
}; };
/* set/reset a flag */ /* set/reset a flag */
PUB_FUNC int tcc_set_flag(TCCState *s, const char *flag_name, int value) static int tcc_set_flag(TCCState *s, const char *flag_name, int value)
{ {
return set_flag(s, flag_defs, countof(flag_defs), return set_flag(s, flag_defs, countof(flag_defs),
flag_name, value); flag_name, value);
} }
static int strstart(const char *str, const char *val, char **ptr) static int strstart(const char *val, const char **str)
{ {
const char *p, *q; const char *p, *q;
p = str; p = *str;
q = val; q = val;
while (*q != '\0') { while (*q) {
if (*p != *q) if (*p != *q)
return 0; return 0;
p++; p++;
q++; q++;
} }
if (ptr) *str = p;
*ptr = (char *) p;
return 1; return 1;
} }
/* Like strstart, but automatically takes into account that ld options can /* Like strstart, but automatically takes into account that ld options can
* *
* - start with double or single dash (e.g. '--soname' or '-soname') * - start with double or single dash (e.g. '--soname' or '-soname')
@ -1446,7 +1455,7 @@ static int strstart(const char *str, const char *val, char **ptr)
* *
* you provide `val` always in 'option[=]' form (no leading -) * you provide `val` always in 'option[=]' form (no leading -)
*/ */
static int link_option(const char *str, const char *val, char **ptr) static int link_option(const char *str, const char *val, const char **ptr)
{ {
const char *p, *q; const char *p, *q;
@ -1476,64 +1485,72 @@ static int link_option(const char *str, const char *val, char **ptr)
} }
if (ptr) if (ptr)
*ptr = (char *) p; *ptr = p;
return 1; return 1;
} }
static const char *skip_linker_arg(const char **str)
{
const char *s1 = *str;
const char *s2 = strchr(s1, ',');
*str = s2 ? s2++ : (s2 = s1 + strlen(s1));
return s2;
}
static char *copy_linker_arg(const char *p)
{
const char *q = p;
skip_linker_arg(&q);
return pstrncpy(tcc_malloc(q - p + 1), p, q - p);
}
/* set linker options */ /* set linker options */
PUB_FUNC const char * tcc_set_linker(TCCState *s, char *option, int multi) static int tcc_set_linker(TCCState *s, const char *option)
{ {
char *p = option;
char *end;
while (option && *option) { while (option && *option) {
end = NULL;
const char *p = option;
char *end = NULL;
int ignoring = 0;
if (link_option(option, "Bsymbolic", &p)) { if (link_option(option, "Bsymbolic", &p)) {
s->symbolic = 1; s->symbolic = 1;
} else if (link_option(option, "nostdlib", &p)) { } else if (link_option(option, "nostdlib", &p)) {
s->nostdlib = 1; s->nostdlib = 1;
} else if (link_option(option, "fini=", &p)) { } else if (link_option(option, "fini=", &p)) {
s->fini_symbol = p; s->fini_symbol = copy_linker_arg(p);
if (s->warn_unsupported) ignoring = 1;
tcc_warning("ignoring -fini %s", p); } else if (link_option(option, "image-base=", &p)
} else if (link_option(option, "image-base=", &p)) { || link_option(option, "Ttext=", &p)) {
s->text_addr = strtoull(p, &end, 16); s->text_addr = strtoull(p, &end, 16);
s->has_text_addr = 1; s->has_text_addr = 1;
} else if (link_option(option, "init=", &p)) { } else if (link_option(option, "init=", &p)) {
s->init_symbol = p; s->init_symbol = copy_linker_arg(p);
if (s->warn_unsupported) ignoring = 1;
tcc_warning("ignoring -init %s", p);
} else if (link_option(option, "oformat=", &p)) { } else if (link_option(option, "oformat=", &p)) {
#if defined(TCC_TARGET_PE) #if defined(TCC_TARGET_PE)
if (strstart(p, "pe-", NULL)) { if (strstart("pe-", &p)) {
#elif defined(TCC_TARGET_X86_64)
if (strstart("elf64-", &p)) {
#else #else
#if defined(TCC_TARGET_X86_64) if (strstart("elf32-", &p)) {
if (strstart(p, "elf64-", NULL)) {
#else
if (strstart(p, "elf32-", NULL)) {
#endif
#endif #endif
s->output_format = TCC_OUTPUT_FORMAT_ELF; s->output_format = TCC_OUTPUT_FORMAT_ELF;
} else if (!strcmp(p, "binary")) { } else if (!strcmp(p, "binary")) {
s->output_format = TCC_OUTPUT_FORMAT_BINARY; s->output_format = TCC_OUTPUT_FORMAT_BINARY;
} else
#ifdef TCC_TARGET_COFF #ifdef TCC_TARGET_COFF
if (!strcmp(p, "coff")) { } else if (!strcmp(p, "coff")) {
s->output_format = TCC_OUTPUT_FORMAT_COFF; s->output_format = TCC_OUTPUT_FORMAT_COFF;
} else
#endif #endif
{ } else
return p; goto err;
}
} else if (link_option(option, "rpath=", &p)) { } else if (link_option(option, "rpath=", &p)) {
s->rpath = p; s->rpath = copy_linker_arg(p);
} else if (link_option(option, "section-alignment=", &p)) { } else if (link_option(option, "section-alignment=", &p)) {
s->section_align = strtoul(p, &end, 16); s->section_align = strtoul(p, &end, 16);
} else if (link_option(option, "soname=", &p)) { } else if (link_option(option, "soname=", &p)) {
s->soname = p; s->soname = copy_linker_arg(p);
multi = 0;
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
} else if (link_option(option, "file-alignment=", &p)) { } else if (link_option(option, "file-alignment=", &p)) {
s->pe_file_align = strtoul(p, &end, 16); s->pe_file_align = strtoul(p, &end, 16);
@ -1561,98 +1578,346 @@ PUB_FUNC const char * tcc_set_linker(TCCState *s, char *option, int multi)
if (!strcmp(p, "wince")) { if (!strcmp(p, "wince")) {
s->pe_subsystem = 9; s->pe_subsystem = 9;
#endif #endif
} else { } else
return p; goto err;
}
#endif #endif
} else
goto err;
} else if (link_option(option, "Ttext=", &p)) { if (ignoring && s->warn_unsupported) err: {
s->text_addr = strtoull(p, &end, 16); char buf[100], *e;
s->has_text_addr = 1; pstrcpy(buf, sizeof buf, e = copy_linker_arg(option)), tcc_free(e);
} else { if (ignoring)
char *comma_ptr = strchr(option, ','); tcc_warning("unsupported linker option '%s'", buf);
if (comma_ptr) else
*comma_ptr = '\0'; tcc_error("unsupported linker option '%s'", buf);
return option; }
option = skip_linker_arg(&p);
}
return 0;
}
typedef struct TCCOption {
const char *name;
uint16_t index;
uint16_t flags;
} TCCOption;
enum {
TCC_OPTION_HELP,
TCC_OPTION_I,
TCC_OPTION_D,
TCC_OPTION_U,
TCC_OPTION_L,
TCC_OPTION_B,
TCC_OPTION_l,
TCC_OPTION_bench,
TCC_OPTION_bt,
TCC_OPTION_b,
TCC_OPTION_g,
TCC_OPTION_c,
TCC_OPTION_static,
TCC_OPTION_shared,
TCC_OPTION_soname,
TCC_OPTION_o,
TCC_OPTION_r,
TCC_OPTION_s,
TCC_OPTION_Wl,
TCC_OPTION_W,
TCC_OPTION_O,
TCC_OPTION_m,
TCC_OPTION_f,
TCC_OPTION_isystem,
TCC_OPTION_nostdinc,
TCC_OPTION_nostdlib,
TCC_OPTION_print_search_dirs,
TCC_OPTION_rdynamic,
TCC_OPTION_pedantic,
TCC_OPTION_pthread,
TCC_OPTION_run,
TCC_OPTION_v,
TCC_OPTION_w,
TCC_OPTION_pipe,
TCC_OPTION_E,
TCC_OPTION_MD,
TCC_OPTION_MF,
TCC_OPTION_x,
};
#define TCC_OPTION_HAS_ARG 0x0001
#define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */
static const TCCOption tcc_options[] = {
{ "h", TCC_OPTION_HELP, 0 },
{ "-help", TCC_OPTION_HELP, 0 },
{ "?", TCC_OPTION_HELP, 0 },
{ "I", TCC_OPTION_I, TCC_OPTION_HAS_ARG },
{ "D", TCC_OPTION_D, TCC_OPTION_HAS_ARG },
{ "U", TCC_OPTION_U, TCC_OPTION_HAS_ARG },
{ "L", TCC_OPTION_L, TCC_OPTION_HAS_ARG },
{ "B", TCC_OPTION_B, TCC_OPTION_HAS_ARG },
{ "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "bench", TCC_OPTION_bench, 0 },
#ifdef CONFIG_TCC_BACKTRACE
{ "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG },
#endif
#ifdef CONFIG_TCC_BCHECK
{ "b", TCC_OPTION_b, 0 },
#endif
{ "g", TCC_OPTION_g, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "c", TCC_OPTION_c, 0 },
{ "static", TCC_OPTION_static, 0 },
{ "shared", TCC_OPTION_shared, 0 },
{ "soname", TCC_OPTION_soname, TCC_OPTION_HAS_ARG },
{ "o", TCC_OPTION_o, TCC_OPTION_HAS_ARG },
{ "pedantic", TCC_OPTION_pedantic, 0},
{ "pthread", TCC_OPTION_pthread, 0},
{ "run", TCC_OPTION_run, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "rdynamic", TCC_OPTION_rdynamic, 0 },
{ "r", TCC_OPTION_r, 0 },
{ "s", TCC_OPTION_s, 0 },
{ "Wl,", TCC_OPTION_Wl, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "O", TCC_OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG },
{ "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "isystem", TCC_OPTION_isystem, TCC_OPTION_HAS_ARG },
{ "nostdinc", TCC_OPTION_nostdinc, 0 },
{ "nostdlib", TCC_OPTION_nostdlib, 0 },
{ "print-search-dirs", TCC_OPTION_print_search_dirs, 0 },
{ "v", TCC_OPTION_v, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "w", TCC_OPTION_w, 0 },
{ "pipe", TCC_OPTION_pipe, 0},
{ "E", TCC_OPTION_E, 0},
{ "MD", TCC_OPTION_MD, 0},
{ "MF", TCC_OPTION_MF, TCC_OPTION_HAS_ARG },
{ "x", TCC_OPTION_x, TCC_OPTION_HAS_ARG },
{ NULL, 0, 0 },
};
static void parse_option_D(TCCState *s1, const char *optarg)
{
char *sym = tcc_strdup(optarg);
char *value = strchr(sym, '=');
if (value)
*value++ = '\0';
tcc_define_symbol(s1, sym, value);
tcc_free(sym);
}
PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv)
{
const TCCOption *popt;
const char *optarg, *r;
int run = 0;
int pthread = 0;
int optind = 0;
/* collect -Wl options for input such as "-Wl,-rpath -Wl,<path>" */
CString linker_arg;
cstr_new(&linker_arg);
while (optind < argc) {
r = argv[optind++];
if (r[0] != '-' || r[1] == '\0') {
/* add a new file */
dynarray_add((void ***)&s->files, &s->nb_files, tcc_strdup(r));
if (run) {
optind--;
/* argv[0] will be this file */
break;
}
continue;
} }
if (multi) { /* find option in table */
option = NULL; for(popt = tcc_options; ; ++popt) {
p = strchr( (end) ? end : p, ','); const char *p1 = popt->name;
if (p) { const char *r1 = r + 1;
*p = 0; /* terminate last option */ if (p1 == NULL)
option = ++p; tcc_error("invalid option -- '%s'", r);
} if (!strstart(p1, &r1))
} else continue;
option = NULL; optarg = r1;
} if (popt->flags & TCC_OPTION_HAS_ARG) {
return NULL; if (*r1 == '\0' && !(popt->flags & TCC_OPTION_NOSEP)) {
} if (optind >= argc)
tcc_error("argument to '%s' is missing", r);
optarg = argv[optind++];
}
} else if (*r1 != '\0')
continue;
break;
}
/* set CONFIG_TCCDIR at runtime */ switch(popt->index) {
LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path) case TCC_OPTION_HELP:
{ return 0;
tcc_free(s->tcc_lib_path); case TCC_OPTION_I:
s->tcc_lib_path = tcc_strdup(path); if (tcc_add_include_path(s, optarg) < 0)
} tcc_error("too many include paths");
break;
PUB_FUNC char *tcc_default_target(TCCState *s, const char *default_file) case TCC_OPTION_D:
{ parse_option_D(s, optarg);
char buf[1024]; break;
char *ext; case TCC_OPTION_U:
const char *name = "a"; tcc_undefine_symbol(s, optarg);
break;
if (default_file && strcmp(default_file, "-")) case TCC_OPTION_L:
name = tcc_basename(default_file); tcc_add_library_path(s, optarg);
pstrcpy(buf, sizeof(buf), name); break;
ext = tcc_fileextension(buf); case TCC_OPTION_B:
#ifdef TCC_TARGET_PE /* set tcc utilities path (mainly for tcc development) */
if (s->output_type == TCC_OUTPUT_DLL) tcc_set_lib_path(s, optarg);
strcpy(ext, ".dll"); break;
else case TCC_OPTION_l:
if (s->output_type == TCC_OUTPUT_EXE) dynarray_add((void ***)&s->files, &s->nb_files, tcc_strdup(r));
strcpy(ext, ".exe"); s->nb_libraries++;
else break;
case TCC_OPTION_pthread:
parse_option_D(s, "_REENTRANT");
pthread = 1;
break;
case TCC_OPTION_bench:
s->do_bench = 1;
break;
#ifdef CONFIG_TCC_BACKTRACE
case TCC_OPTION_bt:
tcc_set_num_callers(atoi(optarg));
break;
#endif #endif
if (( (s->output_type == TCC_OUTPUT_OBJ && !s->reloc_output) || #ifdef CONFIG_TCC_BCHECK
(s->output_type == TCC_OUTPUT_PREPROCESS) ) case TCC_OPTION_b:
&& *ext) s->do_bounds_check = 1;
strcpy(ext, ".o"); s->do_debug = 1;
else break;
strcpy(buf, "a.out"); #endif
case TCC_OPTION_g:
return tcc_strdup(buf); s->do_debug = 1;
} break;
case TCC_OPTION_c:
s->output_type = TCC_OUTPUT_OBJ;
PUB_FUNC void tcc_gen_makedeps(TCCState *s, const char *target, const char *filename) break;
{ case TCC_OPTION_static:
FILE *depout; s->static_link = 1;
char buf[1024], *ext; break;
int i; case TCC_OPTION_shared:
s->output_type = TCC_OUTPUT_DLL;
if (!filename) { break;
/* compute filename automatically case TCC_OPTION_soname:
* dir/file.o -> dir/file.d */ s->soname = tcc_strdup(optarg);
pstrcpy(buf, sizeof(buf), target); break;
ext = tcc_fileextension(buf); case TCC_OPTION_m:
pstrcpy(ext, sizeof(buf) - (ext-buf), ".d"); s->option_m = tcc_strdup(optarg);
filename = buf; break;
case TCC_OPTION_o:
s->outfile = tcc_strdup(optarg);
break;
case TCC_OPTION_r:
/* generate a .o merging several output files */
s->option_r = 1;
s->output_type = TCC_OUTPUT_OBJ;
break;
case TCC_OPTION_isystem:
tcc_add_sysinclude_path(s, optarg);
break;
case TCC_OPTION_nostdinc:
s->nostdinc = 1;
break;
case TCC_OPTION_nostdlib:
s->nostdlib = 1;
break;
case TCC_OPTION_print_search_dirs:
s->print_search_dirs = 1;
break;
case TCC_OPTION_run:
s->output_type = TCC_OUTPUT_MEMORY;
tcc_set_options(s, optarg);
run = 1;
break;
case TCC_OPTION_v:
do ++s->verbose; while (*optarg++ == 'v');
break;
case TCC_OPTION_f:
if (tcc_set_flag(s, optarg, 1) < 0 && s->warn_unsupported)
goto unsupported_option;
break;
case TCC_OPTION_W:
if (tcc_set_warning(s, optarg, 1) < 0 &&
s->warn_unsupported)
goto unsupported_option;
break;
case TCC_OPTION_w:
s->warn_none = 1;
break;
case TCC_OPTION_rdynamic:
s->rdynamic = 1;
break;
case TCC_OPTION_Wl:
if (linker_arg.size)
--linker_arg.size, cstr_ccat(&linker_arg, ',');
cstr_cat(&linker_arg, optarg);
cstr_ccat(&linker_arg, '\0');
break;
case TCC_OPTION_E:
s->output_type = TCC_OUTPUT_PREPROCESS;
break;
case TCC_OPTION_MD:
s->gen_deps = 1;
break;
case TCC_OPTION_MF:
s->deps_outfile = tcc_strdup(optarg);
break;
case TCC_OPTION_O:
case TCC_OPTION_pedantic:
case TCC_OPTION_pipe:
case TCC_OPTION_s:
case TCC_OPTION_x:
/* ignored */
break;
default:
if (s->warn_unsupported) {
unsupported_option:
tcc_warning("unsupported option '%s'", r);
}
break;
}
} }
if (s->verbose) if (pthread && s->output_type != TCC_OUTPUT_OBJ)
printf("<- %s\n", filename); tcc_set_options(s, "-lpthread");
/* XXX return err codes instead of error() ? */ tcc_set_linker(s, (const char *)linker_arg.data);
depout = fopen(filename, "w"); cstr_free(&linker_arg);
if (!depout)
tcc_error("could not open '%s'", filename);
fprintf(depout, "%s : \\\n", target); return optind;
for (i=0; i<s->nb_target_deps; ++i) }
fprintf(depout, " %s \\\n", s->target_deps[i]);
fprintf(depout, "\n"); LIBTCCAPI int tcc_set_options(TCCState *s, const char *str)
fclose(depout); {
const char *s1;
char **argv, *arg;
int argc, len;
int ret;
argc = 0, argv = NULL;
for(;;) {
while (is_space(*str))
str++;
if (*str == '\0')
break;
s1 = str;
while (*str != '\0' && !is_space(*str))
str++;
len = str - s1;
arg = tcc_malloc(len + 1);
pstrncpy(arg, s1, len);
dynarray_add((void ***)&argv, &argc, arg);
}
ret = tcc_parse_args(s, argc, argv);
dynarray_reset(&argv, &argc);
return ret;
} }
PUB_FUNC void tcc_print_stats(TCCState *s, int64_t total_time) PUB_FUNC void tcc_print_stats(TCCState *s, int64_t total_time)
@ -1668,53 +1933,3 @@ PUB_FUNC void tcc_print_stats(TCCState *s, int64_t total_time)
tt, (int)(total_lines / tt), tt, (int)(total_lines / tt),
total_bytes / tt / 1000000.0); total_bytes / tt / 1000000.0);
} }
static void print_paths(const char *msg, char **paths, int nb_paths)
{
int i;
printf("%s:\n%s", msg, nb_paths ? "" : " -\n");
for(i = 0; i < nb_paths; i++)
printf(" %s\n", paths[i]);
}
PUB_FUNC void tcc_display_info(TCCState *s, int what)
{
switch (what) {
case 0:
printf("tcc version %s ("
#ifdef TCC_TARGET_I386
"i386"
# ifdef TCC_TARGET_PE
" Win32"
# endif
#elif defined TCC_TARGET_X86_64
"x86-64"
# ifdef TCC_TARGET_PE
" Win64"
# endif
#elif defined TCC_TARGET_ARM
"ARM"
# ifdef TCC_ARM_HARDFLOAT
" Hard Float"
# endif
# ifdef TCC_TARGET_PE
" WinCE"
# endif
#endif
#ifndef TCC_TARGET_PE
# ifdef __linux
" Linux"
# endif
#endif
")\n", TCC_VERSION);
break;
case 1:
printf("install: %s/\n", s->tcc_lib_path);
/* print_paths("programs", NULL, 0); */
print_paths("crt", s->crt_paths, s->nb_crt_paths);
print_paths("libraries", s->library_paths, s->nb_library_paths);
print_paths("include", s->sysinclude_paths, s->nb_sysinclude_paths);
break;
}
}

View File

@ -19,18 +19,15 @@ LIBTCCAPI TCCState *tcc_new(void);
/* free a TCC compilation context */ /* free a TCC compilation context */
LIBTCCAPI void tcc_delete(TCCState *s); LIBTCCAPI void tcc_delete(TCCState *s);
/* add debug information in the generated code */ /* set CONFIG_TCCDIR at runtime */
LIBTCCAPI void tcc_enable_debug(TCCState *s); LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path);
/* set error/warning display callback */ /* set error/warning display callback */
LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque,
void (*error_func)(void *opaque, const char *msg)); void (*error_func)(void *opaque, const char *msg));
/* set/reset a warning */ /* set options as from command line (multiple supported) */
LIBTCCAPI int tcc_set_warning(TCCState *s, const char *warning_name, int value); LIBTCCAPI int tcc_set_options(TCCState *s, const char *str);
/* set linker option */
LIBTCCAPI const char * tcc_set_linker(TCCState *s, char *option, int multi);
/*****************************/ /*****************************/
/* preprocessor */ /* preprocessor */
@ -50,29 +47,22 @@ LIBTCCAPI void tcc_undefine_symbol(TCCState *s, const char *sym);
/*****************************/ /*****************************/
/* compiling */ /* compiling */
/* add a file (either a C file, dll, an object, a library or an ld /* add a file (C file, dll, object, library, ld script). Return -1 if error. */
script). Return -1 if error. */
LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename); LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename);
/* compile a string containing a C source. Return non zero if /* compile a string containing a C source. Return -1 if error. */
error. */
LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf); LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf);
/*****************************/ /*****************************/
/* linking commands */ /* linking commands */
/* set output type. MUST BE CALLED before any compilation */ /* set output type. MUST BE CALLED before any compilation */
#define TCC_OUTPUT_MEMORY 0 /* output will be ran in memory (no LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type);
output file) (default) */ #define TCC_OUTPUT_MEMORY 0 /* output will be run in memory (default) */
#define TCC_OUTPUT_EXE 1 /* executable file */ #define TCC_OUTPUT_EXE 1 /* executable file */
#define TCC_OUTPUT_DLL 2 /* dynamic library */ #define TCC_OUTPUT_DLL 2 /* dynamic library */
#define TCC_OUTPUT_OBJ 3 /* object file */ #define TCC_OUTPUT_OBJ 3 /* object file */
#define TCC_OUTPUT_PREPROCESS 4 /* preprocessed file (used internally) */ #define TCC_OUTPUT_PREPROCESS 4 /* only preprocess (used internally) */
LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type);
#define TCC_OUTPUT_FORMAT_ELF 0 /* default output format: ELF */
#define TCC_OUTPUT_FORMAT_BINARY 1 /* binary image output */
#define TCC_OUTPUT_FORMAT_COFF 2 /* COFF */
/* equivalent to -Lpath option */ /* equivalent to -Lpath option */
LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname); LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname);
@ -91,21 +81,18 @@ LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename);
tcc_relocate() before. */ tcc_relocate() before. */
LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv); LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv);
/* do all relocations (needed before using tcc_get_symbol()) /* do all relocations (needed before using tcc_get_symbol()) */
possible values for 'ptr': LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr);
/* possible values for 'ptr':
- TCC_RELOCATE_AUTO : Allocate and manage memory internally - TCC_RELOCATE_AUTO : Allocate and manage memory internally
- NULL : return required memory size for the step below - NULL : return required memory size for the step below
- memory address : copy code to memory passed by the caller - memory address : copy code to memory passed by the caller
returns -1 on error. */ returns -1 if error. */
LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr);
#define TCC_RELOCATE_AUTO (void*)1 #define TCC_RELOCATE_AUTO (void*)1
/* return symbol value or NULL if not found */ /* return symbol value or NULL if not found */
LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name); LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name);
/* set CONFIG_TCCDIR at runtime */
LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

610
tcc.c
View File

@ -24,22 +24,6 @@
#include "tcc.h" #include "tcc.h"
#endif #endif
static char **files;
static int nb_files, nb_libraries;
static int multiple_files;
static int print_search_dirs;
static int output_type;
static int reloc_output;
static char *outfile;
static int do_bench = 0;
static int gen_deps;
static const char *deps_outfile;
static const char *m_option;
static CString linker_arg;
#define TCC_OPTION_HAS_ARG 0x0001
#define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */
static void help(void) static void help(void)
{ {
printf("tcc version " TCC_VERSION " - Tiny C Compiler - Copyright (C) 2001-2006 Fabrice Bellard\n" printf("tcc version " TCC_VERSION " - Tiny C Compiler - Copyright (C) 2001-2006 Fabrice Bellard\n"
@ -60,19 +44,16 @@ static void help(void)
" -Idir add include path 'dir'\n" " -Idir add include path 'dir'\n"
" -Dsym[=val] define 'sym' with value 'val'\n" " -Dsym[=val] define 'sym' with value 'val'\n"
" -Usym undefine 'sym'\n" " -Usym undefine 'sym'\n"
" -nostdinc do not use standard system include paths\n"
"Linker options:\n" "Linker options:\n"
" -Ldir add library path 'dir'\n" " -Ldir add library path 'dir'\n"
" -llib link with dynamic or static library 'lib'\n" " -llib link with dynamic or static library 'lib'\n"
" -Bdir use 'dir' as tcc internal library and include path\n"
" -nostdlib do not link with standard crt and libraries\n"
" -pthread link with -lpthread and -D_REENTRANT (POSIX Linux)\n" " -pthread link with -lpthread and -D_REENTRANT (POSIX Linux)\n"
" -r generate (relocatable) object file\n" " -r generate (relocatable) object file\n"
" -rdynamic export all global symbols to dynamic linker\n" " -rdynamic export all global symbols to dynamic linker\n"
" -shared generate a shared library\n" " -shared generate a shared library\n"
" -soname set name for shared library to be used at runtime\n" " -soname set name for shared library to be used at runtime\n"
" -static static linking\n" " -static static linking\n"
" -Wl,opt[=val] set linker option 'opt' (see manual)\n" " -Wl,-opt[=val] set linker option (see manual)\n"
"Debugger options:\n" "Debugger options:\n"
" -g generate runtime debug info\n" " -g generate runtime debug info\n"
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
@ -82,146 +63,14 @@ static void help(void)
" -bt N show N callers in stack traces\n" " -bt N show N callers in stack traces\n"
#endif #endif
"Misc options:\n" "Misc options:\n"
" -nostdinc do not use standard system include paths\n"
" -nostdlib do not link with standard crt and libraries\n"
" -Bdir use 'dir' as tcc internal library and include path\n"
" -MD generate target dependencies for make\n" " -MD generate target dependencies for make\n"
" -MF depfile put generated dependencies here\n" " -MF depfile put generated dependencies here\n"
); );
} }
typedef struct TCCOption {
const char *name;
uint16_t index;
uint16_t flags;
} TCCOption;
enum {
TCC_OPTION_HELP,
TCC_OPTION_I,
TCC_OPTION_D,
TCC_OPTION_U,
TCC_OPTION_L,
TCC_OPTION_B,
TCC_OPTION_l,
TCC_OPTION_bench,
TCC_OPTION_bt,
TCC_OPTION_b,
TCC_OPTION_g,
TCC_OPTION_c,
TCC_OPTION_static,
TCC_OPTION_shared,
TCC_OPTION_soname,
TCC_OPTION_o,
TCC_OPTION_r,
TCC_OPTION_s,
TCC_OPTION_Wl,
TCC_OPTION_W,
TCC_OPTION_O,
TCC_OPTION_m,
TCC_OPTION_f,
TCC_OPTION_isystem,
TCC_OPTION_nostdinc,
TCC_OPTION_nostdlib,
TCC_OPTION_print_search_dirs,
TCC_OPTION_rdynamic,
TCC_OPTION_pedantic,
TCC_OPTION_pthread,
TCC_OPTION_run,
TCC_OPTION_v,
TCC_OPTION_w,
TCC_OPTION_pipe,
TCC_OPTION_E,
TCC_OPTION_MD,
TCC_OPTION_MF,
TCC_OPTION_x,
};
static const TCCOption tcc_options[] = {
{ "h", TCC_OPTION_HELP, 0 },
{ "-help", TCC_OPTION_HELP, 0 },
{ "?", TCC_OPTION_HELP, 0 },
{ "I", TCC_OPTION_I, TCC_OPTION_HAS_ARG },
{ "D", TCC_OPTION_D, TCC_OPTION_HAS_ARG },
{ "U", TCC_OPTION_U, TCC_OPTION_HAS_ARG },
{ "L", TCC_OPTION_L, TCC_OPTION_HAS_ARG },
{ "B", TCC_OPTION_B, TCC_OPTION_HAS_ARG },
{ "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "bench", TCC_OPTION_bench, 0 },
#ifdef CONFIG_TCC_BACKTRACE
{ "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG },
#endif
#ifdef CONFIG_TCC_BCHECK
{ "b", TCC_OPTION_b, 0 },
#endif
{ "g", TCC_OPTION_g, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "c", TCC_OPTION_c, 0 },
{ "static", TCC_OPTION_static, 0 },
{ "shared", TCC_OPTION_shared, 0 },
{ "soname", TCC_OPTION_soname, TCC_OPTION_HAS_ARG },
{ "o", TCC_OPTION_o, TCC_OPTION_HAS_ARG },
{ "pedantic", TCC_OPTION_pedantic, 0},
{ "pthread", TCC_OPTION_pthread, 0},
{ "run", TCC_OPTION_run, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "rdynamic", TCC_OPTION_rdynamic, 0 },
{ "r", TCC_OPTION_r, 0 },
{ "s", TCC_OPTION_s, 0 },
{ "Wl,", TCC_OPTION_Wl, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "O", TCC_OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG },
{ "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "isystem", TCC_OPTION_isystem, TCC_OPTION_HAS_ARG },
{ "nostdinc", TCC_OPTION_nostdinc, 0 },
{ "nostdlib", TCC_OPTION_nostdlib, 0 },
{ "print-search-dirs", TCC_OPTION_print_search_dirs, 0 },
{ "v", TCC_OPTION_v, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "w", TCC_OPTION_w, 0 },
{ "pipe", TCC_OPTION_pipe, 0},
{ "E", TCC_OPTION_E, 0},
{ "MD", TCC_OPTION_MD, 0},
{ "MF", TCC_OPTION_MF, TCC_OPTION_HAS_ARG },
{ "x", TCC_OPTION_x, TCC_OPTION_HAS_ARG },
{ NULL, 0, 0 },
};
static int64_t getclock_us(void)
{
#ifdef _WIN32
struct _timeb tb;
_ftime(&tb);
return (tb.time * 1000LL + tb.millitm) * 1000LL;
#else
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000000LL + tv.tv_usec;
#endif
}
/* convert 'str' into an array of space separated strings */
static int expand_args(char ***pargv, const char *str)
{
const char *s1;
char **argv, *arg;
int argc, len;
argc = 0;
argv = NULL;
for(;;) {
while (is_space(*str))
str++;
if (*str == '\0')
break;
s1 = str;
while (*str != '\0' && !is_space(*str))
str++;
len = str - s1;
arg = tcc_malloc(len + 1);
memcpy(arg, s1, len);
arg[len] = '\0';
dynarray_add((void ***)&argv, &argc, arg);
}
*pargv = argv;
return argc;
}
/* re-execute the i386/x86_64 cross-compilers with tcc -m32/-m64: */ /* re-execute the i386/x86_64 cross-compilers with tcc -m32/-m64: */
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
#ifdef _WIN32 #ifdef _WIN32
@ -266,317 +115,198 @@ static void exec_other_tcc(TCCState *s, char **argv, const char *optarg)
tcc_warning("unsupported option \"-m%s\"", optarg); tcc_warning("unsupported option \"-m%s\"", optarg);
} }
} }
#else
#define exec_other_tcc(s, argv, optarg)
#endif #endif
static void parse_option_D(TCCState *s1, const char *optarg) static void gen_makedeps(TCCState *s, const char *target, const char *filename)
{ {
char *sym = tcc_strdup(optarg); FILE *depout;
char *value = strchr(sym, '='); char buf[1024], *ext;
if (value) int i;
*value++ = '\0';
tcc_define_symbol(s1, sym, value); if (!filename) {
tcc_free(sym); /* compute filename automatically
* dir/file.o -> dir/file.d */
pstrcpy(buf, sizeof(buf), target);
ext = tcc_fileextension(buf);
pstrcpy(ext, sizeof(buf) - (ext-buf), ".d");
filename = buf;
}
if (s->verbose)
printf("<- %s\n", filename);
/* XXX return err codes instead of error() ? */
depout = fopen(filename, "w");
if (!depout)
tcc_error("could not open '%s'", filename);
fprintf(depout, "%s : \\\n", target);
for (i=0; i<s->nb_target_deps; ++i)
fprintf(depout, " %s \\\n", s->target_deps[i]);
fprintf(depout, "\n");
fclose(depout);
} }
static int parse_args(TCCState *s, int argc, char **argv) static char *default_outputfile(TCCState *s, const char *first_file)
{ {
int optind; char buf[1024];
const TCCOption *popt; char *ext;
const char *optarg, *p1, *r1; const char *name = "a";
char *r;
int was_pthread;
was_pthread = 0; /* is set if commandline contains -pthread key */ if (first_file && strcmp(first_file, "-"))
optind = 0; name = tcc_basename(first_file);
cstr_new(&linker_arg); pstrcpy(buf, sizeof(buf), name);
ext = tcc_fileextension(buf);
while (optind < argc) { #ifdef TCC_TARGET_PE
if (s->output_type == TCC_OUTPUT_DLL)
r = argv[optind++]; strcpy(ext, ".dll");
if (r[0] != '-' || r[1] == '\0') { else
/* add a new file */ if (s->output_type == TCC_OUTPUT_EXE)
dynarray_add((void ***)&files, &nb_files, r); strcpy(ext, ".exe");
if (!multiple_files) { else
optind--;
/* argv[0] will be this file */
break;
}
} else {
/* find option in table (match only the first chars */
popt = tcc_options;
for(;;) {
p1 = popt->name;
if (p1 == NULL)
tcc_error("invalid option -- '%s'", r);
r1 = r + 1;
for(;;) {
if (*p1 == '\0')
goto option_found;
if (*r1 != *p1)
break;
p1++;
r1++;
}
popt++;
}
option_found:
if (popt->flags & TCC_OPTION_HAS_ARG) {
if (*r1 != '\0' || (popt->flags & TCC_OPTION_NOSEP)) {
optarg = r1;
} else {
if (optind >= argc)
tcc_error("argument to '%s' is missing", r);
optarg = argv[optind++];
}
} else {
if (*r1 != '\0')
return 0;
optarg = NULL;
}
switch(popt->index) {
case TCC_OPTION_HELP:
return 0;
case TCC_OPTION_I:
if (tcc_add_include_path(s, optarg) < 0)
tcc_error("too many include paths");
break;
case TCC_OPTION_D:
parse_option_D(s, optarg);
break;
case TCC_OPTION_U:
tcc_undefine_symbol(s, optarg);
break;
case TCC_OPTION_L:
tcc_add_library_path(s, optarg);
break;
case TCC_OPTION_B:
/* set tcc utilities path (mainly for tcc development) */
tcc_set_lib_path(s, optarg);
break;
case TCC_OPTION_l:
dynarray_add((void ***)&files, &nb_files, r);
nb_libraries++;
break;
case TCC_OPTION_pthread:
was_pthread = 1;
parse_option_D(s, "_REENTRANT");
break;
case TCC_OPTION_bench:
do_bench = 1;
break;
#ifdef CONFIG_TCC_BACKTRACE
case TCC_OPTION_bt:
tcc_set_num_callers(atoi(optarg));
break;
#endif #endif
#ifdef CONFIG_TCC_BCHECK if (( (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) ||
case TCC_OPTION_b: (s->output_type == TCC_OUTPUT_PREPROCESS) )
s->do_bounds_check = 1; && *ext)
s->do_debug = 1; strcpy(ext, ".o");
break; else
strcpy(buf, "a.out");
return tcc_strdup(buf);
}
static void print_paths(const char *msg, char **paths, int nb_paths)
{
int i;
printf("%s:\n%s", msg, nb_paths ? "" : " -\n");
for(i = 0; i < nb_paths; i++)
printf(" %s\n", paths[i]);
}
static void display_info(TCCState *s, int what)
{
switch (what) {
case 0:
printf("tcc version %s ("
#ifdef TCC_TARGET_I386
"i386"
# ifdef TCC_TARGET_PE
" Win32"
# endif
#elif defined TCC_TARGET_X86_64
"x86-64"
# ifdef TCC_TARGET_PE
" Win64"
# endif
#elif defined TCC_TARGET_ARM
"ARM"
# ifdef TCC_ARM_HARDFLOAT
" Hard Float"
# endif
# ifdef TCC_TARGET_PE
" WinCE"
# endif
#endif #endif
case TCC_OPTION_g: #ifndef TCC_TARGET_PE
s->do_debug = 1; # ifdef __linux
break; " Linux"
case TCC_OPTION_c: # endif
multiple_files = 1; #endif
output_type = TCC_OUTPUT_OBJ; ")\n", TCC_VERSION);
break; break;
case TCC_OPTION_static: case 1:
s->static_link = 1; printf("install: %s/\n", s->tcc_lib_path);
break; /* print_paths("programs", NULL, 0); */
case TCC_OPTION_shared: print_paths("crt", s->crt_paths, s->nb_crt_paths);
output_type = TCC_OUTPUT_DLL; print_paths("libraries", s->library_paths, s->nb_library_paths);
break; print_paths("include", s->sysinclude_paths, s->nb_sysinclude_paths);
case TCC_OPTION_soname: break;
s->soname = optarg;
break;
case TCC_OPTION_m:
m_option = optarg;
break;
case TCC_OPTION_o:
multiple_files = 1;
outfile = tcc_strdup(optarg);
break;
case TCC_OPTION_r:
/* generate a .o merging several output files */
reloc_output = 1;
output_type = TCC_OUTPUT_OBJ;
break;
case TCC_OPTION_isystem:
tcc_add_sysinclude_path(s, optarg);
break;
case TCC_OPTION_nostdinc:
s->nostdinc = 1;
break;
case TCC_OPTION_nostdlib:
s->nostdlib = 1;
break;
case TCC_OPTION_print_search_dirs:
print_search_dirs = 1;
break;
case TCC_OPTION_run:
{
int argc1;
char **argv1;
argc1 = expand_args(&argv1, optarg);
if (argc1 > 0) {
parse_args(s, argc1, argv1);
}
multiple_files = 0;
output_type = TCC_OUTPUT_MEMORY;
break;
}
case TCC_OPTION_v:
do ++s->verbose; while (*optarg++ == 'v');
break;
case TCC_OPTION_f:
if (tcc_set_flag(s, optarg, 1) < 0 && s->warn_unsupported)
goto unsupported_option;
break;
case TCC_OPTION_W:
if (tcc_set_warning(s, optarg, 1) < 0 &&
s->warn_unsupported)
goto unsupported_option;
break;
case TCC_OPTION_w:
s->warn_none = 1;
break;
case TCC_OPTION_rdynamic:
s->rdynamic = 1;
break;
case TCC_OPTION_Wl:
if (linker_arg.size)
--linker_arg.size, cstr_ccat(&linker_arg, ',');
cstr_cat(&linker_arg, optarg);
cstr_ccat(&linker_arg, '\0');
break;
case TCC_OPTION_E:
output_type = TCC_OUTPUT_PREPROCESS;
break;
case TCC_OPTION_MD:
gen_deps = 1;
break;
case TCC_OPTION_MF:
deps_outfile = optarg;
break;
case TCC_OPTION_O:
case TCC_OPTION_pedantic:
case TCC_OPTION_pipe:
case TCC_OPTION_s:
case TCC_OPTION_x:
/* ignored */
break;
default:
if (s->warn_unsupported) {
unsupported_option:
tcc_warning("unsupported option '%s'", r);
}
break;
}
}
} }
if (NULL != (r1 = tcc_set_linker(s, (char *) linker_arg.data, 1))) }
tcc_error("unsupported linker option '%s'", r1);
/* fixme: these options could be different on your platform */ static int64_t getclock_us(void)
if (was_pthread && output_type != TCC_OUTPUT_OBJ) { {
dynarray_add((void ***)&files, &nb_files, "-lpthread"); #ifdef _WIN32
nb_libraries++; struct _timeb tb;
} _ftime(&tb);
return optind; return (tb.time * 1000LL + tb.millitm) * 1000LL;
#else
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000000LL + tv.tv_usec;
#endif
} }
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int i;
TCCState *s; TCCState *s;
int nb_objfiles, ret, optind; int ret, optind, i, bench;
int64_t start_time = 0; int64_t start_time = 0;
const char *default_file = NULL; const char *first_file = NULL;
s = tcc_new(); s = tcc_new();
s->output_type = TCC_OUTPUT_EXE;
output_type = TCC_OUTPUT_EXE; optind = tcc_parse_args(s, argc - 1, argv + 1);
outfile = NULL;
multiple_files = 1;
files = NULL;
nb_files = 0;
nb_libraries = 0;
reloc_output = 0;
print_search_dirs = 0;
m_option = NULL;
ret = 0;
optind = parse_args(s, argc - 1, argv + 1); if (optind == 0) {
#if defined TCC_TARGET_X86_64 || defined TCC_TARGET_I386
if (m_option)
exec_other_tcc(s, argv, m_option);
#endif
if (print_search_dirs) {
psd:
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
tcc_display_info(s, 1);
return 0;
}
if (s->verbose)
tcc_display_info(s, 0);
if (optind == 0 || nb_files == 0) {
if (optind && s->verbose) {
if (s->verbose == 2)
goto psd;
return 0;
}
help(); help();
return 1; return 1;
} }
nb_objfiles = nb_files - nb_libraries; if (s->option_m)
exec_other_tcc(s, argv, s->option_m);
/* if outfile provided without other options, we output an if (s->verbose)
executable */ display_info(s, 0);
if (outfile && output_type == TCC_OUTPUT_MEMORY)
output_type = TCC_OUTPUT_EXE; if (s->print_search_dirs || (s->verbose == 2 && optind == 1)) {
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
display_info(s, 1);
return 0;
}
if (s->verbose && optind == 1)
return 0;
if (s->nb_files == 0)
tcc_error("no input files\n");
/* check -c consistency : only single file handled. XXX: checks file type */ /* check -c consistency : only single file handled. XXX: checks file type */
if (output_type == TCC_OUTPUT_OBJ && !reloc_output) { if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) {
/* accepts only a single input file */ if (s->nb_libraries != 0)
if (nb_objfiles != 1)
tcc_error("cannot specify multiple files with -c");
if (nb_libraries != 0)
tcc_error("cannot specify libraries with -c"); tcc_error("cannot specify libraries with -c");
/* accepts only a single input file */
if (s->nb_files != 1)
tcc_error("cannot specify multiple files with -c");
} }
if (output_type == TCC_OUTPUT_PREPROCESS) { if (s->output_type == TCC_OUTPUT_PREPROCESS) {
if (!outfile) { if (!s->outfile) {
s->outfile = stdout; s->ppfp = stdout;
} else { } else {
s->outfile = fopen(outfile, "w"); s->ppfp = fopen(s->outfile, "w");
if (!s->outfile) if (!s->ppfp)
tcc_error("could not open '%s'", outfile); tcc_error("could not write '%s'", s->outfile);
} }
} }
if (do_bench) { bench = s->do_bench;
if (bench)
start_time = getclock_us(); start_time = getclock_us();
}
tcc_set_output_type(s, output_type); tcc_set_output_type(s, s->output_type);
s->reloc_output = reloc_output;
/* compile or add each files or library */ /* compile or add each files or library */
for(i = 0; i < nb_files && ret == 0; i++) { for(i = ret = 0; i < s->nb_files && ret == 0; i++) {
const char *filename; const char *filename;
filename = files[i]; filename = s->files[i];
if (filename[0] == '-' && filename[1] == 'l') { if (filename[0] == '-' && filename[1] == 'l') {
if (tcc_add_library(s, filename + 2) < 0) { if (tcc_add_library(s, filename + 2) < 0) {
tcc_error_noabort("cannot find %s", filename); tcc_error_noabort("cannot find '%s'", filename);
ret = 1; ret = 1;
} }
} else { } else {
@ -584,16 +314,13 @@ psd:
printf("-> %s\n", filename); printf("-> %s\n", filename);
if (tcc_add_file(s, filename) < 0) if (tcc_add_file(s, filename) < 0)
ret = 1; ret = 1;
if (!default_file) if (!first_file)
default_file = filename; first_file = filename;
} }
} }
/* free all files */
tcc_free(files);
if (0 == ret) { if (0 == ret) {
if (do_bench) if (bench)
tcc_print_stats(s, getclock_us() - start_time); tcc_print_stats(s, getclock_us() - start_time);
if (s->output_type == TCC_OUTPUT_MEMORY) { if (s->output_type == TCC_OUTPUT_MEMORY) {
@ -601,28 +328,23 @@ psd:
ret = tcc_run(s, argc - 1 - optind, argv + 1 + optind); ret = tcc_run(s, argc - 1 - optind, argv + 1 + optind);
#else #else
tcc_error_noabort("-run is not available in a cross compiler"); tcc_error_noabort("-run is not available in a cross compiler");
ret = 1;
#endif #endif
} else if (s->output_type == TCC_OUTPUT_PREPROCESS) { } else if (s->output_type == TCC_OUTPUT_PREPROCESS) {
if (s->outfile) if (s->outfile)
fclose(s->outfile); fclose(s->ppfp);
} else { } else {
if (!outfile) if (!s->outfile)
outfile = tcc_default_target(s, default_file); s->outfile = default_outputfile(s, first_file);
ret = !!tcc_output_file(s, outfile); ret = !!tcc_output_file(s, s->outfile);
/* dump collected dependencies */ /* dump collected dependencies */
if (gen_deps && !ret) if (s->gen_deps && !ret)
tcc_gen_makedeps(s, outfile, deps_outfile); gen_makedeps(s, s->outfile, s->deps_outfile);
} }
} }
tcc_delete(s); tcc_delete(s);
cstr_free(&linker_arg); if (bench)
tcc_free(outfile); tcc_memstats();
#ifdef MEM_DEBUG
if (do_bench) {
printf("memory: %d bytes, max = %d bytes\n", mem_cur_size, mem_max_size);
}
#endif
return ret; return ret;
} }

354
tcc.h
View File

@ -25,10 +25,8 @@
#include "config.h" #include "config.h"
#ifdef CONFIG_TCCBOOT #ifdef CONFIG_TCCBOOT
#include "tccboot.h" #include "tccboot.h"
#define CONFIG_TCC_STATIC #define CONFIG_TCC_STATIC
#else #else
#include <stdlib.h> #include <stdlib.h>
@ -70,16 +68,8 @@
#endif /* !CONFIG_TCCBOOT */ #endif /* !CONFIG_TCCBOOT */
#ifndef PAGESIZE
#define PAGESIZE 4096
#endif
#ifndef O_BINARY #ifndef O_BINARY
#define O_BINARY 0 # define O_BINARY 0
#endif
#ifndef SA_SIGINFO
#define SA_SIGINFO 0x00000004u
#endif #endif
#include "elf.h" #include "elf.h"
@ -516,29 +506,108 @@ struct sym_attr {
}; };
struct TCCState { struct TCCState {
unsigned output_type : 8;
unsigned reloc_output : 1;
BufferedFile **include_stack_ptr;
int *ifdef_stack_ptr;
/* include file handling */ int verbose; /* if true, display some information during compilation */
int nostdinc; /* if true, no standard headers are added */
int nostdlib; /* if true, no standard libraries are added */
int nocommon; /* if true, do not use common symbols for .bss data */
int static_link; /* if true, static linking is performed */
int rdynamic; /* if true, all symbols are exported */
int symbolic; /* if true, resolve symbols in the current module first */
int alacarte_link; /* if true, only link in referenced objects from archive */
char *tcc_lib_path; /* CONFIG_TCCDIR or -B option */
char *soname; /* as specified on the command line (-soname) */
char *rpath; /* as specified on the command line (-Wl,-rpath=) */
/* output type, see TCC_OUTPUT_XXX */
int output_type;
/* output format, see TCC_OUTPUT_FORMAT_xxx */
int output_format;
/* C language options */
int char_is_unsigned;
int leading_underscore;
/* warning switches */
int warn_write_strings;
int warn_unsupported;
int warn_error;
int warn_none;
int warn_implicit_function_declaration;
/* compile with debug symbol (and use them if error during execution) */
int do_debug;
#ifdef CONFIG_TCC_BCHECK
/* compile with built-in memory and bounds checker */
int do_bounds_check;
#endif
addr_t text_addr; /* address of text section */
int has_text_addr;
unsigned long section_align; /* section alignment */
char *init_symbol; /* symbols to call at load-time (not used currently) */
char *fini_symbol; /* symbols to call at unload-time (not used currently) */
#ifdef TCC_TARGET_I386
int seg_size; /* 32. Can be 16 with i386 assembler (.code16) */
#endif
/* array of all loaded dlls (including those referenced by loaded dlls) */
DLLReference **loaded_dlls;
int nb_loaded_dlls;
/* include paths */
char **include_paths; char **include_paths;
int nb_include_paths; int nb_include_paths;
char **sysinclude_paths; char **sysinclude_paths;
int nb_sysinclude_paths; int nb_sysinclude_paths;
CachedInclude **cached_includes;
int nb_cached_includes;
/* library paths */
char **library_paths; char **library_paths;
int nb_library_paths; int nb_library_paths;
/* crt?.o object path */
char **crt_paths; char **crt_paths;
int nb_crt_paths; int nb_crt_paths;
/* array of all loaded dlls (including those referenced by loaded /* error handling */
dlls) */ void *error_opaque;
DLLReference **loaded_dlls; void (*error_func)(void *opaque, const char *msg);
int nb_loaded_dlls; int error_set_jmp_enabled;
jmp_buf error_jmp_buf;
int nb_errors;
/* output file for preprocessing (-E) */
FILE *ppfp;
/* for -MD/-MF: collected dependencies for this compilation */
char **target_deps;
int nb_target_deps;
/* compilation */
BufferedFile *include_stack[INCLUDE_STACK_SIZE];
BufferedFile **include_stack_ptr;
int ifdef_stack[IFDEF_STACK_SIZE];
int *ifdef_stack_ptr;
/* included files enclosed with #ifndef MACRO */
int cached_includes_hash[CACHED_INCLUDES_HASH_SIZE];
CachedInclude **cached_includes;
int nb_cached_includes;
/* #pragma pack stack */
int pack_stack[PACK_STACK_SIZE];
int *pack_stack_ptr;
/* inline functions are stored as token lists and compiled last
only if referenced */
struct InlineFunc **inline_fns;
int nb_inline_fns;
/* sections */ /* sections */
Section **sections; Section **sections;
@ -559,137 +628,54 @@ struct TCCState {
Section *dynsymtab_section; Section *dynsymtab_section;
/* exported dynamic symbol section */ /* exported dynamic symbol section */
Section *dynsym; Section *dynsym;
/* copy of the gobal symtab_section variable */ /* copy of the gobal symtab_section variable */
Section *symtab; Section *symtab;
int nostdinc; /* if true, no standard headers are added */
int nostdlib; /* if true, no standard libraries are added */
int nocommon; /* if true, do not use common symbols for .bss data */
/* if true, static linking is performed */
int static_link;
/* soname as specified on the command line (-soname) */
const char *soname;
/* rpath as specified on the command line (-Wl,-rpath=) */
const char *rpath;
/* if true, all symbols are exported */
int rdynamic;
/* if true, resolve symbols in the current module first (-Wl,Bsymbolic) */
int symbolic;
/* if true, only link in referenced objects from archive */
int alacarte_link;
/* address of text section */
addr_t text_addr;
int has_text_addr;
/* symbols to call at load-time / unload-time */
const char *init_symbol;
const char *fini_symbol;
/* output format, see TCC_OUTPUT_FORMAT_xxx */
int output_format;
/* C language options */
int char_is_unsigned;
int leading_underscore;
/* warning switches */
int warn_write_strings;
int warn_unsupported;
int warn_error;
int warn_none;
int warn_implicit_function_declaration;
/* display some information during compilation */
int verbose;
/* compile with debug symbol (and use them if error during execution) */
int do_debug;
#ifdef CONFIG_TCC_BCHECK
/* compile with built-in memory and bounds checker */
int do_bounds_check;
#endif
/* give the path of the tcc libraries */
char *tcc_lib_path;
/* 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 */ /* tiny assembler state */
Sym *asm_labels; Sym *asm_labels;
/* see include_stack_ptr */
BufferedFile *include_stack[INCLUDE_STACK_SIZE];
/* see ifdef_stack_ptr */
int ifdef_stack[IFDEF_STACK_SIZE];
/* see cached_includes */
int cached_includes_hash[CACHED_INCLUDES_HASH_SIZE];
/* pack stack */
int pack_stack[PACK_STACK_SIZE];
int *pack_stack_ptr;
/* output file for preprocessing */
FILE *outfile;
/* automatically collected dependencies for this compilation */
char **target_deps;
int nb_target_deps;
/* for tcc_relocate */
int runtime_added;
void *runtime_mem;
#ifdef HAVE_SELINUX
void *write_mem;
unsigned long mem_size;
#endif
struct InlineFunc **inline_fns;
int nb_inline_fns;
#ifdef TCC_TARGET_I386
int seg_size;
#endif
/* section alignment */
unsigned long section_align;
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
/* PE info */ /* PE info */
int pe_subsystem; int pe_subsystem;
unsigned long pe_file_align; unsigned pe_file_align;
unsigned long pe_stack_size; unsigned pe_stack_size;
#ifdef TCC_TARGET_X86_64 # ifdef TCC_TARGET_X86_64
Section *uw_pdata; Section *uw_pdata;
int uw_sym; int uw_sym;
unsigned uw_offs; unsigned uw_offs;
#endif # endif
#endif #endif
#if defined TCC_IS_NATIVE && !defined TCC_TARGET_PE \ #ifdef TCC_IS_NATIVE
&& (defined TCC_TARGET_X86_64 || defined TCC_TARGET_ARM) /* for tcc_relocate */
void *runtime_mem;
# ifdef HAVE_SELINUX
void *write_mem;
unsigned long mem_size;
# endif
# if !defined TCC_TARGET_PE && (defined TCC_TARGET_X86_64 || defined TCC_TARGET_ARM)
/* write PLT and GOT here */ /* write PLT and GOT here */
char *runtime_plt_and_got; char *runtime_plt_and_got;
unsigned int runtime_plt_and_got_offset; unsigned runtime_plt_and_got_offset;
# define TCC_HAS_RUNTIME_PLTGOT # define TCC_HAS_RUNTIME_PLTGOT
# endif
#endif #endif
/* used by main and tcc_parse_args only */
char **files; /* files seen on command line */
int nb_files; /* number thereof */
int nb_libraries; /* number of libs thereof */
char *outfile; /* output filename */
char *option_m; /* only -m32/-m64 handled */
int print_search_dirs; /* option */
int option_r; /* option -r */
int do_bench; /* option -bench */
int gen_deps; /* option -MD */
char *deps_outfile; /* option -MF */
}; };
/* The current value can be: */ /* The current value can be: */
#define VT_VALMASK 0x003f #define VT_VALMASK 0x003f /* mask for value location, register or: */
#define VT_CONST 0x0030 /* constant in vc #define VT_CONST 0x0030 /* constant in vc (must be first non register value) */
(must be first non register value) */
#define VT_LLOCAL 0x0031 /* lvalue, offset on stack */ #define VT_LLOCAL 0x0031 /* lvalue, offset on stack */
#define VT_LOCAL 0x0032 /* offset on stack */ #define VT_LOCAL 0x0032 /* offset on stack */
#define VT_CMP 0x0033 /* the value is stored in processor flags (in vc) */ #define VT_CMP 0x0033 /* the value is stored in processor flags (in vc) */
@ -710,29 +696,29 @@ struct TCCState {
#define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED) #define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED)
/* types */ /* types */
#define VT_INT 0 /* integer type */ #define VT_BTYPE 0x000f /* mask for basic type */
#define VT_BYTE 1 /* signed byte type */ #define VT_INT 0 /* integer type */
#define VT_SHORT 2 /* short type */ #define VT_BYTE 1 /* signed byte type */
#define VT_VOID 3 /* void type */ #define VT_SHORT 2 /* short type */
#define VT_PTR 4 /* pointer */ #define VT_VOID 3 /* void type */
#define VT_ENUM 5 /* enum definition */ #define VT_PTR 4 /* pointer */
#define VT_FUNC 6 /* function type */ #define VT_ENUM 5 /* enum definition */
#define VT_STRUCT 7 /* struct/union definition */ #define VT_FUNC 6 /* function type */
#define VT_FLOAT 8 /* IEEE float */ #define VT_STRUCT 7 /* struct/union definition */
#define VT_DOUBLE 9 /* IEEE double */ #define VT_FLOAT 8 /* IEEE float */
#define VT_LDOUBLE 10 /* IEEE long double */ #define VT_DOUBLE 9 /* IEEE double */
#define VT_BOOL 11 /* ISOC99 boolean type */ #define VT_LDOUBLE 10 /* IEEE long double */
#define VT_LLONG 12 /* 64 bit integer */ #define VT_BOOL 11 /* ISOC99 boolean type */
#define VT_LONG 13 /* long integer (NEVER USED as type, only #define VT_LLONG 12 /* 64 bit integer */
during parsing) */ #define VT_LONG 13 /* long integer (NEVER USED as type, only
#define VT_BTYPE 0x000f /* mask for basic type */ during parsing) */
#define VT_UNSIGNED 0x0010 /* unsigned type */ #define VT_UNSIGNED 0x0010 /* unsigned type */
#define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */ #define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */
#define VT_VLA 0x20000 /* VLA type (also has VT_PTR and VT_ARRAY) */ #define VT_BITFIELD 0x0040 /* bitfield modifier */
#define VT_BITFIELD 0x0040 /* bitfield modifier */ #define VT_CONSTANT 0x0800 /* const modifier */
#define VT_CONSTANT 0x0800 /* const modifier */ #define VT_VOLATILE 0x1000 /* volatile modifier */
#define VT_VOLATILE 0x1000 /* volatile modifier */ #define VT_SIGNED 0x2000 /* signed type */
#define VT_SIGNED 0x2000 /* signed type */ #define VT_VLA 0x00020000 /* VLA type (also has VT_PTR and VT_ARRAY) */
/* storage */ /* storage */
#define VT_EXTERN 0x00000080 /* extern definition */ #define VT_EXTERN 0x00000080 /* extern definition */
@ -741,13 +727,13 @@ struct TCCState {
#define VT_INLINE 0x00000400 /* inline definition */ #define VT_INLINE 0x00000400 /* inline definition */
#define VT_IMPORT 0x00004000 /* win32: extern data imported from dll */ #define VT_IMPORT 0x00004000 /* win32: extern data imported from dll */
#define VT_EXPORT 0x00008000 /* win32: data exported from dll */ #define VT_EXPORT 0x00008000 /* win32: data exported from dll */
#define VT_WEAK 0x00010000 /* win32: data exported from dll */ #define VT_WEAK 0x00010000 /* weak symbol */
#define VT_STRUCT_SHIFT 18 /* shift for bitfield shift values */ #define VT_STRUCT_SHIFT 18 /* shift for bitfield shift values (max: 32 - 2*6) */
/* type mask (except storage) */ /* type mask (except storage) */
#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE | VT_IMPORT | VT_EXPORT | VT_WEAK) #define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE | VT_IMPORT | VT_EXPORT | VT_WEAK)
#define VT_TYPE (~(VT_STORAGE)) #define VT_TYPE (~(VT_STORAGE))
/* token values */ /* token values */
@ -999,6 +985,11 @@ ST_DATA int tcc_ext;
/* XXX: get rid of this ASAP */ /* XXX: get rid of this ASAP */
ST_DATA struct TCCState *tcc_state; ST_DATA struct TCCState *tcc_state;
#ifdef MEM_DEBUG
ST_DATA int mem_cur_size;
ST_DATA int mem_max_size;
#endif
#define AFF_PRINT_ERROR 0x0001 /* print error if file not found */ #define AFF_PRINT_ERROR 0x0001 /* print error if file not found */
#define AFF_REFERENCED_DLL 0x0002 /* load a referenced dll from another dll */ #define AFF_REFERENCED_DLL 0x0002 /* load a referenced dll from another dll */
#define AFF_PREPROCESS 0x0004 /* preprocess file */ #define AFF_PREPROCESS 0x0004 /* preprocess file */
@ -1020,19 +1011,19 @@ PUB_FUNC char *tcc_strdup(const char *str);
#undef strdup #undef strdup
#define strdup(s) use_tcc_strdup(s) #define strdup(s) use_tcc_strdup(s)
PUB_FUNC void tcc_memstats(void); PUB_FUNC void tcc_memstats(void);
PUB_FUNC void dynarray_add(void ***ptab, int *nb_ptr, void *data);
PUB_FUNC void dynarray_reset(void *pp, int *n);
PUB_FUNC void tcc_error_noabort(const char *fmt, ...); PUB_FUNC void tcc_error_noabort(const char *fmt, ...);
PUB_FUNC void tcc_error(const char *fmt, ...); PUB_FUNC void tcc_error(const char *fmt, ...);
PUB_FUNC void tcc_warning(const char *fmt, ...); PUB_FUNC void tcc_warning(const char *fmt, ...);
/* other utilities */ /* other utilities */
PUB_FUNC void cstr_ccat(CString *cstr, int ch); ST_FUNC void dynarray_add(void ***ptab, int *nb_ptr, void *data);
PUB_FUNC void cstr_cat(CString *cstr, const char *str); ST_FUNC void dynarray_reset(void *pp, int *n);
PUB_FUNC void cstr_wccat(CString *cstr, int ch); ST_FUNC void cstr_ccat(CString *cstr, int ch);
PUB_FUNC void cstr_new(CString *cstr); ST_FUNC void cstr_cat(CString *cstr, const char *str);
PUB_FUNC void cstr_free(CString *cstr); ST_FUNC void cstr_wccat(CString *cstr, int ch);
PUB_FUNC void cstr_reset(CString *cstr); ST_FUNC void cstr_new(CString *cstr);
ST_FUNC void cstr_free(CString *cstr);
ST_FUNC void cstr_reset(CString *cstr);
ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags); ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags);
ST_FUNC void section_realloc(Section *sec, unsigned long new_size); ST_FUNC void section_realloc(Section *sec, unsigned long new_size);
@ -1059,15 +1050,10 @@ ST_FUNC void tcc_close(void);
ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags); ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags);
ST_FUNC int tcc_add_crt(TCCState *s, const char *filename); ST_FUNC int tcc_add_crt(TCCState *s, const char *filename);
#ifndef TCC_TARGET_PE
ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags); ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags);
#endif
PUB_FUNC int tcc_set_flag(TCCState *s, const char *flag_name, int value);
PUB_FUNC void tcc_print_stats(TCCState *s, int64_t total_time); PUB_FUNC void tcc_print_stats(TCCState *s, int64_t total_time);
PUB_FUNC char *tcc_default_target(TCCState *s, const char *default_file); PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv);
PUB_FUNC void tcc_gen_makedeps(TCCState *s, const char *target, const char *filename);
PUB_FUNC void tcc_display_info(TCCState *s, int what);
/* ------------ tccpp.c ------------ */ /* ------------ tccpp.c ------------ */
@ -1208,6 +1194,10 @@ ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsign
/* ------------ tccelf.c ------------ */ /* ------------ tccelf.c ------------ */
#define TCC_OUTPUT_FORMAT_ELF 0 /* default output format: ELF */
#define TCC_OUTPUT_FORMAT_BINARY 1 /* binary image output */
#define TCC_OUTPUT_FORMAT_COFF 2 /* COFF */
#define ARMAG "!<arch>\012" /* For COFF and a.out archives */ #define ARMAG "!<arch>\012" /* For COFF and a.out archives */
typedef struct { typedef struct {
@ -1259,11 +1249,11 @@ ST_FUNC int handle_eob(void);
/* ------------ xxx-gen.c ------------ */ /* ------------ xxx-gen.c ------------ */
ST_DATA const int reg_classes[NB_REGS
#ifdef TCC_TARGET_X86_64 #ifdef TCC_TARGET_X86_64
+ 7 ST_DATA const int reg_classes[NB_REGS+7];
#else
ST_DATA const int reg_classes[NB_REGS];
#endif #endif
];
ST_FUNC void gsym_addr(int t, int a); ST_FUNC void gsym_addr(int t, int a);
ST_FUNC void gsym(int t); ST_FUNC void gsym(int t);
@ -1329,7 +1319,6 @@ ST_FUNC int tcc_load_coff(TCCState * s1, int fd);
/* ------------ tccasm.c ------------ */ /* ------------ tccasm.c ------------ */
ST_FUNC void asm_instr(void); ST_FUNC void asm_instr(void);
ST_FUNC void asm_global_instr(void); ST_FUNC void asm_global_instr(void);
#ifdef CONFIG_TCC_ASM #ifdef CONFIG_TCC_ASM
ST_FUNC int find_constraint(ASMOperand *operands, int nb_operands, const char *name, const char **pp); ST_FUNC int find_constraint(ASMOperand *operands, int nb_operands, const char *name, const char **pp);
ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe); ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe);
@ -1343,14 +1332,13 @@ ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier);
ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, int nb_outputs, int is_output, uint8_t *clobber_regs, int out_reg); ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, int nb_outputs, int is_output, uint8_t *clobber_regs, int out_reg);
ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str); ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str);
#endif #endif
/* ------------ tccpe.c -------------- */ /* ------------ tccpe.c -------------- */
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd); ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd);
ST_FUNC int pe_output_file(TCCState * s1, const char *filename); ST_FUNC int pe_output_file(TCCState * s1, const char *filename);
ST_FUNC int pe_putimport(TCCState *s1, int dllindex, const char *name, addr_t value); ST_FUNC int pe_putimport(TCCState *s1, int dllindex, const char *name, addr_t value);
ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2); ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2);
/* tiny_impdef.c */
ST_FUNC char *get_export_names(FILE *fp);
#ifdef TCC_TARGET_X86_64 #ifdef TCC_TARGET_X86_64
ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack); ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack);
#endif #endif
@ -1366,7 +1354,7 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack);
/* dummy function for profiling */ /* dummy function for profiling */
ST_FUNC void *dlopen(const char *filename, int flag); ST_FUNC void *dlopen(const char *filename, int flag);
ST_FUNC void dlclose(void *p); ST_FUNC void dlclose(void *p);
//ST_FUNC const char *dlerror(void); ST_FUNC const char *dlerror(void);
ST_FUNC void *resolve_sym(TCCState *s1, const char *symbol); ST_FUNC void *resolve_sym(TCCState *s1, const char *symbol);
#elif !defined _WIN32 #elif !defined _WIN32
ST_FUNC void *resolve_sym(TCCState *s1, const char *symbol); ST_FUNC void *resolve_sym(TCCState *s1, const char *symbol);
@ -1376,7 +1364,7 @@ ST_FUNC void *resolve_sym(TCCState *s1, const char *symbol);
ST_DATA int rt_num_callers; ST_DATA int rt_num_callers;
ST_DATA const char **rt_bound_error_msg; ST_DATA const char **rt_bound_error_msg;
ST_DATA void *rt_prog_main; ST_DATA void *rt_prog_main;
PUB_FUNC void tcc_set_num_callers(int n); ST_FUNC void tcc_set_num_callers(int n);
#endif #endif
#endif #endif

View File

@ -240,7 +240,7 @@ ST_FUNC int add_elf_sym(Section *s, addr_t value, unsigned long size,
} else if (s == tcc_state->dynsymtab_section) { } else if (s == tcc_state->dynsymtab_section) {
/* we accept that two DLL define the same symbol */ /* we accept that two DLL define the same symbol */
} else { } else {
#if 1 #if 0
printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n", printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n",
sym_bind, sh_num, new_vis, esym_bind, esym->st_shndx, esym_vis); sym_bind, sh_num, new_vis, esym_bind, esym->st_shndx, esym_vis);
#endif #endif

58
tccpe.c
View File

@ -1505,10 +1505,10 @@ static int add_dllref(TCCState *s1, const char *dllname)
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
static int read_mem(FILE *fp, unsigned offset, void *buffer, unsigned len) static int read_mem(int fd, unsigned offset, void *buffer, unsigned len)
{ {
fseek(fp, offset, 0); lseek(fd, offset, SEEK_SET);
return len == fread(buffer, 1, len, fp); return len == read(fd, buffer, len);
} }
/* ------------------------------------------------------------- /* -------------------------------------------------------------
@ -1516,7 +1516,7 @@ static int read_mem(FILE *fp, unsigned offset, void *buffer, unsigned len)
* as generated by 'windres.exe -O coff ...'. * as generated by 'windres.exe -O coff ...'.
*/ */
static int pe_load_res(TCCState *s1, FILE *fp) static int pe_load_res(TCCState *s1, int fd)
{ {
struct pe_rsrc_header hdr; struct pe_rsrc_header hdr;
Section *rsrc_section; Section *rsrc_section;
@ -1524,7 +1524,7 @@ static int pe_load_res(TCCState *s1, FILE *fp)
BYTE *ptr; BYTE *ptr;
unsigned offs; unsigned offs;
if (!read_mem(fp, 0, &hdr, sizeof hdr)) if (!read_mem(fd, 0, &hdr, sizeof hdr))
goto quit; goto quit;
if (hdr.filehdr.Machine != 0x014C if (hdr.filehdr.Machine != 0x014C
@ -1535,13 +1535,13 @@ static int pe_load_res(TCCState *s1, FILE *fp)
rsrc_section = new_section(s1, ".rsrc", SHT_PROGBITS, SHF_ALLOC); rsrc_section = new_section(s1, ".rsrc", SHT_PROGBITS, SHF_ALLOC);
ptr = section_ptr_add(rsrc_section, hdr.sectionhdr.SizeOfRawData); ptr = section_ptr_add(rsrc_section, hdr.sectionhdr.SizeOfRawData);
offs = hdr.sectionhdr.PointerToRawData; offs = hdr.sectionhdr.PointerToRawData;
if (!read_mem(fp, offs, ptr, hdr.sectionhdr.SizeOfRawData)) if (!read_mem(fd, offs, ptr, hdr.sectionhdr.SizeOfRawData))
goto quit; goto quit;
offs = hdr.sectionhdr.PointerToRelocations; offs = hdr.sectionhdr.PointerToRelocations;
for (i = 0; i < hdr.sectionhdr.NumberOfRelocations; ++i) for (i = 0; i < hdr.sectionhdr.NumberOfRelocations; ++i)
{ {
struct pe_rsrc_reloc rel; struct pe_rsrc_reloc rel;
if (!read_mem(fp, offs, &rel, sizeof rel)) if (!read_mem(fd, offs, &rel, sizeof rel))
goto quit; goto quit;
// printf("rsrc_reloc: %x %x %x\n", rel.offset, rel.size, rel.type); // printf("rsrc_reloc: %x %x %x\n", rel.offset, rel.size, rel.type);
if (rel.type != 7) /* DIR32NB */ if (rel.type != 7) /* DIR32NB */
@ -1571,22 +1571,26 @@ static char *trimback(char *a, char *e)
return a; return a;
} }
static char *get_line(char *line, int size, FILE *fp) static char *get_line(char *line, int size, int fd)
{ {
if (NULL == fgets(line, size, fp)) int n;
for (n = 0; n < size - 1; )
if (read(fd, line + n, 1) < 1 || line[n++] == '\n')
break;
if (0 == n)
return NULL; return NULL;
trimback(line, strchr(line, 0)); trimback(line, line + n);
return trimfront(line); return trimfront(line);
} }
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
static int pe_load_def(TCCState *s1, FILE *fp) static int pe_load_def(TCCState *s1, int fd)
{ {
int state = 0, ret = -1, dllindex = 0; int state = 0, ret = -1, dllindex = 0;
char line[400], dllname[80], *p; char line[400], dllname[80], *p;
for (;;) { for (;;) {
p = get_line(line, sizeof line, fp); p = get_line(line, sizeof line, fd);
if (NULL == p) if (NULL == p)
break; break;
if (0 == *p || ';' == *p) if (0 == *p || ';' == *p)
@ -1623,11 +1627,11 @@ quit:
#define TINY_IMPDEF_GET_EXPORT_NAMES_ONLY #define TINY_IMPDEF_GET_EXPORT_NAMES_ONLY
#include "win32/tools/tiny_impdef.c" #include "win32/tools/tiny_impdef.c"
static int pe_load_dll(TCCState *s1, const char *dllname, FILE *fp) static int pe_load_dll(TCCState *s1, const char *dllname, int fd)
{ {
char *p, *q; char *p, *q;
int index; int index;
p = get_export_names(fp); p = get_export_names(fd);
if (!p) if (!p)
return -1; return -1;
index = add_dllref(s1, dllname); index = add_dllref(s1, dllname);
@ -1640,18 +1644,14 @@ static int pe_load_dll(TCCState *s1, const char *dllname, FILE *fp)
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd) ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd)
{ {
FILE *fp = fdopen(dup(fd), "rb");
int ret = -1; int ret = -1;
char buf[10]; char buf[10];
if (fp) { if (0 == strcmp(tcc_fileextension(filename), ".def"))
if (0 == strcmp(tcc_fileextension(filename), ".def")) ret = pe_load_def(s1, fd);
ret = pe_load_def(s1, fp); else if (pe_load_res(s1, fd) == 0)
else if (pe_load_res(s1, fp) == 0) ret = 0;
ret = 0; else if (read_mem(fd, 0, buf, sizeof buf) && 0 == strncmp(buf, "MZ", 2))
else if (read_mem(fp, 0, buf, sizeof buf) && 0 == strncmp(buf, "MZ", 2)) ret = pe_load_dll(s1, tcc_basename(filename), fd);
ret = pe_load_dll(s1, tcc_basename(filename), fp);
fclose(fp);
}
return ret; return ret;
} }
@ -1723,7 +1723,7 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack)
#define PE_STDSYM(n,s) "_" n s #define PE_STDSYM(n,s) "_" n s
#endif #endif
static void pe_add_runtime_ex(TCCState *s1, struct pe_info *pe) static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
{ {
const char *start_symbol; const char *start_symbol;
ADDR3264 addr = 0; ADDR3264 addr = 0;
@ -1762,15 +1762,17 @@ static void pe_add_runtime_ex(TCCState *s1, struct pe_info *pe)
if (0 == s1->nostdlib) { if (0 == s1->nostdlib) {
static const char *libs[] = { static const char *libs[] = {
"tcc1", "msvcrt", "kernel32", "", "user32", "gdi32", NULL "libtcc1.a", "msvcrt", "kernel32", "", "user32", "gdi32", NULL
}; };
const char **pp, *p; const char **pp, *p;
for (pp = libs; 0 != (p = *pp); ++pp) { for (pp = libs; 0 != (p = *pp); ++pp) {
if (0 == *p) { if (0 == *p) {
if (PE_DLL != pe_type && PE_GUI != pe_type) if (PE_DLL != pe_type && PE_GUI != pe_type)
break; break;
} else if (tcc_add_library(s1, p) < 0) } else if (pp == libs ? tcc_add_dll(s1, p, 0) : tcc_add_library(s1, p)) {
tcc_error_noabort("cannot find library: %s", p); tcc_error_noabort("cannot find library: %s", p);
break;
}
} }
} }
@ -1802,7 +1804,7 @@ ST_FUNC int pe_output_file(TCCState * s1, const char *filename)
pe.s1 = s1; pe.s1 = s1;
tcc_add_bcheck(s1); tcc_add_bcheck(s1);
pe_add_runtime_ex(s1, &pe); pe_add_runtime(s1, &pe);
relocate_common_syms(); /* assign bss adresses */ relocate_common_syms(); /* assign bss adresses */
tcc_add_linker_symbols(s1); tcc_add_linker_symbols(s1);

18
tccpp.c
View File

@ -118,7 +118,7 @@ static void cstr_realloc(CString *cstr, int new_size)
} }
/* add a byte */ /* add a byte */
PUB_FUNC void cstr_ccat(CString *cstr, int ch) ST_FUNC void cstr_ccat(CString *cstr, int ch)
{ {
int size; int size;
size = cstr->size + 1; size = cstr->size + 1;
@ -128,7 +128,7 @@ PUB_FUNC void cstr_ccat(CString *cstr, int ch)
cstr->size = size; cstr->size = size;
} }
PUB_FUNC void cstr_cat(CString *cstr, const char *str) ST_FUNC void cstr_cat(CString *cstr, const char *str)
{ {
int c; int c;
for(;;) { for(;;) {
@ -141,7 +141,7 @@ PUB_FUNC void cstr_cat(CString *cstr, const char *str)
} }
/* add a wide char */ /* add a wide char */
PUB_FUNC void cstr_wccat(CString *cstr, int ch) ST_FUNC void cstr_wccat(CString *cstr, int ch)
{ {
int size; int size;
size = cstr->size + sizeof(nwchar_t); size = cstr->size + sizeof(nwchar_t);
@ -151,20 +151,20 @@ PUB_FUNC void cstr_wccat(CString *cstr, int ch)
cstr->size = size; cstr->size = size;
} }
PUB_FUNC void cstr_new(CString *cstr) ST_FUNC void cstr_new(CString *cstr)
{ {
memset(cstr, 0, sizeof(CString)); memset(cstr, 0, sizeof(CString));
} }
/* free string and reset it to NULL */ /* free string and reset it to NULL */
PUB_FUNC void cstr_free(CString *cstr) ST_FUNC void cstr_free(CString *cstr)
{ {
tcc_free(cstr->data_allocated); tcc_free(cstr->data_allocated);
cstr_new(cstr); cstr_new(cstr);
} }
/* reset string to empty */ /* reset string to empty */
PUB_FUNC void cstr_reset(CString *cstr) ST_FUNC void cstr_reset(CString *cstr)
{ {
cstr->size = 0; cstr->size = 0;
} }
@ -3112,17 +3112,17 @@ print_line:
: "" : ""
; ;
iptr = iptr_new; iptr = iptr_new;
fprintf(s1->outfile, "# %d \"%s\"%s\n", file->line_num, file->filename, s); fprintf(s1->ppfp, "# %d \"%s\"%s\n", file->line_num, file->filename, s);
} else { } else {
while (d) while (d)
fputs("\n", s1->outfile), --d; fputs("\n", s1->ppfp), --d;
} }
line_ref = (file_ref = file)->line_num; line_ref = (file_ref = file)->line_num;
token_seen = tok != TOK_LINEFEED; token_seen = tok != TOK_LINEFEED;
if (!token_seen) if (!token_seen)
continue; continue;
} }
fputs(get_tok_str(tok, &tokc), s1->outfile); fputs(get_tok_str(tok, &tokc), s1->ppfp);
} }
free_defines(define_start); free_defines(define_start);
return 0; return 0;

View File

@ -54,33 +54,36 @@ LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr)
if (TCC_RELOCATE_AUTO != ptr) if (TCC_RELOCATE_AUTO != ptr)
return tcc_relocate_ex(s1, ptr); return tcc_relocate_ex(s1, ptr);
#ifdef HAVE_SELINUX
/* Use mmap instead of malloc for Selinux
Ref http://www.gnu.org/s/libc/manual/html_node/File-Size.html */
char tmpfname[] = "/tmp/.tccrunXXXXXX";
int fd = mkstemp (tmpfname);
if ((ret= tcc_relocate_ex(s1,NULL)) < 0)return -1;
s1->mem_size=ret;
unlink (tmpfname); ftruncate (fd, s1->mem_size);
s1->write_mem = mmap (NULL, ret, PROT_READ|PROT_WRITE,
MAP_SHARED, fd, 0);
if(s1->write_mem == MAP_FAILED){
tcc_error("/tmp not writeable");
return -1;
}
s1->runtime_mem = mmap (NULL, ret, PROT_READ|PROT_EXEC,
MAP_SHARED, fd, 0);
if(s1->runtime_mem == MAP_FAILED){
tcc_error("/tmp not executable");
return -1;
}
ret = tcc_relocate_ex(s1, s1->write_mem);
#else
ret = tcc_relocate_ex(s1, NULL); ret = tcc_relocate_ex(s1, NULL);
if (-1 != ret) { if (ret < 0)
s1->runtime_mem = tcc_malloc(ret); return ret;
ret = tcc_relocate_ex(s1, s1->runtime_mem);
#ifdef HAVE_SELINUX
{ /* Use mmap instead of malloc for Selinux. Ref:
http://www.gnu.org/s/libc/manual/html_node/File-Size.html */
char tmpfname[] = "/tmp/.tccrunXXXXXX";
int fd = mkstemp (tmpfname);
s1->mem_size = ret;
unlink (tmpfname);
ftruncate (fd, s1->mem_size);
s1->write_mem = mmap (NULL, ret, PROT_READ|PROT_WRITE,
MAP_SHARED, fd, 0);
if (s1->write_mem == MAP_FAILED)
tcc_error("/tmp not writeable");
s1->runtime_mem = mmap (NULL, ret, PROT_READ|PROT_EXEC,
MAP_SHARED, fd, 0);
if (s1->runtime_mem == MAP_FAILED)
tcc_error("/tmp not executable");
ret = tcc_relocate_ex(s1, s1->write_mem);
} }
#else
s1->runtime_mem = tcc_malloc(ret);
ret = tcc_relocate_ex(s1, s1->runtime_mem);
#endif #endif
return ret; return ret;
} }
@ -130,8 +133,7 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr)
addr_t mem; addr_t mem;
int i; int i;
if (0 == s1->runtime_added) { if (NULL == ptr) {
s1->runtime_added = 1;
s1->nb_errors = 0; s1->nb_errors = 0;
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
pe_output_file(s1, NULL); pe_output_file(s1, NULL);
@ -215,6 +217,9 @@ static void set_pages_executable(void *ptr, unsigned long length)
unsigned long old_protect; unsigned long old_protect;
VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect); VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect);
#else #else
#ifndef PAGESIZE
# define PAGESIZE 4096
#endif
addr_t start, end; addr_t start, end;
start = (addr_t)ptr & ~(PAGESIZE - 1); start = (addr_t)ptr & ~(PAGESIZE - 1);
end = (addr_t)ptr + length; end = (addr_t)ptr + length;
@ -226,7 +231,7 @@ static void set_pages_executable(void *ptr, unsigned long length)
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
#ifdef CONFIG_TCC_BACKTRACE #ifdef CONFIG_TCC_BACKTRACE
PUB_FUNC void tcc_set_num_callers(int n) ST_FUNC void tcc_set_num_callers(int n)
{ {
rt_num_callers = n; rt_num_callers = n;
} }
@ -436,6 +441,10 @@ static void sig_error(int signum, siginfo_t *siginf, void *puc)
exit(255); exit(255);
} }
#ifndef SA_SIGINFO
# define SA_SIGINFO 0x00000004u
#endif
/* Generate a stack backtrace when a CPU exception occurs. */ /* Generate a stack backtrace when a CPU exception occurs. */
static void set_exception_handler(void) static void set_exception_handler(void)
{ {
@ -663,14 +672,8 @@ static int rt_get_caller_pc(addr_t *paddr, CONTEXT *uc, int level)
#endif /* _WIN32 */ #endif /* _WIN32 */
#endif /* CONFIG_TCC_BACKTRACE */ #endif /* CONFIG_TCC_BACKTRACE */
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
#ifdef CONFIG_TCC_STATIC #ifdef CONFIG_TCC_STATIC
#define RTLD_LAZY 0x001
#define RTLD_NOW 0x002
#define RTLD_GLOBAL 0x100
#define RTLD_DEFAULT NULL
/* dummy function for profiling */ /* dummy function for profiling */
ST_FUNC void *dlopen(const char *filename, int flag) ST_FUNC void *dlopen(const char *filename, int flag)
{ {
@ -680,26 +683,27 @@ ST_FUNC void *dlopen(const char *filename, int flag)
ST_FUNC void dlclose(void *p) ST_FUNC void dlclose(void *p)
{ {
} }
/*
const char *dlerror(void) ST_FUNC const char *dlerror(void)
{ {
return "error"; return "error";
} }
*/
typedef struct TCCSyms { typedef struct TCCSyms {
char *str; char *str;
void *ptr; void *ptr;
} TCCSyms; } TCCSyms;
#define TCCSYM(a) { #a, &a, },
/* add the symbol you want here if no dynamic linking is done */ /* add the symbol you want here if no dynamic linking is done */
static TCCSyms tcc_syms[] = { static TCCSyms tcc_syms[] = {
#if !defined(CONFIG_TCCBOOT) #if !defined(CONFIG_TCCBOOT)
#define TCCSYM(a) { #a, &a, },
TCCSYM(printf) TCCSYM(printf)
TCCSYM(fprintf) TCCSYM(fprintf)
TCCSYM(fopen) TCCSYM(fopen)
TCCSYM(fclose) TCCSYM(fclose)
#undef TCCSYM
#endif #endif
{ NULL, NULL }, { NULL, NULL },
}; };

View File

@ -6,13 +6,11 @@
under MS-Windows. See tcc-doc.html to have all the features. under MS-Windows. See tcc-doc.html to have all the features.
Installation from the binary ZIP package: Installation from the binary ZIP package:
----------------------------------------- -----------------------------------------
Unzip the package to a directory of your choice. Unzip the package to a directory of your choice.
Set the system PATH: Set the system PATH:
-------------------- --------------------
To be able to invoke the compiler from everywhere on your computer by To be able to invoke the compiler from everywhere on your computer by
@ -20,7 +18,6 @@
system PATH. system PATH.
Examples: Examples:
--------- ---------
Open a console window (DOS box) and 'cd' to the examples directory. Open a console window (DOS box) and 'cd' to the examples directory.
@ -39,9 +36,23 @@
tiny_impdef dll.dll (optional) tiny_impdef dll.dll (optional)
tcc hello_dll.c dll.def tcc hello_dll.c dll.def
For the 'libtcc_test' example type
tcc examples/libtcc_test.c -I libtcc -L libtcc -ltcc Using libtcc as JIT compiler in your program
--------------------------------------------
Check out the 'libtcc_test' example:
- Running it from source:
tcc -I libtcc libtcc/libtcc.def -run examples/libtcc_test.c
- Compiling with TCC:
tcc examples/libtcc_test.c -I libtcc libtcc/libtcc.def
- Compiling with MinGW:
gcc examples/libtcc_test.c -I libtcc libtcc.dll
- Compiling with MSVC:
lib /def:libtcc\libtcc.def /out:libtcc.lib
cl /MD examples/libtcc_test.c -I libtcc libtcc.lib
Import Definition Files: Import Definition Files:
@ -58,7 +69,6 @@
the TCC commandline to link a program that uses opengl32.dll. the TCC commandline to link a program that uses opengl32.dll.
Header Files: Header Files:
------------- -------------
The system header files (except _mingw.h) are from the MinGW The system header files (except _mingw.h) are from the MinGW
@ -71,7 +81,6 @@
into your "tcc/include/winapi" directory. into your "tcc/include/winapi" directory.
Resource Files: Resource Files:
--------------- ---------------
TCC can link windows resources in coff format as generated by MinGW's TCC can link windows resources in coff format as generated by MinGW's
@ -81,7 +90,6 @@
tcc app.c appres.o -o app.exe tcc app.c appres.o -o app.exe
Tiny Libmaker: Tiny Libmaker:
-------------- --------------
The included tiny_libmaker tool by Timovj Lahde can be used as The included tiny_libmaker tool by Timovj Lahde can be used as
@ -90,29 +98,26 @@
tiny_libmaker [rcs] library objectfiles ... tiny_libmaker [rcs] library objectfiles ...
Compilation from source: Compilation from source:
------------------------ ------------------------
* You can use the MinGW and MSYS tools available at * You can use the MinGW and MSYS tools available at
http://www.mingw.org http://www.mingw.org
Untar the TCC archive and type in the MSYS shell: Untar the TCC archive and type in the MSYS shell:
./configure ./configure [--prefix installpath]
make make
make install make install
The default install location is c:\Program Files\tcc The default install location is c:\Program Files\tcc
* Alternatively you can compile TCC with just GCC from MinGW using * Alternatively you can compile TCC with just GCC from MinGW using
win32\build-tcc.bat build-tcc.bat (from the win32 directory)
To install, copy the entire contents of the win32 directory to
where you want.
To install, copy the entire contents of the win32 directory to
where you want.
Limitations: Limitations:
@ -128,7 +133,6 @@
- Bounds checking (option -b) is not supported on 64-bit OS. - Bounds checking (option -b) is not supported on 64-bit OS.
Documentation and License: Documentation and License:
-------------------------- --------------------------
TCC is distributed under the GNU Lesser General Public License. (See TCC is distributed under the GNU Lesser General Public License. (See
@ -139,7 +143,6 @@
http://fabrice.bellard.free.fr/tcc/ http://fabrice.bellard.free.fr/tcc/
WinAPI Help and 3rd-party tools: WinAPI Help and 3rd-party tools:
-------------------------------- --------------------------------
The Windows API documentation (Win95) in a single .hlp file is The Windows API documentation (Win95) in a single .hlp file is
@ -150,5 +153,4 @@
"ResEd", available at the RadASM website. "ResEd", available at the RadASM website.
--- grischka --- grischka

View File

@ -25,9 +25,10 @@
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#include <stdio.h> #include <stdio.h>
#include <io.h>
#include <malloc.h> #include <malloc.h>
char *get_export_names(FILE *fp); char *get_export_names(int fd);
#define tcc_free free #define tcc_free free
#define tcc_realloc realloc #define tcc_realloc realloc
@ -114,7 +115,7 @@ usage:
if (v) if (v)
printf("--> %s\n", file); printf("--> %s\n", file);
p = get_export_names(fp); p = get_export_names(fileno(fp));
if (NULL == p) { if (NULL == p) {
fprintf(stderr, "tiny_impdef: could not get exported function names.\n"); fprintf(stderr, "tiny_impdef: could not get exported function names.\n");
goto the_end; goto the_end;
@ -149,18 +150,18 @@ the_end:
return ret; return ret;
} }
/* -------------------------------------------------------------- */ int read_mem(int fd, unsigned offset, void *buffer, unsigned len)
int read_mem(FILE *fp, unsigned offset, void *buffer, unsigned len)
{ {
fseek(fp, offset, 0); lseek(fd, offset, SEEK_SET);
return len == fread(buffer, 1, len, fp); return len == read(fd, buffer, len);
} }
/* -------------------------------------------------------------- */
/* -------------------------------------------------------------- */ /* -------------------------------------------------------------- */
#endif #endif
char *get_export_names(FILE *fp) char *get_export_names(int fd)
{ {
int l, i, n, n0; int l, i, n, n0;
char *p; char *p;
@ -182,20 +183,20 @@ char *get_export_names(FILE *fp)
n = n0 = 0; n = n0 = 0;
p = NULL; p = NULL;
if (!read_mem(fp, 0, &dh, sizeof dh)) if (!read_mem(fd, 0, &dh, sizeof dh))
goto the_end; goto the_end;
if (!read_mem(fp, dh.e_lfanew, &sig, sizeof sig)) if (!read_mem(fd, dh.e_lfanew, &sig, sizeof sig))
goto the_end; goto the_end;
if (sig != 0x00004550) if (sig != 0x00004550)
goto the_end; goto the_end;
pef_hdroffset = dh.e_lfanew + sizeof sig; pef_hdroffset = dh.e_lfanew + sizeof sig;
if (!read_mem(fp, pef_hdroffset, &ih, sizeof ih)) if (!read_mem(fd, pef_hdroffset, &ih, sizeof ih))
goto the_end; goto the_end;
if (MACHINE != ih.Machine) if (MACHINE != ih.Machine)
goto the_end; goto the_end;
opt_hdroffset = pef_hdroffset + sizeof ih; opt_hdroffset = pef_hdroffset + sizeof ih;
sec_hdroffset = opt_hdroffset + sizeof oh; sec_hdroffset = opt_hdroffset + sizeof oh;
if (!read_mem(fp, opt_hdroffset, &oh, sizeof oh)) if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh))
goto the_end; goto the_end;
if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes) if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes)
@ -204,7 +205,7 @@ char *get_export_names(FILE *fp)
addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
//printf("addr: %08x\n", addr); //printf("addr: %08x\n", addr);
for (i = 0; i < ih.NumberOfSections; ++i) { for (i = 0; i < ih.NumberOfSections; ++i) {
if (!read_mem(fp, sec_hdroffset + i * sizeof ish, &ish, sizeof ish)) if (!read_mem(fd, sec_hdroffset + i * sizeof ish, &ish, sizeof ish))
goto the_end; goto the_end;
//printf("vaddr: %08x\n", ish.VirtualAddress); //printf("vaddr: %08x\n", ish.VirtualAddress);
if (addr >= ish.VirtualAddress && addr < ish.VirtualAddress + ish.SizeOfRawData) if (addr >= ish.VirtualAddress && addr < ish.VirtualAddress + ish.SizeOfRawData)
@ -214,18 +215,18 @@ char *get_export_names(FILE *fp)
found: found:
ref = ish.VirtualAddress - ish.PointerToRawData; ref = ish.VirtualAddress - ish.PointerToRawData;
if (!read_mem(fp, addr - ref, &ied, sizeof ied)) if (!read_mem(fd, addr - ref, &ied, sizeof ied))
goto the_end; goto the_end;
namep = ied.AddressOfNames - ref; namep = ied.AddressOfNames - ref;
for (i = 0; i < ied.NumberOfNames; ++i) { for (i = 0; i < ied.NumberOfNames; ++i) {
if (!read_mem(fp, namep, &ptr, sizeof ptr)) if (!read_mem(fd, namep, &ptr, sizeof ptr))
goto the_end; goto the_end;
namep += sizeof ptr; namep += sizeof ptr;
for (l = 0;;) { for (l = 0;;) {
if (n+1 >= n0) if (n+1 >= n0)
p = tcc_realloc(p, n0 = n0 ? n0 * 2 : 256); p = tcc_realloc(p, n0 = n0 ? n0 * 2 : 256);
if (!read_mem(fp, ptr - ref + l, p + n, 1) || ++l >= 80) { if (!read_mem(fd, ptr - ref + l, p + n, 1) || ++l >= 80) {
tcc_free(p), p = NULL; tcc_free(p), p = NULL;
goto the_end; goto the_end;
} }

View File

@ -79,7 +79,7 @@ int main(int argc, char **argv)
ElfW(Sym) *sym; ElfW(Sym) *sym;
int i, fsize, iarg; int i, fsize, iarg;
char *buf, *shstr, *symtab = NULL, *strtab = NULL; char *buf, *shstr, *symtab = NULL, *strtab = NULL;
int symtabsize = 0, strtabsize = 0; int symtabsize = 0;//, strtabsize = 0;
char *anames = NULL; char *anames = NULL;
int *afpos = NULL; int *afpos = NULL;
int istrlen, strpos = 0, fpos = 0, funccnt = 0, funcmax, hofs; int istrlen, strpos = 0, fpos = 0, funccnt = 0, funcmax, hofs;
@ -171,7 +171,7 @@ int main(int argc, char **argv)
if (!strcmp(shstr + shdr->sh_name, ".strtab")) if (!strcmp(shstr + shdr->sh_name, ".strtab"))
{ {
strtab = (char *)(buf + shdr->sh_offset); strtab = (char *)(buf + shdr->sh_offset);
strtabsize = shdr->sh_size; //strtabsize = shdr->sh_size;
} }
} }
} }