Fix build error in gdb/rocm-tdep.c
[deliverable/binutils-gdb.git] / gas / config / tc-wasm32.c
CommitLineData
f96bd6c2
PC
1/* tc-wasm32.c -- Assembler code for the wasm32 target.
2
b3adc24a 3 Copyright (C) 2017-2020 Free Software Foundation, Inc.
f96bd6c2
PC
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
30enum 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
65struct 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
77const char comment_chars[] = ";#";
78const char line_comment_chars[] = ";#";
79const char line_separator_chars[] = "";
80
81const char *md_shortopts = "m:";
82
83const char EXP_CHARS[] = "eE";
84const char FLT_CHARS[] = "dD";
85
86/* The target specific pseudo-ops which we support. */
87
88const pseudo_typeS md_pseudo_table[] =
89{
90 {NULL, NULL, 0}
91};
92
93/* Opcode hash table. */
94
95static struct hash_control *wasm32_hash;
96
97struct option md_longopts[] =
98{
99 {NULL, no_argument, NULL, 0}
100};
101
102size_t md_longopts_size = sizeof (md_longopts);
103
104/* No relaxation/no machine-dependent frags. */
105
106int
107md_estimate_size_before_relax (fragS * fragp ATTRIBUTE_UNUSED,
108 asection * seg ATTRIBUTE_UNUSED)
109{
110 abort ();
111 return 0;
112}
113
114void
115md_show_usage (FILE * stream)
116{
117 fprintf (stream, _("wasm32 assembler options:\n"));
118}
119
120/* No machine-dependent options. */
121
122int
123md_parse_option (int c ATTRIBUTE_UNUSED, const char *arg ATTRIBUTE_UNUSED)
124{
125 return 0;
126}
127
128/* No machine-dependent symbols. */
129
130symbolS *
131md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
132{
133 return NULL;
134}
135
136/* IEEE little-endian floats. */
137
138const char *
139md_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
146void
147md_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
156void
157md_begin (void)
158{
159 struct wasm32_opcode_s *opcode;
160
161 wasm32_hash = hash_new ();
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 hash_insert (wasm32_hash, opcode->name, (char *) opcode);
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
177valueT
178md_section_align (asection * seg, valueT addr)
179{
fd361982 180 int align = bfd_section_alignment (seg);
f96bd6c2
PC
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
187static bfd_boolean
188apply_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
203void
204md_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
229static inline char *
230skip_space (char *s)
231{
232 while (*s == ' ' || *s == '\t')
233 ++s;
234 return s;
235}
236
237/* Allow '/' in opcodes. */
238
239static inline bfd_boolean
240is_part_of_opcode (char c)
241{
242 return is_part_of_name (c) || (c == '/');
243}
244
245/* Extract an opcode. */
246
247static char *
248extract_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
273static void
274wasm32_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
293static void
294wasm32_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
315static void
316wasm32_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
336static bfd_boolean
337wasm32_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
458static bfd_boolean
459wasm32_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
467static bfd_boolean
468wasm32_sleb128 (char **line, int bits)
469{
470 return wasm32_leb128 (line, bits, 1);
471}
472
473/* Read an f32. (Like float_cons ('f')). */
474
475static void
476wasm32_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
488static void
489wasm32_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
504static void
505wasm32_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
585static void
586wasm32_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
737void
738md_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 *) 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
767int
768wasm32_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
780bfd_boolean
781wasm32_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
795arelent *
796tc_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}
This page took 0.252235 seconds and 4 git commands to generate.