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)
- -pthread option (same as -D_REENTRANT -lpthread) (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:
- 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
#ifdef MEM_DEBUG
int mem_cur_size;
int mem_max_size;
ST_DATA int mem_cur_size;
ST_DATA int mem_max_size;
unsigned malloc_usable_size(void*);
#endif
@ -261,7 +261,7 @@ PUB_FUNC char *tcc_strdup(const char *str)
PUB_FUNC void tcc_memstats(void)
{
#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
}
@ -272,7 +272,7 @@ PUB_FUNC void tcc_memstats(void)
/********************************************************/
/* 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;
void **pp;
@ -292,7 +292,7 @@ PUB_FUNC void dynarray_add(void ***ptab, int *nb_ptr, void *data)
*nb_ptr = nb;
}
PUB_FUNC void dynarray_reset(void *pp, int *n)
ST_FUNC void dynarray_reset(void *pp, int *n)
{
void **p;
for (p = *(void***)pp; *n; ++p, --*n)
@ -860,10 +860,10 @@ LIBTCCAPI void tcc_undefine_symbol(TCCState *s1, const char *sym)
define_undef(s);
}
/* cleanup all static data used during compilation */
static void tcc_cleanup(void)
{
int i, n;
if (NULL == tcc_state)
return;
tcc_state = NULL;
@ -915,18 +915,23 @@ LIBTCCAPI TCCState *tcc_new(void)
define_push(TOK___DATE__, 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 */
tcc_define_symbol(s, "__STDC__", NULL);
tcc_define_symbol(s, "__STDC_VERSION__", "199901L");
/* target defines */
#if defined(TCC_TARGET_I386)
tcc_define_symbol(s, "__i386__", NULL);
tcc_define_symbol(s, "__i386", NULL);
tcc_define_symbol(s, "i386", NULL);
#endif
#if defined(TCC_TARGET_X86_64)
#elif defined(TCC_TARGET_X86_64)
tcc_define_symbol(s, "__x86_64__", NULL);
#endif
#if defined(TCC_TARGET_ARM)
#elif defined(TCC_TARGET_ARM)
tcc_define_symbol(s, "__ARM_ARCH_4__", 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, "__APCS_32__", NULL);
#endif
#ifdef TCC_TARGET_PE
tcc_define_symbol(s, "_WIN32", NULL);
#ifdef TCC_TARGET_X86_64
# ifdef TCC_TARGET_X86_64
tcc_define_symbol(s, "_WIN64", NULL);
#endif
# endif
#else
tcc_define_symbol(s, "__unix__", NULL);
tcc_define_symbol(s, "__unix", NULL);
tcc_define_symbol(s, "unix", NULL);
#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
#if defined(__linux)
# if defined(__linux)
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
/* 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
tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned 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");
#endif
#ifndef TCC_TARGET_PE
/* glibc defines */
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");
#ifndef TCC_TARGET_PE
/* default library paths */
tcc_add_library_path(s, CONFIG_TCC_LIBPATHS);
/* paths for crt objects */
@ -1010,16 +1011,15 @@ LIBTCCAPI TCCState *tcc_new(void)
".dynhashtab", SHF_PRIVATE);
s->alacarte_link = 1;
s->nocommon = 1;
s->section_align = ELF_PAGE_SIZE;
#ifdef CHAR_IS_UNSIGNED
s->char_is_unsigned = 1;
#endif
/* 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;
#endif
if (s->section_align == 0)
s->section_align = ELF_PAGE_SIZE;
#ifdef TCC_TARGET_I386
s->seg_size = 32;
#endif
@ -1060,16 +1060,25 @@ LIBTCCAPI void tcc_delete(TCCState *s1)
dynarray_reset(&s1->include_paths, &s1->nb_include_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);
tcc_free(s1->tcc_lib_path);
#ifdef HAVE_SELINUX
#ifdef TCC_IS_NATIVE
# ifdef HAVE_SELINUX
munmap (s1->write_mem, s1->mem_size);
munmap (s1->runtime_mem, s1->mem_size);
#else
# else
tcc_free(s1->runtime_mem);
# endif
#endif
tcc_free(s1);
}
@ -1236,7 +1245,6 @@ static int tcc_add_library_internal(TCCState *s, const char *fmt,
return -1;
}
#ifndef TCC_TARGET_PE
/* find and load a dll. Return non zero if not found */
/* XXX: add '-rpath' option support ? */
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,
s->library_paths, s->nb_library_paths);
}
#endif
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)
{
#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
add_elf_sym(symtab_section, (uintptr_t)val, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
SHN_ABS, name);
/* XXX: Same problem on linux but currently "solved" elsewhere
via the rather dirty 'runtime_plt_and_got' hack. */
add_elf_sym(symtab_section, (uintptr_t)val, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
SHN_ABS, name);
#endif
return 0;
}
@ -1341,6 +1352,12 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type)
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 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;
}
/* enable debug */
LIBTCCAPI void tcc_enable_debug(TCCState *s)
{
s->do_debug = 1;
}
/* 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;
const FlagDef *p;
@ -1414,30 +1425,28 @@ static const FlagDef flag_defs[] = {
};
/* 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),
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;
p = str;
p = *str;
q = val;
while (*q != '\0') {
while (*q) {
if (*p != *q)
return 0;
p++;
q++;
}
if (ptr)
*ptr = (char *) p;
*str = p;
return 1;
}
/* Like strstart, but automatically takes into account that ld options can
*
* - 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 -)
*/
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;
@ -1476,64 +1485,72 @@ static int link_option(const char *str, const char *val, char **ptr)
}
if (ptr)
*ptr = (char *) p;
*ptr = p;
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 */
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) {
end = NULL;
const char *p = option;
char *end = NULL;
int ignoring = 0;
if (link_option(option, "Bsymbolic", &p)) {
s->symbolic = 1;
} else if (link_option(option, "nostdlib", &p)) {
s->nostdlib = 1;
} else if (link_option(option, "fini=", &p)) {
s->fini_symbol = p;
if (s->warn_unsupported)
tcc_warning("ignoring -fini %s", p);
} else if (link_option(option, "image-base=", &p)) {
s->fini_symbol = copy_linker_arg(p);
ignoring = 1;
} else if (link_option(option, "image-base=", &p)
|| link_option(option, "Ttext=", &p)) {
s->text_addr = strtoull(p, &end, 16);
s->has_text_addr = 1;
} else if (link_option(option, "init=", &p)) {
s->init_symbol = p;
if (s->warn_unsupported)
tcc_warning("ignoring -init %s", p);
s->init_symbol = copy_linker_arg(p);
ignoring = 1;
} else if (link_option(option, "oformat=", &p)) {
#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
#if defined(TCC_TARGET_X86_64)
if (strstart(p, "elf64-", NULL)) {
#else
if (strstart(p, "elf32-", NULL)) {
#endif
if (strstart("elf32-", &p)) {
#endif
s->output_format = TCC_OUTPUT_FORMAT_ELF;
} else if (!strcmp(p, "binary")) {
s->output_format = TCC_OUTPUT_FORMAT_BINARY;
} else
#ifdef TCC_TARGET_COFF
if (!strcmp(p, "coff")) {
} else if (!strcmp(p, "coff")) {
s->output_format = TCC_OUTPUT_FORMAT_COFF;
} else
#endif
{
return p;
}
} else
goto err;
} else if (link_option(option, "rpath=", &p)) {
s->rpath = p;
s->rpath = copy_linker_arg(p);
} else if (link_option(option, "section-alignment=", &p)) {
s->section_align = strtoul(p, &end, 16);
} else if (link_option(option, "soname=", &p)) {
s->soname = p;
multi = 0;
s->soname = copy_linker_arg(p);
#ifdef TCC_TARGET_PE
} else if (link_option(option, "file-alignment=", &p)) {
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")) {
s->pe_subsystem = 9;
#endif
} else {
return p;
}
} else
goto err;
#endif
} else
goto err;
} else if (link_option(option, "Ttext=", &p)) {
s->text_addr = strtoull(p, &end, 16);
s->has_text_addr = 1;
} else {
char *comma_ptr = strchr(option, ',');
if (comma_ptr)
*comma_ptr = '\0';
return option;
if (ignoring && s->warn_unsupported) err: {
char buf[100], *e;
pstrcpy(buf, sizeof buf, e = copy_linker_arg(option)), tcc_free(e);
if (ignoring)
tcc_warning("unsupported linker option '%s'", buf);
else
tcc_error("unsupported linker option '%s'", buf);
}
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) {
option = NULL;
p = strchr( (end) ? end : p, ',');
if (p) {
*p = 0; /* terminate last option */
option = ++p;
}
} else
option = NULL;
}
return NULL;
}
/* find option in table */
for(popt = tcc_options; ; ++popt) {
const char *p1 = popt->name;
const char *r1 = r + 1;
if (p1 == NULL)
tcc_error("invalid option -- '%s'", r);
if (!strstart(p1, &r1))
continue;
optarg = r1;
if (popt->flags & TCC_OPTION_HAS_ARG) {
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 */
LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path)
{
tcc_free(s->tcc_lib_path);
s->tcc_lib_path = tcc_strdup(path);
}
PUB_FUNC char *tcc_default_target(TCCState *s, const char *default_file)
{
char buf[1024];
char *ext;
const char *name = "a";
if (default_file && strcmp(default_file, "-"))
name = tcc_basename(default_file);
pstrcpy(buf, sizeof(buf), name);
ext = tcc_fileextension(buf);
#ifdef TCC_TARGET_PE
if (s->output_type == TCC_OUTPUT_DLL)
strcpy(ext, ".dll");
else
if (s->output_type == TCC_OUTPUT_EXE)
strcpy(ext, ".exe");
else
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 ***)&s->files, &s->nb_files, tcc_strdup(r));
s->nb_libraries++;
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
if (( (s->output_type == TCC_OUTPUT_OBJ && !s->reloc_output) ||
(s->output_type == TCC_OUTPUT_PREPROCESS) )
&& *ext)
strcpy(ext, ".o");
else
strcpy(buf, "a.out");
return tcc_strdup(buf);
}
PUB_FUNC void tcc_gen_makedeps(TCCState *s, const char *target, const char *filename)
{
FILE *depout;
char buf[1024], *ext;
int i;
if (!filename) {
/* 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;
#ifdef CONFIG_TCC_BCHECK
case TCC_OPTION_b:
s->do_bounds_check = 1;
s->do_debug = 1;
break;
#endif
case TCC_OPTION_g:
s->do_debug = 1;
break;
case TCC_OPTION_c:
s->output_type = TCC_OUTPUT_OBJ;
break;
case TCC_OPTION_static:
s->static_link = 1;
break;
case TCC_OPTION_shared:
s->output_type = TCC_OUTPUT_DLL;
break;
case TCC_OPTION_soname:
s->soname = tcc_strdup(optarg);
break;
case TCC_OPTION_m:
s->option_m = tcc_strdup(optarg);
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)
printf("<- %s\n", filename);
if (pthread && s->output_type != TCC_OUTPUT_OBJ)
tcc_set_options(s, "-lpthread");
/* XXX return err codes instead of error() ? */
depout = fopen(filename, "w");
if (!depout)
tcc_error("could not open '%s'", filename);
tcc_set_linker(s, (const char *)linker_arg.data);
cstr_free(&linker_arg);
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);
return optind;
}
LIBTCCAPI int tcc_set_options(TCCState *s, const char *str)
{
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)
@ -1668,53 +1933,3 @@ PUB_FUNC void tcc_print_stats(TCCState *s, int64_t total_time)
tt, (int)(total_lines / tt),
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 */
LIBTCCAPI void tcc_delete(TCCState *s);
/* add debug information in the generated code */
LIBTCCAPI void tcc_enable_debug(TCCState *s);
/* set CONFIG_TCCDIR at runtime */
LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path);
/* set error/warning display callback */
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 */
LIBTCCAPI int tcc_set_warning(TCCState *s, const char *warning_name, int value);
/* set linker option */
LIBTCCAPI const char * tcc_set_linker(TCCState *s, char *option, int multi);
/* set options as from command line (multiple supported) */
LIBTCCAPI int tcc_set_options(TCCState *s, const char *str);
/*****************************/
/* preprocessor */
@ -50,29 +47,22 @@ LIBTCCAPI void tcc_undefine_symbol(TCCState *s, const char *sym);
/*****************************/
/* compiling */
/* add a file (either a C file, dll, an object, a library or an ld
script). Return -1 if error. */
/* add a file (C file, dll, object, library, ld script). Return -1 if error. */
LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename);
/* compile a string containing a C source. Return non zero if
error. */
/* compile a string containing a C source. Return -1 if error. */
LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf);
/*****************************/
/* linking commands */
/* set output type. MUST BE CALLED before any compilation */
#define TCC_OUTPUT_MEMORY 0 /* output will be ran in memory (no
output file) (default) */
LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type);
#define TCC_OUTPUT_MEMORY 0 /* output will be run in memory (default) */
#define TCC_OUTPUT_EXE 1 /* executable file */
#define TCC_OUTPUT_DLL 2 /* dynamic library */
#define TCC_OUTPUT_OBJ 3 /* object file */
#define TCC_OUTPUT_PREPROCESS 4 /* preprocessed file (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 */
#define TCC_OUTPUT_PREPROCESS 4 /* only preprocess (used internally) */
/* equivalent to -Lpath option */
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. */
LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv);
/* do all relocations (needed before using tcc_get_symbol())
possible values for 'ptr':
/* do all relocations (needed before using tcc_get_symbol()) */
LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr);
/* possible values for 'ptr':
- TCC_RELOCATE_AUTO : Allocate and manage memory internally
- NULL : return required memory size for the step below
- memory address : copy code to memory passed by the caller
returns -1 on error. */
LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr);
returns -1 if error. */
#define TCC_RELOCATE_AUTO (void*)1
/* return symbol value or NULL if not found */
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
}
#endif

