static const arch_code_generator_if_t TEMPLATE_code_gen_if = {
TEMPLATE_cg_init,
+ NULL, /* get_pic_base hook */
NULL, /* before abi introduce hook */
TEMPLATE_prepare_graph,
NULL, /* spill hook */
static const arch_code_generator_if_t arm_code_gen_if = {
arm_cg_init,
+ NULL, /* get_pic_base */
arm_before_abi, /* before abi introduce */
arm_prepare_graph,
NULL, /* spill */
int timing; /**< time the backend phases */
int opt_profile; /**< instrument code for profiling */
int omit_fp; /**< try to omit the frame pointer */
+ int pic; /**< create position independent code */
int vrfy_option; /**< backend verify option */
int scheduler; /**< the scheduler */
char target_os[128]; /**< target operating system name */
arch_code_generator_t *cg;
arch_irn_handler_t *phi_handler;
const char *cup_name;
+ ir_type *pic_trampolines_type;
+ ir_type *pic_symbols_type;
};
/**
/* Flag: if set, try to omit the frame pointer if called by the backend */
static int be_omit_fp = 1;
+static int be_pic = 0;
/*
_ ____ ___ ____ _ _ _ _
}
}
+static ir_entity *create_trampoline(be_main_env_t *be, ir_entity *method)
+{
+ ir_type *type = get_entity_type(method);
+ ident *old_id = get_entity_ld_ident(method);
+ ident *id = mangle3("L", old_id, "$stub");
+ ir_type *parent = be->pic_trampolines_type;
+ ir_entity *ent = new_entity(parent, old_id, type);
+ set_entity_ld_ident(ent, id);
+ set_entity_visibility(ent, visibility_local);
+ set_entity_variability(ent, variability_uninitialized);
+
+ return ent;
+}
+
+static int can_address_relative(ir_entity *entity)
+{
+ return get_entity_variability(entity) == variability_initialized
+ || get_entity_visibility(entity) == visibility_local;
+}
+
+/** patches SymConsts to work in position independent code */
+static void fix_pic_symconsts(ir_node *node, void *data)
+{
+ ir_graph *irg;
+ ir_node *pic_base;
+ ir_node *add;
+ ir_node *block;
+ ir_node *unknown;
+ ir_mode *mode;
+ ir_node *load;
+ ir_node *load_res;
+ be_abi_irg_t *env = data;
+ int arity, i;
+ be_main_env_t *be = env->birg->main_env;
+
+ arity = get_irn_arity(node);
+ for (i = 0; i < arity; ++i) {
+ ir_node *pred = get_irn_n(node, i);
+ ir_entity *entity;
+ if (!is_SymConst(pred))
+ continue;
+
+ entity = get_SymConst_entity(pred);
+ block = get_nodes_block(pred);
+ irg = get_irn_irg(pred);
+
+ /* calls can jump to relative addresses, so we can directly jump to
+ the (relatively) known call address or the trampoline */
+ if (is_Call(node) && i == 1) {
+ if(can_address_relative(entity))
+ continue;
+
+ dbg_info *dbgi = get_irn_dbg_info(pred);
+ ir_entity *trampoline = create_trampoline(be, entity);
+ ir_node *trampoline_const
+ = new_rd_SymConst_addr_ent(dbgi, irg, mode_P_code, trampoline,
+ NULL);
+ set_irn_n(node, i, trampoline_const);
+ continue;
+ }
+
+ /* everything else is accessed relative to EIP */
+ mode = get_irn_mode(pred);
+ unknown = new_r_Unknown(irg, mode);
+ pic_base = arch_code_generator_get_pic_base(env->birg->cg);
+ add = new_r_Add(irg, block, pic_base, pred, mode);
+
+ /* make sure the walker doesn't visit this add again */
+ mark_irn_visited(add);
+
+ /* all ok now for locally constructed stuff */
+ if (can_address_relative(entity)) {
+ set_irn_n(node, i, add);
+ continue;
+ }
+
+ /* we need an extra indirection for global data outside our current
+ module. The loads are always safe and can therefore float
+ and need no memory input */
+ load = new_r_Load(irg, block, new_NoMem(), add, mode);
+ load_res = new_r_Proj(irg, block, load, mode, pn_Load_res);
+ set_irn_pinned(load, op_pin_state_floats);
+
+ set_irn_n(node, i, load_res);
+ }
+}
+
be_abi_irg_t *be_abi_introduce(be_irg_t *birg)
{
be_abi_irg_t *env = xmalloc(sizeof(env[0]));
unsigned *limited_bitset;
be_omit_fp = birg->main_env->options->omit_fp;
+ be_pic = birg->main_env->options->pic;
obstack_init(&env->obst);
env->calls = NEW_ARR_F(ir_node*, 0);
+ if (be_pic) {
+ irg_walk_graph(irg, fix_pic_symconsts, NULL, env);
+ }
+
/* Lower all call nodes in the IRG. */
process_calls(env);
*/
void *(*init)(be_irg_t *birg);
+ /**
+ * return node used as base in pic code addresses
+ */
+ ir_node* (*get_pic_base)(void *self);
+
/**
* Called before abi introduce.
*/
#define arch_code_generator_done(cg) _arch_cg_call(cg, done)
#define arch_code_generator_spill(cg, birg) _arch_cg_call_env(cg, birg, spill)
#define arch_code_generator_has_spiller(cg) ((cg)->impl->spill != NULL)
+#define arch_code_generator_get_pic_base(cg) \
+ ((cg)->impl->get_pic_base != NULL ? (cg)->impl->get_pic_base(cg) : NULL)
/**
* Code generator base class.
".section\t.bss",
".section\t.tbss,\"awT\",@nobits",
".section\t.ctors,\"aw\",@progbits",
+ NULL, /* no cstring section */
NULL,
+ NULL
},
{ /* GAS_FLAVOUR_MINGW */
".section\t.text",
".section\t.tbss,\"awT\",@nobits",
".section\t.ctors,\"aw\",@progbits",
NULL,
+ NULL,
+ NULL
},
{ /* GAS_FLAVOUR_YASM */
".section\t.text",
".section\t.bss",
".section\t.tbss,\"awT\",@nobits",
".section\t.ctors,\"aw\",@progbits",
+ NULL,
+ NULL,
NULL
},
{ /* GAS_FLAVOUR_MACH_O */
".data",
NULL, /* TLS is not supported on Mach-O */
".mod_init_func",
- ".cstring"
+ ".cstring",
+ ".section\t__IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5",
+ ".section\t__IMPORT,__pointers,non_lazy_symbol_pointers"
}
};
ir_variability variability = get_entity_variability(ent);
ir_visibility visibility = get_entity_visibility(ent);
+ if (is_Method_type(type) && section != GAS_SECTION_PIC_TRAMPOLINES) {
+ return;
+ }
+
if (section != (be_gas_section_t) -1) {
emit_as_common = 0;
} else if (variability == variability_constant) {
return;
}
/* alignment */
- if (align > 1 && !emit_as_common) {
+ if (align > 1 && !emit_as_common && section != GAS_SECTION_PIC_TRAMPOLINES
+ && section != GAS_SECTION_PIC_SYMBOLS) {
emit_align(align);
}
be_emit_write_line();
break;
}
+ } else if (section == GAS_SECTION_PIC_TRAMPOLINES) {
+ if (be_gas_flavour == GAS_FLAVOUR_MACH_O) {
+ be_emit_cstring("\t.indirect_symbol ");
+ be_emit_ident(get_entity_ident(ent));
+ be_emit_char('\n');
+ be_emit_write_line();
+ be_emit_cstring("\thlt ; hlt ; hlt ; hlt ; hlt\n");
+ be_emit_write_line();
+ } else {
+ panic("PIC trampolines not yet supported in this gas mode");
+ }
} else {
be_emit_irprintf("\t.space %u\n", get_type_size_bytes(type));
be_emit_write_line();
env.section = GAS_SECTION_CTOR;
be_gas_dump_globals(get_constructors_type(), &env,
only_emit_marked_entities);
+ env.section = GAS_SECTION_PIC_SYMBOLS;
+ be_gas_dump_globals(main_env->pic_symbols_type, &env,
+ only_emit_marked_entities);
+
+ if (get_compound_n_members(main_env->pic_trampolines_type) > 0) {
+ env.section = GAS_SECTION_PIC_TRAMPOLINES;
+ be_gas_dump_globals(main_env->pic_trampolines_type, &env,
+ only_emit_marked_entities);
+ if (be_gas_flavour == GAS_FLAVOUR_MACH_O) {
+ be_emit_cstring("\t.subsections_via_symbols\n");
+ be_emit_write_line();
+ }
+ }
}
GAS_SECTION_TLS, /**< thread local storage section */
GAS_SECTION_CTOR, /**< ctor section for instrumentation code init */
GAS_SECTION_CSTRING, /**< section for constant strings */
- GAS_SECTION_LAST = GAS_SECTION_CSTRING
+ GAS_SECTION_PIC_TRAMPOLINES, /**< trampolines for pic codes */
+ GAS_SECTION_PIC_SYMBOLS, /**< contains resolved pic symbols */
+ GAS_SECTION_LAST = GAS_SECTION_PIC_SYMBOLS
} be_gas_section_t;
/**
BE_TIME_OFF, /* no timing */
0, /* no opt profile */
0, /* try to omit frame pointer */
+ 0, /* create PIC code */
BE_VRFY_WARN, /* verification level: warn */
BE_SCHED_LIST, /* scheduler: list scheduler */
"linux", /* target OS name */
LC_OPT_ENT_STR ("config", "read another config file containing backend options", config_file, sizeof(config_file)),
LC_OPT_ENT_ENUM_MASK("dump", "dump irg on several occasions", &dump_var),
LC_OPT_ENT_BOOL ("omitfp", "omit frame pointer", &be_options.omit_fp),
+ LC_OPT_ENT_BOOL ("pic", "create PIC code", &be_options.pic),
LC_OPT_ENT_ENUM_PTR ("vrfy", "verify the backend irg", &vrfy_var),
LC_OPT_ENT_BOOL ("time", "get backend timing statistics", &be_options.timing),
LC_OPT_ENT_BOOL ("profile", "instrument the code for execution count profiling", &be_options.opt_profile),
obstack_init(&env->obst);
env->arch_env = obstack_alloc(&env->obst, sizeof(env->arch_env[0]));
env->options = &be_options;
+ env->pic_trampolines_type
+ = new_type_class(new_id_from_str("$PIC_TRAMPOLINE_TYPE"));
+ env->pic_symbols_type
+ = new_type_struct(new_id_from_str("$PIC_SYMBOLS_TYPE"));
+
+ remove_irp_type(env->pic_trampolines_type);
+ remove_irp_type(env->pic_symbols_type);
+ set_class_final(env->pic_trampolines_type, 1);
arch_env_init(env->arch_env, isa_if, file_handle, env);
be_dbg_close();
be_phi_handler_free(env->phi_handler);
obstack_free(&env->obst, NULL);
+
+ free_type(env->pic_trampolines_type);
+ free_type(env->pic_symbols_type);
}
/**
ir_graph *prof_init_irg = ir_profile_instrument(prof_filename, profile_default);
initialize_birg(&birgs[num_birgs], prof_init_irg, &env);
num_birgs++;
- set_method_img_section(get_irg_entity(prof_init_irg), section_constructors);
} else {
ir_profile_read(prof_filename);
}
#include "gen_ia32_regalloc_if.h"
#include "gen_ia32_machine.h"
#include "ia32_transform.h"
-#include "ia32_pbqp_transform.h"
#include "ia32_emitter.h"
#include "ia32_map_regs.h"
#include "ia32_optimize.h"
#include "ia32_fpu.h"
#include "ia32_architecture.h"
+#ifdef FIRM_GRGEN_BE
+#include "ia32_pbqp_transform.h"
+#endif
+
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
/* TODO: ugly */
if(cg->dump)
be_dump(cg->irg, "-pre_transform", dump_ir_block_graph_sched);
+#ifdef FIRM_GRGEN_BE
/* used for examination purposes only
* if(cg->dump)
dump_irg_grgen(cg->irg, "-pre_transform");
/* transform nodes into assembler instructions by PBQP magic */
ia32_transform_graph_by_pbqp(cg);
+#endif
if(cg->dump)
be_dump(cg->irg, "-after_pbqp_transform", dump_ir_block_graph_sched);
free(cg);
}
+static ir_node *ia32_get_pic_base(void *self) {
+ ir_node *block;
+ ia32_code_gen_t *cg = self;
+ ir_node *get_eip = cg->get_eip;
+ if(get_eip != NULL)
+ return get_eip;
+
+
+ block = get_irg_start_block(cg->irg);
+ get_eip = new_rd_ia32_GetEIP(NULL, cg->irg, block);
+ cg->get_eip = get_eip;
+
+ add_irn_dep(get_eip, get_irg_frame(cg->irg));
+
+ return get_eip;
+}
+
static void *ia32_cg_init(be_irg_t *birg);
static const arch_code_generator_if_t ia32_code_gen_if = {
ia32_cg_init,
+ ia32_get_pic_base,
ia32_before_abi, /* before abi introduce hook */
ia32_prepare_graph,
NULL, /* spill */
ir_node *noreg_xmm; /**< unique NoReg_XMM node */
ir_node *fpu_trunc_mode; /**< truncate fpu mode */
+ ir_node *get_eip; /**< get eip node */
struct obstack *obst;
};
static const arch_env_t *arch_env;
static const ia32_isa_t *isa;
static ia32_code_gen_t *cg;
+static int do_pic;
+static char pic_base_label[128];
/**
* Returns the register at in position pos.
}
}
-static void ia32_emit_entity(ir_entity *entity)
+static void ia32_emit_entity(ir_entity *entity, int no_pic_adjust)
{
ident *id;
id = get_entity_ld_ident(entity);
be_emit_ident(id);
- if(get_entity_owner(entity) == get_tls_type()) {
+ if (get_entity_owner(entity) == get_tls_type()) {
if (get_entity_visibility(entity) == visibility_external_allocated) {
be_emit_cstring("@INDNTPOFF");
} else {
be_emit_cstring("@NTPOFF");
}
}
+
+ if (!no_pic_adjust && do_pic) {
+ /* TODO: only do this when necessary */
+ be_emit_char('-');
+ be_emit_string(pic_base_label);
+ }
}
/**
if (ent != NULL) {
if (is_ia32_am_sc_sign(node))
be_emit_char('-');
- ia32_emit_entity(ent);
+ ia32_emit_entity(ent, 0);
}
if(offs != 0) {
if(attr->symconst != NULL) {
if(attr->sc_sign)
be_emit_char('-');
- ia32_emit_entity(attr->symconst);
+ ia32_emit_entity(attr->symconst, 0);
}
if(attr->symconst == NULL || attr->offset != 0) {
if(attr->symconst != NULL) {
be_emit_cstring("\tcall ");
if (ent) {
- ia32_emit_entity(ent);
+ ia32_emit_entity(ent, 1);
} else {
const arch_register_t *reg = get_in_reg(node, be_pos_Call_ptr);
be_emit_char('*');
emit_sbb( node, in_hi, out_hi);
}
+static void emit_ia32_GetEIP(const ir_node *node)
+{
+ be_emit_cstring("\tcall ");
+ be_emit_string(pic_base_label);
+ be_emit_finish_line_gas(node);
+
+ be_emit_string(pic_base_label);
+ be_emit_cstring(":\n");
+ be_emit_write_line();
+
+ be_emit_cstring("\tpopl ");
+ ia32_emit_dest_register(node, 0);
+ be_emit_char('\n');
+ be_emit_write_line();
+}
+
static void emit_be_Return(const ir_node *node)
{
unsigned pop;
IA32_EMIT(LdTls);
IA32_EMIT(Minus64Bit);
IA32_EMIT(Jcc);
+ IA32_EMIT(GetEIP);
/* benode emitter */
BE_EMIT(Call);
cg = ia32_cg;
isa = (const ia32_isa_t*) cg->arch_env->isa;
arch_env = cg->arch_env;
+ do_pic = cg->birg->main_env->options->pic;
ia32_register_emitters();
+ get_unique_label(pic_base_label, sizeof(pic_base_label), ".PIC_BASE");
+
be_dbg_method_begin(entity, be_abi_get_stack_layout(cg->birg->abi));
be_gas_emit_function_prolog(entity, ia32_cg_config.function_alignment);
mode => $mode_gp,
},
+GetEIP => {
+ op_flags => "c",
+ reg_req => { out => [ "gp" ] },
+ units => [ "GP" ],
+ latency => 5,
+ mode => $mode_gp,
+ modified_flags => $status_flags,
+},
+
Unknown_GP => {
state => "pinned",
op_flags => "c",
static const arch_code_generator_if_t mips_code_gen_if = {
mips_cg_init,
+ NULL, /* get_pic_base */
NULL, /* before abi introduce */
mips_prepare_graph,
NULL, /* spill */
static const arch_code_generator_if_t ppc32_code_gen_if = {
ppc32_cg_init,
+ NULL, /* get_pic_base */
ppc32_before_abi,
ppc32_prepare_graph,
NULL, /* spill */