begnuas.c 49.7 KB
Newer Older
Christian Würdig's avatar
Christian Würdig committed
1
/*
Michael Beck's avatar
Michael Beck committed
2
 * Copyright (C) 1995-2011 University of Karlsruhe.  All right reserved.
Christian Würdig's avatar
Christian Würdig committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 *
 * This file is part of libFirm.
 *
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation and appearing in the file LICENSE.GPL included in the
 * packaging of this file.
 *
 * Licensees holding valid libFirm Professional Edition licenses may use
 * this file in accordance with the libFirm Commercial License.
 * Agreement provided with the Software.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE.
 */

20
/**
Christian Würdig's avatar
Christian Würdig committed
21
22
23
24
25
 * @file
 * @brief       Dumps global variables and constants as gas assembler.
 * @author      Christian Wuerdig, Matthias Braun
 * @date        04.11.2005
 * @version     $Id$
26
 */
27
#include "config.h"
28

Matthias Braun's avatar
Matthias Braun committed
29
30
#include "begnuas.h"

31
32
33
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
Christian Würdig's avatar
Christian Würdig committed
34
#include <assert.h>
35

36
#include "obst.h"
37
38
39
#include "tv.h"
#include "irnode.h"
#include "irprog.h"
40
#include "entity_t.h"
41
#include "error.h"
42
#include "util.h"
43

Matthias Braun's avatar
Matthias Braun committed
44
45
46
#include "be_t.h"
#include "beemitter.h"
#include "be_dbgout.h"
47

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

54
55
static be_gas_section_t current_section = (be_gas_section_t) -1;

Michael Beck's avatar
Michael Beck committed
56
/**
57
58
59
60
 * An environment containing all needed dumper data.
 * Currently we create the file completely in memory first, then
 * write it to the disk. This is an artifact from the old C-generating backend
 * and even there NOT needed. So we might change it in the future.
Michael Beck's avatar
Michael Beck committed
61
 */
62
typedef struct be_gas_decl_env {
63
64
65
66
	be_gas_section_t     section;
	const be_main_env_t *main_env;
} be_gas_decl_env_t;

Matthias Braun's avatar
Matthias Braun committed
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
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;
	const char       *name;

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

	/* shortforms */
	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;
89
90
91
92
		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;
Matthias Braun's avatar
Matthias Braun committed
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
		default: panic("unsupported scetion type 0x%X", section);
		}
		be_emit_irprintf("\t.%s\n", name);
		be_emit_write_line();
	} 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);
		}
	} else {
		panic("unsupported section type 0x%X\n", section);
	}
}

111
112
113
114
static void emit_section_sparc(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;
115
116
117
118
119
120
121
122
123
124
125
126
127
128
	static const char *const basename[GAS_SECTION_LAST+1] = {
		"text",
		"data",
		"rodata",
		"bss",
		"ctors",
		"dtors",
		NULL, /* cstring */
		NULL, /* pic trampolines */
		NULL, /* pic symbols */
		"debug_info",
		"debug_abbrev",
		"debug_line",
		"debug_pubnames"
129
130
131
132
133
134
135
136
137
138
139
	};

	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');
140
	assert(base < (be_gas_section_t)ARRAY_SIZE(basename));
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
	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();
}

172
static void emit_section(be_gas_section_t section, const ir_entity *entity)
Matthias Braun's avatar
Matthias Braun committed
173
{
174
175
	be_gas_section_t base = section & GAS_SECTION_TYPE_MASK;
	be_gas_section_t flags = section & ~GAS_SECTION_TYPE_MASK;
176
177
178
179
180
	const char *f;
	static const struct {
		const char *name;
		const char *type;
		const char *flags;
181
182
183
184
185
186
187
188
189
190
191
192
193
194
	} 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", ""   },
Matthias Braun's avatar
Matthias Braun committed
195
196
	};

Matthias Braun's avatar
Matthias Braun committed
197
198
199
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
		emit_section_macho(section);
		return;
200
	} else if(be_gas_elf_variant == ELF_VARIANT_SPARC) {
201
202
		emit_section_sparc(section, entity);
		return;
Matthias Braun's avatar
Matthias Braun committed
203
204
	}

205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
	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;
		}
	}

233
	assert(base < (be_gas_section_t) ARRAY_SIZE(sectioninfos));
234
235
236
237
	be_emit_cstring("\t.section\t.");
	/* section name */
	if (flags & GAS_SECTION_FLAG_TLS)
		be_emit_char('t');
