diff --git a/configure b/configure index 062d0e3f..12223968 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 557dfcb5..4359944d 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 92613217..205ed154 100644 --- a/libtcc.h +++ b/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 \"\"\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 30bfa381..a5a92eeb 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 2509bace..483afe5e 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 */ + 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 93a46ba9..1b067262 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 06d817df..7695c3c7 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 3ad9a41c..75ca1a41 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 #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: %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 diff --git a/tests/abitest.c b/tests/abitest.c index 7a67bf7d..5fc868a9 100644 --- a/tests/abitest.c +++ b/tests/abitest.c @@ -1,4 +1,3 @@ -#include #include #include #include @@ -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 d21c7fef..1428b1ea 100644 --- a/tests/libtcc_test.c +++ b/tests/libtcc_test.c @@ -6,8 +6,6 @@ #include #include #include -#include - #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 7af8f3e8..8af4e64c 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; }