begnuas.c 43.5 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
22
23
24
25
#include "be_t.h"
#include "bearch.h"
#include "bedwarf.h"
#include "beemitter.h"
#include "bemodule.h"
#include "entity_t.h"
#include "execfreq.h"
26
27
#include "irnode.h"
#include "irprog.h"
28
29
30
#include "irtools.h"
#include "lc_opts_enum.h"
#include "obst.h"
Matthias Braun's avatar
Matthias Braun committed
31
#include "panic.h"
32
#include "tv.h"
33
#include "util.h"
34

35
36
37
38
39
40
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;
41

Matthias Braun's avatar
Matthias Braun committed
42
/** by default, we generate assembler code for the Linux gas */
43
44
45
46
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
47

48
static be_gas_section_t current_section = (be_gas_section_t) -1;
49
50
static pmap            *block_numbers;
static unsigned         next_block_nr;
51

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

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

	/* shortforms */
Matthias Braun's avatar
Matthias Braun committed
62
	const char *name;
Matthias Braun's avatar
Matthias Braun committed
63
64
65
66
67
68
69
70
71
72
73
	if (flags == 0) {
		switch (base) {
		case GAS_SECTION_TEXT:            name = "text";          break;
		case GAS_SECTION_DATA:            name = "data";          break;
		case GAS_SECTION_RODATA:          name = "const";         break;
		case GAS_SECTION_BSS:             name = "data";          break;
		case GAS_SECTION_CONSTRUCTORS:    name = "mod_init_func"; break;
		case GAS_SECTION_DESTRUCTORS:     name = "mod_term_func"; break;
		case GAS_SECTION_PIC_TRAMPOLINES: name = "section\t__IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5"; break;
		case GAS_SECTION_PIC_SYMBOLS:     name = "section\t__IMPORT,__pointers,non_lazy_symbol_pointers"; break;
		case GAS_SECTION_CSTRING:         name = "cstring";       break;
74
75
76
77
		case GAS_SECTION_DEBUG_INFO:      name = "section __DWARF,__debug_info,regular,debug"; break;
		case GAS_SECTION_DEBUG_ABBREV:    name = "section __DWARF,__debug_abbrev,regular,debug"; break;
		case GAS_SECTION_DEBUG_LINE:      name = "section __DWARF,__debug_line,regular,debug"; break;
		case GAS_SECTION_DEBUG_PUBNAMES:  name = "section __DWARF,__debug_pubnames,regular,debug"; break;
78
		case GAS_SECTION_DEBUG_FRAME:     name = "section __DWARF,__debug_frame,regular,debug"; break;
Matthias Braun's avatar
Matthias Braun committed
79
80
81
82
83
84
85
86
87
88
89
		default: panic("unsupported scetion type 0x%X", section);
		}
	} else if (flags & GAS_SECTION_FLAG_COMDAT) {
		switch (base) {
		case GAS_SECTION_TEXT:            name = "section __TEXT,__textcoal_nt,coalesced,pure_instructions"; break;
		case GAS_SECTION_BSS:
		case GAS_SECTION_DATA:            name = "section __DATA,__datacoal_nt,coalesced"; break;
		case GAS_SECTION_RODATA:          name = "section __TEXT,__const_coal,coalesced"; break;
		case GAS_SECTION_CSTRING:         name = "section __TEXT,__const_coal,coalesced"; break;
		default: panic("unsupported scetion type 0x%X", section);
		}
90
91
	} else if (flags & GAS_SECTION_FLAG_TLS) {
		panic("thread local storage not supported on macho (section 0x%X)", section);
Matthias Braun's avatar
Matthias Braun committed
92
	} else {
93
		panic("unsupported section type 0x%X", section);
Matthias Braun's avatar
Matthias Braun committed
94
	}
Matthias Braun's avatar
Matthias Braun committed
95
96
	be_emit_irprintf("\t.%s\n", name);
	be_emit_write_line();
Matthias Braun's avatar
Matthias Braun committed
97
98
}

Matthias Braun's avatar
Matthias Braun committed
99
100
static void emit_section_sparc(be_gas_section_t section,
                               const ir_entity *entity)
