started implementing Mac Style PIC
authorMatthias Braun <matze@braunis.de>
Thu, 3 Apr 2008 21:08:42 +0000 (21:08 +0000)
committerMatthias Braun <matze@braunis.de>
Thu, 3 Apr 2008 21:08:42 +0000 (21:08 +0000)
[r19102]

14 files changed:
ir/be/TEMPLATE/bearch_TEMPLATE.c
ir/be/arm/bearch_arm.c
ir/be/be_t.h
ir/be/beabi.c
ir/be/bearch_t.h
ir/be/begnuas.c
ir/be/begnuas.h
ir/be/bemain.c
ir/be/ia32/bearch_ia32.c
ir/be/ia32/bearch_ia32_t.h
ir/be/ia32/ia32_emitter.c
ir/be/ia32/ia32_spec.pl
ir/be/mips/bearch_mips.c
ir/be/ppc32/bearch_ppc32.c

index 633115f..3ee2f73 100644 (file)
@@ -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 */
index 3501895..e1e67cd 100644 (file)
@@ -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 */
index d3c63fd..cc08bcd 100644 (file)
@@ -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;
 };
 
 /**
index ed5cd50..9e3a970 100644 (file)
@@ -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);
 
index 80c7f62..70914ac 100644 (file)
@@ -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.
index b79ba28..7016855 100644 (file)
@@ -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();
+               }
+       }
 }
index f46ae13..15b461f 100644 (file)
@@ -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;
 
 /**
index 6a29f86..894bebe 100644 (file)
@@ -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);
        }
index d20c867..821c792 100644 (file)
@@ -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"
 #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 */
index 6b2e2d2..2c831df 100644 (file)
@@ -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;
 };
index 4f3c794..1b82926 100644 (file)
@@ -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);
 
index f3fe108..37b40a5 100644 (file)
@@ -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",
index b525d82..46b45b2 100644 (file)
@@ -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 */
index ea04f8a..c5e3c6b 100644 (file)
@@ -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 */