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
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"

View File

@ -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
}

View File

@ -9,19 +9,16 @@
extern "C" {
#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 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 */
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));

17
tcc.h
View File

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

View File

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

View File

@ -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;
}

View File

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

226
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>
#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
#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;
f = k;
if (CONFIG_RUNMEM_RO == 0) {
if (f != 0)
continue;
f = 3; /* change only SHF_EXECINSTR to rwx */
}
#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;
}
/* relocate symbols */
relocate_syms(s1, s1->symtab, !(s1->nostdlib));
if (s1->nb_errors)
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
s1->pe_imagebase = mem;
#endif
/* relocate sections */
#ifndef TCC_TARGET_PE
#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

View File

@ -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");

View File

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

View File

@ -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;
}