1 /* tc-pj.c -- Assemble code for Pico Java 2 Copyright (C) 1999-2014 Free Software Foundation, Inc. 3 4 This file is part of GAS, the GNU Assembler. 5 6 GAS is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3, or (at your option) 9 any later version. 10 11 GAS is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GAS; see the file COPYING. If not, write to 18 the Free Software Foundation, 51 Franklin Street - Fifth Floor, 19 Boston, MA 02110-1301, USA. */ 20 21 /* Contributed by Steve Chamberlain of Transmeta <sac (at) pobox.com>. */ 22 23 #include "as.h" 24 #include "safe-ctype.h" 25 #include "opcode/pj.h" 26 27 extern const pj_opc_info_t pj_opc_info[512]; 28 29 const char comment_chars[] = "!/"; 30 const char line_separator_chars[] = ";"; 31 const char line_comment_chars[] = "/!#"; 32 33 static int pending_reloc; 34 static struct hash_control *opcode_hash_control; 35 36 static void 37 little (int ignore ATTRIBUTE_UNUSED) 38 { 39 target_big_endian = 0; 40 } 41 42 static void 43 big (int ignore ATTRIBUTE_UNUSED) 44 { 45 target_big_endian = 1; 46 } 47 48 const pseudo_typeS md_pseudo_table[] = 49 { 50 {"ml", little, 0}, 51 {"mb", big, 0}, 52 {0, 0, 0} 53 }; 54 55 const char FLT_CHARS[] = "rRsSfFdDxXpP"; 56 const char EXP_CHARS[] = "eE"; 57 58 void 59 md_operand (expressionS *op) 60 { 61 if (strncmp (input_line_pointer, "%hi16", 5) == 0) 62 { 63 if (pending_reloc) 64 as_bad (_("confusing relocation expressions")); 65 pending_reloc = BFD_RELOC_PJ_CODE_HI16; 66 input_line_pointer += 5; 67 expression (op); 68 } 69 70 if (strncmp (input_line_pointer, "%lo16", 5) == 0) 71 { 72 if (pending_reloc) 73 as_bad (_("confusing relocation expressions")); 74 pending_reloc = BFD_RELOC_PJ_CODE_LO16; 75 input_line_pointer += 5; 76 expression (op); 77 } 78 } 79 80 /* Parse an expression and then restore the input line pointer. */ 81 82 static char * 83 parse_exp_save_ilp (char *s, expressionS *op) 84 { 85 char *save = input_line_pointer; 86 87 input_line_pointer = s; 88 expression (op); 89 s = input_line_pointer; 90 input_line_pointer = save; 91 return s; 92 } 93 94 /* This is called by emit_expr via TC_CONS_FIX_NEW when creating a 95 reloc for a cons. We could use the definition there, except that 96 we want to handle magic pending reloc expressions specially. */ 97 98 void 99 pj_cons_fix_new_pj (fragS *frag, int where, int nbytes, expressionS *exp, 100 bfd_reloc_code_real_type r ATTRIBUTE_UNUSED) 101 { 102 static int rv[5][2] = 103 { { 0, 0 }, 104 { BFD_RELOC_8, BFD_RELOC_8 }, 105 { BFD_RELOC_PJ_CODE_DIR16, BFD_RELOC_16 }, 106 { 0, 0 }, 107 { BFD_RELOC_PJ_CODE_DIR32, BFD_RELOC_32 }}; 108 109 fix_new_exp (frag, where, nbytes, exp, 0, 110 pending_reloc ? pending_reloc 111 : rv[nbytes][(now_seg->flags & SEC_CODE) ? 0 : 1]); 112 113 pending_reloc = 0; 114 } 115 116 /* Turn a reloc description character from the pj-opc.h table into 117 code which BFD can handle. */ 118 119 static int 120 c_to_r (int x) 121 { 122 switch (x) 123 { 124 case O_R8: 125 return BFD_RELOC_8_PCREL; 126 case O_U8: 127 case O_8: 128 return BFD_RELOC_8; 129 case O_R16: 130 return BFD_RELOC_PJ_CODE_REL16; 131 case O_U16: 132 case O_16: 133 return BFD_RELOC_PJ_CODE_DIR16; 134 case O_R32: 135 return BFD_RELOC_PJ_CODE_REL32; 136 case O_32: 137 return BFD_RELOC_PJ_CODE_DIR32; 138 } 139 abort (); 140 return 0; 141 } 142 143 /* Handler for the ipush fake opcode, 144 turns ipush <foo> into sipush lo16<foo>, sethi hi16<foo>. */ 145 146 static void 147 ipush_code (pj_opc_info_t *opcode ATTRIBUTE_UNUSED, char *str) 148 { 149 char *b = frag_more (6); 150 expressionS arg; 151 152 b[0] = 0x11; 153 b[3] = 0xed; 154 parse_exp_save_ilp (str + 1, &arg); 155 if (pending_reloc) 156 { 157 as_bad (_("can't have relocation for ipush")); 158 pending_reloc = 0; 159 } 160 161 fix_new_exp (frag_now, b - frag_now->fr_literal + 1, 2, 162 &arg, 0, BFD_RELOC_PJ_CODE_DIR16); 163 fix_new_exp (frag_now, b - frag_now->fr_literal + 4, 2, 164 &arg, 0, BFD_RELOC_PJ_CODE_HI16); 165 } 166 167 /* Insert names into the opcode table which are really mini macros, 168 not opcodes. The fakeness is indicated with an opcode of -1. */ 169 170 static void 171 fake_opcode (const char *name, 172 void (*func) (struct pj_opc_info_t *, char *)) 173 { 174 pj_opc_info_t * fake = xmalloc (sizeof (pj_opc_info_t)); 175 176 fake->opcode = -1; 177 fake->opcode_next = -1; 178 fake->u.func = func; 179 hash_insert (opcode_hash_control, name, (char *) fake); 180 } 181 182 /* Enter another entry into the opcode hash table so the same opcode 183 can have another name. */ 184 185 static void 186 alias (const char *new_name, const char *old) 187 { 188 hash_insert (opcode_hash_control, new_name, 189 (char *) hash_find (opcode_hash_control, old)); 190 } 191 192 /* This function is called once, at assembler startup time. It sets 193 up the hash table with all the opcodes in it, and also initializes 194 some aliases for compatibility with other assemblers. */ 195 196 void 197 md_begin (void) 198 { 199 const pj_opc_info_t *opcode; 200 opcode_hash_control = hash_new (); 201 202 /* Insert names into hash table. */ 203 for (opcode = pj_opc_info; opcode->u.name; opcode++) 204 hash_insert (opcode_hash_control, opcode->u.name, (char *) opcode); 205 206 /* Insert the only fake opcode. */ 207 fake_opcode ("ipush", ipush_code); 208 209 /* Add some aliases for opcode names. */ 210 alias ("ifeq_s", "ifeq"); 211 alias ("ifne_s", "ifne"); 212 alias ("if_icmpge_s", "if_icmpge"); 213 alias ("if_icmpne_s", "if_icmpne"); 214 alias ("if_icmpeq_s", "if_icmpeq"); 215 alias ("if_icmpgt_s", "if_icmpgt"); 216 alias ("goto_s", "goto"); 217 218 bfd_set_arch_mach (stdoutput, TARGET_ARCH, 0); 219 } 220 221 /* This is the guts of the machine-dependent assembler. STR points to 222 a machine dependent instruction. This function is supposed to emit 223 the frags/bytes it assembles to. */ 224 225 void 226 md_assemble (char *str) 227 { 228 char *op_start; 229 char *op_end; 230 231 pj_opc_info_t *opcode; 232 char *output; 233 int idx = 0; 234 char pend; 235 236 int nlen = 0; 237 238 /* Drop leading whitespace. */ 239 while (*str == ' ') 240 str++; 241 242 /* Find the op code end. */ 243 op_start = str; 244 for (op_end = str; 245 *op_end && !is_end_of_line[*op_end & 0xff] && *op_end != ' '; 246 op_end++) 247 nlen++; 248 249 pend = *op_end; 250 *op_end = 0; 251 252 if (nlen == 0) 253 as_bad (_("can't find opcode ")); 254 255 opcode = (pj_opc_info_t *) hash_find (opcode_hash_control, op_start); 256 *op_end = pend; 257 258 if (opcode == NULL) 259 { 260 as_bad (_("unknown opcode %s"), op_start); 261 return; 262 } 263 264 dwarf2_emit_insn (0); 265 if (opcode->opcode == -1) 266 { 267 /* It's a fake opcode. Dig out the args and pretend that was 268 what we were passed. */ 269 (*opcode->u.func) (opcode, op_end); 270 } 271 else 272 { 273 int an; 274 275 output = frag_more (opcode->len); 276 output[idx++] = opcode->opcode; 277 278 if (opcode->opcode_next != -1) 279 output[idx++] = opcode->opcode_next; 280 281 for (an = 0; opcode->arg[an]; an++) 282 { 283 expressionS arg; 284 285 if (*op_end == ',' && an != 0) 286 op_end++; 287 288 if (*op_end == 0) 289 as_bad (_("expected expression")); 290 291 op_end = parse_exp_save_ilp (op_end, &arg); 292 293 fix_new_exp (frag_now, 294 output - frag_now->fr_literal + idx, 295 ASIZE (opcode->arg[an]), 296 &arg, 297 PCREL (opcode->arg[an]), 298 pending_reloc ? pending_reloc : c_to_r (opcode->arg[an])); 299 300 idx += ASIZE (opcode->arg[an]); 301 pending_reloc = 0; 302 } 303 304 while (ISSPACE (*op_end)) 305 op_end++; 306 307 if (*op_end != 0) 308 as_warn (_("extra stuff on line ignored")); 309 310 } 311 312 if (pending_reloc) 313 as_bad (_("Something forgot to clean up\n")); 314 } 315 316 char * 317 md_atof (int type, char *litP, int *sizeP) 318 { 319 return ieee_md_atof (type, litP, sizeP, target_big_endian); 320 } 321 322 const char *md_shortopts = ""; 324 325 struct option md_longopts[] = 326 { 327 #define OPTION_LITTLE (OPTION_MD_BASE) 328 #define OPTION_BIG (OPTION_LITTLE + 1) 329 330 {"little", no_argument, NULL, OPTION_LITTLE}, 331 {"big", no_argument, NULL, OPTION_BIG}, 332 {NULL, no_argument, NULL, 0} 333 }; 334 size_t md_longopts_size = sizeof (md_longopts); 335 336 int 337 md_parse_option (int c, char *arg ATTRIBUTE_UNUSED) 338 { 339 switch (c) 340 { 341 case OPTION_LITTLE: 342 little (0); 343 break; 344 case OPTION_BIG: 345 big (0); 346 break; 347 default: 348 return 0; 349 } 350 return 1; 351 } 352 353 void 354 md_show_usage (FILE *stream) 355 { 356 fprintf (stream, _("\ 357 PJ options:\n\ 358 -little generate little endian code\n\ 359 -big generate big endian code\n")); 360 } 361 362 /* Apply a fixup to the object file. */ 363 364 void 365 md_apply_fix (fixS *fixP, valueT * valP, segT seg ATTRIBUTE_UNUSED) 366 { 367 char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; 368 long val = *valP; 369 long max, min; 370 371 max = min = 0; 372 switch (fixP->fx_r_type) 373 { 374 case BFD_RELOC_VTABLE_INHERIT: 375 case BFD_RELOC_VTABLE_ENTRY: 376 fixP->fx_done = 0; 377 return; 378 379 case BFD_RELOC_PJ_CODE_REL16: 380 if (val < -0x8000 || val >= 0x7fff) 381 as_bad_where (fixP->fx_file, fixP->fx_line, _("pcrel too far")); 382 buf[0] |= (val >> 8) & 0xff; 383 buf[1] = val & 0xff; 384 break; 385 386 case BFD_RELOC_PJ_CODE_HI16: 387 *buf++ = val >> 24; 388 *buf++ = val >> 16; 389 fixP->fx_addnumber = val & 0xffff; 390 break; 391 392 case BFD_RELOC_PJ_CODE_DIR16: 393 case BFD_RELOC_PJ_CODE_LO16: 394 *buf++ = val >> 8; 395 *buf++ = val >> 0; 396 397 max = 0xffff; 398 min = -0xffff; 399 break; 400 401 case BFD_RELOC_8: 402 max = 0xff; 403 min = -0xff; 404 *buf++ = val; 405 break; 406 407 case BFD_RELOC_PJ_CODE_DIR32: 408 *buf++ = val >> 24; 409 *buf++ = val >> 16; 410 *buf++ = val >> 8; 411 *buf++ = val >> 0; 412 break; 413 414 case BFD_RELOC_32: 415 if (target_big_endian) 416 { 417 *buf++ = val >> 24; 418 *buf++ = val >> 16; 419 *buf++ = val >> 8; 420 *buf++ = val >> 0; 421 } 422 else 423 { 424 *buf++ = val >> 0; 425 *buf++ = val >> 8; 426 *buf++ = val >> 16; 427 *buf++ = val >> 24; 428 } 429 break; 430 431 case BFD_RELOC_16: 432 if (target_big_endian) 433 { 434 *buf++ = val >> 8; 435 *buf++ = val >> 0; 436 } 437 else 438 { 439 *buf++ = val >> 0; 440 *buf++ = val >> 8; 441 } 442 break; 443 444 default: 445 abort (); 446 } 447 448 if (max != 0 && (val < min || val > max)) 449 as_bad_where (fixP->fx_file, fixP->fx_line, _("offset out of range")); 450 451 if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0) 452 fixP->fx_done = 1; 453 } 454 455 /* Put number into target byte order. Always put values in an 456 executable section into big endian order. */ 457 458 void 459 md_number_to_chars (char *ptr, valueT use, int nbytes) 460 { 461 if (target_big_endian || now_seg->flags & SEC_CODE) 462 number_to_chars_bigendian (ptr, use, nbytes); 463 else 464 number_to_chars_littleendian (ptr, use, nbytes); 465 } 466 467 /* Translate internal representation of relocation info to BFD target 468 format. */ 469 470 arelent * 471 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) 472 { 473 arelent *rel; 474 bfd_reloc_code_real_type r_type; 475 476 rel = xmalloc (sizeof (arelent)); 477 rel->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); 478 *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); 479 rel->address = fixp->fx_frag->fr_address + fixp->fx_where; 480 481 r_type = fixp->fx_r_type; 482 rel->addend = fixp->fx_addnumber; 483 rel->howto = bfd_reloc_type_lookup (stdoutput, r_type); 484 485 if (rel->howto == NULL) 486 { 487 as_bad_where (fixp->fx_file, fixp->fx_line, 488 _("Cannot represent relocation type %s"), 489 bfd_get_reloc_code_name (r_type)); 490 /* Set howto to a garbage value so that we can keep going. */ 491 rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32); 492 gas_assert (rel->howto != NULL); 493 } 494 495 return rel; 496 } 497