begnuas.c 49 KB
Newer Older
Christian Würdig's avatar
Christian Würdig committed
1
2
/*
 * This file is part of libFirm.
3
 * Copyright (C) 2012 University of Karlsruhe.
Christian Würdig's avatar
Christian Würdig committed
4
5
 */

6
/**
Christian Würdig's avatar
Christian Würdig committed
7
8
9
10
 * @file
 * @brief       Dumps global variables and constants as gas assembler.
 * @author      Christian Wuerdig, Matthias Braun
 * @date        04.11.2005
11
 */
Matthias Braun's avatar
Matthias Braun committed
12
13
#include "begnuas.h"

14
15
#include <assert.h>
#include <ctype.h>
16
17
18
#include <stdlib.h>
#include <string.h>

19
20
21
#include "be_t.h"
#include "bearch.h"
#include "bedwarf.h"
22
#include "beemithlp.h"
23
24
#include "beemitter.h"
#include "bemodule.h"
25
#include "dbginfo.h"
26
27
#include "entity_t.h"
#include "execfreq.h"
28
#include "iredges_t.h"
29
#include "irnode_t.h"
30
#include "irprog.h"
31
32
33
#include "irtools.h"
#include "lc_opts_enum.h"
#include "obst.h"
Matthias Braun's avatar
Matthias Braun committed
34
#include "panic.h"
35
#include "tv.h"
36
#include "util.h"
37

38
39
40
41
42
43
typedef enum object_file_format_t {
	OBJECT_FILE_FORMAT_ELF,    /**< Executable and Linkable Format (unixes) */
	OBJECT_FILE_FORMAT_COFF,   /**< Common Object File Format (Windows) */
	OBJECT_FILE_FORMAT_MACH_O, /**< Mach Object File Format (OS/X) */
	OBJECT_FILE_FORMAT_LAST = OBJECT_FILE_FORMAT_MACH_O
} object_file_format_t;
44

Matthias Braun's avatar
Matthias Braun committed
45
/** by default, we generate assembler code for the Linux gas */
46
47
48
49
static object_file_format_t be_gas_object_file_format = OBJECT_FILE_FORMAT_ELF;
elf_variant_t               be_gas_elf_variant        = ELF_VARIANT_NORMAL;
bool                        be_gas_emit_types         = true;
char                        be_gas_elf_type_char      = '@';
Matthias Braun's avatar
Matthias Braun committed
50

51
static be_gas_section_t current_section = (be_gas_section_t) -1;
52
53
static pmap            *block_numbers;
static unsigned         next_block_nr;
54

Matthias Braun's avatar
Matthias Braun committed
55
56
static void emit_section_macho(be_gas_section_t section)
{
57
58
	be_gas_section_t base  = section & GAS_SECTION_TYPE_MASK;
	be_gas_section_t flags = section & ~GAS_SECTION_TYPE_MASK;
Matthias Braun's avatar
Matthias Braun committed
59
60
61
62
63

	if (current_section == section)
		return;
	current_section = section;

64
65
66
67
68
69
70
71
72
73
	static char const *const macho_shortforms[] = {
		[GAS_SECTION_CONSTRUCTORS] = "mod_init_func",
		[GAS_SECTION_DESTRUCTORS]  = "mod_term_func",
	};
	if (flags == 0 && base < ARRAY_SIZE(macho_shortforms)) {
		const char *const shortform = macho_shortforms[base];
		if (shortform != NULL) {
			be_emit_irprintf("\t.%s\n", shortform);
			be_emit_write_line();
			return;
Matthias Braun's avatar
Matthias Braun committed
74
		}
75
76
77
78
79
80
81
82
83
84
85
	}

	typedef struct {
		const char *segment_section;
		const char *flags;
	} macho_sectioninfo_t;

	static const macho_sectioninfo_t macho_sectioninfos[] = {
		[GAS_SECTION_TEXT]            = { "__TEXT,__text",            "regular,pure_instructions" },
		[GAS_SECTION_DATA]            = { "__DATA,__data",            NULL },
		[GAS_SECTION_RODATA]          = { "__TEXT,__const",           NULL },
86
87
		[GAS_SECTION_REL_RO]          = { "__DATA,__const",           NULL },
		[GAS_SECTION_REL_RO_LOCAL]    = { "__DATA,__const",           NULL },
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
		[GAS_SECTION_BSS]             = { "__DATA,__bss",             NULL },
		[GAS_SECTION_CSTRING]         = { "__TEXT,__cstring",         "cstring_literals" },
		[GAS_SECTION_PIC_TRAMPOLINES] = { "__IMPORT,__jump_table",    "symbol_stubs,self_modifying_code+pure_instructions,5" },
		[GAS_SECTION_PIC_SYMBOLS]     = { "__IMPORT,__pointers",      "non_lazy_symbol_pointers" },
		[GAS_SECTION_DEBUG_INFO]      = { "__DWARF,__debug_info",     "regular,debug" },
		[GAS_SECTION_DEBUG_ABBREV]    = { "__DWARF,__debug_abbrev",   "regular,debug" },
		[GAS_SECTION_DEBUG_LINE]      = { "__DWARF,__debug_line",     "regular,debug" },
		[GAS_SECTION_DEBUG_PUBNAMES]  = { "__DWARF,__debug_pubnames", "regular,debug" },
		[GAS_SECTION_DEBUG_FRAME]     = { "__DWARF,__debug_frame",    "regular,debug" },
	};
	static const macho_sectioninfo_t macho_sectioninfos_coalesce[] = {
		[GAS_SECTION_TEXT]    = { "__TEXT,__textcoal_nt", "coalesced,pure_instructions" },
		[GAS_SECTION_DATA]    = { "__DATA,__datacoal_nt", "coalesced" },
		[GAS_SECTION_BSS]     = { "__DATA,__datacoal_nt", "coalesced" },
		[GAS_SECTION_RODATA]  = { "__TEXT,__const_coal",  "coalesced" },
		[GAS_SECTION_CSTRING] = { "__TEXT,__const_coal",  "coalesced" },
	};

	if (flags & GAS_SECTION_FLAG_TLS)
107
		panic("thread local storage not supported on macho (section 0x%X)", section);
108
109
110
111
112

	macho_sectioninfo_t const *info;
	if (flags & GAS_SECTION_FLAG_COMDAT) {
		assert(base < ARRAY_SIZE(macho_sectioninfos_coalesce));
		info = &macho_sectioninfos_coalesce[base];
Matthias Braun's avatar
Matthias Braun committed
113
	} else {
114
115
		assert(base < ARRAY_SIZE(macho_sectioninfos));
		info = &macho_sectioninfos[base];
Matthias Braun's avatar
Matthias Braun committed
116
	}
117
118
119
120
121
122
123
	if (info->segment_section == NULL)
		panic("Unsupported macho section requested");

	be_emit_irprintf("\t.section\t%s", info->segment_section);
	if (info->flags != NULL)
		be_emit_irprintf(",%s", info->flags);
	be_emit_char('\n');
Matthias Braun's avatar
Matthias Braun committed
124
	be_emit_write_line();
Matthias Braun's avatar
Matthias Braun committed
125
126
}