101
{
Matthias Braun's avatar
Matthias Braun committed
102
	be_gas_section_t base  = section & GAS_SECTION_TYPE_MASK;
103
	be_gas_section_t flags = section & ~GAS_SECTION_TYPE_MASK;
104
105
106
107
108
109
110
	static const char *const basename[GAS_SECTION_LAST+1] = {
		"text",
		"data",
		"rodata",
		"bss",
		"ctors",
		"dtors",
Matthias Braun's avatar
Matthias Braun committed
111
		"jcr",
112
113
114
115
116
117
		NULL, /* cstring */
		NULL, /* pic trampolines */
		NULL, /* pic symbols */
		"debug_info",
		"debug_abbrev",
		"debug_line",
Matthias Braun's avatar
Matthias Braun committed
118
		"debug_pubnames",
119
		"debug_frame",
120
121
122
123
124
125
126
127
128
129
130
	};

	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');
131
	assert(base < (be_gas_section_t)ARRAY_SIZE(basename));
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
	be_emit_string(basename[base]);

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

163
static void emit_section(be_gas_section_t section, const ir_entity *entity)
Matthias Braun's avatar
Matthias Braun committed
164
{
165
166
	be_gas_section_t base = section & GAS_SECTION_TYPE_MASK;
	be_gas_section_t flags = section & ~GAS_SECTION_TYPE_MASK;
167
168
169
170
171
	const char *f;
	static const struct {
		const char *name;
		const char *type;
		const char *flags;
172
173
174
175
176
177
178
	} sectioninfos[GAS_SECTION_LAST+1] = {
		{ "text",           "progbits", "ax" },
		{ "data",           "progbits", "aw" },
		{ "rodata",         "progbits", "a"  },
		{ "bss",            "nobits",   "aw" },
		{ "ctors",          "progbits", "aw" },
		{ "dtors",          "progbits", "aw" },
Matthias Braun's avatar
Matthias Braun committed
179
		{ "jcr",            "progbits", "aw" },
180
181
182
183
184
185
186
		{ 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", ""   },
187
		{ "debug_frame",    "progbits", ""   },
Matthias Braun's avatar
Matthias Braun committed
188
189
	};

Matthias Braun's avatar
Matthias Braun committed
190
191
192
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
		emit_section_macho(section);
		return;
193
	} else if (be_gas_elf_variant == ELF_VARIANT_SPARC) {
194
195
		emit_section_sparc(section, entity);
		return;
Matthias Braun's avatar
Matthias Braun committed
196
197
	}

198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
	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;
		}
	}

226
	assert(base < (be_gas_section_t) ARRAY_SIZE(sectioninfos));
227
228
229
230
	be_emit_cstring("\t.section\t.");
	/* section name */
	if (flags & GAS_SECTION_FLAG_TLS)
		be_emit_char('t');
231
	be_emit_string(sectioninfos[base].name);
232
233
234
235
236
237
238
	if (flags & GAS_SECTION_FLAG_COMDAT) {
		be_emit_char('.');
		be_gas_emit_entity(entity);
	}

	/* section flags */
	be_emit_cstring(",\"");
239
240
241
	for (f = sectioninfos[base].flags; *f != '\0'; ++f) {
		be_emit_char(*f);
	}
242
243
244
245
	if (flags & GAS_SECTION_FLAG_TLS)
		be_emit_char('T');
	if (flags & GAS_SECTION_FLAG_COMDAT)
		be_emit_char('G');
246

247
248
249
250
	/* section type */
	if (be_gas_object_file_format != OBJECT_FILE_FORMAT_COFF) {
		be_emit_cstring("\",");
		be_emit_char(be_gas_elf_type_char);
251
		be_emit_string(sectioninfos[base].type);
252
	}
253
254
255
256
257
258
259
260

	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
261
262
}

Matthias Braun's avatar
Matthias Braun committed
263
264
void be_gas_emit_switch_section(be_gas_section_t section)
{
265
266
	/* you have to produce a switch_section call with entity manually
	 * for comdat sections */
Matthias Braun's avatar
Matthias Braun committed
267
	assert(!(section & GAS_SECTION_FLAG_COMDAT));
268
269
270
271

	emit_section(section, NULL);
}

