tccelf: use rodata_section, use more rodata in tcc itself

libtcc.c: add -Wwrite-strings to -Wall
tccgen.c: ro float-consts, string-consts, ro arrays if base type is
tccpe.c: merge IAT with rodata
tccrun.c: mprotect rodata accordingly. free section data after copy
x86_64.c: do not use got for static data.
tcc -bench: show data.rw/ro

Probably STB_LOCAL should never get to put_got_entry(), and currently
it doesn't seem to happen (See "Hack Alarm" there)

Other files: use more ro-data in tinycc
This commit is contained in:
grischka 2021-02-01 15:10:58 +01:00
parent 02795106e1
commit 72f1dea537
18 changed files with 230 additions and 159 deletions

View File

@ -2826,7 +2826,7 @@ ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
// TODO: Check non-E ABI.
// Note: Technically, r13 (sp) is also callee-saved--but that does not matter yet
static uint8_t reg_saved[] = { 4, 5, 6, 7, 8, 9 /* Note: sometimes special reg "sb" */ , 10, 11 };
static const uint8_t reg_saved[] = { 4, 5, 6, 7, 8, 9 /* Note: sometimes special reg "sb" */ , 10, 11 };
/* mark all used registers */
memcpy(regs_allocated, clobber_regs, sizeof(regs_allocated));

View File

