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