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)
This commit is contained in:
grischka 2017-02-18 09:55:34 +01:00
parent f34b1feaca
commit 2d3b9559bf
17 changed files with 998 additions and 917 deletions

View File

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

View File

@ -28,6 +28,7 @@ LIBS =
ifdef CONFIG_WIN32 ifdef CONFIG_WIN32
ifneq ($(DISABLE_STATIC),no) ifneq ($(DISABLE_STATIC),no)
LIBTCC = libtcc.dll LIBTCC = libtcc.dll
LIBTCCDEF = libtcc.def
endif endif
else else
LIBS=-lm 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) ARM64_CROSS = arm64-tcc$(EXESUF)
C67_CROSS = c67-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 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 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 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 C67_FILES = $(CORE_FILES) c67-gen.c c67-link.c tcccoff.c
ifdef CONFIG_WIN32 ifdef CONFIG_WIN32
PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF)
ifeq ($(ARCH),x86-64) ifeq ($(ARCH),x86-64)
NATIVE_FILES=$(WIN64_FILES) NATIVE_FILES=$(WIN64_FILES)
PROGS_CROSS=$(WIN32_CROSS) $(X64_CROSS) $(ARM_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS) 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) PROGS_CROSS=$(I386_CROSS) $(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(C67_CROSS) $(WINCE_CROSS)
endif endif
ifeq ($(TARGETOS),Darwin) TCCLIBS = $(LIBTCC1) $(LIBTCC) $(LIBTCCDEF)
PROGS += tiny_libmaker$(EXESUF)
endif
TCCLIBS = $(LIBTCC1) $(LIBTCC)
TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info
ifdef CONFIG_CROSS ifdef CONFIG_CROSS
@ -179,7 +175,7 @@ $(ARM64_CROSS): $(ARM64_FILES)
# libtcc generation and test # libtcc generation and test
ifndef ONE_SOURCE 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)) LIBTCC_INC = $(filter %.h,$(CORE_FILES)) $(filter-out $(CORE_FILES) i386-asm.c,$(NATIVE_FILES))
else else
LIBTCC_OBJ = libtcc.o LIBTCC_OBJ = libtcc.o
@ -187,6 +183,8 @@ LIBTCC_INC = $(NATIVE_FILES)
libtcc.o : NATIVE_DEFINES += -DONE_SOURCE libtcc.o : NATIVE_DEFINES += -DONE_SOURCE
endif endif
tcc.o : tcctools.c
$(LIBTCC_OBJ) tcc.o : %.o : %.c $(LIBTCC_INC) $(LIBTCC_OBJ) tcc.o : %.o : %.c $(LIBTCC_INC)
$(CC) -o $@ -c $< $(NATIVE_DEFINES) $(CFLAGS) $(CC) -o $@ -c $< $(NATIVE_DEFINES) $(CFLAGS)
@ -199,9 +197,11 @@ libtcc.so: $(LIBTCC_OBJ)
libtcc.so: CFLAGS+=-fPIC libtcc.so: CFLAGS+=-fPIC
# windows : libtcc.dll # windows : libtcc.dll
libtcc.dll : $(LIBTCC_OBJ) tiny_impdef$(EXESUF) libtcc.dll : $(LIBTCC_OBJ)
$(CC) -shared $(LIBTCC_OBJ) -o $@ $(LDFLAGS) $(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 libtcc.dll : NATIVE_DEFINES += -DLIBTCC_AS_DLL

1
TODO
View File

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

View File

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

View File

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

212
libtcc.c
View File

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

View File

@ -27,7 +27,7 @@ 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 options as from command line (multiple supported) */ /* 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 */ /* preprocessor */

341
tcc.c
View File

@ -23,69 +23,7 @@
#else #else
#include "tcc.h" #include "tcc.h"
#endif #endif
#include "tcctools.c"
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;
}
}
static void help(void) static void help(void)
{ {
@ -100,7 +38,8 @@ static void help(void)
" -Wwarning set or reset (with 'no-' prefix) 'warning' (see man page)\n" " -Wwarning set or reset (with 'no-' prefix) 'warning' (see man page)\n"
" -w disable all warnings\n" " -w disable all warnings\n"
" -v show version\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" " -bench show compilation statistics\n"
"Preprocessor options:\n" "Preprocessor options:\n"
" -Idir add include path 'dir'\n" " -Idir add include path 'dir'\n"
@ -146,115 +85,75 @@ static void help(void)
#endif #endif
#ifdef TCC_TARGET_X86_64 #ifdef TCC_TARGET_X86_64
" -mno-sse disable floats on x86-64\n" " -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 #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) static void version(void)
{ {
const char *s, *s0; printf("tcc version %s ("
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)
{
char child_path[4096], *a0 = argv[0]; const char *target;
int l;
switch (option) {
#ifdef TCC_TARGET_I386 #ifdef TCC_TARGET_I386
case 32: break; "i386"
case 64: target = "x86_64"; #elif defined TCC_TARGET_X86_64
#else "x86-64"
case 64: break; #elif defined TCC_TARGET_C67
case 32: target = "i386"; "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 #endif
l = tcc_basename(a0) - a0;
snprintf(child_path, sizeof child_path,
#ifdef TCC_TARGET_PE #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 #else
"%.*s%s-tcc" " Unidentified system"
#endif #endif
, l, a0, target); ")\n", TCC_VERSION);
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);
}
} }
#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; int i;
printf("%s:\n%s", msg, nb_paths ? "" : " -\n");
for(i = 0; i < nb_paths; i++)
printf(" %s\n", paths[i]);
}
if (!filename) { static void print_search_dirs(TCCState *s)
/* compute filename automatically: dir/file.o -> dir/file.d */ {
snprintf(buf, sizeof buf, "%.*s.d", printf("install: %s\n", s->tcc_lib_path);
(int)(tcc_fileextension(target) - target), target); /* print_dirs("programs", NULL, 0); */
filename = buf; print_dirs("include", s->sysinclude_paths, s->nb_sysinclude_paths);
} print_dirs("libraries", s->library_paths, s->nb_library_paths);
#ifndef TCC_TARGET_PE
if (s->verbose) print_dirs("crt", s->crt_paths, s->nb_crt_paths);
printf("<- %s\n", filename); printf("elfinterp:\n %s\n", DEFAULT_ELFINTERP(s));
#endif
/* 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 char *default_outputfile(TCCState *s, const char *first_file) 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) int main(int argc, char **argv)
{ {
TCCState *s; TCCState *s;
int ret, optind, i; int ret, opt, n = 0;
unsigned start_time = 0; unsigned start_time = 0;
const char *first_file = NULL; const char *first_file;
redo:
s = tcc_new(); s = tcc_new();
opt = tcc_parse_args(s, &argc, &argv, 1);
optind = tcc_parse_args(s, argc - 1, 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;
tcc_set_environment(s); tcc_set_environment(s);
if (optind == 0) { if (opt == OPT_PRINT_DIRS) {
help(); /* initialize search dirs */
return 1; tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
} print_search_dirs(s);
return 0;
if (s->cross_target)
exec_other_tcc(s, argv, s->cross_target);
if (s->verbose)
display_info(s, 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;
}
if (s->verbose)
return 1;
} }
tcc_error("no input files\n");
}
/* check -c consistency : only single file handled. XXX: checks file type */ n = s->nb_files;
if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) { if (n == 0)
if (s->nb_libraries != 0) tcc_error("no input files\n");
tcc_error("cannot specify libraries with -c");
/* accepts only a single input file */ if (s->output_type == TCC_OUTPUT_PREPROCESS) {
if (s->nb_files != 1) if (!s->outfile) {
tcc_error("cannot specify multiple files with -c"); 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->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");
}
if (s->do_bench)
start_time = getclock_ms();
} }
if (s->output_type == 0) if (s->output_type == 0)
s->output_type = TCC_OUTPUT_EXE; s->output_type = TCC_OUTPUT_EXE;
tcc_set_output_type(s, s->output_type); 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 */ /* compile or add each files or library */
for(i = ret = 0; i < s->nb_files && ret == 0; i++) { for (first_file = NULL, ret = 0;;) {
struct filespec *f = s->files[i]; struct filespec *f = s->files[s->nb_files - n];
if (f->type >= AFF_TYPE_LIB) { s->filetype = f->type;
s->alacarte_link = f->type == AFF_TYPE_LIB; s->alacarte_link = f->alacarte;
if (f->type == AFF_TYPE_LIB) {
if (tcc_add_library_err(s, f->name) < 0) if (tcc_add_library_err(s, f->name) < 0)
ret = 1; ret = 1;
} else { } else {
if (1 == s->verbose) if (1 == s->verbose)
printf("-> %s\n", f->name); printf("-> %s\n", f->name);
s->filetype = f->type;
if (tcc_add_file(s, f->name) < 0)
ret = 1;
if (!first_file) if (!first_file)
first_file = f->name; 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; s->alacarte_link = 1;
if (ret || --n == 0 || s->output_type == TCC_OUTPUT_OBJ)
break;
} }
if (s->output_type == TCC_OUTPUT_PREPROCESS) { if (s->output_type == TCC_OUTPUT_PREPROCESS) {
if (s->outfile) if (s->outfile)
fclose(s->ppfp); fclose(s->ppfp);
} else if (0 == ret) { } else if (0 == ret) {
if (s->output_type == TCC_OUTPUT_MEMORY) { if (s->output_type == TCC_OUTPUT_MEMORY) {
#ifdef TCC_IS_NATIVE #ifdef TCC_IS_NATIVE
ret = tcc_run(s, argc - 1 - optind, argv + 1 + optind); ret = tcc_run(s, argc, argv);
#endif #endif
} else { } else {
if (!s->outfile) if (!s->outfile)
s->outfile = default_outputfile(s, first_file); s->outfile = default_outputfile(s, first_file);
ret = !!tcc_output_file(s, s->outfile); if (tcc_output_file(s, s->outfile))
if (s->gen_deps && !ret) ret = 1;
else if (s->gen_deps)
gen_makedeps(s, s->outfile, s->deps_outfile); 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_print_stats(s, getclock_ms() - start_time);
tcc_delete(s); tcc_delete(s);
if (ret == 0 && n)
goto redo; /* compile more files with -c */
return ret; return ret;
} }

34
tcc.h
View File

@ -767,17 +767,19 @@ struct TCCState {
int nb_libraries; /* number of libs thereof */ int nb_libraries; /* number of libs thereof */
int filetype; int filetype;
char *outfile; /* output filename */ char *outfile; /* output filename */
int cross_target; /* -m32/-m64 */
int print_search_dirs; /* option */
int option_r; /* option -r */ int option_r; /* option -r */
int do_bench; /* option -bench */ int do_bench; /* option -bench */
int gen_deps; /* option -MD */ int gen_deps; /* option -MD */
char *deps_outfile; /* option -MF */ char *deps_outfile; /* option -MF */
int option_pthread; /* -pthread option */ int option_pthread; /* -pthread option */
int argc;
char **argv;
}; };
struct filespec { struct filespec {
char type, name[1]; char type;
char alacarte;
char name[1];
}; };
/* The current value can be: */ /* 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) #define realloc(p, s) use_tcc_realloc(p, s)
#undef strdup #undef strdup
#define strdup(s) use_tcc_strdup(s) #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 void tcc_error_noabort(const char *fmt, ...);
PUB_FUNC NORETURN void tcc_error(const char *fmt, ...); PUB_FUNC NORETURN void tcc_error(const char *fmt, ...);
PUB_FUNC void tcc_warning(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_ASMPP 3
#define AFF_TYPE_BIN 4 #define AFF_TYPE_BIN 4
#define AFF_TYPE_LIB 5 #define AFF_TYPE_LIB 5
#define AFF_TYPE_LIBWH 6
/* values from tcc_object_type(...) */ /* values from tcc_object_type(...) */
#define AFF_BINTYPE_REL 1 #define AFF_BINTYPE_REL 1
#define AFF_BINTYPE_DYN 2 #define AFF_BINTYPE_DYN 2
#define AFF_BINTYPE_AR 3 #define AFF_BINTYPE_AR 3
#define AFF_BINTYPE_C67 4 #define AFF_BINTYPE_C67 4
ST_FUNC int tcc_add_crt(TCCState *s, const char *filename); ST_FUNC int tcc_add_crt(TCCState *s, const char *filename);
#ifndef TCC_TARGET_PE #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 int tcc_add_library_err(TCCState *s, const char *f);
PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time); 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); PUB_FUNC void tcc_set_environment(TCCState *s);
#ifdef _WIN32 #ifdef _WIN32
ST_FUNC char *normalize_slashes(char *path); ST_FUNC char *normalize_slashes(char *path);
#endif #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 ------------ */ /* ------------ tccpp.c ------------ */
ST_DATA struct BufferedFile *file; ST_DATA struct BufferedFile *file;
@ -1567,6 +1576,7 @@ ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2);
#ifdef TCC_TARGET_X86_64 #ifdef TCC_TARGET_X86_64
ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack); ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack);
#endif #endif
PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp);
/* symbol properties stored in Elf32_Sym->st_other */ /* symbol properties stored in Elf32_Sym->st_other */
# define ST_PE_EXPORT 0x10 # define ST_PE_EXPORT 0x10
# define ST_PE_IMPORT 0x20 # 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); ST_FUNC void tcc_run_free(TCCState *s1);
#endif #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 #undef ST_DATA
#ifdef ONE_SOURCE #ifdef ONE_SOURCE