238
	be_emit_string(sectioninfos[base].name);
239
240
241
242
243
244
245
	if (flags & GAS_SECTION_FLAG_COMDAT) {
		be_emit_char('.');
		be_gas_emit_entity(entity);
	}

	/* section flags */
	be_emit_cstring(",\"");
246
247
248
	for (f = sectioninfos[base].flags; *f != '\0'; ++f) {
		be_emit_char(*f);
	}
249
250
251
252
	if (flags & GAS_SECTION_FLAG_TLS)
		be_emit_char('T');
	if (flags & GAS_SECTION_FLAG_COMDAT)
		be_emit_char('G');
253

254
255
256
257
	/* section type */
	if (be_gas_object_file_format != OBJECT_FILE_FORMAT_COFF) {
		be_emit_cstring("\",");
		be_emit_char(be_gas_elf_type_char);
258
		be_emit_string(sectioninfos[base].type);
259
	}
260
261
262
263
264
265
266
267

	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
268
269
}

270
271


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

	emit_section(section, NULL);
}

Matthias Braun's avatar
Matthias Braun committed
281
static ir_tarval *get_initializer_tarval(const ir_initializer_t *initializer)
Matthias Braun's avatar
Matthias Braun committed
282
283
284
285
286
287
288
289
290
291
292
293
{
	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();
}

294
static bool initializer_is_string_const(const ir_initializer_t *initializer)
295
296
{
	size_t i, len;
297
	bool found_printable = false;
298
299

	if (initializer->kind != IR_INITIALIZER_COMPOUND)
300
		return false;
301
302
303

	len = initializer->compound.n_initializers;
	if (len < 1)
304
		return false;
305
306
	for (i = 0; i < len; ++i) {
		int               c;
Matthias Braun's avatar
Matthias Braun committed
307
		ir_tarval        *tv;
308
309
310
311
		ir_mode          *mode;
		ir_initializer_t *sub_initializer
			= initializer->compound.initializers[i];

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

		mode = get_tarval_mode(tv);
		if (!mode_is_int(mode) || get_mode_size_bits(mode) != 8)
318
			return false;
319
320
321

		c = get_tarval_long(tv);
		if (isgraph(c) || isspace(c))
322
			found_printable = true;
323
		else if (c != 0)
324
			return false;
325
326

		if (i == len - 1 && c != '\0')
327
			return false;
328
329
330
331
332
333
334
335
336
337
338
	}

	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
339
		ir_tarval *tv = initializer->tarval.value;
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
		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;
372

373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
	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 */
425
		return false;
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
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
	}
	/* 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;
	}

486
487
488
489
490
	/* the java frontend keeps some functions inside classes */
	if (is_Class_type(owner)) {
		return determine_basic_section(entity);
	}

491
492
493
494
495
496
497
498
499
500
501
	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);
502
503
	be_emit_char('\n');
	be_emit_write_line();
Matthias Braun's avatar
Matthias Braun committed
504
505
}

506
static void emit_visibility(const ir_entity *entity)
Matthias Braun's avatar
Matthias Braun committed
507
{
508
509
	ir_linkage linkage = get_entity_linkage(entity);

510
	if (get_entity_linkage(entity) & IR_LINKAGE_WEAK) {
511
512
513
514
		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 ");
515
		be_gas_emit_entity(entity);
Matthias Braun's avatar
Matthias Braun committed
516
517
		be_emit_char('\n');
		be_emit_write_line();
518
519
520
	}

	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O
521
522
			&& (linkage & IR_LINKAGE_HIDDEN_USER)
			&& get_entity_ld_name(entity)[0] != '\0') {
523
		be_emit_cstring("\t.no_dead_strip ");
524
		be_gas_emit_entity(entity);
Matthias Braun's avatar
Matthias Braun committed
525
526
527
528
529
		be_emit_char('\n');
		be_emit_write_line();
	}
}

530
void be_gas_emit_function_prolog(const ir_entity *entity, unsigned po2alignment)
531
{
532
533
534
535
536
	be_gas_section_t section;

	be_dbg_method_begin(entity);

	section = determine_section(NULL, entity);
537
	emit_section(section, entity);
538

Matthias Braun's avatar
Matthias Braun committed
539
540
	/* write the begin line (makes the life easier for scripts parsing the
	 * assembler) */
541
542
	be_emit_write_line();
	be_emit_cstring("# -- Begin  ");
543
	be_gas_emit_entity(entity);
544
545
546
	be_emit_char('\n');
	be_emit_write_line();

547
	if (po2alignment > 0) {
Matthias Braun's avatar
Matthias Braun committed
548
549
550
551
552
553
		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";
		}
Michael Beck's avatar
Michael Beck committed
554
		be_emit_cstring("\t.p2align ");
555
		be_emit_irprintf("%u,%s,%u\n", po2alignment, fill_byte, maximum_skip);
Michael Beck's avatar
Michael Beck committed
556
557
		be_emit_write_line();
	}