127
typedef struct {
128
129
130
	const char *name;
	const char *type;
	const char *flags;
131
132
133
} elf_sectioninfo_t;

static const elf_sectioninfo_t elf_sectioninfos[] = {
134
135
136
137
138
139
140
141
142
143
144
145
146
147
	[GAS_SECTION_TEXT]           = { "text",              "progbits", "ax" },
	[GAS_SECTION_DATA]           = { "data",              "progbits", "aw" },
	[GAS_SECTION_RODATA]         = { "rodata",            "progbits", "a"  },
	[GAS_SECTION_REL_RO_LOCAL]   = { "data.rel.ro.local", "progbits", "aw" },
	[GAS_SECTION_REL_RO]         = { "data.rel.ro",       "progbits", "aw" },
	[GAS_SECTION_BSS]            = { "bss",               "nobits",   "aw" },
	[GAS_SECTION_CONSTRUCTORS]   = { "ctors",             "progbits", "aw" },
	[GAS_SECTION_DESTRUCTORS]    = { "dtors",             "progbits", "aw" },
	[GAS_SECTION_JCR]            = { "jcr",               "progbits", "aw" },
	[GAS_SECTION_DEBUG_INFO]     = { "debug_info",        "progbits", ""   },
	[GAS_SECTION_DEBUG_ABBREV]   = { "debug_abbrev",      "progbits", ""   },
	[GAS_SECTION_DEBUG_LINE]     = { "debug_line",        "progbits", ""   },
	[GAS_SECTION_DEBUG_PUBNAMES] = { "debug_pubnames",    "progbits", ""   },
	[GAS_SECTION_DEBUG_FRAME]    = { "debug_frame",       "progbits", ""   },
148
149
};

Matthias Braun's avatar
Matthias Braun committed
150
151
static void emit_section_sparc(be_gas_section_t section,
                               const ir_entity *entity)
152
{
Matthias Braun's avatar
Matthias Braun committed
153
	be_gas_section_t base  = section & GAS_SECTION_TYPE_MASK;
154
155
156
157
158
159
160
161
162
163
	be_gas_section_t flags = section & ~GAS_SECTION_TYPE_MASK;
	if (current_section == section && !(section & GAS_SECTION_FLAG_COMDAT))
		return;
	current_section = section;

	be_emit_cstring("\t.section\t\".");

	/* Part1: section-name */
	if (flags & GAS_SECTION_FLAG_TLS)
		be_emit_char('t');
164
165
	assert(base < (be_gas_section_t)ARRAY_SIZE(elf_sectioninfos));
	char const *const name = elf_sectioninfos[base].name;
166
167
	assert(name != NULL);
	be_emit_string(name);
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197

	if (flags & GAS_SECTION_FLAG_COMDAT) {
		be_emit_char('.');
		be_gas_emit_entity(entity);
	}
	be_emit_char('"');

	/* for the simple sections we're done here */
	if (flags == 0)
		goto end;

	be_emit_cstring(",#alloc");

	switch (base) {
	case GAS_SECTION_TEXT: be_emit_cstring(",#execinstr"); break;
	case GAS_SECTION_DATA:
	case GAS_SECTION_BSS:  be_emit_cstring(",#write"); break;
	default:
		/* nothing */
		break;
	}
	if (flags & GAS_SECTION_FLAG_TLS) {
		be_emit_cstring(",#tls");
	}

end:
	be_emit_char('\n');
	be_emit_write_line();
}

