Allow -nostdlib -run
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

The -run option did not support -nostdlib correctly.
The argc/argc/envp are now passed on stack according to sysv.

This implementation does not work for TCC_TARGET_PE.
Also arm64 does not work when running tcc compiled with itself.
This is because arm64 assembly is not implemented yet.

The following test code is used to check the code:

  #include <unistd.h>
  #include <sys/syscall.h>
  void _start() {
    syscall(SYS_write, 1, "hello world\n", 12);
    syscall(SYS_exit, 0);
  }

Run this with:
./tcc -nostdlib -lc -run a.c
make tcc_c
./tcc_c -nostdlib -lc -run a.c
This commit is contained in:
herman ten brugge 2025-11-17 14:00:15 +01:00
parent d9ec17d334
commit c52b96cf85
7 changed files with 108 additions and 2 deletions

View File

@ -1396,6 +1396,20 @@ 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,6 +1167,25 @@ 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,6 +504,24 @@ 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

@ -769,6 +769,20 @@ 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,6 +1797,7 @@ 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

@ -249,8 +249,30 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
fflush(stderr);
ret = tcc_setjmp(s1, main_jb, tcc_get_symbol(s1, top_sym));
if (0 == ret)
ret = prog_main(argc, argv, envp);
if (0 == ret) {
if (s1->nostdlib) {
int n = 1;
char **p, **e = 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);
}
else
ret = prog_main(argc, argv, envp);
}
else if (RT_EXIT_ZERO == ret)
ret = 0;

View File

@ -933,6 +933,10 @@ 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
@ -1434,6 +1438,20 @@ 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) {