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.
7 This file is part of GAS.
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)
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.
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. */
38 #endif /* NO_VARARGS */
39 #endif /* NO_STDARG */
41 #include "mips-opcode.h"
46 static int mips_warn_about_macros
;
47 static int mips_noreorder
;
48 static int mips_nomove
;
50 static int mips_nobopt
;
55 /* handle of the OPCODE hash table */
56 static struct hash_control
*op_hash
= NULL
;
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
[] = "#";
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
[] = "#";
71 /* This array holds machine specific line separator characters. */
72 const char line_separator_chars
[] = "";
74 /* Chars that can be used to separate mant from exp in floating point nums */
75 const char EXP_CHARS
[] = "eE";
77 /* Chars that mean this number is a floating point constant */
80 const char FLT_CHARS
[] = "rRsSfFdDxXpP";
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.
87 static char *insn_error
;
89 static int byte_order
= BYTE_ORDER
;
91 static int auto_align
= 1;
93 /* Prototypes for static functions. */
96 #define internalError() \
97 as_fatal ("internal Error, line %d, %s", __LINE__, __FILE__)
99 #define internalError() as_fatal ("MIPS internal Error");
102 static void append_insn
PARAMS ((struct mips_cl_insn
*ip
,
104 bfd_reloc_code_real_type r
));
105 static void macro_build
PARAMS ((int *counter
, expressionS
*ep
,
106 const char *name
, const char *fmt
,
108 static void macro_build_lui
PARAMS ((int *counter
, expressionS
*ep
,
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
,
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));
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));
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.
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,
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. */
161 const pseudo_typeS md_pseudo_table
[] =
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', },
169 /* Relatively generic pseudo-ops that happen to be used on MIPS
171 { "asciiz", stringer
, 1 },
172 { "bss", s_change_sec
, 'b' },
174 { "half", s_cons
, 1 },
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 },
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 },
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 },
206 const relax_typeS md_relax_table
[] = {
211 static char *expr_end
;
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
;
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.
225 register char *retval
= NULL
;
226 register unsigned int i
= 0;
228 if ((op_hash
= hash_new()) == NULL
) {
229 as_fatal("Virtual memory exhausted");
231 for (i
= 0; i
< NUMOPCODES
;) {
232 const char *name
= mips_opcodes
[i
].name
;
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.");
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.");
248 } while ((i
< NUMOPCODES
) && !strcmp(mips_opcodes
[i
].name
, name
));
268 struct mips_cl_insn insn
;
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);
278 imm_expr
.X_seg
= absent_section
;
279 offset_expr
.X_seg
= absent_section
;
283 as_bad("%s `%s'", insn_error
, str
);
286 if (insn
.insn_mo
->pinfo
== INSN_MACRO
) {
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
);
294 append_insn(&insn
, NULL
, BFD_RELOC_UNUSED
);
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."
303 * Output an instruction.
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
;
314 #if 0 /* This is testing the address of the frag, not the alignment of
315 the instruction in the current section. */
321 if (address_expr
!= NULL
) {
324 if (address_expr
->X_seg
== &bfd_abs_section
) {
325 switch (reloc_type
) {
327 ip
->insn_opcode
|= address_expr
->X_add_number
;
331 ip
->insn_opcode
|= address_expr
->X_add_number
& 0xffff;
334 case BFD_RELOC_MIPS_JMP
:
335 case BFD_RELOC_16_PCREL_S2
:
342 assert(reloc_type
!= BFD_RELOC_UNUSED
);
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
,
352 md_number_to_chars(f
, ip
->insn_opcode
, 4);
355 * Fill all delay slots with nops.
357 if (!mips_noreorder
) {
358 if (ip
->insn_mo
->pinfo
& ANY_DELAY
) {
360 md_number_to_chars(f
, 0, 4);
364 if (ip
->insn_mo
->pinfo
& INSN_EXTRA_DELAY
) {
366 md_number_to_chars(f
, 0, 4);
373 macro_build (int *counter
,
378 #else /* ! defined (NO_STDARG) */
380 macro_build (counter
, ep
, name
, fmt
, va_alist
)
386 #endif /* ! defined (NO_STDARG) */
388 struct mips_cl_insn insn
;
389 bfd_reloc_code_real_type r
;
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...
403 if (mips_warn_about_macros
&& *counter
== 1)
404 as_warn("Macro instruction expanded into multiple instructions");
406 *counter
+= 1; /* bump instruction counter */
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);
413 while (strcmp(fmt
, insn
.insn_mo
->args
) != 0) {
415 assert(insn
.insn_mo
->name
);
416 assert(strcmp(name
, insn
.insn_mo
->name
) == 0);
418 assert(insn
.insn_mo
->pinfo
!= INSN_MACRO
);
419 insn
.insn_opcode
= insn
.insn_mo
->match
;
432 insn
.insn_opcode
|= va_arg(args
, int) << 16;
438 insn
.insn_opcode
|= va_arg(args
, int) << 16;
442 insn
.insn_opcode
|= va_arg(args
, int) << 11;
447 insn
.insn_opcode
|= va_arg(args
, int) << 11;
451 insn
.insn_opcode
|= va_arg(args
, int) << 6;
455 insn
.insn_opcode
|= va_arg(args
, int) << 6;
462 insn
.insn_opcode
|= va_arg(args
, int) << 21;
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).
480 if (ep
->X_add_symbol
== NULL
&& ep
->X_seg
== &bfd_abs_section
) {
481 insn
.insn_opcode
|= (ep
->X_add_number
>> 2) & 0xffff;
484 r
= BFD_RELOC_16_PCREL_S2
;
493 assert(r
== BFD_RELOC_UNUSED
? ep
== NULL
: ep
!= NULL
);
494 append_insn(&insn
, ep
, r
);
498 * Generate a "lui" instruction.
501 macro_build_lui (counter
, ep
, regnum
)
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";
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
;
522 r
= BFD_RELOC_HI16_S
;
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...
529 if (mips_warn_about_macros
&& *counter
== 1)
530 as_warn("Macro instruction expanded into multiple instructions");
532 *counter
+= 1; /* bump instruction counter */
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);
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
);
544 append_insn(&insn
, &high_expr
, r
);
548 * Generates code to set the $at register to true (one)
549 * if reg is less than the immediate expression.
552 set_at (counter
, reg
)
557 switch (imm_expr
.X_add_number
& 0xffff8000) {
560 macro_build(counter
, &imm_expr
, "slti", "t,r,j", AT
, reg
);
564 macro_build(counter
, &imm_expr
, "ori", "t,r,i", AT
, 0);
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
);
572 macro_build(counter
, NULL
, "slt", "d,v,t", AT
, reg
, AT
);
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.
581 set_at_unsigned (counter
, reg
)
586 switch (imm_expr
.X_add_number
& 0xffff8000) {
589 macro_build(counter
, &imm_expr
, "sltiu", "t,r,j", AT
, reg
);
593 macro_build(counter
, &imm_expr
, "ori", "t,r,i", AT
, 0);
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
);
601 macro_build(counter
, NULL
, "sltu", "d,v,t", AT
, reg
, AT
);
605 check_absolute_expr (ip
, expr
)
606 struct mips_cl_insn
*ip
;
610 if (expr
->X_seg
!= &bfd_abs_section
)
611 as_warn("Instruction %s requires absolute expression", ip
->insn_mo
->name
);
615 * This routine generates the least number of instructions neccessary to load
616 * an absolute expression value into a register.
619 load_register (counter
, ip
, reg
, ep
)
621 struct mips_cl_insn
*ip
;
625 switch (ep
->X_add_number
& 0xffff8000) {
628 macro_build(counter
, ep
, "addiu", "t,r,j", reg
, 0);
632 macro_build(counter
, ep
, "ori", "t,r,i", reg
, 0);
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
);
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
663 struct mips_cl_insn
*ip
;
665 register int treg
, sreg
, dreg
, breg
;
670 int save_reorder_condition
;
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
;
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;
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
695 save_reorder_condition
= mips_noreorder
;
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",
704 mips_noreorder
= save_reorder_condition
;
709 switch (imm_expr
.X_add_number
& 0xffff8000) {
712 macro_build(&icnt
, &imm_expr
,
713 mask
== M_ADD_I
? "addi" : "addiu", "t,r,j", treg
, sreg
);
717 macro_build(&icnt
, &imm_expr
, "ori", "t,r,i", AT
, 0);
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
);
726 macro_build(&icnt
, NULL
,
727 mask
== M_ADD_I
? "add" : "addu", "d,v,t", treg
, sreg
, AT
);
734 switch (imm_expr
.X_add_number
& 0xffff8000) {
739 macro_build(&icnt
, &imm_expr
, "andi", "t,r,i", treg
, sreg
);
742 macro_build(&icnt
, &imm_expr
, "ori", "t,r,i", treg
, sreg
);
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);
749 macro_build(&icnt
, &imm_expr
, "xori", "t,r,i", treg
, sreg
);
756 macro_build(&icnt
, &imm_expr
, "addiu", "t,r,j", AT
, 0);
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
);
766 macro_build(&icnt
, NULL
, "and", "d,v,t", treg
, sreg
, AT
);
769 macro_build(&icnt
, NULL
, "or", "d,v,t", treg
, sreg
, AT
);
772 macro_build(&icnt
, NULL
, "nor", "d,v,t", treg
, sreg
, AT
);
775 macro_build(&icnt
, NULL
, "xor", "d,v,t", treg
, sreg
, AT
);
784 if (imm_expr
.X_add_number
== 0) {
785 macro_build(&icnt
, &offset_expr
, mask
== M_BEQ_I
? "beq" : "bne",
789 load_register(&icnt
, ip
, AT
, &imm_expr
);
790 macro_build(&icnt
, &offset_expr
, mask
== M_BEQ_I
? "beq" : "bne",
796 macro_build(&icnt
, &offset_expr
, "bgez", "s,p", sreg
);
799 macro_build(&icnt
, NULL
, "slt", "d,v,t", AT
, sreg
, treg
);
800 macro_build(&icnt
, &offset_expr
, "beq", "s,t,p", AT
, 0);
804 imm_expr
.X_add_number
++;
807 if (imm_expr
.X_add_number
== 0) {
808 macro_build(&icnt
, &offset_expr
, "bgez", "s,p", sreg
);
811 if (imm_expr
.X_add_number
== 1) {
812 macro_build(&icnt
, &offset_expr
, "bgtz", "s,p", sreg
);
816 macro_build(&icnt
, &offset_expr
, "beq", "s,t,p", AT
, 0);
821 macro_build(&icnt
, &offset_expr
, "b", "p");
824 macro_build(&icnt
, NULL
, "sltu", "d,v,t", AT
, sreg
, treg
);
825 macro_build(&icnt
, &offset_expr
, "beq", "s,t,p", AT
, 0);
829 if (imm_expr
.X_add_number
== 0) {
830 macro_build(&icnt
, &offset_expr
, "b", "p");
833 if (imm_expr
.X_add_number
== 1) {
834 macro_build(&icnt
, &offset_expr
, "bne", "s,t,p", sreg
, 0);
837 set_at_unsigned(&icnt
, sreg
);
838 macro_build(&icnt
, &offset_expr
, "beq", "s,t,p", AT
, 0);
843 macro_build(&icnt
, &offset_expr
, "bgtz", "s,p", sreg
);
846 macro_build(&icnt
, NULL
, "slt", "d,v,t", AT
, treg
, sreg
);
847 macro_build(&icnt
, &offset_expr
, "bne", "s,t,p", AT
, 0);
852 macro_build(&icnt
, &offset_expr
, "bne", "s,t,p", sreg
, 0);
855 macro_build(&icnt
, NULL
, "sltu", "d,v,t", AT
, treg
, sreg
);
856 macro_build(&icnt
, &offset_expr
, "bne", "s,t,p", AT
, 0);
860 if (imm_expr
.X_add_number
== 0) {
861 macro_build(&icnt
, &offset_expr
, "bne", "s,t,p", sreg
, 0);
864 if (imm_expr
.X_add_number
== -1) {
867 as_warn("Instruction %s is a nop; deleted", ip
->insn_mo
->name
);
870 imm_expr
.X_add_number
++;
871 set_at_unsigned(&icnt
, sreg
);
872 macro_build(&icnt
, &offset_expr
, "beq", "s,t,p", AT
, 0);
877 macro_build(&icnt
, &offset_expr
, "blez", "s,p", sreg
);
880 macro_build(&icnt
, NULL
, "slt", "d,v,t", AT
, treg
, sreg
);
881 macro_build(&icnt
, &offset_expr
, "beq", "s,t,p", AT
, 0);
885 if (imm_expr
.X_add_number
== 0) {
886 macro_build(&icnt
, &offset_expr
, "blez", "s,p", sreg
);
889 if (imm_expr
.X_add_number
== -1) {
890 macro_build(&icnt
, &offset_expr
, "bltz", "s,p", sreg
);
893 imm_expr
.X_add_number
++;
895 macro_build(&icnt
, &offset_expr
, "bne", "s,t,p", AT
, 0);
900 macro_build(&icnt
, &offset_expr
, "beq", "s,t,p", sreg
, 0);
903 macro_build(&icnt
, NULL
, "sltu", "d,v,t", AT
, treg
, sreg
);
904 macro_build(&icnt
, &offset_expr
, "beq", "s,t,p", AT
, 0);
908 if (imm_expr
.X_add_number
== 0) {
909 macro_build(&icnt
, &offset_expr
, "beq", "s,t,p", sreg
, 0);
912 if (imm_expr
.X_add_number
== -1) {
913 macro_build(&icnt
, &offset_expr
, "b", "p");
916 imm_expr
.X_add_number
++;
917 set_at_unsigned(&icnt
, sreg
);
918 macro_build(&icnt
, &offset_expr
, "bne", "s,t,p", AT
, 0);
923 macro_build(&icnt
, &offset_expr
, "bltz", "s,p", sreg
);
926 macro_build(&icnt
, NULL
, "slt", "d,v,t", AT
, sreg
, treg
);
927 macro_build(&icnt
, &offset_expr
, "bne", "s,t,p", AT
, 0);
931 if (imm_expr
.X_add_number
== 0) {
932 macro_build(&icnt
, &offset_expr
, "bltz", "s,p", sreg
);
935 if (imm_expr
.X_add_number
== 1) {
936 macro_build(&icnt
, &offset_expr
, "blez", "s,p", sreg
);
940 macro_build(&icnt
, &offset_expr
, "bne", "s,t,p", AT
, 0);
947 as_warn("Instruction %s is a nop; deleted", ip
->insn_mo
->name
);
950 macro_build(&icnt
, NULL
, "sltu", "d,v,t", AT
, sreg
, treg
);
951 macro_build(&icnt
, &offset_expr
, "bne", "s,t,p", AT
, 0);
955 if (imm_expr
.X_add_number
== 0) {
958 as_warn("Instruction %s is a nop; deleted", ip
->insn_mo
->name
);
961 if (imm_expr
.X_add_number
== 1) {
962 macro_build(&icnt
, &offset_expr
, "beq", "s,t,p", sreg
, 0);
965 set_at_unsigned(&icnt
, sreg
);
966 macro_build(&icnt
, &offset_expr
, "bne", "s,t,p", AT
, 0);
972 as_warn("Divide by zero.");
973 macro_build(&icnt
, NULL
, "break", "c", 7);
977 save_reorder_condition
= mips_noreorder
;
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. */
1003 if (imm_expr
.X_add_number
== 0) {
1004 as_warn("Divide by zero.");
1005 macro_build(&icnt
, NULL
, "break", "c", 7);
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
);
1012 macro_build(&icnt
, NULL
, "move", "d,s", dreg
, 0);
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
);
1020 macro_build(&icnt
, NULL
, "divu", "s,t", sreg
, AT
);
1022 if (mask
== (int)M_DIV_3I
|| mask
== (int)M_DIVU_3I
)
1023 macro_build(&icnt
, NULL
, "mflo", "d", dreg
);
1025 macro_build(&icnt
, NULL
, "mfhi", "d", dreg
);
1026 /* two implicit nop's required for mflo or mfhi */
1031 save_reorder_condition
= mips_noreorder
;
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. */
1044 if (offset_expr
.X_seg
== &bfd_abs_section
) {
1045 load_register(&icnt
, ip
, treg
, &offset_expr
);
1048 macro_build_lui(&icnt
, &offset_expr
, treg
);
1049 macro_build(&icnt
, &offset_expr
, "addiu", "t,r,j", treg
, treg
);
1053 tempreg
= (breg
== treg
) ? AT
: treg
;
1054 if (offset_expr
.X_seg
== &bfd_abs_section
)
1055 load_register(&icnt
, ip
, tempreg
, &offset_expr
);
1057 macro_build_lui(&icnt
, &offset_expr
, tempreg
);
1058 macro_build(&icnt
, &offset_expr
, "addiu", "t,r,j", tempreg
, tempreg
);
1061 macro_build(&icnt
, NULL
, "addu", "d,v,t", treg
, tempreg
, breg
);
1137 macro_build_lui(&icnt
, &offset_expr
, tempreg
);
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)",
1148 load_register(&icnt
, ip
, treg
, &imm_expr
);
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)
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
);
1168 0x4003a0 <main>: lwc1 $f0,-32752($gp)
1169 0x4003a4 <main+4>: lwc1 $f1,-32748($gp)
1170 0x4003a8 <main+8>: nop
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
);
1179 save_reorder_condition
= mips_noreorder
;
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
);
1190 * The MIPS assembler seems to check for X_add_number not
1191 * being double aligned and generating:
1194 * addiu at,at,%lo(foo+1)
1197 * But, the resulting address is the same after relocation so why
1198 * generate the extra instruction?
1200 macro_build_lui(&icnt
, &offset_expr
, AT
);
1202 macro_build(&icnt
, NULL
, "addu", "d,v,t", AT
, AT
, breg
);
1203 save_reorder_condition
= mips_noreorder
;
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
);
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
);
1238 macro_build_lui(&icnt
, &offset_expr
, tempreg
);
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
);
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 */
1256 * The mips assembler some times generates shifts and adds.
1257 * Im not trying to be that fancy. GCC should do this for us
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 */
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
);
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
);
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
);
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
);
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
);
1303 macro_build_lui(&icnt
, &offset_expr
, AT
);
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
);
1313 macro_build(&icnt
, &expr1
, "sltiu", "t,r,j", dreg
, treg
);
1315 macro_build(&icnt
, &expr1
, "sltiu", "t,r,j", dreg
, sreg
);
1317 macro_build(&icnt
, NULL
, "xor", "d,v,t", dreg
, sreg
, treg
);
1318 macro_build(&icnt
, &expr1
, "sltiu", "t,r,j", dreg
, dreg
);
1323 if (imm_expr
.X_add_number
== 0) {
1324 macro_build(&icnt
, &expr1
, "sltiu", "t,r,j", dreg
, sreg
);
1328 /* result is always false */
1329 macro_build(&icnt
, NULL
, "move", "d,s", dreg
, 0);
1332 switch (imm_expr
.X_add_number
& 0xffff8000) {
1335 macro_build(&icnt
, &imm_expr
, "xori", "t,r,i", dreg
, sreg
);
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
);
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
);
1355 macro_build(&icnt
, &expr1
, "sltiu", "t,r,j", dreg
, dreg
);
1360 case M_SGE
: /* sreg >= treg <==> not (sreg < treg) */
1366 macro_build(&icnt
, NULL
, s
, "d,v,t", dreg
, sreg
, treg
);
1367 macro_build(&icnt
, &expr1
, "xori", "t,r,i", dreg
, dreg
);
1370 case M_SGE_I
: /* sreg >= I <==> not (sreg < 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
);
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
);
1382 macro_build(&icnt
, &expr1
, "xori", "t,r,i", dreg
, dreg
);
1387 case M_SGT
: /* sreg > treg <==> treg < sreg */
1393 macro_build(&icnt
, NULL
, s
, "d,v,t", dreg
, treg
, sreg
);
1396 case M_SGT_I
: /* sreg > I <==> I < sreg */
1402 load_register(&icnt
, ip
, AT
, &imm_expr
);
1403 macro_build(&icnt
, NULL
, s
, "d,v,t", dreg
, AT
, sreg
);
1406 case M_SLE
: /* sreg <= treg <==> treg >= sreg <==> not (treg < sreg) */
1412 macro_build(&icnt
, NULL
, s
, "d,v,t", dreg
, treg
, sreg
);
1413 macro_build(&icnt
, &imm_expr
, "xori", "t,r,i", dreg
, dreg
);
1416 case M_SLE_I
: /* sreg <= I <==> I >= sreg <==> not (I < sreg) */
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
);
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
);
1432 load_register(&icnt
, ip
, AT
, &imm_expr
);
1433 macro_build(&icnt
, NULL
, "slt", "d,v,t", dreg
, sreg
, AT
);
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
);
1441 load_register(&icnt
, ip
, AT
, &imm_expr
);
1442 macro_build(&icnt
, NULL
, "sltu", "d,v,t", dreg
, sreg
, AT
);
1447 macro_build(&icnt
, NULL
, "sltu", "d,v,t", dreg
, 0, treg
);
1449 macro_build(&icnt
, NULL
, "sltu", "d,v,t", dreg
, 0, sreg
);
1451 macro_build(&icnt
, NULL
, "xor", "d,v,t", dreg
, sreg
, treg
);
1452 macro_build(&icnt
, NULL
, "sltu", "d,v,t", dreg
, 0, dreg
);
1457 if (imm_expr
.X_add_number
== 0) {
1458 macro_build(&icnt
, NULL
, "sltu", "d,v,t", dreg
, 0, sreg
);
1462 /* result is always true */
1463 macro_build(&icnt
, &expr1
, "addiu", "t,r,j", dreg
, 0);
1466 switch (imm_expr
.X_add_number
& 0xffff8000) {
1469 macro_build(&icnt
, &imm_expr
, "xori", "t,r,i", dreg
, sreg
);
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
);
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
);
1489 macro_build(&icnt
, NULL
, "sltu", "d,v,t", dreg
, 0, dreg
);
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
);
1500 load_register(&icnt
, ip
, AT
, &imm_expr
);
1501 macro_build(&icnt
, NULL
, "sub", "d,v,t", dreg
, sreg
, AT
);
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
);
1510 load_register(&icnt
, ip
, AT
, &imm_expr
);
1511 macro_build(&icnt
, NULL
, "subu", "d,v,t", dreg
, sreg
, AT
);
1516 sreg
= (ip
->insn_opcode
>> 11) & 0x1f; /* floating reg */
1517 dreg
= (ip
->insn_opcode
>> 06) & 0x1f; /* floating reg */
1520 * Is the double cfc1 instruction a bug in the mips assembler;
1521 * or is there a reason for it?
1523 save_reorder_condition
= mips_noreorder
;
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
;
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
);
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
);
1567 if (offset_expr
.X_seg
== &bfd_abs_section
)
1568 load_register(&icnt
, ip
, AT
, &offset_expr
);
1570 macro_build_lui(&icnt
, &offset_expr
, AT
);
1571 macro_build(&icnt
, &offset_expr
, "addiu", "t,r,j", AT
, AT
);
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
);
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
);
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
);
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
);
1604 if (offset_expr
.X_seg
== &bfd_abs_section
)
1605 load_register(&icnt
, ip
, AT
, &offset_expr
);
1607 macro_build_lui(&icnt
, &offset_expr
, AT
);
1608 macro_build(&icnt
, &offset_expr
, "addiu", "t,r,j", AT
, AT
);
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
);
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
);
1629 as_bad("Macro %s not implemented yet", ip
->insn_mo
->name
);
1632 as_warn("Macro used $at after \".set noat\"");
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.
1644 struct mips_cl_insn
*ip
;
1649 struct mips_opcode
*insn
;
1652 unsigned int lastregno
= 0;
1657 for (s
= str
; islower(*s
) || (*s
>= '0' && *s
<= '3') || *s
== '.'; ++s
)
1669 as_warn("Unknown opcode: `%s'", str
);
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";
1679 assert(strcmp(insn
->name
, str
) == 0);
1681 ip
->insn_opcode
= insn
->match
;
1682 for (args
= insn
->args
; ; ++args
) {
1687 case '\0': /* end of args */
1699 ip
->insn_opcode
|= lastregno
<< 21;
1704 ip
->insn_opcode
|= lastregno
<< 16;
1708 ip
->insn_opcode
|= lastregno
<< 11;
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');
1723 case ')': /* these must match exactly */
1728 case '<': /* must be at least one digit */
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.
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;
1742 ip
->insn_opcode
|= imm_expr
.X_add_number
<< 6;
1743 imm_expr
.X_seg
= absent_section
;
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
;
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 */
1766 if (isdigit(s
[1])) {
1773 } while (isdigit(*s
));
1774 } else if (s
[1] == 'f' && s
[2] == 'p') {
1777 } else if (s
[1] == 's' && s
[2] == 'p') {
1780 } else if (s
[1] == 'g' && s
[2] == 'p') {
1783 } else if (s
[1] == 'a' && s
[2] == 't') {
1789 as_bad("Invalid register number (%d)", regno
);
1790 if (regno
== AT
&& !mips_noat
)
1791 as_warn("Used $at without \".set noat\"");
1795 if (args
[1] != *s
) {
1796 if (c
== 'r' || c
== 'v' || c
== 'w') {
1807 ip
->insn_opcode
|= regno
<< 21;
1810 ip
->insn_opcode
|= regno
<< 11;
1814 ip
->insn_opcode
|= regno
<< 16;
1823 ip
->insn_opcode
|= lastregno
<< 21;
1826 ip
->insn_opcode
|= lastregno
<< 16;
1831 case 'D': /* floating point destination register */
1832 case 'S': /* floating point source register */
1833 case 'T': /* floating point target register */
1837 if (s
[0] == '$' && s
[1] == 'f' && isdigit(s
[2])) {
1844 } while (isdigit(*s
));
1847 as_bad("Invalid float register number (%d)", regno
);
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",
1860 if (args
[1] != *s
) {
1861 if (c
== 'V' || c
== 'W') {
1869 ip
->insn_opcode
|= regno
<< 6;
1873 ip
->insn_opcode
|= regno
<< 11;
1877 ip
->insn_opcode
|= regno
<< 16;
1884 ip
->insn_opcode
|= lastregno
<< 11;
1887 ip
->insn_opcode
|= lastregno
<< 16;
1893 my_getExpression(&imm_expr
, s
);
1894 check_absolute_expr(ip
, &imm_expr
);
1899 my_getExpression(&offset_expr
, s
);
1900 imm_reloc
= BFD_RELOC_32
;
1905 as_bad("Floating point constants only implemented for pseudo ops.");
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
);
1914 if (imm_expr
.X_seg
== &bfd_abs_section
)
1915 imm_expr
.X_add_number
=
1916 (imm_expr
.X_add_number
>> 16) & 0xffff;
1918 imm_reloc
= BFD_RELOC_HI16_S
;
1920 imm_reloc
= BFD_RELOC_HI16
;
1923 check_absolute_expr(ip
, &imm_expr
);
1925 if ((unsigned long) imm_expr
.X_add_number
> 65535)
1926 as_bad("16 bit expression not in range 0..65535");
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");
1935 case 'o': /* 16 bit offset */
1936 c
= my_getSmallExpression(&offset_expr
, s
);
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
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)
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;
1956 case 'p': /* pc relative offset */
1957 offset_reloc
= BFD_RELOC_16_PCREL_S2
;
1958 my_getExpression(&offset_expr
, s
);
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
;
1969 if (imm_expr
.X_seg
== &bfd_abs_section
)
1970 imm_expr
.X_add_number
=
1971 (imm_expr
.X_add_number
>> 16) & 0xffff;
1973 imm_reloc
= BFD_RELOC_HI16_S
;
1975 imm_reloc
= BFD_RELOC_HI16
;
1981 case 'a': /* 26 bit address */
1982 my_getExpression(&offset_expr
, s
);
1984 offset_reloc
= BFD_RELOC_MIPS_JMP
;
1988 fprintf(stderr
, "bad char = '%c'\n", *args
);
1993 /* Args don't match. */
1994 if (insn
+ 1 < &mips_opcodes
[NUMOPCODES
] &&
1995 !strcmp(insn
->name
, insn
[1].name
)) {
2000 insn_error
= "ERROR: Illegal operands";
2009 my_getSmallExpression (ep
, str
)
2020 ((str
[1] == 'h' && str
[2] == 'i')
2021 || (str
[1] == 'H' && str
[2] == 'I')
2022 || (str
[1] == 'l' && str
[2] == 'o'))
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...)
2037 for (sp
= str
; *sp
&& *sp
!= ','; sp
++)
2039 if (sp
- 4 >= str
&& sp
[-1] == RP
) {
2040 if (isdigit(sp
[-2])) {
2041 for (sp
-= 3; sp
>= str
&& isdigit(*sp
); sp
--)
2043 if (*sp
== '$' && sp
> str
&& sp
[-1] == LP
) {
2047 } else if (sp
- 5 >= str
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'))) {
2057 /* no expression means zero offset */
2059 /* %xx(reg) is an error */
2060 ep
->X_seg
= absent_section
;
2063 ep
->X_seg
= &bfd_abs_section
;
2066 ep
->X_add_symbol
= NULL
;
2067 ep
->X_subtract_symbol
= NULL
;
2068 ep
->X_add_number
= 0;
2071 my_getExpression(ep
, str
);
2078 my_getExpression(ep
, str
);
2079 return c
; /* => %hi or %lo encountered */
2083 my_getExpression (ep
, str
)
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
;
2098 md_atof (type
,litP
,sizeP
)
2108 md_number_to_chars (buf
, val
, n
)
2114 switch (byte_order
) {
2161 md_parse_option (argP
, cntP
, vecP
)
2166 /* Accept -nocpp but ignore it. */
2167 if (!strcmp(*argP
, "nocpp")) {
2171 return 1; /* pretend you parsed the character */
2175 md_pcrel_from (fixP
)
2178 /* return the address of the delay slot */
2179 return fixP
->fx_size
+ fixP
->fx_where
+ fixP
->fx_frag
->fr_address
;
2183 md_apply_fix (fixP
, valueP
)
2190 assert(fixP
->fx_size
== 4);
2193 fixP
->fx_addnumber
= value
; /* Remember value for tc_gen_reloc */
2195 switch (fixP
->fx_r_type
) {
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 */
2204 case BFD_RELOC_16_PCREL_S2
:
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).
2211 as_warn("Branch to odd address (%x)", value
);
2213 if ((value
& ~0xFFFF) && (value
& ~0xFFFF) != (-1 & ~0xFFFF))
2214 as_bad("Relocation overflow");
2216 /* update old instruction data */
2217 buf
= (unsigned char *)(fixP
->fx_where
+ fixP
->fx_frag
->fr_literal
);
2218 switch (byte_order
) {
2220 insn
= (buf
[3] << 24) | (buf
[2] << 16) | (buf
[1] << 8) | buf
[0];
2224 insn
= (buf
[0] << 24) | (buf
[1] << 16) | (buf
[2] << 8) | buf
[3];
2231 insn
|= value
& 0xFFFF;
2232 md_number_to_chars(buf
, insn
, 4);
2246 const struct mips_opcode
*p
;
2247 int treg
, sreg
, dreg
, shamt
;
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;
2261 for (args
= p
->args
; ; ++args
) {
2271 printf("%c", *args
);
2275 assert(treg
== sreg
);
2276 printf("$%d,$%d", treg
, sreg
);
2280 printf("$%d", dreg
);
2284 printf("$%d", treg
);
2289 printf("$%d", sreg
);
2293 printf("0x%08lx", oc
& 0x1ffffff);
2304 printf("$%d", shamt
);
2315 printf("%08lx UNDEFINED\n", oc
);
2326 name
= input_line_pointer
;
2327 c
= get_symbol_end();
2328 p
= (symbolS
*) symbol_find_or_make(name
);
2329 *input_line_pointer
= c
;
2334 get_optional_absolute_expression ()
2339 s
= expression(&exp
);
2340 if (!(s
== &bfd_abs_section
|| s
== big_section
|| s
== absent_section
)) {
2341 as_bad("Bad Absolute Expression.");
2343 return exp
.X_add_number
;
2351 register long temp_fill
;
2352 long max_alignment
= 15;
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.
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.");
2373 if (*input_line_pointer
== ',') {
2374 input_line_pointer
++;
2375 temp_fill
= get_absolute_expression ();
2381 frag_align (temp
, (int)temp_fill
);
2386 record_alignment(now_seg
, temp
);
2388 demand_empty_rest_of_line();
2404 #ifdef BFD_ASSEMBLER
2405 subseg_set (bss_section
, (subsegT
) get_absolute_expression ());
2407 subseg_new (bss_section
, (subsegT
) get_absolute_expression ());
2409 demand_empty_rest_of_line ();
2412 as_bad("Global pointers not supported; recompile -G 0");
2423 if (log_size
> 0 && auto_align
)
2424 frag_align(log_size
, 0);
2425 cons(1 << log_size
);
2432 as_fatal("Encountered `.err', aborting assembly");
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
);
2450 s_float_cons (is_double
)
2455 int error_code
, repeat
;
2456 extern FLONUM_TYPE generic_floating_point_number
;
2465 if (! is_end_of_line
[(unsigned char) *input_line_pointer
]) {
2467 error_code
= atof_generic(&input_line_pointer
, ".", EXP_CHARS
,
2468 &generic_floating_point_number
);
2470 if (error_code
== ERROR_EXPONENT_OVERFLOW
)
2471 as_warn("Bad floating-point constant: exponent overflow");
2473 as_warn("Bad floating-point constant: unknown error code=%d.", error_code
);
2477 gen_to_words((LITTLENUM_TYPE
*)words
,
2479 11 /* exponent_bits */ );
2481 gen_to_words((LITTLENUM_TYPE
*)words
,
2483 8 /* exponent_bits */ );
2485 if (*input_line_pointer
== ':') {
2486 input_line_pointer
++;
2487 repeat
= get_absolute_expression();
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);
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);
2507 if (*input_line_pointer
!= ',') break;
2508 input_line_pointer
++;
2512 demand_empty_rest_of_line();
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();
2529 char *name
= input_line_pointer
, ch
;
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';
2536 if (strcmp(name
, "reorder") == 0) {
2538 } else if (strcmp(name
, "noreorder") == 0) {
2540 } else if (strcmp(name
, "at") == 0) {
2542 } else if (strcmp(name
, "noat") == 0) {
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) {
2552 } else if (strcmp(name
, "nomove") == 0 || strcmp(name
, "volatile") == 0) {
2554 } else if (strcmp(name
, "bopt") == 0) {
2556 } else if (strcmp(name
, "nobopt") == 0) {
2559 as_warn("Tried to set unrecognized symbol: %s\n", name
);
2561 *input_line_pointer
= ch
;
2562 demand_empty_rest_of_line();
2571 if (*input_line_pointer
++ != '$')
2573 as_warn ("expected `$'");
2576 if (isdigit ((unsigned char) *input_line_pointer
))
2578 reg
= get_absolute_expression ();
2579 if (reg
< 0 || reg
>= 32)
2581 as_warn ("Bad register number");
2587 if (strncmp (input_line_pointer
, "fp", 2) == 0)
2589 else if (strncmp (input_line_pointer
, "sp", 2) == 0)
2591 else if (strncmp (input_line_pointer
, "gp", 2) == 0)
2593 else if (strncmp (input_line_pointer
, "at", 2) == 0)
2597 as_warn ("Unrecognized register name");
2600 input_line_pointer
+= 2;
2606 * Translate internal representation of relocation info to BFD target format.
2609 tc_gen_reloc (section
, fixp
)
2615 reloc
= (arelent
*) xmalloc (sizeof (arelent
));
2616 assert (reloc
!= 0);
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
;
2626 reloc
->addend
= - reloc
->address
;
2628 reloc
->howto
= bfd_reloc_type_lookup (stdoutput
, fixp
->fx_r_type
);
2629 assert (reloc
->howto
!= 0);
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
2636 bfd_get_section_vma (stdoutput
,
2637 bfd_get_section (fixp
->fx_addsy
->bsym
));
2643 /* should never be called */
2645 md_section_align(seg
, addr
)
2649 int align
= bfd_get_section_alignment(stdoutput
, seg
);
2651 return ((addr
+ (1 << align
) - 1) & (-1 << align
));
2655 md_estimate_size_before_relax(fragP
, segtype
)
2659 as_fatal("md_estimate_size_before_relax");
2661 } /* md_estimate_size_before_relax() */
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. */
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
;
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
;
2696 struct file
*proc_file
;
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
;
2709 static struct obstack proc_frags
;
2710 static procS
*proc_lastP
;
2711 static procS
*proc_rootP
;
2712 static int numprocs
;
2717 obstack_begin(&proc_frags
, 0x2000);
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");
2728 extern char hex_value
[];
2736 if (*input_line_pointer
== '-') {
2737 ++input_line_pointer
;
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
)) {
2747 val
|= hex_value
[(int) *input_line_pointer
++];
2749 return negative
? -val
: val
;
2751 ++input_line_pointer
;
2752 while (isdigit(*input_line_pointer
)) {
2754 val
|= *input_line_pointer
++ - '0';
2756 return negative
? -val
: val
;
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");
2765 while (isdigit(*input_line_pointer
)) {
2767 val
+= *input_line_pointer
++ - '0';
2769 return negative
? -val
: val
;
2772 /* The .file directive; just like the usual .file directive, but there
2773 is an initial number which is the ECOFF file index. */
2781 line
= get_number();
2786 /* The .end directive. */
2794 if (!is_end_of_line
[(unsigned char) *input_line_pointer
]) {
2796 demand_empty_rest_of_line();
2799 if (now_seg
!= text_section
)
2800 as_warn(".end not in text section");
2802 as_warn(".end and no .ent seen yet.");
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.");
2812 proc_lastP
->proc_end
= (symbolS
*) 1;
2815 /* The .aent and .ent directives. */
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.");
2833 if (!aent
&& proc_lastP
&& proc_lastP
->proc_end
== NULL
)
2834 as_warn("missing `.end'");
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
;
2849 proc_lastP
->proc_next
= procP
;
2855 demand_empty_rest_of_line();
2858 /* The .frame directive. */
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();
2881 proc_rootP
->proc_framereg
= frame_reg
;
2882 proc_rootP
->proc_frameoffset
= frame_off
;
2883 proc_rootP
->proc_pcreg
= pcreg
;
2884 /* bob macho .frame */
2886 /* We don't have to write out a frame stab for unoptimized code. */
2887 if (!(frame_reg
== 30 && frame_off
== 0)) {
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 */
2898 demand_empty_rest_of_line();
2902 /* The .fmask and .mask directives. */
2909 char str
[100], *strP
;
2915 mask
= get_number();
2916 if (*input_line_pointer
== ',')
2917 input_line_pointer
++;
2918 off
= get_absolute_expression();
2920 /* bob only for coff */
2922 if (reg_type
== 'F' ) {
2923 proc_rootP
->proc_fpreg_mask
= mask
;
2924 proc_rootP
->proc_fpreg_offset
= off
;
2926 proc_rootP
->proc_reg_mask
= mask
;
2927 proc_rootP
->proc_reg_offset
= off
;
2930 /* bob macho .mask + .fmask */
2932 /* We don't have to write out a mask stab if no saved regs. */
2935 as_warn("No .ent for .mask to use." );
2937 for (i
=0; i
<32; i
++ ) {
2939 sprintf(strP
, "%c%d,", reg_type
, i
);
2940 strP
+= strlen(strP
);
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 */
2955 /* The .loc directive. */
2966 assert(now_seg
== text_section
);
2968 lineno
= get_number();
2969 addroff
= obstack_next_free(&frags
) - frag_now
->fr_literal
;
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
;
2979 #endif /* ! defined (OBJ_ECOFF) */