View File

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

122
tccpe.c
View File

@ -962,7 +962,7 @@ static void pe_build_exports(struct pe_info *pe)
} else { } else {
fprintf(op, "LIBRARY %s\n\nEXPORTS\n", dllname); fprintf(op, "LIBRARY %s\n\nEXPORTS\n", dllname);
if (pe->s1->verbose) 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 #endif
@ -1543,6 +1543,102 @@ static int read_mem(int fd, unsigned offset, void *buffer, unsigned len)
return len == read(fd, buffer, 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 * This is for compiled windows resources in 'coff' format
* as generated by 'windres.exe -O coff ...'. * as generated by 'windres.exe -O coff ...'.
@ -1660,20 +1756,20 @@ quit:
} }
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
#define TINY_IMPDEF_GET_EXPORT_NAMES_ONLY static int pe_load_dll(TCCState *s1, const char *filename)
#include "win32/tools/tiny_impdef.c"
static int pe_load_dll(TCCState *s1, const char *dllname, int fd)
{ {
char *p, *q; char *p, *q;
int index; int index, ret;
p = get_export_names(fd);
if (!p) ret = tcc_get_dllexports(filename, &p);
if (ret) {
return -1; return -1;
index = add_dllref(s1, dllname); } else if (p) {
for (q = p; *q; q += 1 + strlen(q)) index = add_dllref(s1, tcc_basename(filename));
pe_putimport(s1, index, q, 0); for (q = p; *q; q += 1 + strlen(q))
tcc_free(p); pe_putimport(s1, index, q, 0);
tcc_free(p);
}
return 0; 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) else if (pe_load_res(s1, fd) == 0)
ret = 0; ret = 0;
else if (read_mem(fd, 0, buf, 4) && 0 == memcmp(buf, "MZ\220", 4)) 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; return ret;
} }

