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] |