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