Matthias Braun's avatar
Matthias Braun committed
272
static ir_tarval *get_initializer_tarval(const ir_initializer_t *initializer)
Matthias Braun's avatar
Matthias Braun committed
273
274
275
276
277
278
279
280
281
{
	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);
		}
	}
282
	return get_tarval_unknown();
Matthias Braun's avatar
Matthias Braun committed
283
284
}

285
286
static bool initializer_is_string_const(const ir_initializer_t *initializer,
                                        bool only_suffix_null)
287
288
{
	if (initializer->kind != IR_INITIALIZER_COMPOUND)
289
		return false;
290

Matthias Braun's avatar
Matthias Braun committed
291
	size_t len = initializer->compound.n_initializers;
292
	if (len < 1)
293
		return false;
Matthias Braun's avatar
Matthias Braun committed
294
295
296

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

Matthias Braun's avatar
Matthias Braun committed
300
		ir_tarval *tv = get_initializer_tarval(sub_initializer);
Matthias Braun's avatar
Matthias Braun committed
301
		if (!tarval_is_constant(tv))
302
			return false;
303

Matthias Braun's avatar
Matthias Braun committed
304
		ir_mode *mode = get_tarval_mode(tv);
305
		if (!mode_is_int(mode) || get_mode_size_bits(mode) != 8)
306
			return false;
307

Matthias Braun's avatar
Matthias Braun committed
308
		int c = get_tarval_long(tv);
309
310
311
312
313
314
315
316
317
		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;
		}
318
319
320
321
322
323
324
325
326
327
328
	}

	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
329
		ir_tarval *tv = initializer->tarval.value;
330
331
332
333
334
335
336
337
338
		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
339
		for (size_t i = 0; i < initializer->compound.n_initializers; ++i) {
340
341
342
343
344
345
346
347
348
349
350
351
352
353
			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
354
355
 * @param only_suffix_null  if true '\0' is only legal at the end of the
 *                          string.
356
 */
357
static bool entity_is_string_const(const ir_entity *ent, bool only_suffix_null)
358
359
{
	/* if it's an array */
Matthias Braun's avatar
Matthias Braun committed
360
	ir_type *type = get_entity_type(ent);
361
	if (!is_Array_type(type))
Matthias Braun's avatar
Matthias Braun committed
362
		return false;
363
364

	/* and the array's element type is primitive */
Matthias Braun's avatar
Matthias Braun committed
365
	ir_type *element_type = get_array_element_type(type);
366
	if (!is_Primitive_type(element_type))
Matthias Braun's avatar
Matthias Braun committed
367
		return false;
368
369
370

	/* 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
371
	ir_mode *mode = get_type_mode(element_type);
372
	if (!mode_is_int(mode) || get_mode_size_bits(mode) != 8)
Matthias Braun's avatar
Matthias Braun committed
373
		return false;
374

375
376
	ir_initializer_t const *const init = get_entity_initializer(ent);
	if (!init)
377
		return false;
378

379
	return initializer_is_string_const(init, only_suffix_null);
380
381
382
383
}

static bool entity_is_null(const ir_entity *entity)
{
Matthias Braun's avatar
Matthias Braun committed
384
385
	ir_initializer_t *initializer = get_entity_initializer(entity);
	return initializer == NULL || initializer_is_null(initializer);
386
387
388
389
390
391
392
393
394
395
396
}

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)
{
397
	if (is_method_entity(entity) || is_alias_entity(entity))
398
399
		return GAS_SECTION_TEXT;

Matthias Braun's avatar
Matthias Braun committed
400
	ir_linkage linkage = get_entity_linkage(entity);
401
402
403
	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
404
		    && entity_is_string_const(entity, true))
405
406
407
408
			return GAS_SECTION_CSTRING;

		return GAS_SECTION_RODATA;
	}
409
	if (entity_is_null(entity) && !is_alias_entity(entity))
410
411
412
413
414
		return GAS_SECTION_BSS;

	return GAS_SECTION_DATA;
}

415
static be_gas_section_t determine_section(be_main_env_t const *const main_env, ir_entity const *const entity)
416
417
418
419
420
421
422
423
{
	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;
424
	} else if (main_env && owner == main_env->pic_symbols_type) {
425
		return GAS_SECTION_PIC_SYMBOLS;
426
	} else if (main_env && owner == main_env->pic_trampolines_type) {
427
428
429
430
431
		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
432
433
	} else if (owner == get_segment_type(IR_SEGMENT_JCR)) {
		return GAS_SECTION_JCR;
434
435
436
437
438
439
440
441
	} 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;
	}

442
443
444
445
446
	/* the java frontend keeps some functions inside classes */
	if (is_Class_type(owner)) {
		return determine_basic_section(entity);
	}

447
	panic("couldn't determine section for %+F", entity);
448
449
}

450
451
452
453
454
455
456
457
458
459
460
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();
}