198
static void emit_section(be_gas_section_t section, const ir_entity *entity)
Matthias Braun's avatar
Matthias Braun committed
199
{
200
201
	be_gas_section_t base = section & GAS_SECTION_TYPE_MASK;
	be_gas_section_t flags = section & ~GAS_SECTION_TYPE_MASK;
Matthias Braun's avatar
Matthias Braun committed
202

Matthias Braun's avatar
Matthias Braun committed
203
204
205
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
		emit_section_macho(section);
		return;
206
	} else if (be_gas_elf_variant == ELF_VARIANT_SPARC) {
207
208
		emit_section_sparc(section, entity);
		return;
Matthias Braun's avatar
Matthias Braun committed
209
210
	}

211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
	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;
		}
	}

239
	assert(base < (be_gas_section_t) ARRAY_SIZE(elf_sectioninfos));
240
241
	elf_sectioninfo_t const *const info = &elf_sectioninfos[base];
	assert(info->name != NULL);
242
243
244
245
	be_emit_cstring("\t.section\t.");
	/* section name */
	if (flags & GAS_SECTION_FLAG_TLS)
		be_emit_char('t');
246
	be_emit_string(info->name);
247
248
249
250
251
252
253
	if (flags & GAS_SECTION_FLAG_COMDAT) {
		be_emit_char('.');
		be_gas_emit_entity(entity);
	}

	/* section flags */
	be_emit_cstring(",\"");
254
	be_emit_string(info->flags);
255
256
257
258
	if (flags & GAS_SECTION_FLAG_TLS)
		be_emit_char('T');
	if (flags & GAS_SECTION_FLAG_COMDAT)
		be_emit_char('G');
259

260
261
262
263
	/* section type */
	if (be_gas_object_file_format != OBJECT_FILE_FORMAT_COFF) {
		be_emit_cstring("\",");
		be_emit_char(be_gas_elf_type_char);
264
		be_emit_string(info->type);
265
	}
266
267
268
269
270
271
272
273

	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();
Matthias Braun's avatar
Matthias Braun committed
274
275
}

Matthias Braun's avatar
Matthias Braun committed
276
277
void be_gas_emit_switch_section(be_gas_section_t section)
{
278
279
	/* you have to produce a switch_section call with entity manually
	 * for comdat sections */
Matthias Braun's avatar
Matthias Braun committed
280
	assert(!(section & GAS_SECTION_FLAG_COMDAT));
281
282
283
284

	emit_section(section, NULL);
}

Matthias Braun's avatar
Matthias Braun committed
285
static ir_tarval *get_initializer_tarval(const ir_initializer_t *initializer)
Matthias Braun's avatar
Matthias Braun committed
286
287
288
289
290
291
292
293
294
{
	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);
		}
	}
295
	return get_tarval_unknown();
Matthias Braun's avatar
Matthias Braun committed
296
297
}

298
299
static bool initializer_is_string_const(const ir_initializer_t *initializer,
                                        bool only_suffix_null)
