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