X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fbegnuas.c;h=fc8dc4a546cd4ed50b99ae77c60d5c0651151475;hb=15e89f31af0f689717f64f3013bce503046b0e56;hp=07260b6fe719fc7ef3ecea517ce9e748777b4ae0;hpb=379fd05b0fb269dd9b9105810de1ce565b18e446;p=libfirm diff --git a/ir/be/begnuas.c b/ir/be/begnuas.c index 07260b6fe..fc8dc4a54 100644 --- a/ir/be/begnuas.c +++ b/ir/be/begnuas.c @@ -47,11 +47,11 @@ #include "beemitter.h" #include "be_dbgout.h" -typedef struct obstack obstack_t; - /** by default, we generate assembler code for the Linux gas */ be_gas_flavour_t be_gas_flavour = GAS_FLAVOUR_ELF; +static be_gas_section_t current_section = (be_gas_section_t) -1; + /** * Return the pseudo-instruction to be issued for a section switch * depending on the current flavour. @@ -68,7 +68,10 @@ static const char *get_section_name(be_gas_section_t section) { ".section\t.rodata", ".section\t.bss", ".section\t.tbss,\"awT\",@nobits", - ".section\t.ctors,\"aw\",@progbits" + ".section\t.ctors,\"aw\",@progbits", + NULL, /* no cstring section */ + NULL, + NULL }, { /* GAS_FLAVOUR_MINGW */ ".section\t.text", @@ -76,7 +79,10 @@ static const char *get_section_name(be_gas_section_t section) { ".section .rdata,\"dr\"", ".section\t.bss", ".section\t.tbss,\"awT\",@nobits", - ".section\t.ctors,\"aw\",@progbits" + ".section\t.ctors,\"aw\",@progbits", + NULL, + NULL, + NULL }, { /* GAS_FLAVOUR_YASM */ ".section\t.text", @@ -84,15 +90,21 @@ static const char *get_section_name(be_gas_section_t section) { ".section\t.rodata", ".section\t.bss", ".section\t.tbss,\"awT\",@nobits", - ".section\t.ctors,\"aw\",@progbits" + ".section\t.ctors,\"aw\",@progbits", + NULL, + NULL, + NULL }, { /* GAS_FLAVOUR_MACH_O */ ".text", ".data", ".const", ".data", - "", /* TLS is not supported on Mach-O */ - "" /* constructors aren't marked with sections in Mach-O */ + NULL, /* TLS is not supported on Mach-O */ + ".mod_init_func", + ".cstring", + ".section\t__IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5", + ".section\t__IMPORT,__pointers,non_lazy_symbol_pointers" } }; @@ -102,15 +114,21 @@ static const char *get_section_name(be_gas_section_t section) { } void be_gas_emit_switch_section(be_gas_section_t section) { + if(current_section == section) + return; + be_emit_char('\t'); be_emit_string(get_section_name(section)); be_emit_char('\n'); be_emit_write_line(); + current_section = section; } void be_gas_emit_function_prolog(ir_entity *entity, unsigned alignment) { const char *name = get_entity_ld_name(entity); + const char *fill_byte = ""; + unsigned maximum_skip; be_gas_emit_switch_section(GAS_SECTION_TEXT); @@ -121,15 +139,19 @@ void be_gas_emit_function_prolog(ir_entity *entity, unsigned alignment) be_emit_char('\n'); be_emit_write_line(); - if (be_gas_flavour != GAS_FLAVOUR_MACH_O) { - unsigned maximum_skip = (1 << alignment) - 1; + /* gcc fills space between function with 0x90, no idea if this is needed */ + if (be_gas_flavour == GAS_FLAVOUR_MACH_O) { + fill_byte = "0x90"; + } + + if (alignment > 0) { + maximum_skip = (1 << alignment) - 1; be_emit_cstring("\t.p2align "); - be_emit_irprintf("%u,,%u\n", alignment, maximum_skip); + be_emit_irprintf("%u,%s,%u\n", alignment, fill_byte, maximum_skip); be_emit_write_line(); } - if (get_entity_visibility(entity) == visibility_external_visible) { - be_emit_cstring(".global "); + be_emit_cstring(".globl "); be_emit_string(name); be_emit_char('\n'); be_emit_write_line(); @@ -183,12 +205,9 @@ void be_gas_emit_function_epilog(ir_entity *entity) * and even there NOT needed. So we might change it in the future. */ typedef struct _be_gas_decl_env { - obstack_t *rodata_obst; /**< An obstack that will be filled with all rodata entities. */ - obstack_t *data_obst; /**< An obstack that will be filled with the initialized entities. */ - obstack_t *bss_obst; /**< An obstack that will be filled with the uninitialized entities. */ - obstack_t *ctor_obst; /**< An obstack that will be filled with the constructor entities. */ const be_main_env_t *main_env; /**< The main backend environment, used for it's debug handle. */ - waitq *worklist; /**< A worklist we use to place not yet handled entities on. */ + be_gas_section_t section; + waitq *worklist; /**< A worklist we use to place not yet handled entities on. */ } be_gas_decl_env_t; /************************************************************************/ @@ -196,39 +215,44 @@ typedef struct _be_gas_decl_env { /** * Output a tarval. * - * @param obst the obstack where the data is written too * @param tv the tarval * @param bytes the width of the tarvals value in bytes */ -static void dump_arith_tarval(obstack_t *obst, tarval *tv, int bytes) +static void dump_arith_tarval(tarval *tv, int bytes) { switch (bytes) { - case 1: - obstack_printf(obst, "0x%02x", get_tarval_sub_bits(tv, 0)); - break; + be_emit_irprintf("0x%02x", get_tarval_sub_bits(tv, 0)); + return; case 2: - obstack_printf(obst, "0x%02x%02x", get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0)); - break; + be_emit_irprintf("0x%02x%02x", get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0)); + return; case 4: - obstack_printf(obst, "0x%02x%02x%02x%02x", + be_emit_irprintf("0x%02x%02x%02x%02x", get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0)); - break; + return; case 8: - obstack_printf(obst, "0x%02x%02x%02x%02x%02x%02x%02x%02x", + be_emit_irprintf("0x%02x%02x%02x%02x%02x%02x%02x%02x", get_tarval_sub_bits(tv, 7), get_tarval_sub_bits(tv, 6), get_tarval_sub_bits(tv, 5), get_tarval_sub_bits(tv, 4), get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0)); - break; + return; - case 10: case 12: - break; + be_emit_irprintf("0x%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x", get_tarval_sub_bits(tv, 11), + get_tarval_sub_bits(tv, 10), get_tarval_sub_bits(tv, 9), + get_tarval_sub_bits(tv, 8), get_tarval_sub_bits(tv, 7), + get_tarval_sub_bits(tv, 6), get_tarval_sub_bits(tv, 5), + get_tarval_sub_bits(tv, 4), get_tarval_sub_bits(tv, 3), + get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), + get_tarval_sub_bits(tv, 0)); + return; case 16: - obstack_printf(obst, "0x%02x%02x%02x%02x%02x%02x%02x%02x" + be_emit_irprintf("0x%02x%02x%02x%02x%02x%02x%02x%02x" "%02x%02x%02x%02x%02x%02x%02x%02x", get_tarval_sub_bits(tv, 15), get_tarval_sub_bits(tv, 16), get_tarval_sub_bits(tv, 13), get_tarval_sub_bits(tv, 12), @@ -238,13 +262,10 @@ static void dump_arith_tarval(obstack_t *obst, tarval *tv, int bytes) get_tarval_sub_bits(tv, 5), get_tarval_sub_bits(tv, 4), get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0)); - break; - - - default: - fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes); - assert(0); + return; } + + panic("Can't dump a tarval with %d bytes\n", bytes); } /** @@ -257,8 +278,8 @@ const char *be_gas_label_prefix(void) { /** * Dump a label. */ -static void dump_label(obstack_t *obst, ir_label_t label) { - obstack_printf(obst, "%s%ld", be_gas_label_prefix(), label); +static void dump_label(ir_label_t label) { + be_emit_irprintf("%s%ld", be_gas_label_prefix(), label); } /** @@ -317,11 +338,9 @@ static tarval *get_atomic_init_tv(ir_node *init) * Dump an atomic value. * * @param env the gas output environment - * @param obst an obstack the output is written to * @param init a node representing the atomic value (on the const code irg) */ -static void do_dump_atomic_init(be_gas_decl_env_t *env, obstack_t *obst, - ir_node *init) +static void do_dump_atomic_init(be_gas_decl_env_t *env, ir_node *init) { ir_mode *mode = get_irn_mode(init); int bytes = get_mode_size_bytes(mode); @@ -332,26 +351,25 @@ static void do_dump_atomic_init(be_gas_decl_env_t *env, obstack_t *obst, init = skip_Id(init); switch (get_irn_opcode(init)) { - case iro_Cast: - do_dump_atomic_init(env, obst, get_Cast_op(init)); + do_dump_atomic_init(env, get_Cast_op(init)); return; case iro_Conv: - do_dump_atomic_init(env, obst, get_Conv_op(init)); + do_dump_atomic_init(env, get_Conv_op(init)); return; case iro_Const: tv = get_Const_tarval(init); /* it's a arithmetic value */ - dump_arith_tarval(obst, tv, bytes); + dump_arith_tarval(tv, bytes); return; case iro_SymConst: switch (get_SymConst_kind(init)) { case symconst_addr_name: - obstack_printf(obst, "%s", get_id_str(get_SymConst_name(init))); + be_emit_ident(get_SymConst_name(init)); break; case symconst_addr_ent: @@ -360,7 +378,7 @@ static void do_dump_atomic_init(be_gas_decl_env_t *env, obstack_t *obst, waitq_put(env->worklist, ent); set_entity_backend_marked(ent, 1); } - obstack_printf(obst, "%s", get_entity_ld_name(ent)); + be_emit_ident(get_entity_ld_ident(ent)); break; case symconst_ofs_ent: @@ -371,25 +389,25 @@ static void do_dump_atomic_init(be_gas_decl_env_t *env, obstack_t *obst, set_entity_backend_marked(ent, 1); } #endif - obstack_printf(obst, "%d", get_entity_offset(ent)); + be_emit_irprintf("%d", get_entity_offset(ent)); break; case symconst_type_size: - obstack_printf(obst, "%u", get_type_size_bytes(get_SymConst_type(init))); + be_emit_irprintf("%u", get_type_size_bytes(get_SymConst_type(init))); break; case symconst_type_align: - obstack_printf(obst, "%u", get_type_alignment_bytes(get_SymConst_type(init))); + be_emit_irprintf("%u", get_type_alignment_bytes(get_SymConst_type(init))); break; case symconst_enum_const: tv = get_enumeration_value(get_SymConst_enum(init)); - dump_arith_tarval(obst, tv, bytes); + dump_arith_tarval(tv, bytes); break; case symconst_label: label = get_SymConst_label(init); - dump_label(obst, label); + dump_label(label); break; default: @@ -398,21 +416,30 @@ static void do_dump_atomic_init(be_gas_decl_env_t *env, obstack_t *obst, return; case iro_Add: - do_dump_atomic_init(env, obst, get_Add_left(init)); - obstack_printf(obst, " + "); - do_dump_atomic_init(env, obst, get_Add_right(init)); + if (!mode_is_int(mode) && !mode_is_reference(mode)) { + panic("Constant must be int or pointer for '+' to work"); + } + do_dump_atomic_init(env, get_Add_left(init)); + be_emit_cstring(" + "); + do_dump_atomic_init(env, get_Add_right(init)); return; case iro_Sub: - do_dump_atomic_init(env, obst, get_Sub_left(init)); - obstack_printf(obst, " - "); - do_dump_atomic_init(env, obst, get_Sub_right(init)); + if (!mode_is_int(mode) && !mode_is_reference(mode)) { + panic("Constant must be int or pointer for '-' to work"); + } + do_dump_atomic_init(env, get_Sub_left(init)); + be_emit_cstring(" - "); + do_dump_atomic_init(env, get_Sub_right(init)); return; case iro_Mul: - do_dump_atomic_init(env, obst, get_Mul_left(init)); - obstack_printf(obst, " * "); - do_dump_atomic_init(env, obst, get_Mul_right(init)); + if (!mode_is_int(mode) && !mode_is_reference(mode)) { + panic("Constant must be int or pointer for '*' to work"); + } + do_dump_atomic_init(env, get_Mul_left(init)); + be_emit_cstring(" * "); + do_dump_atomic_init(env, get_Mul_right(init)); return; default: @@ -423,26 +450,24 @@ static void do_dump_atomic_init(be_gas_decl_env_t *env, obstack_t *obst, /** * Dumps the type for given size (.byte, .long, ...) * - * @param obst an obstack the output is written to * @param size the size in bytes */ -static void dump_size_type(obstack_t *obst, size_t size) { +static void dump_size_type(size_t size) { switch (size) { - case 1: - obstack_printf(obst, "\t.byte\t"); + be_emit_cstring("\t.byte\t"); break; case 2: - obstack_printf(obst, "\t.word\t"); + be_emit_cstring("\t.word\t"); break; case 4: - obstack_printf(obst, "\t.long\t"); + be_emit_cstring("\t.long\t"); break; case 8: - obstack_printf(obst, "\t.quad\t"); + be_emit_cstring("\t.quad\t"); break; case 10: @@ -451,31 +476,29 @@ static void dump_size_type(obstack_t *obst, size_t size) { break; case 16: - obstack_printf(obst, "\t.octa\t"); + be_emit_cstring("\t.octa\t"); break; default: - fprintf(stderr, "Try to dump a type with %u bytes\n", (unsigned) size); - assert(0); + panic("Try to dump a type with %u bytes\n", (unsigned) size); } } /** - * Dump an atomic value to an obstack. + * Emit an atomic value. * * @param env the gas output environment - * @param obst an obstack the output is written to * @param init a node representing the atomic value (on the const code irg) */ -static void dump_atomic_init(be_gas_decl_env_t *env, obstack_t *obst, - ir_node *init) +static void dump_atomic_init(be_gas_decl_env_t *env, ir_node *init) { ir_mode *mode = get_irn_mode(init); int bytes = get_mode_size_bytes(mode); - dump_size_type(obst, bytes); - do_dump_atomic_init(env, obst, init); - obstack_printf(obst, "\n"); + dump_size_type(bytes); + do_dump_atomic_init(env, init); + be_emit_char('\n'); + be_emit_write_line(); } /************************************************************************/ @@ -485,6 +508,7 @@ static void dump_atomic_init(be_gas_decl_env_t *env, obstack_t *obst, static int initializer_is_string_const(const ir_initializer_t *initializer) { size_t i, len; + int found_printable = 0; if(initializer->kind != IR_INITIALIZER_COMPOUND) return 0; @@ -510,16 +534,16 @@ static int initializer_is_string_const(const ir_initializer_t *initializer) return 0; c = get_tarval_long(tv); - if (i < len - 1) { - if (!isgraph(c) && !isspace(c)) - return 0; - } else { - if (c != 0) - return 0; - } + if (isgraph(c) || isspace(c)) + found_printable = 1; + else if(c != 0) + return 0; + + if (i == len - 1 && c != '\0') + return 0; } - return 1; + return found_printable; } /** @@ -532,6 +556,7 @@ static int ent_is_string_const(ir_entity *ent) ir_type *type, *element_type; ir_mode *mode; int i, c, n; + int found_printable = 0; type = get_entity_type(ent); @@ -565,34 +590,42 @@ static int ent_is_string_const(ir_entity *ent) c = (int) get_tarval_long(get_Const_tarval(irn)); - if((i < n - 1 && !(isgraph(c) || isspace(c))) - || (i == n - 1 && c != '\0')) + if (isgraph(c) || isspace(c)) + found_printable = 1; + else if(c != 0) + return 0; + + if (i == n - 1 && c != '\0') return 0; } } /* then we can emit it as a string constant */ - return 1; + return found_printable; } /** * Dump a string constant. * No checks are made!! * - * @param obst The obst to dump on. * @param ent The entity to dump. */ -static void dump_string_cst(obstack_t *obst, ir_entity *ent) +static void dump_string_cst(ir_entity *ent) { - int i, n; + int i, len; ir_type *type; int type_size; int remaining_space; - obstack_printf(obst, "\t.string \""); - n = get_compound_ent_n_values(ent); + len = get_compound_ent_n_values(ent); + if (be_gas_flavour == GAS_FLAVOUR_MACH_O) { + be_emit_cstring("\t.ascii \""); + } else { + be_emit_cstring("\t.string \""); + len -= 1; + } - for (i = 0; i < n-1; ++i) { + for (i = 0; i < len; ++i) { ir_node *irn; int c; @@ -600,39 +633,44 @@ static void dump_string_cst(obstack_t *obst, ir_entity *ent) c = (int) get_tarval_long(get_Const_tarval(irn)); switch (c) { - case '"' : obstack_printf(obst, "\\\""); break; - case '\n': obstack_printf(obst, "\\n"); break; - case '\r': obstack_printf(obst, "\\r"); break; - case '\t': obstack_printf(obst, "\\t"); break; - case '\\': obstack_printf(obst, "\\\\"); break; + case '"' : be_emit_cstring("\\\""); break; + case '\n': be_emit_cstring("\\n"); break; + case '\r': be_emit_cstring("\\r"); break; + case '\t': be_emit_cstring("\\t"); break; + case '\\': be_emit_cstring("\\\\"); break; default : if (isprint(c)) - obstack_printf(obst, "%c", c); + be_emit_char(c); else - obstack_printf(obst, "\\%o", c); + be_emit_irprintf("\\%o", c); break; } } - obstack_printf(obst, "\"\n"); + be_emit_cstring("\"\n"); + be_emit_write_line(); type = get_entity_type(ent); type_size = get_type_size_bytes(type); - remaining_space = type_size - n; + remaining_space = type_size - len; assert(remaining_space >= 0); if(remaining_space > 0) { - obstack_printf(obst, "\t.skip\t%d\n", remaining_space); + be_emit_irprintf("\t.skip\t%d\n", remaining_space); } } -static void dump_string_initializer(obstack_t *obst, - const ir_initializer_t *initializer) +static void dump_string_initializer(const ir_initializer_t *initializer) { size_t i, len; - obstack_printf(obst, "\t.string \""); - len = initializer->compound.n_initializers; - for(i = 0; i < len - 1; ++i) { + if(be_gas_flavour == GAS_FLAVOUR_MACH_O) { + be_emit_cstring("\t.ascii \""); + } else { + be_emit_cstring("\t.string \""); + len -= 1; + } + + for(i = 0; i < len; ++i) { const ir_initializer_t *sub_initializer = get_initializer_compound_value(initializer, i); @@ -640,20 +678,21 @@ static void dump_string_initializer(obstack_t *obst, int c = get_tarval_long(tv); switch (c) { - case '"' : obstack_printf(obst, "\\\""); break; - case '\n': obstack_printf(obst, "\\n"); break; - case '\r': obstack_printf(obst, "\\r"); break; - case '\t': obstack_printf(obst, "\\t"); break; - case '\\': obstack_printf(obst, "\\\\"); break; + case '"' : be_emit_cstring("\\\""); break; + case '\n': be_emit_cstring("\\n"); break; + case '\r': be_emit_cstring("\\r"); break; + case '\t': be_emit_cstring("\\t"); break; + case '\\': be_emit_cstring("\\\\"); break; default : if (isprint(c)) - obstack_printf(obst, "%c", c); + be_emit_char(c); else - obstack_printf(obst, "\\%o", c); + be_emit_irprintf("\\%o", c); break; } } - obstack_printf(obst, "\"\n"); + be_emit_cstring("\"\n"); + be_emit_write_line(); } enum normal_or_bitfield_kind { @@ -868,8 +907,7 @@ static void dump_ir_initializer(normal_or_bitfield *vals, panic("invalid ir_initializer kind found"); } -static void dump_initializer(be_gas_decl_env_t *env, obstack_t *obst, - ir_entity *entity) +static void dump_initializer(be_gas_decl_env_t *env, ir_entity *entity) { const ir_initializer_t *initializer = entity->attr.initializer; ir_type *type; @@ -878,7 +916,7 @@ static void dump_initializer(be_gas_decl_env_t *env, obstack_t *obst, size_t k; if(initializer_is_string_const(initializer)) { - dump_string_initializer(obst, initializer); + dump_string_initializer(initializer); return; } @@ -903,13 +941,14 @@ static void dump_initializer(be_gas_decl_env_t *env, obstack_t *obst, /* now write values sorted */ for (k = 0; k < size; ) { - int space = 0, skip = 0; + int space = 0; + int elem_size = 1; if (vals[k].kind == NORMAL) { if(vals[k].v.value != NULL) { - dump_atomic_init(env, obst, vals[k].v.value); - skip = get_mode_size_bytes(get_irn_mode(vals[k].v.value)) - 1; + dump_atomic_init(env, vals[k].v.value); + elem_size = get_mode_size_bytes(get_irn_mode(vals[k].v.value)); } else { - space = 1; + elem_size = 0; } } else if(vals[k].kind == TARVAL) { tarval *tv = vals[k].v.tarval; @@ -917,43 +956,43 @@ static void dump_initializer(be_gas_decl_env_t *env, obstack_t *obst, assert(tv != NULL); - skip = size - 1; - dump_size_type(obst, size); - dump_arith_tarval(obst, tv, size); - obstack_1grow(obst, '\n'); + elem_size = size; + dump_size_type(size); + dump_arith_tarval(tv, size); + be_emit_char('\n'); + be_emit_write_line(); } else { assert(vals[k].kind == BITFIELD); - obstack_printf(obst, "\t.byte\t%d\n", vals[k].v.bf_val); + be_emit_irprintf("\t.byte\t%d\n", vals[k].v.bf_val); + be_emit_write_line(); } - ++k; + k += elem_size; while (k < size && vals[k].kind == NORMAL && vals[k].v.value == NULL) { ++space; ++k; } - space -= skip; - assert(space >= 0); /* a gap */ - if (space > 0) - obstack_printf(obst, "\t.skip\t%d\n", space); + if (space > 0) { + be_emit_irprintf("\t.skip\t%d\n", space); + be_emit_write_line(); + } } xfree(vals); - } /** * Dump an initializer for a compound entity. */ -static void dump_compound_init(be_gas_decl_env_t *env, obstack_t *obst, - ir_entity *ent) +static void dump_compound_init(be_gas_decl_env_t *env, ir_entity *ent) { normal_or_bitfield *vals; int i, j, n; unsigned k, last_ofs; if(ent->has_initializer) { - dump_initializer(env, obst, ent); + dump_initializer(env, ent); return; } @@ -1029,14 +1068,14 @@ static void dump_compound_init(be_gas_decl_env_t *env, obstack_t *obst, int space = 0, skip = 0; if (vals[k].kind == NORMAL) { if(vals[k].v.value != NULL) { - dump_atomic_init(env, obst, vals[k].v.value); + dump_atomic_init(env, vals[k].v.value); skip = get_mode_size_bytes(get_irn_mode(vals[k].v.value)) - 1; } else { space = 1; } } else { assert(vals[k].kind == BITFIELD); - obstack_printf(obst, "\t.byte\t%d\n", vals[k].v.bf_val); + be_emit_irprintf("\t.byte\t%d\n", vals[k].v.bf_val); } ++k; @@ -1048,71 +1087,91 @@ static void dump_compound_init(be_gas_decl_env_t *env, obstack_t *obst, assert(space >= 0); /* a gap */ - if (space > 0) - obstack_printf(obst, "\t.skip\t%d\n", space); + if (space > 0) { + be_emit_irprintf("\t.skip\t%d\n", space); + be_emit_write_line(); + } } xfree(vals); } +static void emit_align(unsigned alignment) +{ + if (!is_po2(alignment)) + panic("alignment not a power of 2"); + + be_emit_irprintf(".p2align\t%u\n", log2_floor(alignment)); + be_emit_write_line(); +} + /** * Dump a global entity. * * @param env the gas output environment * @param ent the entity to be dumped - * @param emit_commons if non-zero, emit commons (non-local uninitialized entities) */ -static void dump_global(be_gas_decl_env_t *env, ir_entity *ent, int emit_commons) +static void dump_global(be_gas_decl_env_t *env, ir_entity *ent) { - obstack_t *obst; - ir_type *type = get_entity_type(ent); - const char *ld_name = get_entity_ld_name(ent); - unsigned align = get_type_alignment_bytes(type); - int emit_as_common = 0; - ir_variability variability; - ir_visibility visibility; - - obst = env->data_obst; - if (is_Method_type(type)) { - if (be_gas_flavour != GAS_FLAVOUR_MACH_O - && get_method_img_section(ent) == section_constructors) { - obst = env->ctor_obst; - obstack_printf(obst, ".balign\t%u\n", align); - dump_size_type(obst, align); - obstack_printf(obst, "%s\n", ld_name); - } - + ir_type *type = get_entity_type(ent); + ident *ld_ident = get_entity_ld_ident(ent); + unsigned align = get_type_alignment_bytes(type); + int emit_as_common = 0; + be_gas_section_t section = env->section; + 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; } - variability = get_entity_variability(ent); - visibility = get_entity_visibility(ent); - if (variability == variability_constant) { + if (section != (be_gas_section_t) -1) { + emit_as_common = 0; + } else if (variability == variability_constant) { /* a constant entity, put it on the rdata */ - obst = env->rodata_obst; + section = GAS_SECTION_RODATA; + if (be_gas_flavour == GAS_FLAVOUR_MACH_O + && ent_is_string_const(ent)) { + section = GAS_SECTION_CSTRING; + } } else if (variability == variability_uninitialized) { /* uninitialized entity put it in bss segment */ - obst = env->bss_obst; - if (emit_commons && visibility != visibility_local) + section = GAS_SECTION_COMMON; + if (visibility != visibility_local) emit_as_common = 1; + } else { + section = GAS_SECTION_DATA; + } + + if(!emit_as_common) { + be_gas_emit_switch_section(section); } - be_dbg_variable(obst, ent); + be_dbg_variable(ent); /* global or not global */ if (visibility == visibility_external_visible && !emit_as_common) { - obstack_printf(obst, ".global\t%s\n", ld_name); + be_emit_cstring(".globl\t"); + be_emit_ident(ld_ident); + be_emit_char('\n'); + be_emit_write_line(); } else if(visibility == visibility_external_allocated) { - obstack_printf(obst, ".global\t%s\n", ld_name); + be_emit_cstring(".globl\t"); + be_emit_ident(ld_ident); + be_emit_char('\n'); + be_emit_write_line(); /* we can return now... */ return; } /* alignment */ - if (align > 1 && !emit_as_common) { - obstack_printf(obst, ".balign\t%u\n", align); + if (align > 1 && !emit_as_common && section != GAS_SECTION_PIC_TRAMPOLINES + && section != GAS_SECTION_PIC_SYMBOLS) { + emit_align(align); } if (!emit_as_common) { - obstack_printf(obst, "%s:\n", ld_name); + be_emit_ident(ld_ident); + be_emit_cstring(":\n"); + be_emit_write_line(); } if (variability == variability_uninitialized) { @@ -1121,34 +1180,48 @@ static void dump_global(be_gas_decl_env_t *env, ir_entity *ent, int emit_commons case GAS_FLAVOUR_ELF: case GAS_FLAVOUR_MACH_O: case GAS_FLAVOUR_YASM: - obstack_printf(obst, "\t.comm %s,%u,%u\n", - ld_name, get_type_size_bytes(type), align); + be_emit_irprintf("\t.comm %s,%u,%u\n", + get_id_str(ld_ident), get_type_size_bytes(type), align); + be_emit_write_line(); break; case GAS_FLAVOUR_MINGW: - obstack_printf(obst, "\t.comm %s,%u # %u\n", - ld_name, get_type_size_bytes(type), align); + be_emit_irprintf("\t.comm %s,%u # %u\n", + get_id_str(ld_ident), get_type_size_bytes(type), 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 { - obstack_printf(obst, "\t.zero %u\n", get_type_size_bytes(type)); + be_emit_irprintf("\t.space %u\n", get_type_size_bytes(type)); + be_emit_write_line(); } } else { if (is_atomic_entity(ent)) { - dump_atomic_init(env, obst, get_atomic_ent_value(ent)); + dump_atomic_init(env, get_atomic_ent_value(ent)); } else { /* sort_compound_ent_values(ent); */ switch (get_type_tpop_code(get_entity_type(ent))) { case tpo_array: if (ent_is_string_const(ent)) - dump_string_cst(obst, ent); + dump_string_cst(ent); else - dump_compound_init(env, obst, ent); + dump_compound_init(env, ent); break; case tpo_struct: case tpo_class: case tpo_union: - dump_compound_init(env, obst, ent); + dump_compound_init(env, ent); break; default: assert(0); @@ -1162,12 +1235,11 @@ static void dump_global(be_gas_decl_env_t *env, ir_entity *ent, int emit_commons * * @param gt a global like type, either the global or the TLS one * @param env an environment - * @param emit_commons if non-zero, emit commons (non-local uninitialized entities) * @param only_emit_marked if non-zero, external allocated entities that do not have * its visited flag set are ignored */ static void be_gas_dump_globals(ir_type *gt, be_gas_decl_env_t *env, - int emit_commons, int only_emit_marked) + int only_emit_marked) { int i, n = get_compound_n_members(gt); waitq *worklist = new_waitq(); @@ -1194,7 +1266,7 @@ static void be_gas_dump_globals(ir_type *gt, be_gas_decl_env_t *env, while (!waitq_empty(worklist)) { ir_entity *ent = waitq_get(worklist); - dump_global(env, ent, emit_commons); + dump_global(env, ent); } del_waitq(worklist); @@ -1208,83 +1280,29 @@ void be_gas_emit_decls(const be_main_env_t *main_env, int only_emit_marked_entities) { be_gas_decl_env_t env; - obstack_t rodata; - obstack_t data; - obstack_t bss; - obstack_t ctor; - int size; - char *cp; - - /* dump the global type */ - obstack_init(&rodata); - obstack_init(&data); - obstack_init(&bss); - obstack_init(&ctor); - - env.rodata_obst = &rodata; - env.data_obst = &data; - env.bss_obst = &bss; - env.ctor_obst = &ctor; - env.main_env = main_env; - - be_gas_dump_globals(get_glob_type(), &env, 1, only_emit_marked_entities); - - size = obstack_object_size(&data); - cp = obstack_finish(&data); - if (size > 0) { - be_gas_emit_switch_section(GAS_SECTION_DATA); - be_emit_string_len(cp, size); - be_emit_write_line(); - } - - size = obstack_object_size(&rodata); - cp = obstack_finish(&rodata); - if (size > 0) { - be_gas_emit_switch_section(GAS_SECTION_RODATA); - be_emit_string_len(cp, size); - be_emit_write_line(); - } - - size = obstack_object_size(&bss); - cp = obstack_finish(&bss); - if (size > 0) { - be_gas_emit_switch_section(GAS_SECTION_COMMON); - be_emit_string_len(cp, size); - be_emit_write_line(); - } - - size = obstack_object_size(&ctor); - cp = obstack_finish(&ctor); - if (size > 0) { - be_gas_emit_switch_section(GAS_SECTION_CTOR); - be_emit_string_len(cp, size); - be_emit_write_line(); - } - - obstack_free(&rodata, NULL); - obstack_free(&data, NULL); - obstack_free(&bss, NULL); - obstack_free(&ctor, NULL); - - /* dump the Thread Local Storage */ - obstack_init(&data); - - env.rodata_obst = &data; - env.data_obst = &data; - env.bss_obst = &data; - env.ctor_obst = NULL; - - be_gas_dump_globals(get_tls_type(), &env, 0, only_emit_marked_entities); - - size = obstack_object_size(&data); - cp = obstack_finish(&data); - if (size > 0) { - be_gas_emit_switch_section(GAS_SECTION_TLS); - be_emit_cstring(".balign\t32\n"); - be_emit_write_line(); - be_emit_string_len(cp, size); - be_emit_write_line(); + memset(&env, 0, sizeof(env)); + + env.main_env = main_env; + + /* dump global type */ + env.section = (be_gas_section_t) -1; + be_gas_dump_globals(get_glob_type(), &env, only_emit_marked_entities); + env.section = GAS_SECTION_TLS; + be_gas_dump_globals(get_tls_type(), &env, only_emit_marked_entities); + 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(); + } } - - obstack_free(&data, NULL); }