mirror of
git://repo.or.cz/tinycc.git
synced 2026-06-19 11:24:19 +08:00
Fix ARM64 asm and Windows -run support
This commit is contained in:
parent
052e40ddd0
commit
f37fbab915
45
.github/workflows/build.yml
vendored
45
.github/workflows/build.yml
vendored
@ -62,6 +62,23 @@ jobs:
|
||||
cd win32
|
||||
call build-tcc.bat -t 64 -c cl
|
||||
echo ::endgroup::
|
||||
set TCC_RUN_ENV=ok
|
||||
.\tcc -B. -run ..\win32\test_run_argv.c alpha "two words" beta > test_run_argv.out
|
||||
fc /n test_run_argv.out ..\win32\test_run_argv.ref
|
||||
.\tcc -B. -run ..\win32\test_run_env.c
|
||||
> test_run_argv_wc_a.tmp echo a
|
||||
> test_run_argv_wc_b.tmp echo b
|
||||
.\tcc -B. -run ..\win32\test_run_argv.c test_run_argv_wc_*.tmp > test_run_argv_wc.out
|
||||
findstr /c:"argc=3" test_run_argv_wc.out
|
||||
findstr /c:"arg1=<test_run_argv_wc_a.tmp>" test_run_argv_wc.out
|
||||
findstr /c:"arg2=<test_run_argv_wc_b.tmp>" test_run_argv_wc.out
|
||||
.\tcc -B. -run ..\win32\test_run_wargv.c alpha "two words" beta > test_run_wargv.out
|
||||
fc /n test_run_wargv.out ..\win32\test_run_wargv.ref
|
||||
.\tcc -B. -run ..\win32\test_run_wenv.c
|
||||
.\tcc -B. -run ..\win32\test_run_wargv.c test_run_wargv_wc_*.tmp > test_run_wargv_wc.out
|
||||
findstr /c:"argc=3" test_run_wargv_wc.out
|
||||
findstr /c:"arg1=<test_run_wargv_wc_a.tmp>" test_run_wargv_wc.out
|
||||
findstr /c:"arg2=<test_run_wargv_wc_b.tmp>" test_run_wargv_wc.out
|
||||
.\tcc -B. ..\win32\test_pe_field_alignment.c -o test_pe_field_alignment.exe && .\test_pe_field_alignment.exe > test_pe_field_alignment.out
|
||||
fc /n test_pe_field_alignment.out ..\win32\test_pe_field_alignment.ref
|
||||
.\tcc -I.. libtcc.dll -v ../tests/libtcc_test.c -o libtest.exe && .\libtest.exe
|
||||
@ -127,9 +144,26 @@ jobs:
|
||||
call build-tcc.bat -t arm64 -c clang
|
||||
echo ::endgroup::
|
||||
if not exist libtcc.dll exit /b 1
|
||||
set TCC_RUN_ENV=ok
|
||||
.\tcc -B. -v
|
||||
.\tcc -B. -run ..\win32\test_run_argv.c alpha "two words" beta > test_run_argv.out
|
||||
fc /n test_run_argv.out ..\win32\test_run_argv.ref
|
||||
.\tcc -B. -run ..\win32\test_run_env.c
|
||||
.\tcc -B. -run ..\win32\test_run_wargv.c alpha "two words" beta > test_run_wargv.out
|
||||
fc /n test_run_wargv.out ..\win32\test_run_wargv.ref
|
||||
.\tcc -B. -run ..\win32\test_run_wenv.c
|
||||
> test_run_argv_wc_a.tmp echo a
|
||||
> test_run_argv_wc_b.tmp echo b
|
||||
.\tcc -B. -run ..\win32\test_run_argv.c test_run_argv_wc_*.tmp > test_run_argv_wc.out
|
||||
findstr /c:"argc=3" test_run_argv_wc.out
|
||||
findstr /c:"arg1=<test_run_argv_wc_a.tmp>" test_run_argv_wc.out
|
||||
findstr /c:"arg2=<test_run_argv_wc_b.tmp>" test_run_argv_wc.out
|
||||
> test_run_wargv_wc_a.tmp echo a
|
||||
> test_run_wargv_wc_b.tmp echo b
|
||||
.\tcc -B. -run ..\win32\test_run_wargv.c test_run_wargv_wc_*.tmp > test_run_wargv_wc.out
|
||||
findstr /c:"argc=3" test_run_wargv_wc.out
|
||||
findstr /c:"arg1=<test_run_wargv_wc_a.tmp>" test_run_wargv_wc.out
|
||||
findstr /c:"arg2=<test_run_wargv_wc_b.tmp>" test_run_wargv_wc.out
|
||||
type ..\win32\test_run_stdin.ref | .\tcc -B. -run ..\win32\test_run_stdin.c > test_run_stdin.out
|
||||
fc /n test_run_stdin.out ..\win32\test_run_stdin.ref
|
||||
powershell -NoProfile -Command "$before = @(Get-ChildItem -Path $env:TEMP -Filter 'tcc*.tmp' -Name -ErrorAction SilentlyContinue); & .\tcc -B. -run ..\win32\test_run_exit.c; if ($LASTEXITCODE -ne 27) { exit 1 }; $after = @(Get-ChildItem -Path $env:TEMP -Filter 'tcc*.tmp' -Name -ErrorAction SilentlyContinue); if (Compare-Object $before $after) { Write-Host 'Temporary -run file cleanup mismatch'; Compare-Object $before $after; exit 1 }"
|
||||
@ -143,14 +177,9 @@ jobs:
|
||||
.\tcc -B. -DTEST_GOTO ..\win32\test_arm64_inline_asm.c -o test_inline_goto.exe && .\test_inline_goto.exe > test_inline_goto.out
|
||||
> test_inline_goto.expect echo asm goto ok
|
||||
fc /n test_inline_goto.out test_inline_goto.expect
|
||||
.\tcc -B. -DTEST_OPERANDS ..\win32\test_arm64_inline_asm.c -c -o test_inline_operands.obj > test_inline_operands.out 2>&1
|
||||
if not errorlevel 1 exit /b 1
|
||||
type test_inline_operands.out
|
||||
findstr /c:"ARM64 extended inline asm is not implemented" test_inline_operands.out
|
||||
.\tcc -B. -DTEST_CLOBBERS ..\win32\test_arm64_inline_asm.c -c -o test_inline_clobbers.obj > test_inline_clobbers.out 2>&1
|
||||
if not errorlevel 1 exit /b 1
|
||||
type test_inline_clobbers.out
|
||||
findstr /c:"ARM64 extended inline asm is not implemented" test_inline_clobbers.out
|
||||
.\tcc -B. -DTEST_OPERANDS ..\win32\test_arm64_inline_asm.c -o test_inline_operands.exe && .\test_inline_operands.exe > test_inline_operands.out
|
||||
findstr /x /c:"2" test_inline_operands.out
|
||||
.\tcc -B. -DTEST_CLOBBERS ..\win32\test_arm64_inline_asm.c -o test_inline_clobbers.exe && .\test_inline_clobbers.exe
|
||||
> test_rstdin.txt echo arm64 stdin
|
||||
.\tcc -B. -rstdin test_rstdin.txt -run ..\win32\test_rstdin.c > test_rstdin.out
|
||||
type test_rstdin.out
|
||||
|
||||
118
arm64-asm.c
118
arm64-asm.c
@ -479,17 +479,45 @@ static void gen_ldst_imm(uint32_t base_opcode, int rt, int rn,
|
||||
int32_t offset, int size_log2)
|
||||
{
|
||||
uint32_t instr = base_opcode;
|
||||
uint32_t unscaled_opcode = 0;
|
||||
uint32_t imm12;
|
||||
|
||||
if (offset < 0 || (offset & ((1 << size_log2) - 1)))
|
||||
if (offset >= 0 && !(offset & ((1 << size_log2) - 1))) {
|
||||
imm12 = offset >> size_log2;
|
||||
if (imm12 <= 0xFFF) {
|
||||
instr |= ARM64_IMM12(imm12);
|
||||
instr |= ARM64_RN(rn);
|
||||
instr |= ARM64_RT(rt);
|
||||
emit_instr32(instr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (base_opcode) {
|
||||
case ARM64_LDR_X: unscaled_opcode = ARM64_LDUR_X; break;
|
||||
case ARM64_LDR_W: unscaled_opcode = ARM64_LDUR_W; break;
|
||||
case ARM64_LDR_B: unscaled_opcode = ARM64_LDUR_B; break;
|
||||
case ARM64_LDR_H: unscaled_opcode = ARM64_LDUR_H; break;
|
||||
case ARM64_LDR_D: unscaled_opcode = ARM64_LDUR_D_SIMD; break;
|
||||
case ARM64_STR_X: unscaled_opcode = ARM64_STUR_X; break;
|
||||
case ARM64_STR_W: unscaled_opcode = ARM64_STUR_W; break;
|
||||
case ARM64_STR_B: unscaled_opcode = ARM64_STUR_B; break;
|
||||
case ARM64_STR_H: unscaled_opcode = ARM64_STUR_H; break;
|
||||
case ARM64_STR_D: unscaled_opcode = ARM64_STUR_D_SIMD; break;
|
||||
}
|
||||
|
||||
if (unscaled_opcode && offset >= -256 && offset <= 255) {
|
||||
instr = unscaled_opcode;
|
||||
instr |= ((uint32_t)offset & 0x1FFU) << 12;
|
||||
instr |= ARM64_RN(rn);
|
||||
instr |= ARM64_RT(rt);
|
||||
emit_instr32(instr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (offset & ((1 << size_log2) - 1))
|
||||
tcc_error("invalid load/store offset");
|
||||
imm12 = offset >> size_log2;
|
||||
if (imm12 > 0xFFF)
|
||||
tcc_error("load/store offset out of range");
|
||||
instr |= ARM64_IMM12(imm12);
|
||||
instr |= ARM64_RN(rn);
|
||||
instr |= ARM64_RT(rt);
|
||||
emit_instr32(instr);
|
||||
tcc_error("load/store offset out of range");
|
||||
}
|
||||
|
||||
/* Generate STP/LDP (signed immediate) */
|
||||
@ -826,15 +854,41 @@ static int arm64_memory_is_pair_suitable(const SValue *sv)
|
||||
return (offset & 7) == 0 && offset >= -512 && offset <= 504;
|
||||
}
|
||||
|
||||
static int arm64_int_reg_is_allocatable(int reg)
|
||||
{
|
||||
#ifdef TCC_TARGET_PE
|
||||
return reg >= TREG_X0 && reg <= TREG_X17;
|
||||
#else
|
||||
return reg >= TREG_X0 && reg <= TREG_X30;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int arm64_memory_needs_address_reg(const SValue *sv)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = sv->r & ~(VT_BOUNDED | VT_NONCONST);
|
||||
if (!(r & VT_LVAL))
|
||||
return 0;
|
||||
switch (r & VT_VALMASK) {
|
||||
case VT_LOCAL:
|
||||
case VT_LLOCAL:
|
||||
case VT_CONST:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int arm64_prepare_memory_operand(ASMOperand *op, uint8_t *regs_allocated)
|
||||
{
|
||||
int reg;
|
||||
|
||||
if ((op->vt->r & VT_VALMASK) != VT_LLOCAL)
|
||||
if (!arm64_memory_needs_address_reg(op->vt))
|
||||
return 1;
|
||||
|
||||
for (reg = 0; reg < 31; reg++) {
|
||||
if (!(regs_allocated[reg] & REG_IN_MASK)) {
|
||||
if (arm64_int_reg_is_allocatable(reg)
|
||||
&& !(regs_allocated[reg] & REG_IN_MASK)) {
|
||||
regs_allocated[reg] |= REG_IN_MASK;
|
||||
op->reg = reg;
|
||||
op->is_memory = 1;
|
||||
@ -844,6 +898,24 @@ static int arm64_prepare_memory_operand(ASMOperand *op, uint8_t *regs_allocated)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void arm64_load_memory_operand_base(int reg, SValue *sv)
|
||||
{
|
||||
SValue base;
|
||||
int rval;
|
||||
|
||||
base = *sv;
|
||||
base.type.t = VT_PTR;
|
||||
rval = base.r & VT_VALMASK;
|
||||
if (rval == VT_LLOCAL) {
|
||||
base.r = (base.r & ~VT_VALMASK) | VT_LOCAL | VT_LVAL;
|
||||
} else if (rval == VT_CONST || rval == VT_LOCAL) {
|
||||
base.r &= ~VT_LVAL;
|
||||
} else {
|
||||
tcc_internal_error("unsupported ARM64 memory operand base");
|
||||
}
|
||||
load(reg, &base);
|
||||
}
|
||||
|
||||
static int operand_is_sp(const Operand *op)
|
||||
{
|
||||
return op->reg_tok == TOK_ASM_sp;
|
||||
@ -1804,8 +1876,11 @@ ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier)
|
||||
size = 1;
|
||||
else if ((sv->type.t & VT_BTYPE) == VT_SHORT)
|
||||
size = 2;
|
||||
else
|
||||
else if ((sv->type.t & VT_BTYPE) == VT_LLONG ||
|
||||
(sv->type.t & VT_BTYPE) == VT_PTR)
|
||||
size = 8;
|
||||
else
|
||||
size = 4;
|
||||
|
||||
if (modifier == 'x') {
|
||||
size = 8;
|
||||
@ -1877,12 +1952,8 @@ ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
|
||||
for (i = 0; i < nb_operands; i++) {
|
||||
op = &operands[i];
|
||||
if (op->reg >= 0) {
|
||||
if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory) {
|
||||
SValue sv;
|
||||
sv = *op->vt;
|
||||
sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL | VT_LVAL;
|
||||
sv.type.t = VT_PTR;
|
||||
load(op->reg, &sv);
|
||||
if (op->is_memory) {
|
||||
arm64_load_memory_operand_base(op->reg, op->vt);
|
||||
} else if (i >= nb_outputs || op->is_rw) {
|
||||
load(op->reg, op->vt);
|
||||
}
|
||||
@ -1892,6 +1963,8 @@ ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
|
||||
for (i = 0; i < nb_outputs; i++) {
|
||||
op = &operands[i];
|
||||
if (op->reg >= 0) {
|
||||
if (op->is_memory)
|
||||
continue;
|
||||
if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) {
|
||||
if (!op->is_memory) {
|
||||
SValue sv;
|
||||
@ -2026,7 +2099,8 @@ ST_FUNC void asm_compute_constraints(ASMOperand *operands,
|
||||
goto try_next;
|
||||
case 'r':
|
||||
for (reg = 0; reg < 31; reg++) {
|
||||
if (!is_reg_allocated(reg))
|
||||
if (arm64_int_reg_is_allocatable(reg)
|
||||
&& !is_reg_allocated(reg))
|
||||
goto reg_found;
|
||||
}
|
||||
goto try_next;
|
||||
@ -2116,8 +2190,8 @@ ST_FUNC void asm_compute_constraints(ASMOperand *operands,
|
||||
goto try_next;
|
||||
break;
|
||||
default:
|
||||
tcc_warning("asm constraint %d ('%s') could not be satisfied",
|
||||
j, op->constraint);
|
||||
tcc_error("asm constraint %d ('%s') could not be satisfied",
|
||||
j, op->constraint);
|
||||
break;
|
||||
}
|
||||
if (op->input_index >= 0) {
|
||||
@ -2157,15 +2231,13 @@ ST_FUNC void asm_compute_constraints(ASMOperand *operands,
|
||||
ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str)
|
||||
{
|
||||
int reg;
|
||||
TokenSym *ts;
|
||||
|
||||
if (!strcmp(str, "memory") ||
|
||||
!strcmp(str, "cc") ||
|
||||
!strcmp(str, "flags"))
|
||||
return;
|
||||
|
||||
ts = tok_alloc(str, strlen(str));
|
||||
reg = arm64_parse_regvar(ts->tok);
|
||||
reg = arm64_parse_regvar(tok_alloc_const(str));
|
||||
if (reg == -1)
|
||||
tcc_error("invalid clobber register '%s'", str);
|
||||
clobber_regs[reg] = 1;
|
||||
|
||||
@ -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 runrt.o
|
||||
LIN_O = dsohandle.o
|
||||
OSX_O =
|
||||
|
||||
@ -99,6 +99,11 @@ $(TOP)/bcheck.o : XFLAGS += $(BFLAGS)
|
||||
$(X)crt1w.o : crt1.c
|
||||
$(X)wincrt1w.o : wincrt1.c
|
||||
|
||||
ifeq ($(T),arm64-win32)
|
||||
$(TOP)/runmain.o : runmain-arm64.S $(TCC)
|
||||
$S$(XCC) -c $< -o $@ $(XFLAGS)
|
||||
endif
|
||||
|
||||
# don't try to make it
|
||||
$(TCC) : ;
|
||||
|
||||
|
||||
3
libtcc.c
3
libtcc.c
@ -905,6 +905,9 @@ LIBTCCAPI TCCState *tcc_new(void)
|
||||
#ifdef TCC_TARGET_ARM
|
||||
s->float_abi = ARM_FLOAT_ABI;
|
||||
#endif
|
||||
#ifdef TCC_IS_NATIVE
|
||||
s->run_arg_start = -1;
|
||||
#endif
|
||||
#ifdef CONFIG_NEW_DTAGS
|
||||
s->enable_new_dtags = 1;
|
||||
#endif
|
||||
|
||||
1
tcc.c
1
tcc.c
@ -330,6 +330,7 @@ redo:
|
||||
argc = argc0, argv = argv0;
|
||||
s = s1 = tcc_new();
|
||||
opt = tcc_parse_args(s, &argc, &argv);
|
||||
s->run_arg_start = (int)(argv - argv0);
|
||||
|
||||
if (n == 0) {
|
||||
ret = 0;
|
||||
|
||||
1
tcc.h
1
tcc.h
@ -982,6 +982,7 @@ struct TCCState {
|
||||
|
||||
#ifdef TCC_IS_NATIVE
|
||||
const char *run_main; /* entry for tcc_run() */
|
||||
int run_arg_start; /* argv index for tcc -run relative to the host command line */
|
||||
void *run_ptr; /* runtime_memory */
|
||||
unsigned run_size; /* size of runtime_memory */
|
||||
const char *run_stdin; /* custom stdin file for run_main */
|
||||
|
||||
2
tccasm.c
2
tccasm.c
@ -1202,7 +1202,7 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands,
|
||||
sv = *op->vt;
|
||||
if (op->reg >= 0) {
|
||||
sv.r = op->reg;
|
||||
if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory)
|
||||
if (op->is_memory)
|
||||
sv.r |= VT_LVAL;
|
||||
}
|
||||
subst_asm_operand(out_str, &sv, modifier);
|
||||
|
||||
14
tccrun.c
14
tccrun.c
@ -241,6 +241,13 @@ static wchar_t **rt_get_wenviron(void)
|
||||
#endif
|
||||
return env;
|
||||
}
|
||||
|
||||
static int rt_run_argstart = -1;
|
||||
|
||||
static int __cdecl rt_get_run_argstart(void)
|
||||
{
|
||||
return rt_run_argstart;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -288,6 +295,8 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
|
||||
#ifdef _WIN32
|
||||
tcc_add_symbol(s1, "__rt_get_environ", rt_get_environ);
|
||||
tcc_add_symbol(s1, "__rt_get_wenviron", rt_get_wenviron);
|
||||
tcc_add_symbol(s1, "__rt_get_run_argstart", rt_get_run_argstart);
|
||||
rt_run_argstart = s1->run_arg_start;
|
||||
#endif
|
||||
s1->run_main = "_runmain", top_sym = "main";
|
||||
if (s1->elf_entryname)
|
||||
@ -296,7 +305,6 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
|
||||
|
||||
if (tcc_relocate(s1) < 0)
|
||||
return -1;
|
||||
|
||||
prog_main = (void*)get_sym_addr(s1, s1->run_main, 1, 1);
|
||||
if ((addr_t)-1 == (addr_t)prog_main)
|
||||
return -1;
|
||||
@ -318,12 +326,12 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
|
||||
ret = tcc_setjmp(s1, main_jb, tcc_get_symbol(s1, top_sym));
|
||||
if (0 == ret) {
|
||||
ret = prog_main(argc, argv, envp);
|
||||
} else if (RT_EXIT_ZERO == ret) {
|
||||
} else if (RT_EXIT_ZERO == ret)
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
rt_flush_target_io();
|
||||
rt_run_argstart = -1;
|
||||
#endif
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
|
||||
@ -70,6 +70,30 @@ void test_memory_store(void)
|
||||
printf("Test 5 (memory store): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 5a: Stack memory operand with frame-relative offset */
|
||||
void test_stack_memory_operand(void)
|
||||
{
|
||||
long x = 0;
|
||||
long val = 321;
|
||||
|
||||
asm volatile("str %0, %1" : : "r"(val), "m"(x));
|
||||
assert(x == 321);
|
||||
printf("Test 5a (stack memory operand): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 5b: Symbol memory operand */
|
||||
static long arm64_symbol_mem;
|
||||
|
||||
void test_symbol_memory_operand(void)
|
||||
{
|
||||
long val = 654;
|
||||
|
||||
arm64_symbol_mem = 0;
|
||||
asm volatile("str %0, %1" : : "r"(val), "m"(arm64_symbol_mem));
|
||||
assert(arm64_symbol_mem == 654);
|
||||
printf("Test 5b (symbol memory operand): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 6: Clobber list */
|
||||
void test_clobber_list(void)
|
||||
{
|
||||
@ -394,6 +418,8 @@ int main(void)
|
||||
test_read_write_operand();
|
||||
test_memory_load();
|
||||
test_memory_store();
|
||||
test_stack_memory_operand();
|
||||
test_symbol_memory_operand();
|
||||
test_clobber_list();
|
||||
test_multiple_outputs();
|
||||
test_constraint_reference();
|
||||
|
||||
@ -32,7 +32,7 @@ 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 use prog (gcc/clang/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 -v "version" set tcc version
|
||||
@ -65,6 +65,12 @@ exit /B 0
|
||||
if exist %1 rmdir /Q/S %1 && %LOG% %1
|
||||
exit /B 0
|
||||
|
||||
:select_clang
|
||||
if /I not "%CC%"=="clang" exit /B 0
|
||||
if "%~1"=="64" if exist C:\msys64\clang64\bin\x86_64-w64-mingw32-clang.exe set CC=C:\msys64\clang64\bin\x86_64-w64-mingw32-clang.exe
|
||||
if "%~1"=="arm64" if exist C:\msys64\clangarm64\bin\aarch64-w64-mingw32-clang.exe set CC=C:\msys64\clangarm64\bin\aarch64-w64-mingw32-clang.exe
|
||||
exit /B 0
|
||||
|
||||
:cl
|
||||
@echo off
|
||||
set CMD=cl
|
||||
@ -122,6 +128,7 @@ set P=%PARM64%
|
||||
goto :p3
|
||||
|
||||
:p3
|
||||
call :select_clang %T%
|
||||
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
|
||||
@ -212,18 +219,23 @@ exit /B %ERRORLEVEL%
|
||||
.\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/runrt.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 -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 runrt.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
|
||||
@if "%1"=="arm64" (
|
||||
.\tcc -B. -m%1 -c lib/runmain-arm64.S -o lib/%2runmain.o
|
||||
) else (
|
||||
.\tcc -B. -m%1 -c ../lib/runmain.c -o lib/%2runmain.o
|
||||
)
|
||||
@if "%~2"=="" (
|
||||
@rem Keep the repo-root runtime helpers in sync for native -run and tests.
|
||||
if exist tcc.exe copy>nul /y tcc.exe ..\tcc.exe
|
||||
|
||||
407
win32/lib/crt1.c
407
win32/lib/crt1.c
@ -7,6 +7,8 @@
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#define _UNKNOWN_APP 0
|
||||
#define _CONSOLE_APP 1
|
||||
@ -33,6 +35,8 @@
|
||||
|
||||
typedef struct { int newmode; } _startupinfo;
|
||||
int __cdecl __tgetmainargs(int *pargc, _TCHAR ***pargv, _TCHAR ***penv, int globb, _startupinfo*);
|
||||
int __cdecl __getmainargs(int *pargc, char ***pargv, char ***penv, int globb, _startupinfo*);
|
||||
int __cdecl __wgetmainargs(int *pargc, wchar_t ***pargv, wchar_t ***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);
|
||||
@ -42,6 +46,12 @@ __attribute__((weak)) wchar_t **__cdecl __rt_get_wenviron(void);
|
||||
#else
|
||||
__attribute__((weak)) char **__cdecl __rt_get_environ(void);
|
||||
#endif
|
||||
__attribute__((weak)) int __cdecl __rt_get_run_argstart(void);
|
||||
|
||||
void __tcc_run_on_exit(int ret);
|
||||
int __tcc_on_exit(void *function, void *arg);
|
||||
int __tcc_atexit(void (*function)(void));
|
||||
void __attribute__((noreturn)) __tcc_exit(int code);
|
||||
|
||||
#include "crtinit.c"
|
||||
|
||||
@ -72,69 +82,368 @@ void _tstart(void)
|
||||
__tgetmainargs(&__argc, &__targv, &env, _dowildcard, &start_info);
|
||||
run_ctors(__argc, __targv, env);
|
||||
ret = _tmain(__argc, __targv, env);
|
||||
run_dtors();
|
||||
exit(ret);
|
||||
__tcc_exit(ret);
|
||||
}
|
||||
|
||||
// =============================================
|
||||
// for 'tcc -run ,,,'
|
||||
|
||||
__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);
|
||||
}
|
||||
|
||||
static _TCHAR **run_get_tenviron(void)
|
||||
{
|
||||
_TCHAR **env = NULL;
|
||||
_TCHAR **argv = NULL;
|
||||
int argc;
|
||||
_startupinfo start_info = {0};
|
||||
|
||||
#ifdef UNICODE
|
||||
if (__rt_get_wenviron)
|
||||
env = __rt_get_wenviron();
|
||||
if (!env)
|
||||
get_tenviron(&env);
|
||||
#else
|
||||
if (__rt_get_environ)
|
||||
env = __rt_get_environ();
|
||||
if (!env)
|
||||
get_tenviron(&env);
|
||||
#endif
|
||||
if (!env)
|
||||
__tgetmainargs(&argc, &argv, &env, 0, &start_info);
|
||||
return env;
|
||||
}
|
||||
|
||||
typedef struct run_targv_state {
|
||||
int saved_argc;
|
||||
_TCHAR **saved_argv;
|
||||
_TCHAR **run_argv;
|
||||
int active;
|
||||
} run_targv_state;
|
||||
|
||||
static __declspec(thread) run_targv_state *run_targv_tls;
|
||||
|
||||
static void free_run_targv(_TCHAR **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!argv)
|
||||
return;
|
||||
for (i = 0; argv[i]; ++i)
|
||||
free(argv[i]);
|
||||
free(argv);
|
||||
}
|
||||
|
||||
static _TCHAR **dup_run_targv_from_tchar(int argc, _TCHAR **argv)
|
||||
{
|
||||
int i;
|
||||
_TCHAR **copy = malloc(sizeof(*copy) * (argc + 1));
|
||||
|
||||
if (!copy)
|
||||
return NULL;
|
||||
for (i = 0; i < argc; ++i) {
|
||||
size_t len;
|
||||
|
||||
if (!argv[i]) {
|
||||
copy[i] = NULL;
|
||||
continue;
|
||||
}
|
||||
len = _tcslen(argv[i]) + 1;
|
||||
copy[i] = malloc(sizeof(*copy[i]) * len);
|
||||
if (!copy[i])
|
||||
goto fail;
|
||||
memcpy(copy[i], argv[i], sizeof(*copy[i]) * len);
|
||||
}
|
||||
copy[argc] = NULL;
|
||||
return copy;
|
||||
fail:
|
||||
copy[i] = NULL;
|
||||
free_run_targv(copy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static _TCHAR **dup_run_targv_from_char(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
_TCHAR **copy = malloc(sizeof(*copy) * (argc + 1));
|
||||
|
||||
if (!copy)
|
||||
return NULL;
|
||||
for (i = 0; i < argc; ++i) {
|
||||
#ifdef UNICODE
|
||||
size_t len;
|
||||
|
||||
if (!argv[i]) {
|
||||
copy[i] = NULL;
|
||||
continue;
|
||||
}
|
||||
len = strlen(argv[i]) + 1;
|
||||
copy[i] = malloc(sizeof(*copy[i]) * len);
|
||||
if (!copy[i] || (size_t)-1 == mbstowcs(copy[i], argv[i], len))
|
||||
goto fail;
|
||||
#else
|
||||
size_t len;
|
||||
|
||||
if (!argv[i]) {
|
||||
copy[i] = NULL;
|
||||
continue;
|
||||
}
|
||||
len = strlen(argv[i]) + 1;
|
||||
copy[i] = malloc(len);
|
||||
if (!copy[i])
|
||||
goto fail;
|
||||
memcpy(copy[i], argv[i], len);
|
||||
#endif
|
||||
}
|
||||
copy[argc] = NULL;
|
||||
return copy;
|
||||
fail:
|
||||
copy[i] = NULL;
|
||||
free_run_targv(copy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typedef LPWSTR *(WINAPI *run_command_line_to_argv_w_func)(LPCWSTR, int *);
|
||||
|
||||
static wchar_t **run_command_line_to_argv_w(int *pargc)
|
||||
{
|
||||
static run_command_line_to_argv_w_func fn;
|
||||
static int init;
|
||||
|
||||
if (!init) {
|
||||
HMODULE dll = GetModuleHandleA("shell32.dll");
|
||||
if (!dll)
|
||||
dll = LoadLibraryA("shell32.dll");
|
||||
if (dll)
|
||||
fn = (run_command_line_to_argv_w_func)(void *)GetProcAddress(dll, "CommandLineToArgvW");
|
||||
init = 1;
|
||||
}
|
||||
return fn ? fn(GetCommandLineW(), pargc) : NULL;
|
||||
}
|
||||
|
||||
static wchar_t *dup_run_wstr(const wchar_t *s)
|
||||
{
|
||||
size_t len = wcslen(s) + 1;
|
||||
wchar_t *copy = malloc(sizeof(*copy) * len);
|
||||
|
||||
if (!copy)
|
||||
return NULL;
|
||||
memcpy(copy, s, sizeof(*copy) * len);
|
||||
return copy;
|
||||
}
|
||||
|
||||
static void free_run_wargv(wchar_t **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!argv)
|
||||
return;
|
||||
for (i = 0; argv[i]; ++i)
|
||||
free(argv[i]);
|
||||
free(argv);
|
||||
}
|
||||
|
||||
static int append_run_warg(wchar_t ***pargv, int *pargc, wchar_t *arg)
|
||||
{
|
||||
wchar_t **next = realloc(*pargv, sizeof(**pargv) * (*pargc + 2));
|
||||
|
||||
if (!next)
|
||||
return 0;
|
||||
*pargv = next;
|
||||
next[*pargc] = arg;
|
||||
next[*pargc + 1] = NULL;
|
||||
++*pargc;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int run_has_wildcard(const wchar_t *s)
|
||||
{
|
||||
for (; *s; ++s)
|
||||
if (*s == L'*' || *s == L'?')
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run_expand_wildcard_arg(const wchar_t *pattern, wchar_t ***pargv, int *pargc)
|
||||
{
|
||||
WIN32_FIND_DATAW data;
|
||||
HANDLE h = INVALID_HANDLE_VALUE;
|
||||
const wchar_t *p;
|
||||
wchar_t **matches = NULL;
|
||||
int nmatches = 0, i, j, ok = 0;
|
||||
size_t prefix_len = 0;
|
||||
|
||||
for (p = pattern; *p; ++p) {
|
||||
if (*p == L'\\' || *p == L'/' || *p == L':')
|
||||
prefix_len = (size_t)(p - pattern + 1);
|
||||
}
|
||||
|
||||
h = FindFirstFileW(pattern, &data);
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
do {
|
||||
wchar_t *full;
|
||||
size_t name_len;
|
||||
|
||||
if (data.cFileName[0] == L'.'
|
||||
&& (!data.cFileName[1] || (data.cFileName[1] == L'.' && !data.cFileName[2])))
|
||||
continue;
|
||||
name_len = wcslen(data.cFileName);
|
||||
full = malloc(sizeof(*full) * (prefix_len + name_len + 1));
|
||||
if (!full)
|
||||
goto done;
|
||||
memcpy(full, pattern, sizeof(*full) * prefix_len);
|
||||
memcpy(full + prefix_len, data.cFileName, sizeof(*full) * (name_len + 1));
|
||||
if (!append_run_warg(&matches, &nmatches, full)) {
|
||||
free(full);
|
||||
goto done;
|
||||
}
|
||||
} while (FindNextFileW(h, &data));
|
||||
for (i = 0; i + 1 < nmatches; ++i) {
|
||||
for (j = i + 1; j < nmatches; ++j) {
|
||||
if (wcscmp(matches[j], matches[i]) < 0) {
|
||||
wchar_t *tmp = matches[i];
|
||||
matches[i] = matches[j];
|
||||
matches[j] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < nmatches; ++i) {
|
||||
wchar_t *copy = dup_run_wstr(matches[i]);
|
||||
|
||||
if (!copy || !append_run_warg(pargv, pargc, copy)) {
|
||||
free(copy);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
ok = nmatches != 0;
|
||||
done:
|
||||
if (h != INVALID_HANDLE_VALUE)
|
||||
FindClose(h);
|
||||
free_run_wargv(matches);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static wchar_t **build_run_wargv(int *prun_argc)
|
||||
{
|
||||
wchar_t **cmd_argv = NULL, **run_argv = NULL;
|
||||
int cmd_argc, run_argc = 0, base, i;
|
||||
|
||||
if (!__rt_get_run_argstart)
|
||||
return NULL;
|
||||
base = __rt_get_run_argstart();
|
||||
if (base < 0)
|
||||
return NULL;
|
||||
cmd_argv = run_command_line_to_argv_w(&cmd_argc);
|
||||
if (!cmd_argv || base >= cmd_argc)
|
||||
goto fail;
|
||||
for (i = base; i < cmd_argc; ++i) {
|
||||
wchar_t *copy;
|
||||
|
||||
if (_dowildcard && i > base && run_has_wildcard(cmd_argv[i])) {
|
||||
if (run_expand_wildcard_arg(cmd_argv[i], &run_argv, &run_argc))
|
||||
continue;
|
||||
}
|
||||
copy = dup_run_wstr(cmd_argv[i]);
|
||||
if (!copy || !append_run_warg(&run_argv, &run_argc, copy)) {
|
||||
free(copy);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
LocalFree(cmd_argv);
|
||||
*prun_argc = run_argc;
|
||||
return run_argv;
|
||||
fail:
|
||||
if (cmd_argv)
|
||||
LocalFree(cmd_argv);
|
||||
free_run_wargv(run_argv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef UNICODE
|
||||
static _TCHAR **dup_run_targv_from_wchar(int argc, wchar_t **argv)
|
||||
{
|
||||
int i;
|
||||
_TCHAR **copy = malloc(sizeof(*copy) * (argc + 1));
|
||||
|
||||
if (!copy)
|
||||
return NULL;
|
||||
for (i = 0; i < argc; ++i) {
|
||||
size_t len;
|
||||
|
||||
if (!argv[i]) {
|
||||
copy[i] = NULL;
|
||||
continue;
|
||||
}
|
||||
len = wcstombs(NULL, argv[i], 0);
|
||||
if ((size_t)-1 == len)
|
||||
goto fail;
|
||||
copy[i] = malloc(len + 1);
|
||||
if (!copy[i] || (size_t)-1 == wcstombs(copy[i], argv[i], len + 1))
|
||||
goto fail;
|
||||
}
|
||||
copy[argc] = NULL;
|
||||
return copy;
|
||||
fail:
|
||||
copy[i] = NULL;
|
||||
free_run_targv(copy);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void restore_run_targv(int ret, void *opaque)
|
||||
{
|
||||
run_targv_state *state = (run_targv_state *)opaque;
|
||||
|
||||
(void)ret;
|
||||
if (!state || !state->active)
|
||||
return;
|
||||
__argc = state->saved_argc;
|
||||
__targv = state->saved_argv;
|
||||
free_run_targv(state->run_argv);
|
||||
state->run_argv = NULL;
|
||||
state->active = 0;
|
||||
if (run_targv_tls == state)
|
||||
run_targv_tls = NULL;
|
||||
}
|
||||
|
||||
static void restore_run_targv_atexit(void)
|
||||
{
|
||||
restore_run_targv(0, run_targv_tls);
|
||||
}
|
||||
|
||||
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};
|
||||
int run_argc = argc;
|
||||
_TCHAR **env = run_get_tenviron();
|
||||
run_targv_state argv_state = { __argc, __targv, NULL, 0 };
|
||||
wchar_t **run_wargv = NULL;
|
||||
|
||||
__tgetmainargs(&__argc, &__targv, &env, _dowildcard, &start_info);
|
||||
/* may be wrong when tcc has received wildcards (*.c) */
|
||||
if (argc < __argc) {
|
||||
__targv += __argc - argc;
|
||||
__argc = argc;
|
||||
}
|
||||
run_wargv = build_run_wargv(&run_argc);
|
||||
if (run_wargv) {
|
||||
#ifdef UNICODE
|
||||
argv_state.run_argv = dup_run_targv_from_tchar(run_argc, run_wargv);
|
||||
#else
|
||||
__argc = argc;
|
||||
__targv = argv;
|
||||
get_tenviron(&env);
|
||||
argv_state.run_argv = dup_run_targv_from_wchar(run_argc, run_wargv);
|
||||
#endif
|
||||
free_run_wargv(run_wargv);
|
||||
}
|
||||
if (!argv_state.run_argv) {
|
||||
argv_state.run_argv = dup_run_targv_from_char(argc, argv);
|
||||
run_argc = argc;
|
||||
}
|
||||
if (!argv_state.run_argv)
|
||||
return 1;
|
||||
run_targv_tls = &argv_state;
|
||||
if (__tcc_atexit(restore_run_targv_atexit))
|
||||
goto fail;
|
||||
__argc = run_argc;
|
||||
__targv = argv_state.run_argv;
|
||||
argv_state.active = 1;
|
||||
#if defined __i386__ || defined __x86_64__
|
||||
_controlfp(_PC_53, _MCW_PC);
|
||||
#endif
|
||||
@ -142,8 +451,12 @@ int _runtmain(int argc, /* as tcc passed in */ char **argv)
|
||||
run_ctors(__argc, __targv, env);
|
||||
ret = _tmain(__argc, __targv, env);
|
||||
run_dtors();
|
||||
__run_on_exit(ret);
|
||||
__tcc_run_on_exit(ret);
|
||||
return ret;
|
||||
fail:
|
||||
run_targv_tls = NULL;
|
||||
free_run_targv(argv_state.run_argv);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// =============================================
|
||||
|
||||
24
win32/lib/runmain-arm64.S
Normal file
24
win32/lib/runmain-arm64.S
Normal file
@ -0,0 +1,24 @@
|
||||
#ifdef __leading_underscore
|
||||
# define _(s) _##s
|
||||
#else
|
||||
# define _(s) s
|
||||
#endif
|
||||
|
||||
.text
|
||||
.p2align 2
|
||||
|
||||
.global _(__run_on_exit)
|
||||
_(__run_on_exit):
|
||||
b _(__tcc_run_on_exit)
|
||||
|
||||
.global _(on_exit)
|
||||
_(on_exit):
|
||||
b _(__tcc_on_exit)
|
||||
|
||||
.global _(atexit)
|
||||
_(atexit):
|
||||
b _(__tcc_atexit)
|
||||
|
||||
.global _(exit)
|
||||
_(exit):
|
||||
b _(__tcc_exit)
|
||||
71
win32/lib/runrt.c
Normal file
71
win32/lib/runrt.c
Normal file
@ -0,0 +1,71 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __leading_underscore
|
||||
# define _(s) s
|
||||
#else
|
||||
# define _(s) _##s
|
||||
#endif
|
||||
|
||||
extern void (*_(_fini_array_start)[]) (void);
|
||||
extern void (*_(_fini_array_end)[]) (void);
|
||||
|
||||
typedef struct rt_frame {
|
||||
void *ip, *fp, *sp;
|
||||
} rt_frame;
|
||||
|
||||
__attribute__((weak, noreturn)) void __rt_exit(rt_frame *, int);
|
||||
|
||||
static void *rt_exitfunc[32];
|
||||
static void *rt_exitarg[32];
|
||||
static int __rt_nr_exit;
|
||||
|
||||
static void run_dtors(void)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (&_(_fini_array_end)[i] != _(_fini_array_start))
|
||||
(*_(_fini_array_end)[--i])();
|
||||
}
|
||||
|
||||
void __tcc_run_on_exit(int ret)
|
||||
{
|
||||
int n = __rt_nr_exit;
|
||||
|
||||
while (n)
|
||||
--n, ((void (*)(int, void *))rt_exitfunc[n])(ret, rt_exitarg[n]);
|
||||
}
|
||||
|
||||
int __tcc_on_exit(void *function, void *arg)
|
||||
{
|
||||
int n = __rt_nr_exit;
|
||||
|
||||
if (n < 32) {
|
||||
rt_exitfunc[n] = function;
|
||||
rt_exitarg[n] = arg;
|
||||
__rt_nr_exit = n + 1;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int __tcc_atexit(void (*function)(void))
|
||||
{
|
||||
return __tcc_on_exit(function, 0);
|
||||
}
|
||||
|
||||
void __attribute__((noreturn)) __tcc_exit(int code)
|
||||
{
|
||||
rt_frame f;
|
||||
|
||||
run_dtors();
|
||||
__tcc_run_on_exit(code);
|
||||
if (__rt_exit) {
|
||||
f.fp = 0;
|
||||
f.ip = __tcc_exit;
|
||||
f.sp = 0;
|
||||
__rt_exit(&f, code);
|
||||
}
|
||||
fflush(NULL);
|
||||
_exit(code);
|
||||
}
|
||||
@ -5,7 +5,6 @@
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define __UNKNOWN_APP 0
|
||||
#define __CONSOLE_APP 1
|
||||
#define __GUI_APP 2
|
||||
@ -27,10 +26,54 @@ int APIENTRY wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int);
|
||||
|
||||
typedef struct { int newmode; } _startupinfo;
|
||||
int __cdecl __tgetmainargs(int *pargc, _TCHAR ***pargv, _TCHAR ***penv, int globb, _startupinfo*);
|
||||
int __cdecl __getmainargs(int *pargc, char ***pargv, char ***penv, int globb, _startupinfo*);
|
||||
int __cdecl __wgetmainargs(int *pargc, wchar_t ***pargv, wchar_t ***penv, int globb, _startupinfo*);
|
||||
int __cdecl get_tenviron(_TCHAR ***penv);
|
||||
__attribute__((weak)) int __cdecl __rt_get_run_argstart(void);
|
||||
|
||||
#include "crtinit.c"
|
||||
|
||||
static int select_run_arg_start_t(int base, const _TCHAR *arg0, int full_argc, _TCHAR **full_argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (base < 0 || base > full_argc)
|
||||
return -1;
|
||||
if (!arg0)
|
||||
return base;
|
||||
for (i = base; i < full_argc; ++i) {
|
||||
if (full_argv[i] && 0 == _tcscmp(full_argv[i], arg0))
|
||||
return i;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
static int find_run_arg_slice(int globb, int *pstart, int *prun_argc)
|
||||
{
|
||||
int literal_argc, full_argc, base, start, ret = 0;
|
||||
_TCHAR **literal_argv = NULL, **full_argv = NULL;
|
||||
_startupinfo start_info = {0};
|
||||
|
||||
if (!__rt_get_run_argstart)
|
||||
return 0;
|
||||
base = __rt_get_run_argstart();
|
||||
if (base < 0)
|
||||
return 0;
|
||||
if (__tgetmainargs(&literal_argc, &literal_argv, NULL, 0, &start_info))
|
||||
return 0;
|
||||
if (base >= literal_argc)
|
||||
return 0;
|
||||
if (__tgetmainargs(&full_argc, &full_argv, NULL, globb, &start_info))
|
||||
return 0;
|
||||
start = select_run_arg_start_t(base, literal_argv[base], full_argc, full_argv);
|
||||
if (start < 0 || start > full_argc)
|
||||
return 0;
|
||||
*pstart = start;
|
||||
*prun_argc = full_argc - start;
|
||||
ret = 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int go_winmain(TCHAR *arg1)
|
||||
{
|
||||
STARTUPINFO si;
|
||||
@ -78,14 +121,42 @@ int _twinstart(void)
|
||||
|
||||
int _runtwinmain(int argc, /* as tcc passed in */ char **argv)
|
||||
{
|
||||
int saved_argc = __argc;
|
||||
_TCHAR **saved_argv = __targv;
|
||||
int ret;
|
||||
int run_arg_start = -1;
|
||||
#ifdef UNICODE
|
||||
_startupinfo start_info = {0};
|
||||
__tgetmainargs(&__argc, &__targv, NULL, 0, &start_info);
|
||||
/* may be wrong when tcc has received wildcards (*.c) */
|
||||
if (argc < __argc)
|
||||
__targv += __argc - argc, __argc = argc;
|
||||
{
|
||||
int full_argc;
|
||||
_TCHAR **full_argv = NULL;
|
||||
_startupinfo start_info = {0};
|
||||
|
||||
if (find_run_arg_slice(0, &run_arg_start, &__argc)
|
||||
&& !__tgetmainargs(&full_argc, &full_argv, NULL, 0, &start_info)
|
||||
&& run_arg_start <= full_argc)
|
||||
__targv = full_argv + run_arg_start;
|
||||
else {
|
||||
__tgetmainargs(&__argc, &__targv, NULL, 0, &start_info);
|
||||
if (argc < __argc)
|
||||
__targv += __argc - argc, __argc = argc;
|
||||
}
|
||||
}
|
||||
#else
|
||||
__argc = argc, __targv = argv;
|
||||
{
|
||||
int full_argc;
|
||||
_TCHAR **full_argv = NULL;
|
||||
_startupinfo start_info = {0};
|
||||
|
||||
if (find_run_arg_slice(0, &run_arg_start, &__argc)
|
||||
&& !__tgetmainargs(&full_argc, &full_argv, NULL, 0, &start_info)
|
||||
&& run_arg_start <= full_argc)
|
||||
__targv = full_argv + run_arg_start;
|
||||
else
|
||||
__argc = argc, __targv = argv;
|
||||
}
|
||||
#endif
|
||||
return go_winmain(__argc > 1 ? __targv[1] : NULL);
|
||||
ret = go_winmain(__argc > 1 ? __targv[1] : NULL);
|
||||
__argc = saved_argc;
|
||||
__targv = saved_argv;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -3,9 +3,30 @@
|
||||
.global arm64_call_with_dregs
|
||||
|
||||
arm64_call_with_dregs:
|
||||
stp x29, x30, [sp, -32]!
|
||||
stp x19, x20, [sp, 16]
|
||||
mov x29, sp
|
||||
.seh_proc arm64_call_with_dregs
|
||||
sub sp, sp, 80
|
||||
.seh_stackalloc 80
|
||||
str x30, [sp, 0]
|
||||
.seh_save_reg x30, 0
|
||||
str x19, [sp, 8]
|
||||
.seh_save_reg x19, 8
|
||||
str d8, [sp, 16]
|
||||
.seh_save_freg d8, 16
|
||||
str d9, [sp, 24]
|
||||
.seh_save_freg d9, 24
|
||||
str d10, [sp, 32]
|
||||
.seh_save_freg d10, 32
|
||||
str d11, [sp, 40]
|
||||
.seh_save_freg d11, 40
|
||||
str d12, [sp, 48]
|
||||
.seh_save_freg d12, 48
|
||||
str d13, [sp, 56]
|
||||
.seh_save_freg d13, 56
|
||||
str d14, [sp, 64]
|
||||
.seh_save_freg d14, 64
|
||||
str d15, [sp, 72]
|
||||
.seh_save_freg d15, 72
|
||||
.seh_endprologue
|
||||
mov x19, x1
|
||||
|
||||
ldr d8, [x0, 0]
|
||||
@ -29,6 +50,16 @@ arm64_call_with_dregs:
|
||||
str d14, [x19, 48]
|
||||
str d15, [x19, 56]
|
||||
|
||||
ldp x19, x20, [sp, 16]
|
||||
ldp x29, x30, [sp], 32
|
||||
ldr d8, [sp, 16]
|
||||
ldr d9, [sp, 24]
|
||||
ldr d10, [sp, 32]
|
||||
ldr d11, [sp, 40]
|
||||
ldr d12, [sp, 48]
|
||||
ldr d13, [sp, 56]
|
||||
ldr d14, [sp, 64]
|
||||
ldr d15, [sp, 72]
|
||||
ldr x19, [sp, 8]
|
||||
ldr x30, [sp, 0]
|
||||
add sp, sp, 80
|
||||
ret
|
||||
.seh_endproc
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int _dowildcard = 1;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
12
win32/test_run_env.c
Normal file
12
win32/test_run_env.c
Normal file
@ -0,0 +1,12 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv, char **envp)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
if (!envp || !envp[0]) {
|
||||
fputs("missing envp\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
14
win32/test_run_wargv.c
Normal file
14
win32/test_run_wargv.c
Normal file
@ -0,0 +1,14 @@
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
|
||||
int _dowildcard = 1;
|
||||
|
||||
int wmain(int argc, wchar_t **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("argc=%d\n", argc);
|
||||
for (i = 1; i < argc; ++i)
|
||||
printf("arg%d=<%ls>\n", i, argv[i]);
|
||||
return 0;
|
||||
}
|
||||
4
win32/test_run_wargv.ref
Normal file
4
win32/test_run_wargv.ref
Normal file
@ -0,0 +1,4 @@
|
||||
argc=4
|
||||
arg1=<alpha>
|
||||
arg2=<two words>
|
||||
arg3=<beta>
|
||||
13
win32/test_run_wenv.c
Normal file
13
win32/test_run_wenv.c
Normal file
@ -0,0 +1,13 @@
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
|
||||
int wmain(int argc, wchar_t **argv, wchar_t **envp)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
if (!envp || !envp[0]) {
|
||||
fputws(L"missing envp\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user