ia32_gen_decls.c 16.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
/**
 * Dumps global variables and constants as ia32 assembler.
 * @author Christian Wuerdig
 * @date 04.11.2005
 * @version $Id$
 */

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
Christian Würdig's avatar
Christian Würdig committed
11
#include <assert.h>
12

13
#include "obst.h"
14
15
16
17
18
#include "tv.h"
#include "irnode.h"
#include "entity.h"
#include "irprog.h"

Christian Würdig's avatar
Christian Würdig committed
19
#include "../be.h"
Christian Würdig's avatar
Christian Würdig committed
20

Michael Beck's avatar
Michael Beck committed
21
#include "ia32_emitter.h"
22
23
#include "ia32_gen_decls.h"

Christian Würdig's avatar
Christian Würdig committed
24
25
26
typedef struct obstack obstack_t;

typedef struct _ia32_decl_env {
Christian Würdig's avatar
Christian Würdig committed
27
28
29
30
31
	obstack_t *rodata_obst;
	obstack_t *data_obst;
	obstack_t *comm_obst;
	obstack_t *ctor_obst;
	const be_main_env_t *main_env;
Christian Würdig's avatar
Christian Würdig committed
32
33
} ia32_decl_env_t;

34
35
36
37
38
39
40
/************************************************************************/

/*
 * returns the highest bit value
 */
static unsigned highest_bit(unsigned v)
{
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
	int res = -1;

	if (v >= (1U << 16U)) {
		res += 16;
		v >>= 16;
	}
	if (v >= (1U << 8U)) {
		res += 8;
		v >>= 8;
	}
	if (v >= (1U << 4U)) {
		res += 4;
		v >>= 4;
	}
	if (v >= (1U << 2U)) {
		res += 2;
		v >>= 2;
	}
	if (v >= (1U << 1U)) {
		res += 1;
		v >>= 1;
	}
	if (v >= 1)
		res += 1;

	return res;
67
68
}

Christian Würdig's avatar
Christian Würdig committed
69
static void ia32_dump_comm(obstack_t *obst, const char *name, visibility vis, int size, int align) {
Michael Beck's avatar
Michael Beck committed
70
71
	switch (asm_flavour) {
	case ASM_LINUX_GAS:
72
73
		if (vis == visibility_local)
			obstack_printf(obst, "\t.local\t%s\n", name);
Michael Beck's avatar
Michael Beck committed
74
75
76
		obstack_printf(obst, "\t.comm\t%s,%d,%d\n", name, size, align);
		break;
	case ASM_MINGW_GAS:
77
78
79
80
		if (vis == visibility_local)
			obstack_printf(obst, "\t.lcomm\t%s,%d\n", name, size);
		else
			obstack_printf(obst, "\t.comm\t%s,%d\n", name, size);
Michael Beck's avatar
Michael Beck committed
81
82
83
84
		break;
	}
}

Michael Beck's avatar
Michael Beck committed
85
86
/**
 * output the alignment to an obstack
87
 */
Christian Würdig's avatar
Christian Würdig committed
88
static void ia32_dump_align(obstack_t *obst, int align)
89
{
90
	int h = highest_bit(align);
91

92
93
94
	if ((1 << h) < align)
		++h;
	align = (1 << h);
95

96
97
	if (align > 1)
		obstack_printf(obst, "\t.align %d\n", align);
98
99
}

Michael Beck's avatar
Michael Beck committed
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/**
 * output the alignment to a FILE
 */
static void ia32_dump_align_f(FILE *f, int align)
{
	int h = highest_bit(align);

	if ((1 << h) < align)
		++h;
	align = (1 << h);

	if (align > 1)
		fprintf(f, "\t.align %d\n", align);
}

/**
 * output a tarval
 */
