summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgrischka <grischka>2024-02-07 07:42:56 +0100
committergrischka <grischka>2024-02-09 13:38:27 +0100
commitb671fc0594625eb5ac147ec83be6d0c1fc1a6ad5 (patch)
treee21e3d117d34e94375fd8ad7f017ea506b512c1f
parenta0ab99169e35c733a033417f55c35b3c0d0f7194 (diff)
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()
-rwxr-xr-xconfigure14
-rw-r--r--libtcc.c36
-rw-r--r--libtcc.h39
-rw-r--r--tcc.h17
-rw-r--r--tccdbg.c4
-rw-r--r--tccelf.c48
-rw-r--r--tccpe.c6
-rw-r--r--tccrun.c224
-rw-r--r--tests/abitest.c3
-rw-r--r--tests/libtcc_test.c11
-rw-r--r--tests/libtcc_test_mt.c2
11 files changed, 222 insertions, 182 deletions
diff --git a/configure b/configure
index 062d0e3..1222396 100755
--- a/configure
+++ b/configure
@@ -56,6 +56,7 @@ build_cross=
# use CC/AR from environment when set
test -n "$CC" && cc="$CC"
test -n "$AR" && ar="$AR"
+test -n "CFLAGS" && CFLAGS="-Wall -O2"
# find source path
source_path=${0%configure}
@@ -399,14 +400,6 @@ if test "$mingw32" = "no"; then
default infodir "${sharedir}/info"
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
show_help
fi
@@ -464,6 +457,11 @@ if test "$bigendian" = "yes" ; then
confvars="$confvars BIGENDIAN"
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 "${triplet%eabihf}" != "$triplet" ; then
confvars="$confvars arm_eabihf arm_vfp"
diff --git a/libtcc.c b/libtcc.c
index 557dfcb..4359944 100644
--- a/libtcc.c
+++ b/libtcc.c
@@ -249,7 +249,7 @@ ST_FUNC char *tcc_load_text(int fd)
#undef free
#undef realloc
-static void *default_reallocator(void *ptr, size_t size)
+static void *default_reallocator(void *ptr, unsigned long size)
{
void *ptr1;
if (size == 0) {
@@ -275,18 +275,13 @@ static void libc_free(void *ptr)
#define realloc(p, s) use_tcc_realloc(p, s)
/* 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;
}
-LIBTCCAPI TCCReallocFunc tcc_get_realloc()
-{
- return reallocator;
-}
-
/* in case MEM_DEBUG is #defined */
#undef tcc_free
#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_vprintf(&cs, fmt, ap);
- if (!s1 || !s1->error_func) {
+ if (!s1->error_func) {
/* default case: stderr */
if (s1 && s1->output_type == TCC_OUTPUT_PREPROCESS && s1->ppfp == stdout)
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_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 */
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]
);
#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
}
diff --git a/libtcc.h b/libtcc.h
index 9261321..205ed15 100644
--- a/libtcc.h
+++ b/libtcc.h
@@ -9,18 +9,15 @@
extern "C" {
#endif
-struct TCCState;
-
-typedef struct TCCState TCCState;
+/*****************************/
+/* set custom allocator for all allocations (optional) */
-typedef void (*TCCErrorFunc)(void *opaque, const char *msg);
-typedef void *(*TCCReallocFunc)(void *ptr, size_t size);
+typedef void *TCCReallocFunc(void *ptr, unsigned long size);
+LIBTCCAPI void tcc_set_realloc(TCCReallocFunc *my_realloc);
-/* 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();
+typedef struct TCCState TCCState;
/* create a new TCC compilation context */
LIBTCCAPI TCCState *tcc_new(void);
@@ -31,14 +28,9 @@ LIBTCCAPI void tcc_delete(TCCState *s);
/* set CONFIG_TCCDIR at runtime */
LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path);
-/* set error/warning display callback */
-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 error/warning callback (optional) */
+typedef void TCCErrorFunc(void *opaque, const char *msg);
+LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, TCCErrorFunc *error_func);
/* set options as from command line (multiple supported) */
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. */
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 */
@@ -96,18 +91,12 @@ LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename);
LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv);
/* do all relocations (needed before using tcc_get_symbol()) */
-LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr);
-/* 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
+LIBTCCAPI int tcc_relocate(TCCState *s1);
/* return symbol value or NULL if not found */
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,
void (*symbol_cb)(void *ctx, const char *name, const void *val));
diff --git a/tcc.h b/tcc.h
index 30bfa38..a5a92ee 100644
--- a/tcc.h
+++ b/tcc.h
@@ -923,13 +923,11 @@ struct TCCState {
Section *lbounds_section; /* contains local data bound description */
#endif
/* symbol section */
- Section *symtab_section;
+ union { Section *symtab_section, *symtab; }; /* historical alias */
/* temporary dynamic symbol sections (for dll loading) */
Section *dynsymtab_section;
/* exported dynamic symbol section */
Section *dynsym;
- /* copy of the global symtab_section variable */
- Section *symtab;
/* got & plt handling */
Section *got, *plt;
/* debug sections */
@@ -972,6 +970,8 @@ struct TCCState {
int uw_sym;
unsigned uw_offs;
# endif
+#else
+ unsigned shf_RELRO; /* section flags for RELRO sections */
#endif
#if defined TCC_TARGET_MACHO
@@ -991,9 +991,12 @@ struct TCCState {
#endif
#ifdef TCC_IS_NATIVE
- const char *runtime_main;
- void **runtime_mem;
- int nb_runtime_mem;
+ const char *run_main; /* entry for tcc_run() */
+ void *run_ptr; /* ptr to runtime_memory */
+ unsigned run_size; /* size of runtime_memory */
+#ifdef _WIN64
+ void *run_function_table; /* unwind data */
+#endif
#endif
#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 void *section_ptr_add(Section *sec, addr_t size);
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 void init_symtab(Section *s);
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);
diff --git a/tccdbg.c b/tccdbg.c
index 2509bac..483afe5 100644
--- a/tccdbg.c
+++ b/tccdbg.c
@@ -714,9 +714,11 @@ ST_FUNC void tcc_debug_start(TCCState *s1)
char buf[512];
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
symbols can be safely used */
- filename = file->prev ? file->prev->filename : file->filename;
put_elf_sym(symtab_section, 0, 0,
ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0,
SHN_ABS, filename);
diff --git a/tccelf.c b/tccelf.c
index 93a46ba..1b06726 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -48,10 +48,10 @@ struct sym_version {
#define SHF_DYNSYM 0x40000000
#ifdef TCC_TARGET_PE
-static const int shf_RELRO = SHF_ALLOC;
+#define shf_RELRO SHF_ALLOC
static const char rdata[] = ".rdata";
#else
-static const int shf_RELRO = SHF_ALLOC | SHF_WRITE;
+#define shf_RELRO s1->shf_RELRO
static const char rdata[] = ".data.ro";
#endif
@@ -60,6 +60,13 @@ static const char rdata[] = ".data.ro";
ST_FUNC void tccelf_new(TCCState *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 */
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,
".strtab",
".hashtab", SHF_PRIVATE);
- s->symtab = symtab_section;
/* private symbol table for dynamic symbols */
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
}
-static void free_section(Section *s)
+ST_FUNC void free_section(Section *s)
{
+ if (!s)
+ return;
tcc_free(s->data);
+ s->data = NULL;
+ s->data_allocated = s->data_offset = 0;
}
ST_FUNC void tccelf_delete(TCCState *s1)
@@ -127,6 +137,9 @@ ST_FUNC void tccelf_delete(TCCState *s1)
free_section(s1->priv_sections[i]);
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 */
#ifdef TCC_IS_NATIVE
for ( i = 0; i < s1->nb_loaded_dlls; i++) {
@@ -141,9 +154,6 @@ ST_FUNC void tccelf_delete(TCCState *s1)
#endif
/* free loaded dlls array */
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 */
@@ -261,32 +271,32 @@ ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh
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,
const char *symtab_name, int sh_type, int sh_flags,
const char *strtab_name,
const char *hash_name, int hash_sh_flags)
{
Section *symtab, *strtab, *hash;
- int *ptr, nb_buckets;
-
symtab = new_section(s1, symtab_name, sh_type, sh_flags);
symtab->sh_entsize = sizeof(ElfW(Sym));
strtab = new_section(s1, strtab_name, SHT_STRTAB, sh_flags);
- put_elf_str(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->sh_entsize = sizeof(int);
symtab->hash = hash;
hash->link = 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));
+ init_symtab(symtab);
return symtab;
}
diff --git a/tccpe.c b/tccpe.c
index 06d817d..7695c3c 100644
--- a/tccpe.c
+++ b/tccpe.c
@@ -1349,7 +1349,7 @@ static int pe_check_symbols(struct pe_info *pe)
sprintf(buffer, "IAT.%s", name);
is->iat_index = put_elf_sym(
symtab_section, 0, sizeof(DWORD),
- ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT),
+ ELFW(ST_INFO)(STB_LOCAL, STT_OBJECT),
0, SHN_UNDEF, buffer);
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 */
#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
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
pe.thunk = data_section;
pe_build_imports(&pe);
- s1->runtime_main = pe.start_symbol;
+ s1->run_main = pe.start_symbol;
#ifdef TCC_TARGET_X86_64
s1->uw_pdata = find_section(s1, ".pdata");
#endif
diff --git a/tccrun.c b/tccrun.c
index 3ad9a41..75ca1a4 100644
--- a/tccrun.c
+++ b/tccrun.c
@@ -76,8 +76,8 @@ static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap);
# include <sys/mman.h>
#endif
-static int set_pages_executable(TCCState *s1, int mode, void *ptr, unsigned long length);
-static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff);
+static int protect_pages(void *ptr, unsigned long length, int mode);
+static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff);
#ifdef _WIN64
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())
Returns -1 on error. */
-LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr)
+LIBTCCAPI int tcc_relocate(TCCState *s1)
{
+ void *ptr;
int size;
- addr_t ptr_diff = 0;
-
- if (TCC_RELOCATE_AUTO != ptr)
- return tcc_relocate_ex(s1, ptr, 0);
+ unsigned ptr_diff = 0;
size = tcc_relocate_ex(s1, NULL, 0);
if (size < 0)
@@ -103,51 +101,45 @@ LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr)
#ifdef HAVE_SELINUX
{
/* Using mmap instead of malloc */
- void *prx;
+ void *prw;
char tmpfname[] = "/tmp/.tccrunXXXXXX";
int fd = mkstemp(tmpfname);
unlink(tmpfname);
ftruncate(fd, size);
- size = (size + (PAGESIZE-1)) & ~(PAGESIZE-1);
- ptr = mmap(NULL, size * 2, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
- /* mmap RX memory at a fixed distance */
- prx = mmap((char*)ptr + size, size, PROT_READ|PROT_EXEC, MAP_SHARED|MAP_FIXED, fd, 0);
+ ptr = mmap(NULL, size * 2, PROT_READ|PROT_EXEC, MAP_SHARED, fd, 0);
+ /* mmap RW memory at fixed distance */
+ prw = mmap((char*)ptr + size, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, fd, 0);
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");
- ptr_diff = (char*)prx - (char*)ptr;
- //printf("map %p %p %p\n", ptr, prx, (void*)ptr_diff);
+ ptr_diff = (char*)prw - (char*)ptr; /* = size; */
+ //printf("map %p %p %p\n", ptr, prw, (void*)ptr_diff);
}
#else
ptr = tcc_malloc(size);
#endif
- if (tcc_relocate_ex(s1, ptr, ptr_diff))
- return -1;
- dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, (void*)(addr_t)size);
- dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, ptr);
+ s1->run_ptr = ptr;
+ s1->run_size = size;
+ tcc_relocate_ex(s1, ptr, ptr_diff);
return 0;
}
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
- munmap(ptr, size * 2);
+ munmap(ptr, size * 2);
#else
- /* unprotect memory to make it usable for malloc again */
- set_pages_executable(s1, 2, ptr, size);
+ /* unprotect memory to make it usable for malloc again */
+ protect_pages(ptr, size, 2 /*rw*/);
#ifdef _WIN64
- win64_del_function_table(*(void**)ptr);
+ win64_del_function_table(s1->run_function_table);
#endif
- tcc_free(ptr);
+ tcc_free(ptr);
#endif
- }
- tcc_free(s1->runtime_mem);
}
static void run_cdtors(TCCState *s1, const char *start, const char *end,
@@ -198,17 +190,17 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
char **envp = environ;
#endif
- s1->runtime_main = s1->nostdlib ? "_start" : "main";
- if ((s1->dflag & 16) && (addr_t)-1 == get_sym_addr(s1, s1->runtime_main, 0, 1))
+ s1->run_main = s1->nostdlib ? "_start" : "main";
+ if ((s1->dflag & 16) && (addr_t)-1 == get_sym_addr(s1, s1->run_main, 0, 1))
return 0;
tcc_add_symbol(s1, "exit", rt_exit);
tcc_add_symbol(s1, "atexit", rt_atexit);
tcc_add_symbol(s1, "on_exit", rt_on_exit);
- if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
+ if (tcc_relocate(s1) < 0)
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)
return -1;
@@ -275,28 +267,62 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
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 */
-#define CONFIG_RUNMEM_RO 1
+/* 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);
+}
-#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
+/* ------------------------------------------------------------- */
+/* 0 = .text rwx other rw */
+/* 1 = .text rx .rdata r .data/.bss rw */
+#ifndef CONFIG_RUNMEM_RO
+# define CONFIG_RUNMEM_RO 1
#endif
+#define DEBUG_RUNMEN 0
+
/* relocate code. Return -1 on error, required size if ptr is NULL,
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;
- unsigned offset, length, align, max_align, i, k, f;
+ unsigned offset, length, align, i, k, f;
unsigned n, copy;
addr_t mem, addr;
@@ -313,11 +339,15 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff)
return -1;
}
- offset = max_align = 0, mem = (addr_t)ptr;
-#ifdef _WIN64
- offset += sizeof (void*); /* space for function_table pointer */
+ offset = copy = 0;
+ mem = (addr_t)ptr;
+
+#if DEBUG_RUNMEN
+ if (mem)
+ fprintf(stderr, "X: <base> %p len %5x\n",
+ ptr, s1->run_size);
#endif
- copy = 0;
+
redo:
for (k = 0; k < 3; ++k) { /* 0:rx, 1:ro, 2:rw sections */
n = 0; addr = 0;
@@ -329,79 +359,98 @@ redo:
if (shf[k] != (s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR)))
continue;
length = s->data_offset;
- if (copy) {
+
+ if (copy) { /* final step: copy section data to memory */
+ void *ptr;
if (addr == 0)
addr = s->sh_addr;
n = (s->sh_addr - addr) + length;
ptr = (void*)s->sh_addr;
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)
memset(ptr, 0, length);
else
memcpy(ptr, s->data, length);
#ifdef _WIN64
if (s == s1->uw_pdata)
- *(void**)mem = win64_add_function_table(s1);
+ s1->run_function_table = win64_add_function_table(s1);
#endif
- if (s->data) {
- tcc_free(s->data);
- s->data = NULL;
- s->data_allocated = 0;
- }
- s->data_offset = 0;
+ free_section(s);
continue;
}
+
align = s->sh_addralign - 1;
- if (++n == 1 && align < (PAGE_ALIGN - 1))
- align = (PAGE_ALIGN - 1);
- if (max_align < align)
- max_align = align;
- addr = k ? mem : mem + ptr_diff;
+ if (++n == 1) {
+#if 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 */
+ 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;
s->sh_addr = mem ? addr + offset : 0;
offset += length;
#if DEBUG_RUNMEN
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);
#endif
}
if (copy) { /* set permissions */
- if (k == 0 && ptr_diff)
- continue; /* not with HAVE_SELINUX */
- f = k;
-#if !CONFIG_RUNMEM_RO
- if (f != 0)
+ if (n == 0) /* no data */
+ continue;
+#ifdef HAVE_SELINUX
+ if (k == 0) /* SHF_EXECINSTR has its own mapping */
continue;
- f = 3; /* change only SHF_EXECINSTR to rwx */
#endif
+ f = k;
+ if (CONFIG_RUNMEM_RO == 0) {
+ if (f != 0)
+ continue;
+ f = 3; /* change only SHF_EXECINSTR to rwx */
+ }
#if DEBUG_RUNMEN
- printf("protect %d %p %04x\n", f, (void*)addr, n);
+ fprintf(stderr, "protect %3s %p len %5x\n",
+ &"rx\0r \0rw\0rwx"[f*3],
+ (void*)addr, (unsigned)((n + PAGESIZE-1) & ~(PAGESIZE-1)));
#endif
- if (n) {
- if (set_pages_executable(s1, f, (void*)addr, n))
- return -1;
- }
+ 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;
+ }
/* relocate symbols */
relocate_syms(s1, s1->symtab, !(s1->nostdlib));
if (s1->nb_errors)
return -1;
- if (0 == mem)
- return offset + max_align;
-#ifdef TCC_TARGET_PE
- s1->pe_imagebase = mem;
+ if (0 == mem) {
+ offset = (offset + (PAGESIZE-1)) & ~(PAGESIZE-1);
+#ifndef HAVE_SELINUX
+ offset += PAGESIZE; /* extra space to align malloc memory start */
#endif
+ return offset;
+ }
- /* relocate sections */
-#ifndef TCC_TARGET_PE
+#ifdef TCC_TARGET_PE
+ s1->pe_imagebase = mem;
+#else
relocate_plt(s1);
#endif
relocate_sections(s1);
@@ -412,7 +461,7 @@ redo:
/* ------------------------------------------------------------- */
/* 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
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 = (end + PAGESIZE - 1) & ~(PAGESIZE - 1);
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 */
# if (defined TCC_TARGET_ARM && !TARGETOS_BSD) || defined TCC_TARGET_ARM64
if (mode == 0 || mode == 3) {
@@ -472,6 +521,7 @@ static void win64_del_function_table(void *p)
}
}
#endif
+
#endif //ndef CONFIG_TCC_BACKTRACE_ONLY
/* ------------------------------------------------------------- */
#ifdef CONFIG_TCC_BACKTRACE
diff --git a/tests/abitest.c b/tests/abitest.c
index 7a67bf7..5fc868a 100644
--- a/tests/abitest.c
+++ b/tests/abitest.c
@@ -1,4 +1,3 @@
-#include <unistd.h>
#include <libtcc.h>
#include <stdlib.h>
#include <stdio.h>
@@ -53,7 +52,7 @@ static int run_callback(const char *src, callback_type callback) {
return -1;
if (tcc_compile_string(s, src) == -1)
return -1;
- if (tcc_relocate(s, TCC_RELOCATE_AUTO) == -1)
+ if (tcc_relocate(s) == -1)
return -1;
ptr = tcc_get_symbol(s, "f");
diff --git a/tests/libtcc_test.c b/tests/libtcc_test.c
index d21c7fe..1428b1e 100644
--- a/tests/libtcc_test.c
+++ b/tests/libtcc_test.c
@@ -6,8 +6,6 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <assert.h>
-
#include "libtcc.h"
void handle_error(void *opaque, const char *msg)
@@ -59,14 +57,9 @@ int main(int argc, char **argv)
exit(1);
}
- assert(tcc_get_error_func(s) == NULL);
- assert(tcc_get_error_opaque(s) == NULL);
-
+ /* set custom error/warning printer */
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 */
for (i = 1; i < argc; ++i) {
char *a = argv[i];
@@ -92,7 +85,7 @@ int main(int argc, char **argv)
tcc_add_symbol(s, "hello", hello);
/* relocate the code */
- if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0)
+ if (tcc_relocate(s) < 0)
return 1;
/* get entry symbol */
diff --git a/tests/libtcc_test_mt.c b/tests/libtcc_test_mt.c
index 7af8f3e..8af4e64 100644
--- a/tests/libtcc_test_mt.c
+++ b/tests/libtcc_test_mt.c
@@ -128,7 +128,7 @@ void *reloc_state(TCCState *s, const char *entry)
{
void *func;
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");
return NULL;
}