| 1 | /* tc-i860.c -- Assembler for the Intel i860 architecture.
 | 
|---|
| 2 |    Copyright 1989, 1992, 1993, 1994, 1995, 1998, 1999, 2000, 2001, 2002
 | 
|---|
| 3 |    Free Software Foundation, Inc.
 | 
|---|
| 4 | 
 | 
|---|
| 5 |    Brought back from the dead and completely reworked
 | 
|---|
| 6 |    by Jason Eckhardt <jle@cygnus.com>.
 | 
|---|
| 7 | 
 | 
|---|
| 8 |    This file is part of GAS, the GNU Assembler.
 | 
|---|
| 9 | 
 | 
|---|
| 10 |    GAS is free software; you can redistribute it and/or modify
 | 
|---|
| 11 |    it under the terms of the GNU General Public License as published by
 | 
|---|
| 12 |    the Free Software Foundation; either version 2, or (at your option)
 | 
|---|
| 13 |    any later version.
 | 
|---|
| 14 | 
 | 
|---|
| 15 |    GAS is distributed in the hope that it will be useful,
 | 
|---|
| 16 |    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|---|
| 17 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
|---|
| 18 |    GNU General Public License for more details.
 | 
|---|
| 19 | 
 | 
|---|
| 20 |    You should have received a copy of the GNU General Public License along
 | 
|---|
| 21 |    with GAS; see the file COPYING.  If not, write to the Free Software
 | 
|---|
| 22 |    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 | 
|---|
| 23 | 
 | 
|---|
| 24 | #include <stdio.h>
 | 
|---|
| 25 | #include <string.h>
 | 
|---|
| 26 | #include "as.h"
 | 
|---|
| 27 | #include "safe-ctype.h"
 | 
|---|
| 28 | #include "subsegs.h"
 | 
|---|
| 29 | #include "opcode/i860.h"
 | 
|---|
| 30 | #include "elf/i860.h"
 | 
|---|
| 31 | 
 | 
|---|
| 32 | /* Defined by default since this is primarily a SVR4/860 assembler.
 | 
|---|
| 33 |    However, I'm trying to leave the door open for Intel syntax. Of course,
 | 
|---|
| 34 |    if full support for anything other than SVR4 is done, then we should
 | 
|---|
| 35 |    select this based on a command-line flag.  */
 | 
|---|
| 36 | #define SYNTAX_SVR4
 | 
|---|
| 37 | 
 | 
|---|
| 38 | /* The opcode hash table.  */
 | 
|---|
| 39 | static struct hash_control *op_hash = NULL;
 | 
|---|
| 40 | 
 | 
|---|
| 41 | /* These characters always start a comment.  */
 | 
|---|
| 42 | const char comment_chars[] = "#!/";
 | 
|---|
| 43 | 
 | 
|---|
| 44 | /* These characters start a comment at the beginning of a line.  */
 | 
|---|
| 45 | const char line_comment_chars[] = "#/";
 | 
|---|
| 46 | 
 | 
|---|
| 47 | const char line_separator_chars[] = ";";
 | 
|---|
| 48 | 
 | 
|---|
| 49 | /* Characters that can be used to separate the mantissa from the exponent
 | 
|---|
| 50 |    in floating point numbers.  */
 | 
|---|
| 51 | const char EXP_CHARS[] = "eE";
 | 
|---|
| 52 | 
 | 
|---|
| 53 | /* Characters that indicate this number is a floating point constant.
 | 
|---|
| 54 |    As in 0f12.456 or 0d1.2345e12.  */
 | 
|---|
| 55 | const char FLT_CHARS[] = "rRsSfFdDxXpP";
 | 
|---|
| 56 | 
 | 
|---|
| 57 | /* Register prefix.  */
 | 
|---|
| 58 | #ifdef SYNTAX_SVR4
 | 
|---|
| 59 | static const char reg_prefix = '%';
 | 
|---|
| 60 | #else
 | 
|---|
| 61 | static const char reg_prefix = 0;
 | 
|---|
| 62 | #endif
 | 
|---|
| 63 | 
 | 
|---|
| 64 | struct i860_it
 | 
|---|
| 65 | {
 | 
|---|
| 66 |   char *error;
 | 
|---|
| 67 |   unsigned long opcode;
 | 
|---|
| 68 |   expressionS exp;
 | 
|---|
| 69 |   enum expand_type expand;
 | 
|---|
| 70 |   bfd_reloc_code_real_type reloc;
 | 
|---|
| 71 |   int pcrel;
 | 
|---|
| 72 |   valueT fup;
 | 
|---|
| 73 | } the_insn;
 | 
|---|
| 74 | 
 | 
|---|
| 75 | static char *expr_end;
 | 
|---|
| 76 | 
 | 
|---|
| 77 | /* Indicates error if a pseudo operation was expanded after a branch.  */
 | 
|---|
| 78 | static char last_expand;
 | 
|---|
| 79 | 
 | 
|---|
| 80 | /* If true, then warn if any pseudo operations were expanded.  */
 | 
|---|
| 81 | static int target_warn_expand = 0;
 | 
|---|
| 82 | 
 | 
|---|
| 83 | /* Prototypes.  */
 | 
|---|
| 84 | static void i860_process_insn   PARAMS ((char *));
 | 
|---|
| 85 | static void s_dual              PARAMS ((int));
 | 
|---|
| 86 | static void s_enddual           PARAMS ((int));
 | 
|---|
| 87 | static void s_atmp              PARAMS ((int));
 | 
|---|
| 88 | static int i860_get_expression  PARAMS ((char *));
 | 
|---|
| 89 | static bfd_reloc_code_real_type obtain_reloc_for_imm16
 | 
|---|
| 90 |   PARAMS ((fixS *, long *));
 | 
|---|
| 91 | #ifdef DEBUG_I860
 | 
|---|
| 92 | static void print_insn          PARAMS ((struct i860_it *));
 | 
|---|
| 93 | #endif
 | 
|---|
| 94 | 
 | 
|---|
| 95 | const pseudo_typeS md_pseudo_table[] =
 | 
|---|
| 96 | {
 | 
|---|
| 97 | #ifdef OBJ_ELF
 | 
|---|
| 98 |   {"align",   s_align_bytes, 0},
 | 
|---|
| 99 | #endif
 | 
|---|
| 100 |   {"dual",    s_dual,        0},
 | 
|---|
| 101 |   {"enddual", s_enddual,     0},
 | 
|---|
| 102 |   {"atmp",    s_atmp,        0},
 | 
|---|
| 103 |   {NULL,      0,             0},
 | 
|---|
| 104 | };
 | 
|---|
| 105 | 
 | 
|---|
| 106 | /* Dual-instruction mode handling.  */
 | 
|---|
| 107 | enum dual
 | 
|---|
| 108 | {
 | 
|---|
| 109 |   DUAL_OFF = 0, DUAL_ON, DUAL_DDOT, DUAL_ONDDOT,
 | 
|---|
| 110 | };
 | 
|---|
| 111 | static enum dual dual_mode = DUAL_OFF;
 | 
|---|
| 112 | 
 | 
|---|
| 113 | /* Handle ".dual" directive.  */
 | 
|---|
| 114 | static void
 | 
|---|
| 115 | s_dual (ignore)
 | 
|---|
| 116 |      int ignore ATTRIBUTE_UNUSED;
 | 
|---|
| 117 | {
 | 
|---|
| 118 |   dual_mode = DUAL_ON;
 | 
|---|
| 119 | }
 | 
|---|
| 120 | 
 | 
|---|
| 121 | /* Handle ".enddual" directive.  */
 | 
|---|
| 122 | static void
 | 
|---|
| 123 | s_enddual (ignore)
 | 
|---|
| 124 |      int ignore ATTRIBUTE_UNUSED;
 | 
|---|
| 125 | {
 | 
|---|
| 126 |   dual_mode = DUAL_OFF;
 | 
|---|
| 127 | }
 | 
|---|
| 128 | 
 | 
|---|
| 129 | /* Temporary register used when expanding assembler pseudo operations.  */
 | 
|---|
| 130 | static int atmp = 31;
 | 
|---|
| 131 | 
 | 
|---|
| 132 | static void
 | 
|---|
| 133 | s_atmp (ignore)
 | 
|---|
| 134 |      int ignore ATTRIBUTE_UNUSED;
 | 
|---|
| 135 | {
 | 
|---|
| 136 |   register int temp;
 | 
|---|
| 137 |   if (strncmp (input_line_pointer, "sp", 2) == 0)
 | 
|---|
| 138 |     {
 | 
|---|
| 139 |       input_line_pointer += 2;
 | 
|---|
| 140 |       atmp = 2;
 | 
|---|
| 141 |     }
 | 
|---|
| 142 |   else if (strncmp (input_line_pointer, "fp", 2) == 0)
 | 
|---|
| 143 |     {
 | 
|---|
| 144 |       input_line_pointer += 2;
 | 
|---|
| 145 |       atmp = 3;
 | 
|---|
| 146 |     }
 | 
|---|
| 147 |   else if (strncmp (input_line_pointer, "r", 1) == 0)
 | 
|---|
| 148 |     {
 | 
|---|
| 149 |       input_line_pointer += 1;
 | 
|---|
| 150 |       temp = get_absolute_expression ();
 | 
|---|
| 151 |       if (temp >= 0 && temp <= 31)
 | 
|---|
| 152 |         atmp = temp;
 | 
|---|
| 153 |       else
 | 
|---|
| 154 |         as_bad (_("Unknown temporary pseudo register"));
 | 
|---|
| 155 |     }
 | 
|---|
| 156 |   else
 | 
|---|
| 157 |     {
 | 
|---|
| 158 |       as_bad (_("Unknown temporary pseudo register"));
 | 
|---|
| 159 |     }
 | 
|---|
| 160 |   demand_empty_rest_of_line ();
 | 
|---|
| 161 | }
 | 
|---|
| 162 | 
 | 
|---|
| 163 | /* This function is called once, at assembler startup time.  It should
 | 
|---|
| 164 |    set up all the tables and data structures that the MD part of the
 | 
|---|
| 165 |    assembler will need.  */
 | 
|---|
| 166 | void
 | 
|---|
| 167 | md_begin ()
 | 
