Compare commits

..

5 Commits

Author SHA1 Message Date
herman ten brugge
34eed88a70 Small updates
Some checks are pending
build and test / test-x86_64-linux (push) Waiting to run
build and test / test-x86_64-osx (push) Waiting to run
build and test / test-aarch64-osx (push) Waiting to run
build and test / test-x86_64-win32 (push) Waiting to run
build and test / test-i386-win32 (push) Waiting to run
build and test / test-armv7-linux (push) Waiting to run
build and test / test-aarch64-linux (push) Waiting to run
build and test / test-riscv64-linux (push) Waiting to run
Allow 'make speedtest' in tests directory
Fix compiler warning tccpp.c
2025-12-17 20:22:08 +01:00
herman ten brugge
3c18df610d Fix clang macos 15 bug on arm64 in tests/tcctest.c 2025-12-17 19:54:22 +01:00
herman ten brugge
f3de8b5307 Use macos 15 in build.yml 2025-12-17 18:21:01 +01:00
herman ten brugge
8569427459 Move -run -nostdlib code to lib directory
tcc.h, arm-gen.c, arm64-gen.c, i386-gen.c, riscv64-gen.c, x86_64-gen.c:
- remove old code

tccrun.c:
- update to use lib/run_nostdlib.c

Makefile, lib/Makefile, lib/run_nostdlib.c:
- new code

tests/nostdlib_test.c:
- testcode
2025-12-15 14:45:11 +01:00
Stefan
829c848520 tccpp.c: Configurable integer literal overflow handling
Add the define TCC_CUT_ON_INTEGER_LITERAL_OVERFLOW to use the most
significant digits of an integer literal before its parsing led to an
overflow.

When compiling tcc with another compiler, which is not able to handle
64 bit arithmetic, it is beneficial to use the last value before an
integer literal overflows. Parsing 0x1000000000000000 then results in
0x10000000. The mescc from GNU Mes is able to compile a first tcc on a
32 bit system without 64 bit arithmetic. This change allows this first
tcc to compile a second tcc with complete 64 bit arithmetic.
2025-12-13 18:53:15 +01:00
15 changed files with 286 additions and 119 deletions

View File

@ -14,7 +14,7 @@ jobs:
run: ./configure && make && make test -k
test-x86_64-osx:
runs-on: macos-13
runs-on: macos-15-intel
timeout-minutes: 2
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
@ -22,7 +22,7 @@ jobs:
run: ./configure && make && make test -k
test-aarch64-osx:
runs-on: macos-14
runs-on: macos-15
timeout-minutes: 2
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0

View File

@ -367,7 +367,7 @@ IR = $(IM) mkdir -p $2 && cp -r $1/. $2
IM = @echo "-> $2 : $1" ;
BINCHECK = $(if $(wildcard $(PROGS) *-tcc$(EXESUF)),,@echo "Makefile: nothing found to install" && exit 1)
EXTRA_O = runmain.o bt-exe.o bt-dll.o bt-log.o bcheck.o
EXTRA_O = runmain.o run_nostdlib.o bt-exe.o bt-dll.o bt-log.o bcheck.o
# install progs & libs
install-unx:

View File

@ -1396,20 +1396,6 @@ void gfunc_call(int nb_args)
float_abi = def_float_abi;
}
void tcc_run_start(int (*prog_main)(int, char **, char **), int cnt, char **var)
{
#ifdef __arm__
void *sp;
__asm__("sub sp, sp, %1\n"
"\tmov %0, sp"
: "=r" (sp)
: "r" ((((size_t) cnt + 1) & -2) * sizeof(char *)));
memcpy(sp, var, cnt * sizeof(char *));
__asm__("mov pc, %0" : : "r" (prog_main));
#endif
}
/* generate function prolog of type 't' */
void gfunc_prolog(Sym *func_sym)
{

View File

@ -1167,25 +1167,6 @@ ST_FUNC void gfunc_call(int nb_args)
tcc_free(t);
}
void tcc_run_start(int (*prog_main)(int, char **, char **), int cnt, char **var)
{
#if defined(__aarch64__)
#if defined(__TINYC__)
// FIXME: immplement arm64 assembler
fprintf(stderr, "tcc -nostdlib -run not implement for arm64\n");
#else
void *sp;
__asm__("sub sp, sp, %1\n"
"\tmov %0, sp"
: "=r" (sp)
: "r" ((((size_t) cnt + 1) & -2) * sizeof(char *)));
memcpy(sp, var, cnt * sizeof(char *));
__asm__("br %0" : : "r" (prog_main));
#endif
#endif
}
static unsigned long arm64_func_va_list_stack;
static int arm64_func_va_list_gr_offs;
static int arm64_func_va_list_vr_offs;