461
462
static void emit_weak(const ir_entity *entity)
{
463
	const char *directive;
464
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
465
466
		directive = entity_has_definition(entity) ? ".weak_definition"
		                                          : ".weak_reference";
467
	} else {
468
		directive = ".weak";
469
	}
470
	emit_symbol_directive(directive, entity);
Matthias Braun's avatar
Matthias Braun committed
471
472
}

473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
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");
	}
	case ir_visibility_local:
	case ir_visibility_private:
		*output_global = false;
		return NULL;
	}
	panic("invalid visibility");
}

498
static void emit_visibility(const ir_entity *entity, bool implicit_globl)
Matthias Braun's avatar
Matthias Braun committed
499
{
500
	ir_linkage const linkage = get_entity_linkage(entity);
501

502
	if (linkage & IR_LINKAGE_WEAK)
503
		emit_weak(entity);
504
505

	if (entity_has_definition(entity)) {
506
507
508
509
510
511
512
		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);
513
514
515
	}

	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O
516
517
			&& (linkage & IR_LINKAGE_HIDDEN_USER)
			&& get_entity_ld_name(entity)[0] != '\0') {
518
		emit_symbol_directive(".no_dead_strip", entity);
Matthias Braun's avatar
Matthias Braun committed
519
520
521
	}
}

Matthias Braun's avatar
Matthias Braun committed
522
523
void be_gas_emit_function_prolog(const ir_entity *entity, unsigned po2alignment,
                                 const parameter_dbg_info_t *parameter_infos)
524
{
525
	be_dwarf_method_before(entity, parameter_infos);
526

Matthias Braun's avatar
Matthias Braun committed
527
	be_gas_section_t section = determine_section(NULL, entity);
528
	emit_section(section, entity);
529

Matthias Braun's avatar
Matthias Braun committed
530
531
	/* write the begin line (makes the life easier for scripts parsing the
	 * assembler) */
532
533
534
535
536
537
	if (be_options.verbose_asm) {
		be_emit_cstring("# -- Begin  ");
		be_gas_emit_entity(entity);
		be_emit_char('\n');
		be_emit_write_line();
	}
538

539
	if (po2alignment > 0) {
Matthias Braun's avatar
Matthias Braun committed
540
		const char *fill_byte    = "";
Matthias Braun's avatar
Matthias Braun committed
541
542
543
544
545
		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
546
		be_emit_cstring("\t.p2align ");
547
		be_emit_irprintf("%u,%s,%u\n", po2alignment, fill_byte, maximum_skip);
Michael Beck's avatar
Michael Beck committed
548
549
		be_emit_write_line();
	}
550
	emit_visibility(entity, false);
551

Matthias Braun's avatar
Matthias Braun committed
552
553
	switch (be_gas_object_file_format) {
	case OBJECT_FILE_FORMAT_ELF:
554
		be_emit_cstring("\t.type\t");
555
		be_gas_emit_entity(entity);
556
557
558
		be_emit_cstring(", ");
		be_emit_char(be_gas_elf_type_char);
		be_emit_cstring("function\n");
559
560
		be_emit_write_line();
		break;
Matthias Braun's avatar
Matthias Braun committed
561
	case OBJECT_FILE_FORMAT_COFF:
562
		be_emit_cstring("\t.def\t");
563
		be_gas_emit_entity(entity);
Matthias Braun's avatar
Matthias Braun committed
564
		be_emit_cstring(";");
565
		if (get_entity_visibility(entity) == ir_visibility_local) {
Matthias Braun's avatar
Matthias Braun committed
566
			be_emit_cstring("\t.scl\t3;");
567
		} else {
Matthias Braun's avatar
Matthias Braun committed
568
			be_emit_cstring("\t.scl\t2;");
569
		}
Matthias Braun's avatar
Matthias Braun committed
570
		be_emit_cstring("\t.type\t32;\t.endef\n");
571
572
		be_emit_write_line();
		break;
Matthias Braun's avatar
Matthias Braun committed
573
	case OBJECT_FILE_FORMAT_MACH_O:
574
575
		break;
	}
576
	be_gas_emit_entity(entity);
577
578
	be_emit_cstring(":\n");
	be_emit_write_line();
579
580

	be_dwarf_method_begin();
581
582
}

