diff options
Diffstat (limited to 'binutils-2.24/gas/config/tc-microblaze.c')
-rw-r--r-- | binutils-2.24/gas/config/tc-microblaze.c | 2525 |
1 files changed, 0 insertions, 2525 deletions
diff --git a/binutils-2.24/gas/config/tc-microblaze.c b/binutils-2.24/gas/config/tc-microblaze.c deleted file mode 100644 index 872737b3..00000000 --- a/binutils-2.24/gas/config/tc-microblaze.c +++ /dev/null @@ -1,2525 +0,0 @@ -/* tc-microblaze.c -- Assemble code for Xilinx MicroBlaze - - Copyright 2009, 2010, 2012 Free Software Foundation. - - 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, MA - 02110-1301, USA. */ - -#include "as.h" -#include <stdio.h> -#include "bfd.h" -#include "subsegs.h" -#define DEFINE_TABLE -#include "../opcodes/microblaze-opc.h" -#include "../opcodes/microblaze-opcm.h" -#include "safe-ctype.h" -#include <string.h> -#include <dwarf2dbg.h> -#include "aout/stab_gnu.h" - -#ifndef streq -#define streq(a,b) (strcmp (a, b) == 0) -#endif - -#define OPTION_EB (OPTION_MD_BASE + 0) -#define OPTION_EL (OPTION_MD_BASE + 1) - -void microblaze_generate_symbol (char *sym); -static bfd_boolean check_spl_reg (unsigned *); - -/* Several places in this file insert raw instructions into the - object. They should generate the instruction - and then use these four macros to crack the instruction value into - the appropriate byte values. */ -#define INST_BYTE0(x) (target_big_endian ? (((x) >> 24) & 0xFF) : ((x) & 0xFF)) -#define INST_BYTE1(x) (target_big_endian ? (((x) >> 16) & 0xFF) : (((x) >> 8) & 0xFF)) -#define INST_BYTE2(x) (target_big_endian ? (((x) >> 8) & 0xFF) : (((x) >> 16) & 0xFF)) -#define INST_BYTE3(x) (target_big_endian ? ((x) & 0xFF) : (((x) >> 24) & 0xFF)) - -/* 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[] = "#"; - -const char line_separator_chars[] = ";"; - -/* This array holds the chars that only start a comment at the beginning of - a line. */ -const char line_comment_chars[] = "#"; - -const int md_reloc_size = 8; /* Size of relocation record. */ - -/* Chars that can be used to separate mant - from exp in floating point numbers. */ -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"; - -/* INST_PC_OFFSET and INST_NO_OFFSET are 0 and 1. */ -#define UNDEFINED_PC_OFFSET 2 -#define DEFINED_ABS_SEGMENT 3 -#define DEFINED_PC_OFFSET 4 -#define DEFINED_RO_SEGMENT 5 -#define DEFINED_RW_SEGMENT 6 -#define LARGE_DEFINED_PC_OFFSET 7 -#define GOT_OFFSET 8 -#define PLT_OFFSET 9 -#define GOTOFF_OFFSET 10 -#define TLSGD_OFFSET 11 -#define TLSLD_OFFSET 12 -#define TLSDTPMOD_OFFSET 13 -#define TLSDTPREL_OFFSET 14 -#define TLSGOTTPREL_OFFSET 15 -#define TLSTPREL_OFFSET 16 - -/* Initialize the relax table. */ -const relax_typeS md_relax_table[] = -{ - { 1, 1, 0, 0 }, /* 0: Unused. */ - { 1, 1, 0, 0 }, /* 1: Unused. */ - { 1, 1, 0, 0 }, /* 2: Unused. */ - { 1, 1, 0, 0 }, /* 3: Unused. */ - { 32767, -32768, INST_WORD_SIZE, LARGE_DEFINED_PC_OFFSET }, /* 4: DEFINED_PC_OFFSET. */ - { 1, 1, 0, 0 }, /* 5: Unused. */ - { 1, 1, 0, 0 }, /* 6: Unused. */ - { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 7: LARGE_DEFINED_PC_OFFSET. */ - { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 8: GOT_OFFSET. */ - { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 9: PLT_OFFSET. */ - { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 10: GOTOFF_OFFSET. */ - { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 11: TLSGD_OFFSET. */ - { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 12: TLSLD_OFFSET. */ - { 0x7fffffff, 0x80000000, INST_WORD_SIZE*1, 0 }, /* 13: TLSDTPMOD_OFFSET. */ - { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 14: TLSDTPREL_OFFSET. */ - { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 15: TLSGOTTPREL_OFFSET. */ - { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 } /* 16: TLSTPREL_OFFSET. */ -}; - -static struct hash_control * opcode_hash_control; /* Opcode mnemonics. */ - -static segT sbss_segment = 0; /* Small bss section. */ -static segT sbss2_segment = 0; /* Section not used. */ -static segT sdata_segment = 0; /* Small data section. */ -static segT sdata2_segment = 0; /* Small read-only section. */ -static segT rodata_segment = 0; /* read-only section. */ - -/* Generate a symbol for stabs information. */ - -void -microblaze_generate_symbol (char *sym) -{ -#define MICROBLAZE_FAKE_LABEL_NAME "XL0\001" - static int microblaze_label_count; - sprintf (sym, "%sL%d", MICROBLAZE_FAKE_LABEL_NAME, microblaze_label_count); - ++microblaze_label_count; -} - -/* Handle the section changing pseudo-ops. */ - -static void -microblaze_s_text (int ignore ATTRIBUTE_UNUSED) -{ -#ifdef OBJ_ELF - obj_elf_text (ignore); -#else - s_text (ignore); -#endif -} - -static void -microblaze_s_data (int ignore ATTRIBUTE_UNUSED) -{ -#ifdef OBJ_ELF - obj_elf_change_section (".data", SHT_PROGBITS, SHF_ALLOC+SHF_WRITE, 0, 0, 0, 0); -#else - s_data (ignore); -#endif -} - -/* Things in the .sdata segment are always considered to be in the small data section. */ - -static void -microblaze_s_sdata (int ignore ATTRIBUTE_UNUSED) -{ -#ifdef OBJ_ELF - obj_elf_change_section (".sdata", SHT_PROGBITS, SHF_ALLOC+SHF_WRITE, 0, 0, 0, 0); -#else - s_data (ignore); -#endif -} - -/* Pseudo op to make file scope bss items. */ - -static void -microblaze_s_lcomm (int xxx ATTRIBUTE_UNUSED) -{ - char *name; - char c; - char *p; - offsetT size; - symbolS *symbolP; - offsetT align; - char *pfrag; - int align2; - segT current_seg = now_seg; - subsegT current_subseg = now_subseg; - - name = input_line_pointer; - c = get_symbol_end (); - - /* Just after name is now '\0'. */ - p = input_line_pointer; - *p = c; - SKIP_WHITESPACE (); - if (*input_line_pointer != ',') - { - as_bad (_("Expected comma after symbol-name: rest of line ignored.")); - ignore_rest_of_line (); - return; - } - - input_line_pointer++; /* skip ',' */ - if ((size = get_absolute_expression ()) < 0) - { - as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) size); - ignore_rest_of_line (); - return; - } - - /* The third argument to .lcomm is the alignment. */ - if (*input_line_pointer != ',') - align = 8; - else - { - ++input_line_pointer; - align = get_absolute_expression (); - if (align <= 0) - { - as_warn (_("ignoring bad alignment")); - align = 8; - } - } - - *p = 0; - symbolP = symbol_find_or_make (name); - *p = c; - - if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) - { - as_bad (_("Ignoring attempt to re-define symbol `%s'."), - S_GET_NAME (symbolP)); - ignore_rest_of_line (); - return; - } - - if (S_GET_VALUE (symbolP) && S_GET_VALUE (symbolP) != (valueT) size) - { - as_bad (_("Length of .lcomm \"%s\" is already %ld. Not changed to %ld."), - S_GET_NAME (symbolP), - (long) S_GET_VALUE (symbolP), - (long) size); - - ignore_rest_of_line (); - return; - } - - /* Allocate_bss. */ - if (align) - { - /* Convert to a power of 2 alignment. */ - for (align2 = 0; (align & 1) == 0; align >>= 1, ++align2); - if (align != 1) - { - as_bad (_("Common alignment not a power of 2")); - ignore_rest_of_line (); - return; - } - } - else - align2 = 0; - - record_alignment (current_seg, align2); - subseg_set (current_seg, current_subseg); - if (align2) - frag_align (align2, 0, 0); - if (S_GET_SEGMENT (symbolP) == current_seg) - symbol_get_frag (symbolP)->fr_symbol = 0; - symbol_set_frag (symbolP, frag_now); - pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, size, - (char *) 0); - *pfrag = 0; - S_SET_SIZE (symbolP, size); - S_SET_SEGMENT (symbolP, current_seg); - subseg_set (current_seg, current_subseg); - demand_empty_rest_of_line (); -} - -static void -microblaze_s_rdata (int localvar) -{ -#ifdef OBJ_ELF - if (localvar == 0) - { - /* rodata. */ - obj_elf_change_section (".rodata", SHT_PROGBITS, SHF_ALLOC, 0, 0, 0, 0); - if (rodata_segment == 0) - rodata_segment = subseg_new (".rodata", 0); - } - else - { - /* 1 .sdata2. */ - obj_elf_change_section (".sdata2", SHT_PROGBITS, SHF_ALLOC, 0, 0, 0, 0); - } -#else - s_data (ignore); -#endif -} - -static void -microblaze_s_bss (int localvar) -{ -#ifdef OBJ_ELF - if (localvar == 0) /* bss. */ - obj_elf_change_section (".bss", SHT_NOBITS, SHF_ALLOC+SHF_WRITE, 0, 0, 0, 0); - else if (localvar == 1) - { - /* sbss. */ - obj_elf_change_section (".sbss", SHT_NOBITS, SHF_ALLOC+SHF_WRITE, 0, 0, 0, 0); - if (sbss_segment == 0) - sbss_segment = subseg_new (".sbss", 0); - } -#else - s_data (ignore); -#endif -} - -/* endp_p is always 1 as this func is called only for .end <funcname> - This func consumes the <funcname> and calls regular processing - s_func(1) with arg 1 (1 for end). */ - -static void -microblaze_s_func (int end_p ATTRIBUTE_UNUSED) -{ - *input_line_pointer = get_symbol_end (); - s_func (1); -} - -/* Handle the .weakext pseudo-op as defined in Kane and Heinrich. */ - -static void -microblaze_s_weakext (int ignore ATTRIBUTE_UNUSED) -{ - char *name; - int c; - symbolS *symbolP; - expressionS exp; - - name = input_line_pointer; - c = get_symbol_end (); - symbolP = symbol_find_or_make (name); - S_SET_WEAK (symbolP); - *input_line_pointer = c; - - SKIP_WHITESPACE (); - - if (!is_end_of_line[(unsigned char) *input_line_pointer]) - { - if (S_IS_DEFINED (symbolP)) - { - as_bad ("Ignoring attempt to redefine symbol `%s'.", - S_GET_NAME (symbolP)); - ignore_rest_of_line (); - return; - } - - if (*input_line_pointer == ',') - { - ++input_line_pointer; - SKIP_WHITESPACE (); - } - - expression (&exp); - if (exp.X_op != O_symbol) - { - as_bad ("bad .weakext directive"); - ignore_rest_of_line (); - return; - } - symbol_set_value_expression (symbolP, &exp); - } - - demand_empty_rest_of_line (); -} - -/* This table describes all the machine specific pseudo-ops the assembler - has to support. The fields are: - Pseudo-op name without dot - Function to call to execute this pseudo-op - Integer arg to pass to the function. */ -/* If the pseudo-op is not found in this table, it searches in the obj-elf.c, - and then in the read.c table. */ -const pseudo_typeS md_pseudo_table[] = -{ - {"lcomm", microblaze_s_lcomm, 1}, - {"data", microblaze_s_data, 0}, - {"data8", cons, 1}, /* Same as byte. */ - {"data16", cons, 2}, /* Same as hword. */ - {"data32", cons, 4}, /* Same as word. */ - {"ent", s_func, 0}, /* Treat ent as function entry point. */ - {"end", microblaze_s_func, 1}, /* Treat end as function end point. */ - {"gpword", s_rva, 4}, /* gpword label => store resolved label address in data section. */ - {"weakext", microblaze_s_weakext, 0}, - {"rodata", microblaze_s_rdata, 0}, - {"sdata2", microblaze_s_rdata, 1}, - {"sdata", microblaze_s_sdata, 0}, - {"bss", microblaze_s_bss, 0}, - {"sbss", microblaze_s_bss, 1}, - {"text", microblaze_s_text, 0}, - {"word", cons, 4}, - {"frame", s_ignore, 0}, - {"mask", s_ignore, 0}, /* Emitted by gcc. */ - {NULL, NULL, 0} -}; - -/* This function is called once, at assembler startup time. This should - set up all the tables, etc that the MD part of the assembler needs. */ - -void -md_begin (void) -{ - struct op_code_struct * opcode; - - opcode_hash_control = hash_new (); - - /* Insert unique names into hash table. */ - for (opcode = opcodes; opcode->name; opcode ++) - hash_insert (opcode_hash_control, opcode->name, (char *) opcode); -} - -/* Try to parse a reg name. */ - -static char * -parse_reg (char * s, unsigned * reg) -{ - unsigned tmpreg = 0; - - /* Strip leading whitespace. */ - while (ISSPACE (* s)) - ++ s; - - if (strncasecmp (s, "rpc", 3) == 0) - { - *reg = REG_PC; - return s + 3; - } - else if (strncasecmp (s, "rmsr", 4) == 0) - { - *reg = REG_MSR; - return s + 4; - } - else if (strncasecmp (s, "rear", 4) == 0) - { - *reg = REG_EAR; - return s + 4; - } - else if (strncasecmp (s, "resr", 4) == 0) - { - *reg = REG_ESR; - return s + 4; - } - else if (strncasecmp (s, "rfsr", 4) == 0) - { - *reg = REG_FSR; - return s + 4; - } - else if (strncasecmp (s, "rbtr", 4) == 0) - { - *reg = REG_BTR; - return s + 4; - } - else if (strncasecmp (s, "redr", 4) == 0) - { - *reg = REG_EDR; - return s + 4; - } - /* MMU registers start. */ - else if (strncasecmp (s, "rpid", 4) == 0) - { - *reg = REG_PID; - return s + 4; - } - else if (strncasecmp (s, "rzpr", 4) == 0) - { - *reg = REG_ZPR; - return s + 4; - } - else if (strncasecmp (s, "rtlbx", 5) == 0) - { - *reg = REG_TLBX; - return s + 5; - } - else if (strncasecmp (s, "rtlblo", 6) == 0) - { - *reg = REG_TLBLO; - return s + 6; - } - else if (strncasecmp (s, "rtlbhi", 6) == 0) - { - *reg = REG_TLBHI; - return s + 6; - } - else if (strncasecmp (s, "rtlbsx", 6) == 0) - { - *reg = REG_TLBSX; - return s + 6; - } - /* MMU registers end. */ - else if (strncasecmp (s, "rpvr", 4) == 0) - { - if (ISDIGIT (s[4]) && ISDIGIT (s[5])) - { - tmpreg = (s[4]-'0')*10 + s[5] - '0'; - s += 6; - } - - else if (ISDIGIT (s[4])) - { - tmpreg = s[4] - '0'; - s += 5; - } - else - as_bad (_("register expected, but saw '%.6s'"), s); - if ((int) tmpreg >= MIN_PVR_REGNUM && tmpreg <= MAX_PVR_REGNUM) - *reg = REG_PVR + tmpreg; - else - { - as_bad (_("Invalid register number at '%.6s'"), s); - *reg = REG_PVR; - } - return s; - } - else if (strncasecmp (s, "rsp", 3) == 0) - { - *reg = REG_SP; - return s + 3; - } - else if (strncasecmp (s, "rfsl", 4) == 0) - { - if (ISDIGIT (s[4]) && ISDIGIT (s[5])) - { - tmpreg = (s[4] - '0') * 10 + s[5] - '0'; - s += 6; - } - else if (ISDIGIT (s[4])) - { - tmpreg = s[4] - '0'; - s += 5; - } - else - as_bad (_("register expected, but saw '%.6s'"), s); - - if ((int) tmpreg >= MIN_REGNUM && tmpreg <= MAX_REGNUM) - *reg = tmpreg; - else - { - as_bad (_("Invalid register number at '%.6s'"), s); - *reg = 0; - } - return s; - } - /* Stack protection registers. */ - else if (strncasecmp (s, "rshr", 4) == 0) - { - *reg = REG_SHR; - return s + 4; - } - else if (strncasecmp (s, "rslr", 4) == 0) - { - *reg = REG_SLR; - return s + 4; - } - else - { - if (TOLOWER (s[0]) == 'r') - { - if (ISDIGIT (s[1]) && ISDIGIT (s[2])) - { - tmpreg = (s[1] - '0') * 10 + s[2] - '0'; - s += 3; - } - else if (ISDIGIT (s[1])) - { - tmpreg = s[1] - '0'; - s += 2; - } - else - as_bad (_("register expected, but saw '%.6s'"), s); - - if ((int)tmpreg >= MIN_REGNUM && tmpreg <= MAX_REGNUM) - *reg = tmpreg; - else - { - as_bad (_("Invalid register number at '%.6s'"), s); - *reg = 0; - } - return s; - } - } - as_bad (_("register expected, but saw '%.6s'"), s); - *reg = 0; - return s; -} - -static char * -parse_exp (char *s, expressionS *e) -{ - char *save; - char *new_pointer; - - /* Skip whitespace. */ - while (ISSPACE (* s)) - ++ s; - - save = input_line_pointer; - input_line_pointer = s; - - expression (e); - - if (e->X_op == O_absent) - as_fatal (_("missing operand")); - - new_pointer = input_line_pointer; - input_line_pointer = save; - - return new_pointer; -} - -/* Symbol modifiers (@GOT, @PLT, @GOTOFF). */ -#define IMM_NONE 0 -#define IMM_GOT 1 -#define IMM_PLT 2 -#define IMM_GOTOFF 3 -#define IMM_TLSGD 4 -#define IMM_TLSLD 5 -#define IMM_TLSDTPMOD 6 -#define IMM_TLSDTPREL 7 -#define IMM_TLSTPREL 8 -#define IMM_MAX 9 - -struct imm_type { - char *isuffix; /* Suffix String */ - int itype; /* Suffix Type */ - int otype; /* Offset Type */ -}; - -/* These are NOT in assending order of type, GOTOFF is ahead to make - sure @GOTOFF does not get matched with @GOT */ -static struct imm_type imm_types[] = { - { "NONE", IMM_NONE , 0 }, - { "GOTOFF", IMM_GOTOFF , GOTOFF_OFFSET }, - { "GOT", IMM_GOT , GOT_OFFSET }, - { "PLT", IMM_PLT , PLT_OFFSET }, - { "TLSGD", IMM_TLSGD , TLSGD_OFFSET }, - { "TLSLDM", IMM_TLSLD, TLSLD_OFFSET }, - { "TLSDTPMOD", IMM_TLSDTPMOD, TLSDTPMOD_OFFSET }, - { "TLSDTPREL", IMM_TLSDTPREL, TLSDTPREL_OFFSET }, - { "TLSTPREL", IMM_TLSTPREL, TLSTPREL_OFFSET } -}; - -static int -match_imm (const char *s, int *ilen) -{ - int i; - int slen; - - /* Check for matching suffix */ - for (i = 1; i < IMM_MAX; i++) - { - slen = strlen (imm_types[i].isuffix); - - if (strncmp (imm_types[i].isuffix, s, slen) == 0) - { - *ilen = slen; - return imm_types[i].itype; - } - } /* for */ - *ilen = 0; - return 0; -} - -static int -get_imm_otype (int itype) -{ - int i, otype; - - otype = 0; - /* Check for matching itype */ - for (i = 1; i < IMM_MAX; i++) - { - if (imm_types[i].itype == itype) - { - otype = imm_types[i].otype; - break; - } - } - return otype; -} - -static symbolS * GOT_symbol; - -#define GOT_SYMBOL_NAME "_GLOBAL_OFFSET_TABLE_" - -static char * -parse_imm (char * s, expressionS * e, int min, int max) -{ - char *new_pointer; - char *atp; - int itype, ilen; - - ilen = 0; - - /* Find the start of "@GOT" or "@PLT" suffix (if any) */ - for (atp = s; *atp != '@'; atp++) - if (is_end_of_line[(unsigned char) *atp]) - break; - - if (*atp == '@') - { - itype = match_imm (atp + 1, &ilen); - if (itype != 0) - { - *atp = 0; - e->X_md = itype; - } - else - { - atp = NULL; - e->X_md = 0; - ilen = 0; - } - *atp = 0; - } - else - { - atp = NULL; - e->X_md = 0; - } - - if (atp && !GOT_symbol) - { - GOT_symbol = symbol_find_or_make (GOT_SYMBOL_NAME); - } - - new_pointer = parse_exp (s, e); - - if (!GOT_symbol && ! strncmp (s, GOT_SYMBOL_NAME, 20)) - { - GOT_symbol = symbol_find_or_make (GOT_SYMBOL_NAME); - } - - if (e->X_op == O_absent) - ; /* An error message has already been emitted. */ - else if ((e->X_op != O_constant && e->X_op != O_symbol) ) - as_fatal (_("operand must be a constant or a label")); - else if ((e->X_op == O_constant) && ((int) e->X_add_number < min - || (int) e->X_add_number > max)) - { - as_fatal (_("operand must be absolute in range %d..%d, not %d"), - min, max, (int) e->X_add_number); - } - - if (atp) - { - *atp = '@'; /* restore back (needed?) */ - if (new_pointer >= atp) - new_pointer += ilen + 1; /* sizeof (imm_suffix) + 1 for '@' */ - } - return new_pointer; -} - -static char * -check_got (int * got_type, int * got_len) -{ - char *new_pointer; - char *atp; - char *past_got; - int first, second; - char *tmpbuf; - - /* Find the start of "@GOT" or "@PLT" suffix (if any). */ - for (atp = input_line_pointer; *atp != '@'; atp++) - if (is_end_of_line[(unsigned char) *atp]) - return NULL; - - if (strncmp (atp + 1, "GOTOFF", 5) == 0) - { - *got_len = 6; - *got_type = IMM_GOTOFF; - } - else if (strncmp (atp + 1, "GOT", 3) == 0) - { - *got_len = 3; - *got_type = IMM_GOT; - } - else if (strncmp (atp + 1, "PLT", 3) == 0) - { - *got_len = 3; - *got_type = IMM_PLT; - } - else - return NULL; - - if (!GOT_symbol) - GOT_symbol = symbol_find_or_make (GOT_SYMBOL_NAME); - - first = atp - input_line_pointer; - - past_got = atp + *got_len + 1; - for (new_pointer = past_got; !is_end_of_line[(unsigned char) *new_pointer++];) - ; - second = new_pointer - past_got; - tmpbuf = xmalloc (first + second + 2); /* One extra byte for ' ' and one for NUL. */ - memcpy (tmpbuf, input_line_pointer, first); - tmpbuf[first] = ' '; /* @GOTOFF is replaced with a single space. */ - memcpy (tmpbuf + first + 1, past_got, second); - tmpbuf[first + second + 1] = '\0'; - - return tmpbuf; -} - -extern void -parse_cons_expression_microblaze (expressionS *exp, int size) -{ - if (size == 4) - { - /* Handle @GOTOFF et.al. */ - char *save, *gotfree_copy; - int got_len, got_type; - - save = input_line_pointer; - gotfree_copy = check_got (& got_type, & got_len); - if (gotfree_copy) - input_line_pointer = gotfree_copy; - - expression (exp); - - if (gotfree_copy) - { - exp->X_md = got_type; - input_line_pointer = save + (input_line_pointer - gotfree_copy) - + got_len; - free (gotfree_copy); - } - } - else - expression (exp); -} - -/* This is the guts of the machine-dependent assembler. STR points to a - machine dependent instruction. This function is supposed to emit - the frags/bytes it assembles to. */ - -static char * str_microblaze_ro_anchor = "RO"; -static char * str_microblaze_rw_anchor = "RW"; - -static bfd_boolean -check_spl_reg (unsigned * reg) -{ - if ((*reg == REG_MSR) || (*reg == REG_PC) - || (*reg == REG_EAR) || (*reg == REG_ESR) - || (*reg == REG_FSR) || (*reg == REG_BTR) || (*reg == REG_EDR) - || (*reg == REG_PID) || (*reg == REG_ZPR) - || (*reg == REG_TLBX) || (*reg == REG_TLBLO) - || (*reg == REG_TLBHI) || (*reg == REG_TLBSX) - || (*reg == REG_SHR) || (*reg == REG_SLR) - || (*reg >= REG_PVR+MIN_PVR_REGNUM && *reg <= REG_PVR+MAX_PVR_REGNUM)) - return TRUE; - - return FALSE; -} - -/* Here we decide which fixups can be adjusted to make them relative to - the beginning of the section instead of the symbol. Basically we need - to make sure that the dynamic relocations are done correctly, so in - some cases we force the original symbol to be used. */ - -int -tc_microblaze_fix_adjustable (struct fix *fixP) -{ - if (GOT_symbol && fixP->fx_subsy == GOT_symbol) - return 0; - - if (fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_GOTOFF - || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_32_GOTOFF - || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_GOT - || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_PLT - || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSGD - || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSLD - || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_32_TLSDTPMOD - || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_32_TLSDTPREL - || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSDTPREL - || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSGOTTPREL - || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSTPREL) - return 0; - - return 1; -} - -void -md_assemble (char * str) -{ - char * op_start; - char * op_end; - struct op_code_struct * opcode, *opcode1; - char * output = NULL; - int nlen = 0; - int i; - unsigned long inst, inst1; - unsigned reg1; - unsigned reg2; - unsigned reg3; - unsigned isize; - unsigned int immed, temp; - expressionS exp; - char name[20]; - - /* Drop leading whitespace. */ - while (ISSPACE (* str)) - str ++; - - /* Find the op code end. */ - for (op_start = op_end = str; - *op_end && !is_end_of_line[(unsigned char) *op_end] && *op_end != ' '; - op_end++) - { - name[nlen] = op_start[nlen]; - nlen++; - if (nlen == sizeof (name) - 1) - break; - } - - name [nlen] = 0; - - if (nlen == 0) - { - as_bad (_("can't find opcode ")); - return; - } - - opcode = (struct op_code_struct *) hash_find (opcode_hash_control, name); - if (opcode == NULL) - { - as_bad (_("unknown opcode \"%s\""), name); - return; - } - - inst = opcode->bit_sequence; - isize = 4; - - switch (opcode->inst_type) - { - case INST_TYPE_RD_R1_R2: - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®1); /* Get rd. */ - else - { - as_fatal (_("Error in statement syntax")); - reg1 = 0; - } - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®2); /* Get r1. */ - else - { - as_fatal (_("Error in statement syntax")); - reg2 = 0; - } - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®3); /* Get r2. */ - else - { - as_fatal (_("Error in statement syntax")); - reg3 = 0; - } - - /* Check for spl registers. */ - if (check_spl_reg (& reg1)) - as_fatal (_("Cannot use special register with this instruction")); - if (check_spl_reg (& reg2)) - as_fatal (_("Cannot use special register with this instruction")); - if (check_spl_reg (& reg3)) - as_fatal (_("Cannot use special register with this instruction")); - - if (streq (name, "sub")) - { - /* sub rd, r1, r2 becomes rsub rd, r2, r1. */ - inst |= (reg1 << RD_LOW) & RD_MASK; - inst |= (reg3 << RA_LOW) & RA_MASK; - inst |= (reg2 << RB_LOW) & RB_MASK; - } - else - { - inst |= (reg1 << RD_LOW) & RD_MASK; - inst |= (reg2 << RA_LOW) & RA_MASK; - inst |= (reg3 << RB_LOW) & RB_MASK; - } - output = frag_more (isize); - break; - - case INST_TYPE_RD_R1_IMM: - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®1); /* Get rd. */ - else - { - as_fatal (_("Error in statement syntax")); - reg1 = 0; - } - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®2); /* Get r1. */ - else - { - as_fatal (_("Error in statement syntax")); - reg2 = 0; - } - if (strcmp (op_end, "")) - op_end = parse_imm (op_end + 1, & exp, MIN_IMM, MAX_IMM); - else - as_fatal (_("Error in statement syntax")); - - /* Check for spl registers. */ - if (check_spl_reg (& reg1)) - as_fatal (_("Cannot use special register with this instruction")); - if (check_spl_reg (& reg2)) - as_fatal (_("Cannot use special register with this instruction")); - - if (exp.X_op != O_constant) - { - char *opc; - relax_substateT subtype; - - if (streq (name, "lmi")) - as_fatal (_("lmi pseudo instruction should not use a label in imm field")); - else if (streq (name, "smi")) - as_fatal (_("smi pseudo instruction should not use a label in imm field")); - - if (reg2 == REG_ROSDP) - opc = str_microblaze_ro_anchor; - else if (reg2 == REG_RWSDP) - opc = str_microblaze_rw_anchor; - else - opc = NULL; - if (exp.X_md != 0) - subtype = get_imm_otype(exp.X_md); - else - subtype = opcode->inst_offset_type; - - output = frag_var (rs_machine_dependent, - isize * 2, /* maxm of 2 words. */ - isize, /* minm of 1 word. */ - subtype, /* PC-relative or not. */ - exp.X_add_symbol, - exp.X_add_number, - opc); - immed = 0; - } - else - { - output = frag_more (isize); - immed = exp.X_add_number; - } - - if (streq (name, "lmi") || streq (name, "smi")) - { - /* Load/store 32-d consecutive registers. Used on exit/entry - to subroutines to save and restore registers to stack. - Generate 32-d insts. */ - int count; - - count = 32 - reg1; - if (streq (name, "lmi")) - opcode = (struct op_code_struct *) hash_find (opcode_hash_control, "lwi"); - else - opcode = (struct op_code_struct *) hash_find (opcode_hash_control, "swi"); - if (opcode == NULL) - { - as_bad (_("unknown opcode \"%s\""), "lwi"); - return; - } - inst = opcode->bit_sequence; - inst |= (reg1 << RD_LOW) & RD_MASK; - inst |= (reg2 << RA_LOW) & RA_MASK; - inst |= (immed << IMM_LOW) & IMM_MASK; - - for (i = 0; i < count - 1; i++) - { - output[0] = INST_BYTE0 (inst); - output[1] = INST_BYTE1 (inst); - output[2] = INST_BYTE2 (inst); - output[3] = INST_BYTE3 (inst); - output = frag_more (isize); - immed = immed + 4; - reg1++; - inst = opcode->bit_sequence; - inst |= (reg1 << RD_LOW) & RD_MASK; - inst |= (reg2 << RA_LOW) & RA_MASK; - inst |= (immed << IMM_LOW) & IMM_MASK; - } - } - else - { - temp = immed & 0xFFFF8000; - if ((temp != 0) && (temp != 0xFFFF8000)) - { - /* Needs an immediate inst. */ - opcode1 = (struct op_code_struct *) hash_find (opcode_hash_control, "imm"); - if (opcode1 == NULL) - { - as_bad (_("unknown opcode \"%s\""), "imm"); - return; - } - - inst1 = opcode1->bit_sequence; - inst1 |= ((immed & 0xFFFF0000) >> 16) & IMM_MASK; - output[0] = INST_BYTE0 (inst1); - output[1] = INST_BYTE1 (inst1); - output[2] = INST_BYTE2 (inst1); - output[3] = INST_BYTE3 (inst1); - output = frag_more (isize); - } - inst |= (reg1 << RD_LOW) & RD_MASK; - inst |= (reg2 << RA_LOW) & RA_MASK; - inst |= (immed << IMM_LOW) & IMM_MASK; - } - break; - - case INST_TYPE_RD_R1_IMM5: - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®1); /* Get rd. */ - else - { - as_fatal (_("Error in statement syntax")); - reg1 = 0; - } - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®2); /* Get r1. */ - else - { - as_fatal (_("Error in statement syntax")); - reg2 = 0; - } - if (strcmp (op_end, "")) - op_end = parse_imm (op_end + 1, & exp, MIN_IMM, MAX_IMM); - else - as_fatal (_("Error in statement syntax")); - - /* Check for spl registers. */ - if (check_spl_reg (®1)) - as_fatal (_("Cannot use special register with this instruction")); - if (check_spl_reg (®2)) - as_fatal (_("Cannot use special register with this instruction")); - - if (exp.X_op != O_constant) - as_warn (_("Symbol used as immediate for shift instruction")); - else - { - output = frag_more (isize); - immed = exp.X_add_number; - } - - if (immed != (immed % 32)) - { - as_warn (_("Shift value > 32. using <value %% 32>")); - immed = immed % 32; - } - inst |= (reg1 << RD_LOW) & RD_MASK; - inst |= (reg2 << RA_LOW) & RA_MASK; - inst |= (immed << IMM_LOW) & IMM5_MASK; - break; - - case INST_TYPE_R1_R2: - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®1); /* Get r1. */ - else - { - as_fatal (_("Error in statement syntax")); - reg1 = 0; - } - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®2); /* Get r2. */ - else - { - as_fatal (_("Error in statement syntax")); - reg2 = 0; - } - - /* Check for spl registers. */ - if (check_spl_reg (& reg1)) - as_fatal (_("Cannot use special register with this instruction")); - if (check_spl_reg (& reg2)) - as_fatal (_("Cannot use special register with this instruction")); - - inst |= (reg1 << RA_LOW) & RA_MASK; - inst |= (reg2 << RB_LOW) & RB_MASK; - output = frag_more (isize); - break; - - case INST_TYPE_RD_R1: - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®1); /* Get rd. */ - else - { - as_fatal (_("Error in statement syntax")); - reg1 = 0; - } - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®2); /* Get r1. */ - else - { - as_fatal (_("Error in statement syntax")); - reg2 =0; - } - - /* Check for spl registers. */ - if (check_spl_reg (®1)) - as_fatal (_("Cannot use special register with this instruction")); - if (check_spl_reg (®2)) - as_fatal (_("Cannot use special register with this instruction")); - - inst |= (reg1 << RD_LOW) & RD_MASK; - inst |= (reg2 << RA_LOW) & RA_MASK; - output = frag_more (isize); - break; - - case INST_TYPE_RD_RFSL: - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®1); /* Get rd. */ - else - { - as_fatal (_("Error in statement syntax")); - reg1 = 0; - } - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, &immed); /* Get rfslN. */ - else - { - as_fatal (_("Error in statement syntax")); - immed = 0; - } - - /* Check for spl registers. */ - if (check_spl_reg (®1)) - as_fatal (_("Cannot use special register with this instruction")); - - inst |= (reg1 << RD_LOW) & RD_MASK; - inst |= (immed << IMM_LOW) & RFSL_MASK; - output = frag_more (isize); - break; - - case INST_TYPE_RD_IMM15: - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®1); /* Get rd. */ - else - { - as_fatal (_("Error in statement syntax")); - reg1 = 0; - } - - if (strcmp (op_end, "")) - op_end = parse_imm (op_end + 1, & exp, MIN_IMM15, MAX_IMM15); - else - as_fatal (_("Error in statement syntax")); - - /* Check for spl registers. */ - if (check_spl_reg (®1)) - as_fatal (_("Cannot use special register with this instruction")); - - if (exp.X_op != O_constant) - as_fatal (_("Symbol used as immediate value for msrset/msrclr instructions")); - else - { - output = frag_more (isize); - immed = exp.X_add_number; - } - inst |= (reg1 << RD_LOW) & RD_MASK; - inst |= (immed << IMM_LOW) & IMM15_MASK; - break; - - case INST_TYPE_R1_RFSL: - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®1); /* Get r1. */ - else - { - as_fatal (_("Error in statement syntax")); - reg1 = 0; - } - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, &immed); /* Get rfslN. */ - else - { - as_fatal (_("Error in statement syntax")); - immed = 0; - } - - /* Check for spl registers. */ - if (check_spl_reg (®1)) - as_fatal (_("Cannot use special register with this instruction")); - - inst |= (reg1 << RA_LOW) & RA_MASK; - inst |= (immed << IMM_LOW) & RFSL_MASK; - output = frag_more (isize); - break; - - case INST_TYPE_RFSL: - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, &immed); /* Get rfslN. */ - else - { - as_fatal (_("Error in statement syntax")); - immed = 0; - } - inst |= (immed << IMM_LOW) & RFSL_MASK; - output = frag_more (isize); - break; - - case INST_TYPE_R1: - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®1); /* Get r1. */ - else - { - as_fatal (_("Error in statement syntax")); - reg1 = 0; - } - - /* Check for spl registers. */ - if (check_spl_reg (®1)) - as_fatal (_("Cannot use special register with this instruction")); - - inst |= (reg1 << RA_LOW) & RA_MASK; - output = frag_more (isize); - break; - - /* For tuqula insn...:) */ - case INST_TYPE_RD: - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®1); /* Get rd. */ - else - { - as_fatal (_("Error in statement syntax")); - reg1 = 0; - } - - /* Check for spl registers. */ - if (check_spl_reg (®1)) - as_fatal (_("Cannot use special register with this instruction")); - - inst |= (reg1 << RD_LOW) & RD_MASK; - output = frag_more (isize); - break; - - case INST_TYPE_RD_SPECIAL: - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®1); /* Get rd. */ - else - { - as_fatal (_("Error in statement syntax")); - reg1 = 0; - } - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®2); /* Get r1. */ - else - { - as_fatal (_("Error in statement syntax")); - reg2 = 0; - } - - if (reg2 == REG_MSR) - immed = opcode->immval_mask | REG_MSR_MASK; - else if (reg2 == REG_PC) - immed = opcode->immval_mask | REG_PC_MASK; - else if (reg2 == REG_EAR) - immed = opcode->immval_mask | REG_EAR_MASK; - else if (reg2 == REG_ESR) - immed = opcode->immval_mask | REG_ESR_MASK; - else if (reg2 == REG_FSR) - immed = opcode->immval_mask | REG_FSR_MASK; - else if (reg2 == REG_BTR) - immed = opcode->immval_mask | REG_BTR_MASK; - else if (reg2 == REG_EDR) - immed = opcode->immval_mask | REG_EDR_MASK; - else if (reg2 == REG_PID) - immed = opcode->immval_mask | REG_PID_MASK; - else if (reg2 == REG_ZPR) - immed = opcode->immval_mask | REG_ZPR_MASK; - else if (reg2 == REG_TLBX) - immed = opcode->immval_mask | REG_TLBX_MASK; - else if (reg2 == REG_TLBLO) - immed = opcode->immval_mask | REG_TLBLO_MASK; - else if (reg2 == REG_TLBHI) - immed = opcode->immval_mask | REG_TLBHI_MASK; - else if (reg2 == REG_SHR) - immed = opcode->immval_mask | REG_SHR_MASK; - else if (reg2 == REG_SLR) - immed = opcode->immval_mask | REG_SLR_MASK; - else if (reg2 >= (REG_PVR+MIN_PVR_REGNUM) && reg2 <= (REG_PVR+MAX_PVR_REGNUM)) - immed = opcode->immval_mask | REG_PVR_MASK | reg2; - else - as_fatal (_("invalid value for special purpose register")); - inst |= (reg1 << RD_LOW) & RD_MASK; - inst |= (immed << IMM_LOW) & IMM_MASK; - output = frag_more (isize); - break; - - case INST_TYPE_SPECIAL_R1: - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®1); /* Get rd. */ - else - { - as_fatal (_("Error in statement syntax")); - reg1 = 0; - } - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®2); /* Get r1. */ - else - { - as_fatal (_("Error in statement syntax")); - reg2 = 0; - } - - if (reg1 == REG_MSR) - immed = opcode->immval_mask | REG_MSR_MASK; - else if (reg1 == REG_PC) - immed = opcode->immval_mask | REG_PC_MASK; - else if (reg1 == REG_EAR) - immed = opcode->immval_mask | REG_EAR_MASK; - else if (reg1 == REG_ESR) - immed = opcode->immval_mask | REG_ESR_MASK; - else if (reg1 == REG_FSR) - immed = opcode->immval_mask | REG_FSR_MASK; - else if (reg1 == REG_BTR) - immed = opcode->immval_mask | REG_BTR_MASK; - else if (reg1 == REG_EDR) - immed = opcode->immval_mask | REG_EDR_MASK; - else if (reg1 == REG_PID) - immed = opcode->immval_mask | REG_PID_MASK; - else if (reg1 == REG_ZPR) - immed = opcode->immval_mask | REG_ZPR_MASK; - else if (reg1 == REG_TLBX) - immed = opcode->immval_mask | REG_TLBX_MASK; - else if (reg1 == REG_TLBLO) - immed = opcode->immval_mask | REG_TLBLO_MASK; - else if (reg1 == REG_TLBHI) - immed = opcode->immval_mask | REG_TLBHI_MASK; - else if (reg1 == REG_TLBSX) - immed = opcode->immval_mask | REG_TLBSX_MASK; - else if (reg1 == REG_SHR) - immed = opcode->immval_mask | REG_SHR_MASK; - else if (reg1 == REG_SLR) - immed = opcode->immval_mask | REG_SLR_MASK; - else - as_fatal (_("invalid value for special purpose register")); - inst |= (reg2 << RA_LOW) & RA_MASK; - inst |= (immed << IMM_LOW) & IMM_MASK; - output = frag_more (isize); - break; - - case INST_TYPE_R1_R2_SPECIAL: - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®1); /* Get r1. */ - else - { - as_fatal (_("Error in statement syntax")); - reg1 = 0; - } - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®2); /* Get r2. */ - else - { - as_fatal (_("Error in statement syntax")); - reg2 =0; - } - - /* Check for spl registers. */ - if (check_spl_reg (®1)) - as_fatal (_("Cannot use special register with this instruction")); - if (check_spl_reg (®2)) - as_fatal (_("Cannot use special register with this instruction")); - - /* insn wic ra, rb => wic ra, ra, rb. */ - inst |= (reg1 << RA_LOW) & RA_MASK; - inst |= (reg2 << RB_LOW) & RB_MASK; - - output = frag_more (isize); - break; - - case INST_TYPE_RD_R2: - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®1); /* Get rd. */ - else - { - as_fatal (_("Error in statement syntax")); - reg1 = 0; - } - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®2); /* Get r2. */ - else - { - as_fatal (_("Error in statement syntax")); - reg2 = 0; - } - - /* Check for spl registers. */ - if (check_spl_reg (®1)) - as_fatal (_("Cannot use special register with this instruction")); - if (check_spl_reg (®2)) - as_fatal (_("Cannot use special register with this instruction")); - - inst |= (reg1 << RD_LOW) & RD_MASK; - inst |= (reg2 << RB_LOW) & RB_MASK; - output = frag_more (isize); - break; - - case INST_TYPE_R1_IMM: - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®1); /* Get r1. */ - else - { - as_fatal (_("Error in statement syntax")); - reg1 = 0; - } - if (strcmp (op_end, "")) - op_end = parse_imm (op_end + 1, & exp, MIN_IMM, MAX_IMM); - else - as_fatal (_("Error in statement syntax")); - - /* Check for spl registers. */ - if (check_spl_reg (®1)) - as_fatal (_("Cannot use special register with this instruction")); - - if (exp.X_op != O_constant) - { - char *opc = NULL; - relax_substateT subtype; - - if (exp.X_md != 0) - subtype = get_imm_otype(exp.X_md); - else - subtype = opcode->inst_offset_type; - - output = frag_var (rs_machine_dependent, - isize * 2, /* maxm of 2 words. */ - isize, /* minm of 1 word. */ - subtype, /* PC-relative or not. */ - exp.X_add_symbol, - exp.X_add_number, - opc); - immed = 0; - } - else - { - output = frag_more (isize); - immed = exp.X_add_number; - } - - temp = immed & 0xFFFF8000; - if ((temp != 0) && (temp != 0xFFFF8000)) - { - /* Needs an immediate inst. */ - opcode1 = (struct op_code_struct *) hash_find (opcode_hash_control, "imm"); - if (opcode1 == NULL) - { - as_bad (_("unknown opcode \"%s\""), "imm"); - return; - } - - inst1 = opcode1->bit_sequence; - inst1 |= ((immed & 0xFFFF0000) >> 16) & IMM_MASK; - output[0] = INST_BYTE0 (inst1); - output[1] = INST_BYTE1 (inst1); - output[2] = INST_BYTE2 (inst1); - output[3] = INST_BYTE3 (inst1); - output = frag_more (isize); - } - - inst |= (reg1 << RA_LOW) & RA_MASK; - inst |= (immed << IMM_LOW) & IMM_MASK; - break; - - case INST_TYPE_RD_IMM: - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®1); /* Get rd. */ - else - { - as_fatal (_("Error in statement syntax")); - reg1 = 0; - } - if (strcmp (op_end, "")) - op_end = parse_imm (op_end + 1, & exp, MIN_IMM, MAX_IMM); - else - as_fatal (_("Error in statement syntax")); - - /* Check for spl registers. */ - if (check_spl_reg (®1)) - as_fatal (_("Cannot use special register with this instruction")); - - if (exp.X_op != O_constant) - { - char *opc = NULL; - relax_substateT subtype; - - if (exp.X_md != 0) - subtype = get_imm_otype(exp.X_md); - else - subtype = opcode->inst_offset_type; - - output = frag_var (rs_machine_dependent, - isize * 2, /* maxm of 2 words. */ - isize, /* minm of 1 word. */ - subtype, /* PC-relative or not. */ - exp.X_add_symbol, - exp.X_add_number, - opc); - immed = 0; - } - else - { - output = frag_more (isize); - immed = exp.X_add_number; - } - - temp = immed & 0xFFFF8000; - if ((temp != 0) && (temp != 0xFFFF8000)) - { - /* Needs an immediate inst. */ - opcode1 = (struct op_code_struct *) hash_find (opcode_hash_control, "imm"); - if (opcode1 == NULL) - { - as_bad (_("unknown opcode \"%s\""), "imm"); - return; - } - - inst1 = opcode1->bit_sequence; - inst1 |= ((immed & 0xFFFF0000) >> 16) & IMM_MASK; - output[0] = INST_BYTE0 (inst1); - output[1] = INST_BYTE1 (inst1); - output[2] = INST_BYTE2 (inst1); - output[3] = INST_BYTE3 (inst1); - output = frag_more (isize); - } - - inst |= (reg1 << RD_LOW) & RD_MASK; - inst |= (immed << IMM_LOW) & IMM_MASK; - break; - - case INST_TYPE_R2: - if (strcmp (op_end, "")) - op_end = parse_reg (op_end + 1, ®2); /* Get r2. */ - else - { - as_fatal (_("Error in statement syntax")); - reg2 = 0; - } - - /* Check for spl registers. */ - if (check_spl_reg (®2)) - as_fatal (_("Cannot use special register with this instruction")); - - inst |= (reg2 << RB_LOW) & RB_MASK; - output = frag_more (isize); - break; - - case INST_TYPE_IMM: - if (streq (name, "imm")) - as_fatal (_("An IMM instruction should not be present in the .s file")); - - op_end = parse_imm (op_end + 1, & exp, MIN_IMM, MAX_IMM); - - if (exp.X_op != O_constant) - { - char *opc = NULL; - relax_substateT subtype; - - if (exp.X_md != 0) - subtype = get_imm_otype(exp.X_md); - else - subtype = opcode->inst_offset_type; - - output = frag_var (rs_machine_dependent, - isize * 2, /* maxm of 2 words. */ - isize, /* minm of 1 word. */ - subtype, /* PC-relative or not. */ - exp.X_add_symbol, - exp.X_add_number, - opc); - immed = 0; - } - else - { - output = frag_more (isize); - immed = exp.X_add_number; - } - - - temp = immed & 0xFFFF8000; - if ((temp != 0) && (temp != 0xFFFF8000)) - { - /* Needs an immediate inst. */ - opcode1 = (struct op_code_struct *) hash_find (opcode_hash_control, "imm"); - if (opcode1 == NULL) - { - as_bad (_("unknown opcode \"%s\""), "imm"); - return; - } - - inst1 = opcode1->bit_sequence; - inst1 |= ((immed & 0xFFFF0000) >> 16) & IMM_MASK; - output[0] = INST_BYTE0 (inst1); - output[1] = INST_BYTE1 (inst1); - output[2] = INST_BYTE2 (inst1); - output[3] = INST_BYTE3 (inst1); - output = frag_more (isize); - } - inst |= (immed << IMM_LOW) & IMM_MASK; - break; - - case INST_TYPE_NONE: - output = frag_more (isize); - break; - - case INST_TYPE_IMM5: - if (strcmp(op_end, "")) - op_end = parse_imm (op_end + 1, & exp, MIN_IMM5, MAX_IMM5); - else - as_fatal(_("Error in statement syntax")); - if (exp.X_op != O_constant) { - as_warn(_("Symbol used as immediate for mbar instruction")); - } else { - output = frag_more (isize); - immed = exp.X_add_number; - } - if (immed != (immed % 32)) { - as_warn(_("Immediate value for mbar > 32. using <value %% 32>")); - immed = immed % 32; - } - inst |= (immed << IMM_MBAR); - break; - - default: - as_fatal (_("unimplemented opcode \"%s\""), name); - } - - /* Drop whitespace after all the operands have been parsed. */ - while (ISSPACE (* op_end)) - op_end ++; - - /* Give warning message if the insn has more operands than required. */ - if (strcmp (op_end, opcode->name) && strcmp (op_end, "")) - as_warn (_("ignoring operands: %s "), op_end); - - output[0] = INST_BYTE0 (inst); - output[1] = INST_BYTE1 (inst); - output[2] = INST_BYTE2 (inst); - output[3] = INST_BYTE3 (inst); - -#ifdef OBJ_ELF - dwarf2_emit_insn (4); -#endif -} - -symbolS * -md_undefined_symbol (char * name ATTRIBUTE_UNUSED) -{ - return NULL; -} - -/* Various routines to kill one day. */ -/* Equal to MAX_PRECISION in atof-ieee.c */ -#define MAX_LITTLENUMS 6 - -/* 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.*/ -char * -md_atof (int type, char * litP, int * sizeP) -{ - int prec; - LITTLENUM_TYPE words[MAX_LITTLENUMS]; - int i; - 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_NTOF()"); - } - - t = atof_ieee (input_line_pointer, type, words); - - if (t) - input_line_pointer = t; - - *sizeP = prec * sizeof (LITTLENUM_TYPE); - - if (! target_big_endian) - { - for (i = prec - 1; i >= 0; i--) - { - md_number_to_chars (litP, (valueT) words[i], - sizeof (LITTLENUM_TYPE)); - litP += sizeof (LITTLENUM_TYPE); - } - } - else - for (i = 0; i < prec; i++) - { - md_number_to_chars (litP, (valueT) words[i], - sizeof (LITTLENUM_TYPE)); - litP += sizeof (LITTLENUM_TYPE); - } - - return NULL; -} - -const char * md_shortopts = ""; - -struct option md_longopts[] = -{ - {"EB", no_argument, NULL, OPTION_EB}, - {"EL", no_argument, NULL, OPTION_EL}, - { NULL, no_argument, NULL, 0} -}; - -size_t md_longopts_size = sizeof (md_longopts); - -int md_short_jump_size; - -void -md_create_short_jump (char * ptr ATTRIBUTE_UNUSED, - addressT from_Nddr ATTRIBUTE_UNUSED, - addressT to_Nddr ATTRIBUTE_UNUSED, - fragS * frag ATTRIBUTE_UNUSED, - symbolS * to_symbol ATTRIBUTE_UNUSED) -{ - as_fatal (_("failed sanity check: short_jump")); -} - -void -md_create_long_jump (char * ptr ATTRIBUTE_UNUSED, - addressT from_Nddr ATTRIBUTE_UNUSED, - addressT to_Nddr ATTRIBUTE_UNUSED, - fragS * frag ATTRIBUTE_UNUSED, - symbolS * to_symbol ATTRIBUTE_UNUSED) -{ - as_fatal (_("failed sanity check: long_jump")); -} - -/* Called after relaxing, change the frags so they know how big they are. */ - -void -md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, - segT sec ATTRIBUTE_UNUSED, - fragS * fragP) -{ - fixS *fixP; - - switch (fragP->fr_subtype) - { - case UNDEFINED_PC_OFFSET: - fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol, - fragP->fr_offset, TRUE, BFD_RELOC_64_PCREL); - fragP->fr_fix += INST_WORD_SIZE * 2; - fragP->fr_var = 0; - break; - case DEFINED_ABS_SEGMENT: - if (fragP->fr_symbol == GOT_symbol) - fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol, - fragP->fr_offset, TRUE, BFD_RELOC_MICROBLAZE_64_GOTPC); - else - fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol, - fragP->fr_offset, FALSE, BFD_RELOC_64); - fragP->fr_fix += INST_WORD_SIZE * 2; - fragP->fr_var = 0; - break; - case DEFINED_RO_SEGMENT: - fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE, fragP->fr_symbol, - fragP->fr_offset, FALSE, BFD_RELOC_MICROBLAZE_32_ROSDA); - fragP->fr_fix += INST_WORD_SIZE; - fragP->fr_var = 0; - break; - case DEFINED_RW_SEGMENT: - fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE, fragP->fr_symbol, - fragP->fr_offset, FALSE, BFD_RELOC_MICROBLAZE_32_RWSDA); - fragP->fr_fix += INST_WORD_SIZE; - fragP->fr_var = 0; - break; - case DEFINED_PC_OFFSET: - fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE, fragP->fr_symbol, - fragP->fr_offset, TRUE, BFD_RELOC_MICROBLAZE_32_LO_PCREL); - fragP->fr_fix += INST_WORD_SIZE; - fragP->fr_var = 0; - break; - case LARGE_DEFINED_PC_OFFSET: - fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol, - fragP->fr_offset, TRUE, BFD_RELOC_64_PCREL); - fragP->fr_fix += INST_WORD_SIZE * 2; - fragP->fr_var = 0; - break; - case GOT_OFFSET: - fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol, - fragP->fr_offset, FALSE, BFD_RELOC_MICROBLAZE_64_GOT); - fragP->fr_fix += INST_WORD_SIZE * 2; - fragP->fr_var = 0; - break; - case PLT_OFFSET: - fixP = fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol, - fragP->fr_offset, TRUE, BFD_RELOC_MICROBLAZE_64_PLT); - /* fixP->fx_plt = 1; */ - (void) fixP; - fragP->fr_fix += INST_WORD_SIZE * 2; - fragP->fr_var = 0; - break; - case GOTOFF_OFFSET: - fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol, - fragP->fr_offset, FALSE, BFD_RELOC_MICROBLAZE_64_GOTOFF); - fragP->fr_fix += INST_WORD_SIZE * 2; - fragP->fr_var = 0; - break; - case TLSGD_OFFSET: - fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol, - fragP->fr_offset, FALSE, BFD_RELOC_MICROBLAZE_64_TLSGD); - fragP->fr_fix += INST_WORD_SIZE * 2; - fragP->fr_var = 0; - break; - case TLSLD_OFFSET: - fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol, - fragP->fr_offset, FALSE, BFD_RELOC_MICROBLAZE_64_TLSLD); - fragP->fr_fix += INST_WORD_SIZE * 2; - fragP->fr_var = 0; - break; - case TLSDTPREL_OFFSET: - fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol, - fragP->fr_offset, FALSE, BFD_RELOC_MICROBLAZE_64_TLSDTPREL); - fragP->fr_fix += INST_WORD_SIZE * 2; - fragP->fr_var = 0; - break; - - default: - abort (); - } -} - -/* Applies the desired value to the specified location. - Also sets up addends for 'rela' type relocations. */ -void -md_apply_fix (fixS * fixP, - valueT * valp, - segT segment) -{ - char * buf = fixP->fx_where + fixP->fx_frag->fr_literal; - char * file = fixP->fx_file ? fixP->fx_file : _("unknown"); - const char * symname; - /* Note: use offsetT because it is signed, valueT is unsigned. */ - offsetT val = (offsetT) * valp; - int i; - struct op_code_struct * opcode1; - unsigned long inst1; - - symname = fixP->fx_addsy ? S_GET_NAME (fixP->fx_addsy) : _("<unknown>"); - - /* fixP->fx_offset is supposed to be set up correctly for all - symbol relocations. */ - if (fixP->fx_addsy == NULL) - { - if (!fixP->fx_pcrel) - fixP->fx_offset = val; /* Absolute relocation. */ - else - fprintf (stderr, "NULL symbol PC-relative relocation? offset = %08x, val = %08x\n", - (unsigned int) fixP->fx_offset, (unsigned int) val); - } - - /* If we aren't adjusting this fixup to be against the section - symbol, we need to adjust the value. */ - if (fixP->fx_addsy != NULL) - { - if (S_IS_WEAK (fixP->fx_addsy) - || (symbol_used_in_reloc_p (fixP->fx_addsy) - && (((bfd_get_section_flags (stdoutput, - S_GET_SEGMENT (fixP->fx_addsy)) - & SEC_LINK_ONCE) != 0) - || !strncmp (segment_name (S_GET_SEGMENT (fixP->fx_addsy)), - ".gnu.linkonce", - sizeof (".gnu.linkonce") - 1)))) - { - val -= S_GET_VALUE (fixP->fx_addsy); - if (val != 0 && ! fixP->fx_pcrel) - { - /* In this case, the bfd_install_relocation routine will - incorrectly add the symbol value back in. We just want - the addend to appear in the object file. - FIXME: If this makes VALUE zero, we're toast. */ - val -= S_GET_VALUE (fixP->fx_addsy); - } - } - } - - /* If the fix is relative to a symbol which is not defined, or not - in the same segment as the fix, we cannot resolve it here. */ - /* fixP->fx_addsy is NULL if valp contains the entire relocation. */ - if (fixP->fx_addsy != NULL - && (!S_IS_DEFINED (fixP->fx_addsy) - || (S_GET_SEGMENT (fixP->fx_addsy) != segment))) - { - fixP->fx_done = 0; -#ifdef OBJ_ELF - /* For ELF we can just return and let the reloc that will be generated - take care of everything. For COFF we still have to insert 'val' - into the insn since the addend field will be ignored. */ - /* return; */ -#endif - } - /* All fixups in the text section must be handled in the linker. */ - else if (segment->flags & SEC_CODE) - fixP->fx_done = 0; - else if (!fixP->fx_pcrel && fixP->fx_addsy != NULL) - fixP->fx_done = 0; - else - fixP->fx_done = 1; - - switch (fixP->fx_r_type) - { - case BFD_RELOC_MICROBLAZE_32_LO: - case BFD_RELOC_MICROBLAZE_32_LO_PCREL: - if (target_big_endian) - { - buf[2] |= ((val >> 8) & 0xff); - buf[3] |= (val & 0xff); - } - else - { - buf[1] |= ((val >> 8) & 0xff); - buf[0] |= (val & 0xff); - } - break; - case BFD_RELOC_MICROBLAZE_32_ROSDA: - case BFD_RELOC_MICROBLAZE_32_RWSDA: - /* Don't do anything if the symbol is not defined. */ - if (fixP->fx_addsy == NULL || S_IS_DEFINED (fixP->fx_addsy)) - { - if (((val & 0xFFFF8000) != 0) && ((val & 0xFFFF8000) != 0xFFFF8000)) - as_bad_where (file, fixP->fx_line, - _("pcrel for branch to %s too far (0x%x)"), - symname, (int) val); - if (target_big_endian) - { - buf[2] |= ((val >> 8) & 0xff); - buf[3] |= (val & 0xff); - } - else - { - buf[1] |= ((val >> 8) & 0xff); - buf[0] |= (val & 0xff); - } - } - break; - case BFD_RELOC_32: - case BFD_RELOC_RVA: - case BFD_RELOC_32_PCREL: - case BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM: - /* Don't do anything if the symbol is not defined. */ - if (fixP->fx_addsy == NULL || S_IS_DEFINED (fixP->fx_addsy)) - { - if (target_big_endian) - { - buf[0] |= ((val >> 24) & 0xff); - buf[1] |= ((val >> 16) & 0xff); - buf[2] |= ((val >> 8) & 0xff); - buf[3] |= (val & 0xff); - } - else - { - buf[3] |= ((val >> 24) & 0xff); - buf[2] |= ((val >> 16) & 0xff); - buf[1] |= ((val >> 8) & 0xff); - buf[0] |= (val & 0xff); - } - } - break; - case BFD_RELOC_64_PCREL: - case BFD_RELOC_64: - /* Add an imm instruction. First save the current instruction. */ - for (i = 0; i < INST_WORD_SIZE; i++) - buf[i + INST_WORD_SIZE] = buf[i]; - - /* Generate the imm instruction. */ - opcode1 = (struct op_code_struct *) hash_find (opcode_hash_control, "imm"); - if (opcode1 == NULL) - { - as_bad (_("unknown opcode \"%s\""), "imm"); - return; - } - - inst1 = opcode1->bit_sequence; - if (fixP->fx_addsy == NULL || S_IS_DEFINED (fixP->fx_addsy)) - inst1 |= ((val & 0xFFFF0000) >> 16) & IMM_MASK; - - buf[0] = INST_BYTE0 (inst1); - buf[1] = INST_BYTE1 (inst1); - buf[2] = INST_BYTE2 (inst1); - buf[3] = INST_BYTE3 (inst1); - - /* Add the value only if the symbol is defined. */ - if (fixP->fx_addsy == NULL || S_IS_DEFINED (fixP->fx_addsy)) - { - if (target_big_endian) - { - buf[6] |= ((val >> 8) & 0xff); - buf[7] |= (val & 0xff); - } - else - { - buf[5] |= ((val >> 8) & 0xff); - buf[4] |= (val & 0xff); - } - } - break; - - case BFD_RELOC_MICROBLAZE_64_TLSDTPREL: - case BFD_RELOC_MICROBLAZE_64_TLSGD: - case BFD_RELOC_MICROBLAZE_64_TLSLD: - S_SET_THREAD_LOCAL (fixP->fx_addsy); - - case BFD_RELOC_MICROBLAZE_64_GOTPC: - case BFD_RELOC_MICROBLAZE_64_GOT: - case BFD_RELOC_MICROBLAZE_64_PLT: - case BFD_RELOC_MICROBLAZE_64_GOTOFF: - /* Add an imm instruction. First save the current instruction. */ - for (i = 0; i < INST_WORD_SIZE; i++) - buf[i + INST_WORD_SIZE] = buf[i]; - - /* Generate the imm instruction. */ - opcode1 = (struct op_code_struct *) hash_find (opcode_hash_control, "imm"); - if (opcode1 == NULL) - { - as_bad (_("unknown opcode \"%s\""), "imm"); - return; - } - - inst1 = opcode1->bit_sequence; - - /* We can fixup call to a defined non-global address - within the same section only. */ - buf[0] = INST_BYTE0 (inst1); - buf[1] = INST_BYTE1 (inst1); - buf[2] = INST_BYTE2 (inst1); - buf[3] = INST_BYTE3 (inst1); - return; - - default: - break; - } - - if (fixP->fx_addsy == NULL) - { - /* This fixup has been resolved. Create a reloc in case the linker - moves code around due to relaxing. */ - if (fixP->fx_r_type == BFD_RELOC_64_PCREL) - fixP->fx_r_type = BFD_RELOC_MICROBLAZE_64_NONE; - else - fixP->fx_r_type = BFD_RELOC_NONE; - fixP->fx_addsy = section_symbol (absolute_section); - } - return; -} - -void -md_operand (expressionS * expressionP) -{ - /* Ignore leading hash symbol, if present. */ - if (*input_line_pointer == '#') - { - input_line_pointer ++; - expression (expressionP); - } -} - -/* Called just before address relaxation, return the length - by which a fragment must grow to reach it's destination. */ - -int -md_estimate_size_before_relax (fragS * fragP, - segT segment_type) -{ - sbss_segment = bfd_get_section_by_name (stdoutput, ".sbss"); - sbss2_segment = bfd_get_section_by_name (stdoutput, ".sbss2"); - sdata_segment = bfd_get_section_by_name (stdoutput, ".sdata"); - sdata2_segment = bfd_get_section_by_name (stdoutput, ".sdata2"); - - switch (fragP->fr_subtype) - { - case INST_PC_OFFSET: - /* Used to be a PC-relative branch. */ - if (!fragP->fr_symbol) - { - /* We know the abs value: Should never happen. */ - as_bad (_("Absolute PC-relative value in relaxation code. Assembler error.....")); - abort (); - } - else if (S_GET_SEGMENT (fragP->fr_symbol) == segment_type && - !S_IS_WEAK (fragP->fr_symbol)) - { - fragP->fr_subtype = DEFINED_PC_OFFSET; - /* Don't know now whether we need an imm instruction. */ - fragP->fr_var = INST_WORD_SIZE; - } - else if (S_IS_DEFINED (fragP->fr_symbol) - && (((S_GET_SEGMENT (fragP->fr_symbol))->flags & SEC_CODE) == 0)) - { - /* Cannot have a PC-relative branch to a diff segment. */ - as_bad (_("PC relative branch to label %s which is not in the instruction space"), - S_GET_NAME (fragP->fr_symbol)); - fragP->fr_subtype = UNDEFINED_PC_OFFSET; - fragP->fr_var = INST_WORD_SIZE*2; - } - else - { - fragP->fr_subtype = UNDEFINED_PC_OFFSET; - fragP->fr_var = INST_WORD_SIZE*2; - } - break; - - case INST_NO_OFFSET: - /* Used to be a reference to somewhere which was unknown. */ - if (fragP->fr_symbol) - { - if (fragP->fr_opcode == NULL) - { - /* Used as an absolute value. */ - fragP->fr_subtype = DEFINED_ABS_SEGMENT; - /* Variable part does not change. */ - fragP->fr_var = INST_WORD_SIZE*2; - } - else if (streq (fragP->fr_opcode, str_microblaze_ro_anchor)) - { - /* It is accessed using the small data read only anchor. */ - if ((S_GET_SEGMENT (fragP->fr_symbol) == bfd_com_section_ptr) - || (S_GET_SEGMENT (fragP->fr_symbol) == sdata2_segment) - || (S_GET_SEGMENT (fragP->fr_symbol) == sbss2_segment) - || (! S_IS_DEFINED (fragP->fr_symbol))) - { - fragP->fr_subtype = DEFINED_RO_SEGMENT; - fragP->fr_var = INST_WORD_SIZE; - } - else - { - /* Variable not in small data read only segment accessed - using small data read only anchor. */ - char *file = fragP->fr_file ? fragP->fr_file : _("unknown"); - - as_bad_where (file, fragP->fr_line, - _("Variable is accessed using small data read " - "only anchor, but it is not in the small data " - "read only section")); - fragP->fr_subtype = DEFINED_RO_SEGMENT; - fragP->fr_var = INST_WORD_SIZE; - } - } - else if (streq (fragP->fr_opcode, str_microblaze_rw_anchor)) - { - if ((S_GET_SEGMENT (fragP->fr_symbol) == bfd_com_section_ptr) - || (S_GET_SEGMENT (fragP->fr_symbol) == sdata_segment) - || (S_GET_SEGMENT (fragP->fr_symbol) == sbss_segment) - || (!S_IS_DEFINED (fragP->fr_symbol))) - { - /* It is accessed using the small data read write anchor. */ - fragP->fr_subtype = DEFINED_RW_SEGMENT; - fragP->fr_var = INST_WORD_SIZE; - } - else - { - char *file = fragP->fr_file ? fragP->fr_file : _("unknown"); - - as_bad_where (file, fragP->fr_line, - _("Variable is accessed using small data read " - "write anchor, but it is not in the small data " - "read write section")); - fragP->fr_subtype = DEFINED_RW_SEGMENT; - fragP->fr_var = INST_WORD_SIZE; - } - } - else - { - as_bad (_("Incorrect fr_opcode value in frag. Internal error.....")); - abort (); - } - } - else - { - /* We know the abs value: Should never happen. */ - as_bad (_("Absolute value in relaxation code. Assembler error.....")); - abort (); - } - break; - - case UNDEFINED_PC_OFFSET: - case LARGE_DEFINED_PC_OFFSET: - case DEFINED_ABS_SEGMENT: - case GOT_OFFSET: - case PLT_OFFSET: - case GOTOFF_OFFSET: - case TLSGD_OFFSET: - case TLSLD_OFFSET: - case TLSTPREL_OFFSET: - case TLSDTPREL_OFFSET: - fragP->fr_var = INST_WORD_SIZE*2; - break; - case DEFINED_RO_SEGMENT: - case DEFINED_RW_SEGMENT: - case DEFINED_PC_OFFSET: - case TLSDTPMOD_OFFSET: - fragP->fr_var = INST_WORD_SIZE; - break; - default: - abort (); - } - - return fragP->fr_var; -} - -/* Put number into target byte order. */ - -void -md_number_to_chars (char * ptr, valueT use, int nbytes) -{ - if (target_big_endian) - number_to_chars_bigendian (ptr, use, nbytes); - else - number_to_chars_littleendian (ptr, use, nbytes); -} - -/* Round up a section size to the appropriate boundary. */ - -valueT -md_section_align (segT segment ATTRIBUTE_UNUSED, valueT size) -{ - return size; /* Byte alignment is fine. */ -} - - -/* The location from which a PC relative jump should be calculated, - given a PC relative reloc. */ - -long -md_pcrel_from_section (fixS * fixp, segT sec ATTRIBUTE_UNUSED) -{ -#ifdef OBJ_ELF - /* If the symbol is undefined or defined in another section - we leave the add number alone for the linker to fix it later. - Only account for the PC pre-bump (No PC-pre-bump on the Microblaze). */ - - if (fixp->fx_addsy != (symbolS *) NULL - && (!S_IS_DEFINED (fixp->fx_addsy) - || (S_GET_SEGMENT (fixp->fx_addsy) != sec))) - return 0; - else - { - /* The case where we are going to resolve things... */ - if (fixp->fx_r_type == BFD_RELOC_64_PCREL) - return fixp->fx_where + fixp->fx_frag->fr_address + INST_WORD_SIZE; - else - return fixp->fx_where + fixp->fx_frag->fr_address; - } -#endif -} - - -#define F(SZ,PCREL) (((SZ) << 1) + (PCREL)) -#define MAP(SZ,PCREL,TYPE) case F (SZ, PCREL): code = (TYPE); break - -arelent * -tc_gen_reloc (asection * section ATTRIBUTE_UNUSED, fixS * fixp) -{ - arelent * rel; - bfd_reloc_code_real_type code; - - switch (fixp->fx_r_type) - { - case BFD_RELOC_NONE: - case BFD_RELOC_MICROBLAZE_64_NONE: - case BFD_RELOC_32: - case BFD_RELOC_MICROBLAZE_32_LO: - case BFD_RELOC_MICROBLAZE_32_LO_PCREL: - case BFD_RELOC_RVA: - case BFD_RELOC_64: - case BFD_RELOC_64_PCREL: - case BFD_RELOC_MICROBLAZE_32_ROSDA: - case BFD_RELOC_MICROBLAZE_32_RWSDA: - case BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM: - case BFD_RELOC_MICROBLAZE_64_GOTPC: - case BFD_RELOC_MICROBLAZE_64_GOT: - case BFD_RELOC_MICROBLAZE_64_PLT: - case BFD_RELOC_MICROBLAZE_64_GOTOFF: - case BFD_RELOC_MICROBLAZE_32_GOTOFF: - case BFD_RELOC_MICROBLAZE_64_TLSGD: - case BFD_RELOC_MICROBLAZE_64_TLSLD: - case BFD_RELOC_MICROBLAZE_32_TLSDTPMOD: - case BFD_RELOC_MICROBLAZE_32_TLSDTPREL: - case BFD_RELOC_MICROBLAZE_64_TLSDTPREL: - case BFD_RELOC_MICROBLAZE_64_TLSGOTTPREL: - case BFD_RELOC_MICROBLAZE_64_TLSTPREL: - code = fixp->fx_r_type; - break; - - default: - switch (F (fixp->fx_size, fixp->fx_pcrel)) - { - MAP (1, 0, BFD_RELOC_8); - MAP (2, 0, BFD_RELOC_16); - MAP (4, 0, BFD_RELOC_32); - MAP (1, 1, BFD_RELOC_8_PCREL); - MAP (2, 1, BFD_RELOC_16_PCREL); - MAP (4, 1, BFD_RELOC_32_PCREL); - default: - code = fixp->fx_r_type; - as_bad (_("Can not do %d byte %srelocation"), - fixp->fx_size, - fixp->fx_pcrel ? _("pc-relative") : ""); - } - break; - } - - rel = (arelent *) xmalloc (sizeof (arelent)); - rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); - - if (code == BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM) - *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy); - else - *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); - - rel->address = fixp->fx_frag->fr_address + fixp->fx_where; - /* Always pass the addend along! */ - rel->addend = fixp->fx_offset; - rel->howto = bfd_reloc_type_lookup (stdoutput, code); - - if (rel->howto == NULL) - { - as_bad_where (fixp->fx_file, fixp->fx_line, - _("Cannot represent relocation type %s"), - bfd_get_reloc_code_name (code)); - - /* Set howto to a garbage value so that we can keep going. */ - rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32); - gas_assert (rel->howto != NULL); - } - return rel; -} - -int -md_parse_option (int c, char * arg ATTRIBUTE_UNUSED) -{ - switch (c) - { - case OPTION_EB: - target_big_endian = 1; - break; - case OPTION_EL: - target_big_endian = 0; - break; - default: - return 0; - } - return 1; -} - -void -md_show_usage (FILE * stream ATTRIBUTE_UNUSED) -{ - /* fprintf(stream, _("\ - MicroBlaze options:\n\ - -noSmall Data in the comm and data sections do not go into the small data section\n")); */ -} - - -/* Create a fixup for a cons expression. If parse_cons_expression_microblaze - found a machine specific op in an expression, - then we create relocs accordingly. */ - -void -cons_fix_new_microblaze (fragS * frag, - int where, - int size, - expressionS *exp) -{ - - bfd_reloc_code_real_type r; - - if ((exp->X_op == O_subtract) && (exp->X_add_symbol) && - (exp->X_op_symbol) && (now_seg != absolute_section) && (size == 4) - && (!S_IS_LOCAL (exp->X_op_symbol))) - r = BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM; - else if (exp->X_md == IMM_GOTOFF && exp->X_op == O_symbol_rva) - { - exp->X_op = O_symbol; - r = BFD_RELOC_MICROBLAZE_32_GOTOFF; - } - else - { - switch (size) - { - case 1: - r = BFD_RELOC_8; - break; - case 2: - r = BFD_RELOC_16; - break; - case 4: - r = BFD_RELOC_32; - break; - case 8: - r = BFD_RELOC_64; - break; - default: - as_bad (_("unsupported BFD relocation size %u"), size); - r = BFD_RELOC_32; - break; - } - } - fix_new_exp (frag, where, size, exp, 0, r); -} |