URL
https://opencores.org/ocsvn/or1k_old/or1k_old/trunk
Subversion Repositories or1k_old
[/] [or1k_old/] [trunk/] [binutils/] [binutils-2.16.1/] [gas/] [config/] [tc-or32.c] - Rev 1782
Compare with Previous | Blame | View Log
/* Assembly backend for the OpenRISC 1000. Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. Contributed by Damjan Lampret <lampret@opencores.org> Modified by Johan Rydberg <johan.rydberg@netinsight.se> Gyorgy Jeney <nog@sdf.lonestar.org> Based upon a29k port and mips port. This file is part of GAS, the GNU Assembler. GAS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GAS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GAS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* tc-a29k.c used as a template. */ #include "safe-ctype.h" #include "as.h" #include "opcode/or32.h" #include "struc-symbol.h" #include "elf/or32.h" #define DEBUG 0 #if DEBUG > 1 #define DEBUG1(x...) fprintf(stderr, x) #else #define DEBUG1(x...) #endif #if DEBUG > 2 #define DEBUG2(x...) fprintf(stderr, x) #else #define DEBUG2(x...) #endif #if DEBUG > 3 #define DEBUG3(x...) fprintf(stderr, x) #else #define DEBUG3(x...) #endif #ifndef REGISTER_PREFIX #define REGISTER_PREFIX '%' #endif /* Make it easier to clone this machine desc into another one. */ #define machine_opcode or32_opcode #define machine_opcodes or32_opcodes #define machine_ip or32_ip #define machine_it or32_it /* Handle of the OPCODE hash table. */ static struct hash_control *op_hash = NULL; struct machine_it { char * error; unsigned long opcode; struct nlist * nlistp; expressionS exp; int pcrel; int reloc; } the_insn; static void machine_ip PARAMS ((char *)); const pseudo_typeS md_pseudo_table[] = { {"align", s_align_bytes, 4 }, {"space", s_space, 0 }, {"cputype", s_ignore, 0 }, {"reg", s_lsym, 0 }, /* Register equate, same as equ. */ {"sect", s_ignore, 0 }, /* Creation of coff sections. */ {"proc", s_ignore, 0 }, /* Start of a function. */ {"endproc", s_ignore, 0 }, /* Function end. */ {"half", cons, 2 }, {"word", cons, 4 }, {NULL, 0, 0 }, }; int md_short_jump_size = 4; int md_long_jump_size = 4; #if defined(BFD_HEADERS) #ifdef RELSZ const int md_reloc_size = RELSZ; /* Coff headers. */ #else const int md_reloc_size = 12; /* Something else headers. */ #endif #else const int md_reloc_size = 12; /* Not bfdized. */ #endif /* This array holds the chars that always start a comment. If the pre-processor is disabled, these aren't very useful. */ const char comment_chars[] = "#"; /* This array holds the chars that only start a comment at the beginning of a line. If the line seems to have the form '# 123 filename' .line and .file directives will appear in the pre-processed output. */ /* Note that input_file.c hand checks for '#' at the beginning of the first line of the input file. This is because the compiler outputs #NO_APP at the beginning of its output. */ /* Also note that comments like this one will always work. */ const char line_comment_chars[] = "#"; /* We needed an unused char for line separation to work around the lack of macros, using sed and such. */ const char line_separator_chars[] = ";"; /* Chars that can be used to separate mant from exp in floating point nums. */ const char EXP_CHARS[] = "eE"; /* Chars that mean this number is a floating point constant. As in 0f12.456 or 0d1.2345e12. */ const char FLT_CHARS[] = "rRsSfFdDxXpP"; /* "l.jalr r9" precalculated opcode. */ static unsigned long jalr_r9_opcode; static int check_invalid_opcode PARAMS ((unsigned long)); static void encode PARAMS ((const struct machine_opcode *, unsigned long *, signed long, char)); static char * parse_operand PARAMS ((char *, expressionS *, int)); /* Set bits in machine opcode according to insn->encoding description and passed operand. */ static void encode (insn, opcode, param_val, param_ch) const struct machine_opcode *insn; unsigned long *opcode; signed long param_val; char param_ch; { int opc_pos = 0; int param_pos = 0; char *enc; DEBUG2(" encode: opcode=%.8lx param_val=%.8lx abs=%.8lx param_ch=%c\n", *opcode, param_val, abs (param_val), param_ch); for (enc = insn->encoding; *enc != '\0'; enc++) if (*enc == param_ch) { if (enc - 2 >= insn->encoding && (*(enc - 2) == '0') && (*(enc - 1) == 'x')) continue; else param_pos ++; } opc_pos = 32; for (enc = insn->encoding; *enc != '\0';) { if ((*enc == '0') && (*(enc + 1) == 'x')) { int tmp = strtol (enc, NULL, 16); opc_pos -= 4; *opcode |= tmp << opc_pos; enc += 3; } else if ((*enc == '0') || (*enc == '-')) { opc_pos--; enc++; } else if (*enc == '1') { opc_pos--; *opcode |= 1 << opc_pos; enc++; } else if (*enc == param_ch) { opc_pos--; param_pos--; *opcode |= ((param_val >> param_pos) & 0x1) << opc_pos; enc++; } else if (ISALPHA (*enc)) { opc_pos--; enc++; } else enc++; } DEBUG2(" opcode=%.8lx\n", *opcode); } /* This function is called once, at assembler startup time. It should set up all the tables, etc., that the MD part of the assembler will need. */ void md_begin () { const char *retval = NULL; int lose = 0; int skipnext = 0; int i; /* Hash up all the opcodes for fast use later. */ op_hash = hash_new (); for (i = 0; i < num_opcodes; i++) { const char *name = machine_opcodes[i].name; if (skipnext) { skipnext = 0; continue; } retval = hash_insert (op_hash, name, (PTR) &machine_opcodes[i]); if (retval != NULL) { fprintf (stderr, "internal error: can't hash `%s': %s\n", machine_opcodes[i].name, retval); lose = 1; } } if (lose) as_fatal (_("Broken assembler. No assembly attempted.")); encode (&machine_opcodes[insn_index ("l.jalr")], &jalr_r9_opcode, 9, 'B'); } /* Returs non zero if instruction is to be used. */ static int check_invalid_opcode (opcode) unsigned long opcode; { return opcode == jalr_r9_opcode; } /* Assemble a single instruction. Its label has already been handled by the generic front end. We just parse opcode and operands, and produce the bytes of data and relocation. */ void md_assemble (str) char *str; { char *toP; DEBUG1("NEW INSTRUCTION %s\n", str); know (str); machine_ip (str); toP = frag_more (4); /* Put out the opcode. */ md_number_to_chars (toP, the_insn.opcode, 4); /* Put out the symbol-dependent stuff. */ if (the_insn.reloc != BFD_RELOC_NONE) { DEBUG1(" fix_new_exp> pcrel=%i reloc=%i sym=%s\n", the_insn.pcrel, the_insn.reloc, the_insn.exp.X_add_symbol->bsym ? the_insn.exp.X_add_symbol->bsym->name : "(none)"); fix_new_exp (frag_now, (toP - frag_now->fr_literal), 4, /* size */ &the_insn.exp, the_insn.pcrel, the_insn.reloc); } } static int mask_or_shift = 0; static char * parse_operand (s, operandp, opt) char *s; expressionS *operandp; int opt; { char *save = input_line_pointer; char *new; DEBUG3(" PROCESS NEW OPERAND(%s) == %c (%d)\n", s, opt ? opt : '!', opt); input_line_pointer = s; if (strncasecmp (s, "HI(", 3) == 0) { mask_or_shift = BFD_RELOC_HI16; input_line_pointer += 3; } else if (strncasecmp (s, "LO(", 3) == 0) { mask_or_shift = BFD_RELOC_LO16; input_line_pointer += 3; } else mask_or_shift = 0; if ((*s == '(') && (*(s+1) == 'r')) s++; if ((*s == 'r') && ISDIGIT (*(s + 1))) { operandp->X_add_number = strtol (s + 1, NULL, 10); operandp->X_op = O_register; for (; (*s != ',') && (*s != '\0');) s++; input_line_pointer = save; return s; } expression (operandp); if (operandp->X_op == O_absent) { if (! opt) as_bad (_("missing operand")); else { operandp->X_add_number = 0; operandp->X_op = O_constant; } } new = input_line_pointer; input_line_pointer = save; DEBUG3(" %s=parse_operand(%s): operandp->X_op = %u\n", new, s, operandp->X_op); return new; } /* Instruction parsing. Takes a string containing the opcode. Operands are at input_line_pointer. Output is in the_insn. Warnings or errors are generated. */ static void machine_ip (str) char *str; { char *s; const char *args; const struct machine_opcode *insn; unsigned long opcode; expressionS operand; int reloc = BFD_RELOC_NONE; DEBUG2("machine_ip(%s)\n", str); s = str; for (; ISALNUM (*s) || *s == '.' || *s == '_'; ++s) if (ISUPPER (*s)) *s = TOLOWER (*s); switch (*s) { case '\0': break; case ' ': /* FIXME-SOMEDAY more whitespace. */ *s++ = '\0'; break; default: as_bad (_("unknown opcode1: `%s'"), str); return; } if ((insn = (struct machine_opcode *) hash_find (op_hash, str)) == NULL) { as_bad (_("unknown opcode2 `%s'."), str); return; } opcode = 0; memset (&the_insn, '\0', sizeof (the_insn)); the_insn.reloc = BFD_RELOC_NONE; reloc = BFD_RELOC_NONE; /* Build the opcode, checking as we go to make sure that the operands match. If an operand matches, we modify the_insn or opcode appropriately, and do a "continue". If an operand fails to match, we "break". */ if (insn->args[0] != '\0') { /* Prime the pump. */ s = parse_operand (s, &operand, (insn->args[0] == 'I') || (strcmp(insn->name, "l.nop") == 0) ); } for (args = insn->args;; ++args) { DEBUG2(" args = %s\n", args); switch (*args) { case '\0': /* End of args. */ /* We have have 0 args, do the bazoooka! */ if (args == insn->args) encode (insn, &opcode, 0, 0); if (*s == '\0') { /* We are truly done. */ the_insn.opcode = opcode; if (check_invalid_opcode (opcode)) as_bad (_("instruction not allowed: %s"), str); return; } as_bad (_("too many operands: %s"), s); break; case ',': /* Must match a comma. */ if (*s++ == ',') { reloc = BFD_RELOC_NONE; /* Parse next operand. */ s = parse_operand (s, &operand, args[1] == 'I'); DEBUG3(" ',' case: operand->X_add_number = %d, *args = %s, *s = %s\n", operand.X_add_number, args, s); continue; } break; case '(': /* Must match a (. */ s = parse_operand (s, &operand, args[1] == 'I'); continue; case ')': /* Must match a ). */ continue; case 'r': /* A general register. */ args++; if (operand.X_op != O_register) break; /* Only registers. */ know (operand.X_add_symbol == 0); know (operand.X_op_symbol == 0); encode (insn, &opcode, operand.X_add_number, *args); DEBUG3(" r: operand->X_op = %d\n", operand.X_op); continue; default: if (mask_or_shift) { DEBUG3("mask_or_shift = %d\n", mask_or_shift); reloc = mask_or_shift; } mask_or_shift = 0; if (*s == '(') operand.X_op = O_constant; else if (*s == ')') s += 1; DEBUG3(" default case: operand.X_add_number = %d, *args = %s, *s = %s\n", operand.X_add_number, args, s); if (operand.X_op == O_constant) { unsigned long add = operand.X_add_number; if (reloc == BFD_RELOC_NONE) { bfd_vma v, mask; mask = 0x3ffffff; v = abs (operand.X_add_number) & ~ mask; if (v) as_bad (_("call/jmp target out of range (1)")); } if (reloc == BFD_RELOC_HI16) add = (operand.X_add_number >> 16) & 0xffff; the_insn.pcrel = 0; encode (insn, &opcode, add, *args); continue; } if (reloc == BFD_RELOC_NONE) the_insn.reloc = BFD_RELOC_28_PCREL_S2; else the_insn.reloc = reloc; /* the_insn.reloc = insn->reloc; */ DEBUG1(" reloc sym=%d\n", the_insn.reloc); DEBUG1(" BFD_RELOC_NONE=%d\n", BFD_RELOC_NONE); the_insn.exp = operand; the_insn.pcrel = 1; /* Assume PC-relative jump. */ /* FIXME-SOON, Do we figure out whether abs later, after know sym val? */ if (reloc == BFD_RELOC_LO16 || reloc == BFD_RELOC_HI16) the_insn.pcrel = 0; if (reloc == BFD_RELOC_NONE) encode (insn, &opcode, operand.X_add_number, *args); else encode (insn, &opcode, 0, *args); continue; } /* Types or values of args don't match. */ as_bad (_("invalid operands")); return; } } /* This is identical to the md_atof in m68k.c. I think this is right, but I'm not sure. Turn a string in input_line_pointer into a floating point constant of type type, and store the appropriate bytes in *litP. The number of LITTLENUMS emitted is stored in *sizeP . An error message is returned, or NULL on OK. */ /* Equal to MAX_PRECISION in atof-ieee.c. */ #define MAX_LITTLENUMS 6 char * md_atof (type, litP, sizeP) char type; char * litP; int * sizeP; { int prec; LITTLENUM_TYPE words[MAX_LITTLENUMS]; LITTLENUM_TYPE *wordP; char *t; switch (type) { case 'f': case 'F': case 's': case 'S': prec = 2; break; case 'd': case 'D': case 'r': case 'R': prec = 4; break; case 'x': case 'X': prec = 6; break; case 'p': case 'P': prec = 6; break; default: *sizeP = 0; return _("Bad call to MD_ATOF()"); } t = atof_ieee (input_line_pointer, type, words); if (t) input_line_pointer = t; *sizeP = prec * sizeof (LITTLENUM_TYPE); for (wordP = words; prec--;) { md_number_to_chars (litP, (valueT) (*wordP++), sizeof (LITTLENUM_TYPE)); litP += sizeof (LITTLENUM_TYPE); } return NULL; } /* Write out big-endian. */ void md_number_to_chars (buf, val, n) char *buf; valueT val; int n; { number_to_chars_bigendian (buf, val, n); } void md_apply_fix3 (fixP, val, seg) fixS * fixP; valueT * val; segT seg ATTRIBUTE_UNUSED; { bfd_byte *buf; long insn; buf = (bfd_byte *) (fixP->fx_where + fixP->fx_frag->fr_literal); DEBUG1("md_apply_fix3 *val=%x fixP->fx_r_type=%i sym=%s\n", *val, fixP->fx_r_type, fixP->fx_addsy ? fixP->fx_addsy->bsym->name : "(none)"); if ((fixP->fx_addsy == (symbolS *) NULL) && !fixP->fx_pcrel) fixP->fx_done = 1; know (fixP->fx_size == 4); know (fixP->fx_r_type < BFD_RELOC_NONE); switch (fixP->fx_r_type) { case BFD_RELOC_32: /* XXXXXXXX pattern in a word. */ DEBUG1("reloc_const: val=%x\n", *val); /* If we are deleting this reloc entry, we must fill in the value now. This can happen if we have a .word which is not resolved when it appears but is later defined. We also need to fill in the value if this is an embedded PIC switch table entry. */ if (fixP->fx_done) md_number_to_chars ((char *) buf, *val, 4); break; case BFD_RELOC_16: /* XXXX0000 pattern in a word. */ DEBUG1("reloc_const: val=%x\n", *val); /* If we are deleting this reloc entry, we must fill in the value now. */ assert (fixP->fx_size == 2); if (fixP->fx_done) md_number_to_chars ((char *) buf, *val, 2); break; case BFD_RELOC_8: /* XX000000 pattern in a word. */ case BFD_RELOC_LO16: /* 0000XXXX pattern in a word. */ DEBUG1("reloc_const: val=%x\n", *val); break; case BFD_RELOC_HI16: /* 0000XXXX pattern in a word. */ DEBUG1("reloc_consth: val=%x\n", *val); break; case BFD_RELOC_28_PCREL_S2: /* 0000XXXX pattern in a word. */ DEBUG1("reloc_pcrel: *val=%x done=%d fixP->fx_pcrel=%i line=%i\n", *val, fixP->fx_done, fixP->fx_pcrel, fixP->fx_line); if ((*val & 0x3) != 0) as_bad_where (fixP->fx_file, fixP->fx_line, _("Branch to odd address (%lx)"), (long) *val); /* * We need to save the bits in the instruction since fixup_segment() * might be deleting the relocation entry (i.e., a branch within * the current segment). */ if (! fixP->fx_done) break; /* update old instruction data */ if (target_big_endian) insn = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; else insn = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; insn |= (*val >> 2) & 0x03ffffff; md_number_to_chars ((char *) buf, insn, 4); DEBUG1("Resulting instruction: %08x\n", insn); break; case BFD_RELOC_VTABLE_INHERIT: case BFD_RELOC_VTABLE_ENTRY: fixP->fx_done = 0; break; case BFD_RELOC_NONE: default: as_bad (_("bad relocation type: 0x%02x"), fixP->fx_r_type); break; } fixP->fx_addnumber = *val; /* Remember value for emit_reloc. */ } #ifdef OBJ_COFF short tc_coff_fix2rtype (fixP) fixS *fixP; { DEBUG1("tc_coff_fix2rtype\n"); switch (fixP->fx_r_type) { case RELOC_32: return (R_WORD); case RELOC_8: return (R_BYTE); case RELOC_CONST: return (R_ILOHALF); case RELOC_CONSTH: return (R_IHIHALF); case RELOC_JUMPTARG: return (R_IREL); default: printf ("need %d\n", fixP->fx_r_type); abort (); } return 0; } #endif /* OBJ_COFF */ /* Should never be called for or32. */ void md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol) char * ptr ATTRIBUTE_UNUSED; addressT from_addr ATTRIBUTE_UNUSED; addressT to_addr ATTRIBUTE_UNUSED; fragS * frag ATTRIBUTE_UNUSED; symbolS * to_symbol ATTRIBUTE_UNUSED; { as_fatal ("or32_create_short_jmp\n"); } /* Should never be called for or32. */ void md_convert_frag (headers, seg, fragP) bfd * headers ATTRIBUTE_UNUSED; segT seg ATTRIBUTE_UNUSED; fragS * fragP ATTRIBUTE_UNUSED; { as_fatal ("or32_convert_frag\n"); } /* Should never be called for or32. */ void md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol) char * ptr ATTRIBUTE_UNUSED; addressT from_addr ATTRIBUTE_UNUSED; addressT to_addr ATTRIBUTE_UNUSED; fragS * frag ATTRIBUTE_UNUSED; symbolS * to_symbol ATTRIBUTE_UNUSED; { as_fatal ("or32_create_long_jump\n"); } /* Should never be called for or32. */ int md_estimate_size_before_relax (fragP, segtype) fragS * fragP ATTRIBUTE_UNUSED; segT segtype ATTRIBUTE_UNUSED; { as_fatal ("or32_estimate_size_before_relax\n"); return 0; } /* Translate internal representation of relocation info to target format. On sparc/29k: first 4 bytes are normal unsigned long address, next three bytes are index, most sig. byte first. Byte 7 is broken up with bit 7 as external, bits 6 & 5 unused, and the lower five bits as relocation type. Next 4 bytes are long addend. */ /* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com. */ #ifdef OBJ_AOUT void tc_aout_fix_to_chars (where, fixP, segment_address_in_file) char *where; fixS *fixP; relax_addressT segment_address_in_file; { long r_symbolnum; DEBUG1("tc_aout_fix_to_chars\n"); know (fixP->fx_r_type < BFD_RELOC_NONE); know (fixP->fx_addsy != NULL); md_number_to_chars (where, fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file, 4); r_symbolnum = (S_IS_DEFINED (fixP->fx_addsy) ? S_GET_TYPE (fixP->fx_addsy) : fixP->fx_addsy->sy_number); where[4] = (r_symbolnum >> 16) & 0x0ff; where[5] = (r_symbolnum >> 8) & 0x0ff; where[6] = r_symbolnum & 0x0ff; where[7] = (((!S_IS_DEFINED (fixP->fx_addsy)) << 7) & 0x80) | (0 & 0x60) | (fixP->fx_r_type & 0x1F); /* Also easy. */ md_number_to_chars (&where[8], fixP->fx_addnumber, 4); } #endif /* OBJ_AOUT */ const char *md_shortopts = ""; struct option md_longopts[] = { { NULL, no_argument, NULL, 0 } }; size_t md_longopts_size = sizeof (md_longopts); int md_parse_option (c, arg) int c ATTRIBUTE_UNUSED; char * arg ATTRIBUTE_UNUSED; { return 0; } void md_show_usage (stream) FILE * stream ATTRIBUTE_UNUSED; { } /* This is called when a line is unrecognized. This is used to handle definitions of or32 style local labels. */ int or32_unrecognized_line (c) int c; { int lab; char *s; if (c != '$' || ! ISDIGIT ((unsigned char) input_line_pointer[0])) return 0; s = input_line_pointer; lab = 0; while (ISDIGIT ((unsigned char) *s)) { lab = lab * 10 + *s - '0'; ++s; } if (*s != ':') /* Not a label definition. */ return 0; if (dollar_label_defined (lab)) { as_bad (_("label \"$%d\" redefined"), lab); return 0; } define_dollar_label (lab); colon (dollar_label_name (lab, 0)); input_line_pointer = s + 1; return 1; } /* Default the values of symbols known that should be "predefined". We don't bother to predefine them unless you actually use one, since there are a lot of them. */ symbolS * md_undefined_symbol (name) char *name ATTRIBUTE_UNUSED; { return NULL; } /* Parse an operand that is machine-specific. */ void md_operand (expressionP) expressionS *expressionP; { DEBUG3(" md_operand(input_line_pointer = %s)\n", input_line_pointer); if (input_line_pointer[0] == REGISTER_PREFIX && input_line_pointer[1] == 'r') { /* We have a numeric register expression. No biggy. */ input_line_pointer += 2; /* Skip %r */ (void) expression (expressionP); if (expressionP->X_op != O_constant || expressionP->X_add_number > 255) as_bad (_("Invalid expression after %%%%\n")); expressionP->X_op = O_register; } else if (input_line_pointer[0] == '&') { /* We are taking the 'address' of a register...this one is not in the manual, but it *is* in traps/fpsymbol.h! What they seem to want is the register number, as an absolute number. */ input_line_pointer++; /* Skip & */ (void) expression (expressionP); if (expressionP->X_op != O_register) as_bad (_("invalid register in & expression")); else expressionP->X_op = O_constant; } else if (input_line_pointer[0] == '$' && ISDIGIT ((unsigned char) input_line_pointer[1])) { long lab; char *name; symbolS *sym; /* This is a local label. */ ++input_line_pointer; lab = (long) get_absolute_expression (); if (dollar_label_defined (lab)) { name = dollar_label_name (lab, 0); sym = symbol_find (name); } else { name = dollar_label_name (lab, 1); sym = symbol_find_or_make (name); } expressionP->X_op = O_symbol; expressionP->X_add_symbol = sym; expressionP->X_add_number = 0; } else if (input_line_pointer[0] == '$') { char *s; char type; int fieldnum, fieldlimit; LITTLENUM_TYPE floatbuf[8]; /* $float(), $doubleN(), or $extendN() convert floating values to integers. */ s = input_line_pointer; ++s; fieldnum = 0; if (strncmp (s, "double", sizeof "double" - 1) == 0) { s += sizeof "double" - 1; type = 'd'; fieldlimit = 2; } else if (strncmp (s, "float", sizeof "float" - 1) == 0) { s += sizeof "float" - 1; type = 'f'; fieldlimit = 1; } else if (strncmp (s, "extend", sizeof "extend" - 1) == 0) { s += sizeof "extend" - 1; type = 'x'; fieldlimit = 4; } else return; if (ISDIGIT (*s)) { fieldnum = *s - '0'; ++s; } if (fieldnum >= fieldlimit) return; SKIP_WHITESPACE (); if (*s != '(') return; ++s; SKIP_WHITESPACE (); s = atof_ieee (s, type, floatbuf); if (s == NULL) return; s = s; SKIP_WHITESPACE (); if (*s != ')') return; ++s; SKIP_WHITESPACE (); input_line_pointer = s; expressionP->X_op = O_constant; expressionP->X_unsigned = 1; expressionP->X_add_number = ((floatbuf[fieldnum * 2] << LITTLENUM_NUMBER_OF_BITS) + floatbuf[fieldnum * 2 + 1]); } } /* Round up a section size to the appropriate boundary. */ valueT md_section_align (seg, addr) asection *seg; valueT addr; { int align = bfd_get_section_alignment (stdoutput, seg); return ((addr + (1 << align) - 1) & (-1 << align)); } /* Exactly what point is a PC-relative offset relative TO? On the 29000, they're relative to the address of the instruction, which we have set up as the address of the fixup too. */ long md_pcrel_from (fixP) fixS *fixP; { return fixP->fx_where + fixP->fx_frag->fr_address; } /* Generate a reloc for a fixup. */ arelent * tc_gen_reloc (seg, fixp) asection *seg ATTRIBUTE_UNUSED; fixS *fixp; { arelent *reloc; DEBUG1("tc_gen_reloc fixp (off=%08x addn=%08x line=%i pcrel=%i sym=%s)\n", fixp->fx_offset, fixp->fx_addnumber, fixp->fx_line, fixp->fx_pcrel, fixp->fx_addsy ? fixp->fx_addsy->bsym->name : "(none)"); reloc = (arelent *) xmalloc (sizeof (arelent)); reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; DEBUG1("reloc->address=%08x fixp->fx_frag->fr_address=%08x fixp->fx_where=%08x fixp->fx_addnumber=%08x\n", reloc->address, fixp->fx_frag->fr_address, fixp->fx_where, fixp->fx_addnumber); reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); if (reloc->howto == (reloc_howto_type *) NULL) { as_bad_where (fixp->fx_file, fixp->fx_line, _("reloc %d not supported by object file format"), (int) fixp->fx_r_type); return NULL; } if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) reloc->address = fixp->fx_offset; else if (fixp->fx_pcrel) { bfd_vma pcrel_address; pcrel_address = reloc->address; if (OUTPUT_FLAVOR == bfd_target_elf_flavour) { /* At this point, fx_addnumber is "symbol offset - pcrel_address". Relocations want only the symbol offset. */ reloc->addend = fixp->fx_addnumber; } else { if (OUTPUT_FLAVOR != bfd_target_aout_flavour) /* A gruesome hack which is a result of the gruesome gas reloc handling. */ reloc->addend = pcrel_address; else reloc->addend = -pcrel_address; } } else reloc->addend = fixp->fx_addnumber; DEBUG1("addend: %x\n", reloc->addend); return reloc; }