View File

@ -1,6 +1,6 @@
#include <tcclib.h>
int fib(n)
int fib(int n)
{
if (n <= 2)
return 1;
@ -18,6 +18,6 @@ int main(int argc, char **argv)
}
n = atoi(argv[1]);
printf("fib(%d) = %d\n", n, fib(n, 2));
printf("fib(%d) = %d\n", n, fib(n));
return 0;
}

View File

@ -504,24 +504,6 @@ ST_FUNC void gfunc_call(int nb_args)
vtop--;
}
void tcc_run_start(int (*prog_main)(int, char **, char **), int cnt, char **var)
{
#ifdef __i386__
#ifdef TCC_TARGET_PE
fprintf(stderr, "tcc -nostdlib -run not implement for TCC_TARGET_PE\n");
#else
void *sp;
__asm("sub %1, %%esp\n"
"\tmov %%esp, %0"
: "=r" (sp)
: "r" ((((size_t) cnt + 1) & -2) * sizeof(char *)));
memcpy(sp, var, cnt * sizeof(char *));
__asm__("jmp *%0" : : "r" (prog_main));
#endif
#endif
}
#ifdef TCC_TARGET_PE
#define FUNC_PROLOG_SIZE (10 + USE_EBX)
#else

View File

@ -50,13 +50,13 @@ Nat = $(if $X,no,)
Cbt = $(Nat)$(subst yes,,$(CONFIG_backtrace))
Cbc = $(Cbt)$(subst yes,,$(CONFIG_bcheck))
$(Nat)COMMON_O += runmain.o tcov.o
$(Nat)COMMON_O += runmain.o run_nostdlib.o tcov.o
$(Cbt)COMMON_O += bt-exe.o bt-log.o
$(Cbt)WIN_O += bt-dll.o
$(Cbc)COMMON_O += bcheck.o
# not in libtcc1.a
EXTRA_O = runmain.o bt-exe.o bt-dll.o bt-log.o bcheck.o
EXTRA_O = runmain.o run_nostdlib.o bt-exe.o bt-dll.o bt-log.o bcheck.o
OBJ-i386 = $(I386_O) $(LIN_O)
OBJ-x86_64 = $(X86_64_O) $(LIN_O)

94
lib/run_nostdlib.c Normal file
View File

