Browse Source

tcctools.c: integrate tiny_libmaker/_impdef

usage:
    tcc -ar [rcsv] lib files...
    tcc -impdef lib.dll [-v] [-o lib.def]

also:
- support more files with -c: tcc -c f1.c f2.c ...
- fix a bug which caused tcc f1.c f2.S to produce no asm
- allow tcc -ar @listfile too
- change prototype: _void_ tcc_set_options(...)
- apply -Wl,-whole-archive when a librariy is given
  as libxxx.a also (not just for -lxxx)
master
grischka 7 years ago
parent
commit
2d3b9559bf
  1. 1
      Changelog
  2. 20
      Makefile
  3. 1
      TODO
  4. 22
      conftest.c
  5. 30
      lib/Makefile
  6. 210
      libtcc.c
  7. 2
      libtcc.h
  8. 339
      tcc.c
  9. 34
      tcc.h
  10. 1
      tccasm.c
  11. 122
      tccpe.c
  12. 547
      tcctools.c
  13. 2
      tests/tcctest.c
  14. 31
      win32/build-tcc.bat
  15. 22
      win32/tcc-win32.txt
  16. 249
      win32/tools/tiny_impdef.c
  17. 278
      win32/tools/tiny_libmaker.c

1
Changelog

@ -7,6 +7,7 @@ User interface:
- -mms-bitfields option (David Mertens)
- -include <file> option (Michael Matz)
- @listfile support (Vlad Vissoultchev)
- tcc -ar/-impdef - formerly tiny_xxx tools integrated (grischka)
- CPATH, C_INCLUDE_PATH and LD_LIBRARY_PATH environment variables support
(Andrew Aladjev, Urs Janssen)

20
Makefile

@ -28,6 +28,7 @@ LIBS =
ifdef CONFIG_WIN32
ifneq ($(DISABLE_STATIC),no)
LIBTCC = libtcc.dll
LIBTCCDEF = libtcc.def
endif
else
LIBS=-lm
@ -82,7 +83,7 @@ ARM_CROSS = $(ARM_FPA_CROSS) $(ARM_FPA_LD_CROSS) $(ARM_VFP_CROSS) $(ARM_EABI_CRO
ARM64_CROSS = arm64-tcc$(EXESUF)
C67_CROSS = c67-tcc$(EXESUF)
CORE_FILES = tcc.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c tccrun.c
CORE_FILES = tcc.c tcctools.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c tccrun.c
CORE_FILES += tcc.h config.h libtcc.h tcctok.h
I386_FILES = $(CORE_FILES) i386-gen.c i386-link.c i386-asm.c i386-asm.h i386-tok.h
WIN32_FILES = $(CORE_FILES) i386-gen.c i386-link.c i386-asm.c i386-asm.h i386-tok.h tccpe.c
@ -94,7 +95,6 @@ ARM64_FILES = $(CORE_FILES) arm64-gen.c arm64-link.c
C67_FILES = $(CORE_FILES) c67-gen.c c67-link.c tcccoff.c
ifdef CONFIG_WIN32
PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF)
ifeq ($(ARCH),x86-64)
NATIVE_FILES=$(WIN64_FILES)
PROGS_CROSS=$(WIN32_CROSS) $(X64_CROSS) $(ARM_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS)
@ -124,11 +124,7 @@ NATIVE_FILES=$(ARM64_FILES)
PROGS_CROSS=$(I386_CROSS) $(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(C67_CROSS) $(WINCE_CROSS)
endif
ifeq ($(TARGETOS),Darwin)
PROGS += tiny_libmaker$(EXESUF)
endif
TCCLIBS = $(LIBTCC1) $(LIBTCC)
TCCLIBS = $(LIBTCC1) $(LIBTCC) $(LIBTCCDEF)
TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info
ifdef CONFIG_CROSS
@ -179,7 +175,7 @@ $(ARM64_CROSS): $(ARM64_FILES)
# libtcc generation and test
ifndef ONE_SOURCE
LIBTCC_OBJ = $(filter-out tcc.o,$(patsubst %.c,%.o,$(filter %.c,$(NATIVE_FILES))))
LIBTCC_OBJ = $(filter-out tcc.o tcctools.o,$(patsubst %.c,%.o,$(filter %.c,$(NATIVE_FILES))))
LIBTCC_INC = $(filter %.h,$(CORE_FILES)) $(filter-out $(CORE_FILES) i386-asm.c,$(NATIVE_FILES))
else
LIBTCC_OBJ = libtcc.o
@ -187,6 +183,8 @@ LIBTCC_INC = $(NATIVE_FILES)
libtcc.o : NATIVE_DEFINES += -DONE_SOURCE
endif
tcc.o : tcctools.c
$(LIBTCC_OBJ) tcc.o : %.o : %.c $(LIBTCC_INC)
$(CC) -o $@ -c $< $(NATIVE_DEFINES) $(CFLAGS)
@ -199,9 +197,11 @@ libtcc.so: $(LIBTCC_OBJ)
libtcc.so: CFLAGS+=-fPIC
# windows : libtcc.dll
libtcc.dll : $(LIBTCC_OBJ) tiny_impdef$(EXESUF)
libtcc.dll : $(LIBTCC_OBJ)
$(CC) -shared $(LIBTCC_OBJ) -o $@ $(LDFLAGS)
./tiny_impdef $@
libtcc.def : libtcc.dll tcc$(EXESUF)
./tcc$(EXESUF) -impdef $< -o $@
libtcc.dll : NATIVE_DEFINES += -DLIBTCC_AS_DLL

1
TODO

@ -2,6 +2,7 @@ TODO list:
Bugs:
- i386 fastcall is mostly wrong
- FPU st(0) is left unclean (kwisatz haderach). Incompatible with
optimized gcc/msc code
- see transparent union pb in /urs/include/sys/socket.h

22
conftest.c

@ -1,9 +1,9 @@
#include <stdio.h>
/* Define architecture */
#if defined(__i386__)
#if defined(__i386__) || defined _M_IX86
# define TRIPLET_ARCH "i386"
#elif defined(__x86_64__)
#elif defined(__x86_64__) || defined _M_AMD64
# define TRIPLET_ARCH "x86_64"
#elif defined(__arm__)
# define TRIPLET_ARCH "arm"
@ -18,6 +18,8 @@
# define TRIPLET_OS "linux"
#elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
# define TRIPLET_OS "kfreebsd"
#elif defined _WIN32
# define TRIPLET_OS "win32"
#elif !defined (__GNU__)
# define TRIPLET_OS "unknown"
#endif
@ -33,7 +35,9 @@
# define TRIPLET_ABI "gnu"
#endif
#ifdef __GNU__
#if defined _WIN32
# define TRIPLET TRIPLET_ARCH "-" TRIPLET_OS
#elif defined __GNU__
# define TRIPLET TRIPLET_ARCH "-" TRIPLET_ABI
#else
# define TRIPLET TRIPLET_ARCH "-" TRIPLET_OS "-" TRIPLET_ABI
@ -59,6 +63,13 @@ int main(int argc, char *argv[])
case 'v':
printf("%d\n", __GNUC__);
break;
#elif defined __TINYC__
case 'v':
puts("0");
break;
case 'm':
printf("%d\n", __TINYC__);
break;
#else
case 'm':
case 'v':
@ -68,9 +79,8 @@ int main(int argc, char *argv[])
case 't':
puts(TRIPLET);
break;
case -1:
/* to test -Wno-unused-result */
fread(NULL, 1, 1, NULL);
default:
break;
}
return 0;

