LIBTCCAPI tcc_relocate(s) : REMOVED 2nd argument

removed second argument for tcc_relocate(s). previous
'TCC_RELOCATE_AUTO' is now default and only behavior.

Rationale:
  In the past, the option to compile into memory provided by the
  user was introduced because only one TCCState could exist at a time.

  This is no longer a limitation.  As such it is also possible now to
  keep any number of compiled code snippets around together with their
  state in order to run them as needed.

- Also
  - LIBTCCAPI tcc_get_error_func/opaque() removed
  - tccrun/SELINUX: switch rx/rw mappings such that rx comes first
    (risc64-link.c:relocate_plt() does not like got < plt)
  - tcc_relocate_ex(): free local symbols and obsolete sections
    to reduce memory after tcc_relocate()
This commit is contained in:
grischka 2024-02-07 07:42:56 +01:00
parent a0ab99169e
commit b671fc0594
11 changed files with 224 additions and 184 deletions

14
configure vendored
View file

@ -56,6 +56,7 @@ build_cross=
# use CC/AR from environment when set # use CC/AR from environment when set
test -n "$CC" && cc="$CC" test -n "$CC" && cc="$CC"
test -n "$AR" && ar="$AR" test -n "$AR" && ar="$AR"
test -n "CFLAGS" && CFLAGS="-Wall -O2"
# find source path # find source path
source_path=${0%configure} source_path=${0%configure}
@ -399,14 +400,6 @@ if test "$mingw32" = "no"; then
default infodir "${sharedir}/info" default infodir "${sharedir}/info"
fi fi
# set default CFLAGS
default CFLAGS "-Wall -O2"
if test "$mingw32" = "yes" -a "$cc_name" = "gcc"; then
# avoid mingw dependencies such as 'libgcc_s_dw2-1.dll'
default LDFLAGS "-static"
fi
if test x"$show_help" = "xyes" ; then if test x"$show_help" = "xyes" ; then
show_help show_help
fi fi
@ -464,6 +457,11 @@ if test "$bigendian" = "yes" ; then
confvars="$confvars BIGENDIAN" confvars="$confvars BIGENDIAN"
fi fi
if test "$mingw32" = "yes" -a "$cc_name" = "gcc"; then
# avoid mingw dependencies such as 'libgcc_s_dw2-1.dll'
default LDFLAGS "-static"
fi
if test "$cpu" = "arm"; then if test "$cpu" = "arm"; then
if test "${triplet%eabihf}" != "$triplet" ; then if test "${triplet%eabihf}" != "$triplet" ; then
confvars="$confvars arm_eabihf arm_vfp" confvars="$confvars arm_eabihf arm_vfp"

View file

@ -249,7 +249,7 @@ ST_FUNC char *tcc_load_text(int fd)
#undef free #undef free
#undef realloc #undef realloc
static void *default_reallocator(void *ptr, size_t size) static void *default_reallocator(void *ptr, unsigned long size)
{ {
void *ptr1; void *ptr1;
if (size == 0) { if (size == 0) {
@ -275,18 +275,13 @@ static void libc_free(void *ptr)
#define realloc(p, s) use_tcc_realloc(p, s) #define realloc(p, s) use_tcc_realloc(p, s)
/* global so that every tcc_alloc()/tcc_free() call doesn't need to be changed */ /* global so that every tcc_alloc()/tcc_free() call doesn't need to be changed */
static TCCReallocFunc reallocator = default_reallocator; static void *(*reallocator)(void*, unsigned long) = default_reallocator;
LIBTCCAPI void tcc_set_realloc(TCCReallocFunc realloc) LIBTCCAPI void tcc_set_realloc(TCCReallocFunc *realloc)
{ {
reallocator = realloc; reallocator = realloc;
} }
LIBTCCAPI TCCReallocFunc tcc_get_realloc()
{
return reallocator;
}
/* in case MEM_DEBUG is #defined */ /* in case MEM_DEBUG is #defined */
#undef tcc_free #undef tcc_free
#undef tcc_malloc #undef tcc_malloc
@ -646,7 +641,7 @@ static void error1(int mode, const char *fmt, va_list ap)
} }
cstr_printf(&cs, mode == ERROR_WARN ? "warning: " : "error: "); cstr_printf(&cs, mode == ERROR_WARN ? "warning: " : "error: ");
cstr_vprintf(&cs, fmt, ap); cstr_vprintf(&cs, fmt, ap);
if (!s1 || !s1->error_func) { if (!s1->error_func) {
/* default case: stderr */ /* default case: stderr */
if (s1 && s1->output_type == TCC_OUTPUT_PREPROCESS && s1->ppfp == stdout) if (s1 && s1->output_type == TCC_OUTPUT_PREPROCESS && s1->ppfp == stdout)
printf("\n"); /* print a newline during tcc -E */ printf("\n"); /* print a newline during tcc -E */
@ -666,22 +661,12 @@ static void error1(int mode, const char *fmt, va_list ap)
} }
} }
LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, TCCErrorFunc error_func) LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, TCCErrorFunc *error_func)
{ {
s->error_opaque = error_opaque; s->error_opaque = error_opaque;
s->error_func = error_func; s->error_func = error_func;
} }
LIBTCCAPI TCCErrorFunc tcc_get_error_func(TCCState *s)
{
return s->error_func;
}
LIBTCCAPI void *tcc_get_error_opaque(TCCState *s)
{
return s->error_opaque;
}
/* error without aborting current compilation */ /* error without aborting current compilation */
PUB_FUNC int _tcc_error_noabort(const char *fmt, ...) PUB_FUNC int _tcc_error_noabort(const char *fmt, ...)
{ {
@ -2245,6 +2230,15 @@ PUB_FUNC void tcc_print_stats(TCCState *s1, unsigned total_time)
s1->total_output[3] s1->total_output[3]
); );
#ifdef MEM_DEBUG #ifdef MEM_DEBUG
fprintf(stderr, "# %d bytes memory used\n", mem_max_size); fprintf(stderr, "# memory usage");
#ifdef TCC_IS_NATIVE
if (s1->run_size) {
Section *s = s1->symtab;
int ms = s->data_offset + s->link->data_offset + s->hash->data_offset;
fprintf(stderr, ": %d to run, %d symbols, %d other,",
s1->run_size, ms, mem_cur_size - s1->run_size - ms);
}
#endif
fprintf(stderr, " %d max (bytes)\n", mem_max_size);
#endif #endif
} }

