Home | History | Annotate | Line # | Download | only in config
      1      1.1  christos /* tc-wasm32.c -- Assembler code for the wasm32 target.
      2      1.1  christos 
      3  1.1.1.6  christos    Copyright (C) 2017-2026 Free Software Foundation, Inc.
      4      1.1  christos 
      5      1.1  christos    This file is part of GAS, the GNU Assembler.
      6      1.1  christos 
      7      1.1  christos    GAS is free software; you can redistribute it and/or modify it
      8      1.1  christos    under the terms of the GNU General Public License as published by
      9      1.1  christos    the Free Software Foundation; either version 3, or (at your option)
     10      1.1  christos    any later version.
     11      1.1  christos 
     12      1.1  christos    GAS is distributed in the hope that it will be useful, but WITHOUT
     13      1.1  christos    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     14      1.1  christos    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     15      1.1  christos    License for more details.
     16      1.1  christos 
     17      1.1  christos    You should have received a copy of the GNU General Public License
     18      1.1  christos    along with GAS; see the file COPYING.  If not, write to the Free
     19      1.1  christos    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
     20      1.1  christos    02110-1301, USA.  */
     21      1.1  christos 
     22      1.1  christos #include "as.h"
     23      1.1  christos #include "safe-ctype.h"
     24      1.1  christos #include "subsegs.h"
     25      1.1  christos #include "dwarf2dbg.h"
     26      1.1  christos #include "dw2gencfi.h"
     27      1.1  christos #include "elf/wasm32.h"
     28      1.1  christos #include <float.h>
     29      1.1  christos 
     30      1.1  christos enum wasm_class
     31      1.1  christos {
     32      1.1  christos   wasm_typed,			/* a typed opcode: block, loop, or if */
     33      1.1  christos   wasm_special,			/* a special opcode: unreachable, nop, else,
     34      1.1  christos 				   or end */
     35      1.1  christos   wasm_break,			/* "br" */
     36      1.1  christos   wasm_break_if,		/* "br_if" opcode */
     37      1.1  christos   wasm_break_table,		/* "br_table" opcode */
     38      1.1  christos   wasm_return,			/* "return" opcode */
     39      1.1  christos   wasm_call,			/* "call" opcode */
     40      1.1  christos   wasm_call_indirect,		/* "call_indirect" opcode */
     41      1.1  christos   wasm_get_local,		/* "get_local" and "get_global" */
     42      1.1  christos   wasm_set_local,		/* "set_local" and "set_global" */
     43      1.1  christos   wasm_tee_local,		/* "tee_local" */
     44      1.1  christos   wasm_drop,			/* "drop" */
     45      1.1  christos   wasm_constant_i32,		/* "i32.const" */
     46      1.1  christos   wasm_constant_i64,		/* "i64.const" */
     47      1.1  christos   wasm_constant_f32,		/* "f32.const" */
     48      1.1  christos   wasm_constant_f64,		/* "f64.const" */
     49      1.1  christos   wasm_unary,			/* unary operators */
     50      1.1  christos   wasm_binary,			/* binary operators */
     51      1.1  christos   wasm_conv,			/* conversion operators */
     52      1.1  christos   wasm_load,			/* load operators */
     53      1.1  christos   wasm_store,			/* store operators */
     54      1.1  christos   wasm_select,			/* "select" */
     55      1.1  christos   wasm_relational,		/* comparison operators, except for "eqz" */
     56      1.1  christos   wasm_eqz,			/* "eqz" */
     57      1.1  christos   wasm_current_memory,		/* "current_memory" */
     58      1.1  christos   wasm_grow_memory,		/* "grow_memory" */
     59      1.1  christos   wasm_signature		/* "signature", which isn't an opcode */
     60      1.1  christos };
     61      1.1  christos 
     62      1.1  christos #define WASM_OPCODE(opcode, name, intype, outtype, class, signedness)   \
     63      1.1  christos   { name, wasm_ ## class, opcode },
     64      1.1  christos 
     65      1.1  christos struct wasm32_opcode_s
     66      1.1  christos {
     67      1.1  christos   const char *name;
     68      1.1  christos   enum wasm_class clas;
     69      1.1  christos   unsigned char opcode;
     70      1.1  christos } wasm32_opcodes[] =
     71      1.1  christos {
     72      1.1  christos #include "opcode/wasm.h"
     73      1.1  christos   {
     74      1.1  christos   NULL, 0, 0}
     75      1.1  christos };
     76      1.1  christos 
     77      1.1  christos const char comment_chars[] = ";#";
     78      1.1  christos const char line_comment_chars[] = ";#";
     79      1.1  christos const char line_separator_chars[] = "";
     80      1.1  christos 
     81  1.1.1.5  christos const char md_shortopts[] = "m:";
     82      1.1  christos 
     83      1.1  christos const char EXP_CHARS[] = "eE";
     84      1.1  christos const char FLT_CHARS[] = "dD";
     85      1.1  christos 
     86      1.1  christos /* The target specific pseudo-ops which we support.  */
     87      1.1  christos 
     88      1.1  christos const pseudo_typeS md_pseudo_table[] =
     89      1.1  christos {
     90      1.1  christos   {NULL, NULL, 0}
     91      1.1  christos };
     92      1.1  christos 
     93      1.1  christos /* Opcode hash table.  */
     94      1.1  christos 
     95  1.1.1.3  christos static htab_t wasm32_hash;
     96      1.1  christos 
     97  1.1.1.5  christos const struct option md_longopts[] =
     98      1.1  christos {
     99      1.1  christos   {NULL, no_argument, NULL, 0}
    100      1.1  christos };
    101      1.1  christos 
    102  1.1.1.5  christos const size_t md_longopts_size = sizeof (md_longopts);
    103      1.1  christos 
    104      1.1  christos /* No relaxation/no machine-dependent frags.  */
    105      1.1  christos 
    106      1.1  christos int
    107      1.1  christos md_estimate_size_before_relax (fragS * fragp ATTRIBUTE_UNUSED,
    108      1.1  christos 			       asection * seg ATTRIBUTE_UNUSED)
    109      1.1  christos {
    110      1.1  christos   abort ();
    111      1.1  christos   return 0;
    112      1.1  christos }
    113      1.1  christos 
    114      1.1  christos void
    115      1.1  christos md_show_usage (FILE * stream)
    116      1.1  christos {
    117      1.1  christos   fprintf (stream, _("wasm32 assembler options:\n"));
    118      1.1  christos }
    119      1.1  christos 
    120      1.1  christos /* No machine-dependent options.  */
    121      1.1  christos 
    122      1.1  christos int
    123      1.1  christos md_parse_option (int c ATTRIBUTE_UNUSED, const char *arg ATTRIBUTE_UNUSED)
    124      1.1  christos {
    125      1.1  christos   return 0;
    126      1.1  christos }
    127      1.1  christos 
    128      1.1  christos /* No machine-dependent symbols.  */
    129      1.1  christos 
    130      1.1  christos symbolS *
    131      1.1  christos md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
    132      1.1  christos {
    133      1.1  christos   return NULL;
    134      1.1  christos }
    135      1.1  christos 
    136      1.1  christos /* IEEE little-endian floats.  */
    137      1.1  christos 
    138      1.1  christos const char *
    139      1.1  christos md_atof (int type, char *litP, int *sizeP)
    140      1.1  christos {
    141  1.1.1.3  christos   return ieee_md_atof (type, litP, sizeP, false);
    142      1.1  christos }
    143      1.1  christos 
    144      1.1  christos /* No machine-dependent frags.  */
    145      1.1  christos 
    146      1.1  christos void
    147      1.1  christos md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
    148      1.1  christos 		 asection * sec ATTRIBUTE_UNUSED,
    149      1.1  christos 		 fragS * fragP ATTRIBUTE_UNUSED)
    150      1.1  christos {
    151      1.1  christos   abort ();
    152      1.1  christos }
    153      1.1  christos 
    154      1.1  christos /* Build opcode hash table, set some flags.  */
    155      1.1  christos 
    156      1.1  christos void
    157      1.1  christos md_begin (void)
    158      1.1  christos {
    159      1.1  christos   struct wasm32_opcode_s *opcode;
    160      1.1  christos 
    161  1.1.1.3  christos   wasm32_hash = str_htab_create ();
    162      1.1  christos 
    163      1.1  christos   /* Insert unique names into hash table.  This hash table then
    164      1.1  christos      provides a quick index to the first opcode with a particular name
    165      1.1  christos      in the opcode table.  */
    166      1.1  christos   for (opcode = wasm32_opcodes; opcode->name; opcode++)
    167  1.1.1.3  christos     str_hash_insert (wasm32_hash, opcode->name, opcode, 0);
    168      1.1  christos 
    169      1.1  christos   linkrelax = 0;
    170      1.1  christos   flag_sectname_subst = 1;
    171      1.1  christos   flag_no_comments = 0;
    172      1.1  christos   flag_keep_locals = 1;
    173      1.1  christos }
    174      1.1  christos 
    175      1.1  christos /* Do the normal thing for md_section_align.  */
    176      1.1  christos 
    177      1.1  christos valueT
    178      1.1  christos md_section_align (asection * seg, valueT addr)
    179      1.1  christos {
    180  1.1.1.2  christos   int align = bfd_section_alignment (seg);
    181  1.1.1.5  christos   return (addr + ((valueT) 1 << align) - 1) & -((valueT) 1 << align);
    182      1.1  christos }
    183      1.1  christos 
    184      1.1  christos /* Apply a fixup, return TRUE if done (and no relocation is
    185      1.1  christos    needed).  */
    186      1.1  christos 
    187  1.1.1.3  christos static bool
    188      1.1  christos apply_full_field_fix (fixS * fixP, char *buf, bfd_vma val, int size)
    189      1.1  christos {
    190      1.1  christos   if (fixP->fx_addsy != NULL || fixP->fx_pcrel)
    191      1.1  christos     {
    192      1.1  christos       fixP->fx_addnumber = val;
    193  1.1.1.3  christos       return false;
    194      1.1  christos     }
    195      1.1  christos 
    196      1.1  christos   number_to_chars_littleendian (buf, val, size);
    197  1.1.1.3  christos   return true;
    198      1.1  christos }
    199      1.1  christos 
    200      1.1  christos /* Apply a fixup (potentially PC-relative), set the fx_done flag if
    201      1.1  christos    done.  */
    202      1.1  christos 
    203      1.1  christos void
    204      1.1  christos md_apply_fix (fixS * fixP, valueT * valP, segT seg ATTRIBUTE_UNUSED)
    205      1.1  christos {
    206      1.1  christos   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
    207  1.1.1.5  christos   valueT val = *valP;
    208      1.1  christos 
    209      1.1  christos   if (fixP->fx_pcrel)
    210      1.1  christos     {
    211      1.1  christos       switch (fixP->fx_r_type)
    212      1.1  christos 	{
    213      1.1  christos 	default:
    214      1.1  christos 	  bfd_set_error (bfd_error_bad_value);
    215      1.1  christos 	  return;
    216      1.1  christos 
    217      1.1  christos 	case BFD_RELOC_32:
    218      1.1  christos 	  fixP->fx_r_type = BFD_RELOC_32_PCREL;
    219      1.1  christos 	  return;
    220      1.1  christos 	}
    221      1.1  christos     }
    222      1.1  christos 
    223      1.1  christos   if (apply_full_field_fix (fixP, buf, val, fixP->fx_size))
    224      1.1  christos     fixP->fx_done = 1;
    225      1.1  christos }
    226      1.1  christos 
    227      1.1  christos /* Skip whitespace.  */
    228      1.1  christos 
    229      1.1  christos static inline char *
    230      1.1  christos skip_space (char *s)
    231      1.1  christos {
    232  1.1.1.5  christos   while (is_whitespace (*s))
    233      1.1  christos     ++s;
    234      1.1  christos   return s;
    235      1.1  christos }
    236      1.1  christos 
    237      1.1  christos /* Allow '/' in opcodes.  */
    238      1.1  christos 
    239  1.1.1.3  christos static inline bool
    240      1.1  christos is_part_of_opcode (char c)
    241      1.1  christos {
    242      1.1  christos   return is_part_of_name (c) || (c == '/');
    243      1.1  christos }
    244      1.1  christos 
    245      1.1  christos /* Extract an opcode.  */
    246      1.1  christos 
    247      1.1  christos static char *
    248      1.1  christos extract_opcode (char *from, char *to, int limit)
    249      1.1  christos {
    250      1.1  christos   char *op_end;
    251      1.1  christos   int size = 0;
    252      1.1  christos 
    253      1.1  christos   /* Drop leading whitespace.  */
    254      1.1  christos   from = skip_space (from);
    255      1.1  christos   *to = 0;
    256      1.1  christos 
    257      1.1  christos   /* Find the op code end.  */
    258      1.1  christos   for (op_end = from; *op_end != 0 && is_part_of_opcode (*op_end);)
    259      1.1  christos     {
    260      1.1  christos       to[size++] = *op_end++;
    261      1.1  christos       if (size + 1 >= limit)
    262      1.1  christos 	break;
    263      1.1  christos     }
    264      1.1  christos 
    265      1.1  christos   to[size] = 0;
    266      1.1  christos   return op_end;
    267      1.1  christos }
    268      1.1  christos 
    269      1.1  christos /* Produce an unsigned LEB128 integer padded to the right number of
    270      1.1  christos    bytes to store BITS bits, of value VALUE.  Uses FRAG_APPEND_1_CHAR
    271      1.1  christos    to write.  */
    272      1.1  christos 
    273      1.1  christos static void
    274      1.1  christos wasm32_put_long_uleb128 (int bits, unsigned long value)
    275      1.1  christos {
    276      1.1  christos   unsigned char c;
    277      1.1  christos   int i = 0;
    278      1.1  christos 
    279      1.1  christos   do
    280      1.1  christos     {
    281      1.1  christos       c = value & 0x7f;
    282      1.1  christos       value >>= 7;
    283      1.1  christos       if (i < (bits - 1) / 7)
    284      1.1  christos 	c |= 0x80;
    285      1.1  christos       FRAG_APPEND_1_CHAR (c);
    286      1.1  christos     }
    287      1.1  christos   while (++i < (bits + 6) / 7);
    288      1.1  christos }
    289      1.1  christos 
    290      1.1  christos /* Produce a signed LEB128 integer, using FRAG_APPEND_1_CHAR to
    291      1.1  christos    write.  */
    292      1.1  christos 
    293      1.1  christos static void
    294      1.1  christos wasm32_put_sleb128 (long value)
    295      1.1  christos {
    296      1.1  christos   unsigned char c;
    297      1.1  christos   int more;
    298      1.1  christos 
    299      1.1  christos   do
    300      1.1  christos     {
    301      1.1  christos       c = (value & 0x7f);
    302      1.1  christos       value >>= 7;
    303      1.1  christos       more = !((((value == 0) && ((c & 0x40) == 0))
    304      1.1  christos 		|| ((value == -1) && ((c & 0x40) != 0))));
    305      1.1  christos       if (more)
    306      1.1  christos 	c |= 0x80;
    307      1.1  christos       FRAG_APPEND_1_CHAR (c);
    308      1.1  christos     }
    309      1.1  christos   while (more);
    310      1.1  christos }
    311      1.1  christos 
    312      1.1  christos /* Produce an unsigned LEB128 integer, using FRAG_APPEND_1_CHAR to
    313      1.1  christos    write.  */
    314      1.1  christos 
    315      1.1  christos static void
    316      1.1  christos wasm32_put_uleb128 (unsigned long value)
    317      1.1  christos {
    318      1.1  christos   unsigned char c;
    319      1.1  christos 
    320      1.1  christos   do
    321      1.1  christos     {
    322      1.1  christos       c = value & 0x7f;
    323      1.1  christos       value >>= 7;
    324      1.1  christos       if (value)
    325      1.1  christos 	c |= 0x80;
    326      1.1  christos       FRAG_APPEND_1_CHAR (c);
    327      1.1  christos     }
    328      1.1  christos   while (value);
    329      1.1  christos }
    330      1.1  christos 
    331      1.1  christos /* Read an integer expression.  Produce an LEB128-encoded integer if
    332      1.1  christos    it's a constant, a padded LEB128 plus a relocation if it's a
    333      1.1  christos    symbol, or a special relocation for <expr>@got, <expr>@gotcode, and
    334      1.1  christos    <expr>@plt{__sigchar_<signature>}.  */
    335      1.1  christos 
    336  1.1.1.3  christos static bool
    337      1.1  christos wasm32_leb128 (char **line, int bits, int sign)
    338      1.1  christos {
    339      1.1  christos   char *t = input_line_pointer;
    340      1.1  christos   char *str = *line;
    341      1.1  christos   char *str0 = str;
    342      1.1  christos   struct reloc_list *reloc;
    343      1.1  christos   expressionS ex;
    344      1.1  christos   int gotrel = 0;
    345      1.1  christos   int pltrel = 0;
    346      1.1  christos   int code = 0;
    347      1.1  christos   const char *relname;
    348      1.1  christos 
    349      1.1  christos   input_line_pointer = str;
    350      1.1  christos   expression (&ex);
    351      1.1  christos 
    352      1.1  christos   if (ex.X_op == O_constant && *input_line_pointer != '@')
    353      1.1  christos     {
    354      1.1  christos       long value = ex.X_add_number;
    355      1.1  christos 
    356      1.1  christos       str = input_line_pointer;
    357      1.1  christos       str = skip_space (str);
    358      1.1  christos       *line = str;
    359      1.1  christos       if (sign)
    360      1.1  christos 	wasm32_put_sleb128 (value);
    361      1.1  christos       else
    362      1.1  christos 	{
    363      1.1  christos 	  if (value < 0)
    364      1.1  christos 	    as_bad (_("unexpected negative constant"));
    365      1.1  christos 	  wasm32_put_uleb128 (value);
    366      1.1  christos 	}
    367      1.1  christos       input_line_pointer = t;
    368      1.1  christos       return str != str0;
    369      1.1  christos     }
    370      1.1  christos 
    371  1.1.1.5  christos   reloc = notes_alloc (sizeof (*reloc));
    372      1.1  christos   reloc->u.a.offset_sym = expr_build_dot ();
    373      1.1  christos   if (ex.X_op == O_symbol)
    374      1.1  christos     {
    375      1.1  christos       reloc->u.a.sym = ex.X_add_symbol;
    376      1.1  christos       reloc->u.a.addend = ex.X_add_number;
    377      1.1  christos     }
    378      1.1  christos   else
    379      1.1  christos     {
    380      1.1  christos       reloc->u.a.sym = make_expr_symbol (&ex);
    381      1.1  christos       reloc->u.a.addend = 0;
    382      1.1  christos     }
    383      1.1  christos   /* i32.const fpointer@gotcode */
    384  1.1.1.3  christos   if (startswith (input_line_pointer, "@gotcode"))
    385      1.1  christos     {
    386      1.1  christos       gotrel = 1;
    387      1.1  christos       code = 1;
    388      1.1  christos       input_line_pointer += 8;
    389      1.1  christos     }
    390      1.1  christos   /* i32.const data@got */
    391  1.1.1.3  christos   else if (startswith (input_line_pointer, "@got"))
    392      1.1  christos     {
    393      1.1  christos       gotrel = 1;
    394      1.1  christos       input_line_pointer += 4;
    395      1.1  christos     }
    396      1.1  christos   /* call f@plt{__sigchar_FiiiiE} */
    397  1.1.1.3  christos   else if (startswith (input_line_pointer, "@plt"))
    398      1.1  christos     {
    399      1.1  christos       char *end_of_sig;
    400      1.1  christos 
    401      1.1  christos       pltrel = 1;
    402      1.1  christos       code = 1;
    403      1.1  christos       input_line_pointer += 4;
    404      1.1  christos 
    405  1.1.1.3  christos       if (startswith (input_line_pointer, "{")
    406      1.1  christos           && (end_of_sig = strchr (input_line_pointer, '}')))
    407      1.1  christos 	{
    408      1.1  christos 	  char *signature;
    409      1.1  christos 	  struct reloc_list *reloc2;
    410      1.1  christos 	  size_t siglength = end_of_sig - (input_line_pointer + 1);
    411      1.1  christos 
    412      1.1  christos 	  signature = strndup (input_line_pointer + 1, siglength);
    413      1.1  christos 
    414  1.1.1.5  christos 	  reloc2 = notes_alloc (sizeof (*reloc2));
    415      1.1  christos 	  reloc2->u.a.offset_sym = expr_build_dot ();
    416      1.1  christos 	  reloc2->u.a.sym = symbol_find_or_make (signature);
    417      1.1  christos 	  reloc2->u.a.addend = 0;
    418      1.1  christos 	  reloc2->u.a.howto = bfd_reloc_name_lookup
    419      1.1  christos 	    (stdoutput, "R_WASM32_PLT_SIG");
    420      1.1  christos 	  reloc2->next = reloc_list;
    421      1.1  christos 	  reloc_list = reloc2;
    422      1.1  christos 	  input_line_pointer = end_of_sig + 1;
    423      1.1  christos 	}
    424      1.1  christos       else
    425      1.1  christos 	{
    426      1.1  christos 	  as_bad (_("no function type on PLT reloc"));
    427      1.1  christos 	}
    428      1.1  christos     }
    429      1.1  christos 
    430      1.1  christos   if (gotrel && code)
    431      1.1  christos     relname = "R_WASM32_LEB128_GOT_CODE";
    432      1.1  christos   else if (gotrel)
    433      1.1  christos     relname = "R_WASM32_LEB128_GOT";
    434      1.1  christos   else if (pltrel)
    435      1.1  christos     relname = "R_WASM32_LEB128_PLT";
    436      1.1  christos   else
    437      1.1  christos     relname = "R_WASM32_LEB128";
    438      1.1  christos 
    439      1.1  christos   reloc->u.a.howto = bfd_reloc_name_lookup (stdoutput, relname);
    440      1.1  christos   if (!reloc->u.a.howto)
    441      1.1  christos     as_bad (_("couldn't find relocation to use"));
    442      1.1  christos   reloc->file = as_where (&reloc->line);
    443      1.1  christos   reloc->next = reloc_list;
    444      1.1  christos   reloc_list = reloc;
    445      1.1  christos 
    446      1.1  christos   str = input_line_pointer;
    447      1.1  christos   str = skip_space (str);
    448      1.1  christos   *line = str;
    449      1.1  christos   wasm32_put_long_uleb128 (bits, 0);
    450      1.1  christos   input_line_pointer = t;
    451      1.1  christos 
    452      1.1  christos   return str != str0;
    453      1.1  christos }
    454      1.1  christos 
    455      1.1  christos /* Read an integer expression and produce an unsigned LEB128 integer,
    456      1.1  christos    or a relocation for it.  */
    457      1.1  christos 
    458  1.1.1.3  christos static bool
    459      1.1  christos wasm32_uleb128 (char **line, int bits)
    460      1.1  christos {
    461      1.1  christos   return wasm32_leb128 (line, bits, 0);
    462      1.1  christos }
    463      1.1  christos 
    464      1.1  christos /* Read an integer expression and produce a signed LEB128 integer, or
    465      1.1  christos    a relocation for it.  */
    466      1.1  christos 
    467  1.1.1.3  christos static bool
    468      1.1  christos wasm32_sleb128 (char **line, int bits)
    469      1.1  christos {
    470      1.1  christos   return wasm32_leb128 (line, bits, 1);
    471      1.1  christos }
    472      1.1  christos 
    473      1.1  christos /* Read an f32.  (Like float_cons ('f')).  */
    474      1.1  christos 
    475      1.1  christos static void
    476      1.1  christos wasm32_f32 (char **line)
    477      1.1  christos {
    478      1.1  christos   char *t = input_line_pointer;
    479      1.1  christos 
    480      1.1  christos   input_line_pointer = *line;
    481      1.1  christos   float_cons ('f');
    482      1.1  christos   *line = input_line_pointer;
    483      1.1  christos   input_line_pointer = t;
    484      1.1  christos }
    485      1.1  christos 
    486      1.1  christos /* Read an f64.  (Like float_cons ('d')).  */
    487      1.1  christos 
    488      1.1  christos static void
    489      1.1  christos wasm32_f64 (char **line)
    490      1.1  christos {
    491      1.1  christos   char *t = input_line_pointer;
    492      1.1  christos 
    493      1.1  christos   input_line_pointer = *line;
    494      1.1  christos   float_cons ('d');
    495      1.1  christos   *line = input_line_pointer;
    496      1.1  christos   input_line_pointer = t;
    497      1.1  christos }
    498      1.1  christos 
    499      1.1  christos /* Assemble a signature from LINE, replacing it with the new input
    500      1.1  christos    pointer.  Signatures are simple expressions matching the regexp
    501      1.1  christos    F[ilfd]*v?E, and interpreted as though they were C++-mangled
    502      1.1  christos    function types on a 64-bit machine. */
    503      1.1  christos 
    504      1.1  christos static void
    505      1.1  christos wasm32_signature (char **line)
    506      1.1  christos {
    507      1.1  christos   unsigned long count = 0;
    508      1.1  christos   char *str = *line;
    509      1.1  christos   char *ostr;
    510      1.1  christos   char *result;
    511      1.1  christos 
    512      1.1  christos   if (*str++ != 'F')
    513      1.1  christos     as_bad (_("Not a function type"));
    514      1.1  christos   result = str;
    515      1.1  christos   ostr = str + 1;
    516      1.1  christos   str++;
    517      1.1  christos 
    518      1.1  christos   while (*str != 'E')
    519      1.1  christos     {
    520      1.1  christos       switch (*str++)
    521      1.1  christos 	{
    522      1.1  christos 	case 'i':
    523      1.1  christos 	case 'l':
    524      1.1  christos 	case 'f':
    525      1.1  christos 	case 'd':
    526      1.1  christos 	  count++;
    527      1.1  christos 	  break;
    528      1.1  christos 	default:
    529      1.1  christos 	  as_bad (_("Unknown type %c\n"), str[-1]);
    530      1.1  christos 	}
    531      1.1  christos     }
    532      1.1  christos   wasm32_put_uleb128 (count);
    533      1.1  christos   str = ostr;
    534      1.1  christos   while (*str != 'E')
    535      1.1  christos     {
    536      1.1  christos       switch (*str++)
    537      1.1  christos 	{
    538      1.1  christos 	case 'i':
    539      1.1  christos 	  FRAG_APPEND_1_CHAR (BLOCK_TYPE_I32);
    540      1.1  christos 	  break;
    541      1.1  christos 	case 'l':
    542      1.1  christos 	  FRAG_APPEND_1_CHAR (BLOCK_TYPE_I64);
    543      1.1  christos 	  break;
    544      1.1  christos 	case 'f':
    545      1.1  christos 	  FRAG_APPEND_1_CHAR (BLOCK_TYPE_F32);
    546      1.1  christos 	  break;
    547      1.1  christos 	case 'd':
    548      1.1  christos 	  FRAG_APPEND_1_CHAR (BLOCK_TYPE_F64);
    549      1.1  christos 	  break;
    550      1.1  christos 	default:
    551      1.1  christos 	  as_bad (_("Unknown type"));
    552      1.1  christos 	}
    553      1.1  christos     }
    554      1.1  christos   str++;
    555      1.1  christos   switch (*result)
    556      1.1  christos     {
    557      1.1  christos     case 'v':
    558      1.1  christos       FRAG_APPEND_1_CHAR (0x00);	/* no return value */
    559      1.1  christos       break;
    560      1.1  christos     case 'i':
    561      1.1  christos       FRAG_APPEND_1_CHAR (0x01);	/* one return value */
    562      1.1  christos       FRAG_APPEND_1_CHAR (BLOCK_TYPE_I32);
    563      1.1  christos       break;
    564      1.1  christos     case 'l':
    565      1.1  christos       FRAG_APPEND_1_CHAR (0x01);	/* one return value */
    566      1.1  christos       FRAG_APPEND_1_CHAR (BLOCK_TYPE_I64);
    567      1.1  christos       break;
    568      1.1  christos     case 'f':
    569      1.1  christos       FRAG_APPEND_1_CHAR (0x01);	/* one return value */
    570      1.1  christos       FRAG_APPEND_1_CHAR (BLOCK_TYPE_F32);
    571      1.1  christos       break;
    572      1.1  christos     case 'd':
    573      1.1  christos       FRAG_APPEND_1_CHAR (0x01);	/* one return value */
    574      1.1  christos       FRAG_APPEND_1_CHAR (BLOCK_TYPE_F64);
    575      1.1  christos       break;
    576      1.1  christos     default:
    577      1.1  christos       as_bad (_("Unknown type"));
    578      1.1  christos     }
    579      1.1  christos   *line = str;
    580      1.1  christos }
    581      1.1  christos 
    582      1.1  christos /* Main operands function.  Read the operands for OPCODE from LINE,
    583      1.1  christos    replacing it with the new input pointer.  */
    584      1.1  christos 
    585      1.1  christos static void
    586      1.1  christos wasm32_operands (struct wasm32_opcode_s *opcode, char **line)
    587      1.1  christos {
    588      1.1  christos   char *str = *line;
    589      1.1  christos   unsigned long block_type = 0;
    590      1.1  christos 
    591      1.1  christos   FRAG_APPEND_1_CHAR (opcode->opcode);
    592      1.1  christos   str = skip_space (str);
    593      1.1  christos   if (str[0] == '[')
    594      1.1  christos     {
    595      1.1  christos       if (opcode->clas == wasm_typed)
    596      1.1  christos 	{
    597      1.1  christos 	  str++;
    598      1.1  christos 	  block_type = BLOCK_TYPE_NONE;
    599      1.1  christos 	  if (str[0] != ']')
    600      1.1  christos 	    {
    601      1.1  christos 	      str = skip_space (str);
    602      1.1  christos 	      switch (str[0])
    603      1.1  christos 		{
    604      1.1  christos 		case 'i':
    605      1.1  christos 		  block_type = BLOCK_TYPE_I32;
    606      1.1  christos 		  str++;
    607      1.1  christos 		  break;
    608      1.1  christos 		case 'l':
    609      1.1  christos 		  block_type = BLOCK_TYPE_I64;
    610      1.1  christos 		  str++;
    611      1.1  christos 		  break;
    612      1.1  christos 		case 'f':
    613      1.1  christos 		  block_type = BLOCK_TYPE_F32;
    614      1.1  christos 		  str++;
    615      1.1  christos 		  break;
    616      1.1  christos 		case 'd':
    617      1.1  christos 		  block_type = BLOCK_TYPE_F64;
    618      1.1  christos 		  str++;
    619      1.1  christos 		  break;
    620      1.1  christos 		}
    621      1.1  christos 	      str = skip_space (str);
    622      1.1  christos 	      if (str[0] == ']')
    623      1.1  christos 		str++;
    624      1.1  christos 	      else
    625      1.1  christos 		as_bad (_("only single block types allowed"));
    626      1.1  christos 	      str = skip_space (str);
    627      1.1  christos 	    }
    628      1.1  christos 	  else
    629      1.1  christos 	    {
    630      1.1  christos 	      str++;
    631      1.1  christos 	      str = skip_space (str);
    632      1.1  christos 	    }
    633      1.1  christos 	}
    634      1.1  christos       else
    635      1.1  christos 	as_bad (_("instruction does not take a block type"));
    636      1.1  christos     }
    637      1.1  christos 
    638      1.1  christos   switch (opcode->clas)
    639      1.1  christos     {
    640      1.1  christos     case wasm_drop:
    641      1.1  christos     case wasm_special:
    642      1.1  christos     case wasm_binary:
    643      1.1  christos     case wasm_unary:
    644      1.1  christos     case wasm_relational:
    645      1.1  christos     case wasm_select:
    646      1.1  christos     case wasm_eqz:
    647      1.1  christos     case wasm_conv:
    648      1.1  christos     case wasm_return:
    649      1.1  christos       break;
    650      1.1  christos     case wasm_typed:
    651      1.1  christos       if (block_type == 0)
    652      1.1  christos 	as_bad (_("missing block type"));
    653      1.1  christos       FRAG_APPEND_1_CHAR (block_type);
    654      1.1  christos       break;
    655      1.1  christos     case wasm_store:
    656      1.1  christos     case wasm_load:
    657      1.1  christos       if (str[0] == 'a' && str[1] == '=')
    658      1.1  christos 	{
    659      1.1  christos 	  str += 2;
    660      1.1  christos 	  if (!wasm32_uleb128 (&str, 32))
    661      1.1  christos 	    as_bad (_("missing alignment hint"));
    662      1.1  christos 	}
    663      1.1  christos       else
    664      1.1  christos 	{
    665      1.1  christos 	  as_bad (_("missing alignment hint"));
    666      1.1  christos 	}
    667      1.1  christos       str = skip_space (str);
    668      1.1  christos       if (!wasm32_uleb128 (&str, 32))
    669      1.1  christos 	as_bad (_("missing offset"));
    670      1.1  christos       break;
    671      1.1  christos     case wasm_set_local:
    672      1.1  christos     case wasm_get_local:
    673      1.1  christos     case wasm_tee_local:
    674      1.1  christos       if (!wasm32_uleb128 (&str, 32))
    675      1.1  christos 	as_bad (_("missing local index"));
    676      1.1  christos       break;
    677      1.1  christos     case wasm_break:
    678      1.1  christos     case wasm_break_if:
    679      1.1  christos       if (!wasm32_uleb128 (&str, 32))
    680      1.1  christos 	as_bad (_("missing break count"));
    681      1.1  christos       break;
    682      1.1  christos     case wasm_current_memory:
    683      1.1  christos     case wasm_grow_memory:
    684      1.1  christos       if (!wasm32_uleb128 (&str, 32))
    685      1.1  christos 	as_bad (_("missing reserved current_memory/grow_memory argument"));
    686      1.1  christos       break;
    687      1.1  christos     case wasm_call:
    688      1.1  christos       if (!wasm32_uleb128 (&str, 32))
    689      1.1  christos 	as_bad (_("missing call argument"));
    690      1.1  christos       break;
    691      1.1  christos     case wasm_call_indirect:
    692      1.1  christos       if (!wasm32_uleb128 (&str, 32))
    693      1.1  christos 	as_bad (_("missing call signature"));
    694      1.1  christos       if (!wasm32_uleb128 (&str, 32))
    695      1.1  christos 	as_bad (_("missing table index"));
    696      1.1  christos       break;
    697      1.1  christos     case wasm_constant_i32:
    698      1.1  christos       wasm32_sleb128 (&str, 32);
    699      1.1  christos       break;
    700      1.1  christos     case wasm_constant_i64:
    701      1.1  christos       wasm32_sleb128 (&str, 64);
    702      1.1  christos       break;
    703      1.1  christos     case wasm_constant_f32:
    704      1.1  christos       wasm32_f32 (&str);
    705      1.1  christos       return;
    706      1.1  christos     case wasm_constant_f64:
    707      1.1  christos       wasm32_f64 (&str);
    708      1.1  christos       return;
    709      1.1  christos     case wasm_break_table:
    710      1.1  christos       {
    711      1.1  christos 	do
    712      1.1  christos 	  {
    713      1.1  christos 	    wasm32_uleb128 (&str, 32);
    714      1.1  christos 	    str = skip_space (str);
    715      1.1  christos 	  }
    716      1.1  christos 	while (str[0]);
    717      1.1  christos 
    718      1.1  christos 	break;
    719      1.1  christos       }
    720      1.1  christos     case wasm_signature:
    721      1.1  christos       wasm32_signature (&str);
    722      1.1  christos     }
    723      1.1  christos   str = skip_space (str);
    724      1.1  christos 
    725      1.1  christos   if (*str)
    726      1.1  christos     as_bad (_("junk at end of line, first unrecognized character is `%c'"),
    727      1.1  christos 	    *str);
    728      1.1  christos 
    729      1.1  christos   *line = str;
    730      1.1  christos 
    731      1.1  christos   return;
    732      1.1  christos }
    733      1.1  christos 
    734      1.1  christos /* Main assembly function.  Find the opcode and call
    735      1.1  christos    wasm32_operands().  */
    736      1.1  christos 
    737      1.1  christos void
    738      1.1  christos md_assemble (char *str)
    739      1.1  christos {
    740      1.1  christos   char op[32];
    741      1.1  christos   char *t;
    742      1.1  christos   struct wasm32_opcode_s *opcode;
    743      1.1  christos 
    744      1.1  christos   str = skip_space (extract_opcode (str, op, sizeof (op)));
    745      1.1  christos 
    746      1.1  christos   if (!op[0])
    747      1.1  christos     as_bad (_("can't find opcode "));
    748      1.1  christos 
    749  1.1.1.5  christos   opcode = str_hash_find (wasm32_hash, op);
    750      1.1  christos 
    751      1.1  christos   if (opcode == NULL)
    752      1.1  christos     {
    753      1.1  christos       as_bad (_("unknown opcode `%s'"), op);
    754      1.1  christos       return;
    755      1.1  christos     }
    756      1.1  christos 
    757      1.1  christos   dwarf2_emit_insn (0);
    758      1.1  christos 
    759      1.1  christos   t = input_line_pointer;
    760      1.1  christos   wasm32_operands (opcode, &str);
    761      1.1  christos   input_line_pointer = t;
    762      1.1  christos }
    763      1.1  christos 
    764      1.1  christos /* Don't replace PLT/GOT relocations with section symbols, so they
    765      1.1  christos    don't get an addend.  */
    766      1.1  christos 
    767      1.1  christos int
    768      1.1  christos wasm32_force_relocation (fixS * f)
    769      1.1  christos {
    770      1.1  christos   if (f->fx_r_type == BFD_RELOC_WASM32_LEB128_PLT
    771      1.1  christos       || f->fx_r_type == BFD_RELOC_WASM32_LEB128_GOT)
    772      1.1  christos     return 1;
    773      1.1  christos 
    774      1.1  christos   return 0;
    775      1.1  christos }
    776      1.1  christos 
    777      1.1  christos /* Don't replace PLT/GOT relocations with section symbols, so they
    778      1.1  christos    don't get an addend.  */
    779      1.1  christos 
    780  1.1.1.3  christos bool
    781      1.1  christos wasm32_fix_adjustable (fixS * fixP)
    782      1.1  christos {
    783      1.1  christos   if (fixP->fx_addsy == NULL)
    784  1.1.1.3  christos     return true;
    785      1.1  christos 
    786      1.1  christos   if (fixP->fx_r_type == BFD_RELOC_WASM32_LEB128_PLT
    787      1.1  christos       || fixP->fx_r_type == BFD_RELOC_WASM32_LEB128_GOT)
    788  1.1.1.3  christos     return false;
    789      1.1  christos 
    790  1.1.1.3  christos   return true;
    791      1.1  christos }
    792      1.1  christos 
    793      1.1  christos /* Generate a reloc for FIXP.  */
    794      1.1  christos 
    795      1.1  christos arelent *
    796      1.1  christos tc_gen_reloc (asection * sec ATTRIBUTE_UNUSED, fixS * fixp)
    797      1.1  christos {
    798      1.1  christos   arelent *reloc;
    799      1.1  christos 
    800  1.1.1.5  christos   reloc = notes_alloc (sizeof (arelent));
    801  1.1.1.5  christos   reloc->sym_ptr_ptr = notes_alloc (sizeof (asymbol *));
    802      1.1  christos   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
    803      1.1  christos   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
    804      1.1  christos 
    805      1.1  christos   /* Make sure none of our internal relocations make it this far.
    806      1.1  christos      They'd better have been fully resolved by this point.  */
    807      1.1  christos   gas_assert ((int) fixp->fx_r_type > 0);
    808      1.1  christos 
    809      1.1  christos   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
    810      1.1  christos   if (reloc->howto == NULL)
    811      1.1  christos     {
    812      1.1  christos       as_bad_where (fixp->fx_file, fixp->fx_line,
    813      1.1  christos 		    _("cannot represent `%s' relocation in object file"),
    814      1.1  christos 		    bfd_get_reloc_code_name (fixp->fx_r_type));
    815      1.1  christos       return NULL;
    816      1.1  christos     }
    817      1.1  christos 
    818      1.1  christos   reloc->addend = fixp->fx_offset;
    819      1.1  christos 
    820      1.1  christos   return reloc;
    821      1.1  christos }
    822