|---|
| 168 | {
 | 
|---|
| 169 |   const char *retval = NULL;
 | 
|---|
| 170 |   int lose = 0;
 | 
|---|
| 171 |   unsigned int i = 0;
 | 
|---|
| 172 | 
 | 
|---|
| 173 |   op_hash = hash_new ();
 | 
|---|
| 174 | 
 | 
|---|
| 175 |   while (i860_opcodes[i].name != NULL)
 | 
|---|
| 176 |     {
 | 
|---|
| 177 |       const char *name = i860_opcodes[i].name;
 | 
|---|
| 178 |       retval = hash_insert (op_hash, name, (PTR)&i860_opcodes[i]);
 | 
|---|
| 179 |       if (retval != NULL)
 | 
|---|
| 180 |         {
 | 
|---|
| 181 |           fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
 | 
|---|
| 182 |                    i860_opcodes[i].name, retval);
 | 
|---|
| 183 |           lose = 1;
 | 
|---|
| 184 |         }
 | 
|---|
| 185 |       do
 | 
|---|
| 186 |         {
 | 
|---|
| 187 |           if (i860_opcodes[i].match & i860_opcodes[i].lose)
 | 
|---|
| 188 |             {
 | 
|---|
| 189 |               fprintf (stderr,
 | 
|---|
| 190 |                        _("internal error: losing opcode: `%s' \"%s\"\n"),
 | 
|---|
| 191 |                        i860_opcodes[i].name, i860_opcodes[i].args);
 | 
|---|
| 192 |               lose = 1;
 | 
|---|
| 193 |             }
 | 
|---|
| 194 |           ++i;
 | 
|---|
| 195 |         }
 | 
|---|
| 196 |       while (i860_opcodes[i].name != NULL
 | 
|---|
| 197 |              && strcmp (i860_opcodes[i].name, name) == 0);
 | 
|---|
| 198 |     }
 | 
|---|
| 199 | 
 | 
|---|
| 200 |   if (lose)
 | 
|---|
| 201 |     as_fatal (_("Defective assembler.  No assembly attempted."));
 | 
|---|
| 202 | }
 | 
|---|
| 203 | 
 | 
|---|
| 204 | /* This is the core of the machine-dependent assembler.  STR points to a
 | 
|---|
| 205 |    machine dependent instruction.  This function emits the frags/bytes
 | 
|---|
| 206 |    it assembles to.  */
 | 
|---|
| 207 | void
 | 
|---|
| 208 | md_assemble (str)
 | 
|---|
| 209 |      char *str;
 | 
|---|
| 210 | {
 | 
|---|
| 211 |   char *destp;
 | 
|---|
| 212 |   int num_opcodes = 1;
 | 
|---|
| 213 |   int i;
 | 
|---|
| 214 |   struct i860_it pseudo[3];
 | 
|---|
| 215 | 
 | 
|---|
| 216 |   assert (str);
 | 
|---|
| 217 | 
 | 
|---|
| 218 |   /* Assemble the instruction.  */
 | 
|---|
| 219 |   i860_process_insn (str);
 | 
|---|
| 220 | 
 | 
|---|
| 221 |   /* Check for expandable flag to produce pseudo-instructions.  This
 | 
|---|
| 222 |      is an undesirable feature that should be avoided.  */
 | 
|---|
| 223 |   if (the_insn.expand != 0
 | 
|---|
| 224 |       && ! (the_insn.fup & (OP_SEL_HA | OP_SEL_H | OP_SEL_L | OP_SEL_GOT
 | 
|---|
| 225 |                             | OP_SEL_GOTOFF | OP_SEL_PLT)))
 | 
|---|
| 226 |     {
 | 
|---|
| 227 |       for (i = 0; i < 3; i++)
 | 
|---|
| 228 |         pseudo[i] = the_insn;
 | 
|---|
| 229 | 
 | 
|---|
| 230 |       switch (the_insn.expand)
 | 
|---|
| 231 |         {
 | 
|---|
| 232 | 
 | 
|---|
| 233 |         case E_DELAY:
 | 
|---|
| 234 |           num_opcodes = 1;
 | 
|---|
| 235 |           break;
 | 
|---|
| 236 | 
 | 
|---|
| 237 |         case E_MOV:
 | 
|---|
| 238 |           if (the_insn.exp.X_add_symbol == NULL
 | 
|---|
| 239 |               && the_insn.exp.X_op_symbol == NULL
 | 
|---|
| 240 |               && (the_insn.exp.X_add_number < (1 << 15)
 | 
|---|
| 241 |                   && the_insn.exp.X_add_number >= -(1 << 15)))
 | 
|---|
| 242 |             break;
 | 
|---|
| 243 | 
 | 
|---|
| 244 |           /* Emit "or l%const,r0,ireg_dest".  */
 | 
|---|
| 245 |           pseudo[0].opcode = (the_insn.opcode & 0x001f0000) | 0xe4000000;
 | 
|---|
| 246 |           pseudo[0].fup = (OP_IMM_S16 | OP_SEL_L);
 | 
|---|
| 247 | 
 | 
|---|
| 248 |           /* Emit "orh h%const,ireg_dest,ireg_dest".  */
 | 
|---|
| 249 |           pseudo[1].opcode = (the_insn.opcode & 0x03ffffff) | 0xec000000
 | 
|---|
| 250 |                               | ((the_insn.opcode & 0x001f0000) << 5);
 | 
|---|
| 251 |           pseudo[1].fup = (OP_IMM_S16 | OP_SEL_H);
 | 
|---|
| 252 | 
 | 
|---|
| 253 |           num_opcodes = 2;
 | 
|---|
| 254 |           break;
 | 
|---|
| 255 | 
 | 
|---|
| 256 |         case E_ADDR:
 | 
|---|
| 257 |           if (the_insn.exp.X_add_symbol == NULL
 | 
|---|
| 258 |               && the_insn.exp.X_op_symbol == NULL
 | 
|---|
| 259 |               && (the_insn.exp.X_add_number < (1 << 15)
 | 
|---|
| 260 |                   && the_insn.exp.X_add_number >= -(1 << 15)))
 | 
|---|
| 261 |             break;
 | 
|---|
| 262 | 
 | 
|---|
| 263 |           /* Emit "orh ha%addr_expr,r0,r31".  */
 | 
|---|
| 264 |           pseudo[0].opcode = 0xec000000 | (atmp << 16);
 | 
|---|
| 265 |           pseudo[0].fup = (OP_IMM_S16 | OP_SEL_HA);
 | 
|---|
| 266 | 
 | 
|---|
| 267 |           /* Emit "l%addr_expr(r31),ireg_dest".  We pick up the fixup
 | 
|---|
| 268 |              information from the original instruction.   */
 | 
|---|
| 269 |           pseudo[1].opcode = (the_insn.opcode & ~0x03e00000) | (atmp << 21);
 | 
|---|
| 270 |           pseudo[1].fup = the_insn.fup | OP_SEL_L;
 | 
|---|
| 271 | 
 | 
|---|
| 272 |           num_opcodes = 2;
 | 
|---|
| 273 |           break;
 | 
|---|
| 274 | 
 | 
|---|
| 275 |         case E_U32:
 | 
|---|
| 276 |           if (the_insn.exp.X_add_symbol == NULL
 | 
|---|
| 277 |               && the_insn.exp.X_op_symbol == NULL
 | 
|---|
| 278 |               && (the_insn.exp.X_add_number < (1 << 16)
 | 
|---|
| 279 |                   && the_insn.exp.X_add_number >= 0))
 | 
|---|
| 280 |             break;
 | 
|---|
| 281 | 
 | 
|---|
| 282 |           /* Emit "$(opcode)h h%const,ireg_src2,r31".  */
 | 
|---|
| 283 |           pseudo[0].opcode = (the_insn.opcode & 0xf3e0ffff) | 0x0c000000
 | 
|---|
| 284 |                               | (atmp << 16);
 | 
|---|
| 285 |           pseudo[0].fup = (OP_IMM_S16 | OP_SEL_H);
 | 
|---|
| 286 | 
 | 
|---|
| 287 |           /* Emit "$(opcode) l%const,r31,ireg_dest".  */
 | 
|---|
| 288 |           pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000
 | 
|---|
| 289 |                               | (atmp << 21);
 | 
|---|
| 290 |           pseudo[1].fup = (OP_IMM_S16 | OP_SEL_L);
 | 
|---|
| 291 | 
 | 
|---|
| 292 |           num_opcodes = 2;
 | 
|---|
| 293 |           break;
 | 
|---|
| 294 | 
 | 
|---|
| 295 |         case E_AND:
 | 
|---|
| 296 |           if (the_insn.exp.X_add_symbol == NULL
 | 
|---|
| 297 |               && the_insn.exp.X_op_symbol == NULL
 | 
|---|
| 298 |               && (the_insn.exp.X_add_number < (1 << 16)
 | 
|---|
| 299 |                   && the_insn.exp.X_add_number >= 0))
 | 
|---|
| 300 |             break;
 | 
|---|
| 301 | 
 | 
|---|
| 302 |           /* Emit "andnot h%const,ireg_src2,r31".  */
 | 
|---|
| 303 |           pseudo[0].opcode = (the_insn.opcode & 0x03e0ffff) | 0xd4000000
 | 
|---|
| 304 |                               | (atmp << 16);
 | 
|---|
| 305 |           pseudo[0].fup = (OP_IMM_S16 | OP_SEL_H);
 | 
|---|
| 306 |           pseudo[0].exp.X_add_number = -1 - the_insn.exp.X_add_number;
 | 
|---|
| 307 | 
 | 
|---|
| 308 |           /* Emit "andnot l%const,r31,ireg_dest".  */
 | 
|---|
| 309 |           pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000
 | 
|---|
| 310 |                               | (atmp << 21);
 | 
|---|
| 311 |           pseudo[1].fup = (OP_IMM_S16 | OP_SEL_L);
 | 
|---|
| 312 |           pseudo[1].exp.X_add_number = -1 - the_insn.exp.X_add_number;
 | 
|---|
| 313 | 
 | 
|---|
| 314 |           num_opcodes = 2;
 | 
|---|
| 315 |           break;
 | 
|---|
| 316 | 
 | 
|---|
| 317 |         case E_S32:
 | 
|---|
| 318 |           if (the_insn.exp.X_add_symbol == NULL
 | 
|---|
| 319 |               && the_insn.exp.X_op_symbol == NULL
 | 
|---|
| 320 |               && (the_insn.exp.X_add_number < (1 << 15)
 | 
|---|
| 321 |                   && the_insn.exp.X_add_number >= -(1 << 15)))
 | 
|---|
| 322 |             break;
 | 
|---|
| 323 | 
 | 
|---|
| 324 |           /* Emit "orh h%const,r0,r31".  */
 | 
|---|
| 325 |           pseudo[0].opcode = 0xec000000 | (atmp << 16);
 | 
|---|
| 326 |           pseudo[0].fup = (OP_IMM_S16 | OP_SEL_H);
 | 
|---|
| 327 | 
 | 
|---|
| 328 |           /* Emit "or l%const,r31,r31".  */
 | 
|---|
| 329 |           pseudo[1].opcode = 0xe4000000 | (atmp << 21) | (atmp << 16);
 | 
|---|
| 330 |           pseudo[1].fup = (OP_IMM_S16 | OP_SEL_L);
 | 
|---|
| 331 | 
 | 
|---|
| 332 |           /* Emit "r31,ireg_src2,ireg_dest".  */
 | 
|---|
| 333 |           pseudo[2].opcode = (the_insn.opcode & ~0x0400ffff) | (atmp << 11);
 | 
|---|
| 334 |           pseudo[2].fup = OP_IMM_S16;
 | 
|---|
| 335 | 
 | 
|---|
| 336 |           num_opcodes = 3;
 | 
|---|
| 337 |           break;
 | 
|---|
| 338 | 
 | 
|---|
| 339 |         default:
 | 
|---|
| 340 |           as_fatal (_("failed sanity check."));
 | 
|---|
| 341 |         }
 | 
|---|
| 342 | 
 | 
|---|
| 343 |       the_insn = pseudo[0];
 | 
|---|
| 344 | 
 | 
|---|
| 345 |       /* Warn if an opcode is expanded after a delayed branch.  */
 | 
|---|
| 346 |       if (num_opcodes > 1 && last_expand == 1)
 | 
|---|
| 347 |         as_warn (_("Expanded opcode after delayed branch: `%s'"), str);
 | 
|---|
| 348 | 
 | 
|---|
| 349 |       /* Warn if an opcode is expanded in dual mode.  */
 | 
|---|
| 350 |       if (num_opcodes > 1 && dual_mode != DUAL_OFF)
 | 
|---|
| 351 |         as_warn (_("Expanded opcode in dual mode: `%s'"), str);
 | 
|---|
| 352 | 
 | 
|---|
| 353 |       /* Notify if any expansions happen.  */
 | 
|---|
| 354 |       if (target_warn_expand && num_opcodes > 1)
 | 
|---|
| 355 |         as_warn (_("An instruction was expanded (%s)"), str);
 | 
|---|
| 356 |     }
 | 
|---|
| 357 | 
 | 
|---|
| 358 |   i = 0;
 | 
|---|
| 359 |   do
 | 
|---|
| 360 |     {
 | 
|---|
| 361 |       /* Output the opcode.  Note that the i860 always reads instructions
 | 
|---|
| 362 |          as little-endian data.  */
 | 
|---|
| 363 |       destp = frag_more (4);
 | 
|---|
| 364 |       number_to_chars_littleendian (destp, the_insn.opcode, 4);
 | 
|---|
| 365 | 
 | 
|---|
| 366 |       /* Check for expanded opcode after branch or in dual mode.  */
 | 
|---|
| 367 |       last_expand = the_insn.pcrel;
 | 
|---|
| 368 | 
 | 
|---|
| 369 |       /* Output the symbol-dependent stuff.  */
 | 
|---|
| 370 |       if (the_insn.fup != OP_NONE)
 | 
|---|
| 371 |         {
 | 
|---|
| 372 |           fixS *fix;
 | 
|---|
| 373 |           fix = fix_new_exp (frag_now,
 | 
|---|
| 374 |                              destp - frag_now->fr_literal,
 | 
|---|
| 375 |                              4,
 | 
|---|
| 376 |                              &the_insn.exp,
 | 
|---|
| 377 |                              the_insn.pcrel,
 | 
|---|
| 378 |                              the_insn.reloc);
 | 
|---|
| 379 | 
 | 
|---|
| 380 |           /* Despite the odd name, this is a scratch field.  We use
 | 
|---|
| 381 |              it to encode operand type information.  */
 | 
|---|
| 382 |           fix->fx_addnumber = the_insn.fup;
 | 
|---|
| 383 |         }
 | 
|---|
| 384 |       the_insn = pseudo[++i];
 | 
|---|
| 385 |     }
 | 
|---|
| 386 |   while (--num_opcodes > 0);
 | 
|---|
| 387 | 
 | 
|---|
| 388 | }
 | 