@ -0,0 +1,94 @@
/* ------------------------------------------------------------- */
/* support for run_nostdlib() */
// FIXME: implement arm64 assembler
#if defined(__aarch64__)
#define USE_ARM64_ASM
static void *alloca_arm64(unsigned long);
__asm__(
#ifdef __leading_underscore
"_alloca_arm64:\n\t"
#else
"alloca_arm64:\n\t"
#endif
".int 0x91003c00\n\t" // add x0, x0, #15
".int 0x927cec00\n\t" // and x0, x0, #-16
".int 0xcb2063ff\n\t" // sub sp, sp, x0
".int 0x910003e0\n\t" // mov x0, sp
".int 0xd65f03c0" // ret
);
static void goto_arm64(void *start);
__asm__(
#ifdef __leading_underscore
"_goto_arm64:\n\t"
#else
"goto_arm64:\n\t"
#endif
".int 0xd61f0000" // br x0
);
#endif
void _run_nostdlib(void *start, int argc, char **argv, char **envp)
{
#if !defined(_WIN32)
int i, n = 1;
unsigned long l;
char **sp, **e = envp;
if (envp)
while (*e++)
n++;
l = (((unsigned long) argc + n + 2 + 1) & -2) * sizeof(char *);
/* nostdlib so avoid alloca() */
/* also code below will be removed because compiler detects dead store */
#if defined(USE_ARM64_ASM)
sp = alloca_arm64(l);
#else
#if defined(__aarch64__)
__asm__("sub sp, sp, %1\n"
"\tmov %0, sp"
#elif defined(__arm__)
__asm__("sub sp, sp, %1\n"
"\tmov %0, sp"
#elif defined(__i386__)
__asm("sub %1, %%esp\n"
"\tmov %%esp, %0"
#elif defined(__riscv)
__asm__("sub sp, sp, %1\n"
"\tmv %0, sp"
#elif defined(__x86_64__)
__asm__("subq %1, %%rsp\n"
"\tmovq %%rsp, %0"
#endif
: "=r" (sp)
: "r" (l));
#endif
/* create sysv memory layout: argc, argv[], NULL, envp[], NULL */
sp[0] = (char *) (__SIZE_TYPE__) argc;
for (i = 0; i < argc; i++)
sp[i + 1] = argv[i];
sp[argc + 1] = (char *) 0;
if (envp)
for (i = 0; i < n; i++)
sp[i + argc + 2] = envp[i];
else
sp[argc + 2] = (char *) 0;
#endif
/* goto *start does not work for clang. Use assembly. */
#if defined(USE_ARM64_ASM)
goto_arm64(start);
#else
#if defined(__aarch64__)
__asm__("br %0" : : "r" (start));
#elif defined(__arm__)
__asm__("mov pc, %0" : : "r" (start));
#elif defined(__i386__)
__asm__("jmp *%0" : : "r" (start));
#elif defined(__riscv)
__asm__("jalr %0" : : "r" (start));
#elif defined(__x86_64__)
__asm__("jmp *%0" : : "r" (start));
#endif
#endif
}

View File

@ -769,20 +769,6 @@ done:
tcc_free(info);
}
void tcc_run_start(int (*prog_main)(int, char **, char **), int cnt, char **var)
{
#ifdef __riscv
void *sp;
__asm__("sub sp, sp, %1\n"
"\tmv %0, sp"
: "=r" (sp)
: "r" ((((size_t) cnt + 1) & -2) * sizeof(char *)));
memcpy(sp, var, cnt * sizeof(char *));
__asm__("jalr %0" : : "r" (prog_main));
#endif
}
static int func_sub_sp_offset, num_va_regs, func_va_list_ofs;
ST_FUNC void gfunc_prolog(Sym *func_sym)

1
tcc.h
View File

@ -1797,7 +1797,6 @@ ST_FUNC const char *dlerror(void);
ST_FUNC void *dlsym(void *handle, const char *symbol);
#endif
ST_FUNC void tcc_run_free(TCCState *s1);
ST_FUNC void tcc_run_start(int (*prog_main)(int, char **, char **), int cnt, char **var);
#endif
/* ------------ tcctools.c ----------------- */

23
tccpp.c
View File

@ -2550,7 +2550,7 @@ static void parse_number(const char *p)
}
}
} else {
unsigned long long n, n1;
unsigned long long n = 0, n1 = 0;
int lcount, ucount, ov = 0;
const char *p1;
@ -2561,7 +2561,6 @@ static void parse_number(const char *p)
b = 8;
q++;
}
n = 0;
while(1) {
t = *q++;
/* no need for checks except for base 10 / 8 errors */
@ -2575,13 +2574,23 @@ static void parse_number(const char *p)
t = t - '0';
if (t >= b)
tcc_error("invalid digit");
n1 = n;
n = n * b + t;
/* detect overflow */
if (n1 >= 0x1000000000000000ULL && n / b != n1)
ov = 1;
if (!ov) {
/* detect overflow */
if (n1 >= 0x1000000000000000ULL && n / b != n1)
ov = 1;
else
n1 = n;
}
}
#ifdef TCC_CUT_ON_INTEGER_LITERAL_OVERFLOW
/* On integer literal overflow use the most significant digits before
the overflow happened. Effectively this cuts the 0x1000000000000000
from above down to 0x10000000 and allows to bootstrap tcc with 32 bit
arithmetic. */
if (ov)
n = n1;
#endif
/* Determine the characteristics (unsigned and/or 64bit) the type of
the constant must have according to the constant suffix(es) */
lcount = ucount = 0;

View File