583
void be_gas_emit_function_epilog(const ir_entity *entity)
584
{
585
586
	be_dwarf_method_end();

Matthias Braun's avatar
Matthias Braun committed
587
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_ELF) {
588
		be_emit_cstring("\t.size\t");
589
		be_gas_emit_entity(entity);
590
		be_emit_cstring(", .-");
591
		be_gas_emit_entity(entity);
592
593
594
595
		be_emit_char('\n');
		be_emit_write_line();
	}

596
597
598
599
600
601
	if (be_options.verbose_asm) {
		be_emit_cstring("# -- End  ");
		be_gas_emit_entity(entity);
		be_emit_char('\n');
		be_emit_write_line();
	}
602
603
604

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

606
	next_block_nr += 199;
607
	next_block_nr -= next_block_nr % 100;
608
609
}

Michael Beck's avatar
Michael Beck committed
610
/**
611
 * Output parts of a tarval.
Michael Beck's avatar
Michael Beck committed
612
 *
613
614
615
 * @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
616
 */
617
static void emit_tv(ir_tarval *const tv, unsigned const offset, unsigned const n)
618
{
619
620
621
	be_emit_cstring("0x");
	for (unsigned i = n; i-- != 0;) {
		be_emit_irprintf("%02x", get_tarval_sub_bits(tv, offset + i));
622
	}
623
624
}

625
626
627
/**
 * Return the label prefix for labeled instructions.
 */
Matthias Braun's avatar
Matthias Braun committed
628
629
const char *be_gas_insn_label_prefix(void)
{
630
631
632
	return ".LE";
}

633
/**
Michael Beck's avatar
Michael Beck committed
634
635
636
 * Dump an atomic value.
 *
 * @param init  a node representing the atomic value (on the const code irg)
637
 */
638
static void emit_init_expression(ir_node *const init)
639
{
Matthias Braun's avatar
Matthias Braun committed
640
641
	ir_mode *mode  = get_irn_mode(init);
	int      bytes = get_mode_size_bytes(mode);
642

643
	switch (get_irn_opcode(init)) {
Matthias Braun's avatar
Matthias Braun committed
644
	case iro_Id:
645
		emit_init_expression(get_Id_pred(init));
Matthias Braun's avatar
Matthias Braun committed
646
647
		return;

648
	case iro_Conv:
649
		emit_init_expression(get_Conv_op(init));
650
651
		return;

Matthias Braun's avatar
Matthias Braun committed
652
653
	case iro_Const: {
		ir_tarval *tv = get_Const_tarval(init);
654
		/* it's an arithmetic value */
655
		emit_tv(tv, 0, bytes);
656
		return;
Matthias Braun's avatar
Matthias Braun committed
657
	}
658

659
660
661
	case iro_Address:
		be_gas_emit_entity(get_Address_entity(init));
		return;
662

663
664
665
	case iro_Offset:
		be_emit_irprintf("%d", get_entity_offset(get_Offset_entity(init)));
		return;
666

667
668
669
	case iro_Align:
		be_emit_irprintf("%u", get_type_alignment_bytes(get_Align_type(init)));
		return;
670

671
672
673
	case iro_Size:
		be_emit_irprintf("%u", get_type_size_bytes(get_Size_type(init)));
		return;
674

Michael Beck's avatar
Michael Beck committed
675
676
	case iro_Add:
		if (!mode_is_int(mode) && !mode_is_reference(mode)) {
677
			panic("constant must be int or pointer for '+' to work");
Michael Beck's avatar
Michael Beck committed
678
		}
679
		emit_init_expression(get_Add_left(init));
Michael Beck's avatar
Michael Beck committed
680
		be_emit_cstring(" + ");
681
		emit_init_expression(get_Add_right(init));
Michael Beck's avatar
Michael Beck committed
682
		return;
683

Michael Beck's avatar
Michael Beck committed
684
685
	case iro_Sub:
		if (!mode_is_int(mode) && !mode_is_reference(mode)) {
686
			panic("constant must be int or pointer for '-' to work");
Michael Beck's avatar
Michael Beck committed
687
		}
688
		emit_init_expression(get_Sub_left(init));
Michael Beck's avatar
Michael Beck committed
689
		be_emit_cstring(" - ");
690
		emit_init_expression(get_Sub_right(init));
Michael Beck's avatar
Michael Beck committed
691
692
693
694
		return;

	case iro_Mul:
		if (!mode_is_int(mode) && !mode_is_reference(mode)) {
695
			panic("constant must be int or pointer for '*' to work");
Michael Beck's avatar
Michael Beck committed
696
		}
697
		emit_init_expression(get_Mul_left(init));
Michael Beck's avatar
Michael Beck committed
698
		be_emit_cstring(" * ");
699
		emit_init_expression(get_Mul_right(init));
Michael Beck's avatar
Michael Beck committed
700
701
		return;

Olaf Liebe's avatar
Olaf Liebe committed
702
703
704
705
	case iro_Unknown:
		be_emit_cstring("0");
		return;

Michael Beck's avatar
Michael Beck committed
706
	default:
707
		panic("unsupported IR-node %+F", init);
708
	}
709
710
}