547
tcctools.c Normal file
View File

@ -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
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "tcc.h"
//#define ARMAG "!<arch>\n"
#define ARFMAG "`\n"
typedef struct {
char ar_name[16];
char ar_date[12];
char ar_uid[6];
char ar_gid[6];
char ar_mode[8];
char ar_size[10];
char ar_fmag[2];
} ArHdr;
static unsigned long le2belong(unsigned long ul) {
return ((ul & 0xFF0000)>>8)+((ul & 0xFF000000)>>24) +
((ul & 0xFF)<<24)+((ul & 0xFF00)<<8);
}
/* Returns 1 if s contains any of the chars of list, else 0 */
static int contains_any(const char *s, const char *list) {
const char *l;
for (; *s; s++) {
for (l = list; *l; l++) {
if (*s == *l)
return 1;
}
}
return 0;
}
static int ar_usage(int ret) {
fprintf(stderr, "usage: tcc -ar [rcsv] lib file...\n");
fprintf(stderr, "create library ([abdioptxN] not supported).\n");
return ret;
}
ST_FUNC int tcc_tool_ar(TCCState *s1, int argc, char **argv)
{
static ArHdr arhdr = {
"/ ",
" ",
"0 ",
"0 ",
"0 ",
" ",
ARFMAG
};
static ArHdr arhdro = {
" ",
" ",
"0 ",
"0 ",
"0 ",
" ",
ARFMAG
};
FILE *fi, *fh = NULL, *fo = NULL;
ElfW(Ehdr) *ehdr;
ElfW(Shdr) *shdr;
ElfW(Sym) *sym;
int i, fsize, i_lib, i_obj;
char *buf, *shstr, *symtab = NULL, *strtab = NULL;
int symtabsize = 0;//, strtabsize = 0;
char *anames = NULL;
int *afpos = NULL;
int istrlen, strpos = 0, fpos = 0, funccnt = 0, funcmax, hofs;
char tfile[260], stmp[20];
char *file, *name;
int ret = 2;
char *ops_conflict = "habdioptxN"; // unsupported but destructive if ignored.
int verbose = 0;
i_lib = 0; i_obj = 0; // will hold the index of the lib and first obj
for (i = 1; i < argc; i++) {
const char *a = argv[i];
if (*a == '-' && strstr(a, "."))
ret = 1; // -x.y is always invalid (same as gnu ar)
if ((*a == '-') || (i == 1 && !strstr(a, "."))) { // options argument
if (contains_any(a, ops_conflict))
ret = 1;
if (strstr(a, "v"))
verbose = 1;
} else { // lib or obj files: don't abort - keep validating all args.
if (!i_lib) // first file is the lib
i_lib = i;
else if (!i_obj) // second file is the first obj
i_obj = i;
}
}
if (!i_obj) // i_obj implies also i_lib. we require both.
ret = 1;
if (ret == 1)
return ar_usage(ret);
if ((fh = fopen(argv[i_lib], "wb")) == NULL)
{
fprintf(stderr, "tcc: ar: can't open file %s \n", argv[i_lib]);
goto the_end;
}
sprintf(tfile, "%s.tmp", argv[i_lib]);
if ((fo = fopen(tfile, "wb+")) == NULL)
{
fprintf(stderr, "tcc: ar: can't create temporary file %s\n", tfile);
goto the_end;
}
funcmax = 250;
afpos = tcc_realloc(NULL, funcmax * sizeof *afpos); // 250 func
memcpy(&arhdro.ar_mode, "100666", 6);
// i_obj = first input object file
while (i_obj < argc)
{
if (*argv[i_obj] == '-') { // by now, all options start with '-'
i_obj++;
continue;
}
if ((fi = fopen(argv[i_obj], "rb")) == NULL) {
fprintf(stderr, "tcc: ar: can't open file %s \n", argv[i_obj]);
goto the_end;
}
if (verbose)
printf("a - %s\n", argv[i_obj]);
fseek(fi, 0, SEEK_END);
fsize = ftell(fi);
fseek(fi, 0, SEEK_SET);
buf = tcc_malloc(fsize + 1);
fread(buf, fsize, 1, fi);
fclose(fi);
// elf header
ehdr = (ElfW(Ehdr) *)buf;
if (ehdr->e_ident[4] != ELFCLASSW)
{
fprintf(stderr, "tcc: ar: Unsupported Elf Class: %s\n", argv[i_obj]);
goto the_end;
}
shdr = (ElfW(Shdr) *) (buf + ehdr->e_shoff + ehdr->e_shstrndx * ehdr->e_shentsize);
shstr = (char *)(buf + shdr->sh_offset);
for (i = 0; i < ehdr->e_shnum; i++)
{
shdr = (ElfW(Shdr) *) (buf + ehdr->e_shoff + i * ehdr->e_shentsize);
if (!shdr->sh_offset)
continue;
if (shdr->sh_type == SHT_SYMTAB)
{
symtab = (char *)(buf + shdr->sh_offset);
symtabsize = shdr->sh_size;
}
if (shdr->sh_type == SHT_STRTAB)
{
if (!strcmp(shstr + shdr->sh_name, ".strtab"))
{
strtab = (char *)(buf + shdr->sh_offset);
//strtabsize = shdr->sh_size;
}
}
}
if (symtab && symtabsize)
{
int nsym = symtabsize / sizeof(ElfW(Sym));
//printf("symtab: info size shndx name\n");
for (i = 1; i < nsym; i++)
{
sym = (ElfW(Sym) *) (symtab + i * sizeof(ElfW(Sym)));
if (sym->st_shndx &&
(sym->st_info == 0x10
|| sym->st_info == 0x11
|| sym->st_info == 0x12
)) {
//printf("symtab: %2Xh %4Xh %2Xh %s\n", sym->st_info, sym->st_size, sym->st_shndx, strtab + sym->st_name);
istrlen = strlen(strtab + sym->st_name)+1;
anames = tcc_realloc(anames, strpos+istrlen);
strcpy(anames + strpos, strtab + sym->st_name);
strpos += istrlen;
if (++funccnt >= funcmax) {
funcmax += 250;
afpos = tcc_realloc(afpos, funcmax * sizeof *afpos); // 250 func more
}
afpos[funccnt] = fpos;
}
}
}
file = argv[i_obj];
for (name = strchr(file, 0);
name > file && name[-1] != '/' && name[-1] != '\\';
--name);
istrlen = strlen(name);
if (istrlen >= sizeof(arhdro.ar_name))
istrlen = sizeof(arhdro.ar_name) - 1;
memset(arhdro.ar_name, ' ', sizeof(arhdro.ar_name));
memcpy(arhdro.ar_name, name, istrlen);
arhdro.ar_name[istrlen] = '/';
sprintf(stmp, "%-10d", fsize);
memcpy(&arhdro.ar_size, stmp, 10);
fwrite(&arhdro, sizeof(arhdro), 1, fo);
fwrite(buf, fsize, 1, fo);
tcc_free(buf);
i_obj++;
fpos += (fsize + sizeof(arhdro));
}
hofs = 8 + sizeof(arhdr) + strpos + (funccnt+1) * sizeof(int);
fpos = 0;
if ((hofs & 1)) // align
hofs++, fpos = 1;
// write header
fwrite("!<arch>\n", 8, 1, fh);
sprintf(stmp, "%-10d", (int)(strpos + (funccnt+1) * sizeof(int)));
memcpy(&arhdr.ar_size, stmp, 10);
fwrite(&arhdr, sizeof(arhdr), 1, fh);
afpos[0] = le2belong(funccnt);
for (i=1; i<=funccnt; i++)
afpos[i] = le2belong(afpos[i] + hofs);
fwrite(afpos, (funccnt+1) * sizeof(int), 1, fh);
fwrite(anames, strpos, 1, fh);
if (fpos)
fwrite("", 1, 1, fh);
// write objects
fseek(fo, 0, SEEK_END);
fsize = ftell(fo);
fseek(fo, 0, SEEK_SET);
buf = tcc_malloc(fsize + 1);
fread(buf, fsize, 1, fo);
fwrite(buf, fsize, 1, fh);
tcc_free(buf);
ret = 0;
the_end:
if (anames)
tcc_free(anames);
if (afpos)
tcc_free(afpos);
if (fh)
fclose(fh);
if (fo)
fclose(fo), remove(tfile);
return ret;
}
/* -------------------------------------------------------------- */
/*
* tiny_impdef creates an export definition file (.def) from a dll
* on MS-Windows. Usage: tiny_impdef library.dll [-o outputfile]"
*
* Copyright (c) 2005,2007 grischka
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef TCC_TARGET_PE
ST_FUNC int tcc_tool_impdef(TCCState *s1, int argc, char **argv)
{
int ret, v, i;
char infile[MAX_PATH];
char outfile[MAX_PATH];
const char *file;
char *p, *q;
FILE *fp, *op;
#ifdef _WIN32
char path[MAX_PATH];
#endif
infile[0] = outfile[0] = 0;
fp = op = NULL;
ret = 1;
p = NULL;
v = 0;
for (i = 1; i < argc; ++i) {
const char *a = argv[i];
if ('-' == a[0]) {
if (0 == strcmp(a, "-v")) {
v = 1;
} else if (0 == strcmp(a, "-o")) {
if (++i == argc)
goto usage;
strcpy(outfile, argv[i]);
} else
goto usage;
} else if (0 == infile[0])
strcpy(infile, a);
else
goto usage;
}
if (0 == infile[0]) {
usage:
fprintf(stderr,
"usage: tcc -impdef library.dll [-v] [-o outputfile]\n"
"create export definition file (.def) from dll\n"
);
goto the_end;
}
if (0 == outfile[0]) {
strcpy(outfile, tcc_basename(infile));
q = strrchr(outfile, '.');
if (NULL == q)
q = strchr(outfile, 0);
strcpy(q, ".def");
}
file = infile;
#ifdef _WIN32
if (SearchPath(NULL, file, ".dll", sizeof path, path, NULL))
file = path;
#endif
ret = tcc_get_dllexports(file, &p);
if (ret || !p) {
fprintf(stderr, "tcc: impdef: %s '%s'\n",
ret == 32 ? "can't read symbols from 32bit" :
ret == 64 ? "can't read symbols from 64bit" :
ret == -1 ? "can't find file" :
ret == 0 ? "no symbols found in" :
"unknown file type", file);
ret = 1;
goto the_end;
}
if (v)
printf("-> %s\n", file);
op = fopen(outfile, "w");
if (NULL == op) {
fprintf(stderr, "tcc: impdef: could not create output file: %s\n", outfile);
goto the_end;
}
fprintf(op, "LIBRARY %s\n\nEXPORTS\n", tcc_basename(file));
for (q = p, i = 0; *q; ++i) {
fprintf(op, "%s\n", q);
q += strlen(q) + 1;
}
if (v)
printf("<- %s (%d symbol%s)\n", outfile, i, "s" + (i<2));
ret = 0;
the_end:
/* cannot free memory received from tcc_get_dllexports
if it came from a dll */
/* if (p)
tcc_free(p); */
if (fp)
fclose(fp);
if (op)
fclose(op);
return ret;
}
#endif /* TCC_TARGET_PE */
/* -------------------------------------------------------------- */
/*
* TCC - Tiny C Compiler
*
* Copyright (c) 2001-2004 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* re-execute the i386/x86_64 cross-compilers with tcc -m32/-m64: */
#if !defined TCC_TARGET_I386 && !defined TCC_TARGET_X86_64
ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int option)
{
tcc_error("-m%d not implemented.", option);
}
#else
#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 /* _WIN32 */
ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int target)
{
char program[4096];
char *a0 = argv[0];
int prefix = tcc_basename(a0) - a0;
snprintf(program, sizeof program,
"%.*s%s"
#ifdef TCC_TARGET_PE
"-win32"
#endif
"-tcc"
#ifdef _WIN32
".exe"
#endif
, prefix, a0, target == 64 ? "x86_64" : "i386");
if (strcmp(a0, program))
execvp(argv[0] = program, argv);
tcc_error("could not run '%s'", program);
}
#endif /* TCC_TARGET_I386 && TCC_TARGET_X86_64 */
/* -------------------------------------------------------------- */
/* enable commandline wildcard expansion (tcc -o x.exe *.c) */
#ifdef _WIN32
int _CRT_glob = 1;
#ifndef _CRT_glob
int _dowildcard = 1;
#endif
#endif
/* -------------------------------------------------------------- */
/* generate xxx.d file */
ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
{
FILE *depout;
char buf[1024];
int 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);
}
/* -------------------------------------------------------------- */

