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).
This commit is contained in:
grischka 2026-05-04 10:30:15 +02:00
parent 576cd2a923
commit 30afb50e64
33 changed files with 602 additions and 456 deletions

View File

@ -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

View File

@ -31,8 +31,10 @@ ifdef CONFIG_WIN32
LIBTCCDEF = libtcc.def
endif
ifneq ($(CONFIG_debug),yes)
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
CFG = -unx

View File

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

View File

@ -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 |

View File

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

View File

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

View File

@ -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

View File

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

View File

@ -23,13 +23,6 @@ typedef unsigned long long uint64_t;
#include <string.h>
#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;

View File

@ -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

View File

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

10
tcc.c
View File

@ -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);
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;
}

21
tcc.h
View File

@ -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 <windows.h>
# include <io.h> /* open, close etc. */
# include <direct.h> /* 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);

View File

@ -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();

View File

@ -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, ...);

63
tccpe.c
View File

@ -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;
}
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 + 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)
if (s1->nb_errors)
goto done;
pe_write(&pe);
dynarray_reset(&pe.sec_info, &pe.sec_count);
} 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)

View File

@ -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;

View File

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

View File

@ -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

View File

@ -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 <tcclib.h>
#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;
}

164
tests/msvcrt_start.c Normal file
View File

@ -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 <windows.h>
#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 <stdarg.h>
#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 */

View File

@ -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,7 +2553,7 @@ 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",
printf(LONG_LONG_FORMAT " " LONG_LONG_FORMAT " " LONG_LONG_FORMAT " "XLONG_LONG_FORMAT"\n",
(long long)1,
(long long)-2,
1LL,
@ -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)

74
tests/test-win32.bat Normal file
View File

@ -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%

View File

@ -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'

View File

@ -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%

View File

@ -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__))

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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
/* ---------------------------------------------- */

View File

@ -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;

27
win32/lib/winex.c Normal file
View File

@ -0,0 +1,27 @@
/* ------------------------------------------------------------------------- */
/* winex.c : extra stuff */
#if __aarch64__
#include <stdlib.h>
/* 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

View File

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