From 30afb50e6436175e0eacf4b6d407d2eb867b265a Mon Sep 17 00:00:00 2001 From: grischka Date: Mon, 4 May 2026 10:30:15 +0200 Subject: [PATCH] arm64-win32 review: fix problems and pass tests tccpe.c: - fix arm64 unwind codes (to make native set/longjmp() work) sizeof(RUNTIME_FUNCTION) is 8 on arm64 in the first place no need to note stack slots if we don't save any registers anyway arm64-gen.c: - fix long double reg-move - fix arm64_hfa() for structs with float arrays - gfunc_prolog(): setup stackframe eariler (simplifies unwind codes) - new function gv_addr(RC); win32/include/setjmp.h: - provide correct definition for setjmo() (frameoffset = 224) tccasm.c: - support ".quad" with symbol & relocation - support ".size" - fix ". - symbol" arithmetic win32/lib/crt1.c and win32/include/stdlib.h: - do not write to __argc/__argv which reside in msvcrt.dll (msvcrt.dll on arm64 does not like that, crashes on unload) tcc.c,libtcc.c: - new functions tcc_fopen/fclose to avoid different stdio unstances in tcc.exe & libtcc.dll tests & github workflow: - add test-win32.bat to run tests with a tcc compiled by build-tcc.bat - add msvcrt_start.c for gcc/clang to use the same runtime as tcc the problem is that newer gcc as well as clang and cl are linking to newer runtimes (such as UCRT) that have partially different printf format behavior which makes tcctest fail. the solution here is to force these compilers to link with msvcrt.dll just like tcc. Also, there is no gcc on arm64-win32 currently at all. Anyway, this approach to running the github CI tests does not require msys2. But It does rely on gnumake as well as on some 'sh' shell though which seems to be installed somewhere (maybe it is the one from git). --- .github/workflows/build.yml | 63 +++++++------- Makefile | 4 +- arm64-asm.c | 4 - arm64-gen.c | 48 +++++----- i386-asm.c | 7 -- lib/Makefile | 4 +- lib/armflush.c | 13 +++ lib/bt-dll.c | 27 +++++- lib/lib-arm64.c | 7 -- lib/libtcc1.c | 22 +---- libtcc.c | 9 +- tcc.c | 12 +-- tcc.h | 21 +++-- tccasm.c | 41 ++++++--- tcclib.h | 2 + tccpe.c | 69 +++++---------- tccrun.c | 2 + tcctok.h | 7 +- tests/Makefile | 9 +- tests/libtcc_test_mt.c | 20 ++--- tests/msvcrt_start.c | 164 +++++++++++++++++++++++++++++++++++ tests/tcctest.c | 37 ++++---- tests/test-win32.bat | 74 ++++++++++++++++ tests/tests2/Makefile | 23 ++--- win32/build-tcc.bat | 135 ++++++++++++++-------------- win32/include/_mingw.h | 8 +- win32/include/setjmp.h | 32 +++---- win32/include/stdlib.h | 15 ++++ win32/include/winapi/winnt.h | 61 +++---------- win32/lib/chkstk.S | 74 +--------------- win32/lib/crt1.c | 9 +- win32/lib/winex.c | 27 ++++++ x86_64-gen.c | 8 -- 33 files changed, 602 insertions(+), 456 deletions(-) create mode 100644 tests/msvcrt_start.c create mode 100644 tests/test-win32.bat create mode 100644 win32/lib/winex.c diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2fbddce1..6ffa502f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -34,56 +34,51 @@ jobs: timeout-minutes: 6 steps: - uses: actions/checkout@v4 - - name: make & test tcc (x86_64-win32) - shell: cmd - run: | - echo ::group:: setup msys mingw64-gcc - set MSYS2_PATH_TYPE=inherit - set MSYSTEM=MINGW64 - set CHERE_INVOKING=yes - C:\msys64\usr\bin\bash -l -c "pacman -S --noconfirm mingw-w64-x86_64-gcc" - echo ::endgroup:: - C:\msys64\usr\bin\bash -l -c "./configure && make && make test -k" - - uses: ilammy/msvc-dev-cmd@v1 - with: - arch: amd64 - - name: build with MSVC (x86_64-win32) + - name: test (x86_64-win32) shell: cmd run: | echo ::group:: run build-tcc.bat cd win32 - call build-tcc.bat -t 64 -c cl + call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=amd64 + call build-tcc.bat -c cl -t x86_64 + @echo off echo ::endgroup:: - .\tcc -I.. libtcc.dll -v ../tests/libtcc_test.c -o libtest.exe && .\libtest.exe - .\tcc -I.. libtcc.dll -run ../tests/libtcc_test.c + cd ..\tests + call test-win32.bat all -k test-i386-win32: runs-on: windows-2025 timeout-minutes: 6 steps: - uses: actions/checkout@v4 - - name: make & test tcc (i386-win32) - shell: cmd - run: | - echo ::group:: setup msys mingw32-gcc - set MSYS2_PATH_TYPE=inherit - set MSYSTEM=MINGW32 - set CHERE_INVOKING=yes - C:\msys64\usr\bin\bash -l -c "pacman -S --noconfirm mingw-w64-i686-gcc" - echo ::endgroup:: - C:\msys64\usr\bin\bash -l -c "./configure && make && make test -k" - - uses: ilammy/msvc-dev-cmd@v1 - with: - arch: x86 - - name: build with MSVC (i386-win32) + - name: test (i386-win32) shell: cmd run: | echo ::group:: run build-tcc.bat cd win32 - call build-tcc.bat -t 32 -c cl + call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=x86 + call build-tcc.bat -c cl -t i386 + @echo off echo ::endgroup:: - .\tcc -I.. libtcc.dll -v ../tests/libtcc_test.c -o libtest.exe && .\libtest.exe - .\tcc -I.. libtcc.dll -run ../tests/libtcc_test.c + cd ..\tests + call test-win32.bat -p c:\mingw32\bin all -k + + test-arm64-win32: + runs-on: windows-11-arm + timeout-minutes: 6 + steps: + - uses: actions/checkout@v4 + - name: test (arm64-win32) + shell: cmd + run: | + echo ::group:: run build-tcc.bat + cd win32 + call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=arm64 + call build-tcc.bat -c cl -t arm64 + @echo off + echo ::endgroup:: + cd ..\tests + call test-win32.bat -c clang all -k test-armv7-linux: runs-on: ubuntu-22.04 diff --git a/Makefile b/Makefile index 4491bd9d..125cc918 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,9 @@ ifdef CONFIG_WIN32 LIBTCCDEF = libtcc.def endif ifneq ($(CONFIG_debug),yes) - LDFLAGS += -s + ifneq ($(CC_NAME),clang) + LDFLAGS += -s + endif endif NATIVE_TARGET = $(if $(findstring arm64,$(ARCH)),arm64-win32,$(ARCH)-win$(if $(findstring arm,$(ARCH)),ce,32)) else diff --git a/arm64-asm.c b/arm64-asm.c index 63c98a21..d34ff214 100644 --- a/arm64-asm.c +++ b/arm64-asm.c @@ -86,11 +86,7 @@ enum { #define TREG_X30 30 #define TREG_SP 31 -#ifdef TCC_TARGET_PE -#define ARM64_FREG_BASE 19 -#else #define ARM64_FREG_BASE 20 -#endif #define ARM64_FREG_LAST (ARM64_FREG_BASE + 7) typedef struct Operand { diff --git a/arm64-gen.c b/arm64-gen.c index 643aaccf..9157a9d2 100644 --- a/arm64-gen.c +++ b/arm64-gen.c @@ -579,7 +579,7 @@ ST_FUNC void load(int r, SValue *sv) if (svr < VT_CONST) { if (IS_FREG(r) && IS_FREG(svr)) if (svtt == VT_LDOUBLE) - o(ARM64_MOV_V16B | fltr(r) | fltr(svr) << 5); + o(ARM64_MOV_V16B | fltr(r) | fltr(svr) * 0x10020); // mov v(r).16b,v(svr).16b else o(ARM64_FMOV_SCALAR | fltr(r) | fltr(svr) << 5); // fmov d(r),d(svr) @@ -794,7 +794,7 @@ static int arm64_hfa_aux(CType *type, int *fsize, int num) return num; } } - else if ((type->t & VT_ARRAY) && ((type->t & VT_BTYPE) != VT_PTR)) { + else if (type->t & VT_ARRAY) { /* handle float array within struct */ int num1; if (!type->ref->c) return num; @@ -811,8 +811,7 @@ static int arm64_hfa_aux(CType *type, int *fsize, int num) static int arm64_hfa(CType *type, unsigned *fsize) { - if ((type->t & VT_BTYPE) == VT_STRUCT || - ((type->t & VT_ARRAY) && ((type->t & VT_BTYPE) != VT_PTR))) { + if ((type->t & VT_BTYPE) == VT_STRUCT) { int sz = 0; int n = arm64_hfa_aux(type, &sz, 0); if (0 < n && n <= 4) { @@ -1037,6 +1036,13 @@ static void arm64_sub_sp(uint64_t diff) } } +static int gv_addr(int r) +{ + gaddrof(); + vtop->type.t = VT_PTR; + return gv(r); +} + ST_FUNC void gfunc_call(int nb_args) { CType *return_type; @@ -1147,9 +1153,7 @@ ST_FUNC void gfunc_call(int nb_args) else if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { int align, size = type_size(&vtop->type, &align); if (size) { - vtop->type.t = VT_PTR; - gaddrof(); - gv(RC_R(a[i] / 2)); + gv_addr(RC_R(a[i] / 2)); arm64_ldrs(a[i] / 2, size); } } @@ -1165,9 +1169,7 @@ ST_FUNC void gfunc_call(int nb_args) uint32_t j, sz, n = arm64_hfa(&vtop->type, &sz); if (n > 0) { /* HFA struct - load from memory into float registers */ - vtop->type.t = VT_PTR; - gaddrof(); - gv(RC_R30); + gv_addr(RC_R30); for (j = 0; j < n; j++) o(0x3d4003c0 | (sz & 16) << 19 | -(sz & 8) << 27 | (sz & 4) << 29 | @@ -1186,7 +1188,7 @@ ST_FUNC void gfunc_call(int nb_args) if ((return_type->t & VT_BTYPE) == VT_STRUCT) { if (a[0] == 1) { // indirect return: set x8 and discard the stack value - gv(RC_R(8)); + gv_addr(RC_R(8)); --vtop; } else @@ -1206,7 +1208,7 @@ ST_FUNC void gfunc_call(int nb_args) int bt = rt & VT_BTYPE; if (bt == VT_STRUCT && !(a[0] & 1)) { // A struct was returned in registers, so write it out: - gv(RC_R(8)); + gv_addr(RC_R(8)); --vtop; if (a[0] == 0) { int align, size = type_size(return_type, &align); @@ -1271,6 +1273,7 @@ ST_FUNC void gfunc_prolog(Sym *func_sym) for (sym = func_type->ref; sym; sym = sym->next) ++n; + pcs_n = n - 1; c = n + variadic; t = tcc_malloc(c * sizeof(*t)); @@ -1321,6 +1324,8 @@ ST_FUNC void gfunc_prolog(Sym *func_sym) arm64_func_start_offset = ind; o(0xa9b27bfd); // stp x29,x30,[sp,#-224]! + o(0x910003fd); // mov x29,sp + for (i = 0; i < last_float; i++) // stp q0,q1,[sp,#16], stp q2,q3,[sp,#48] // stp q4,q5,[sp,#80], stp q6,q7,[sp,#112] @@ -1368,7 +1373,6 @@ ST_FUNC void gfunc_prolog(Sym *func_sym) tcc_free(a); tcc_free(t); - o(0x910003fd); // mov x29,sp arm64_func_sub_sp_offset = ind; /* In gfunc_epilog these will be replaced with stack setup code. */ for (i = 0; i < ARM64_FUNC_STACK_SETUP_SLOTS; ++i) @@ -1384,8 +1388,7 @@ ST_FUNC void gen_va_start(void) { int r; --vtop; // we don't need the "arg" - gaddrof(); - r = intr(gv(RC_INT)); + r = intr(gv_addr(RC_INT)); #ifdef TCC_TARGET_PE if (arm64_func_va_list_stack) { @@ -1433,13 +1436,12 @@ ST_FUNC void gen_va_arg(CType *t) uint32_t r0, r1; #ifdef TCC_TARGET_PE - int indirect = 0, slot = size + 7 & -8; + int indirect = 0, slot = (size + 7) & -8; if (size > 16) indirect = 1, slot = 8; - gaddrof(); - r0 = intr(gv(RC_INT)); + r0 = intr(gv_addr(RC_INT)); r1 = get_reg(RC_INT); vtop[0].r = r1 | VT_LVAL; r1 = intr(r1); @@ -1459,7 +1461,6 @@ ST_FUNC void gen_va_arg(CType *t) o(0x9100001e | r1 << 5 | slot << 10); // add x30,x(r1),#(slot) o(0xf900001e | r0 << 5); // str x30,[x(r0)] // ap += slot } - if (indirect) o(ARM64_LDR_X | ARM64_RN(r1) | r1); // ldr x(r1),[x(r1)] @@ -1469,8 +1470,7 @@ ST_FUNC void gen_va_arg(CType *t) if (!is_float(t->t)) hfa = arm64_hfa(t, &fsize); - gaddrof(); - r0 = intr(gv(RC_INT)); + r0 = intr(gv_addr(RC_INT)); r1 = get_reg(RC_INT); vtop[0].r = r1 | VT_LVAL; r1 = intr(r1); @@ -1570,8 +1570,7 @@ ST_FUNC void gfunc_return(CType *func_type) case 0: if ((func_type->t & VT_BTYPE) == VT_STRUCT) { int align, size = type_size(func_type, &align); - gaddrof(); - gv(RC_R(0)); + gv_addr(RC_R(0)); arm64_ldrs(0, size); } else @@ -1590,8 +1589,7 @@ ST_FUNC void gfunc_return(CType *func_type) if ((func_type->t & VT_BTYPE) == VT_STRUCT) { /* HFA struct return - load from the address on vtop into float registers */ uint32_t j, sz, n = arm64_hfa(func_type, &sz); - gaddrof(); - gv(RC_R(0)); + gv_addr(RC_R(0)); for (j = 0; j < n; j++) o(0x3d400000 | (sz & 16) << 19 | -(sz & 8) << 27 | (sz & 4) << 29 | diff --git a/i386-asm.c b/i386-asm.c index 64e44ce9..884b18cb 100644 --- a/i386-asm.c +++ b/i386-asm.c @@ -494,13 +494,6 @@ ST_FUNC void gen_expr32(ExprValue *pe) gen_addr32(pe->sym ? VT_SYM : 0, pe->sym, pe->v); } -#ifdef TCC_TARGET_X86_64 -ST_FUNC void gen_expr64(ExprValue *pe) -{ - gen_addr64(pe->sym ? VT_SYM : 0, pe->sym, pe->v); -} -#endif - /* XXX: unify with C code output ? */ static void gen_disp32(ExprValue *pe) { diff --git a/lib/Makefile b/lib/Makefile index 98126ea4..0afadff5 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -41,7 +41,7 @@ ARM_O = libtcc1.o armeabi.o armflush.o $(COMMON_O) ARM64_O = lib-arm64.o $(COMMON_O) RISCV64_O = lib-arm64.o $(COMMON_O) COMMON_O = stdatomic.o atomic.o builtin.o alloca.o alloca-bt.o -WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o +WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o winex.o LIN_O = dsohandle.o OSX_O = @@ -63,7 +63,7 @@ OBJ-x86_64 = $(X86_64_O) va_list.o $(LIN_O) OBJ-x86_64-osx = $(X86_64_O) va_list.o $(OSX_O) OBJ-i386-win32 = $(I386_O) chkstk.o $(WIN_O) OBJ-x86_64-win32 = $(X86_64_O) chkstk.o $(WIN_O) -OBJ-arm64 = $(ARM64_O) $(LIN_O) +OBJ-arm64 = $(ARM64_O) armflush.o $(LIN_O) OBJ-arm64-osx = $(ARM64_O) $(OSX_O) OBJ-arm64-win32 = $(ARM64_O) chkstk.o $(WIN_O) OBJ-arm = $(ARM_O) $(LIN_O) diff --git a/lib/armflush.c b/lib/armflush.c index c379e436..d3ee99e7 100644 --- a/lib/armflush.c +++ b/lib/armflush.c @@ -4,6 +4,9 @@ intrinsic with gcc. However tcc in order to compile itself needs this function */ +/* ------------------------------------------------------------- */ +#if defined __arm__ + #ifdef __TINYC__ /* syscall wrapper */ @@ -49,3 +52,13 @@ void __clear_cache(void *beginning, void *end) * However, there is no ARM asm parser in tcc so we use it for now */ syscall(__ARM_NR_cacheflush, beginning, end, 0); } + +/* ------------------------------------------------------------- */ +#elif defined __aarch64__ +void __clear_cache(void *beg, void *end) +{ + __arm64_clear_cache(beg, end); +} + +/* ------------------------------------------------------------- */ +#endif diff --git a/lib/bt-dll.c b/lib/bt-dll.c index 7c62cefa..e22f3776 100644 --- a/lib/bt-dll.c +++ b/lib/bt-dll.c @@ -34,7 +34,11 @@ REDIR(__bound_strncmp) \ REDIR(__bound_strcat) \ REDIR(__bound_strchr) \ - REDIR(__bound_strdup) + REDIR(__bound_strdup) \ + REDIR(__bound_strncat) \ + REDIR(__bound_strrchr) \ + REDIR(__bound_setjmp) \ + REDIR(__bound_longjmp) #ifdef __leading_underscore #define _(s) "_"#s @@ -45,11 +49,28 @@ #define REDIR(s) void *s; static struct { REDIR_ALL } all_ptrs; #undef REDIR + #define REDIR(s) #s"\0" static const char all_names[] = REDIR_ALL; #undef REDIR -#define REDIR(s) __asm__(".global " _(s) ";" _(s) ": jmp *%0" : : "m" (all_ptrs.s) ); -static void all_jmps() { REDIR_ALL } + +#if __aarch64__ +# define REDIR(s) \ + __asm__(".global "_(s)";"_(s)":"); \ + __asm__(".int 0x58000090"); /* ldr x16, [pc, #16] */ \ + __asm__(".int 0xf9400210"); /* ldr x16, [x16] */ \ + __asm__(".int 0xd61f0200"); /* br x16 */ \ + __asm__(".int 0xd503201f"); /* nop for alignment */ \ + __asm__(".quad all_ptrs + (. - all_jmps - 16) / 24 * 8"); \ + __asm__(".type "_(s)",function\n.size "_(s)",.-"_(s)); + + __asm__(".text\n.align 8\nall_jmps:"); + REDIR_ALL +#else +# define REDIR(s) \ + __asm__(".global "_(s)";"_(s)":"); goto *all_ptrs.s; + static void all_jmps() { REDIR_ALL } +#endif #undef REDIR void __bt_init_dll(int bcheck) diff --git a/lib/lib-arm64.c b/lib/lib-arm64.c index 5637358e..3c30f97c 100644 --- a/lib/lib-arm64.c +++ b/lib/lib-arm64.c @@ -23,13 +23,6 @@ typedef unsigned long long uint64_t; #include #endif -#if !defined __riscv && !defined __APPLE__ -void __clear_cache(void *beg, void *end) -{ - __arm64_clear_cache(beg, end); -} -#endif - typedef union { struct { uint64_t x0, x1; }; long double f; diff --git a/lib/libtcc1.c b/lib/libtcc1.c index 4bbd1cc7..878f9512 100644 --- a/lib/libtcc1.c +++ b/lib/libtcc1.c @@ -107,10 +107,9 @@ union float_long { }; /* XXX: we don't support several builtin supports for now */ -#if !defined __x86_64__ && !defined __arm__ && !defined __riscv && !defined __aarch64__ +#if defined __i386__ /* XXX: use gcc/tcc intrinsic ? */ -#if defined __i386__ #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ __asm__ ("subl %5,%1\n\tsbbl %3,%0" \ : "=r" ((USItype) (sh)), \ @@ -139,9 +138,6 @@ union float_long { : "=r" (__cbtmp) : "rm" ((USItype) (x))); \ (count) = __cbtmp ^ 31; \ } while (0) -#else -#error unsupported CPU type -#endif /* most of this code is taken from libgcc2.c from gcc */ @@ -478,7 +474,7 @@ long long __ashldi3(long long a, int b) #endif } -#endif /* !__x86_64__ */ +#endif /* __i386__ */ /* XXX: fix tcc's code generator to do this instead */ float __floatundisf(unsigned long long a) @@ -625,17 +621,3 @@ long long __fixxfdi (long double a1) return s ? ret : -ret; } #endif /* !ARM */ - -#if defined _WIN64 -/* MSVC x64 intrinsic */ -void __faststorefence(void) -{ -#if defined(__aarch64__) - /* ARM64: Data Memory Barrier (Inner Shareable) */ - __asm__("dmb ish"); -#else - /* x86-64: lock prefix to flush store buffer */ - __asm__("lock; orl $0,(%%rsp)" ::: "memory"); -#endif -} -#endif diff --git a/libtcc.c b/libtcc.c index ce3a9796..9fd92e2d 100644 --- a/libtcc.c +++ b/libtcc.c @@ -124,8 +124,15 @@ static void tcc_add_systemdir(TCCState *s) tcc_add_library_path(s, normalize_slashes(buf)); } #endif +/* for tcc -E : On windows (depending on compiler) a FILE* + must be created by the same module where it is used. */ +PUB_FUNC FILE *tcc_fopen(const char *f, const char *m) { + return fopen(f, m); +} +PUB_FUNC int tcc_fclose(FILE *f) { + return fclose(f); +} #endif - /********************************************************/ PUB_FUNC void tcc_enter_state(TCCState *s1) diff --git a/tcc.c b/tcc.c index e1819239..e59d8fbb 100644 --- a/tcc.c +++ b/tcc.c @@ -293,7 +293,7 @@ int main(int argc, char **argv) const char *first_file; int argc0 = argc; char **argv0 = argv; - FILE *ppfp = stdout; + FILE *ppfp = NULL; redo: argc = argc0, argv = argv0; @@ -335,7 +335,7 @@ redo: tcc_error_noabort("no input files"); } else if (s->output_type == TCC_OUTPUT_PREPROCESS) { if (s->outfile && 0!=strcmp("-",s->outfile)) { - ppfp = fopen(s->outfile, "wb"); + ppfp = tcc_fopen(s->outfile, "wb"); if (!ppfp) tcc_error_noabort("could not write '%s'", s->outfile); } @@ -355,8 +355,8 @@ redo: if (s->output_type == 0) s->output_type = TCC_OUTPUT_EXE; tcc_set_output_type(s, s->output_type); - s->ppfp = ppfp; - + if (ppfp) + s->ppfp = ppfp; if ((s->output_type == TCC_OUTPUT_MEMORY || s->output_type == TCC_OUTPUT_PREPROCESS) && (s->dflag & 16)) { /* -dt option */ @@ -422,7 +422,7 @@ redo: tcc_delete(s); if (!done) goto redo; - if (ppfp && ppfp != stdout) - fclose(ppfp); + if (ppfp) + tcc_fclose(ppfp); return ret; } diff --git a/tcc.h b/tcc.h index 04befa20..27ce1d2b 100644 --- a/tcc.h +++ b/tcc.h @@ -52,6 +52,9 @@ extern long double strtold (const char *__nptr, char **__endptr); #ifdef _WIN32 # define WIN32_LEAN_AND_MEAN 1 +# ifndef _WIN32_WINNT +# define _WIN32_WINNT 0x502 /* AddVectoredExceptionHandler */ +# endif # include # include /* open, close etc. */ # include /* getcwd */ @@ -86,6 +89,9 @@ extern long double strtold (const char *__nptr, char **__endptr); # define __x86_64__ 1 # endif # endif +# if defined(_M_ARM64) && !defined(__aarch64__) +# define __aarch64__ 1 +# endif # ifndef va_copy # define va_copy(a,b) a = b # endif @@ -228,8 +234,7 @@ extern long double strtold (const char *__nptr, char **__endptr); /* No ten-byte long doubles on window and macos except in cross-compilers made by a mingw-GCC */ #if defined TCC_TARGET_PE \ - || (defined TCC_TARGET_MACHO && defined TCC_TARGET_ARM64) \ - || (defined _WIN32 && !defined __GNUC__) + || (defined TCC_TARGET_MACHO && defined TCC_TARGET_ARM64) # define TCC_USING_DOUBLE_FOR_LDOUBLE 1 #endif @@ -1312,6 +1317,11 @@ PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time); PUB_FUNC int tcc_parse_args(TCCState *s, int *argc, char ***argv); #ifdef _WIN32 ST_FUNC char *normalize_slashes(char *path); +PUB_FUNC FILE *tcc_fopen(const char *f, const char *m); +PUB_FUNC int tcc_fclose(FILE *f); +#else +# define tcc_fopen fopen +# define tcc_fclose fclose #endif ST_FUNC DLLReference *tcc_add_dllref(TCCState *s1, const char *dllname, int level); ST_FUNC char *tcc_load_text(int fd); @@ -1683,7 +1693,6 @@ ST_FUNC void gen_increment_tcov (SValue *sv); /* ------------ x86_64-gen.c ------------ */ #ifdef TCC_TARGET_X86_64 -ST_FUNC void gen_addr64(int r, Sym *sym, int64_t c); ST_FUNC void gen_opl(int op); #ifdef TCC_TARGET_PE ST_FUNC void gen_vla_result(int addr); @@ -1742,11 +1751,11 @@ ST_FUNC int find_constraint(ASMOperand *operands, int nb_operands, const char *n ST_FUNC Sym* get_asm_sym(int name, Sym *csym); ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe); ST_FUNC int asm_int_expr(TCCState *s1); -/* ------------ i386-asm.c ------------ */ -ST_FUNC void gen_expr32(ExprValue *pe); -#ifdef TCC_TARGET_X86_64 +#if PTR_SIZE == 8 ST_FUNC void gen_expr64(ExprValue *pe); #endif +/* ------------ i386-asm.c ------------ */ +ST_FUNC void gen_expr32(ExprValue *pe); ST_FUNC void asm_opcode(TCCState *s1, int opcode); ST_FUNC int asm_parse_regvar(int t); ST_FUNC void asm_compute_constraints(ASMOperand *operands, int nb_operands, int nb_outputs, const uint8_t *clobber_regs, int *pout_reg); diff --git a/tccasm.c b/tccasm.c index 29602317..508712ec 100644 --- a/tccasm.c +++ b/tccasm.c @@ -25,6 +25,26 @@ static Section *last_text_section; /* to handle .previous asm directive */ static int asmgoto_n; +static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global); +static Sym* asm_new_label(TCCState *s1, int label, int is_local); +static Sym* asm_new_label1(TCCState *s1, int label, int is_local, int sh_num, int value); + +#if PTR_SIZE == 8 +/* output constant with relocation if 'r & VT_SYM' is true */ +ST_FUNC void gen_addr64(int r, Sym *sym, int64_t c) +{ + if (r & VT_SYM) + greloca(cur_text_section, sym, ind, R_DATA_PTR, c), c=0; + gen_le32(c); + gen_le32(c>>32); +} + +ST_FUNC void gen_expr64(ExprValue *pe) +{ + gen_addr64(pe->sym ? VT_SYM : 0, pe->sym, pe->v); +} +#endif + static int asm_get_prefix_name(TCCState *s1, const char *prefix, unsigned int n) { char buf[64]; @@ -37,10 +57,6 @@ ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n) return asm_get_prefix_name(s1, "L..", n); } -static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global); -static Sym* asm_new_label(TCCState *s1, int label, int is_local); -static Sym* asm_new_label1(TCCState *s1, int label, int is_local, int sh_num, int value); - /* If a C name has an _ prepended then only asm labels that start with _ are representable in C, by removing the first _. ASM names without _ at the beginning don't correspond to C names, but we use @@ -328,12 +344,12 @@ static inline void asm_expr_sum(TCCState *s1, ExprValue *pe) if (esym1 && esym1->st_shndx == esym2->st_shndx && esym1->st_shndx != SHN_UNDEF) { /* we also accept defined symbols in the same section */ - pe->v += esym1->st_value - esym2->st_value; + pe->v += (int)(esym1->st_value - esym2->st_value); pe->sym = NULL; } else if (esym2->st_shndx == cur_text_section->sh_num) { /* When subtracting a defined symbol in current section this actually makes the value PC-relative. */ - pe->v += 0 - esym2->st_value; + pe->v += (int)(0 - esym2->st_value); pe->pcrel = 1; e2.sym = NULL; } else { @@ -543,7 +559,7 @@ static void asm_parse_directive(TCCState *s1, int global) ind += size; break; case TOK_ASMDIR_quad: -#ifdef TCC_TARGET_X86_64 +#if PTR_SIZE == 8 size = 8; goto asm_data; #else @@ -592,7 +608,7 @@ static void asm_parse_directive(TCCState *s1, int global) if (sec->sh_type != SHT_NOBITS) { if (size == 4) { gen_expr32(&e); -#ifdef TCC_TARGET_X86_64 +#if PTR_SIZE == 8 } else if (size == 8) { gen_expr64(&e); #endif @@ -812,6 +828,7 @@ static void asm_parse_directive(TCCState *s1, int global) case TOK_ASMDIR_size: { Sym *sym; + ElfSym *esym; next(); if (tok < TOK_IDENT) @@ -823,8 +840,10 @@ static void asm_parse_directive(TCCState *s1, int global) tcc_warning_c(warn_unsupported)("ignoring .size %s,*", get_tok_str(tok, NULL)); next(); skip(','); - while (tok != TOK_LINEFEED && tok != ';' && tok != CH_EOF) { - next(); + n = asm_int_expr(s1); + esym = elfsym(sym); + if (esym) { + esym->st_size = n; } } break; @@ -952,7 +971,7 @@ static void asm_parse_directive(TCCState *s1, int global) } break; #endif -#ifdef TCC_TARGET_X86_64 +#if PTR_SIZE == 8 /* added for compatibility with GAS */ case TOK_ASMDIR_code64: next(); diff --git a/tcclib.h b/tcclib.h index 8d59e4c9..b99cf69a 100644 --- a/tcclib.h +++ b/tcclib.h @@ -19,6 +19,7 @@ int atoi(const char *nptr); long int strtol(const char *nptr, char **endptr, int base); unsigned long int strtoul(const char *nptr, char **endptr, int base); void exit(int); +void *alloca(size_t); /* stdio.h */ typedef struct __FILE FILE; @@ -39,6 +40,7 @@ int getchar(void); char *gets(char *s); int ungetc(int c, FILE *stream); int fflush(FILE *stream); +int puts(const char *s); int putchar (int c); int printf(const char *format, ...); diff --git a/tccpe.c b/tccpe.c index 11817e33..918ba47f 100644 --- a/tccpe.c +++ b/tccpe.c @@ -1958,6 +1958,7 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack) for (n = o + sizeof *p; o < n; o += sizeof p->BeginAddress) put_elf_reloc(symtab_section, pd, o, R_XXX_RELATIVE, s1->uw_sym); } + #elif defined(TCC_TARGET_ARM64) /* ARM64 unwind codes: save_fplr_x: 10iiiiii - stp x29,lr,[sp,#-(i+1)*8]! @@ -1975,10 +1976,7 @@ static Section *pe_add_unwind_info(TCCState *s1) s1->uw_pdata->sh_addralign = 4; } s = find_section(s1, ".xdata"); - if (NULL == s) { - s = new_section(s1, ".xdata", SHT_PROGBITS, SHF_ALLOC); - s->sh_addralign = 4; - } + s->sh_addralign = 4; if (0 == s1->uw_sym) s1->uw_sym = put_elf_sym(symtab_section, 0, 0, 0, 0, text_section->sh_num, ".uw_text_base"); @@ -1992,31 +1990,22 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack) { TCCState *s1 = tcc_state; Section *pd, *xd; - unsigned o, n, d, code_bytes, func_len, stack_slots; + unsigned o, d, code_bytes, func_len; unsigned char *q; uint32_t header; - struct { + struct /* _RUNTIME_FUNCTION */ { DWORD BeginAddress; - DWORD EndAddress; DWORD UnwindData; } *p; + int epilog; + xd = pe_add_unwind_info(s1); pd = s1->uw_pdata; - stack = (stack + 15) & ~15; - stack_slots = stack >> 4; func_len = (end - start) >> 2; code_bytes = 0; - if (stack_slots) { - if (stack_slots <= 31) { - code_bytes += 1; - } else if (stack_slots <= 0x7ff) { - code_bytes += 2; - } else { - code_bytes += 4; - } - } + epilog = code_bytes; code_bytes += 3; /* set_fp, save_fplr_x, end */ code_bytes = (code_bytes + 3) & ~3; @@ -2025,23 +2014,13 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack) q = section_ptr_add(xd, 4 + code_bytes); /* Full ARM64 xdata header: E=1 with one epilog and no exception handler. */ - header = (func_len & 0x3ffff) | (1u << 21) | ((code_bytes >> 2) << 27); + header = (func_len & 0x3ffff) + | 1 << 21 + | (epilog & 0x1F) << 22 + | (code_bytes >> 2) << 27 + ; write32le(q, header); q += 4; - - if (stack_slots) { - if (stack_slots <= 31) { - *q++ = stack_slots; /* alloc_s */ - } else if (stack_slots <= 0x7ff) { - *q++ = 0xC0 | (stack_slots >> 8); /* alloc_m */ - *q++ = stack_slots & 0xff; - } else { - *q++ = 0xE0; /* alloc_l */ - *q++ = (stack_slots >> 16) & 0xff; - *q++ = (stack_slots >> 8) & 0xff; - *q++ = stack_slots & 0xff; - } - } *q++ = 0xE1; /* set_fp */ *q++ = 0x9B; /* save_fplr_x: stp x29,lr,[sp,#-224]! */ *q++ = 0xE4; /* end */ @@ -2050,14 +2029,10 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack) o = pd->data_offset; p = section_ptr_add(pd, sizeof *p); - p->BeginAddress = start; - p->EndAddress = end; p->UnwindData = d; - - for (n = o + 2 * sizeof p->BeginAddress; o < n; o += sizeof p->BeginAddress) - put_elf_reloc(symtab_section, pd, o, R_XXX_RELATIVE, s1->uw_sym); - put_elf_reloc(symtab_section, pd, n, R_XXX_RELATIVE, s1->uw_xsym); + put_elf_reloc(symtab_section, pd, o, R_XXX_RELATIVE, s1->uw_sym); + put_elf_reloc(symtab_section, pd, o + 4, R_XXX_RELATIVE, s1->uw_xsym); } #endif /* ------------------------------------------------------------- */ @@ -2252,20 +2227,22 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename) resolve_common_syms(s1); pe_set_options(s1, &pe); pe_check_symbols(&pe); - if (s1->nb_errors) - ; - else if (filename) { + goto done; + if (filename) { pe_assign_addresses(&pe); relocate_syms(s1, s1->symtab, 0); + if (s1->nb_errors) + goto done; s1->pe_imagebase = pe.imagebase; relocate_sections(s1); pe.start_addr = (DWORD) (get_sym_addr(s1, pe.start_symbol, 1, 1) - pe.imagebase); - if (0 == s1->nb_errors) - pe_write(&pe); - dynarray_reset(&pe.sec_info, &pe.sec_count); + if (s1->nb_errors) + goto done; + pe_write(&pe); } else { + /* -run */ #ifdef TCC_IS_NATIVE pe.thunk = data_section; pe_build_imports(&pe); @@ -2275,6 +2252,8 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename) #endif #endif } +done: + dynarray_reset(&pe.sec_info, &pe.sec_count); pe_free_imports(&pe); #if PE_PRINT_SECTIONS if (g_debug & 8) diff --git a/tccrun.c b/tccrun.c index efec3228..8c9a6126 100644 --- a/tccrun.c +++ b/tccrun.c @@ -434,6 +434,8 @@ redo: /* relocate symbols */ relocate_syms(s1, s1->symtab, 1); + if (s1->nb_errors) + goto redo; /* relocate sections */ #ifdef TCC_TARGET_PE s1->pe_imagebase = mem; diff --git a/tcctok.h b/tcctok.h index 2abbe090..ec44b244 100644 --- a/tcctok.h +++ b/tcctok.h @@ -402,12 +402,13 @@ DEF_ASMDIR(endr) DEF_ASMDIR(org) DEF_ASMDIR(quad) -#if defined(TCC_TARGET_I386) +#if PTR_SIZE == 4 DEF_ASMDIR(code16) DEF_ASMDIR(code32) -#elif defined(TCC_TARGET_X86_64) +#else DEF_ASMDIR(code64) -#elif defined(TCC_TARGET_RISCV64) +#endif +#if defined(TCC_TARGET_RISCV64) DEF_ASMDIR(option) #endif DEF_ASMDIR(short) diff --git a/tests/Makefile b/tests/Makefile index 410bbc8e..adb5733c 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -72,9 +72,9 @@ endif RUN_TCC = -run $(TOPSRC)/tcc.c $(TCCFLAGS) DISAS = objdump -d ifdef CONFIG_OSX -DUMPTCC = (set -x; $(TOP)/tcc -vv; otool -L $(TOP)/tcc; exit 1) +DUMPTCC = (set -x; $(TCC_LOCAL) -vv; otool -L $(TCC_LOCAL); exit 1) else -DUMPTCC = (set -x; $(TOP)/tcc -vv; ldd $(TOP)/tcc; exit 1) +DUMPTCC = (set -x; $(TCC_LOCAL) -vv; ldd $(TCC_LOCAL); exit 1) endif all test : @@ -82,6 +82,7 @@ all test : @$(TCC_LOCAL) -v @$(MAKE) --no-print-directory -s clean @$(MAKE) --no-print-directory -s -r _all + @echo ------- ALL TESTS PASSED -------- _all : $(TESTS) @@ -109,8 +110,8 @@ libtcc_test_mt$(EXESUF): libtcc_test_mt.c # test.ref - generate using cc test.ref: tcctest.c - $(CC) -o tcctest.gcc $< $(CFLAGS) -w -O0 -std=gnu99 -fno-omit-frame-pointer - ./tcctest.gcc > $@ + $(CC) -o tcctest.gcc$(EXESUF) $< $(CFLAGS) -w -O0 -std=gnu99 -fno-omit-frame-pointer + ./tcctest.gcc$(EXESUF) > $@ # auto test test1 test1b: tcctest.c test.ref diff --git a/tests/libtcc_test_mt.c b/tests/libtcc_test_mt.c index 23764637..396e4e25 100644 --- a/tests/libtcc_test_mt.c +++ b/tests/libtcc_test_mt.c @@ -162,6 +162,7 @@ void *reloc_state(TCCState *s, const char *entry) { void *func; tcc_add_symbol(s, "add", add); + tcc_add_symbol(s, "printf", printf); if (tcc_relocate(s) < 0) { fprintf(stderr, __FILE__ ": could not relocate tcc state.\n"); return NULL; @@ -337,16 +338,15 @@ int main(int argc, char **argv) #else #include - #ifdef _WIN32 -# ifdef __i386__ -# define LIBTCC_TEST_WINAPI __attribute__((__stdcall__)) -# else -# define LIBTCC_TEST_WINAPI +# ifndef _WIN64 + __declspec(stdcall) # endif -void LIBTCC_TEST_WINAPI Sleep(unsigned int milliseconds); + void Sleep(unsigned); +# define sleep_ms Sleep #else -unsigned int sleep(unsigned int seconds); + int usleep(unsigned long); +# define sleep_ms(x) usleep((x)*1000); #endif int fib(n) @@ -356,11 +356,7 @@ int fib(n) int main(int argc, char **argv) { -#ifdef _WIN32 - Sleep(1000); -#else - sleep(1); -#endif + sleep_ms(333); printf(" %d", fib(atoi(argv[1]))); return 0; } diff --git a/tests/msvcrt_start.c b/tests/msvcrt_start.c new file mode 100644 index 00000000..5ca2c5ac --- /dev/null +++ b/tests/msvcrt_start.c @@ -0,0 +1,164 @@ +/* ------------------------------------------------------------- */ +/* minimal startup with runtime linker to msvcrt */ + +#if 0 + +#define REDIR_ALL \ + REDIR(__set_app_type)\ + REDIR(__getmainargs)\ + REDIR(_controlfp)\ + REDIR(_vsnprintf)\ + REDIR(exit)\ + \ + REDIR(puts)\ + REDIR(printf)\ + REDIR(putchar)\ + REDIR(strtod)\ + REDIR(memset)\ + REDIR(strcpy)\ + REDIR(strlen)\ + REDIR(malloc)\ + REDIR(free)\ + +#if defined __i386__ && !defined __TINYC__ +# define __leading_underscore 1 +#endif + +#ifdef __leading_underscore +# define _(s) "_"#s +#else +# define _(s) #s +#endif + +#define REDIR(s) void *s; +static struct { REDIR_ALL } all_ptrs; +#undef REDIR + +#define REDIR(s) #s"\0" +static const char all_names[] = REDIR_ALL; +#undef REDIR + +#if __aarch64__ + #if defined __TINYC__ + # define ALIGN ".align 8" + #else + # define ALIGN ".align 3" /* .align is power of 2 on non-ELF platforms */ + #endif +# define REDIR(s) \ + __asm__("\n"_(s)":"); \ + __asm__(".int 0x58000090"); /* ldr x16, [pc, #16] */ \ + __asm__(".int 0xf9400210"); /* ldr x16, [x16] */ \ + __asm__(".int 0xd61f0200"); /* br x16 */ \ + __asm__(".int 0xd503201f"); /* nop for alignment */ \ + __asm__(".quad all_ptrs + (. - all_jmps - 16) / 24 * 8"); \ + __asm__(".global "_(s)); + + __asm__("\t.text\n\t"ALIGN"\nall_jmps:"); + REDIR_ALL +#else +# define REDIR(s) \ + __asm__("\n"_(s)":");\ + __asm__("jmp *%0"::"m"(all_ptrs.s));\ + __asm__(".global "_(s)); + + static void all_jmps() { REDIR_ALL } +#endif +#undef REDIR + +#if 0 +# include +#else +# if __i386__ +# define STDCALL __declspec(stdcall) +# else +# define STDCALL +# endif +# define DWORD long unsigned +# define HMODULE void* +# define HANDLE void* +S TDCALL HMODULE LoadLibraryA(const char *); +S TDCALL HMODULE GetProcAddress(HMODULE , char*); +S TDCALL void ExitProcess(int); +S TDCALL int WriteFile(HANDLE, const void*, DWORD, DWORD*, void*); +S TDCALL HANDLE GetStdHandle(DWORD); +S TDCALL int FlushFileBuffers(HANDLE); +# define STD_ERROR_HANDLE -12 +#endif + +static void eput(const char *s) +{ + DWORD n_out; + int n = 0; + while (s[n]) + ++n; + WriteFile(GetStdHandle(STD_ERROR_HANDLE), s, n, &n_out, 0); +} + +static void rt_reloc() +{ + const char *s = all_names; + void **p = (void**)&all_ptrs; + void *dll = LoadLibraryA("msvcrt.dll"); + do { + char buf[100], *d = buf; + *p = (void*)GetProcAddress(dll, (char*)s); + *d++ = '_'; do *d++ = *s; while (*s++); + if (0 == *p) + *p = (void*)GetProcAddress(dll, buf); + if (0 == *p) { + eput("MSVCRT_START.C: RUNTIME RELOCATION ERROR: '"); + eput(buf+1); + eput("'\n"); + ExitProcess(-1); + } + ++p; + } while (*s); +} + +#else +# define rt_reloc() +#endif + +int main(int argc, char **argv, char **env); +void exit(int); +void __set_app_type(int apptype); + +typedef struct { int newmode; } _startupinfo; +int __getmainargs(int *pargc, char ***pargv, char ***penv, int globb, _startupinfo*); + +void _controlfp(unsigned a, unsigned b); +#define _MCW_PC 0x00030000 // Precision Control +#define _PC_53 0x00010000 // 53 bits + +int __argc; +char **__argv; +char **environ; +_startupinfo start_info = {0}; + +void mainCRTStartup(void) +{ + rt_reloc(); +#if defined __i386__ || defined __x86_64__ + _controlfp(_PC_53, _MCW_PC); +#endif + __set_app_type(1); + __getmainargs(&__argc, &__argv, &environ, 0, &start_info); + exit(main(__argc, __argv, environ)); +} + +#include +#define size_t __SIZE_TYPE__ +int printf(const char *, ...); +int _vsnprintf(char *, size_t, const char *, va_list); + +/* undefined on windows-11-arm64 */ +int vprintf(const char *format, va_list ap) +{ + char buf[1000]; + _vsnprintf(buf, sizeof buf, format, ap); + return printf("%s", buf); +} + +void __main() {} /* for gcc */ +void _pei386_runtime_relocator(void) {} /* for gcc */ +void __chkstk(unsigned n) {} /* for clang */ diff --git a/tests/tcctest.c b/tests/tcctest.c index 49959417..0bb392e4 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -81,9 +81,6 @@ typedef __SIZE_TYPE__ uintptr_t; #include incname #include stringify(funnyname) -int puts(const char *s); -void *alloca(size_t size); - int fib(int n); void num(int n); void forward_ref(void); @@ -287,6 +284,7 @@ comment printf("basefromheader %s\n", get_basefile_from_header()); printf("base %s\n", __BASE_FILE__); +#if !(defined _WIN32 && CC_NAME == CC_clang) { /* Some compilers (clang) prepend './' to __FILE__ from included files. */ @@ -295,6 +293,8 @@ comment fn += 2; printf("filefromheader %s\n", fn); } +#endif + printf("file %s\n", __FILE__); /* Check that funnily named include was in fact included */ @@ -1095,8 +1095,10 @@ void struct_test() sizeof(struct aligntest2), __alignof__(struct aligntest2)); printf("aligntest3 sizeof=%d alignof=%d\n", sizeof(struct aligntest3), __alignof__(struct aligntest3)); +#if !(defined _WIN32 && CC_NAME == CC_clang) printf("aligntest4 sizeof=%d alignof=%d\n", sizeof(struct aligntest4), __alignof__(struct aligntest4)); +#endif printf("aligntest5 sizeof=%d alignof=%d\n", sizeof(struct aligntest5), __alignof__(struct aligntest5)); printf("aligntest6 sizeof=%d alignof=%d\n", @@ -1105,8 +1107,10 @@ void struct_test() sizeof(struct aligntest7), __alignof__(struct aligntest7)); printf("aligntest8 sizeof=%d alignof=%d\n", sizeof(struct aligntest8), __alignof__(struct aligntest8)); +#if !(defined _WIN32 && CC_NAME == CC_clang) printf("aligntest9 sizeof=%d alignof=%d\n", sizeof(struct aligntest9), __alignof__(struct aligntest9)); +#endif printf("aligntest10 sizeof=%d alignof=%d\n", sizeof(struct aligntest10), __alignof__(struct aligntest10)); printf("altest5 sizeof=%d alignof=%d\n", @@ -1117,7 +1121,9 @@ void struct_test() sizeof(altest7), __alignof__(altest7)); /* empty structures (GCC extension) */ +#if !(defined _WIN32 && CC_NAME == CC_clang) printf("sizeof(struct empty) = %d\n", sizeof(struct empty)); +#endif printf("alignof(struct empty) = %d\n", __alignof__(struct empty)); printf("Large: sizeof=%d\n", sizeof(ls)); @@ -2176,15 +2182,6 @@ float strtof(const char *nptr, char **endptr); LONG_DOUBLE strtold(const char *nptr, char **endptr); #endif -#if CC_NAME == CC_clang -/* In clang 0.0/0.0 is nan and not -nan. - Also some older clang version do v=-v - as v = -0 - v */ -static char enable_nan_test = 0; -#else -static char enable_nan_test = 1; -#endif - #define FTEST(prefix, typename, type, fmt)\ void prefix ## cmp(type a, type b)\ {\ @@ -2240,7 +2237,7 @@ void prefix ## fcast(type a)\ b = llia;\ printf("lltof: " fmt "\n", b);\ b = llua;\ - printf("ulltof: " fmt "\n", b);\ + if (CC_NAME != CC_clang) printf("ulltof: " fmt "\n", b);\ }\ \ float prefix ## retf(type a) { return a; }\ @@ -2300,7 +2297,7 @@ void prefix ## test(void)\ prefix ## fcast(-2334.6);\ prefix ## call();\ prefix ## signed_zeros();\ - if (enable_nan_test) prefix ## nan();\ + if (CC_NAME != CC_clang) prefix ## nan();\ } FTEST(f, float, float, "%f") @@ -2556,8 +2553,8 @@ void longlong_test(void) a = ia; b = ua; printf(LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", a, b); - printf(LONG_LONG_FORMAT " " LONG_LONG_FORMAT " " LONG_LONG_FORMAT " %Lx\n", - (long long)1, + printf(LONG_LONG_FORMAT " " LONG_LONG_FORMAT " " LONG_LONG_FORMAT " "XLONG_LONG_FORMAT"\n", + (long long)1, (long long)-2, 1LL, 0x1234567812345679); @@ -2867,12 +2864,14 @@ void stdarg_test(void) stdarg_for_struct(bob, bob2, bob3, bob4, bob, bob, bob.profile); stdarg_for_libc("stdarg_for_libc: %s %.2f %d\n", "string", 1.23, 456); stdarg_syntax(1, 17); +#if !(defined _WIN32 && CC_NAME == CC_clang) /* broken clang */ stdarg_double_struct(6,-1,pts[0],pts[1],pts[2],pts[3],pts[4],pts[5]); stdarg_double_struct(7,1,pts[0],-1.0,pts[1],pts[2],pts[3],pts[4],pts[5]); stdarg_double_struct(7,2,pts[0],pts[1],-1.0,pts[2],pts[3],pts[4],pts[5]); stdarg_double_struct(7,3,pts[0],pts[1],pts[2],-1.0,pts[3],pts[4],pts[5]); stdarg_double_struct(7,4,pts[0],pts[1],pts[2],pts[3],-1.0,pts[4],pts[5]); stdarg_double_struct(7,5,pts[0],pts[1],pts[2],pts[3],pts[4],-1.0,pts[5]); +#endif } int reltab[3] = { 1, 2, 3 }; @@ -3289,7 +3288,7 @@ void local_label_test(void) } /* inline assembler test */ -#if defined(__i386__) || defined(__x86_64__) +#if (defined(__i386__) || defined(__x86_64__)) && !(defined _WIN32 && CC_NAME == CC_clang) typedef __SIZE_TYPE__ word; @@ -3551,8 +3550,8 @@ void asm_local_label_diff (void) { printf ("asm_local_label_diff: %d %d\n", alld_stuff[0], alld_stuff[1]); } -#endif -#endif +#endif //!__APPLE__ +#endif //!_WIN32 /* This checks that static local variables are available from assembler. */ void asm_local_statics (void) diff --git a/tests/test-win32.bat b/tests/test-win32.bat new file mode 100644 index 00000000..bf593cbf --- /dev/null +++ b/tests/test-win32.bat @@ -0,0 +1,74 @@ +@echo off +setlocal +set CC=gcc +set TESTS= +if "%1"=="/?" goto :usage +goto :p0 + +:usage +echo usage: test-win32.bat [options...] [tests...] +echo options: +echo -c compiler reference compiler (gcc or clang) +echo -p path prepend path to PATH +echo tests tests to run (default all) +echo requires: make, gcc/clang, and sh in the PATH +exit /B 1 + +:p2 +shift +:p1 +shift +:p0 +if "%1"=="-c" set CC=%2&&goto p2 +if "%1"=="-p" set PATH=%2;%PATH%&&goto p2 +if not "%1"=="" set TESTS=%TESTS% %1&&goto p1 +if "%TESTS%"=="" set TESTS=all -k + +set PATH=%CD%\..\win32;%PATH% + +for /f "delims=-" %%a in ('tcc.exe -dumpmachine') do set ARCH=%%a +set ARCH=%ARCH:aarch=arm% +set MACH=%ARCH:i386=x86% +set MACH=%MACH:x86_64=amd64% +rem echo ARCH:%ARCH% MACHINE:%MACH% + +set CRTLIB=c:/windows/system32/msvcrt.dll +set LIBTCC=libtcc.dll +set LGCC=-lgcc +if %CC%==gcc goto :c2 + +set CRTLIB=msvcrt.lib +set LIBTCC=libtcc.lib +set LGCC= +if exist %CRTLIB% goto :c3 +tcc -impdef msvcrt.dll +lib >nul /def:msvcrt.def /out:%CRTLIB% /machine:%MACH% +:c2 +if not exist %CRTLIB% echo test-win32.bat: error: %CRTLIB% not found&&exit /b 1 +:c3 + +set REF_LINK=-nostdlib msvcrt_start.c %LGCC% -lkernel32 %CRTLIB% +set CFG_MAK=..\config.mak +set CFG_H=..\config.h + +echo>>%CFG_H% #define CC_NAME CC_%CC% +echo>>%CFG_H% #define GCC_MAJOR 15 + +if exist %CFG_MAK% del %CFG_MAK% +echo>>%CFG_MAK% CC = %CC%.exe +echo>>%CFG_MAK% CC_NAME = %CC% +echo>>%CFG_MAK% ARCH = %ARCH% +echo>>%CFG_MAK% CFLAGS = -Wall -O0 +echo>>%CFG_MAK% LDFLAGS = +echo>>%CFG_MAK% LIBSUF = .lib +echo>>%CFG_MAK% prefix = $(TOP)/bin +echo>>%CFG_MAK% EXESUF = .exe +echo>>%CFG_MAK% DLLSUF = .dll +echo>>%CFG_MAK% TARGETOS = WIN32 +echo>>%CFG_MAK% CONFIG_WIN32 = yes +echo>>%CFG_MAK% TOPSRC = $(TOP) +echo>>%CFG_MAK% SHELL = sh +echo>>%CFG_MAK% test.ref: CFLAGS += %REF_LINK% + +set GMAKE=make +%GMAKE% TCC_LOCAL=tcc.exe LIBTCC=win32/%LIBTCC% %TESTS% diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile index b01009c1..620ed77e 100644 --- a/tests/tests2/Makefile +++ b/tests/tests2/Makefile @@ -48,26 +48,16 @@ ifeq (-$(CONFIG_WIN32)-,-yes-) SKIP += 117_builtins.test # win32 port doesn't define __builtins SKIP += 124_atomic_counter.test # No pthread support endif -ifneq (,$(filter arm% riscv%,$(ARCH))) - SKIP += 85_asm-outside-function.test - SKIP += 98_al_ax_extend.test - SKIP += 99_fastcall.test - SKIP += 127_asm_goto.test -endif -ifeq (,$(filter arm64 aarch64,$(ARCH))) - SKIP += 138_arm64_encoding.test - SKIP += 139_arm64_errors.test -endif -ifneq (,$(findstring win32,$(CROSS_TARGET))) - SKIP += 106_versym.test - SKIP += 114_bound_signal.test - SKIP += 124_atomic_counter.test -endif ifneq (,$(filter OpenBSD FreeBSD NetBSD,$(TARGETOS))) SKIP += 106_versym.test # no pthread_condattr_setpshared SKIP += 114_bound_signal.test # libc problem signal/fork SKIP += 116_bound_setjmp2.test # No TLS_FUNC/TLS_VAR in bcheck.c endif +ifeq (,$(filter arm64 aarch64,$(ARCH))) + SKIP += 138_arm64_encoding.test + SKIP += 139_arm64_errors.test + SKIP += 140_arm64_extasm.test +endif # Some tests might need arguments ARGS = @@ -88,8 +78,8 @@ endif # These tests run several snippets from the same file one by one 60_errors_and_warnings.test : FLAGS += -dt -139_arm64_errors.test : FLAGS += -dt 96_nodata_wanted.test : FLAGS += -dt +139_arm64_errors.test : FLAGS += -dt # Always generate certain .expects (don't put these in the GIT), GEN-ALWAYS = @@ -141,6 +131,7 @@ endif 126_bound_global.test: NORUN = true 128_run_atexit.test: FLAGS += -dt 132_bound_test.test: FLAGS += -b +140_arm64_extasm.test: GEN = $(GEN-TCC) # Filter source directory in warnings/errors (out-of-tree builds) FILTER = 2>&1 | sed -e 's,$(SRC)/,,g' diff --git a/win32/build-tcc.bat b/win32/build-tcc.bat index e5b576bc..16f69e17 100644 --- a/win32/build-tcc.bat +++ b/win32/build-tcc.bat @@ -5,13 +5,15 @@ @echo off setlocal if (%1)==(-clean) goto :cleanup -set CC=gcc +set CC=gcc -O2 -Wall set /p VERSION= < ..\VERSION set TCCDIR= set BINDIR= set DOC=no -set XCC=no +set TX= +set SELF=%~nx0 goto :a0 + :a2 shift :a3 @@ -27,20 +29,22 @@ if (%1)==(-v) set VERSION=%~2&& goto :a2 if (%1)==(-i) set TCCDIR=%2&& goto :a2 if (%1)==(-b) set BINDIR=%2&& goto :a2 if (%1)==(-d) set DOC=yes&& goto :a3 -if (%1)==(-x) set XCC=yes&& goto :a3 +if (%1)==(-x) set TX=%2&& goto :a2 if (%1)==() goto :p1 + :usage echo usage: build-tcc.bat [ options ... ] echo options: echo -c prog use prog (gcc/tcc/cl) to compile tcc echo -c "prog options" use prog with options to compile tcc -echo -t 32/64 force 32/64 bit default target +echo -t target set target +echo -x target build tcc cross-compiler for target echo -v "version" set tcc version echo -i tccdir install tcc into tccdir echo -b bindir but install tcc.exe and libtcc.dll into bindir echo -d create tcc-doc.html too (needs makeinfo) -echo -x build the cross compiler too echo -clean delete all previously produced files and directories +echo supported targets i386 x86_64 arm64 exit /B 1 @rem ------------------------------------------------------ @@ -65,6 +69,7 @@ exit /B 0 if exist %1 rmdir /Q/S %1 && %LOG% %1 exit /B 0 +@rem ------------------------------------------------------ :cl @echo off set CMD=cl @@ -84,36 +89,19 @@ echo on @rem main program :p1 -if not %T%_==_ goto :p2 -set T=32 -if %PROCESSOR_ARCHITECTURE%_==AMD64_ set T=64 -if %PROCESSOR_ARCHITEW6432%_==AMD64_ set T=64 -:p2 -if "%CC:~-3%"=="gcc" set CC=%CC% -O2 -s -static -if (%BINDIR%)==() set BINDIR=%TCCDIR% +if not _%TX%_==__ set T=%TX%&&set TX=%TX%-win32- +if _%T%_%PROCESSOR_ARCHITECTURE%_==__x86_ set T=i386 +if _%T%_%PROCESSOR_ARCHITECTURE%_==__ARM64_ set T=arm64 +if _%T%_==__ set T=x86_64 +if %T%==i386 set D=-DTCC_TARGET_PE -DTCC_TARGET_I386 +if %T%==x86_64 set D=-DTCC_TARGET_PE -DTCC_TARGET_X86_64 +if %T%==arm64 set D=-DTCC_TARGET_PE -DTCC_TARGET_ARM64 +if "%D%"=="" echo %SELF%: error: unknown target '%T%'&&exit /B 1 -set D32=-DTCC_TARGET_PE -DTCC_TARGET_I386 -set D64=-DTCC_TARGET_PE -DTCC_TARGET_X86_64 -set P32=i386-win32 -set P64=x86_64-win32 +@if (%CC:~0,3%)==(gcc) set CC=%CC% -s -static +@if (%BINDIR%)==() set BINDIR=%TCCDIR% -if %T%==64 goto :t64 -set D=%D32% -set P=%P32% -set DX=%D64% -set PX=%P64% -set TX=64 -goto :p3 - -:t64 -set D=%D64% -set P=%P64% -set DX=%D32% -set PX=%P32% -set TX=32 -goto :p3 - -:p3 +:git_hash git.exe --version 2>nul if not %ERRORLEVEL%==0 goto :git_done for /f %%b in ('git.exe rev-parse --abbrev-ref HEAD') do set GITHASH=%%b @@ -125,34 +113,37 @@ if %ERRORLEVEL%==1 set GITHASH=%GITHASH%* :config.h echo>..\config.h #define TCC_VERSION "%VERSION%" -if not (%GITHASH%)==() echo>> ..\config.h #define TCC_GITHASH "%GITHASH%" -@if not (%BINDIR%)==(%TCCDIR%) echo>> ..\config.h #define CONFIG_TCCDIR "%TCCDIR:\=/%" -if %TX%==64 echo>> ..\config.h #ifdef TCC_TARGET_X86_64 -if %TX%==32 echo>> ..\config.h #ifdef TCC_TARGET_I386 -echo>> ..\config.h #define CONFIG_TCC_CROSSPREFIX "%PX%-" -echo>> ..\config.h #endif +@if not "%GITHASH%"=="" echo>>..\config.h #define TCC_GITHASH "%GITHASH%" +@if not _%BINDIR%_==_%TCCDIR%_ echo>>..\config.h #define CONFIG_TCCDIR "%TCCDIR:\=/%" +@if not _%TX%_==__ @echo>>..\config.h #define CONFIG_TCC_CROSSPREFIX "%TX%" @rem echo>> ..\config.h #define CONFIG_TCC_PREDEFS 1 @rem %CC% -DC2STR ..\conftest.c -o c2str.exe @rem .\c2str.exe ../include/tccdefs.h ../tccdefs_.h -for %%f in (*tcc.exe *tcc.dll) do @del %%f +@if not _%TX%_==__ goto :tcc_cross +@if not _%TCC_C%_==__ goto :tcc_only -@if _%TCC_C%_==__ goto compiler_2parts -@rem if TCC_C was defined then build only tcc.exe +@if _%LIBTCC_C%_==__ set LIBTCC_C=..\libtcc.c +@set IMPLIB=libtcc.dll +@if "%CC:~0,5%"=="clang" set IMPLIB=libtcc.lib + +%CC% -o libtcc.dll -shared %LIBTCC_C% %D% -DLIBTCC_AS_DLL +@if errorlevel 1 goto :the_end +%CC% -o tcc.exe ..\tcc.c %IMPLIB% %D% -DONE_SOURCE"=0" +@if errorlevel 1 goto :the_end +@goto :compiler_done + +:tcc_only %CC% -o tcc.exe %TCC_C% %D% @if errorlevel 1 goto :the_end @goto :compiler_done -:compiler_2parts -@if _%LIBTCC_C%_==__ set LIBTCC_C=..\libtcc.c -%CC% -o libtcc.dll -shared %LIBTCC_C% %D% -DLIBTCC_AS_DLL -@if errorlevel 1 goto :the_end -%CC% -o tcc.exe ..\tcc.c libtcc.dll %D% -DONE_SOURCE"=0" -@if errorlevel 1 goto :the_end -if not _%XCC%_==_yes_ goto :compiler_done -%CC% -o %PX%-tcc.exe ..\tcc.c %DX% +:tcc_cross +%CC% -o %TX%tcc.exe ..\tcc.c %D% @if errorlevel 1 goto :the_end +@goto :compiler_done + :compiler_done @if (%EXES_ONLY%)==(yes) goto :files_done @@ -168,8 +159,7 @@ if exist libtcc.dll .\tcc -impdef libtcc.dll -o libtcc\libtcc.def @if errorlevel 1 goto :the_end :lib -call :make_lib %T% || goto :the_end -@if exist %PX%-tcc.exe call :make_lib %TX% %PX%- || goto :the_end +@call :make_lib %TX% || goto :the_end :tcc-doc.html @if not (%DOC%)==(yes) goto :doc-done @@ -193,23 +183,26 @@ for %%f in (include examples libtcc doc) do @xcopy>nul /s/i/q/y %%f %TCCDIR%\%%f exit /B %ERRORLEVEL% :make_lib -.\tcc -B. -m%1 -c ../lib/libtcc1.c -.\tcc -B. -m%1 -c lib/crt1.c -.\tcc -B. -m%1 -c lib/crt1w.c -.\tcc -B. -m%1 -c lib/wincrt1.c -.\tcc -B. -m%1 -c lib/wincrt1w.c -.\tcc -B. -m%1 -c lib/dllcrt1.c -.\tcc -B. -m%1 -c lib/dllmain.c -.\tcc -B. -m%1 -c lib/chkstk.S -.\tcc -B. -m%1 -c ../lib/alloca.S -.\tcc -B. -m%1 -c ../lib/alloca-bt.S -.\tcc -B. -m%1 -c ../lib/stdatomic.c -.\tcc -B. -m%1 -c ../lib/atomic.S -.\tcc -B. -m%1 -c ../lib/builtin.c -.\tcc -B. -m%1 -ar lib/%2libtcc1.a libtcc1.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o chkstk.o alloca.o alloca-bt.o stdatomic.o atomic.o builtin.o -.\tcc -B. -m%1 -c ../lib/bcheck.c -o lib/%2bcheck.o -bt -I.. -.\tcc -B. -m%1 -c ../lib/bt-exe.c -o lib/%2bt-exe.o -.\tcc -B. -m%1 -c ../lib/bt-log.c -o lib/%2bt-log.o -.\tcc -B. -m%1 -c ../lib/bt-dll.c -o lib/%2bt-dll.o -.\tcc -B. -m%1 -c ../lib/runmain.c -o lib/%2runmain.o +@set LIBTCC1=libtcc1 +@if _%1_==_arm64_ set LIBTCC1=lib-arm64 +.\%1tcc -B. -c ../lib/%LIBTCC1%.c +.\%1tcc -B. -c lib/crt1.c +.\%1tcc -B. -c lib/crt1w.c +.\%1tcc -B. -c lib/wincrt1.c +.\%1tcc -B. -c lib/wincrt1w.c +.\%1tcc -B. -c lib/dllcrt1.c +.\%1tcc -B. -c lib/dllmain.c +.\%1tcc -B. -c lib/winex.c +.\%1tcc -B. -c lib/chkstk.S +.\%1tcc -B. -c ../lib/alloca.S +.\%1tcc -B. -c ../lib/alloca-bt.S +.\%1tcc -B. -c ../lib/stdatomic.c +.\%1tcc -B. -c ../lib/atomic.S +.\%1tcc -B. -c ../lib/builtin.c +.\%1tcc -ar lib/%1libtcc1.a %LIBTCC1%.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o winex.o chkstk.o alloca.o alloca-bt.o stdatomic.o atomic.o builtin.o +.\%1tcc -B. -c ../lib/bcheck.c -o lib/%1bcheck.o -bt -I.. +.\%1tcc -B. -c ../lib/bt-exe.c -o lib/%1bt-exe.o +.\%1tcc -B. -c ../lib/bt-log.c -o lib/%1bt-log.o +.\%1tcc -B. -c ../lib/bt-dll.c -o lib/%1bt-dll.o +.\%1tcc -B. -c ../lib/runmain.c -o lib/%1runmain.o exit /B %ERRORLEVEL% diff --git a/win32/include/_mingw.h b/win32/include/_mingw.h index 77a3bce6..3a677202 100644 --- a/win32/include/_mingw.h +++ b/win32/include/_mingw.h @@ -70,20 +70,14 @@ #ifdef _WIN64 #define __stdcall -#if defined(__aarch64__) || defined(_M_ARM64) || defined(_ARM64_) -#ifndef _M_ARM64 +#if defined(__aarch64__) #define _M_ARM64 1 -#endif -#ifndef _ARM64_ #define _ARM64_ 1 -#endif #else #define _AMD64_ 1 #define __x86_64 1 #define _M_X64 100 /* Visual Studio */ #define _M_AMD64 100 /* Visual Studio */ -#define USE_MINGW_SETJMP_TWO_ARGS -#define mingw_getsp tinyc_getbp #endif #else #define __stdcall __attribute__((__stdcall__)) diff --git a/win32/include/setjmp.h b/win32/include/setjmp.h index dc971c77..ab6a4248 100644 --- a/win32/include/setjmp.h +++ b/win32/include/setjmp.h @@ -170,7 +170,6 @@ extern "C" { double D[8]; } _JUMP_BUFFER; #else - #define _JBLEN 1 #define _JBTYPE int #endif @@ -179,31 +178,22 @@ extern "C" { #define _JMP_BUF_DEFINED #endif - void * __cdecl __attribute__ ((__nothrow__)) mingw_getsp(void); +#pragma pack(pop) -#ifdef USE_MINGW_SETJMP_TWO_ARGS -#ifndef _INC_SETJMPEX -#define setjmp(BUF) _setjmp((BUF),mingw_getsp()) - int __cdecl __attribute__ ((__nothrow__)) _setjmp(jmp_buf _Buf,void *_Ctx); -#else -#undef setjmp -#define setjmp(BUF) _setjmpex((BUF),mingw_getsp()) -#define setjmpex(BUF) _setjmpex((BUF),mingw_getsp()) - int __cdecl __attribute__ ((__nothrow__)) _setjmpex(jmp_buf _Buf,void *_Ctx); -#endif -#else -#ifndef _INC_SETJMPEX -#define setjmp _setjmp -#endif - int __cdecl __attribute__ ((__nothrow__)) setjmp(jmp_buf _Buf); +#if defined __aarch64__ + int _setjmpex(jmp_buf _Buf, void *frame); + #define setjmp(BUF) _setjmpex((BUF), (char*)__builtin_frame_address(0) + 224) +#elif defined __x86_64__ + int _setjmp(jmp_buf _Buf, void *frame); + #define setjmp(BUF) _setjmp((BUF), __builtin_frame_address(0)) +#else /* __i386__ */ + int _setjmp(jmp_buf _Buf); + #define setjmp _setjmp #endif - __declspec(noreturn) __attribute__ ((__nothrow__)) void __cdecl ms_longjmp(jmp_buf _Buf,int _Value)/* throw(...)*/; - __declspec(noreturn) __attribute__ ((__nothrow__)) void __cdecl longjmp(jmp_buf _Buf,int _Value); +__declspec(noreturn) void longjmp(jmp_buf _Buf,int _Value); #ifdef __cplusplus } #endif - -#pragma pack(pop) #endif diff --git a/win32/include/stdlib.h b/win32/include/stdlib.h index 21a0fbd9..b710ec13 100644 --- a/win32/include/stdlib.h +++ b/win32/include/stdlib.h @@ -207,6 +207,21 @@ extern "C" { #endif #endif #endif + +#if defined __aarch64__ +/* something does not work using those from msvcrt.dll */ +# undef __argc +# undef __argv +# undef __wargv +# undef _wenviron +# undef _environ +extern int __argc; +extern char **__argv; +extern wchar_t **__wargv; +extern char **_environ; +extern wchar_t **_wenviron; +#endif + #ifndef _pgmptr #ifdef _MSVCRT_ extern char *_pgmptr; diff --git a/win32/include/winapi/winnt.h b/win32/include/winapi/winnt.h index 01a850a8..405413fb 100644 --- a/win32/include/winapi/winnt.h +++ b/win32/include/winapi/winnt.h @@ -47,9 +47,6 @@ extern "C" { #endif #endif -#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(__aarch64__) && !defined(_ARM64_) -#define _ARM64_ -#endif #ifdef _WIN64 #define MAX_NATURAL_ALIGNMENT sizeof(ULONGLONG) @@ -832,8 +829,6 @@ typedef DWORD LCID; typedef ULONG_PTR KSPIN_LOCK; typedef KSPIN_LOCK *PKSPIN_LOCK; -#if defined(_AMD64_) || defined(_ARM64_) - #if defined(__x86_64) && !defined(RC_INVOKED) #ifdef __cplusplus @@ -1285,7 +1280,6 @@ typedef DWORD LCID; #ifdef __cplusplus } #endif -#endif #define EXCEPTION_READ_FAULT 0 #define EXCEPTION_WRITE_FAULT 1 @@ -1339,7 +1333,6 @@ typedef DWORD LCID; #define LEGACY_SAVE_AREA_LENGTH sizeof(XMM_SAVE_AREA32) -#if defined(__x86_64) || defined(_AMD64_) typedef struct DECLSPEC_ALIGN(16) _CONTEXT { DWORD64 P1Home; DWORD64 P2Home; @@ -1411,7 +1404,6 @@ typedef DWORD LCID; DWORD64 LastExceptionToRip; DWORD64 LastExceptionFromRip; } CONTEXT,*PCONTEXT; -#endif /* defined(__x86_64) || defined(_AMD64_) */ #define RUNTIME_FUNCTION_INDIRECT 0x1 @@ -1422,41 +1414,24 @@ typedef DWORD LCID; } RUNTIME_FUNCTION,*PRUNTIME_FUNCTION; typedef PRUNTIME_FUNCTION (*PGET_RUNTIME_FUNCTION_CALLBACK)(DWORD64 ControlPc,PVOID Context); + typedef DWORD (*POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK)(HANDLE Process,PVOID TableAddress,PDWORD Entries,PRUNTIME_FUNCTION *Functions); -#if defined(_ARM64_) || defined(__aarch64__) +#define OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME "OutOfProcessFunctionTableCallback" +#endif /* defined(__x86_64) && !defined(RC_INVOKED) */ + +#if defined(_ARM64_) /* ARM64 Context Definition */ #define CONTEXT_ARM64 0x00400000 - -#ifndef CONTEXT_CONTROL #define CONTEXT_CONTROL (CONTEXT_ARM64 | 0x00000001L) -#endif -#ifndef CONTEXT_INTEGER #define CONTEXT_INTEGER (CONTEXT_ARM64 | 0x00000002L) -#endif -#ifndef CONTEXT_FLOATING_POINT #define CONTEXT_FLOATING_POINT (CONTEXT_ARM64 | 0x00000004L) -#endif -#ifndef CONTEXT_DEBUG #define CONTEXT_DEBUG (CONTEXT_ARM64 | 0x00000008L) -#endif - -#ifndef CONTEXT_FULL #define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT) -#endif -#ifndef CONTEXT_ALL #define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG) -#endif - -#ifndef ARM64_MAX_BREAKPOINTS #define ARM64_MAX_BREAKPOINTS 8 -#endif -#ifndef ARM64_MAX_WATCHPOINTS #define ARM64_MAX_WATCHPOINTS 2 -#endif -#ifndef _ARM64_NT_NEON128_DECLARED -#define _ARM64_NT_NEON128_DECLARED typedef union _ARM64_NT_NEON128 { struct { ULONGLONG Low; @@ -1467,10 +1442,7 @@ typedef DWORD LCID; WORD H[8]; BYTE B[16]; } ARM64_NT_NEON128,*PARM64_NT_NEON128; -#endif -#ifndef _ARM64_CONTEXT_DECLARED -#define _ARM64_CONTEXT_DECLARED typedef struct DECLSPEC_ALIGN(16) _ARM64_NT_CONTEXT { ULONG ContextFlags; ULONG Cpsr; @@ -1522,27 +1494,20 @@ typedef DWORD LCID; } ARM64_NT_CONTEXT,*PARM64_NT_CONTEXT; C_ASSERT(sizeof(ARM64_NT_CONTEXT) == 0x390); - C_ASSERT(offsetof(ARM64_NT_CONTEXT, ContextFlags) == 0x000); - C_ASSERT(offsetof(ARM64_NT_CONTEXT, X) == 0x008); - C_ASSERT(offsetof(ARM64_NT_CONTEXT, Fp) == 0x0f0); - C_ASSERT(offsetof(ARM64_NT_CONTEXT, Lr) == 0x0f8); - C_ASSERT(offsetof(ARM64_NT_CONTEXT, Sp) == 0x100); - C_ASSERT(offsetof(ARM64_NT_CONTEXT, Pc) == 0x108); - C_ASSERT(offsetof(ARM64_NT_CONTEXT, V) == 0x110); - C_ASSERT(sizeof(((ARM64_NT_CONTEXT *)0)->V[0]) == 16); - C_ASSERT(offsetof(ARM64_NT_CONTEXT, Fpcr) == 0x310); - C_ASSERT(offsetof(ARM64_NT_CONTEXT, Fpsr) == 0x314); - C_ASSERT(offsetof(ARM64_NT_CONTEXT, Bvr) == 0x338); - C_ASSERT(offsetof(ARM64_NT_CONTEXT, Wvr) == 0x380); -#endif typedef ARM64_NT_CONTEXT CONTEXT,*PCONTEXT; -#endif /* _ARM64_ || __aarch64__ */ + typedef struct _RUNTIME_FUNCTION { + DWORD BeginAddress; + DWORD UnwindData; + } RUNTIME_FUNCTION,*PRUNTIME_FUNCTION; + + typedef PRUNTIME_FUNCTION (*PGET_RUNTIME_FUNCTION_CALLBACK)(DWORD64 ControlPc,PVOID Context); typedef DWORD (*POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK)(HANDLE Process,PVOID TableAddress,PDWORD Entries,PRUNTIME_FUNCTION *Functions); -#define OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME "OutOfProcessFunctionTableCallback" +#endif /* _ARM64_ */ +#if (defined _ARM64_ || defined _AMD64_) && !defined RC_INVOKED NTSYSAPI VOID __cdecl RtlRestoreContext (PCONTEXT ContextRecord,struct _EXCEPTION_RECORD *ExceptionRecord); NTSYSAPI BOOLEAN __cdecl RtlAddFunctionTable(PRUNTIME_FUNCTION FunctionTable,DWORD EntryCount,DWORD64 BaseAddress); NTSYSAPI BOOLEAN __cdecl RtlInstallFunctionTableCallback(DWORD64 TableIdentifier,DWORD64 BaseAddress,DWORD Length,PGET_RUNTIME_FUNCTION_CALLBACK Callback,PVOID Context,PCWSTR OutOfProcessCallbackDll); diff --git a/win32/lib/chkstk.S b/win32/lib/chkstk.S index 43e21634..2b5b6175 100644 --- a/win32/lib/chkstk.S +++ b/win32/lib/chkstk.S @@ -9,7 +9,6 @@ /* ---------------------------------------------- */ #if defined(__aarch64__) -/* ---------------------------------------------- */ .globl __chkstk __chkstk: @@ -33,68 +32,8 @@ L_chkstk_tail: L_chkstk_done: ret -.globl _(tinyc_getbp) -_(tinyc_getbp): - mov x0, x29 - ret - -.globl _(mingw_getsp) -_(mingw_getsp): - mov x0, sp - ret - -.globl _(__mingw_setjmp) -_(__mingw_setjmp): - /* _JUMP_BUFFER layout matches win32/include/setjmp.h for _ARM64_: - 0x00 Frame, 0x08 Reserved, 0x10-0x68 X19-X30, 0x70 Sp, - 0x78 Fpcr/Fpsr, 0x80-0xB8 D8-D15. */ - str xzr, [x0] /* Frame = 0 */ - stp x19, x20, [x0, 16] - stp x21, x22, [x0, 32] - stp x23, x24, [x0, 48] - stp x25, x26, [x0, 64] - stp x27, x28, [x0, 80] - stp x29, x30, [x0, 96] - mov x2, sp - str x2, [x0, 112] /* Sp */ - mrs x2, FPCR - str w2, [x0, 120] /* Fpcr */ - mrs x2, FPSR - str w2, [x0, 124] /* Fpsr */ - stp d8, d9, [x0, 128] - stp d10, d11, [x0, 144] - stp d12, d13, [x0, 160] - stp d14, d15, [x0, 176] - mov x0, 0 - ret - -.globl _(__mingw_longjmp) -_(__mingw_longjmp): - ldp x19, x20, [x0, 16] - ldp x21, x22, [x0, 32] - ldp x23, x24, [x0, 48] - ldp x25, x26, [x0, 64] - ldp x27, x28, [x0, 80] - ldp x29, x30, [x0, 96] - ldr x2, [x0, 112] /* Sp */ - mov sp, x2 - ldr w2, [x0, 120] /* Fpcr */ - msr FPCR, x2 - ldr w2, [x0, 124] /* Fpsr */ - msr FPSR, x2 - ldp d8, d9, [x0, 128] - ldp d10, d11, [x0, 144] - ldp d12, d13, [x0, 160] - ldp d14, d15, [x0, 176] - mov x0, x1 - cbnz x0, L_longjmp_done - mov x0, 1 -L_longjmp_done: - ret - -/* ---------------------------------------------- */ -#elif !defined(__x86_64__) /* ---------------------------------------------- */ +#elif defined(__i386__) .globl _(__chkstk) _(__chkstk): @@ -118,8 +57,7 @@ P0: jmp *4(%eax) /* ---------------------------------------------- */ -#else -/* ---------------------------------------------- */ +#else /* __x86_64__ */ .globl _(__chkstk) _(__chkstk): @@ -143,14 +81,6 @@ P0: mov (%rax),%rcx /* restore ecx */ jmp *8(%rax) -/* ---------------------------------------------- */ -/* setjmp/longjmp support */ - -.globl _(tinyc_getbp) -_(tinyc_getbp): - mov %rbp,%rax - ret - /* ---------------------------------------------- */ #endif /* ---------------------------------------------- */ diff --git a/win32/lib/crt1.c b/win32/lib/crt1.c index e1910813..7022872a 100644 --- a/win32/lib/crt1.c +++ b/win32/lib/crt1.c @@ -75,10 +75,11 @@ __attribute__((weak)) extern int __run_on_exit(); int _runtmain(int argc, /* as tcc passed in */ char **argv) { int ret; -#ifdef UNICODE +#if defined UNICODE || defined __aarch64__ _startupinfo start_info = {0}; - - __tgetmainargs(&__argc, &__targv, &_tenviron, _dowildcard, &start_info); + __tgetmainargs(&__argc, &__targv, &_tenviron, 0, &start_info); +#endif +#ifdef UNICODE /* may be wrong when tcc has received wildcards (*.c) */ if (argc < __argc) { __targv += __argc - argc; @@ -93,6 +94,8 @@ int _runtmain(int argc, /* as tcc passed in */ char **argv) #endif run_ctors(__argc, __targv, _tenviron); ret = _tmain(__argc, __targv, _tenviron); + fflush(stdout); + fflush(stderr); run_dtors(); __run_on_exit(ret); return ret; diff --git a/win32/lib/winex.c b/win32/lib/winex.c new file mode 100644 index 00000000..d84d8d75 --- /dev/null +++ b/win32/lib/winex.c @@ -0,0 +1,27 @@ +/* ------------------------------------------------------------------------- */ +/* winex.c : extra stuff */ + +#if __aarch64__ +#include +/* replaces environ from arm64-msvcrt.dll which does not exist */ +char **_environ; +wchar_t **_wenviron; +/* those do exist but have problems */ +int __argc; +char **__argv; +wchar_t **__wargv; +#endif + +#if __aarch64__ || __x86_64__ +/* MSVC x64 intrinsic */ +void __faststorefence(void) +{ +#if __aarch64__ + /* ARM64: Data Memory Barrier (Inner Shareable) */ + __asm__("dmb ish"); +#elif __x86_64__ + /* x86-64: lock prefix to flush store buffer */ + __asm__("lock; orl $0,(%%rsp)" ::: "memory"); +#endif +} +#endif diff --git a/x86_64-gen.c b/x86_64-gen.c index e1f4ae70..06eb90c0 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -266,14 +266,6 @@ ST_FUNC void gen_addr32(int r, Sym *sym, int c) gen_le32(c); } -/* output constant with relocation if 'r & VT_SYM' is true */ -ST_FUNC void gen_addr64(int r, Sym *sym, int64_t c) -{ - if (r & VT_SYM) - greloca(cur_text_section, sym, ind, R_X86_64_64, c), c=0; - gen_le64(c); -} - /* output constant with relocation if 'r & VT_SYM' is true */ ST_FUNC void gen_addrpc32(int r, Sym *sym, int c) {