aboutsummaryrefslogtreecommitdiff
path: root/gas/config
diff options
context:
space:
mode:
authorPip Cet <pipcet@gmail.com>2017-03-30 10:57:21 +0100
committerNick Clifton <nickc@redhat.com>2017-03-30 10:57:21 +0100
commitf96bd6c2d7a3801fabbf9d834f7a29b752aa7532 (patch)
tree6c4ee43355083f19052f09a0fb5bbc4e47c4a08a /gas/config
parent662659a1a582af14aa45a458005e2a4df514b6d7 (diff)
downloadgdb-f96bd6c2d7a3801fabbf9d834f7a29b752aa7532.zip
gdb-f96bd6c2d7a3801fabbf9d834f7a29b752aa7532.tar.gz
gdb-f96bd6c2d7a3801fabbf9d834f7a29b752aa7532.tar.bz2
Add support for the WebAssembly file format and the wasm32 ELF conversion to gas and the binutils.
binutils * readelf.c: Add support for wasm32 ELF format WebAssembly files. (guess_is_rela): Likewise. (dump_relocations): Likewise. (is_32bit_abs_reloc): Likewise. (is_none_reloc_): Likewise. * NEWS: Mention the new support. * testsuite/lib/binutils-common.exp (is_elf_format): Mark wasm32 as ELF target. (supports_gnu_unique): Mark wasm32 as supporting STB_GNU_UNIQUE. * testsuite/binutils-all/nm.exp: Mark wasm32 as requiring .size annotations. * testsuite/binutils-all/wasm32: New directory. * testsuite/binutils-all/wasm32/create-wasm.d: New file. * testsuite/binutils-all/wasm32/create-wasm.s: Likewise. * testsuite/binutils-all/wasm32/custom-section.d: Likewise. * testsuite/binutils-all/wasm32/custom-section.s: Likewise. * testsuite/binutils-all/wasm32/invalid-wasm-1.d: Likewise. * testsuite/binutils-all/wasm32/invalid-wasm-1.s: Likewise. * testsuite/binutils-all/wasm32/long-sections.d: Likewise. * testsuite/binutils-all/wasm32/long-sections.s: Likewise. * testsuite/binutils-all/wasm32/parse-wasm.d: Likewise. * testsuite/binutils-all/wasm32/parse-wasm.s: Likewise. * testsuite/binutils-all/wasm32/parse-wasm-2.d: Likewise. * testsuite/binutils-all/wasm32/parse-wasm-2.s: Likewise. * testsuite/binutils-all/wasm32/prepared-section.d: Likewise. * testsuite/binutils-all/wasm32/prepared-section.s: Likewise. * testsuite/binutils-all/wasm32/wasm32.exp: New file, run tests. gas * config/tc-wasm32.h: New file: Add WebAssembly assembler target. * config/tc-wasm32.c: New file: Add WebAssembly assembler target. * Makefile.am: Add WebAssembly assembler target. * configure.tgt: Add WebAssembly assembler target. * doc/c-wasm32.texi: New file: Start documenting WebAssembly assembler. * doc/all.texi: Define WASM32. * doc/as.texinfo: Add WebAssembly entries. * NEWS: Mention the new support. * Makefile.in: Regenerate. * po/gas.pot: Regenerate. * po/POTFILES.in: Regenerate. * testsuite/gas/wasm32: New directory. * testsuite/gas/wasm32/allinsn.d: New file. * testsuite/gas/wasm32/allinsn.s: New file. * testsuite/gas/wasm32/illegal.l: New file. * testsuite/gas/wasm32/illegal.s: New file. * testsuite/gas/wasm32/illegal-2.l: New file. * testsuite/gas/wasm32/illegal-2.s: New file. * testsuite/gas/wasm32/illegal-3.l: New file. * testsuite/gas/wasm32/illegal-3.s: New file. * testsuite/gas/wasm32/illegal-4.l: New file. * testsuite/gas/wasm32/illegal-4.s: New file. * testsuite/gas/wasm32/illegal-5.l: New file. * testsuite/gas/wasm32/illegal-5.s: New file. * testsuite/gas/wasm32/illegal-6.l: New file. * testsuite/gas/wasm32/illegal-6.s: New file. * testsuite/gas/wasm32/illegal-7.l: New file. * testsuite/gas/wasm32/illegal-7.s: New file. * testsuite/gas/wasm32/illegal-8.l: New file. * testsuite/gas/wasm32/illegal-8.s: New file. * testsuite/gas/wasm32/illegal-9.l: New file. * testsuite/gas/wasm32/illegal-9.s: New file. * testsuite/gas/wasm32/illegal-10.l: New file. * testsuite/gas/wasm32/illegal-10.s: New file. * testsuite/gas/wasm32/illegal-11.l: New file. * testsuite/gas/wasm32/illegal-11.s: New file. * testsuite/gas/wasm32/illegal-12.l: New file. * testsuite/gas/wasm32/illegal-12.s: New file. * testsuite/gas/wasm32/illegal-13.l: New file. * testsuite/gas/wasm32/illegal-13.s: New file. * testsuite/gas/wasm32/illegal-14.l: New file. * testsuite/gas/wasm32/illegal-14.s: New file. * testsuite/gas/wasm32/illegal-15.l: New file. * testsuite/gas/wasm32/illegal-15.s: New file. * testsuite/gas/wasm32/illegal-16.l: New file. * testsuite/gas/wasm32/illegal-16.s: New file. * testsuite/gas/wasm32/illegal-17.l: New file. * testsuite/gas/wasm32/illegal-17.s: New file. * testsuite/gas/wasm32/illegal-18.l: New file. * testsuite/gas/wasm32/illegal-18.s: New file. * testsuite/gas/wasm32/illegal-19.l: New file. * testsuite/gas/wasm32/illegal-19.s: New file. * testsuite/gas/wasm32/illegal-20.l: New file. * testsuite/gas/wasm32/illegal-20.s: New file. * testsuite/gas/wasm32/illegal-21.l: New file. * testsuite/gas/wasm32/illegal-21.s: New file. * testsuite/gas/wasm32/illegal-22.l: New file. * testsuite/gas/wasm32/illegal-22.s: New file. * testsuite/gas/wasm32/illegal-24.l: New file. * testsuite/gas/wasm32/illegal-24.s: New file. * testsuite/gas/wasm32/illegal-25.l: New file. * testsuite/gas/wasm32/illegal-25.s: New file. * testsuite/gas/wasm32/reloc.d: New file. * testsuite/gas/wasm32/reloc.s: New file. * testsuite/gas/wasm32/wasm32.exp: New tests for WebAssembly architecture. opcodes * configure.ac: Add (empty) bfd_wasm32_arch target. * configure: Regenerate * po/opcodes.pot: Regenerate. include * opcode/wasm.h: New file to support wasm32 architecture. * elf/wasm32.h: Add R_WASM32_32 relocation. bfd * elf32-wasm32.c: Add relocation code, two relocs. * reloc.c: Add wasm32 relocations. * libbfd.h: Regenerate. * bfd-in2.h: Regenerate. * bfd/po/bfd.pot: Regenerate.
Diffstat (limited to 'gas/config')
-rw-r--r--gas/config/tc-wasm32.c821
-rw-r--r--gas/config/tc-wasm32.h89
2 files changed, 910 insertions, 0 deletions
diff --git a/gas/config/tc-wasm32.c b/gas/config/tc-wasm32.c
new file mode 100644
index 0000000..0b05ef1
--- /dev/null
+++ b/gas/config/tc-wasm32.c
@@ -0,0 +1,821 @@
+/* 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)
+ {
+ char *end_of_sig;
+
+ pltrel = 1;
+ code = 1;
+ input_line_pointer += 4;
+
+ 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 0000000..220ad56
--- /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