711
/**
Michael Beck's avatar
Michael Beck committed
712
713
714
 * Dumps the type for given size (.byte, .long, ...)
 *
 * @param size  the size in bytes
715
 */
716
static void emit_size_type(size_t size)
717
{
Christian Würdig's avatar
Christian Würdig committed
718
	switch (size) {
719
720
721
722
	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;
723

724
	default:
725
		panic("try to dump a type with %u bytes", (unsigned)size);
726
	}
Christian Würdig's avatar
Christian Würdig committed
727
728
}

729
static void emit_string_char(int c)
730
{
731
732
733
734
735
736
737
738
739
740
741
742
	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;
743
	}
744
}
745

746
747
748
749
750
751
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) {
752
753
754
		const ir_initializer_t *sub_initializer
			= get_initializer_compound_value(initializer, i);

Matthias Braun's avatar
Matthias Braun committed
755
756
		ir_tarval *tv = get_initializer_tarval(sub_initializer);
		int        c  = get_tarval_long(tv);
757
		emit_string_char(c);
758
	}
759
760
	be_emit_cstring("\"\n");
	be_emit_write_line();
761
762

	return initializer->compound.n_initializers;
763
764
}

765
766
767
768
769
770
771
772
773
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('"');
}

774
775
776
777
778
779
780
781
782
783
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();
}

784
typedef enum normal_or_bitfield_kind {
785
	NORMAL = 0,
786
	TARVAL,
787
	STRING,
788
	BITFIELD
789
} normal_or_bitfield_kind;
790
791

typedef struct {
792
	normal_or_bitfield_kind kind;
793
	ir_type                *type;
794
	union {
795
796
797
798
		ir_node                *value;
		ir_tarval              *tarval;
		unsigned char           bf_val;
		const ir_initializer_t *string;
799
800
801
	} v;
} normal_or_bitfield;