|---|
| 389 | 
 | 
|---|
| 390 | /* Assemble the instruction pointed to by STR.  */
 | 
|---|
| 391 | static void
 | 
|---|
| 392 | i860_process_insn (str)
 | 
|---|
| 393 |      char *str;
 | 
|---|
| 394 | {
 | 
|---|
| 395 |   char *s;
 | 
|---|
| 396 |   const char *args;
 | 
|---|
| 397 |   char c;
 | 
|---|
| 398 |   struct i860_opcode *insn;
 | 
|---|
| 399 |   char *args_start;
 | 
|---|
| 400 |   unsigned long opcode;
 | 
|---|
| 401 |   unsigned int mask;
 | 
|---|
| 402 |   int match = 0;
 | 
|---|
| 403 |   int comma = 0;
 | 
|---|
| 404 | 
 | 
|---|
| 405 | #if 1 /* For compiler warnings.  */
 | 
|---|
| 406 |   args = 0;
 | 
|---|
| 407 |   insn = 0;
 | 
|---|
| 408 |   args_start = 0;
 | 
|---|
| 409 |   opcode = 0;
 | 
|---|
| 410 | #endif
 | 
|---|
| 411 | 
 | 
|---|
| 412 |   for (s = str; ISLOWER (*s) || *s == '.' || *s == '3'
 | 
|---|
| 413 |        || *s == '2' || *s == '1'; ++s)
 | 
|---|
| 414 |     ;
 | 
|---|
| 415 | 
 | 
|---|
| 416 |   switch (*s)
 | 
|---|
| 417 |     {
 | 
|---|
| 418 |     case '\0':
 | 
|---|
| 419 |       break;
 | 
|---|
| 420 | 
 | 
|---|
| 421 |     case ',':
 | 
|---|
| 422 |       comma = 1;
 | 
|---|
| 423 | 
 | 
|---|
| 424 |       /*FALLTHROUGH*/
 | 
|---|
| 425 | 
 | 
|---|
| 426 |     case ' ':
 | 
|---|
| 427 |       *s++ = '\0';
 | 
|---|
| 428 |       break;
 | 
|---|
| 429 | 
 | 
|---|
| 430 |     default:
 | 
|---|
| 431 |       as_fatal (_("Unknown opcode: `%s'"), str);
 | 
|---|
| 432 |     }
 | 
|---|
| 433 | 
 | 
|---|
| 434 |   /* Check for dual mode ("d.") opcode prefix.  */
 | 
|---|
| 435 |   if (strncmp (str, "d.", 2) == 0)
 | 
|---|
| 436 |     {
 | 
|---|
| 437 |       if (dual_mode == DUAL_ON)
 | 
|---|
| 438 |         dual_mode = DUAL_ONDDOT;
 | 
|---|
| 439 |       else
 | 
|---|
| 440 |         dual_mode = DUAL_DDOT;
 | 
|---|
| 441 |       str += 2;
 | 
|---|
| 442 |     }
 | 
|---|
| 443 | 
 | 
|---|
| 444 |   if ((insn = (struct i860_opcode *) hash_find (op_hash, str)) == NULL)
 | 
|---|
| 445 |     {
 | 
|---|
| 446 |       if (dual_mode == DUAL_DDOT || dual_mode == DUAL_ONDDOT)
 | 
|---|
| 447 |         str -= 2;
 | 
|---|
| 448 |       as_bad (_("Unknown opcode: `%s'"), str);
 | 
|---|
| 449 |       return;
 | 
|---|
| 450 |     }
 | 
|---|
| 451 | 
 | 
|---|
| 452 |   if (comma)
 | 
|---|
| 453 |     *--s = ',';
 | 
|---|
| 454 | 
 | 
|---|
| 455 |   args_start = s;
 | 
|---|
| 456 |   for (;;)
 | 
|---|
| 457 |     {
 | 
|---|
| 458 |       opcode = insn->match;
 | 
|---|
| 459 |       memset (&the_insn, '\0', sizeof (the_insn));
 | 
|---|
| 460 |       the_insn.reloc = BFD_RELOC_NONE;
 | 
|---|
| 461 |       the_insn.pcrel = 0;
 | 
|---|
| 462 |       the_insn.fup = OP_NONE;
 | 
|---|
| 463 | 
 | 
|---|
| 464 |       /* Build the opcode, checking as we go that the operands match.  */
 | 
|---|
| 465 |       for (args = insn->args; ; ++args)
 | 
|---|
| 466 |         {
 | 
|---|
| 467 |           switch (*args)
 | 
|---|
| 468 |             {
 | 
|---|
| 469 | 
 | 
|---|
| 470 |             /* End of args.  */
 | 
|---|
| 471 |             case '\0':
 | 
|---|
| 472 |               if (*s == '\0')
 | 
|---|
| 473 |                 match = 1;
 | 
|---|
| 474 |               break;
 | 
|---|
| 475 | 
 | 
|---|
| 476 |             /* These must match exactly.  */
 | 
|---|
| 477 |             case '+':
 | 
|---|
| 478 |             case '(':
 | 
|---|
| 479 |             case ')':
 | 
|---|
| 480 |             case ',':
 | 
|---|
| 481 |             case ' ':
 | 
|---|
| 482 |               if (*s++ == *args)
 | 
|---|
| 483 |                 continue;
 | 
|---|
| 484 |               break;
 | 
|---|
| 485 | 
 | 
|---|
| 486 |             /* Must be at least one digit.  */
 | 
|---|
| 487 |             case '#':
 | 
|---|
| 488 |               if (ISDIGIT (*s++))
 | 
|---|
| 489 |                 {
 | 
|---|
| 490 |                   while (ISDIGIT (*s))
 | 
|---|
| 491 |                     ++s;
 | 
|---|
| 492 |                   continue;
 | 
|---|
| 493 |                 }
 | 
|---|
| 494 |               break;
 | 
|---|
| 495 | 
 | 
|---|
| 496 |             /* Next operand must be a register.  */
 | 
|---|
| 497 |             case '1':
 | 
|---|
| 498 |             case '2':
 | 
|---|
| 499 |             case 'd':
 | 
|---|
| 500 |               /* Check for register prefix if necessary.  */
 | 
|---|
| 501 |               if (reg_prefix && *s != reg_prefix)
 | 
|---|
| 502 |                 goto error;
 | 
|---|
| 503 |               else
 | 
|---|
| 504 |                 s++;
 | 
|---|
| 505 | 
 | 
|---|
| 506 |               switch (*s)
 | 
|---|
| 507 |                 {
 | 
|---|
| 508 |                 /* Frame pointer.  */
 | 
|---|
| 509 |                 case 'f':
 | 
|---|
| 510 |                   s++;
 | 
|---|
| 511 |                   if (*s++ == 'p')
 | 
|---|
| 512 |                     {
 | 
|---|
| 513 |                       mask = 0x3;
 | 
|---|
| 514 |                       break;
 | 
|---|
| 515 |                     }
 | 
|---|
| 516 |                   goto error;
 | 
|---|
| 517 | 
 | 
|---|
| 518 |                 /* Stack pointer.  */
 | 
|---|
| 519 |                 case 's':
 | 
|---|
| 520 |                   s++;
 | 
|---|
| 521 |                   if (*s++ == 'p')
 | 
|---|
| 522 |                     {
 | 
|---|
| 523 |                       mask = 0x2;
 | 
|---|
| 524 |                       break;
 | 
|---|
| 525 |                     }
 | 
|---|
| 526 |                   goto error;
 | 
|---|
| 527 | 
 | 
|---|
| 528 |                 /* Any register r0..r31.  */
 | 
|---|
| 529 |                 case 'r':
 | 
|---|
| 530 |                   s++;
 | 
|---|
| 531 |                   if (!ISDIGIT (c = *s++))
 | 
|---|
| 532 |                     {
 | 
|---|
| 533 |                       goto error;
 | 
|---|
| 534 |                     }
 | 
|---|
| 535 |                   if (ISDIGIT (*s))
 | 
|---|
| 536 |                     {
 | 
|---|
| 537 |                       if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32)
 | 
|---|
| 538 |                         goto error;
 | 
|---|
| 539 |                     }
 | 
|---|
| 540 |                   else
 | 
|---|
| 541 |                     c -= '0';
 | 
|---|
| 542 |                   mask = c;
 | 
|---|
| 543 |                   break;
 | 
|---|
| 544 | 
 | 
|---|
| 545 |                 /* Not this opcode.  */
 | 
|---|
| 546 |                 default:
 | 
|---|
| 547 |                   goto error;
 | 
|---|
| 548 |                 }
 | 
|---|
| 549 | 
 | 
|---|
| 550 |               /* Obtained the register, now place it in the opcode.  */
 | 
|---|
| 551 |               switch (*args)
 | 
|---|
| 552 |                 {
 | 
|---|
| 553 |                 case '1':
 | 
|---|
| 554 |                   opcode |= mask << 11;
 | 
|---|
| 555 |                   continue;
 | 
|---|
| 556 | 
 | 
|---|
| 557 |                 case '2':
 | 
|---|
| 558 |                   opcode |= mask << 21;
 | 
|---|
| 559 |                   continue;
 | 
|---|
| 560 | 
 | 
|---|
| 561 |                 case 'd':
 | 
|---|
| 562 |                   opcode |= mask << 16;
 | 
|---|
| 563 |                   continue;
 | 
|---|
| 564 | 
 | 
|---|
| 565 |                 }
 | 
|---|
| 566 |               break;
 | 
|---|
| 567 | 
 | 
|---|
| 568 |             /* Next operand is a floating point register.  */
 | 
|---|
| 569 |             case 'e':
 | 
|---|
| 570 |             case 'f':
 | 
|---|
| 571 |             case 'g':
 | 
|---|
| 572 |               /* Check for register prefix if necessary.  */
 | 
|---|
| 573 |               if (reg_prefix && *s != reg_prefix)
 | 
|---|
| 574 |                 goto error;
 | 
|---|
| 575 |               else
 | 
|---|
| 576 |                 s++;
 | 
|---|
| 577 | 
 | 
|---|
| 578 |               if (*s++ == 'f' && ISDIGIT (*s))
 | 
|---|
| 579 |                 {
 | 
|---|
| 580 |                   mask = *s++;
 | 
|---|
| 581 |                   if (ISDIGIT (*s))
 | 
|---|
| 582 |                     {
 | 
|---|
| 583 |                       mask = 10 * (mask - '0') + (*s++ - '0');
 | 
|---|
| 584 |                       if (mask >= 32)
 | 
|---|
| 585 |                         {
 | 
|---|
| 586 |                           break;
 | 
|---|
| 587 |                         }
 | 
|---|
| 588 |                     }
 | 
|---|
| 589 |                   else
 | 
|---|
| 590 |                     mask -= '0';
 | 
|---|
| 591 | 
 | 
|---|
| 592 |                   switch (*args)
 | 
|---|
| 593 |                     {
 | 
|---|
| 594 | 
 | 
|---|
| 595 |                     case 'e':
 | 
|---|
| 596 |                       opcode |= mask << 11;
 | 
|---|
| 597 |                       continue;
 | 
|---|
| 598 | 
 | 
|---|
| 599 |                     case 'f':
 | 
|---|
| 600 |                       opcode |= mask << 21;
 | 
|---|
| 601 |                       continue;
 | 
|---|
| 602 | 
 | 
|---|
| 603 |                     case 'g':
 | 
|---|
| 604 |                       opcode |= mask << 16;
 | 
|---|
| 605 |                       if (dual_mode != DUAL_OFF)
 | 
|---|
| 606 |                         opcode |= (1 << 9);
 | 
|---|
| 607 |                       if (dual_mode == DUAL_DDOT)
 | 
|---|
| 608 |                         dual_mode = DUAL_OFF;
 | 
|---|
| 609 |                       if (dual_mode == DUAL_ONDDOT)
 | 
|---|
| 610 |                         dual_mode = DUAL_ON;
 | 
|---|
| 611 |                       if ((opcode & (1 << 10)) && mask != 0
 | 
|---|
| 612 |                           && (mask == ((opcode >> 11) & 0x1f)))
 | 
|---|
| 613 |                         as_warn (_("Pipelined instruction: fsrc1 = fdest"));
 | 
|---|
| 614 |                       continue;
 | 
|---|
| 615 |                     }
 | 
|---|
| 616 |                 }
 | 
|---|
| 617 |               break;
 | 
|---|
| 618 | 
 | 
|---|
| 619 |             /* Next operand must be a control register.  */
 | 
|---|
| 620 |             case 'c':
 | 
|---|
| 621 |               /* Check for register prefix if necessary.  */
 | 
|---|
| 622 |               if (reg_prefix && *s != reg_prefix)
 | 
|---|
| 623 |                 goto error;
 | 
|---|
| 624 |               else
 | 
|---|
| 625 |                 s++;
 | 
|---|
| 626 | 
 | 
|---|
| 627 |               if (strncmp (s, "fir", 3) == 0)
 | 
|---|
| 628 |                 {
 | 
|---|
| 629 |                   opcode |= 0x0 << 21;
 | 
|---|
| 630 |                   s += 3;
 | 
|---|
| 631 |                   continue;
 | 
|---|
| 632 |                 }
 | 
|---|
| 633 |               if (strncmp (s, "psr", 3) == 0)
 | 
|---|
| 634 |                 {
 | 
|---|
| 635 |                   opcode |= 0x1 << 21;
 | 
|---|
| 636 |                   s += 3;
 | 
|---|
| 637 |                   continue;
 | 
|---|
| 638 |                 }
 | 
|---|
| 639 |               if (strncmp (s, "dirbase", 7) == 0)
 | 
|---|
| 640 |                 {
 | 
|---|
| 641 |                   opcode |= 0x2 << 21;
 | 
|---|
| 642 |                   s += 7;
 | 
|---|
| 643 |                   continue;
 | 
|---|
| 644 |                 }
 | 
|---|
| 645 |               if (strncmp (s, "db", 2) == 0)
 | 
|---|
| 646 |                 {
 | 
|---|
| 647 |                   opcode |= 0x3 << 21;
 | 
|---|
| 648 |                   s += 2;
 | 
|---|
| 649 |                   continue;
 | 
|---|
| 650 |                 }
 | 
|---|
| 651 |               if (strncmp (s, "fsr", 3) == 0)
 | 
|---|
| 652 |                 {
 | 
|---|
| 653 |                   opcode |= 0x4 << 21;
 | 
|---|
| 654 |                   s += 3;
 | 
|---|
| 655 |                   continue;
 | 
|---|
| 656 |                 }
 | 
|---|
| 657 |               if (strncmp (s, "epsr", 4) == 0)
 | 
|---|
| 658 |                 {
 | 
|---|
| 659 |                   opcode |= 0x5 << 21;
 | 
|---|
| 660 |                   s += 4;
 | 
|---|
| 661 |                   continue;
 | 
|---|
| 662 |                 }
 | 
|---|
| 663 |               break;
 | 
|---|
| 664 | 
 | 
|---|
| 665 |             /* 5-bit immediate in src1.  */
 | 
|---|
| 666 |             case '5':
 | 
|---|
| 667 |               if (! i860_get_expression (s))
 | 
|---|
| 668 |                 {
 | 
|---|
| 669 |                   s = expr_end;
 | 
|---|
| 670 |                   the_insn.fup |= OP_IMM_U5;
 | 
|---|
| 671 |                   continue;
 | 
|---|
| 672 |                 }
 | 
|---|
| 673 |               break;
 | 
|---|
| 674 | 
 | 
|---|
| 675 |             /* 26-bit immediate, relative branch (lbroff).  */
 | 
|---|
| 676 |             case 'l':
 | 
|---|
| 677 |               the_insn.pcrel = 1;
 | 
|---|
| 678 |               the_insn.fup |= OP_IMM_BR26;
 | 
|---|
| 679 |               goto immediate;
 | 
|---|
| 680 | 
 | 
|---|
| 681 |             /* 16-bit split immediate, relative branch (sbroff).  */
 | 
|---|
| 682 |             case 'r':
 | 
|---|
| 683 |               the_insn.pcrel = 1;
 | 
|---|
| 684 |               the_insn.fup |= OP_IMM_BR16;
 | 
|---|
| 685 |               goto immediate;
 | 
|---|
| 686 | 
 | 
|---|
| 687 |             /* 16-bit split immediate.  */
 | 
|---|
| 688 |             case 's':
 | 
|---|
| 689 |               the_insn.fup |= OP_IMM_SPLIT16;
 | 
|---|
| 690 |               goto immediate;
 | 
|---|
| 691 | 
 | 
|---|
| 692 |             /* 16-bit split immediate, byte aligned (st.b).  */
 | 
|---|
| 693 |             case 'S':
 | 
|---|
| 694 |               the_insn.fup |= OP_IMM_SPLIT16;
 | 
|---|
| 695 |               goto immediate;
 | 
|---|
| 696 | 
 | 
|---|
| 697 |             /* 16-bit split immediate, half-word aligned (st.s).  */
 | 
|---|
| 698 |             case 'T':
 | 
|---|
| 699 |               the_insn.fup |= (OP_IMM_SPLIT16 | OP_ENCODE1 | OP_ALIGN2);
 | 
|---|
| 700 |               goto immediate;
 | 
|---|
| 701 | 
 | 
|---|
| 702 |             /* 16-bit split immediate, word aligned (st.l).  */
 | 
|---|
| 703 |             case 'U':
 | 
|---|
| 704 |               the_insn.fup |= (OP_IMM_SPLIT16 | OP_ENCODE1 | OP_ALIGN4);
 | 
|---|
| 705 |               goto immediate;
 | 
|---|
| 706 | 
 | 
|---|
| 707 |             /* 16-bit immediate.  */
 | 
|---|
| 708 |             case 'i':
 | 
|---|
| 709 |               the_insn.fup |= OP_IMM_S16;
 | 
|---|
| 710 |               goto immediate;
 | 
|---|
| 711 | 
 | 
|---|
| 712 |             /* 16-bit immediate, byte aligned (ld.b).  */
 | 
|---|
| 713 |             case 'I':
 | 
|---|
| 714 |               the_insn.fup |= OP_IMM_S16;
 | 
|---|
| 715 |               goto immediate;
 | 
|---|
| 716 | 
 | 
|---|
| 717 |             /* 16-bit immediate, half-word aligned (ld.s).  */
 | 
|---|
| 718 |             case 'J':
 | 
|---|
| 719 |               the_insn.fup |= (OP_IMM_S16 | OP_ENCODE1 | OP_ALIGN2);
 | 
|---|
| 720 |               goto immediate;
 | 
|---|
| 721 | 
 | 
|---|
| 722 |             /* 16-bit immediate, word aligned (ld.l, {p}fld.l, fst.l).  */
 | 
|---|
| 723 |             case 'K':
 | 
|---|
| 724 |               if (insn->name[0] == 'l')
 | 
|---|
| 725 |                 the_insn.fup |= (OP_IMM_S16 | OP_ENCODE1 | OP_ALIGN4);
 | 
|---|
| 726 |               else
 | 
|---|
| 727 |                 the_insn.fup |= (OP_IMM_S16 | OP_ENCODE2 | OP_ALIGN4);
 | 
|---|
| 728 |               goto immediate;
 | 
|---|
| 729 | 
 | 
|---|
| 730 |             /* 16-bit immediate, double-word aligned ({p}fld.d, fst.d).  */
 | 
|---|
| 731 |             case 'L':
 | 
|---|
| 732 |               the_insn.fup |= (OP_IMM_S16 | OP_ENCODE3 | OP_ALIGN8);
 | 
|---|
| 733 |               goto immediate;
 | 
|---|
| 734 | 
 | 
|---|
| 735 |             /* 16-bit immediate, quad-word aligned (fld.q, fst.q).  */
 | 
|---|
| 736 |             case 'M':
 | 
|---|
| 737 |               the_insn.fup |= (OP_IMM_S16 | OP_ENCODE3 | OP_ALIGN16);
 | 
|---|
| 738 | 
 | 
|---|
| 739 |               /*FALLTHROUGH*/
 | 
|---|
| 740 | 
 | 
|---|
| 741 |               /* Handle the immediate for either the Intel syntax or
 | 
|---|
| 742 |                  SVR4 syntax. The Intel syntax is "ha%immediate"
 | 
|---|
| 743 |                  whereas SVR4 syntax is "[immediate]@ha".  */
 | 
|---|
| 744 |             immediate:
 | 
|---|
| 745 | #ifdef SYNTAX_SVR4
 | 
|---|
| 746 |               if (*s == ' ')
 | 
|---|
| 747 |                 s++;
 | 
|---|
| 748 | 
 | 
|---|
| 749 |               /* Note that if i860_get_expression() fails, we will still
 | 
|---|
| 750 |                  have created U entries in the symbol table for the
 | 
|---|
| 751 |                  'symbols' in the input string.  Try not to create U
 | 
|---|
| 752 |                  symbols for registers, etc.  */
 | 
|---|
| 753 |               if (! i860_get_expression (s))
 | 
|---|
| 754 |                 s = expr_end;
 | 
|---|
| 755 |               else
 | 
|---|
| 756 |                 goto error;
 | 
|---|
| 757 | 
 | 
|---|
| 758 |               if (strncmp (s, "@ha", 3) == 0)
 | 
|---|
| 759 |                 {
 | 
|---|
| 760 |                   the_insn.fup |= OP_SEL_HA;
 | 
|---|
| 761 |                   s += 3;
 | 
|---|
| 762 |                 }
 | 
|---|
| 763 |               else if (strncmp (s, "@h", 2) == 0)
 | 
|---|
| 764 |                 {
 | 
|---|
| 765 |                   the_insn.fup |= OP_SEL_H;
 | 
|---|
| 766 |                   s += 2;
 | 
|---|
| 767 |                 }
 | 
|---|
| 768 |               else if (strncmp (s, "@l", 2) == 0)
 | 
|---|
| 769 |                 {
 | 
|---|
| 770 |                   the_insn.fup |= OP_SEL_L;
 | 
|---|
| 771 |                   s += 2;
 | 
|---|
| 772 |                 }
 | 
|---|
| 773 |               else if (strncmp (s, "@gotoff", 7) == 0
 | 
|---|
| 774 |                        || strncmp (s, "@GOTOFF", 7) == 0)
 | 
|---|
| 775 |                 {
 | 
|---|
| 776 |                   as_bad (_("Assembler does not yet support PIC"));
 | 
|---|
| 777 |                   the_insn.fup |= OP_SEL_GOTOFF;
 | 
|---|
| 778 |                   s += 7;
 | 
|---|
| 779 |                 }
 | 
|---|
| 780 |               else if (strncmp (s, "@got", 4) == 0
 | 
|---|
| 781 |                        || strncmp (s, "@GOT", 4) == 0)
 | 
|---|
| 782 |                 {
 | 
|---|
| 783 |                   as_bad (_("Assembler does not yet support PIC"));
 | 
|---|
| 784 |                   the_insn.fup |= OP_SEL_GOT;
 | 
|---|
| 785 |                   s += 4;
 | 
|---|
| 786 |                 }
 | 
|---|
| 787 |               else if (strncmp (s, "@plt", 4) == 0
 | 
|---|
| 788 |                        || strncmp (s, "@PLT", 4) == 0)
 | 
|---|
| 789 |                 {
 | 
|---|
| 790 |                   as_bad (_("Assembler does not yet support PIC"));
 | 
|---|
| 791 |                   the_insn.fup |= OP_SEL_PLT;
 | 
|---|
| 792 |                   s += 4;
 | 
|---|
| 793 |                 }
 | 
|---|
| 794 | 
 | 
|---|
| 795 |               the_insn.expand = insn->expand;
 | 
|---|
| 796 | 
 | 
|---|
| 797 |               continue;
 | 
|---|
| 798 | #else /* ! SYNTAX_SVR4 */
 | 
|---|
| 799 |               if (*s == ' ')
 | 
|---|
| 800 |                 s++;
 | 
|---|
| 801 |               if (strncmp (s, "ha%", 3) == 0)
 | 
|---|
| 802 |                 {
 | 
|---|
| 803 |                   the_insn.fup |= OP_SEL_HA;
 | 
|---|
| 804 |                   s += 3;
 | 
|---|
| 805 |                 }
 | 
|---|
| 806 |               else if (strncmp (s, "h%", 2) == 0)
 | 
|---|
| 807 |                 {
 | 
|---|
| 808 |                   the_insn.fup |= OP_SEL_H;
 | 
|---|
| 809 |                   s += 2;
 | 
|---|
| 810 |                 }
 | 
|---|
| 811 |               else if (strncmp (s, "l%", 2) == 0)
 | 
|---|
| 812 |                 {
 | 
|---|
| 813 |                   the_insn.fup |= OP_SEL_L;
 | 
|---|
| 814 |                   s += 2;
 | 
|---|
| 815 |                 }
 | 
|---|
| 816 |               the_insn.expand = insn->expand;
 | 
|---|
| 817 | 
 | 
|---|
| 818 |               /* Note that if i860_get_expression() fails, we will still
 | 
|---|
| 819 |                  have created U entries in the symbol table for the
 | 
|---|
| 820 |                  'symbols' in the input string.  Try not to create U
 | 
|---|
| 821 |                  symbols for registers, etc.  */
 | 
|---|
| 822 |               if (! i860_get_expression (s))
 | 
|---|
| 823 |                 s = expr_end;
 | 
|---|
| 824 |               else
 | 
|---|
| 825 |                 goto error;
 | 
|---|
| 826 | 
 | 
|---|
| 827 |               continue;
 | 
|---|
| 828 | #endif /* SYNTAX_SVR4 */
 | 
|---|
| 829 |               break;
 | 
|---|
| 830 | 
 | 
|---|
| 831 |             default:
 | 
|---|
| 832 |               as_fatal (_("failed sanity check."));
 | 
|---|
| 833 |             }
 | 
|---|
| 834 |           break;
 | 
|---|
| 835 |         }
 | 
|---|
| 836 |     error:
 | 
|---|
| 837 |       if (match == 0)
 | 
|---|
| 838 |         {
 | 
|---|
| 839 |           /* Args don't match.  */
 | 
|---|
| 840 |           if (insn[1].name != NULL
 | 
|---|
| 841 |               && ! strcmp (insn->name, insn[1].name))
 | 
|---|
| 842 |             {
 | 
|---|
| 843 |               ++insn;
 | 
|---|
| 844 |               s = args_start;
 | 
|---|
| 845 |               continue;
 | 
|---|
| 846 |             }
 | 
|---|
| 847 |           else
 | 
|---|
| 848 |             {
 | 
|---|
| 849 |               as_bad (_("Illegal operands for %s"), insn->name);
 | 
|---|
| 850 |               return;
 | 
|---|
| 851 |             }
 | 
|---|
| 852 |         }
 | 
|---|
| 853 |       break;
 | 
|---|
| 854 |     }
 | 