610
tcc.c
View File

@ -24,22 +24,6 @@
#include "tcc.h"
#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)
{
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"
" -Dsym[=val] define 'sym' with value 'val'\n"
" -Usym undefine 'sym'\n"
" -nostdinc do not use standard system include paths\n"
"Linker options:\n"
" -Ldir add library path 'dir'\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"
" -r generate (relocatable) object file\n"
" -rdynamic export all global symbols to dynamic linker\n"
" -shared generate a shared library\n"
" -soname set name for shared library to be used at runtime\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"
" -g generate runtime debug info\n"
#ifdef CONFIG_TCC_BCHECK
@ -82,146 +63,14 @@ static void help(void)
" -bt N show N callers in stack traces\n"
#endif
"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"
" -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: */
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
#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);
}
}
#else
#define exec_other_tcc(s, argv, optarg)
#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);
char *value = strchr(sym, '=');
if (value)
*value++ = '\0';
tcc_define_symbol(s1, sym, value);
tcc_free(sym);
FILE *depout;
char buf[1024], *ext;
int i;
if (!filename) {
/* 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;
const TCCOption *popt;
const char *optarg, *p1, *r1;
char *r;
int was_pthread;
char buf[1024];
char *ext;
const char *name = "a";
was_pthread = 0; /* is set if commandline contains -pthread key */
optind = 0;
cstr_new(&linker_arg);
while (optind < argc) {
r = argv[optind++];
if (r[0] != '-' || r[1] == '\0') {
/* add a new file */
dynarray_add((void ***)&files, &nb_files, r);
if (!multiple_files) {
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;
if (first_file && strcmp(first_file, "-"))
name = tcc_basename(first_file);
pstrcpy(buf, sizeof(buf), name);
ext = tcc_fileextension(buf);
#ifdef TCC_TARGET_PE
if (s->output_type == TCC_OUTPUT_DLL)
strcpy(ext, ".dll");
else
if (s->output_type == TCC_OUTPUT_EXE)
strcpy(ext, ".exe");
else
#endif
#ifdef CONFIG_TCC_BCHECK
case TCC_OPTION_b:
s->do_bounds_check = 1;
s->do_debug = 1;
break;
if (( (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) ||
(s->output_type == TCC_OUTPUT_PREPROCESS) )
&& *ext)
strcpy(ext, ".o");
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
case TCC_OPTION_g:
s->do_debug = 1;
break;
case TCC_OPTION_c:
multiple_files = 1;
output_type = TCC_OUTPUT_OBJ;
break;
case TCC_OPTION_static:
s->static_link = 1;
break;
case TCC_OPTION_shared:
output_type = TCC_OUTPUT_DLL;
break;
case TCC_OPTION_soname:
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;
}
}
#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;
}
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 */
if (was_pthread && output_type != TCC_OUTPUT_OBJ) {
dynarray_add((void ***)&files, &nb_files, "-lpthread");
nb_libraries++;
}
return optind;
}
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
}
int main(int argc, char **argv)
{
int i;
TCCState *s;
int nb_objfiles, ret, optind;
int ret, optind, i, bench;
int64_t start_time = 0;
const char *default_file = NULL;
const char *first_file = NULL;
s = tcc_new();
s->output_type = TCC_OUTPUT_EXE;
output_type = TCC_OUTPUT_EXE;
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 = tcc_parse_args(s, argc - 1, argv + 1);
optind = parse_args(s, argc - 1, argv + 1);
#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;
}
if (optind == 0) {
help();
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
executable */
if (outfile && output_type == TCC_OUTPUT_MEMORY)
output_type = TCC_OUTPUT_EXE;
if (s->verbose)
display_info(s, 0);
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 */
if (output_type == TCC_OUTPUT_OBJ && !reloc_output) {
/* accepts only a single input file */
if (nb_objfiles != 1)
tcc_error("cannot specify multiple files with -c");
if (nb_libraries != 0)
if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) {
if (s->nb_libraries != 0)
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 (!outfile) {
s->outfile = stdout;
if (s->output_type == TCC_OUTPUT_PREPROCESS) {
if (!s->outfile) {
s->ppfp = stdout;
} else {
s->outfile = fopen(outfile, "w");
if (!s->outfile)
tcc_error("could not open '%s'", outfile);
s->ppfp = fopen(s->outfile, "w");
if (!s->ppfp)
tcc_error("could not write '%s'", s->outfile);
}
}
if (do_bench) {
bench = s->do_bench;
if (bench)
start_time = getclock_us();
}
tcc_set_output_type(s, output_type);
s->reloc_output = reloc_output;
tcc_set_output_type(s, s->output_type);
/* 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;
filename = files[i];
filename = s->files[i];
if (filename[0] == '-' && filename[1] == 'l') {
if (tcc_add_library(s, filename + 2) < 0) {
tcc_error_noabort("cannot find %s", filename);
tcc_error_noabort("cannot find '%s'", filename);
ret = 1;
}
} else {
@ -584,16 +314,13 @@ psd:
printf("-> %s\n", filename);
if (tcc_add_file(s, filename) < 0)
ret = 1;
if (!default_file)
default_file = filename;
if (!first_file)
first_file = filename;
}
}
/* free all files */
tcc_free(files);
if (0 == ret) {
if (do_bench)
if (bench)
tcc_print_stats(s, getclock_us() - start_time);
if (s->output_type == TCC_OUTPUT_MEMORY) {
@ -601,28 +328,23 @@ psd:
ret = tcc_run(s, argc - 1 - optind, argv + 1 + optind);
#else
tcc_error_noabort("-run is not available in a cross compiler");
ret = 1;
#endif
} else if (s->output_type == TCC_OUTPUT_PREPROCESS) {
if (s->outfile)
fclose(s->outfile);
fclose(s->ppfp);
} else {
if (!outfile)
outfile = tcc_default_target(s, default_file);
ret = !!tcc_output_file(s, outfile);
if (!s->outfile)
s->outfile = default_outputfile(s, first_file);
ret = !!tcc_output_file(s, s->outfile);
/* dump collected dependencies */
if (gen_deps && !ret)
tcc_gen_makedeps(s, outfile, deps_outfile);
if (s->gen_deps && !ret)
gen_makedeps(s, s->outfile, s->deps_outfile);
}
}
tcc_delete(s);
cstr_free(&linker_arg);
tcc_free(outfile);
#ifdef MEM_DEBUG
if (do_bench) {
printf("memory: %d bytes, max = %d bytes\n", mem_cur_size, mem_max_size);
}
#endif
if (bench)
tcc_memstats();
return ret;
}

354
tcc.h
View File

@ -25,10 +25,8 @@
#include "config.h"
#ifdef CONFIG_TCCBOOT
#include "tccboot.h"
#define CONFIG_TCC_STATIC
#else
#include <stdlib.h>
@ -70,16 +68,8 @@
#endif /* !CONFIG_TCCBOOT */
#ifndef PAGESIZE
#define PAGESIZE 4096
#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif
#ifndef SA_SIGINFO
#define SA_SIGINFO 0x00000004u
# define O_BINARY 0
#endif
#include "elf.h"
@ -516,29 +506,108 @@ struct sym_attr {
};
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;
int nb_include_paths;
char **sysinclude_paths;
int nb_sysinclude_paths;
CachedInclude **cached_includes;
int nb_cached_includes;
/* library paths */
char **library_paths;
int nb_library_paths;
/* crt?.o object path */
char **crt_paths;
int nb_crt_paths;
/* array of all loaded dlls (including those referenced by loaded
dlls) */
DLLReference **loaded_dlls;
int nb_loaded_dlls;
/* 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;
/* 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 */
Section **sections;
@ -559,137 +628,54 @@ struct TCCState {
Section *dynsymtab_section;
/* exported dynamic symbol section */
Section *dynsym;
/* copy of the gobal symtab_section variable */
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 */
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
/* PE info */
int pe_subsystem;
unsigned long pe_file_align;
unsigned long pe_stack_size;
#ifdef TCC_TARGET_X86_64
unsigned pe_file_align;
unsigned pe_stack_size;
# ifdef TCC_TARGET_X86_64
Section *uw_pdata;
int uw_sym;
unsigned uw_offs;
#endif
# endif
#endif
#if defined TCC_IS_NATIVE && !defined TCC_TARGET_PE \
&& (defined TCC_TARGET_X86_64 || defined TCC_TARGET_ARM)
#ifdef TCC_IS_NATIVE
/* 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 */
char *runtime_plt_and_got;
unsigned int runtime_plt_and_got_offset;
# define TCC_HAS_RUNTIME_PLTGOT
unsigned runtime_plt_and_got_offset;
# define TCC_HAS_RUNTIME_PLTGOT
# 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: */
#define VT_VALMASK 0x003f
#define VT_CONST 0x0030 /* constant in vc
(must be first non register value) */
#define VT_VALMASK 0x003f /* mask for value location, register or: */
#define VT_CONST 0x0030 /* constant in vc (must be first non register value) */
#define VT_LLOCAL 0x0031 /* lvalue, offset on stack */
#define VT_LOCAL 0x0032 /* offset on stack */
#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)
/* types */
#define VT_INT 0 /* integer type */
#define VT_BYTE 1 /* signed byte type */
#define VT_SHORT 2 /* short type */
#define VT_VOID 3 /* void type */
#define VT_PTR 4 /* pointer */
#define VT_ENUM 5 /* enum definition */
#define VT_FUNC 6 /* function type */
#define VT_STRUCT 7 /* struct/union definition */
#define VT_FLOAT 8 /* IEEE float */
#define VT_DOUBLE 9 /* IEEE double */
#define VT_LDOUBLE 10 /* IEEE long double */
#define VT_BOOL 11 /* ISOC99 boolean type */
#define VT_LLONG 12 /* 64 bit integer */
#define VT_LONG 13 /* long integer (NEVER USED as type, only
during parsing) */
#define VT_BTYPE 0x000f /* mask for basic type */
#define VT_UNSIGNED 0x0010 /* unsigned type */
#define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */
#define VT_VLA 0x20000 /* VLA type (also has VT_PTR and VT_ARRAY) */
#define VT_BITFIELD 0x0040 /* bitfield modifier */
#define VT_CONSTANT 0x0800 /* const modifier */
#define VT_VOLATILE 0x1000 /* volatile modifier */
#define VT_SIGNED 0x2000 /* signed type */
#define VT_BTYPE 0x000f /* mask for basic type */
#define VT_INT 0 /* integer type */
#define VT_BYTE 1 /* signed byte type */
#define VT_SHORT 2 /* short type */
#define VT_VOID 3 /* void type */
#define VT_PTR 4 /* pointer */
#define VT_ENUM 5 /* enum definition */
#define VT_FUNC 6 /* function type */
#define VT_STRUCT 7 /* struct/union definition */
#define VT_FLOAT 8 /* IEEE float */
#define VT_DOUBLE 9 /* IEEE double */
#define VT_LDOUBLE 10 /* IEEE long double */
#define VT_BOOL 11 /* ISOC99 boolean type */
#define VT_LLONG 12 /* 64 bit integer */
#define VT_LONG 13 /* long integer (NEVER USED as type, only
during parsing) */
#define VT_UNSIGNED 0x0010 /* unsigned type */
#define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */
#define VT_BITFIELD 0x0040 /* bitfield modifier */
#define VT_CONSTANT 0x0800 /* const modifier */
#define VT_VOLATILE 0x1000 /* volatile modifier */
#define VT_SIGNED 0x2000 /* signed type */
#define VT_VLA 0x00020000 /* VLA type (also has VT_PTR and VT_ARRAY) */
/* storage */
#define VT_EXTERN 0x00000080 /* extern definition */
@ -741,13 +727,13 @@ struct TCCState {
#define VT_INLINE 0x00000400 /* inline definition */
#define VT_IMPORT 0x00004000 /* win32: extern data imported 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) */
#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 */
@ -999,6 +985,11 @@ ST_DATA int tcc_ext;
/* XXX: get rid of this ASAP */
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_REFERENCED_DLL 0x0002 /* load a referenced dll from another dll */
#define AFF_PREPROCESS 0x0004 /* preprocess file */
@ -1020,19 +1011,19 @@ PUB_FUNC char *tcc_strdup(const char *str);
#undef strdup
#define strdup(s) use_tcc_strdup(s)
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(const char *fmt, ...);
PUB_FUNC void tcc_warning(const char *fmt, ...);
/* other utilities */
PUB_FUNC void cstr_ccat(CString *cstr, int ch);
PUB_FUNC void cstr_cat(CString *cstr, const char *str);
PUB_FUNC void cstr_wccat(CString *cstr, int ch);
PUB_FUNC void cstr_new(CString *cstr);
PUB_FUNC void cstr_free(CString *cstr);
PUB_FUNC void cstr_reset(CString *cstr);
ST_FUNC void dynarray_add(void ***ptab, int *nb_ptr, void *data);
ST_FUNC void dynarray_reset(void *pp, int *n);
ST_FUNC void cstr_ccat(CString *cstr, int ch);
ST_FUNC void cstr_cat(CString *cstr, const char *str);
ST_FUNC void cstr_wccat(CString *cstr, int ch);
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 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_crt(TCCState *s, const char *filename);
#ifndef TCC_TARGET_PE
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 char *tcc_default_target(TCCState *s, const char *default_file);
PUB_FUNC void tcc_gen_makedeps(TCCState *s, const char *target, const char *filename);
PUB_FUNC void tcc_display_info(TCCState *s, int what);
PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv);
/* ------------ tccpp.c ------------ */
@ -1208,6 +1194,10 @@ ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsign
/* ------------ 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 */
typedef struct {
@ -1259,11 +1249,11 @@ ST_FUNC int handle_eob(void);
/* ------------ xxx-gen.c ------------ */
ST_DATA const int reg_classes[NB_REGS
#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
];
ST_FUNC void gsym_addr(int t, int a);
ST_FUNC void gsym(int t);
@ -1329,7 +1319,6 @@ ST_FUNC int tcc_load_coff(TCCState * s1, int fd);
/* ------------ tccasm.c ------------ */
ST_FUNC void asm_instr(void);
ST_FUNC void asm_global_instr(void);
#ifdef CONFIG_TCC_ASM
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);
@ -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_clobber(uint8_t *clobber_regs, const char *str);
#endif
/* ------------ tccpe.c -------------- */
#ifdef TCC_TARGET_PE
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_putimport(TCCState *s1, int dllindex, const char *name, addr_t value);
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
ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack);
#endif
@ -1366,7 +1354,7 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack);
/* dummy function for profiling */
ST_FUNC void *dlopen(const char *filename, int flag);
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);
#elif !defined _WIN32
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 const char **rt_bound_error_msg;
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

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) {
/* we accept that two DLL define the same symbol */
} 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",
sym_bind, sh_num, new_vis, esym_bind, esym->st_shndx, esym_vis);
#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);
return len == fread(buffer, 1, len, fp);
lseek(fd, offset, SEEK_SET);
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 ...'.
*/
static int pe_load_res(TCCState *s1, FILE *fp)
static int pe_load_res(TCCState *s1, int fd)
{
struct pe_rsrc_header hdr;
Section *rsrc_section;
@ -1524,7 +1524,7 @@ static int pe_load_res(TCCState *s1, FILE *fp)
BYTE *ptr;
unsigned offs;
if (!read_mem(fp, 0, &hdr, sizeof hdr))
if (!read_mem(fd, 0, &hdr, sizeof hdr))
goto quit;
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);
ptr = section_ptr_add(rsrc_section, hdr.sectionhdr.SizeOfRawData);
offs = hdr.sectionhdr.PointerToRawData;
if (!read_mem(fp, offs, ptr, hdr.sectionhdr.SizeOfRawData))
if (!read_mem(fd, offs, ptr, hdr.sectionhdr.SizeOfRawData))
goto quit;
offs = hdr.sectionhdr.PointerToRelocations;
for (i = 0; i < hdr.sectionhdr.NumberOfRelocations; ++i)
{
struct pe_rsrc_reloc rel;
if (!read_mem(fp, offs, &rel, sizeof rel))
if (!read_mem(fd, offs, &rel, sizeof rel))
goto quit;
// printf("rsrc_reloc: %x %x %x\n", rel.offset, rel.size, rel.type);
if (rel.type != 7) /* DIR32NB */
@ -1571,22 +1571,26 @@ static char *trimback(char *a, char *e)
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;
trimback(line, strchr(line, 0));
trimback(line, line + n);
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;
char line[400], dllname[80], *p;
for (;;) {
p = get_line(line, sizeof line, fp);
p = get_line(line, sizeof line, fd);
if (NULL == p)
break;
if (0 == *p || ';' == *p)
@ -1623,11 +1627,11 @@ quit:
#define TINY_IMPDEF_GET_EXPORT_NAMES_ONLY
#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;
int index;
p = get_export_names(fp);
p = get_export_names(fd);
if (!p)
return -1;
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)
{
FILE *fp = fdopen(dup(fd), "rb");
int ret = -1;
char buf[10];
if (fp) {
if (0 == strcmp(tcc_fileextension(filename), ".def"))
ret = pe_load_def(s1, fp);
else if (pe_load_res(s1, fp) == 0)
ret = 0;
else if (read_mem(fp, 0, buf, sizeof buf) && 0 == strncmp(buf, "MZ", 2))
ret = pe_load_dll(s1, tcc_basename(filename), fp);
fclose(fp);
}
if (0 == strcmp(tcc_fileextension(filename), ".def"))
ret = pe_load_def(s1, fd);
else if (pe_load_res(s1, fd) == 0)
ret = 0;
else if (read_mem(fd, 0, buf, sizeof buf) && 0 == strncmp(buf, "MZ", 2))
ret = pe_load_dll(s1, tcc_basename(filename), fd);
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
#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;
ADDR3264 addr = 0;
@ -1762,15 +1762,17 @@ static void pe_add_runtime_ex(TCCState *s1, struct pe_info *pe)
if (0 == s1->nostdlib) {
static const char *libs[] = {
"tcc1", "msvcrt", "kernel32", "", "user32", "gdi32", NULL
"libtcc1.a", "msvcrt", "kernel32", "", "user32", "gdi32", NULL
};
const char **pp, *p;
for (pp = libs; 0 != (p = *pp); ++pp) {
if (0 == *p) {
if (PE_DLL != pe_type && PE_GUI != pe_type)
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);
break;
}
}
}
@ -1802,7 +1804,7 @@ ST_FUNC int pe_output_file(TCCState * s1, const char *filename)
pe.s1 = s1;
tcc_add_bcheck(s1);
pe_add_runtime_ex(s1, &pe);
pe_add_runtime(s1, &pe);
relocate_common_syms(); /* assign bss adresses */
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 */
PUB_FUNC void cstr_ccat(CString *cstr, int ch)
ST_FUNC void cstr_ccat(CString *cstr, int ch)
{
int size;
size = cstr->size + 1;
@ -128,7 +128,7 @@ PUB_FUNC void cstr_ccat(CString *cstr, int ch)
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;
for(;;) {
@ -141,7 +141,7 @@ PUB_FUNC void cstr_cat(CString *cstr, const char *str)
}
/* add a wide char */
PUB_FUNC void cstr_wccat(CString *cstr, int ch)
ST_FUNC void cstr_wccat(CString *cstr, int ch)
{
int size;
size = cstr->size + sizeof(nwchar_t);
@ -151,20 +151,20 @@ PUB_FUNC void cstr_wccat(CString *cstr, int ch)
cstr->size = size;
}
PUB_FUNC void cstr_new(CString *cstr)
ST_FUNC void cstr_new(CString *cstr)
{
memset(cstr, 0, sizeof(CString));
}
/* 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);
cstr_new(cstr);
}
/* reset string to empty */
PUB_FUNC void cstr_reset(CString *cstr)
ST_FUNC void cstr_reset(CString *cstr)
{
cstr->size = 0;
}
@ -3112,17 +3112,17 @@ print_line:
: ""
;
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 {
while (d)
fputs("\n", s1->outfile), --d;
fputs("\n", s1->ppfp), --d;
}
line_ref = (file_ref = file)->line_num;
token_seen = tok != TOK_LINEFEED;
if (!token_seen)
continue;
}
fputs(get_tok_str(tok, &tokc), s1->outfile);
fputs(get_tok_str(tok, &tokc), s1->ppfp);
}
free_defines(define_start);
return 0;

