This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Other format: | [Raw text] |
This patch adds support for assembling WebAssembly opcodes into ELF binaries (which can then be converted into WebAssembly modules). In order to pass tests, it also adds the first wasm32-specific relocation (other than R_WASM32_NONE), a simple absolute 32-bit relocation. There is no support for assembling WebAssembly structured expressions (the "was" language): instead of (i32.add (i32.const 1) (i32.const 2)), we expect input of the form: i32.const 1 i32.const 2 i32.add (That's what the assembled code looks like anyway.) The next patch will include a number of tests that can now be run. As always, comments and improvements would be most welcome. Thanks, Pip Cet Suggested change log entries: bfd/: 2017-03-27 Pip Cet <pipcet@gmail.com> * elf32-wasm32.c: Add relocation code, two relocs. * reloc.c: Add wasm32 relocations. * libbfd.h: Regenerate. * bfd-in2.h: Regenerate. gas/: 2017-03-27 Pip Cet <pipcet@gmail.com> * config/tc-wasm32.h: Add WebAssembly assembler target. * config/tc-wasm32.c: Add WebAssembly assembler target. * Makefile.am: Add WebAssembly assembler target. * doc/wasm32.texi: Start documenting WebAssembly assembler. * configure.tgt: Likewise * Makefile.in: Regenerate. * po/gas.pot: Regenerate. * po/POTFILES.in: Regenerate. opcodes/: 2017-03-27 Pip Cet <pipcet@gmail.com> * configure.ac: Add (empty) bfd_wasm32_arch target. * configure: Regenerate * po/opcodes.pot: Regenerate. include/: 2017-03-27 Pip Cet <pipcet@gmail.com> * opcode/wasm.h: New file to support wasm32 architecture. * elf/wasm32.h: Add R_WASM32_32 relocation. ------- diff --git a/bfd/elf32-wasm32.c b/bfd/elf32-wasm32.c index 9b3827248f..510e429046 100644 --- a/bfd/elf32-wasm32.c +++ b/bfd/elf32-wasm32.c @@ -23,8 +23,108 @@ #include "libbfd.h" #include "elf-bfd.h" #include "bfd_stdint.h" +#include "libiberty.h" #include "elf/wasm32.h" +static reloc_howto_type elf32_wasm32_howto_table[] = +{ + HOWTO (R_WASM32_NONE, /* type */ + 0, /* rightshift */ + 3, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_WASM32_NONE", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* 32 bit absolute */ + HOWTO (R_WASM32_32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_WASM32_32", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ +}; + +/* Look up the relocation CODE. */ + +static reloc_howto_type * +elf32_wasm32_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, + bfd_reloc_code_real_type code) +{ + switch (code) + { + case BFD_RELOC_NONE: + return &elf32_wasm32_howto_table[R_WASM32_NONE]; + case BFD_RELOC_32: + return &elf32_wasm32_howto_table[R_WASM32_32]; + default: + break; + } + + return NULL; +} + +/* Look up the relocation R_NAME. */ + +static reloc_howto_type * +elf32_wasm32_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, + const char *r_name) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE (elf32_wasm32_howto_table); i++) + if (elf32_wasm32_howto_table[i].name != NULL + && strcasecmp (elf32_wasm32_howto_table[i].name, r_name) == 0) + return &elf32_wasm32_howto_table[i]; + + return NULL; +} + +/* Look up the relocation R_TYPE. */ + +static reloc_howto_type * +elf32_wasm32_rtype_to_howto (bfd *abfd, unsigned r_type) +{ + unsigned int i = r_type; + + if (i >= ARRAY_SIZE (elf32_wasm32_howto_table)) + { + /* xgettext:c-format */ + _bfd_error_handler (_("%B: invalid relocation type %d"), + abfd, (int) r_type); + i = R_WASM32_NONE; + } + + if (elf32_wasm32_howto_table[i].type != r_type) + return NULL; + + return &elf32_wasm32_howto_table[i]; +} + +/* Translate the ELF-internal relocation RELA into CACHE_PTR. */ + +static void +elf32_wasm32_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, + arelent *cache_ptr, + Elf_Internal_Rela *dst) +{ + unsigned int r_type = ELF32_R_TYPE (dst->r_info); + cache_ptr->howto = elf32_wasm32_rtype_to_howto (abfd, r_type); +} + #define ELF_ARCH bfd_arch_wasm32 #define ELF_TARGET_ID EM_WEBASSEMBLY #define ELF_MACHINE_CODE EM_WEBASSEMBLY @@ -40,8 +140,11 @@ /* For testing. */ #define elf_backend_want_dynrelro 1 -#define bfd_elf32_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup _bfd_norelocs_bfd_reloc_name_lookup +#define elf_info_to_howto elf32_wasm32_info_to_howto_rela +#define elf_info_to_howto_rel NULL + +#define bfd_elf32_bfd_reloc_type_lookup elf32_wasm32_reloc_type_lookup +#define bfd_elf32_bfd_reloc_name_lookup elf32_wasm32_reloc_name_lookup #define ELF_DYNAMIC_INTERPRETER "/sbin/elf-dynamic-interpreter.so" diff --git a/bfd/reloc.c b/bfd/reloc.c index d4229a4b79..2791458516 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -7853,6 +7853,29 @@ ENUMX ENUMDOC Visium Relocations. +ENUM + BFD_RELOC_WASM32_LEB128 +ENUMX + BFD_RELOC_WASM32_LEB128_GOT +ENUMX + BFD_RELOC_WASM32_LEB128_GOT_CODE +ENUMX + BFD_RELOC_WASM32_LEB128_PLT +ENUMX + BFD_RELOC_WASM32_PLT_INDEX +ENUMX + BFD_RELOC_WASM32_ABS32_CODE +ENUMX + BFD_RELOC_WASM32_COPY +ENUMX + BFD_RELOC_WASM32_CODE_POINTER +ENUMX + BFD_RELOC_WASM32_INDEX +ENUMX + BFD_RELOC_WASM32_PLT_SIG +ENUMDOC + WebAssembly relocations. + ENDSENUM BFD_RELOC_UNUSED CODE_FRAGMENT diff --git a/gas/Makefile.am b/gas/Makefile.am index 851532cc69..c9f9de0503 100644 --- a/gas/Makefile.am +++ b/gas/Makefile.am @@ -196,6 +196,7 @@ TARGET_CPU_CFILES = \ config/tc-v850.c \ config/tc-vax.c \ config/tc-visium.c \ + config/tc-wasm32.c \ config/tc-xstormy16.c \ config/tc-xc16x.c \ config/tc-xgate.c \ @@ -271,6 +272,7 @@ TARGET_CPU_HFILES = \ config/tc-v850.h \ config/tc-vax.h \ config/tc-visium.h \ + config/tc-wasm32.h \ config/tc-xstormy16.h \ config/tc-xc16x.h \ config/tc-xgate.h \ diff --git a/gas/config/tc-wasm32.c b/gas/config/tc-wasm32.c new file mode 100644 index 0000000000..e78f8917b0 --- /dev/null +++ b/gas/config/tc-wasm32.c @@ -0,0 +1,813 @@ +/* tc-wasm32.c -- Assembler code for the wasm32 target. + + Copyright (C) 2017 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#include "as.h" +#include "safe-ctype.h" +#include "subsegs.h" +#include "dwarf2dbg.h" +#include "dw2gencfi.h" +#include "elf/wasm32.h" +#include <float.h> + +enum wasm_class +{ + wasm_typed, /* a typed opcode: block, loop, or if */ + wasm_special, /* a special opcode: unreachable, nop, else, + or end */ + wasm_break, /* "br" */ + wasm_break_if, /* "br_if" opcode */ + wasm_break_table, /* "br_table" opcode */ + wasm_return, /* "return" opcode */ + wasm_call, /* "call" opcode */ + wasm_call_indirect, /* "call_indirect" opcode */ + wasm_get_local, /* "get_local" and "get_global" */ + wasm_set_local, /* "set_local" and "set_global" */ + wasm_tee_local, /* "tee_local" */ + wasm_drop, /* "drop" */ + wasm_constant_i32, /* "i32.const" */ + wasm_constant_i64, /* "i64.const" */ + wasm_constant_f32, /* "f32.const" */ + wasm_constant_f64, /* "f64.const" */ + wasm_unary, /* unary operators */ + wasm_binary, /* binary operators */ + wasm_conv, /* conversion operators */ + wasm_load, /* load operators */ + wasm_store, /* store operators */ + wasm_select, /* "select" */ + wasm_relational, /* comparison operators, except for "eqz" */ + wasm_eqz, /* "eqz" */ + wasm_current_memory, /* "current_memory" */ + wasm_grow_memory, /* "grow_memory" */ + wasm_signature /* "signature", which isn't an opcode */ +}; + +#define WASM_OPCODE(opcode, name, intype, outtype, class, signedness) \ + { name, wasm_ ## class, opcode }, + +struct wasm32_opcode_s +{ + const char *name; + enum wasm_class clas; + unsigned char opcode; +} wasm32_opcodes[] = +{ +#include "opcode/wasm.h" + { + NULL, 0, 0} +}; + +const char comment_chars[] = ";#"; +const char line_comment_chars[] = ";#"; +const char line_separator_chars[] = ""; + +const char *md_shortopts = "m:"; + +const char EXP_CHARS[] = "eE"; +const char FLT_CHARS[] = "dD"; + +/* The target specific pseudo-ops which we support. */ + +const pseudo_typeS md_pseudo_table[] = { + {NULL, NULL, 0} +}; + +/* Opcode hash table. */ + +static struct hash_control *wasm32_hash; + +struct option md_longopts[] = { + {NULL, no_argument, NULL, 0} +}; + +size_t md_longopts_size = sizeof (md_longopts); + +/* No relaxation/no machine-dependent frags. */ + +int +md_estimate_size_before_relax (fragS * fragp ATTRIBUTE_UNUSED, + asection * seg ATTRIBUTE_UNUSED) +{ + abort (); + return 0; +} + +void +md_show_usage (FILE * stream) +{ + fprintf (stream, _("wasm32 assembler options:\n")); +} + +/* No machine-dependent options. */ + +int +md_parse_option (int c ATTRIBUTE_UNUSED, const char *arg ATTRIBUTE_UNUSED) +{ + return 0; +} + +/* No machine-dependent symbols. */ + +symbolS * +md_undefined_symbol (char *name ATTRIBUTE_UNUSED) +{ + return NULL; +} + +/* IEEE little-endian floats. */ + +const char * +md_atof (int type, char *litP, int *sizeP) +{ + return ieee_md_atof (type, litP, sizeP, FALSE); +} + +/* No machine-dependent frags. */ + +void +md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, + asection * sec ATTRIBUTE_UNUSED, + fragS * fragP ATTRIBUTE_UNUSED) +{ + abort (); +} + +/* Build opcode hash table, set some flags. */ + +void +md_begin (void) +{ + struct wasm32_opcode_s *opcode; + + wasm32_hash = hash_new (); + + /* Insert unique names into hash table. This hash table then + * provides a quick index to the first opcode with a particular name + * in the opcode table. */ + for (opcode = wasm32_opcodes; opcode->name; opcode++) + hash_insert (wasm32_hash, opcode->name, (char *) opcode); + + linkrelax = 0; + flag_sectname_subst = 1; + flag_no_comments = 0; + flag_keep_locals = 1; +} + +/* Do the normal thing for md_section_align. */ + +valueT +md_section_align (asection * seg, valueT addr) +{ + int align = bfd_get_section_alignment (stdoutput, seg); + return ((addr + (1 << align) - 1) & -(1 << align)); +} + +/* Apply a fixup, return TRUE if done (and no relocation is + needed). */ + +static bfd_boolean +apply_full_field_fix (fixS * fixP, char *buf, bfd_vma val, int size) +{ + if (fixP->fx_addsy != NULL || fixP->fx_pcrel) + { + fixP->fx_addnumber = val; + + return FALSE; + } + number_to_chars_littleendian (buf, val, size); + + return TRUE; +} + +/* Apply a fixup (potentially PC-relative), set the fx_done flag if + done. */ + +void +md_apply_fix (fixS * fixP, valueT * valP, segT seg ATTRIBUTE_UNUSED) +{ + char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; + long val = (long) *valP; + + if (fixP->fx_pcrel) + { + switch (fixP->fx_r_type) + { + default: + bfd_set_error (bfd_error_bad_value); + return; + + case BFD_RELOC_32: + fixP->fx_r_type = BFD_RELOC_32_PCREL; + return; + } + } + + if (apply_full_field_fix (fixP, buf, val, fixP->fx_size)) + fixP->fx_done = 1; +} + +/* Skip whitespace. */ + +static inline char * +skip_space (char *s) +{ + while (*s == ' ' || *s == '\t') + ++s; + return s; +} + +/* Allow '/' in opcodes. */ + +static inline bfd_boolean +is_part_of_opcode (char c) +{ + return is_part_of_name (c) || (c == '/'); +} + +/* Extract an opcode. */ + +static char * +extract_opcode (char *from, char *to, int limit) +{ + char *op_end; + int size = 0; + + /* Drop leading whitespace. */ + from = skip_space (from); + *to = 0; + + /* Find the op code end. */ + for (op_end = from; *op_end != 0 && is_part_of_opcode (*op_end);) + { + to[size++] = *op_end++; + if (size + 1 >= limit) + break; + } + + to[size] = 0; + return op_end; +} + +/* Produce an unsigned LEB128 integer padded to the right number of + bytes to store BITS bits, of value VALUE. Uses FRAG_APPEND_1_CHAR + to write. */ + +static void +wasm32_put_long_uleb128 (int bits, unsigned long value) +{ + unsigned char c; + int i = 0; + + do + { + c = value & 0x7f; + value >>= 7; + if (i < (bits - 1) / 7) + c |= 0x80; + FRAG_APPEND_1_CHAR (c); + } + while (++i < (bits + 6) / 7); +} + +/* Produce a signed LEB128 integer, using FRAG_APPEND_1_CHAR to + write. */ + +static void +wasm32_put_sleb128 (long value) +{ + unsigned char c; + int more; + + do + { + c = (value & 0x7f); + value >>= 7; + more = !((((value == 0) && ((c & 0x40) == 0)) + || ((value == -1) && ((c & 0x40) != 0)))); + if (more) + c |= 0x80; + FRAG_APPEND_1_CHAR (c); + } + while (more); +} + +/* Produce an unsigned LEB128 integer, using FRAG_APPEND_1_CHAR to + write. */ + +static void +wasm32_put_uleb128 (unsigned long value) +{ + unsigned char c; + + do + { + c = value & 0x7f; + value >>= 7; + if (value) + c |= 0x80; + FRAG_APPEND_1_CHAR (c); + } + while (value); +} + +/* Read an integer expression. Produce an LEB128-encoded integer if + it's a constant, a padded LEB128 plus a relocation if it's a + symbol, or a special relocation for <expr>@got, <expr>@gotcode, and + <expr>@plt{__sigchar_<signature>}. */ + +static bfd_boolean +wasm32_leb128 (char **line, int bits, int sign) +{ + char *t = input_line_pointer; + char *str = *line; + char *str0 = str; + struct reloc_list *reloc; + expressionS ex; + int gotrel = 0; + int pltrel = 0; + int code = 0; + const char *relname; + + input_line_pointer = str; + expression (&ex); + + if (ex.X_op == O_constant && *input_line_pointer != '@') + { + long value = ex.X_add_number; + + str = input_line_pointer; + str = skip_space (str); + *line = str; + if (sign) + wasm32_put_sleb128 (value); + else + { + if (value < 0) + as_bad (_("unexpected negative constant")); + wasm32_put_uleb128 (value); + } + input_line_pointer = t; + return str != str0; + } + + reloc = XNEW (struct reloc_list); + reloc->u.a.offset_sym = expr_build_dot (); + if (ex.X_op == O_symbol) + { + reloc->u.a.sym = ex.X_add_symbol; + reloc->u.a.addend = ex.X_add_number; + } + else + { + reloc->u.a.sym = make_expr_symbol (&ex); + reloc->u.a.addend = 0; + } + /* i32.const fpointer@gotcode */ + if (strncmp (input_line_pointer, "@gotcode", 8) == 0) + { + gotrel = 1; + code = 1; + input_line_pointer += 8; + } + /* i32.const data@got */ + else if (strncmp (input_line_pointer, "@got", 4) == 0) + { + gotrel = 1; + input_line_pointer += 4; + } + /* call f@plt{__sigchar_FiiiiE} */ + else if (strncmp (input_line_pointer, "@plt", 4) == 0) + { + pltrel = 1; + code = 1; + input_line_pointer += 4; + char *end_of_sig; + if (strncmp (input_line_pointer, "{", 1) == 0 + && (end_of_sig = strchr (input_line_pointer, '}'))) + { + char *signature; + struct reloc_list *reloc2; + size_t siglength = end_of_sig - (input_line_pointer + 1); + + signature = strndup (input_line_pointer + 1, siglength); + + reloc2 = XNEW (struct reloc_list); + reloc2->u.a.offset_sym = expr_build_dot (); + reloc2->u.a.sym = symbol_find_or_make (signature); + reloc2->u.a.addend = 0; + reloc2->u.a.howto = bfd_reloc_name_lookup + (stdoutput, "R_WASM32_PLT_SIG"); + reloc2->next = reloc_list; + reloc_list = reloc2; + input_line_pointer = end_of_sig + 1; + } + else + { + as_bad (_("no function type on PLT reloc")); + } + } + + if (gotrel && code) + relname = "R_WASM32_LEB128_GOT_CODE"; + else if (gotrel) + relname = "R_WASM32_LEB128_GOT"; + else if (pltrel) + relname = "R_WASM32_LEB128_PLT"; + else + relname = "R_WASM32_LEB128"; + + reloc->u.a.howto = bfd_reloc_name_lookup (stdoutput, relname); + if (!reloc->u.a.howto) + as_bad (_("couldn't find relocation to use")); + reloc->file = as_where (&reloc->line); + reloc->next = reloc_list; + reloc_list = reloc; + + str = input_line_pointer; + str = skip_space (str); + *line = str; + wasm32_put_long_uleb128 (bits, 0); + input_line_pointer = t; + + return str != str0; +} + +/* Read an integer expression and produce an unsigned LEB128 integer, + or a relocation for it. */ + +static bfd_boolean +wasm32_uleb128 (char **line, int bits) +{ + return wasm32_leb128 (line, bits, 0); +} + +/* Read an integer expression and produce a signed LEB128 integer, or + a relocation for it. */ + +static bfd_boolean +wasm32_sleb128 (char **line, int bits) +{ + return wasm32_leb128 (line, bits, 1); +} + +/* Read an f32. (Like float_cons ('f')). */ + +static void +wasm32_f32 (char **line) +{ + char *t = input_line_pointer; + input_line_pointer = *line; + float_cons ('f'); + *line = input_line_pointer; + input_line_pointer = t; +} + +/* Read an f64. (Like float_cons ('d')). */ + +static void +wasm32_f64 (char **line) +{ + char *t = input_line_pointer; + input_line_pointer = *line; + float_cons ('d'); + *line = input_line_pointer; + input_line_pointer = t; +} + +/* Assemble a signature from LINE, replacing it with the new input + pointer. Signatures are simple expressions matching the regexp + F[ilfd]*v?E, and interpreted as though they were C++-mangled + function types on a 64-bit machine. */ + +static void +wasm32_signature (char **line) +{ + unsigned long count = 0; + char *str = *line; + char *ostr; + char *result; + if (*str++ != 'F') + as_bad (_("Not a function type")); + result = str; + ostr = str + 1; + str++; + while (*str != 'E') + { + switch (*str++) + { + case 'i': + case 'l': + case 'f': + case 'd': + count++; + break; + default: + as_bad (_("Unknown type %c\n"), str[-1]); + } + } + wasm32_put_uleb128 (count); + str = ostr; + while (*str != 'E') + { + switch (*str++) + { + case 'i': + FRAG_APPEND_1_CHAR (BLOCK_TYPE_I32); + break; + case 'l': + FRAG_APPEND_1_CHAR (BLOCK_TYPE_I64); + break; + case 'f': + FRAG_APPEND_1_CHAR (BLOCK_TYPE_F32); + break; + case 'd': + FRAG_APPEND_1_CHAR (BLOCK_TYPE_F64); + break; + default: + as_bad (_("Unknown type")); + } + } + str++; + switch (*result) + { + case 'v': + FRAG_APPEND_1_CHAR (0x00); /* no return value */ + break; + case 'i': + FRAG_APPEND_1_CHAR (0x01); /* one return value */ + FRAG_APPEND_1_CHAR (BLOCK_TYPE_I32); + break; + case 'l': + FRAG_APPEND_1_CHAR (0x01); /* one return value */ + FRAG_APPEND_1_CHAR (BLOCK_TYPE_I64); + break; + case 'f': + FRAG_APPEND_1_CHAR (0x01); /* one return value */ + FRAG_APPEND_1_CHAR (BLOCK_TYPE_F32); + break; + case 'd': + FRAG_APPEND_1_CHAR (0x01); /* one return value */ + FRAG_APPEND_1_CHAR (BLOCK_TYPE_F64); + break; + default: + as_bad (_("Unknown type")); + } + *line = str; +} + +/* Main operands function. Read the operands for OPCODE from LINE, + replacing it with the new input pointer. */ + +static void +wasm32_operands (struct wasm32_opcode_s *opcode, char **line) +{ + char *str = *line; + unsigned long block_type = 0; + FRAG_APPEND_1_CHAR (opcode->opcode); + str = skip_space (str); + if (str[0] == '[') + { + if (opcode->clas == wasm_typed) + { + str++; + block_type = BLOCK_TYPE_NONE; + if (str[0] != ']') + { + str = skip_space (str); + switch (str[0]) + { + case 'i': + block_type = BLOCK_TYPE_I32; + str++; + break; + case 'l': + block_type = BLOCK_TYPE_I64; + str++; + break; + case 'f': + block_type = BLOCK_TYPE_F32; + str++; + break; + case 'd': + block_type = BLOCK_TYPE_F64; + str++; + break; + } + str = skip_space (str); + if (str[0] == ']') + str++; + else + as_bad (_("only single block types allowed")); + str = skip_space (str); + } + else + { + str++; + str = skip_space (str); + } + } + else + as_bad (_("instruction does not take a block type")); + } + + switch (opcode->clas) + { + case wasm_drop: + case wasm_special: + case wasm_binary: + case wasm_unary: + case wasm_relational: + case wasm_select: + case wasm_eqz: + case wasm_conv: + case wasm_return: + break; + case wasm_typed: + if (block_type == 0) + as_bad (_("missing block type")); + FRAG_APPEND_1_CHAR (block_type); + break; + case wasm_store: + case wasm_load: + if (str[0] == 'a' && str[1] == '=') + { + str += 2; + if (!wasm32_uleb128 (&str, 32)) + as_bad (_("missing alignment hint")); + } + else + { + as_bad (_("missing alignment hint")); + } + str = skip_space (str); + if (!wasm32_uleb128 (&str, 32)) + as_bad (_("missing offset")); + break; + case wasm_set_local: + case wasm_get_local: + case wasm_tee_local: + if (!wasm32_uleb128 (&str, 32)) + as_bad (_("missing local index")); + break; + case wasm_break: + case wasm_break_if: + if (!wasm32_uleb128 (&str, 32)) + as_bad (_("missing break count")); + break; + case wasm_current_memory: + case wasm_grow_memory: + if (!wasm32_uleb128 (&str, 32)) + as_bad (_("missing reserved current_memory/grow_memory argument")); + break; + case wasm_call: + if (!wasm32_uleb128 (&str, 32)) + as_bad (_("missing call argument")); + break; + case wasm_call_indirect: + if (!wasm32_uleb128 (&str, 32)) + as_bad (_("missing call signature")); + if (!wasm32_uleb128 (&str, 32)) + as_bad (_("missing table index")); + break; + case wasm_constant_i32: + wasm32_sleb128 (&str, 32); + break; + case wasm_constant_i64: + wasm32_sleb128 (&str, 64); + break; + case wasm_constant_f32: + wasm32_f32 (&str); + return; + case wasm_constant_f64: + wasm32_f64 (&str); + return; + case wasm_break_table: + { + do + { + wasm32_uleb128 (&str, 32); + str = skip_space (str); + } + while (str[0]); + + break; + } + case wasm_signature: + wasm32_signature (&str); + } + str = skip_space (str); + + if (*str) + as_bad (_("junk at end of line, first unrecognized character is `%c'"), + *str); + + *line = str; + + return; +} + +/* Main assembly function. Find the opcode and call + wasm32_operands(). */ + +void +md_assemble (char *str) +{ + char op[32]; + char *t; + struct wasm32_opcode_s *opcode; + + str = skip_space (extract_opcode (str, op, sizeof (op))); + + if (!op[0]) + as_bad (_("can't find opcode ")); + + opcode = (struct wasm32_opcode_s *) hash_find (wasm32_hash, op); + + if (opcode == NULL) + { + as_bad (_("unknown opcode `%s'"), op); + return; + } + + dwarf2_emit_insn (0); + + t = input_line_pointer; + wasm32_operands (opcode, &str); + input_line_pointer = t; +} + +/* Don't replace PLT/GOT relocations with section symbols, so they + don't get an addend. */ + +int +wasm32_force_relocation (fixS * f) +{ + if (f->fx_r_type == BFD_RELOC_WASM32_LEB128_PLT + || f->fx_r_type == BFD_RELOC_WASM32_LEB128_GOT) + return 1; + + return 0; +} + +/* Don't replace PLT/GOT relocations with section symbols, so they + don't get an addend. */ + +bfd_boolean +wasm32_fix_adjustable (fixS * fixP) +{ + if (fixP->fx_addsy == NULL) + return TRUE; + + if (fixP->fx_r_type == BFD_RELOC_WASM32_LEB128_PLT + || fixP->fx_r_type == BFD_RELOC_WASM32_LEB128_GOT) + return FALSE; + + return TRUE; +} + +/* Generate a reloc for FIXP. */ + +arelent * +tc_gen_reloc (asection * sec ATTRIBUTE_UNUSED, fixS * fixp) +{ + arelent *reloc; + + reloc = (arelent *) xmalloc (sizeof (*reloc)); + reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); + reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; + + /* Make sure none of our internal relocations make it this far. + They'd better have been fully resolved by this point. */ + gas_assert ((int) fixp->fx_r_type > 0); + + reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); + if (reloc->howto == NULL) + { + as_bad_where (fixp->fx_file, fixp->fx_line, + _("cannot represent `%s' relocation in object file"), + bfd_get_reloc_code_name (fixp->fx_r_type)); + return NULL; + } + + reloc->addend = fixp->fx_offset; + + return reloc; +} diff --git a/gas/config/tc-wasm32.h b/gas/config/tc-wasm32.h new file mode 100644 index 0000000000..220ad56b8e --- /dev/null +++ b/gas/config/tc-wasm32.h @@ -0,0 +1,89 @@ +/* This file is tc-wasm32.h. + Copyright (C) 2017 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#define TC_WASM32 +#define TARGET_FORMAT "elf32-wasm32" +#define TARGET_ARCH bfd_arch_wasm32 +#define TARGET_MACH 1 + +/* WebAssembly is strictly little-endian. */ +#define TARGET_BYTES_BIG_ENDIAN 0 +#define md_number_to_chars number_to_chars_littleendian + +#define DIFF_EXPR_OK + +/* No machine-dependent operand expressions. */ +#define md_operand(x) + +/* No broken word processing. */ +#define WORKING_DOT_WORD + +/* Force some relocations. */ +#define EXTERN_FORCE_RELOC 1 +extern int wasm32_force_relocation (struct fix *); +#define TC_FORCE_RELOCATION(fix) wasm32_force_relocation (fix) +#define TC_FORCE_RELOCATION_LOCAL(fix) 1 +#define TC_FORCE_RELOCATION_SUB_SAME(fix,seg) wasm32_force_relocation (fix) +#define TC_FORCE_RELOCATION_SUB_ABS(fix,seg) wasm32_force_relocation (fix) +#define TC_FORCE_RELOCATION_SUB_LOCAL(fix,seg) wasm32_force_relocation (fix) +#define TC_VALIDATE_FIX_SUB(fix,seg) wasm32_force_relocation (fix) + +/* This is ELF, values passed to md_apply_fix don't include the symbol + value. */ +#define MD_APPLY_SYM_VALUE(FIX) 0 + +/* PC-relative relocations are relative to the relocation offset. */ +#define MD_PCREL_FROM_SECTION(FIX, SEC) 0 + +#define DWARF2_LINE_MIN_INSN_LENGTH 1 + +/* WebAssembly uses 32-bit addresses. */ +#define TC_ADDRESS_BYTES() 4 +#define DWARF2_ADDR_SIZE(bfd) 4 + +/* Enable cfi directives. */ +#define TARGET_USE_CFIPOP 1 + +/* The stack grows down, and there is no harm in claiming it is only + byte aligned. */ +#define DWARF2_CIE_DATA_ALIGNMENT -1 + +/* Define the column that represents the PC. FIXME: this depends on + the ABI. */ +#define DWARF2_DEFAULT_RETURN_COLUMN 36 + +/* Define a hook to setup initial CFI state. */ +#define tc_cfi_frame_initial_instructions() do { } while (0) + +#define elf_tc_final_processing() +#define md_post_relax_hook +#define md_start_line_hook() +#define HANDLE_ALIGN(fragP) + + +extern bfd_boolean wasm32_fix_adjustable (struct fix *); +#define tc_fix_adjustable(FIX) wasm32_fix_adjustable (FIX) + +/* Type names for blocks and signatures. */ +#define BLOCK_TYPE_NONE 0x40 +#define BLOCK_TYPE_I32 0x7f +#define BLOCK_TYPE_I64 0x7e +#define BLOCK_TYPE_F32 0x7d +#define BLOCK_TYPE_F64 0x7c diff --git a/gas/configure.tgt b/gas/configure.tgt index acc3cf0aef..6000c7c202 100644 --- a/gas/configure.tgt +++ b/gas/configure.tgt @@ -111,6 +111,7 @@ case ${cpu} in tilegx*) cpu_type=tilegx endian=little ;; v850*) cpu_type=v850 ;; visium) cpu_type=visium endian=big ;; + wasm32) cpu_type=wasm32 endian=little ;; x86_64*) cpu_type=i386 arch=x86_64;; xgate) cpu_type=xgate ;; xtensa*) cpu_type=xtensa arch=xtensa ;; @@ -462,6 +463,8 @@ case ${generic_target} in visium-*-elf) fmt=elf ;; + wasm32-*-*) fmt=elf ;; + xstormy16-*-*) fmt=elf ;; xgate-*-*) fmt=elf ;; diff --git a/gas/doc/wasm32.texi b/gas/doc/wasm32.texi new file mode 100644 index 0000000000..cb21f6d706 --- /dev/null +++ b/gas/doc/wasm32.texi @@ -0,0 +1,120 @@ +@c Copyright (C) 2017 Free Software Foundation, Inc. +@c This is part of the GAS manual. +@c For copying conditions, see the file as.texinfo. +@c man end + +@ifset GENERIC +@page +@node WebAssembly-Dependent +@chapter WebAssembly Dependent Features +@end ifset + +@ifclear GENERIC +@node Machine Dependencies +@chapter WebAssembly Dependent Features +@end ifclear + +@cindex WebAssembly support +@menu +* WebAssembly Notes:: Notes +* WebAssembly Syntax:: Syntax +* WebAssembly Floating Point:: Floating Point +* WebAssembly Directives:: WebAssembly Machine Directives +* WebAssembly Opcodes:: Opcodes +@end menu + +@node WebAssembly Notes +@section Notes +@cindex WebAssembly notes +@cindex notes for WebAssembly + +While WebAssembly provides its own module format for executables, this +documentation describes how to use @code{@value{AS}} to produce +intermediate ELF object format files. + +@cindex WebAssembly Syntax +@node WebAssembly Syntax +@section Syntax +The assembler syntax directly encodes sequences of opcodes as defined +in the WebAssembly binary encoding specification at +https://github.com/webassembly/spec/BinaryEncoding.md. Structured +sexp-style expressions are not supported as input. + +@menu +* WebAssembly-Chars:: Special Characters +* WebAssembly Opcodes:: Regular Opcodes +* WebAssembly-Regs:: Register Names +* WebAssembly-Relocs:: Relocations +@end menu + +@node WebAssembly-Chars +@subsection Special Characters + +@cindex line comment character, WebAssembly +@cindex WebAssembly line comment character +@samp{#} and @samp{;} are the line comment characters. Note that if +@samp{#} is the first character on a line then it can also be a +logical line number directive (@pxref{Comments}) or a preprocessor +control command (@pxref{Preprocessing}). + +@node WebAssembly-Opcodes +@subsection Regular Opcodes +@cindex opcodes, WebAssembly +@cindex WebAssembly opcodes +Ordinary instructions are encoded with the WebAssembly mnemonics as +listed at: +@url{https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md}. + +Opcodes are written directly in the order in which they are encoded, +without going through an intermediate sexp-style expression as in the +@code{was} format. + +For ``typed'' opcodes (block, if, etc.), the type of the block is +specified in square brackets following the opcode: @code{if[i]}, +@code{if[]}. + +@node WebAssembly-Relocs +@subsection Relocations +@cindex WebAssembly relocations +@cindex relocations, WebAssembly + +Special relocations are available by using the @samp{@@@var{plt}}, +@samp{@@@var{got}}, or @samp{@@@var{got}} suffixes after a constant +expression, which correspond to the R_ASMJS_LEB128_PLT, +R_ASMJS_LEB128_GOT, and R_ASMJS_LEB128_GOT_CODE relocations, +respectively. + +The @samp{@@@var{plt}} suffix is followed by a symbol name in braces; +the symbol value is used to determine the function signature for which +a PLT stub is generated. Currently, the symbol @em{name} is parsed +from its last @samp{F} character to determine the argument count of +the function, which is also necessary for generating a PLT stub. + +@node WebAssembly-Signatures +@subsection Signatures +@cindex WebAssembly signatures +@cindex signatures, WebAssembly + +Function signatures are specified with the @code{signature} +pseudo-opcode, followed by a simple function signature imitating a +C++-mangled function type: @code{F} followed by an optional @code{v}, +then a sequence of @code{i}, @code{l}, @code{f}, and @code{d} +characters to mark i32, i64, f32, and f64 parameters, respectively; +followed by a final @code{E} to mark the end of the function +signature. + +@node WebAssembly Floating Point +@section Floating Point +@cindex floating point, WebAssembly (@sc{ieee}) +@cindex WebAssembly floating point (@sc{ieee}) +WebAssembly uses little-endian @sc{ieee} floating-point numbers. + +@node WebAssembly module layout +@section WebAssembly Module Layout +@cindex module layout, WebAssembly +@cindex WebAssembly module layout +@code{@value{AS}} will only produce ELF output, not a valid +WebAssembly module. It is possible to make @code{@value{AS}} produce +output in a single ELF section which becomes a valid WebAssembly +module, but a linker script to do so may be preferrable, as it doesn't +require running the entire module through the assembler at once. diff --git a/include/elf/wasm32.h b/include/elf/wasm32.h index 38e6c2e950..45ea9a17b9 100644 --- a/include/elf/wasm32.h +++ b/include/elf/wasm32.h @@ -23,6 +23,8 @@ /* Relocation types. */ START_RELOC_NUMBERS (elf_wasm32_reloc_type) + RELOC_NUMBER (R_WASM32_NONE, 0) + RELOC_NUMBER (R_WASM32_32, 1) END_RELOC_NUMBERS (R_WASM32_max = 1) #endif /* _ELF_WASM32_H */ diff --git a/include/opcode/wasm.h b/include/opcode/wasm.h new file mode 100644 index 0000000000..9f533e12ae --- /dev/null +++ b/include/opcode/wasm.h @@ -0,0 +1,226 @@ +/* WebAssembly assembler/disassembler support. + Copyright (C) 2017 Free Software Foundation, Inc. + + This file is part of GAS, the GNU assembler. + + GAS is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING3. If not, write to the Free + Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +/* WebAssembly opcodes. Each opcode invokes the WASM_OPCODE macro + with the following arguments: + + 1. Code byte. + 2. Mnemonic. + 3. Input type. + 4. Output type. + 5. Opcode class. + 6. Signedness information. +*/ + +WASM_OPCODE(0x00, "unreachable", void, void, special, agnostic) +WASM_OPCODE(0x01, "nop", void, void, special, agnostic) +WASM_OPCODE(0x02, "block", void, void, typed, agnostic) +WASM_OPCODE(0x03, "loop", void, void, typed, agnostic) +WASM_OPCODE(0x04, "if", void, void, typed, agnostic) +WASM_OPCODE(0x05, "else", void, void, special, agnostic) +WASM_OPCODE(0x0b, "end", void, void, special, agnostic) +WASM_OPCODE(0x0c, "br", void, void, break, agnostic) +WASM_OPCODE(0x0d, "br_if", void, void, break_if, agnostic) +WASM_OPCODE(0x0e, "br_table", void, void, break_table, agnostic) +WASM_OPCODE(0x0f, "return", void, void, return, agnostic) + +WASM_OPCODE(0x10, "call", any, any, call, agnostic) +WASM_OPCODE(0x11, "call_indirect", any, any, call_indirect, agnostic) + +WASM_OPCODE(0x1a, "drop", any, any, drop, agnostic) +WASM_OPCODE(0x1b, "select", any, any, select, agnostic) + +WASM_OPCODE(0x20, "get_local", any, any, get_local, agnostic) +WASM_OPCODE(0x21, "set_local", any, any, set_local, agnostic) +WASM_OPCODE(0x22, "tee_local", any, any, tee_local, agnostic) +WASM_OPCODE(0x23, "get_global", any, any, get_local, agnostic) +WASM_OPCODE(0x24, "set_global", any, any, set_local, agnostic) + +WASM_OPCODE(0x28, "i32.load", i32, i32, load, agnostic) +WASM_OPCODE(0x29, "i64.load", i32, i64, load, agnostic) +WASM_OPCODE(0x2a, "f32.load", i32, f32, load, agnostic) +WASM_OPCODE(0x2b, "f64.load", i32, f64, load, agnostic) +WASM_OPCODE(0x2c, "i32.load8_s", i32, i32, load, signed) +WASM_OPCODE(0x2d, "i32.load8_u", i32, i32, load, unsigned) +WASM_OPCODE(0x2e, "i32.load16_s", i32, i32, load, signed) +WASM_OPCODE(0x2f, "i32.load16_u", i32, i32, load, unsigned) +WASM_OPCODE(0x30, "i64.load8_s", i32, i64, load, signed) +WASM_OPCODE(0x31, "i64.load8_u", i32, i64, load, unsigned) +WASM_OPCODE(0x32, "i64.load16_s", i32, i64, load, signed) +WASM_OPCODE(0x33, "i64.load16_u", i32, i64, load, unsigned) +WASM_OPCODE(0x34, "i64.load32_s", i32, i64, load, signed) +WASM_OPCODE(0x35, "i64.load32_u", i32, i64, load, unsigned) +WASM_OPCODE(0x36, "i32.store", i32, void, store, agnostic) +WASM_OPCODE(0x37, "i64.store", i64, void, store, agnostic) +WASM_OPCODE(0x38, "f32.store", f32, void, store, agnostic) +WASM_OPCODE(0x39, "f64.store", f64, void, store, agnostic) +WASM_OPCODE(0x3a, "i32.store8", i32, void, store, agnostic) +WASM_OPCODE(0x3b, "i32.store16", i32, void, store, agnostic) +WASM_OPCODE(0x3c, "i64.store8", i64, void, store, agnostic) +WASM_OPCODE(0x3d, "i64.store16", i64, void, store, agnostic) +WASM_OPCODE(0x3e, "i64.store32", i64, void, store, agnostic) + +WASM_OPCODE(0x3f, "current_memory", void, i32, current_memory, agnostic) +WASM_OPCODE(0x40, "grow_memory", void, i32, grow_memory, agnostic) + +WASM_OPCODE(0x41, "i32.const", i32, i32, constant_i32, agnostic) +WASM_OPCODE(0x42, "i64.const", i64, i64, constant_i64, agnostic) +WASM_OPCODE(0x43, "f32.const", f32, f32, constant_f32, agnostic) +WASM_OPCODE(0x44, "f64.const", f64, f64, constant_f64, agnostic) + +WASM_OPCODE(0x45, "i32.eqz", i32, i32, eqz, agnostic) +WASM_OPCODE(0x46, "i32.eq", i32, i32, relational, agnostic) +WASM_OPCODE(0x47, "i32.ne", i32, i32, relational, agnostic) +WASM_OPCODE(0x48, "i32.lt_s", i32, i32, relational, signed) +WASM_OPCODE(0x49, "i32.lt_u", i32, i32, relational, unsigned) +WASM_OPCODE(0x4a, "i32.gt_s", i32, i32, relational, signed) +WASM_OPCODE(0x4b, "i32.gt_u", i32, i32, relational, unsigned) +WASM_OPCODE(0x4c, "i32.le_s", i32, i32, relational, signed) +WASM_OPCODE(0x4d, "i32.le_u", i32, i32, relational, unsigned) +WASM_OPCODE(0x4e, "i32.ge_s", i32, i32, relational, signed) +WASM_OPCODE(0x4f, "i32.ge_u", i32, i32, relational, unsigned) + +WASM_OPCODE(0x50, "i64.eqz", i64, i32, eqz, agnostic) +WASM_OPCODE(0x51, "i64.eq", i64, i32, relational, agnostic) +WASM_OPCODE(0x52, "i64.ne", i64, i32, relational, agnostic) +WASM_OPCODE(0x53, "i64.lt_s", i64, i32, relational, signed) +WASM_OPCODE(0x54, "i64.lt_u", i64, i32, relational, unsigned) +WASM_OPCODE(0x55, "i64.gt_s", i64, i32, relational, signed) +WASM_OPCODE(0x56, "i64.gt_u", i64, i32, relational, unsigned) +WASM_OPCODE(0x57, "i64.le_s", i64, i32, relational, signed) +WASM_OPCODE(0x58, "i64.le_u", i64, i32, relational, unsigned) +WASM_OPCODE(0x59, "i64.ge_s", i64, i32, relational, signed) +WASM_OPCODE(0x5a, "i64.ge_u", i64, i32, relational, unsigned) + +WASM_OPCODE(0x5b, "f32.eq", f32, i32, relational, floating) +WASM_OPCODE(0x5c, "f32.ne", f32, i32, relational, floating) +WASM_OPCODE(0x5d, "f32.lt", f32, i32, relational, floating) +WASM_OPCODE(0x5e, "f32.gt", f32, i32, relational, floating) +WASM_OPCODE(0x5f, "f32.le", f32, i32, relational, floating) +WASM_OPCODE(0x60, "f32.ge", f32, i32, relational, floating) + +WASM_OPCODE(0x61, "f64.eq", f64, i32, relational, floating) +WASM_OPCODE(0x62, "f64.ne", f64, i32, relational, floating) +WASM_OPCODE(0x63, "f64.lt", f64, i32, relational, floating) +WASM_OPCODE(0x64, "f64.gt", f64, i32, relational, floating) +WASM_OPCODE(0x65, "f64.le", f64, i32, relational, floating) +WASM_OPCODE(0x66, "f64.ge", f64, i32, relational, floating) + +WASM_OPCODE(0x67, "i32.clz", i32, i32, unary, agnostic) +WASM_OPCODE(0x68, "i32.ctz", i32, i32, unary, agnostic) +WASM_OPCODE(0x69, "i32.popcnt", i32, i32, unary, agnostic) + +WASM_OPCODE(0x6a, "i32.add", i32, i32, binary, agnostic) +WASM_OPCODE(0x6b, "i32.sub", i32, i32, binary, agnostic) +WASM_OPCODE(0x6c, "i32.mul", i32, i32, binary, agnostic) +WASM_OPCODE(0x6d, "i32.div_s", i32, i32, binary, signed) +WASM_OPCODE(0x6e, "i32.div_u", i32, i32, binary, unsigned) +WASM_OPCODE(0x6f, "i32.rem_s", i32, i32, binary, signed) +WASM_OPCODE(0x70, "i32.rem_u", i32, i32, binary, unsigned) +WASM_OPCODE(0x71, "i32.and", i32, i32, binary, agnostic) +WASM_OPCODE(0x72, "i32.or", i32, i32, binary, agnostic) +WASM_OPCODE(0x73, "i32.xor", i32, i32, binary, agnostic) +WASM_OPCODE(0x74, "i32.shl", i32, i32, binary, agnostic) +WASM_OPCODE(0x75, "i32.shr_s", i32, i32, binary, signed) +WASM_OPCODE(0x76, "i32.shr_u", i32, i32, binary, unsigned) +WASM_OPCODE(0x77, "i32.rotl", i32, i32, binary, agnostic) +WASM_OPCODE(0x78, "i32.rotr", i32, i32, binary, agnostic) + +WASM_OPCODE(0x79, "i64.clz", i64, i64, unary, agnostic) +WASM_OPCODE(0x7a, "i64.ctz", i64, i64, unary, agnostic) +WASM_OPCODE(0x7b, "i64.popcnt", i64, i64, unary, agnostic) + +WASM_OPCODE(0x7c, "i64.add", i64, i64, binary, agnostic) +WASM_OPCODE(0x7d, "i64.sub", i64, i64, binary, agnostic) +WASM_OPCODE(0x7e, "i64.mul", i64, i64, binary, agnostic) +WASM_OPCODE(0x7f, "i64.div_s", i64, i64, binary, signed) +WASM_OPCODE(0x80, "i64.div_u", i64, i64, binary, unsigned) +WASM_OPCODE(0x81, "i64.rem_s", i64, i64, binary, signed) +WASM_OPCODE(0x82, "i64.rem_u", i64, i64, binary, unsigned) +WASM_OPCODE(0x83, "i64.and", i64, i64, binary, agnostic) +WASM_OPCODE(0x84, "i64.or", i64, i64, binary, agnostic) +WASM_OPCODE(0x85, "i64.xor", i64, i64, binary, agnostic) +WASM_OPCODE(0x86, "i64.shl", i64, i64, binary, agnostic) +WASM_OPCODE(0x87, "i64.shr_s", i64, i64, binary, signed) +WASM_OPCODE(0x88, "i64.shr_u", i64, i64, binary, unsigned) +WASM_OPCODE(0x89, "i64.rotl", i64, i64, binary, agnostic) +WASM_OPCODE(0x8a, "i64.rotr", i64, i64, binary, agnostic) + +WASM_OPCODE(0x8b, "f32.abs", f32, f32, unary, floating) +WASM_OPCODE(0x8c, "f32.neg", f32, f32, unary, floating) +WASM_OPCODE(0x8d, "f32.ceil", f32, f32, unary, floating) +WASM_OPCODE(0x8e, "f32.floor", f32, f32, unary, floating) +WASM_OPCODE(0x8f, "f32.trunc", f32, f32, unary, floating) +WASM_OPCODE(0x90, "f32.nearest", f32, f32, unary, floating) +WASM_OPCODE(0x91, "f32.sqrt", f32, f32, unary, floating) +WASM_OPCODE(0x92, "f32.add", f32, f32, binary, floating) +WASM_OPCODE(0x93, "f32.sub", f32, f32, binary, floating) +WASM_OPCODE(0x94, "f32.mul", f32, f32, binary, floating) +WASM_OPCODE(0x95, "f32.div", f32, f32, binary, floating) +WASM_OPCODE(0x96, "f32.min", f32, f32, binary, floating) +WASM_OPCODE(0x97, "f32.max", f32, f32, binary, floating) +WASM_OPCODE(0x98, "f32.copysign", f32, f32, binary, floating) + +WASM_OPCODE(0x99, "f64.abs", f64, f64, unary, floating) +WASM_OPCODE(0x9a, "f64.neg", f64, f64, unary, floating) +WASM_OPCODE(0x9b, "f64.ceil", f64, f64, unary, floating) +WASM_OPCODE(0x9c, "f64.floor", f64, f64, unary, floating) +WASM_OPCODE(0x9d, "f64.trunc", f64, f64, unary, floating) +WASM_OPCODE(0x9e, "f64.nearest", f64, f64, unary, floating) +WASM_OPCODE(0x9f, "f64.sqrt", f64, f64, unary, floating) +WASM_OPCODE(0xa0, "f64.add", f64, f64, binary, floating) +WASM_OPCODE(0xa1, "f64.sub", f64, f64, binary, floating) +WASM_OPCODE(0xa2, "f64.mul", f64, f64, binary, floating) +WASM_OPCODE(0xa3, "f64.div", f64, f64, binary, floating) +WASM_OPCODE(0xa4, "f64.min", f64, f64, binary, floating) +WASM_OPCODE(0xa5, "f64.max", f64, f64, binary, floating) +WASM_OPCODE(0xa6, "f64.copysign", f64, f64, binary, floating) + +WASM_OPCODE(0xa7, "i32.wrap/i64", i64, i32, conv, agnostic) +WASM_OPCODE(0xa8, "i32.trunc_s/f32", f32, i32, conv, signed) +WASM_OPCODE(0xa9, "i32.trunc_u/f32", f32, i32, conv, unsigned) +WASM_OPCODE(0xaa, "i32.trunc_s/f64", f64, i32, conv, signed) +WASM_OPCODE(0xab, "i32.trunc_u/f64", f64, i32, conv, unsigned) +WASM_OPCODE(0xac, "i64.extend_s/i32", i32, i64, conv, signed) +WASM_OPCODE(0xad, "i64.extend_u/i32", i32, i64, conv, unsigned) +WASM_OPCODE(0xae, "i64.trunc_s/f32", f32, i64, conv, signed) +WASM_OPCODE(0xaf, "i64.trunc_u/f32", f32, i64, conv, unsigned) +WASM_OPCODE(0xb0, "i64.trunc_s/f64", f64, i64, conv, signed) +WASM_OPCODE(0xb1, "i64.trunc_u/f64", f64, i64, conv, unsigned) + +WASM_OPCODE(0xb2, "f32.convert_s/i32", i32, f32, conv, signed) +WASM_OPCODE(0xb3, "f32.convert_u/i32", i32, f32, conv, unsigned) +WASM_OPCODE(0xb4, "f32.convert_s/i64", i64, f32, conv, signed) +WASM_OPCODE(0xb5, "f32.convert_u/i64", i64, f32, conv, unsigned) +WASM_OPCODE(0xb6, "f32.demote/f64", f64, f32, conv, floating) +WASM_OPCODE(0xb7, "f64.convert_s/i32", i32, f64, conv, signed) +WASM_OPCODE(0xb8, "f64.convert_u/i32", i32, f64, conv, unsigned) +WASM_OPCODE(0xb9, "f64.convert_s/i64", i64, f64, conv, signed) +WASM_OPCODE(0xba, "f64.convert_u/i64", i64, f64, conv, unsigned) +WASM_OPCODE(0xbb, "f64.promote/f32", f32, f64, conv, floating) + +WASM_OPCODE(0xbc, "i32.reinterpret/f32", f32, i32, conv, agnostic) +WASM_OPCODE(0xbd, "i64.reinterpret/f64", f64, i64, conv, agnostic) +WASM_OPCODE(0xbe, "f32.reinterpret/i32", i32, f32, conv, agnostic) +WASM_OPCODE(0xbf, "f64.reinterpret/i64", i64, f64, conv, agnostic) + +/* This isn't, strictly speaking, an opcode, but is treated as such by + the assembler. */ +WASM_OPCODE(0x60, "signature", void, void, signature, agnostic) diff --git a/opcodes/configure.ac b/opcodes/configure.ac index 617a86ca5c..ca982924e6 100644 --- a/opcodes/configure.ac +++ b/opcodes/configure.ac @@ -348,6 +348,7 @@ if test x${all_targets} = xfalse ; then bfd_vax_arch) ta="$ta vax-dis.lo" ;; bfd_visium_arch) ta="$ta visium-dis.lo visium-opc.lo" ;; bfd_w65_arch) ta="$ta w65-dis.lo" ;; + bfd_wasm32_arch) ;; bfd_we32k_arch) ;; bfd_xc16x_arch) ta="$ta xc16x-asm.lo xc16x-desc.lo xc16x-dis.lo xc16x-ibld.lo xc16x-opc.lo" using_cgen=yes ;; bfd_xgate_arch) ta="$ta xgate-dis.lo xgate-opc.lo" ;;
Attachment:
binutils-wasm-005.diff
Description: Text document
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |