From efdfc8f707c7e48c856cf9a945209ba421f26b70 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Thu, 3 Apr 2008 21:08:42 +0000 Subject: [PATCH] started implementing Mac Style PIC [r19102] --- ir/be/TEMPLATE/bearch_TEMPLATE.c | 1 + ir/be/arm/bearch_arm.c | 1 + ir/be/be_t.h | 3 ++ ir/be/beabi.c | 93 ++++++++++++++++++++++++++++++++ ir/be/bearch_t.h | 7 +++ ir/be/begnuas.c | 41 +++++++++++++- ir/be/begnuas.h | 4 +- ir/be/bemain.c | 14 ++++- ir/be/ia32/bearch_ia32.c | 25 ++++++++- ir/be/ia32/bearch_ia32_t.h | 1 + ir/be/ia32/ia32_emitter.c | 38 +++++++++++-- ir/be/ia32/ia32_spec.pl | 9 ++++ ir/be/mips/bearch_mips.c | 1 + ir/be/ppc32/bearch_ppc32.c | 1 + 14 files changed, 229 insertions(+), 10 deletions(-) diff --git a/ir/be/TEMPLATE/bearch_TEMPLATE.c b/ir/be/TEMPLATE/bearch_TEMPLATE.c index 633115f9c..3ee2f7361 100644 --- a/ir/be/TEMPLATE/bearch_TEMPLATE.c +++ b/ir/be/TEMPLATE/bearch_TEMPLATE.c @@ -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 */ diff --git a/ir/be/arm/bearch_arm.c b/ir/be/arm/bearch_arm.c index 3501895cd..e1e67cd9c 100644 --- a/ir/be/arm/bearch_arm.c +++ b/ir/be/arm/bearch_arm.c @@ -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 */ diff --git a/ir/be/be_t.h b/ir/be/be_t.h index d3c63fd5e..cc08bcdb7 100644 --- a/ir/be/be_t.h +++ b/ir/be/be_t.h @@ -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; }; /** diff --git a/ir/be/beabi.c b/ir/be/beabi.c index ed5cd50f4..9e3a970a0 100644 --- a/ir/be/beabi.c +++ b/ir/be/beabi.c @@ -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); diff --git a/ir/be/bearch_t.h b/ir/be/bearch_t.h index 80c7f62ad..70914ac5a 100644 --- a/ir/be/bearch_t.h +++ b/ir/be/bearch_t.h @@ -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. diff --git a/ir/be/begnuas.c b/ir/be/begnuas.c index b79ba281f..701685548 100644 --- a/ir/be/begnuas.c +++ b/ir/be/begnuas.c @@ -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(); + } + } } diff --git a/ir/be/begnuas.h b/ir/be/begnuas.h index f46ae139b..15b461f2f 100644 --- a/ir/be/begnuas.h +++ b/ir/be/begnuas.h @@ -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; /** diff --git a/ir/be/bemain.c b/ir/be/bemain.c index 6a29f868a..894bebe19 100644 --- a/ir/be/bemain.c +++ b/ir/be/bemain.c @@ -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); } diff --git a/ir/be/ia32/bearch_ia32.c b/ir/be/ia32/bearch_ia32.c index d20c867d0..821c79273 100644 --- a/ir/be/ia32/bearch_ia32.c +++ b/ir/be/ia32/bearch_ia32.c @@ -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 */ diff --git a/ir/be/ia32/bearch_ia32_t.h b/ir/be/ia32/bearch_ia32_t.h index 6b2e2d2eb..2c831df80 100644 --- a/ir/be/ia32/bearch_ia32_t.h +++ b/ir/be/ia32/bearch_ia32_t.h @@ -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; }; diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index 4f3c794cc..1b8292666 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -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); diff --git a/ir/be/ia32/ia32_spec.pl b/ir/be/ia32/ia32_spec.pl index f3fe10800..37b40a51d 100644 --- a/ir/be/ia32/ia32_spec.pl +++ b/ir/be/ia32/ia32_spec.pl @@ -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", diff --git a/ir/be/mips/bearch_mips.c b/ir/be/mips/bearch_mips.c index b525d82c9..46b45b2f0 100644 --- a/ir/be/mips/bearch_mips.c +++ b/ir/be/mips/bearch_mips.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 */ diff --git a/ir/be/ppc32/bearch_ppc32.c b/ir/be/ppc32/bearch_ppc32.c index ea04f8a3c..c5e3c6b99 100644 --- a/ir/be/ppc32/bearch_ppc32.c +++ b/ir/be/ppc32/bearch_ppc32.c @@ -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 */ -- 2.20.1