|---|
| 855 | 
 | 
|---|
| 856 |   the_insn.opcode = opcode;
 | 
|---|
| 857 | }
 | 
|---|
| 858 | 
 | 
|---|
| 859 | static int
 | 
|---|
| 860 | i860_get_expression (str)
 | 
|---|
| 861 |      char *str;
 | 
|---|
| 862 | {
 | 
|---|
| 863 |   char *save_in;
 | 
|---|
| 864 |   segT seg;
 | 
|---|
| 865 | 
 | 
|---|
| 866 |   save_in = input_line_pointer;
 | 
|---|
| 867 |   input_line_pointer = str;
 | 
|---|
| 868 |   seg = expression (&the_insn.exp);
 | 
|---|
| 869 |   if (seg != absolute_section
 | 
|---|
| 870 |       && seg != undefined_section
 | 
|---|
| 871 |       && ! SEG_NORMAL (seg))
 | 
|---|
| 872 |     {
 | 
|---|
| 873 |       the_insn.error = _("bad segment");
 | 
|---|
| 874 |       expr_end = input_line_pointer;
 | 
|---|
| 875 |       input_line_pointer = save_in;
 | 
|---|
| 876 |       return 1;
 | 
|---|
| 877 |     }
 | 
|---|
| 878 |   expr_end = input_line_pointer;
 | 
|---|
| 879 |   input_line_pointer = save_in;
 | 
|---|
| 880 |   return 0;
 | 
|---|
| 881 | }
 | 
