]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gas/config/tc-wasm32.c
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / gas / config / tc-wasm32.c
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
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 bfd_boolean
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 bfd_boolean
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 bfd_boolean
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 (strncmp (input_line_pointer, "@gotcode", 8) == 0)
385 {
386 gotrel = 1;
387 code = 1;
388 input_line_pointer += 8;
389 }
390 /* i32.const data@got */
391 else if (strncmp (input_line_pointer, "@got", 4) == 0)
392 {
393 gotrel = 1;
394 input_line_pointer += 4;
395 }
396 /* call f@plt{__sigchar_FiiiiE} */
397 else if (strncmp (input_line_pointer, "@plt", 4) == 0)
398 {
399 char *end_of_sig;
400
401 pltrel = 1;
402 code = 1;
403 input_line_pointer += 4;
404
405 if (strncmp (input_line_pointer, "{", 1) == 0
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 bfd_boolean
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 bfd_boolean
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 bfd_boolean
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 }