From f96bd6c2d7a3801fabbf9d834f7a29b752aa7532 Mon Sep 17 00:00:00 2001 From: Pip Cet Date: Thu, 30 Mar 2017 10:57:21 +0100 Subject: 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. --- gas/config/tc-wasm32.c | 821 +++++++++++++++++++++++++++++++++++++++++++++++++ gas/config/tc-wasm32.h | 89 ++++++ 2 files changed, 910 insertions(+) create mode 100644 gas/config/tc-wasm32.c create mode 100644 gas/config/tc-wasm32.h (limited to 'gas/config') 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 + +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 @got, @gotcode, and + @plt{__sigchar_}. */ + +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 -- cgit v1.1