558
	emit_visibility(entity);
559

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

589
void be_gas_emit_function_epilog(const ir_entity *entity)
590
{
Matthias Braun's avatar
Matthias Braun committed
591
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_ELF) {
592
		be_emit_cstring("\t.size\t");
593
		be_gas_emit_entity(entity);
594
		be_emit_cstring(", .-");
595
		be_gas_emit_entity(entity);
596
597
598
599
600
		be_emit_char('\n');
		be_emit_write_line();
	}

	be_emit_cstring("# -- End  ");
601
	be_gas_emit_entity(entity);
602
603
	be_emit_char('\n');
	be_emit_write_line();
604
605
606
607
608

	be_dbg_method_end();

	be_emit_char('\n');
	be_emit_write_line();
609
610
}

Michael Beck's avatar
Michael Beck committed
611
/**
Michael Beck's avatar
Michael Beck committed
612
613
614
615
 * Output a tarval.
 *
 * @param tv     the tarval
 * @param bytes  the width of the tarvals value in bytes
Michael Beck's avatar
Michael Beck committed
616
 */
617
static void emit_arith_tarval(ir_tarval *tv, unsigned bytes)
618
{
619
620
	switch (bytes) {
	case 1:
621
		be_emit_irprintf("0x%02x", get_tarval_sub_bits(tv, 0));
Matthias Braun's avatar
Matthias Braun committed
622
		return;
623
624

	case 2:
625
626
		be_emit_irprintf("0x%02x%02x",
			get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
Matthias Braun's avatar
Matthias Braun committed
627
		return;
628
629

	case 4:
630
		be_emit_irprintf("0x%02x%02x%02x%02x",
631
632
			get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2),
			get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
Matthias Braun's avatar
Matthias Braun committed
633
		return;
634
635

	case 8:
636
		be_emit_irprintf("0x%02x%02x%02x%02x%02x%02x%02x%02x",
637
638
639
640
			get_tarval_sub_bits(tv, 7), get_tarval_sub_bits(tv, 6),
			get_tarval_sub_bits(tv, 5), get_tarval_sub_bits(tv, 4),
			get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2),
			get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
Matthias Braun's avatar
Matthias Braun committed
641
		return;
642
	}
Matthias Braun's avatar
Matthias Braun committed
643

644
	panic("Can't dump a tarval with %d bytes", bytes);
645
646
}

647
648
649
/**
 * Return the label prefix for labeled instructions.
 */
Matthias Braun's avatar
Matthias Braun committed
650
651
const char *be_gas_insn_label_prefix(void)
{
652
653
654
	return ".LE";
}

655
656
/**
 * Return the tarval of an atomic initializer.
Michael Beck's avatar
Michael Beck committed
657
 *
Michael Beck's avatar
Michael Beck committed
658
 * @param init  a node representing the initializer (on the const code irg)
Michael Beck's avatar
Michael Beck committed
659
660
 *
 * @return the tarval
661
 */
Matthias Braun's avatar
Matthias Braun committed
662
static ir_tarval *get_atomic_init_tv(ir_node *init)
663
{
664
665
	for (;;) {
		ir_mode *mode = get_irn_mode(init);
666

667
		switch (get_irn_opcode(init)) {
668

669
670
671
		case iro_Cast:
			init = get_Cast_op(init);
			continue;
672

673
674
675
		case iro_Conv:
			init = get_Conv_op(init);
			continue;
676

677
678
		case iro_Const:
			return get_Const_tarval(init);
679

680
681
682
683
		case iro_SymConst:
			switch (get_SymConst_kind(init)) {
			case symconst_type_size:
				return new_tarval_from_long(get_type_size_bytes(get_SymConst_type(init)), mode);
684

685
686
			case symconst_type_align:
				return new_tarval_from_long(get_type_alignment_bytes(get_SymConst_type(init)), mode);
687

Michael Beck's avatar
Michael Beck committed
688
689
690
			case symconst_ofs_ent:
				return new_tarval_from_long(get_entity_offset(get_SymConst_entity(init)), mode);

691
692
			case symconst_enum_const:
				return get_enumeration_value(get_SymConst_enum(init));
693

694
695
696
			default:
				return NULL;
			}
697
698
699

		default:
			return NULL;
700
		}
701
702
703
	}
}

704
/**
Michael Beck's avatar
Michael Beck committed
705
706
707
708
 * Dump an atomic value.
 *
 * @param env   the gas output environment
 * @param init  a node representing the atomic value (on the const code irg)
709
 */
710
static void emit_init_expression(be_gas_decl_env_t *env, ir_node *init)
711
{
712
713
	ir_mode *mode = get_irn_mode(init);
	int bytes     = get_mode_size_bytes(mode);
Matthias Braun's avatar
Matthias Braun committed
714
	ir_tarval *tv;
715
	ir_entity *ent;
716

717
718
	init = skip_Id(init);

719
720
	switch (get_irn_opcode(init)) {
	case iro_Cast:
721
		emit_init_expression(env, get_Cast_op(init));
722
723
724
		return;

	case iro_Conv:
725
		emit_init_expression(env, get_Conv_op(init));
726
727
728
729
730
		return;

	case iro_Const:
		tv = get_Const_tarval(init);

731
		/* it's an arithmetic value */
732
		emit_arith_tarval(tv, bytes);
733
734
735
736
737
		return;

	case iro_SymConst:
		switch (get_SymConst_kind(init)) {
		case symconst_addr_ent:
738
			ent = get_SymConst_entity(init);
739
			be_gas_emit_entity(ent);
740
741
			break;

742
		case symconst_ofs_ent:
743
			ent = get_SymConst_entity(init);
744
			be_emit_irprintf("%d", get_entity_offset(ent));
745
746
			break;

747
		case symconst_type_size:
748
			be_emit_irprintf("%u", get_type_size_bytes(get_SymConst_type(init)));
749
750
			break;

751
		case symconst_type_align:
752
			be_emit_irprintf("%u", get_type_alignment_bytes(get_SymConst_type(init)));
753
754
			break;

Michael Beck's avatar
Michael Beck committed
755
		case symconst_enum_const:
756
			tv = get_enumeration_value(get_SymConst_enum(init));
757
			emit_arith_tarval(tv, bytes);
Michael Beck's avatar
Michael Beck committed
758
759
			break;

760
		default:
761
			assert(!"emit_atomic_init(): don't know how to init from this SymConst");
762
763
764
		}
		return;

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

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

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

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

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

801
/**
Michael Beck's avatar
Michael Beck committed
802
803
804
 * Dumps the type for given size (.byte, .long, ...)
 *
 * @param size  the size in bytes
805
 */
806
static void emit_size_type(size_t size)
807
{
Christian Würdig's avatar
Christian Würdig committed
808
	switch (size) {
809
810
811
812
	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;
813

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

819
/**
Michael Beck's avatar
Michael Beck committed
820
 * Dump a string constant.
821
 * No checks are made!!
Michael Beck's avatar
Michael Beck committed
822
823
 *
 * @param ent  The entity to dump.
824
 */
825
static void emit_string_cst(const ir_entity *ent)
826
{
827
	int      i, len;
828
	int      output_len;
829
830
831
	ir_type *type;
	int      type_size;
	int      remaining_space;
832

833
834
	len        = get_compound_ent_n_values(ent);
	output_len = len;
Matthias Braun's avatar
Matthias Braun committed
835
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
836
837
838
		be_emit_cstring("\t.ascii \"");
	} else {
		be_emit_cstring("\t.string \"");
839
		output_len -= 1;
840
	}
841

842
	for (i = 0; i < output_len; ++i) {
843
844
845
846
847
848
849
		ir_node *irn;
		int c;

		irn = get_compound_ent_value(ent, i);
		c = (int) get_tarval_long(get_Const_tarval(irn));

		switch (c) {
850
851
852
853
854
		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;
855
856
		default  :
			if (isprint(c))
857
				be_emit_char(c);
858
			else
859
				be_emit_irprintf("\\%03o", c);
860
861
862
			break;
		}
	}
863
864
	be_emit_cstring("\"\n");
	be_emit_write_line();
865
866
867

	type            = get_entity_type(ent);
	type_size       = get_type_size_bytes(type);
868
	remaining_space = type_size - len;
869
	assert(remaining_space >= 0);
Michael Beck's avatar
Michael Beck committed
870
	if (remaining_space > 0) {
871
		be_emit_irprintf("\t.space\t%d, 0\n", remaining_space);
872
	}
873
874
}

875
static size_t emit_string_initializer(const ir_initializer_t *initializer)
876
877
878
879
{
	size_t i, len;

	len = initializer->compound.n_initializers;
Matthias Braun's avatar
Matthias Braun committed
880
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
Matthias Braun's avatar
Matthias Braun committed
881
882
		be_emit_cstring("\t.ascii \"");
	} else {
883
884
885
886
		be_emit_cstring("\t.string \"");
		len -= 1;
	}

Michael Beck's avatar
Michael Beck committed
887
	for (i = 0; i < len; ++i) {
888
889
890
		const ir_initializer_t *sub_initializer
			= get_initializer_compound_value(initializer, i);

Matthias Braun's avatar
Matthias Braun committed
891
892
		ir_tarval *tv = get_initializer_tarval(sub_initializer);
		int        c  = get_tarval_long(tv);
893
894

		switch (c) {
895
896
897
898
899
		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;
900
901
		default  :
			if (isprint(c))
902
				be_emit_char(c);
903
			else
904
				be_emit_irprintf("\\%03o", c);
905
906
907
			break;
		}
	}
908
909
	be_emit_cstring("\"\n");
	be_emit_write_line();
910
911

	return initializer->compound.n_initializers;
912
913
}

914
typedef enum normal_or_bitfield_kind {
915
	NORMAL = 0,
916
	TARVAL,
917
	STRING,
918
	BITFIELD
919
} normal_or_bitfield_kind;
920
921

typedef struct {
922
	normal_or_bitfield_kind kind;
923
	ir_type                *type;
924
	union {
925
926
927
928
		ir_node                *value;
		ir_tarval              *tarval;
		unsigned char           bf_val;
		const ir_initializer_t *string;
929
930
931
	} v;
} normal_or_bitfield;

932
933
934
935
936
937
938
939
940
941
static int is_type_variable_size(ir_type *type)
{
	(void) type;
	/* TODO */
	return 0;
}

static size_t get_initializer_size(const ir_initializer_t *initializer,
                                   ir_type *type)
{
Michael Beck's avatar
Michael Beck committed
942
	switch (get_initializer_kind(initializer)) {
Michael Beck's avatar
Michael Beck committed
943
	case IR_INITIALIZER_TARVAL:
Matthias Braun's avatar
Matthias Braun committed
944
		assert(get_tarval_mode(get_initializer_tarval_value(initializer)) == get_type_mode(type));
945
946
947
948
		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
949
	case IR_INITIALIZER_COMPOUND:
Michael Beck's avatar
Michael Beck committed
950
		if (!is_type_variable_size(type)) {
951
952
			return get_type_size_bytes(type);
		} else {
Michael Beck's avatar
Michael Beck committed
953
			size_t n_entries
954
				= get_initializer_compound_n_entries(initializer);
Michael Beck's avatar
Michael Beck committed
955
			size_t i;
956
			unsigned initializer_size = get_type_size_bytes(type);
Michael Beck's avatar
Michael Beck committed
957
			for (i = 0; i < n_entries; ++i) {
958
959
960
961
962
963
964
965
966
				ir_entity *entity = get_compound_member(type, i);
				ir_type   *type   = get_entity_type(entity);

				const ir_initializer_t *sub_initializer
					= get_initializer_compound_value(initializer, i);

				unsigned offset = get_entity_offset(entity);
				unsigned size   = get_initializer_size(sub_initializer, type);

Michael Beck's avatar
Michael Beck committed
967
				if (offset + size > initializer_size) {
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
					initializer_size = offset + size;
				}
			}
			return initializer_size;
		}
	}

	panic("found invalid initializer");
}

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

983
static void emit_bitfield(normal_or_bitfield *vals, size_t offset_bits,
984
985
                          const ir_initializer_t *initializer, ir_type *type)
{
986
	static const size_t BITS_PER_BYTE = 8;
Matthias Braun's avatar
Matthias Braun committed
987
988
989
990
991
992
	ir_mode   *mode      = get_type_mode(type);
	ir_tarval *tv        = NULL;
	int        value_len;
	size_t     bit_offset;
	size_t     end;
	bool       big_endian = be_get_backend_param()->byte_order_big_endian;
993

Michael Beck's avatar
Michael Beck committed
994
	switch (get_initializer_kind(initializer)) {
995
996
997
998
999
1000
1001
	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
1002
		if (!is_Const(node)) {
1003
1004
1005
1006
1007
1008
1009
1010
1011
			panic("bitfield initializer not a Const node");
		}
		tv = get_Const_tarval(node);
		break;
	}
	case IR_INITIALIZER_COMPOUND:
		panic("bitfield initializer is compound");
	}
	if (tv == NULL) {
1012
		panic("Couldn't get numeric value for bitfield initializer");
1013
	}
1014
	tv = tarval_convert_to(tv, get_type_mode(type));
1015

1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
	value_len  = get_type_size_bytes(get_primitive_base_type(type));
	bit_offset = 0;
	end        = get_mode_size_bits(mode);
	while (bit_offset < end) {
		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;
		unsigned char curr_bits;
		normal_or_bitfield *val;
		if (src_bits_len > dst_bits_len)
			src_bits_len = dst_bits_len;

		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));
		val->kind  = BITFIELD;
		curr_bits  = get_tarval_sub_bits(tv, src_offset);
		curr_bits  = curr_bits >> src_offset_bits;
		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;
1051
1052
1053
	}
}

