Add and stabilize Windows ARM64 support

This commit is contained in:
Benjamin Oldenburg 2026-03-15 16:29:02 +07:00
parent 98765e5ebc
commit 4f4b3dda6b
32 changed files with 4126 additions and 203 deletions

View File

@ -85,6 +85,23 @@ jobs:
.\tcc -I.. libtcc.dll -v ../tests/libtcc_test.c -o libtest.exe && .\libtest.exe
.\tcc -I.. libtcc.dll -run ../tests/libtcc_test.c
test-aarch64-win32:
runs-on: windows-11-arm
timeout-minutes: 6
steps:
- uses: actions/checkout@v4
- uses: ilammy/msvc-dev-cmd@v1
with:
arch: arm64
- name: build & test tcc (aarch64-win32)
shell: cmd
run: |
echo ::group:: build with clang
cd win32
call build-tcc.bat -t arm64 -c clang
echo ::endgroup::
.\tcc -v
test-armv7-linux:
runs-on: ubuntu-22.04
timeout-minutes: 8

View File

@ -33,8 +33,9 @@ ifdef CONFIG_WIN32
ifneq ($(CONFIG_debug),yes)
LDFLAGS += -s
endif
NATIVE_TARGET = $(ARCH)-win$(if $(findstring arm,$(ARCH)),ce,32)
NATIVE_TARGET = $(if $(findstring arm64,$(ARCH)),arm64-win32,$(ARCH)-win$(if $(findstring arm,$(ARCH)),ce,32))
else
CFG = -unx
LIBS+=-lm
ifneq ($(CONFIG_ldl),no)
@ -113,6 +114,7 @@ DEF-arm64-osx = $(DEF-arm64) -DTCC_TARGET_MACHO
DEF-arm64-FreeBSD = $(DEF-arm64) -DTARGETOS_FreeBSD
DEF-arm64-NetBSD = $(DEF-arm64) -DTARGETOS_NetBSD
DEF-arm64-OpenBSD = $(DEF-arm64) -DTARGETOS_OpenBSD
DEF-arm64-win32 = $(DEF-arm64) -DTCC_TARGET_PE
DEF-riscv64 = -DTCC_TARGET_RISCV64
DEF-c67 = -DTCC_TARGET_C67 -w # disable warnigs
DEF-x86_64-FreeBSD = $(DEF-x86_64) -DTARGETOS_FreeBSD
@ -130,7 +132,7 @@ TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info
all: $(PROGS) $(TCCLIBS) $(TCCDOCS)
# cross compiler targets to build
TCC_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm-wince c67
TCC_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm64-win32 arm-wince c67
TCC_X += riscv64 arm64-osx
# TCC_X += arm-fpa arm-fpa-ld arm-vfp arm-eabi
@ -212,8 +214,9 @@ arm-fpa-ld_FILES = $(arm_FILES)
arm-vfp_FILES = $(arm_FILES)
arm-eabi_FILES = $(arm_FILES)
arm-eabihf_FILES = $(arm_FILES)
arm64_FILES = $(CORE_FILES) arm64-gen.c arm64-link.c arm64-asm.c
arm64_FILES = $(CORE_FILES) arm64-gen.c arm64-link.c arm64-asm.c arm64-tok.h
arm64-osx_FILES = $(arm64_FILES) tccmacho.c
arm64-win32_FILES = $(arm64_FILES) tccpe.c
c67_FILES = $(CORE_FILES) c67-gen.c c67-link.c tcccoff.c
riscv64_FILES = $(CORE_FILES) riscv64-gen.c riscv64-link.c riscv64-asm.c

File diff suppressed because it is too large Load Diff

View File

