0
|
1 /* Dwarf2 assembler output helper routines.
|
|
2 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008
|
|
3 Free Software Foundation, Inc.
|
|
4
|
|
5 This file is part of GCC.
|
|
6
|
|
7 GCC is free software; you can redistribute it and/or modify it under
|
|
8 the terms of the GNU General Public License as published by the Free
|
|
9 Software Foundation; either version 3, or (at your option) any later
|
|
10 version.
|
|
11
|
|
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
15 for more details.
|
|
16
|
|
17 You should have received a copy of the GNU General Public License
|
|
18 along with GCC; see the file COPYING3. If not see
|
|
19 <http://www.gnu.org/licenses/>. */
|
|
20
|
|
21
|
|
22 #include "config.h"
|
|
23 #include "system.h"
|
|
24 #include "coretypes.h"
|
|
25 #include "tm.h"
|
|
26 #include "flags.h"
|
|
27 #include "tree.h"
|
|
28 #include "rtl.h"
|
|
29 #include "output.h"
|
|
30 #include "target.h"
|
|
31 #include "dwarf2asm.h"
|
|
32 #include "dwarf2.h"
|
|
33 #include "splay-tree.h"
|
|
34 #include "ggc.h"
|
|
35 #include "tm_p.h"
|
|
36
|
|
37
|
|
38 /* How to start an assembler comment. */
|
|
39 #ifndef ASM_COMMENT_START
|
|
40 #define ASM_COMMENT_START ";#"
|
|
41 #endif
|
|
42
|
|
43
|
|
44 /* Output an unaligned integer with the given value and size. Prefer not
|
|
45 to print a newline, since the caller may want to add a comment. */
|
|
46
|
|
47 void
|
|
48 dw2_assemble_integer (int size, rtx x)
|
|
49 {
|
|
50 const char *op = integer_asm_op (size, FALSE);
|
|
51
|
|
52 if (op)
|
|
53 {
|
|
54 fputs (op, asm_out_file);
|
|
55 if (GET_CODE (x) == CONST_INT)
|
|
56 fprintf (asm_out_file, HOST_WIDE_INT_PRINT_HEX,
|
|
57 (unsigned HOST_WIDE_INT) INTVAL (x));
|
|
58 else
|
|
59 output_addr_const (asm_out_file, x);
|
|
60 }
|
|
61 else
|
|
62 assemble_integer (x, size, BITS_PER_UNIT, 1);
|
|
63 }
|
|
64
|
|
65
|
|
66 /* Output a value of a given size in target byte order. */
|
|
67
|
|
68 void
|
|
69 dw2_asm_output_data_raw (int size, unsigned HOST_WIDE_INT value)
|
|
70 {
|
|
71 unsigned char bytes[8];
|
|
72 int i;
|
|
73
|
|
74 for (i = 0; i < 8; ++i)
|
|
75 {
|
|
76 bytes[i] = value & 0xff;
|
|
77 value >>= 8;
|
|
78 }
|
|
79
|
|
80 if (BYTES_BIG_ENDIAN)
|
|
81 {
|
|
82 for (i = size - 1; i > 0; --i)
|
|
83 fprintf (asm_out_file, "0x%x,", bytes[i]);
|
|
84 fprintf (asm_out_file, "0x%x", bytes[0]);
|
|
85 }
|
|
86 else
|
|
87 {
|
|
88 for (i = 0; i < size - 1; ++i)
|
|
89 fprintf (asm_out_file, "0x%x,", bytes[i]);
|
|
90 fprintf (asm_out_file, "0x%x", bytes[i]);
|
|
91 }
|
|
92 }
|
|
93
|
|
94 /* Output an immediate constant in a given SIZE in bytes. */
|
|
95
|
|
96 void
|
|
97 dw2_asm_output_data (int size, unsigned HOST_WIDE_INT value,
|
|
98 const char *comment, ...)
|
|
99 {
|
|
100 va_list ap;
|
|
101 const char *op = integer_asm_op (size, FALSE);
|
|
102
|
|
103 va_start (ap, comment);
|
|
104
|
|
105 if (size * 8 < HOST_BITS_PER_WIDE_INT)
|
|
106 value &= ~(~(unsigned HOST_WIDE_INT) 0 << (size * 8));
|
|
107
|
|
108 if (op)
|
|
109 fprintf (asm_out_file, "%s" HOST_WIDE_INT_PRINT_HEX, op, value);
|
|
110 else
|
|
111 assemble_integer (GEN_INT (value), size, BITS_PER_UNIT, 1);
|
|
112
|
|
113 if (flag_debug_asm && comment)
|
|
114 {
|
|
115 fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
|
|
116 vfprintf (asm_out_file, comment, ap);
|
|
117 }
|
|
118 fputc ('\n', asm_out_file);
|
|
119
|
|
120 va_end (ap);
|
|
121 }
|
|
122
|
|
123 /* Output the difference between two symbols in a given size. */
|
|
124 /* ??? There appear to be assemblers that do not like such
|
|
125 subtraction, but do support ASM_SET_OP. It's unfortunately
|
|
126 impossible to do here, since the ASM_SET_OP for the difference
|
|
127 symbol must appear after both symbols are defined. */
|
|
128
|
|
129 void
|
|
130 dw2_asm_output_delta (int size, const char *lab1, const char *lab2,
|
|
131 const char *comment, ...)
|
|
132 {
|
|
133 va_list ap;
|
|
134
|
|
135 va_start (ap, comment);
|
|
136
|
|
137 #ifdef ASM_OUTPUT_DWARF_DELTA
|
|
138 ASM_OUTPUT_DWARF_DELTA (asm_out_file, size, lab1, lab2);
|
|
139 #else
|
|
140 dw2_assemble_integer (size,
|
|
141 gen_rtx_MINUS (Pmode,
|
|
142 gen_rtx_SYMBOL_REF (Pmode, lab1),
|
|
143 gen_rtx_SYMBOL_REF (Pmode, lab2)));
|
|
144 #endif
|
|
145 if (flag_debug_asm && comment)
|
|
146 {
|
|
147 fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
|
|
148 vfprintf (asm_out_file, comment, ap);
|
|
149 }
|
|
150 fputc ('\n', asm_out_file);
|
|
151
|
|
152 va_end (ap);
|
|
153 }
|
|
154
|
|
155 /* Output a section-relative reference to a LABEL, which was placed in
|
|
156 BASE. In general this can only be done for debugging symbols.
|
|
157 E.g. on most targets with the GNU linker, this is accomplished with
|
|
158 a direct reference and the knowledge that the debugging section
|
|
159 will be placed at VMA 0. Some targets have special relocations for
|
|
160 this that we must use. */
|
|
161
|
|
162 void
|
|
163 dw2_asm_output_offset (int size, const char *label,
|
|
164 section *base ATTRIBUTE_UNUSED,
|
|
165 const char *comment, ...)
|
|
166 {
|
|
167 va_list ap;
|
|
168
|
|
169 va_start (ap, comment);
|
|
170
|
|
171 #ifdef ASM_OUTPUT_DWARF_OFFSET
|
|
172 ASM_OUTPUT_DWARF_OFFSET (asm_out_file, size, label, base);
|
|
173 #else
|
|
174 dw2_assemble_integer (size, gen_rtx_SYMBOL_REF (Pmode, label));
|
|
175 #endif
|
|
176
|
|
177 if (flag_debug_asm && comment)
|
|
178 {
|
|
179 fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
|
|
180 vfprintf (asm_out_file, comment, ap);
|
|
181 }
|
|
182 fputc ('\n', asm_out_file);
|
|
183
|
|
184 va_end (ap);
|
|
185 }
|
|
186
|
|
187 #if 0
|
|
188
|
|
189 /* Output a self-relative reference to a label, possibly in a
|
|
190 different section or object file. */
|
|
191
|
|
192 void
|
|
193 dw2_asm_output_pcrel (int size ATTRIBUTE_UNUSED,
|
|
194 const char *label ATTRIBUTE_UNUSED,
|
|
195 const char *comment, ...)
|
|
196 {
|
|
197 va_list ap;
|
|
198
|
|
199 va_start (ap, comment);
|
|
200
|
|
201 #ifdef ASM_OUTPUT_DWARF_PCREL
|
|
202 ASM_OUTPUT_DWARF_PCREL (asm_out_file, size, label);
|
|
203 #else
|
|
204 dw2_assemble_integer (size,
|
|
205 gen_rtx_MINUS (Pmode,
|
|
206 gen_rtx_SYMBOL_REF (Pmode, label),
|
|
207 pc_rtx));
|
|
208 #endif
|
|
209
|
|
210 if (flag_debug_asm && comment)
|
|
211 {
|
|
212 fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
|
|
213 vfprintf (asm_out_file, comment, ap);
|
|
214 }
|
|
215 fputc ('\n', asm_out_file);
|
|
216
|
|
217 va_end (ap);
|
|
218 }
|
|
219 #endif /* 0 */
|
|
220
|
|
221 /* Output an absolute reference to a label. */
|
|
222
|
|
223 void
|
|
224 dw2_asm_output_addr (int size, const char *label,
|
|
225 const char *comment, ...)
|
|
226 {
|
|
227 va_list ap;
|
|
228
|
|
229 va_start (ap, comment);
|
|
230
|
|
231 dw2_assemble_integer (size, gen_rtx_SYMBOL_REF (Pmode, label));
|
|
232
|
|
233 if (flag_debug_asm && comment)
|
|
234 {
|
|
235 fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
|
|
236 vfprintf (asm_out_file, comment, ap);
|
|
237 }
|
|
238 fputc ('\n', asm_out_file);
|
|
239
|
|
240 va_end (ap);
|
|
241 }
|
|
242
|
|
243 /* Similar, but use an RTX expression instead of a text label. */
|
|
244
|
|
245 void
|
|
246 dw2_asm_output_addr_rtx (int size, rtx addr,
|
|
247 const char *comment, ...)
|
|
248 {
|
|
249 va_list ap;
|
|
250
|
|
251 va_start (ap, comment);
|
|
252
|
|
253 dw2_assemble_integer (size, addr);
|
|
254
|
|
255 if (flag_debug_asm && comment)
|
|
256 {
|
|
257 fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
|
|
258 vfprintf (asm_out_file, comment, ap);
|
|
259 }
|
|
260 fputc ('\n', asm_out_file);
|
|
261
|
|
262 va_end (ap);
|
|
263 }
|
|
264
|
|
265 /* Output the first ORIG_LEN characters of STR as a string.
|
|
266 If ORIG_LEN is equal to -1, ignore this parameter and output
|
|
267 the entire STR instead.
|
|
268 If COMMENT is not NULL and comments in the debug information
|
|
269 have been requested by the user, append the given COMMENT
|
|
270 to the generated output. */
|
|
271
|
|
272 void
|
|
273 dw2_asm_output_nstring (const char *str, size_t orig_len,
|
|
274 const char *comment, ...)
|
|
275 {
|
|
276 size_t i, len;
|
|
277 va_list ap;
|
|
278
|
|
279 va_start (ap, comment);
|
|
280
|
|
281 len = orig_len;
|
|
282
|
|
283 if (len == (size_t) -1)
|
|
284 len = strlen (str);
|
|
285
|
|
286 if (flag_debug_asm && comment)
|
|
287 {
|
|
288 fputs ("\t.ascii \"", asm_out_file);
|
|
289 for (i = 0; i < len; i++)
|
|
290 {
|
|
291 int c = str[i];
|
|
292 if (c == '\"' || c == '\\')
|
|
293 fputc ('\\', asm_out_file);
|
|
294 if (ISPRINT(c))
|
|
295 fputc (c, asm_out_file);
|
|
296 else
|
|
297 fprintf (asm_out_file, "\\%o", c);
|
|
298 }
|
|
299 fprintf (asm_out_file, "\\0\"\t%s ", ASM_COMMENT_START);
|
|
300 vfprintf (asm_out_file, comment, ap);
|
|
301 fputc ('\n', asm_out_file);
|
|
302 }
|
|
303 else
|
|
304 {
|
|
305 /* If an explicit length was given, we can't assume there
|
|
306 is a null termination in the string buffer. */
|
|
307 if (orig_len == (size_t) -1)
|
|
308 len += 1;
|
|
309 ASM_OUTPUT_ASCII (asm_out_file, str, len);
|
|
310 if (orig_len != (size_t) -1)
|
|
311 assemble_integer (const0_rtx, 1, BITS_PER_UNIT, 1);
|
|
312 }
|
|
313
|
|
314 va_end (ap);
|
|
315 }
|
|
316
|
|
317
|
|
318 /* Return the size of an unsigned LEB128 quantity. */
|
|
319
|
|
320 int
|
|
321 size_of_uleb128 (unsigned HOST_WIDE_INT value)
|
|
322 {
|
|
323 int size = 0;
|
|
324
|
|
325 do
|
|
326 {
|
|
327 value >>= 7;
|
|
328 size += 1;
|
|
329 }
|
|
330 while (value != 0);
|
|
331
|
|
332 return size;
|
|
333 }
|
|
334
|
|
335 /* Return the size of a signed LEB128 quantity. */
|
|
336
|
|
337 int
|
|
338 size_of_sleb128 (HOST_WIDE_INT value)
|
|
339 {
|
|
340 int size = 0, byte;
|
|
341
|
|
342 do
|
|
343 {
|
|
344 byte = (value & 0x7f);
|
|
345 value >>= 7;
|
|
346 size += 1;
|
|
347 }
|
|
348 while (!((value == 0 && (byte & 0x40) == 0)
|
|
349 || (value == -1 && (byte & 0x40) != 0)));
|
|
350
|
|
351 return size;
|
|
352 }
|
|
353
|
|
354 /* Given an encoding, return the number of bytes the format occupies.
|
|
355 This is only defined for fixed-size encodings, and so does not
|
|
356 include leb128. */
|
|
357
|
|
358 int
|
|
359 size_of_encoded_value (int encoding)
|
|
360 {
|
|
361 if (encoding == DW_EH_PE_omit)
|
|
362 return 0;
|
|
363
|
|
364 switch (encoding & 0x07)
|
|
365 {
|
|
366 case DW_EH_PE_absptr:
|
|
367 return POINTER_SIZE / BITS_PER_UNIT;
|
|
368 case DW_EH_PE_udata2:
|
|
369 return 2;
|
|
370 case DW_EH_PE_udata4:
|
|
371 return 4;
|
|
372 case DW_EH_PE_udata8:
|
|
373 return 8;
|
|
374 default:
|
|
375 gcc_unreachable ();
|
|
376 }
|
|
377 }
|
|
378
|
|
379 /* Yield a name for a given pointer encoding. */
|
|
380
|
|
381 const char *
|
|
382 eh_data_format_name (int format)
|
|
383 {
|
|
384 #if HAVE_DESIGNATED_INITIALIZERS
|
|
385 #define S(p, v) [p] = v,
|
|
386 #else
|
|
387 #define S(p, v) case p: return v;
|
|
388 #endif
|
|
389
|
|
390 #if HAVE_DESIGNATED_INITIALIZERS
|
|
391 __extension__ static const char * const format_names[256] = {
|
|
392 #else
|
|
393 switch (format) {
|
|
394 #endif
|
|
395
|
|
396 S(DW_EH_PE_absptr, "absolute")
|
|
397 S(DW_EH_PE_omit, "omit")
|
|
398 S(DW_EH_PE_aligned, "aligned absolute")
|
|
399
|
|
400 S(DW_EH_PE_uleb128, "uleb128")
|
|
401 S(DW_EH_PE_udata2, "udata2")
|
|
402 S(DW_EH_PE_udata4, "udata4")
|
|
403 S(DW_EH_PE_udata8, "udata8")
|
|
404 S(DW_EH_PE_sleb128, "sleb128")
|
|
405 S(DW_EH_PE_sdata2, "sdata2")
|
|
406 S(DW_EH_PE_sdata4, "sdata4")
|
|
407 S(DW_EH_PE_sdata8, "sdata8")
|
|
408
|
|
409 S(DW_EH_PE_absptr | DW_EH_PE_pcrel, "pcrel")
|
|
410 S(DW_EH_PE_uleb128 | DW_EH_PE_pcrel, "pcrel uleb128")
|
|
411 S(DW_EH_PE_udata2 | DW_EH_PE_pcrel, "pcrel udata2")
|
|
412 S(DW_EH_PE_udata4 | DW_EH_PE_pcrel, "pcrel udata4")
|
|
413 S(DW_EH_PE_udata8 | DW_EH_PE_pcrel, "pcrel udata8")
|
|
414 S(DW_EH_PE_sleb128 | DW_EH_PE_pcrel, "pcrel sleb128")
|
|
415 S(DW_EH_PE_sdata2 | DW_EH_PE_pcrel, "pcrel sdata2")
|
|
416 S(DW_EH_PE_sdata4 | DW_EH_PE_pcrel, "pcrel sdata4")
|
|
417 S(DW_EH_PE_sdata8 | DW_EH_PE_pcrel, "pcrel sdata8")
|
|
418
|
|
419 S(DW_EH_PE_absptr | DW_EH_PE_textrel, "textrel")
|
|
420 S(DW_EH_PE_uleb128 | DW_EH_PE_textrel, "textrel uleb128")
|
|
421 S(DW_EH_PE_udata2 | DW_EH_PE_textrel, "textrel udata2")
|
|
422 S(DW_EH_PE_udata4 | DW_EH_PE_textrel, "textrel udata4")
|
|
423 S(DW_EH_PE_udata8 | DW_EH_PE_textrel, "textrel udata8")
|
|
424 S(DW_EH_PE_sleb128 | DW_EH_PE_textrel, "textrel sleb128")
|
|
425 S(DW_EH_PE_sdata2 | DW_EH_PE_textrel, "textrel sdata2")
|
|
426 S(DW_EH_PE_sdata4 | DW_EH_PE_textrel, "textrel sdata4")
|
|
427 S(DW_EH_PE_sdata8 | DW_EH_PE_textrel, "textrel sdata8")
|
|
428
|
|
429 S(DW_EH_PE_absptr | DW_EH_PE_datarel, "datarel")
|
|
430 S(DW_EH_PE_uleb128 | DW_EH_PE_datarel, "datarel uleb128")
|
|
431 S(DW_EH_PE_udata2 | DW_EH_PE_datarel, "datarel udata2")
|
|
432 S(DW_EH_PE_udata4 | DW_EH_PE_datarel, "datarel udata4")
|
|
433 S(DW_EH_PE_udata8 | DW_EH_PE_datarel, "datarel udata8")
|
|
434 S(DW_EH_PE_sleb128 | DW_EH_PE_datarel, "datarel sleb128")
|
|
435 S(DW_EH_PE_sdata2 | DW_EH_PE_datarel, "datarel sdata2")
|
|
436 S(DW_EH_PE_sdata4 | DW_EH_PE_datarel, "datarel sdata4")
|
|
437 S(DW_EH_PE_sdata8 | DW_EH_PE_datarel, "datarel sdata8")
|
|
438
|
|
439 S(DW_EH_PE_absptr | DW_EH_PE_funcrel, "funcrel")
|
|
440 S(DW_EH_PE_uleb128 | DW_EH_PE_funcrel, "funcrel uleb128")
|
|
441 S(DW_EH_PE_udata2 | DW_EH_PE_funcrel, "funcrel udata2")
|
|
442 S(DW_EH_PE_udata4 | DW_EH_PE_funcrel, "funcrel udata4")
|
|
443 S(DW_EH_PE_udata8 | DW_EH_PE_funcrel, "funcrel udata8")
|
|
444 S(DW_EH_PE_sleb128 | DW_EH_PE_funcrel, "funcrel sleb128")
|
|
445 S(DW_EH_PE_sdata2 | DW_EH_PE_funcrel, "funcrel sdata2")
|
|
446 S(DW_EH_PE_sdata4 | DW_EH_PE_funcrel, "funcrel sdata4")
|
|
447 S(DW_EH_PE_sdata8 | DW_EH_PE_funcrel, "funcrel sdata8")
|
|
448
|
|
449 S(DW_EH_PE_indirect | DW_EH_PE_absptr | DW_EH_PE_pcrel,
|
|
450 "indirect pcrel")
|
|
451 S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_pcrel,
|
|
452 "indirect pcrel uleb128")
|
|
453 S(DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_pcrel,
|
|
454 "indirect pcrel udata2")
|
|
455 S(DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_pcrel,
|
|
456 "indirect pcrel udata4")
|
|
457 S(DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_pcrel,
|
|
458 "indirect pcrel udata8")
|
|
459 S(DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_pcrel,
|
|
460 "indirect pcrel sleb128")
|
|
461 S(DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_pcrel,
|
|
462 "indirect pcrel sdata2")
|
|
463 S(DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_pcrel,
|
|
464 "indirect pcrel sdata4")
|
|
465 S(DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_pcrel,
|
|
466 "indirect pcrel sdata8")
|
|
467
|
|
468 S(DW_EH_PE_indirect | DW_EH_PE_absptr | DW_EH_PE_textrel,
|
|
469 "indirect textrel")
|
|
470 S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_textrel,
|
|
471 "indirect textrel uleb128")
|
|
472 S(DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_textrel,
|
|
473 "indirect textrel udata2")
|
|
474 S(DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_textrel,
|
|
475 "indirect textrel udata4")
|
|
476 S(DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_textrel,
|
|
477 "indirect textrel udata8")
|
|
478 S(DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_textrel,
|
|
479 "indirect textrel sleb128")
|
|
480 S(DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_textrel,
|
|
481 "indirect textrel sdata2")
|
|
482 S(DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_textrel,
|
|
483 "indirect textrel sdata4")
|
|
484 S(DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_textrel,
|
|
485 "indirect textrel sdata8")
|
|
486
|
|
487 S(DW_EH_PE_indirect | DW_EH_PE_absptr | DW_EH_PE_datarel,
|
|
488 "indirect datarel")
|
|
489 S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_datarel,
|
|
490 "indirect datarel uleb128")
|
|
491 S(DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_datarel,
|
|
492 "indirect datarel udata2")
|
|
493 S(DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_datarel,
|
|
494 "indirect datarel udata4")
|
|
495 S(DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_datarel,
|
|
496 "indirect datarel udata8")
|
|
497 S(DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_datarel,
|
|
498 "indirect datarel sleb128")
|
|
499 S(DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_datarel,
|
|
500 "indirect datarel sdata2")
|
|
501 S(DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_datarel,
|
|
502 "indirect datarel sdata4")
|
|
503 S(DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_datarel,
|
|
504 "indirect datarel sdata8")
|
|
505
|
|
506 S(DW_EH_PE_indirect | DW_EH_PE_absptr | DW_EH_PE_funcrel,
|
|
507 "indirect funcrel")
|
|
508 S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_funcrel,
|
|
509 "indirect funcrel uleb128")
|
|
510 S(DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_funcrel,
|
|
511 "indirect funcrel udata2")
|
|
512 S(DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_funcrel,
|
|
513 "indirect funcrel udata4")
|
|
514 S(DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_funcrel,
|
|
515 "indirect funcrel udata8")
|
|
516 S(DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_funcrel,
|
|
517 "indirect funcrel sleb128")
|
|
518 S(DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_funcrel,
|
|
519 "indirect funcrel sdata2")
|
|
520 S(DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_funcrel,
|
|
521 "indirect funcrel sdata4")
|
|
522 S(DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_funcrel,
|
|
523 "indirect funcrel sdata8")
|
|
524
|
|
525 #if HAVE_DESIGNATED_INITIALIZERS
|
|
526 };
|
|
527
|
|
528 gcc_assert (format >= 0 && format < 0x100 && format_names[format]);
|
|
529
|
|
530 return format_names[format];
|
|
531 #else
|
|
532 }
|
|
533 gcc_unreachable ();
|
|
534 #endif
|
|
535 }
|
|
536
|
|
537 /* Output an unsigned LEB128 quantity, but only the byte values. */
|
|
538
|
|
539 void
|
|
540 dw2_asm_output_data_uleb128_raw (unsigned HOST_WIDE_INT value)
|
|
541 {
|
|
542 while (1)
|
|
543 {
|
|
544 int byte = (value & 0x7f);
|
|
545 value >>= 7;
|
|
546 if (value != 0)
|
|
547 /* More bytes to follow. */
|
|
548 byte |= 0x80;
|
|
549
|
|
550 fprintf (asm_out_file, "0x%x", byte);
|
|
551 if (value == 0)
|
|
552 break;
|
|
553 fputc (',', asm_out_file);
|
|
554 }
|
|
555 }
|
|
556
|
|
557 /* Output an unsigned LEB128 quantity. */
|
|
558
|
|
559 void
|
|
560 dw2_asm_output_data_uleb128 (unsigned HOST_WIDE_INT value,
|
|
561 const char *comment, ...)
|
|
562 {
|
|
563 va_list ap;
|
|
564
|
|
565 va_start (ap, comment);
|
|
566
|
|
567 #ifdef HAVE_AS_LEB128
|
|
568 fprintf (asm_out_file, "\t.uleb128 " HOST_WIDE_INT_PRINT_HEX , value);
|
|
569
|
|
570 if (flag_debug_asm && comment)
|
|
571 {
|
|
572 fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
|
|
573 vfprintf (asm_out_file, comment, ap);
|
|
574 }
|
|
575 #else
|
|
576 {
|
|
577 unsigned HOST_WIDE_INT work = value;
|
|
578 const char *byte_op = targetm.asm_out.byte_op;
|
|
579
|
|
580 if (byte_op)
|
|
581 fputs (byte_op, asm_out_file);
|
|
582 do
|
|
583 {
|
|
584 int byte = (work & 0x7f);
|
|
585 work >>= 7;
|
|
586 if (work != 0)
|
|
587 /* More bytes to follow. */
|
|
588 byte |= 0x80;
|
|
589
|
|
590 if (byte_op)
|
|
591 {
|
|
592 fprintf (asm_out_file, "0x%x", byte);
|
|
593 if (work != 0)
|
|
594 fputc (',', asm_out_file);
|
|
595 }
|
|
596 else
|
|
597 assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
|
|
598 }
|
|
599 while (work != 0);
|
|
600
|
|
601 if (flag_debug_asm)
|
|
602 {
|
|
603 fprintf (asm_out_file, "\t%s uleb128 " HOST_WIDE_INT_PRINT_HEX,
|
|
604 ASM_COMMENT_START, value);
|
|
605 if (comment)
|
|
606 {
|
|
607 fputs ("; ", asm_out_file);
|
|
608 vfprintf (asm_out_file, comment, ap);
|
|
609 }
|
|
610 }
|
|
611 }
|
|
612 #endif
|
|
613 fputc ('\n', asm_out_file);
|
|
614
|
|
615 va_end (ap);
|
|
616 }
|
|
617
|
|
618 /* Output an signed LEB128 quantity, but only the byte values. */
|
|
619
|
|
620 void
|
|
621 dw2_asm_output_data_sleb128_raw (HOST_WIDE_INT value)
|
|
622 {
|
|
623 int byte, more;
|
|
624
|
|
625 while (1)
|
|
626 {
|
|
627 byte = (value & 0x7f);
|
|
628 value >>= 7;
|
|
629 more = !((value == 0 && (byte & 0x40) == 0)
|
|
630 || (value == -1 && (byte & 0x40) != 0));
|
|
631 if (more)
|
|
632 byte |= 0x80;
|
|
633
|
|
634 fprintf (asm_out_file, "0x%x", byte);
|
|
635 if (!more)
|
|
636 break;
|
|
637 fputc (',', asm_out_file);
|
|
638 }
|
|
639 }
|
|
640
|
|
641 /* Output a signed LEB128 quantity. */
|
|
642
|
|
643 void
|
|
644 dw2_asm_output_data_sleb128 (HOST_WIDE_INT value,
|
|
645 const char *comment, ...)
|
|
646 {
|
|
647 va_list ap;
|
|
648
|
|
649 va_start (ap, comment);
|
|
650
|
|
651 #ifdef HAVE_AS_LEB128
|
|
652 fprintf (asm_out_file, "\t.sleb128 " HOST_WIDE_INT_PRINT_DEC, value);
|
|
653
|
|
654 if (flag_debug_asm && comment)
|
|
655 {
|
|
656 fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
|
|
657 vfprintf (asm_out_file, comment, ap);
|
|
658 }
|
|
659 #else
|
|
660 {
|
|
661 HOST_WIDE_INT work = value;
|
|
662 int more, byte;
|
|
663 const char *byte_op = targetm.asm_out.byte_op;
|
|
664
|
|
665 if (byte_op)
|
|
666 fputs (byte_op, asm_out_file);
|
|
667 do
|
|
668 {
|
|
669 byte = (work & 0x7f);
|
|
670 /* arithmetic shift */
|
|
671 work >>= 7;
|
|
672 more = !((work == 0 && (byte & 0x40) == 0)
|
|
673 || (work == -1 && (byte & 0x40) != 0));
|
|
674 if (more)
|
|
675 byte |= 0x80;
|
|
676
|
|
677 if (byte_op)
|
|
678 {
|
|
679 fprintf (asm_out_file, "0x%x", byte);
|
|
680 if (more)
|
|
681 fputc (',', asm_out_file);
|
|
682 }
|
|
683 else
|
|
684 assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
|
|
685 }
|
|
686 while (more);
|
|
687
|
|
688 if (flag_debug_asm)
|
|
689 {
|
|
690 fprintf (asm_out_file, "\t%s sleb128 " HOST_WIDE_INT_PRINT_DEC,
|
|
691 ASM_COMMENT_START, value);
|
|
692 if (comment)
|
|
693 {
|
|
694 fputs ("; ", asm_out_file);
|
|
695 vfprintf (asm_out_file, comment, ap);
|
|
696 }
|
|
697 }
|
|
698 }
|
|
699 #endif
|
|
700 fputc ('\n', asm_out_file);
|
|
701
|
|
702 va_end (ap);
|
|
703 }
|
|
704
|
|
705 void
|
|
706 dw2_asm_output_delta_uleb128 (const char *lab1 ATTRIBUTE_UNUSED,
|
|
707 const char *lab2 ATTRIBUTE_UNUSED,
|
|
708 const char *comment, ...)
|
|
709 {
|
|
710 va_list ap;
|
|
711
|
|
712 va_start (ap, comment);
|
|
713
|
|
714 #ifdef HAVE_AS_LEB128
|
|
715 fputs ("\t.uleb128 ", asm_out_file);
|
|
716 assemble_name (asm_out_file, lab1);
|
|
717 fputc ('-', asm_out_file);
|
|
718 assemble_name (asm_out_file, lab2);
|
|
719 #else
|
|
720 gcc_unreachable ();
|
|
721 #endif
|
|
722
|
|
723 if (flag_debug_asm && comment)
|
|
724 {
|
|
725 fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
|
|
726 vfprintf (asm_out_file, comment, ap);
|
|
727 }
|
|
728 fputc ('\n', asm_out_file);
|
|
729
|
|
730 va_end (ap);
|
|
731 }
|
|
732
|
|
733 #if 0
|
|
734
|
|
735 void
|
|
736 dw2_asm_output_delta_sleb128 (const char *lab1 ATTRIBUTE_UNUSED,
|
|
737 const char *lab2 ATTRIBUTE_UNUSED,
|
|
738 const char *comment, ...)
|
|
739 {
|
|
740 va_list ap;
|
|
741
|
|
742 va_start (ap, comment);
|
|
743
|
|
744 #ifdef HAVE_AS_LEB128
|
|
745 fputs ("\t.sleb128 ", asm_out_file);
|
|
746 assemble_name (asm_out_file, lab1);
|
|
747 fputc ('-', asm_out_file);
|
|
748 assemble_name (asm_out_file, lab2);
|
|
749 #else
|
|
750 gcc_unreachable ();
|
|
751 #endif
|
|
752
|
|
753 if (flag_debug_asm && comment)
|
|
754 {
|
|
755 fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
|
|
756 vfprintf (asm_out_file, comment, ap);
|
|
757 }
|
|
758 fputc ('\n', asm_out_file);
|
|
759
|
|
760 va_end (ap);
|
|
761 }
|
|
762 #endif /* 0 */
|
|
763
|
|
764 static int dw2_output_indirect_constant_1 (splay_tree_node, void *);
|
|
765
|
|
766 static GTY((param1_is (char *), param2_is (tree))) splay_tree indirect_pool;
|
|
767
|
|
768 static GTY(()) int dw2_const_labelno;
|
|
769
|
|
770 #if defined(HAVE_GAS_HIDDEN) && defined(SUPPORTS_ONE_ONLY)
|
|
771 # define USE_LINKONCE_INDIRECT 1
|
|
772 #else
|
|
773 # define USE_LINKONCE_INDIRECT 0
|
|
774 #endif
|
|
775
|
|
776 /* Comparison function for a splay tree in which the keys are strings.
|
|
777 K1 and K2 have the dynamic type "const char *". Returns <0, 0, or
|
|
778 >0 to indicate whether K1 is less than, equal to, or greater than
|
|
779 K2, respectively. */
|
|
780
|
|
781 static int
|
|
782 splay_tree_compare_strings (splay_tree_key k1, splay_tree_key k2)
|
|
783 {
|
|
784 const char *s1 = (const char *)k1;
|
|
785 const char *s2 = (const char *)k2;
|
|
786 int ret;
|
|
787
|
|
788 if (s1 == s2)
|
|
789 return 0;
|
|
790
|
|
791 ret = strcmp (s1, s2);
|
|
792
|
|
793 /* The strings are always those from IDENTIFIER_NODEs, and,
|
|
794 therefore, we should never have two copies of the same
|
|
795 string. */
|
|
796 gcc_assert (ret);
|
|
797
|
|
798 return ret;
|
|
799 }
|
|
800
|
|
801 /* Put X, a SYMBOL_REF, in memory. Return a SYMBOL_REF to the allocated
|
|
802 memory. Differs from force_const_mem in that a single pool is used for
|
|
803 the entire unit of translation, and the memory is not guaranteed to be
|
|
804 "near" the function in any interesting sense. IS_PUBLIC controls whether
|
|
805 the symbol can be shared across the entire application (or DSO). */
|
|
806
|
|
807 rtx
|
|
808 dw2_force_const_mem (rtx x, bool is_public)
|
|
809 {
|
|
810 splay_tree_node node;
|
|
811 const char *key;
|
|
812 tree decl;
|
|
813
|
|
814 if (! indirect_pool)
|
|
815 /* We use strcmp, rather than just comparing pointers, so that the
|
|
816 sort order will not depend on the host system. */
|
|
817 indirect_pool = splay_tree_new_ggc (splay_tree_compare_strings);
|
|
818
|
|
819 gcc_assert (GET_CODE (x) == SYMBOL_REF);
|
|
820
|
|
821 key = XSTR (x, 0);
|
|
822 node = splay_tree_lookup (indirect_pool, (splay_tree_key) key);
|
|
823 if (node)
|
|
824 decl = (tree) node->value;
|
|
825 else
|
|
826 {
|
|
827 tree id;
|
|
828 const char *str = targetm.strip_name_encoding (key);
|
|
829
|
|
830 if (is_public && USE_LINKONCE_INDIRECT)
|
|
831 {
|
|
832 char *ref_name = XALLOCAVEC (char, strlen (str) + sizeof "DW.ref.");
|
|
833
|
|
834 sprintf (ref_name, "DW.ref.%s", str);
|
|
835 id = get_identifier (ref_name);
|
|
836 decl = build_decl (VAR_DECL, id, ptr_type_node);
|
|
837 DECL_ARTIFICIAL (decl) = 1;
|
|
838 DECL_IGNORED_P (decl) = 1;
|
|
839 TREE_PUBLIC (decl) = 1;
|
|
840 DECL_INITIAL (decl) = decl;
|
|
841 make_decl_one_only (decl);
|
|
842 }
|
|
843 else
|
|
844 {
|
|
845 char label[32];
|
|
846
|
|
847 ASM_GENERATE_INTERNAL_LABEL (label, "LDFCM", dw2_const_labelno);
|
|
848 ++dw2_const_labelno;
|
|
849 id = get_identifier (label);
|
|
850 decl = build_decl (VAR_DECL, id, ptr_type_node);
|
|
851 DECL_ARTIFICIAL (decl) = 1;
|
|
852 DECL_IGNORED_P (decl) = 1;
|
|
853 TREE_STATIC (decl) = 1;
|
|
854 DECL_INITIAL (decl) = decl;
|
|
855 }
|
|
856
|
|
857 id = maybe_get_identifier (str);
|
|
858 if (id)
|
|
859 TREE_SYMBOL_REFERENCED (id) = 1;
|
|
860
|
|
861 splay_tree_insert (indirect_pool, (splay_tree_key) key,
|
|
862 (splay_tree_value) decl);
|
|
863 }
|
|
864
|
|
865 return XEXP (DECL_RTL (decl), 0);
|
|
866 }
|
|
867
|
|
868 /* A helper function for dw2_output_indirect_constants called through
|
|
869 splay_tree_foreach. Emit one queued constant to memory. */
|
|
870
|
|
871 static int
|
|
872 dw2_output_indirect_constant_1 (splay_tree_node node,
|
|
873 void *data ATTRIBUTE_UNUSED)
|
|
874 {
|
|
875 const char *sym;
|
|
876 rtx sym_ref;
|
|
877 tree decl;
|
|
878
|
|
879 sym = (const char *) node->key;
|
|
880 decl = (tree) node->value;
|
|
881 sym_ref = gen_rtx_SYMBOL_REF (Pmode, sym);
|
|
882 sym = targetm.strip_name_encoding (sym);
|
|
883 if (TREE_PUBLIC (decl) && USE_LINKONCE_INDIRECT)
|
|
884 fprintf (asm_out_file, "\t.hidden %sDW.ref.%s\n", user_label_prefix, sym);
|
|
885 assemble_variable (decl, 1, 1, 1);
|
|
886 assemble_integer (sym_ref, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
|
|
887
|
|
888 return 0;
|
|
889 }
|
|
890
|
|
891 /* Emit the constants queued through dw2_force_const_mem. */
|
|
892
|
|
893 void
|
|
894 dw2_output_indirect_constants (void)
|
|
895 {
|
|
896 if (indirect_pool)
|
|
897 splay_tree_foreach (indirect_pool, dw2_output_indirect_constant_1, NULL);
|
|
898 }
|
|
899
|
|
900 /* Like dw2_asm_output_addr_rtx, but encode the pointer as directed.
|
|
901 If PUBLIC is set and the encoding is DW_EH_PE_indirect, the indirect
|
|
902 reference is shared across the entire application (or DSO). */
|
|
903
|
|
904 void
|
|
905 dw2_asm_output_encoded_addr_rtx (int encoding, rtx addr, bool is_public,
|
|
906 const char *comment, ...)
|
|
907 {
|
|
908 int size;
|
|
909 va_list ap;
|
|
910
|
|
911 va_start (ap, comment);
|
|
912
|
|
913 size = size_of_encoded_value (encoding);
|
|
914
|
|
915 if (encoding == DW_EH_PE_aligned)
|
|
916 {
|
|
917 assemble_align (POINTER_SIZE);
|
|
918 assemble_integer (addr, size, POINTER_SIZE, 1);
|
|
919 return;
|
|
920 }
|
|
921
|
|
922 /* NULL is _always_ represented as a plain zero, as is 1 for Ada's
|
|
923 "all others". */
|
|
924 if (addr == const0_rtx || addr == const1_rtx)
|
|
925 assemble_integer (addr, size, BITS_PER_UNIT, 1);
|
|
926 else
|
|
927 {
|
|
928 restart:
|
|
929 /* Allow the target first crack at emitting this. Some of the
|
|
930 special relocations require special directives instead of
|
|
931 just ".4byte" or whatever. */
|
|
932 #ifdef ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX
|
|
933 ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX (asm_out_file, encoding, size,
|
|
934 addr, done);
|
|
935 #endif
|
|
936
|
|
937 /* Indirection is used to get dynamic relocations out of a
|
|
938 read-only section. */
|
|
939 if (encoding & DW_EH_PE_indirect)
|
|
940 {
|
|
941 /* It is very tempting to use force_const_mem so that we share data
|
|
942 with the normal constant pool. However, we've already emitted
|
|
943 the constant pool for this function. Moreover, we'd like to
|
|
944 share these constants across the entire unit of translation and
|
|
945 even, if possible, across the entire application (or DSO). */
|
|
946 addr = dw2_force_const_mem (addr, is_public);
|
|
947 encoding &= ~DW_EH_PE_indirect;
|
|
948 goto restart;
|
|
949 }
|
|
950
|
|
951 switch (encoding & 0xF0)
|
|
952 {
|
|
953 case DW_EH_PE_absptr:
|
|
954 dw2_assemble_integer (size, addr);
|
|
955 break;
|
|
956
|
|
957 case DW_EH_PE_pcrel:
|
|
958 gcc_assert (GET_CODE (addr) == SYMBOL_REF);
|
|
959 #ifdef ASM_OUTPUT_DWARF_PCREL
|
|
960 ASM_OUTPUT_DWARF_PCREL (asm_out_file, size, XSTR (addr, 0));
|
|
961 #else
|
|
962 dw2_assemble_integer (size, gen_rtx_MINUS (Pmode, addr, pc_rtx));
|
|
963 #endif
|
|
964 break;
|
|
965
|
|
966 default:
|
|
967 /* Other encodings should have been handled by
|
|
968 ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX. */
|
|
969 gcc_unreachable ();
|
|
970 }
|
|
971
|
|
972 #ifdef ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX
|
|
973 done:;
|
|
974 #endif
|
|
975 }
|
|
976
|
|
977 if (flag_debug_asm && comment)
|
|
978 {
|
|
979 fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
|
|
980 vfprintf (asm_out_file, comment, ap);
|
|
981 }
|
|
982 fputc ('\n', asm_out_file);
|
|
983
|
|
984 va_end (ap);
|
|
985 }
|
|
986
|
|
987 #include "gt-dwarf2asm.h"
|