+ 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;
+ }
+ }
+ panic("invalid initializer in initializer_is_null");
+}
+
+/**
+ * Determine if an entity is a string constant
+ * @param ent The entity
+ * @return 1 if it is a string constant, 0 otherwise
+ */
+static int entity_is_string_const(const ir_entity *ent)
+{
+ ir_type *type, *element_type;
+ ir_mode *mode;
+ int i, c, n;
+
+ type = get_entity_type(ent);
+
+ /* if it's an array */
+ if (!is_Array_type(type))
+ return 0;
+
+ element_type = get_array_element_type(type);
+
+ /* and the array's element type is primitive */
+ if (!is_Primitive_type(element_type))
+ return 0;
+
+ /* and the mode of the element type is an int of
+ * the same size as the byte mode */
+ mode = get_type_mode(element_type);
+ if (!mode_is_int(mode) || get_mode_size_bits(mode) != 8)
+ return 0;
+
+ if (ent->initializer != NULL) {
+ return initializer_is_string_const(ent->initializer);
+ } else if (entity_has_compound_ent_values(ent)) {
+ int found_printable = 0;
+ /* if it contains only printable chars and a 0 at the end */
+ n = get_compound_ent_n_values(ent);
+ for (i = 0; i < n; ++i) {
+ ir_node *irn = get_compound_ent_value(ent, i);
+ if (! is_Const(irn))
+ return 0;
+
+ c = (int) get_tarval_long(get_Const_tarval(irn));
+
+ if (isgraph(c) || isspace(c))
+ found_printable = 1;
+ else if (c != 0)
+ return 0;
+
+ if (i == n - 1 && c != '\0')
+ return 0;
+ }
+ return found_printable;
+ }
+
+ return 0;
+}
+
+static bool entity_is_null(const ir_entity *entity)
+{
+ if (entity->initializer != NULL) {
+ return initializer_is_null(entity->initializer);
+ } else if (entity_has_compound_ent_values(entity)) {
+ /* I'm too lazy to implement this case as compound graph paths will be
+ * remove anyway in the future */
+ return false;
+ }
+ /* uninitialized, NULL is fine */
+ return true;
+}
+
+static bool is_comdat(const ir_entity *entity)
+{
+ ir_linkage linkage = get_entity_linkage(entity);
+ return (linkage & IR_LINKAGE_MERGE)
+ && (linkage & IR_LINKAGE_GARBAGE_COLLECT);
+}
+
+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) {