30
lib/Makefile

@ -20,9 +20,6 @@ ifndef TARGET
TARGET = x86_64
else ifeq ($(ARCH),arm)
TARGET = arm
# using gcc, need asm
XCC = $(CC)
XFLAGS = $(CFLAGS) -fPIC
else ifeq ($(ARCH),arm64)
TARGET = arm64
endif
@ -37,6 +34,9 @@ cross : $(DIR)/libtcc1.a
native : TCC = $(TOP)/tcc$(EXESUF)
cross : TCC = $(TOP)/$(TARGET)-tcc$(EXESUF)
XCC = $(TCC) -B$(TOPSRC)
XAR = $(TCC) -ar
I386_O = libtcc1.o alloca86.o alloca86-bt.o $(BCHECK_O)
X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o $(BCHECK_O)
ARM_O = libtcc1.o armeabi.o alloca-arm.o
@ -47,53 +47,43 @@ ifeq "$(TARGET)" "i386-win32"
OBJ = $(addprefix $(DIR)/,$(I386_O) $(WIN32_O))
TGT = -DTCC_TARGET_I386 -DTCC_TARGET_PE
XCC = $(TCC) -B$(TOPSRC)/win32 -I$(TOPSRC)/include
XAR = $(DIR)/tiny_libmaker$(EXESUF)
else ifeq "$(TARGET)" "x86_64-win32"
OBJ = $(addprefix $(DIR)/,$(X86_64_O) $(WIN32_O))
TGT = -DTCC_TARGET_X86_64 -DTCC_TARGET_PE
XCC = $(TCC) -B$(TOPSRC)/win32 -I$(TOPSRC)/include
XAR = $(DIR)/tiny_libmaker$(EXESUF)
else ifeq "$(TARGET)" "i386"
OBJ = $(addprefix $(DIR)/,$(I386_O))
TGT = -DTCC_TARGET_I386
XCC ?= $(TCC) -B$(TOPSRC)
else ifeq "$(TARGET)" "x86_64"
OBJ = $(addprefix $(DIR)/,$(X86_64_O))
TGT = -DTCC_TARGET_X86_64
XCC ?= $(TCC) -B$(TOPSRC)
else ifeq "$(TARGET)" "arm"
OBJ = $(addprefix $(DIR)/,$(ARM_O))
TGT = -DTCC_TARGET_ARM
XCC ?= $(TCC) -B$(TOPSRC)
# using gcc, need asm
XCC = $(CC)
XFLAGS = $(CFLAGS) -fPIC
XAR = $(AR)
else ifeq "$(TARGET)" "arm64"
OBJ = $(addprefix $(DIR)/,$(ARM64_O))
TGT = -DTCC_TARGET_ARM64
XCC ?= $(TCC) -B$(TOPSRC)
else
$(error libtcc1.a not supported on target '$(TARGET)')
endif
ifeq ($(TARGETOS),Darwin)
XAR = $(DIR)/tiny_libmaker$(EXESUF)
XFLAGS += -D_ANSI_SOURCE
BCHECK_O =
endif
ifdef XAR
AR = $(XAR)
endif
$(DIR)/libtcc1.a ../libtcc1.a : $(OBJ) $(XAR)
$(AR) rcs $@ $(OBJ)
$(DIR)/libtcc1.a ../libtcc1.a : $(OBJ)
$(XAR) rcs $@ $(OBJ)
$(DIR)/%.o : %.c
$(XCC) -c $< -o $@ $(TGT) $(XFLAGS)
$(DIR)/%.o : %.S
$(XCC) -c $< -o $@ $(TGT) $(XFLAGS)
# windows : utilities
$(DIR)/tiny_%$(EXESUF) : $(TOPSRC)/win32/tools/tiny_%.c
$(CC) -o $@ $< $(CFLAGS) $(LDFLAGS) $(TGT)
$(OBJ) $(XAR) : $(DIR)/exists
$(OBJ) : $(DIR)/exists
%/exists :
mkdir -p $(DIR)