View file

@ -9,19 +9,16 @@
extern "C" { extern "C" {
#endif #endif
struct TCCState; /*****************************/
/* set custom allocator for all allocations (optional) */
typedef void *TCCReallocFunc(void *ptr, unsigned long size);
LIBTCCAPI void tcc_set_realloc(TCCReallocFunc *my_realloc);
/*****************************/
typedef struct TCCState TCCState; typedef struct TCCState TCCState;
typedef void (*TCCErrorFunc)(void *opaque, const char *msg);
typedef void *(*TCCReallocFunc)(void *ptr, size_t size);
/* to be used for all allocation (including tcc_new()), otherwise malloc(), realloc(), free() */
LIBTCCAPI void tcc_set_realloc(TCCReallocFunc realloc);
/* return current allocator */
LIBTCCAPI TCCReallocFunc tcc_get_realloc();
/* create a new TCC compilation context */ /* create a new TCC compilation context */
LIBTCCAPI TCCState *tcc_new(void); LIBTCCAPI TCCState *tcc_new(void);
@ -31,14 +28,9 @@ LIBTCCAPI void tcc_delete(TCCState *s);
/* set CONFIG_TCCDIR at runtime */ /* set CONFIG_TCCDIR at runtime */
LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path); LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path);
/* set error/warning display callback */ /* set error/warning callback (optional) */
LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, TCCErrorFunc error_func); typedef void TCCErrorFunc(void *opaque, const char *msg);
LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, TCCErrorFunc *error_func);
/* return error/warning callback */
LIBTCCAPI TCCErrorFunc tcc_get_error_func(TCCState *s);
/* return error/warning callback opaque pointer */
LIBTCCAPI void *tcc_get_error_opaque(TCCState *s);
/* set options as from command line (multiple supported) */ /* set options as from command line (multiple supported) */
LIBTCCAPI int tcc_set_options(TCCState *s, const char *str); LIBTCCAPI int tcc_set_options(TCCState *s, const char *str);
@ -67,6 +59,9 @@ LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename);
/* compile a string containing a C source. Return -1 if error. */ /* compile a string containing a C source. Return -1 if error. */
LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf); LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf);
/* Tip: to have more specific errors/warnings from tcc_compile_string(),
you can prefix the string with "#line <num> \"<filename>\"\n" */
/*****************************/ /*****************************/
/* linking commands */ /* linking commands */
@ -96,18 +91,12 @@ LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename);
LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv); LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv);
/* do all relocations (needed before using tcc_get_symbol()) */ /* do all relocations (needed before using tcc_get_symbol()) */
LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr); LIBTCCAPI int tcc_relocate(TCCState *s1);
/* possible values for 'ptr':
- TCC_RELOCATE_AUTO : Allocate and manage memory internally
- NULL : return required memory size for the step below
- memory address : copy code to memory passed by the caller
returns -1 if error. */
#define TCC_RELOCATE_AUTO (void*)1
/* return symbol value or NULL if not found */ /* return symbol value or NULL if not found */
LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name); LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name);
/* return symbol value or NULL if not found */ /* list all (global) symbols and their values via 'symbol_cb()' */
LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx, LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx,
void (*symbol_cb)(void *ctx, const char *name, const void *val)); void (*symbol_cb)(void *ctx, const char *name, const void *val));

17
tcc.h
View file

