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) {