300
301
{
	if (initializer->kind != IR_INITIALIZER_COMPOUND)
302
		return false;
303

Matthias Braun's avatar
Matthias Braun committed
304
	size_t len = initializer->compound.n_initializers;
305
	if (len < 1)
306
		return false;
Matthias Braun's avatar
Matthias Braun committed
307
308
309

	bool found_printable = false;
	for (size_t i = 0; i < len; ++i) {
310
311
312
		ir_initializer_t *sub_initializer
			= initializer->compound.initializers[i];

Matthias Braun's avatar
Matthias Braun committed
313
		ir_tarval *tv = get_initializer_tarval(sub_initializer);
Matthias Braun's avatar
Matthias Braun committed
314
		if (!tarval_is_constant(tv))
315
			return false;
316

Matthias Braun's avatar
Matthias Braun committed
317
		ir_mode *mode = get_tarval_mode(tv);
318
		if (!mode_is_int(mode) || get_mode_size_bits(mode) != 8)
319
			return false;
320

Matthias Braun's avatar
Matthias Braun committed
321
		int c = get_tarval_long(tv);
322
323
324
325
326
327
328
329
330
		if (i == len-1) {
			if (c != '\0')
				return false;
		} else {
			if (isgraph(c) || isspace(c))
				found_printable = true;
			else if (c != 0 || only_suffix_null)
				return false;
		}
331
332
333
334
335
336
337
338
339
340
341
	}

	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: {
Matthias Braun's avatar
Matthias Braun committed
342
		ir_tarval *tv = initializer->tarval.value;
343
344
345
346
347
348
349
350
351
		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: {
Matthias Braun's avatar
Matthias Braun committed
352
		for (size_t i = 0; i < initializer->compound.n_initializers; ++i) {
353
354
355
356
357
358
359
360
361
362
363
364
365
366
			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
367
368
 * @param only_suffix_null  if true '\0' is only legal at the end of the
 *                          string.
369
 */
370
static bool entity_is_string_const(const ir_entity *ent, bool only_suffix_null)
371
372
{
	/* if it's an array */
Matthias Braun's avatar
Matthias Braun committed
373
	ir_type *type = get_entity_type(ent);
374
	if (!is_Array_type(type))
Matthias Braun's avatar
Matthias Braun committed
375
		return false;
376
377

	/* and the array's element type is primitive */
Matthias Braun's avatar
Matthias Braun committed
378
	ir_type *element_type = get_array_element_type(type);
379
	if (!is_Primitive_type(element_type))
Matthias Braun's avatar
Matthias Braun committed
380
		return false;
381
382
383

	/* and the mode of the element type is an int of
	 * the same size as the byte mode */
Matthias Braun's avatar
Matthias Braun committed
384
	ir_mode *mode = get_type_mode(element_type);
385
	if (!mode_is_int(mode) || get_mode_size_bits(mode) != 8)
Matthias Braun's avatar
Matthias Braun committed
386
		return false;
387

388
389
	ir_initializer_t const *const init = get_entity_initializer(ent);
	if (!init)
390
		return false;
391

392
	return initializer_is_string_const(init, only_suffix_null);
393
394
}

395
static bool entity_is_zero_initialized(ir_entity const *entity)
396
{
397
398
	if (is_alias_entity(entity))
		return false;
Matthias Braun's avatar
Matthias Braun committed
399
	ir_initializer_t *initializer = get_entity_initializer(entity);
400
	return initializer != NULL && initializer_is_null(initializer);
401
402
403
404
405
406
407
408
409
}

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);
}

410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
typedef enum reloc_class_t {
	NO_RELOCATIONS,
	ONLY_LOCAL_RELOCATIONS,
	ANY_RELOCATIONS,
} reloc_class_t;

static reloc_class_t classify_expr_relocs(ir_node const *const node)
{
	switch (get_irn_opcode(node)) {
	case iro_Conv:
		return classify_expr_relocs(get_Conv_op(node));
	case iro_Address: {
		ir_entity const *const entity     = get_Address_entity(node);
		ir_visibility    const visibility = get_entity_visibility(entity);
		return visibility == ir_visibility_local
		    || visibility == ir_visibility_private ? ONLY_LOCAL_RELOCATIONS
		                                           : ANY_RELOCATIONS;
	}
	case iro_Offset:
	case iro_Align:
	case iro_Const:
	case iro_Size:
	case iro_Unknown:
		return NO_RELOCATIONS;
	case iro_Add:
	case iro_Sub:
	case iro_Mul:
		return MAX(classify_expr_relocs(get_binop_left(node)),
		           classify_expr_relocs(get_binop_right(node)));
	default:
		panic("unsupported IR-node %+F in initializer", node);
	}
}

static reloc_class_t classify_initializer_relocs(
		ir_initializer_t const *const init)
{
	switch (get_initializer_kind(init)) {
	case IR_INITIALIZER_NULL:
	case IR_INITIALIZER_TARVAL:
		return NO_RELOCATIONS;
	case IR_INITIALIZER_CONST:
		return classify_expr_relocs(get_initializer_const_value(init));
	case IR_INITIALIZER_COMPOUND: {
		reloc_class_t result = NO_RELOCATIONS;
		for (size_t i = 0, n = get_initializer_compound_n_entries(init); i < n;
		     ++i) {
			ir_initializer_t const *const subinit
				= get_initializer_compound_value(init, i);
			result = MAX(result, classify_initializer_relocs(subinit));
		}
		return result;
	}
	}
	panic("invalid initializer");
}

467
468
static be_gas_section_t determine_basic_section(const ir_entity *entity)
{
469
	if (is_method_entity(entity) || is_alias_entity(entity))
470
471
		return GAS_SECTION_TEXT;

472
	if (get_entity_linkage(entity) & IR_LINKAGE_CONSTANT) {
473
474
		/* mach-o is the only one with a cstring section */
		if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O
475
		    && (get_entity_linkage(entity) & IR_LINKAGE_NO_IDENTITY)
476
		    && entity_is_string_const(entity, true))
477
478
			return GAS_SECTION_CSTRING;

479
		if (be_options.pic_style != BE_PIC_NONE) {
480
481
482
483
484
485
486
487
488
489
			ir_initializer_t const *const init = get_entity_initializer(entity);
			switch (classify_initializer_relocs(init)) {
			case ONLY_LOCAL_RELOCATIONS: return GAS_SECTION_REL_RO_LOCAL;
			case ANY_RELOCATIONS:        return GAS_SECTION_REL_RO;
			case NO_RELOCATIONS:         return GAS_SECTION_RODATA;
			}
			panic("invalid relocation class");
		} else {
			return GAS_SECTION_RODATA;
		}
490
	}
491
	if (entity_is_zero_initialized(entity))
492
493
494
495
496
		return GAS_SECTION_BSS;

	return GAS_SECTION_DATA;
}

497
static be_gas_section_t determine_section(be_main_env_t const *const main_env, ir_entity const *const entity)
498
499
500
501
502
503
504
505
{
	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;
506
	} else if (main_env && owner == main_env->pic_symbols_type) {
507
		return GAS_SECTION_PIC_SYMBOLS;
508
	} else if (main_env && owner == main_env->pic_trampolines_type) {
509
510
511
512
513
		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;
Matthias Braun's avatar
Matthias Braun committed
514
515
	} else if (owner == get_segment_type(IR_SEGMENT_JCR)) {
		return GAS_SECTION_JCR;
516
517
518
519
520
521
522
523
	} 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;
	}

524
525
526
527
528
	/* the java frontend keeps some functions inside classes */
	if (is_Class_type(owner)) {
		return determine_basic_section(entity);
	}