View File

@ -3431,7 +3431,7 @@ void builtin_test(void)
i = sizeof (__builtin_choose_expr (0, ll, s)); i = sizeof (__builtin_choose_expr (0, ll, s));
printf("bce: %d\n", i); printf("bce: %d\n", i);
printf("bera: %p\n", __builtin_extract_return_addr((void*)43)); //printf("bera: %p\n", __builtin_extract_return_addr((void*)43));
} }
#ifndef _WIN32 #ifndef _WIN32

View File

@ -5,10 +5,6 @@
@echo off @echo off
setlocal setlocal
set VSCOMNTOOLS=%VS150COMNTOOLS%
if "%VSCOMNTOOLS%"=="" set VSCOMNTOOLS=%VS140COMNTOOLS%
if "%VSCOMNTOOLS%"=="" set VSCOMNTOOLS=%VS130COMNTOOLS%
if "%VSCOMNTOOLS%"=="" set VSCOMNTOOLS=%VS120COMNTOOLS%
set CC=gcc -Os -s set CC=gcc -Os -s
set /p VERSION= < ..\VERSION set /p VERSION= < ..\VERSION
set INST= set INST=
@ -70,10 +66,17 @@ goto :a1
if not (%1)==() goto :usage if not (%1)==() goto :usage
if not "%CC%"=="@call :cl" goto :p1 if not "%CC%"=="@call :cl" goto :p1
set VSCOMNTOOLS=%VS150COMNTOOLS%
if "%VSCOMNTOOLS%"=="" set VSCOMNTOOLS=%VS140COMNTOOLS%
if "%VSCOMNTOOLS%"=="" set VSCOMNTOOLS=%VS130COMNTOOLS%
if "%VSCOMNTOOLS%"=="" set VSCOMNTOOLS=%VS120COMNTOOLS%
if %T%_==32_ set CLVARS="%VSCOMNTOOLS%..\..\VC\bin\vcvars32.bat" if %T%_==32_ set CLVARS="%VSCOMNTOOLS%..\..\VC\bin\vcvars32.bat"
if %T%_==64_ set CLVARS="%VSCOMNTOOLS%..\..\VC\bin\amd64\vcvars64.bat" if %T%_==64_ set CLVARS="%VSCOMNTOOLS%..\..\VC\bin\amd64\vcvars64.bat"
if %T%_==_ set T=32& if %Platform%_==X64_ set T=64 if %T%_==_ set T=32& if %Platform%_==X64_ set T=64
if %CLVARS%_==_ goto :p1
if exist %CLVARS% call %CLVARS%
:p1 :p1
if not %T%_==_ goto :p2 if not %T%_==_ goto :p2
set T=32 set T=32
if %PROCESSOR_ARCHITECTURE%_==AMD64_ set T=64 if %PROCESSOR_ARCHITECTURE%_==AMD64_ set T=64
@ -97,9 +100,6 @@ set PX=i386-win32
@echo on @echo on
@if %CLVARS%_==_ goto :config.h
call %CLVARS%
:config.h :config.h
echo>..\config.h #define TCC_VERSION "%VERSION%" echo>..\config.h #define TCC_VERSION "%VERSION%"
echo>> ..\config.h #ifdef TCC_TARGET_X86_64 echo>> ..\config.h #ifdef TCC_TARGET_X86_64
@ -108,7 +108,7 @@ echo>> ..\config.h #else
echo>> ..\config.h #define CONFIG_TCC_LIBPATHS "{B}/lib/32;{B}/lib" echo>> ..\config.h #define CONFIG_TCC_LIBPATHS "{B}/lib/32;{B}/lib"
echo>> ..\config.h #endif echo>> ..\config.h #endif
@del /q *tcc.exe tiny_*.exe *tcc.dll for %%f in (*tcc.exe *tcc.dll) do @del %%f
:compiler :compiler
%CC% -o libtcc.dll -shared ..\libtcc.c %D% -DONE_SOURCE -DLIBTCC_AS_DLL %CC% -o libtcc.dll -shared ..\libtcc.c %D% -DONE_SOURCE -DLIBTCC_AS_DLL
@ -116,10 +116,6 @@ echo>> ..\config.h #endif
%CC% -o tcc.exe ..\tcc.c libtcc.dll %D% %CC% -o tcc.exe ..\tcc.c libtcc.dll %D%
%CC% -o %PX%-tcc.exe ..\tcc.c %DX% -DONE_SOURCE %CC% -o %PX%-tcc.exe ..\tcc.c %DX% -DONE_SOURCE
:tools
%CC% -o tiny_impdef.exe tools\tiny_impdef.c %D%
%CC% -o tiny_libmaker.exe tools\tiny_libmaker.c %D%
@if (%TCC_FILES%)==(no) goto :files-done @if (%TCC_FILES%)==(no) goto :files-done
if not exist libtcc mkdir libtcc if not exist libtcc mkdir libtcc
@ -129,12 +125,11 @@ if not exist lib\64 mkdir lib\64
copy>nul ..\include\*.h include copy>nul ..\include\*.h include
copy>nul ..\tcclib.h include copy>nul ..\tcclib.h include
copy>nul ..\libtcc.h libtcc copy>nul ..\libtcc.h libtcc
tiny_impdef libtcc.dll -o libtcc\libtcc.def
copy>nul ..\tests\libtcc_test.c examples copy>nul ..\tests\libtcc_test.c examples
copy>nul tcc-win32.txt doc copy>nul tcc-win32.txt doc
copy>nul tiny_libmaker.exe tiny_libmaker-m%T%.exe .\tcc -impdef libtcc.dll -o libtcc\libtcc.def
%CC% -o tiny_libmaker-m%TX%.exe tools\tiny_libmaker.c %DX% @if errorlevel 1 goto :the_end
:libtcc1.a :libtcc1.a
@set O1=libtcc1.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o chkstk.o bcheck.o @set O1=libtcc1.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o chkstk.o bcheck.o
@ -149,7 +144,7 @@ copy>nul tiny_libmaker.exe tiny_libmaker-m%T%.exe
.\tcc -m32 %D32% -w -c ../lib/bcheck.c .\tcc -m32 %D32% -w -c ../lib/bcheck.c
.\tcc -m32 %D32% -c ../lib/alloca86.S .\tcc -m32 %D32% -c ../lib/alloca86.S
.\tcc -m32 %D32% -c ../lib/alloca86-bt.S .\tcc -m32 %D32% -c ../lib/alloca86-bt.S
tiny_libmaker-m32 lib/32/libtcc1.a %O1% alloca86.o alloca86-bt.o .\tcc -m32 -ar lib/32/libtcc1.a %O1% alloca86.o alloca86-bt.o
@if errorlevel 1 goto :the_end @if errorlevel 1 goto :the_end
.\tcc -m64 %D64% -c ../lib/libtcc1.c .\tcc -m64 %D64% -c ../lib/libtcc1.c
.\tcc -m64 %D64% -c lib/crt1.c .\tcc -m64 %D64% -c lib/crt1.c
@ -162,7 +157,7 @@ tiny_libmaker-m32 lib/32/libtcc1.a %O1% alloca86.o alloca86-bt.o
.\tcc -m64 %D64% -w -c ../lib/bcheck.c .\tcc -m64 %D64% -w -c ../lib/bcheck.c
.\tcc -m64 %D64% -c ../lib/alloca86_64.S .\tcc -m64 %D64% -c ../lib/alloca86_64.S
.\tcc -m64 %D64% -c ../lib/alloca86_64-bt.S .\tcc -m64 %D64% -c ../lib/alloca86_64-bt.S
tiny_libmaker-m64 lib/64/libtcc1.a %O1% alloca86_64.o alloca86_64-bt.o .\tcc -m64 -ar lib/64/libtcc1.a %O1% alloca86_64.o alloca86_64-bt.o
@if errorlevel 1 goto :the_end @if errorlevel 1 goto :the_end
:tcc-doc.html :tcc-doc.html
@ -172,7 +167,7 @@ cmd /c makeinfo --html --no-split ../tcc-doc.texi -o doc/tcc-doc.html
:doc-done :doc-done
:files-done :files-done
@del /q *.o *.def *-m??.exe for %%f in (*.o *.def) do @del %%f
:copy-install :copy-install
@if (%INST%)==() goto :the_end @if (%INST%)==() goto :the_end

