Removed generation of the PT_GNU_PROPERTY segment
[external/binutils.git] / gas / config / tc-wasm32.c
1 /* tc-wasm32.c -- Assembler code for the wasm32 target.
2
3    Copyright (C) 2017-2019 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 struct hash_control *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 = 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
177 valueT
178 md_section_align (asection * seg, valueT addr)
179 {
180   int align = bfd_get_section_alignment (stdoutput, 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 *) 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 }