@ -141,7 +141,7 @@ enum {
#define USING_GLOBALS
#include "tcc.h"
ST_DATA const char *target_machine_defs =
ST_DATA const char * const target_machine_defs =
"__arm__\0"
"__arm\0"
"arm\0"

View File

@ -50,7 +50,7 @@
#include "tcc.h"
#include <assert.h>
ST_DATA const char *target_machine_defs =
ST_DATA const char * const target_machine_defs =
"__aarch64__\0"
;

View File

@ -116,7 +116,7 @@ enum {
#define USING_GLOBALS
#include "tcc.h"
ST_DATA const char *target_machine_defs =
ST_DATA const char * const target_machine_defs =
"__C67__\0"
;
@ -371,7 +371,7 @@ int C67_map_D12(char *s)
void C67_asm(char *s, int a, int b, int c)
void C67_asm(const char *s, int a, int b, int c)
{
BOOL xpath;

View File

@ -638,10 +638,12 @@ static void asm_rex(int width64, Operand *ops, int nb_ops, int *op_type,
}
#endif
static void maybe_print_stats (void)
{
static int already = 1;
if (!already)
static int already;
if (0 && !already)
/* print stats about opcodes */
{
const struct ASMInstr *pa;
@ -1604,12 +1606,12 @@ ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
call-preserved registers, but currently it doesn't matter. */
#ifdef TCC_TARGET_X86_64
#ifdef TCC_TARGET_PE
static uint8_t reg_saved[] = { 3, 6, 7, 12, 13, 14, 15 };
static const uint8_t reg_saved[] = { 3, 6, 7, 12, 13, 14, 15 };
#else
static uint8_t reg_saved[] = { 3, 12, 13, 14, 15 };
static const uint8_t reg_saved[] = { 3, 12, 13, 14, 15 };
#endif
#else
static uint8_t reg_saved[] = { 3, 6, 7 };
static const uint8_t reg_saved[] = { 3, 6, 7 };
#endif
/* mark all used registers */

View File

@ -81,7 +81,7 @@ enum {
#define USING_GLOBALS
#include "tcc.h"
ST_DATA const char *target_machine_defs =
ST_DATA const char * const target_machine_defs =
"__i386__\0"
"__i386\0"
;
@ -372,8 +372,8 @@ static void gcall_or_jmp(int is_jmp)
}
}
static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
static const uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
static const uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
/* Return the number of registers needed to return the struct, or 0 if
returning via struct pointer. */
@ -479,7 +479,7 @@ ST_FUNC void gfunc_call(int nb_args)
if ((func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) ||
func_call == FUNC_FASTCALLW) {
int fastcall_nb_regs;
uint8_t *fastcall_regs_ptr;
const uint8_t *fastcall_regs_ptr;
if (func_call == FUNC_FASTCALLW) {
fastcall_regs_ptr = fastcallw_regs;
fastcall_nb_regs = 2;
@ -519,7 +519,7 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
CType *func_type = &func_sym->type;
int addr, align, size, func_call, fastcall_nb_regs;
int param_index, param_addr;
uint8_t *fastcall_regs_ptr;
const uint8_t *fastcall_regs_ptr;
Sym *sym;
CType *type;

View File

@ -1580,7 +1580,7 @@ static const TCCOption tcc_options[] = {
static const FlagDef options_W[] = {
{ 0, 0, "all" },
{ offsetof(TCCState, warn_unsupported), 0, "unsupported" },
{ offsetof(TCCState, warn_write_strings), 0, "write-strings" },
{ offsetof(TCCState, warn_write_strings), WD_ALL, "write-strings" },
{ offsetof(TCCState, warn_error), 0, "error" },
{ offsetof(TCCState, warn_gcc_compat), 0, "gcc-compat" },
{ offsetof(TCCState, warn_implicit_function_declaration), WD_ALL,
@ -1997,8 +1997,12 @@ PUB_FUNC void tcc_print_stats(TCCState *s1, unsigned total_time)
(double)total_time/1000,
(unsigned)total_lines*1000/total_time,
(double)total_bytes/1000/total_time);
fprintf(stderr, "* text %d, data %d, bss %d bytes\n",
s1->total_output[0], s1->total_output[1], s1->total_output[2]);
fprintf(stderr, "* text %d, data.rw %d, data.ro %d, bss %d bytes\n",
s1->total_output[0],
s1->total_output[1],
s1->total_output[2],
s1->total_output[3]
);
#ifdef MEM_DEBUG
fprintf(stderr, "* %d bytes memory used\n", mem_max_size);
#endif

View File

@ -36,7 +36,7 @@
#include "tcc.h"
#include <assert.h>
ST_DATA const char *target_machine_defs =
ST_DATA const char * const target_machine_defs =
"__riscv\0"
"__riscv_xlen 64\0"
"__riscv_flen 64\0"

8
tcc.h
View File

@ -885,7 +885,7 @@ struct TCCState {
Section *plt;
/* predefined sections */
Section *text_section, *data_section, *data_ro_section, *bss_section;
Section *text_section, *data_section, *rodata_section, *bss_section;
Section *common_section;
Section *cur_text_section; /* current section where function code is generated */
#ifdef CONFIG_TCC_BCHECK
@ -960,7 +960,7 @@ struct TCCState {
int total_idents;
int total_lines;
int total_bytes;
int total_output[3];
int total_output[4];
/* option -dnum (for general development purposes) */
int g_debug;
@ -1639,7 +1639,7 @@ ST_FUNC void relocate_plt(TCCState *s1);
ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val);
/* ------------ xxx-gen.c ------------ */
ST_DATA const char *target_machine_defs;
ST_DATA const char * const target_machine_defs;
ST_DATA const int reg_classes[NB_REGS];
ST_FUNC void gsym_addr(int t, int a);
@ -1842,7 +1842,7 @@ ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
#define text_section TCC_STATE_VAR(text_section)
#define data_section TCC_STATE_VAR(data_section)
#define data_ro_section TCC_STATE_VAR(data_ro_section)
#define rodata_section TCC_STATE_VAR(rodata_section)
#define bss_section TCC_STATE_VAR(bss_section)
#define common_section TCC_STATE_VAR(common_section)
#define cur_text_section TCC_STATE_VAR(cur_text_section)

View File

@ -58,8 +58,12 @@ ST_FUNC void tccelf_new(TCCState *s)
/* create standard sections */
text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
#ifdef TCC_TARGET_PE
rodata_section = new_section(s, ".rdata", SHT_PROGBITS, SHF_ALLOC);
#else
/* create ro data section (make ro after relocation done with GNU_RELRO) */
data_ro_section = new_section(s, ".data.ro", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
rodata_section = new_section(s, ".data.ro", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
#endif
bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
common_section = new_section(s, ".common", SHT_NOBITS, SHF_PRIVATE);
common_section->sh_num = SHN_COMMON;
@ -206,7 +210,7 @@ ST_FUNC void tccelf_end_file(TCCState *s1)
tcc_free(tr);
/* record text/data/bss output for -bench info */
for (i = 0; i < 3; ++i) {
for (i = 0; i < 4; ++i) {
s = s1->sections[i + 1];
s1->total_output[i] += s->data_offset - s->sh_offset;
}
@ -1255,11 +1259,16 @@ redo:
&& ELFW(ST_TYPE)(sym->st_info) == STT_FUNC)))
goto jmp_slot;
}
} else if (!(sym->st_shndx == SHN_ABS
} else if (sym->st_shndx == SHN_ABS) {
if (sym->st_value == 0) /* from tcc_add_btstub() */
continue;
#ifndef TCC_TARGET_ARM
&& PTR_SIZE == 8
if (PTR_SIZE != 8)
continue;
#endif
))
/* from tcc_add_symbol(): on 64 bit platforms these
need to go through .got */
} else
continue;
}
@ -1314,7 +1323,7 @@ redo:
ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, addr_t offs)
{
int shn = sec ? sec->sh_num : offs ? SHN_ABS : SHN_UNDEF;
int shn = sec ? sec->sh_num : offs || !name ? SHN_ABS : SHN_UNDEF;
if (sec && offs == -1)
offs = sec->data_offset;
return set_elf_sym(symtab_section, offs, 0,
@ -1326,7 +1335,7 @@ static void add_init_array_defines(TCCState *s1, const char *section_name)
Section *s;
addr_t end_offset;
char buf[1024];
s = find_section(s1, section_name);
s = find_section_create(s1, section_name, 0);
if (!s) {
end_offset = 0;
s = data_section;
@ -1407,12 +1416,8 @@ ST_FUNC void tcc_add_btstub(TCCState *s1)
put_ptr(s1, stab_section, -1);
put_ptr(s1, stab_section->link, 0);
section_ptr_add(s, 3 * PTR_SIZE);
/* prog_base */
#ifndef TCC_TARGET_MACHO
/* XXX this relocation is wrong, it uses sym-index 0 (local,undef) */
put_elf_reloc(s1->symtab, s, s->data_offset, R_DATA_PTR, 0);
#endif
section_ptr_add(s, PTR_SIZE);
/* prog_base : local nameless symbol with offset 0 at SHN_ABS */
put_ptr(s1, NULL, 0);
n = 2 * PTR_SIZE;
#ifdef CONFIG_TCC_BCHECK
if (s1->do_bounds_check) {
@ -1421,10 +1426,10 @@ ST_FUNC void tcc_add_btstub(TCCState *s1)
}
#endif
section_ptr_add(s, n);
cstr_new(&cstr);
cstr_printf(&cstr,
" extern void __bt_init(),*__rt_info[],__bt_init_dll();"
"extern void __bt_init(),__bt_init_dll();"
"static void *__rt_info[];"
"__attribute__((constructor)) static void __bt_init_rt(){");
#ifdef TCC_TARGET_PE
if (s1->output_type == TCC_OUTPUT_DLL)
@ -1526,8 +1531,9 @@ ST_FUNC void tcc_add_runtime(TCCState *s1)
tcc_add_btstub(s1);
}
#endif
if (strlen(TCC_LIBTCC1) > 0)
if (TCC_LIBTCC1[0])
tcc_add_support(s1, TCC_LIBTCC1);
#if TARGETOS_OpenBSD || TARGETOS_FreeBSD || TARGETOS_NetBSD
/* add crt end if not memory output */
if (s1->output_type != TCC_OUTPUT_MEMORY) {
@ -1568,7 +1574,9 @@ static void tcc_add_linker_symbols(TCCState *s1)
set_global_sym(s1, "__global_pointer$", data_section, 0x800);
#endif
/* horrible new standard ldscript defines */
#ifndef TCC_TARGET_PE
add_init_array_defines(s1, ".preinit_array");
#endif
add_init_array_defines(s1, ".init_array");
add_init_array_defines(s1, ".fini_array");
/* add start and stop symbols for sections whose name can be
@ -1996,12 +2004,12 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr,
} else if (s->sh_type == SHT_NOBITS) {
if (k != 6)
continue;
} else if (s == data_ro_section ||
} else if ((s == rodata_section
#ifdef CONFIG_TCC_BCHECK
s == bounds_section ||
s == lbounds_section ||
|| s == bounds_section
|| s == lbounds_section
#endif
0) {
) && (s->sh_flags & SHF_WRITE)) {
if (k != 4)
continue;
/* Align next section on page size.
@ -2029,18 +2037,15 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr,
ph->p_vaddr = addr;
ph->p_paddr = ph->p_vaddr;
}
if (s == data_ro_section ||
#ifdef CONFIG_TCC_BCHECK
s == bounds_section ||
s == lbounds_section ||
#endif
0) {
if (k == 4) {
if (roinf->sh_size == 0) {
roinf->sh_offset = s->sh_offset;
roinf->sh_addr = s->sh_addr;
}
roinf->sh_size = (addr - roinf->sh_addr) + s->sh_size;
}
addr += s->sh_size;
if (s->sh_type != SHT_NOBITS)
file_offset += s->sh_size;

View File

@ -2356,7 +2356,7 @@ ST_FUNC int gv(int rc)
(vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
/* CPUs usually cannot use float constants, so we store them
generically in data segment */
init_params p = { data_section };
init_params p = { rodata_section };
unsigned long offset;
size = type_size(&vtop->type, &align);
if (NODATA_WANTED)
@ -3095,11 +3095,12 @@ static void type_to_str(char *buf, int buf_size,
pstrcat(buf, buf_size, "typedef ");
if (t & VT_INLINE)
pstrcat(buf, buf_size, "inline ");
if (t & VT_VOLATILE)
pstrcat(buf, buf_size, "volatile ");
if (t & VT_CONSTANT)
pstrcat(buf, buf_size, "const ");
if (bt != VT_PTR) {
if (t & VT_VOLATILE)
pstrcat(buf, buf_size, "volatile ");
if (t & VT_CONSTANT)
pstrcat(buf, buf_size, "const ");
}
if (((t & VT_DEFSIGN) && bt == VT_BYTE)
|| ((t & VT_UNSIGNED)
&& (bt == VT_SHORT || bt == VT_INT || bt == VT_LLONG)
@ -5932,18 +5933,22 @@ ST_FUNC void unary(void)
/* fall thru */
case TOK___FUNC__:
{
Section *sec;
void *ptr;
int len;
/* special function name identifier */
len = strlen(funcname) + 1;
/* generate char[len] type */
type.t = VT_BYTE;
if (tcc_state->warn_write_strings)
type.t |= VT_CONSTANT;
mk_pointer(&type);
type.t |= VT_ARRAY;
type.ref->c = len;
vpush_ref(&type, data_section, data_section->data_offset, len);
sec = rodata_section;
vpush_ref(&type, sec, sec->data_offset, len);
if (!NODATA_WANTED) {
ptr = section_ptr_add(data_section, len);
ptr = section_ptr_add(sec, len);
memcpy(ptr, funcname, len);
}
next();
@ -5968,6 +5973,7 @@ ST_FUNC void unary(void)
mk_pointer(&type);
type.t |= VT_ARRAY;
memset(&ad, 0, sizeof(AttributeDef));
ad.section = rodata_section;
decl_initializer_alloc(&type, &ad, VT_CONST, 2, 0, 0);
break;
case '(':
@ -8526,11 +8532,16 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
/* allocate symbol in corresponding section */
sec = ad->section;
if (!sec) {
if (type->t & VT_CONSTANT)
sec = data_ro_section;
else if (has_init)
CType *tp = type;
while ((tp->t & (VT_BTYPE|VT_ARRAY)) == (VT_PTR|VT_ARRAY))
tp = &tp->ref->type;
if (tp->t & VT_CONSTANT) {
sec = rodata_section;
} else if (has_init) {
sec = data_section;
else if (tcc_state->nocommon)
/*if (tcc_state->g_debug & 4)
tcc_warning("rw data: %s", get_tok_str(v, 0));*/
} else if (tcc_state->nocommon)
sec = bss_section;
}

View File

@ -259,7 +259,7 @@ static void * add_lc(struct macho *mo, uint32_t cmd, uint32_t cmdsize)
return lc;
}
static struct segment_command_64 * add_segment(struct macho *mo, char *name)
static struct segment_command_64 * add_segment(struct macho *mo, const char *name)
{
struct segment_command_64 *sc = add_lc(mo, LC_SEGMENT_64, sizeof(*sc));
strncpy(sc->segname, name, 16);
@ -272,7 +272,7 @@ static struct segment_command_64 * get_segment(struct macho *mo, int i)
return (struct segment_command_64 *) (mo->lc[mo->seg2lc[i]]);
}
static int add_section(struct macho *mo, struct segment_command_64 **_seg, char *name)
static int add_section(struct macho *mo, struct segment_command_64 **_seg, const char *name)
{
struct segment_command_64 *seg = *_seg;
int ret = seg->nsects;
@ -525,10 +525,10 @@ static void create_symtab(TCCState *s1, struct macho *mo)
}
}
struct {
const struct {
int seg;
uint32_t flags;
char *name;
const char *name;
} skinfo[sk_last] = {
/*[sk_unknown] =*/ { 0 },
/*[sk_discard] =*/ { 0 },

44
tccpe.c
View File

@ -20,8 +20,8 @@
#include "tcc.h"
#define PE_MERGE_DATA
/* #define PE_PRINT_SECTIONS */
#define PE_MERGE_DATA 1
#define PE_PRINT_SECTIONS 0
#ifndef _WIN32
#define stricmp strcasecmp
@ -294,6 +294,7 @@ struct pe_rsrc_reloc {
enum {
sec_text = 0,
sec_rdata ,
sec_data ,
sec_bss ,
sec_idata ,
@ -725,6 +726,8 @@ static int pe_write(struct pe_info *pe)
for (i = 0; i < pe->sec_count; ++i) {
Section *s;
si = pe->sec_info[i];
if (!si->data_size)
continue;
for (s = si->sec; s; s = s->prev) {
pe_fpad(&pf, file_offset);
pe_fwrite(s->data, s->data_offset, &pf);
@ -1084,6 +1087,7 @@ static int pe_section_class(Section *s)
return sec_idata;
if (0 == strcmp(name, ".pdata"))
return sec_pdata;
return sec_rdata;
} else if (type == SHT_NOBITS) {
if (flags & SHF_WRITE)
return sec_bss;
@ -1106,6 +1110,7 @@ static int pe_assign_addresses (struct pe_info *pe)
int *section_order;
struct section_info *si;
Section *s;
TCCState *s1 = pe->s1;
if (PE_DLL == pe->type)
pe->reloc = new_section(pe->s1, ".reloc", SHT_PROGBITS, 0);
@ -1113,8 +1118,8 @@ static int pe_assign_addresses (struct pe_info *pe)
section_order = tcc_malloc(pe->s1->nb_sections * sizeof (int));
for (o = k = 0 ; k < sec_last; ++k) {
for (i = 1; i < pe->s1->nb_sections; ++i) {
s = pe->s1->sections[i];
for (i = 1; i < s1->nb_sections; ++i) {
s = s1->sections[i];
if (k == pe_section_class(s))
section_order[o++] = i;
}
@ -1125,16 +1130,15 @@ static int pe_assign_addresses (struct pe_info *pe)
for (i = 0; i < o; ++i) {
k = section_order[i];
s = pe->s1->sections[k];
s = s1->sections[k];
c = pe_section_class(s);
if ((c == sec_stab || c == sec_stabstr) && 0 == pe->s1->do_debug)
if ((c == sec_stab || c == sec_stabstr) && 0 == s1->do_debug)
continue;
#ifdef PE_MERGE_DATA
if (c == sec_bss)
if (PE_MERGE_DATA && c == sec_bss)
c = sec_data;
#endif
if (si && c == si->cls) {
/* merge with previous section */
s->sh_addr = addr = ((addr - 1) | (16 - 1)) + 1;
@ -1143,7 +1147,8 @@ static int pe_assign_addresses (struct pe_info *pe)
s->sh_addr = addr = pe_virtual_align(pe, addr);
}
if (c == sec_data && NULL == pe->thunk)
if (NULL == pe->thunk
&& c == (data_section == rodata_section ? sec_data : sec_rdata))
pe->thunk = s;
if (s == pe->thunk) {
@ -1192,8 +1197,8 @@ add_section:
}
tcc_free(section_order);
#if 0
for (i = 1; i < pe->s1->nb_sections; ++i) {
Section *s = pe->s1->sections[i];
for (i = 1; i < s1->nb_sections; ++i) {
Section *s = s1->sections[i];
int type = s->sh_type;
int flags = s->sh_flags;
printf("section %-16s %-10s %08x %04x %s,%s,%s\n",
@ -1210,7 +1215,7 @@ add_section:
flags & SHF_EXECINSTR ? "exec" : ""
);
}
pe->s1->verbose = 2;
s1->verbose = 2;
#endif
return 0;
}
@ -1345,7 +1350,7 @@ static int pe_check_symbols(struct pe_info *pe)
}
/*----------------------------------------------------------------------------*/
#ifdef PE_PRINT_SECTIONS
#if PE_PRINT_SECTIONS
static void pe_print_section(FILE * f, Section * s)
{
/* just if you're curious */
@ -1923,11 +1928,11 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
set_global_sym(s1, start_symbol, NULL, 0);
if (0 == s1->nostdlib) {
static const char *libs[] = {
static const char * const libs[] = {
"msvcrt", "kernel32", "", "user32", "gdi32", NULL
};
const char **pp, *p;
if (strlen(TCC_LIBTCC1) > 0)
const char * const *pp, *p;
if (TCC_LIBTCC1[0])
tcc_add_support(s1, TCC_LIBTCC1);
for (pp = libs; 0 != (p = *pp); ++pp) {
if (*p)
@ -2038,8 +2043,9 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
pe_free_imports(&pe);
#ifdef PE_PRINT_SECTIONS
pe_print_sections(s1, "tcc.log");
#if PE_PRINT_SECTIONS
if (s1->g_debug & 8)
pe_print_sections(s1, "tcc.log");
#endif
return ret;
}

View File

@ -3669,7 +3669,7 @@ ST_INLN void unget_tok(int last_tok)
/* ------------------------------------------------------------------------- */
/* init preprocessor */
static const char *target_os_defs =
static const char * const target_os_defs =
#ifdef TCC_TARGET_PE
"_WIN32\0"
# if PTR_SIZE == 8

160
tccrun.c
View File

@ -55,7 +55,7 @@ static void rt_exit(int code);
# include <sys/mman.h>
#endif
static void set_pages_executable(TCCState *s1, void *ptr, unsigned long length);
static void 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);
#ifdef _WIN64
@ -94,7 +94,6 @@ LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr)
prx = mmap((char*)ptr + size, size, PROT_READ|PROT_EXEC, MAP_SHARED|MAP_FIXED, fd, 0);
if (ptr == MAP_FAILED || prx == MAP_FAILED)
tcc_error("tccrun: could not map memory");
dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, (void*)(addr_t)(size*2));
ptr_diff = (char*)prx - (char*)ptr;
close(fd);
//printf("map %p %p %p\n", ptr, prx, (void*)ptr_diff);
@ -103,6 +102,7 @@ LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr)
ptr = tcc_malloc(size);
#endif
tcc_relocate_ex(s1, ptr, ptr_diff); /* no more errors expected */
dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, (void*)(addr_t)size);
dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, ptr);
return 0;
}
@ -111,15 +111,18 @@ ST_FUNC void tcc_run_free(TCCState *s1)
{
int i;
for (i = 0; i < s1->nb_runtime_mem; ++i) {
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
unsigned size = (unsigned)(addr_t)s1->runtime_mem[i++];
munmap(s1->runtime_mem[i], size);
munmap(ptr, size * 2);
#else
/* unprotect memory to make it usable for malloc again */
set_pages_executable(s1, 2, ptr, size);
#ifdef _WIN64
win64_del_function_table(*(void**)s1->runtime_mem[i]);
win64_del_function_table(*(void**)ptr);
#endif
tcc_free(s1->runtime_mem[i]);
tcc_free(ptr);
#endif
}
tcc_free(s1->runtime_mem);
@ -182,8 +185,9 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
*(void**)p = _rt_error;
#ifdef CONFIG_TCC_BCHECK
if (s1->do_bounds_check) {
rc->bounds_start = (void*)bounds_section->sh_addr;
if ((p = tcc_get_symbol(s1, "__bound_init")))
((void(*)(addr_t, int))p)(bounds_section->sh_addr, 1);
((void(*)(void*,int))p)(rc->bounds_start, 1);
}
#endif
set_exception_handler();
@ -207,13 +211,20 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
return ret;
}
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
#define DEBUG_RUNMEN 0
/* enable rx/ro/rw permissions */
#define CONFIG_RUNMEM_RO 1
#if CONFIG_RUNMEM_RO
# define PAGE_ALIGN PAGESIZE
#elif defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
/* To avoid that x86 processors would reload cached instructions
each time when data is written in the near, we need to make
sure that code and data do not share the same 64 byte unit */
#define RUN_SECTION_ALIGNMENT 63
# define PAGE_ALIGN 64
#else
#define RUN_SECTION_ALIGNMENT 0
# define PAGE_ALIGN 1
#endif
/* relocate code. Return -1 on error, required size if ptr is NULL,
@ -222,6 +233,7 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff)
{
Section *s;
unsigned offset, length, align, max_align, i, k, f;
unsigned n, copy;
addr_t mem, addr;
if (NULL == ptr) {
@ -241,35 +253,80 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff)
#ifdef _WIN64
offset += sizeof (void*); /* space for function_table pointer */
#endif
for (k = 0; k < 2; ++k) {
f = 0, addr = k ? mem : mem + ptr_diff;
copy = 0;
redo:
for (k = 0; k < 3; ++k) { /* 0:rx, 1:ro, 2:rw sections */
n = 0; addr = 0;
for(i = 1; i < s1->nb_sections; i++) {
static const char shf[] = {
SHF_ALLOC|SHF_EXECINSTR, SHF_ALLOC, SHF_ALLOC|SHF_WRITE
};
s = s1->sections[i];
if (0 == (s->sh_flags & SHF_ALLOC))
if (shf[k] != (s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR)))
continue;
if (k != !(s->sh_flags & SHF_EXECINSTR))
length = s->data_offset;
if (copy) {
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);
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);
#endif
if (s->data) {
tcc_free(s->data);
s->data = NULL;
s->data_allocated = 0;
}
s->data_offset = 0;
continue;
}
align = s->sh_addralign - 1;
if (++f == 1 && align < RUN_SECTION_ALIGNMENT)
align = RUN_SECTION_ALIGNMENT;
if (++n == 1 && align < (PAGE_ALIGN - 1))
align = (PAGE_ALIGN - 1);
if (max_align < align)
max_align = align;
addr = k ? mem : mem + ptr_diff;
offset += -(addr + offset) & align;
s->sh_addr = mem ? addr + offset : 0;
offset += s->data_offset;
#if 0
offset += length;
#if DEBUG_RUNMEN
if (mem)
printf("%-16s %p len %04x align %2d\n",
s->name, (void*)s->sh_addr, (unsigned)s->data_offset, align + 1);
printf("%d: %-16s %p len %04x 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)
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)
set_pages_executable(s1, f, (void*)addr, n);
}
}
if (copy)
return 0;
/* relocate symbols */
relocate_syms(s1, s1->symtab, !(s1->nostdlib));
if (s1->nb_errors)
return -1;
if (0 == mem)
return offset + max_align;
@ -282,55 +339,46 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff)
relocate_plt(s1);
#endif
relocate_sections(s1);
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (0 == (s->sh_flags & SHF_ALLOC))
continue;
length = s->data_offset;
ptr = (void*)s->sh_addr;
if (s->sh_flags & SHF_EXECINSTR)
ptr = (char*)((addr_t)ptr - ptr_diff);
if (NULL == s->data || s->sh_type == SHT_NOBITS)
memset(ptr, 0, length);
else
memcpy(ptr, s->data, length);
/* mark executable sections as executable in memory */
if (s->sh_flags & SHF_EXECINSTR)
set_pages_executable(s1, (char*)((addr_t)ptr + ptr_diff), length);
}
#ifdef _WIN64
*(void**)mem = win64_add_function_table(s1);
#endif
return 0;
copy = 1;
goto redo;
}
/* ------------------------------------------------------------- */
/* allow to run code in memory */
static void set_pages_executable(TCCState *s1, void *ptr, unsigned long length)
static void set_pages_executable(TCCState *s1, int mode, void *ptr, unsigned long length)
{
#ifdef _WIN32
unsigned long old_protect;
VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect);
static const unsigned char protect[] = {
PAGE_EXECUTE_READ,
PAGE_READONLY,
PAGE_READWRITE,
PAGE_EXECUTE_READWRITE
};
DWORD old;
VirtualProtect(ptr, length, protect[mode], &old);
#else
void __clear_cache(void *beginning, void *end);
# ifndef HAVE_SELINUX
static const unsigned char protect[] = {
PROT_READ | PROT_EXEC,
PROT_READ,
PROT_READ | PROT_WRITE,
PROT_READ | PROT_WRITE | PROT_EXEC
};
addr_t start, end;
start = (addr_t)ptr & ~(PAGESIZE - 1);
end = (addr_t)ptr + length;
end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1);
if (mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC))
if (mprotect((void *)start, end - start, protect[mode]))
tcc_error("mprotect failed: did you mean to configure --with-selinux?");
# endif
/* XXX: BSD sometimes dump core with bad system call */
# if (defined(TCC_TARGET_ARM) && \
!defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)) || \
defined(TCC_TARGET_ARM64)
__clear_cache(ptr, (char *)ptr + length);
# if (TCC_TARGET_ARM && !TARGETOS_BSD) || TCC_TARGET_ARM64
if (mode == 0 || mode == 3) {
void __clear_cache(void *beginning, void *end);
__clear_cache(ptr, (char *)ptr + length);
}
# endif
#endif
}

View File

@ -68,7 +68,7 @@ static int ar_usage(int ret) {
ST_FUNC int tcc_tool_ar(TCCState *s1, int argc, char **argv)
{
static ArHdr arhdr = {
static const ArHdr arhdr_init = {
"/ ",
" ",
"0 ",
@ -78,15 +78,8 @@ ST_FUNC int tcc_tool_ar(TCCState *s1, int argc, char **argv)
ARFMAG
};
static ArHdr arhdro = {
" ",
" ",
"0 ",
"0 ",
"0 ",
" ",
ARFMAG
};
ArHdr arhdr = arhdr_init;
ArHdr arhdro = arhdr_init;
FILE *fi, *fh = NULL, *fo = NULL;
ElfW(Ehdr) *ehdr;
@ -506,9 +499,9 @@ ST_FUNC void tcc_tool_cross(TCCState *s1, char **argv, int target)
/* enable commandline wildcard expansion (tcc -o x.exe *.c) */
#ifdef _WIN32
int _CRT_glob = 1;
const int _CRT_glob = 1;
#ifndef _CRT_glob
int _dowildcard = 1;
const int _dowildcard = 1;
#endif
#endif

View File

@ -42,8 +42,8 @@ int main()
__label__ ts0, te0, ts1, te1;
int tl, dl;
static char ds0 = 0;
static char de0 = 0;
static const char ds0 = 0;
static const char de0 = 0;
/* get reference size of empty jmp */
ts0:;
if (!SKIP) {}
@ -52,7 +52,7 @@ te0:;
tl = -(&&te0 - &&ts0);
/* test data and code suppression */
static char ds1 = 0;
static const char ds1 = 0;
ts1:;
if (!SKIP) {
void *p = (void*)&main;
@ -75,7 +75,7 @@ ts1:;
s.x, s.y, s.z, s.a, s.b);
}
te1:;
static char de1 = 0;
static const char de1 = 0;
dl += &de1 - &ds1;
tl += &&te1 - &&ts1;

View File

@ -112,7 +112,7 @@ enum {
#include "tcc.h"
#include <assert.h>
ST_DATA const char *target_machine_defs =
ST_DATA const char * const target_machine_defs =
"__x86_64__\0"
"__amd64__\0"
;
@ -575,7 +575,9 @@ void store(int r, SValue *v)
#ifndef TCC_TARGET_PE
/* we need to access the variable via got */
if (fr == VT_CONST && (v->r & VT_SYM)) {
if (fr == VT_CONST
&& (v->r & VT_SYM)
&& !(v->sym->type.t & VT_STATIC)) {
/* mov xx(%rip), %r11 */
o(0x1d8b4c);
gen_gotpcrel(TREG_R11, v->sym, v->c.i);