529
	panic("couldn't determine section for %+F", entity);
530
531
}

532
533
534
535
536
537
538
539
540
541
542
static void emit_symbol_directive(const char *directive,
								  const ir_entity *entity)
{
	be_emit_char('\t');
	be_emit_string(directive);
	be_emit_char(' ');
	be_gas_emit_entity(entity);
	be_emit_char('\n');
	be_emit_write_line();
}

543
544
static void emit_weak(const ir_entity *entity)
{
545
	const char *directive;
546
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
547
548
		directive = entity_has_definition(entity) ? ".weak_definition"
		                                          : ".weak_reference";
549
	} else {
550
		directive = ".weak";
551
	}
552
	emit_symbol_directive(directive, entity);
Matthias Braun's avatar
Matthias Braun committed
553
554
}

555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
static const char *get_visibility_directive(const ir_entity *entity,
											bool *output_global)
{
	switch (get_entity_visibility(entity)) {
	case ir_visibility_external: return NULL;
	case ir_visibility_external_private: {
		switch (be_gas_object_file_format) {
		case OBJECT_FILE_FORMAT_MACH_O:
			*output_global = false;
			return ".private_extern";
		case OBJECT_FILE_FORMAT_ELF:
			return ".hidden";
		case OBJECT_FILE_FORMAT_COFF:
			panic("ir_visibility_external_private not supported for COFF");
		}
		panic("invalid object file format");
	}
572
573
574
575
576
577
578
579
580
581
582
	case ir_visibility_external_protected: {
		switch (be_gas_object_file_format) {
		case OBJECT_FILE_FORMAT_MACH_O:
			return NULL;
		case OBJECT_FILE_FORMAT_ELF:
			return ".protected";
		case OBJECT_FILE_FORMAT_COFF:
			panic("ir_visibility_external_protected not supported for COFF");
		}
		panic("invalid object file format");
	}
583
584
585
586
587
588
589
590
	case ir_visibility_local:
	case ir_visibility_private:
		*output_global = false;
		return NULL;
	}
	panic("invalid visibility");
}

591
static void emit_visibility(const ir_entity *entity, bool implicit_globl)
Matthias Braun's avatar
Matthias Braun committed
592
{
593
	ir_linkage const linkage = get_entity_linkage(entity);
594

595
	if (linkage & IR_LINKAGE_WEAK)
596
		emit_weak(entity);
597

598
599
600
601
602
603
604
	bool output_global = !implicit_globl;
	const char *const directive
		= get_visibility_directive(entity, &output_global);
	if (output_global)
		emit_symbol_directive(".globl", entity);
	if (directive != NULL)
		emit_symbol_directive(directive, entity);
605
606

	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O
607
608
			&& (linkage & IR_LINKAGE_HIDDEN_USER)
			&& get_entity_ld_name(entity)[0] != '\0') {
609
		emit_symbol_directive(".no_dead_strip", entity);
Matthias Braun's avatar
Matthias Braun committed
610
611
612
	}
}

Matthias Braun's avatar
Matthias Braun committed
613
614
void be_gas_emit_function_prolog(const ir_entity *entity, unsigned po2alignment,
                                 const parameter_dbg_info_t *parameter_infos)
615
{
616
	be_dwarf_function_before(entity, parameter_infos);
617

Matthias Braun's avatar
Matthias Braun committed
618
	be_gas_section_t section = determine_section(NULL, entity);
619
	emit_section(section, entity);
620

Matthias Braun's avatar
Matthias Braun committed
621
622
	/* write the begin line (makes the life easier for scripts parsing the
	 * assembler) */
623
624
625
626
627
628
	if (be_options.verbose_asm) {
		be_emit_cstring("# -- Begin  ");
		be_gas_emit_entity(entity);
		be_emit_char('\n');
		be_emit_write_line();
	}
629

630
	if (po2alignment > 0) {
Matthias Braun's avatar
Matthias Braun committed
631
		const char *fill_byte    = "";
Matthias Braun's avatar
Matthias Braun committed
632
633
634
635
636
		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";
		}
Michael Beck's avatar
Michael Beck committed
637
		be_emit_cstring("\t.p2align ");
638
		be_emit_irprintf("%u,%s,%u\n", po2alignment, fill_byte, maximum_skip);
Michael Beck's avatar
Michael Beck committed
639
640
		be_emit_write_line();
	}
641
	emit_visibility(entity, false);
642

Matthias Braun's avatar
Matthias Braun committed
643
644
	switch (be_gas_object_file_format) {
	case OBJECT_FILE_FORMAT_ELF:
645
		be_emit_cstring("\t.type\t");
646
		be_gas_emit_entity(entity);
647
648
649
		be_emit_cstring(", ");
		be_emit_char(be_gas_elf_type_char);
		be_emit_cstring("function\n");
650
651
		be_emit_write_line();
		break;
Matthias Braun's avatar
Matthias Braun committed
652
	case OBJECT_FILE_FORMAT_COFF:
653
		be_emit_cstring("\t.def\t");
654
		be_gas_emit_entity(entity);
Matthias Braun's avatar
Matthias Braun committed
655
		be_emit_cstring(";");
656
		if (get_entity_visibility(entity) == ir_visibility_local) {
Matthias Braun's avatar
Matthias Braun committed
657
			be_emit_cstring("\t.scl\t3;");
658
		} else {
Matthias Braun's avatar
Matthias Braun committed
659
			be_emit_cstring("\t.scl\t2;");
660
		}
Matthias Braun's avatar
Matthias Braun committed
661
		be_emit_cstring("\t.type\t32;\t.endef\n");
662
663
		be_emit_write_line();
		break;
Matthias Braun's avatar
Matthias Braun committed
664
	case OBJECT_FILE_FORMAT_MACH_O:
665
666
		if (section == (GAS_SECTION_TEXT | GAS_SECTION_FLAG_COMDAT))
			emit_symbol_directive(".weak_definition", entity);
667
668
		break;
	}