View File

@ -39,7 +39,7 @@
For the 'Hello DLL' example type For the 'Hello DLL' example type
tcc -shared dll.c tcc -shared dll.c
tiny_impdef dll.dll (optional) tcc -impdef dll.dll (optional)
tcc hello_dll.c dll.def tcc hello_dll.c dll.def
@ -66,10 +66,10 @@
To link with Windows system DLLs, TCC uses import definition To link with Windows system DLLs, TCC uses import definition
files (.def) instead of libraries. files (.def) instead of libraries.
The included 'tiny_impdef' program may be used to make additional The now built-in 'tiny_impdef' program may be used to make
.def files for any DLL. For example: additional .def files for any DLL. For example
tiny_impdef.exe opengl32.dll tcc -impdef [-v] opengl32.dll [-o opengl32.def]
Put opengl32.def into the tcc/lib directory. Specify -lopengl32 at Put opengl32.def into the tcc/lib directory. Specify -lopengl32 at
the TCC commandline to link a program that uses opengl32.dll. the TCC commandline to link a program that uses opengl32.dll.
@ -98,10 +98,10 @@
Tiny Libmaker: Tiny Libmaker:
-------------- --------------
The included tiny_libmaker tool by Timovj Lahde can be used as The now built-in tiny_libmaker tool by Timovj Lahde can be used as
'ar' replacement to make a library from several object files: 'ar' replacement to make a library from several object files:
tiny_libmaker [rcs] library objectfiles ... tcc -ar [rcsv] library objectfiles ...
Compilation from source: Compilation from source:
@ -143,15 +143,13 @@
------------ ------------
- On the object file level, currently TCC supports only the ELF format, - On the object file level, currently TCC supports only the ELF format,
not COFF as used by MinGW and MSVC. It is not possible to exchange not COFF as used by MinGW and MSVC. It is not possible to exchange
object files or libraries between TCC and these compilers. However object files or libraries between TCC and these compilers.
libraries for TCC from objects by TCC can be made using tiny_libmaker
or MinGW's ar. However libraries for TCC from objects by TCC can be made using
tcc -ar lib.a files.o ,,,
- No leading underscore is generated in the ELF symbols. - No leading underscore is generated in the ELF symbols.
- Bounds checking (option -b) is not supported on 64-bit OS.
Documentation and License: Documentation and License:
-------------------------- --------------------------
TCC is distributed under the GNU Lesser General Public License. (See TCC is distributed under the GNU Lesser General Public License. (See

View File

@ -1,249 +0,0 @@
/* -------------------------------------------------------------- */
/*
* tiny_impdef creates an export definition file (.def) from a dll
* on MS-Windows. Usage: tiny_impdef library.dll [-o outputfile]"
*
* Copyright (c) 2005,2007 grischka
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef TINY_IMPDEF_GET_EXPORT_NAMES_ONLY
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <io.h>
#include <malloc.h>
static char *get_export_names(int fd);
#define tcc_free free
#define tcc_realloc realloc
/* extract the basename of a file */
static char *file_basename(const char *name)
{
const char *p = strchr(name, 0);
while (p > name
&& p[-1] != '/'
&& p[-1] != '\\'
)
--p;
return (char*)p;
}
int main(int argc, char **argv)
{
int ret, v, i;
char infile[MAX_PATH];
char outfile[MAX_PATH];
static const char *ext[] = { ".dll", ".exe", NULL };
const char *file, **pp;
char path[MAX_PATH], *p, *q;
FILE *fp, *op;
infile[0] = 0;
outfile[0] = 0;
fp = op = NULL;
v = 0;
ret = 1;
p = NULL;
for (i = 1; i < argc; ++i) {
const char *a = argv[i];
if ('-' == a[0]) {
if (0 == strcmp(a, "-v")) {
v = 1;
} else if (0 == strcmp(a, "-o")) {
if (++i == argc)
goto usage;
strcpy(outfile, argv[i]);
} else
goto usage;
} else if (0 == infile[0])
strcpy(infile, a);
else
goto usage;
}
if (0 == infile[0]) {
usage:
fprintf(stderr,
"tiny_impdef: create export definition file (.def) from a dll\n"
"Usage: tiny_impdef library.dll [-o outputfile]\n"
);
goto the_end;
}
if (0 == outfile[0])
{
strcpy(outfile, file_basename(infile));
q = strrchr(outfile, '.');
if (NULL == q)
q = strchr(outfile, 0);
strcpy(q, ".def");
}
file = infile;
#ifdef _WIN32
pp = ext;
do if (SearchPath(NULL, file, *pp, sizeof path, path, NULL)) {
file = path;
break;
} while (*pp++);
#endif
fp = fopen(file, "rb");
if (NULL == fp) {
fprintf(stderr, "tiny_impdef: no such file: %s\n", infile);
goto the_end;
}
if (v)
printf("--> %s\n", file);
p = get_export_names(fileno(fp));
if (NULL == p) {
fprintf(stderr, "tiny_impdef: could not get exported function names.\n");
goto the_end;
}
op = fopen(outfile, "w");
if (NULL == op) {
fprintf(stderr, "tiny_impdef: could not create output file: %s\n", outfile);
goto the_end;
}
fprintf(op, "LIBRARY %s\n\nEXPORTS\n", file_basename(file));
for (q = p, i = 0; *q; ++i) {
fprintf(op, "%s\n", q);
q += strlen(q) + 1;
}
if (v) {
printf("<-- %s\n", outfile);
printf("%d symbol(s) found\n", i);
}
ret = 0;
the_end:
if (p)
free(p);
if (fp)
fclose(fp);
if (op)
fclose(op);
return ret;
}
int read_mem(int fd, unsigned offset, void *buffer, unsigned len)
{
lseek(fd, offset, SEEK_SET);
return len == read(fd, buffer, len);
}
/* -------------------------------------------------------------- */
#if defined TCC_TARGET_X86_64
# define IMAGE_FILE_MACHINE 0x8664
#elif defined TCC_TARGET_ARM
# define IMAGE_FILE_MACHINE 0x01C0
#elif 1 /* defined TCC_TARGET_I386 */
# define IMAGE_FILE_MACHINE 0x014C
#endif
/* -------------------------------------------------------------- */
#endif
static char *get_export_names(int fd)
{
int l, i, n, n0;
char *p;
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;
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)
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;
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;
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:
return p;
}
/* -------------------------------------------------------------- */

View File

@ -1,278 +0,0 @@
/*
* 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
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../../elf.h"
#ifdef TCC_TARGET_X86_64
# define ELFCLASSW ELFCLASS64
# define ElfW(type) Elf##64##_##type
# define ELFW(type) ELF##64##_##type
#else
# define ELFCLASSW ELFCLASS32
# define ElfW(type) Elf##32##_##type
# define ELFW(type) ELF##32##_##type
#endif
#define ARMAG "!<arch>\n"
#define ARFMAG "`\n"
typedef struct ArHdr {
char ar_name[16];
char ar_date[12];
char ar_uid[6];
char ar_gid[6];
char ar_mode[8];
char ar_size[10];
char ar_fmag[2];
} ArHdr;
unsigned long le2belong(unsigned long ul) {
return ((ul & 0xFF0000)>>8)+((ul & 0xFF000000)>>24) +
((ul & 0xFF)<<24)+((ul & 0xFF00)<<8);
}
ArHdr arhdr = {
"/ ",
" ",
"0 ",
"0 ",
"0 ",
" ",
ARFMAG
};
ArHdr arhdro = {
" ",
" ",
"0 ",
"0 ",
"0 ",
" ",
ARFMAG
};
/* Returns 1 if s contains any of the chars of list, else 0 */
int contains_any(const char *s, const char *list) {
const char *l;
for (; *s; s++) {
for (l = list; *l; l++) {
if (*s == *l)
return 1;
}
}
return 0;
}
int usage(int ret) {
fprintf(stderr, "usage: tiny_libmaker [rcsv] lib file...\n");
fprintf(stderr, "Always creates a new lib. [abdioptxN] are explicitly rejected.\n");
return ret;
}
int main(int argc, char **argv)
{
FILE *fi, *fh = NULL, *fo = NULL;
ElfW(Ehdr) *ehdr;
ElfW(Shdr) *shdr;
ElfW(Sym) *sym;
int i, fsize, i_lib, i_obj;
char *buf, *shstr, *symtab = NULL, *strtab = NULL;
int symtabsize = 0;//, strtabsize = 0;
char *anames = NULL;
int *afpos = NULL;
int istrlen, strpos = 0, fpos = 0, funccnt = 0, funcmax, hofs;
char tfile[260], stmp[20];
char *file, *name;
int ret = 2;
char *ops_conflict = "habdioptxN"; // unsupported but destructive if ignored.
int verbose = 0;
i_lib = 0; i_obj = 0; // will hold the index of the lib and first obj
for (i = 1; i < argc; i++) {
const char *a = argv[i];
if (*a == '-' && strstr(a, "."))
return usage(1); // -x.y is always invalid (same as gnu ar)
if ((*a == '-') || (i == 1 && !strstr(a, "."))) { // options argument
if (contains_any(a, ops_conflict))
return usage(1);
if (strstr(a, "v"))
verbose = 1;
} else { // lib or obj files: don't abort - keep validating all args.
if (!i_lib) // first file is the lib
i_lib = i;
else if (!i_obj) // second file is the first obj
i_obj = i;
}
}
if (!i_obj) // i_obj implies also i_lib. we require both.
return usage(1);
if ((fh = fopen(argv[i_lib], "wb")) == NULL)
{
fprintf(stderr, "Can't open file %s \n", argv[i_lib]);
goto the_end;
}
sprintf(tfile, "%s.tmp", argv[i_lib]);
if ((fo = fopen(tfile, "wb+")) == NULL)
{
fprintf(stderr, "Can't create temporary file %s\n", tfile);
goto the_end;
}
funcmax = 250;
afpos = realloc(NULL, funcmax * sizeof *afpos); // 250 func
memcpy(&arhdro.ar_mode, "100666", 6);
// i_obj = first input object file
while (i_obj < argc)
{
if (*argv[i_obj] == '-') { // by now, all options start with '-'
i_obj++;
continue;
}
if (verbose)
printf("a - %s\n", argv[i_obj]);
if ((fi = fopen(argv[i_obj], "rb")) == NULL)
{
fprintf(stderr, "Can't open file %s \n", argv[i_obj]);
goto the_end;
}
fseek(fi, 0, SEEK_END);
fsize = ftell(fi);
fseek(fi, 0, SEEK_SET);
buf = malloc(fsize + 1);
fread(buf, fsize, 1, fi);
fclose(fi);
// elf header
ehdr = (ElfW(Ehdr) *)buf;
if (ehdr->e_ident[4] != ELFCLASSW)
{
fprintf(stderr, "Unsupported Elf Class: %s\n", argv[i_obj]);
goto the_end;
}
shdr = (ElfW(Shdr) *) (buf + ehdr->e_shoff + ehdr->e_shstrndx * ehdr->e_shentsize);
shstr = (char *)(buf + shdr->sh_offset);
for (i = 0; i < ehdr->e_shnum; i++)
{
shdr = (ElfW(Shdr) *) (buf + ehdr->e_shoff + i * ehdr->e_shentsize);
if (!shdr->sh_offset)
continue;
if (shdr->sh_type == SHT_SYMTAB)
{
symtab = (char *)(buf + shdr->sh_offset);
symtabsize = shdr->sh_size;
}
if (shdr->sh_type == SHT_STRTAB)
{
if (!strcmp(shstr + shdr->sh_name, ".strtab"))
{
strtab = (char *)(buf + shdr->sh_offset);
//strtabsize = shdr->sh_size;
}
}
}
if (symtab && symtabsize)
{
int nsym = symtabsize / sizeof(ElfW(Sym));
//printf("symtab: info size shndx name\n");
for (i = 1; i < nsym; i++)
{
sym = (ElfW(Sym) *) (symtab + i * sizeof(ElfW(Sym)));
if (sym->st_shndx &&
(sym->st_info == 0x10
|| sym->st_info == 0x11
|| sym->st_info == 0x12
)) {
//printf("symtab: %2Xh %4Xh %2Xh %s\n", sym->st_info, sym->st_size, sym->st_shndx, strtab + sym->st_name);
istrlen = strlen(strtab + sym->st_name)+1;
anames = realloc(anames, strpos+istrlen);
strcpy(anames + strpos, strtab + sym->st_name);
strpos += istrlen;
if (++funccnt >= funcmax) {
funcmax += 250;
afpos = realloc(afpos, funcmax * sizeof *afpos); // 250 func more
}
afpos[funccnt] = fpos;
}
}
}
file = argv[i_obj];
for (name = strchr(file, 0);
name > file && name[-1] != '/' && name[-1] != '\\';
--name);
istrlen = strlen(name);
if (istrlen >= sizeof(arhdro.ar_name))
istrlen = sizeof(arhdro.ar_name) - 1;
memset(arhdro.ar_name, ' ', sizeof(arhdro.ar_name));
memcpy(arhdro.ar_name, name, istrlen);
arhdro.ar_name[istrlen] = '/';
sprintf(stmp, "%-10d", fsize);
memcpy(&arhdro.ar_size, stmp, 10);
fwrite(&arhdro, sizeof(arhdro), 1, fo);
fwrite(buf, fsize, 1, fo);
free(buf);
i_obj++;
fpos += (fsize + sizeof(arhdro));
}
hofs = 8 + sizeof(arhdr) + strpos + (funccnt+1) * sizeof(int);
fpos = 0;
if ((hofs & 1)) // align
hofs++, fpos = 1;
// write header
fwrite("!<arch>\n", 8, 1, fh);
sprintf(stmp, "%-10d", (int)(strpos + (funccnt+1) * sizeof(int)));
memcpy(&arhdr.ar_size, stmp, 10);
fwrite(&arhdr, sizeof(arhdr), 1, fh);
afpos[0] = le2belong(funccnt);
for (i=1; i<=funccnt; i++)
afpos[i] = le2belong(afpos[i] + hofs);
fwrite(afpos, (funccnt+1) * sizeof(int), 1, fh);
fwrite(anames, strpos, 1, fh);
if (fpos)
fwrite("", 1, 1, fh);
// write objects
fseek(fo, 0, SEEK_END);
fsize = ftell(fo);
fseek(fo, 0, SEEK_SET);
buf = malloc(fsize + 1);
fread(buf, fsize, 1, fo);
fwrite(buf, fsize, 1, fh);
free(buf);
ret = 0;
the_end:
if (anames)
free(anames);
if (afpos)
free(afpos);
if (fh)
fclose(fh);
if (fo)
fclose(fo), remove(tfile);
return ret;
}