|---|
| 882 | 
 | 
|---|
| 883 | /* Turn a string in input_line_pointer into a floating point constant of
 | 
|---|
| 884 |    type TYPE, and store the appropriate bytes in *LITP.  The number of
 | 
|---|
| 885 |    LITTLENUMS emitted is stored in *SIZEP.  An error message is returned,
 | 
|---|
| 886 |    or NULL on OK.  */
 | 
|---|
| 887 | 
 | 
|---|
| 888 | /* Equal to MAX_PRECISION in atof-ieee.c.  */
 | 
|---|
| 889 | #define MAX_LITTLENUMS 6
 | 
|---|
| 890 | 
 | 
|---|
| 891 | char *
 | 
|---|
| 892 | md_atof (type, litP, sizeP)
 | 
|---|
| 893 |      char type;
 | 
|---|
| 894 |      char *litP;
 | 
|---|
| 895 |      int *sizeP;
 | 
|---|
| 896 | {
 | 
|---|
| 897 |   int prec;
 | 
|---|
| 898 |   LITTLENUM_TYPE words[MAX_LITTLENUMS];
 | 
|---|
| 899 |   LITTLENUM_TYPE *wordP;
 | 
|---|
| 900 |   char *t;
 | 
|---|
| 901 | 
 | 
|---|
| 902 |   switch (type)
 | 
|---|
| 903 |     {
 | 
|---|
| 904 |     case 'f':
 | 
|---|
| 905 |     case 'F':
 | 
|---|
| 906 |     case 's':
 | 
|---|
| 907 |     case 'S':
 | 
|---|
| 908 |       prec = 2;
 | 
|---|
| 909 |       break;
 | 
|---|
| 910 | 
 | 
|---|
| 911 |     case 'd':
 | 
|---|
| 912 |     case 'D':
 | 
|---|
| 913 |     case 'r':
 | 
|---|
| 914 |     case 'R':
 | 
|---|
| 915 |       prec = 4;
 | 
|---|
| 916 |       break;
 | 
|---|
| 917 | 
 | 
|---|
| 918 |     case 'x':
 | 
|---|
| 919 |     case 'X':
 | 
|---|
| 920 |       prec = 6;
 | 
|---|
| 921 |       break;
 | 
|---|
| 922 | 
 | 
|---|
| 923 |     case 'p':
 | 
|---|
| 924 |     case 'P':
 | 
|---|
| 925 |       prec = 6;
 | 
|---|
| 926 |       break;
 | 
|---|
| 927 | 
 | 
|---|
| 928 |     default:
 | 
|---|
| 929 |       *sizeP = 0;
 | 
|---|
| 930 |       return _("Bad call to MD_ATOF()");
 | 
|---|
| 931 |     }
 | 
|---|
| 932 |   t = atof_ieee (input_line_pointer, type, words);
 | 
|---|
| 933 |   if (t)
 | 
|---|
| 934 |     input_line_pointer = t;
 | 
|---|
| 935 |   *sizeP = prec * sizeof (LITTLENUM_TYPE);
 | 
|---|
| 936 |   for (wordP = words; prec--;)
 | 
|---|
| 937 |     {
 | 
|---|
| 938 |       md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE));
 | 