802
803
804
static size_t get_initializer_size(const ir_initializer_t *initializer,
                                   ir_type *type)
{
Michael Beck's avatar
Michael Beck committed
805
	switch (get_initializer_kind(initializer)) {
Michael Beck's avatar
Michael Beck committed
806
	case IR_INITIALIZER_TARVAL:
Matthias Braun's avatar
Matthias Braun committed
807
		assert(get_tarval_mode(get_initializer_tarval_value(initializer)) == get_type_mode(type));
808
809
810
811
		return get_type_size_bytes(type);
	case IR_INITIALIZER_CONST:
	case IR_INITIALIZER_NULL:
		return get_type_size_bytes(type);
Michael Beck's avatar
Michael Beck committed
812
	case IR_INITIALIZER_COMPOUND:
813
814
815
816
817
818
819
820
821
822
823
824
825
826
		if (is_Array_type(type)) {
			if (is_array_variable_size(type)) {
				ir_type   *element_type = get_array_element_type(type);
				unsigned   element_size = get_type_size_bytes(element_type);
				unsigned   element_align
					= get_type_alignment_bytes(element_type);
				unsigned   misalign     = element_size % element_align;
				size_t     n_inits
					= get_initializer_compound_n_entries(initializer);
				element_size += element_align - misalign;
				return n_inits * element_size;
			} else {
				return get_type_size_bytes(type);
			}
827
		} else {
828
829
830
831
832
833
834
835
836
837
838
			assert(is_compound_type(type));
			size_t size = get_type_size_bytes(type);
			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);
839
			}
840
			return size;
841
842
843
844
845
846
847
848
849
850
851
		}
	}

	panic("found invalid initializer");
}

#ifndef NDEBUG
static normal_or_bitfield *glob_vals;
static size_t              max_vals;
#endif

852
853
static void emit_bitfield(normal_or_bitfield *vals, unsigned offset_bits,
                          unsigned bitfield_size,
854
855
                          const ir_initializer_t *initializer, ir_type *type)
{
856
	static const size_t BITS_PER_BYTE = 8;
857

858
	ir_tarval *tv = NULL;
Michael Beck's avatar
Michael Beck committed
859
	switch (get_initializer_kind(initializer)) {
860
861
862
863
864
865
866
	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
867
		if (!is_Const(node)) {
868
869
870
871
872
873
874
875
			panic("bitfield initializer not a Const node");
		}
		tv = get_Const_tarval(node);
		break;
	}
	case IR_INITIALIZER_COMPOUND:
		panic("bitfield initializer is compound");
	}
876
	if (tv == NULL || tv == tarval_bad) {
877
		panic("couldn't get numeric value for bitfield initializer");
878
879
	}

880
	int    value_len  = get_type_size_bytes(type);
Matthias Braun's avatar
Matthias Braun committed
881
	size_t bit_offset = 0;
882
	size_t end        = bitfield_size;
Matthias Braun's avatar
Matthias Braun committed
883
	bool   big_endian = be_get_backend_param()->byte_order_big_endian;
884
	while (bit_offset < end) {
Matthias Braun's avatar
Matthias Braun committed
885
886
887
888
889
890
		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;
891
892
893
		if (src_bits_len > dst_bits_len)
			src_bits_len = dst_bits_len;

Matthias Braun's avatar
Matthias Braun committed
894
		normal_or_bitfield *val;
895
896
897
898
899
900
901
902
903
		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
904
905
906
		val->kind = BITFIELD;
		unsigned char curr_bits = get_tarval_sub_bits(tv, src_offset);
		curr_bits = curr_bits >> src_offset_bits;
907
908
909
910
911
912
913
914
		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;
915
916
917
	}
}