669
	be_gas_emit_entity(entity);
670
671
	be_emit_cstring(":\n");
	be_emit_write_line();
672

673
	be_dwarf_function_begin();
674
675
}

676
void be_gas_emit_function_epilog(const ir_entity *entity)
677
{
678
	be_dwarf_function_end();
679

Matthias Braun's avatar
Matthias Braun committed
680
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_ELF) {
681
		be_emit_cstring("\t.size\t");
682
		be_gas_emit_entity(entity);
683
		be_emit_cstring(", .-");
684
		be_gas_emit_entity(entity);
685
686
687
688
		be_emit_char('\n');
		be_emit_write_line();
	}

689
690
691
692
693
694
	if (be_options.verbose_asm) {
		be_emit_cstring("# -- End  ");
		be_gas_emit_entity(entity);
		be_emit_char('\n');
		be_emit_write_line();
	}
695
696
697

	be_emit_char('\n');
	be_emit_write_line();
698

699
	next_block_nr += 199;
700
	next_block_nr -= next_block_nr % 100;
701
702
}

Michael Beck's avatar
Michael Beck committed
703
/**
704
 * Output parts of a tarval.
Michael Beck's avatar
Michael Beck committed
705
 *
706
707
708
 * @param tv      The tarval
 * @param offset  The byte offst to start at
 * @param n       How many bytes to output
Michael Beck's avatar
Michael Beck committed
709
 */
710
static void emit_tv(ir_tarval *const tv, unsigned const offset, unsigned const n)
711
{
712
713
714
	be_emit_cstring("0x");
	for (unsigned i = n; i-- != 0;) {
		be_emit_irprintf("%02x", get_tarval_sub_bits(tv, offset + i));
715
	}
716
717
}

718
719
720
/**
 * Return the label prefix for labeled instructions.
 */
Matthias Braun's avatar
Matthias Braun committed
721
722
const char *be_gas_insn_label_prefix(void)
{
723
724
725
	return ".LE";
}

726
/**
Michael Beck's avatar
Michael Beck committed
727
728
729
 * Dump an atomic value.
 *
 * @param init  a node representing the atomic value (on the const code irg)
730
 */
731
static void emit_init_expression(ir_node *const init)
732
{
Matthias Braun's avatar
Matthias Braun committed
733
734
	ir_mode *mode  = get_irn_mode(init);
	int      bytes = get_mode_size_bytes(mode);
735

736
737
	switch (get_irn_opcode(init)) {
	case iro_Conv:
738
		emit_init_expression(get_Conv_op(init));
739
740
		return;

Matthias Braun's avatar
Matthias Braun committed
741
742
	case iro_Const: {
		ir_tarval *tv = get_Const_tarval(init);
743
		/* it's an arithmetic value */
744
		emit_tv(tv, 0, bytes);
745
		return;
Matthias Braun's avatar
Matthias Braun committed
746
	}
747

748
749
750
	case iro_Address:
		be_gas_emit_entity(get_Address_entity(init));
		return;
751

752
753
754
	case iro_Offset:
		be_emit_irprintf("%d", get_entity_offset(get_Offset_entity(init)));
		return;
755

756
	case iro_Align:
757
		be_emit_irprintf("%u", get_type_alignment(get_Align_type(init)));
758
		return;
759

760
	case iro_Size:
761
		be_emit_irprintf("%u", get_type_size(get_Size_type(init)));
762
		return;
763

Michael Beck's avatar
Michael Beck committed
764
765
	case iro_Add:
		if (!mode_is_int(mode) && !mode_is_reference(mode)) {
766
			panic("constant must be int or pointer for '+' to work");
Michael Beck's avatar
Michael Beck committed
767
		}
768
		emit_init_expression(get_Add_left(init));
Michael Beck's avatar
Michael Beck committed
769
		be_emit_cstring(" + ");
770
		emit_init_expression(get_Add_right(init));
Michael Beck's avatar
Michael Beck committed
771
		return;
772

Michael Beck's avatar
Michael Beck committed
773
774
	case iro_Sub:
		if (!mode_is_int(mode) && !mode_is_reference(mode)) {
775
			panic("constant must be int or pointer for '-' to work");
Michael Beck's avatar
Michael Beck committed
776
		}
777
		emit_init_expression(get_Sub_left(init));
Michael Beck's avatar
Michael Beck committed
778
		be_emit_cstring(" - ");
779
		emit_init_expression(get_Sub_right(init));
Michael Beck's avatar
Michael Beck committed
780
781
782
783
		return;

	case iro_Mul:
		if (!mode_is_int(mode) && !mode_is_reference(mode)) {
784
			panic("constant must be int or pointer for '*' to work");
Michael Beck's avatar
Michael Beck committed
785
		}
786
		emit_init_expression(get_Mul_left(init));
Michael Beck's avatar
Michael Beck committed
787
		be_emit_cstring(" * ");
788
		emit_init_expression(get_Mul_right(init));
Michael Beck's avatar
Michael Beck committed
789
790
		return;

Olaf Liebe's avatar
Olaf Liebe committed
791
792
793
794
	case iro_Unknown:
		be_emit_cstring("0");
		return;

Michael Beck's avatar
Michael Beck committed
795
	default:
796
		panic("unsupported IR-node %+F", init);
797
	}
798
799
}

