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