Christian Würdig's avatar
Christian Würdig committed
118
static void dump_arith_tarval(obstack_t *obst, tarval *tv, int bytes)
119
{
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
	switch (bytes) {

	case 1:
		obstack_printf(obst, "0x%02x", get_tarval_sub_bits(tv, 0));
		break;

	case 2:
		obstack_printf(obst, "0x%02x%02x", get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
		break;

	case 4:
		obstack_printf(obst, "0x%02x%02x%02x%02x",
			get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
		break;

	case 8:
		obstack_printf(obst, "0x%02x%02x%02x%02x%02x%02x%02x%02x",
			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));
		break;

	case 10:
	case 12:
		break;

	default:
		fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes);
		assert(0);
	}
149
150
151
152
153
}

/*
 * dump an atomic value
 */
Christian Würdig's avatar
Christian Würdig committed
154
static void do_dump_atomic_init(obstack_t *obst, ir_node *init)
155
{
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
	ir_mode *mode = get_irn_mode(init);
	int bytes     = get_mode_size_bytes(mode);
	tarval *tv;

	switch (get_irn_opcode(init)) {

	case iro_Cast:
		do_dump_atomic_init(obst, get_Cast_op(init));
		return;

	case iro_Conv:
		do_dump_atomic_init(obst, get_Conv_op(init));
		return;

	case iro_Const:
		tv = get_Const_tarval(init);

		/* beware of old stuff */
174
		//assert(! mode_is_reference(mode));
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189

		/* it's a arithmetic value */
		dump_arith_tarval(obst, tv, bytes);
		return;

	case iro_SymConst:
		switch (get_SymConst_kind(init)) {
		case symconst_addr_name:
			obstack_printf(obst, "%s", get_id_str(get_SymConst_name(init)));
			break;

		case symconst_addr_ent:
			obstack_printf(obst, "%s", get_entity_ld_name(get_SymConst_entity(init)));
			break;

190
		case symconst_type_size:
191
192
193
			obstack_printf(obst, "%d", get_type_size_bytes(get_SymConst_type(init)));
			break;

194
195
196
197
		case symconst_type_align:
			obstack_printf(obst, "%d", get_type_alignment_bytes(get_SymConst_type(init)));
			break;

Michael Beck's avatar
Michael Beck committed
198
		case symconst_enum_const:
199
200
			tv = get_enumeration_value(get_SymConst_enum(init));
			dump_arith_tarval(obst, tv, bytes);
Michael Beck's avatar
Michael Beck committed
201
202
			break;

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
		default:
			assert(0 && "dump_atomic_init(): don't know how to init from this SymConst");
		}
		return;

		case iro_Add:
			do_dump_atomic_init(obst, get_Add_left(init));
			obstack_printf(obst, " + ");
			do_dump_atomic_init(obst, get_Add_right(init));
			return;

		case iro_Sub:
			do_dump_atomic_init(obst, get_Sub_left(init));
			obstack_printf(obst, " - ");
			do_dump_atomic_init(obst, get_Sub_right(init));
			return;

		case iro_Mul:
			do_dump_atomic_init(obst, get_Mul_left(init));
			obstack_printf(obst, " * ");
			do_dump_atomic_init(obst, get_Mul_right(init));
			return;

		default:
			assert(0 && "dump_atomic_init(): unknown IR-node");
	}
229
230
231
}

/*
Christian Würdig's avatar
Christian Würdig committed
232
 * dumps the type for given size (.byte, .long, ...)
233
 */
Christian Würdig's avatar
Christian Würdig committed
234
235
static void dump_size_type(obstack_t *obst, int size) {
	switch (size) {
236

237
238
239
	case 1:
		obstack_printf(obst, "\t.byte\t");
		break;
240

241
242
243
	case 2:
		obstack_printf(obst, "\t.value\t");
		break;
244

245
246
247
	case 4:
		obstack_printf(obst, "\t.long\t");
		break;
248

249
250
251
	case 8:
		obstack_printf(obst, "\t.quad\t");
		break;
252

253
254
255
256
	case 10:
	case 12:
		/* handled in arith */
		break;
257

258
	default:
Christian Würdig's avatar
Christian Würdig committed
259
		fprintf(stderr, "Try to dump a type with %d bytes\n", size);
260
261
		assert(0);
	}
Christian Würdig's avatar
Christian Würdig committed
262
263
264
265
266
267
268
269
270
}