800
/**
Michael Beck's avatar
Michael Beck committed
801
802
803
 * Dumps the type for given size (.byte, .long, ...)
 *
 * @param size  the size in bytes
804
 */
805
static void emit_size_type(size_t size)
806
{
Christian Würdig's avatar
Christian Würdig committed
807
	switch (size) {
808
809
810
811
	case 1: be_emit_cstring("\t.byte\t");  break;
	case 2: be_emit_cstring("\t.short\t"); break;
	case 4: be_emit_cstring("\t.long\t");  break;
	case 8: be_emit_cstring("\t.quad\t");  break;
812

813
	default:
814
		panic("try to dump a type with %u bytes", (unsigned)size);
815
	}
Christian Würdig's avatar
Christian Würdig committed
816
817
}

818
static void emit_string_char(int c)
819
{
820
821
822
823
824
825
826
827
828
829
830
831
	switch (c) {
	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))
			be_emit_char(c);
		else
			be_emit_irprintf("\\%03o", c);
		break;
832
	}
833
}
834

835
836
837
838
839
840
static size_t emit_string_initializer(const ir_initializer_t *initializer)
{
	be_emit_cstring("\t.asciz \"");

	size_t len = initializer->compound.n_initializers;
	for (size_t i = 0; i < len-1; ++i) {
841
842
843
		const ir_initializer_t *sub_initializer
			= get_initializer_compound_value(initializer, i);

Matthias Braun's avatar
Matthias Braun committed
844
845
		ir_tarval *tv = get_initializer_tarval(sub_initializer);
		int        c  = get_tarval_long(tv);
846
		emit_string_char(c);
847
	}
848
849
	be_emit_cstring("\"\n");
	be_emit_write_line();
850
851

	return initializer->compound.n_initializers;
852
853
}

854
855
856
857
858
859
860
861
862
void be_gas_emit_string_literal(const char *string)
{
	be_emit_char('"');
	for (const char *c = string; *c != '\0'; ++c) {
		emit_string_char(*c);
	}
	be_emit_char('"');
}

863
864
865
866
867
868
869
870
871
872
void be_gas_emit_cstring(const char *string)
{
	be_emit_cstring("\t.asciz \"");
	for (const char *c = string; *c != '\0'; ++c) {
		emit_string_char(*c);
	}
	be_emit_cstring("\"\n");
	be_emit_write_line();
}

873
typedef enum normal_or_bitfield_kind {
874
	NORMAL = 0,
875
	TARVAL,
876
	STRING,
877
	BITFIELD
878
} normal_or_bitfield_kind;
879
880

typedef struct {
881
	normal_or_bitfield_kind kind;
882
	ir_type                *type;
883
	union {
884
885
886
887
		ir_node                *value;
		ir_tarval              *tarval;
		unsigned char           bf_val;
		const ir_initializer_t *string;
888
889
890
	} v;
} normal_or_bitfield;

891
892
893
static size_t get_initializer_size(const ir_initializer_t *initializer,
                                   ir_type *type)
{
Michael Beck's avatar
Michael Beck committed
894
	switch (get_initializer_kind(initializer)) {
Michael Beck's avatar
Michael Beck committed
895
	case IR_INITIALIZER_TARVAL:
Matthias Braun's avatar
Matthias Braun committed
896
		assert(get_tarval_mode(get_initializer_tarval_value(initializer)) == get_type_mode(type));
897
		return get_type_size(type);
898
899
	case IR_INITIALIZER_CONST:
	case IR_INITIALIZER_NULL:
900
		return get_type_size(type);
Michael Beck's avatar
Michael Beck committed
901
	case IR_INITIALIZER_COMPOUND:
902
903
		if (is_Array_type(type)) {
			if (is_array_variable_size(type)) {
904
905
906
907
				ir_type   *element_type  = get_array_element_type(type);
				unsigned   element_size  = get_type_size(element_type);
				unsigned   element_align = get_type_alignment(element_type);
				unsigned   misalign      = element_size % element_align;
908
909
910
911
912
				size_t     n_inits
					= get_initializer_compound_n_entries(initializer);
				element_size += element_align - misalign;
				return n_inits * element_size;
			} else {
913
				return get_type_size(type);
914
			}
915
		} else {
916
			assert(is_compound_type(type));
917
			size_t size = get_type_size(type);
918
919
920
921
922
923
924
925
926
			if (is_compound_variable_size(type)) {
				/* last initializer has to be an array of variable size */
				size_t l = get_initializer_compound_n_entries(initializer)-1;
				const ir_initializer_t *last
					= get_initializer_compound_value(initializer, l);
				const ir_entity *last_ent  = get_compound_member(type, l);
				ir_type         *last_type = get_entity_type(last_ent);
				assert(is_array_variable_size(last_type));
				size += get_initializer_size(last, last_type);
927
			}
928
			return size;
929
930
931
932
933
934
		}
	}

	panic("found invalid initializer");
}