|---|
| 939 |       litP += sizeof (LITTLENUM_TYPE);
 | 
|---|
| 940 |     }
 | 
|---|
| 941 |   return 0;
 | 
|---|
| 942 | }
 | 
|---|
| 943 | 
 | 
|---|
| 944 | /* Write out in current endian mode.  */
 | 
|---|
| 945 | void
 | 
|---|
| 946 | md_number_to_chars (buf, val, n)
 | 
|---|
| 947 |      char *buf;
 | 
|---|
| 948 |      valueT val;
 | 
|---|
| 949 |      int n;
 | 
|---|
| 950 | {
 | 
|---|
| 951 |   if (target_big_endian)
 | 
|---|
| 952 |     number_to_chars_bigendian (buf, val, n);
 | 
|---|
| 953 |   else
 | 
|---|
| 954 |     number_to_chars_littleendian (buf, val, n);
 | 
|---|
| 955 | }
 | 
|---|
| 956 | 
 | 
|---|
| 957 | /* This should never be called for i860.  */
 | 
|---|
| 958 | int
 | 
|---|
| 959 | md_estimate_size_before_relax (fragP, segtype)
 | 
|---|
| 960 |      register fragS *fragP ATTRIBUTE_UNUSED;
 | 
|---|
| 961 |      segT segtype ATTRIBUTE_UNUSED;
 | 
|---|
| 962 | {
 | 
|---|
| 963 |   as_fatal (_("i860_estimate_size_before_relax\n"));
 | 
|---|
| 964 | }
 | 
|---|
| 965 | 
 | 
|---|
| 966 | #ifdef DEBUG_I860
 | 
|---|
| 967 | static void
 | 
|---|
| 968 | print_insn (insn)
 | 
|---|
| 969 |      struct i860_it *insn;
 | 
|---|
| 970 | {
 | 
|---|
| 971 |   if (insn->error)
 | 
|---|
| 972 |     fprintf (stderr, "ERROR: %s\n", insn->error);
 | 
|---|
| 973 | 
 | 
|---|
| 974 |   fprintf (stderr, "opcode = 0x%08lx\t", insn->opcode);
 | 
|---|
| 975 |   fprintf (stderr, "expand = 0x%x\t", insn->expand);
 | 
|---|
| 976 |   fprintf (stderr, "reloc = %s\t\n",
 | 
|---|
| 977 |            bfd_get_reloc_code_name (insn->reloc));
 | 
|---|
| 978 |   fprintf (stderr, "exp =  {\n");
 | 
|---|
| 979 |   fprintf (stderr, "\t\tX_add_symbol = %s\n",
 | 
|---|
| 980 |            insn->exp.X_add_symbol ?
 | 
|---|
| 981 |            (S_GET_NAME (insn->exp.X_add_symbol) ?
 | 
|---|
| 982 |             S_GET_NAME (insn->exp.X_add_symbol) : "???") : "0");
 | 
|---|
| 983 |   fprintf (stderr, "\t\tX_op_symbol = %s\n",
 | 
|---|
| 984 |            insn->exp.X_op_symbol ?
 | 
|---|
| 985 |            (S_GET_NAME (insn->exp.X_op_symbol) ?
 | 
|---|
| 986 |             S_GET_NAME (insn->exp.X_op_symbol) : "???") : "0");
 | 
|---|
| 987 |   fprintf (stderr, "\t\tX_add_number = %lx\n",
 | 
|---|
| 988 |            insn->exp.X_add_number);
 | 
|---|
| 989 |   fprintf (stderr, "}\n");
 | 
|---|
| 990 | }
 | 
|---|
| 991 | #endif /* DEBUG_I860 */
 | 
|---|
| 992 | 
 | 
|---|
| 993 |  | 
|---|
| 994 | 
 | 
|---|
| 995 | #ifdef OBJ_ELF
 | 
|---|
| 996 | const char *md_shortopts = "VQ:";
 | 
|---|
| 997 | #else
 | 
|---|
| 998 | const char *md_shortopts = "";
 | 
|---|
| 999 | #endif
 | 
|---|
| 1000 | 
 | 
|---|
| 1001 | #define OPTION_EB               (OPTION_MD_BASE + 0)
 | 
|---|
| 1002 | #define OPTION_EL               (OPTION_MD_BASE + 1)
 | 
|---|
| 1003 | #define OPTION_WARN_EXPAND      (OPTION_MD_BASE + 2)
 | 
|---|
| 1004 | 
 | 
|---|
| 1005 | struct option md_longopts[] = {
 | 
|---|
| 1006 |   { "EB",           no_argument, NULL, OPTION_EB },
 | 
|---|
| 1007 |   { "EL",           no_argument, NULL, OPTION_EL },
 | 
|---|
| 1008 |   { "mwarn-expand", no_argument, NULL, OPTION_WARN_EXPAND },
 | 
|---|
| 1009 |   { NULL,           no_argument, NULL, 0 }
 | 
|---|
| 1010 | };
 | 
|---|
| 1011 | size_t md_longopts_size = sizeof (md_longopts);
 | 
|---|
| 1012 | 
 | 
|---|
| 1013 | int
 | 
|---|
| 1014 | md_parse_option (c, arg)
 | 
|---|
| 1015 |      int c;
 | 
|---|
| 1016 |      char *arg ATTRIBUTE_UNUSED;
 | 
|---|
| 1017 | {
 | 
|---|
| 1018 |   switch (c)
 | 
|---|
| 1019 |     {
 | 
|---|
| 1020 |     case OPTION_EB:
 | 
|---|
| 1021 |       target_big_endian = 1;
 | 
|---|
| 1022 |       break;
 | 
|---|
| 1023 | 
 | 
|---|
| 1024 |     case OPTION_EL:
 | 
|---|
| 1025 |       target_big_endian = 0;
 | 
|---|
| 1026 |       break;
 | 
|---|
| 1027 | 
 | 
|---|
| 1028 |     case OPTION_WARN_EXPAND:
 | 
|---|
| 1029 |       target_warn_expand = 1;
 | 
|---|
| 1030 |       break;
 | 
|---|
| 1031 | 
 | 
|---|
| 1032 | #ifdef OBJ_ELF
 | 
|---|
| 1033 |     /* SVR4 argument compatibility (-V): print version ID.  */
 | 
|---|
| 1034 |     case 'V':
 | 
|---|
| 1035 |       print_version_id ();
 | 
|---|
| 1036 |       break;
 | 
|---|
| 1037 | 
 | 
|---|
| 1038 |     /* SVR4 argument compatibility (-Qy, -Qn): controls whether
 | 
|---|
| 1039 |        a .comment section should be emitted or not (ignored).  */
 | 
|---|
| 1040 |     case 'Q':
 | 
|---|
| 1041 |       break;
 | 
|---|
| 1042 | #endif
 | 
|---|
| 1043 | 
 | 
|---|
| 1044 |     default:
 | 
|---|
| 1045 |       return 0;
 | 
|---|
| 1046 |     }
 | 
|---|
| 1047 | 
 | 
|---|
| 1048 |   return 1;
 | 
|---|
| 1049 | }
 | 