/*
 * dump an atomic value
 */
static void dump_atomic_init(obstack_t *obst, ir_node *init)
{
	ir_mode *mode = get_irn_mode(init);
	int bytes     = get_mode_size_bytes(mode);
271

Christian Würdig's avatar
Christian Würdig committed
272
	dump_size_type(obst, bytes);
273
274
	do_dump_atomic_init(obst, init);
	obstack_printf(obst, "\n");
275
276
277
278
279
280
281
282
283
284
285
286
287
}

/************************************************************************/
/* Routines to dump global variables                                    */
/************************************************************************/

/**
 * Determine if an entity is a string constant
 * @param ent The entity
 * @return 1 if it is a string constant, 0 otherwise
 */
static int ent_is_string_const(entity *ent)
{
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
	int res = 0;
	ir_type *ty;

	ty = get_entity_type(ent);

	/* if it's an array */
	if (is_Array_type(ty)) {
		ir_type *elm_ty = get_array_element_type(ty);

		/* and the array's element type is primitive */
		if (is_Primitive_type(elm_ty)) {
			ir_mode *mode = get_type_mode(elm_ty);

			/*
			* and the mode of the element type is an int of
			* the same size as the byte mode
			*/
			if (mode_is_int(mode)
				&& get_mode_size_bits(mode) == get_mode_size_bits(mode_Bs))
			{
				int i, c, n;

				n = get_compound_ent_n_values(ent);
				for (i = 0; i < n; ++i) {
					ir_node *irn = get_compound_ent_value(ent, i);
					if(get_irn_opcode(irn) != iro_Const)
						return 0;

					c = (int) get_tarval_long(get_Const_tarval(irn));

					if((i < n - 1 && !(isgraph(c) || isspace(c)))
						|| (i == n - 1 && c != '\0'))
						return 0;
				}

				res = 1;
			}
		}
326
327
	}

328
	return res;
329
330
331
332
333
334
335
336
}

/**
 * Dump a atring constant.
 * No checks are made!!
 * @param obst The obst to dump on.
 * @param ent The entity to dump.
 */
Christian Würdig's avatar
Christian Würdig committed
337
static void dump_string_cst(obstack_t *obst, entity *ent)
338
{
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
	int i, n;

	obstack_printf(obst, "\t.string \"");
	n = get_compound_ent_n_values(ent);

	for (i = 0; i < n-1; ++i) {
		ir_node *irn;
		int c;

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

		switch (c) {
		case '"' : obstack_printf(obst, "\\\""); break;
		case '\n': obstack_printf(obst, "\\n"); break;
		case '\r': obstack_printf(obst, "\\r"); break;
		case '\t': obstack_printf(obst, "\\t"); break;
356
		case '\\': obstack_printf(obst, "\\\\"); break;
357
358
359
360
361
362
363
364
365
		default  :
			if (isprint(c))
				obstack_printf(obst, "%c", c);
			else
				obstack_printf(obst, "%O", c);
			break;
		}
	}
	obstack_printf(obst, "\"\n");
366
367
368
}

struct arr_info {
369
370
371
	int n_elems;
	int visit_cnt;
	int size;
372
373
};

Michael Beck's avatar
Michael Beck committed
374
375
376
/**
 * Dump the size of an object
 */
Christian Würdig's avatar
Christian Würdig committed
377
static void dump_object_size(obstack_t *obst, const char *name, int size) {
Michael Beck's avatar
Michael Beck committed
378
379
380
381
382
383
	switch (asm_flavour) {
	case ASM_LINUX_GAS:
		obstack_printf(obst, "\t.type\t%s,@object\n", name);
		obstack_printf(obst, "\t.size\t%s,%d\n", name, size);
		break;
	}
384
385
}

386
387
388
389
/*
 * Dumps the initialization of global variables that are not
 * "uninitialized".
 */