@ -923,13 +923,11 @@ struct TCCState {
Section *lbounds_section; /* contains local data bound description */ Section *lbounds_section; /* contains local data bound description */
#endif #endif
/* symbol section */ /* symbol section */
Section *symtab_section; union { Section *symtab_section, *symtab; }; /* historical alias */
/* temporary dynamic symbol sections (for dll loading) */ /* temporary dynamic symbol sections (for dll loading) */
Section *dynsymtab_section; Section *dynsymtab_section;
/* exported dynamic symbol section */ /* exported dynamic symbol section */
Section *dynsym; Section *dynsym;
/* copy of the global symtab_section variable */
Section *symtab;
/* got & plt handling */ /* got & plt handling */
Section *got, *plt; Section *got, *plt;
/* debug sections */ /* debug sections */
@ -972,6 +970,8 @@ struct TCCState {
int uw_sym; int uw_sym;
unsigned uw_offs; unsigned uw_offs;
# endif # endif
#else
unsigned shf_RELRO; /* section flags for RELRO sections */
#endif #endif
#if defined TCC_TARGET_MACHO #if defined TCC_TARGET_MACHO
@ -991,9 +991,12 @@ struct TCCState {
#endif #endif
#ifdef TCC_IS_NATIVE #ifdef TCC_IS_NATIVE
const char *runtime_main; const char *run_main; /* entry for tcc_run() */
void **runtime_mem; void *run_ptr; /* ptr to runtime_memory */
int nb_runtime_mem; unsigned run_size; /* size of runtime_memory */
#ifdef _WIN64
void *run_function_table; /* unwind data */
#endif
#endif #endif
#ifdef CONFIG_TCC_BACKTRACE #ifdef CONFIG_TCC_BACKTRACE
@ -1542,7 +1545,9 @@ ST_FUNC void section_realloc(Section *sec, unsigned long new_size);
ST_FUNC size_t section_add(Section *sec, addr_t size, int align); ST_FUNC size_t section_add(Section *sec, addr_t size, int align);
ST_FUNC void *section_ptr_add(Section *sec, addr_t size); ST_FUNC void *section_ptr_add(Section *sec, addr_t size);
ST_FUNC Section *find_section(TCCState *s1, const char *name); ST_FUNC Section *find_section(TCCState *s1, const char *name);
ST_FUNC void free_section(Section *s);
ST_FUNC Section *new_symtab(TCCState *s1, const char *symtab_name, int sh_type, int sh_flags, const char *strtab_name, const char *hash_name, int hash_sh_flags); ST_FUNC Section *new_symtab(TCCState *s1, const char *symtab_name, int sh_type, int sh_flags, const char *strtab_name, const char *hash_name, int hash_sh_flags);
ST_FUNC void init_symtab(Section *s);
ST_FUNC int put_elf_str(Section *s, const char *sym); ST_FUNC int put_elf_str(Section *s, const char *sym);
ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int shndx, const char *name); ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int shndx, const char *name);

View file

@ -714,9 +714,11 @@ ST_FUNC void tcc_debug_start(TCCState *s1)
char buf[512]; char buf[512];
char *filename; char *filename;
/* we might currently #include the <command-line> */
filename = file->prev ? file->prev->filename : file->filename;
/* an elf symbol of type STT_FILE must be put so that STB_LOCAL /* an elf symbol of type STT_FILE must be put so that STB_LOCAL
symbols can be safely used */ symbols can be safely used */
filename = file->prev ? file->prev->filename : file->filename;
put_elf_sym(symtab_section, 0, 0, put_elf_sym(symtab_section, 0, 0,
ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0, ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0,
SHN_ABS, filename); SHN_ABS, filename);

View file

@ -48,10 +48,10 @@ struct sym_version {
#define SHF_DYNSYM 0x40000000 #define SHF_DYNSYM 0x40000000
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
static const int shf_RELRO = SHF_ALLOC; #define shf_RELRO SHF_ALLOC
static const char rdata[] = ".rdata"; static const char rdata[] = ".rdata";
#else #else
static const int shf_RELRO = SHF_ALLOC | SHF_WRITE; #define shf_RELRO s1->shf_RELRO
static const char rdata[] = ".data.ro"; static const char rdata[] = ".data.ro";
#endif #endif
@ -60,6 +60,13 @@ static const char rdata[] = ".data.ro";
ST_FUNC void tccelf_new(TCCState *s) ST_FUNC void tccelf_new(TCCState *s)
{ {
TCCState *s1 = s; TCCState *s1 = s;
#ifndef TCC_TARGET_PE
shf_RELRO = SHF_ALLOC;
if (s1->output_type != TCC_OUTPUT_MEMORY)
shf_RELRO |= SHF_WRITE; /* the ELF loader will set it to RO at runtime */
#endif
/* no section zero */ /* no section zero */
dynarray_add(&s->sections, &s->nb_sections, NULL); dynarray_add(&s->sections, &s->nb_sections, NULL);
@ -76,7 +83,6 @@ ST_FUNC void tccelf_new(TCCState *s)
symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0, symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0,
".strtab", ".strtab",
".hashtab", SHF_PRIVATE); ".hashtab", SHF_PRIVATE);
s->symtab = symtab_section;
/* private symbol table for dynamic symbols */ /* private symbol table for dynamic symbols */
s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE|SHF_DYNSYM, s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE|SHF_DYNSYM,
@ -99,9 +105,13 @@ ST_FUNC void tccelf_new(TCCState *s)
#endif #endif
} }
static void free_section(Section *s) ST_FUNC void free_section(Section *s)
{ {
if (!s)
return;
tcc_free(s->data); tcc_free(s->data);
s->data = NULL;
s->data_allocated = s->data_offset = 0;
} }
ST_FUNC void tccelf_delete(TCCState *s1) ST_FUNC void tccelf_delete(TCCState *s1)
@ -127,6 +137,9 @@ ST_FUNC void tccelf_delete(TCCState *s1)
free_section(s1->priv_sections[i]); free_section(s1->priv_sections[i]);
dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections); dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections);
tcc_free(s1->sym_attrs);
symtab_section = NULL; /* for tccrun.c:rt_printline() */
/* free any loaded DLLs */ /* free any loaded DLLs */
#ifdef TCC_IS_NATIVE #ifdef TCC_IS_NATIVE
for ( i = 0; i < s1->nb_loaded_dlls; i++) { for ( i = 0; i < s1->nb_loaded_dlls; i++) {
@ -141,9 +154,6 @@ ST_FUNC void tccelf_delete(TCCState *s1)
#endif #endif
/* free loaded dlls array */ /* free loaded dlls array */
dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls); dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls);
tcc_free(s1->sym_attrs);
symtab_section = NULL; /* for tccrun.c:rt_printline() */
} }
/* save section data state */ /* save section data state */
@ -261,32 +271,32 @@ ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh
return sec; return sec;
} }
ST_FUNC void init_symtab(Section *s)
{
int *ptr, nb_buckets = 1;
put_elf_str(s->link, "");
section_ptr_add(s, sizeof (ElfW(Sym)));
ptr = section_ptr_add(s->hash, (2 + nb_buckets + 1) * sizeof(int));
ptr[0] = nb_buckets;
ptr[1] = 1;
memset(ptr + 2, 0, (nb_buckets + 1) * sizeof(int));
}
ST_FUNC Section *new_symtab(TCCState *s1, ST_FUNC Section *new_symtab(TCCState *s1,
const char *symtab_name, int sh_type, int sh_flags, const char *symtab_name, int sh_type, int sh_flags,
const char *strtab_name, const char *strtab_name,
const char *hash_name, int hash_sh_flags) const char *hash_name, int hash_sh_flags)
{ {
Section *symtab, *strtab, *hash; Section *symtab, *strtab, *hash;
int *ptr, nb_buckets;
symtab = new_section(s1, symtab_name, sh_type, sh_flags); symtab = new_section(s1, symtab_name, sh_type, sh_flags);
symtab->sh_entsize = sizeof(ElfW(Sym)); symtab->sh_entsize = sizeof(ElfW(Sym));
strtab = new_section(s1, strtab_name, SHT_STRTAB, sh_flags); strtab = new_section(s1, strtab_name, SHT_STRTAB, sh_flags);
put_elf_str(strtab, "");
symtab->link = strtab; symtab->link = strtab;
put_elf_sym(symtab, 0, 0, 0, 0, 0, NULL);
nb_buckets = 1;
hash = new_section(s1, hash_name, SHT_HASH, hash_sh_flags); hash = new_section(s1, hash_name, SHT_HASH, hash_sh_flags);
hash->sh_entsize = sizeof(int); hash->sh_entsize = sizeof(int);
symtab->hash = hash; symtab->hash = hash;
hash->link = symtab; hash->link = symtab;
init_symtab(symtab);
ptr = section_ptr_add(hash, (2 + nb_buckets + 1) * sizeof(int));
ptr[0] = nb_buckets;
ptr[1] = 1;
memset(ptr + 2, 0, (nb_buckets + 1) * sizeof(int));
return symtab; return symtab;
} }

