Commit | Line | Data |
---|---|---|
73589c9d | 1 | /* tc-or1k.c -- Assembler for the OpenRISC family. |
b90efa5b | 2 | Copyright (C) 2001-2015 Free Software Foundation, Inc. |
73589c9d | 3 | Contributed for OR32 by Johan Rydberg, jrydberg@opencores.org |
c7e40348 NC |
4 | |
5 | This file is part of GAS, the GNU Assembler. | |
6 | ||
7 | GAS is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
ec2655a6 | 9 | the Free Software Foundation; either version 3, or (at your option) |
c7e40348 NC |
10 | any later version. |
11 | ||
12 | GAS is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
73589c9d | 18 | along with this program; if not, see <http://www.gnu.org/licenses/> */ |
c7e40348 | 19 | #include "as.h" |
73589c9d | 20 | #include "safe-ctype.h" |
c7e40348 NC |
21 | #include "subsegs.h" |
22 | #include "symcat.h" | |
73589c9d CS |
23 | #include "opcodes/or1k-desc.h" |
24 | #include "opcodes/or1k-opc.h" | |
c7e40348 | 25 | #include "cgen.h" |
73589c9d CS |
26 | #include "elf/or1k.h" |
27 | #include "dw2gencfi.h" | |
c7e40348 NC |
28 | |
29 | /* Structure to hold all of the different components describing | |
30 | an individual instruction. */ | |
c7e40348 | 31 | |
73589c9d | 32 | typedef struct |
c7e40348 | 33 | { |
73589c9d CS |
34 | const CGEN_INSN * insn; |
35 | const CGEN_INSN * orig_insn; | |
36 | CGEN_FIELDS fields; | |
c7e40348 NC |
37 | #if CGEN_INT_INSN_P |
38 | CGEN_INSN_INT buffer [1]; | |
39 | #define INSN_VALUE(buf) (*(buf)) | |
40 | #else | |
41 | unsigned char buffer [CGEN_MAX_INSN_SIZE]; | |
42 | #define INSN_VALUE(buf) (buf) | |
43 | #endif | |
73589c9d CS |
44 | char * addr; |
45 | fragS * frag; | |
c7e40348 NC |
46 | int num_fixups; |
47 | fixS * fixups [GAS_CGEN_MAX_FIXUPS]; | |
48 | int indices [MAX_OPERAND_INSTANCES]; | |
73589c9d CS |
49 | } |
50 | or1k_insn; | |
c7e40348 NC |
51 | |
52 | const char comment_chars[] = "#"; | |
53 | const char line_comment_chars[] = "#"; | |
54 | const char line_separator_chars[] = ";"; | |
55 | const char EXP_CHARS[] = "eE"; | |
56 | const char FLT_CHARS[] = "dD"; | |
57 | ||
73589c9d CS |
58 | #define OR1K_SHORTOPTS "m:" |
59 | const char * md_shortopts = OR1K_SHORTOPTS; | |
c7e40348 NC |
60 | |
61 | struct option md_longopts[] = | |
62 | { | |
63 | {NULL, no_argument, NULL, 0} | |
64 | }; | |
65 | size_t md_longopts_size = sizeof (md_longopts); | |
66 | ||
73589c9d | 67 | unsigned long or1k_machine = 0; /* default */ |
c7e40348 NC |
68 | |
69 | int | |
ea1562b3 | 70 | md_parse_option (int c ATTRIBUTE_UNUSED, char * arg ATTRIBUTE_UNUSED) |
c7e40348 NC |
71 | { |
72 | return 0; | |
73 | } | |
74 | ||
75 | void | |
ea1562b3 | 76 | md_show_usage (FILE * stream ATTRIBUTE_UNUSED) |
c7e40348 NC |
77 | { |
78 | } | |
79 | ||
80 | static void | |
ea1562b3 | 81 | ignore_pseudo (int val ATTRIBUTE_UNUSED) |
c7e40348 NC |
82 | { |
83 | discard_rest_of_line (); | |
84 | } | |
85 | ||
73589c9d CS |
86 | static bfd_boolean nodelay = FALSE; |
87 | static void | |
88 | s_nodelay (int val ATTRIBUTE_UNUSED) | |
89 | { | |
90 | nodelay = TRUE; | |
91 | } | |
92 | ||
93 | const char or1k_comment_chars [] = ";#"; | |
c7e40348 NC |
94 | |
95 | /* The target specific pseudo-ops which we support. */ | |
96 | const pseudo_typeS md_pseudo_table[] = | |
97 | { | |
73589c9d | 98 | { "align", s_align_bytes, 0 }, |
c7e40348 NC |
99 | { "word", cons, 4 }, |
100 | { "proc", ignore_pseudo, 0 }, | |
101 | { "endproc", ignore_pseudo, 0 }, | |
73589c9d CS |
102 | { "nodelay", s_nodelay, 0 }, |
103 | { NULL, NULL, 0 } | |
c7e40348 NC |
104 | }; |
105 | ||
106 | ||
c7e40348 | 107 | void |
ea1562b3 | 108 | md_begin (void) |
c7e40348 NC |
109 | { |
110 | /* Initialize the `cgen' interface. */ | |
111 | ||
112 | /* Set the machine number and endian. */ | |
73589c9d | 113 | gas_cgen_cpu_desc = or1k_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0, |
c7e40348 NC |
114 | CGEN_CPU_OPEN_ENDIAN, |
115 | CGEN_ENDIAN_BIG, | |
116 | CGEN_CPU_OPEN_END); | |
73589c9d | 117 | or1k_cgen_init_asm (gas_cgen_cpu_desc); |
c7e40348 NC |
118 | |
119 | /* This is a callback from cgen to gas to parse operands. */ | |
120 | cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand); | |
121 | } | |
122 | ||
123 | void | |
ea1562b3 | 124 | md_assemble (char * str) |
c7e40348 NC |
125 | { |
126 | static int last_insn_had_delay_slot = 0; | |
73589c9d | 127 | or1k_insn insn; |
c7e40348 NC |
128 | char * errmsg; |
129 | ||
130 | /* Initialize GAS's cgen interface for a new instruction. */ | |
131 | gas_cgen_init_parse (); | |
132 | ||
73589c9d | 133 | insn.insn = or1k_cgen_assemble_insn |
c7e40348 NC |
134 | (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg); |
135 | ||
136 | if (!insn.insn) | |
137 | { | |
20203fb9 | 138 | as_bad ("%s", errmsg); |
c7e40348 NC |
139 | return; |
140 | } | |
141 | ||
142 | /* Doesn't really matter what we pass for RELAX_P here. */ | |
143 | gas_cgen_finish_insn (insn.insn, insn.buffer, | |
73589c9d | 144 | CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL); |
c7e40348 | 145 | |
c7e40348 NC |
146 | last_insn_had_delay_slot |
147 | = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_DELAY_SLOT); | |
73589c9d | 148 | (void) last_insn_had_delay_slot; |
c7e40348 NC |
149 | } |
150 | ||
151 | ||
152 | /* The syntax in the manual says constants begin with '#'. | |
153 | We just ignore it. */ | |
154 | ||
155 | void | |
ea1562b3 | 156 | md_operand (expressionS * expressionP) |
c7e40348 NC |
157 | { |
158 | if (* input_line_pointer == '#') | |
159 | { | |
160 | input_line_pointer ++; | |
161 | expression (expressionP); | |
162 | } | |
163 | } | |
164 | ||
165 | valueT | |
ea1562b3 | 166 | md_section_align (segT segment, valueT size) |
c7e40348 NC |
167 | { |
168 | int align = bfd_get_section_alignment (stdoutput, segment); | |
8d3842cd | 169 | return ((size + (1 << align) - 1) & -(1 << align)); |
c7e40348 NC |
170 | } |
171 | ||
172 | symbolS * | |
ea1562b3 | 173 | md_undefined_symbol (char * name ATTRIBUTE_UNUSED) |
c7e40348 NC |
174 | { |
175 | return 0; | |
176 | } | |
177 | ||
c7e40348 | 178 | |
73589c9d | 179 | /* Interface to relax_segment. */ |
c7e40348 NC |
180 | |
181 | const relax_typeS md_relax_table[] = | |
182 | { | |
183 | /* The fields are: | |
184 | 1) most positive reach of this state, | |
185 | 2) most negative reach of this state, | |
186 | 3) how many bytes this mode will add to the size of the current frag | |
187 | 4) which index into the table to try if we can't fit into this one. */ | |
188 | ||
189 | /* The first entry must be unused because an `rlx_more' value of zero ends | |
190 | each list. */ | |
191 | {1, 1, 0, 0}, | |
192 | ||
73589c9d CS |
193 | /* The displacement used by GAS is from the end of the 4 byte insn, |
194 | so we subtract 4 from the following. */ | |
195 | {(((1 << 25) - 1) << 2) - 4, -(1 << 25) - 4, 0, 0}, | |
c7e40348 NC |
196 | }; |
197 | ||
c7e40348 | 198 | int |
73589c9d | 199 | md_estimate_size_before_relax (fragS * fragP, segT segment ATTRIBUTE_UNUSED) |
c7e40348 | 200 | { |
606ab118 | 201 | return md_relax_table[fragP->fr_subtype].rlx_length; |
c7e40348 NC |
202 | } |
203 | ||
204 | /* *fragP has been relaxed to its final size, and now needs to have | |
205 | the bytes inside it modified to conform to the new size. | |
206 | ||
207 | Called after relaxation is finished. | |
208 | fragP->fr_type == rs_machine_dependent. | |
209 | fragP->fr_subtype is the subtype of what the address relaxed to. */ | |
210 | ||
211 | void | |
ea1562b3 | 212 | md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, |
73589c9d CS |
213 | segT sec ATTRIBUTE_UNUSED, |
214 | fragS * fragP ATTRIBUTE_UNUSED) | |
c7e40348 NC |
215 | { |
216 | /* FIXME */ | |
217 | } | |
218 | ||
73589c9d | 219 | |
c7e40348 NC |
220 | /* Functions concerning relocs. */ |
221 | ||
222 | /* The location from which a PC relative jump should be calculated, | |
223 | given a PC relative reloc. */ | |
224 | ||
225 | long | |
ea1562b3 | 226 | md_pcrel_from_section (fixS * fixP, segT sec) |
c7e40348 NC |
227 | { |
228 | if (fixP->fx_addsy != (symbolS *) NULL | |
229 | && (! S_IS_DEFINED (fixP->fx_addsy) | |
73589c9d CS |
230 | || (S_GET_SEGMENT (fixP->fx_addsy) != sec) |
231 | || S_IS_EXTERNAL (fixP->fx_addsy) | |
232 | || S_IS_WEAK (fixP->fx_addsy))) | |
233 | { | |
234 | /* The symbol is undefined (or is defined but not in this section). | |
235 | Let the linker figure it out. */ | |
236 | return 0; | |
237 | } | |
c7e40348 | 238 | |
73589c9d | 239 | return fixP->fx_frag->fr_address + fixP->fx_where; |
c7e40348 NC |
240 | } |
241 | ||
242 | ||
243 | /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP. | |
244 | Returns BFD_RELOC_NONE if no reloc type can be found. | |
245 | *FIXP may be modified if desired. */ | |
246 | ||
247 | bfd_reloc_code_real_type | |
ea1562b3 | 248 | md_cgen_lookup_reloc (const CGEN_INSN * insn ATTRIBUTE_UNUSED, |
73589c9d CS |
249 | const CGEN_OPERAND * operand, |
250 | fixS * fixP) | |
c7e40348 | 251 | { |
73589c9d CS |
252 | if (fixP->fx_cgen.opinfo) |
253 | return fixP->fx_cgen.opinfo; | |
c7e40348 NC |
254 | |
255 | switch (operand->type) | |
256 | { | |
73589c9d | 257 | case OR1K_OPERAND_DISP26: |
5d6255fe | 258 | fixP->fx_pcrel = 1; |
73589c9d | 259 | return BFD_RELOC_OR1K_REL_26; |
c7e40348 | 260 | |
73589c9d CS |
261 | default: /* avoid -Wall warning */ |
262 | return BFD_RELOC_NONE; | |
c7e40348 | 263 | } |
c7e40348 | 264 | } |
73589c9d | 265 | |
c7e40348 NC |
266 | /* Write a value out to the object file, using the appropriate endianness. */ |
267 | ||
268 | void | |
ea1562b3 | 269 | md_number_to_chars (char * buf, valueT val, int n) |
c7e40348 NC |
270 | { |
271 | number_to_chars_bigendian (buf, val, n); | |
272 | } | |
273 | ||
274 | /* Turn a string in input_line_pointer into a floating point constant of type | |
275 | type, and store the appropriate bytes in *litP. The number of LITTLENUMS | |
73589c9d | 276 | emitted is stored in *sizeP . An error message is returned, or NULL on OK. */ |
c7e40348 | 277 | |
73589c9d | 278 | /* Equal to MAX_PRECISION in atof-ieee.c. */ |
c7e40348 NC |
279 | #define MAX_LITTLENUMS 6 |
280 | ||
281 | char * | |
ea1562b3 | 282 | md_atof (int type, char * litP, int * sizeP) |
c7e40348 | 283 | { |
499ac353 | 284 | return ieee_md_atof (type, litP, sizeP, TRUE); |
c7e40348 NC |
285 | } |
286 | ||
b34976b6 | 287 | bfd_boolean |
73589c9d | 288 | or1k_fix_adjustable (fixS * fixP) |
c7e40348 | 289 | { |
ea1562b3 | 290 | /* We need the symbol name for the VTABLE entries. */ |
c7e40348 NC |
291 | if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT |
292 | || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) | |
73589c9d CS |
293 | return FALSE; |
294 | ||
295 | return TRUE; | |
296 | } | |
297 | ||
298 | #define GOT_NAME "_GLOBAL_OFFSET_TABLE_" | |
299 | ||
300 | arelent * | |
8a9e7a91 | 301 | tc_gen_reloc (asection * section, fixS * fixp) |
73589c9d | 302 | { |
8a9e7a91 PZ |
303 | arelent *reloc; |
304 | bfd_reloc_code_real_type code; | |
73589c9d | 305 | |
8a9e7a91 PZ |
306 | reloc = xmalloc (sizeof (arelent)); |
307 | ||
308 | reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); | |
309 | *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); | |
310 | reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; | |
311 | ||
312 | if (fixp->fx_pcrel) | |
313 | { | |
314 | if (section->use_rela_p) | |
315 | fixp->fx_offset -= md_pcrel_from_section (fixp, section); | |
316 | else | |
317 | fixp->fx_offset = reloc->address; | |
318 | } | |
319 | reloc->addend = fixp->fx_offset; | |
320 | ||
321 | code = fixp->fx_r_type; | |
322 | switch (code) | |
323 | { | |
324 | case BFD_RELOC_16: | |
325 | if (fixp->fx_pcrel) | |
326 | code = BFD_RELOC_16_PCREL; | |
327 | break; | |
328 | ||
329 | case BFD_RELOC_32: | |
330 | if (fixp->fx_pcrel) | |
331 | code = BFD_RELOC_32_PCREL; | |
332 | break; | |
333 | ||
334 | case BFD_RELOC_64: | |
335 | if (fixp->fx_pcrel) | |
336 | code = BFD_RELOC_64_PCREL; | |
337 | break; | |
338 | ||
339 | default: | |
340 | break; | |
341 | } | |
342 | ||
343 | reloc->howto = bfd_reloc_type_lookup (stdoutput, code); | |
344 | if (reloc->howto == NULL) | |
73589c9d | 345 | { |
8a9e7a91 PZ |
346 | as_bad_where (fixp->fx_file, fixp->fx_line, |
347 | _ | |
348 | ("cannot represent %s relocation in this object file format"), | |
349 | bfd_get_reloc_code_name (code)); | |
350 | return NULL; | |
73589c9d CS |
351 | } |
352 | ||
8a9e7a91 | 353 | return reloc; |
73589c9d CS |
354 | } |
355 | ||
356 | void | |
357 | or1k_apply_fix (struct fix *f, valueT *t, segT s) | |
358 | { | |
359 | gas_cgen_md_apply_fix (f, t, s); | |
360 | ||
361 | switch (f->fx_r_type) | |
362 | { | |
363 | case BFD_RELOC_OR1K_TLS_GD_HI16: | |
364 | case BFD_RELOC_OR1K_TLS_GD_LO16: | |
365 | case BFD_RELOC_OR1K_TLS_LDM_HI16: | |
366 | case BFD_RELOC_OR1K_TLS_LDM_LO16: | |
367 | case BFD_RELOC_OR1K_TLS_LDO_HI16: | |
368 | case BFD_RELOC_OR1K_TLS_LDO_LO16: | |
369 | case BFD_RELOC_OR1K_TLS_IE_HI16: | |
370 | case BFD_RELOC_OR1K_TLS_IE_LO16: | |
371 | case BFD_RELOC_OR1K_TLS_LE_HI16: | |
372 | case BFD_RELOC_OR1K_TLS_LE_LO16: | |
373 | S_SET_THREAD_LOCAL (f->fx_addsy); | |
374 | break; | |
375 | default: | |
376 | break; | |
377 | } | |
378 | } | |
c7e40348 | 379 | |
73589c9d CS |
380 | void |
381 | or1k_elf_final_processing (void) | |
382 | { | |
383 | if (nodelay) | |
384 | elf_elfheader (stdoutput)->e_flags |= EF_OR1K_NODELAY; | |
c7e40348 | 385 | } |
73589c9d CS |
386 | |
387 | /* Standard calling conventions leave the CFA at SP on entry. */ | |
388 | ||
389 | void | |
390 | or1k_cfi_frame_initial_instructions (void) | |
391 | { | |
392 | cfi_add_CFA_def_cfa_register (1); | |
393 | } | |
394 |