935
936
937
static unsigned long compute_entity_size(ir_entity const *const entity)
{
	ir_type *const type = get_entity_type(entity);
938
	unsigned long  size = get_type_size(type);
939
	if (is_alias_entity(entity))
940
		return size;
941

942
	/* Note that for variable array/compound types we may have to inspect the
Matthias Braun's avatar
Matthias Braun committed
943
	 * initializer to get the actual size */
944
945
946
947
948
949
	ir_initializer_t const *const initializer = get_entity_initializer(entity);
	if (initializer != NULL)
		size = get_initializer_size(initializer, type);
	return size;
}

950
951
#ifndef NDEBUG
static normal_or_bitfield *glob_vals;
952
static unsigned long       max_vals;
953
954
#endif

955
956
static void emit_bitfield(normal_or_bitfield *vals, unsigned offset_bits,
                          unsigned bitfield_size,
957
958
                          const ir_initializer_t *initializer, ir_type *type)
{
959
	static const size_t BITS_PER_BYTE = 8;
960

961
	ir_tarval *tv = NULL;
Michael Beck's avatar
Michael Beck committed
962
	switch (get_initializer_kind(initializer)) {
963
964
965
966
967
968
969
	case IR_INITIALIZER_NULL:
		return;
	case IR_INITIALIZER_TARVAL:
		tv = get_initializer_tarval_value(initializer);
		break;
	case IR_INITIALIZER_CONST: {
		ir_node *node = get_initializer_const_value(initializer);
Michael Beck's avatar
Michael Beck committed
970
		if (!is_Const(node)) {
971
972
973
974
975
976
977
978
			panic("bitfield initializer not a Const node");
		}
		tv = get_Const_tarval(node);
		break;
	}
	case IR_INITIALIZER_COMPOUND:
		panic("bitfield initializer is compound");
	}
979
	if (tv == NULL || tv == tarval_bad) {
980
		panic("couldn't get numeric value for bitfield initializer");
981
982
	}

983
	int    value_len  = get_type_size(type);
Matthias Braun's avatar
Matthias Braun committed
984
	size_t bit_offset = 0;
985
	size_t end        = bitfield_size;
Matthias Braun's avatar
Matthias Braun committed
986
	bool   big_endian = be_get_backend_param()->byte_order_big_endian;
987
	while (bit_offset < end) {
Matthias Braun's avatar
Matthias Braun committed
988
989
990
991
992
993
		size_t src_offset      = bit_offset / BITS_PER_BYTE;
		size_t src_offset_bits = bit_offset % BITS_PER_BYTE;
		size_t dst_offset      = (bit_offset+offset_bits) / BITS_PER_BYTE;
		size_t dst_offset_bits = (bit_offset+offset_bits) % BITS_PER_BYTE;
		size_t src_bits_len    = end-bit_offset;
		size_t dst_bits_len    = BITS_PER_BYTE-dst_offset_bits;
994
995
996
		if (src_bits_len > dst_bits_len)
			src_bits_len = dst_bits_len;

Matthias Braun's avatar
Matthias Braun committed
997
		normal_or_bitfield *val;
998
999
1000
1001
1002
1003
1004
1005
1006
		if (big_endian) {
			val = &vals[value_len - dst_offset - 1];
		} else {
			val = &vals[dst_offset];
		}

		assert((val-glob_vals) < (ptrdiff_t) max_vals);
		assert(val->kind == BITFIELD ||
				(val->kind == NORMAL && val->v.value == NULL));
Matthias Braun's avatar
Matthias Braun committed
1007
1008
1009
		val->kind = BITFIELD;
		unsigned char curr_bits = get_tarval_sub_bits(tv, src_offset);
		curr_bits = curr_bits >> src_offset_bits;
1010
1011
1012
1013
1014
1015
1016
1017
		if (src_offset_bits + src_bits_len > 8) {
			unsigned next_bits = get_tarval_sub_bits(tv, src_offset+1);
			curr_bits |= next_bits << (8 - src_offset_bits);
		}
		curr_bits &= (1 << src_bits_len) - 1;
		val->v.bf_val |= curr_bits << dst_offset_bits;

		bit_offset += dst_bits_len;
1018
1019
1020
	}
}

1021
static void emit_ir_initializer(normal_or_bitfield *vals,
1022
1023
1024
                                const ir_initializer_t *initializer,
                                ir_type *type)
{
1025
	assert((unsigned long) (vals - glob_vals) <= max_vals);
1026

1027
	if (initializer_is_string_const(initializer, false)) {
1028
1029
1030
1031
1032
1033
		assert(vals->kind != BITFIELD);
		vals->kind     = STRING;
		vals->v.string = initializer;
		return;
	}

Michael Beck's avatar
Michael Beck committed
1034
	switch (get_initializer_kind(initializer)) {
1035
1036
	case IR_INITIALIZER_NULL:
		return;
Matthias Braun's avatar
Matthias Braun committed
1037
	case IR_INITIALIZER_TARVAL:
1038
1039
		assert(vals->kind != BITFIELD);
		vals->kind     = TARVAL;
1040
		vals->type     = type;