View file

@ -1349,7 +1349,7 @@ static int pe_check_symbols(struct pe_info *pe)
sprintf(buffer, "IAT.%s", name); sprintf(buffer, "IAT.%s", name);
is->iat_index = put_elf_sym( is->iat_index = put_elf_sym(
symtab_section, 0, sizeof(DWORD), symtab_section, 0, sizeof(DWORD),
ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT), ELFW(ST_INFO)(STB_LOCAL, STT_OBJECT),
0, SHN_UNDEF, buffer); 0, SHN_UNDEF, buffer);
offset = text_section->data_offset; offset = text_section->data_offset;
@ -1970,7 +1970,7 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
/* grab the startup code from libtcc1.a */ /* grab the startup code from libtcc1.a */
#ifdef TCC_IS_NATIVE #ifdef TCC_IS_NATIVE
if (TCC_OUTPUT_MEMORY != s1->output_type || s1->runtime_main) if (TCC_OUTPUT_MEMORY != s1->output_type || s1->run_main)
#endif #endif
set_global_sym(s1, start_symbol, NULL, 0); set_global_sym(s1, start_symbol, NULL, 0);
@ -2078,7 +2078,7 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
#ifdef TCC_IS_NATIVE #ifdef TCC_IS_NATIVE
pe.thunk = data_section; pe.thunk = data_section;
pe_build_imports(&pe); pe_build_imports(&pe);
s1->runtime_main = pe.start_symbol; s1->run_main = pe.start_symbol;
#ifdef TCC_TARGET_X86_64 #ifdef TCC_TARGET_X86_64
s1->uw_pdata = find_section(s1, ".pdata"); s1->uw_pdata = find_section(s1, ".pdata");
#endif #endif

