From 8569427459e88d6df704e6525f27d5707fe03c97 Mon Sep 17 00:00:00 2001 From: herman ten brugge Date: Mon, 15 Dec 2025 14:45:11 +0100 Subject: [PATCH] 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 --- Makefile | 2 +- arm-gen.c | 14 ---- arm64-gen.c | 19 ------ i386-gen.c | 18 ----- lib/Makefile | 4 +- lib/run_nostdlib.c | 94 +++++++++++++++++++++++++ riscv64-gen.c | 14 ---- tcc.h | 1 - tccrun.c | 30 +++----- tests/nostdlib_test.c | 155 ++++++++++++++++++++++++++++++++++++++++++ x86_64-gen.c | 19 ------ 11 files changed, 262 insertions(+), 108 deletions(-) create mode 100644 lib/run_nostdlib.c create mode 100755 tests/nostdlib_test.c diff --git a/Makefile b/Makefile index b5427d7f..981eed26 100644 --- a/Makefile +++ b/Makefile @@ -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: diff --git a/arm-gen.c b/arm-gen.c index df5a3452..81fa185a 100644 --- a/arm-gen.c +++ b/arm-gen.c @@ -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) { diff --git a/arm64-gen.c b/arm64-gen.c index ab552893..03ae56c3 100644 --- a/arm64-gen.c +++ b/arm64-gen.c @@ -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; diff --git a/i386-gen.c b/i386-gen.c index d6a37a9a..c8d8af53 100644 --- a/i386-gen.c +++ b/i386-gen.c @@ -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 diff --git a/lib/Makefile b/lib/Makefile index 942add92..b7c2770a 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -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) diff --git a/lib/run_nostdlib.c b/lib/run_nostdlib.c new file mode 100644 index 00000000..91a7b043 --- /dev/null +++ b/lib/run_nostdlib.c @@ -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 +} diff --git a/riscv64-gen.c b/riscv64-gen.c index 75329058..e03d6e42 100644 --- a/riscv64-gen.c +++ b/riscv64-gen.c @@ -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) diff --git a/tcc.h b/tcc.h index 058507fe..1c2f6949 100644 --- a/tcc.h +++ b/tcc.h @@ -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 ----------------- */ diff --git a/tccrun.c b/tccrun.c index aab3e40d..1fbbf6d2 100644 --- a/tccrun.c +++ b/tccrun.c @@ -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); diff --git a/tests/nostdlib_test.c b/tests/nostdlib_test.c new file mode 100755 index 00000000..7c7f982f --- /dev/null +++ b/tests/nostdlib_test.c @@ -0,0 +1,155 @@ +#!/usr/local/bin/tcc -run -nostdlib + +// Not working on windows and apple because of different API. + +#include +#include +#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); +} diff --git a/x86_64-gen.c b/x86_64-gen.c index 37832672..0e63e685 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -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) {