Commit | Line | Data |
---|---|---|
5749c497 KR |
1 | /* tc-alpha.c - Processor-specific code for the DEC Alpha CPU. |
2 | Copyright (C) 1989, 1993, 1994 Free Software Foundation, Inc. | |
3 | Contributed by Carnegie Mellon University, 1993. | |
4 | Written by Alessandro Forin, based on earlier gas-1.38 target CPU files. | |
5 | Modified by Ken Raeburn for gas-2.x and ECOFF support. | |
6 | ||
7 | This file is part of GAS, the GNU Assembler. | |
8 | ||
9 | GAS is free software; you can redistribute it and/or modify | |
10 | it under the terms of the GNU General Public License as published by | |
11 | the Free Software Foundation; either version 2, or (at your option) | |
12 | any later version. | |
13 | ||
14 | GAS is distributed in the hope that it will be useful, | |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | GNU General Public License for more details. | |
18 | ||
19 | You should have received a copy of the GNU General Public License | |
20 | along with GAS; see the file COPYING. If not, write to | |
21 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
22 | ||
23 | /* | |
24 | * Mach Operating System | |
25 | * Copyright (c) 1993 Carnegie Mellon University | |
26 | * All Rights Reserved. | |
27 | * | |
28 | * Permission to use, copy, modify and distribute this software and its | |
29 | * documentation is hereby granted, provided that both the copyright | |
30 | * notice and this permission notice appear in all copies of the | |
31 | * software, derivative works or modified versions, and any portions | |
32 | * thereof, and that both notices appear in supporting documentation. | |
33 | * | |
34 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS | |
35 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR | |
36 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | |
37 | * | |
38 | * Carnegie Mellon requests users of this software to return to | |
39 | * | |
40 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU | |
41 | * School of Computer Science | |
42 | * Carnegie Mellon University | |
43 | * Pittsburgh PA 15213-3890 | |
44 | * | |
45 | * any improvements or extensions that they make and grant Carnegie the | |
46 | * rights to redistribute these changes. | |
47 | */ | |
48 | /* | |
49 | * HISTORY | |
50 | * 5-Oct-93 Alessandro Forin (af) at Carnegie-Mellon University | |
51 | * First Checkin | |
52 | * | |
5749c497 KR |
53 | * Author: Alessandro Forin, Carnegie Mellon University |
54 | * Date: Jan 1993 | |
55 | */ | |
56 | ||
a2a1a548 ILT |
57 | #include <ctype.h> |
58 | ||
5749c497 KR |
59 | #include "as.h" |
60 | #include "alpha-opcode.h" | |
61 | #include "subsegs.h" | |
62 | ||
30869211 KR |
63 | /* @@ Will a simple 0x8000 work here? If not, why not? */ |
64 | #define GP_ADJUSTMENT (0x8000 - 0x10) | |
65 | ||
5749c497 KR |
66 | /* These are exported to relaxing code, even though we don't do any |
67 | relaxing on this processor currently. */ | |
68 | const relax_typeS md_relax_table[1]; | |
69 | int md_short_jump_size = 4; | |
70 | int md_long_jump_size = 4; | |
71 | ||
72 | /* handle of the OPCODE hash table */ | |
73 | static struct hash_control *op_hash; | |
74 | ||
40cd35ff KR |
75 | /* Sections and symbols we'll want to keep track of. */ |
76 | static segT lita_sec, rdata, sdata, lit8_sec, lit4_sec; | |
77 | static symbolS *lit8_sym, *lit4_sym; | |
5749c497 | 78 | |
40cd35ff | 79 | /* Setting for ".set [no]{at,macro}". */ |
5749c497 KR |
80 | static int at_ok = 1, macro_ok = 1; |
81 | ||
82 | /* Keep track of global pointer. */ | |
c79e67a3 | 83 | valueT alpha_gp_value; |
5749c497 KR |
84 | static symbolS *gp; |
85 | ||
86 | /* We'll probably be using this relocation frequently, and we | |
87 | will want to compare for it. */ | |
a2a1a548 | 88 | static const reloc_howto_type *gpdisp_hi16_howto; |
5749c497 KR |
89 | |
90 | /* These are exported to ECOFF code. */ | |
91 | unsigned long alpha_gprmask, alpha_fprmask; | |
92 | ||
93 | /* Used for LITUSE relocations. */ | |
94 | static expressionS lituse_basereg, lituse_byteoff, lituse_jsr; | |
95 | ||
cf272f02 KR |
96 | /* Address size: In OSF/1 1.3, an undocumented "-32addr" option will |
97 | cause all addresses to be treated as 32-bit values in memory. (The | |
98 | in-register versions are all sign-extended to 64 bits, of course.) | |
99 | Some other systems may want this option too. */ | |
100 | static int addr32; | |
101 | ||
5749c497 KR |
102 | /* Imported functions -- they should be defined in header files somewhere. */ |
103 | extern segT subseg_get (); | |
104 | extern PTR bfd_alloc_by_size_t (); | |
105 | extern void s_globl (), s_long (), s_short (), s_space (), cons (), s_text (), | |
106 | s_data (), float_cons (); | |
107 | ||
c79e67a3 | 108 | /* Static functions, needing forward declarations. */ |
a2a1a548 | 109 | static void s_base (), s_proc (), s_alpha_set (); |
5749c497 KR |
110 | static void s_gprel32 (), s_rdata (), s_sdata (), s_alpha_comm (); |
111 | static int alpha_ip (); | |
112 | ||
aaeee550 KR |
113 | static void emit_unaligned_io PARAMS ((char *, int, valueT, int)); |
114 | static void emit_load_unal PARAMS ((int, valueT, int)); | |
115 | static void emit_store_unal PARAMS ((int, valueT, int)); | |
116 | static void emit_byte_manip_r PARAMS ((char *, int, int, int, int, int)); | |
117 | static void emit_extract_r PARAMS ((int, int, int, int, int)); | |
118 | static void emit_insert_r PARAMS ((int, int, int, int, int)); | |
119 | static void emit_mask_r PARAMS ((int, int, int, int, int)); | |
120 | static void emit_sign_extend PARAMS ((int, int)); | |
121 | static void emit_bis_r PARAMS ((int, int, int)); | |
122 | static int build_mem PARAMS ((int, int, int, bfd_signed_vma)); | |
123 | static int build_operate_n PARAMS ((int, int, int, int, int)); | |
124 | static void emit_sll_n PARAMS ((int, int, int)); | |
125 | static void emit_ldah_num PARAMS ((int, bfd_vma, int)); | |
126 | static void emit_addq_r PARAMS ((int, int, int)); | |
127 | static void emit_lda_n PARAMS ((int, bfd_vma, int)); | |
128 | static void emit_add64 PARAMS ((int, int, bfd_vma)); | |
71f9b3c0 | 129 | static int in_range_signed PARAMS ((bfd_vma, int)); |
aaeee550 | 130 | |
5749c497 KR |
131 | const pseudo_typeS md_pseudo_table[] = |
132 | { | |
133 | {"common", s_comm, 0}, /* is this used? */ | |
134 | {"comm", s_alpha_comm, 0}, /* osf1 compiler does this */ | |
135 | {"rdata", s_rdata, 0}, | |
136 | {"sdata", s_sdata, 0}, | |
137 | {"gprel32", s_gprel32, 0}, | |
138 | {"t_floating", float_cons, 'd'}, | |
139 | {"s_floating", float_cons, 'f'}, | |
140 | {"f_floating", float_cons, 'F'}, | |
141 | {"g_floating", float_cons, 'G'}, | |
142 | {"d_floating", float_cons, 'D'}, | |
143 | ||
144 | {"proc", s_proc, 0}, | |
145 | {"aproc", s_proc, 1}, | |
146 | {"set", s_alpha_set, 0}, | |
147 | {"reguse", s_ignore, 0}, | |
148 | {"livereg", s_ignore, 0}, | |
149 | {"extern", s_ignore, 0}, /*??*/ | |
150 | {"base", s_base, 0}, /*??*/ | |
151 | {"option", s_ignore, 0}, | |
152 | {"prologue", s_ignore, 0}, | |
153 | {"aent", s_ignore, 0}, | |
154 | {"ugen", s_ignore, 0}, | |
155 | ||
156 | /* We don't do any optimizing, so we can safely ignore these. */ | |
157 | {"noalias", s_ignore, 0}, | |
158 | {"alias", s_ignore, 0}, | |
159 | ||
160 | {NULL, 0, 0}, | |
161 | }; | |
162 | ||
163 | #define SA 21 /* shift for register Ra */ | |
164 | #define SB 16 /* shift for register Rb */ | |
165 | #define SC 0 /* shift for register Rc */ | |
166 | #define SN 13 /* shift for 8 bit immediate # */ | |
167 | ||
168 | #define T9 23 | |
169 | #define T10 24 | |
170 | #define T11 25 | |
0952861c KR |
171 | #define T12 26 |
172 | #define RA 26 /* note: same as T12 */ | |
5749c497 KR |
173 | #define PV 27 |
174 | #define AT 28 | |
175 | #define GP 29 | |
176 | #define SP 30 | |
177 | #define ZERO 31 | |
178 | ||
179 | #define OPCODE(X) (((X) >> 26) & 0x3f) | |
180 | #define OP_FCN(X) (((X) >> 5) & 0x7f) | |
181 | ||
182 | #ifndef FIRST_32BIT_QUADRANT | |
183 | #define FIRST_32BIT_QUADRANT 0 | |
184 | #endif | |
185 | ||
186 | int first_32bit_quadrant = FIRST_32BIT_QUADRANT; | |
187 | int base_register = FIRST_32BIT_QUADRANT ? ZERO : GP; | |
188 | ||
189 | int no_mixed_code = 0; | |
190 | int nofloats = 0; | |
191 | ||
192 | /* This array holds the chars that always start a comment. If the | |
193 | pre-processor is disabled, these aren't very useful */ | |
194 | const char comment_chars[] = "#"; | |
195 | ||
196 | /* This array holds the chars that only start a comment at the beginning of | |
197 | a line. If the line seems to have the form '# 123 filename' | |
198 | .line and .file directives will appear in the pre-processed output */ | |
199 | /* Note that input_file.c hand checks for '#' at the beginning of the | |
200 | first line of the input file. This is because the compiler outputs | |
201 | #NO_APP at the beginning of its output. */ | |
a2a1a548 | 202 | /* Also note that C style comments are always recognized. */ |
30869211 | 203 | const char line_comment_chars[] = "#!"; |
5749c497 KR |
204 | |
205 | /* Chars that can be used to separate mant from exp in floating point nums */ | |
206 | const char EXP_CHARS[] = "eE"; | |
207 | ||
208 | const char line_separator_chars[1]; | |
209 | ||
210 | /* Chars that mean this number is a floating point constant, as in | |
211 | "0f12.456" or "0d1.2345e12". */ | |
0952861c | 212 | /* @@ Do all of these really get used on the alpha?? */ |
5749c497 KR |
213 | char FLT_CHARS[] = "rRsSfFdDxXpP"; |
214 | ||
215 | /* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be | |
216 | changed in read.c. Ideally it shouldn't have to know about it at all, | |
217 | but nothing is ideal around here. */ | |
218 | ||
219 | struct reloc_data { | |
220 | expressionS exp; | |
221 | int pcrel; | |
222 | bfd_reloc_code_real_type code; | |
223 | }; | |
224 | ||
225 | /* Occasionally, two relocations will be desired for one address. | |
226 | Mainly only in cases like "jsr $r,foo" where we want both a LITUSE | |
227 | and a HINT reloc. */ | |
228 | #define MAX_RELOCS 2 | |
229 | ||
230 | struct alpha_it { | |
231 | unsigned long opcode; /* need at least 32 bits */ | |
232 | struct reloc_data reloc[MAX_RELOCS]; | |
233 | }; | |
234 | ||
c79e67a3 | 235 | static void getExpression (char *str, struct alpha_it *insn); |
5749c497 KR |
236 | static char *expr_end; |
237 | ||
238 | #define note_gpreg(R) (alpha_gprmask |= (1 << (R))) | |
239 | #define note_fpreg(R) (alpha_fprmask |= (1 << (R))) | |
240 | ||
241 | int | |
242 | tc_get_register (frame) | |
243 | int frame; | |
244 | { | |
5749c497 KR |
245 | int framereg = SP; |
246 | ||
247 | SKIP_WHITESPACE (); | |
248 | if (*input_line_pointer == '$') | |
249 | { | |
250 | input_line_pointer++; | |
251 | if (input_line_pointer[0] == 's' | |
252 | && input_line_pointer[1] == 'p') | |
253 | { | |
254 | input_line_pointer += 2; | |
255 | framereg = SP; | |
256 | } | |
257 | else | |
258 | framereg = get_absolute_expression (); | |
259 | framereg &= 31; /* ? */ | |
260 | } | |
261 | else | |
262 | as_warn ("frame reg expected, using $%d.", framereg); | |
263 | ||
264 | note_gpreg (framereg); | |
265 | return framereg; | |
266 | } | |
267 | ||
268 | static void | |
269 | s_rdata (ignore) | |
270 | int ignore; | |
271 | { | |
272 | int temp; | |
273 | ||
274 | temp = get_absolute_expression (); | |
275 | #if 0 | |
276 | if (!rdata) | |
277 | rdata = subseg_get (".rdata", 0); | |
278 | subseg_set (rdata, (subsegT) temp); | |
279 | #else | |
280 | rdata = subseg_new (".rdata", 0); | |
281 | #endif | |
282 | demand_empty_rest_of_line (); | |
283 | } | |
284 | ||
285 | static void | |
286 | s_sdata (ignore) | |
287 | int ignore; | |
288 | { | |
289 | int temp; | |
290 | ||
291 | temp = get_absolute_expression (); | |
292 | #if 0 | |
293 | if (!sdata) | |
294 | sdata = subseg_get (".sdata", 0); | |
295 | subseg_set (sdata, (subsegT) temp); | |
296 | #else | |
297 | sdata = subseg_new (".sdata", 0); | |
298 | #endif | |
299 | demand_empty_rest_of_line (); | |
300 | } | |
301 | ||
302 | static void | |
303 | s_alpha_comm (ignore) | |
304 | int ignore; | |
305 | { | |
306 | register char *name; | |
307 | register char c; | |
308 | register char *p; | |
309 | offsetT temp; | |
310 | register symbolS *symbolP; | |
311 | ||
312 | name = input_line_pointer; | |
313 | c = get_symbol_end (); | |
314 | /* just after name is now '\0' */ | |
315 | p = input_line_pointer; | |
316 | *p = c; | |
317 | SKIP_WHITESPACE (); | |
318 | /* Alpha OSF/1 compiler doesn't provide the comma, gcc does. */ | |
319 | if (*input_line_pointer == ',') | |
320 | { | |
321 | input_line_pointer++; | |
322 | SKIP_WHITESPACE (); | |
323 | } | |
324 | if ((temp = get_absolute_expression ()) < 0) | |
325 | { | |
326 | as_warn (".COMMon length (%ld.) <0! Ignored.", (long) temp); | |
327 | ignore_rest_of_line (); | |
328 | return; | |
329 | } | |
330 | *p = 0; | |
331 | symbolP = symbol_find_or_make (name); | |
332 | *p = c; | |
333 | if (S_IS_DEFINED (symbolP)) | |
334 | { | |
335 | as_bad ("Ignoring attempt to re-define symbol"); | |
336 | ignore_rest_of_line (); | |
337 | return; | |
338 | } | |
339 | if (S_GET_VALUE (symbolP)) | |
340 | { | |
341 | if (S_GET_VALUE (symbolP) != (valueT) temp) | |
342 | as_bad ("Length of .comm \"%s\" is already %ld. Not changed to %ld.", | |
343 | S_GET_NAME (symbolP), | |
344 | (long) S_GET_VALUE (symbolP), | |
345 | (long) temp); | |
346 | } | |
347 | else | |
348 | { | |
349 | S_SET_VALUE (symbolP, (valueT) temp); | |
350 | S_SET_EXTERNAL (symbolP); | |
351 | } | |
352 | ||
353 | know (symbolP->sy_frag == &zero_address_frag); | |
354 | demand_empty_rest_of_line (); | |
355 | } | |
356 | ||
5749c497 KR |
357 | arelent * |
358 | tc_gen_reloc (sec, fixp) | |
359 | asection *sec; | |
360 | fixS *fixp; | |
361 | { | |
362 | arelent *reloc; | |
5749c497 KR |
363 | |
364 | reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent)); | |
365 | reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym; | |
366 | reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; | |
367 | ||
a2a1a548 | 368 | if (fixp->fx_r_type > BFD_RELOC_UNUSED) |
5749c497 KR |
369 | abort (); |
370 | ||
371 | if (fixp->fx_r_type == BFD_RELOC_ALPHA_GPDISP_HI16) | |
372 | { | |
373 | if (!gpdisp_hi16_howto) | |
374 | gpdisp_hi16_howto = bfd_reloc_type_lookup (stdoutput, | |
375 | fixp->fx_r_type); | |
376 | reloc->howto = gpdisp_hi16_howto; | |
377 | } | |
378 | else | |
379 | reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); | |
380 | assert (reloc->howto != 0); | |
381 | if (!fixp->fx_pcrel != !reloc->howto->pc_relative) | |
382 | { | |
ade614d5 KR |
383 | as_fatal ("internal error? cannot generate `%s' relocation", |
384 | bfd_get_reloc_code_name (fixp->fx_r_type)); | |
5749c497 KR |
385 | } |
386 | assert (!fixp->fx_pcrel == !reloc->howto->pc_relative); | |
387 | ||
30869211 KR |
388 | if (fixp->fx_r_type == BFD_RELOC_ALPHA_LITERAL) |
389 | { | |
390 | /* fake out bfd_perform_relocation. sigh */ | |
391 | reloc->addend = -alpha_gp_value; | |
392 | } | |
393 | else if (reloc->howto->pc_relative && reloc->howto->pcrel_offset) | |
5749c497 KR |
394 | { |
395 | reloc->addend = fixp->fx_offset - reloc->address; | |
396 | } | |
397 | else | |
398 | reloc->addend = fixp->fx_offset; | |
399 | return reloc; | |
400 | } | |
401 | ||
402 | static void | |
403 | s_base () | |
404 | { | |
405 | if (first_32bit_quadrant) | |
406 | { | |
407 | /* not fatal, but it might not work in the end */ | |
408 | as_warn ("File overrides no-base-register option."); | |
409 | first_32bit_quadrant = 0; | |
410 | } | |
411 | ||
412 | SKIP_WHITESPACE (); | |
413 | if (*input_line_pointer == '$') | |
414 | { /* $rNN form */ | |
415 | input_line_pointer++; | |
416 | if (*input_line_pointer == 'r') | |
417 | input_line_pointer++; | |
418 | } | |
419 | ||
420 | base_register = get_absolute_expression (); | |
421 | if (base_register < 0 || base_register > 31) | |
422 | { | |
423 | base_register = GP; | |
a2a1a548 | 424 | as_warn ("Bad base register, using $%d.", base_register); |
5749c497 KR |
425 | } |
426 | demand_empty_rest_of_line (); | |
427 | } | |
428 | ||
71f9b3c0 | 429 | static int in_range_signed (val, nbits) |
aaeee550 | 430 | bfd_vma val; |
71f9b3c0 | 431 | int nbits; |
aaeee550 KR |
432 | { |
433 | /* Look at top bit of value that would be stored, figure out how it | |
434 | would be extended by the hardware, and see if that matches the | |
435 | original supplied value. */ | |
436 | bfd_vma mask; | |
437 | bfd_vma one = 1; | |
438 | bfd_vma top_bit, stored_value, missing_bits; | |
439 | ||
440 | mask = (one << nbits) - 1; | |
441 | stored_value = val & mask; | |
442 | top_bit = stored_value & (one << nbits - 1); | |
443 | missing_bits = val & ~mask; | |
71f9b3c0 KR |
444 | /* will sign-extend */ |
445 | if (top_bit) | |
aaeee550 | 446 | { |
71f9b3c0 KR |
447 | /* all remaining bits beyond mask should be one */ |
448 | missing_bits |= mask; | |
449 | return missing_bits + 1 == 0; | |
aaeee550 KR |
450 | } |
451 | else | |
452 | { | |
71f9b3c0 KR |
453 | /* all other bits should be zero */ |
454 | return missing_bits == 0; | |
aaeee550 KR |
455 | } |
456 | } | |
457 | ||
71f9b3c0 KR |
458 | #if 0 |
459 | static int in_range_unsigned (val, nbits) | |
460 | bfd_vma val; | |
461 | int nbits; | |
462 | { | |
463 | /* Look at top bit of value that would be stored, figure out how it | |
464 | would be extended by the hardware, and see if that matches the | |
465 | original supplied value. */ | |
466 | bfd_vma mask; | |
467 | bfd_vma one = 1; | |
468 | bfd_vma top_bit, stored_value, missing_bits; | |
469 | ||
470 | mask = (one << nbits) - 1; | |
471 | stored_value = val & mask; | |
472 | top_bit = stored_value & (one << nbits - 1); | |
473 | missing_bits = val & ~mask; | |
474 | return missing_bits == 0; | |
475 | } | |
476 | #endif | |
477 | ||
5749c497 KR |
478 | static void |
479 | s_gprel32 () | |
480 | { | |
481 | expressionS e; | |
482 | char *p; | |
483 | ||
484 | SKIP_WHITESPACE (); | |
485 | expression (&e); | |
486 | switch (e.X_op) | |
487 | { | |
488 | case O_constant: | |
489 | e.X_add_symbol = section_symbol (absolute_section); | |
490 | /* fall through */ | |
491 | case O_symbol: | |
492 | e.X_op = O_subtract; | |
493 | e.X_op_symbol = gp; | |
494 | break; | |
495 | default: | |
496 | abort (); | |
497 | } | |
498 | p = frag_more (4); | |
499 | memset (p, 0, 4); | |
500 | fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &e, 0, | |
501 | BFD_RELOC_GPREL32); | |
502 | } | |
503 | ||
504 | static void | |
40cd35ff KR |
505 | create_literal_section (secp, name) |
506 | segT *secp; | |
507 | const char *name; | |
5749c497 KR |
508 | { |
509 | segT current_section = now_seg; | |
510 | int current_subsec = now_subseg; | |
40cd35ff | 511 | segT new_sec; |
5749c497 | 512 | |
40cd35ff | 513 | *secp = new_sec = subseg_new (name, 0); |
5749c497 | 514 | subseg_set (current_section, current_subsec); |
40cd35ff KR |
515 | bfd_set_section_alignment (stdoutput, new_sec, 3); |
516 | bfd_set_section_flags (stdoutput, new_sec, | |
5749c497 KR |
517 | SEC_RELOC | SEC_ALLOC | SEC_LOAD | SEC_READONLY |
518 | | SEC_DATA); | |
40cd35ff KR |
519 | } |
520 | ||
40cd35ff KR |
521 | static valueT |
522 | get_lit8_offset (val) | |
523 | bfd_vma val; | |
524 | { | |
525 | valueT retval; | |
526 | if (lit8_sec == 0) | |
527 | { | |
528 | create_literal_section (&lit8_sec, ".lit8"); | |
529 | lit8_sym = section_symbol (lit8_sec); | |
530 | } | |
531 | retval = add_to_literal_pool ((symbolS *) 0, val, lit8_sec, 8); | |
532 | if (retval >= 0xfff0) | |
533 | as_fatal ("overflow in fp literal (.lit8) table"); | |
534 | return retval; | |
535 | } | |
536 | ||
537 | static valueT | |
538 | get_lit4_offset (val) | |
539 | bfd_vma val; | |
540 | { | |
541 | valueT retval; | |
542 | if (lit4_sec == 0) | |
543 | { | |
544 | create_literal_section (&lit4_sec, ".lit4"); | |
545 | lit4_sym = section_symbol (lit4_sec); | |
546 | } | |
547 | retval = add_to_literal_pool ((symbolS *) 0, val, lit4_sec, 4); | |
548 | if (retval >= 0xfff0) | |
549 | as_fatal ("overflow in fp literal (.lit4) table"); | |
550 | return retval; | |
5749c497 KR |
551 | } |
552 | ||
50c551d0 | 553 | static struct alpha_it clear_insn; |
5749c497 | 554 | |
50c551d0 KR |
555 | /* This function is called once, at assembler startup time. It should |
556 | set up all the tables, etc. that the MD part of the assembler will | |
557 | need, that can be determined before arguments are parsed. */ | |
558 | void | |
559 | md_begin () | |
0952861c | 560 | { |
50c551d0 KR |
561 | const char *retval, *name; |
562 | unsigned int i = 0; | |
0952861c | 563 | |
50c551d0 | 564 | op_hash = hash_new (); |
0952861c | 565 | |
50c551d0 KR |
566 | for (i = 0; i < NUMOPCODES; ) |
567 | { | |
568 | const char *name = alpha_opcodes[i].name; | |
569 | retval = hash_insert (op_hash, name, (PTR) &alpha_opcodes[i]); | |
5749c497 | 570 | if (retval) |
0952861c | 571 | as_fatal ("internal error: can't hash opcode `%s': %s", |
50c551d0 | 572 | name, retval); |
0952861c | 573 | |
5749c497 | 574 | do |
50c551d0 KR |
575 | i++; |
576 | while (i < NUMOPCODES | |
577 | && (alpha_opcodes[i].name == name | |
578 | || !strcmp (alpha_opcodes[i].name, name))); | |
5749c497 KR |
579 | } |
580 | /* Some opcodes include modifiers of various sorts with a "/mod" | |
581 | syntax, like the architecture documentation suggests. However, | |
582 | for use with gcc at least, we also need to access those same | |
583 | opcodes without the "/". */ | |
50c551d0 | 584 | for (i = 0; i < NUMOPCODES; ) |
5749c497 | 585 | { |
50c551d0 | 586 | name = alpha_opcodes[i].name; |
0952861c | 587 | |
5749c497 KR |
588 | if (strchr (name, '/')) |
589 | { | |
50c551d0 KR |
590 | char *p = xmalloc (strlen (name)); |
591 | const char *q = name; | |
592 | char *q2 = p; | |
593 | ||
594 | for (; *q; q++) | |
595 | if (*q /= '/') | |
596 | *q2++ = *q; | |
597 | ||
598 | *q2++ = 0; | |
599 | retval = hash_insert (op_hash, p, (PTR) &alpha_opcodes[i]); | |
0952861c KR |
600 | /* Ignore failures -- the opcode table does duplicate some |
601 | variants in different forms, like "hw_stq" and "hw_st/q". | |
50c551d0 KR |
602 | Maybe the variants can be eliminated, and this error |
603 | checking restored. */ | |
5749c497 | 604 | } |
0952861c | 605 | |
5749c497 | 606 | do |
50c551d0 KR |
607 | i++; |
608 | while (i < NUMOPCODES | |
609 | && (alpha_opcodes[i].name == name | |
610 | || !strcmp (alpha_opcodes[i].name, name))); | |
0952861c | 611 | } |
5749c497 KR |
612 | |
613 | lituse_basereg.X_op = O_constant; | |
614 | lituse_basereg.X_add_number = 1; | |
615 | lituse_byteoff.X_op = O_constant; | |
616 | lituse_byteoff.X_add_number = 2; | |
617 | lituse_jsr.X_op = O_constant; | |
618 | lituse_jsr.X_add_number = 3; | |
619 | ||
620 | /* So .sbss will get used for tiny objects. */ | |
621 | bfd_set_gp_size (stdoutput, 8); | |
71f9b3c0 | 622 | create_literal_section (&lita_sec, ".lita"); |
5749c497 KR |
623 | /* For handling the GP, create a symbol that won't be output in the |
624 | symbol table. We'll edit it out of relocs later. */ | |
fd4f335c | 625 | gp = symbol_create ("<GP value>", lita_sec, 0x8000, &zero_address_frag); |
aaeee550 KR |
626 | |
627 | memset (&clear_insn, 0, sizeof (clear_insn)); | |
628 | for (i = 0; i < MAX_RELOCS; i++) | |
629 | clear_insn.reloc[i].code = BFD_RELOC_NONE; | |
5749c497 KR |
630 | } |
631 | ||
632 | int optnum = 1; | |
633 | ||
0952861c KR |
634 | static void |
635 | emit_insn (insn) | |
636 | struct alpha_it *insn; | |
637 | { | |
638 | char *toP; | |
639 | int j; | |
640 | ||
641 | toP = frag_more (4); | |
642 | ||
643 | /* put out the opcode */ | |
644 | md_number_to_chars (toP, insn->opcode, 4); | |
645 | ||
646 | /* put out the symbol-dependent stuff */ | |
647 | for (j = 0; j < MAX_RELOCS; j++) | |
648 | { | |
649 | struct reloc_data *r = &insn->reloc[j]; | |
650 | fixS *f; | |
651 | ||
652 | if (r->code != BFD_RELOC_NONE) | |
653 | { | |
654 | if (r->exp.X_op == O_constant) | |
655 | { | |
656 | r->exp.X_add_symbol = section_symbol (absolute_section); | |
657 | r->exp.X_op = O_symbol; | |
658 | } | |
659 | f = fix_new_exp (frag_now, (toP - frag_now->fr_literal), 4, | |
660 | &r->exp, r->pcrel, r->code); | |
661 | } | |
662 | if (r->code == BFD_RELOC_ALPHA_GPDISP_LO16) | |
663 | { | |
664 | static bit_fixS cookie; | |
665 | /* @@ This'll make the range checking in write.c shut up. */ | |
666 | f->fx_bit_fixP = &cookie; | |
667 | } | |
668 | } | |
669 | } | |
670 | ||
5749c497 KR |
671 | void |
672 | md_assemble (str) | |
673 | char *str; | |
674 | { | |
0952861c | 675 | int i, count; |
5749c497 KR |
676 | #define MAX_INSNS 5 |
677 | struct alpha_it insns[MAX_INSNS]; | |
678 | ||
679 | count = alpha_ip (str, insns); | |
680 | if (count <= 0) | |
681 | return; | |
682 | ||
683 | for (i = 0; i < count; i++) | |
0952861c | 684 | emit_insn (&insns[i]); |
5749c497 KR |
685 | } |
686 | ||
40cd35ff KR |
687 | static inline void |
688 | maybe_set_gp (sec) | |
689 | asection *sec; | |
690 | { | |
691 | bfd_vma vma; | |
692 | if (!sec) | |
693 | return; | |
694 | vma = bfd_get_section_vma (foo, sec); | |
695 | if (vma && vma < alpha_gp_value) | |
696 | alpha_gp_value = vma; | |
697 | } | |
698 | ||
5749c497 KR |
699 | static void |
700 | select_gp_value () | |
701 | { | |
c79e67a3 KR |
702 | if (alpha_gp_value != 0) |
703 | abort (); | |
704 | ||
40cd35ff KR |
705 | /* Get minus-one in whatever width... */ |
706 | alpha_gp_value = 0; alpha_gp_value--; | |
707 | ||
708 | /* Select the smallest VMA of these existing sections. */ | |
709 | maybe_set_gp (lita_sec); | |
710 | /* maybe_set_gp (sdata); Was disabled before -- should we use it? */ | |
5749c497 | 711 | #if 0 |
40cd35ff KR |
712 | maybe_set_gp (lit8_sec); |
713 | maybe_set_gp (lit4_sec); | |
5749c497 | 714 | #endif |
5749c497 | 715 | |
c79e67a3 | 716 | alpha_gp_value += GP_ADJUSTMENT; |
5749c497 | 717 | |
c79e67a3 | 718 | S_SET_VALUE (gp, alpha_gp_value); |
5749c497 KR |
719 | |
720 | #ifdef DEBUG1 | |
c79e67a3 | 721 | printf ("Chose GP value of %lx\n", alpha_gp_value); |
5749c497 | 722 | #endif |
5749c497 KR |
723 | } |
724 | ||
725 | int | |
726 | alpha_force_relocation (f) | |
727 | fixS *f; | |
728 | { | |
729 | switch (f->fx_r_type) | |
730 | { | |
731 | case BFD_RELOC_ALPHA_GPDISP_HI16: | |
732 | case BFD_RELOC_ALPHA_GPDISP_LO16: | |
733 | case BFD_RELOC_ALPHA_LITERAL: | |
734 | case BFD_RELOC_ALPHA_LITUSE: | |
735 | case BFD_RELOC_GPREL32: | |
736 | return 1; | |
737 | case BFD_RELOC_ALPHA_HINT: | |
738 | case BFD_RELOC_64: | |
739 | case BFD_RELOC_32: | |
740 | case BFD_RELOC_16: | |
741 | case BFD_RELOC_8: | |
742 | case BFD_RELOC_23_PCREL_S2: | |
743 | case BFD_RELOC_14: | |
0952861c | 744 | case BFD_RELOC_26: |
5749c497 KR |
745 | return 0; |
746 | default: | |
747 | abort (); | |
748 | return 0; | |
749 | } | |
750 | } | |
751 | ||
752 | int | |
753 | alpha_fix_adjustable (f) | |
754 | fixS *f; | |
755 | { | |
756 | /* Are there any relocation types for which we must generate a reloc | |
757 | but we can adjust the values contained within it? */ | |
758 | switch (f->fx_r_type) | |
759 | { | |
760 | case BFD_RELOC_ALPHA_GPDISP_HI16: | |
761 | case BFD_RELOC_ALPHA_GPDISP_LO16: | |
762 | return 0; | |
763 | case BFD_RELOC_GPREL32: | |
764 | return 1; | |
a2a1a548 ILT |
765 | default: |
766 | return !alpha_force_relocation (f); | |
5749c497 | 767 | } |
a2a1a548 | 768 | /*NOTREACHED*/ |
5749c497 KR |
769 | } |
770 | ||
4a6e1a39 | 771 | valueT |
5749c497 KR |
772 | md_section_align (seg, size) |
773 | segT seg; | |
4a6e1a39 | 774 | valueT size; |
5749c497 KR |
775 | { |
776 | #ifdef OBJ_ECOFF | |
777 | /* This should probably be handled within BFD, or by pulling the | |
778 | number from BFD at least. */ | |
779 | #define MIN 15 | |
780 | size += MIN; | |
781 | size &= ~MIN; | |
782 | #endif | |
783 | return size; | |
784 | } | |
785 | ||
786 | /* Add this thing to the .lita section and produce a LITERAL reloc referring | |
0952861c | 787 | to it. */ |
5749c497 | 788 | |
0952861c KR |
789 | /* Are we currently eligible to emit a LITUSE reloc for the literal |
790 | references just generated? */ | |
791 | static int lituse_pending; | |
5749c497 KR |
792 | |
793 | static void | |
794 | load_symbol_address (reg, insn) | |
795 | int reg; | |
796 | struct alpha_it *insn; | |
797 | { | |
798 | static symbolS *lita_sym; | |
799 | ||
800 | int x; | |
5749c497 | 801 | valueT retval; |
5749c497 KR |
802 | |
803 | if (!lita_sym) | |
804 | { | |
805 | lita_sym = section_symbol (lita_sec); | |
806 | S_CLEAR_EXTERNAL (lita_sym); | |
807 | } | |
808 | ||
809 | retval = add_to_literal_pool (insn->reloc[0].exp.X_add_symbol, | |
810 | insn->reloc[0].exp.X_add_number, | |
811 | lita_sec, 8); | |
812 | ||
5749c497 KR |
813 | /* Now emit a LITERAL relocation for the original section. */ |
814 | insn->reloc[0].exp.X_op = O_symbol; | |
815 | insn->reloc[0].exp.X_add_symbol = lita_sym; | |
816 | insn->reloc[0].exp.X_add_number = retval; | |
817 | insn->reloc[0].code = BFD_RELOC_ALPHA_LITERAL; | |
0952861c | 818 | lituse_pending = 1; |
5749c497 KR |
819 | |
820 | if (retval == 0x8000) | |
821 | /* Overflow? */ | |
822 | as_fatal ("overflow in literal (.lita) table"); | |
823 | x = retval; | |
cf272f02 KR |
824 | if (addr32) |
825 | insn->opcode = (0xa0000000 /* ldl */ | |
826 | | (reg << SA) | |
827 | | (base_register << SB) | |
828 | | (x & 0xffff)); | |
829 | else | |
830 | insn->opcode = (0xa4000000 /* ldq */ | |
831 | | (reg << SA) | |
832 | | (base_register << SB) | |
833 | | (x & 0xffff)); | |
5749c497 KR |
834 | note_gpreg (base_register); |
835 | } | |
836 | ||
837 | /* To load an address with a single instruction, | |
838 | emit a LITERAL reloc in this section, and a REFQUAD | |
839 | for the .lita section, so that we'll be able to access | |
840 | it via $gp: | |
841 | lda REG, xx -> ldq REG, -32752(gp) | |
842 | lda REG, xx+4 -> ldq REG, -32752(gp) | |
843 | lda REG, 4(REG) | |
844 | ||
845 | The offsets need to start near -0x8000, and the generated LITERAL | |
846 | relocations should negate the offset. I don't completely grok the | |
847 | scheme yet. */ | |
848 | ||
849 | static int | |
850 | load_expression (reg, insn) | |
851 | int reg; | |
852 | struct alpha_it *insn; | |
853 | { | |
a2a1a548 | 854 | valueT addend, addendhi, addendlo; |
5749c497 KR |
855 | int num_insns = 1; |
856 | ||
40cd35ff KR |
857 | if (insn->reloc[0].exp.X_add_symbol->bsym->flags & BSF_SECTION_SYM) |
858 | { | |
859 | addend = 0; | |
860 | } | |
861 | else | |
862 | { | |
863 | addend = insn->reloc[0].exp.X_add_number; | |
864 | insn->reloc[0].exp.X_add_number = 0; | |
865 | } | |
5749c497 KR |
866 | load_symbol_address (reg, insn); |
867 | if (addend) | |
868 | { | |
a2a1a548 ILT |
869 | if ((addend & ~0x7fffffff) != 0 |
870 | && (addend & ~0x7fffffff) + 0x80000000 != 0) | |
871 | { | |
872 | as_bad ("assembler not prepared to handle constants >32 bits yet"); | |
873 | addend = 0; | |
874 | } | |
875 | addendlo = addend & 0xffff; | |
876 | addend -= addendlo; | |
877 | addendhi = addend >> 16; | |
878 | if (addendlo & 0x8000) | |
879 | addendhi++; | |
880 | /* It appears that the BASEREG LITUSE reloc should not be used on | |
881 | an LDAH instruction. */ | |
882 | if (addendlo) | |
883 | { | |
884 | insn[1].opcode = (0x20000000 /* lda */ | |
885 | | (reg << SA) | |
886 | | (reg << SB) | |
887 | | (addendlo & 0xffff)); | |
888 | insn[1].reloc[0].code = BFD_RELOC_ALPHA_LITUSE; | |
889 | insn[1].reloc[0].exp = lituse_basereg; | |
890 | num_insns++; | |
891 | } | |
892 | if (addendhi) | |
893 | { | |
894 | insn[num_insns].opcode = (0x24000000 | |
895 | | (reg << SA) | |
896 | | (reg << SB) | |
897 | | (addendhi & 0xffff)); | |
898 | num_insns++; | |
899 | } | |
900 | if (num_insns == 1) | |
901 | abort (); | |
0952861c | 902 | lituse_pending = 0; |
5749c497 KR |
903 | } |
904 | return num_insns; | |
905 | } | |
906 | ||
c79e67a3 | 907 | static inline void |
5749c497 KR |
908 | getExpression (str, this_insn) |
909 | char *str; | |
910 | struct alpha_it *this_insn; | |
911 | { | |
912 | char *save_in; | |
913 | segT seg; | |
914 | ||
915 | #if 0 /* Not converted to bfd yet, and I don't think we need them | |
916 | for ECOFF. Re-adding a.out support will probably require | |
917 | them though. */ | |
918 | static const struct am { | |
919 | char *name; | |
920 | bfd_reloc_code_real_type reloc; | |
921 | } macro[] = { | |
922 | { "hi", RELOC_48_63 }, | |
923 | { "lo", RELOC_0_15 }, | |
924 | { "ml", RELOC_16_31 }, | |
925 | { "mh", RELOC_32_47 }, | |
926 | { "uhi", RELOC_U_48_63 }, | |
927 | { "uml", RELOC_U_16_31 }, | |
928 | { "umh", RELOC_U_32_47 }, | |
929 | { 0, } | |
930 | }; | |
931 | ||
932 | /* Handle macros: "%macroname(expr)" */ | |
933 | if (*str == '%') | |
934 | { | |
935 | struct am *m; | |
936 | char *p, *q; | |
937 | ||
938 | str++; | |
939 | m = ¯o[0]; | |
940 | while (q = m->name) | |
941 | { | |
942 | p = str; | |
943 | while (*q && *p == *q) | |
944 | p++, q++; | |
945 | if (*q == 0) | |
946 | break; | |
947 | m++; | |
948 | } | |
949 | if (q) | |
950 | { | |
951 | str = p; /* keep the '(' */ | |
952 | this_insn->reloc = m->reloc; | |
953 | } | |
954 | } | |
955 | #endif | |
956 | ||
957 | save_in = input_line_pointer; | |
958 | input_line_pointer = str; | |
959 | ||
960 | seg = expression (&this_insn->reloc[0].exp); | |
961 | /* XXX validate seg and exp, make sure they're reasonable */ | |
962 | expr_end = input_line_pointer; | |
963 | input_line_pointer = save_in; | |
5749c497 KR |
964 | } |
965 | ||
0952861c KR |
966 | static void |
967 | emit_unaligned_io (dir, addr_reg, addr_offset, reg) | |
968 | char *dir; | |
969 | int addr_reg, reg; | |
970 | valueT addr_offset; | |
971 | { | |
972 | char buf[90]; | |
973 | sprintf (buf, "%sq_u $%d,%ld($%d)", dir, reg, (long) addr_offset, addr_reg); | |
974 | md_assemble (buf); | |
975 | } | |
976 | ||
977 | static void | |
978 | emit_load_unal (addr_reg, addr_offset, reg) | |
979 | int addr_reg, reg; | |
980 | valueT addr_offset; | |
981 | { | |
982 | emit_unaligned_io ("ld", addr_reg, addr_offset, reg); | |
983 | } | |
984 | ||
985 | static void | |
986 | emit_store_unal (addr_reg, addr_offset, reg) | |
987 | int addr_reg, reg; | |
988 | valueT addr_offset; | |
989 | { | |
990 | emit_unaligned_io ("st", addr_reg, addr_offset, reg); | |
991 | } | |
992 | ||
993 | static void | |
994 | emit_byte_manip_r (op, in, mask, out, mode, which) | |
995 | char *op; | |
a2a1a548 | 996 | int in, mask, out, mode, which; |
0952861c KR |
997 | { |
998 | char buf[90]; | |
999 | sprintf (buf, "%s%c%c $%d,$%d,$%d", op, mode, which, in, mask, out); | |
1000 | md_assemble (buf); | |
1001 | } | |
1002 | ||
1003 | static void | |
1004 | emit_extract_r (in, mask, out, mode, which) | |
a2a1a548 | 1005 | int in, mask, out, mode, which; |
0952861c KR |
1006 | { |
1007 | emit_byte_manip_r ("ext", in, mask, out, mode, which); | |
1008 | } | |
1009 | ||
1010 | static void | |
1011 | emit_insert_r (in, mask, out, mode, which) | |
a2a1a548 | 1012 | int in, mask, out, mode, which; |
0952861c KR |
1013 | { |
1014 | emit_byte_manip_r ("ins", in, mask, out, mode, which); | |
1015 | } | |
1016 | ||
1017 | static void | |
1018 | emit_mask_r (in, mask, out, mode, which) | |
a2a1a548 | 1019 | int in, mask, out, mode, which; |
0952861c KR |
1020 | { |
1021 | emit_byte_manip_r ("msk", in, mask, out, mode, which); | |
1022 | } | |
1023 | ||
1024 | static void | |
1025 | emit_sign_extend (reg, size) | |
a2a1a548 | 1026 | int reg, size; |
0952861c KR |
1027 | { |
1028 | char buf[90]; | |
1029 | sprintf (buf, "sll $%d,0x%x,$%d", reg, 64 - size, reg); | |
1030 | md_assemble (buf); | |
1031 | sprintf (buf, "sra $%d,0x%x,$%d", reg, 64 - size, reg); | |
1032 | md_assemble (buf); | |
1033 | } | |
1034 | ||
1035 | static void | |
1036 | emit_bis_r (in1, in2, out) | |
a2a1a548 | 1037 | int in1, in2, out; |
0952861c KR |
1038 | { |
1039 | char buf[90]; | |
1040 | sprintf (buf, "bis $%d,$%d,$%d", in1, in2, out); | |
1041 | md_assemble (buf); | |
1042 | } | |
1043 | ||
aaeee550 KR |
1044 | static int |
1045 | build_mem (opc, ra, rb, disp) | |
1046 | int opc, ra, rb; | |
1047 | bfd_signed_vma disp; | |
1048 | { | |
aaeee550 KR |
1049 | if ((disp >> 15) != 0 |
1050 | && (disp >> 15) + 1 != 0) | |
1051 | abort (); | |
1052 | return ((opc << 26) | (ra << SA) | (rb << SB) | (disp & 0xffff)); | |
1053 | } | |
1054 | ||
1055 | static int | |
1056 | build_operate_n (opc, fn, ra, lit, rc) | |
1057 | int opc, fn, ra, rc; | |
1058 | int lit; | |
1059 | { | |
1060 | if (lit & ~0xff) | |
1061 | abort (); | |
1062 | return ((opc << 26) | (fn << 5) | (ra << SA) | (lit << SN) | (1 << 12) | (rc << SC)); | |
1063 | } | |
1064 | ||
1065 | static void | |
1066 | emit_sll_n (dest, disp, src) | |
1067 | int dest, disp, src; | |
1068 | { | |
1069 | struct alpha_it insn = clear_insn; | |
1070 | insn.opcode = build_operate_n (0x12, 0x39, src, disp, dest); | |
1071 | emit_insn (&insn); | |
1072 | } | |
1073 | ||
1074 | static void | |
1075 | emit_ldah_num (dest, addend, src) | |
1076 | int dest, src; | |
1077 | bfd_vma addend; | |
1078 | { | |
1079 | struct alpha_it insn = clear_insn; | |
1080 | insn.opcode = build_mem (0x09, dest, src, addend); | |
1081 | emit_insn (&insn); | |
1082 | } | |
1083 | ||
1084 | static void | |
1085 | emit_addq_r (in1, in2, out) | |
1086 | int in1, in2, out; | |
1087 | { | |
1088 | struct alpha_it insn = clear_insn; | |
1089 | insn.opcode = 0x40000400 | (in1 << SA) | (in2 << SB) | (out << SC); | |
1090 | emit_insn (&insn); | |
1091 | } | |
1092 | ||
1093 | static void | |
1094 | emit_lda_n (dest, addend, src) | |
1095 | int dest, src; | |
1096 | bfd_vma addend; | |
1097 | { | |
1098 | struct alpha_it insn = clear_insn; | |
1099 | insn.opcode = build_mem (0x08, dest, src, addend); | |
1100 | emit_insn (&insn); | |
1101 | } | |
1102 | ||
1103 | static void | |
1104 | emit_add64 (in, out, num) | |
1105 | int in, out; | |
1106 | bfd_vma num; | |
1107 | { | |
1108 | bfd_signed_vma snum = num; | |
1109 | ||
71f9b3c0 | 1110 | if (in_range_signed (num, 16)) |
aaeee550 KR |
1111 | { |
1112 | emit_lda_n (out, num, in); | |
1113 | return; | |
1114 | } | |
1115 | if ((num & 0xffff) == 0 | |
1116 | && in == ZERO | |
71f9b3c0 | 1117 | && in_range_signed (snum >> 16, 16)) |
aaeee550 KR |
1118 | { |
1119 | emit_ldah_num (out, snum >> 16, in); | |
1120 | return; | |
1121 | } | |
ade614d5 | 1122 | /* I'm not sure this one is getting invoked when it could. */ |
aaeee550 KR |
1123 | if ((num & 1) == 0 && in == ZERO) |
1124 | { | |
71f9b3c0 | 1125 | if (in_range_signed (snum >> 1, 16)) |
aaeee550 KR |
1126 | { |
1127 | emit_lda_n (out, snum >> 1, in); | |
1128 | emit_addq_r (out, out, out); | |
1129 | return; | |
1130 | } | |
1131 | else if (num & 0x1fffe == 0 | |
71f9b3c0 | 1132 | && in_range_signed (snum >> 17, 16)) |
aaeee550 KR |
1133 | { |
1134 | emit_ldah_num (out, snum >> 17, in); | |
1135 | emit_addq_r (out, out, out); | |
1136 | return; | |
1137 | } | |
1138 | } | |
71f9b3c0 | 1139 | if (in_range_signed (num, 32)) |
aaeee550 KR |
1140 | { |
1141 | bfd_vma lo = num & 0xffff; | |
1142 | if (lo & 0x8000) | |
1143 | lo -= 0x10000; | |
1144 | num -= lo; | |
1145 | emit_ldah_num (out, snum >> 16, in); | |
1146 | if (lo) | |
1147 | emit_lda_n (out, lo, out); | |
1148 | return; | |
1149 | } | |
1150 | ||
1151 | if (in != ZERO && in != AT && out != AT && at_ok) | |
1152 | { | |
1153 | emit_add64 (ZERO, AT, num); | |
1154 | emit_addq_r (AT, in, out); | |
1155 | return; | |
1156 | } | |
1157 | ||
1158 | if (in != ZERO) | |
1159 | as_bad ("load expression too complex to expand"); | |
1160 | ||
1161 | /* Could check also for loading 16- or 32-bit value and shifting by | |
1162 | arbitrary displacement. */ | |
1163 | ||
1164 | { | |
1165 | bfd_vma lo = snum & 0xffffffff; | |
1166 | if (lo & 0x80000000) | |
1167 | lo -= ((bfd_vma)0x10000000 << 4); | |
1168 | snum -= lo; | |
aaeee550 KR |
1169 | emit_add64 (ZERO, out, snum >> 32); |
1170 | emit_sll_n (out, 32, out); | |
1171 | if (lo != 0) | |
1172 | emit_add64 (out, out, lo); | |
1173 | } | |
1174 | } | |
1175 | ||
5749c497 KR |
1176 | static int |
1177 | alpha_ip (str, insns) | |
1178 | char *str; | |
1179 | struct alpha_it insns[]; | |
1180 | { | |
1181 | char *s; | |
1182 | const char *args; | |
1183 | char c; | |
1184 | unsigned long i; | |
1185 | struct alpha_opcode *pattern; | |
1186 | char *argsStart; | |
1187 | unsigned int opcode; | |
1188 | unsigned int mask; | |
1189 | int match = 0, num_gen = 1; | |
1190 | int comma = 0; | |
71f9b3c0 KR |
1191 | int do_add64, add64_in, add64_out; |
1192 | bfd_vma add64_addend; | |
5749c497 KR |
1193 | |
1194 | for (s = str; | |
1195 | islower (*s) || *s == '_' || *s == '/' || *s == '4' || *s == '8'; | |
1196 | ++s) | |
1197 | ; | |
1198 | switch (*s) | |
1199 | { | |
1200 | ||
1201 | case '\0': | |
1202 | break; | |
1203 | ||
1204 | case ',': | |
1205 | comma = 1; | |
1206 | ||
1207 | /*FALLTHROUGH*/ | |
1208 | ||
1209 | case ' ': | |
1210 | *s++ = '\0'; | |
1211 | break; | |
1212 | ||
1213 | default: | |
3a443b1e | 1214 | as_fatal ("Unknown opcode: `%s'", str); |
5749c497 KR |
1215 | } |
1216 | if ((pattern = (struct alpha_opcode *) hash_find (op_hash, str)) == NULL) | |
1217 | { | |
71f9b3c0 | 1218 | as_bad ("Unknown opcode: `%s'", str); |
5749c497 KR |
1219 | return -1; |
1220 | } | |
1221 | if (comma) | |
1222 | *--s = ','; | |
1223 | ||
1224 | argsStart = s; | |
1225 | for (;;) | |
1226 | { | |
71f9b3c0 | 1227 | do_add64 = 0; |
5749c497 KR |
1228 | opcode = pattern->match; |
1229 | num_gen = 1; | |
aaeee550 KR |
1230 | for (i = 0; i < MAX_INSNS; i++) |
1231 | insns[i] = clear_insn; | |
5749c497 KR |
1232 | |
1233 | /* Build the opcode, checking as we go to make sure that the | |
1234 | operands match. */ | |
1235 | for (args = pattern->args;; ++args) | |
1236 | { | |
1237 | switch (*args) | |
1238 | { | |
1239 | ||
1240 | case '\0': /* end of args */ | |
1241 | if (*s == '\0') | |
1242 | { | |
1243 | match = 1; | |
1244 | } | |
1245 | break; | |
1246 | ||
1247 | case '+': | |
1248 | if (*s == '+') | |
1249 | { | |
1250 | ++s; | |
1251 | continue; | |
1252 | } | |
1253 | if (*s == '-') | |
1254 | { | |
1255 | continue; | |
1256 | } | |
1257 | break; | |
1258 | ||
1259 | case '(': /* these must match exactly */ | |
1260 | case ')': | |
1261 | case ',': | |
1262 | case ' ': | |
1263 | case '0': | |
1264 | if (*s++ == *args) | |
1265 | continue; | |
1266 | break; | |
1267 | ||
1268 | case '1': /* next operand must be a register */ | |
1269 | case '2': | |
1270 | case '3': | |
1271 | case 'r': | |
1272 | case 'R': | |
1273 | if (*s++ == '$') | |
1274 | { | |
1275 | switch (c = *s++) | |
1276 | { | |
1277 | ||
1278 | case 'a': /* $at: as temporary */ | |
1279 | if (*s++ != 't') | |
1280 | goto error; | |
1281 | mask = AT; | |
1282 | break; | |
1283 | ||
1284 | case 'g': /* $gp: base register */ | |
1285 | if (*s++ != 'p') | |
1286 | goto error; | |
1287 | mask = base_register; | |
1288 | break; | |
1289 | ||
1290 | case 's': /* $sp: stack pointer */ | |
1291 | if (*s++ != 'p') | |
1292 | goto error; | |
1293 | mask = SP; | |
1294 | break; | |
1295 | ||
1296 | ||
1297 | case 'r': /* any register */ | |
1298 | if (!isdigit (c = *s++)) | |
1299 | { | |
1300 | goto error; | |
1301 | } | |
1302 | /* FALLTHROUGH */ | |
1303 | case '0': | |
1304 | case '1': | |
1305 | case '2': | |
1306 | case '3': | |
1307 | case '4': | |
1308 | case '5': | |
1309 | case '6': | |
1310 | case '7': | |
1311 | case '8': | |
1312 | case '9': | |
1313 | if (isdigit (*s)) | |
1314 | { | |
1315 | if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32) | |
1316 | { | |
1317 | goto error; | |
1318 | } | |
1319 | } | |
1320 | else | |
1321 | { | |
1322 | c -= '0'; | |
1323 | } | |
1324 | if ((c == GP) && first_32bit_quadrant) | |
1325 | c = ZERO; | |
1326 | ||
1327 | mask = c; | |
1328 | break; | |
1329 | ||
1330 | default: | |
1331 | goto error; | |
1332 | } | |
1333 | note_gpreg (mask); | |
1334 | /* Got the register, now figure out where it goes in | |
1335 | the opcode. */ | |
1336 | doregister: | |
1337 | switch (*args) | |
1338 | { | |
1339 | ||
1340 | case '1': | |
1341 | case 'e': | |
1342 | opcode |= mask << SA; | |
1343 | continue; | |
1344 | ||
1345 | case '2': | |
1346 | case 'f': | |
1347 | opcode |= mask << SB; | |
1348 | continue; | |
1349 | ||
1350 | case '3': | |
1351 | case 'g': | |
1352 | opcode |= mask; | |
1353 | continue; | |
1354 | ||
1355 | case 'r': | |
1356 | opcode |= (mask << SA) | mask; | |
1357 | continue; | |
1358 | ||
1359 | case 'R': /* ra and rb are the same */ | |
1360 | opcode |= (mask << SA) | (mask << SB); | |
1361 | continue; | |
1362 | ||
1363 | case 'E': | |
1364 | opcode |= (mask << SA) | (mask << SB) | (mask); | |
1365 | continue; | |
1366 | } | |
1367 | } | |
1368 | break; | |
1369 | ||
1370 | case 'e': /* next operand is a floating point register */ | |
1371 | case 'f': | |
1372 | case 'g': | |
1373 | case 'E': | |
1374 | if (*s++ == '$' && *s++ == 'f' && isdigit (*s)) | |
1375 | { | |
1376 | mask = *s++; | |
1377 | if (isdigit (*s)) | |
1378 | { | |
1379 | mask = 10 * (mask - '0') + (*s++ - '0'); | |
1380 | if (mask >= 32) | |
1381 | { | |
1382 | break; | |
1383 | } | |
1384 | } | |
1385 | else | |
1386 | { | |
1387 | mask -= '0'; | |
1388 | } | |
1389 | note_fpreg (mask); | |
1390 | /* same encoding as gp registers */ | |
1391 | goto doregister; | |
1392 | } | |
1393 | break; | |
1394 | ||
1395 | #if 0 | |
1396 | case 'h': /* bits 16..31 */ | |
1397 | insns[0].reloc = RELOC_16_31; | |
1398 | goto immediate; | |
1399 | #endif | |
1400 | ||
1401 | case 'l': /* bits 0..15 */ | |
1402 | insns[0].reloc[0].code = BFD_RELOC_16; | |
1403 | goto immediate; | |
1404 | ||
1405 | case 'L': /* 21 bit PC relative immediate */ | |
1406 | insns[0].reloc[0].code = BFD_RELOC_23_PCREL_S2; | |
1407 | insns[0].reloc[0].pcrel = 1; | |
1408 | goto immediate; | |
1409 | ||
1410 | case 'i': /* 14 bit immediate */ | |
1411 | if (OPCODE (opcode) != 0x1a) | |
1412 | /* Not a jmp variant?? */ | |
1413 | abort (); | |
1414 | else if (opcode & 0x8000) | |
1415 | /* ret or jsr_coroutine */ | |
1416 | { | |
1417 | insns[0].reloc[0].code = BFD_RELOC_14; | |
1418 | insns[0].reloc[0].pcrel = 0; | |
1419 | } | |
1420 | else | |
1421 | /* jmp or jsr */ | |
1422 | { | |
1423 | insns[0].reloc[0].code = BFD_RELOC_ALPHA_HINT; | |
1424 | insns[0].reloc[0].pcrel = 1; | |
1425 | } | |
1426 | goto immediate; | |
1427 | ||
1428 | case 'b': /* 8 bit immediate */ | |
1429 | insns[0].reloc[0].code = BFD_RELOC_8; | |
1430 | goto immediate; | |
1431 | ||
0952861c KR |
1432 | case 'I': /* 26 bit immediate, for PALcode */ |
1433 | insns[0].reloc[0].code = BFD_RELOC_26; | |
1434 | goto immediate; | |
1435 | ||
71f9b3c0 KR |
1436 | case 't': /* 12 bit displacement, for PALcode */ |
1437 | insns[0].reloc[0].code = BFD_RELOC_12_PCREL; | |
5749c497 KR |
1438 | goto immediate; |
1439 | ||
1440 | case '8': /* 8 bit 0...7 */ | |
71f9b3c0 | 1441 | insns[0].reloc[0].code = BFD_RELOC_8; |
5749c497 KR |
1442 | goto immediate; |
1443 | ||
5749c497 KR |
1444 | immediate: |
1445 | if (*s == ' ') | |
1446 | s++; | |
c79e67a3 | 1447 | getExpression (s, &insns[0]); |
5749c497 KR |
1448 | s = expr_end; |
1449 | /* Handle overflow in certain instructions by converting | |
1450 | to other instructions. */ | |
1451 | if (insns[0].reloc[0].code == BFD_RELOC_8 | |
1452 | && insns[0].reloc[0].exp.X_op == O_constant | |
1453 | && (insns[0].reloc[0].exp.X_add_number < 0 | |
1454 | || insns[0].reloc[0].exp.X_add_number > 0xff)) | |
1455 | { | |
1456 | if (OPCODE (opcode) == 0x10 | |
1457 | && (OP_FCN (opcode) == 0x00 /* addl */ | |
1458 | || OP_FCN (opcode) == 0x40 /* addl/v */ | |
1459 | || OP_FCN (opcode) == 0x20 /* addq */ | |
1460 | || OP_FCN (opcode) == 0x60 /* addq/v */ | |
1461 | || OP_FCN (opcode) == 0x09 /* subl */ | |
1462 | || OP_FCN (opcode) == 0x49 /* subl/v */ | |
1463 | || OP_FCN (opcode) == 0x29 /* subq */ | |
1464 | || OP_FCN (opcode) == 0x69 /* subq/v */ | |
1465 | || OP_FCN (opcode) == 0x02 /* s4addl */ | |
1466 | || OP_FCN (opcode) == 0x22 /* s4addq */ | |
1467 | || OP_FCN (opcode) == 0x0b /* s4subl */ | |
1468 | || OP_FCN (opcode) == 0x2b /* s4subq */ | |
1469 | || OP_FCN (opcode) == 0x12 /* s8addl */ | |
1470 | || OP_FCN (opcode) == 0x32 /* s8addq */ | |
1471 | || OP_FCN (opcode) == 0x1b /* s8subl */ | |
1472 | || OP_FCN (opcode) == 0x3b /* s8subq */ | |
1473 | ) | |
1474 | /* Can we make it fit by negating? */ | |
1475 | && -insns[0].reloc[0].exp.X_add_number < 0xff | |
1476 | && -insns[0].reloc[0].exp.X_add_number > 0) | |
1477 | { | |
1478 | opcode ^= 0x120; /* convert add<=>sub */ | |
1479 | insns[0].reloc[0].exp.X_add_number *= -1; | |
1480 | } | |
1481 | else if (at_ok && macro_ok) | |
1482 | { | |
1483 | /* Constant value supplied, but it's too large. */ | |
71f9b3c0 KR |
1484 | do_add64 = 1; |
1485 | add64_in = ZERO; | |
1486 | add64_out = AT; | |
1487 | add64_addend = insns[0].reloc[0].exp.X_add_number; | |
aaeee550 KR |
1488 | opcode &= ~ 0x1000; |
1489 | opcode |= (AT << SB); | |
5749c497 KR |
1490 | insns[0].reloc[0].code = BFD_RELOC_NONE; |
1491 | } | |
1492 | else | |
1493 | as_bad ("overflow in 8-bit literal field in `operate' format insn"); | |
1494 | } | |
aaeee550 KR |
1495 | else if (insns[0].reloc[0].code == BFD_RELOC_16 |
1496 | && insns[0].reloc[0].exp.X_op == O_constant | |
71f9b3c0 KR |
1497 | && !in_range_signed (insns[0].reloc[0].exp.X_add_number, |
1498 | 16)) | |
aaeee550 KR |
1499 | { |
1500 | bfd_vma val = insns[0].reloc[0].exp.X_add_number; | |
1501 | if (OPCODE (opcode) == 0x08) | |
1502 | { | |
71f9b3c0 KR |
1503 | do_add64 = 1; |
1504 | add64_in = ZERO; | |
1505 | add64_out = AT; | |
1506 | add64_addend = val; | |
aaeee550 KR |
1507 | opcode &= ~0x1000; |
1508 | opcode |= (AT << SB); | |
1509 | insns[0].reloc[0].code = BFD_RELOC_NONE; | |
1510 | } | |
1511 | else if (OPCODE (opcode) == 0x09 | |
71f9b3c0 | 1512 | && in_range_signed (val >> 16, 16)) |
aaeee550 KR |
1513 | { |
1514 | /* ldah with high operand - convert to low */ | |
1515 | insns[0].reloc[0].exp.X_add_number >>= 16; | |
1516 | } | |
1517 | else | |
1518 | as_bad ("I don't know how to handle 32+ bit constants here yet, sorry."); | |
1519 | } | |
1520 | else if (insns[0].reloc[0].code == BFD_RELOC_32 | |
1521 | && insns[0].reloc[0].exp.X_op == O_constant) | |
1522 | { | |
1523 | bfd_vma val = insns[0].reloc[0].exp.X_add_number; | |
1524 | bfd_signed_vma sval = val; | |
1525 | if (val >> 32 != 0 | |
1526 | && sval >> 32 != 0 | |
1527 | && sval >> 32 != -1) | |
1528 | as_bad ("I don't know how to handle 64 bit constants here yet, sorry."); | |
1529 | } | |
5749c497 KR |
1530 | continue; |
1531 | ||
40cd35ff KR |
1532 | case 'F': |
1533 | { | |
a2a1a548 | 1534 | int format, length, mode, i; |
40cd35ff KR |
1535 | char temp[20 /*MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT*/]; |
1536 | char *err; | |
1537 | static const char formats[4] = "FGfd"; | |
1538 | bfd_vma bits, offset; | |
1539 | char *old_input_line_pointer = input_line_pointer; | |
1540 | ||
1541 | input_line_pointer = s; | |
1542 | SKIP_WHITESPACE (); | |
1543 | memset (temp, 0, sizeof (temp)); | |
1544 | mode = (opcode >> 26) & 3; | |
1545 | format = formats[mode]; | |
1546 | err = md_atof (format, temp, &length); | |
1547 | if (err) | |
1548 | { | |
1549 | as_bad ("Bad floating literal: %s", err); | |
1550 | bits = 0; | |
1551 | } | |
1552 | else | |
1553 | { | |
1554 | /* Generate little-endian number from byte sequence. */ | |
1555 | bits = 0; | |
1556 | for (i = length - 1; i >= 0; i--) | |
1557 | bits += ((bfd_vma)(temp[i] & 0xff)) << (i * 8); | |
1558 | } | |
1559 | switch (length) | |
1560 | { | |
1561 | case 8: | |
1562 | offset = get_lit8_offset (bits) - 0x8000; | |
1563 | insns[0].reloc[0].exp.X_add_symbol = lit8_sym; | |
1564 | insns[0].reloc[0].exp.X_add_number = 0x8000; | |
1565 | break; | |
1566 | case 4: | |
1567 | offset = get_lit4_offset (bits) - 0x8000; | |
1568 | insns[0].reloc[0].exp.X_add_symbol = lit4_sym; | |
1569 | insns[0].reloc[0].exp.X_add_number = 0x8000; | |
1570 | break; | |
1571 | default: | |
1572 | abort (); | |
1573 | } | |
1574 | insns[0].reloc[0].exp.X_op = O_symbol; | |
1575 | offset &= 0xffff; | |
1576 | num_gen = load_expression (AT, &insns[0]); | |
0952861c KR |
1577 | if (lituse_pending) |
1578 | { | |
1579 | insns[num_gen].reloc[0].code = BFD_RELOC_ALPHA_LITUSE; | |
1580 | insns[num_gen].reloc[0].exp = lituse_basereg; | |
1581 | lituse_pending = 0; | |
1582 | } | |
40cd35ff KR |
1583 | insns[num_gen++].opcode = opcode | (AT << SB) | offset; |
1584 | opcode = insns[0].opcode; | |
1585 | s = input_line_pointer; | |
1586 | input_line_pointer = old_input_line_pointer; | |
1587 | } | |
1588 | continue; | |
1589 | ||
5749c497 KR |
1590 | /* The following two.. take advantage of the fact that |
1591 | opcode already contains most of what we need to know. | |
1592 | We just prepend to the instr an "ldah | |
1593 | $r,%ml(expr)($base)" and turn this one (done later | |
1594 | after we return) into something like "stq | |
1595 | $r,%lo(expr)(at)" or "ldq $r,%lo(expr)($r)". | |
1596 | ||
1597 | NOTE: This can fail later on at link time if the | |
1598 | offset from $base actually turns out to be more than | |
1599 | 2**31 or 2**47 if use_large_offsets is set. */ | |
1600 | case 'P': /* Addressing macros: PUT */ | |
1601 | mask = AT; /* register 'at' */ | |
1602 | /* fall through */ | |
1603 | ||
1604 | case 'G': /* Addressing macros: GET */ | |
5749c497 KR |
1605 | /* All it is missing is the expression, which is what we |
1606 | will get now */ | |
1607 | ||
1608 | if (*s == ' ') | |
1609 | s++; | |
c79e67a3 | 1610 | getExpression (s, &insns[0]); |
5749c497 KR |
1611 | s = expr_end; |
1612 | ||
1613 | /* Must check for "lda ..,number" too */ | |
1614 | if (insns[0].reloc[0].exp.X_op == O_big) | |
1615 | { | |
1616 | as_warn ("Sorry, not yet. Put bignums in .data section yourself."); | |
1617 | return -1; | |
1618 | } | |
1619 | if (insns[0].reloc[0].exp.X_op == O_constant) | |
1620 | { | |
aaeee550 KR |
1621 | bfd_vma val = insns[0].reloc[0].exp.X_add_number; |
1622 | bfd_vma top, low; | |
5749c497 KR |
1623 | |
1624 | insns[0].reloc[0].code = BFD_RELOC_NONE; | |
1625 | insns[1].reloc[0].code = BFD_RELOC_NONE; | |
1626 | ||
aaeee550 KR |
1627 | low = val & 0xffff; |
1628 | if (low & 0x8000) | |
1629 | low -= 0x10000; | |
1630 | top = val - low; | |
1631 | if (top) | |
5749c497 | 1632 | { |
71f9b3c0 KR |
1633 | do_add64 = 1; |
1634 | add64_in = ZERO; | |
1635 | add64_out = AT; | |
1636 | add64_addend = top; | |
aaeee550 | 1637 | opcode |= AT << SB; |
5749c497 KR |
1638 | } |
1639 | else | |
aaeee550 KR |
1640 | opcode |= ZERO << SB; |
1641 | opcode &= ~0x1000; | |
1642 | opcode |= low & 0xffff; | |
5749c497 KR |
1643 | } |
1644 | else if (insns[0].reloc[0].exp.X_op == O_symbol) | |
1645 | { | |
1646 | unsigned long old_opcode = opcode; | |
1647 | int tmp_reg; | |
1648 | ||
1649 | if (!macro_ok) | |
1650 | as_bad ("insn requires expansion but `nomacro' specified"); | |
1651 | else if (*args == 'G') | |
1652 | tmp_reg = mask; | |
1653 | else if (!at_ok) | |
1654 | as_bad ("insn expansion requires AT use, but `noat' specified"); | |
1655 | else | |
1656 | tmp_reg = AT; | |
1657 | num_gen = load_expression (tmp_reg, insns); | |
1658 | opcode = insns[0].opcode; | |
0952861c KR |
1659 | /* lda is opcode 8, 0x20000000, and the macros that use |
1660 | this code have an opcode field of 0. The latter | |
1661 | require further processing, and we don't have the | |
1662 | true opcode here. */ | |
1663 | if (OPCODE (old_opcode) != 0 | |
1664 | && OPCODE (old_opcode) != 0x08) | |
5749c497 KR |
1665 | { |
1666 | struct alpha_it *i; | |
1667 | i = &insns[num_gen++]; | |
5749c497 | 1668 | i->opcode = old_opcode | (tmp_reg << SB); |
40cd35ff | 1669 | |
0952861c KR |
1670 | if (lituse_pending) |
1671 | { | |
1672 | i->reloc[0].code = BFD_RELOC_ALPHA_LITUSE; | |
1673 | i->reloc[0].exp = lituse_basereg; | |
1674 | lituse_pending = 0; | |
1675 | } | |
5749c497 KR |
1676 | } |
1677 | } | |
1678 | else | |
1679 | { | |
1680 | /* Not a number */ | |
1681 | num_gen = 2; | |
1682 | insns[1].reloc[0].exp = insns[0].reloc[0].exp; | |
1683 | ||
1684 | /* Generate: ldah REG,x1(GP); OP ?,x0(REG) */ | |
1685 | ||
1686 | abort (); /* relocs need fixing */ | |
1687 | #if 0 | |
1688 | insns[1].reloc = RELOC_0_15; | |
1689 | insns[1].opcode = opcode | mask << SB; | |
1690 | ||
1691 | insns[0].reloc = RELOC_16_31; | |
1692 | opcode = 0x24000000 /*ldah*/ | mask << SA | (base_register << SB); | |
1693 | #endif | |
1694 | } | |
1695 | ||
1696 | continue; | |
1697 | ||
1698 | /* Same failure modes as above, actually most of the | |
40cd35ff | 1699 | same code shared. */ |
5749c497 KR |
1700 | case 'B': /* Builtins */ |
1701 | args++; | |
1702 | switch (*args) | |
1703 | { | |
1704 | ||
1705 | case 'a': /* ldgp */ | |
1706 | ||
1707 | if (first_32bit_quadrant || no_mixed_code) | |
1708 | return -1; | |
1709 | switch (OUTPUT_FLAVOR) | |
1710 | { | |
1711 | case bfd_target_aout_flavour: | |
1712 | /* this is cmu's a.out version */ | |
1713 | insns[0].reloc[0].code = BFD_RELOC_NONE; | |
1714 | /* generate "zap %r,0xf,%r" to take high 32 bits */ | |
1715 | opcode |= 0x48001600 /* zap ?,#,?*/ | (0xf << SN); | |
1716 | break; | |
1717 | case bfd_target_ecoff_flavour: | |
1718 | /* Given "ldgp R1,N(R2)", turn it into something | |
1719 | like "ldah R1,###(R2) ; lda R1,###(R1)" with | |
1720 | appropriate constants and relocations. */ | |
1721 | { | |
1722 | unsigned long r1, r2; | |
1723 | unsigned long addend = 0; | |
1724 | ||
1725 | num_gen = 2; | |
1726 | r2 = mask; | |
1727 | r1 = opcode & 0x3f; | |
1728 | insns[0].reloc[0].code = BFD_RELOC_ALPHA_GPDISP_HI16; | |
1729 | insns[0].reloc[0].pcrel = 1; | |
1730 | insns[0].reloc[0].exp.X_op = O_symbol; | |
1731 | insns[0].reloc[0].exp.X_add_symbol = gp; | |
1732 | insns[0].reloc[0].exp.X_add_number = 0; | |
1733 | insns[0].opcode = (0x24000000 /* ldah */ | |
1734 | | (r1 << SA) | |
1735 | | (r2 << SB)); | |
1736 | insns[1].reloc[0].code = BFD_RELOC_ALPHA_GPDISP_LO16; | |
1737 | insns[1].reloc[0].exp.X_op = O_symbol; | |
1738 | insns[1].reloc[0].exp.X_add_symbol = gp; | |
1739 | insns[1].reloc[0].exp.X_add_number = 4; | |
1740 | insns[1].reloc[0].pcrel = 1; | |
1741 | insns[1].opcode = 0x20000000 | (r1 << SA) | (r1 << SB); | |
1742 | opcode = insns[0].opcode; | |
1743 | /* merge in addend */ | |
1744 | insns[1].opcode |= addend & 0xffff; | |
1745 | insns[0].opcode |= ((addend >> 16) | |
1746 | + (addend & 0x8000 ? 1 : 0)); | |
0952861c KR |
1747 | if (r2 == PV) |
1748 | ecoff_set_gp_prolog_size (0); | |
5749c497 KR |
1749 | } |
1750 | break; | |
1751 | default: | |
1752 | abort (); | |
1753 | } | |
1754 | continue; | |
1755 | ||
1756 | ||
1757 | case 'b': /* setgp */ | |
1758 | switch (OUTPUT_FLAVOR) | |
1759 | { | |
1760 | case bfd_target_aout_flavour: | |
1761 | /* generate "zap %r,0xf,$gp" to take high 32 bits */ | |
1762 | opcode |= 0x48001600 /* zap ?,#,?*/ | |
1763 | | (0xf << SN) | (base_register); | |
1764 | break; | |
1765 | default: | |
1766 | abort (); | |
1767 | } | |
1768 | continue; | |
1769 | ||
1770 | case 'c': /* jsr $r,foo becomes | |
1771 | lda $27,foo | |
1772 | jsr $r,($27),foo | |
1773 | Register 27, t12, is used by convention | |
1774 | here. */ | |
1775 | { | |
1776 | struct alpha_it *jsr; | |
1777 | expressionS etmp; | |
1778 | struct reloc_data *r; | |
1779 | ||
1780 | /* We still have to parse the function name */ | |
1781 | if (*s == ' ') | |
1782 | s++; | |
c79e67a3 | 1783 | getExpression (s, &insns[0]); |
5749c497 KR |
1784 | etmp = insns[0].reloc[0].exp; |
1785 | s = expr_end; | |
1786 | num_gen = load_expression (PV, &insns[0]); | |
1787 | note_gpreg (PV); | |
1788 | ||
1789 | jsr = &insns[num_gen++]; | |
71f9b3c0 | 1790 | jsr->opcode = (pattern->match |
5749c497 KR |
1791 | | (mask << SA) |
1792 | | (PV << SB) | |
1793 | | 0); | |
0952861c | 1794 | if (lituse_pending) |
5749c497 KR |
1795 | { |
1796 | /* LITUSE wasn't emitted yet */ | |
1797 | jsr->reloc[0].code = BFD_RELOC_ALPHA_LITUSE; | |
1798 | jsr->reloc[0].exp = lituse_jsr; | |
1799 | r = &jsr->reloc[1]; | |
0952861c | 1800 | lituse_pending = 0; |
5749c497 KR |
1801 | } |
1802 | else | |
1803 | r = &jsr->reloc[0]; | |
1804 | r->exp = etmp; | |
1805 | r->code = BFD_RELOC_ALPHA_HINT; | |
1806 | r->pcrel = 1; | |
1807 | opcode = insns[0].opcode; | |
1808 | } | |
1809 | continue; | |
1810 | ||
0952861c KR |
1811 | case 'd': |
1812 | /* Sub-word loads and stores. We load the address into | |
1813 | $at, which might involve using the `P' parameter | |
1814 | processing too, then emit a sequence to get the job | |
1815 | done, using unaligned memory accesses and byte | |
1816 | manipulation, with t9 and t10 as temporaries. */ | |
1817 | { | |
1818 | /* Characteristics of access. */ | |
1819 | int is_load, is_unsigned = 0, is_unaligned = 0; | |
1820 | int mode_size, mode; | |
1821 | /* Register operand. */ | |
1822 | int reg; | |
1823 | /* Addend for loads and stores. */ | |
1824 | valueT addend; | |
1825 | /* Which register do we use for the address? */ | |
1826 | int addr; | |
1827 | ||
1828 | { | |
1829 | /* Pick apart name and set flags. */ | |
a2a1a548 | 1830 | const char *s = pattern->name; |
0952861c KR |
1831 | |
1832 | if (*s == 'u') | |
1833 | { | |
1834 | is_unaligned = 1; | |
1835 | s++; | |
1836 | } | |
1837 | ||
1838 | if (s[0] == 'l' && s[1] == 'd') | |
1839 | is_load = 1; | |
1840 | else if (s[0] == 's' && s[1] == 't') | |
1841 | is_load = 0; | |
1842 | else | |
1843 | as_fatal ("unrecognized sub-word access insn `%s'", | |
1844 | str); | |
1845 | s += 2; | |
1846 | ||
1847 | mode = *s++; | |
1848 | if (mode == 'b') mode_size = 1; | |
1849 | else if (mode == 'w') mode_size = 2; | |
1850 | else if (mode == 'l') mode_size = 4; | |
1851 | else if (mode == 'q') mode_size = 8; | |
1852 | else abort (); | |
1853 | ||
1854 | if (*s == 'u') | |
1855 | { | |
1856 | is_unsigned = 1; | |
1857 | s++; | |
1858 | } | |
1859 | ||
1860 | assert (*s == 0); | |
1861 | ||
1862 | /* Longwords are always kept sign-extended. */ | |
1863 | if (mode == 'l' && is_unsigned) | |
1864 | abort (); | |
1865 | /* There's no special unaligned byte handling. */ | |
1866 | if (mode == 'b' && is_unaligned) | |
1867 | abort (); | |
1868 | /* Stores don't care about signedness. */ | |
1869 | if (!is_load && is_unsigned) | |
1870 | abort (); | |
1871 | } | |
1872 | ||
1873 | if (args[-2] == 'P') | |
1874 | { | |
1875 | addr = AT; | |
1876 | addend = 0; | |
1877 | } | |
1878 | else | |
1879 | { | |
1880 | /* foo r1,num(r2) | |
1881 | r2 -> mask | |
1882 | r1 -> (opcode >> SA) & 31 | |
1883 | num -> insns->reloc[0].* | |
1884 | ||
1885 | We want to emit "lda at,num(r2)", since these | |
1886 | operations require the use of a single register | |
1887 | with the starting address of the memory operand | |
1888 | we want to access. | |
1889 | ||
1890 | We could probably get away without doing this | |
1891 | (and use r2 below, with the addend for the | |
1892 | actual reads and writes) in cases where the | |
1893 | addend is known to be a multiple of 8. */ | |
1894 | int r2 = mask; | |
1895 | int r1 = (opcode >> SA) & 31; | |
1896 | ||
1897 | if (insns[0].reloc[0].code == BFD_RELOC_NONE) | |
1898 | addend = 0; | |
1899 | else if (insns[0].reloc[0].code == BFD_RELOC_16) | |
1900 | { | |
1901 | if (insns[0].reloc[0].exp.X_op != O_constant) | |
1902 | abort (); | |
1903 | addend = insns[0].reloc[0].exp.X_add_number; | |
1904 | } | |
1905 | else | |
1906 | abort (); | |
1907 | ||
1908 | if (addend + mode_size - 1 < 0x7fff | |
1909 | && (addend % 8) == 0 | |
1910 | && (r2 < T9 || r2 > T12)) | |
1911 | { | |
1912 | addr = r2; | |
1913 | num_gen = 0; | |
1914 | } | |
1915 | else | |
1916 | { | |
1917 | /* Let later relocation processing deal | |
1918 | with the addend field. */ | |
1919 | insns[num_gen-1].opcode = (0x20000000 /* lda */ | |
1920 | | (AT << SA) | |
1921 | | (r2 << SB)); | |
1922 | addr = AT; | |
1923 | addend = 0; | |
1924 | } | |
1925 | reg = r1; | |
1926 | } | |
1927 | ||
1928 | /* Because the emit_* routines append directly to | |
1929 | the current frag, we now need to flush any | |
1930 | pending insns. */ | |
1931 | { | |
1932 | int i; | |
1933 | for (i = 0; i < num_gen; i++) | |
1934 | emit_insn (&insns[i]); | |
1935 | num_gen = 0; | |
1936 | } | |
1937 | ||
1938 | if (is_load) | |
1939 | { | |
1940 | int reg2, reg3; | |
1941 | ||
1942 | if (is_unaligned) | |
1943 | reg2 = T9, reg3 = T10; | |
1944 | else | |
1945 | reg2 = reg; | |
1946 | ||
1947 | emit_load_unal (addr, addend, T9); | |
1948 | if (is_unaligned) | |
1949 | emit_load_unal (addr, addend + mode_size - 1, T10); | |
1950 | emit_extract_r (T9, addr, reg2, mode, 'l'); | |
1951 | if (is_unaligned) | |
1952 | { | |
1953 | emit_extract_r (T10, addr, reg3, mode, 'h'); | |
1954 | emit_bis_r (T9, T10, reg); | |
1955 | } | |
1956 | if (!is_unsigned) | |
1957 | emit_sign_extend (reg, mode_size * 8); | |
1958 | } | |
1959 | else | |
1960 | { | |
1961 | /* The second word gets processed first | |
1962 | because if the address does turn out to be | |
1963 | aligned, the processing for the second word | |
1964 | will be pushing around all-zeros, and the | |
1965 | entire value will be handled as the `first' | |
1966 | word. So we want to store the `first' word | |
1967 | last. */ | |
1968 | /* Pair these up so that the memory loads get | |
1969 | separated from each other, as well as being | |
1970 | well in advance of the uses of the values | |
1971 | loaded. */ | |
1972 | if (is_unaligned) | |
1973 | { | |
1974 | emit_load_unal (addr, addend + mode_size - 1, T11); | |
1975 | emit_insert_r (reg, addr, T12, mode, 'h'); | |
1976 | } | |
1977 | emit_load_unal (addr, addend, T9); | |
1978 | emit_insert_r (reg, addr, T10, mode, 'l'); | |
1979 | if (is_unaligned) | |
1980 | emit_mask_r (T12, addr, T12, mode, 'h'); | |
1981 | emit_mask_r (T10, addr, T10, mode, 'l'); | |
1982 | if (is_unaligned) | |
1983 | emit_bis_r (T11, T12, T11); | |
1984 | emit_bis_r (T9, T10, T9); | |
1985 | if (is_unaligned) | |
1986 | emit_store_unal (addr, addend + mode_size - 1, T11); | |
1987 | emit_store_unal (addr, addend, T9); | |
1988 | } | |
1989 | } | |
1990 | return 0; | |
1991 | ||
5749c497 KR |
1992 | /* DIVISION and MODULUS. Yech. |
1993 | Convert OP x,y,result | |
1994 | to mov x,t10 | |
1995 | mov y,t11 | |
1996 | jsr t9, __OP | |
1997 | mov t12,result | |
1998 | ||
1999 | with appropriate optimizations if t10,t11,t12 | |
2000 | are the registers specified by the compiler. | |
2001 | We are missing an obvious optimization | |
2002 | opportunity here; if the ldq generated by the | |
2003 | jsr assembly requires a cycle or two to make | |
2004 | the value available, initiating it before one | |
2005 | or two of the mov instructions would result in | |
2006 | faster execution. */ | |
2007 | case '0': /* reml */ | |
2008 | case '1': /* divl */ | |
2009 | case '2': /* remq */ | |
2010 | case '3': /* divq */ | |
2011 | case '4': /* remlu */ | |
2012 | case '5': /* divlu */ | |
2013 | case '6': /* remqu */ | |
2014 | case '7': /* divqu */ | |
2015 | { | |
2016 | static char func[8][6] = { | |
2017 | "reml", "divl", "remq", "divq", | |
2018 | "remlu", "divlu", "remqu", "divqu" | |
2019 | }; | |
2020 | char expansion[64]; | |
2021 | int reg; | |
2022 | ||
2023 | /* All regs parsed, in opcode */ | |
2024 | ||
2025 | /* Do the expansions, one instr at a time */ | |
2026 | ||
2027 | reg = (opcode >> SA) & 31; | |
2028 | if (reg != T10) | |
2029 | { | |
2030 | /* x->t10 */ | |
2031 | sprintf (expansion, "mov $%d,$%d", reg, T10); | |
2032 | md_assemble (expansion); | |
2033 | } | |
2034 | reg = (opcode >> SB) & 31; | |
2035 | if (reg == T10) | |
2036 | /* we already overwrote it! */ | |
2037 | abort (); | |
2038 | else if (reg != T11) | |
2039 | { | |
2040 | /* y->t11 */ | |
2041 | sprintf (expansion, "mov $%d,$%d", reg, T11); | |
2042 | md_assemble (expansion); | |
2043 | } | |
2044 | sprintf (expansion, "lda $%d,__%s", PV, func[*args - '0']); | |
2045 | md_assemble (expansion); | |
2046 | sprintf (expansion, "jsr $%d,($%d),__%s", T9, PV, | |
2047 | func[*args - '0']); | |
2048 | md_assemble (expansion); | |
2049 | #if 0 /* huh? */ | |
2050 | if (!first_32bit_quadrant) | |
2051 | { | |
2052 | sprintf (expansion, | |
2053 | "zap $%d,0xf,$%d", | |
2054 | T9, base_register); | |
2055 | md_assemble (expansion); | |
2056 | } | |
2057 | #endif | |
2058 | sprintf (expansion, "ldgp $%d,0($%d)", | |
2059 | base_register, T9); | |
2060 | md_assemble (expansion); | |
2061 | ||
2062 | /* Use insns[0] to get at the result */ | |
2063 | if ((reg = (opcode & 31)) != PV) | |
2064 | opcode = (0x47e00400 /* or zero,zero,zero */ | |
2065 | | (PV << SB) | |
2066 | | reg /* Rc */ ); /* pv->z */ | |
2067 | else | |
2068 | num_gen = 0; | |
2069 | } | |
2070 | continue; | |
2071 | } | |
2072 | /* fall through */ | |
2073 | ||
2074 | default: | |
2075 | abort (); | |
2076 | } | |
2077 | break; | |
2078 | } | |
2079 | error: | |
2080 | if (match == 0) | |
2081 | { | |
2082 | /* Args don't match. */ | |
2083 | if (&pattern[1] - alpha_opcodes < NUMOPCODES | |
2084 | && !strcmp (pattern->name, pattern[1].name)) | |
2085 | { | |
2086 | ++pattern; | |
2087 | s = argsStart; | |
2088 | continue; | |
2089 | } | |
2090 | else | |
2091 | { | |
2092 | as_warn ("Illegal operands"); | |
2093 | return -1; | |
2094 | } | |
2095 | } | |
2096 | else | |
2097 | { | |
2098 | /* Args match, see if a float instructions and -nofloats */ | |
2099 | if (nofloats && pattern->isa_float) | |
2100 | return -1; | |
2101 | } | |
2102 | break; | |
2103 | } | |
2104 | ||
71f9b3c0 KR |
2105 | if (do_add64) |
2106 | { | |
2107 | emit_add64 (add64_in, add64_out, add64_addend); | |
2108 | } | |
2109 | ||
5749c497 KR |
2110 | insns[0].opcode = opcode; |
2111 | return num_gen; | |
2112 | } | |
2113 | ||
2114 | /* Turn a string in input_line_pointer into a floating point constant | |
2115 | of type type, and store the appropriate bytes in *litP. The number | |
2116 | of LITTLENUMS emitted is stored in *sizeP. An error message is | |
2117 | returned, or NULL on OK. */ | |
2118 | ||
2119 | /* Equal to MAX_PRECISION in atof-ieee.c */ | |
2120 | #define MAX_LITTLENUMS 6 | |
2121 | ||
2122 | char * | |
2123 | md_atof (type, litP, sizeP) | |
2124 | char type; | |
2125 | char *litP; | |
2126 | int *sizeP; | |
2127 | { | |
2128 | int prec; | |
2129 | LITTLENUM_TYPE words[MAX_LITTLENUMS]; | |
2130 | LITTLENUM_TYPE *wordP; | |
2131 | char *t; | |
2132 | char *atof_ieee (), *vax_md_atof (); | |
2133 | ||
2134 | switch (type) | |
2135 | { | |
2136 | /* VAX floats */ | |
2137 | case 'G': | |
c79e67a3 | 2138 | /* VAX md_atof doesn't like "G" for some reason. */ |
5749c497 KR |
2139 | type = 'g'; |
2140 | case 'F': | |
2141 | case 'D': | |
2142 | return vax_md_atof (type, litP, sizeP); | |
2143 | ||
2144 | /* IEEE floats */ | |
2145 | case 'f': | |
2146 | prec = 2; | |
2147 | break; | |
2148 | ||
2149 | case 'd': | |
2150 | prec = 4; | |
2151 | break; | |
2152 | ||
2153 | case 'x': | |
2154 | case 'X': | |
2155 | prec = 6; | |
2156 | break; | |
2157 | ||
2158 | case 'p': | |
2159 | case 'P': | |
2160 | prec = 6; | |
2161 | break; | |
2162 | ||
2163 | default: | |
2164 | *sizeP = 0; | |
2165 | return "Bad call to MD_ATOF()"; | |
2166 | } | |
2167 | t = atof_ieee (input_line_pointer, type, words); | |
2168 | if (t) | |
2169 | input_line_pointer = t; | |
2170 | *sizeP = prec * sizeof (LITTLENUM_TYPE); | |
2171 | ||
2172 | for (wordP = words + prec - 1; prec--;) | |
2173 | { | |
2174 | md_number_to_chars (litP, (long) (*wordP--), sizeof (LITTLENUM_TYPE)); | |
2175 | litP += sizeof (LITTLENUM_TYPE); | |
2176 | } | |
2177 | ||
2178 | return 0; | |
2179 | } | |
2180 | ||
2181 | void | |
2182 | md_bignum_to_chars (buf, bignum, nchars) | |
2183 | char *buf; | |
2184 | LITTLENUM_TYPE *bignum; | |
2185 | int nchars; | |
2186 | { | |
2187 | while (nchars) | |
2188 | { | |
2189 | LITTLENUM_TYPE work = *bignum++; | |
2190 | int nb = CHARS_PER_LITTLENUM; | |
2191 | ||
2192 | do | |
2193 | { | |
2194 | *buf++ = work & ((1 << BITS_PER_CHAR) - 1); | |
2195 | if (--nchars == 0) | |
2196 | return; | |
2197 | work >>= BITS_PER_CHAR; | |
2198 | } | |
2199 | while (--nb); | |
2200 | } | |
2201 | } | |
f3d817d8 DM |
2202 | \f |
2203 | CONST char *md_shortopts = "Fm:"; | |
2204 | struct option md_longopts[] = { | |
2205 | #define OPTION_32ADDR (OPTION_MD_BASE) | |
2206 | {"32addr", no_argument, NULL, OPTION_32ADDR}, | |
2207 | {NULL, no_argument, NULL, 0} | |
2208 | }; | |
2209 | size_t md_longopts_size = sizeof(md_longopts); | |
5749c497 KR |
2210 | |
2211 | int | |
f3d817d8 DM |
2212 | md_parse_option (c, arg) |
2213 | int c; | |
2214 | char *arg; | |
5749c497 | 2215 | { |
f3d817d8 | 2216 | switch (c) |
5749c497 | 2217 | { |
f3d817d8 | 2218 | case 'F': |
5749c497 | 2219 | nofloats = 1; |
f3d817d8 DM |
2220 | break; |
2221 | ||
2222 | case OPTION_32ADDR: | |
cf272f02 | 2223 | addr32 = 1; |
f3d817d8 | 2224 | break; |
f3d817d8 DM |
2225 | |
2226 | default: | |
2227 | return 0; | |
5749c497 | 2228 | } |
f3d817d8 DM |
2229 | |
2230 | return 1; | |
5749c497 KR |
2231 | } |
2232 | ||
f3d817d8 DM |
2233 | void |
2234 | md_show_usage (stream) | |
2235 | FILE *stream; | |
2236 | { | |
2237 | fprintf(stream, "\ | |
2238 | Alpha options:\n\ | |
2239 | -32addr treat addresses as 32-bit values\n\ | |
2240 | -F lack floating point instructions support\n\ | |
2241 | -m21064 | -m21066 | -m21164\n\ | |
a2a1a548 | 2242 | specify variant of Alpha architecture\n"); |
f3d817d8 DM |
2243 | } |
2244 | \f | |
5749c497 KR |
2245 | static void |
2246 | s_proc (is_static) | |
a2a1a548 | 2247 | int is_static; |
5749c497 KR |
2248 | { |
2249 | /* XXXX Align to cache linesize XXXXX */ | |
2250 | char *name; | |
2251 | char c; | |
2252 | char *p; | |
2253 | symbolS *symbolP; | |
2254 | int temp; | |
2255 | ||
2256 | /* Takes ".proc name,nargs" */ | |
2257 | name = input_line_pointer; | |
2258 | c = get_symbol_end (); | |
2259 | p = input_line_pointer; | |
2260 | symbolP = symbol_find_or_make (name); | |
2261 | *p = c; | |
2262 | SKIP_WHITESPACE (); | |
2263 | if (*input_line_pointer != ',') | |
2264 | { | |
2265 | *p = 0; | |
2266 | as_warn ("Expected comma after name \"%s\"", name); | |
2267 | *p = c; | |
2268 | temp = 0; | |
2269 | ignore_rest_of_line (); | |
2270 | } | |
2271 | else | |
2272 | { | |
2273 | input_line_pointer++; | |
2274 | temp = get_absolute_expression (); | |
2275 | } | |
2276 | /* symbolP->sy_other = (signed char) temp; */ | |
2277 | as_warn ("unhandled: .proc %s,%d", name, temp); | |
2278 | demand_empty_rest_of_line (); | |
2279 | } | |
2280 | ||
2281 | static void | |
2282 | s_alpha_set (x) | |
2283 | int x; | |
2284 | { | |
2285 | char *name = input_line_pointer, ch, *s; | |
2286 | int yesno = 1; | |
2287 | ||
2288 | while (!is_end_of_line[(unsigned char) *input_line_pointer]) | |
2289 | input_line_pointer++; | |
2290 | ch = *input_line_pointer; | |
2291 | *input_line_pointer = '\0'; | |
2292 | ||
2293 | s = name; | |
2294 | if (s[0] == 'n' && s[1] == 'o') | |
2295 | { | |
2296 | yesno = 0; | |
2297 | s += 2; | |
2298 | } | |
2299 | if (!strcmp ("reorder", s)) | |
2300 | /* ignore */ ; | |
2301 | else if (!strcmp ("at", s)) | |
2302 | at_ok = yesno; | |
2303 | else if (!strcmp ("macro", s)) | |
2304 | macro_ok = yesno; | |
3a443b1e C |
2305 | else if (!strcmp ("move", s)) |
2306 | /* ignore */ ; | |
2307 | else if (!strcmp ("volatile", s)) | |
2308 | /* ignore */ ; | |
5749c497 | 2309 | else |
71f9b3c0 | 2310 | as_warn ("Tried to .set unrecognized mode `%s'", name); |
5749c497 KR |
2311 | *input_line_pointer = ch; |
2312 | demand_empty_rest_of_line (); | |
2313 | } | |
2314 | ||
2315 | /* @@ Is this right?? */ | |
2316 | long | |
2317 | md_pcrel_from (fixP) | |
2318 | fixS *fixP; | |
2319 | { | |
2320 | valueT addr = fixP->fx_where + fixP->fx_frag->fr_address; | |
2321 | switch (fixP->fx_r_type) | |
2322 | { | |
2323 | case BFD_RELOC_ALPHA_GPDISP_HI16: | |
2324 | case BFD_RELOC_ALPHA_GPDISP_LO16: | |
2325 | return addr; | |
2326 | default: | |
2327 | return fixP->fx_size + addr; | |
2328 | } | |
2329 | } | |
2330 | ||
2331 | int | |
2332 | alpha_do_align (n, fill) | |
2333 | int n; | |
a2a1a548 | 2334 | const char *fill; |
5749c497 KR |
2335 | { |
2336 | if (!fill | |
2337 | && (now_seg == text_section | |
2338 | || !strcmp (now_seg->name, ".init") | |
2339 | || !strcmp (now_seg->name, ".fini"))) | |
2340 | { | |
4a6e1a39 | 2341 | static const unsigned char nop_pattern[] = { 0x1f, 0x04, 0xff, 0x47 }; |
5749c497 KR |
2342 | frag_align_pattern (n, nop_pattern, sizeof (nop_pattern)); |
2343 | return 1; | |
2344 | } | |
2345 | return 0; | |
2346 | } | |
2347 | ||
2348 | int | |
2349 | md_apply_fix (fixP, valueP) | |
2350 | fixS *fixP; | |
2351 | valueT *valueP; | |
2352 | { | |
2353 | valueT value; | |
2354 | int size; | |
2355 | valueT addend; | |
2356 | char *p = fixP->fx_frag->fr_literal + fixP->fx_where; | |
2357 | ||
2358 | value = *valueP; | |
2359 | ||
2360 | switch (fixP->fx_r_type) | |
2361 | { | |
2362 | /* The GPDISP relocations are processed internally with a symbol | |
2363 | referring to the current function; we need to drop in a value | |
2364 | which, when added to the address of the start of the function, | |
2365 | gives the desired GP. */ | |
2366 | case BFD_RELOC_ALPHA_GPDISP_HI16: | |
2367 | case BFD_RELOC_ALPHA_GPDISP_LO16: | |
2368 | addend = value; | |
2369 | if (fixP->fx_r_type == BFD_RELOC_ALPHA_GPDISP_HI16) | |
2370 | { | |
2371 | assert (fixP->fx_next->fx_r_type == BFD_RELOC_ALPHA_GPDISP_LO16); | |
2372 | #ifdef DEBUG1 | |
2373 | printf ("hi16: "); | |
2374 | fprintf_vma (stdout, addend); | |
2375 | printf ("\n"); | |
2376 | #endif | |
2377 | if (addend & 0x8000) | |
2378 | addend += 0x10000; | |
2379 | addend >>= 16; | |
2380 | fixP->fx_offset = 4; /* @@ Compute this using fx_next. */ | |
2381 | } | |
2382 | else | |
2383 | { | |
2384 | #ifdef DEBUG1 | |
2385 | printf ("lo16: "); | |
2386 | fprintf_vma (stdout, addend); | |
2387 | printf ("\n"); | |
2388 | #endif | |
2389 | addend &= 0xffff; | |
2390 | fixP->fx_offset = 0; | |
2391 | } | |
2392 | md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, | |
2393 | addend, 2); | |
2394 | fixP->fx_addsy = section_symbol (absolute_section); | |
2395 | fixP->fx_offset += fixP->fx_frag->fr_address + fixP->fx_where; | |
2396 | break; | |
2397 | ||
2398 | case BFD_RELOC_8: | |
2399 | /* Write 8 bits, shifted left 13 bit positions. */ | |
2400 | value &= 0xff; | |
2401 | p++; | |
2402 | *p &= 0x1f; | |
2403 | *p |= (value << 5) & 0xe0; | |
2404 | value >>= 3; | |
2405 | p++; | |
2406 | *p &= 0xe0; | |
2407 | *p |= value; | |
2408 | value >>= 5; | |
2409 | fixP->fx_done = 1; | |
5749c497 KR |
2410 | if (value != 0) |
2411 | as_bad_where (fixP->fx_file, fixP->fx_line, | |
2412 | "overflow in type-%d reloc", (int) fixP->fx_r_type); | |
2413 | return 3; | |
2414 | ||
2415 | case BFD_RELOC_32: | |
30869211 KR |
2416 | size = 4; |
2417 | goto do_it; | |
5749c497 | 2418 | case BFD_RELOC_64: |
30869211 KR |
2419 | size = 8; |
2420 | goto do_it; | |
5749c497 KR |
2421 | case BFD_RELOC_16: |
2422 | /* Don't want overflow checking. */ | |
2423 | size = 2; | |
2424 | do_it: | |
2425 | if (fixP->fx_pcrel == 0 | |
2426 | && fixP->fx_addsy == 0) | |
2427 | { | |
2428 | md_number_to_chars (p, value, size); | |
2429 | /* @@ Overflow checks?? */ | |
2430 | goto done; | |
2431 | } | |
2432 | break; | |
2433 | ||
0952861c KR |
2434 | case BFD_RELOC_26: |
2435 | if (fixP->fx_addsy != 0 | |
2436 | && fixP->fx_addsy->bsym->section != absolute_section) | |
2437 | as_bad_where (fixP->fx_file, fixP->fx_line, | |
2438 | "PALcode instructions require immediate constant function code"); | |
2439 | else if (value >> 26 != 0) | |
2440 | as_bad_where (fixP->fx_file, fixP->fx_line, | |
2441 | "overflow in 26-bit PALcode function field"); | |
2442 | *p++ = value & 0xff; | |
2443 | value >>= 8; | |
2444 | *p++ = value & 0xff; | |
2445 | value >>= 8; | |
2446 | *p++ = value & 0xff; | |
2447 | value >>= 8; | |
2448 | { | |
2449 | char x = *p; | |
2450 | x &= ~3; | |
2451 | x |= (value & 3); | |
2452 | *p++ = x; | |
2453 | } | |
2454 | goto done; | |
2455 | ||
5749c497 KR |
2456 | case BFD_RELOC_14: |
2457 | if (fixP->fx_addsy != 0 | |
2458 | && fixP->fx_addsy->bsym->section != absolute_section) | |
2459 | as_bad_where (fixP->fx_file, fixP->fx_line, | |
2460 | "ret/jsr_coroutine requires constant in displacement field"); | |
2461 | else if (value >> 14 != 0) | |
2462 | as_bad_where (fixP->fx_file, fixP->fx_line, | |
2463 | "overflow in 14-bit operand field of ret or jsr_coroutine"); | |
2464 | *p++ = value & 0xff; | |
2465 | value >>= 8; | |
2466 | *p = (*p & 0xc0) | (value & 0x3f); | |
2467 | goto done; | |
2468 | ||
2469 | case BFD_RELOC_23_PCREL_S2: | |
2470 | /* Write 21 bits only. */ | |
2471 | value >>= 2; | |
2472 | *p++ = value & 0xff; | |
2473 | value >>= 8; | |
2474 | *p++ = value & 0xff; | |
2475 | value >>= 8; | |
2476 | *p &= 0xe0; | |
2477 | *p |= (value & 0x1f); | |
2478 | goto done; | |
2479 | ||
71f9b3c0 KR |
2480 | case BFD_RELOC_12_PCREL: |
2481 | *p++ = value & 0xff; | |
2482 | value >>= 8; | |
2483 | *p &= 0xf0; | |
2484 | *p |= (value & 0x0f); | |
2485 | goto done; | |
2486 | ||
5749c497 KR |
2487 | case BFD_RELOC_ALPHA_LITERAL: |
2488 | case BFD_RELOC_ALPHA_LITUSE: | |
2489 | return 2; | |
2490 | ||
2491 | case BFD_RELOC_GPREL32: | |
2492 | assert (fixP->fx_subsy == gp); | |
c79e67a3 | 2493 | value = - alpha_gp_value; /* huh? this works... */ |
5749c497 KR |
2494 | fixP->fx_subsy = 0; |
2495 | md_number_to_chars (p, value, 4); | |
2496 | break; | |
2497 | ||
2498 | case BFD_RELOC_ALPHA_HINT: | |
2499 | if (fixP->fx_addsy == 0 && fixP->fx_pcrel == 0) | |
2500 | { | |
2501 | size = 2; | |
2502 | goto do_it; | |
2503 | } | |
2504 | return 2; | |
2505 | ||
2506 | default: | |
71f9b3c0 KR |
2507 | as_fatal ("unhandled relocation type %s", |
2508 | bfd_get_reloc_code_name (fixP->fx_r_type)); | |
5749c497 KR |
2509 | return 9; |
2510 | } | |
2511 | ||
2512 | if (fixP->fx_addsy == 0 && fixP->fx_pcrel == 0) | |
2513 | { | |
2514 | printf ("type %d reloc done?\n", fixP->fx_r_type); | |
2515 | done: | |
2516 | fixP->fx_done = 1; | |
2517 | return 42; | |
2518 | } | |
2519 | ||
2520 | return 0x12345678; | |
2521 | } | |
2522 | ||
2523 | void | |
4a6e1a39 | 2524 | alpha_frob_ecoff_data () |
5749c497 | 2525 | { |
c79e67a3 | 2526 | select_gp_value (); |
5749c497 | 2527 | /* $zero and $f31 are read-only */ |
c79e67a3 KR |
2528 | alpha_gprmask &= ~1; |
2529 | alpha_fprmask &= ~1; | |
5749c497 KR |
2530 | } |
2531 | ||
2532 | /* The Alpha has support for some VAX floating point types, as well as for | |
2533 | IEEE floating point. We consider IEEE to be the primary floating point | |
2534 | format, and sneak in the VAX floating point support here. */ | |
2535 | #define md_atof vax_md_atof | |
2536 | #include "config/atof-vax.c" |