Commit efdfc8f7 authored by Matthias Braun's avatar Matthias Braun
Browse files

started implementing Mac Style PIC

[r19102]
parent d1142773
......@@ -321,6 +321,7 @@ static void *TEMPLATE_cg_init(be_irg_t *birg);
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 */
......
......@@ -577,6 +577,7 @@ static void *arm_cg_init(be_irg_t *birg);
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 */
......
......@@ -67,6 +67,7 @@ struct be_options_t {
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 */
......@@ -83,6 +84,8 @@ struct be_main_env_t {
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;
};
/**
......
......@@ -115,6 +115,7 @@ static heights_t *ir_heights;
/* 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;
/*
_ ____ ___ ____ _ _ _ _
......@@ -2000,6 +2001,93 @@ void fix_call_state_inputs(be_abi_irg_t *env)
}
}
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]));
......@@ -2012,6 +2100,7 @@ be_abi_irg_t *be_abi_introduce(be_irg_t *birg)
unsigned *limited_bitset;
be_omit_fp = birg->main_env->options->omit_fp;
be_pic = birg->main_env->options->pic;
obstack_init(&env->obst);
......@@ -2044,6 +2133,10 @@ be_abi_irg_t *be_abi_introduce(be_irg_t *birg)
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);
......
......@@ -317,6 +317,11 @@ struct arch_code_generator_if_t {
*/
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.
*/
......@@ -387,6 +392,8 @@ do { \
#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.
......
......@@ -69,7 +69,9 @@ static const char *get_section_name(be_gas_section_t section) {
".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",
......@@ -79,6 +81,8 @@ static const char *get_section_name(be_gas_section_t section) {
".section\t.tbss,\"awT\",@nobits",
".section\t.ctors,\"aw\",@progbits",
NULL,
NULL,
NULL
},
{ /* GAS_FLAVOUR_YASM */
".section\t.text",
......@@ -87,6 +91,8 @@ static const char *get_section_name(be_gas_section_t section) {
".section\t.bss",
".section\t.tbss,\"awT\",@nobits",
".section\t.ctors,\"aw\",@progbits",
NULL,
NULL,
NULL
},
{ /* GAS_FLAVOUR_MACH_O */
......@@ -96,7 +102,9 @@ static const char *get_section_name(be_gas_section_t section) {
".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"
}
};
......@@ -1099,6 +1107,10 @@ static void dump_global(be_gas_decl_env_t *env, ir_entity *ent)
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) {
......@@ -1136,7 +1148,8 @@ static void dump_global(be_gas_decl_env_t *env, ir_entity *ent)
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);
}
......@@ -1162,6 +1175,17 @@ static void dump_global(be_gas_decl_env_t *env, ir_entity *ent)
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();
......@@ -1253,4 +1277,17 @@ void be_gas_emit_decls(const be_main_env_t *main_env,
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();
}
}
}
......@@ -41,7 +41,9 @@ typedef enum section_t {
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;
/**
......
......@@ -87,6 +87,7 @@ static be_options_t be_options = {
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 */
......@@ -149,6 +150,7 @@ static const lc_opt_table_entry_t be_main_options[] = {
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),
......@@ -249,6 +251,14 @@ static be_main_env_t *be_init_env(be_main_env_t *env, FILE *file_handle)
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);
......@@ -275,6 +285,9 @@ static void be_done_env(be_main_env_t *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);
}
/**
......@@ -443,7 +456,6 @@ static void be_main_loop(FILE *file_handle, const char *cup_name)
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);
}
......
......@@ -76,7 +76,6 @@
#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"
......@@ -87,6 +86,10 @@
#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 */
......@@ -957,6 +960,7 @@ static void ia32_prepare_graph(void *self) {
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");
......@@ -964,6 +968,7 @@ static void ia32_prepare_graph(void *self) {
/* 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);
......@@ -1515,10 +1520,28 @@ static void ia32_codegen(void *self) {
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 */
......
......@@ -75,6 +75,7 @@ struct ia32_code_gen_t {
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;
};
......
......@@ -71,6 +71,8 @@ DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
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.
......@@ -456,7 +458,7 @@ void ia32_emit_unop(const ir_node *node, int pos) {
}
}
static void ia32_emit_entity(ir_entity *entity)
static void ia32_emit_entity(ir_entity *entity, int no_pic_adjust)
{
ident *id;
......@@ -464,13 +466,19 @@ static void ia32_emit_entity(ir_entity *entity)
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);
}
}
/**
......@@ -491,7 +499,7 @@ void ia32_emit_am(const ir_node *node) {
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) {
......@@ -1138,7 +1146,7 @@ static void emit_ia32_Immediate(const ir_node *node)
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) {
......@@ -1532,7 +1540,7 @@ static void emit_be_Call(const ir_node *node)
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('*');
......@@ -1789,6 +1797,22 @@ zero_neg:
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;
......@@ -1852,6 +1876,7 @@ static void ia32_register_emitters(void) {
IA32_EMIT(LdTls);
IA32_EMIT(Minus64Bit);
IA32_EMIT(Jcc);
IA32_EMIT(GetEIP);
/* benode emitter */
BE_EMIT(Call);
......@@ -2090,9 +2115,12 @@ void ia32_gen_routine(ia32_code_gen_t *ia32_cg, ir_graph *irg)
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);
......
......@@ -1174,6 +1174,15 @@ Const => {
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",
......
......@@ -552,6 +552,7 @@ static void *mips_cg_init(be_irg_t *birg);
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 */
......
......@@ -595,6 +595,7 @@ static void *ppc32_cg_init(be_irg_t *birg);
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 */
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment