+static be_gas_section_t determine_basic_section(const ir_entity *entity)
+{
+ ir_linkage linkage;
+
+ if (is_method_entity(entity))
+ return GAS_SECTION_TEXT;
+
+ linkage = get_entity_linkage(entity);
+ if (linkage & IR_LINKAGE_CONSTANT) {
+ /* mach-o is the only one with a cstring section */
+ if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O
+ && entity_is_string_const(entity))
+ return GAS_SECTION_CSTRING;
+
+ return GAS_SECTION_RODATA;
+ }
+ if (entity_is_null(entity))
+ return GAS_SECTION_BSS;
+
+ return GAS_SECTION_DATA;
+}
+
+static be_gas_section_t determine_section(be_gas_decl_env_t *env,
+ const ir_entity *entity)
+{
+ ir_type *owner = get_entity_owner(entity);
+
+ if (owner == get_segment_type(IR_SEGMENT_GLOBAL)) {
+ be_gas_section_t section = determine_basic_section(entity);
+ if (is_comdat(entity))
+ section |= GAS_SECTION_FLAG_COMDAT;
+ return section;
+ } else if (env != NULL && owner == env->main_env->pic_symbols_type) {
+ return GAS_SECTION_PIC_SYMBOLS;
+ } else if (env != NULL && owner == env->main_env->pic_trampolines_type) {
+ return GAS_SECTION_PIC_TRAMPOLINES;
+ } else if (owner == get_segment_type(IR_SEGMENT_CONSTRUCTORS)) {
+ return GAS_SECTION_CONSTRUCTORS;
+ } else if (owner == get_segment_type(IR_SEGMENT_DESTRUCTORS)) {
+ return GAS_SECTION_DESTRUCTORS;
+ } else if (owner == get_segment_type(IR_SEGMENT_THREAD_LOCAL)) {
+ be_gas_section_t section = determine_basic_section(entity);
+ if (is_comdat(entity))
+ section |= GAS_SECTION_FLAG_COMDAT;
+
+ return section | GAS_SECTION_FLAG_TLS;
+ }
+
+ /* the java frontend keeps some functions inside classes */
+ if (is_Class_type(owner)) {
+ return determine_basic_section(entity);
+ }
+
+ panic("Couldn't determine section for %+F?!?", entity);
+}
+
+static void emit_weak(const ir_entity *entity)
+{
+ if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
+ be_emit_cstring("\t.weak_reference ");
+ } else {
+ be_emit_cstring("\t.weak ");
+ }
+ be_gas_emit_entity(entity);
+ be_emit_char('\n');
+ be_emit_write_line();
+}
+
+static void emit_visibility(const ir_entity *entity)
+{
+ ir_linkage linkage = get_entity_linkage(entity);
+
+ if (get_entity_linkage(entity) & IR_LINKAGE_WEAK) {
+ emit_weak(entity);
+ /* Note: .weak seems to imply .globl so no need to output .globl */
+ } else if (get_entity_visibility(entity) == ir_visibility_default) {
+ be_emit_cstring(".globl ");
+ be_gas_emit_entity(entity);
+ be_emit_char('\n');
+ be_emit_write_line();
+ }
+
+ if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O
+ && (linkage & IR_LINKAGE_HIDDEN_USER)
+ && get_entity_ld_name(entity)[0] != '\0') {
+ be_emit_cstring("\t.no_dead_strip ");
+ be_gas_emit_entity(entity);
+ be_emit_char('\n');
+ be_emit_write_line();
+ }
+}
+
+void be_gas_emit_function_prolog(const ir_entity *entity, unsigned po2alignment)
+{
+ be_gas_section_t section = determine_section(NULL, entity);
+ emit_section(section, entity);
+
+ /* write the begin line (makes the life easier for scripts parsing the
+ * assembler) */
+ be_emit_write_line();
+ be_emit_cstring("# -- Begin ");
+ be_gas_emit_entity(entity);
+ be_emit_char('\n');
+ be_emit_write_line();
+
+ if (po2alignment > 0) {
+ const char *fill_byte = "";
+ unsigned maximum_skip = (1 << po2alignment) - 1;
+ /* gcc fills space between function with 0x90... */
+ if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
+ fill_byte = "0x90";
+ }
+ be_emit_cstring("\t.p2align ");
+ be_emit_irprintf("%u,%s,%u\n", po2alignment, fill_byte, maximum_skip);
+ be_emit_write_line();
+ }
+ emit_visibility(entity);
+
+ switch (be_gas_object_file_format) {
+ case OBJECT_FILE_FORMAT_ELF:
+ case OBJECT_FILE_FORMAT_ELF_SPARC:
+ be_emit_cstring("\t.type\t");
+ be_gas_emit_entity(entity);
+ be_emit_cstring(", ");
+ be_emit_char(be_gas_elf_type_char);
+ be_emit_cstring("function\n");
+ be_emit_write_line();
+ break;
+ case OBJECT_FILE_FORMAT_COFF:
+ be_emit_cstring("\t.def\t");
+ be_gas_emit_entity(entity);
+ be_emit_cstring(";");
+ if (get_entity_visibility(entity) == ir_visibility_local) {
+ be_emit_cstring("\t.scl\t3;");
+ } else {
+ be_emit_cstring("\t.scl\t2;");
+ }
+ be_emit_cstring("\t.type\t32;\t.endef\n");
+ be_emit_write_line();
+ break;
+ case OBJECT_FILE_FORMAT_MACH_O:
+ break;
+ }
+ be_gas_emit_entity(entity);
+ be_emit_cstring(":\n");
+ be_emit_write_line();
+}
+
+void be_gas_emit_function_epilog(const ir_entity *entity)
+{
+ if (be_gas_object_file_format == OBJECT_FILE_FORMAT_ELF) {
+ be_emit_cstring("\t.size\t");
+ be_gas_emit_entity(entity);
+ be_emit_cstring(", .-");
+ be_gas_emit_entity(entity);
+ be_emit_char('\n');
+ be_emit_write_line();
+ }
+
+ be_emit_cstring("# -- End ");
+ be_gas_emit_entity(entity);
+ be_emit_char('\n');
+ be_emit_write_line();
+}