1  /* tc-or1k.c -- Assembler for the OpenRISC family.
       2     Copyright (C) 2001-2023 Free Software Foundation, Inc.
       3     Contributed for OR32 by Johan Rydberg, jrydberg@opencores.org
       4  
       5     This file is part of GAS, the GNU Assembler.
       6  
       7     GAS is free software; you can redistribute it and/or modify
       8     it under the terms of the GNU General Public License as published by
       9     the Free Software Foundation; either version 3, or (at your option)
      10     any later version.
      11  
      12     GAS is distributed in the hope that it will be useful,
      13     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15     GNU General Public License for more details.
      16  
      17     You should have received a copy of the GNU General Public License
      18     along with this program; if not, see <http://www.gnu.org/licenses/> */
      19  #include "as.h"
      20  #include "safe-ctype.h"
      21  #include "subsegs.h"
      22  #include "symcat.h"
      23  #include "opcodes/or1k-desc.h"
      24  #include "opcodes/or1k-opc.h"
      25  #include "cgen.h"
      26  #include "elf/or1k.h"
      27  #include "dw2gencfi.h"
      28  
      29  /* Structure to hold all of the different components describing
      30     an individual instruction.  */
      31  
      32  typedef struct
      33  {
      34    const CGEN_INSN *     insn;
      35    const CGEN_INSN *     orig_insn;
      36    CGEN_FIELDS           fields;
      37  #if CGEN_INT_INSN_P
      38    CGEN_INSN_INT         buffer [1];
      39  #define INSN_VALUE(buf) (*(buf))
      40  #else
      41    unsigned char         buffer [CGEN_MAX_INSN_SIZE];
      42  #define INSN_VALUE(buf) (buf)
      43  #endif
      44    char *                addr;
      45    fragS *               frag;
      46    int                   num_fixups;
      47    fixS *                fixups [GAS_CGEN_MAX_FIXUPS];
      48    int                   indices [MAX_OPERAND_INSTANCES];
      49  }
      50  or1k_insn;
      51  
      52  const char comment_chars[]        = "#";
      53  const char line_comment_chars[]   = "#";
      54  const char line_separator_chars[] = ";";
      55  const char EXP_CHARS[]            = "eE";
      56  const char FLT_CHARS[]            = "dD";
      57  
      58  #define OR1K_SHORTOPTS "m:"
      59  const char * md_shortopts = OR1K_SHORTOPTS;
      60  
      61  struct option md_longopts[] =
      62  {
      63    {NULL, no_argument, NULL, 0}
      64  };
      65  size_t md_longopts_size = sizeof (md_longopts);
      66  
      67  unsigned long or1k_machine = 0; /* default */
      68  
      69  int
      70  md_parse_option (int c ATTRIBUTE_UNUSED, const char * arg ATTRIBUTE_UNUSED)
      71  {
      72    return 0;
      73  }
      74  
      75  void
      76  md_show_usage (FILE * stream ATTRIBUTE_UNUSED)
      77  {
      78  }
      79  
      80  static void
      81  ignore_pseudo (int val ATTRIBUTE_UNUSED)
      82  {
      83    discard_rest_of_line ();
      84  }
      85  
      86  static bool nodelay = false;
      87  static void
      88  s_nodelay (int val ATTRIBUTE_UNUSED)
      89  {
      90    nodelay = true;
      91  }
      92  
      93  const char or1k_comment_chars [] = ";#";
      94  
      95  /* The target specific pseudo-ops which we support.  */
      96  const pseudo_typeS md_pseudo_table[] =
      97  {
      98    { "align",    s_align_bytes,  0 },
      99    { "word",     cons,           4 },
     100    { "proc",     ignore_pseudo,  0 },
     101    { "endproc",  ignore_pseudo,  0 },
     102    { "nodelay",  s_nodelay,      0 },
     103    { NULL,       NULL,           0 }
     104  };
     105  
     106  
     107  void
     108  md_begin (void)
     109  {
     110    /* Initialize the `cgen' interface.  */
     111  
     112    /* Set the machine number and endian.  */
     113    gas_cgen_cpu_desc = or1k_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
     114                                                CGEN_CPU_OPEN_ENDIAN,
     115                                                CGEN_ENDIAN_BIG,
     116                                                CGEN_CPU_OPEN_END);
     117    or1k_cgen_init_asm (gas_cgen_cpu_desc);
     118  
     119    /* This is a callback from cgen to gas to parse operands.  */
     120    cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
     121  }
     122  
     123  void
     124  md_assemble (char * str)
     125  {
     126    static int last_insn_had_delay_slot = 0;
     127    or1k_insn insn;
     128    char *    errmsg;
     129  
     130    /* Initialize GAS's cgen interface for a new instruction.  */
     131    gas_cgen_init_parse ();
     132  
     133    insn.insn = or1k_cgen_assemble_insn
     134      (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
     135  
     136    if (!insn.insn)
     137      {
     138        as_bad ("%s", errmsg);
     139        return;
     140      }
     141  
     142    /* Doesn't really matter what we pass for RELAX_P here.  */
     143    gas_cgen_finish_insn (insn.insn, insn.buffer,
     144                          CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
     145  
     146    last_insn_had_delay_slot
     147      = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_DELAY_SLOT);
     148    (void) last_insn_had_delay_slot;
     149  }
     150  
     151  
     152  /* The syntax in the manual says constants begin with '#'.
     153     We just ignore it.  */
     154  
     155  void
     156  md_operand (expressionS * expressionP)
     157  {
     158    if (* input_line_pointer == '#')
     159      {
     160        input_line_pointer ++;
     161        expression (expressionP);
     162      }
     163  }
     164  
     165  valueT
     166  md_section_align (segT segment, valueT size)
     167  {
     168    int align = bfd_section_alignment (segment);
     169    return ((size + (1 << align) - 1) & -(1 << align));
     170  }
     171  
     172  symbolS *
     173  md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
     174  {
     175    return 0;
     176  }
     177  
     178  
     179  /* Interface to relax_segment.  */
     180  
     181  const relax_typeS md_relax_table[] =
     182  {
     183  /* The fields are:
     184     1) most positive reach of this state,
     185     2) most negative reach of this state,
     186     3) how many bytes this mode will add to the size of the current frag
     187     4) which index into the table to try if we can't fit into this one.  */
     188  
     189    /* The first entry must be unused because an `rlx_more' value of zero ends
     190       each list.  */
     191    {1, 1, 0, 0},
     192  
     193    /* The displacement used by GAS is from the end of the 4 byte insn,
     194       so we subtract 4 from the following.  */
     195    {(((1 << 25) - 1) << 2) - 4, -(1 << 25) - 4, 0, 0},
     196  };
     197  
     198  int
     199  md_estimate_size_before_relax (fragS * fragP, segT segment ATTRIBUTE_UNUSED)
     200  {
     201    return md_relax_table[fragP->fr_subtype].rlx_length;
     202  }
     203  
     204  /* *fragP has been relaxed to its final size, and now needs to have
     205     the bytes inside it modified to conform to the new size.
     206  
     207     Called after relaxation is finished.
     208     fragP->fr_type == rs_machine_dependent.
     209     fragP->fr_subtype is the subtype of what the address relaxed to.  */
     210  
     211  void
     212  md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
     213                   segT    sec  ATTRIBUTE_UNUSED,
     214                   fragS * fragP ATTRIBUTE_UNUSED)
     215  {
     216    /* FIXME */
     217  }
     218  
     219  
     220  /* Functions concerning relocs.  */
     221  
     222  /* The location from which a PC relative jump should be calculated,
     223     given a PC relative reloc.  */
     224  
     225  long
     226  md_pcrel_from_section (fixS * fixP, segT sec)
     227  {
     228    if (fixP->fx_addsy != (symbolS *) NULL
     229        && (! S_IS_DEFINED (fixP->fx_addsy)
     230            || (S_GET_SEGMENT (fixP->fx_addsy) != sec)
     231            || S_IS_EXTERNAL (fixP->fx_addsy)
     232            || S_IS_WEAK (fixP->fx_addsy)))
     233      {
     234          /* The symbol is undefined (or is defined but not in this section).
     235           Let the linker figure it out.  */
     236        return 0;
     237      }
     238  
     239    return fixP->fx_frag->fr_address + fixP->fx_where;
     240  }
     241  
     242  
     243  /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
     244     Returns BFD_RELOC_NONE if no reloc type can be found.
     245     *FIXP may be modified if desired.  */
     246  
     247  bfd_reloc_code_real_type
     248  md_cgen_lookup_reloc (const CGEN_INSN *    insn ATTRIBUTE_UNUSED,
     249                        const CGEN_OPERAND * operand,
     250                        fixS *               fixP)
     251  {
     252    if (fixP->fx_cgen.opinfo)
     253      return fixP->fx_cgen.opinfo;
     254  
     255    switch (operand->type)
     256      {
     257      case OR1K_OPERAND_DISP26:
     258        fixP->fx_pcrel = 1;
     259        return BFD_RELOC_OR1K_REL_26;
     260  
     261      default: /* avoid -Wall warning */
     262        return BFD_RELOC_NONE;
     263      }
     264  }
     265  
     266  /* Write a value out to the object file, using the appropriate endianness.  */
     267  
     268  void
     269  md_number_to_chars (char * buf, valueT val, int n)
     270  {
     271    number_to_chars_bigendian (buf, val, n);
     272  }
     273  
     274  /* Turn a string in input_line_pointer into a floating point constant of type
     275     type, and store the appropriate bytes in *litP.  The number of LITTLENUMS
     276     emitted is stored in *sizeP .  An error message is returned, or NULL on OK.  */
     277  
     278  const char *
     279  md_atof (int type, char * litP, int *  sizeP)
     280  {
     281    return ieee_md_atof (type, litP, sizeP, true);
     282  }
     283  
     284  bool
     285  or1k_fix_adjustable (fixS * fixP)
     286  {
     287    /* We need the symbol name for the VTABLE entries.  */
     288    if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
     289        || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
     290      return false;
     291  
     292    return true;
     293  }
     294  
     295  #define GOT_NAME "_GLOBAL_OFFSET_TABLE_"
     296  
     297  arelent *
     298  tc_gen_reloc (asection * section, fixS * fixp)
     299  {
     300    arelent *reloc;
     301    bfd_reloc_code_real_type code;
     302  
     303    reloc = XNEW (arelent);
     304  
     305    reloc->sym_ptr_ptr = XNEW (asymbol *);
     306    *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
     307    reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
     308  
     309    if (fixp->fx_pcrel)
     310      {
     311        if (section->use_rela_p)
     312          fixp->fx_offset -= md_pcrel_from_section (fixp, section);
     313        else
     314          fixp->fx_offset = reloc->address;
     315      }
     316    reloc->addend = fixp->fx_offset;
     317  
     318    code = fixp->fx_r_type;
     319    switch (code)
     320      {
     321      case BFD_RELOC_16:
     322        if (fixp->fx_pcrel)
     323          code = BFD_RELOC_16_PCREL;
     324        break;
     325  
     326      case BFD_RELOC_32:
     327        if (fixp->fx_pcrel)
     328          code = BFD_RELOC_32_PCREL;
     329        break;
     330  
     331      case BFD_RELOC_64:
     332        if (fixp->fx_pcrel)
     333          code = BFD_RELOC_64_PCREL;
     334        break;
     335  
     336      default:
     337        break;
     338      }
     339  
     340    reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
     341    if (reloc->howto == NULL)
     342      {
     343        as_bad_where (fixp->fx_file, fixp->fx_line,
     344                      _
     345                      ("cannot represent %s relocation in this object file format"),
     346                      bfd_get_reloc_code_name (code));
     347        return NULL;
     348      }
     349  
     350    return reloc;
     351  }
     352  
     353  void
     354  or1k_apply_fix (struct fix *f, valueT *t, segT s)
     355  {
     356    gas_cgen_md_apply_fix (f, t, s);
     357  
     358    switch (f->fx_r_type)
     359      {
     360      case BFD_RELOC_OR1K_TLS_GD_HI16:
     361      case BFD_RELOC_OR1K_TLS_GD_LO16:
     362      case BFD_RELOC_OR1K_TLS_GD_PG21:
     363      case BFD_RELOC_OR1K_TLS_GD_LO13:
     364      case BFD_RELOC_OR1K_TLS_LDM_HI16:
     365      case BFD_RELOC_OR1K_TLS_LDM_LO16:
     366      case BFD_RELOC_OR1K_TLS_LDM_PG21:
     367      case BFD_RELOC_OR1K_TLS_LDM_LO13:
     368      case BFD_RELOC_OR1K_TLS_LDO_HI16:
     369      case BFD_RELOC_OR1K_TLS_LDO_LO16:
     370      case BFD_RELOC_OR1K_TLS_IE_HI16:
     371      case BFD_RELOC_OR1K_TLS_IE_LO16:
     372      case BFD_RELOC_OR1K_TLS_IE_PG21:
     373      case BFD_RELOC_OR1K_TLS_IE_LO13:
     374      case BFD_RELOC_OR1K_TLS_LE_HI16:
     375      case BFD_RELOC_OR1K_TLS_LE_LO16:
     376        S_SET_THREAD_LOCAL (f->fx_addsy);
     377        break;
     378      default:
     379        break;
     380      }
     381  }
     382  
     383  void
     384  or1k_elf_final_processing (void)
     385  {
     386    if (nodelay)
     387      elf_elfheader (stdoutput)->e_flags |= EF_OR1K_NODELAY;
     388  }
     389  
     390  /* Standard calling conventions leave the CFA at SP on entry.  */
     391  
     392  void
     393  or1k_cfi_frame_initial_instructions (void)
     394  {
     395      cfi_add_CFA_def_cfa_register (1);
     396  }
     397