Commit | Line | Data |
---|---|---|
df7b86aa | 1 | /* tc-dlx.c -- Assemble for the DLX |
82704155 | 2 | Copyright (C) 2002-2019 Free Software Foundation, Inc. |
d172d4ba NC |
3 | |
4 | This file is part of GAS, the GNU Assembler. | |
5 | ||
6 | GAS is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
ec2655a6 | 8 | the Free Software Foundation; either version 3, or (at your option) |
d172d4ba NC |
9 | any later version. |
10 | ||
11 | GAS is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with GAS; see the file COPYING. If not, write to the Free | |
4b4da160 NC |
18 | Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA |
19 | 02110-1301, USA. */ | |
d172d4ba NC |
20 | |
21 | /* Initially created by Kuang Hwa Lin, 3/20/2002. */ | |
22 | ||
d172d4ba | 23 | #include "as.h" |
df7b86aa | 24 | #include "safe-ctype.h" |
d172d4ba NC |
25 | #include "tc-dlx.h" |
26 | #include "opcode/dlx.h" | |
48afb194 TS |
27 | #include "elf/dlx.h" |
28 | #include "bfd/elf32-dlx.h" | |
d172d4ba NC |
29 | |
30 | /* Make it easier to clone this machine desc into another one. */ | |
31 | #define machine_opcode dlx_opcode | |
32 | #define machine_opcodes dlx_opcodes | |
33 | #define machine_ip dlx_ip | |
34 | #define machine_it dlx_it | |
35 | ||
36 | #define NO_RELOC BFD_RELOC_NONE | |
37 | #define RELOC_DLX_REL26 BFD_RELOC_DLX_JMP26 | |
38 | #define RELOC_DLX_16 BFD_RELOC_16 | |
39 | #define RELOC_DLX_REL16 BFD_RELOC_16_PCREL_S2 | |
40 | #define RELOC_DLX_HI16 BFD_RELOC_HI16_S | |
41 | #define RELOC_DLX_LO16 BFD_RELOC_LO16 | |
42 | #define RELOC_DLX_VTINHERIT BFD_RELOC_VTABLE_INHERIT | |
43 | #define RELOC_DLX_VTENTRY BFD_RELOC_VTABLE_ENTRY | |
44 | ||
45 | /* handle of the OPCODE hash table */ | |
46 | static struct hash_control *op_hash = NULL; | |
47 | ||
48 | struct machine_it | |
49 | { | |
50 | char *error; | |
51 | unsigned long opcode; | |
52 | struct nlist *nlistp; | |
53 | expressionS exp; | |
54 | int pcrel; | |
55 | int size; | |
56 | int reloc_offset; /* Offset of reloc within insn. */ | |
4bfaa1ca | 57 | bfd_reloc_code_real_type reloc; |
d172d4ba NC |
58 | int HI; |
59 | int LO; | |
60 | } | |
61 | the_insn; | |
62 | ||
d172d4ba NC |
63 | /* This array holds the chars that always start a comment. If the |
64 | pre-processor is disabled, these aren't very useful. */ | |
65 | const char comment_chars[] = ";"; | |
66 | ||
67 | /* This array holds the chars that only start a comment at the beginning of | |
68 | a line. If the line seems to have the form '# 123 filename' | |
69 | .line and .file directives will appear in the pre-processed output. */ | |
70 | /* Note that input_file.c hand checks for '#' at the beginning of the | |
71 | first line of the input file. This is because the compiler outputs | |
72 | #NO_APP at the beginning of its output. */ | |
73 | /* Also note that comments like this one will always work. */ | |
74 | const char line_comment_chars[] = "#"; | |
75 | ||
76 | /* We needed an unused char for line separation to work around the | |
77 | lack of macros, using sed and such. */ | |
78 | const char line_separator_chars[] = "@"; | |
79 | ||
80 | /* Chars that can be used to separate mant from exp in floating point nums. */ | |
81 | const char EXP_CHARS[] = "eE"; | |
82 | ||
83 | /* Chars that mean this number is a floating point constant. | |
84 | As in 0f12.456 | |
85 | or 0d1.2345e12. */ | |
86 | const char FLT_CHARS[] = "rRsSfFdDxXpP"; | |
87 | ||
88 | static void | |
e0471c16 | 89 | insert_sreg (const char *regname, int regnum) |
d172d4ba NC |
90 | { |
91 | /* Must be large enough to hold the names of the special registers. */ | |
92 | char buf[80]; | |
93 | int i; | |
94 | ||
95 | symbol_table_insert (symbol_new (regname, reg_section, (valueT) regnum, | |
96 | &zero_address_frag)); | |
97 | for (i = 0; regname[i]; i++) | |
98 | buf[i] = ISLOWER (regname[i]) ? TOUPPER (regname[i]) : regname[i]; | |
99 | buf[i] = '\0'; | |
100 | ||
101 | symbol_table_insert (symbol_new (buf, reg_section, (valueT) regnum, | |
102 | &zero_address_frag)); | |
103 | } | |
104 | ||
105 | /* Install symbol definitions for assorted special registers. | |
106 | See MIPS Assembly Language Programmer's Guide page 1-4 */ | |
107 | ||
108 | static void | |
ea1562b3 | 109 | define_some_regs (void) |
d172d4ba | 110 | { |
d172d4ba NC |
111 | /* Software representation. */ |
112 | insert_sreg ("zero", 0); | |
113 | insert_sreg ("at", 1); | |
114 | insert_sreg ("v0", 2); | |
115 | insert_sreg ("v1", 3); | |
116 | insert_sreg ("a0", 4); | |
117 | insert_sreg ("a1", 5); | |
118 | insert_sreg ("a2", 6); | |
119 | insert_sreg ("a3", 7); | |
120 | insert_sreg ("t0", 8); | |
121 | insert_sreg ("t1", 9); | |
122 | insert_sreg ("t2", 10); | |
123 | insert_sreg ("t3", 11); | |
124 | insert_sreg ("t4", 12); | |
125 | insert_sreg ("t5", 13); | |
126 | insert_sreg ("t6", 14); | |
127 | insert_sreg ("t7", 15); | |
128 | insert_sreg ("s0", 16); | |
129 | insert_sreg ("s1", 17); | |
130 | insert_sreg ("s2", 18); | |
131 | insert_sreg ("s3", 19); | |
132 | insert_sreg ("s4", 20); | |
133 | insert_sreg ("s5", 21); | |
134 | insert_sreg ("s6", 22); | |
135 | insert_sreg ("s7", 23); | |
136 | insert_sreg ("t8", 24); | |
137 | insert_sreg ("t9", 25); | |
138 | insert_sreg ("k0", 26); | |
139 | insert_sreg ("k1", 27); | |
140 | insert_sreg ("gp", 28); | |
141 | insert_sreg ("sp", 29); | |
142 | insert_sreg ("fp", 30); | |
143 | insert_sreg ("ra", 31); | |
144 | /* Special registers. */ | |
145 | insert_sreg ("pc", 0); | |
146 | insert_sreg ("npc", 1); | |
147 | insert_sreg ("iad", 2); | |
148 | } | |
149 | ||
ea1562b3 | 150 | /* Subroutine check the string to match an register. */ |
d172d4ba NC |
151 | |
152 | static int | |
ea1562b3 | 153 | match_sft_register (char *name) |
d172d4ba NC |
154 | { |
155 | #define MAX_REG_NO 35 | |
156 | /* Currently we have 35 software registers defined - | |
157 | we borrowed from MIPS. */ | |
e0471c16 | 158 | static const char *soft_reg[] = |
d172d4ba NC |
159 | { |
160 | "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", | |
161 | "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", | |
162 | "s0", "s1", "s2", "s3", "s4", "s5", "s7", "k0", "k1", | |
163 | "gp", "sp", "fp", "ra", "pc", "npc", "iad", | |
164 | "EndofTab" /* End of the Table indicator */ | |
165 | }; | |
166 | char low_name[21], *ptr; | |
167 | int idx; | |
168 | ||
169 | for (ptr = name,idx = 0; *ptr != '\0'; ptr++) | |
170 | low_name[idx++] = TOLOWER (*ptr); | |
171 | ||
172 | low_name[idx] = '\0'; | |
173 | idx = 0; | |
174 | ||
175 | while (idx < MAX_REG_NO && strcmp (soft_reg[idx], & low_name [0])) | |
176 | idx += 1; | |
177 | ||
178 | return idx < MAX_REG_NO; | |
179 | } | |
180 | ||
181 | /* Subroutine check the string to match an register. */ | |
182 | ||
183 | static int | |
ea1562b3 | 184 | is_ldst_registers (char *name) |
d172d4ba NC |
185 | { |
186 | char *ptr = name; | |
187 | ||
188 | /* The first character of the register name got to be either %, $, r of R. */ | |
189 | if ((ptr[0] == '%' || ptr[0] == '$' || ptr[0] == 'r' || ptr[0] == 'R') | |
190 | && ISDIGIT ((unsigned char) ptr[1])) | |
191 | return 1; | |
192 | ||
193 | /* Now check the software register representation. */ | |
194 | return match_sft_register (ptr); | |
195 | } | |
196 | ||
197 | /* Subroutine of s_proc so targets can choose a different default prefix. | |
198 | If DEFAULT_PREFIX is NULL, use the target's "leading char". */ | |
199 | ||
200 | static void | |
ea1562b3 | 201 | s_proc (int end_p) |
d172d4ba NC |
202 | { |
203 | /* Record the current function so that we can issue an error message for | |
204 | misplaced .func,.endfunc, and also so that .endfunc needs no | |
205 | arguments. */ | |
206 | static char *current_name; | |
207 | static char *current_label; | |
208 | ||
209 | if (end_p) | |
210 | { | |
211 | if (current_name == NULL) | |
212 | { | |
213 | as_bad (_("missing .proc")); | |
214 | ignore_rest_of_line (); | |
215 | return; | |
216 | } | |
217 | ||
218 | current_name = current_label = NULL; | |
219 | SKIP_WHITESPACE (); | |
220 | while (!is_end_of_line[(unsigned char) *input_line_pointer]) | |
221 | input_line_pointer++; | |
222 | } | |
223 | else | |
224 | { | |
225 | char *name, *label; | |
226 | char delim1, delim2; | |
227 | ||
228 | if (current_name != NULL) | |
229 | { | |
230 | as_bad (_(".endfunc missing for previous .proc")); | |
231 | ignore_rest_of_line (); | |
232 | return; | |
233 | } | |
234 | ||
d02603dc | 235 | delim1 = get_symbol_name (&name); |
d172d4ba NC |
236 | name = xstrdup (name); |
237 | *input_line_pointer = delim1; | |
d02603dc | 238 | SKIP_WHITESPACE_AFTER_NAME (); |
d172d4ba NC |
239 | |
240 | if (*input_line_pointer != ',') | |
241 | { | |
242 | char leading_char = 0; | |
243 | ||
244 | leading_char = bfd_get_symbol_leading_char (stdoutput); | |
245 | /* Missing entry point, use function's name with the leading | |
246 | char prepended. */ | |
247 | if (leading_char) | |
74cda0c4 | 248 | { |
f3719d90 | 249 | unsigned len = strlen (name) + 1; |
325801bd | 250 | label = XNEWVEC (char, len + 1); |
f3719d90 AM |
251 | label[0] = leading_char; |
252 | memcpy (label + 1, name, len); | |
74cda0c4 | 253 | } |
d172d4ba NC |
254 | else |
255 | label = name; | |
256 | } | |
257 | else | |
258 | { | |
259 | ++input_line_pointer; | |
260 | SKIP_WHITESPACE (); | |
d02603dc | 261 | delim2 = get_symbol_name (&label); |
d172d4ba | 262 | label = xstrdup (label); |
d02603dc | 263 | (void) restore_line_pointer (delim2); |
d172d4ba NC |
264 | } |
265 | ||
266 | current_name = name; | |
267 | current_label = label; | |
268 | } | |
269 | demand_empty_rest_of_line (); | |
270 | } | |
271 | ||
272 | /* This function is called once, at assembler startup time. It should | |
273 | set up all the tables, etc., that the MD part of the assembler will | |
274 | need. */ | |
275 | ||
276 | void | |
ea1562b3 | 277 | md_begin (void) |
d172d4ba NC |
278 | { |
279 | const char *retval = NULL; | |
280 | int lose = 0; | |
281 | unsigned int i; | |
282 | ||
283 | /* Create a new hash table. */ | |
284 | op_hash = hash_new (); | |
285 | ||
286 | /* Hash up all the opcodes for fast use later. */ | |
287 | for (i = 0; i < num_dlx_opcodes; i++) | |
288 | { | |
289 | const char *name = machine_opcodes[i].name; | |
290 | ||
ea1562b3 | 291 | retval = hash_insert (op_hash, name, (void *) &machine_opcodes[i]); |
d172d4ba NC |
292 | |
293 | if (retval != NULL) | |
294 | { | |
b1b17bc5 | 295 | fprintf (stderr, _("internal error: can't hash `%s': %s\n"), |
d172d4ba NC |
296 | machine_opcodes[i].name, retval); |
297 | lose = 1; | |
298 | } | |
299 | } | |
300 | ||
301 | if (lose) | |
302 | as_fatal (_("Broken assembler. No assembly attempted.")); | |
303 | ||
304 | define_some_regs (); | |
d172d4ba NC |
305 | } |
306 | ||
d172d4ba NC |
307 | /* This function will check the opcode and return 1 if the opcode is one |
308 | of the load/store instruction, and it will fix the operand string to | |
309 | the standard form so we can use the standard parse_operand routine. */ | |
310 | ||
311 | #define READ_OP 0x100 | |
312 | #define WRITE_OP 0x200 | |
313 | static char iBuf[81]; | |
314 | ||
315 | static char * | |
ea1562b3 | 316 | dlx_parse_loadop (char * str) |
d172d4ba NC |
317 | { |
318 | char *ptr = str; | |
319 | int idx = 0; | |
320 | ||
321 | /* The last pair of ()/[] is the register, all other are the | |
322 | reloc displacement, and if there is a register then it ought | |
323 | to have a pair of ()/[] | |
324 | This is not necessarily true, what if the load instruction come | |
325 | without the register and with %hi/%lo modifier? */ | |
326 | for (idx = 0; idx < 72 && ptr[idx] != '\0'; idx++) | |
327 | ; | |
328 | ||
329 | if (idx == 72) | |
330 | { | |
331 | badoperand_load: | |
332 | as_bad (_("Bad operand for a load instruction: <%s>"), str); | |
333 | return NULL; | |
334 | } | |
335 | else | |
336 | { | |
337 | int i, pb = 0; | |
338 | int m2 = 0; | |
339 | char rs1[7], rd[7], endm, match = '0'; | |
340 | char imm[72]; | |
341 | ||
342 | idx -= 1; | |
343 | switch (str[idx]) | |
344 | { | |
345 | case ')': | |
346 | match = '('; | |
347 | endm = ')'; | |
348 | break; | |
349 | case ']': | |
350 | match = '['; | |
351 | endm = ']'; | |
352 | break; | |
353 | default: | |
354 | /* No register indicated, fill in zero. */ | |
355 | rs1[0] = 'r'; | |
356 | rs1[1] = '0'; | |
357 | rs1[2] = '\0'; | |
358 | match = 0; | |
359 | endm = 0; | |
360 | m2 = 1; | |
361 | } | |
362 | ||
363 | if (!m2) | |
364 | { | |
365 | /* Searching for (/[ which will match the ]/). */ | |
366 | for (pb = idx - 1; str[pb] != match; pb -= 1) | |
367 | /* Match can only be either '[' or '(', if it is | |
c03099e6 | 368 | '(' then this can be a normal expression, we'll treat |
d172d4ba NC |
369 | it as an operand. */ |
370 | if (str[pb] == endm || pb < (idx - 5)) | |
371 | goto load_no_rs1; | |
372 | pb += 1; | |
373 | ||
374 | for (i = 0; (pb + i) < idx; i++) | |
375 | rs1[i] = str[pb+i]; | |
376 | ||
377 | rs1[i] = '\0'; | |
378 | ||
379 | if (is_ldst_registers (& rs1[0])) | |
380 | /* Point to the last character of the imm. */ | |
381 | pb -= 1; | |
382 | else | |
383 | { | |
384 | load_no_rs1: | |
385 | if (match == '[') | |
386 | goto badoperand_load; | |
387 | /* No register indicated, fill in zero and restore the imm. */ | |
388 | rs1[0] = 'r'; | |
389 | rs1[1] = '0'; | |
390 | rs1[2] = '\0'; | |
391 | m2 = 1; | |
392 | } | |
393 | } | |
394 | ||
395 | /* Duplicate the first register. */ | |
396 | for (i = 0; i < 7 && str[i] != ','; i++) | |
397 | rd[i] = ptr[i]; | |
398 | ||
399 | if (str[i] != ',') | |
400 | goto badoperand_load; | |
401 | else | |
402 | rd[i] = '\0'; | |
403 | ||
404 | /* Copy the immd. */ | |
405 | if (m2) | |
406 | /* Put the '\0' back in. */ | |
407 | pb = idx + 1; | |
408 | ||
409 | for (i++, m2 = 0; i < pb; m2++,i++) | |
410 | imm[m2] = ptr[i]; | |
411 | ||
412 | imm[m2] = '\0'; | |
413 | ||
2d2255b5 | 414 | /* Assemble the instruction to gas internal format. */ |
d172d4ba NC |
415 | for (i = 0; rd[i] != '\0'; i++) |
416 | iBuf[i] = rd[i]; | |
417 | ||
418 | iBuf[i++] = ','; | |
419 | ||
420 | for (pb = 0 ; rs1[pb] != '\0'; i++, pb++) | |
421 | iBuf[i] = rs1[pb]; | |
422 | ||
423 | iBuf[i++] = ','; | |
424 | ||
425 | for (pb = 0; imm[pb] != '\0'; i++, pb++) | |
426 | iBuf[i] = imm[pb]; | |
427 | ||
428 | iBuf[i] = '\0'; | |
429 | return iBuf; | |
430 | } | |
431 | } | |
432 | ||
433 | static char * | |
ea1562b3 | 434 | dlx_parse_storeop (char * str) |
d172d4ba NC |
435 | { |
436 | char *ptr = str; | |
437 | int idx = 0; | |
438 | ||
439 | /* Search for the ','. */ | |
440 | for (idx = 0; idx < 72 && ptr[idx] != ','; idx++) | |
441 | ; | |
442 | ||
443 | if (idx == 72) | |
444 | { | |
445 | badoperand_store: | |
446 | as_bad (_("Bad operand for a store instruction: <%s>"), str); | |
447 | return NULL; | |
448 | } | |
449 | else | |
450 | { | |
451 | /* idx now points to the ','. */ | |
452 | int i, pb = 0; | |
453 | int comma = idx; | |
454 | int m2 = 0; | |
455 | char rs1[7], rd[7], endm, match = '0'; | |
456 | char imm[72]; | |
457 | ||
458 | /* Now parse the '(' and ')', and make idx point to ')'. */ | |
459 | idx -= 1; | |
460 | switch (str[idx]) | |
461 | { | |
462 | case ')': | |
463 | match = '('; | |
464 | endm = ')'; | |
465 | break; | |
466 | case ']': | |
467 | match = '['; | |
468 | endm = ']'; | |
469 | break; | |
470 | default: | |
471 | /* No register indicated, fill in zero. */ | |
472 | rs1[0] = 'r'; | |
473 | rs1[1] = '0'; | |
474 | rs1[2] = '\0'; | |
475 | match = 0; | |
476 | endm = 0; | |
477 | m2 = 1; | |
478 | } | |
479 | ||
480 | if (!m2) | |
481 | { | |
482 | /* Searching for (/[ which will match the ]/). */ | |
483 | for (pb = idx - 1; str[pb] != match; pb -= 1) | |
484 | if (pb < (idx - 5) || str[pb] == endm) | |
485 | goto store_no_rs1; | |
486 | pb += 1; | |
487 | ||
488 | for (i = 0; (pb + i) < idx; i++) | |
489 | rs1[i] = str[pb + i]; | |
490 | ||
491 | rs1[i] = '\0'; | |
492 | ||
493 | if (is_ldst_registers (& rs1[0])) | |
494 | /* Point to the last character of the imm. */ | |
495 | pb -= 1; | |
496 | else | |
497 | { | |
498 | store_no_rs1: | |
499 | if (match == '[') | |
500 | goto badoperand_store; | |
501 | ||
502 | /* No register indicated, fill in zero and restore the imm. */ | |
503 | rs1[0] = 'r'; | |
504 | rs1[1] = '0'; | |
505 | rs1[2] = '\0'; | |
506 | pb = comma; | |
507 | } | |
508 | } | |
509 | else | |
510 | /* No register was specified. */ | |
511 | pb = comma; | |
512 | ||
513 | /* Duplicate the first register. */ | |
514 | for (i = comma + 1; (str[i] == ' ' || str[i] == '\t'); i++) | |
515 | ; | |
516 | ||
517 | for (m2 = 0; (m2 < 7 && str[i] != '\0'); i++, m2++) | |
518 | { | |
519 | if (str[i] != ' ' && str[i] != '\t') | |
520 | rd[m2] = str[i]; | |
521 | else | |
522 | goto badoperand_store; | |
523 | } | |
524 | ||
525 | if (str[i] != '\0') | |
526 | goto badoperand_store; | |
527 | else | |
528 | rd[m2] = '\0'; | |
529 | ||
530 | /* Copy the immd. */ | |
531 | for (i = 0; i < pb; i++) | |
532 | imm[i] = ptr[i]; | |
533 | ||
534 | imm[i] = '\0'; | |
535 | ||
2d2255b5 | 536 | /* Assemble the instruction to gas internal format. */ |
d172d4ba NC |
537 | for (i = 0; rd[i] != '\0'; i++) |
538 | iBuf[i] = rd[i]; | |
539 | iBuf[i++] = ','; | |
540 | for (pb = 0 ; rs1[pb] != '\0'; i++, pb++) | |
541 | iBuf[i] = rs1[pb]; | |
542 | iBuf[i++] = ','; | |
543 | for (pb = 0; imm[pb] != '\0'; i++, pb++) | |
544 | iBuf[i] = imm[pb]; | |
545 | iBuf[i] = '\0'; | |
546 | return iBuf; | |
547 | } | |
548 | } | |
549 | ||
550 | static char * | |
ea1562b3 | 551 | fix_ld_st_operand (unsigned long opcode, char* str) |
d172d4ba NC |
552 | { |
553 | /* Check the opcode. */ | |
554 | switch ((int) opcode) | |
555 | { | |
556 | case LBOP: | |
557 | case LBUOP: | |
558 | case LSBUOP: | |
559 | case LHOP: | |
560 | case LHUOP: | |
561 | case LSHUOP: | |
562 | case LWOP: | |
563 | case LSWOP: | |
564 | return dlx_parse_loadop (str); | |
565 | case SBOP: | |
566 | case SHOP: | |
567 | case SWOP: | |
568 | return dlx_parse_storeop (str); | |
569 | default: | |
570 | return str; | |
571 | } | |
572 | } | |
573 | ||
ea1562b3 NC |
574 | static int |
575 | hilo_modifier_ok (char *s) | |
576 | { | |
577 | char *ptr = s; | |
578 | int idx, count = 1; | |
579 | ||
580 | if (*ptr != '(') | |
581 | return 1; | |
582 | ||
583 | for (idx = 1; ptr[idx] != '\0' && ptr[idx] != '[' && idx < 73; idx += 1) | |
584 | { | |
585 | if (count == 0) | |
586 | return count; | |
587 | ||
588 | if (ptr[idx] == '(') | |
589 | count += 1; | |
590 | ||
591 | if (ptr[idx] == ')') | |
592 | count -= 1; | |
593 | } | |
594 | ||
595 | return (count == 0) ? 1:0; | |
596 | } | |
597 | ||
598 | static char * | |
599 | parse_operand (char *s, expressionS *operandp) | |
600 | { | |
601 | char *save = input_line_pointer; | |
d3ce72d0 | 602 | char *new_pos; |
ea1562b3 NC |
603 | |
604 | the_insn.HI = the_insn.LO = 0; | |
605 | ||
606 | /* Search for %hi and %lo, make a mark and skip it. */ | |
607 | if (strncmp (s, "%hi", 3) == 0) | |
608 | { | |
609 | s += 3; | |
610 | the_insn.HI = 1; | |
611 | } | |
612 | else | |
613 | { | |
614 | if (strncmp (s, "%lo", 3) == 0) | |
615 | { | |
616 | s += 3; | |
617 | the_insn.LO = 1; | |
618 | } | |
619 | else | |
620 | the_insn.LO = 0; | |
621 | } | |
622 | ||
623 | if (the_insn.HI || the_insn.LO) | |
624 | { | |
625 | if (!hilo_modifier_ok (s)) | |
626 | as_bad (_("Expression Error for operand modifier %%hi/%%lo\n")); | |
627 | } | |
628 | ||
629 | /* Check for the % and $ register representation */ | |
630 | if ((s[0] == '%' || s[0] == '$' || s[0] == 'r' || s[0] == 'R') | |
631 | && ISDIGIT ((unsigned char) s[1])) | |
632 | { | |
633 | /* We have a numeric register expression. No biggy. */ | |
634 | s += 1; | |
635 | input_line_pointer = s; | |
636 | (void) expression (operandp); | |
637 | if (operandp->X_op != O_constant | |
638 | || operandp->X_add_number > 31) | |
639 | as_bad (_("Invalid expression after %%%%\n")); | |
640 | operandp->X_op = O_register; | |
641 | } | |
642 | else | |
643 | { | |
644 | /* Normal operand parsing. */ | |
645 | input_line_pointer = s; | |
646 | (void) expression (operandp); | |
647 | } | |
648 | ||
d3ce72d0 | 649 | new_pos = input_line_pointer; |
ea1562b3 | 650 | input_line_pointer = save; |
d3ce72d0 | 651 | return new_pos; |
ea1562b3 NC |
652 | } |
653 | ||
d172d4ba NC |
654 | /* Instruction parsing. Takes a string containing the opcode. |
655 | Operands are at input_line_pointer. Output is in the_insn. | |
656 | Warnings or errors are generated. */ | |
657 | ||
658 | static void | |
ea1562b3 | 659 | machine_ip (char *str) |
d172d4ba NC |
660 | { |
661 | char *s; | |
662 | const char *args; | |
663 | struct machine_opcode *insn; | |
d172d4ba NC |
664 | unsigned long opcode; |
665 | expressionS the_operand; | |
666 | expressionS *operand = &the_operand; | |
667 | unsigned int reg, reg_shift = 0; | |
668 | ||
97d24fbb AM |
669 | memset (&the_insn, '\0', sizeof (the_insn)); |
670 | the_insn.reloc = NO_RELOC; | |
671 | ||
d172d4ba NC |
672 | /* Fixup the opcode string to all lower cases, and also |
673 | allow numerical digits. */ | |
674 | s = str; | |
675 | ||
676 | if (ISALPHA (*s)) | |
677 | for (; ISALNUM (*s); ++s) | |
678 | if (ISUPPER (*s)) | |
679 | *s = TOLOWER (*s); | |
680 | ||
681 | switch (*s) | |
682 | { | |
683 | case '\0': | |
684 | break; | |
685 | ||
686 | /* FIXME-SOMEDAY more whitespace. */ | |
687 | case ' ': | |
688 | *s++ = '\0'; | |
689 | break; | |
690 | ||
691 | default: | |
692 | as_bad (_("Unknown opcode: `%s'"), str); | |
693 | return; | |
694 | } | |
695 | ||
97d24fbb | 696 | /* Hash the opcode, insn will have the string from opcode table. */ |
d172d4ba NC |
697 | if ((insn = (struct machine_opcode *) hash_find (op_hash, str)) == NULL) |
698 | { | |
699 | /* Handle the ret and return macro here. */ | |
700 | if ((strcmp (str, "ret") == 0) || (strcmp (str, "return") == 0)) | |
97d24fbb | 701 | the_insn.opcode = JROP | 0x03e00000; /* 0x03e00000 = r31 << 21 */ |
d172d4ba NC |
702 | else |
703 | as_bad (_("Unknown opcode `%s'."), str); | |
704 | ||
705 | return; | |
706 | } | |
707 | ||
d172d4ba | 708 | opcode = insn->opcode; |
d172d4ba NC |
709 | |
710 | /* Set the sip reloc HI16 flag. */ | |
711 | if (!set_dlx_skip_hi16_flag (1)) | |
712 | as_bad (_("Can not set dlx_skip_hi16_flag")); | |
713 | ||
714 | /* Fix the operand string if it is one of load store instructions. */ | |
715 | s = fix_ld_st_operand (opcode, s); | |
716 | ||
717 | /* Build the opcode, checking as we go to make sure that the | |
718 | operands match. | |
719 | If an operand matches, we modify the_insn or opcode appropriately, | |
720 | and do a "continue". If an operand fails to match, we "break". */ | |
721 | if (insn->args[0] != '\0' && insn->args[0] != 'N') | |
722 | { | |
723 | /* Prime the pump. */ | |
724 | if (*s == '\0') | |
725 | { | |
726 | as_bad (_("Missing arguments for opcode <%s>."), str); | |
727 | return; | |
728 | } | |
729 | else | |
730 | s = parse_operand (s, operand); | |
731 | } | |
732 | else if (insn->args[0] == 'N') | |
733 | { | |
734 | /* Clean up the insn and done! */ | |
735 | the_insn.opcode = opcode; | |
736 | return; | |
737 | } | |
738 | ||
739 | /* Parse through the args (this is from opcode table), *s point to | |
740 | the current character of the instruction stream. */ | |
741 | for (args = insn->args;; ++args) | |
742 | { | |
743 | switch (*args) | |
744 | { | |
745 | /* End of Line. */ | |
746 | case '\0': | |
747 | /* End of args. */ | |
748 | if (*s == '\0') | |
749 | { | |
750 | /* We are truly done. */ | |
751 | the_insn.opcode = opcode; | |
752 | /* Clean up the HI and LO mark. */ | |
753 | the_insn.HI = 0; | |
754 | the_insn.LO = 0; | |
755 | return; | |
756 | } | |
757 | ||
758 | the_insn.HI = 0; | |
759 | the_insn.LO = 0; | |
760 | as_bad (_("Too many operands: %s"), s); | |
761 | break; | |
762 | ||
763 | /* ',' Args separator */ | |
764 | case ',': | |
765 | /* Must match a comma. */ | |
766 | if (*s++ == ',') | |
767 | { | |
768 | /* Parse next operand. */ | |
769 | s = parse_operand (s, operand); | |
770 | continue; | |
771 | } | |
772 | break; | |
773 | ||
774 | /* It can be a 'a' register or 'i' operand. */ | |
775 | case 'P': | |
776 | /* Macro move operand/reg. */ | |
777 | if (operand->X_op == O_register) | |
778 | { | |
33eaf5de | 779 | /* It's a register. */ |
d172d4ba NC |
780 | reg_shift = 21; |
781 | goto general_reg; | |
782 | } | |
1a0670f3 | 783 | /* Fall through. */ |
d172d4ba NC |
784 | |
785 | /* The immediate 16 bits literal, bit 0-15. */ | |
786 | case 'i': | |
787 | /* offset, unsigned. */ | |
788 | case 'I': | |
789 | /* offset, signed. */ | |
790 | if (operand->X_op == O_constant) | |
791 | { | |
792 | if (the_insn.HI) | |
793 | operand->X_add_number >>= 16; | |
794 | ||
795 | opcode |= operand->X_add_number & 0xFFFF; | |
796 | ||
797 | if (the_insn.HI && the_insn.LO) | |
798 | as_bad (_("Both the_insn.HI and the_insn.LO are set : %s"), s); | |
799 | else | |
800 | { | |
801 | the_insn.HI = 0; | |
802 | the_insn.LO = 0; | |
803 | } | |
804 | continue; | |
805 | } | |
806 | ||
3739860c | 807 | the_insn.reloc = (the_insn.HI) ? RELOC_DLX_HI16 |
a7844384 | 808 | : (the_insn.LO ? RELOC_DLX_LO16 : RELOC_DLX_16); |
d172d4ba NC |
809 | the_insn.reloc_offset = 2; |
810 | the_insn.size = 2; | |
811 | the_insn.pcrel = 0; | |
812 | the_insn.exp = * operand; | |
813 | the_insn.HI = 0; | |
814 | the_insn.LO = 0; | |
815 | continue; | |
816 | ||
817 | case 'd': | |
818 | /* offset, signed. */ | |
819 | if (operand->X_op == O_constant) | |
820 | { | |
821 | opcode |= operand->X_add_number & 0xFFFF; | |
822 | continue; | |
823 | } | |
824 | the_insn.reloc = RELOC_DLX_REL16; | |
825 | the_insn.reloc_offset = 0; /* BIG-ENDIAN Byte 3 of insn. */ | |
826 | the_insn.size = 4; | |
827 | the_insn.pcrel = 1; | |
828 | the_insn.exp = *operand; | |
829 | continue; | |
830 | ||
831 | /* The immediate 26 bits literal, bit 0-25. */ | |
832 | case 'D': | |
833 | /* offset, signed. */ | |
834 | if (operand->X_op == O_constant) | |
835 | { | |
836 | opcode |= operand->X_add_number & 0x3FFFFFF; | |
837 | continue; | |
838 | } | |
839 | the_insn.reloc = RELOC_DLX_REL26; | |
840 | the_insn.reloc_offset = 0; /* BIG-ENDIAN Byte 3 of insn. */ | |
841 | the_insn.size = 4; | |
842 | the_insn.pcrel = 1; | |
843 | the_insn.exp = *operand; | |
844 | continue; | |
845 | ||
846 | /* Type 'a' Register. */ | |
847 | case 'a': | |
848 | /* A general register at bits 21-25, rs1. */ | |
d172d4ba NC |
849 | reg_shift = 21; |
850 | goto general_reg; | |
851 | ||
852 | /* Type 'b' Register. */ | |
853 | case 'b': | |
854 | /* A general register at bits 16-20, rs2/rd. */ | |
d172d4ba NC |
855 | reg_shift = 16; |
856 | goto general_reg; | |
857 | ||
858 | /* Type 'c' Register. */ | |
859 | case 'c': | |
860 | /* A general register at bits 11-15, rd. */ | |
d172d4ba NC |
861 | reg_shift = 11; |
862 | ||
863 | general_reg: | |
864 | know (operand->X_add_symbol == 0); | |
865 | know (operand->X_op_symbol == 0); | |
866 | reg = operand->X_add_number; | |
867 | if (reg & 0xffffffe0) | |
868 | as_fatal (_("failed regnum sanity check.")); | |
869 | else | |
870 | /* Got the register, now figure out where it goes in the opcode. */ | |
871 | opcode |= reg << reg_shift; | |
872 | ||
873 | switch (*args) | |
874 | { | |
875 | case 'a': | |
876 | case 'b': | |
877 | case 'c': | |
878 | case 'P': | |
879 | continue; | |
880 | } | |
881 | as_fatal (_("failed general register sanity check.")); | |
882 | break; | |
883 | ||
884 | default: | |
885 | BAD_CASE (*args); | |
886 | } | |
887 | ||
888 | /* Types or values of args don't match. */ | |
b1b17bc5 | 889 | as_bad (_("Invalid operands")); |
d172d4ba NC |
890 | return; |
891 | } | |
892 | } | |
893 | ||
ea1562b3 NC |
894 | /* Assemble a single instruction. Its label has already been handled |
895 | by the generic front end. We just parse opcode and operands, and | |
896 | produce the bytes of data and relocation. */ | |
897 | ||
898 | void | |
899 | md_assemble (char *str) | |
900 | { | |
901 | char *toP; | |
902 | fixS *fixP; | |
903 | bit_fixS *bitP; | |
904 | ||
905 | know (str); | |
906 | machine_ip (str); | |
907 | toP = frag_more (4); | |
d4f4f3fb AM |
908 | dwarf2_emit_insn (4); |
909 | ||
ea1562b3 NC |
910 | /* Put out the opcode. */ |
911 | md_number_to_chars (toP, the_insn.opcode, 4); | |
912 | ||
913 | /* Put out the symbol-dependent stuff. */ | |
914 | if (the_insn.reloc != NO_RELOC) | |
915 | { | |
916 | fixP = fix_new_exp (frag_now, | |
917 | (toP - frag_now->fr_literal + the_insn.reloc_offset), | |
918 | the_insn.size, & the_insn.exp, the_insn.pcrel, | |
919 | the_insn.reloc); | |
920 | ||
921 | /* Turn off complaints that the addend is | |
922 | too large for things like foo+100000@ha. */ | |
923 | switch (the_insn.reloc) | |
924 | { | |
925 | case RELOC_DLX_HI16: | |
926 | case RELOC_DLX_LO16: | |
927 | fixP->fx_no_overflow = 1; | |
928 | break; | |
929 | default: | |
930 | break; | |
931 | } | |
932 | ||
933 | switch (fixP->fx_r_type) | |
934 | { | |
935 | case RELOC_DLX_REL26: | |
325801bd | 936 | bitP = XNEW (bit_fixS); |
ea1562b3 NC |
937 | bitP->fx_bit_size = 26; |
938 | bitP->fx_bit_offset = 25; | |
939 | bitP->fx_bit_base = the_insn.opcode & 0xFC000000; | |
940 | bitP->fx_bit_base_adj = 0; | |
941 | bitP->fx_bit_max = 0; | |
942 | bitP->fx_bit_min = 0; | |
943 | bitP->fx_bit_add = 0x03FFFFFF; | |
944 | fixP->fx_bit_fixP = bitP; | |
945 | break; | |
946 | case RELOC_DLX_LO16: | |
947 | case RELOC_DLX_REL16: | |
325801bd | 948 | bitP = XNEW (bit_fixS); |
ea1562b3 NC |
949 | bitP->fx_bit_size = 16; |
950 | bitP->fx_bit_offset = 15; | |
951 | bitP->fx_bit_base = the_insn.opcode & 0xFFFF0000; | |
952 | bitP->fx_bit_base_adj = 0; | |
953 | bitP->fx_bit_max = 0; | |
954 | bitP->fx_bit_min = 0; | |
955 | bitP->fx_bit_add = 0x0000FFFF; | |
956 | fixP->fx_bit_fixP = bitP; | |
957 | break; | |
958 | case RELOC_DLX_HI16: | |
325801bd | 959 | bitP = XNEW (bit_fixS); |
ea1562b3 NC |
960 | bitP->fx_bit_size = 16; |
961 | bitP->fx_bit_offset = 15; | |
962 | bitP->fx_bit_base = the_insn.opcode & 0xFFFF0000; | |
963 | bitP->fx_bit_base_adj = 0; | |
964 | bitP->fx_bit_max = 0; | |
965 | bitP->fx_bit_min = 0; | |
966 | bitP->fx_bit_add = 0x0000FFFF; | |
967 | fixP->fx_bit_fixP = bitP; | |
968 | break; | |
969 | default: | |
970 | fixP->fx_bit_fixP = NULL; | |
971 | break; | |
972 | } | |
973 | } | |
974 | } | |
975 | ||
d172d4ba | 976 | /* This is identical to the md_atof in m68k.c. I think this is right, |
499ac353 NC |
977 | but I'm not sure. Dlx will not use it anyway, so I just leave it |
978 | here for now. */ | |
d172d4ba | 979 | |
6d4af3c2 | 980 | const char * |
ea1562b3 | 981 | md_atof (int type, char *litP, int *sizeP) |
d172d4ba | 982 | { |
499ac353 | 983 | return ieee_md_atof (type, litP, sizeP, TRUE); |
d172d4ba NC |
984 | } |
985 | ||
986 | /* Write out big-endian. */ | |
987 | void | |
ea1562b3 | 988 | md_number_to_chars (char *buf, valueT val, int n) |
d172d4ba NC |
989 | { |
990 | number_to_chars_bigendian (buf, val, n); | |
991 | } | |
992 | ||
b34976b6 | 993 | bfd_boolean |
ea1562b3 | 994 | md_dlx_fix_adjustable (fixS *fixP) |
d172d4ba NC |
995 | { |
996 | /* We need the symbol name for the VTABLE entries. */ | |
a161fe53 AM |
997 | return (fixP->fx_r_type != BFD_RELOC_VTABLE_INHERIT |
998 | && fixP->fx_r_type != BFD_RELOC_VTABLE_ENTRY); | |
d172d4ba NC |
999 | } |
1000 | ||
1001 | void | |
55cf6793 | 1002 | md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) |
d172d4ba NC |
1003 | { |
1004 | long val = *valP; | |
1005 | char *place = fixP->fx_where + fixP->fx_frag->fr_literal; | |
1006 | ||
d172d4ba NC |
1007 | switch (fixP->fx_r_type) |
1008 | { | |
a7844384 | 1009 | case RELOC_DLX_LO16: |
d172d4ba | 1010 | case RELOC_DLX_REL16: |
ea1562b3 | 1011 | if (fixP->fx_bit_fixP != NULL) |
d172d4ba NC |
1012 | { |
1013 | val = (val & 0x0000FFFF) | fixP->fx_bit_fixP->fx_bit_base; | |
1014 | free (fixP->fx_bit_fixP); | |
ea1562b3 | 1015 | fixP->fx_bit_fixP = NULL; |
d172d4ba | 1016 | } |
d172d4ba NC |
1017 | break; |
1018 | ||
1019 | case RELOC_DLX_HI16: | |
ea1562b3 | 1020 | if (fixP->fx_bit_fixP != NULL) |
d172d4ba NC |
1021 | { |
1022 | val = (val >> 16) | fixP->fx_bit_fixP->fx_bit_base; | |
1023 | free (fixP->fx_bit_fixP); | |
ea1562b3 | 1024 | fixP->fx_bit_fixP = NULL; |
d172d4ba | 1025 | } |
d172d4ba NC |
1026 | break; |
1027 | ||
1028 | case RELOC_DLX_REL26: | |
ea1562b3 | 1029 | if (fixP->fx_bit_fixP != NULL) |
d172d4ba NC |
1030 | { |
1031 | val = (val & 0x03FFFFFF) | fixP->fx_bit_fixP->fx_bit_base; | |
1032 | free (fixP->fx_bit_fixP); | |
ea1562b3 | 1033 | fixP->fx_bit_fixP = NULL; |
d172d4ba | 1034 | } |
d172d4ba NC |
1035 | break; |
1036 | ||
1037 | case BFD_RELOC_VTABLE_INHERIT: | |
1038 | /* This borrowed from tc-ppc.c on a whim. */ | |
1039 | fixP->fx_done = 0; | |
1040 | if (fixP->fx_addsy | |
1041 | && !S_IS_DEFINED (fixP->fx_addsy) | |
1042 | && !S_IS_WEAK (fixP->fx_addsy)) | |
1043 | S_SET_WEAK (fixP->fx_addsy); | |
1044 | return; | |
1045 | ||
1046 | case BFD_RELOC_VTABLE_ENTRY: | |
1047 | fixP->fx_done = 0; | |
1048 | return; | |
1049 | ||
1050 | default: | |
1051 | break; | |
1052 | } | |
1053 | ||
1054 | number_to_chars_bigendian (place, val, fixP->fx_size); | |
a161fe53 | 1055 | if (fixP->fx_addsy == NULL) |
d172d4ba | 1056 | fixP->fx_done = 1; |
5bc11336 AM |
1057 | if (fixP->fx_bit_fixP != NULL) |
1058 | fixP->fx_no_overflow = 1; | |
d172d4ba NC |
1059 | } |
1060 | ||
5a38dc70 | 1061 | const char *md_shortopts = ""; |
d172d4ba NC |
1062 | |
1063 | struct option md_longopts[] = | |
1064 | { | |
1065 | {NULL, no_argument, NULL, 0} | |
1066 | }; | |
1067 | ||
1068 | size_t md_longopts_size = sizeof (md_longopts); | |
1069 | ||
1070 | int | |
ea1562b3 | 1071 | md_parse_option (int c ATTRIBUTE_UNUSED, |
17b9d67d | 1072 | const char *arg ATTRIBUTE_UNUSED) |
d172d4ba NC |
1073 | { |
1074 | return 0; | |
1075 | } | |
1076 | ||
1077 | void | |
ea1562b3 | 1078 | md_show_usage (FILE *stream ATTRIBUTE_UNUSED) |
d172d4ba | 1079 | { |
d172d4ba NC |
1080 | } |
1081 | ||
1082 | /* This is called when a line is unrecognized. */ | |
1083 | ||
1084 | int | |
ea1562b3 | 1085 | dlx_unrecognized_line (int c) |
d172d4ba NC |
1086 | { |
1087 | int lab; | |
1088 | char *s; | |
1089 | ||
1090 | if (c != '$' || ! ISDIGIT ((unsigned char) input_line_pointer[0])) | |
1091 | return 0; | |
1092 | ||
1093 | s = input_line_pointer; | |
1094 | ||
1095 | lab = 0; | |
1096 | while (ISDIGIT ((unsigned char) *s)) | |
1097 | { | |
1098 | lab = lab * 10 + *s - '0'; | |
1099 | ++s; | |
1100 | } | |
1101 | ||
1102 | if (*s != ':') | |
ea1562b3 NC |
1103 | /* Not a label definition. */ |
1104 | return 0; | |
d172d4ba NC |
1105 | |
1106 | if (dollar_label_defined (lab)) | |
1107 | { | |
1108 | as_bad (_("label \"$%d\" redefined"), lab); | |
1109 | return 0; | |
1110 | } | |
1111 | ||
1112 | define_dollar_label (lab); | |
1113 | colon (dollar_label_name (lab, 0)); | |
1114 | input_line_pointer = s + 1; | |
1115 | ||
1116 | return 1; | |
1117 | } | |
1118 | ||
1119 | /* Default the values of symbols known that should be "predefined". We | |
1120 | don't bother to predefine them unless you actually use one, since there | |
1121 | are a lot of them. */ | |
1122 | ||
1123 | symbolS * | |
ea1562b3 | 1124 | md_undefined_symbol (char *name ATTRIBUTE_UNUSED) |
d172d4ba NC |
1125 | { |
1126 | return NULL; | |
1127 | } | |
1128 | ||
d172d4ba | 1129 | /* Parse an operand that is machine-specific, the function was called |
2d2255b5 | 1130 | in expr.c by operand() function, when everything failed before it |
d172d4ba NC |
1131 | call a quit. */ |
1132 | ||
1133 | void | |
ea1562b3 | 1134 | md_operand (expressionS* expressionP) |
d172d4ba NC |
1135 | { |
1136 | /* Check for the #number representation */ | |
1137 | if (input_line_pointer[0] == '#' && | |
1138 | ISDIGIT ((unsigned char) input_line_pointer[1])) | |
1139 | { | |
1140 | /* We have a numeric number expression. No biggy. */ | |
1141 | input_line_pointer += 1; /* Skip # */ | |
1142 | ||
1143 | (void) expression (expressionP); | |
1144 | ||
1145 | if (expressionP->X_op != O_constant) | |
1146 | as_bad (_("Invalid expression after # number\n")); | |
1147 | } | |
1148 | ||
1149 | return; | |
d172d4ba NC |
1150 | } |
1151 | ||
1152 | /* Round up a section size to the appropriate boundary. */ | |
1153 | ||
1154 | valueT | |
ea1562b3 NC |
1155 | md_section_align (segT segment ATTRIBUTE_UNUSED, |
1156 | valueT size) | |
d172d4ba NC |
1157 | { |
1158 | /* Byte alignment is fine. */ | |
1159 | return size; | |
1160 | } | |
1161 | ||
1162 | /* Exactly what point is a PC-relative offset relative TO? | |
1163 | On the 29000, they're relative to the address of the instruction, | |
1164 | which we have set up as the address of the fixup too. */ | |
1165 | ||
1166 | long | |
ea1562b3 | 1167 | md_pcrel_from (fixS* fixP) |
d172d4ba NC |
1168 | { |
1169 | return 4 + fixP->fx_where + fixP->fx_frag->fr_address; | |
1170 | } | |
1171 | ||
d172d4ba NC |
1172 | /* Translate internal representation of relocation info to BFD target |
1173 | format. | |
1174 | FIXME: To what extent can we get all relevant targets to use this? | |
1175 | The above FIXME is from a29k, but I think it is also needed here. */ | |
1176 | ||
1177 | arelent * | |
ea1562b3 NC |
1178 | tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, |
1179 | fixS *fixP) | |
d172d4ba NC |
1180 | { |
1181 | arelent * reloc; | |
1182 | ||
325801bd | 1183 | reloc = XNEW (arelent); |
d172d4ba NC |
1184 | reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type); |
1185 | ||
ea1562b3 | 1186 | if (reloc->howto == NULL) |
d172d4ba NC |
1187 | { |
1188 | as_bad_where (fixP->fx_file, fixP->fx_line, | |
b1b17bc5 | 1189 | _("internal error: can't export reloc type %d (`%s')"), |
d172d4ba NC |
1190 | fixP->fx_r_type, |
1191 | bfd_get_reloc_code_name (fixP->fx_r_type)); | |
1192 | return NULL; | |
1193 | } | |
1194 | ||
9c2799c2 | 1195 | gas_assert (!fixP->fx_pcrel == !reloc->howto->pc_relative); |
d172d4ba | 1196 | |
325801bd | 1197 | reloc->sym_ptr_ptr = XNEW (asymbol *); |
d172d4ba NC |
1198 | *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy); |
1199 | reloc->address = fixP->fx_frag->fr_address + fixP->fx_where; | |
1200 | ||
a161fe53 AM |
1201 | if (fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) |
1202 | reloc->address = fixP->fx_offset; | |
1203 | reloc->addend = 0; | |
1204 | ||
d172d4ba NC |
1205 | return reloc; |
1206 | } | |
1207 | ||
ea1562b3 NC |
1208 | const pseudo_typeS |
1209 | dlx_pseudo_table[] = | |
1210 | { | |
1211 | /* Some additional ops that are used by gcc-dlx. */ | |
38a57ae7 | 1212 | {"asciiz", stringer, 8 + 1}, |
ea1562b3 NC |
1213 | {"half", cons, 2}, |
1214 | {"dword", cons, 8}, | |
1215 | {"word", cons, 4}, | |
1216 | {"proc", s_proc, 0}, | |
1217 | {"endproc", s_proc, 1}, | |
1218 | {NULL, NULL, 0} | |
1219 | }; | |
d172d4ba NC |
1220 | |
1221 | void | |
ea1562b3 | 1222 | dlx_pop_insert (void) |
d172d4ba NC |
1223 | { |
1224 | pop_insert (dlx_pseudo_table); | |
1225 | return ; | |
1226 | } |