[PATCH 40/57][Arm][OBJDUMP] Add support for MVE instructions: vdup, veor, vfma, vfms...
[binutils-gdb.git] / gas / config / tc-wasm32.c
blobc57611c5a7d79cbe4a5a3bcb2512cbed947acb52
1 /* tc-wasm32.c -- Assembler code for the wasm32 target.
3 Copyright (C) 2017-2019 Free Software Foundation, Inc.
5 This file is part of GAS, the GNU Assembler.
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.
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.
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. */
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>
30 enum wasm_class
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 */
62 #define WASM_OPCODE(opcode, name, intype, outtype, class, signedness) \
63 { name, wasm_ ## class, opcode },
65 struct wasm32_opcode_s
67 const char *name;
68 enum wasm_class clas;
69 unsigned char opcode;
70 } wasm32_opcodes[] =
72 #include "opcode/wasm.h"
74 NULL, 0, 0}
77 const char comment_chars[] = ";#";
78 const char line_comment_chars[] = ";#";
79 const char line_separator_chars[] = "";
81 const char *md_shortopts = "m:";
83 const char EXP_CHARS[] = "eE";
84 const char FLT_CHARS[] = "dD";
86 /* The target specific pseudo-ops which we support. */
88 const pseudo_typeS md_pseudo_table[] =
90 {NULL, NULL, 0}
93 /* Opcode hash table. */
95 static struct hash_control *wasm32_hash;
97 struct option md_longopts[] =
99 {NULL, no_argument, NULL, 0}
102 size_t md_longopts_size = sizeof (md_longopts);
104 /* No relaxation/no machine-dependent frags. */
107 md_estimate_size_before_relax (fragS * fragp ATTRIBUTE_UNUSED,
108 asection * seg ATTRIBUTE_UNUSED)
110 abort ();
111 return 0;
114 void
115 md_show_usage (FILE * stream)
117 fprintf (stream, _("wasm32 assembler options:\n"));
120 /* No machine-dependent options. */
123 md_parse_option (int c ATTRIBUTE_UNUSED, const char *arg ATTRIBUTE_UNUSED)
125 return 0;
128 /* No machine-dependent symbols. */
130 symbolS *
131 md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
133 return NULL;
136 /* IEEE little-endian floats. */
138 const char *
139 md_atof (int type, char *litP, int *sizeP)
141 return ieee_md_atof (type, litP, sizeP, FALSE);
144 /* No machine-dependent frags. */
146 void
147 md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
148 asection * sec ATTRIBUTE_UNUSED,
149 fragS * fragP ATTRIBUTE_UNUSED)
151 abort ();
154 /* Build opcode hash table, set some flags. */
156 void
157 md_begin (void)
159 struct wasm32_opcode_s *opcode;
161 wasm32_hash = hash_new ();
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 hash_insert (wasm32_hash, opcode->name, (char *) opcode);
169 linkrelax = 0;
170 flag_sectname_subst = 1;
171 flag_no_comments = 0;
172 flag_keep_locals = 1;
175 /* Do the normal thing for md_section_align. */
177 valueT
178 md_section_align (asection * seg, valueT addr)
180 int align = bfd_get_section_alignment (stdoutput, seg);
181 return ((addr + (1 << align) - 1) & -(1 << align));
184 /* Apply a fixup, return TRUE if done (and no relocation is
185 needed). */
187 static bfd_boolean
188 apply_full_field_fix (fixS * fixP, char *buf, bfd_vma val, int size)
190 if (fixP->fx_addsy != NULL || fixP->fx_pcrel)
192 fixP->fx_addnumber = val;
193 return FALSE;
196 number_to_chars_littleendian (buf, val, size);
197 return TRUE;
200 /* Apply a fixup (potentially PC-relative), set the fx_done flag if
201 done. */
203 void
204 md_apply_fix (fixS * fixP, valueT * valP, segT seg ATTRIBUTE_UNUSED)
206 char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
207 long val = (long) *valP;
209 if (fixP->fx_pcrel)
211 switch (fixP->fx_r_type)
213 default:
214 bfd_set_error (bfd_error_bad_value);
215 return;
217 case BFD_RELOC_32:
218 fixP->fx_r_type = BFD_RELOC_32_PCREL;
219 return;
223 if (apply_full_field_fix (fixP, buf, val, fixP->fx_size))
224 fixP->fx_done = 1;
227 /* Skip whitespace. */
229 static inline char *
230 skip_space (char *s)
232 while (*s == ' ' || *s == '\t')
233 ++s;
234 return s;
237 /* Allow '/' in opcodes. */
239 static inline bfd_boolean
240 is_part_of_opcode (char c)
242 return is_part_of_name (c) || (c == '/');
245 /* Extract an opcode. */
247 static char *
248 extract_opcode (char *from, char *to, int limit)
250 char *op_end;
251 int size = 0;
253 /* Drop leading whitespace. */
254 from = skip_space (from);
255 *to = 0;
257 /* Find the op code end. */
258 for (op_end = from; *op_end != 0 && is_part_of_opcode (*op_end);)
260 to[size++] = *op_end++;
261 if (size + 1 >= limit)
262 break;
265 to[size] = 0;
266 return op_end;
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. */
273 static void
274 wasm32_put_long_uleb128 (int bits, unsigned long value)
276 unsigned char c;
277 int i = 0;
281 c = value & 0x7f;
282 value >>= 7;
283 if (i < (bits - 1) / 7)
284 c |= 0x80;
285 FRAG_APPEND_1_CHAR (c);
287 while (++i < (bits + 6) / 7);
290 /* Produce a signed LEB128 integer, using FRAG_APPEND_1_CHAR to
291 write. */
293 static void
294 wasm32_put_sleb128 (long value)
296 unsigned char c;
297 int more;
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);
309 while (more);
312 /* Produce an unsigned LEB128 integer, using FRAG_APPEND_1_CHAR to
313 write. */
315 static void
316 wasm32_put_uleb128 (unsigned long value)
318 unsigned char c;
322 c = value & 0x7f;
323 value >>= 7;
324 if (value)
325 c |= 0x80;
326 FRAG_APPEND_1_CHAR (c);
328 while (value);
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>}. */
336 static bfd_boolean
337 wasm32_leb128 (char **line, int bits, int sign)
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;
349 input_line_pointer = str;
350 expression (&ex);
352 if (ex.X_op == O_constant && *input_line_pointer != '@')
354 long value = ex.X_add_number;
356 str = input_line_pointer;
357 str = skip_space (str);
358 *line = str;
359 if (sign)
360 wasm32_put_sleb128 (value);
361 else
363 if (value < 0)
364 as_bad (_("unexpected negative constant"));
365 wasm32_put_uleb128 (value);
367 input_line_pointer = t;
368 return str != str0;
371 reloc = XNEW (struct reloc_list);
372 reloc->u.a.offset_sym = expr_build_dot ();
373 if (ex.X_op == O_symbol)
375 reloc->u.a.sym = ex.X_add_symbol;
376 reloc->u.a.addend = ex.X_add_number;
378 else
380 reloc->u.a.sym = make_expr_symbol (&ex);
381 reloc->u.a.addend = 0;
383 /* i32.const fpointer@gotcode */
384 if (strncmp (input_line_pointer, "@gotcode", 8) == 0)
386 gotrel = 1;
387 code = 1;
388 input_line_pointer += 8;
390 /* i32.const data@got */
391 else if (strncmp (input_line_pointer, "@got", 4) == 0)
393 gotrel = 1;
394 input_line_pointer += 4;
396 /* call f@plt{__sigchar_FiiiiE} */
397 else if (strncmp (input_line_pointer, "@plt", 4) == 0)
399 char *end_of_sig;
401 pltrel = 1;
402 code = 1;
403 input_line_pointer += 4;
405 if (strncmp (input_line_pointer, "{", 1) == 0
406 && (end_of_sig = strchr (input_line_pointer, '}')))
408 char *signature;
409 struct reloc_list *reloc2;
410 size_t siglength = end_of_sig - (input_line_pointer + 1);
412 signature = strndup (input_line_pointer + 1, siglength);
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;
424 else
426 as_bad (_("no function type on PLT reloc"));
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";
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;
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;
452 return str != str0;
455 /* Read an integer expression and produce an unsigned LEB128 integer,
456 or a relocation for it. */
458 static bfd_boolean
459 wasm32_uleb128 (char **line, int bits)
461 return wasm32_leb128 (line, bits, 0);
464 /* Read an integer expression and produce a signed LEB128 integer, or
465 a relocation for it. */
467 static bfd_boolean
468 wasm32_sleb128 (char **line, int bits)
470 return wasm32_leb128 (line, bits, 1);
473 /* Read an f32. (Like float_cons ('f')). */
475 static void
476 wasm32_f32 (char **line)
478 char *t = input_line_pointer;
480 input_line_pointer = *line;
481 float_cons ('f');
482 *line = input_line_pointer;
483 input_line_pointer = t;
486 /* Read an f64. (Like float_cons ('d')). */
488 static void
489 wasm32_f64 (char **line)
491 char *t = input_line_pointer;
493 input_line_pointer = *line;
494 float_cons ('d');
495 *line = input_line_pointer;
496 input_line_pointer = t;
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. */
504 static void
505 wasm32_signature (char **line)
507 unsigned long count = 0;
508 char *str = *line;
509 char *ostr;
510 char *result;
512 if (*str++ != 'F')
513 as_bad (_("Not a function type"));
514 result = str;
515 ostr = str + 1;
516 str++;
518 while (*str != 'E')
520 switch (*str++)
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]);
532 wasm32_put_uleb128 (count);
533 str = ostr;
534 while (*str != 'E')
536 switch (*str++)
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"));
554 str++;
555 switch (*result)
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"));
579 *line = str;
582 /* Main operands function. Read the operands for OPCODE from LINE,
583 replacing it with the new input pointer. */
585 static void
586 wasm32_operands (struct wasm32_opcode_s *opcode, char **line)
588 char *str = *line;
589 unsigned long block_type = 0;
591 FRAG_APPEND_1_CHAR (opcode->opcode);
592 str = skip_space (str);
593 if (str[0] == '[')
595 if (opcode->clas == wasm_typed)
597 str++;
598 block_type = BLOCK_TYPE_NONE;
599 if (str[0] != ']')
601 str = skip_space (str);
602 switch (str[0])
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;
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);
628 else
630 str++;
631 str = skip_space (str);
634 else
635 as_bad (_("instruction does not take a block type"));
638 switch (opcode->clas)
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] == '=')
659 str += 2;
660 if (!wasm32_uleb128 (&str, 32))
661 as_bad (_("missing alignment hint"));
663 else
665 as_bad (_("missing alignment hint"));
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:
713 wasm32_uleb128 (&str, 32);
714 str = skip_space (str);
716 while (str[0]);
718 break;
720 case wasm_signature:
721 wasm32_signature (&str);
723 str = skip_space (str);
725 if (*str)
726 as_bad (_("junk at end of line, first unrecognized character is `%c'"),
727 *str);
729 *line = str;
731 return;
734 /* Main assembly function. Find the opcode and call
735 wasm32_operands(). */
737 void
738 md_assemble (char *str)
740 char op[32];
741 char *t;
742 struct wasm32_opcode_s *opcode;
744 str = skip_space (extract_opcode (str, op, sizeof (op)));
746 if (!op[0])
747 as_bad (_("can't find opcode "));
749 opcode = (struct wasm32_opcode_s *) hash_find (wasm32_hash, op);
751 if (opcode == NULL)
753 as_bad (_("unknown opcode `%s'"), op);
754 return;
757 dwarf2_emit_insn (0);
759 t = input_line_pointer;
760 wasm32_operands (opcode, &str);
761 input_line_pointer = t;
764 /* Don't replace PLT/GOT relocations with section symbols, so they
765 don't get an addend. */
768 wasm32_force_relocation (fixS * f)
770 if (f->fx_r_type == BFD_RELOC_WASM32_LEB128_PLT
771 || f->fx_r_type == BFD_RELOC_WASM32_LEB128_GOT)
772 return 1;
774 return 0;
777 /* Don't replace PLT/GOT relocations with section symbols, so they
778 don't get an addend. */
780 bfd_boolean
781 wasm32_fix_adjustable (fixS * fixP)
783 if (fixP->fx_addsy == NULL)
784 return TRUE;
786 if (fixP->fx_r_type == BFD_RELOC_WASM32_LEB128_PLT
787 || fixP->fx_r_type == BFD_RELOC_WASM32_LEB128_GOT)
788 return FALSE;
790 return TRUE;
793 /* Generate a reloc for FIXP. */
795 arelent *
796 tc_gen_reloc (asection * sec ATTRIBUTE_UNUSED, fixS * fixp)
798 arelent *reloc;
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;
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);
809 reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
810 if (reloc->howto == NULL)
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;
818 reloc->addend = fixp->fx_offset;
820 return reloc;