1 /* tc-wasm32.c -- Assembler code for the wasm32 target.
2 
3    Copyright (C) 2017-2021 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
md_estimate_size_before_relax(fragS * fragp ATTRIBUTE_UNUSED,asection * seg ATTRIBUTE_UNUSED)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
md_show_usage(FILE * stream)115 md_show_usage (FILE * stream)
116 {
117   fprintf (stream, _("wasm32 assembler options:\n"));
118 }
119 
120 /* No machine-dependent options.  */
121 
122 int
md_parse_option(int c ATTRIBUTE_UNUSED,const char * arg ATTRIBUTE_UNUSED)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 *
md_undefined_symbol(char * name ATTRIBUTE_UNUSED)131 md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
132 {
133   return NULL;
134 }
135 
136 /* IEEE little-endian floats.  */
137 
138 const char *
md_atof(int type,char * litP,int * sizeP)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
md_convert_frag(bfd * abfd ATTRIBUTE_UNUSED,asection * sec ATTRIBUTE_UNUSED,fragS * fragP ATTRIBUTE_UNUSED)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
md_begin(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
md_section_align(asection * seg,valueT addr)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
apply_full_field_fix(fixS * fixP,char * buf,bfd_vma val,int size)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
md_apply_fix(fixS * fixP,valueT * valP,segT seg ATTRIBUTE_UNUSED)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 *
skip_space(char * s)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
is_part_of_opcode(char c)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 *
extract_opcode(char * from,char * to,int limit)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
wasm32_put_long_uleb128(int bits,unsigned long value)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
wasm32_put_sleb128(long value)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
wasm32_put_uleb128(unsigned long value)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
wasm32_leb128(char ** line,int bits,int sign)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
wasm32_uleb128(char ** line,int bits)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
wasm32_sleb128(char ** line,int bits)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
wasm32_f32(char ** line)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
wasm32_f64(char ** line)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
wasm32_signature(char ** line)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
wasm32_operands(struct wasm32_opcode_s * opcode,char ** line)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
md_assemble(char * str)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
wasm32_force_relocation(fixS * f)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
wasm32_fix_adjustable(fixS * fixP)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 *
tc_gen_reloc(asection * sec ATTRIBUTE_UNUSED,fixS * fixp)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 }
822