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
This commit is contained in:
herman ten brugge 2025-12-15 14:45:11 +01:00
parent 829c848520
commit 8569427459
11 changed files with 262 additions and 108 deletions

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

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

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

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