Christian Würdig's avatar
Christian Würdig committed
390
391
392
393
static void dump_global(const arch_env_t *arch_env,
						obstack_t *rdata_obstack, obstack_t *data_obstack,
						obstack_t *comm_obstack, obstack_t *ctor_obstack,
						entity *ent)
394
{
395
396
	ir_type *ty         = get_entity_type(ent);
	const char *ld_name = get_entity_ld_name(ent);
Christian Würdig's avatar
Christian Würdig committed
397
	obstack_t *obst     = data_obstack;
398
399
400
	int align, h;

	/*
Michael Beck's avatar
Michael Beck committed
401
402
	 * FIXME: did NOT work for partly constant values
	 */
403
404
405
406
407
408
409
410
411
412
413
414
415
416
	if (! is_Method_type(ty)) {
		ent_variability variability = get_entity_variability(ent);
		visibility visibility = get_entity_visibility(ent);

		if (variability == variability_constant) {
			/* a constant entity, put it on the rdata */
			obst = rdata_obstack;
		}

		/* check, whether it is initialized, if yes create data */
		if (variability != variability_uninitialized) {
			if (visibility == visibility_external_visible) {
				obstack_printf(obst, ".globl\t%s\n", ld_name);
			}
Michael Beck's avatar
Michael Beck committed
417
			dump_object_size(obst, ld_name, get_type_size_bytes(ty));
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

			align = get_type_alignment_bytes(ty);
			ia32_dump_align(obst, align);

			obstack_printf(obst, "%s:\n", ld_name);

			if (is_atomic_type(ty)) {
				if (get_entity_visibility(ent) != visibility_external_allocated)
					dump_atomic_init(obst, get_atomic_ent_value(ent));
			}
			else {
				int i, size = 0;

				if (ent_is_string_const(ent)) {
					dump_string_cst(obst, ent);
				}
				else if (is_Array_type(ty)) {
					int filler;

					/* potential spare values should be already included! */
					for (i = 0; i < get_compound_ent_n_values(ent); ++i) {
						entity *step = get_compound_ent_value_member(ent, i);
						ir_type *stype = get_entity_type(step);

						if (get_type_mode(stype)) {
							int align = (get_type_alignment_bits(stype) + 7) >> 3;
							int n     = size % align;

							if (n > 0) {
								obstack_printf(obst, "\t.zero\t%d\n", align - n);
								size += align - n;
							}
						}
						dump_atomic_init(obst, get_compound_ent_value(ent, i));
						size += get_type_size_bytes(stype);
					}
					filler = get_type_size_bytes(ty) - size;

					if (filler > 0)
						obstack_printf(obst, "\t.zero\t%d\n", filler);
				}
				else if (is_compound_type(ty)) {
					ir_node **vals;
					int type_size, j;

					/* Compound entities are NOT sorted.
Michael Beck's avatar
Michael Beck committed
464
465
466
					 * The sorting strategy used doesn't work for `value' compound fields nor
					 * for partially_constant entities.
					 */
467
468

					/*
Michael Beck's avatar
Michael Beck committed
469
470
471
					 * in the worst case, every entity allocates one byte, so the type
					 * size should be equal or bigger the number of fields
					 */
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
					type_size = get_type_size_bytes(ty);
					vals      = xcalloc(type_size, sizeof(*vals));

					/* collect the values and store them at the offsets */
					for(i = 0; i < get_compound_ent_n_values(ent); ++i) {
						int                 graph_length, aipos, offset;
						struct arr_info     *ai;
						int                 all_n = 1;
						compound_graph_path *path = get_compound_ent_value_path(ent, i);

						/* get the access path to the costant value */
						graph_length = get_compound_graph_path_length(path);
						ai = xcalloc(graph_length, sizeof(struct arr_info));

						/* We wanna know how many arrays are on the path to the entity. We also have to know how
Michael Beck's avatar
Michael Beck committed
487
						 * many elements each array holds to calculate the offset for the entity. */
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
						for (j = 0; j < graph_length; j++) {
							entity  *step      = get_compound_graph_path_node(path, j);
							ir_type *step_type = get_entity_type(step);
							int     ty_size    = (get_type_size_bits(step_type) + 7) >> 3;
							int     k, n       = 0;

							if (is_Array_type(step_type))
								for (k = 0; k < get_array_n_dimensions(step_type); k++)
									n += get_tarval_long(get_Const_tarval(get_array_upper_bound(step_type, k)));
								if (n) all_n *= n;
								ai[j].n_elems = n ? all_n + 1 : 0;
								ai[j].visit_cnt = 0;
								ai[j].size = ty_size;
						}

						aipos = graph_length - 1;
						if (aipos) aipos--;

						for (offset = j = 0; j < graph_length; j++) {
							entity *step       = get_compound_graph_path_node(path, j);
							ir_type *step_type = get_entity_type(step);
							int ent_ofs        = get_entity_offset_bytes(step);
							int stepsize       = 0;

							/* add all positive offsets (= offsets in structs) */
							if (ent_ofs >= 0) offset += ent_ofs;

							if (j == graph_length - 1) {
								stepsize = (get_type_size_bits(step_type) + 7) >> 3;

								/* Search the next free position in vals depending on the information from above (ai). */
519
								while (vals[offset] && aipos >= 0) {
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
									if (ai[aipos].visit_cnt < ai[aipos].n_elems) {
										offset += stepsize;
										ai[aipos].visit_cnt++;
									}
									else
										while (aipos >= 0 && ai[aipos].visit_cnt == ai[aipos].n_elems) {
											stepsize = ai[aipos--].size;
											offset  += stepsize;
										}
								}

								assert(aipos >= 0 && "couldn't store entity");
								vals[offset] = get_compound_ent_value(ent, i);
							}
						}

						free(ai);
					}

					/* now write them sorted */
					for(i = 0; i < type_size; ) {
						if (vals[i]) {
							dump_atomic_init(obst, vals[i]);
							i += (get_mode_size_bytes(get_irn_mode(vals[i])));
						}
						else {
							/* a gap */
							obstack_printf(obst, "\t.byte\t0\n");
							++i;
						}
					}
					free(vals);
				}
				else {
					assert(0 && "unsupported type");
				}
			}
			obstack_printf(obst, "\n");
		}
		else if (visibility != visibility_external_allocated) {
Michael Beck's avatar
Michael Beck committed
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
			/* uninitialized and NOT external */
			if (get_entity_owner(ent) != get_tls_type()) {
				/* calculate the alignment */
				align = get_type_alignment_bytes(ty);
				h = highest_bit(align);

				if ((1 << h) < align)
					++h;
				align = (1 << h);

				if (align < 1)
					align = 1;

				ia32_dump_comm(comm_obstack, ld_name, visibility,
					get_type_size_bytes(ty), align);
			} else {
				/* TLS */
				if (visibility == visibility_external_visible) {
					obstack_printf(obst, ".globl\t%s\n", ld_name);
				}
				dump_object_size(comm_obstack, ld_name, get_type_size_bytes(ty));
				align = get_type_alignment_bytes(ty);
				ia32_dump_align(obst, align);
				obstack_printf(comm_obstack, "%s:\n\t.zero %d\n", ld_name, get_type_size_bytes(ty));
			}
585
		}
Christian Würdig's avatar
Christian Würdig committed
586
587
588
589
590
	} /* ! is method type */
	else if (ctor_obstack && arch_ent_is_constructor(arch_env, ent)) {
		ia32_dump_align(ctor_obstack, get_type_alignment_bytes(ty));
		dump_size_type(ctor_obstack, get_type_alignment_bytes(ty));
		obstack_printf(ctor_obstack, "%s\n", ld_name);
591
	}
592
593
}