View File

@ -54,33 +54,36 @@ LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr)
if (TCC_RELOCATE_AUTO != 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);
if (-1 != ret) {
s1->runtime_mem = tcc_malloc(ret);
ret = tcc_relocate_ex(s1, s1->runtime_mem);
if (ret < 0)
return ret;
#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
return ret;
}
@ -130,8 +133,7 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr)
addr_t mem;
int i;
if (0 == s1->runtime_added) {
s1->runtime_added = 1;
if (NULL == ptr) {
s1->nb_errors = 0;
#ifdef TCC_TARGET_PE
pe_output_file(s1, NULL);
@ -215,6 +217,9 @@ static void set_pages_executable(void *ptr, unsigned long length)
unsigned long old_protect;
VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect);
#else
#ifndef PAGESIZE
# define PAGESIZE 4096
#endif
addr_t start, end;
start = (addr_t)ptr & ~(PAGESIZE - 1);
end = (addr_t)ptr + length;
@ -226,7 +231,7 @@ static void set_pages_executable(void *ptr, unsigned long length)
/* ------------------------------------------------------------- */
#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;
}
@ -436,6 +441,10 @@ static void sig_error(int signum, siginfo_t *siginf, void *puc)
exit(255);
}
#ifndef SA_SIGINFO
# define SA_SIGINFO 0x00000004u
#endif
/* Generate a stack backtrace when a CPU exception occurs. */
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 /* CONFIG_TCC_BACKTRACE */
/* ------------------------------------------------------------- */
#ifdef CONFIG_TCC_STATIC
#define RTLD_LAZY 0x001
#define RTLD_NOW 0x002
#define RTLD_GLOBAL 0x100
#define RTLD_DEFAULT NULL
/* dummy function for profiling */
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)
{
}
/*
const char *dlerror(void)
ST_FUNC const char *dlerror(void)
{
return "error";
}
*/
typedef struct TCCSyms {
char *str;
void *ptr;
} TCCSyms;
#define TCCSYM(a) { #a, &a, },
/* add the symbol you want here if no dynamic linking is done */
static TCCSyms tcc_syms[] = {
#if !defined(CONFIG_TCCBOOT)
#define TCCSYM(a) { #a, &a, },
TCCSYM(printf)
TCCSYM(fprintf)
TCCSYM(fopen)
TCCSYM(fclose)
#undef TCCSYM
#endif
{ NULL, NULL },
};

View File

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

View File

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

View File

@ -79,7 +79,7 @@ int main(int argc, char **argv)
ElfW(Sym) *sym;
int i, fsize, iarg;
char *buf, *shstr, *symtab = NULL, *strtab = NULL;
int symtabsize = 0, strtabsize = 0;
int symtabsize = 0;//, strtabsize = 0;
char *anames = NULL;
int *afpos = NULL;
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"))
{
strtab = (char *)(buf + shdr->sh_offset);
strtabsize = shdr->sh_size;
//strtabsize = shdr->sh_size;
}
}
}