+static void emit_section(be_gas_section_t section, const ir_entity *entity)
+{
+ be_gas_section_t base = section & GAS_SECTION_TYPE_MASK;
+ be_gas_section_t flags = section & ~GAS_SECTION_TYPE_MASK;
+ const char *f;
+ static const struct {
+ const char *name;
+ const char *type;
+ const char *flags;
+ } sectioninfos[GAS_SECTION_LAST+1] = {
+ { "text", "progbits", "ax" },
+ { "data", "progbits", "aw" },
+ { "rodata", "progbits", "a" },
+ { "bss", "nobits", "aw" },
+ { "ctors", "progbits", "aw" },
+ { "dtors", "progbits", "aw" },
+ { NULL, NULL, NULL }, /* cstring */
+ { NULL, NULL, NULL }, /* pic trampolines */
+ { NULL, NULL, NULL }, /* pic symbols */
+ { "debug_info", "progbits", "" },
+ { "debug_abbrev", "progbits", "" },
+ { "debug_line", "progbits", "" },
+ { "debug_pubnames", "progbits", "" },
+ { "debug_frame", "progbits", "" },
+ };
+
+ if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
+ emit_section_macho(section);
+ return;
+ } else if(be_gas_elf_variant == ELF_VARIANT_SPARC) {
+ emit_section_sparc(section, entity);
+ return;
+ }
+
+ if (current_section == section && !(section & GAS_SECTION_FLAG_COMDAT))
+ return;
+ current_section = section;
+
+ /* shortforms */
+ if (flags == 0) {
+ switch (base) {
+ case GAS_SECTION_TEXT:
+ be_emit_cstring("\t.text\n");
+ be_emit_write_line();
+ return;
+ case GAS_SECTION_DATA:
+ be_emit_cstring("\t.data\n");
+ be_emit_write_line();
+ return;
+ case GAS_SECTION_RODATA:
+ be_emit_cstring("\t.section\t.rodata\n");
+ be_emit_write_line();
+ return;
+ case GAS_SECTION_BSS:
+ be_emit_cstring("\t.bss\n");
+ be_emit_write_line();
+ return;
+ default:
+ break;
+ }
+ }
+
+ assert(base < (be_gas_section_t) ARRAY_SIZE(sectioninfos));
+ be_emit_cstring("\t.section\t.");
+ /* section name */
+ if (flags & GAS_SECTION_FLAG_TLS)
+ be_emit_char('t');
+ be_emit_string(sectioninfos[base].name);
+ if (flags & GAS_SECTION_FLAG_COMDAT) {
+ be_emit_char('.');
+ be_gas_emit_entity(entity);
+ }
+
+ /* section flags */
+ be_emit_cstring(",\"");
+ for (f = sectioninfos[base].flags; *f != '\0'; ++f) {
+ be_emit_char(*f);
+ }
+ if (flags & GAS_SECTION_FLAG_TLS)
+ be_emit_char('T');
+ if (flags & GAS_SECTION_FLAG_COMDAT)
+ be_emit_char('G');
+
+ /* section type */
+ if (be_gas_object_file_format != OBJECT_FILE_FORMAT_COFF) {
+ be_emit_cstring("\",");
+ be_emit_char(be_gas_elf_type_char);
+ be_emit_string(sectioninfos[base].type);
+ }
+
+ if (flags & GAS_SECTION_FLAG_COMDAT) {
+ be_emit_char(',');
+ be_gas_emit_entity(entity);
+ be_emit_cstring(",comdat");
+ }
+ be_emit_char('\n');
+ be_emit_write_line();
+}
+
+
+
+void be_gas_emit_switch_section(be_gas_section_t section)
+{
+ /* you have to produce a switch_section call with entity manually
+ * for comdat sections */
+ assert( !(section & GAS_SECTION_FLAG_COMDAT));
+
+ emit_section(section, NULL);
+}
+
+static ir_tarval *get_initializer_tarval(const ir_initializer_t *initializer)
+{
+ if (initializer->kind == IR_INITIALIZER_TARVAL)
+ return initializer->tarval.value;
+ if (initializer->kind == IR_INITIALIZER_CONST) {
+ ir_node *node = initializer->consti.value;
+ if (is_Const(node)) {
+ return get_Const_tarval(node);
+ }
+ }
+ return get_tarval_undefined();
+}
+
+static bool initializer_is_string_const(const ir_initializer_t *initializer)
+{
+ size_t i, len;
+ bool found_printable = false;
+
+ if (initializer->kind != IR_INITIALIZER_COMPOUND)
+ return false;
+
+ len = initializer->compound.n_initializers;
+ if (len < 1)
+ return false;
+ for (i = 0; i < len; ++i) {
+ int c;
+ ir_tarval *tv;
+ ir_mode *mode;
+ ir_initializer_t *sub_initializer
+ = initializer->compound.initializers[i];
+
+ tv = get_initializer_tarval(sub_initializer);
+ if (!tarval_is_constant(tv))
+ return false;
+
+ mode = get_tarval_mode(tv);
+ if (!mode_is_int(mode) || get_mode_size_bits(mode) != 8)
+ return false;
+
+ c = get_tarval_long(tv);
+ if (isgraph(c) || isspace(c))
+ found_printable = true;
+ else if (c != 0)
+ return false;
+
+ if (i == len - 1 && c != '\0')
+ return false;
+ }
+
+ return found_printable;
+}
+
+static bool initializer_is_null(const ir_initializer_t *initializer)
+{
+ switch (initializer->kind) {
+ case IR_INITIALIZER_NULL:
+ return true;
+ case IR_INITIALIZER_TARVAL: {
+ ir_tarval *tv = initializer->tarval.value;
+ return tarval_is_null(tv);
+ }
+ case IR_INITIALIZER_CONST: {
+ ir_node *value = initializer->consti.value;
+ if (!is_Const(value))
+ return false;
+ return is_Const_null(value);
+ }
+ case IR_INITIALIZER_COMPOUND: {
+ size_t i;
+ for (i = 0; i < initializer->compound.n_initializers; ++i) {
+ ir_initializer_t *subinitializer
+ = initializer->compound.initializers[i];
+ if (!initializer_is_null(subinitializer))
+ return false;
+ }
+ return true;
+ }