@ -206,9 +206,10 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
const char *top_sym;
jmp_buf main_jb;
#if defined(__APPLE__) || defined(__FreeBSD__)
char **envp = NULL;
#elif defined(__OpenBSD__) || defined(__NetBSD__)
#if defined(__APPLE__)
extern char ***_NSGetEnviron(void);
char **envp = *_NSGetEnviron();
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
extern char **environ;
char **envp = environ;
#else
@ -221,6 +222,7 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
tcc_add_symbol(s1, "__rt_exit", rt_exit);
if (s1->nostdlib) {
tcc_add_support(s1, "run_nostdlib.o");
s1->run_main = top_sym = s1->elf_entryname ? s1->elf_entryname : "_start";
} else {
tcc_add_support(s1, "runmain.o");
@ -251,24 +253,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) {
if (s1->nostdlib) {
int n = 1;
char **p, **e = envp;
void (*run_nostdlib)(void *start, int argc, char **argv, char **envp);
/* create sysv memory layout: argc, argv[], NULL, envp[], NULL */
if (envp)
while (*e++)
n++;
p = tcc_malloc((argc + n + 2) * sizeof(char *));
p[0] = (char *) (size_t) argc;
memcpy(p + 1, argv, argc * sizeof(char *));
p[argc + 1] = NULL;
if (envp)
memcpy(p + argc + 2, envp, n * sizeof(char *));
else
p[argc + 2] = NULL;
/* Probably never returns */
tcc_run_start(prog_main, argc + n + 2, p);
tcc_free(p);
run_nostdlib = (void *)get_sym_addr(s1, "_run_nostdlib", 1, 1);
if ((addr_t)-1 == (addr_t)run_nostdlib)
return -1;
run_nostdlib(prog_main, argc, argv, envp); /* never returns */
}
else
ret = prog_main(argc, argv, envp);

155
tests/nostdlib_test.c Executable file
View File

@ -0,0 +1,155 @@
#!/usr/local/bin/tcc -run -nostdlib
// Not working on windows and apple because of different API.
#include <unistd.h>
#include <sys/syscall.h>
#if defined __x86_64__
__asm__ ("syscall:\n\t"
"mov %rdi,%rax\n\t"
"mov %rsi,%rdi\n\t"
"mov %rdx,%rsi\n\t"
"mov %rcx,%rdx\n\t"
"mov %r8,%r10\n\t"
"mov %r9,%r8\n\t"
"mov 0x8(%rsp),%r9\n\t"
"syscall\n\t"
"ret");
__asm__ (".global _start\n\t"
"_start:\n\t"
"mov 0(%rsp), %rdi\n\t"
"lea 8(%rsp), %rsi\n\t"
"jmp print");
#elif defined __i386__
__asm__ ("syscall:\n\t"
"push %ebp\n\t"
"push %edi\n\t"
"push %esi\n\t"
"push %ebx\n\t"
"mov 0x2c(%esp),%ebp\n\t"
"mov 0x28(%esp),%edi\n\t"
"mov 0x24(%esp),%esi\n\t"
"mov 0x20(%esp),%edx\n\t"
"mov 0x1c(%esp),%ecx\n\t"
"mov 0x18(%esp),%ebx\n\t"
"mov 0x14(%esp),%eax\n\t"
// "call *%gs:0x10\n\t"
".byte 0x65,0xff,0x15,0x10,0x00,0x00,0x00\n\t"
"pop %ebx\n\t"
"pop %esi\n\t"
"pop %edi\n\t"
"pop %ebp\n\t"
"ret");
__asm__ (".global _start\n\t"
"_start:\n\t"
"pop %esi\n\t"
"mov %esp, %ecx\n\t"
"and $0xfffffff0,%esp\n\t"
"push %ecx\n\t"
"push %esi\n\t"
"call print");
#elif defined __arm__
__asm__ ("syscall:\n\t"
"mov r12, sp\n\t"
"push {r4, r5, r6, r7}\n\t"
"mov r7, r0\n\t"
"mov r0, r1\n\t"
"mov r1, r2\n\t"
"mov r2, r3\n\t"
"ldm r12, {r3, r4, r5, r6}\n\t"
"svc 0x00000000\n\t"
"pop {r4, r5, r6, r7}\n\t"
"mov pc, lr");
__asm__ (".global _start\n\t"
"_start:\n\t"
"pop {r0}\n\t"
"mov r1, sp\n\t"
"bl print");
#elif defined __aarch64__
__asm__ ("syscall:\n\t"
".int 0x2a0003e8\n\t" // mov w8, w0
".int 0xaa0103e0\n\t" // x0, x1
".int 0xaa0203e1\n\t" // mov x1, x2
".int 0xaa0303e2\n\t" // mov x2, x3
".int 0xaa0403e3\n\t" // mov x3, x4
".int 0xaa0503e4\n\t" // mov x4, x5
".int 0xaa0603e5\n\t" // mov x5, x6
".int 0xaa0703e6\n\t" // mov x6, x7
".int 0xd4000001\n\t" // svc #0x0
".int 0xd65f03c0"); // ret
__asm__ (".global _start\n\t"
"_start:\n\t"
".int 0xf94003e0\n\t" // ldr x0, [sp]
".int 0x910023e1\n\t" // add x1, sp, #08
".reloc .,R_AARCH64_CALL26,print\n\t"
".int 0x94000000"); // bl print
#elif defined __riscv
__asm__ ("syscall:\n\t"
"mv t1,a0\n\t"
"mv a0,a1\n\t"
"mv a1,a2\n\t"
"mv a2,a3\n\t"
"mv a3,a4\n\t"
"mv a4,a5\n\t"
"mv a5,a6\n\t"
"mv a6,a7\n\t"
"mv a7,t1\n\t"
"ecall\n\t"
"ret");
__asm__ (".global _start\n\t"
"_start:\n\t"
"ld a0,0(sp)\n\t"
"addi a1,sp,8\n\t"
"jal print");
#endif
unsigned long strlen(const char *s)
{
unsigned long len = 0;
while (*s++)
len++;
return len;
}
static void pr_num(int num)
{
char val[20], *p = &val[20];
*--p = '\0';
do {
int a = num, b = 0;
while (a >= 10) {
a -= 10;
b++;
}
*--p = a + '0';
num = b;
} while (num);
syscall(SYS_write, 1, p, strlen(p));
}
static void pr_str(int n, char *s)
{
pr_num(n);
syscall(SYS_write, 1, ": ", 2);
syscall(SYS_write, 1, s, strlen(s));
syscall(SYS_write, 1, "\n", 1);
}
void print(int argc, char **argv) {
int i;
char **envp = &argv[argc + 1];
syscall(SYS_write, 1, "argc: ", 6);
pr_num(argc);
syscall(SYS_write, 1, "\n", 1);
syscall(SYS_write, 1, "argv[]\n", 7);
for (i = 0; i < argc; i++)
pr_str(i, argv[i]);
syscall(SYS_write, 1, "envp[]\n", 7);
i = 0;
while (*envp)
pr_str(i++, *envp++);
syscall(SYS_exit, 0);
}

View File

@ -1173,6 +1173,10 @@ void char_short_test()
the presence of undefined behaviour (like __csf is). */
var1 = csf(unsigned char,0x89898989);
var4 = csf(signed char,0xabababab);
#ifdef __clang__
/* on macos 15 arm64 this prints -1987475063 instead of 137 */
var1 &= 0xff;
#endif
printf("promote char/short funcret %d "LONG_LONG_FORMAT"\n", var1, var4);
printf("promote char/short fumcret VA %d %d %d %d\n",
csf(unsigned short,0xcdcdcdcd),

View File

@ -933,11 +933,6 @@ void gfunc_call(int nb_args)
vtop--;
}
void tcc_run_start(int (*prog_main)(int, char **, char **), int cnt, char **var)
{
fprintf(stderr, "tcc -nostdlib -run not implement for TCC_TARGET_PE\n");
}
#define FUNC_PROLOG_SIZE 11
/* generate function prolog of type 't' */
@ -1438,20 +1433,6 @@ void gfunc_call(int nb_args)
vtop--;
}
void tcc_run_start(int (*prog_main)(int, char **, char **), int cnt, char **var)
{
#ifdef __x86_64__
void *sp;
__asm__("subq %1, %%rsp\n"
"\tmovq %%rsp, %0"
: "=r" (sp)
: "r" ((((size_t) cnt + 1) & -2) * sizeof(char *)));
memcpy(sp, var, cnt * sizeof(char *));
__asm__("jmp *%0" : : "r" (prog_main));
#endif
}
#define FUNC_PROLOG_SIZE 11
static void push_arg_reg(int i) {