From 096125d963400951e0f160ced86416ef8c9c98b0 Mon Sep 17 00:00:00 2001 From: grischka Date: Sat, 18 Feb 2017 09:51:23 +0100 Subject: [PATCH] win32: adjust new unicode support - lib/Makefile: add (win)crt1_w.o - crt1.c/_runtmain: return to tcc & only use for UNICODE (because it might be not 100% reliable with for example wildcards (tcc *.c -run ...) - tccrun.c/tccpe.c: load -run startup_code only if called from tcc_run(). Otherwise main may not be defined. See libtcc_test.c - tests2/Makefile: pass extra options in FLAGS to allow overriding TCC Also: - tccpe.c: support weak attribute. (I first tried to solve the problem above by using it but then didn't) --- Changelog | 1 + lib/Makefile | 2 +- libtcc.c | 3 --- tccpe.c | 25 ++++++++++++++----------- tccrun.c | 1 + tests/tests2/Makefile | 10 ++++------ win32/build-tcc.bat | 10 +++++----- win32/lib/crt1.c | 23 +++++++++++------------ win32/lib/crt1w.c | 3 +++ win32/lib/wincrt1.c | 21 ++++++++++++--------- win32/lib/wincrt1w.c | 3 +++ 11 files changed, 55 insertions(+), 47 deletions(-) create mode 100644 win32/lib/crt1w.c create mode 100644 win32/lib/wincrt1w.c diff --git a/Changelog b/Changelog index 69285367..a8928fca 100644 --- a/Changelog +++ b/Changelog @@ -17,6 +17,7 @@ Platforms: - provide a runtime library for ARM (Thomas Preud'homme) - many x86-64 ABI fixes incl. XMM register passing and tests (James Lyon) - ABI tests with native compiler using libtcc (James Lyon) +- UNICODE startup code supports wmain and wWinMain (YX Hao) Features: - VLA (variable length array) improved (James Lyon, Pip Cet) diff --git a/lib/Makefile b/lib/Makefile index 9596cbb2..4cc8093e 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -41,7 +41,7 @@ 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 ARM64_O = lib-arm64.o -WIN32_O = crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o +WIN32_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o chkstk.o ifeq "$(TARGET)" "i386-win32" OBJ = $(addprefix $(DIR)/,$(I386_O) $(WIN32_O)) diff --git a/libtcc.c b/libtcc.c index f1bbc6cf..afcaae73 100644 --- a/libtcc.c +++ b/libtcc.c @@ -743,9 +743,6 @@ LIBTCCAPI TCCState *tcc_new(void) #endif #ifdef TCC_TARGET_I386 s->seg_size = 32; -#endif -#ifdef TCC_IS_NATIVE - s->runtime_main = "main"; #endif /* enable this if you want symbols with leading underscore on windows: */ #if 0 /* def TCC_TARGET_PE */ diff --git a/tccpe.c b/tccpe.c index 8bb3d855..cf2e4752 100644 --- a/tccpe.c +++ b/tccpe.c @@ -358,6 +358,7 @@ struct pe_info { int type; DWORD sizeofheaders; ADDR3264 imagebase; + const char *start_symbol; DWORD start_addr; DWORD imp_offs; DWORD imp_size; @@ -638,7 +639,6 @@ static int pe_write(struct pe_info *pe) switch (si->cls) { case sec_text: pe_header.opthdr.BaseOfCode = addr; - pe_header.opthdr.AddressOfEntryPoint = addr + pe->start_addr; break; case sec_data: @@ -700,6 +700,7 @@ static int pe_write(struct pe_info *pe) //pe_header.filehdr.TimeDateStamp = time(NULL); pe_header.filehdr.NumberOfSections = pe->sec_count; + pe_header.opthdr.AddressOfEntryPoint = pe->start_addr; pe_header.opthdr.SizeOfHeaders = pe->sizeofheaders; pe_header.opthdr.ImageBase = pe->imagebase; pe_header.opthdr.Subsystem = pe->subsystem; @@ -1309,6 +1310,9 @@ static int pe_check_symbols(struct pe_info *pe) } not_found: + if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK) + /* STB_WEAK undefined symbols are accepted */ + continue; tcc_error_noabort("undefined symbol '%s'", name); ret = -1; @@ -1793,8 +1797,9 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe) ++start_symbol; /* grab the startup code from libtcc1 */ - /* only (PE_Dll == pe_type) doesn't need it, - (TCC_OUTPUT_MEMORY == s1->output_type && PE_Dll == pe_type) is illegal */ +#ifdef TCC_IS_NATIVE + if (TCC_OUTPUT_MEMORY != s1->output_type || s1->runtime_main) +#endif set_elf_sym(symtab_section, 0, 0, ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, @@ -1817,16 +1822,10 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe) } } - if (TCC_OUTPUT_MEMORY == s1->output_type) { + if (TCC_OUTPUT_MEMORY == s1->output_type) pe_type = PE_RUN; -#ifdef TCC_IS_NATIVE - s1->runtime_main = start_symbol; -#endif - } else { - pe->start_addr = (DWORD)(uintptr_t)tcc_get_symbol_err(s1, start_symbol); - } - pe->type = pe_type; + pe->start_symbol = start_symbol; } static void pe_set_options(TCCState * s1, struct pe_info *pe) @@ -1905,6 +1904,9 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename) pe_relocate_rva(&pe, s); } } + pe.start_addr = (DWORD) + ((uintptr_t)tcc_get_symbol_err(s1, pe.start_symbol) + - pe.imagebase); if (s1->nb_errors) ret = -1; else @@ -1914,6 +1916,7 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename) #ifdef TCC_IS_NATIVE pe.thunk = data_section; pe_build_imports(&pe); + s1->runtime_main = pe.start_symbol; #endif } diff --git a/tccrun.c b/tccrun.c index 18aed611..950ffb00 100644 --- a/tccrun.c +++ b/tccrun.c @@ -107,6 +107,7 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv) { int (*prog_main)(int, char **); + s1->runtime_main = "main"; if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0) return -1; prog_main = tcc_get_symbol_err(s1, s1->runtime_main); diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile index bbcb9aba..ef82d2a5 100644 --- a/tests/tests2/Makefile +++ b/tests/tests2/Makefile @@ -28,9 +28,6 @@ endif ifeq (,$(filter i386 x86-64,$(ARCH))) SKIP += 85_asm-outside-function.test endif -ifeq ($(TARGETOS),Windows) - SKIP += 76_dollars_in_identifiers.test -endif # Some tests might need arguments ARGS = @@ -42,7 +39,8 @@ NORUN = 42_function_pointer.test : NORUN = true # Some tests might need different flags -76_dollars_in_identifiers.test : TCCFLAGS += -fdollars-in-identifiers +FLAGS = +76_dollars_in_identifiers.test : FLAGS += -fdollars-in-identifiers # Filter source directory in warnings/errors (out-of-tree builds) FILTER = 2>&1 | sed 's,$(SRC)/,,g' @@ -57,9 +55,9 @@ all test: $(filter-out $(SKIP),$(TESTS)) @echo Test: $*... # test -run @if test -z "$(NORUN)"; then \ - $(TCC) -run $< $(ARGS) $(FILTER) >$*.output 2>&1 || true; \ + $(TCC) $(FLAGS) -run $< $(ARGS) $(FILTER) >$*.output 2>&1 || true; \ else \ - $(TCC) $< -o ./$*.exe $(FILTER) >$*.output 2>&1; \ + $(TCC) $(FLAGS) $< -o ./$*.exe $(FILTER) >$*.output 2>&1; \ ./$*.exe $(ARGS) >>$*.output 2>&1 || true; \ fi @diff -Nbu $(SRC)/$*.expect $*.output && rm -f $*.output $*.exe diff --git a/win32/build-tcc.bat b/win32/build-tcc.bat index 8da1404f..daf5a12a 100644 --- a/win32/build-tcc.bat +++ b/win32/build-tcc.bat @@ -137,12 +137,12 @@ copy>nul tiny_libmaker.exe tiny_libmaker-m%T%.exe %CC% -o tiny_libmaker-m%TX%.exe tools\tiny_libmaker.c %DX% :libtcc1.a -@set O1=libtcc1.o crt1.o wincrt1.o crt1_w.o wincrt1_w.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 .\tcc -m32 %D32% -c ../lib/libtcc1.c .\tcc -m32 %D32% -c lib/crt1.c -.\tcc -m32 %D32% -c lib/crt1.c -D_UNICODE -DUNICODE -o crt1_w.o +.\tcc -m32 %D32% -c lib/crt1w.c .\tcc -m32 %D32% -c lib/wincrt1.c -.\tcc -m32 %D32% -c lib/wincrt1.c -D_UNICODE -DUNICODE -o wincrt1_w.o +.\tcc -m32 %D32% -c lib/wincrt1w.c .\tcc -m32 %D32% -c lib/dllcrt1.c .\tcc -m32 %D32% -c lib/dllmain.c .\tcc -m32 %D32% -c lib/chkstk.S @@ -153,9 +153,9 @@ tiny_libmaker-m32 lib/32/libtcc1.a %O1% alloca86.o alloca86-bt.o @if errorlevel 1 goto :the_end .\tcc -m64 %D64% -c ../lib/libtcc1.c .\tcc -m64 %D64% -c lib/crt1.c -.\tcc -m64 %D64% -c lib/crt1.c -D_UNICODE -DUNICODE -o crt1_w.o +.\tcc -m64 %D64% -c lib/crt1w.c .\tcc -m64 %D64% -c lib/wincrt1.c -.\tcc -m64 %D64% -c lib/wincrt1.c -D_UNICODE -DUNICODE -o wincrt1_w.o +.\tcc -m64 %D64% -c lib/wincrt1w.c .\tcc -m64 %D64% -c lib/dllcrt1.c .\tcc -m64 %D64% -c lib/dllmain.c .\tcc -m64 %D64% -c lib/chkstk.S diff --git a/win32/lib/crt1.c b/win32/lib/crt1.c index 1e2bd174..a9b1a300 100644 --- a/win32/lib/crt1.c +++ b/win32/lib/crt1.c @@ -65,24 +65,23 @@ void _tstart(void) exit(ret); } -void _runtmain(int argc0, /* as tcc passed in */ char **argv0) +int _runtmain(int argc, /* as tcc passed in */ char **argv) { - __TRY__ - int argc, ret; - _TCHAR **argv; - _TCHAR **env; - _startupinfo start_info; +#ifdef UNICODE + int wargc; + _TCHAR **wargv, **wenv; + _startupinfo start_info = {0}; - __set_app_type(_CONSOLE_APP); + __tgetmainargs(&wargc, &wargv, &wenv, _dowildcard, &start_info); + if (argc < wargc) + wargv += wargc - argc; +#define argv wargv +#endif #ifdef __i386 _controlfp(_PC_53, _MCW_PC); #endif - - start_info.newmode = 0; - __tgetmainargs( &argc, &argv, &env, _dowildcard, &start_info); - ret = _tmain(argc0, argv + argc - argc0, env); - exit(ret); + return _tmain(argc, argv, NULL); } // ============================================= diff --git a/win32/lib/crt1w.c b/win32/lib/crt1w.c new file mode 100644 index 00000000..2b8bbc8b --- /dev/null +++ b/win32/lib/crt1w.c @@ -0,0 +1,3 @@ +#define _UNICODE 1 +#define UNICODE 1 +#include "crt1.c" diff --git a/win32/lib/wincrt1.c b/win32/lib/wincrt1.c index 06f42f08..a4197bb9 100644 --- a/win32/lib/wincrt1.c +++ b/win32/lib/wincrt1.c @@ -68,22 +68,25 @@ int _twinstart(void) exit(ret); } -int _runtwinmain(int argc0, /* as tcc passed in */ char **argv0) +int _runtwinmain(int argc, /* as tcc passed in */ char **argv) { _TCHAR *szCmd, *p; - int argc; - _TCHAR **argv; - _TCHAR **env; - _startupinfo start_info; +#ifdef UNICODE + int wargc; + _TCHAR **wargv, **wenv; + _startupinfo start_info = {0}; - start_info.newmode = 0; - __tgetmainargs(&argc, &argv, &env, 0, &start_info); + __tgetmainargs(&wargc, &wargv, &wenv, 0, &start_info); + if (argc < wargc) + wargv += wargc - argc; +#define argv wargv +#endif p = GetCommandLine(); szCmd = NULL; - if (argc0 > 1) - szCmd = _tcsstr(p, argv[argc - argc0 + 1]); + if (argc > 1) + szCmd = _tcsstr(p, argv[1]); if (NULL == szCmd) szCmd = __T(""); else if (szCmd > p && szCmd[-1] == __T('\"')) diff --git a/win32/lib/wincrt1w.c b/win32/lib/wincrt1w.c new file mode 100644 index 00000000..a7d349e1 --- /dev/null +++ b/win32/lib/wincrt1w.c @@ -0,0 +1,3 @@ +#define _UNICODE 1 +#define UNICODE 1 +#include "wincrt1.c"