918
static void emit_ir_initializer(normal_or_bitfield *vals,
919
920
921
                                const ir_initializer_t *initializer,
                                ir_type *type)
{
922
	assert((size_t) (vals - glob_vals) <= max_vals);
923

924
	if (initializer_is_string_const(initializer, false)) {
925
926
927
928
929
930
		assert(vals->kind != BITFIELD);
		vals->kind     = STRING;
		vals->v.string = initializer;
		return;
	}

Michael Beck's avatar
Michael Beck committed
931
	switch (get_initializer_kind(initializer)) {
932
933
	case IR_INITIALIZER_NULL:
		return;
Matthias Braun's avatar
Matthias Braun committed
934
	case IR_INITIALIZER_TARVAL:
935
936
		assert(vals->kind != BITFIELD);
		vals->kind     = TARVAL;
937
		vals->type     = type;
938
939
		vals->v.tarval = get_initializer_tarval_value(initializer);
		assert(get_type_mode(type) == get_tarval_mode(vals->v.tarval));
Matthias Braun's avatar
Matthias Braun committed
940
		for (size_t i = 1; i < get_type_size_bytes(type); ++i) {
941
			vals[i].kind    = NORMAL;
942
			vals[i].type    = NULL;
943
944
945
946
			vals[i].v.value = NULL;
		}
		return;

Matthias Braun's avatar
Matthias Braun committed
947
	case IR_INITIALIZER_CONST:
948
949
		assert(vals->kind != BITFIELD);
		vals->kind    = NORMAL;
950
		vals->type    = type;
951
		vals->v.value = get_initializer_const_value(initializer);
Matthias Braun's avatar
Matthias Braun committed
952
		for (size_t i = 1; i < get_type_size_bytes(type); ++i) {
953
			vals[i].kind    = NORMAL;
954
			vals[i].type    = NULL;
955
956
957
958
			vals[i].v.value = NULL;
		}
		return;

Matthias Braun's avatar
Matthias Braun committed
959
	case IR_INITIALIZER_COMPOUND:
Michael Beck's avatar
Michael Beck committed
960
		if (is_Array_type(type)) {
961
962
963
964
			ir_type *element_type = get_array_element_type(type);
			size_t   skip         = get_type_size_bytes(element_type);
			size_t   alignment    = get_type_alignment_bytes(element_type);
			size_t   misalign     = skip % alignment;
Michael Beck's avatar
Michael Beck committed
965
			if (misalign != 0) {
966
967
968
				skip += alignment - misalign;
			}

Matthias Braun's avatar
Matthias Braun committed
969
970
971
			for (size_t i = 0,
			     n = get_initializer_compound_n_entries(initializer);
			     i < n; ++i) {
972
973
974
				ir_initializer_t *sub_initializer
					= get_initializer_compound_value(initializer, i);

975
				emit_ir_initializer(vals, sub_initializer, element_type);
976
977
978
979
980

				vals += skip;
			}
		} else {
			assert(is_compound_type(type));
Matthias Braun's avatar
Matthias Braun committed
981
982
983
984
			for (size_t i = 0, n_members = get_compound_n_members(type);
			     i < n_members; ++i) {
				ir_entity *member = get_compound_member(type, i);
				size_t     offset = get_entity_offset(member);
985
986

				assert(i < get_initializer_compound_n_entries(initializer));
Matthias Braun's avatar
Matthias Braun committed
987
				ir_initializer_t *sub_initializer
988
989
					= get_initializer_compound_value(initializer, i);

990
991
992
993
994
995
996
				ir_type *subtype       = get_entity_type(member);
				unsigned bitfield_size = get_entity_bitfield_size(member);
				if (bitfield_size > 0) {
					unsigned offset_bits = get_entity_bitfield_offset(member);
					emit_bitfield(&vals[offset], offset_bits, bitfield_size,
								  sub_initializer, subtype);
					continue;
997
998
				}

999
				emit_ir_initializer(&vals[offset], sub_initializer, subtype);
1000
1001
1002
1003
1004
			}
		}

		return;
	}
1005
	panic("invalid ir_initializer kind found");
1006
1007
}

1008
1009
1010
static void emit_tarval_data(ir_type *type, ir_tarval *tv)
{
	size_t size = get_type_size_bytes(type);
1011
1012
	if (size > 8) {
		assert(size % 4 == 0);
1013
		if (be_get_backend_param()->byte_order_big_endian) {
1014
1015
1016
1017
1018
			for (unsigned i = size; i != 0;) {
				emit_size_type(4);
				emit_tv(tv, i -= 4, 4);
				be_emit_char('\n');
			}
1019
1020
		} else {
			/* Beware: Mixed endian output! One little endian number emitted as
1021
1022
1023
1024
1025
1026
			 * longs.  Each long initializer is written in big endian. */
			for (unsigned i = 0; i != size; i += 4) {
				emit_size_type(4);
				emit_tv(tv, i, 4);
				be_emit_char('\n');
			}
1027
1028
1029
1030
		}
	} else {
		/* default case */
		emit_size_type(size);
1031
		emit_tv(tv, 0, size);
1032
1033
		be_emit_char('\n');
	}
1034
	be_emit_write_line();
1035
1036
1037
1038
1039
1040
1041
}

/**
 * Emit an atomic value.
 *
 * @param init  a node representing the atomic value (on the const code irg)
 */