@ -12,18 +12,29 @@
#ifdef TARGET_DEFS_ONLY
// Number of registers available to allocator:
#ifdef TCC_TARGET_PE
#define NB_REGS 27 // x0-x17, x30, v0-v7 (x18 reserved on Windows)
#define TREG_R(x) (x) // x = 0..17
#define TREG_R30 18
#define TREG_F(x) (x + 19) // x = 0..7
#define RC_INT (1 << 0)
#define RC_FLOAT (1 << 1)
#define RC_R(x) (1 << (2 + (x))) // x = 0..17
#define RC_R30 (1 << 20)
#define RC_F(x) (1 << (21 + (x))) // x = 0..7
#else
#define NB_REGS 28 // x0-x18, x30, v0-v7
#define TREG_R(x) (x) // x = 0..18
#define TREG_R30 19
#define TREG_F(x) (x + 20) // x = 0..7
// Register classes sorted from more general to more precise:
#define RC_INT (1 << 0)
#define RC_FLOAT (1 << 1)
#define RC_R(x) (1 << (2 + (x))) // x = 0..18
#define RC_R30 (1 << 21)
#define RC_F(x) (1 << (22 + (x))) // x = 0..7
#endif
// Register classes sorted from more general to more precise:
#define RC_IRET (RC_R(0)) // int return register class
#define RC_FRET (RC_F(0)) // float return register class
@ -38,7 +49,7 @@
#define MAX_ALIGN 16
#ifndef TCC_TARGET_MACHO
#if !defined(TCC_TARGET_MACHO) && !defined(TCC_TARGET_PE)
#define CHAR_IS_UNSIGNED
#endif
@ -79,7 +90,9 @@ ST_DATA const int reg_classes[NB_REGS] = {
RC_INT | RC_R(15),
RC_INT | RC_R(16),
RC_INT | RC_R(17),
#ifndef TCC_TARGET_PE
RC_INT | RC_R(18),
#endif
RC_R30, // not in RC_INT as we make special use of x30
RC_FLOAT | RC_F(0),
RC_FLOAT | RC_F(1),
@ -460,10 +473,18 @@ static void arm64_strv(int sz_, int dst, int bas, uint64_t off)
static void arm64_sym(int r, Sym *sym, unsigned long addend)
{
#ifdef TCC_TARGET_PE
/* PE links symbol addresses directly; there is no ELF-style GOT here. */
greloca(cur_text_section, sym, ind, R_AARCH64_ADR_PREL_PG_HI21, 0);
o(0x90000000 | r); // adrp xr, #sym
greloca(cur_text_section, sym, ind, R_AARCH64_ADD_ABS_LO12_NC, 0);
o(0x91000000 | r | (r << 5)); // add xr, xr, #sym
#else
greloca(cur_text_section, sym, ind, R_AARCH64_ADR_GOT_PAGE, 0);
o(0x90000000 | r); // adrp xr, #sym
greloca(cur_text_section, sym, ind, R_AARCH64_LD64_GOT_LO12_NC, 0);
o(0xf9400000 | r | (r << 5)); // ld xr,[xr, #sym]
#endif
if (addend) {
// add xr, xr, #addend
if (addend & 0xffful)
@ -722,10 +743,7 @@ static void gen_bounds_epilog(void)
if (offset_modified) {
saved_ind = ind;
ind = func_bound_ind;
greloca(cur_text_section, sym_data, ind, R_AARCH64_ADR_GOT_PAGE, 0);
o(0x90000000 | 0); // adrp x0, #sym_data
greloca(cur_text_section, sym_data, ind, R_AARCH64_LD64_GOT_LO12_NC, 0);
o(0xf9400000 | 0 | (0 << 5)); // ld x0,[x0, #sym_data]
arm64_sym(0, sym_data, 0);
gen_bounds_call(TOK___bound_local_new);
ind = saved_ind;
}
@ -733,10 +751,7 @@ static void gen_bounds_epilog(void)
/* generate bound check local freeing */
o(0xa9bf07e0); /* stp x0, x1, [sp, #-16]! */
o(0x3c9f0fe0); /* str q0, [sp, #-16]! */
greloca(cur_text_section, sym_data, ind, R_AARCH64_ADR_GOT_PAGE, 0);
o(0x90000000 | 0); // adrp x0, #sym_data
greloca(cur_text_section, sym_data, ind, R_AARCH64_LD64_GOT_LO12_NC, 0);
o(0xf9400000 | 0 | (0 << 5)); // ld x0,[x0, #sym_data]
arm64_sym(0, sym_data, 0);
gen_bounds_call(TOK___bound_local_delete);
o(0x3cc107e0); /* ldr q0, [sp], #16 */
o(0xa8c107e0); /* ldp x0, x1, [sp], #16 */
@ -745,6 +760,8 @@ static void gen_bounds_epilog(void)
static int arm64_hfa_aux(CType *type, int *fsize, int num)
{
if (!type)
return -1;
if (is_float(type->t)) {
int a, n = type_size(type, &a);
if (num >= 4 || (*fsize && *fsize != n))
@ -753,13 +770,27 @@ static int arm64_hfa_aux(CType *type, int *fsize, int num)
return num + 1;
}
else if ((type->t & VT_BTYPE) == VT_STRUCT) {
int is_struct = 0; // rather than union
int is_struct = 1; /* assume struct, check if union */
Sym *field;
if (!type->ref)
return -1;
/* A union has all fields at offset 0, a struct has increasing offsets */
for (field = type->ref->next; field; field = field->next)
if (field->c) {
if (field->c != 0) {
is_struct = 1;
break;
}
/* If all fields are at offset 0 and there's more than one field, it's a union */
if (type->ref->next && type->ref->next->next && !type->ref->next->c) {
/* Check if all fields are at offset 0 (union) */
int all_zero = 1;
for (field = type->ref->next; field; field = field->next)
if (field->c != 0) {
all_zero = 0;
break;
}
is_struct = !all_zero;
}
if (is_struct) {
int num0 = num;
for (field = type->ref->next; field; field = field->next) {
@ -788,6 +819,8 @@ static int arm64_hfa_aux(CType *type, int *fsize, int num)
}
else if ((type->t & VT_ARRAY) && ((type->t & VT_BTYPE) != VT_PTR)) {
int num1;
if (!type->ref || (type->t & VT_VLA))
return -1;
if (!type->ref->c)
return num;
num1 = arm64_hfa_aux(&type->ref->type, fsize, num);
@ -803,10 +836,16 @@ static int arm64_hfa_aux(CType *type, int *fsize, int num)
static int arm64_hfa(CType *type, unsigned *fsize)
{
int n, sz;
if (!type)
return 0;
if ((type->t & VT_BTYPE) == VT_STRUCT ||
((type->t & VT_ARRAY) && ((type->t & VT_BTYPE) != VT_PTR))) {
int sz = 0;
int n = arm64_hfa_aux(type, &sz, 0);
if (!type->ref || (type->t & VT_VLA))
return 0;
sz = 0;
n = arm64_hfa_aux(type, &sz, 0);
if (0 < n && n <= 4) {
if (fsize)
*fsize = sz;
@ -825,6 +864,7 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l
for (i = 0; i < n; i++) {
int hfa = arm64_hfa(type[i], 0);
int win_vararg_float = 0;
int size, align;
if ((type[i]->t & VT_ARRAY) ||
@ -838,6 +878,15 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l
nx = 8;
nv = 8;
}
#elif defined(TCC_TARGET_PE)
if (variadic && i >= variadic && (hfa || is_float(type[i]->t))) {
hfa = 0;
if (is_float(type[i]->t)) {
win_vararg_float = 1;
size = 8;
align = 8;
}
}
#endif
if (hfa)
// B.2
@ -858,7 +907,7 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l
size = (size + 7) & ~7;
// C.1
if (is_float(type[i]->t) && nv < 8) {
if (!win_vararg_float && is_float(type[i]->t) && nv < 8) {
a[i] = 16 + (nv++ << 1);
continue;
}
@ -887,7 +936,7 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l
size = 8;
// C.6
if (hfa || is_float(type[i]->t)) {
if (!win_vararg_float && (hfa || is_float(type[i]->t))) {
a[i] = ns;
ns += size;
continue;
@ -992,6 +1041,32 @@ static int n_func_args(CType *type)
return n_args;
}
static void arm64_sub_sp(uint64_t diff)
{
if (!diff)
return;
#ifdef TCC_TARGET_PE
if (diff >= 4096) {
Sym *sym = external_helper_sym(TOK___chkstk);
arm64_movimm(15, diff >> 4);
greloca(cur_text_section, sym, ind, R_AARCH64_CALL26, 0);
o(0x94000000); // bl __chkstk
o(0xcb2f73ff); // sub sp,sp,x15,lsl #4
return;
}
#endif
if (!(diff >> 24)) {
if (diff & 0xfff)
o(0xd10003ff | (diff & 0xfff) << 10); // sub sp,sp,#low12
if (diff >> 12)
o(0xd14003ff | (diff >> 12) << 10); // sub sp,sp,#high12,lsl #12
} else {
arm64_movimm(16, diff);
o(0xcb3063ff); // sub sp,sp,x16
}
}
ST_FUNC void gfunc_call(int nb_args)
{
CType *return_type;
@ -999,8 +1074,10 @@ ST_FUNC void gfunc_call(int nb_args)
unsigned long *a, *a1;
unsigned long stack;
int i;
int variadic = (vtop[-nb_args].type.ref->f.func_type == FUNC_ELLIPSIS);
int var_nb_arg = n_func_args(&vtop[-nb_args].type);
int func_type = vtop[-nb_args].type.ref->f.func_type;
int variadic = (func_type == FUNC_ELLIPSIS);
int old_style = (func_type == FUNC_OLD);
int var_nb_arg = variadic ? n_func_args(&vtop[-nb_args].type) : 0;
save_regs(nb_args + 1);
@ -1021,7 +1098,7 @@ ST_FUNC void gfunc_call(int nb_args)
for (i = 0; i < nb_args; i++)
t[nb_args - i] = &vtop[-i].type;
stack = arm64_pcs(variadic ? var_nb_arg : 0, nb_args, t, a);
stack = arm64_pcs((variadic || old_style) ? var_nb_arg : 0, nb_args, t, a);
// Allocate space for structs replaced by pointer:
for (i = nb_args; i; i--)
@ -1038,10 +1115,7 @@ ST_FUNC void gfunc_call(int nb_args)
if (stack >= 0x1000000) // 16Mb
tcc_error("stack size too big %lu", stack);
if (stack & 0xfff)
o(0xd10003ff | (stack & 0xfff) << 10); // sub sp,sp,#(n)
if (stack >> 12)
o(0xd14003ff | (stack >> 12) << 10);
arm64_sub_sp(stack);
// First pass: set all values on stack
for (i = nb_args; i; i--) {
@ -1089,7 +1163,14 @@ ST_FUNC void gfunc_call(int nb_args)
for (i = nb_args; i; i--, vtop--) {
if (a[i] < 16 && !(a[i] & 1)) {
// value in general-purpose registers
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
if ((variadic || old_style) && i > var_nb_arg && is_float(vtop->type.t)) {
gv(RC_FLOAT);
if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
o(0x9e660000 | intr(a[i] / 2) | fltr(vtop->r) << 5); // fmov xN,dM
else
o(0x1e260000 | intr(a[i] / 2) | fltr(vtop->r) << 5); // fmov wN,sM
}
else if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
int align, size = type_size(&vtop->type, &align);
if (size) {
vtop->type.t = VT_PTR;
@ -1108,14 +1189,20 @@ ST_FUNC void gfunc_call(int nb_args)
// value in floating-point registers
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
uint32_t j, sz, n = arm64_hfa(&vtop->type, &sz);
vtop->type.t = VT_PTR;
gaddrof();
gv(RC_R30);
for (j = 0; j < n; j++)
o(0x3d4003c0 |
(sz & 16) << 19 | -(sz & 8) << 27 | (sz & 4) << 29 |
(a[i] / 2 - 8 + j) |
j << 10); // ldr ([sdq])(*),[x30,#(j * sz)]
if (n > 0) {
/* HFA struct - load from memory into float registers */
vtop->type.t = VT_PTR;
gaddrof();
gv(RC_R30);
for (j = 0; j < n; j++)
o(0x3d4003c0 |
(sz & 16) << 19 | -(sz & 8) << 27 | (sz & 4) << 29 |
(a[i] / 2 - 8 + j) |
j << 10); // ldr ([sdq])(*),[x30,#(j * sz)]
} else {
/* Non-HFA struct in float register slot - shouldn't happen */
gv(RC_F(a[i] / 2 - 8));
}
}
else
gv(RC_F(a[i] / 2 - 8));
@ -1157,12 +1244,13 @@ ST_FUNC void gfunc_call(int nb_args)
}
else if (a[0] == 16) {
/* HFA struct return - store from float registers to the address in x8 */
uint32_t j, sz, n = arm64_hfa(return_type, &sz);
for (j = 0; j < n; j++)
o(0x3d000100 |
(sz & 16) << 19 | -(sz & 8) << 27 | (sz & 4) << 29 |
(a[i] / 2 - 8 + j) |
j << 10); // str ([sdq])(*),[x8,#(j * sz)]
(fltr(REG_FRET) + j) |
j << 10); // str ([sdq])(j),[x8,#(j * sz)]
}
}
}
@ -1177,11 +1265,23 @@ static int arm64_func_va_list_gr_offs;
static int arm64_func_va_list_vr_offs;
static int arm64_func_sub_sp_offset;
#define ARM64_FUNC_STACK_SETUP_SLOTS 6
#ifdef TCC_TARGET_PE
static unsigned long arm64_pe_param_off(unsigned long a)
{
return a < 16 ? 160 + a / 2 * 8 :
a < 32 ? 16 + (a - 16) / 2 * 16 :
224 + ((a - 32) >> 1 << 1);
}
#endif
ST_FUNC void gfunc_prolog(Sym *func_sym)
{
CType *func_type = &func_sym->type;
int n = 0;
int i = 0;
int pcs_n;
Sym *sym;
CType **t;
unsigned long *a;
@ -1195,13 +1295,26 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
for (sym = func_type->ref; sym; sym = sym->next)
++n;
t = n ? tcc_malloc(n * sizeof(*t)) : NULL;
a = n ? tcc_malloc(n * sizeof(*a)) : NULL;
pcs_n = n - 1;
t = n || variadic ? tcc_malloc((n + variadic) * sizeof(*t)) : NULL;
a = n || variadic ? tcc_malloc((n + variadic) * sizeof(*a)) : NULL;
for (sym = func_type->ref; sym; sym = sym->next)
t[i++] = &sym->type;
#ifdef TCC_TARGET_PE
if (variadic) {
t[i++] = &int_type;
++pcs_n;
}
#endif
arm64_func_va_list_stack = arm64_pcs(variadic ? var_nb_arg : 0, n - 1, t, a);
arm64_func_va_list_stack = arm64_pcs(variadic ? var_nb_arg : 0,
pcs_n, t, a);
#ifdef TCC_TARGET_PE
if (variadic)
arm64_func_va_list_stack = arm64_pe_param_off(a[n]);
#endif
#if !defined(TCC_TARGET_MACHO)
if (variadic) {
@ -1264,11 +1377,11 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
// HFAs of float and double need to be written differently:
if (16 <= a[i] && a[i] < 32 && (sym->type.t & VT_BTYPE) == VT_STRUCT) {
uint32_t j, sz, k = arm64_hfa(&sym->type, &sz);
if (sz < 16)
if (k > 0 && sz < 16)
for (j = 0; j < k; j++) {
o(0x3d0003e0 | -(sz & 8) << 27 | (sz & 4) << 29 |
((a[i] - 16) / 2 + j) | (off / sz + j) << 10);
// str ([sdq])(*),[sp,#(j * sz)]
// str ([sdq])(j),[sp,#(j * sz)]
}
}
}
@ -1278,9 +1391,9 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
o(0x910003fd); // mov x29,sp
arm64_func_sub_sp_offset = ind;
// In gfunc_epilog these will be replaced with code to decrement SP:
o(0xd503201f); // nop
o(0xd503201f); // nop
/* In gfunc_epilog these will be replaced with stack setup code. */
for (i = 0; i < ARM64_FUNC_STACK_SETUP_SLOTS; ++i)
o(0xd503201f); // nop
loc = 0;
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check)
@ -1295,6 +1408,16 @@ ST_FUNC void gen_va_start(void)
gaddrof();
r = intr(gv(RC_INT));
#ifdef TCC_TARGET_PE
if (arm64_func_va_list_stack) {
arm64_movimm(30, arm64_func_va_list_stack);
o(0x8b1e03be); // add x30,x29,x30
} else
o(0x910283be); // add x30,x29,#160
o(0xf900001e | r << 5); // str x30,[x(r)]
--vtop;
return;
#else
if (arm64_func_va_list_stack) {
//xx could use add (immediate) here
arm64_movimm(30, arm64_func_va_list_stack + 224);
@ -1324,6 +1447,7 @@ ST_FUNC void gen_va_start(void)
#endif
--vtop;
#endif
}
ST_FUNC void gen_va_arg(CType *t)
@ -1332,6 +1456,51 @@ ST_FUNC void gen_va_arg(CType *t)
unsigned fsize, hfa = arm64_hfa(t, &fsize);
uint32_t r0, r1;
#ifdef TCC_TARGET_PE
uint32_t slot = size;
int indirect = 0;
if ((t->t & VT_BTYPE) == VT_STRUCT) {
if (size > 16) {
slot = 8;
indirect = 1;
} else {
slot = (size + 7) & -8;
}
} else if (slot > 16) {
slot = 8;
indirect = 1;
} else if (slot < 8) {
slot = 8;
}
gaddrof();
r0 = intr(gv(RC_INT));
r1 = get_reg(RC_INT);
vtop[0].r = r1 | VT_LVAL;
r1 = intr(r1);
o(0xf9400000 | r1 | r0 << 5); // ldr x(r1),[x(r0)] // ap
if (slot) {
if (slot == 16) {
o(0x910363be); // add x30,x29,#216
o(0xeb1e003f | r1 << 5); // cmp x(r1),x30
o(0x54000041); // b.ne .+8
o(0x910383a0 | r1 | 29 << 5); // add x(r1),x29,#224
}
if (align == 16) {
o(0x91003c00 | r1 | r1 << 5); // add x(r1),x(r1),#15
o(0x927cec00 | r1 | r1 << 5); // and x(r1),x(r1),#-16
}
o(0x9100001e | r1 << 5 | slot << 10); // add x30,x(r1),#(slot)
o(0xf900001e | r0 << 5); // str x30,[x(r0)] // ap += slot
}
if (indirect)
o(0xf9400000 | r1 | r1 << 5); // ldr x(r1),[x(r1)]
return;
#endif
if (is_float(t->t)) {
hfa = 1;
fsize = size;
@ -1451,13 +1620,14 @@ ST_FUNC void gfunc_return(CType *func_type)
}
case 16:
if ((func_type->t & VT_BTYPE) == VT_STRUCT) {
uint32_t j, sz, n = arm64_hfa(&vtop->type, &sz);
/* 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));
for (j = 0; j < n; j++)
o(0x3d400000 |
(sz & 16) << 19 | -(sz & 8) << 27 | (sz & 4) << 29 |
j | j << 10); // ldr ([sdq])(*),[x0,#(j * sz)]
(fltr(REG_FRET) + j) | j << 10); // ldr ([sdq])(j),[x0,#(j * sz)]
}
else
gv(RC_FRET);
@ -1470,44 +1640,34 @@ ST_FUNC void gfunc_return(CType *func_type)
ST_FUNC void gfunc_epilog(void)
{
int i;
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check)
gen_bounds_epilog();
#endif
if (loc) {
// Insert instructions to subtract size of stack frame from SP.
unsigned char *ptr = cur_text_section->data + arm64_func_sub_sp_offset;
/* Insert instructions to subtract the stack frame from SP. */
addr_t saved_ind = ind;
addr_t patch_end = arm64_func_sub_sp_offset + ARM64_FUNC_STACK_SETUP_SLOTS * 4;
uint64_t diff = (-loc + 15) & ~15;
if (!(diff >> 24)) {
if (diff & 0xfff) // sub sp,sp,#(diff & 0xfff)
write32le(ptr, 0xd10003ff | (diff & 0xfff) << 10);
if (diff >> 12) // sub sp,sp,#(diff >> 12),lsl #12
write32le(ptr + 4, 0xd14003ff | (diff >> 12) << 10);
}
else {
// In this case we may subtract more than necessary,
// but always less than 17/16 of what we were aiming for.
int i = 0;
int j = 0;
while (diff >> 20) {
diff = (diff + 0xffff) >> 16;
++i;
}
while (diff >> 16) {
diff = (diff + 1) >> 1;
++j;
}
write32le(ptr, 0xd2800010 | diff << 5 | i << 21);
// mov x16,#(diff),lsl #(16 * i)
write32le(ptr + 4, 0xcb3063ff | j << 10);
// sub sp,sp,x16,lsl #(j)
}
ind = arm64_func_sub_sp_offset;
arm64_sub_sp(diff);
for (i = ind; i < patch_end; i += 4)
write32le(cur_text_section->data + i, 0xd503201f); // nop
ind = saved_ind;
}
o(0x910003bf); // mov sp,x29
o(0xa8ce7bfd); // ldp x29,x30,[sp],#224
o(0xd65f03c0); // ret
#ifdef TCC_TARGET_PE
{
unsigned start = arm64_func_sub_sp_offset - 8;
pe_add_unwind_data(start, ind, -loc);
}
#endif
}
ST_FUNC void gen_fill_nops(int bytes)
@ -2096,10 +2256,7 @@ ST_FUNC void gen_increment_tcov (SValue *sv)
vpushv(sv);
vtop->r = r1 = get_reg(RC_INT);
r2 = get_reg(RC_INT);
greloca(cur_text_section, sv->sym, ind, R_AARCH64_ADR_GOT_PAGE, 0);
o(0x90000000 | r1); // adrp r1, #sym
greloca(cur_text_section, sv->sym, ind, R_AARCH64_LD64_GOT_LO12_NC, 0);
o(0xf9400000 | r1 | (r1 << 5)); // ld xr,[xr, #sym]
arm64_sym(r1, sv->sym, 0);
o(0xf9400000 | (intr(r1)<<5) | intr(r2)); // ldr r2, [r1]
o(0x91000400 | (intr(r2)<<5) | intr(r2)); // add r2, r2, #1
o(0xf9000000 | (intr(r1)<<5) | intr(r2)); // str r2, [r1]

View File

@ -50,6 +50,8 @@ ST_FUNC int code_reloc (int reloc_type)
case R_AARCH64_JUMP26:
case R_AARCH64_CALL26:
case R_AARCH64_JUMP_SLOT:
case R_AARCH64_CONDBR19:
case R_AARCH64_TSTBR14:
return 1;
}
return -1;
@ -61,7 +63,7 @@ ST_FUNC int code_reloc (int reloc_type)
ST_FUNC int gotplt_entry_type (int reloc_type)
{
switch (reloc_type) {
case R_AARCH64_PREL32:
case R_AARCH64_PREL32:
case R_AARCH64_MOVW_UABS_G0_NC:
case R_AARCH64_MOVW_UABS_G1_NC:
case R_AARCH64_MOVW_UABS_G2_NC:
@ -76,6 +78,8 @@ ST_FUNC int gotplt_entry_type (int reloc_type)
case R_AARCH64_GLOB_DAT:
case R_AARCH64_JUMP_SLOT:
case R_AARCH64_COPY:
case R_AARCH64_CONDBR19:
case R_AARCH64_TSTBR14:
return NO_GOTPLT_ENTRY;
case R_AARCH64_ABS32:
@ -238,8 +242,23 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
return;
case R_AARCH64_ADR_PREL_PG_HI21: {
uint64_t off = (val >> 12) - (addr >> 12);
#ifdef TCC_TARGET_PE
/* Weak undefined symbols resolve to address 0 on PE. ADRP cannot
encode that from the default 64-bit image base, so materialize
zero directly and let the paired ADD handle any low addend. */
if ((off + ((uint64_t)1 << 20)) >> 21) {
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
if (sym->st_shndx == SHN_UNDEF
&& ELFW(ST_BIND)(sym->st_info) == STB_WEAK) {
write32le(ptr, 0xd2800000 | (read32le(ptr) & 0x1f));
return;
}
tcc_error_noabort("R_AARCH64_ADR_PREL_PG_HI21 relocation failed");
}
#else
if ((off + ((uint64_t)1 << 20)) >> 21)
tcc_error_noabort("R_AARCH64_ADR_PREL_PG_HI21 relocation failed");
#endif
write32le(ptr, ((read32le(ptr) & 0x9f00001f) |
(off & 0x1ffffc) << 3 | (off & 3) << 29));
return;
@ -265,19 +284,58 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
write32le(ptr, ((read32le(ptr) & 0xffc003ff) |
(val & 0xff0) << 6));
return;
case R_AARCH64_CONDBR19:
/* Conditional branch: 19-bit signed offset, bits 23:5 */
#ifdef DEBUG_RELOC
printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val,
(char *) symtab_section->link->data + sym->st_name);
#endif
if (((val - addr) + ((uint64_t)1 << 20)) & ~(uint64_t)0x1ffffc)
tcc_error_noabort("R_AARCH64_CONDBR19 relocation failed"
" (val=%lx, addr=%lx)", (long)val, (long)addr);
write32le(ptr, ((read32le(ptr) & 0xff00001f) |
(((val - addr) >> 2 & 0x7ffff) << 5)));
return;
case R_AARCH64_TSTBR14:
/* Test and branch: 14-bit signed offset, bits 20:5 */
#ifdef DEBUG_RELOC
printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val,
(char *) symtab_section->link->data + sym->st_name);
#endif
if (((val - addr) + ((uint64_t)1 << 15)) & ~(uint64_t)0xfffc)
tcc_error_noabort("R_AARCH64_TSTBR14 relocation failed"
" (val=%lx, addr=%lx)", (long)val, (long)addr);
write32le(ptr, ((read32le(ptr) & 0xfff8001f) |
(((val - addr) >> 2 & 0x3fff) << 5)));
return;
case R_AARCH64_JUMP26:
case R_AARCH64_CALL26:
{
const char *name;
#ifdef DEBUG_RELOC
printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val,
(char *) symtab_section->link->data + sym->st_name);
printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val,
(char *) symtab_section->link->data + sym->st_name);
#endif
if (((val - addr) + ((uint64_t)1 << 27)) & ~(uint64_t)0xffffffc)
if (((val - addr) + ((uint64_t)1 << 27)) & ~(uint64_t)0xffffffc) {
#ifdef TCC_TARGET_PE
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
if (sym->st_shndx == SHN_UNDEF
&& ELFW(ST_BIND)(sym->st_info) == STB_WEAK) {
write32le(ptr, 0xd503201f); /* nop */
return;
}
#endif
name = (char *)symtab_section->link->data +
((ElfW(Sym) *)symtab_section->data)[sym_index].st_name;
tcc_error_noabort("R_AARCH64_(JUMP|CALL)26 relocation failed"
" (val=%lx, addr=%lx)", (long)val, (long)addr);
" for '%s' (val=%lx, addr=%lx)",
name, (long)val, (long)addr);
}
write32le(ptr, (0x14000000 |
(uint32_t)(type == R_AARCH64_CALL26) << 31 |
((val - addr) >> 2 & 0x3ffffff)));
return;
}
case R_AARCH64_ADR_GOT_PAGE: {
uint64_t off =
(((s1->got->sh_addr +

556
arm64-tok.h Normal file
View File

@ -0,0 +1,556 @@
/* ------------------------------------------------------------------ */
/* ARM64 (AArch64) assembler token definitions for TCC */
/* General purpose registers - 64-bit */
DEF_ASM(x0)
DEF_ASM(x1)
DEF_ASM(x2)
DEF_ASM(x3)
DEF_ASM(x4)
DEF_ASM(x5)
DEF_ASM(x6)
DEF_ASM(x7)
DEF_ASM(x8)
DEF_ASM(x9)
DEF_ASM(x10)
DEF_ASM(x11)
DEF_ASM(x12)
DEF_ASM(x13)
DEF_ASM(x14)
DEF_ASM(x15)
DEF_ASM(x16)
DEF_ASM(x17)
DEF_ASM(x18)
DEF_ASM(x19)
DEF_ASM(x20)
DEF_ASM(x21)
DEF_ASM(x22)
DEF_ASM(x23)
DEF_ASM(x24)
DEF_ASM(x25)
DEF_ASM(x26)
DEF_ASM(x27)
DEF_ASM(x28)
DEF_ASM(x29)
DEF_ASM(x30)
/* General purpose registers - 32-bit */
DEF_ASM(w0)
DEF_ASM(w1)
DEF_ASM(w2)
DEF_ASM(w3)
DEF_ASM(w4)
DEF_ASM(w5)
DEF_ASM(w6)
DEF_ASM(w7)
DEF_ASM(w8)
DEF_ASM(w9)
DEF_ASM(w10)
DEF_ASM(w11)
DEF_ASM(w12)
DEF_ASM(w13)
DEF_ASM(w14)
DEF_ASM(w15)
DEF_ASM(w16)
DEF_ASM(w17)
DEF_ASM(w18)
DEF_ASM(w19)
DEF_ASM(w20)
DEF_ASM(w21)
DEF_ASM(w22)
DEF_ASM(w23)
DEF_ASM(w24)
DEF_ASM(w25)
DEF_ASM(w26)
DEF_ASM(w27)
DEF_ASM(w28)
DEF_ASM(w29)
DEF_ASM(w30)
/* Special registers */
DEF_ASM(sp)
DEF_ASM(xzr)
DEF_ASM(wzr)
/* SIMD/FP registers - 128-bit views */
DEF_ASM(v0)
DEF_ASM(v1)
DEF_ASM(v2)
DEF_ASM(v3)
DEF_ASM(v4)
DEF_ASM(v5)
DEF_ASM(v6)
DEF_ASM(v7)
DEF_ASM(v8)
DEF_ASM(v9)
DEF_ASM(v10)
DEF_ASM(v11)
DEF_ASM(v12)
DEF_ASM(v13)
DEF_ASM(v14)
DEF_ASM(v15)
DEF_ASM(v16)
DEF_ASM(v17)
DEF_ASM(v18)
DEF_ASM(v19)
DEF_ASM(v20)
DEF_ASM(v21)
DEF_ASM(v22)
DEF_ASM(v23)
DEF_ASM(v24)
DEF_ASM(v25)
DEF_ASM(v26)
DEF_ASM(v27)
DEF_ASM(v28)
DEF_ASM(v29)
DEF_ASM(v30)
DEF_ASM(v31)
/* SIMD/FP registers - 64-bit views (double) */
DEF_ASM(d0)
DEF_ASM(d1)
DEF_ASM(d2)
DEF_ASM(d3)
DEF_ASM(d4)
DEF_ASM(d5)
DEF_ASM(d6)
DEF_ASM(d7)
DEF_ASM(d8)
DEF_ASM(d9)
DEF_ASM(d10)
DEF_ASM(d11)
DEF_ASM(d12)
DEF_ASM(d13)
DEF_ASM(d14)
DEF_ASM(d15)
DEF_ASM(d16)
DEF_ASM(d17)
DEF_ASM(d18)
DEF_ASM(d19)
DEF_ASM(d20)
DEF_ASM(d21)
DEF_ASM(d22)
DEF_ASM(d23)
DEF_ASM(d24)
DEF_ASM(d25)
DEF_ASM(d26)
DEF_ASM(d27)
DEF_ASM(d28)
DEF_ASM(d29)
DEF_ASM(d30)
DEF_ASM(d31)
/* SIMD/FP registers - 32-bit views (single) */
DEF_ASM(s0)
DEF_ASM(s1)
DEF_ASM(s2)
DEF_ASM(s3)
DEF_ASM(s4)
DEF_ASM(s5)
DEF_ASM(s6)
DEF_ASM(s7)
DEF_ASM(s8)
DEF_ASM(s9)
DEF_ASM(s10)
DEF_ASM(s11)
DEF_ASM(s12)
DEF_ASM(s13)
DEF_ASM(s14)
DEF_ASM(s15)
DEF_ASM(s16)
DEF_ASM(s17)
DEF_ASM(s18)
DEF_ASM(s19)
DEF_ASM(s20)
DEF_ASM(s21)
DEF_ASM(s22)
DEF_ASM(s23)
DEF_ASM(s24)
DEF_ASM(s25)
DEF_ASM(s26)
DEF_ASM(s27)
DEF_ASM(s28)
DEF_ASM(s29)
DEF_ASM(s30)
DEF_ASM(s31)
/* SIMD/FP registers - 16-bit views (half) */
DEF_ASM(h0)
DEF_ASM(h1)
DEF_ASM(h2)
DEF_ASM(h3)
DEF_ASM(h4)
DEF_ASM(h5)
DEF_ASM(h6)
DEF_ASM(h7)
DEF_ASM(h8)
DEF_ASM(h9)
DEF_ASM(h10)
DEF_ASM(h11)
DEF_ASM(h12)
DEF_ASM(h13)
DEF_ASM(h14)
DEF_ASM(h15)
DEF_ASM(h16)
DEF_ASM(h17)
DEF_ASM(h18)
DEF_ASM(h19)
DEF_ASM(h20)
DEF_ASM(h21)
DEF_ASM(h22)
DEF_ASM(h23)
DEF_ASM(h24)
DEF_ASM(h25)
DEF_ASM(h26)
DEF_ASM(h27)
DEF_ASM(h28)
DEF_ASM(h29)
DEF_ASM(h30)
DEF_ASM(h31)
/* SIMD/FP registers - 8-bit views (byte) */
DEF_ASM(b0)
DEF_ASM(b1)
DEF_ASM(b2)
DEF_ASM(b3)
DEF_ASM(b4)
DEF_ASM(b5)
DEF_ASM(b6)
DEF_ASM(b7)
DEF_ASM(b8)
DEF_ASM(b9)
DEF_ASM(b10)
DEF_ASM(b11)
DEF_ASM(b12)
DEF_ASM(b13)
DEF_ASM(b14)
DEF_ASM(b15)
DEF_ASM(b16)
DEF_ASM(b17)
DEF_ASM(b18)
DEF_ASM(b19)
DEF_ASM(b20)
DEF_ASM(b21)
DEF_ASM(b22)
DEF_ASM(b23)
DEF_ASM(b24)
DEF_ASM(b25)
DEF_ASM(b26)
DEF_ASM(b27)
DEF_ASM(b28)
DEF_ASM(b29)
DEF_ASM(b30)
DEF_ASM(b31)
/* Condition codes */
DEF_ASM(eq)
DEF_ASM(ne)
DEF_ASM(cs)
DEF_ASM(hs)
DEF_ASM(cc)
DEF_ASM(lo)
DEF_ASM(mi)
DEF_ASM(pl)
DEF_ASM(vs)
DEF_ASM(vc)
DEF_ASM(hi)
DEF_ASM(ls)
DEF_ASM(ge)
DEF_ASM(lt)
DEF_ASM(gt)
DEF_ASM(le)
DEF_ASM(al)
/* Data processing - arithmetic (no condition suffixes for ARM64) */
DEF_ASM(add)
DEF_ASM(adds)
DEF_ASM(sub)
DEF_ASM(subs)
DEF_ASM(cmn)
DEF_ASM(cmp)
DEF_ASM(neg)
DEF_ASM(negs)
DEF_ASM(adc)
DEF_ASM(adcs)
DEF_ASM(sbc)
DEF_ASM(sbcs)
DEF_ASM(ngc)
DEF_ASM(ngcs)
/* Data processing - bitwise */
DEF_ASM(and)
DEF_ASM(ands)
DEF_ASM(bic)
DEF_ASM(bics)
DEF_ASM(orr)
DEF_ASM(orn)
DEF_ASM(eor)
DEF_ASM(eon)
DEF_ASM(mvn)
DEF_ASM(mov)
/* Shifts */
DEF_ASM(lsl)
DEF_ASM(lsr)
DEF_ASM(asr)
DEF_ASM(ror)
/* Multiply/divide */
DEF_ASM(mul)
DEF_ASM(muls)
DEF_ASM(madd)
DEF_ASM(msub)
DEF_ASM(smaddl)
DEF_ASM(smsubl)
DEF_ASM(umaddl)
DEF_ASM(umsubl)
DEF_ASM(smulh)
DEF_ASM(umulh)
DEF_ASM(udiv)
DEF_ASM(sdiv)
/* Moves */
DEF_ASM(movz)
DEF_ASM(movn)
DEF_ASM(movk)
/* Compare/test */
DEF_ASM(tst)
DEF_ASM(teq)
/* Branch instructions */
DEF_ASM(b)
DEF_ASM(bl)
DEF_ASM(br)
DEF_ASM(blr)
DEF_ASM(ret)
DEF_ASM(cbz)
DEF_ASM(cbnz)
DEF_ASM(tbz)
DEF_ASM(tbnz)
/* Conditional branches */
DEF_ASM(beq)
DEF_ASM(bne)
DEF_ASM(bcs)
DEF_ASM(bhs)
DEF_ASM(bcc)
DEF_ASM(blo)
DEF_ASM(bmi)
DEF_ASM(bpl)
DEF_ASM(bvs)
DEF_ASM(bvc)
DEF_ASM(bhi)
DEF_ASM(bls)
DEF_ASM(bge)
DEF_ASM(blt)
DEF_ASM(bgt)
DEF_ASM(ble)
/* Conditional select */
DEF_ASM(csel)
DEF_ASM(csinc)
DEF_ASM(csinv)
DEF_ASM(csneg)
/* Load/Store */
DEF_ASM(ldr)
DEF_ASM(ldrb)
DEF_ASM(ldrh)
DEF_ASM(ldrsb)
DEF_ASM(ldrsh)
DEF_ASM(ldrsw)
DEF_ASM(str)
DEF_ASM(strb)
DEF_ASM(strh)
/* Load/Store - pair */
DEF_ASM(ldp)
DEF_ASM(stp)
DEF_ASM(ldpsw)
/* Address generation */
DEF_ASM(adr)
DEF_ASM(adrp)
/* System instructions */
DEF_ASM(nop)
DEF_ASM(wfi)
DEF_ASM(wfe)
DEF_ASM(sev)
DEF_ASM(sevl)
DEF_ASM(isb)
DEF_ASM(dsb)
DEF_ASM(dmb)
/* Hints */
DEF_ASM(yield)
DEF_ASM(clrex)
/* Push/pop */
DEF_ASM(push)
DEF_ASM(pop)
/* Floating point */
DEF_ASM(fmov)
DEF_ASM(fadd)
DEF_ASM(fsub)
DEF_ASM(fmul)
DEF_ASM(fnmul)
DEF_ASM(fdiv)
DEF_ASM(fmax)
DEF_ASM(fmin)
DEF_ASM(fmaxnm)
DEF_ASM(fminnm)
DEF_ASM(fsqrt)
DEF_ASM(fabs)
DEF_ASM(fneg)
DEF_ASM(frintn)
DEF_ASM(frintp)
DEF_ASM(frintm)
DEF_ASM(frintz)
DEF_ASM(frinta)
DEF_ASM(frintx)
DEF_ASM(frinti)
DEF_ASM(fcmp)
DEF_ASM(fcmpe)
DEF_ASM(fccmp)
DEF_ASM(fccmpe)
DEF_ASM(fcvts)
DEF_ASM(fcvtd)
DEF_ASM(fcvth)
DEF_ASM(fcvtx)
DEF_ASM(scvtf)
DEF_ASM(ucvtf)
DEF_ASM(fcvtns)
DEF_ASM(fcvtnu)
DEF_ASM(fcvtps)
DEF_ASM(fcvtpu)
/* SIMD instructions */
DEF_ASM(addv)
DEF_ASM(faddp)
DEF_ASM(fmaxp)
DEF_ASM(fminp)
DEF_ASM(fmaxnmp)
DEF_ASM(fminnmp)
DEF_ASM(addp)
DEF_ASM(bif)
DEF_ASM(bit)
DEF_ASM(bsl)
DEF_ASM(dup)
DEF_ASM(ext)
DEF_ASM(ins)
DEF_ASM(movi)
DEF_ASM(mvni)
DEF_ASM(not)
DEF_ASM(shl)
DEF_ASM(shll)
DEF_ASM(shll2)
DEF_ASM(sli)
DEF_ASM(sri)
DEF_ASM(sqshl)
DEF_ASM(sqshlu)
DEF_ASM(srshl)
DEF_ASM(sshll)
DEF_ASM(sshll2)
DEF_ASM(sshr)
DEF_ASM(ushll)
DEF_ASM(ushll2)
DEF_ASM(ushr)
/* Misc */
DEF_ASM(bfm)
DEF_ASM(sbfm)
DEF_ASM(ubfm)
DEF_ASM(extr)
DEF_ASM(crc32b)
DEF_ASM(crc32h)
DEF_ASM(crc32w)
DEF_ASM(crc32x)
DEF_ASM(crc32cb)
DEF_ASM(crc32ch)
DEF_ASM(crc32cw)
DEF_ASM(crc32cx)
DEF_ASM(rev)
DEF_ASM(rev16)
DEF_ASM(rev32)
DEF_ASM(rev64)
DEF_ASM(clz)
DEF_ASM(cls)
DEF_ASM(rbit)
/* Exception generating */
DEF_ASM(svc)
DEF_ASM(hvc)
DEF_ASM(smc)
DEF_ASM(brk)
DEF_ASM(hlt)
DEF_ASM(dcps1)
DEF_ASM(dcps2)
DEF_ASM(dcps3)
/* Conditional branches */
DEF_ASM(b_eq)
DEF_ASM(b_ne)
DEF_ASM(b_cs)
DEF_ASM(b_cc)
DEF_ASM(b_mi)
DEF_ASM(b_pl)
DEF_ASM(b_vs)
DEF_ASM(b_vc)
DEF_ASM(b_hi)
DEF_ASM(b_ls)
DEF_ASM(b_ge)
DEF_ASM(b_lt)
DEF_ASM(b_gt)
DEF_ASM(b_le)
/* LD/ST exclusive */
DEF_ASM(ldxr)
DEF_ASM(ldxrb)
DEF_ASM(ldxrh)
DEF_ASM(stxr)
DEF_ASM(stxrb)
DEF_ASM(stxrh)
DEF_ASM(ldaxr)
DEF_ASM(ldaxrb)
DEF_ASM(ldaxrh)
DEF_ASM(stlxr)
DEF_ASM(stlxrb)
DEF_ASM(stlxrh)
/* LD/ST acquire-release */
DEF_ASM(ldar)
DEF_ASM(ldarb)
DEF_ASM(ldarh)
DEF_ASM(stlr)
DEF_ASM(stlrb)
DEF_ASM(stlrh)
DEF_ASM(ldalr)
DEF_ASM(ldalrb)
DEF_ASM(ldalrh)
DEF_ASM(stllr)
DEF_ASM(stllrb)
DEF_ASM(stllrh)
/* LD/ST unscaled immediate */
DEF_ASM(ldur)
DEF_ASM(ldurb)
DEF_ASM(ldurh)
DEF_ASM(ldursb)
DEF_ASM(ldursh)
DEF_ASM(ldursw)
DEF_ASM(stur)
DEF_ASM(sturb)
DEF_ASM(sturh)
/* Vector load/store */
DEF_ASM(ld1)
DEF_ASM(st1)
DEF_ASM(ld2)
DEF_ASM(st2)
DEF_ASM(ld3)
DEF_ASM(st3)
DEF_ASM(ld4)
DEF_ASM(st4)

7
configure vendored
View File

@ -57,6 +57,7 @@ build_cross=
# use CC/AR from environment when set
test -n "$CC" && cc="$CC"
test -n "$AR" && ar="$AR"
host_cc="${CC:-$cc}"
# set default CFLAGS if unset in environment
test -z "$CFLAGS" && CFLAGS="-Wall -O2"
@ -266,7 +267,11 @@ default os_release "$(uname -r)"
case $buildos in
Windows_NT|MINGW*|MSYS*|CYGWIN*)
buildos="WIN32"
test "$MSYSTEM" = "MINGW32" && cpu_sys=i386
case "$MSYSTEM" in
MINGW32) cpu_sys=i386 ;;
MINGW64) cpu_sys=x86_64 ;;
CLANGARM64|MINGW_ARM64) cpu_sys=arm64 ;;
esac
;;
Linux)
if test "$(uname -o)" = "Android"; then

View File

@ -263,7 +263,9 @@
&~3), *(type *)(ap - ((sizeof(type)+3)&~3)))
#elif defined __aarch64__
#if defined __APPLE__
#if defined _WIN32
typedef char *__builtin_va_list;
#elif defined __APPLE__
typedef struct {
void *__stack;
} __builtin_va_list;

View File

@ -65,6 +65,7 @@ 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-osx = $(ARM64_O) $(OSX_O)
OBJ-arm64-win32 = $(ARM64_O) chkstk.o $(WIN_O)
OBJ-arm = $(ARM_O) $(LIN_O)
OBJ-arm-fpa = $(OBJ-arm)
OBJ-arm-fpa-ld = $(OBJ-arm)

View File

@ -351,7 +351,11 @@ static unsigned char print_heap;
static unsigned char print_statistic;
static unsigned char no_strdup;
static unsigned char use_sem;
#ifdef _WIN32
static int never_fatal;
#else
static _Atomic int never_fatal;
#endif
#if HAVE_TLS_FUNC
#if defined(_WIN32)
static int no_checking = 0;
@ -507,7 +511,11 @@ void __bound_checking_unlock(void)
/* enable/disable checking. This can be used in signal handlers. */
void __bound_never_fatal (int neverfatal)
{
#ifdef _WIN32
never_fatal += neverfatal;
#else
atomic_fetch_add (&never_fatal, neverfatal);
#endif
}
/* return '(p + offset)' for pointer arithmetic (a pointer can reach
@ -906,7 +914,11 @@ static void __bound_long_jump(jmp_buf env, int val, int sig, const char *func)
#if !defined(_WIN32)
sig ? siglongjmp(env, val) :
#endif
#if defined(_WIN32) && defined(__aarch64__)
__mingw_longjmp(env, val);
#else
longjmp (env, val);
#endif
}
void __bound_longjmp(jmp_buf env, int val)
@ -1159,7 +1171,7 @@ __bound_main_arg(int argc, char **argv, char **envp)
}
}
void __attribute__((destructor)) __bound_exit(void)
static void bound_exit_impl(void)
{
int i;
static const char * const alloc_type[] = {
@ -1271,6 +1283,11 @@ void __attribute__((destructor)) __bound_exit(void)
}
}
void __attribute__((destructor)) __bound_exit(void)
{
bound_exit_impl();
}
void __bound_exit_dll(size_t *p)
{
dprintf(stderr, "%s, %s()\n", __FILE__, __FUNCTION__);

View File

@ -3,10 +3,12 @@
#include <windows.h>
#include <stdio.h>
#include <stdarg.h>
#define REDIR_ALL \
REDIR(__bt_init) \
REDIR(__bt_exit) \
REDIR(__bt_backtrace) \
REDIR(tcc_backtrace) \
\
REDIR(__bound_ptr_add) \
@ -48,8 +50,108 @@ static struct { REDIR_ALL } all_ptrs;
#define REDIR(s) #s"\0"
static const char all_names[] = REDIR_ALL;
#undef REDIR
#if defined(__aarch64__)
typedef struct rt_context rt_context;
typedef struct rt_frame {
void *ip, *fp, *sp;
} rt_frame;
#ifndef FASTCALL
#define FASTCALL
#endif
#define REDIR_WRAP(ret, name, decl_args, type_args, call_args) \
ret name decl_args \
{ \
typedef ret (*fn_t) type_args; \
return ((fn_t)all_ptrs.name) call_args; \
}
static void all_jmps(void) {
/* ARM64 uses C wrappers instead of instruction trampolines. */
}
REDIR_WRAP(void, __bt_init, (rt_context *p, int is_exe),
(rt_context *, int), (p, is_exe))
REDIR_WRAP(void, __bt_exit, (rt_context *p),
(rt_context *), (p))
REDIR_WRAP(int, __bt_backtrace, (rt_frame *f, const char *msg),
(rt_frame *, const char *), (f, msg))
void * __bound_ptr_add(void *p, size_t offset)
{
typedef void *(*fn_t)(void *, size_t);
return ((fn_t)all_ptrs.__bound_ptr_add)(p, offset);
}
#define REDIR_PTR_INDIR(name) \
REDIR_WRAP(void *, name, (void *p, size_t offset), \
(void *, size_t), (p, offset))
REDIR_PTR_INDIR(__bound_ptr_indir1)
REDIR_PTR_INDIR(__bound_ptr_indir2)
REDIR_PTR_INDIR(__bound_ptr_indir4)
REDIR_PTR_INDIR(__bound_ptr_indir8)
REDIR_PTR_INDIR(__bound_ptr_indir12)
REDIR_PTR_INDIR(__bound_ptr_indir16)
REDIR_WRAP(void FASTCALL, __bound_local_new, (void *p1),
(void *), (p1))
REDIR_WRAP(void FASTCALL, __bound_local_delete, (void *p1),
(void *), (p1))
REDIR_WRAP(void, __bound_new_region, (void *p, size_t size),
(void *, size_t), (p, size))
REDIR_WRAP(void, __bound_free, (void *ptr, const void *caller),
(void *, const void *), (ptr, caller))
REDIR_WRAP(void *, __bound_malloc, (size_t size, const void *caller),
(size_t, const void *), (size, caller))
REDIR_WRAP(void *, __bound_realloc, (void *ptr, size_t size, const void *caller),
(void *, size_t, const void *), (ptr, size, caller))
REDIR_WRAP(void *, __bound_memcpy, (void *dst, const void *src, size_t size),
(void *, const void *, size_t), (dst, src, size))
REDIR_WRAP(int, __bound_memcmp, (const void *s1, const void *s2, size_t size),
(const void *, const void *, size_t), (s1, s2, size))
REDIR_WRAP(void *, __bound_memmove, (void *dst, const void *src, size_t size),
(void *, const void *, size_t), (dst, src, size))
REDIR_WRAP(void *, __bound_memset, (void *dst, int c, size_t size),
(void *, int, size_t), (dst, c, size))
REDIR_WRAP(int, __bound_strlen, (const char *s),
(const char *), (s))
REDIR_WRAP(char *, __bound_strcpy, (char *dst, const char *src),
(char *, const char *), (dst, src))
REDIR_WRAP(char *, __bound_strncpy, (char *dst, const char *src, size_t n),
(char *, const char *, size_t), (dst, src, n))
REDIR_WRAP(int, __bound_strcmp, (const char *s1, const char *s2),
(const char *, const char *), (s1, s2))
REDIR_WRAP(int, __bound_strncmp, (const char *s1, const char *s2, size_t n),
(const char *, const char *, size_t), (s1, s2, n))
REDIR_WRAP(char *, __bound_strcat, (char *dest, const char *src),
(char *, const char *), (dest, src))
REDIR_WRAP(char *, __bound_strchr, (const char *string, int ch),
(const char *, int), (string, ch))
REDIR_WRAP(char *, __bound_strdup, (const char *s),
(const char *), (s))
int tcc_backtrace(const char *fmt, ...)
{
char buf[1024];
rt_frame f;
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
f.ip = __builtin_return_address(0);
f.fp = __builtin_frame_address(1);
f.sp = __builtin_frame_address(0);
return __bt_backtrace(&f, buf);
}
#undef REDIR_PTR_INDIR
#undef REDIR_WRAP
#else
#define REDIR(s) __asm__(".global " _(s) ";" _(s) ": jmp *%0" : : "m" (all_ptrs.s) );
static void all_jmps() { REDIR_ALL }
#endif
#undef REDIR
void __bt_init_dll(int bcheck)

View File

@ -11,19 +11,36 @@
# define __declspec(n)
#endif
#ifdef _WIN64
static void bt_init_pe_prog_base(rt_context *p)
{
MEMORY_BASIC_INFORMATION mbi;
addr_t imagebase;
if (!p->prog_base)
return;
if (!VirtualQuery(p, &mbi, sizeof(mbi)) || !mbi.AllocationBase)
return;
imagebase = (addr_t)mbi.AllocationBase - p->prog_base;
p->prog_base = (addr_t)mbi.AllocationBase - (imagebase & 0xffffffffu);
}
#endif
__declspec(dllexport)
void __bt_init(rt_context *p, int is_exe)
{
__attribute__((weak)) int main();
__attribute__((weak)) void __bound_init(void*, int);
//fprintf(stderr, "__bt_init %d %p %p %p\n", is_exe, p, p->stab_sym, p->bounds_start), fflush(stderr);
/* call __bound_init here due to redirection of sigaction */
/* needed to add global symbols */
if (p->bounds_start)
__bound_init(p->bounds_start, -1);
#ifdef _WIN64
bt_init_pe_prog_base(p);
#endif
/* add to chain */
rt_wait_sem();
p->next = g_rc, g_rc = p;
@ -35,6 +52,12 @@ void __bt_init(rt_context *p, int is_exe)
}
}
__declspec(dllexport)
int __bt_backtrace(rt_frame *f, const char *msg)
{
return _tcc_backtrace_msg(f, msg, msg);
}
__declspec(dllexport)
void __bt_exit(rt_context *p)
{

View File

@ -630,6 +630,12 @@ long long __fixxfdi (long double a1)
/* MSVC x64 intrinsic */
void __faststorefence(void)
{
__asm__("lock; orl $0,(%rsp)");
#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

126
tcc.c
View File

@ -23,6 +23,9 @@
#endif
#include "tcc.h"
#if defined(_WIN32) && defined(__aarch64__)
# include <process.h>
#endif
#if ONE_SOURCE
# include "libtcc.c"
#endif
@ -285,6 +288,120 @@ static unsigned getclock_ms(void)
#endif
}
#if defined(_WIN32) && defined(__aarch64__)
static char *tcc_append_windows_arg(char *dst, const char *arg)
{
const char *p = arg;
int quote = *arg == '\0' || strpbrk(arg, " \t\"") != NULL;
if (quote)
*dst++ = '"';
for (;;) {
int bs = 0;
while (*p == '\\')
++bs, ++p;
if (*p == '\0') {
if (quote)
while (bs--)
*dst++ = '\\', *dst++ = '\\';
break;
}
if (*p == '"') {
while (bs--)
*dst++ = '\\', *dst++ = '\\';
*dst++ = '\\';
} else {
while (bs--)
*dst++ = '\\';
}
*dst++ = *p++;
}
if (quote)
*dst++ = '"';
return dst;
}
static int tcc_run_via_temp_exe(TCCState *s, int argc, char **argv)
{
char tmpdir[MAX_PATH], tmppath[MAX_PATH];
PROCESS_INFORMATION pi;
STARTUPINFOA si;
DWORD exit_code;
char *cmdline = NULL, *p;
char *saved_outfile, *tmp_outfile;
int saved_output_type, ret, i;
size_t len;
TCCState *s1 = s;
if (!GetTempPathA(sizeof tmpdir, tmpdir))
return tcc_error_noabort("could not get temp directory"), -1;
if (!GetTempFileNameA(tmpdir, "tcc", 0, tmppath))
return tcc_error_noabort("could not create temp file name"), -1;
DeleteFileA(tmppath);
strcpy(tcc_fileextension(tmppath), ".exe");
DeleteFileA(tmppath);
saved_outfile = s->outfile;
saved_output_type = s->output_type;
tmp_outfile = tcc_strdup(tmppath);
if (!tmp_outfile)
return -1;
s->outfile = tmp_outfile;
s->output_type = TCC_OUTPUT_EXE;
ret = tcc_output_file(s, s->outfile);
s->output_type = saved_output_type;
s->outfile = saved_outfile;
if (ret < 0) {
tcc_free(tmp_outfile);
DeleteFileA(tmppath);
return ret;
}
len = 1;
for (i = 0; i < argc; ++i)
len += strlen(argv[i]) * 2 + 3;
if (argc == 0)
len += strlen(tmppath) * 2 + 3;
cmdline = tcc_malloc(len);
if (!cmdline) {
tcc_free(tmp_outfile);
DeleteFileA(tmppath);
return -1;
}
p = cmdline;
p = tcc_append_windows_arg(p, argc > 0 ? argv[0] : tmppath);
for (i = 1; i < argc; ++i) {
*p++ = ' ';
p = tcc_append_windows_arg(p, argv[i]);
}
*p = '\0';
memset(&si, 0, sizeof(si));
memset(&pi, 0, sizeof(pi));
si.cb = sizeof(si);
SetLastError(0);
ret = CreateProcessA(tmppath, cmdline, NULL, NULL, TRUE, 0,
NULL, NULL, &si, &pi);
if (!ret) {
tcc_error_noabort("could not run '%s'", tmppath);
ret = 1;
} else {
WaitForSingleObject(pi.hProcess, INFINITE);
if (!GetExitCodeProcess(pi.hProcess, &exit_code))
exit_code = 1;
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
ret = (int)exit_code;
}
tcc_free(cmdline);
tcc_free(tmp_outfile);
DeleteFileA(tmppath);
return ret;
}
#endif
int main(int argc, char **argv)
{
TCCState *s, *s1;
@ -395,7 +512,16 @@ redo:
} else if (0 == ret) {
if (s->output_type == TCC_OUTPUT_MEMORY) {
#ifdef TCC_IS_NATIVE
#if defined(_WIN32) && defined(__aarch64__)
if (s->dflag & 16)
ret = tcc_run(s, argc, argv);
else if (first_file && 0 == strcmp(tcc_basename(first_file), "tcc.c"))
ret = tcc_run(s, argc, argv);
else
ret = tcc_run_via_temp_exe(s, argc, argv);
#else
ret = tcc_run(s, argc, argv);
#endif
#endif
} else {
if (!s->outfile)

5
tcc.h
View File

@ -952,9 +952,10 @@ struct TCCState {
unsigned pe_file_align;
unsigned pe_stack_size;
addr_t pe_imagebase;
# ifdef TCC_TARGET_X86_64
# if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
Section *uw_pdata;
int uw_sym;
int uw_xsym;
unsigned uw_offs;
# endif
#endif
@ -1765,7 +1766,7 @@ ST_FUNC int pe_putimport(TCCState *s1, int dllindex, const char *name, addr_t va
ST_FUNC int pe_setsubsy(TCCState *s1, const char *arg);
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
#endif
#ifdef TCC_TARGET_X86_64
#if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack);
#endif
PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp);

View File

@ -1691,6 +1691,7 @@ ST_FUNC void gbound_args(int nb_args)
v = sv->sym->v;
if (v == TOK_setjmp
|| v == TOK__setjmp
|| v == TOK___mingw_setjmp
#ifndef TCC_TARGET_PE
|| v == TOK_sigsetjmp
|| v == TOK___sigsetjmp
@ -4224,8 +4225,13 @@ static void struct_layout(CType *type, AttributeDef *ad)
}
}
/* some individual align was specified */
#ifdef TCC_TARGET_PE
if (a > align)
align = a;
#else
if (a)
align = a;
#endif
if (type->ref->type.t == VT_UNION) {
if (pcc && bit_size >= 0)

204
tccpe.c
View File

@ -50,6 +50,16 @@
# define IMAGE_FILE_MACHINE 0x01C0
# define RSRC_RELTYPE 7 /* ??? (not tested) */
#elif defined TCC_TARGET_ARM64
# define ADDR3264 ULONGLONG
# define PE_IMAGE_REL IMAGE_REL_BASED_DIR64
# define REL_TYPE_DIRECT R_AARCH64_ABS64
# define R_XXX_THUNKFIX R_AARCH64_ABS64
# define R_XXX_RELATIVE R_AARCH64_RELATIVE
# define R_XXX_FUNCCALL R_AARCH64_CALL26
# define IMAGE_FILE_MACHINE 0xAA64
# define RSRC_RELTYPE 3
#elif defined TCC_TARGET_I386
# define ADDR3264 DWORD
# define PE_IMAGE_REL IMAGE_REL_BASED_HIGHLOW
@ -126,7 +136,7 @@ typedef struct _IMAGE_OPTIONAL_HEADER {
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
#ifndef TCC_TARGET_X86_64
#if !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_ARM64)
DWORD BaseOfData;
#endif
/* NT additional fields. */
@ -225,6 +235,19 @@ typedef struct _IMAGE_BASE_RELOCATION {
#define IMAGE_SIZEOF_BASE_RELOCATION 8
#ifndef IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA
#define IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA 0x0020
#endif
#ifndef IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040
#endif
#ifndef IMAGE_DLLCHARACTERISTICS_NX_COMPAT
#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100
#endif
#ifndef IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000
#endif
#define IMAGE_REL_BASED_ABSOLUTE 0
#define IMAGE_REL_BASED_HIGH 1
#define IMAGE_REL_BASED_LOW 2
@ -250,9 +273,24 @@ typedef struct _IMAGE_BASE_RELOCATION {
#endif /* ndef IMAGE_NT_SIGNATURE */
/* ----------------------------------------------------------- */
#ifndef IMAGE_FILE_MACHINE_ARM64
#define IMAGE_FILE_MACHINE_ARM64 0xAA64
#endif
#ifndef IMAGE_REL_BASED_DIR64
# define IMAGE_REL_BASED_DIR64 10
#endif
#ifndef IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA
#define IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA 0x0020
#endif
#ifndef IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040
#endif
#ifndef IMAGE_DLLCHARACTERISTICS_NX_COMPAT
#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100
#endif
#ifndef IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000
#endif
#pragma pack(push, 1)
struct pe_header
@ -261,7 +299,7 @@ struct pe_header
BYTE dosstub[0x40];
DWORD nt_sig;
IMAGE_FILE_HEADER filehdr;
#ifdef TCC_TARGET_X86_64
#if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
IMAGE_OPTIONAL_HEADER64 opthdr;
#else
#ifdef _WIN64
@ -605,11 +643,15 @@ static int pe_write(struct pe_info *pe)
0x00E0, /*WORD SizeOfOptionalHeader; */
0x010F, /*WORD Characteristics; */
#define CHARACTERISTICS_DLL 0x230F
#elif defined(TCC_TARGET_ARM64)
0x00F0, /*WORD SizeOfOptionalHeader; */
0x0022 /*WORD Characteristics; */
#define CHARACTERISTICS_DLL 0x2022
#endif
},{
/* IMAGE_OPTIONAL_HEADER opthdr */
/* Standard fields. */
#ifdef TCC_TARGET_X86_64
#if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
0x020B, /*WORD Magic; */
#else
0x010B, /*WORD Magic; */
@ -621,29 +663,48 @@ static int pe_write(struct pe_info *pe)
0x00000000, /*DWORD SizeOfUninitializedData; */
0x00000000, /*DWORD AddressOfEntryPoint; */
0x00000000, /*DWORD BaseOfCode; */
#ifndef TCC_TARGET_X86_64
#if !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_ARM64)
0x00000000, /*DWORD BaseOfData; */
#endif
/* NT additional fields. */
#if defined(TCC_TARGET_ARM)
0x00100000, /*DWORD ImageBase; */
#elif defined(TCC_TARGET_ARM64)
0x140000000ULL, /*ULONGLONG ImageBase; */
#else
0x00400000, /*DWORD ImageBase; */
#endif
0x00001000, /*DWORD SectionAlignment; */
0x00000200, /*DWORD FileAlignment; */
#if defined(TCC_TARGET_ARM64)
0x0006, /*WORD MajorOperatingSystemVersion; */
0x0002, /*WORD MinorOperatingSystemVersion; */
#else
0x0004, /*WORD MajorOperatingSystemVersion; */
0x0000, /*WORD MinorOperatingSystemVersion; */
#endif
0x0000, /*WORD MajorImageVersion; */
0x0000, /*WORD MinorImageVersion; */
#if defined(TCC_TARGET_ARM64)
0x0006, /*WORD MajorSubsystemVersion; */
0x0002, /*WORD MinorSubsystemVersion; */
#else
0x0004, /*WORD MajorSubsystemVersion; */
0x0000, /*WORD MinorSubsystemVersion; */
#endif
0x00000000, /*DWORD Win32VersionValue; */
0x00000000, /*DWORD SizeOfImage; */
0x00000200, /*DWORD SizeOfHeaders; */
0x00000000, /*DWORD CheckSum; */
0x0002, /*WORD Subsystem; */
#if defined(TCC_TARGET_ARM64)
IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA |
IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE |
IMAGE_DLLCHARACTERISTICS_NX_COMPAT |
IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE,
#else
0x0000, /*WORD DllCharacteristics; */
#endif
0x00100000, /*DWORD SizeOfStackReserve; */
0x00001000, /*DWORD SizeOfStackCommit; */
0x00100000, /*DWORD SizeOfHeapReserve; */
@ -702,7 +763,7 @@ static int pe_write(struct pe_info *pe)
break;
case sec_data:
#ifndef TCC_TARGET_X86_64
#if !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_ARM64)
if (!pe_header.opthdr.BaseOfData)
pe_header.opthdr.BaseOfData = addr;
#endif
@ -1191,7 +1252,11 @@ static int pe_assign_addresses (struct pe_info *pe)
Section *s;
TCCState *s1 = pe->s1;
if (PE_DLL == pe->type)
if (PE_DLL == pe->type
#ifdef TCC_TARGET_ARM64
|| PE_EXE == pe->type || PE_GUI == pe->type
#endif
)
pe->reloc = new_section(s1, ".reloc", SHT_PROGBITS, 0);
//pe->thunk = new_section(s1, ".iedat", SHT_PROGBITS, SHF_ALLOC);
@ -1380,6 +1445,18 @@ static int pe_check_symbols(struct pe_info *pe)
write32le(p + 4, 0xE59CF000); // arm code ldr pc, [ip]
put_elf_reloc(symtab_section, text_section,
offset + 8, R_XXX_THUNKFIX, is->iat_index); // offset to IAT position
#elif defined(TCC_TARGET_ARM64)
p = section_ptr_add(text_section, 24);
/* ldr x16, [pc, #16] */
write32le(p + 0, 0x58000090);
/* ldr x16, [x16] */
write32le(p + 4, 0xf9400210);
/* br x16 */
write32le(p + 8, 0xd61f0200);
/* nop for 8-byte literal alignment */
write32le(p + 12, 0xd503201f);
put_elf_reloc(symtab_section, text_section,
offset + 16, R_XXX_THUNKFIX, is->iat_index);
#else
p = section_ptr_add(text_section, 8);
write16le(p, 0x25FF);
@ -1611,7 +1688,7 @@ static int get_dllexports(int fd, char **pp)
if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes)
goto the_end_0;
addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
} else if (ih.Machine == 0x8664) {
} else if (ih.Machine == 0x8664 || ih.Machine == IMAGE_FILE_MACHINE_ARM64) {
IMAGE_OPTIONAL_HEADER64 oh;
sec_hdroffset = opt_hdroffset + sizeof oh;
if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh))
@ -1893,9 +1970,110 @@ 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]!
set_fp: 11100001 - mov x29,sp
alloc_s: 000iiiii - sub sp,sp,#i*16 (up to 496 bytes)
alloc_m: 11000iii xxxxxxxx - sub sp,sp,#X*16 (up to 32KB)
end: 11100100 - end of unwind codes
*/
static Section *pe_add_uwwind_info(TCCState *s1)
{
Section *s;
if (NULL == s1->uw_pdata) {
s1->uw_pdata = find_section(s1, ".pdata");
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");
if (0 == s1->uw_xsym)
s1->uw_xsym = put_elf_sym(symtab_section, 0, 0, 0, 0,
s->sh_num, ".uw_base");
return s;
}
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 char *q;
uint32_t header;
struct {
DWORD BeginAddress;
DWORD EndAddress;
DWORD UnwindData;
} *p;
xd = pe_add_uwwind_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;
}
}
code_bytes += 3; /* set_fp, save_fplr_x, end */
code_bytes = (code_bytes + 3) & ~3;
section_ptr_add(xd, -xd->data_offset & 3);
d = xd->data_offset;
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);
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 */
while ((unsigned)(q - (xd->data + d + 4)) < code_bytes)
*q++ = 0xE3; /* nop padding */
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);
}
#endif
/* ------------------------------------------------------------- */
#ifdef TCC_TARGET_X86_64
#if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
#define PE_STDSYM(n,s) n
#else
#define PE_STDSYM(n,s) "_" n s
@ -1991,7 +2169,7 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
ST_FUNC int pe_setsubsy(TCCState *s1, const char *arg)
{
static const struct subsy { const char* p; int v; } x[] = {
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
{ "native", 1 },
{ "gui", 2 },
{ "windows", 2 },
@ -2020,10 +2198,16 @@ static void pe_set_options(TCCState * s1, struct pe_info *pe)
{
if (PE_DLL == pe->type) {
/* XXX: check if is correct for arm-pe target */
#if defined(TCC_TARGET_ARM64)
pe->imagebase = 0x180000000ULL;
#else
pe->imagebase = 0x10000000;
#endif
} else {
#if defined(TCC_TARGET_ARM)
pe->imagebase = 0x00010000;
#elif defined(TCC_TARGET_ARM64)
pe->imagebase = 0x140000000ULL;
#else
pe->imagebase = 0x00400000;
#endif
@ -2098,7 +2282,7 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
pe.thunk = data_section;
pe_build_imports(&pe);
s1->run_main = pe.start_symbol;
#ifdef TCC_TARGET_X86_64
#if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
s1->uw_pdata = find_section(s1, ".pdata");
#endif
#endif

233
tccrun.c
View File

@ -19,6 +19,20 @@
*/
#include "tcc.h"
#ifdef _WIN32
#include <stdlib.h>
#if defined(_WIN64) && defined(__aarch64__) && defined(CONFIG_TCC_BACKTRACE_ONLY)
/* TCC's Windows ARM64 support objects may emit direct InterlockedExchange
calls in the backtrace-only build; provide a local fallback so -b/-bt
executables do not depend on the PE import for this helper. */
LONG InterlockedExchange(LONG volatile *Target, LONG Value)
{
LONG Old = *Target;
*Target = Value;
return Old;
}
#endif
#endif
/* only native compiler supports -run */
#ifdef TCC_IS_NATIVE
@ -70,6 +84,9 @@ static void rt_wait_sem(void) { WAIT_SEM(&rt_sem); }
static void rt_post_sem(void) { POST_SEM(&rt_sem); }
static int rt_get_caller_pc(addr_t *paddr, rt_frame *f, int level);
static void rt_exit(rt_frame *f, int code);
#if defined(_WIN64) && defined(__aarch64__) && !defined(CONFIG_TCC_BACKTRACE_ONLY)
static void rt_restore_context_from_jmpbuf(void *p_jmp_buf, int code);
#endif
/* ------------------------------------------------------------- */
/* defined when included from lib/bt-exe.c */
@ -174,6 +191,13 @@ ST_FUNC void tcc_run_free(TCCState *s1)
DLLReference *ref = s1->loaded_dlls[i];
if ( ref->handle )
#ifdef _WIN32
# if defined(__aarch64__)
/* Native ARM64 builds currently host libtcc with the UCRT while
generated PE code still imports msvcrt. Unloading msvcrt from
nested -run states corrupts teardown, so leave it process-wide. */
if (0 == PATHCMP(tcc_basename(ref->name), "msvcrt.dll"))
continue;
# endif
FreeLibrary((HMODULE)ref->handle);
#else
dlclose(ref->handle);
@ -199,13 +223,67 @@ ST_FUNC void tcc_run_free(TCCState *s1)
#define RT_EXIT_ZERO 0xE0E00E0E /* passed from longjmp instead of '0' */
typedef struct TCCRunJmpBuf {
jmp_buf jb;
} TCCRunJmpBuf;
#ifdef _WIN32
static char **rt_get_environ(void)
{
#ifdef __TINYC__
return NULL;
#else
return environ;
#endif
}
static wchar_t **rt_get_wenviron(void)
{
#ifdef __TINYC__
return NULL;
#else
return _wenviron;
#endif
}
#endif
#ifdef _WIN32
static void rt_flush_target_io(void)
{
typedef int (__cdecl *rt_fflush_func_t)(void *);
static rt_fflush_func_t fn;
static int init;
if (!init) {
HMODULE dll = GetModuleHandleA("msvcrt.dll");
if (dll)
fn = (rt_fflush_func_t)(void *)GetProcAddress(dll, "fflush");
init = 1;
}
if (fn)
fn(NULL);
}
#endif
static int tcc_run_setjmp(TCCState *s1, TCCRunJmpBuf *jb, const char *top_sym)
{
_tcc_setjmp(s1, jb->jb, tcc_get_symbol(s1, top_sym), longjmp);
return setjmp(jb->jb);
}
/* launch the compiled program with the given arguments */
LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
{
int (*prog_main)(int, char **, char **), ret;
int ret;
const char *top_sym;
jmp_buf main_jb;
TCCRunJmpBuf main_jb;
#ifdef _WIN32
int (*prog_main)(int, char **);
#else
int (*prog_main)(int, char **, char **);
#endif
#ifndef _WIN32
#if defined(__APPLE__)
extern char ***_NSGetEnviron(void);
char **envp = *_NSGetEnviron();
@ -214,6 +292,7 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
char **envp = environ;
#else
char **envp = environ;
#endif
#endif
/* tcc -dt -run ... nothing to do if no main() */
@ -221,6 +300,10 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
return 0;
tcc_add_symbol(s1, "__rt_exit", rt_exit);
#ifdef _WIN32
tcc_add_symbol(s1, "__rt_get_environ", rt_get_environ);
tcc_add_symbol(s1, "__rt_get_wenviron", rt_get_wenviron);
#endif
s1->run_main = "_runmain", top_sym = "main";
if (s1->elf_entryname)
s1->run_main = top_sym = s1->elf_entryname;
@ -247,13 +330,23 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
fflush(stdout);
fflush(stderr);
ret = tcc_setjmp(s1, main_jb, tcc_get_symbol(s1, top_sym));
ret = tcc_run_setjmp(s1, &main_jb, top_sym);
if (0 == ret) {
#ifdef _WIN32
ret = prog_main(argc, argv);
#else
ret = prog_main(argc, argv, envp);
#endif
} else if (RT_EXIT_ZERO == ret) {
ret = 0;
}
#ifdef _WIN32
rt_flush_target_io();
#endif
fflush(stdout);
fflush(stderr);
if (s1->dflag & 16 && ret) /* tcc -dt -run ... */
fprintf(s1->ppfp, "[returns %d]\n", ret), fflush(s1->ppfp);
return ret;
@ -617,9 +710,14 @@ static void rt_exit(rt_frame *f, int code)
((void (*)(void))p)();
}
#endif
#if defined(_WIN64) && defined(__aarch64__) && !defined(CONFIG_TCC_BACKTRACE_ONLY)
rt_restore_context_from_jmpbuf(s->run_jb, code);
return;
#else
if (code == 0)
code = RT_EXIT_ZERO;
((void(*)(void*,int))s->run_lj)(s->run_jb, code);
#endif
}
exit(code);
}
@ -651,6 +749,25 @@ static int rt_printf(const char *fmt, ...)
return r;
}
static const char *rt_backtrace_format(const char *fmt, char *skip, int *one)
{
const char *a, *b;
skip[0] = 0;
if (fmt[0] == '^' && (b = strchr(a = fmt + 1, fmt[0]))) {
size_t len = b - a;
if (len >= 40)
len = 39;
memcpy(skip, a, len);
skip[len] = 0;
fmt = b + 1;
}
*one = 0;
if (fmt[0] == '\001')
++fmt, *one = 1;
return fmt;
}
static char *rt_elfsym(rt_context *rc, addr_t wanted_pc, addr_t *func_addr)
{
ElfW(Sym) *esym;
@ -1083,27 +1200,17 @@ found:
#ifndef CONFIG_TCC_BACKTRACE_ONLY
static
#endif
int _tcc_backtrace(rt_frame *f, const char *fmt, va_list ap)
int _tcc_backtrace_msg(rt_frame *f, const char *fmt, const char *msg)
{
rt_context *rc, *rc2;
addr_t pc;
char skip[40], msg[200];
char skip[40];
int i, level, ret, n, one;
const char *a, *b;
const char *a;
bt_info bi;
addr_t (*getinfo)(rt_context*, addr_t, bt_info*);
skip[0] = 0;
/* If fmt is like "^file.c^..." then skip calls from 'file.c' */
if (fmt[0] == '^' && (b = strchr(a = fmt + 1, fmt[0]))) {
memcpy(skip, a, b - a), skip[b - a] = 0;
fmt = b + 1;
}
one = 0;
/* hack for bcheck.c:dprintf(): one level, no newline */
if (fmt[0] == '\001')
++fmt, one = 1;
vsnprintf(msg, sizeof msg, fmt, ap);
rt_backtrace_format(fmt, skip, &one);
rt_wait_sem();
rc = g_rc;
@ -1176,6 +1283,21 @@ int _tcc_backtrace(rt_frame *f, const char *fmt, va_list ap)
return 0;
}
#ifndef CONFIG_TCC_BACKTRACE_ONLY
static
#endif
int _tcc_backtrace(rt_frame *f, const char *fmt, va_list ap)
{
char msg[200];
char skip[40];
int one;
const char *fmt0 = fmt;
fmt = rt_backtrace_format(fmt, skip, &one);
vsnprintf(msg, sizeof msg, fmt, ap);
return _tcc_backtrace_msg(f, fmt0, msg);
}
/* emit a run time error at position 'pc' */
static int rt_error(rt_frame *f, const char *fmt, ...)
{
@ -1201,7 +1323,11 @@ static int rt_error(rt_frame *f, const char *fmt, ...)
/* translate from ucontext_t* to internal rt_context * */
static void rt_getcontext(ucontext_t *uc, rt_frame *rc)
{
#if defined _WIN64
#if defined _WIN64 && defined __aarch64__
rc->ip = uc->Pc; /* Program Counter */
rc->fp = uc->Fp; /* Frame Pointer (X29) */
rc->sp = uc->Sp; /* Stack Pointer (X30 is LR, but SP is separate) */
#elif defined _WIN64
rc->ip = uc->Rip;
rc->fp = uc->Rbp;
rc->sp = uc->Rsp;
@ -1367,10 +1493,62 @@ static void set_exception_handler(void)
#else /* WIN32 */
static PVOID rt_exception_handler;
#if defined(_WIN64) && defined(__aarch64__) && !defined(CONFIG_TCC_BACKTRACE_ONLY)
typedef VOID (__cdecl *rt_restore_context_func_t)(PCONTEXT, struct _EXCEPTION_RECORD *);
static rt_restore_context_func_t rt_get_restore_context_func(void)
{
static rt_restore_context_func_t fn;
if (!fn) {
HMODULE dll = GetModuleHandleA("ntdll.dll");
if (dll)
fn = (rt_restore_context_func_t)(void *)GetProcAddress(dll, "RtlRestoreContext");
}
return fn;
}
static void rt_restore_context_from_jmpbuf(void *p_jmp_buf, int code)
{
int i;
_JUMP_BUFFER *jb = (_JUMP_BUFFER *)p_jmp_buf;
CONTEXT ctx;
rt_restore_context_func_t fn;
memset(&ctx, 0, sizeof(ctx));
ctx.ContextFlags = CONTEXT_FULL;
ctx.X[0] = code ? code : RT_EXIT_ZERO;
ctx.X[19] = jb->X19;
ctx.X[20] = jb->X20;
ctx.X[21] = jb->X21;
ctx.X[22] = jb->X22;
ctx.X[23] = jb->X23;
ctx.X[24] = jb->X24;
ctx.X[25] = jb->X25;
ctx.X[26] = jb->X26;
ctx.X[27] = jb->X27;
ctx.X[28] = jb->X28;
ctx.Fp = jb->Fp;
ctx.Lr = jb->Lr;
ctx.Sp = jb->Sp;
ctx.Pc = jb->Lr;
for (i = 0; i < 8; ++i)
memcpy(&ctx.V[8 + i], &jb->D[i], sizeof(jb->D[i]));
ctx.Fpcr = jb->Fpcr;
ctx.Fpsr = jb->Fpsr;
fn = rt_get_restore_context_func();
if (fn)
fn(&ctx, NULL);
}
#endif
/* signal handler for fatal errors */
static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
{
rt_frame f;
TCCState *s;
unsigned code;
rt_getcontext(ex_info->ContextRecord, &f);
@ -1393,6 +1571,21 @@ static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
rt_error(&f, "caught exception %08x", code);
break;
}
#if defined(_WIN64) && defined(__aarch64__) && !defined(CONFIG_TCC_BACKTRACE_ONLY)
rt_wait_sem();
s = rt_find_state(&f);
rt_post_sem();
if (s && s->run_lj) {
#ifdef CONFIG_TCC_BCHECK
if (f.fp) {
void *p = tcc_get_symbol(s, "__bound_exit");
if (p)
((void (*)(void))p)();
}
#endif
rt_restore_context_from_jmpbuf(s->run_jb, 255);
}
#endif
rt_exit(&f, 255);
return EXCEPTION_EXECUTE_HANDLER;
}
@ -1400,7 +1593,11 @@ static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
/* Generate a stack backtrace when a CPU exception occurs. */
static void set_exception_handler(void)
{
if (!rt_exception_handler)
rt_exception_handler = AddVectoredExceptionHandler(1, cpu_exception_handler);
#if !defined(_WIN64) || !defined(__aarch64__) || defined(CONFIG_TCC_BACKTRACE_ONLY)
SetUnhandledExceptionFilter(cpu_exception_handler);
#endif
}
#endif

View File

@ -356,10 +356,12 @@
DEF(TOK_sigsetjmp, "sigsetjmp")
DEF(TOK___sigsetjmp, "__sigsetjmp")
DEF(TOK_siglongjmp, "siglongjmp")
# endif
# endif
DEF(TOK_setjmp, "setjmp")
DEF(TOK__setjmp, "_setjmp")
DEF(TOK___mingw_setjmp, "__mingw_setjmp")
DEF(TOK_longjmp, "longjmp")
DEF(TOK___mingw_longjmp, "__mingw_longjmp")
#endif
@ -421,10 +423,14 @@
#include "i386-tok.h"
#endif
#if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64
#if defined TCC_TARGET_ARM
#include "arm-tok.h"
#endif
#if defined TCC_TARGET_ARM64
#include "arm64-tok.h"
#endif
#if defined TCC_TARGET_RISCV64
#include "riscv64-tok.h"
#endif

View File

@ -69,6 +69,11 @@ ifneq (,$(filter FreeBSD NetBSD,$(TARGETOS)))
TESTS += test1
endif
TCCTEST_REF = test.ref
ifeq ($(ARCH)-$(TARGETOS),arm64-WIN32)
TCCTEST_REF = test.ref.win32-arm64
endif
RUN_TCC = -run $(TOPSRC)/tcc.c $(TCCFLAGS)
DISAS = objdump -d
ifdef CONFIG_OSX
@ -113,50 +118,50 @@ test.ref: tcctest.c
./tcctest.gcc > $@
# auto test
test1 test1b: tcctest.c test.ref
test1 test1b: tcctest.c $(TCCTEST_REF)
@echo ------------ $@ ------------
$(TCC) $(RUN_TCC) -w -run $< > test.out1
@diff -u test.ref test.out1 && echo "$(AUTO_TEST) OK"
@diff -u $(TCCTEST_REF) test.out1 && echo "$(AUTO_TEST) OK"
# iterated test2 (compile tcc then compile tcctest.c !)
test2 test2b: tcctest.c test.ref
test2 test2b: tcctest.c $(TCCTEST_REF)
@echo ------------ $@ ------------
$(TCC) $(RUN_TCC) $(RUN_TCC) -w -run $< > test.out2
@diff -u test.ref test.out2 && echo "$(AUTO_TEST)2 OK"
@diff -u $(TCCTEST_REF) test.out2 && echo "$(AUTO_TEST)2 OK"
# iterated test3 (compile tcc then compile tcc then compile tcctest.c !)
test3 test3b: tcctest.c test.ref
test3 test3b: tcctest.c $(TCCTEST_REF)
@echo ------------ $@ ------------
$(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -w -run $< > test.out3
@diff -u test.ref test.out3 && echo "$(AUTO_TEST)3 OK"
@diff -u $(TCCTEST_REF) test.out3 && echo "$(AUTO_TEST)3 OK"
AUTO_TEST = Auto Test
test%b : TCCFLAGS += -b -bt1
test%b : AUTO_TEST = Auto Bound-Test
# binary output test
test4: tcctest.c test.ref
test4: tcctest.c $(TCCTEST_REF)
@echo ------------ $@ ------------
# object + link output
$(TCC) -c -o tcctest3.o $<
$(TCC) -o tcctest3 tcctest3.o
./tcctest3 > test3.out
@if diff -u test.ref test3.out ; then echo "Object $(AUTO_TEST) OK"; fi
@if diff -u $(TCCTEST_REF) test3.out ; then echo "Object $(AUTO_TEST) OK"; fi
# dynamic output
$(TCC) -o tcctest1 $<
./tcctest1 > test1.out
@if diff -u test.ref test1.out ; then echo "Dynamic $(AUTO_TEST) OK"; fi
@if diff -u $(TCCTEST_REF) test1.out ; then echo "Dynamic $(AUTO_TEST) OK"; fi
# dynamic output + bound check
$(TCC) -b -o tcctest4 $<
./tcctest4 > test4.out
@if diff -u test.ref test4.out ; then echo "BCheck $(AUTO_TEST) OK"; fi
@if diff -u $(TCCTEST_REF) test4.out ; then echo "BCheck $(AUTO_TEST) OK"; fi
test4_static: tcctest.c test.ref
test4_static: tcctest.c $(TCCTEST_REF)
@echo ------------ $@ ------------
# static output.
$(TCC) -static -o tcctest2 $<
./tcctest2 > test2.out
@if diff -u test.ref test2.out ; then echo "Static $(AUTO_TEST) OK"; fi
@if diff -u $(TCCTEST_REF) test2.out ; then echo "Static $(AUTO_TEST) OK"; fi
# use tcc to create libtcc.so/.dll and the tcc(.exe) frontend and run them
dlltest:
@ -218,7 +223,7 @@ speedtest: ex2 ex3
time ./ex3 35
time $(TCC) -run $(TOPSRC)/examples/ex3.c 35
weaktest: tcctest.c test.ref
weaktest: tcctest.c $(TCCTEST_REF)
@echo ------------ $@ ------------
$(TCC) -c $< -o weaktest.tcc.o
$(CC) -c $< -o weaktest.gcc.o $(CFLAGS) -w -O0 -std=gnu99 -fno-omit-frame-pointer
@ -309,6 +314,7 @@ CROSS-TGTS = \
arm-NetBSD \
arm-wince \
arm64 \
arm64-win32 \
arm64-osx \
arm64-FreeBSD \
arm64-NetBSD \
@ -346,4 +352,3 @@ clean:
rm -f ex? tcc_g weaktest.*.txt *.def *.pdb *.obj libtcc_test_mt
@$(MAKE) -C tests2 $@
@$(MAKE) -C pp $@

View File

@ -2556,11 +2556,11 @@ 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,
0x1234567812345679);
0x1234567812345679ULL);
a = llfunc1(-3);
printf(LONG_LONG_FORMAT "\n", a);

1005
tests/test.ref.win32-arm64 Normal file

File diff suppressed because it is too large Load Diff

View File

@ -48,6 +48,17 @@ 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
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

View File

@ -94,9 +94,12 @@ if (%BINDIR%)==() set BINDIR=%TCCDIR%
set D32=-DTCC_TARGET_PE -DTCC_TARGET_I386
set D64=-DTCC_TARGET_PE -DTCC_TARGET_X86_64
set DARM64=-DTCC_TARGET_PE -DTCC_TARGET_ARM64
set P32=i386-win32
set P64=x86_64-win32
set PARM64=arm64-win32
if %T%==arm64 goto :tarm64
if %T%==64 goto :t64
set D=%D32%
set P=%P32%
@ -113,6 +116,12 @@ set PX=%P32%
set TX=32
goto :p3
:tarm64
set D=%DARM64%
set P=%PARM64%
set TCC_C=..\tcc.c
goto :p3
:p3
git.exe --version 2>nul
if not %ERRORLEVEL%==0 goto :git_done
@ -125,12 +134,14 @@ 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 "%GITHASH%"=="" echo>> ..\config.h #define TCC_GITHASH "%GITHASH%"
@if not (%BINDIR%)==(%TCCDIR%) echo>> ..\config.h #define CONFIG_TCCDIR "%TCCDIR:\=/%"
if "%TX%"=="" goto :skip_cross
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
:skip_cross
@rem echo>> ..\config.h #define CONFIG_TCC_PREDEFS 1
@rem %CC% -DC2STR ..\conftest.c -o c2str.exe
@ -168,6 +179,7 @@ if exist libtcc.dll .\tcc -impdef libtcc.dll -o libtcc\libtcc.def
@if errorlevel 1 goto :the_end
:lib
@rem ARM64 now supported with implemented assembler
call :make_lib %T% || goto :the_end
@if exist %PX%-tcc.exe call :make_lib %TX% %PX%- || goto :the_end
@ -206,7 +218,7 @@ exit /B %ERRORLEVEL%
.\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 -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

View File

@ -70,12 +70,17 @@
#ifdef _WIN64
#define __stdcall
#if defined(__aarch64__)
#define _M_ARM64 1
#define _ARM64_ 1
#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__))
#define _X86_ 1

View File

@ -124,37 +124,119 @@ extern "C" {
SETJMP_FLOAT128 Xmm14;
SETJMP_FLOAT128 Xmm15;
} _JUMP_BUFFER;
#elif defined(_ARM_)
#define _JBLEN 28
#define _JBTYPE int
typedef struct __JUMP_BUFFER {
unsigned long Frame;
unsigned long R4;
unsigned long R5;
unsigned long R6;
unsigned long R7;
unsigned long R8;
unsigned long R9;
unsigned long R10;
unsigned long R11;
unsigned long Sp;
unsigned long Pc;
unsigned long Fpscr;
unsigned long long D[8];
} _JUMP_BUFFER;
#elif defined(_ARM64_)
#define _JBLEN 24
#define _JBTYPE unsigned __int64
typedef struct __JUMP_BUFFER {
unsigned __int64 Frame;
unsigned __int64 Reserved;
unsigned __int64 X19;
unsigned __int64 X20;
unsigned __int64 X21;
unsigned __int64 X22;
unsigned __int64 X23;
unsigned __int64 X24;
unsigned __int64 X25;
unsigned __int64 X26;
unsigned __int64 X27;
unsigned __int64 X28;
unsigned __int64 Fp;
unsigned __int64 Lr;
unsigned __int64 Sp;
unsigned long Fpcr;
unsigned long Fpsr;
double D[8];
} _JUMP_BUFFER;
#else
#define _JBLEN 1
#define _JBTYPE int
#endif
#ifndef _JMP_BUF_DEFINED
typedef _JBTYPE jmp_buf[_JBLEN];
#define _JMP_BUF_DEFINED
#endif
__declspec(noreturn) __attribute__ ((__nothrow__)) void __cdecl longjmp(jmp_buf _Buf, int _Value);
#if (defined(_X86_) && !defined(__x86_64))
int __cdecl __attribute__ ((__nothrow__, __returns_twice__)) _setjmp(jmp_buf _Buf);
int __cdecl __attribute__ ((__nothrow__, __returns_twice__)) _setjmp3(jmp_buf _Buf, int _Count, ...);
#else
#ifndef __aarch64__
int __cdecl __attribute__ ((__nothrow__, __returns_twice__)) _setjmp(jmp_buf _Buf, void *_Frame);
#endif
int __cdecl __attribute__ ((__nothrow__, __returns_twice__)) _setjmpex(jmp_buf _Buf, void *_Frame);
#endif
#if defined(__arm__) || defined(__aarch64__)
int __cdecl __attribute__ ((__nothrow__, __returns_twice__)) __mingw_setjmp(jmp_buf _Buf);
__declspec(noreturn) __attribute__ ((__nothrow__)) void __cdecl __mingw_longjmp(jmp_buf _Buf, int _Value);
#endif
#if defined(__TCC_BCHECK__)
__declspec(noreturn) __attribute__ ((__nothrow__)) void __cdecl __bound_longjmp(jmp_buf _Buf, int _Value);
#endif
void * __cdecl __attribute__ ((__nothrow__)) mingw_getsp(void);
#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);
#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) __attribute__ ((__nothrow__)) void __cdecl ms_longjmp(jmp_buf _Buf, int _Value);
#ifdef __cplusplus
}
#endif
#pragma pack(pop)
#ifdef setjmp
#undef setjmp
#endif
#if (defined(_X86_) && !defined(__x86_64))
#define setjmp(BUF) _setjmp3((BUF), 0)
#elif defined(__arm__) || defined(__aarch64__)
#define setjmp(BUF) __mingw_setjmp((BUF))
#elif defined(USE_MINGW_SETJMP_TWO_ARGS)
#ifndef _INC_SETJMPEX
#define setjmp(BUF) _setjmp((BUF), mingw_getsp())
#else
#define setjmp(BUF) _setjmpex((BUF), mingw_getsp())
#define setjmpex(BUF) _setjmpex((BUF), mingw_getsp())
#endif
#else
#ifndef _INC_SETJMPEX
#define setjmp _setjmp
#endif
#endif
#ifdef longjmp
#undef longjmp
#endif
#if defined(__TCC_BCHECK__) && defined(__aarch64__)
#define longjmp __bound_longjmp
#elif defined(__arm__) || defined(__aarch64__)
#define longjmp __mingw_longjmp
#else
#define longjmp longjmp
#endif
#endif

View File

@ -224,6 +224,8 @@ extern "C" {
extern wchar_t **_imp___wpgmptr;
#endif
#endif
_CRTIMP errno_t __cdecl _get_environ(char ***_Value);
_CRTIMP errno_t __cdecl _get_wenviron(wchar_t ***_Value);
errno_t __cdecl _get_pgmptr(char **_Value);
errno_t __cdecl _get_wpgmptr(wchar_t **_Value);
#ifndef _fmode

View File

@ -21,7 +21,7 @@ extern "C" {
#define __CRT_UNALIGNED
#endif
#if defined(__ia64__) || defined(__x86_64)
#if defined(__ia64__) || defined(__x86_64) || defined(__aarch64__)
#define UNALIGNED __CRT_UNALIGNED
#ifdef _WIN64
#define UNALIGNED64 __CRT_UNALIGNED
@ -47,6 +47,9 @@ 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)
@ -65,7 +68,7 @@ extern "C" {
#ifdef _WIN64
#ifdef _AMD64_
#define PROBE_ALIGNMENT(_s) TYPE_ALIGNMENT(DWORD)
#elif defined(_IA64_)
#elif defined(_IA64_) || defined(_ARM64_)
#define PROBE_ALIGNMENT(_s) (TYPE_ALIGNMENT(_s) > TYPE_ALIGNMENT(DWORD) ? TYPE_ALIGNMENT(_s) : TYPE_ALIGNMENT(DWORD))
#else
#error No Target Architecture
@ -79,7 +82,7 @@ extern "C" {
#include <basetsd.h>
#if defined(_X86_) || defined(__ia64__) || defined(__x86_64)
#if defined(_X86_) || defined(__ia64__) || defined(__x86_64) || defined(__aarch64__)
#define DECLSPEC_IMPORT __declspec(dllimport)
#else
#define DECLSPEC_IMPORT
@ -321,7 +324,7 @@ typedef DWORD LCID;
#define Int32x32To64(a,b) (LONGLONG)((LONGLONG)(LONG)(a) *(LONG)(b))
#define UInt32x32To64(a,b) (ULONGLONG)((ULONGLONG)(DWORD)(a) *(DWORD)(b))
#define Int64ShrlMod32(a,b) ((DWORDLONG)(a)>>(b))
#elif defined(__ia64__) || defined(__x86_64)
#elif defined(__ia64__) || defined(__x86_64) || defined(__aarch64__)
#define Int32x32To64(a,b) ((LONGLONG)((LONG)(a)) *(LONGLONG)((LONG)(b)))
#define UInt32x32To64(a,b) ((ULONGLONG)((DWORD)(a)) *(ULONGLONG)((DWORD)(b)))
#define Int64ShrlMod32(a,b) ((ULONGLONG)(a) >> (b))
@ -829,7 +832,7 @@ typedef DWORD LCID;
typedef ULONG_PTR KSPIN_LOCK;
typedef KSPIN_LOCK *PKSPIN_LOCK;
#ifdef _AMD64_
#if defined(_AMD64_) || defined(_ARM64_)
#if defined(__x86_64) && !defined(RC_INVOKED)
@ -1336,6 +1339,7 @@ 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;
@ -1407,6 +1411,7 @@ typedef DWORD LCID;
DWORD64 LastExceptionToRip;
DWORD64 LastExceptionFromRip;
} CONTEXT,*PCONTEXT;
#endif /* defined(__x86_64) || defined(_AMD64_) */
#define RUNTIME_FUNCTION_INDIRECT 0x1
@ -1417,6 +1422,52 @@ typedef DWORD LCID;
} RUNTIME_FUNCTION,*PRUNTIME_FUNCTION;
typedef PRUNTIME_FUNCTION (*PGET_RUNTIME_FUNCTION_CALLBACK)(DWORD64 ControlPc,PVOID Context);
#ifdef _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_CONTEXT_DECLARED
#define _ARM64_CONTEXT_DECLARED
typedef struct _CONTEXT {
DWORD64 ContextFlags;
DWORD64 X[29];
DWORD64 Fp;
DWORD64 Lr;
DWORD64 Sp;
DWORD64 Pc;
DWORD64 V[32];
DWORD Fpcr;
DWORD Fpsr;
DWORD Bcr[8];
DWORD Bvr[8];
DWORD Wcr[2];
DWORD Wvr[2];
} CONTEXT,*PCONTEXT;
#endif
#endif /* _ARM64_ */
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"
@ -1962,6 +2013,25 @@ typedef DWORD LCID;
DWORD64 ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
} EXCEPTION_RECORD64,*PEXCEPTION_RECORD64;
#if defined(__aarch64__) && !defined(_ARM64_CONTEXT_DECLARED)
#define _ARM64_CONTEXT_DECLARED
typedef struct _CONTEXT {
DWORD64 ContextFlags;
DWORD64 X[29];
DWORD64 Fp;
DWORD64 Lr;
DWORD64 Sp;
DWORD64 Pc;
DWORD64 V[32];
DWORD Fpcr;
DWORD Fpsr;
DWORD Bcr[8];
DWORD Bvr[8];
DWORD Wcr[2];
DWORD Wvr[2];
} CONTEXT,*PCONTEXT;
#endif
typedef struct _EXCEPTION_POINTERS {
PEXCEPTION_RECORD ExceptionRecord;
PCONTEXT ContextRecord;
@ -3701,6 +3771,7 @@ typedef DWORD LCID;
#define IMAGE_FILE_MACHINE_CEF 0x0CEF
#define IMAGE_FILE_MACHINE_EBC 0x0EBC
#define IMAGE_FILE_MACHINE_AMD64 0x8664
#define IMAGE_FILE_MACHINE_ARM64 0xAA64
#define IMAGE_FILE_MACHINE_M32R 0x9041
#define IMAGE_FILE_MACHINE_CEE 0xC0EE

View File

@ -8,7 +8,81 @@
#endif
/* ---------------------------------------------- */
#ifndef __x86_64__
#if defined(__aarch64__)
/* ---------------------------------------------- */
.globl __chkstk
__chkstk:
.long 0x910003f0
.long 0xd37cedf1
.long 0xb4000131
.long 0xf1400620
.long 0x540000a9
.long 0xd1400610
.long 0xf940021f
.long 0xd1400631
.long 0x17fffffb
.long 0xcb110210
.long 0xf940021f
.long 0xd65f03c0
.globl _(tinyc_getbp)
_(tinyc_getbp):
mov x0, x29
ret
.globl _(mingw_getsp)
_(mingw_getsp):
.long 0x910003e0
.long 0xd65f03c0
.globl _(__mingw_setjmp)
_(__mingw_setjmp):
.long 0xf900001f
.long 0xa9015013
.long 0xa9025815
.long 0xa9036017
.long 0xa9046819
.long 0xa905701b
.long 0xa906781d
.long 0x910003e2
.long 0xf9003802
.long 0xd53b4402
.long 0xb9007802
.long 0xd53b4422
.long 0xb9007c02
.long 0x6d082408
.long 0x6d092c0a
.long 0x6d0a340c
.long 0x6d0b3c0e
.long 0xd2800000
.long 0xd65f03c0
.globl _(__mingw_longjmp)
_(__mingw_longjmp):
.long 0xa9415013
.long 0xa9425815
.long 0xa9436017
.long 0xa9446819
.long 0xa945701b
.long 0xa946781d
.long 0xf9403802
.long 0x9100005f
.long 0xb9407802
.long 0xd51b4402
.long 0xb9407c02
.long 0xd51b4422
.long 0x6d482408
.long 0x6d492c0a
.long 0x6d4a340c
.long 0x6d4b3c0e
.long 0xaa0103e0
.long 0xb5000040
.long 0xd2800020
.long 0xd65f03c0
/* ---------------------------------------------- */
#elif !defined(__x86_64__)
/* ---------------------------------------------- */
.globl _(__chkstk)
@ -69,5 +143,3 @@ _(tinyc_getbp):
/* ---------------------------------------------- */
#endif
/* ---------------------------------------------- */

View File

@ -22,18 +22,26 @@
#define _tstart _wstart
#define _tmain wmain
#define _runtmain _runwmain
#define get_tenviron _get_wenviron
#else
#define __tgetmainargs __getmainargs
#define _tstart _start
#define _tmain main
#define _runtmain _runmain
#define get_tenviron _get_environ
#endif
typedef struct { int newmode; } _startupinfo;
int __cdecl __tgetmainargs(int *pargc, _TCHAR ***pargv, _TCHAR ***penv, int globb, _startupinfo*);
int __cdecl get_tenviron(_TCHAR ***penv);
void __cdecl __set_app_type(int apptype);
unsigned int __cdecl _controlfp(unsigned int new_value, unsigned int mask);
extern int _tmain(int argc, _TCHAR * argv[], _TCHAR * env[]);
#ifdef UNICODE
__attribute__((weak)) wchar_t **__cdecl __rt_get_wenviron(void);
#else
__attribute__((weak)) char **__cdecl __rt_get_environ(void);
#endif
#include "crtinit.c"
@ -48,6 +56,7 @@ static LONG WINAPI catch_sig(EXCEPTION_POINTERS *ex)
void _tstart(void)
{
int ret;
_TCHAR **env = NULL;
_startupinfo start_info = {0};
SetUnhandledExceptionFilter(catch_sig);
@ -60,9 +69,9 @@ void _tstart(void)
_controlfp(_PC_53, _MCW_PC);
#endif
__tgetmainargs( &__argc, &__targv, &_tenviron, _dowildcard, &start_info);
run_ctors(__argc, __targv, _tenviron);
ret = _tmain(__argc, __targv, _tenviron);
__tgetmainargs(&__argc, &__targv, &env, _dowildcard, &start_info);
run_ctors(__argc, __targv, env);
ret = _tmain(__argc, __targv, env);
run_dtors();
exit(ret);
}
@ -70,15 +79,52 @@ void _tstart(void)
// =============================================
// for 'tcc -run ,,,'
__attribute__((weak)) extern int __run_on_exit();
__attribute__((weak)) void __run_on_exit(int ret)
{
(void)ret;
}
static void run_stdio_init(void)
{
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
}
int _runtmain(int argc, /* as tcc passed in */ char **argv)
{
int ret;
_TCHAR **env = NULL;
#ifdef UNICODE
if (__rt_get_wenviron) {
env = __rt_get_wenviron();
#if defined __i386__ || defined __x86_64__
_controlfp(_PC_53, _MCW_PC);
#endif
run_stdio_init();
run_ctors(argc, (_TCHAR **)argv, env);
ret = _tmain(argc, (_TCHAR **)argv, env);
run_dtors();
__run_on_exit(ret);
return ret;
}
#else
if (__rt_get_environ) {
env = __rt_get_environ();
#if defined __i386__ || defined __x86_64__
_controlfp(_PC_53, _MCW_PC);
#endif
run_stdio_init();
run_ctors(argc, (_TCHAR **)argv, env);
ret = _tmain(argc, (_TCHAR **)argv, env);
run_dtors();
__run_on_exit(ret);
return ret;
}
#endif
#ifdef UNICODE
_startupinfo start_info = {0};
__tgetmainargs(&__argc, &__targv, &_tenviron, _dowildcard, &start_info);
__tgetmainargs(&__argc, &__targv, &env, _dowildcard, &start_info);
/* may be wrong when tcc has received wildcards (*.c) */
if (argc < __argc) {
__targv += __argc - argc;
@ -87,12 +133,14 @@ int _runtmain(int argc, /* as tcc passed in */ char **argv)
#else
__argc = argc;
__targv = argv;
get_tenviron(&env);
#endif
#if defined __i386__ || defined __x86_64__
_controlfp(_PC_53, _MCW_PC);
#endif
run_ctors(__argc, __targv, _tenviron);
ret = _tmain(__argc, __targv, _tenviron);
run_stdio_init();
run_ctors(__argc, __targv, env);
ret = _tmain(__argc, __targv, env);
run_dtors();
__run_on_exit(ret);
return ret;

View File

@ -16,21 +16,25 @@ void _controlfp(unsigned a, unsigned b);
#define __tgetmainargs __wgetmainargs
#define _twinstart _wwinstart
#define _runtwinmain _runwwinmain
#define get_tenviron _get_wenviron
int APIENTRY wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int);
#else
#define __tgetmainargs __getmainargs
#define _twinstart _winstart
#define _runtwinmain _runwinmain
#define get_tenviron _get_environ
#endif
typedef struct { int newmode; } _startupinfo;
int __cdecl __tgetmainargs(int *pargc, _TCHAR ***pargv, _TCHAR ***penv, int globb, _startupinfo*);
int __cdecl get_tenviron(_TCHAR ***penv);
#include "crtinit.c"
static int go_winmain(TCHAR *arg1)
{
STARTUPINFO si;
_TCHAR **env = NULL;
_TCHAR *szCmd, *p;
int fShow;
int retval;
@ -51,7 +55,8 @@ static int go_winmain(TCHAR *arg1)
#if defined __i386__ || defined __x86_64__
_controlfp(0x10000, 0x30000);
#endif
run_ctors(__argc, __targv, _tenviron);
get_tenviron(&env);
run_ctors(__argc, __targv, env);
retval = _tWinMain(GetModuleHandle(NULL), NULL, szCmd, fShow);
run_dtors();
return retval;
@ -67,7 +72,7 @@ int _twinstart(void)
_startupinfo start_info_con = {0};
SetUnhandledExceptionFilter(catch_sig);
__set_app_type(__GUI_APP);
__tgetmainargs(&__argc, &__targv, &_tenviron, 0, &start_info_con);
__tgetmainargs(&__argc, &__targv, NULL, 0, &start_info_con);
exit(go_winmain(__argc > 1 ? __targv[1] : NULL));
}
@ -75,7 +80,7 @@ int _runtwinmain(int argc, /* as tcc passed in */ char **argv)
{
#ifdef UNICODE
_startupinfo start_info = {0};
__tgetmainargs(&__argc, &__targv, &_tenviron, 0, &start_info);
__tgetmainargs(&__argc, &__targv, NULL, 0, &start_info);
/* may be wrong when tcc has received wildcards (*.c) */
if (argc < __argc)
__targv += __argc - argc, __argc = argc;

12
win32/test_arm64.c Normal file
View File

@ -0,0 +1,12 @@
/* Simple ARM64 Windows test program - no inline asm */
#include <stdio.h>
int main(int argc, char **argv) {
int x = 42;
int y = x * 2;
printf("Hello from ARM64 Windows!\n");
printf("x = %d, y = %d\n", x, y);
return 0;
}