210
libtcc.c

@ -239,7 +239,7 @@ PUB_FUNC char *tcc_strdup(const char *str)
return ptr;
}
PUB_FUNC void tcc_memstats(int bench)
PUB_FUNC void tcc_memcheck(void)
{
}
@ -379,7 +379,7 @@ PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line)
return ptr;
}
PUB_FUNC void tcc_memstats(int bench)
PUB_FUNC void tcc_memcheck(void)
{
if (mem_cur_size) {
mem_debug_header_t *header = mem_debug_chain;
@ -393,8 +393,7 @@ PUB_FUNC void tcc_memstats(int bench)
#if MEM_DEBUG-0 == 2
exit(2);
#endif
} else if (bench)
fprintf(stderr, "mem_max_size= %d bytes\n", mem_max_size);
}
}
#endif /* MEM_DEBUG */
@ -435,7 +434,7 @@ ST_FUNC void dynarray_reset(void *pp, int *n)
*(void**)pp = NULL;
}
static void tcc_split_path(TCCState *s, void ***p_ary, int *p_nb_ary, const char *in)
static void tcc_split_path(TCCState *s, void *p_ary, int *p_nb_ary, const char *in)
{
const char *p;
do {
@ -878,18 +877,14 @@ LIBTCCAPI TCCState *tcc_new(void)
tcc_define_symbol(s, "__REDIRECT_NTH(name, proto, alias)",
"name proto __asm__ (#alias) __THROW");
# endif
#endif /* ndef TCC_TARGET_PE */
/* Some GCC builtins that are simple to express as macros. */
tcc_define_symbol(s, "__builtin_extract_return_addr(x)", "x");
#endif /* ndef TCC_TARGET_PE */
return s;
}
LIBTCCAPI void tcc_delete(TCCState *s1)
{
int bench = s1->do_bench;
tcc_cleanup();
/* free sections */
@ -915,6 +910,7 @@ LIBTCCAPI void tcc_delete(TCCState *s1)
dynarray_reset(&s1->files, &s1->nb_files);
dynarray_reset(&s1->target_deps, &s1->nb_target_deps);
dynarray_reset(&s1->pragma_libs, &s1->nb_pragma_libs);
dynarray_reset(&s1->argv, &s1->argc);
#ifdef TCC_IS_NATIVE
/* free runtime memory */
@ -923,7 +919,7 @@ LIBTCCAPI void tcc_delete(TCCState *s1)
tcc_free(s1);
if (0 == --nb_states)
tcc_memstats(bench);
tcc_memcheck();
}
LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type)
@ -965,7 +961,7 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type)
# endif
#else
/* paths for crt objects */
tcc_split_path(s, (void ***)&s->crt_paths, &s->nb_crt_paths, CONFIG_TCC_CRTPREFIX);
tcc_split_path(s, &s->crt_paths, &s->nb_crt_paths, CONFIG_TCC_CRTPREFIX);
/* add libc crt1/crti objects */
if ((output_type == TCC_OUTPUT_EXE || output_type == TCC_OUTPUT_DLL) &&
!s->nostdlib) {
@ -979,13 +975,13 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type)
LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname)
{
tcc_split_path(s, (void ***)&s->include_paths, &s->nb_include_paths, pathname);
tcc_split_path(s, &s->include_paths, &s->nb_include_paths, pathname);
return 0;
}
LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname)
{
tcc_split_path(s, (void ***)&s->sysinclude_paths, &s->nb_sysinclude_paths, pathname);
tcc_split_path(s, &s->sysinclude_paths, &s->nb_sysinclude_paths, pathname);
return 0;
}
@ -1106,7 +1102,7 @@ LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename)
LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname)
{
tcc_split_path(s, (void ***)&s->library_paths, &s->nb_library_paths, pathname);
tcc_split_path(s, &s->library_paths, &s->nb_library_paths, pathname);
return 0;
}
@ -1440,6 +1436,7 @@ typedef struct TCCOption {
enum {
TCC_OPTION_HELP,
TCC_OPTION_v,
TCC_OPTION_I,
TCC_OPTION_D,
TCC_OPTION_U,
@ -1480,13 +1477,14 @@ enum {
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
TCC_OPTION_x,
TCC_OPTION_ar,
TCC_OPTION_impdef
};
#define TCC_OPTION_HAS_ARG 0x0001
@ -1496,6 +1494,7 @@ static const TCCOption tcc_options[] = {
{ "h", TCC_OPTION_HELP, 0 },
{ "-help", TCC_OPTION_HELP, 0 },
{ "?", TCC_OPTION_HELP, 0 },
{ "v", TCC_OPTION_v, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "I", TCC_OPTION_I, TCC_OPTION_HAS_ARG },
{ "D", TCC_OPTION_D, TCC_OPTION_HAS_ARG },
{ "U", TCC_OPTION_U, TCC_OPTION_HAS_ARG },
@ -1542,13 +1541,16 @@ static const TCCOption tcc_options[] = {
{ "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 },
{ "ar", TCC_OPTION_ar, 0},
#ifdef TCC_TARGET_PE
{ "impdef", TCC_OPTION_impdef, 0},
#endif
{ NULL, 0, 0 },
};
@ -1595,58 +1597,106 @@ static void args_parser_add_file(TCCState *s, const char* filename, int filetype
{
struct filespec *f = tcc_malloc(sizeof *f + strlen(filename));
f->type = filetype;
f->alacarte = s->alacarte_link;
strcpy(f->name, filename);
dynarray_add(&s->files, &s->nb_files, f);
}
static int args_parser_make_argv(const char *r, int *argc, char ***argv)
{
int ret = 0, q, c;
CString str;
for(;;) {
while (c = (unsigned char)*r, c && c <= ' ')
++r;
if (c == 0)
break;
q = 0;
cstr_new(&str);
while (c = (unsigned char)*r, c) {
++r;
if (c == '\\' && (*r == '"' || *r == '\\')) {
c = *r++;
} else if (c == '"') {
q = !q;
continue;
} else if (q == 0 && c <= ' ') {
break;
}
cstr_ccat(&str, c);
}
cstr_ccat(&str, 0);
//printf("<%s>\n", str.data), fflush(stdout);
dynarray_add(argv, argc, tcc_strdup(str.data));
cstr_free(&str);
++ret;
}
return ret;
}
/* read list file */
static void args_parser_listfile(TCCState *s, const char *filename)
static void args_parser_listfile(TCCState *s,
const char *filename, int optind, int *pargc, char ***pargv)
{
int fd;
int fd, i;
size_t len;
char *p;
int argc = 0;
char **argv = NULL;
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
tcc_error("file '%s' not found", filename);
tcc_error("listfile '%s' not found", filename);
len = lseek(fd, 0, SEEK_END);
p = tcc_malloc(len + 1), p[len] = 0;
lseek(fd, 0, SEEK_SET), read(fd, p, len), close(fd);
tcc_set_options(s, p);
for (i = 0; i < *pargc; ++i)
if (i == optind)
args_parser_make_argv(p, &argc, &argv);
else
dynarray_add(&argv, &argc, tcc_strdup((*pargv)[i]));
tcc_free(p);
dynarray_reset(&s->argv, &s->argc);
*pargc = s->argc = argc, *pargv = s->argv = argv;
}
PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv)
PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv, int optind)
{
const TCCOption *popt;
const char *optarg, *r;
const char *run = NULL;
int optind = 0;
int x;
int last_o = -1;
int x;
CString linker_arg; /* collect -Wl options */
char buf[1024];
int tool = 0, arg_start = 0, noaction = optind;
char **argv = *pargv;
int argc = *pargc;
cstr_new(&linker_arg);
while (optind < argc) {
r = argv[optind++];
reparse:
r = argv[optind];
if (r[0] == '@' && r[1] != '\0') {
args_parser_listfile(s, r + 1);
args_parser_listfile(s, r + 1, optind, &argc, &argv);
continue;
}
optind++;
if (tool) {
if (r[0] == '-' && r[1] == 'v' && r[2] == 0)
++s->verbose;
continue;
}
reparse:
if (r[0] != '-' || r[1] == '\0') {
if (r[0] != '@') /* allow "tcc file(s) -run @ args ..." */
args_parser_add_file(s, r, s->filetype);
if (run) {
tcc_set_options(s, run);
optind--;
/* argv[0] will be this file */
arg_start = optind - 1;
break;
}
continue;
@ -1675,7 +1725,7 @@ reparse:
switch(popt->index) {
case TCC_OPTION_HELP:
return 0;
return OPT_HELP;
case TCC_OPTION_I:
tcc_add_include_path(s, optarg);
break;
@ -1693,7 +1743,7 @@ reparse:
tcc_set_lib_path(s, optarg);
break;
case TCC_OPTION_l:
args_parser_add_file(s, optarg, AFF_TYPE_LIBWH - s->alacarte_link);
args_parser_add_file(s, optarg, AFF_TYPE_LIB);
s->nb_libraries++;
break;
case TCC_OPTION_pthread:
@ -1774,9 +1824,6 @@ reparse:
case TCC_OPTION_nostdlib:
s->nostdlib = 1;
break;
case TCC_OPTION_print_search_dirs:
s->print_search_dirs = 1;
break;
case TCC_OPTION_run:
#ifndef TCC_IS_NATIVE
tcc_error("-run is not available in a cross compiler");
@ -1786,6 +1833,7 @@ reparse:
goto set_output_type;
case TCC_OPTION_v:
do ++s->verbose; while (*optarg++ == 'v');
++noaction;
break;
case TCC_OPTION_f:
if (set_flag(s, options_f, optarg) < 0)
@ -1804,12 +1852,13 @@ reparse:
break;
#endif
case TCC_OPTION_m:
if (set_flag(s, options_m, optarg) == 0)
break;
else if (x = atoi(optarg), x == 32 || x == 64)
s->cross_target = x;
else
goto unsupported_option;
if (set_flag(s, options_m, optarg) < 0) {
if (x = atoi(optarg), x != 32 && x != 64)
goto unsupported_option;
if (PTR_SIZE != x/8)
return x;
++noaction;
}
break;
case TCC_OPTION_W:
if (set_flag(s, options_W, optarg) < 0)
@ -1860,6 +1909,20 @@ reparse:
case TCC_OPTION_O:
last_o = atoi(optarg);
break;
case TCC_OPTION_print_search_dirs:
x = OPT_PRINT_DIRS;
goto extra_action;
case TCC_OPTION_impdef:
x = OPT_IMPDEF;
goto extra_action;
case TCC_OPTION_ar:
x = OPT_AR;
extra_action:
arg_start = optind - 1;
if (arg_start != noaction)
tcc_error("cannot parse %s here", r);
tool = x;
break;
case TCC_OPTION_traditional:
case TCC_OPTION_pedantic:
case TCC_OPTION_pipe:
@ -1873,53 +1936,32 @@ unsupported_option:
break;
}
}
if (last_o > 0)
tcc_define_symbol(s, "__OPTIMIZE__", NULL);
if (linker_arg.size) {
r = linker_arg.data;
goto arg_err;
}
return optind;
*pargc = argc - arg_start;
*pargv = argv + arg_start;
if (tool)
return tool;
if (optind != noaction)
return 0;
if (s->verbose == 2)
return OPT_PRINT_DIRS;
if (s->verbose)
return OPT_V;
return OPT_HELP;
}
LIBTCCAPI int tcc_set_options(TCCState *s, const char *r)
LIBTCCAPI void tcc_set_options(TCCState *s, const char *r)
{
char **argv;
int argc;
int ret, q, c;
CString str;
argc = 0, argv = NULL;
for(;;) {
while (c = (unsigned char)*r, c && c <= ' ')
++r;
if (c == 0)
break;
q = 0;
cstr_new(&str);
while (c = (unsigned char)*r, c) {
++r;
if (c == '\\' && (*r == '"' || *r == '\\')) {
c = *r++;
} else if (c == '"') {
q = !q;
continue;
} else if (q == 0 && c <= ' ') {
break;
}
cstr_ccat(&str, c);
}
cstr_ccat(&str, 0);
//printf("<%s>\n", str.data), fflush(stdout);
dynarray_add(&argv, &argc, tcc_strdup(str.data));
cstr_free(&str);
}
ret = tcc_parse_args(s, argc, argv);
char **argv = NULL;
int argc = 0;
args_parser_make_argv(r, &argc, &argv);
tcc_parse_args(s, &argc, &argv, 0);
dynarray_reset(&argv, &argc);
return ret;
}
PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time)
@ -1928,11 +1970,15 @@ PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time)
total_time = 1;
if (total_bytes < 1)
total_bytes = 1;
fprintf(stderr, "%d idents, %d lines, %d bytes, %0.3f s, %u lines/s, %0.1f MB/s\n",
fprintf(stderr, "* %d idents, %d lines, %d bytes\n"
"* %0.3f s, %u lines/s, %0.1f MB/s\n",
tok_ident - TOK_IDENT, total_lines, total_bytes,
(double)total_time/1000,
(unsigned)total_lines*1000/total_time,
(double)total_bytes/1000/total_time);
#ifdef MEM_DEBUG
fprintf(stderr, "* %d bytes memory used\n", mem_max_size);
#endif
}
PUB_FUNC void tcc_set_environment(TCCState *s)

2
libtcc.h

@ -27,7 +27,7 @@ LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque,
void (*error_func)(void *opaque, const char *msg));
/* set options as from command line (multiple supported) */
LIBTCCAPI int tcc_set_options(TCCState *s, const char *str);
LIBTCCAPI void tcc_set_options(TCCState *s, const char *str);
/*****************************/
/* preprocessor */

339
tcc.c

@ -23,69 +23,7 @@
#else
#include "tcc.h"
#endif
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"
#elif defined TCC_TARGET_X86_64
"x86-64"
#elif defined TCC_TARGET_C67
"C67"
#elif defined TCC_TARGET_ARM
"ARM"
# ifdef TCC_ARM_HARDFLOAT
" Hard Float"
# endif
#elif defined TCC_TARGET_ARM64
"AArch64"
# ifdef TCC_ARM_HARDFLOAT
" Hard Float"
# endif
#endif
#ifdef TCC_TARGET_PE
" Windows"
#elif defined(__APPLE__)
/* Current Apple OS name as of 2016 */
" macOS"
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
" FreeBSD"
#elif defined(__DragonFly__)
" DragonFly BSD"
#elif defined(__NetBSD__)
" NetBSD"
#elif defined(__OpenBSD__)
" OpenBSD"
#elif defined(__linux__)
" Linux"
#else
" Unidentified system"
#endif
")\n", TCC_VERSION);
break;
case 1:
printf("install: %s\n", s->tcc_lib_path);
/* print_paths("programs", NULL, 0); */
print_paths("include", s->sysinclude_paths, s->nb_sysinclude_paths);
print_paths("libraries", s->library_paths, s->nb_library_paths);
#ifndef TCC_TARGET_PE
print_paths("crt", s->crt_paths, s->nb_crt_paths);
printf("elfinterp:\n %s\n", DEFAULT_ELFINTERP(s));
#endif
break;
}
}
#include "tcctools.c"
static void help(void)
{
@ -100,7 +38,8 @@ static void help(void)
" -Wwarning set or reset (with 'no-' prefix) 'warning' (see man page)\n"
" -w disable all warnings\n"
" -v show version\n"
" -vv show included files (as sole argument: show search paths)\n"
" -vv show included files (as sole argument show search paths)\n"
" -h show this help\n"
" -bench show compilation statistics\n"
"Preprocessor options:\n"
" -Idir add include path 'dir'\n"
@ -146,115 +85,75 @@ static void help(void)
#endif
#ifdef TCC_TARGET_X86_64
" -mno-sse disable floats on x86-64\n"
#endif
"Tools:\n"
" create library : tcc -ar [rcsv] lib.a files\n"
#ifdef TCC_TARGET_PE
" create .def file : tcc -impdef lib.dll [-v] [-o lib.def]\n"
#endif
);
}
/* re-execute the i386/x86_64 cross-compilers with tcc -m32/-m64: */
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
#ifdef _WIN32
#include <process.h>
static char *str_replace(const char *str, const char *p, const char *r)
{
const char *s, *s0;
char *d, *d0;
int sl, pl, rl;
sl = strlen(str);
pl = strlen(p);
rl = strlen(r);
for (d0 = NULL;; d0 = tcc_malloc(sl + 1)) {
for (d = d0, s = str; s0 = s, s = strstr(s, p), s; s += pl) {
if (d) {
memcpy(d, s0, sl = s - s0), d += sl;
memcpy(d, r, rl), d += rl;
} else
sl += rl - pl;
}
if (d) {
strcpy(d, s0);
return d0;
}
}
}
static int execvp_win32(const char *prog, char **argv)
{
int ret; char **p;
/* replace all " by \" */
for (p = argv; *p; ++p)
if (strchr(*p, '"'))
*p = str_replace(*p, "\"", "\\\"");
ret = _spawnvp(P_NOWAIT, prog, (const char *const*)argv);
if (-1 == ret)
return ret;
cwait(&ret, ret, WAIT_CHILD);
exit(ret);
}
#define execvp execvp_win32
#endif
static void exec_other_tcc(TCCState *s, char **argv, int option)
static void version(void)
{
char child_path[4096], *a0 = argv[0]; const char *target;
int l;
switch (option) {
printf("tcc version %s ("
#ifdef TCC_TARGET_I386
case 32: break;
case 64: target = "x86_64";
#else
case 64: break;
case 32: target = "i386";
"i386"
#elif defined TCC_TARGET_X86_64
"x86-64"
#elif defined TCC_TARGET_C67
"C67"
#elif defined TCC_TARGET_ARM
"ARM"
# ifdef TCC_ARM_HARDFLOAT
" Hard Float"
# endif
#elif defined TCC_TARGET_ARM64
"AArch64"
# ifdef TCC_ARM_HARDFLOAT
" Hard Float"
# endif
#endif
l = tcc_basename(a0) - a0;
snprintf(child_path, sizeof child_path,
#ifdef TCC_TARGET_PE
"%.*s%s-win32-tcc"
" Windows"
#elif defined(__APPLE__)
/* Current Apple OS name as of 2016 */
" macOS"
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
" FreeBSD"
#elif defined(__DragonFly__)
" DragonFly BSD"
#elif defined(__NetBSD__)
" NetBSD"
#elif defined(__OpenBSD__)
" OpenBSD"
#elif defined(__linux__)
" Linux"
#else
"%.*s%s-tcc"
" Unidentified system"
#endif
, l, a0, target);
if (strcmp(a0, child_path)) {
if (s->verbose > 0)
printf("tcc: using '%s'\n", child_path + l), fflush(stdout);
execvp(argv[0] = child_path, argv);
}
tcc_error("'%s' not found", child_path + l);
}
")\n", TCC_VERSION);
}
#else
#define exec_other_tcc(s, argv, option)
#endif
static void gen_makedeps(TCCState *s, const char *target, const char *filename)
static void print_dirs(const char *msg, char **paths, int nb_paths)
{
FILE *depout;
char buf[1024];
int i;
printf("%s:\n%s", msg, nb_paths ? "" : " -\n");
for(i = 0; i < nb_paths; i++)
printf(" %s\n", paths[i]);
}
if (!filename) {
/* compute filename automatically: dir/file.o -> dir/file.d */
snprintf(buf, sizeof buf, "%.*s.d",
(int)(tcc_fileextension(target) - target), target);
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 void print_search_dirs(TCCState *s)
{
printf("install: %s\n", s->tcc_lib_path);
/* print_dirs("programs", NULL, 0); */
print_dirs("include", s->sysinclude_paths, s->nb_sysinclude_paths);
print_dirs("libraries", s->library_paths, s->nb_library_paths);
#ifndef TCC_TARGET_PE
print_dirs("crt", s->crt_paths, s->nb_crt_paths);
printf("elfinterp:\n %s\n", DEFAULT_ELFINTERP(s));
#endif
}
static char *default_outputfile(TCCState *s, const char *first_file)
@ -296,109 +195,113 @@ static unsigned getclock_ms(void)
int main(int argc, char **argv)
{
TCCState *s;
int ret, optind, i;
int ret, opt, n = 0;
unsigned start_time = 0;
const char *first_file = NULL;
const char *first_file;
redo:
s = tcc_new();
opt = tcc_parse_args(s, &argc, &argv, 1);
if (n == 0) {
if (opt == OPT_HELP)
return help(), 1;
if (opt == OPT_M32 || opt == OPT_M64)
tcc_tool_cross(s, argv, opt); /* never returns */
if (s->verbose)
version();
if (opt == OPT_AR)
return tcc_tool_ar(s, argc, argv);
#ifdef TCC_TARGET_PE
if (opt == OPT_IMPDEF)
return tcc_tool_impdef(s, argc, argv);
#endif
if (opt == OPT_V)
return 0;
optind = tcc_parse_args(s, argc - 1, argv + 1);
tcc_set_environment(s);
if (optind == 0) {
help();
return 1;
}
if (s->cross_target)
exec_other_tcc(s, argv, s->cross_target);
tcc_set_environment(s);
if (s->verbose)
display_info(s, 0);
if (opt == OPT_PRINT_DIRS) {
/* initialize search dirs */
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
print_search_dirs(s);
return 0;
}
if (s->nb_files == 0) {
if (optind == 1) {
if (s->print_search_dirs || s->verbose == 2) {
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
display_info(s, 1);
return 1;
n = s->nb_files;
if (n == 0)
tcc_error("no input files\n");
if (s->output_type == TCC_OUTPUT_PREPROCESS) {
if (!s->outfile) {
s->ppfp = stdout;
} else {
s->ppfp = fopen(s->outfile, "w");
if (!s->ppfp)
tcc_error("could not write '%s'", s->outfile);
}
if (s->verbose)
return 1;
} else if (s->output_type == TCC_OUTPUT_OBJ) {
if (s->nb_libraries != 0 && !s->option_r)
tcc_error("cannot specify libraries with -c");
if (n > 1 && s->outfile)
tcc_error("cannot specify output file with -c many files");
} else {
if (s->option_pthread)
tcc_set_options(s, "-lpthread");
}
tcc_error("no input files\n");
}
/* check -c consistency : only single file handled. XXX: checks file type */
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 (s->do_bench)
start_time = getclock_ms();
}
if (s->output_type == 0)
s->output_type = TCC_OUTPUT_EXE;
tcc_set_output_type(s, s->output_type);
if (s->output_type == TCC_OUTPUT_PREPROCESS) {
if (!s->outfile) {
s->ppfp = stdout;
} else {
s->ppfp = fopen(s->outfile, "w");
if (!s->ppfp)
tcc_error("could not write '%s'", s->outfile);
}
} else if (s->output_type != TCC_OUTPUT_OBJ) {
if (s->option_pthread)
tcc_set_options(s, "-lpthread");
}
if (s->do_bench)
start_time = getclock_ms();
/* compile or add each files or library */
for(i = ret = 0; i < s->nb_files && ret == 0; i++) {
struct filespec *f = s->files[i];
if (f->type >= AFF_TYPE_LIB) {
s->alacarte_link = f->type == AFF_TYPE_LIB;
for (first_file = NULL, ret = 0;;) {
struct filespec *f = s->files[s->nb_files - n];
s->filetype = f->type;
s->alacarte_link = f->alacarte;
if (f->type == AFF_TYPE_LIB) {
if (tcc_add_library_err(s, f->name) < 0)
ret = 1;
} else {
if (1 == s->verbose)
printf("-> %s\n", f->name);
s->filetype = f->type;
if (tcc_add_file(s, f->name) < 0)
ret = 1;
if (!first_file)
first_file = f->name;
if (tcc_add_file(s, f->name) < 0)
ret = 1;
}
s->filetype = AFF_TYPE_NONE;
s->filetype = 0;
s->alacarte_link = 1;
if (ret || --n == 0 || s->output_type == TCC_OUTPUT_OBJ)
break;
}
if (s->output_type == TCC_OUTPUT_PREPROCESS) {
if (s->outfile)
fclose(s->ppfp);
} else if (0 == ret) {
if (s->output_type == TCC_OUTPUT_MEMORY) {
#ifdef TCC_IS_NATIVE
ret = tcc_run(s, argc - 1 - optind, argv + 1 + optind);
ret = tcc_run(s, argc, argv);
#endif
} else {
if (!s->outfile)
s->outfile = default_outputfile(s, first_file);
ret = !!tcc_output_file(s, s->outfile);
if (s->gen_deps && !ret)
if (tcc_output_file(s, s->outfile))
ret = 1;
else if (s->gen_deps)
gen_makedeps(s, s->outfile, s->deps_outfile);
}
}
if (s->do_bench)
if (s->do_bench && ret == 0 && n == 0)
tcc_print_stats(s, getclock_ms() - start_time);
tcc_delete(s);
if (ret == 0 && n)
goto redo; /* compile more files with -c */
return ret;
}

34
tcc.h

@ -767,17 +767,19 @@ struct TCCState {
int nb_libraries; /* number of libs thereof */
int filetype;
char *outfile; /* output filename */
int cross_target; /* -m32/-m64 */
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 */
int option_pthread; /* -pthread option */
int argc;
char **argv;
};
struct filespec {
char type, name[1];
char type;
char alacarte;
char name[1];
};
/* The current value can be: */
@ -1091,7 +1093,7 @@ PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line);
#define realloc(p, s) use_tcc_realloc(p, s)
#undef strdup
#define strdup(s) use_tcc_strdup(s)
PUB_FUNC void tcc_memstats(int bench);
PUB_FUNC void tcc_memcheck(void);
PUB_FUNC void tcc_error_noabort(const char *fmt, ...);
PUB_FUNC NORETURN void tcc_error(const char *fmt, ...);
PUB_FUNC void tcc_warning(const char *fmt, ...);
@ -1131,14 +1133,12 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
#define AFF_TYPE_ASMPP 3
#define AFF_TYPE_BIN 4
#define AFF_TYPE_LIB 5
#define AFF_TYPE_LIBWH 6
/* values from tcc_object_type(...) */
#define AFF_BINTYPE_REL 1
#define AFF_BINTYPE_DYN 2
#define AFF_BINTYPE_AR 3
#define AFF_BINTYPE_C67 4
ST_FUNC int tcc_add_crt(TCCState *s, const char *filename);
#ifndef TCC_TARGET_PE
@ -1149,12 +1149,21 @@ ST_FUNC void tcc_add_pragma_libs(TCCState *s1);
PUB_FUNC int tcc_add_library_err(TCCState *s, const char *f);
PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time);
PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv);
PUB_FUNC int tcc_parse_args(TCCState *s, int *argc, char ***argv, int optind);
PUB_FUNC void tcc_set_environment(TCCState *s);
#ifdef _WIN32
ST_FUNC char *normalize_slashes(char *path);
#endif
/* tcc_parse_args return codes: */
#define OPT_HELP 1
#define OPT_V 3
#define OPT_PRINT_DIRS 4
#define OPT_AR 5
#define OPT_IMPDEF 6
#define OPT_M32 32
#define OPT_M64 64
/* ------------ tccpp.c ------------ */
ST_DATA struct BufferedFile *file;
@ -1567,6 +1576,7 @@ ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2);
#ifdef TCC_TARGET_X86_64
ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack);
#endif
PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp);
/* symbol properties stored in Elf32_Sym->st_other */
# define ST_PE_EXPORT 0x10
# define ST_PE_IMPORT 0x20
@ -1595,6 +1605,16 @@ ST_FUNC void tcc_set_num_callers(int n);
ST_FUNC void tcc_run_free(TCCState *s1);
#endif
/* ------------ tcctools.c ----------------- */
#if 0 /* included in tcc.c */
ST_FUNC int tcc_tool_ar(TCCState *s, int argc, char **argv);
#ifdef TCC_TARGET_PE
ST_FUNC int tcc_tool_impdef(TCCState *s, int argc, char **argv);
#endif
ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int option);
ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename);
#endif
/********************************************************/
#undef ST_DATA
#ifdef ONE_SOURCE