1054
static void emit_ir_initializer(normal_or_bitfield *vals,
1055
1056
1057
1058
1059
                                const ir_initializer_t *initializer,
                                ir_type *type)
{
	assert((size_t) (vals - glob_vals) < max_vals);

1060
1061
1062
1063
1064
1065
1066
	if (initializer_is_string_const(initializer)) {
		assert(vals->kind != BITFIELD);
		vals->kind     = STRING;
		vals->v.string = initializer;
		return;
	}

Michael Beck's avatar
Michael Beck committed
1067
	switch (get_initializer_kind(initializer)) {
1068
1069
1070
1071
1072
1073
1074
	case IR_INITIALIZER_NULL:
		return;
	case IR_INITIALIZER_TARVAL: {
		size_t i;

		assert(vals->kind != BITFIELD);
		vals->kind     = TARVAL;
1075
		vals->type     = type;
1076
1077
		vals->v.tarval = get_initializer_tarval_value(initializer);
		assert(get_type_mode(type) == get_tarval_mode(vals->v.tarval));
Michael Beck's avatar
Michael Beck committed
1078
		for (i = 1; i < get_type_size_bytes(type); ++i) {
1079
			vals[i].kind    = NORMAL;
1080
			vals[i].type    = NULL;
1081
1082
1083
1084
1085
1086
1087
1088
1089
			vals[i].v.value = NULL;
		}
		return;
	}
	case IR_INITIALIZER_CONST: {
		size_t i;

		assert(vals->kind != BITFIELD);
		vals->kind    = NORMAL;
1090
		vals->type    = type;
1091
		vals->v.value = get_initializer_const_value(initializer);
Michael Beck's avatar
Michael Beck committed
1092
		for (i = 1; i < get_type_size_bytes(type); ++i) {
1093
			vals[i].kind    = NORMAL;
1094
			vals[i].type    = NULL;
1095
1096
1097
1098
1099
1100
1101
1102
			vals[i].v.value = NULL;
		}
		return;
	}
	case IR_INITIALIZER_COMPOUND: {
		size_t i = 0;
		size_t n = get_initializer_compound_n_entries(initializer);

Michael Beck's avatar
Michael Beck committed
1103
		if (is_Array_type(type)) {
1104
1105
1106
1107
			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
1108
			if (misalign != 0) {
1109
1110
1111
				skip += alignment - misalign;
			}

Michael Beck's avatar
Michael Beck committed
1112
			for (i = 0; i < n; ++i) {
1113
1114
1115
				ir_initializer_t *sub_initializer
					= get_initializer_compound_value(initializer, i);

1116
				emit_ir_initializer(vals, sub_initializer, element_type);
1117
1118
1119
1120

				vals += skip;
			}
		} else {
Michael Beck's avatar
Michael Beck committed
1121
			size_t n_members, i;
1122
			assert(is_compound_type(type));
Michael Beck's avatar
Michael Beck committed
1123
			n_members = get_compound_n_members(type);
Michael Beck's avatar
Michael Beck committed
1124
			for (i = 0; i < n_members; ++i) {
1125
1126
1127
1128
				ir_entity        *member    = get_compound_member(type, i);
				size_t            offset    = get_entity_offset(member);
				ir_type          *subtype   = get_entity_type(member);
				ir_mode          *mode      = get_type_mode(subtype);
1129
1130