216
tccrun.c
View file

@ -76,8 +76,8 @@ static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap);
# include <sys/mman.h> # include <sys/mman.h>
#endif #endif
static int set_pages_executable(TCCState *s1, int mode, void *ptr, unsigned long length); static int protect_pages(void *ptr, unsigned long length, int mode);
static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff); static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff);
#ifdef _WIN64 #ifdef _WIN64
static void *win64_add_function_table(TCCState *s1); static void *win64_add_function_table(TCCState *s1);
@ -88,13 +88,11 @@ static void win64_del_function_table(void *);
/* Do all relocations (needed before using tcc_get_symbol()) /* Do all relocations (needed before using tcc_get_symbol())
Returns -1 on error. */ Returns -1 on error. */
LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr) LIBTCCAPI int tcc_relocate(TCCState *s1)
{ {
void *ptr;
int size; int size;
addr_t ptr_diff = 0; unsigned ptr_diff = 0;
if (TCC_RELOCATE_AUTO != ptr)
return tcc_relocate_ex(s1, ptr, 0);
size = tcc_relocate_ex(s1, NULL, 0); size = tcc_relocate_ex(s1, NULL, 0);
if (size < 0) if (size < 0)
@ -103,52 +101,46 @@ LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr)
#ifdef HAVE_SELINUX #ifdef HAVE_SELINUX
{ {
/* Using mmap instead of malloc */ /* Using mmap instead of malloc */
void *prx; void *prw;
char tmpfname[] = "/tmp/.tccrunXXXXXX"; char tmpfname[] = "/tmp/.tccrunXXXXXX";
int fd = mkstemp(tmpfname); int fd = mkstemp(tmpfname);
unlink(tmpfname); unlink(tmpfname);
ftruncate(fd, size); ftruncate(fd, size);
size = (size + (PAGESIZE-1)) & ~(PAGESIZE-1); ptr = mmap(NULL, size * 2, PROT_READ|PROT_EXEC, MAP_SHARED, fd, 0);
ptr = mmap(NULL, size * 2, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); /* mmap RW memory at fixed distance */
/* mmap RX memory at a fixed distance */ prw = mmap((char*)ptr + size, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, fd, 0);
prx = mmap((char*)ptr + size, size, PROT_READ|PROT_EXEC, MAP_SHARED|MAP_FIXED, fd, 0);
close(fd); close(fd);
if (ptr == MAP_FAILED || prx == MAP_FAILED) if (ptr == MAP_FAILED || prw == MAP_FAILED)
return tcc_error_noabort("tccrun: could not map memory"); return tcc_error_noabort("tccrun: could not map memory");
ptr_diff = (char*)prx - (char*)ptr; ptr_diff = (char*)prw - (char*)ptr; /* = size; */
//printf("map %p %p %p\n", ptr, prx, (void*)ptr_diff); //printf("map %p %p %p\n", ptr, prw, (void*)ptr_diff);
} }
#else #else
ptr = tcc_malloc(size); ptr = tcc_malloc(size);
#endif #endif
if (tcc_relocate_ex(s1, ptr, ptr_diff)) s1->run_ptr = ptr;
return -1; s1->run_size = size;
dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, (void*)(addr_t)size); tcc_relocate_ex(s1, ptr, ptr_diff);
dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, ptr);
return 0; return 0;
} }
ST_FUNC void tcc_run_free(TCCState *s1) ST_FUNC void tcc_run_free(TCCState *s1)
{ {
int i; void *ptr = s1->run_ptr;
unsigned size = s1->run_size;
for (i = 0; i < s1->nb_runtime_mem; i += 2) {
unsigned size = (unsigned)(addr_t)s1->runtime_mem[i];
void *ptr = s1->runtime_mem[i+1];
#ifdef HAVE_SELINUX #ifdef HAVE_SELINUX
munmap(ptr, size * 2); munmap(ptr, size * 2);
#else #else
/* unprotect memory to make it usable for malloc again */ /* unprotect memory to make it usable for malloc again */
set_pages_executable(s1, 2, ptr, size); protect_pages(ptr, size, 2 /*rw*/);
#ifdef _WIN64 #ifdef _WIN64
win64_del_function_table(*(void**)ptr); win64_del_function_table(s1->run_function_table);
#endif #endif
tcc_free(ptr); tcc_free(ptr);
#endif #endif
} }
tcc_free(s1->runtime_mem);
}
static void run_cdtors(TCCState *s1, const char *start, const char *end, static void run_cdtors(TCCState *s1, const char *start, const char *end,
int argc, char **argv, char **envp) int argc, char **argv, char **envp)
@ -198,17 +190,17 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
char **envp = environ; char **envp = environ;
#endif #endif
s1->runtime_main = s1->nostdlib ? "_start" : "main"; s1->run_main = s1->nostdlib ? "_start" : "main";
if ((s1->dflag & 16) && (addr_t)-1 == get_sym_addr(s1, s1->runtime_main, 0, 1)) if ((s1->dflag & 16) && (addr_t)-1 == get_sym_addr(s1, s1->run_main, 0, 1))
return 0; return 0;
tcc_add_symbol(s1, "exit", rt_exit); tcc_add_symbol(s1, "exit", rt_exit);
tcc_add_symbol(s1, "atexit", rt_atexit); tcc_add_symbol(s1, "atexit", rt_atexit);
tcc_add_symbol(s1, "on_exit", rt_on_exit); tcc_add_symbol(s1, "on_exit", rt_on_exit);
if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0) if (tcc_relocate(s1) < 0)
return -1; return -1;
prog_main = (void*)get_sym_addr(s1, s1->runtime_main, 1, 1); prog_main = (void*)get_sym_addr(s1, s1->run_main, 1, 1);
if ((addr_t)-1 == (addr_t)prog_main) if ((addr_t)-1 == (addr_t)prog_main)
return -1; return -1;
@ -275,28 +267,62 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
return ret; return ret;
} }
#define DEBUG_RUNMEN 0 /* ------------------------------------------------------------- */
/* remove all STB_LOCAL symbols */
static void cleanup_symbols(TCCState *s1)
{
Section *s = s1->symtab;
int sym_index, end_sym = s->data_offset / sizeof (ElfSym);
/* reset symtab */
s->data_offset = s->link->data_offset = s->hash->data_offset = 0;
init_symtab(s);
/* re-add symbols except STB_LOCAL */
for (sym_index = 1; sym_index < end_sym; ++sym_index) {
ElfW(Sym) *sym = &((ElfW(Sym) *)s->data)[sym_index];
const char *name = (char *)s->link->data + sym->st_name;
if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL)
continue;
//printf("sym %s\n", name);
put_elf_sym(s, sym->st_value, sym->st_size, sym->st_info, sym->st_other, sym->st_shndx, name);
}
}
/* enable rx/ro/rw permissions */ /* free all sections except symbols */
static void cleanup_sections(TCCState *s1)
{
struct { Section **secs; int nb_secs; } *p = (void*)&s1->sections;
int i, f = 2;
do {
for (i = --f; i < p->nb_secs; i++) {
Section *s = p->secs[i];
if (s == s1->symtab || s == s1->symtab->link || s == s1->symtab->hash
|| 0 == memcmp(s->name, ".stab", 5)
|| 0 == memcmp(s->name, ".debug_", 7)) {
s->data = tcc_realloc(s->data, s->data_allocated = s->data_offset);
} else {
free_section(s);
if (0 == (s->sh_flags & SHF_ALLOC))
tcc_free(s), p->secs[i] = NULL;
}
}
} while (++p, f);
}
/* ------------------------------------------------------------- */
/* 0 = .text rwx other rw */
/* 1 = .text rx .rdata r .data/.bss rw */
#ifndef CONFIG_RUNMEM_RO
# define CONFIG_RUNMEM_RO 1 # define CONFIG_RUNMEM_RO 1
#if CONFIG_RUNMEM_RO
# define PAGE_ALIGN PAGESIZE
#elif defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
/* To avoid that x86 processors would reload cached instructions
each time when data is written in the near, we need to make
sure that code and data do not share the same 64 byte unit */
# define PAGE_ALIGN 64
#else
# define PAGE_ALIGN 1
#endif #endif
#define DEBUG_RUNMEN 0
/* relocate code. Return -1 on error, required size if ptr is NULL, /* relocate code. Return -1 on error, required size if ptr is NULL,
otherwise copy code into buffer passed by the caller */ otherwise copy code into buffer passed by the caller */
static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff) static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff)
{ {
Section *s; Section *s;
unsigned offset, length, align, max_align, i, k, f; unsigned offset, length, align, i, k, f;
unsigned n, copy; unsigned n, copy;
addr_t mem, addr; addr_t mem, addr;
@ -313,11 +339,15 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff)
return -1; return -1;
} }
offset = max_align = 0, mem = (addr_t)ptr; offset = copy = 0;
#ifdef _WIN64 mem = (addr_t)ptr;
offset += sizeof (void*); /* space for function_table pointer */
#if DEBUG_RUNMEN
if (mem)
fprintf(stderr, "X: <base> %p len %5x\n",
ptr, s1->run_size);
#endif #endif
copy = 0;
redo: redo:
for (k = 0; k < 3; ++k) { /* 0:rx, 1:ro, 2:rw sections */ for (k = 0; k < 3; ++k) { /* 0:rx, 1:ro, 2:rw sections */
n = 0; addr = 0; n = 0; addr = 0;
@ -329,79 +359,98 @@ redo:
if (shf[k] != (s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR))) if (shf[k] != (s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR)))
continue; continue;
length = s->data_offset; length = s->data_offset;
if (copy) {
if (copy) { /* final step: copy section data to memory */
void *ptr;
if (addr == 0) if (addr == 0)
addr = s->sh_addr; addr = s->sh_addr;
n = (s->sh_addr - addr) + length; n = (s->sh_addr - addr) + length;
ptr = (void*)s->sh_addr; ptr = (void*)s->sh_addr;
if (k == 0) if (k == 0)
ptr = (void*)(s->sh_addr - ptr_diff); ptr = (void*)(s->sh_addr + ptr_diff);
if (NULL == s->data || s->sh_type == SHT_NOBITS) if (NULL == s->data || s->sh_type == SHT_NOBITS)
memset(ptr, 0, length); memset(ptr, 0, length);
else else
memcpy(ptr, s->data, length); memcpy(ptr, s->data, length);
#ifdef _WIN64 #ifdef _WIN64
if (s == s1->uw_pdata) if (s == s1->uw_pdata)
*(void**)mem = win64_add_function_table(s1); s1->run_function_table = win64_add_function_table(s1);
#endif #endif
if (s->data) { free_section(s);
tcc_free(s->data);
s->data = NULL;
s->data_allocated = 0;
}
s->data_offset = 0;
continue; continue;
} }
align = s->sh_addralign - 1; align = s->sh_addralign - 1;
if (++n == 1 && align < (PAGE_ALIGN - 1)) if (++n == 1) {
align = (PAGE_ALIGN - 1); #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
if (max_align < align) /* To avoid that x86 processors would reload cached instructions
max_align = align; each time when data is written in the near, we need to make
addr = k ? mem : mem + ptr_diff; sure that code and data do not share the same 64 byte unit */
if (align < 63)
align = 63;
#endif
/* start new page for different permissions */
if (CONFIG_RUNMEM_RO || k < 2)
align = PAGESIZE - 1;
}
addr = k ? mem + ptr_diff : mem;
offset += -(addr + offset) & align; offset += -(addr + offset) & align;
s->sh_addr = mem ? addr + offset : 0; s->sh_addr = mem ? addr + offset : 0;
offset += length; offset += length;
#if DEBUG_RUNMEN #if DEBUG_RUNMEN
if (mem) if (mem)
printf("%d: %-16s %p len %04x align %04x\n", fprintf(stderr, "%d: %-16s %p len %5x align %04x\n",
k, s->name, (void*)s->sh_addr, length, align + 1); k, s->name, (void*)s->sh_addr, length, align + 1);
#endif #endif
} }
if (copy) { /* set permissions */ if (copy) { /* set permissions */
if (k == 0 && ptr_diff) if (n == 0) /* no data */
continue; /* not with HAVE_SELINUX */ continue;
#ifdef HAVE_SELINUX
if (k == 0) /* SHF_EXECINSTR has its own mapping */
continue;
#endif
f = k; f = k;
#if !CONFIG_RUNMEM_RO if (CONFIG_RUNMEM_RO == 0) {
if (f != 0) if (f != 0)
continue; continue;
f = 3; /* change only SHF_EXECINSTR to rwx */ f = 3; /* change only SHF_EXECINSTR to rwx */
#endif
#if DEBUG_RUNMEN
printf("protect %d %p %04x\n", f, (void*)addr, n);
#endif
if (n) {
if (set_pages_executable(s1, f, (void*)addr, n))
return -1;
} }
#if DEBUG_RUNMEN
fprintf(stderr, "protect %3s %p len %5x\n",
&"rx\0r \0rw\0rwx"[f*3],
(void*)addr, (unsigned)((n + PAGESIZE-1) & ~(PAGESIZE-1)));
#endif
if (protect_pages((void*)addr, n, f) < 0)
return tcc_error_noabort(
"mprotect failed "
"(did you mean to configure --with-selinux?)");
} }
} }
if (copy) if (copy) {
/* remove local symbols and free sections except symtab */
cleanup_symbols(s1);
cleanup_sections(s1);
return 0; return 0;
}
/* relocate symbols */ /* relocate symbols */
relocate_syms(s1, s1->symtab, !(s1->nostdlib)); relocate_syms(s1, s1->symtab, !(s1->nostdlib));
if (s1->nb_errors) if (s1->nb_errors)
return -1; return -1;
if (0 == mem)
return offset + max_align; if (0 == mem) {
offset = (offset + (PAGESIZE-1)) & ~(PAGESIZE-1);
#ifndef HAVE_SELINUX
offset += PAGESIZE; /* extra space to align malloc memory start */
#endif
return offset;
}
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
s1->pe_imagebase = mem; s1->pe_imagebase = mem;
#endif #else
/* relocate sections */
#ifndef TCC_TARGET_PE
relocate_plt(s1); relocate_plt(s1);
#endif #endif
relocate_sections(s1); relocate_sections(s1);
@ -412,7 +461,7 @@ redo:
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
/* allow to run code in memory */ /* allow to run code in memory */
static int set_pages_executable(TCCState *s1, int mode, void *ptr, unsigned long length) static int protect_pages(void *ptr, unsigned long length, int mode)
{ {
#ifdef _WIN32 #ifdef _WIN32
static const unsigned char protect[] = { static const unsigned char protect[] = {
@ -437,7 +486,7 @@ static int set_pages_executable(TCCState *s1, int mode, void *ptr, unsigned long
end = (addr_t)ptr + length; end = (addr_t)ptr + length;
end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1); end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1);
if (mprotect((void *)start, end - start, protect[mode])) if (mprotect((void *)start, end - start, protect[mode]))
return tcc_error_noabort("mprotect failed: did you mean to configure --with-selinux?"); return -1;
/* XXX: BSD sometimes dump core with bad system call */ /* XXX: BSD sometimes dump core with bad system call */
# if (defined TCC_TARGET_ARM && !TARGETOS_BSD) || defined TCC_TARGET_ARM64 # if (defined TCC_TARGET_ARM && !TARGETOS_BSD) || defined TCC_TARGET_ARM64
if (mode == 0 || mode == 3) { if (mode == 0 || mode == 3) {
@ -472,6 +521,7 @@ static void win64_del_function_table(void *p)
} }
} }
#endif #endif
#endif //ndef CONFIG_TCC_BACKTRACE_ONLY #endif //ndef CONFIG_TCC_BACKTRACE_ONLY
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
#ifdef CONFIG_TCC_BACKTRACE #ifdef CONFIG_TCC_BACKTRACE

View file

@ -1,4 +1,3 @@
#include <unistd.h>
#include <libtcc.h> #include <libtcc.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@ -53,7 +52,7 @@ static int run_callback(const char *src, callback_type callback) {
return -1; return -1;
if (tcc_compile_string(s, src) == -1) if (tcc_compile_string(s, src) == -1)
return -1; return -1;
if (tcc_relocate(s, TCC_RELOCATE_AUTO) == -1) if (tcc_relocate(s) == -1)
return -1; return -1;
ptr = tcc_get_symbol(s, "f"); ptr = tcc_get_symbol(s, "f");

View file

@ -6,8 +6,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <assert.h>
#include "libtcc.h" #include "libtcc.h"
void handle_error(void *opaque, const char *msg) void handle_error(void *opaque, const char *msg)
@ -59,14 +57,9 @@ int main(int argc, char **argv)
exit(1); exit(1);
} }
assert(tcc_get_error_func(s) == NULL); /* set custom error/warning printer */
assert(tcc_get_error_opaque(s) == NULL);
tcc_set_error_func(s, stderr, handle_error); tcc_set_error_func(s, stderr, handle_error);
assert(tcc_get_error_func(s) == handle_error);
assert(tcc_get_error_opaque(s) == stderr);
/* if tcclib.h and libtcc1.a are not installed, where can we find them */ /* if tcclib.h and libtcc1.a are not installed, where can we find them */
for (i = 1; i < argc; ++i) { for (i = 1; i < argc; ++i) {
char *a = argv[i]; char *a = argv[i];
@ -92,7 +85,7 @@ int main(int argc, char **argv)
tcc_add_symbol(s, "hello", hello); tcc_add_symbol(s, "hello", hello);
/* relocate the code */ /* relocate the code */
if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0) if (tcc_relocate(s) < 0)
return 1; return 1;
/* get entry symbol */ /* get entry symbol */

View file

@ -128,7 +128,7 @@ void *reloc_state(TCCState *s, const char *entry)
{ {
void *func; void *func;
tcc_add_symbol(s, "add", add); tcc_add_symbol(s, "add", add);
if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0) { if (tcc_relocate(s) < 0) {
fprintf(stderr, __FILE__ ": could not relocate tcc state.\n"); fprintf(stderr, __FILE__ ": could not relocate tcc state.\n");
return NULL; return NULL;
} }