mirror of
https://github.com/mirror/tinycc.git
synced 2024-12-26 03:50:07 +08:00
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:
parent
a0ab99169e
commit
b671fc0594
14
configure
vendored
14
configure
vendored
@ -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"
|
||||
|
36
libtcc.c
36
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
|
||||
}
|
||||
|
41
libtcc.h
41
libtcc.h
@ -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
17
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);
|
||||
|
4
tccdbg.c
4
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);
|
||||
|
48
tccelf.c
48
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;
|
||||
}
|
||||
|
||||
|
6
tccpe.c
6
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
|
||||
|
226
tccrun.c
226
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
|
||||
#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
|
||||
|
@ -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");
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user