* write.c (write_contents): Compute the relocs before writing out
[deliverable/binutils-gdb.git] / gas / config / tc-mips.c
1 /* tc-mips.c -- assemble code for a MIPS chip.
2 Copyright (C) 1993 Free Software Foundation, Inc.
3 Contributed by the OSF and Ralph Campbell.
4 Written by Keith Knowles and Ralph Campbell, working independently.
5 Modified for ECOFF support by Ian Lance Taylor of Cygnus Support.
6
7 This file is part of GAS.
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 #include "as.h"
24
25 #include <ctype.h>
26
27 #ifndef __STDC__
28 #ifndef NO_STDARG
29 #define NO_STDARG
30 #endif
31 #endif
32
33 #ifndef NO_STDARG
34 #include <stdarg.h>
35 #else
36 #ifndef NO_VARARGS
37 #include <varargs.h>
38 #endif /* NO_VARARGS */
39 #endif /* NO_STDARG */
40
41 #include "mips-opcode.h"
42
43 #define AT 1
44 #define RA 31
45
46 static int mips_warn_about_macros;
47 static int mips_noreorder;
48 static int mips_nomove;
49 static int mips_noat;
50 static int mips_nobopt;
51
52 #define N_RMASK 0xc4
53 #define N_VFP 0xd4
54
55 /* handle of the OPCODE hash table */
56 static struct hash_control *op_hash = NULL;
57
58 /* This array holds the chars that always start a comment. If the
59 pre-processor is disabled, these aren't very useful */
60 const char comment_chars[] = "#";
61
62 /* This array holds the chars that only start a comment at the beginning of
63 a line. If the line seems to have the form '# 123 filename'
64 .line and .file directives will appear in the pre-processed output */
65 /* Note that input_file.c hand checks for '#' at the beginning of the
66 first line of the input file. This is because the compiler outputs
67 #NO_APP at the beginning of its output. */
68 /* Also note that C style comments are always supported. */
69 const char line_comment_chars[] = "#";
70
71 /* This array holds machine specific line separator characters. */
72 const char line_separator_chars[] = "";
73
74 /* Chars that can be used to separate mant from exp in floating point nums */
75 const char EXP_CHARS[] = "eE";
76
77 /* Chars that mean this number is a floating point constant */
78 /* As in 0f12.456 */
79 /* or 0d1.2345e12 */
80 const char FLT_CHARS[] = "rRsSfFdDxXpP";
81
82 /* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
83 changed in read.c . Ideally it shouldn't have to know about it at all,
84 but nothing is ideal around here.
85 */
86
87 static char *insn_error;
88
89 static int byte_order = BYTE_ORDER;
90
91 static int auto_align = 1;
92 \f
93 /* Prototypes for static functions. */
94
95 #ifdef __STDC__
96 #define internalError() \
97 as_fatal ("internal Error, line %d, %s", __LINE__, __FILE__)
98 #else
99 #define internalError() as_fatal ("MIPS internal Error");
100 #endif
101
102 static void append_insn PARAMS ((struct mips_cl_insn *ip,
103 expressionS *p,
104 bfd_reloc_code_real_type r));
105 static void macro_build PARAMS ((int *counter, expressionS *ep,
106 const char *name, const char *fmt,
107 ...));
108 static void macro_build_lui PARAMS ((int *counter, expressionS *ep,
109 int regnum));
110 static void set_at PARAMS ((int *counter, int reg));
111 static void set_at_unsigned PARAMS ((int *counter, int reg));
112 static void check_absolute_expr PARAMS ((struct mips_cl_insn *ip,
113 expressionS *expr));
114 static void load_register PARAMS ((int *counter,
115 struct mips_cl_insn *ip,
116 int reg, expressionS *ep));
117 static void macro PARAMS ((struct mips_cl_insn *ip));
118 static void mips_ip PARAMS ((char *str, struct mips_cl_insn *ip));
119 static int my_getSmallExpression PARAMS ((expressionS *ep, char *str));
120 static void my_getExpression PARAMS ((expressionS *ep, char *str));
121 static symbolS *get_symbol PARAMS ((void));
122 static long get_optional_absolute_expression PARAMS ((void));
123 static void s_align PARAMS ((int));
124 static void s_change_sec PARAMS ((int));
125 static void s_cons PARAMS ((int));
126 static void s_err PARAMS ((int));
127 static void s_extern PARAMS ((int));
128 static void s_float_cons PARAMS ((int));
129 static void s_option PARAMS ((int));
130 static void s_mipsset PARAMS ((int));
131 #ifndef OBJ_ECOFF
132 static void md_obj_begin PARAMS ((void));
133 static void md_obj_end PARAMS ((void));
134 static long get_number PARAMS ((void));
135 static void s_ent PARAMS ((int));
136 static void s_mipsend PARAMS ((int));
137 static void s_file PARAMS ((int));
138 static void s_frame PARAMS ((int));
139 static void s_loc PARAMS ((int));
140 static void s_mask PARAMS ((char));
141 #endif
142 \f
143 /* Pseudo-op table.
144
145 The following pseudo-ops from the Kane and Heinrich MIPS book
146 should be defined here, but are currently unsupported: .alias,
147 .galive, .gjaldef, .gjrlive, .livereg, .noalias.
148
149 The following pseudo-ops from the Kane and Heinrich MIPS book are
150 specific to the type of debugging information being generated, and
151 should be defined by the object format: .aent, .begin, .bend,
152 .bgnb, .end, .endb, .ent, .fmask, .frame, .loc, .mask, .verstamp,
153 .vreg.
154
155 The following pseudo-ops from the Kane and Heinrich MIPS book are
156 not MIPS CPU specific, but are also not specific to the object file
157 format. This file is probably the best place to define them, but
158 they are not currently supported: .asm0, .endr, .lab, .repeat,
159 .struct, .weakext. */
160
161 const pseudo_typeS md_pseudo_table[] =
162 {
163 /* MIPS specific pseudo-ops. */
164 { "option", s_option, 0 },
165 { "set", s_mipsset, 0 },
166 { "rdata", s_change_sec, 'r', },
167 { "sdata", s_change_sec, 's', },
168
169 /* Relatively generic pseudo-ops that happen to be used on MIPS
170 chips. */
171 { "asciiz", stringer, 1 },
172 { "bss", s_change_sec, 'b' },
173 { "err", s_err, 0 },
174 { "half", s_cons, 1 },
175
176 /* These pseudo-ops are defined in read.c, but must be overridden
177 here for one reason or another. */
178 { "align", s_align, 0 },
179 { "byte", s_cons, 0 },
180 { "data", s_change_sec, 'd' },
181 { "double", s_float_cons, 1 },
182 { "extern", s_extern, 0 },
183 { "float", s_float_cons, 0 },
184 { "text", s_change_sec, 't' },
185 { "word", s_cons, 2 },
186
187 #ifndef OBJ_ECOFF
188 /* These pseudo-ops should be defined by the object file format.
189 However, ECOFF is the only format which currently defines them,
190 so we have versions here for a.out. */
191 { "aent", s_ent, 1 },
192 { "end", s_mipsend, 0 },
193 { "ent", s_ent, 0 },
194 { "file", s_file, 0 },
195 { "fmask", s_ignore, 'F' },
196 { "frame", s_ignore, 0 },
197 { "loc", s_ignore, 0 },
198 { "mask", s_ignore, 'R' },
199 { "verstamp", s_ignore, 0 },
200 #endif
201
202 /* Sentinel. */
203 { NULL }
204 };
205 \f
206 const relax_typeS md_relax_table[] = {
207 0
208 };
209
210
211 static char *expr_end;
212
213 static expressionS imm_expr;
214 static expressionS offset_expr;
215 static bfd_reloc_code_real_type imm_reloc;
216 static bfd_reloc_code_real_type offset_reloc;
217
218 /*
219 * This function is called once, at assembler startup time. It should
220 * set up all the tables, etc. that the MD part of the assembler will need.
221 */
222 void
223 md_begin()
224 {
225 register char *retval = NULL;
226 register unsigned int i = 0;
227
228 if ((op_hash = hash_new()) == NULL) {
229 as_fatal("Virtual memory exhausted");
230 }
231 for (i = 0; i < NUMOPCODES;) {
232 const char *name = mips_opcodes[i].name;
233
234 retval = hash_insert(op_hash, name, &mips_opcodes[i]);
235 if (retval != NULL && *retval != '\0') {
236 fprintf (stderr, "internal error: can't hash `%s': %s\n",
237 mips_opcodes[i].name, retval);
238 as_fatal ("Broken assembler. No assembly attempted.");
239 }
240 do {
241 if ((mips_opcodes[i].match & mips_opcodes[i].mask) !=
242 mips_opcodes[i].match) {
243 fprintf (stderr, "internal error: bad opcode: `%s' \"%s\"\n",
244 mips_opcodes[i].name, mips_opcodes[i].args);
245 as_fatal ("Broken assembler. No assembly attempted.");
246 }
247 ++i;
248 } while ((i < NUMOPCODES) && !strcmp(mips_opcodes[i].name, name));
249 }
250
251 #ifndef OBJ_ECOFF
252 md_obj_begin ();
253 #endif
254 }
255
256 void
257 md_end ()
258 {
259 #ifndef OBJ_ECOFF
260 md_obj_end ();
261 #endif
262 }
263
264 void
265 md_assemble(str)
266 char *str;
267 {
268 struct mips_cl_insn insn;
269 static int init;
270
271 if (!init) {
272 /* set the default alignment for the text section (2**2) */
273 /* This should go in md_begin but text_section isn't initialized then */
274 record_alignment(text_section, 2);
275 init = 1;
276 }
277
278 imm_expr.X_seg = absent_section;
279 offset_expr.X_seg = absent_section;
280
281 mips_ip(str, &insn);
282 if (insn_error) {
283 as_bad("%s `%s'", insn_error, str);
284 return;
285 }
286 if (insn.insn_mo->pinfo == INSN_MACRO) {
287 macro(&insn);
288 } else {
289 if (imm_expr.X_seg != absent_section)
290 append_insn(&insn, &imm_expr, imm_reloc);
291 else if (offset_expr.X_seg != absent_section)
292 append_insn(&insn, &offset_expr, offset_reloc);
293 else
294 append_insn(&insn, NULL, BFD_RELOC_UNUSED);
295 }
296 }
297
298 #define ALIGN_ERR "Attempt to assemble instruction onto non word boundary."
299 #define ALIGN_ERR2 "GAS doesn't do implicit alignment; use .align directive."
300
301 /*
302 * append insn
303 * Output an instruction.
304 */
305 static void
306 append_insn(ip, address_expr, reloc_type)
307 struct mips_cl_insn *ip;
308 expressionS *address_expr;
309 bfd_reloc_code_real_type reloc_type;
310 {
311 char *f;
312
313 f = frag_more(4);
314 #if 0 /* This is testing the address of the frag, not the alignment of
315 the instruction in the current section. */
316 if ((int) f & 3) {
317 as_bad(ALIGN_ERR);
318 as_bad(ALIGN_ERR2);
319 }
320 #endif
321 if (address_expr != NULL) {
322 fixS *fixP;
323
324 if (address_expr->X_seg == &bfd_abs_section) {
325 switch (reloc_type) {
326 case BFD_RELOC_32:
327 ip->insn_opcode |= address_expr->X_add_number;
328 break;
329
330 case BFD_RELOC_LO16:
331 ip->insn_opcode |= address_expr->X_add_number & 0xffff;
332 break;
333
334 case BFD_RELOC_MIPS_JMP:
335 case BFD_RELOC_16_PCREL_S2:
336 goto need_reloc;
337
338 default:
339 internalError();
340 }
341 } else {
342 assert(reloc_type != BFD_RELOC_UNUSED);
343 need_reloc:
344 fixP = fix_new(frag_now, f - frag_now->fr_literal, 4,
345 address_expr->X_add_symbol,
346 address_expr->X_subtract_symbol,
347 address_expr->X_add_number,
348 reloc_type == BFD_RELOC_16_PCREL_S2,
349 reloc_type);
350 }
351 }
352 md_number_to_chars(f, ip->insn_opcode, 4);
353
354 /*
355 * Fill all delay slots with nops.
356 */
357 if (!mips_noreorder) {
358 if (ip->insn_mo->pinfo & ANY_DELAY) {
359 f = frag_more(4);
360 md_number_to_chars(f, 0, 4);
361 };
362
363 /* One extra nop */
364 if (ip->insn_mo->pinfo & INSN_EXTRA_DELAY) {
365 f = frag_more(4);
366 md_number_to_chars(f, 0, 4);
367 }
368 }
369 }
370
371 #ifndef NO_STDARG
372 static void
373 macro_build (int *counter,
374 expressionS *ep,
375 const char *name,
376 const char *fmt,
377 ...)
378 #else /* ! defined (NO_STDARG) */
379 static void
380 macro_build (counter, ep, name, fmt, va_alist)
381 int *counter;
382 expressionS *ep;
383 const char *name;
384 const char *fmt;
385 va_dcl
386 #endif /* ! defined (NO_STDARG) */
387 {
388 struct mips_cl_insn insn;
389 bfd_reloc_code_real_type r;
390 va_list args;
391
392 #ifndef NO_STDARG
393 va_start(args, fmt);
394 #else
395 va_start(args);
396 #endif
397
398 /*
399 * If the macro is about to expand into a second instruction,
400 * print a warning if needed. We need to pass ip as a parameter
401 * to generate a better warning message here...
402 */
403 if (mips_warn_about_macros && *counter == 1)
404 as_warn("Macro instruction expanded into multiple instructions");
405
406 *counter += 1; /* bump instruction counter */
407
408 r = BFD_RELOC_UNUSED;
409 insn.insn_mo = (struct mips_opcode *) hash_find(op_hash, name);
410 assert(insn.insn_mo);
411 assert(strcmp(name, insn.insn_mo->name) == 0);
412
413 while (strcmp(fmt, insn.insn_mo->args) != 0) {
414 ++insn.insn_mo;
415 assert(insn.insn_mo->name);
416 assert(strcmp(name, insn.insn_mo->name) == 0);
417 }
418 assert(insn.insn_mo->pinfo != INSN_MACRO);
419 insn.insn_opcode = insn.insn_mo->match;
420 for (;;) {
421 switch (*fmt++) {
422 case '\0':
423 break;
424
425 case ',':
426 case '(':
427 case ')':
428 continue;
429
430 case 't':
431 case 'w':
432 insn.insn_opcode |= va_arg(args, int) << 16;
433 continue;
434
435 case 'c':
436 case 'T':
437 case 'W':
438 insn.insn_opcode |= va_arg(args, int) << 16;
439 continue;
440
441 case 'd':
442 insn.insn_opcode |= va_arg(args, int) << 11;
443 continue;
444
445 case 'V':
446 case 'S':
447 insn.insn_opcode |= va_arg(args, int) << 11;
448 continue;
449
450 case '<':
451 insn.insn_opcode |= va_arg(args, int) << 6;
452 continue;
453
454 case 'D':
455 insn.insn_opcode |= va_arg(args, int) << 6;
456 continue;
457
458 case 'b':
459 case 's':
460 case 'r':
461 case 'v':
462 insn.insn_opcode |= va_arg(args, int) << 21;
463 continue;
464
465 case 'i':
466 case 'j':
467 case 'o':
468 r = BFD_RELOC_LO16;
469 continue;
470
471 case 'p':
472 assert(ep != NULL);
473 /*
474 * This allows macro() to pass an immediate expression for
475 * creating short branches without creating a symbol.
476 * Note that the expression still might come from the assembly
477 * input, in which case the value is not checked for range nor
478 * is a relocation entry generated (yuck).
479 */
480 if (ep->X_add_symbol == NULL && ep->X_seg == &bfd_abs_section) {
481 insn.insn_opcode |= (ep->X_add_number >> 2) & 0xffff;
482 ep = NULL;
483 } else
484 r = BFD_RELOC_16_PCREL_S2;
485 continue;
486
487 default:
488 internalError();
489 }
490 break;
491 }
492 va_end(args);
493 assert(r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
494 append_insn(&insn, ep, r);
495 }
496
497 /*
498 * Generate a "lui" instruction.
499 */
500 static void
501 macro_build_lui (counter, ep, regnum)
502 int *counter;
503 expressionS *ep;
504 int regnum;
505 {
506 expressionS high_expr;
507 struct mips_cl_insn insn;
508 bfd_reloc_code_real_type r;
509 CONST char *name = "lui";
510 CONST char *fmt = "t,u";
511
512 high_expr = *ep;
513
514 if (high_expr.X_seg == &bfd_abs_section) {
515 /* we can compute the instruction now without a relocation entry */
516 if (high_expr.X_add_number & 0x8000)
517 high_expr.X_add_number += 0x10000;
518 high_expr.X_add_number =
519 ((unsigned long) high_expr.X_add_number >> 16) & 0xffff;
520 r = BFD_RELOC_UNUSED;
521 } else
522 r = BFD_RELOC_HI16_S;
523
524 /*
525 * If the macro is about to expand into a second instruction,
526 * print a warning if needed. We need to pass ip as a parameter
527 * to generate a better warning message here...
528 */
529 if (mips_warn_about_macros && *counter == 1)
530 as_warn("Macro instruction expanded into multiple instructions");
531
532 *counter += 1; /* bump instruction counter */
533
534 insn.insn_mo = (struct mips_opcode *) hash_find(op_hash, name);
535 assert(insn.insn_mo);
536 assert(strcmp(name, insn.insn_mo->name) == 0);
537 assert(strcmp(fmt, insn.insn_mo->args) == 0);
538
539 insn.insn_opcode = insn.insn_mo->match | (regnum << 16);
540 if (r == BFD_RELOC_UNUSED) {
541 insn.insn_opcode |= high_expr.X_add_number;
542 append_insn(&insn, NULL, r);
543 } else
544 append_insn(&insn, &high_expr, r);
545 }
546
547 /* set_at()
548 * Generates code to set the $at register to true (one)
549 * if reg is less than the immediate expression.
550 */
551 static void
552 set_at (counter, reg)
553 int *counter;
554 int reg;
555 {
556
557 switch (imm_expr.X_add_number & 0xffff8000) {
558 case 0:
559 case 0xffff8000:
560 macro_build(counter, &imm_expr, "slti", "t,r,j", AT, reg);
561 return;
562
563 case 0x8000:
564 macro_build(counter, &imm_expr, "ori", "t,r,i", AT, 0);
565 break;
566
567 default:
568 macro_build_lui(counter, &imm_expr, AT);
569 if (imm_expr.X_add_number & 0xffff)
570 macro_build(counter, &imm_expr, "addiu", "t,r,j", AT, AT);
571 }
572 macro_build(counter, NULL, "slt", "d,v,t", AT, reg, AT);
573 }
574
575 /* set_at_unsigned()
576 * Generates code to set the $at register to true (one)
577 * if reg is less than the immediate expression.
578 * Unsigned comparison is perfomed.
579 */
580 static void
581 set_at_unsigned (counter, reg)
582 int *counter;
583 int reg;
584 {
585
586 switch (imm_expr.X_add_number & 0xffff8000) {
587 case 0:
588 case 0xffff8000:
589 macro_build(counter, &imm_expr, "sltiu", "t,r,j", AT, reg);
590 return;
591
592 case 0x8000:
593 macro_build(counter, &imm_expr, "ori", "t,r,i", AT, 0);
594 break;
595
596 default:
597 macro_build_lui(counter, &imm_expr, AT);
598 if (imm_expr.X_add_number & 0xffff)
599 macro_build(counter, &imm_expr, "addiu", "t,r,j", AT, AT);
600 }
601 macro_build(counter, NULL, "sltu", "d,v,t", AT, reg, AT);
602 }
603
604 static void
605 check_absolute_expr (ip, expr)
606 struct mips_cl_insn *ip;
607 expressionS *expr;
608 {
609
610 if (expr->X_seg != &bfd_abs_section)
611 as_warn("Instruction %s requires absolute expression", ip->insn_mo->name);
612 }
613
614 /* load_register()
615 * This routine generates the least number of instructions neccessary to load
616 * an absolute expression value into a register.
617 */
618 static void
619 load_register (counter, ip, reg, ep)
620 int *counter;
621 struct mips_cl_insn *ip;
622 int reg;
623 expressionS *ep;
624 {
625 switch (ep->X_add_number & 0xffff8000) {
626 case 0:
627 case 0xffff8000:
628 macro_build(counter, ep, "addiu", "t,r,j", reg, 0);
629 break;
630
631 case 0x8000:
632 macro_build(counter, ep, "ori", "t,r,i", reg, 0);
633 break;
634
635 default:
636 macro_build_lui(counter, ep, reg);
637 if (ep->X_add_number & 0xffff)
638 macro_build(counter, ep, "addiu", "t,r,j", reg, reg);
639 }
640 }
641
642
643 /*
644 * Build macros
645 * This routine implements the seemingly endless macro or synthesized
646 * instructions and addressing modes in the mips assembly language. Many
647 * of these macros are simple and are similar to each other. These could
648 * probably be handled by some kind of table or grammer aproach instead of
649 * this verbose method. Others are not simple macros but are more like
650 * optimizing code generation.
651 * One interesting optimization is when several store macros appear
652 * consecutivly that would load AT with the upper half of the same address.
653 * The ensuing load upper instructions are ommited. This implies some kind
654 * of global optimization. We currently only optimize within a single macro.
655 * For many of the load and store macros if the address is specified as a
656 * constant expression in the first 64k of memory (ie ld $2,0x4000c) we
657 * first load register 'at' with zero and use it as the base register. The
658 * mips assembler simply uses register $zero. Just one tiny optimization
659 * we're missing.
660 */
661 static void
662 macro (ip)
663 struct mips_cl_insn *ip;
664 {
665 register int treg, sreg, dreg, breg;
666 int tempreg;
667 int mask;
668 int icnt = 0;
669 int used_at;
670 int save_reorder_condition;
671 expressionS expr1;
672 const char *s;
673
674 treg = (ip->insn_opcode >> 16) & 0x1f;
675 dreg = (ip->insn_opcode >> 11) & 0x1f;
676 sreg = breg = (ip->insn_opcode >> 21) & 0x1f;
677 mask = ip->insn_mo->mask;
678
679 expr1.X_seg = &bfd_abs_section;
680 expr1.X_subtract_symbol = NULL;
681 expr1.X_add_symbol = NULL;
682 expr1.X_add_number = 1;
683
684 switch (mask) {
685 case M_ABS:
686 case M_ABSU:
687 /*
688 Note: mips algorithm requires the move in the delay slot.
689 <main>: bgez $a0,0x4001bc <main+12>
690 <main+4>: move v0,$a0
691 <main+8>: sub v0,$zero,$a0
692 <main+12>: nop
693 */
694
695 save_reorder_condition = mips_noreorder;
696 mips_noreorder = 1;
697
698 expr1.X_add_number = 8;
699 macro_build(&icnt, &expr1, "bgez", "s,p", sreg);
700 macro_build(&icnt, NULL, "move", "d,s", dreg, sreg, 0);
701 macro_build(&icnt, NULL, mask == M_ABS ? "sub" : "subu", "d,v,t",
702 dreg, 0, sreg);
703
704 mips_noreorder = save_reorder_condition;
705 return;
706
707 case M_ADD_I:
708 case M_ADDU_I:
709 switch (imm_expr.X_add_number & 0xffff8000) {
710 case 0:
711 case 0xffff8000:
712 macro_build(&icnt, &imm_expr,
713 mask == M_ADD_I ? "addi" : "addiu", "t,r,j", treg, sreg);
714 return;
715
716 case 0x8000:
717 macro_build(&icnt, &imm_expr, "ori", "t,r,i", AT, 0);
718 break;
719
720 default:
721 macro_build_lui(&icnt, &imm_expr, AT);
722 if (imm_expr.X_add_number & 0xffff)
723 macro_build(&icnt, &imm_expr, "addiu", "t,r,j", AT, AT);
724 break;
725 }
726 macro_build(&icnt, NULL,
727 mask == M_ADD_I ? "add" : "addu", "d,v,t", treg, sreg, AT);
728 break;
729
730 case M_AND_I:
731 case M_OR_I:
732 case M_NOR_I:
733 case M_XOR_I:
734 switch (imm_expr.X_add_number & 0xffff8000) {
735 case 0:
736 case 0x8000:
737 switch (mask) {
738 case M_AND_I:
739 macro_build(&icnt, &imm_expr, "andi", "t,r,i", treg, sreg);
740 return;
741 case M_OR_I:
742 macro_build(&icnt, &imm_expr, "ori", "t,r,i", treg, sreg);
743 return;
744 case M_NOR_I:
745 macro_build(&icnt, &imm_expr, "ori", "t,r,i", treg, sreg);
746 macro_build(&icnt, &imm_expr, "nor", "d,v,t", treg, treg, 0);
747 return;
748 case M_XOR_I:
749 macro_build(&icnt, &imm_expr, "xori", "t,r,i", treg, sreg);
750 return;
751 default:
752 internalError();
753 }
754
755 case 0xffff8000:
756 macro_build(&icnt, &imm_expr, "addiu", "t,r,j", AT, 0);
757 break;
758
759 default:
760 macro_build_lui(&icnt, &imm_expr, AT);
761 if (imm_expr.X_add_number & 0xffff)
762 macro_build(&icnt, &imm_expr, "addiu", "t,r,j", AT, AT);
763 }
764 switch (mask) {
765 case M_AND_I:
766 macro_build(&icnt, NULL, "and", "d,v,t", treg, sreg, AT);
767 break;
768 case M_OR_I:
769 macro_build(&icnt, NULL, "or", "d,v,t", treg, sreg, AT);
770 break;
771 case M_NOR_I:
772 macro_build(&icnt, NULL, "nor", "d,v,t", treg, sreg, AT);
773 break;
774 case M_XOR_I:
775 macro_build(&icnt, NULL, "xor", "d,v,t", treg, sreg, AT);
776 break;
777 default:
778 internalError();
779 }
780 break;
781
782 case M_BEQ_I:
783 case M_BNE_I:
784 if (imm_expr.X_add_number == 0) {
785 macro_build(&icnt, &offset_expr, mask == M_BEQ_I ? "beq" : "bne",
786 "s,t,p", sreg, 0);
787 return;
788 }
789 load_register(&icnt, ip, AT, &imm_expr);
790 macro_build(&icnt, &offset_expr, mask == M_BEQ_I ? "beq" : "bne",
791 "s,t,p", sreg, AT);
792 break;
793
794 case M_BGE:
795 if (treg == 0) {
796 macro_build(&icnt, &offset_expr, "bgez", "s,p", sreg);
797 return;
798 }
799 macro_build(&icnt, NULL, "slt", "d,v,t", AT, sreg, treg);
800 macro_build(&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
801 break;
802
803 case M_BGT_I:
804 imm_expr.X_add_number++;
805 /* FALLTHROUGH */
806 case M_BGE_I:
807 if (imm_expr.X_add_number == 0) {
808 macro_build(&icnt, &offset_expr, "bgez", "s,p", sreg);
809 return;
810 }
811 if (imm_expr.X_add_number == 1) {
812 macro_build(&icnt, &offset_expr, "bgtz", "s,p", sreg);
813 return;
814 }
815 set_at(&icnt, sreg);
816 macro_build(&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
817 break;
818
819 case M_BGEU:
820 if (treg == 0) {
821 macro_build(&icnt, &offset_expr, "b", "p");
822 return;
823 }
824 macro_build(&icnt, NULL, "sltu", "d,v,t", AT, sreg, treg);
825 macro_build(&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
826 break;
827
828 case M_BGEU_I:
829 if (imm_expr.X_add_number == 0) {
830 macro_build(&icnt, &offset_expr, "b", "p");
831 return;
832 }
833 if (imm_expr.X_add_number == 1) {
834 macro_build(&icnt, &offset_expr, "bne", "s,t,p", sreg, 0);
835 return;
836 }
837 set_at_unsigned(&icnt, sreg);
838 macro_build(&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
839 break;
840
841 case M_BGT:
842 if (treg == 0) {
843 macro_build(&icnt, &offset_expr, "bgtz", "s,p", sreg);
844 return;
845 }
846 macro_build(&icnt, NULL, "slt", "d,v,t", AT, treg, sreg);
847 macro_build(&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
848 break;
849
850 case M_BGTU:
851 if (treg == 0) {
852 macro_build(&icnt, &offset_expr, "bne", "s,t,p", sreg, 0);
853 return;
854 }
855 macro_build(&icnt, NULL, "sltu", "d,v,t", AT, treg, sreg);
856 macro_build(&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
857 break;
858
859 case M_BGTU_I:
860 if (imm_expr.X_add_number == 0) {
861 macro_build(&icnt, &offset_expr, "bne", "s,t,p", sreg, 0);
862 return;
863 }
864 if (imm_expr.X_add_number == -1) {
865 /* NOP */
866 if (mips_noreorder)
867 as_warn("Instruction %s is a nop; deleted", ip->insn_mo->name);
868 return;
869 }
870 imm_expr.X_add_number++;
871 set_at_unsigned(&icnt, sreg);
872 macro_build(&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
873 break;
874
875 case M_BLE:
876 if (treg == 0) {
877 macro_build(&icnt, &offset_expr, "blez", "s,p", sreg);
878 return;
879 }
880 macro_build(&icnt, NULL, "slt", "d,v,t", AT, treg, sreg);
881 macro_build(&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
882 break;
883
884 case M_BLE_I:
885 if (imm_expr.X_add_number == 0) {
886 macro_build(&icnt, &offset_expr, "blez", "s,p", sreg);
887 return;
888 }
889 if (imm_expr.X_add_number == -1) {
890 macro_build(&icnt, &offset_expr, "bltz", "s,p", sreg);
891 return;
892 }
893 imm_expr.X_add_number++;
894 set_at(&icnt, sreg);
895 macro_build(&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
896 break;
897
898 case M_BLEU:
899 if (treg == 0) {
900 macro_build(&icnt, &offset_expr, "beq", "s,t,p", sreg, 0);
901 return;
902 }
903 macro_build(&icnt, NULL, "sltu", "d,v,t", AT, treg, sreg);
904 macro_build(&icnt, &offset_expr, "beq", "s,t,p", AT, 0);
905 break;
906
907 case M_BLEU_I:
908 if (imm_expr.X_add_number == 0) {
909 macro_build(&icnt, &offset_expr, "beq", "s,t,p", sreg, 0);
910 return;
911 }
912 if (imm_expr.X_add_number == -1) {
913 macro_build(&icnt, &offset_expr, "b", "p");
914 return;
915 }
916 imm_expr.X_add_number++;
917 set_at_unsigned(&icnt, sreg);
918 macro_build(&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
919 break;
920
921 case M_BLT:
922 if (treg == 0) {
923 macro_build(&icnt, &offset_expr, "bltz", "s,p", sreg);
924 return;
925 }
926 macro_build(&icnt, NULL, "slt", "d,v,t", AT, sreg, treg);
927 macro_build(&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
928 break;
929
930 case M_BLT_I:
931 if (imm_expr.X_add_number == 0) {
932 macro_build(&icnt, &offset_expr, "bltz", "s,p", sreg);
933 return;
934 }
935 if (imm_expr.X_add_number == 1) {
936 macro_build(&icnt, &offset_expr, "blez", "s,p", sreg);
937 return;
938 }
939 set_at(&icnt, sreg);
940 macro_build(&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
941 break;
942
943 case M_BLTU:
944 if (treg == 0) {
945 /* NOP */
946 if (mips_noreorder)
947 as_warn("Instruction %s is a nop; deleted", ip->insn_mo->name);
948 return;
949 }
950 macro_build(&icnt, NULL, "sltu", "d,v,t", AT, sreg, treg);
951 macro_build(&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
952 break;
953
954 case M_BLTU_I:
955 if (imm_expr.X_add_number == 0) {
956 /* NOP */
957 if (mips_noreorder)
958 as_warn("Instruction %s is a nop; deleted", ip->insn_mo->name);
959 return;
960 }
961 if (imm_expr.X_add_number == 1) {
962 macro_build(&icnt, &offset_expr, "beq", "s,t,p", sreg, 0);
963 return;
964 }
965 set_at_unsigned(&icnt, sreg);
966 macro_build(&icnt, &offset_expr, "bne", "s,t,p", AT, 0);
967 break;
968
969 case M_DIV_3:
970 case M_REM_3:
971 if (treg == 0) {
972 as_warn("Divide by zero.");
973 macro_build(&icnt, NULL, "break", "c", 7);
974 return;
975 }
976
977 save_reorder_condition = mips_noreorder;
978 mips_noreorder = 1;
979 macro_build(&icnt, NULL, "div", "s,t", sreg, treg);
980 expr1.X_add_number = 8;
981 macro_build(&icnt, &expr1, "bne", "s,t,p", treg, 0);
982 macro_build(&icnt, NULL, "nop", "", 0);
983 macro_build(&icnt, NULL, "break", "c", 7);
984 expr1.X_add_number = -1;
985 macro_build(&icnt, &expr1, "addiu", "t,r,j", AT, 0);
986 expr1.X_add_number = 16;
987 macro_build(&icnt, &expr1, "bne", "s,t,p", treg, AT);
988 expr1.X_add_number = 0x80000000;
989 macro_build_lui(&icnt, &expr1, AT);
990 expr1.X_add_number = 8;
991 macro_build(&icnt, &expr1, "bne", "s,t,p", sreg, AT);
992 macro_build(&icnt, NULL, "nop", "", 0);
993 macro_build(&icnt, NULL, "break", "c", 6);
994 mips_noreorder = save_reorder_condition;
995 macro_build(&icnt, NULL, mask == M_DIV_3 ? "mflo" : "mfhi", "d", dreg);
996 /* with reorder on there will be two implicit nop instructions here. */
997 break;
998
999 case M_DIV_3I:
1000 case M_DIVU_3I:
1001 case M_REM_3I:
1002 case M_REMU_3I:
1003 if (imm_expr.X_add_number == 0) {
1004 as_warn("Divide by zero.");
1005 macro_build(&icnt, NULL, "break", "c", 7);
1006 return;
1007 }
1008 if (imm_expr.X_add_number == 1) {
1009 if (mask == (int)M_DIV_3I || mask == (int)M_DIVU_3I)
1010 macro_build(&icnt, NULL, "move", "d,s", dreg, sreg);
1011 else
1012 macro_build(&icnt, NULL, "move", "d,s", dreg, 0);
1013 return;
1014 }
1015
1016 load_register(&icnt, ip, AT, &imm_expr);
1017 if (mask == (int)M_DIV_3I || mask == (int)M_REM_3I)
1018 macro_build(&icnt, NULL, "div", "s,t", sreg, AT);
1019 else
1020 macro_build(&icnt, NULL, "divu", "s,t", sreg, AT);
1021
1022 if (mask == (int)M_DIV_3I || mask == (int)M_DIVU_3I)
1023 macro_build(&icnt, NULL, "mflo", "d", dreg);
1024 else
1025 macro_build(&icnt, NULL, "mfhi", "d", dreg);
1026 /* two implicit nop's required for mflo or mfhi */
1027 break;
1028
1029 case M_DIVU_3:
1030 case M_REMU_3:
1031 save_reorder_condition = mips_noreorder;
1032 mips_noreorder = 1;
1033 macro_build(&icnt, NULL, "divu", "s,t", sreg, treg);
1034 expr1.X_add_number = 8;
1035 macro_build(&icnt, &expr1, "bne", "s,t,p", treg, 0);
1036 macro_build(&icnt, NULL, "nop", "", 0);
1037 macro_build(&icnt, NULL, "break", "c", 7);
1038 mips_noreorder = save_reorder_condition;
1039 macro_build(&icnt, NULL, mask == M_DIVU_3 ? "mflo" : "mfhi", "d", dreg);
1040 /* with reorder on there will be two implicit nop instructions here. */
1041 return;
1042
1043 case M_LA:
1044 if (offset_expr.X_seg == &bfd_abs_section) {
1045 load_register(&icnt, ip, treg, &offset_expr);
1046 return;
1047 }
1048 macro_build_lui(&icnt, &offset_expr, treg);
1049 macro_build(&icnt, &offset_expr, "addiu", "t,r,j", treg, treg);
1050 return;
1051
1052 case M_LA_AB:
1053 tempreg = (breg == treg) ? AT : treg;
1054 if (offset_expr.X_seg == &bfd_abs_section)
1055 load_register(&icnt, ip, tempreg, &offset_expr);
1056 else {
1057 macro_build_lui(&icnt, &offset_expr, tempreg);
1058 macro_build(&icnt, &offset_expr, "addiu", "t,r,j", tempreg, tempreg);
1059 }
1060 if (breg != 0)
1061 macro_build(&icnt, NULL, "addu", "d,v,t", treg, tempreg, breg);
1062 if (breg == treg)
1063 break;
1064 return;
1065
1066 case M_LB_AB:
1067 s = "lb";
1068 goto ld;
1069 case M_LBU_AB:
1070 s = "lbu";
1071 goto ld;
1072 case M_LH_AB:
1073 s = "lh";
1074 goto ld;
1075 case M_LHU_AB:
1076 s = "lhu";
1077 goto ld;
1078 case M_LW_AB:
1079 s = "lw";
1080 goto ld;
1081 case M_LWC0_AB:
1082 s = "lwc0";
1083 goto ld;
1084 case M_LWC1_AB:
1085 s = "lwc1";
1086 goto ld;
1087 case M_LWC2_AB:
1088 s = "lwc2";
1089 goto ld;
1090 case M_LWC3_AB:
1091 s = "lwc3";
1092 goto ld;
1093 case M_LWL_AB:
1094 s = "lwl";
1095 goto ld;
1096 case M_LWR_AB:
1097 s = "lwr";
1098 ld:
1099 if (breg == treg) {
1100 tempreg = AT;
1101 used_at = 1;
1102 } else {
1103 tempreg = treg;
1104 used_at = 0;
1105 }
1106 goto ld_st;
1107 case M_SB_AB:
1108 s = "sb";
1109 goto st;
1110 case M_SH_AB:
1111 s = "sh";
1112 goto st;
1113 case M_SW_AB:
1114 s = "sw";
1115 goto st;
1116 case M_SWC0_AB:
1117 s = "swc0";
1118 goto st;
1119 case M_SWC1_AB:
1120 s = "swc1";
1121 goto st;
1122 case M_SWC2_AB:
1123 s = "swc2";
1124 goto st;
1125 case M_SWC3_AB:
1126 s = "swc3";
1127 goto st;
1128 case M_SWL_AB:
1129 s = "swl";
1130 goto st;
1131 case M_SWR_AB:
1132 s = "swr";
1133 st:
1134 tempreg = AT;
1135 used_at = 1;
1136 ld_st:
1137 macro_build_lui(&icnt, &offset_expr, tempreg);
1138 if (breg != 0)
1139 macro_build(&icnt, NULL, "addu", "d,v,t", tempreg, tempreg, breg);
1140 macro_build(&icnt, &offset_expr, s,
1141 mask == M_LWC1_AB || mask == M_SWC1_AB ? "T,o(b)" : "t,o(b)",
1142 treg, tempreg);
1143 if (used_at)
1144 break;
1145 return;
1146
1147 case M_LI:
1148 load_register(&icnt, ip, treg, &imm_expr);
1149 return;
1150
1151 case M_LI_D:
1152 /*
1153 0x400370 <main>: lui $at,%hi(foo)
1154 0x400374 <main+4>: lw $v0,%lo(foo)($at)
1155 0x400378 <main+8>: lw $v1,%lo(foo+4)($at)
1156 .data
1157 <foo>:
1158 .float 3.133435
1159 */
1160 macro_build_lui(&icnt, &offset_expr, AT);
1161 macro_build(&icnt, &offset_expr, "lw", "t,o(b)", treg, AT);
1162 offset_expr.X_add_number = 4;
1163 macro_build(&icnt, &offset_expr, "lw", "t,o(b)", treg+1, AT);
1164 break;
1165
1166 case M_LI_DD:
1167 /*
1168 0x4003a0 <main>: lwc1 $f0,-32752($gp)
1169 0x4003a4 <main+4>: lwc1 $f1,-32748($gp)
1170 0x4003a8 <main+8>: nop
1171 */
1172 sreg = (ip->insn_opcode >> 11) & 0x1f; /* Fs reg */
1173 macro_build(&icnt, &offset_expr, "lwc1", "T,o(b)", treg, AT);
1174 offset_expr.X_add_number = 4;
1175 macro_build(&icnt, &offset_expr, "lwc1", "T,o(b)", treg+1, AT);
1176 break;
1177
1178 case M_L_DOB:
1179 save_reorder_condition = mips_noreorder;
1180 mips_noreorder = 1;
1181 macro_build(&icnt, &offset_expr, "lwc1", "T,o(b)", treg, breg);
1182 /* unecessary implicit nop */
1183 mips_noreorder = save_reorder_condition;
1184 offset_expr.X_add_number += 4;
1185 macro_build(&icnt, &offset_expr, "lwc1", "T,o(b)", treg+1, breg);
1186 return;
1187
1188 case M_L_DAB:
1189 /*
1190 * The MIPS assembler seems to check for X_add_number not
1191 * being double aligned and generating:
1192 * lui at,%hi(foo+1)
1193 * addu at,at,v1
1194 * addiu at,at,%lo(foo+1)
1195 * lwc1 f2,0(at)
1196 * lwc1 f3,4(at)
1197 * But, the resulting address is the same after relocation so why
1198 * generate the extra instruction?
1199 */
1200 macro_build_lui(&icnt, &offset_expr, AT);
1201 if (breg != 0)
1202 macro_build(&icnt, NULL, "addu", "d,v,t", AT, AT, breg);
1203 save_reorder_condition = mips_noreorder;
1204 mips_noreorder = 1;
1205 macro_build(&icnt, &offset_expr, "lwc1", "T,o(b)", treg, AT);
1206 /* unecessary implicit nop */
1207 mips_noreorder = save_reorder_condition;
1208 offset_expr.X_add_number += 4;
1209 macro_build(&icnt, &offset_expr, "lwc1", "T,o(b)", treg+1, AT);
1210 break;
1211
1212 case M_LD_OB:
1213 s = "lw";
1214 goto sd_ob;
1215 case M_SD_OB:
1216 s = "sw";
1217 sd_ob:
1218 macro_build(&icnt, &offset_expr, s, "t,o(b)", treg, breg);
1219 offset_expr.X_add_number = 4;
1220 macro_build(&icnt, &offset_expr, s, "t,o(b)", treg+1, breg);
1221 return;
1222
1223 case M_LD_AB:
1224 s = "lw";
1225 if (breg == treg) {
1226 tempreg = AT;
1227 used_at = 1;
1228 } else {
1229 tempreg = treg;
1230 used_at = 0;
1231 }
1232 goto sd_ab;
1233 case M_SD_AB:
1234 s = "sw";
1235 tempreg = AT;
1236 used_at = 1;
1237 sd_ab:
1238 macro_build_lui(&icnt, &offset_expr, tempreg);
1239 if (breg != 0)
1240 macro_build(&icnt, NULL, "addu", "d,v,t", tempreg, tempreg, breg);
1241 macro_build(&icnt, &offset_expr, s, "t,o(b)", treg, tempreg);
1242 offset_expr.X_add_number += 4;
1243 macro_build(&icnt, &offset_expr, s, "t,o(b)", treg+1, tempreg);
1244 if (used_at)
1245 break;
1246 return;
1247
1248 case M_MUL:
1249 macro_build(&icnt, NULL, "multu", "s,t", sreg, treg);
1250 macro_build(&icnt, NULL, "mflo", "d", dreg);
1251 /* two implicit nop's required for mflo */
1252 return;
1253
1254 case M_MUL_I:
1255 /*
1256 * The mips assembler some times generates shifts and adds.
1257 * Im not trying to be that fancy. GCC should do this for us
1258 * anyway.
1259 */
1260 load_register(&icnt, ip, AT, &imm_expr);
1261 macro_build(&icnt, NULL, "mult", "s,t", sreg, AT);
1262 macro_build(&icnt, NULL, "mflo", "d", dreg);
1263 /* two implicit nop's required for mflo */
1264 break;
1265
1266 case M_ROL:
1267 macro_build(&icnt, NULL, "subu", "d,v,t", AT, 0, treg);
1268 macro_build(&icnt, NULL, "srlv", "d,t,s", AT, sreg, AT);
1269 macro_build(&icnt, NULL, "sllv", "d,t,s", dreg, sreg, treg);
1270 macro_build(&icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
1271 break;
1272
1273 case M_ROL_I:
1274 macro_build(&icnt, NULL, "sll", "d,w,<", AT, sreg,
1275 imm_expr.X_add_number & 0x1f);
1276 macro_build(&icnt, NULL, "srl", "d,w,<", dreg, sreg,
1277 (0 - imm_expr.X_add_number) & 0x1f);
1278 macro_build(&icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
1279 break;
1280
1281 case M_ROR:
1282 macro_build(&icnt, NULL, "subu", "d,v,t", AT, 0, treg);
1283 macro_build(&icnt, NULL, "sllv", "d,t,s", AT, sreg, AT);
1284 macro_build(&icnt, NULL, "srlv", "d,t,s", dreg, sreg, treg);
1285 macro_build(&icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
1286 break;
1287
1288 case M_ROR_I:
1289 macro_build(&icnt, NULL, "srl", "d,w,<", AT, sreg,
1290 imm_expr.X_add_number & 0x1f);
1291 macro_build(&icnt, NULL, "sll", "d,w,<", dreg, sreg,
1292 (0 - imm_expr.X_add_number) & 0x1f);
1293 macro_build(&icnt, NULL, "or", "d,v,t", dreg, dreg, AT);
1294 break;
1295
1296 case M_S_DOB:
1297 macro_build(&icnt, &offset_expr, "swc1", "T,o(b)", treg, breg);
1298 offset_expr.X_add_number += 4;
1299 macro_build(&icnt, &offset_expr, "swc1", "T,o(b)", treg+1, breg);
1300 return;
1301
1302 case M_S_DAB:
1303 macro_build_lui(&icnt, &offset_expr, AT);
1304 if (breg != 0)
1305 macro_build(&icnt, NULL, "addu", "d,v,t", AT, AT, breg);
1306 macro_build(&icnt, &offset_expr, "swc1", "T,o(b)", treg, AT);
1307 offset_expr.X_add_number += 4;
1308 macro_build(&icnt, &offset_expr, "swc1", "T,o(b)", treg+1, AT);
1309 break;
1310
1311 case M_SEQ:
1312 if (sreg == 0)
1313 macro_build(&icnt, &expr1, "sltiu", "t,r,j", dreg, treg);
1314 else if (treg == 0)
1315 macro_build(&icnt, &expr1, "sltiu", "t,r,j", dreg, sreg);
1316 else {
1317 macro_build(&icnt, NULL, "xor", "d,v,t", dreg, sreg, treg);
1318 macro_build(&icnt, &expr1, "sltiu", "t,r,j", dreg, dreg);
1319 }
1320 return;
1321
1322 case M_SEQ_I:
1323 if (imm_expr.X_add_number == 0) {
1324 macro_build(&icnt, &expr1, "sltiu", "t,r,j", dreg, sreg);
1325 return;
1326 }
1327 if (sreg == 0) {
1328 /* result is always false */
1329 macro_build(&icnt, NULL, "move", "d,s", dreg, 0);
1330 return;
1331 }
1332 switch (imm_expr.X_add_number & 0xffff8000) {
1333 case 0:
1334 case 0x8000:
1335 macro_build(&icnt, &imm_expr, "xori", "t,r,i", dreg, sreg);
1336 used_at = 0;
1337 break;
1338
1339 case 0xffff8000:
1340 if (imm_expr.X_add_number != -32768) {
1341 imm_expr.X_add_number = -imm_expr.X_add_number;
1342 macro_build(&icnt, &imm_expr, "addiu", "t,r,j", dreg, sreg);
1343 used_at = 0;
1344 break;
1345 }
1346 /* FALLTHROUGH */
1347
1348 default:
1349 macro_build_lui(&icnt, &imm_expr, AT);
1350 if (imm_expr.X_add_number & 0xffff)
1351 macro_build(&icnt, &imm_expr, "addiu", "t,r,j", AT, AT);
1352 macro_build(&icnt, NULL, "xor", "d,v,t", dreg, sreg, AT);
1353 used_at = 1;
1354 }
1355 macro_build(&icnt, &expr1, "sltiu", "t,r,j", dreg, dreg);
1356 if (used_at)
1357 break;
1358 return;
1359
1360 case M_SGE: /* sreg >= treg <==> not (sreg < treg) */
1361 s = "slt";
1362 goto sge;
1363 case M_SGEU:
1364 s = "sltu";
1365 sge:
1366 macro_build(&icnt, NULL, s, "d,v,t", dreg, sreg, treg);
1367 macro_build(&icnt, &expr1, "xori", "t,r,i", dreg, dreg);
1368 return;
1369
1370 case M_SGE_I: /* sreg >= I <==> not (sreg < I) */
1371 case M_SGEU_I:
1372 if (imm_expr.X_add_number < 32768 && imm_expr.X_add_number > -32769) {
1373 macro_build(&icnt, &expr1,
1374 mask == M_SGE_I ? "slti" : "sltiu", "t,r,j", dreg, sreg);
1375 used_at = 0;
1376 } else {
1377 load_register(&icnt, ip, AT, &imm_expr);
1378 macro_build(&icnt, NULL,
1379 mask == M_SGE_I ? "slt" : "sltu", "d,v,t", dreg, sreg, AT);
1380 used_at = 1;
1381 }
1382 macro_build(&icnt, &expr1, "xori", "t,r,i", dreg, dreg);
1383 if (used_at)
1384 break;
1385 return;
1386
1387 case M_SGT: /* sreg > treg <==> treg < sreg */
1388 s = "slt";
1389 goto sgt;
1390 case M_SGTU:
1391 s = "sltu";
1392 sgt:
1393 macro_build(&icnt, NULL, s, "d,v,t", dreg, treg, sreg);
1394 return;
1395
1396 case M_SGT_I: /* sreg > I <==> I < sreg */
1397 s = "slt";
1398 goto sgti;
1399 case M_SGTU_I:
1400 s = "sltu";
1401 sgti:
1402 load_register(&icnt, ip, AT, &imm_expr);
1403 macro_build(&icnt, NULL, s, "d,v,t", dreg, AT, sreg);
1404 break;
1405
1406 case M_SLE: /* sreg <= treg <==> treg >= sreg <==> not (treg < sreg) */
1407 s = "slt";
1408 goto sle;
1409 case M_SLEU:
1410 s = "sltu";
1411 sle:
1412 macro_build(&icnt, NULL, s, "d,v,t", dreg, treg, sreg);
1413 macro_build(&icnt, &imm_expr, "xori", "t,r,i", dreg, dreg);
1414 return;
1415
1416 case M_SLE_I: /* sreg <= I <==> I >= sreg <==> not (I < sreg) */
1417 s = "slt";
1418 goto slei;
1419 case M_SLEU_I:
1420 s = "sltu";
1421 slei:
1422 load_register(&icnt, ip, AT, &imm_expr);
1423 macro_build(&icnt, NULL, s, "d,v,t", dreg, AT, sreg);
1424 macro_build(&icnt, &offset_expr, "xori", "t,r,i", dreg, dreg);
1425 break;
1426
1427 case M_SLT_I:
1428 if (imm_expr.X_add_number < 32768 && imm_expr.X_add_number > -32769) {
1429 macro_build(&icnt, &imm_expr, "slti", "t,r,j", dreg, sreg);
1430 return;
1431 }
1432 load_register(&icnt, ip, AT, &imm_expr);
1433 macro_build(&icnt, NULL, "slt", "d,v,t", dreg, sreg, AT);
1434 break;
1435
1436 case M_SLTU_I:
1437 if (imm_expr.X_add_number < 32768 && imm_expr.X_add_number > -32769) {
1438 macro_build(&icnt, &imm_expr, "sltiu", "t,r,j", dreg, sreg);
1439 return;
1440 }
1441 load_register(&icnt, ip, AT, &imm_expr);
1442 macro_build(&icnt, NULL, "sltu", "d,v,t", dreg, sreg, AT);
1443 break;
1444
1445 case M_SNE:
1446 if (sreg == 0)
1447 macro_build(&icnt, NULL, "sltu", "d,v,t", dreg, 0, treg);
1448 else if (treg == 0)
1449 macro_build(&icnt, NULL, "sltu", "d,v,t", dreg, 0, sreg);
1450 else {
1451 macro_build(&icnt, NULL, "xor", "d,v,t", dreg, sreg, treg);
1452 macro_build(&icnt, NULL, "sltu", "d,v,t", dreg, 0, dreg);
1453 }
1454 return;
1455
1456 case M_SNE_I:
1457 if (imm_expr.X_add_number == 0) {
1458 macro_build(&icnt, NULL, "sltu", "d,v,t", dreg, 0, sreg);
1459 return;
1460 }
1461 if (sreg == 0) {
1462 /* result is always true */
1463 macro_build(&icnt, &expr1, "addiu", "t,r,j", dreg, 0);
1464 return;
1465 }
1466 switch (imm_expr.X_add_number & 0xffff8000) {
1467 case 0:
1468 case 0x8000:
1469 macro_build(&icnt, &imm_expr, "xori", "t,r,i", dreg, sreg);
1470 used_at = 0;
1471 break;
1472
1473 case 0xffff8000:
1474 if (imm_expr.X_add_number != -32768) {
1475 imm_expr.X_add_number = -imm_expr.X_add_number;
1476 macro_build(&icnt, &imm_expr, "addiu", "t,r,j", dreg, sreg);
1477 used_at = 0;
1478 break;
1479 }
1480 /* FALLTHROUGH */
1481
1482 default:
1483 macro_build_lui(&icnt, &imm_expr, AT);
1484 if (imm_expr.X_add_number & 0xffff)
1485 macro_build(&icnt, &imm_expr, "addiu", "t,r,j", AT, AT);
1486 macro_build(&icnt, NULL, "xor", "d,v,t", dreg, sreg, AT);
1487 used_at = 1;
1488 }
1489 macro_build(&icnt, NULL, "sltu", "d,v,t", dreg, 0, dreg);
1490 if (used_at)
1491 break;
1492 return;
1493
1494 case M_SUB_I:
1495 if (imm_expr.X_add_number < 32768 && imm_expr.X_add_number > -32768) {
1496 imm_expr.X_add_number = -imm_expr.X_add_number;
1497 macro_build(&icnt, &imm_expr, "addi", "t,r,j", dreg, sreg);
1498 return;
1499 }
1500 load_register(&icnt, ip, AT, &imm_expr);
1501 macro_build(&icnt, NULL, "sub", "d,v,t", dreg, sreg, AT);
1502 break;
1503
1504 case M_SUBU_I:
1505 if (imm_expr.X_add_number < 32768 && imm_expr.X_add_number > -32768) {
1506 imm_expr.X_add_number = -imm_expr.X_add_number;
1507 macro_build(&icnt, &imm_expr, "addiu", "t,r,j", dreg, sreg);
1508 return;
1509 }
1510 load_register(&icnt, ip, AT, &imm_expr);
1511 macro_build(&icnt, NULL, "subu", "d,v,t", dreg, sreg, AT);
1512 break;
1513
1514 case M_TRUNCWD:
1515 case M_TRUNCWS:
1516 sreg = (ip->insn_opcode >> 11) & 0x1f; /* floating reg */
1517 dreg = (ip->insn_opcode >> 06) & 0x1f; /* floating reg */
1518
1519 /*
1520 * Is the double cfc1 instruction a bug in the mips assembler;
1521 * or is there a reason for it?
1522 */
1523 save_reorder_condition = mips_noreorder;
1524 mips_noreorder = 1;
1525 macro_build(&icnt, NULL, "cfc1", "t,d", treg, 31);
1526 macro_build(&icnt, NULL, "cfc1", "t,d", treg, 31);
1527 macro_build(&icnt, NULL, "nop", "");
1528 expr1.X_add_number = 3;
1529 macro_build(&icnt, &expr1, "ori", "t,r,i", AT, treg);
1530 expr1.X_add_number = 2;
1531 macro_build(&icnt, &expr1, "xori", "t,r,i", AT, AT);
1532 macro_build(&icnt, NULL, "ctc1", "t,d", AT, 31);
1533 macro_build(&icnt, NULL, "nop", "");
1534 macro_build(&icnt, NULL,
1535 mask == M_TRUNCWD ? "cvt.w.d" : "cvt.w.s", "D,S", dreg, sreg);
1536 macro_build(&icnt, NULL, "ctc1", "t,d", treg, 31);
1537 macro_build(&icnt, NULL, "nop", "");
1538 mips_noreorder = save_reorder_condition;
1539 break;
1540
1541 case M_ULH:
1542 s = "lb";
1543 goto ulh;
1544 case M_ULHU:
1545 s = "lbu";
1546 ulh:
1547 /* avoid load delay */
1548 offset_expr.X_add_number += 1;
1549 macro_build(&icnt, &offset_expr, s, "t,o(b)", treg, breg);
1550 offset_expr.X_add_number -= 1;
1551 macro_build(&icnt, &offset_expr, "lbu", "t,o(b)", AT, breg);
1552 macro_build(&icnt, NULL, "sll", "d,w,<", treg, treg, 8);
1553 macro_build(&icnt,NULL, "or", "d,v,t", treg, treg, AT);
1554 break;
1555
1556 case M_ULW:
1557 /* does this work on a big endian machine? */
1558 offset_expr.X_add_number += 3;
1559 macro_build(&icnt, &offset_expr, "lwl", "t,o(b)", treg, breg);
1560 offset_expr.X_add_number -= 3;
1561 macro_build(&icnt, &offset_expr, "lwr", "t,o(b)", treg, breg);
1562 return;
1563
1564 case M_ULH_A:
1565 case M_ULHU_A:
1566 case M_ULW_A:
1567 if (offset_expr.X_seg == &bfd_abs_section)
1568 load_register(&icnt, ip, AT, &offset_expr);
1569 else {
1570 macro_build_lui(&icnt, &offset_expr, AT);
1571 macro_build(&icnt, &offset_expr, "addiu", "t,r,j", AT, AT);
1572 }
1573 if (mask == M_ULW_A) {
1574 expr1.X_add_number = 3;
1575 macro_build(&icnt, &expr1, "lwl", "t,o(b)", treg, AT);
1576 imm_expr.X_add_number = 0;
1577 macro_build(&icnt, &expr1, "lwr", "t,o(b)", treg, AT);
1578 } else {
1579 macro_build(&icnt, &expr1,
1580 mask == M_ULH_A ? "lb" : "lbu", "t,o(b)", treg, AT);
1581 imm_expr.X_add_number = 0;
1582 macro_build(&icnt, &expr1, "lbu", "t,o(b)", AT, AT);
1583 macro_build(&icnt, NULL, "sll", "d,w,<", treg, treg, 8);
1584 macro_build(&icnt, NULL, "or", "d,v,t", treg, treg, AT);
1585 }
1586 break;
1587
1588 case M_USH:
1589 macro_build(&icnt, &offset_expr, "sb", "t,o(b)", treg, breg);
1590 macro_build(&icnt, NULL, "srl", "d,w,<", AT, treg, 8);
1591 offset_expr.X_add_number += 1;
1592 macro_build(&icnt, &offset_expr, "sb", "t,o(b)", AT, breg);
1593 break;
1594
1595 case M_USW:
1596 offset_expr.X_add_number += 3;
1597 macro_build(&icnt, &offset_expr, "swl", "t,o(b)", treg, breg);
1598 offset_expr.X_add_number -= 3;
1599 macro_build(&icnt, &offset_expr, "swr", "t,o(b)", treg, breg);
1600 return;
1601
1602 case M_USH_A:
1603 case M_USW_A:
1604 if (offset_expr.X_seg == &bfd_abs_section)
1605 load_register(&icnt, ip, AT, &offset_expr);
1606 else {
1607 macro_build_lui(&icnt, &offset_expr, AT);
1608 macro_build(&icnt, &offset_expr, "addiu", "t,r,j", AT, AT);
1609 }
1610 if (mask == M_USW_A) {
1611 expr1.X_add_number = 3;
1612 macro_build(&icnt, &expr1, "swl", "t,o(b)", treg, AT);
1613 expr1.X_add_number = 0;
1614 macro_build(&icnt, &expr1, "swr", "t,o(b)", treg, AT);
1615 } else {
1616 expr1.X_add_number = 0;
1617 macro_build(&icnt, &expr1, "sb", "t,o(b)", treg, AT);
1618 macro_build(&icnt, NULL, "srl", "d,w,<", treg, treg, 8);
1619 expr1.X_add_number = 1;
1620 macro_build(&icnt, &expr1, "sb", "t,o(b)", treg, AT);
1621 expr1.X_add_number = 0;
1622 macro_build(&icnt, &expr1, "lbu", "t,o(b)", AT, AT);
1623 macro_build(&icnt, NULL, "sll", "d,w,<", treg, treg, 8);
1624 macro_build(&icnt, NULL, "or", "d,v,t", treg, treg, AT);
1625 }
1626 break;
1627
1628 default:
1629 as_bad("Macro %s not implemented yet", ip->insn_mo->name);
1630 }
1631 if (mips_noat)
1632 as_warn("Macro used $at after \".set noat\"");
1633 }
1634
1635
1636 /*
1637 This routine assembles an instruction into its binary format. As a side
1638 effect it sets one of the global variables imm_reloc or offset_reloc to the
1639 type of relocation to do if one of the operands is an address expression.
1640 */
1641 static void
1642 mips_ip (str, ip)
1643 char *str;
1644 struct mips_cl_insn *ip;
1645 {
1646 char *s;
1647 const char *args;
1648 char c;
1649 struct mips_opcode *insn;
1650 char *argsStart;
1651 unsigned int regno;
1652 unsigned int lastregno = 0;
1653 char *s_reset;
1654
1655 insn_error = NULL;
1656
1657 for (s = str; islower(*s) || (*s >= '0' && *s <= '3') || *s == '.'; ++s)
1658 continue;
1659 switch (*s) {
1660
1661 case '\0':
1662 break;
1663
1664 case ' ':
1665 *s++ = '\0';
1666 break;
1667
1668 default:
1669 as_warn("Unknown opcode: `%s'", str);
1670 exit(1);
1671 }
1672 if ((insn = (struct mips_opcode *) hash_find(op_hash, str)) == NULL) {
1673 as_warn("`%s' not in hash table.", str);
1674 insn_error = "ERROR: Unrecognized opcode";
1675 return;
1676 }
1677 argsStart = s;
1678 for (;;) {
1679 assert(strcmp(insn->name, str) == 0);
1680 ip->insn_mo = insn;
1681 ip->insn_opcode = insn->match;
1682 for (args = insn->args; ; ++args) {
1683 if (*s == ' ')
1684 ++s;
1685 switch (*args) {
1686
1687 case '\0': /* end of args */
1688 if (*s == '\0')
1689 return;
1690 break;
1691
1692 case ',':
1693 if (*s++ == *args)
1694 continue;
1695 s--;
1696 switch (*++args) {
1697 case 'r':
1698 case 'v':
1699 ip->insn_opcode |= lastregno << 21;
1700 continue;
1701
1702 case 'w':
1703 case 'W':
1704 ip->insn_opcode |= lastregno << 16;
1705 continue;
1706
1707 case 'V':
1708 ip->insn_opcode |= lastregno << 11;
1709 continue;
1710 }
1711 break;
1712
1713 case '(':
1714 /* handle optional base register.
1715 Either the base register is omitted or
1716 we must have a left paren. */
1717 /* this is dependent on the next operand specifier
1718 is a 'b' for base register */
1719 assert(args[1] == 'b');
1720 if (*s == '\0')
1721 return;
1722
1723 case ')': /* these must match exactly */
1724 if (*s++ == *args)
1725 continue;
1726 break;
1727
1728 case '<': /* must be at least one digit */
1729 /*
1730 * According to the manual, if the shift amount is greater
1731 * than 31 or less than 0 the the shift amount should be
1732 * mod 32. In reality the mips assembler issues an error.
1733 * We issue a warning and do the mod.
1734 */
1735 my_getExpression(&imm_expr, s);
1736 check_absolute_expr(ip, &imm_expr);
1737 if ((unsigned long) imm_expr.X_add_number > 31) {
1738 as_warn("Improper shift amount (%d)",
1739 imm_expr.X_add_number);
1740 imm_expr.X_add_number = imm_expr.X_add_number % 32;
1741 }
1742 ip->insn_opcode |= imm_expr.X_add_number << 6;
1743 imm_expr.X_seg = absent_section;
1744 s = expr_end;
1745 continue;
1746
1747 case 'c': /* break code */
1748 my_getExpression(&imm_expr, s);
1749 check_absolute_expr(ip, &imm_expr);
1750 if ((unsigned)imm_expr.X_add_number > 1023)
1751 as_warn("Illegal break code (%d)", imm_expr.X_add_number);
1752 ip->insn_opcode |= imm_expr.X_add_number << 16;
1753 imm_expr.X_seg = absent_section;
1754 s = expr_end;
1755 continue;
1756
1757 case 'b': /* base register */
1758 case 'd': /* destination register */
1759 case 's': /* source register */
1760 case 't': /* target register */
1761 case 'r': /* both target and source */
1762 case 'v': /* both dest and source */
1763 case 'w': /* both dest and target */
1764 s_reset = s;
1765 if (s[0] == '$') {
1766 if (isdigit(s[1])) {
1767 ++s;
1768 regno = 0;
1769 do {
1770 regno *= 10;
1771 regno += *s - '0';
1772 ++s;
1773 } while (isdigit(*s));
1774 } else if (s[1] == 'f' && s[2] == 'p') {
1775 s += 3;
1776 regno = 30;
1777 } else if (s[1] == 's' && s[2] == 'p') {
1778 s += 3;
1779 regno = 29;
1780 } else if (s[1] == 'g' && s[2] == 'p') {
1781 s += 3;
1782 regno = 28;
1783 } else if (s[1] == 'a' && s[2] == 't') {
1784 s += 3;
1785 regno = 1;
1786 } else
1787 goto notreg;
1788 if (regno > 31)
1789 as_bad("Invalid register number (%d)", regno);
1790 if (regno == AT && !mips_noat)
1791 as_warn("Used $at without \".set noat\"");
1792 c = *args;
1793 if (*s == ' ')
1794 s++;
1795 if (args[1] != *s) {
1796 if (c == 'r' || c == 'v' || c == 'w') {
1797 regno = lastregno;
1798 s = s_reset;
1799 args++;
1800 }
1801 }
1802 switch (c) {
1803 case 'r':
1804 case 's':
1805 case 'v':
1806 case 'b':
1807 ip->insn_opcode |= regno << 21;
1808 break;
1809 case 'd':
1810 ip->insn_opcode |= regno << 11;
1811 break;
1812 case 'w':
1813 case 't':
1814 ip->insn_opcode |= regno << 16;
1815 }
1816 lastregno = regno;
1817 continue;
1818 }
1819 notreg:
1820 switch (*args++) {
1821 case 'r':
1822 case 'v':
1823 ip->insn_opcode |= lastregno << 21;
1824 continue;
1825 case 'w':
1826 ip->insn_opcode |= lastregno << 16;
1827 continue;
1828 }
1829 break;
1830
1831 case 'D': /* floating point destination register */
1832 case 'S': /* floating point source register */
1833 case 'T': /* floating point target register */
1834 case 'V':
1835 case 'W':
1836 s_reset = s;
1837 if (s[0] == '$' && s[1] == 'f' && isdigit(s[2])) {
1838 s += 2;
1839 regno = 0;
1840 do {
1841 regno *= 10;
1842 regno += *s - '0';
1843 ++s;
1844 } while (isdigit(*s));
1845
1846 if (regno > 31)
1847 as_bad("Invalid float register number (%d)", regno);
1848
1849 if ((regno & 1) &&
1850 !(strcmp(str, "mtc1") == 0 ||
1851 strcmp(str, "mfc1") == 0 ||
1852 strcmp(str, "lwc1") == 0 ||
1853 strcmp(str, "swc1") == 0))
1854 as_warn("Float register should be even, was %d",
1855 regno);
1856
1857 c = *args;
1858 if (*s == ' ')
1859 s++;
1860 if (args[1] != *s) {
1861 if (c == 'V' || c == 'W') {
1862 regno = lastregno;
1863 s = s_reset;
1864 args++;
1865 }
1866 }
1867 switch (c) {
1868 case 'D':
1869 ip->insn_opcode |= regno << 6;
1870 break;
1871 case 'V':
1872 case 'S':
1873 ip->insn_opcode |= regno << 11;
1874 break;
1875 case 'W':
1876 case 'T':
1877 ip->insn_opcode |= regno << 16;
1878 }
1879 lastregno = regno;
1880 continue;
1881 }
1882 switch (*args++) {
1883 case 'V':
1884 ip->insn_opcode |= lastregno << 11;
1885 continue;
1886 case 'W':
1887 ip->insn_opcode |= lastregno << 16;
1888 continue;
1889 }
1890 break;
1891
1892 case 'I':
1893 my_getExpression(&imm_expr, s);
1894 check_absolute_expr(ip, &imm_expr);
1895 s = expr_end;
1896 continue;
1897
1898 case 'A':
1899 my_getExpression(&offset_expr, s);
1900 imm_reloc = BFD_RELOC_32;
1901 s = expr_end;
1902 continue;
1903
1904 case 'F':
1905 as_bad("Floating point constants only implemented for pseudo ops.");
1906 continue;
1907
1908 case 'i': /* 16 bit unsigned immediate */
1909 case 'j': /* 16 bit signed immediate */
1910 imm_reloc = BFD_RELOC_LO16;
1911 c = my_getSmallExpression(&imm_expr, s);
1912 if (c) {
1913 if (c != 'l') {
1914 if (imm_expr.X_seg == &bfd_abs_section)
1915 imm_expr.X_add_number =
1916 (imm_expr.X_add_number >> 16) & 0xffff;
1917 else if (c == 'h')
1918 imm_reloc = BFD_RELOC_HI16_S;
1919 else
1920 imm_reloc = BFD_RELOC_HI16;
1921 }
1922 } else
1923 check_absolute_expr(ip, &imm_expr);
1924 if (*args == 'i') {
1925 if ((unsigned long) imm_expr.X_add_number > 65535)
1926 as_bad("16 bit expression not in range 0..65535");
1927 } else {
1928 if (imm_expr.X_add_number < -32768 ||
1929 imm_expr.X_add_number > 32767)
1930 as_bad("16 bit expression not in range -32768..32767");
1931 }
1932 s = expr_end;
1933 continue;
1934
1935 case 'o': /* 16 bit offset */
1936 c = my_getSmallExpression(&offset_expr, s);
1937 /*
1938 * If this value won't fit into a 16 bit offset, then
1939 * go find a macro that will generate the 32 bit offset
1940 * code pattern.
1941 */
1942 if ((offset_expr.X_add_symbol
1943 && offset_expr.X_seg != &bfd_abs_section)
1944 || offset_expr.X_subtract_symbol
1945 || offset_expr.X_add_number > 32767
1946 || offset_expr.X_add_number < -32768)
1947 break;
1948
1949 offset_reloc = BFD_RELOC_LO16;
1950 if (c == 'h' || c == 'H')
1951 offset_expr.X_add_number =
1952 (offset_expr.X_add_number >> 16) & 0xffff;
1953 s = expr_end;
1954 continue;
1955
1956 case 'p': /* pc relative offset */
1957 offset_reloc = BFD_RELOC_16_PCREL_S2;
1958 my_getExpression(&offset_expr, s);
1959 s = expr_end;
1960 continue;
1961
1962 case 'u': /* upper 16 bits */
1963 c = my_getSmallExpression(&imm_expr, s);
1964 if ((unsigned long)imm_expr.X_add_number > 65535)
1965 as_bad("lui expression not in range 0..65535");
1966 imm_reloc = BFD_RELOC_LO16;
1967 if (c) {
1968 if (c != 'l') {
1969 if (imm_expr.X_seg == &bfd_abs_section)
1970 imm_expr.X_add_number =
1971 (imm_expr.X_add_number >> 16) & 0xffff;
1972 else if (c == 'h')
1973 imm_reloc = BFD_RELOC_HI16_S;
1974 else
1975 imm_reloc = BFD_RELOC_HI16;
1976 }
1977 }
1978 s = expr_end;
1979 continue;
1980
1981 case 'a': /* 26 bit address */
1982 my_getExpression(&offset_expr, s);
1983 s = expr_end;
1984 offset_reloc = BFD_RELOC_MIPS_JMP;
1985 continue;
1986
1987 default:
1988 fprintf(stderr, "bad char = '%c'\n", *args);
1989 internalError();
1990 }
1991 break;
1992 }
1993 /* Args don't match. */
1994 if (insn + 1 < &mips_opcodes[NUMOPCODES] &&
1995 !strcmp(insn->name, insn[1].name)) {
1996 ++insn;
1997 s = argsStart;
1998 continue;
1999 }
2000 insn_error = "ERROR: Illegal operands";
2001 return;
2002 }
2003 }
2004
2005 #define LP '('
2006 #define RP ')'
2007
2008 static int
2009 my_getSmallExpression (ep, str)
2010 expressionS *ep;
2011 char *str;
2012 {
2013 char *sp;
2014 int c = 0;
2015
2016 if (*str == ' ')
2017 str++;
2018 if (*str == LP
2019 || (*str == '%' &&
2020 ((str[1] == 'h' && str[2] == 'i')
2021 || (str[1] == 'H' && str[2] == 'I')
2022 || (str[1] == 'l' && str[2] == 'o'))
2023 && str[3] == LP)) {
2024 if (*str == LP)
2025 c = 0;
2026 else {
2027 c = str[1];
2028 str += 3;
2029 }
2030
2031 /*
2032 * A small expression may be followed by a base register.
2033 * Scan to the end of this operand, and then back over a possible
2034 * base register. Then scan the small expression up to that
2035 * point. (Based on code in sparc.c...)
2036 */
2037 for (sp = str; *sp && *sp != ','; sp++)
2038 ;
2039 if (sp - 4 >= str && sp[-1] == RP) {
2040 if (isdigit(sp[-2])) {
2041 for (sp -= 3; sp >= str && isdigit(*sp); sp--)
2042 ;
2043 if (*sp == '$' && sp > str && sp[-1] == LP) {
2044 sp--;
2045 goto do_it;
2046 }
2047 } else if (sp - 5 >= str
2048 && sp[-5] == LP
2049 && sp[-4] == '$'
2050 && ((sp[-3] == 'f' && sp[-2] == 'p')
2051 || (sp[-3] == 's' && sp[-2] == 'p')
2052 || (sp[-3] == 'g' && sp[-2] == 'p')
2053 || (sp[-3] == 'a' && sp[-2] == 't'))) {
2054 sp -= 5;
2055 do_it:
2056 if (sp == str) {
2057 /* no expression means zero offset */
2058 if (c) {
2059 /* %xx(reg) is an error */
2060 ep->X_seg = absent_section;
2061 expr_end = str - 3;
2062 } else {
2063 ep->X_seg = &bfd_abs_section;
2064 expr_end = sp;
2065 }
2066 ep->X_add_symbol = NULL;
2067 ep->X_subtract_symbol = NULL;
2068 ep->X_add_number = 0;
2069 } else {
2070 *sp = '\0';
2071 my_getExpression(ep, str);
2072 *sp = LP;
2073 }
2074 return c;
2075 }
2076 }
2077 }
2078 my_getExpression(ep, str);
2079 return c; /* => %hi or %lo encountered */
2080 }
2081
2082 static void
2083 my_getExpression (ep, str)
2084 expressionS *ep;
2085 char *str;
2086 {
2087 char *save_in;
2088 asection *seg;
2089
2090 save_in = input_line_pointer;
2091 input_line_pointer = str;
2092 seg = expression(ep);
2093 expr_end = input_line_pointer;
2094 input_line_pointer = save_in;
2095 }
2096
2097 char *
2098 md_atof (type,litP,sizeP)
2099 char type;
2100 char *litP;
2101 int *sizeP;
2102 {
2103 internalError();
2104 return NULL;
2105 }
2106
2107 void
2108 md_number_to_chars (buf, val, n)
2109 char *buf;
2110 long val;
2111 int n;
2112 {
2113
2114 switch (byte_order) {
2115 case LITTLE_ENDIAN:
2116 switch (n) {
2117
2118 case 4:
2119 *buf++ = val;
2120 *buf++ = val >> 8;
2121 *buf++ = val >> 16;
2122 *buf = val >> 24;
2123 return;
2124
2125 case 2:
2126 *buf++ = val;
2127 *buf = val >> 8;
2128 return;
2129
2130 case 1:
2131 *buf = val;
2132 return;
2133
2134 default:
2135 internalError();
2136 }
2137
2138 case BIG_ENDIAN:
2139
2140 switch (n) {
2141
2142 case 4:
2143 *buf++ = val >> 24;
2144 *buf++ = val >> 16;
2145 case 2:
2146 *buf++ = val >> 8;
2147 case 1:
2148 *buf = val;
2149 return;
2150
2151 default:
2152 internalError();
2153 }
2154
2155 default:
2156 internalError();
2157 }
2158 }
2159
2160 int
2161 md_parse_option (argP, cntP, vecP)
2162 char **argP;
2163 int *cntP;
2164 char ***vecP;
2165 {
2166 /* Accept -nocpp but ignore it. */
2167 if (!strcmp(*argP, "nocpp")) {
2168 *argP += 5;
2169 return 1;
2170 }
2171 return 1; /* pretend you parsed the character */
2172 }
2173
2174 long
2175 md_pcrel_from (fixP)
2176 fixS *fixP;
2177 {
2178 /* return the address of the delay slot */
2179 return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
2180 }
2181
2182 int
2183 md_apply_fix (fixP, valueP)
2184 fixS *fixP;
2185 long *valueP;
2186 {
2187 unsigned char *buf;
2188 long insn, value;
2189
2190 assert(fixP->fx_size == 4);
2191
2192 value = *valueP;
2193 fixP->fx_addnumber = value; /* Remember value for tc_gen_reloc */
2194
2195 switch (fixP->fx_r_type) {
2196 case BFD_RELOC_32:
2197 case BFD_RELOC_MIPS_JMP:
2198 case BFD_RELOC_HI16:
2199 case BFD_RELOC_HI16_S:
2200 case BFD_RELOC_LO16:
2201 /* Nothing needed to do. The value comes from the reloc entry */
2202 return 1;
2203
2204 case BFD_RELOC_16_PCREL_S2:
2205 /*
2206 * We need to save the bits in the instruction since fixup_segment()
2207 * might be deleting the relocation entry (i.e., a branch within
2208 * the current segment).
2209 */
2210 if (value & 0x3)
2211 as_warn("Branch to odd address (%x)", value);
2212 value >>= 2;
2213 if ((value & ~0xFFFF) && (value & ~0xFFFF) != (-1 & ~0xFFFF))
2214 as_bad("Relocation overflow");
2215
2216 /* update old instruction data */
2217 buf = (unsigned char *)(fixP->fx_where + fixP->fx_frag->fr_literal);
2218 switch (byte_order) {
2219 case LITTLE_ENDIAN:
2220 insn = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
2221 break;
2222
2223 case BIG_ENDIAN:
2224 insn = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
2225 break;
2226
2227 default:
2228 internalError();
2229 return 0;
2230 }
2231 insn |= value & 0xFFFF;
2232 md_number_to_chars(buf, insn, 4);
2233 break;
2234
2235 default:
2236 internalError();
2237 }
2238 return 1;
2239 }
2240
2241 #if 0
2242 void
2243 printInsn(oc)
2244 unsigned long oc;
2245 {
2246 const struct mips_opcode *p;
2247 int treg, sreg, dreg, shamt;
2248 short imm;
2249 const char *args;
2250 int i;
2251
2252 for (i = 0; i < NUMOPCODES; ++i) {
2253 p = &mips_opcodes[i];
2254 if (((oc & p->mask) == p->match) && (p->pinfo != INSN_MACRO)) {
2255 printf("%08lx %s\t", oc, p->name);
2256 treg = (oc >> 16) & 0x1f;
2257 sreg = (oc >> 21) & 0x1f;
2258 dreg = (oc >> 11) & 0x1f;
2259 shamt = (oc >> 6) & 0x1f;
2260 imm = oc;
2261 for (args = p->args; ; ++args) {
2262 switch (*args) {
2263
2264 case '\0':
2265 printf("\n");
2266 break;
2267
2268 case ',':
2269 case '(':
2270 case ')':
2271 printf("%c", *args);
2272 continue;
2273
2274 case 'r':
2275 assert(treg == sreg);
2276 printf("$%d,$%d", treg, sreg);
2277 continue;
2278
2279 case 'd':
2280 printf("$%d", dreg);
2281 continue;
2282
2283 case 't':
2284 printf("$%d", treg);
2285 continue;
2286
2287 case 'b':
2288 case 's':
2289 printf("$%d", sreg);
2290 continue;
2291
2292 case 'a':
2293 printf("0x%08lx", oc & 0x1ffffff);
2294 continue;
2295
2296 case 'i':
2297 case 'j':
2298 case 'o':
2299 case 'u':
2300 printf("%d", imm);
2301 continue;
2302
2303 case '<':
2304 printf("$%d", shamt);
2305 continue;
2306
2307 default:
2308 internalError();
2309 }
2310 break;
2311 }
2312 return;
2313 }
2314 }
2315 printf("%08lx UNDEFINED\n", oc);
2316 }
2317 #endif
2318
2319 static symbolS *
2320 get_symbol ()
2321 {
2322 int c;
2323 char *name;
2324 symbolS *p;
2325
2326 name = input_line_pointer;
2327 c = get_symbol_end();
2328 p = (symbolS *) symbol_find_or_make(name);
2329 *input_line_pointer = c;
2330 return p;
2331 }
2332
2333 static long
2334 get_optional_absolute_expression ()
2335 {
2336 expressionS exp;
2337 asection *s;
2338
2339 s = expression(&exp);
2340 if (!(s == &bfd_abs_section || s == big_section || s == absent_section)) {
2341 as_bad("Bad Absolute Expression.");
2342 }
2343 return exp.X_add_number;
2344 }
2345
2346 static void
2347 s_align (x)
2348 int x;
2349 {
2350 register int temp;
2351 register long temp_fill;
2352 long max_alignment = 15;
2353
2354 /*
2355
2356 o Note that the assembler pulls down any immediately preceeding label
2357 to the aligned address.
2358 o It's not documented but auto alignment is reinstated by
2359 a .align pseudo instruction.
2360 o Note also that after auto alignment is turned off the mips assembler
2361 issues an error on attempt to assemble an improperly aligned data item.
2362 We don't.
2363
2364 */
2365
2366 temp = get_absolute_expression ();
2367 if (temp > max_alignment)
2368 as_bad("Alignment too large: %d. assumed.", temp = max_alignment);
2369 else if (temp < 0) {
2370 as_warn("Alignment negative: 0 assumed.");
2371 temp = 0;
2372 }
2373 if (*input_line_pointer == ',') {
2374 input_line_pointer ++;
2375 temp_fill = get_absolute_expression ();
2376 } else
2377 temp_fill = 0;
2378 if (temp) {
2379 auto_align = 1;
2380 if (!need_pass_2)
2381 frag_align (temp, (int)temp_fill);
2382 } else {
2383 auto_align = 0;
2384 }
2385
2386 record_alignment(now_seg, temp);
2387
2388 demand_empty_rest_of_line();
2389 }
2390
2391 static void
2392 s_change_sec (sec)
2393 int sec;
2394 {
2395 switch (sec) {
2396 case 't':
2397 s_text();
2398 break;
2399 case 'r':
2400 case 'd':
2401 s_data();
2402 break;
2403 case 'b':
2404 #ifdef BFD_ASSEMBLER
2405 subseg_set (bss_section, (subsegT) get_absolute_expression ());
2406 #else
2407 subseg_new (bss_section, (subsegT) get_absolute_expression ());
2408 #endif
2409 demand_empty_rest_of_line ();
2410 break;
2411 default:
2412 as_bad("Global pointers not supported; recompile -G 0");
2413 return;
2414 }
2415 auto_align = 1;
2416 }
2417
2418 static void
2419 s_cons (log_size)
2420 int log_size;
2421 {
2422
2423 if (log_size > 0 && auto_align)
2424 frag_align(log_size, 0);
2425 cons(1 << log_size);
2426 }
2427
2428 static void
2429 s_err (x)
2430 int x;
2431 {
2432 as_fatal("Encountered `.err', aborting assembly");
2433 }
2434
2435 static void
2436 s_extern (x)
2437 int x;
2438 {
2439 long size;
2440 symbolS *symbolP;
2441
2442 symbolP = get_symbol();
2443 if (*input_line_pointer == ',')
2444 input_line_pointer++;
2445 size = get_optional_absolute_expression();
2446 S_SET_VALUE(symbolP, size);
2447 }
2448
2449 static void
2450 s_float_cons (is_double)
2451 int is_double;
2452 {
2453 char *f;
2454 short words[4];
2455 int error_code, repeat;
2456 extern FLONUM_TYPE generic_floating_point_number;
2457
2458 if (auto_align)
2459 if (is_double)
2460 frag_align(3, 0);
2461 else
2462 frag_align(2, 0);
2463
2464 SKIP_WHITESPACE ();
2465 if (! is_end_of_line [(unsigned char) *input_line_pointer]) {
2466 do {
2467 error_code = atof_generic(&input_line_pointer, ".", EXP_CHARS,
2468 &generic_floating_point_number);
2469 if (error_code) {
2470 if (error_code == ERROR_EXPONENT_OVERFLOW)
2471 as_warn("Bad floating-point constant: exponent overflow");
2472 else
2473 as_warn("Bad floating-point constant: unknown error code=%d.", error_code);
2474 }
2475
2476 if (is_double) {
2477 gen_to_words((LITTLENUM_TYPE *)words,
2478 4 /* precision */,
2479 11 /* exponent_bits */ );
2480 } else {
2481 gen_to_words((LITTLENUM_TYPE *)words,
2482 2 /* precision */,
2483 8 /* exponent_bits */ );
2484 }
2485 if (*input_line_pointer == ':') {
2486 input_line_pointer++;
2487 repeat = get_absolute_expression();
2488 } else {
2489 repeat = 1;
2490 }
2491 if (is_double) {
2492 f = frag_more(repeat * 8);
2493 for (;repeat--; f += 8) {
2494 md_number_to_chars(f+6, words[0], 2);
2495 md_number_to_chars(f+4, words[1], 2);
2496 md_number_to_chars(f+2, words[2], 2);
2497 md_number_to_chars(f, words[3], 2);
2498 }
2499 } else {
2500 f = frag_more(repeat * 4);
2501 for (;repeat--; f += 4) {
2502 md_number_to_chars(f+2, words[0], 2);
2503 md_number_to_chars(f, words[1], 2);
2504 }
2505 }
2506 SKIP_WHITESPACE();
2507 if (*input_line_pointer != ',') break;
2508 input_line_pointer++;
2509 SKIP_WHITESPACE();
2510 } while (1);
2511 }
2512 demand_empty_rest_of_line();
2513 }
2514
2515 static void
2516 s_option (x)
2517 int x;
2518 {
2519 if (strcmp(input_line_pointer, "O1") != 0
2520 && strcmp(input_line_pointer, "O2") != 0)
2521 as_warn("Unrecognized option");
2522 demand_empty_rest_of_line();
2523 }
2524
2525 static void
2526 s_mipsset (x)
2527 int x;
2528 {
2529 char *name = input_line_pointer, ch;
2530
2531 while (!is_end_of_line[(unsigned char) *input_line_pointer])
2532 input_line_pointer++;
2533 ch = *input_line_pointer;
2534 *input_line_pointer = '\0';
2535
2536 if (strcmp(name, "reorder") == 0) {
2537 mips_noreorder = 0;
2538 } else if (strcmp(name, "noreorder") == 0) {
2539 mips_noreorder = 1;
2540 } else if (strcmp(name, "at") == 0) {
2541 mips_noat = 0;
2542 } else if (strcmp(name, "noat") == 0) {
2543 mips_noat = 1;
2544 } else if (strcmp(name, "macro") == 0) {
2545 mips_warn_about_macros = 0;
2546 } else if (strcmp(name, "nomacro") == 0) {
2547 if (mips_noreorder == 0)
2548 as_bad("`noreorder' must be set before `nomacro'");
2549 mips_warn_about_macros = 1;
2550 } else if (strcmp(name, "move") == 0 || strcmp(name, "novolatile") == 0) {
2551 mips_nomove = 0;
2552 } else if (strcmp(name, "nomove") == 0 || strcmp(name, "volatile") == 0) {
2553 mips_nomove = 1;
2554 } else if (strcmp(name, "bopt") == 0) {
2555 mips_nobopt = 0;
2556 } else if (strcmp(name, "nobopt") == 0) {
2557 mips_nobopt = 1;
2558 } else {
2559 as_warn("Tried to set unrecognized symbol: %s\n", name);
2560 }
2561 *input_line_pointer = ch;
2562 demand_empty_rest_of_line();
2563 }
2564
2565 int
2566 tc_get_register ()
2567 {
2568 int reg;
2569
2570 SKIP_WHITESPACE ();
2571 if (*input_line_pointer++ != '$')
2572 {
2573 as_warn ("expected `$'");
2574 return 0;
2575 }
2576 if (isdigit ((unsigned char) *input_line_pointer))
2577 {
2578 reg = get_absolute_expression ();
2579 if (reg < 0 || reg >= 32)
2580 {
2581 as_warn ("Bad register number");
2582 reg = 0;
2583 }
2584 }
2585 else
2586 {
2587 if (strncmp (input_line_pointer, "fp", 2) == 0)
2588 reg = 30;
2589 else if (strncmp (input_line_pointer, "sp", 2) == 0)
2590 reg = 29;
2591 else if (strncmp (input_line_pointer, "gp", 2) == 0)
2592 reg = 28;
2593 else if (strncmp (input_line_pointer, "at", 2) == 0)
2594 reg = 1;
2595 else
2596 {
2597 as_warn ("Unrecognized register name");
2598 return 0;
2599 }
2600 input_line_pointer += 2;
2601 }
2602 return reg;
2603 }
2604
2605 /*
2606 * Translate internal representation of relocation info to BFD target format.
2607 */
2608 arelent *
2609 tc_gen_reloc (section, fixp)
2610 asection *section;
2611 fixS *fixp;
2612 {
2613 arelent *reloc;
2614
2615 reloc = (arelent *) xmalloc (sizeof (arelent));
2616 assert (reloc != 0);
2617
2618 reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
2619 reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
2620 if (fixp->fx_pcrel == 0)
2621 reloc->addend = fixp->fx_addnumber;
2622 else
2623 #ifdef OBJ_ELF
2624 reloc->addend = 0;
2625 #else
2626 reloc->addend = - reloc->address;
2627 #endif
2628 reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
2629 assert (reloc->howto != 0);
2630
2631 #ifdef OBJ_ECOFF
2632 /* FIXME: This does the right thing, but it's confusing. There
2633 should be a more coherent approach, but I don't know what it
2634 would be. */
2635 reloc->addend -=
2636 bfd_get_section_vma (stdoutput,
2637 bfd_get_section (fixp->fx_addsy->bsym));
2638 #endif
2639
2640 return reloc;
2641 }
2642
2643 /* should never be called */
2644 long
2645 md_section_align(seg, addr)
2646 asection *seg;
2647 long addr;
2648 {
2649 int align = bfd_get_section_alignment(stdoutput, seg);
2650
2651 return ((addr + (1 << align) - 1) & (-1 << align));
2652 }
2653
2654 int
2655 md_estimate_size_before_relax(fragP, segtype)
2656 fragS *fragP;
2657 asection *segtype;
2658 {
2659 as_fatal("md_estimate_size_before_relax");
2660 return(1);
2661 } /* md_estimate_size_before_relax() */
2662 \f
2663 #ifndef OBJ_ECOFF
2664
2665 /* These functions should really be defined by the object file format,
2666 since they are related to debugging information. However, this
2667 code has to work for the a.out format, which does not define them,
2668 so we provide simple versions here. These don't actually generate
2669 any debugging information, but they do simple checking and someday
2670 somebody may make them useful. */
2671
2672 typedef struct loc {
2673 struct loc *loc_next;
2674 unsigned long loc_fileno;
2675 unsigned long loc_lineno;
2676 unsigned long loc_offset;
2677 unsigned short loc_delta;
2678 unsigned short loc_count;
2679 #if 0
2680 fragS *loc_frag;
2681 #endif
2682 } locS;
2683
2684 typedef struct proc {
2685 struct proc *proc_next;
2686 struct symbol *proc_isym;
2687 struct symbol *proc_end;
2688 unsigned long proc_reg_mask;
2689 unsigned long proc_reg_offset;
2690 unsigned long proc_fpreg_mask;
2691 unsigned long proc_fpreg_offset;
2692 unsigned long proc_frameoffset;
2693 unsigned long proc_framereg;
2694 unsigned long proc_pcreg;
2695 locS *proc_iline;
2696 struct file *proc_file;
2697 int proc_index;
2698 } procS;
2699
2700 typedef struct file {
2701 struct file *file_next;
2702 unsigned long file_fileno;
2703 struct symbol *file_symbol;
2704 struct symbol *file_end;
2705 struct proc *file_proc;
2706 int file_numprocs;
2707 } fileS;
2708
2709 static struct obstack proc_frags;
2710 static procS *proc_lastP;
2711 static procS *proc_rootP;
2712 static int numprocs;
2713
2714 static void
2715 md_obj_begin ()
2716 {
2717 obstack_begin(&proc_frags, 0x2000);
2718 }
2719
2720 static void
2721 md_obj_end ()
2722 {
2723 /* check for premature end, nesting errors, etc */
2724 if (proc_lastP && proc_lastP->proc_end == NULL)
2725 as_warn("missing `.end' at end of assembly");
2726 }
2727
2728 extern char hex_value[];
2729
2730 static long
2731 get_number ()
2732 {
2733 int negative = 0;
2734 long val = 0;
2735
2736 if (*input_line_pointer == '-') {
2737 ++input_line_pointer;
2738 negative = 1;
2739 }
2740 if (!isdigit(*input_line_pointer))
2741 as_bad("Expected simple number.");
2742 if (input_line_pointer[0] == '0') {
2743 if (input_line_pointer[1] == 'x') {
2744 input_line_pointer += 2;
2745 while (isxdigit(*input_line_pointer)) {
2746 val <<= 4;
2747 val |= hex_value[(int) *input_line_pointer++];
2748 }
2749 return negative ? -val : val;
2750 } else {
2751 ++input_line_pointer;
2752 while (isdigit(*input_line_pointer)) {
2753 val <<= 3;
2754 val |= *input_line_pointer++ - '0';
2755 }
2756 return negative ? -val : val;
2757 }
2758 }
2759 if (!isdigit(*input_line_pointer)) {
2760 printf(" *input_line_pointer == '%c' 0x%02x\n",
2761 *input_line_pointer, *input_line_pointer);
2762 as_warn("Invalid number");
2763 return -1;
2764 }
2765 while (isdigit(*input_line_pointer)) {
2766 val *= 10;
2767 val += *input_line_pointer++ - '0';
2768 }
2769 return negative ? -val : val;
2770 }
2771
2772 /* The .file directive; just like the usual .file directive, but there
2773 is an initial number which is the ECOFF file index. */
2774
2775 static void
2776 s_file (x)
2777 int x;
2778 {
2779 int line;
2780
2781 line = get_number();
2782 s_app_file();
2783 }
2784
2785
2786 /* The .end directive. */
2787
2788 static void
2789 s_mipsend (x)
2790 int x;
2791 {
2792 symbolS *p;
2793
2794 if (!is_end_of_line[(unsigned char) *input_line_pointer]) {
2795 p = get_symbol();
2796 demand_empty_rest_of_line();
2797 } else
2798 p = NULL;
2799 if (now_seg != text_section)
2800 as_warn(".end not in text section");
2801 if (!proc_lastP) {
2802 as_warn(".end and no .ent seen yet.");
2803 return;
2804 }
2805
2806 if (p != NULL) {
2807 assert(S_GET_NAME(p));
2808 if (strcmp(S_GET_NAME(p), S_GET_NAME(proc_lastP->proc_isym)))
2809 as_warn(".end symbol does not match .ent symbol.");
2810 }
2811
2812 proc_lastP->proc_end = (symbolS *) 1;
2813 }
2814
2815 /* The .aent and .ent directives. */
2816
2817 static void
2818 s_ent (aent)
2819 int aent;
2820 {
2821 int number = 0;
2822 procS *procP;
2823 symbolS *symbolP;
2824
2825 symbolP = get_symbol();
2826 if (*input_line_pointer == ',')
2827 input_line_pointer++;
2828 if (isdigit(*input_line_pointer) || *input_line_pointer == '-')
2829 number = get_number();
2830 if (now_seg != text_section)
2831 as_warn(".ent or .aent not in text section.");
2832
2833 if (!aent && proc_lastP && proc_lastP->proc_end == NULL)
2834 as_warn("missing `.end'");
2835
2836 if (!aent) {
2837 procP = (procS *) obstack_alloc(&proc_frags, sizeof(*procP));
2838 procP->proc_isym = symbolP;
2839 procP->proc_reg_mask = 0;
2840 procP->proc_reg_offset = 0;
2841 procP->proc_fpreg_mask = 0;
2842 procP->proc_fpreg_offset = 0;
2843 procP->proc_frameoffset = 0;
2844 procP->proc_framereg = 0;
2845 procP->proc_pcreg = 0;
2846 procP->proc_end = NULL;
2847 procP->proc_next = NULL;
2848 if (proc_lastP)
2849 proc_lastP->proc_next = procP;
2850 else
2851 proc_rootP = procP;
2852 proc_lastP = procP;
2853 numprocs++;
2854 }
2855 demand_empty_rest_of_line();
2856 }
2857
2858 /* The .frame directive. */
2859
2860 static void
2861 s_frame (x)
2862 int x;
2863 {
2864 #if 0
2865 char str[100];
2866 symbolS *symP;
2867 int frame_reg;
2868 int frame_off;
2869 int pcreg;
2870
2871 frame_reg = tc_get_register();
2872 if (*input_line_pointer == ',')
2873 input_line_pointer++;
2874 frame_off = get_optional_absolute_expression();
2875 if (*input_line_pointer == ',')
2876 input_line_pointer++;
2877 pcreg = tc_get_register();
2878
2879 /* bob third eye */
2880 assert(proc_rootP);
2881 proc_rootP->proc_framereg = frame_reg;
2882 proc_rootP->proc_frameoffset = frame_off;
2883 proc_rootP->proc_pcreg = pcreg;
2884 /* bob macho .frame */
2885
2886 /* We don't have to write out a frame stab for unoptimized code. */
2887 if (!(frame_reg == 30 && frame_off == 0)) {
2888 if (!proc_lastP)
2889 as_warn("No .ent for .frame to use." );
2890 (void) sprintf(str, "R%d;%d", frame_reg, frame_off );
2891 symP = symbol_new(str, N_VFP, 0, frag_now );
2892 S_SET_TYPE(symP, N_RMASK);
2893 S_SET_OTHER(symP, 0);
2894 S_SET_DESC(symP, 0);
2895 symP->sy_forward = proc_lastP->proc_isym;
2896 /* bob perhaps I should have used pseudo set */
2897 }
2898 demand_empty_rest_of_line();
2899 #endif
2900 }
2901
2902 /* The .fmask and .mask directives. */
2903
2904 static void
2905 s_mask (reg_type)
2906 char reg_type;
2907 {
2908 #if 0
2909 char str[100], *strP;
2910 symbolS *symP;
2911 int i;
2912 unsigned int mask;
2913 int off;
2914
2915 mask = get_number();
2916 if (*input_line_pointer == ',')
2917 input_line_pointer++;
2918 off = get_absolute_expression();
2919
2920 /* bob only for coff */
2921 assert(proc_rootP);
2922 if (reg_type == 'F' ) {
2923 proc_rootP->proc_fpreg_mask = mask;
2924 proc_rootP->proc_fpreg_offset = off;
2925 } else {
2926 proc_rootP->proc_reg_mask = mask;
2927 proc_rootP->proc_reg_offset = off;
2928 }
2929
2930 /* bob macho .mask + .fmask */
2931
2932 /* We don't have to write out a mask stab if no saved regs. */
2933 if (!(mask == 0)) {
2934 if (!proc_lastP)
2935 as_warn("No .ent for .mask to use." );
2936 strP = str;
2937 for (i=0; i<32; i++ ) {
2938 if (mask%2) {
2939 sprintf(strP, "%c%d,", reg_type, i );
2940 strP += strlen(strP);
2941 }
2942 mask /= 2;
2943 }
2944 sprintf(strP, ";%d,", off );
2945 symP = symbol_new(str, N_RMASK, 0, frag_now);
2946 S_SET_TYPE(symP, N_RMASK);
2947 S_SET_OTHER(symP, 0);
2948 S_SET_DESC(symP, 0);
2949 symP->sy_forward = proc_lastP->proc_isym;
2950 /* bob perhaps I should have used pseudo set */
2951 }
2952 #endif
2953 }
2954
2955 /* The .loc directive. */
2956
2957 static void
2958 s_loc (x)
2959 int x;
2960 {
2961 #if 0
2962 symbolS * symbolP;
2963 int lineno;
2964 int addroff;
2965
2966 assert(now_seg == text_section);
2967
2968 lineno = get_number();
2969 addroff = obstack_next_free(&frags) - frag_now->fr_literal;
2970
2971 symbolP = symbol_new ("", N_SLINE, addroff, frag_now);
2972 S_SET_TYPE(symbolP, N_SLINE);
2973 S_SET_OTHER(symbolP, 0);
2974 S_SET_DESC(symbolP, lineno);
2975 symbolP->sy_segment = now_seg;
2976 #endif
2977 }
2978
2979 #endif /* ! defined (OBJ_ECOFF) */
2980
This page took 0.088445 seconds and 5 git commands to generate.