1
tccasm.c

@ -1005,6 +1005,7 @@ ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess)
/* default section is text */
cur_text_section = text_section;
ind = cur_text_section->data_offset;
nocode_wanted = 0;
/* an elf symbol of type STT_FILE must be put so that STB_LOCAL
symbols can be safely used */

122
tccpe.c

@ -962,7 +962,7 @@ static void pe_build_exports(struct pe_info *pe)
} else {
fprintf(op, "LIBRARY %s\n\nEXPORTS\n", dllname);
if (pe->s1->verbose)
printf("<- %s (%d symbols)\n", buf, sym_count);
printf("<- %s (%d symbol%s)\n", buf, sym_count, "s" + (sym_count < 2));
}
#endif
@ -1543,6 +1543,102 @@ static int read_mem(int fd, unsigned offset, void *buffer, unsigned len)
return len == read(fd, buffer, len);
}
/* ------------------------------------------------------------- */
PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp)
{
int l, i, n, n0, ret;
char *p;
int fd;
IMAGE_SECTION_HEADER ish;
IMAGE_EXPORT_DIRECTORY ied;
IMAGE_DOS_HEADER dh;
IMAGE_FILE_HEADER ih;
DWORD sig, ref, addr, ptr, namep;
#ifdef TCC_TARGET_X86_64
IMAGE_OPTIONAL_HEADER64 oh;
#else
IMAGE_OPTIONAL_HEADER32 oh;
#endif
int pef_hdroffset, opt_hdroffset, sec_hdroffset;
n = n0 = 0;
p = NULL;
ret = -1;
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
goto the_end_1;
ret = 1;
if (!read_mem(fd, 0, &dh, sizeof dh))
goto the_end;
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(fd, pef_hdroffset, &ih, sizeof ih))
goto the_end;
if (IMAGE_FILE_MACHINE != ih.Machine) {
if (ih.Machine == 0x014C)
ret = 32;
else if (ih.Machine == 0x8664)
ret = 64;
goto the_end;
}
opt_hdroffset = pef_hdroffset + sizeof ih;
sec_hdroffset = opt_hdroffset + sizeof oh;
if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh))
goto the_end;
if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes)
goto the_end_0;
addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
//printf("addr: %08x\n", addr);
for (i = 0; i < ih.NumberOfSections; ++i) {
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)
goto found;
}
goto the_end_0;
found:
ref = ish.VirtualAddress - ish.PointerToRawData;
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(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(fd, ptr - ref + l++, p + n, 1)) {
tcc_free(p), p = NULL;
goto the_end;
}
if (p[n++] == 0)
break;
}
}
if (p)
p[n] = 0;
the_end_0:
ret = 0;
the_end:
close(fd);
the_end_1:
*pp = p;
return ret;
}
/* -------------------------------------------------------------
* This is for compiled windows resources in 'coff' format
* as generated by 'windres.exe -O coff ...'.
@ -1660,20 +1756,20 @@ quit:
}
/* ------------------------------------------------------------- */
#define TINY_IMPDEF_GET_EXPORT_NAMES_ONLY
#include "win32/tools/tiny_impdef.c"
static int pe_load_dll(TCCState *s1, const char *dllname, int fd)
static int pe_load_dll(TCCState *s1, const char *filename)
{
char *p, *q;
int index;
p = get_export_names(fd);
if (!p)
int index, ret;
ret = tcc_get_dllexports(filename, &p);
if (ret) {
return -1;
index = add_dllref(s1, dllname);
for (q = p; *q; q += 1 + strlen(q))
pe_putimport(s1, index, q, 0);
tcc_free(p);
} else if (p) {
index = add_dllref(s1, tcc_basename(filename));
for (q = p; *q; q += 1 + strlen(q))
pe_putimport(s1, index, q, 0);
tcc_free(p);
}
return 0;
}
@ -1687,7 +1783,7 @@ ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd)
else if (pe_load_res(s1, fd) == 0)
ret = 0;
else if (read_mem(fd, 0, buf, 4) && 0 == memcmp(buf, "MZ\220", 4))
ret = pe_load_dll(s1, tcc_basename(filename), fd);
ret = pe_load_dll(s1, filename);
return ret;
}

547
tcctools.c

@ -0,0 +1,547 @@
/* -------------------------------------------------------------- */
/*
* TCC - Tiny C Compiler
*
* tcctools.c - extra tools and and -m32/64 support
*
*/
/* -------------------------------------------------------------- */
/*
* This program is for making libtcc1.a without ar
* tiny_libmaker - tiny elf lib maker
* usage: tiny_libmaker [lib] files...
* Copyright (c) 2007 Timppa
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
*