|---|
| 1050 | 
 | 
|---|
| 1051 | void
 | 
|---|
| 1052 | md_show_usage (stream)
 | 
|---|
| 1053 |      FILE *stream;
 | 
|---|
| 1054 | {
 | 
|---|
| 1055 |   fprintf (stream, _("\
 | 
|---|
| 1056 |   -EL                     generate code for little endian mode (default)\n\
 | 
|---|
| 1057 |   -EB                     generate code for big endian mode\n\
 | 
|---|
| 1058 |   -mwarn-expand           warn if pseudo operations are expanded\n"));
 | 
|---|
| 1059 | #ifdef OBJ_ELF
 | 
|---|
| 1060 |   /* SVR4 compatibility flags.  */
 | 
|---|
| 1061 |   fprintf (stream, _("\
 | 
|---|
| 1062 |   -V                      print assembler version number\n\
 | 
|---|
| 1063 |   -Qy, -Qn                ignored\n"));
 | 
|---|
| 1064 | #endif
 | 
|---|
| 1065 | }
 | 
|---|
| 1066 | 
 | 
|---|
| 1067 |  | 
|---|
| 1068 | 
 | 
|---|
| 1069 | /* We have no need to default values of symbols.  */
 | 
|---|
| 1070 | symbolS *
 | 
|---|
| 1071 | md_undefined_symbol (name)
 | 
|---|
| 1072 |      char *name ATTRIBUTE_UNUSED;
 | 
|---|
| 1073 | {
 | 
|---|
| 1074 |   return 0;
 | 
|---|
| 1075 | }
 | 
|---|
| 1076 | 
 | 
|---|
| 1077 | /* The i860 denotes auto-increment with '++'.  */
 | 
|---|
| 1078 | void
 | 
|---|
| 1079 | md_operand (exp)
 | 
|---|
| 1080 |      expressionS *exp;
 | 
|---|
| 1081 | {
 | 
|---|
| 1082 |   char *s;
 | 
|---|
| 1083 | 
 | 
|---|
| 1084 |   for (s = input_line_pointer; *s; s++)
 | 
|---|
| 1085 |     {
 | 
|---|
| 1086 |       if (s[0] == '+' && s[1] == '+')
 | 
|---|
| 1087 |         {
 | 
|---|
| 1088 |           input_line_pointer += 2;
 | 
|---|
| 1089 |           exp->X_op = O_register;
 | 
|---|
| 1090 |           break;
 | 
|---|
| 1091 |         }
 | 
|---|
| 1092 |     }
 | 
|---|
| 1093 | }
 | 
|---|
| 1094 | 
 | 
|---|
| 1095 | /* Round up a section size to the appropriate boundary.  */
 | 
|---|
| 1096 | valueT
 | 
|---|
| 1097 | md_section_align (segment, size)
 | 
|---|
| 1098 |      segT segment ATTRIBUTE_UNUSED;
 | 
|---|
| 1099 |      valueT size ATTRIBUTE_UNUSED;
 | 
|---|
| 1100 | {
 | 
|---|
| 1101 |   /* Byte alignment is fine.  */
 | 
|---|
| 1102 |   return size;
 | 
|---|
| 1103 | }
 | 
|---|
| 1104 | 
 | 
|---|
| 1105 | /* On the i860, a PC-relative offset is relative to the address of the
 | 
|---|
| 1106 |    of the offset plus its size.  */
 | 
|---|
| 1107 | long
 | 
|---|
| 1108 | md_pcrel_from (fixP)
 | 
|---|
| 1109 |      fixS *fixP;
 | 
|---|
| 1110 | {
 | 
|---|
| 1111 |   return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
 | 
|---|
| 1112 | }
 | 
|---|
| 1113 | 
 | 
|---|
| 1114 | /* Determine the relocation needed for non PC-relative 16-bit immediates.
 | 
|---|
| 1115 |    Also adjust the given immediate as necessary.  Finally, check that
 | 
|---|
| 1116 |    all constraints (such as alignment) are satisfied.   */
 | 
|---|
| 1117 | static bfd_reloc_code_real_type
 | 
|---|
| 1118 | obtain_reloc_for_imm16 (fix, val)
 | 
|---|
| 1119 |      fixS *fix;
 | 
|---|
| 1120 |      long *val;
 | 
|---|
| 1121 | {
 | 
|---|
| 1122 |   valueT fup = fix->fx_addnumber;
 | 
|---|
| 1123 |   bfd_reloc_code_real_type reloc;
 | 
|---|
| 1124 | 
 | 
|---|
| 1125 |   if (fix->fx_pcrel)
 | 
|---|
| 1126 |     abort ();
 | 
|---|
| 1127 | 
 | 
|---|
| 1128 |   /* Check alignment restrictions.  */
 | 
|---|
| 1129 |   if ((fup & OP_ALIGN2) && (*val & 0x1))
 | 
|---|
| 1130 |     as_bad_where (fix->fx_file, fix->fx_line,
 | 
|---|
| 1131 |                   _("This immediate requires 0 MOD 2 alignment"));
 | 
|---|
| 1132 |   else if ((fup & OP_ALIGN4) && (*val & 0x3))
 | 
|---|
| 1133 |     as_bad_where (fix->fx_file, fix->fx_line,
 | 
|---|
| 1134 |                   _("This immediate requires 0 MOD 4 alignment"));
 | 
|---|
| 1135 |   else if ((fup & OP_ALIGN8) && (*val & 0x7))
 | 
|---|
| 1136 |     as_bad_where (fix->fx_file, fix->fx_line,
 | 
|---|
| 1137 |                   _("This immediate requires 0 MOD 8 alignment"));
 | 
|---|
| 1138 |   else if ((fup & OP_ALIGN16) && (*val & 0xf))
 | 
|---|
| 1139 |     as_bad_where (fix->fx_file, fix->fx_line,
 | 
|---|
| 1140 |                   _("This immediate requires 0 MOD 16 alignment"));
 | 
|---|
| 1141 | 
 | 
|---|
| 1142 |   if (fup & OP_SEL_HA)
 | 
|---|
| 1143 |     {
 | 
|---|
| 1144 |       *val = (*val >> 16) + (*val & 0x8000 ? 1 : 0);
 | 
|---|
| 1145 |       reloc = BFD_RELOC_860_HIGHADJ;
 | 
|---|
| 1146 |     }
 | 
|---|
| 1147 |   else if (fup & OP_SEL_H)
 | 
|---|
| 1148 |     {
 | 
|---|
| 1149 |       *val >>= 16;
 | 
|---|
| 1150 |       reloc = BFD_RELOC_860_HIGH;
 | 
|---|
| 1151 |     }
 | 
|---|
| 1152 |   else if (fup & OP_SEL_L)
 | 
|---|
| 1153 |     {
 | 
|---|
| 1154 |       int num_encode;
 | 
|---|
| 1155 |       if (fup & OP_IMM_SPLIT16)
 | 
|---|
| 1156 |         {
 | 
|---|
| 1157 |           if (fup & OP_ENCODE1)
 | 
|---|
| 1158 |             {
 | 
|---|
| 1159 |               num_encode = 1;
 | 
|---|
| 1160 |               reloc = BFD_RELOC_860_SPLIT1;
 | 
|---|
| 1161 |             }
 | 
|---|
| 1162 |           else if (fup & OP_ENCODE2)
 | 
|---|
| 1163 |             {
 | 
|---|
| 1164 |               num_encode = 2;
 | 
|---|
| 1165 |               reloc = BFD_RELOC_860_SPLIT2;
 | 
|---|
| 1166 |             }
 | 
|---|
| 1167 |           else
 | 
|---|
| 1168 |             {
 | 
|---|
| 1169 |               num_encode = 0;
 | 
|---|
| 1170 |               reloc = BFD_RELOC_860_SPLIT0;
 | 
|---|
| 1171 |             }
 | 
|---|
| 1172 |         }
 | 
|---|
| 1173 |       else
 | 
|---|
| 1174 |         {
 | 
|---|
| 1175 |           if (fup & OP_ENCODE1)
 | 
|---|
| 1176 |             {
 | 
|---|
| 1177 |               num_encode = 1;
 | 
|---|
| 1178 |               reloc = BFD_RELOC_860_LOW1;
 | 
|---|
| 1179 |             }
 | 
|---|
| 1180 |           else if (fup & OP_ENCODE2)
 | 
|---|
| 1181 |             {
 | 
|---|
| 1182 |               num_encode = 2;
 | 
|---|
| 1183 |               reloc = BFD_RELOC_860_LOW2;
 | 
|---|
| 1184 |             }
 | 
|---|
| 1185 |           else if (fup & OP_ENCODE3)
 | 
|---|
| 1186 |             {
 | 
|---|
| 1187 |               num_encode = 3;
 | 
|---|
| 1188 |               reloc = BFD_RELOC_860_LOW3;
 | 
|---|
| 1189 |             }
 | 
|---|
| 1190 |           else
 | 
|---|
| 1191 |             {
 | 
|---|
| 1192 |               num_encode = 0;
 | 
|---|
| 1193 |               reloc = BFD_RELOC_860_LOW0;
 | 
|---|
| 1194 |             }
 | 
|---|
| 1195 |         }
 | 
|---|
| 1196 | 
 | 
|---|
| 1197 |       /* Preserve size encode bits.  */
 | 
|---|
| 1198 |       *val &= ~((1 << num_encode) - 1);
 | 
|---|
| 1199 |     }
 | 
|---|
| 1200 |   else
 | 
|---|
| 1201 |     {
 | 
|---|
| 1202 |       /* No selector.  What reloc do we generate (???)?  */
 | 
|---|
| 1203 |       reloc = BFD_RELOC_32;
 | 
|---|
| 1204 |     }
 | 
|---|
| 1205 | 
 | 
|---|
| 1206 |   return reloc;
 | 
|---|
| 1207 | }
 | 
|---|
| 1208 | 
 | 
|---|
| 1209 | /* Attempt to simplify or eliminate a fixup. To indicate that a fixup
 | 
|---|
| 1210 |    has been eliminated, set fix->fx_done. If fix->fx_addsy is non-NULL,
 | 
|---|
| 1211 |    we will have to generate a reloc entry.  */
 | 
|---|
| 1212 | 
 | 
|---|
| 1213 | void
 | 
|---|
| 1214 | md_apply_fix3 (fix, valP, seg)
 | 
|---|
| 1215 |      fixS * fix;
 | 
|---|
| 1216 |      valueT * valP;
 | 
|---|
| 1217 |      segT seg ATTRIBUTE_UNUSED;
 | 
|---|
| 1218 | {
 | 
|---|
| 1219 |   char *buf;
 | 
|---|
| 1220 |   long val = *valP;
 | 
|---|
| 1221 |   unsigned long insn;
 | 
|---|
| 1222 |   valueT fup;
 | 
|---|
| 1223 | 
 | 
|---|
| 1224 |   buf = fix->fx_frag->fr_literal + fix->fx_where;
 | 
|---|
| 1225 | 
 | 
|---|
| 1226 |   /* Recall that earlier we stored the opcode little-endian.  */
 | 
|---|
| 1227 |   insn = bfd_getl32 (buf);
 | 
|---|
| 1228 | 
 | 
|---|
| 1229 |   /* We stored a fix-up in this oddly-named scratch field.  */
 | 
|---|
| 1230 |   fup = fix->fx_addnumber;
 | 
|---|
| 1231 | 
 | 
|---|
| 1232 |   /* Determine the necessary relocations as well as inserting an
 | 
|---|
| 1233 |      immediate into the instruction.   */
 | 
|---|
| 1234 |   if (fup == OP_IMM_U5)
 | 
|---|
| 1235 |     {
 | 
|---|
| 1236 |       if (val & ~0x1f)
 | 
|---|
| 1237 |         as_bad_where (fix->fx_file, fix->fx_line,
 | 
|---|
| 1238 |                       _("5-bit immediate too large"));
 | 
|---|
| 1239 |       if (fix->fx_addsy)
 | 
|---|
| 1240 |         as_bad_where (fix->fx_file, fix->fx_line,
 | 
|---|
| 1241 |                       _("5-bit field must be absolute"));
 | 
|---|
| 1242 | 
 | 
|---|
| 1243 |       insn |= (val & 0x1f) << 11;
 | 
|---|
| 1244 |       bfd_putl32 (insn, buf);
 | 
|---|
| 1245 |       fix->fx_r_type = BFD_RELOC_NONE;
 | 
|---|
| 1246 |       fix->fx_done = 1;
 | 
|---|
| 1247 |     }
 | 
|---|
| 1248 |   else if (fup & OP_IMM_S16)
 | 
|---|
| 1249 |     {
 | 
|---|
| 1250 |       fix->fx_r_type = obtain_reloc_for_imm16 (fix, &val);
 | 
|---|
| 1251 | 
 | 
|---|
| 1252 |       /* Insert the immediate.  */
 | 
|---|
| 1253 |       if (fix->fx_addsy)
 | 
|---|
| 1254 |         fix->fx_done = 0;
 | 
|---|
| 1255 |       else
 | 
|---|
| 1256 |         {
 | 
|---|
| 1257 |           insn |= val & 0xffff;
 | 
|---|
| 1258 |           bfd_putl32 (insn, buf);
 | 
|---|
| 1259 |           fix->fx_r_type = BFD_RELOC_NONE;
 | 
|---|
| 1260 |           fix->fx_done = 1;
 | 
|---|
| 1261 |         }
 | 
|---|
| 1262 |     }
 | 
|---|
| 1263 |   else if (fup & OP_IMM_U16)
 | 
|---|
| 1264 |     abort ();
 | 
|---|
| 1265 | 
 | 
|---|
| 1266 |   else if (fup & OP_IMM_SPLIT16)
 | 
|---|
| 1267 |     {
 | 
|---|
| 1268 |       fix->fx_r_type = obtain_reloc_for_imm16 (fix, &val);
 | 
|---|
| 1269 | 
 | 
|---|
| 1270 |       /* Insert the immediate.  */
 | 
|---|
| 1271 |       if (fix->fx_addsy)
 | 
|---|
| 1272 |         fix->fx_done = 0;
 | 
|---|
| 1273 |       else
 | 
|---|
| 1274 |         {
 | 
|---|
| 1275 |           insn |= val & 0x7ff;
 | 
|---|
| 1276 |           insn |= (val & 0xf800) << 5;
 | 
|---|
| 1277 |           bfd_putl32 (insn, buf);
 | 
|---|
| 1278 |           fix->fx_r_type = BFD_RELOC_NONE;
 | 
|---|
| 1279 |           fix->fx_done = 1;
 | 
|---|
| 1280 |         }
 | 
|---|
| 1281 |     }
 | 
|---|
| 1282 |   else if (fup & OP_IMM_BR16)
 | 
|---|
| 1283 |     {
 | 
|---|
| 1284 |       if (val & 0x3)
 | 
|---|
| 1285 |         as_bad_where (fix->fx_file, fix->fx_line,
 | 
|---|
| 1286 |                       _("A branch offset requires 0 MOD 4 alignment"));
 | 
|---|
| 1287 | 
 | 
|---|
| 1288 |       val = val >> 2;
 | 
|---|
| 1289 | 
 | 
|---|
| 1290 |       /* Insert the immediate.  */
 | 
|---|
| 1291 |       if (fix->fx_addsy)
 | 
|---|
| 1292 |         {
 | 
|---|
| 1293 |           fix->fx_done = 0;
 | 
|---|
| 1294 |           fix->fx_r_type = BFD_RELOC_860_PC16;
 | 
|---|
| 1295 |         }
 | 
|---|
| 1296 |       else
 | 
|---|
| 1297 |         {
 | 
|---|
| 1298 |           insn |= (val & 0x7ff);
 | 
|---|
| 1299 |           insn |= ((val & 0xf800) << 5);
 | 
|---|
| 1300 |           bfd_putl32 (insn, buf);
 | 
|---|
| 1301 |           fix->fx_r_type = BFD_RELOC_NONE;
 | 
|---|
| 1302 |           fix->fx_done = 1;
 | 
|---|
| 1303 |         }
 | 
|---|
| 1304 |     }
 | 
|---|
| 1305 |   else if (fup & OP_IMM_BR26)
 | 
|---|
| 1306 |     {
 | 
|---|
| 1307 |       if (val & 0x3)
 | 
|---|
| 1308 |         as_bad_where (fix->fx_file, fix->fx_line,
 | 
|---|
| 1309 |                       _("A branch offset requires 0 MOD 4 alignment"));
 | 
|---|
| 1310 | 
 | 
|---|
| 1311 |       val >>= 2;
 | 
|---|
| 1312 | 
 | 
|---|
| 1313 |       /* Insert the immediate.  */
 | 
|---|
| 1314 |       if (fix->fx_addsy)
 | 
|---|
| 1315 |         {
 | 
|---|
| 1316 |           fix->fx_r_type = BFD_RELOC_860_PC26;
 | 
|---|
| 1317 |           fix->fx_done = 0;
 | 
|---|
| 1318 |         }
 | 
|---|
| 1319 |       else
 | 
|---|
| 1320 |         {
 | 
|---|
| 1321 |           insn |= (val & 0x3ffffff);
 | 
|---|
| 1322 |           bfd_putl32 (insn, buf);
 | 
|---|
| 1323 |           fix->fx_r_type = BFD_RELOC_NONE;
 | 
|---|
| 1324 |           fix->fx_done = 1;
 | 
|---|
| 1325 |         }
 | 
|---|
| 1326 |     }
 | 
|---|
| 1327 |   else if (fup != OP_NONE)
 | 
|---|
| 1328 |     {
 | 
|---|
| 1329 |       as_bad_where (fix->fx_file, fix->fx_line,
 | 
|---|
| 1330 |                     _("Unrecognized fix-up (0x%08lx)"), (unsigned long) fup);
 | 
|---|
| 1331 |       abort ();
 | 
|---|
| 1332 |     }
 | 
|---|
| 1333 |   else
 | 
|---|
| 1334 |     {
 | 
|---|
| 1335 |       /* I believe only fix-ups such as ".long .ep.main-main+0xc8000000"
 | 
|---|
| 1336 |          reach here (???).  */
 | 
|---|
| 1337 |       if (fix->fx_addsy)
 | 
|---|
| 1338 |         {
 | 
|---|
| 1339 |           fix->fx_r_type = BFD_RELOC_32;
 | 
|---|
| 1340 |           fix->fx_done = 0;
 | 
|---|
| 1341 |         }
 | 
|---|
| 1342 |       else
 | 
|---|
| 1343 |         {
 | 
|---|
| 1344 |           insn |= (val & 0xffffffff);
 | 
|---|
| 1345 |           bfd_putl32 (insn, buf);
 | 
|---|
| 1346 |           fix->fx_r_type = BFD_RELOC_NONE;
 | 
|---|
| 1347 |           fix->fx_done = 1;
 | 
|---|
| 1348 |         }
 | 
|---|
| 1349 |     }
 | 
|---|
| 1350 | }
 | 
|---|
| 1351 | 
 | 
|---|
| 1352 | /* Generate a machine dependent reloc from a fixup.  */
 | 
|---|
| 1353 | arelent*
 | 
|---|
| 1354 | tc_gen_reloc (section, fixp)
 | 
|---|
| 1355 |      asection *section ATTRIBUTE_UNUSED;
 | 
|---|
| 1356 |      fixS *fixp;
 | 
|---|
| 1357 | {
 | 
|---|
| 1358 |   arelent *reloc;
 | 
|---|
| 1359 | 
 | 
|---|
| 1360 |   reloc = xmalloc (sizeof (*reloc));
 | 
|---|
| 1361 |   reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
 | 
|---|
| 1362 |   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
 | 
|---|
| 1363 |   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
 | 
|---|
| 1364 |   reloc->addend = fixp->fx_offset;
 | 
|---|
| 1365 |   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
 | 
|---|
| 1366 | 
 | 
|---|
| 1367 |   if (! reloc->howto)
 | 
|---|
| 1368 |     {
 | 
|---|
| 1369 |       as_bad_where (fixp->fx_file, fixp->fx_line,
 | 
|---|
| 1370 |                     "Cannot represent %s relocation in object file",
 | 
|---|
| 1371 |                     bfd_get_reloc_code_name (fixp->fx_r_type));
 | 
|---|
| 1372 |     }
 | 
|---|
| 1373 |   return reloc;
 | 
|---|
| 1374 | }
 | 
|---|