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