Michael Beck's avatar
Michael Beck committed
594
/**
595
596
 * Dumps declarations of global variables and the initialization code.
 */
Christian Würdig's avatar
Christian Würdig committed
597
static void ia32_dump_globals(ir_type *gt, ia32_decl_env_t *env)
598
{
Michael Beck's avatar
Michael Beck committed
599
	int i, n = get_compound_n_members(gt);
600

601
	for (i = 0; i < n; i++)
Christian Würdig's avatar
Christian Würdig committed
602
		dump_global(env->main_env->arch_env, env->rodata_obst, env->data_obst, env->comm_obst, env->ctor_obst,
Christian Würdig's avatar
Christian Würdig committed
603
			get_compound_member(gt, i));
604
605
606
607
}

/************************************************************************/

Christian Würdig's avatar
Christian Würdig committed
608
void ia32_gen_decls(FILE *out, const be_main_env_t *main_env) {
Christian Würdig's avatar
Christian Würdig committed
609
610
	ia32_decl_env_t env;
	obstack_t rodata, data, comm, ctor;
611
612
613
	int    size;
	char   *cp;

Michael Beck's avatar
Michael Beck committed
614
	/* dump the global type */
615
616
617
618
	obstack_init(&rodata);
	obstack_init(&data);
	obstack_init(&comm);

Christian Würdig's avatar
Christian Würdig committed
619
	if (main_env->options->opt_profile)
Christian Würdig's avatar
Christian Würdig committed
620
621
622
623
624
		obstack_init(&ctor);

	env.rodata_obst = &rodata;
	env.data_obst   = &data;
	env.comm_obst   = &comm;
Christian Würdig's avatar
Christian Würdig committed
625
626
	env.ctor_obst   = main_env->options->opt_profile ? &ctor : NULL;
	env.main_env    = main_env;
Christian Würdig's avatar
Christian Würdig committed
627
628

	ia32_dump_globals(get_glob_type(), &env);
629
630
631
632

	size = obstack_object_size(&data);
	cp   = obstack_finish(&data);
	if (size > 0) {
Michael Beck's avatar
Michael Beck committed
633
		ia32_switch_section(out, SECTION_DATA);
634
635
636
637
638
639
		fwrite(cp, 1, size, out);
	}

	size = obstack_object_size(&rodata);
	cp   = obstack_finish(&rodata);
	if (size > 0) {
Michael Beck's avatar
Michael Beck committed
640
		ia32_switch_section(out, SECTION_RODATA);
641
642
643
644
645
646
		fwrite(cp, 1, size, out);
	}

	size = obstack_object_size(&comm);
	cp   = obstack_finish(&comm);
	if (size > 0) {
Michael Beck's avatar
Michael Beck committed
647
		ia32_switch_section(out, SECTION_COMMON);
648
649
650
		fwrite(cp, 1, size, out);
	}

Christian Würdig's avatar
Christian Würdig committed
651
	if (main_env->options->opt_profile) {
Christian Würdig's avatar
Christian Würdig committed
652
653
654
655
656
657
658
659
660
		size = obstack_object_size(&ctor);
		cp   = obstack_finish(&ctor);
		if (size > 0) {
			ia32_switch_section(out, SECTION_CTOR);
			fwrite(cp, 1, size, out);
		}
		obstack_free(&ctor, NULL);
	}

661
662
663
	obstack_free(&rodata, NULL);
	obstack_free(&data, NULL);
	obstack_free(&comm, NULL);
Michael Beck's avatar
Michael Beck committed
664
665
666

	/* dump the Thread Local Storage */
	obstack_init(&data);
Christian Würdig's avatar
Christian Würdig committed
667
668
669
670
671
672
673

	env.rodata_obst = &data;
	env.data_obst   = &data;
	env.comm_obst   = &data;
	env.ctor_obst   = NULL;

	ia32_dump_globals(get_tls_type(), &env);
Michael Beck's avatar
Michael Beck committed
674
675
676
677
678
679
680
681
682

	size = obstack_object_size(&data);
	cp   = obstack_finish(&data);
	if (size > 0) {
		ia32_switch_section(out, SECTION_TLS);
		ia32_dump_align_f(out, 32);
		fwrite(cp, 1, size, out);
	}

Christian Würdig's avatar
Christian Würdig committed
683
	obstack_free(&data, NULL);
684
}