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]

[PATCH] [WebAssembly] Skeleton support


This patch adds skeleton support for the WebAssembly architecture; BFD
constants, new (mostly empty) files, and a single substantial file,
bfd/wasm-module.c, which is a first attempt at a backend for
WebAssembly modules (files beginning with "\0asm").

If config.sub is updated to today's GNU version, "./configure
--target=wasm32-unknown-none --disable-gdb --enable-maintainer-mode
--disable-gas --disable-ld --disable-opcodes && make" succeeds and the
produced "nm" binary can read names/symbols from WebAssembly modules.

Obviously this isn't yet very useful, but I figured I had to start somewhere.

This is my first patch, so any advice or criticism that may help me
when it comes to future patches would be most welcome.

Thanks
Pip Cet

------
 bfd/ChangeLog               |  15 +
 bfd/Makefile.am             |   2 +
 bfd/Makefile.in             |   3 +
 bfd/archures.c              |   4 +
 bfd/bfd-in2.h               |   2 +
 bfd/config.bfd              |   6 +
 bfd/configure               |   2 +
 bfd/configure.ac            |   2 +
 bfd/cpu-wasm32.c            |  36 ++
 bfd/doc/webassembly.texi    |  29 ++
 bfd/elf32-wasm32.c          |  52 ++
 bfd/po/SRC-POTFILES.in      |   1 +
 bfd/targets.c               |   2 +
 bfd/wasm-module.c           | 814 +++++++++++++++++++++++++++++++
 include/ChangeLog           |   4 +
 include/elf/wasm32.h        |  28 ++

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 50e76c2dea..8ba59fe27e 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,18 @@
+2017-03-20  Pip Cet  <pipcet@gmail.com>
+
+    * Makefile.am: Add WebAssembly architecture.
+    * configure.ac: Likewise.
+    * targets.c: Likewise.
+    * config.bfd (targ_cpu): Likewise.
+    * archures.c: Likewise.
+    * cpu-wasm32.c: New file to support WebAssembly architecture.
+    * elf32-wasm32.c: Likewise.
+    * wasm-module.c: Initial backend for WebAssembly modules.
+    * doc/webassembly.texi: Start documentation for wasm-module.c.
+    * bfd-in2.h: Regenerate.
+    * Makefile.in: Regenerate.
+    * configure: Regenerate.
+
 2017-03-20  Alan Modra  <amodra@gmail.com>

     PR 21266
diff --git a/bfd/Makefile.am b/bfd/Makefile.am
index 0b0226306f..e3b536460e 100644
--- a/bfd/Makefile.am
+++ b/bfd/Makefile.am
@@ -169,6 +169,7 @@ ALL_MACHINES = \
     cpu-vax.lo \
     cpu-visium.lo \
     cpu-w65.lo \
+    cpu-wasm32.lo \
     cpu-we32k.lo \
     cpu-xc16x.lo \
     cpu-xgate.lo \
@@ -257,6 +258,7 @@ ALL_MACHINES_CFILES = \
     cpu-v850_rh850.c \
     cpu-vax.c \
     cpu-visium.c \
+    cpu-wasm32.c \
     cpu-w65.c \
     cpu-we32k.c \
     cpu-xc16x.c \
diff --git a/bfd/Makefile.in b/bfd/Makefile.in
index 096c7ef043..76446ce7c0 100644
--- a/bfd/Makefile.in
+++ b/bfd/Makefile.in
@@ -502,6 +502,7 @@ ALL_MACHINES = \
     cpu-vax.lo \
     cpu-visium.lo \
     cpu-w65.lo \
+    cpu-wasm32.lo \
     cpu-we32k.lo \
     cpu-xc16x.lo \
     cpu-xgate.lo \
@@ -590,6 +591,7 @@ ALL_MACHINES_CFILES = \
     cpu-v850_rh850.c \
     cpu-vax.c \
     cpu-visium.c \
+    cpu-wasm32.c \
     cpu-w65.c \
     cpu-we32k.c \
     cpu-xc16x.c \
@@ -1446,6 +1448,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-vax.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-visium.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-w65.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-wasm32.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-we32k.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-xc16x.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-xgate.Plo@am__quote@
diff --git a/bfd/archures.c b/bfd/archures.c
index c909db012d..dcf9be30b1 100644
--- a/bfd/archures.c
+++ b/bfd/archures.c
@@ -528,6 +528,8 @@ DESCRIPTION
 .#define bfd_mach_nios2r2    2
 .  bfd_arch_visium,    {* Visium *}
 .#define bfd_mach_visium    1
+.  bfd_arch_wasm32,
+.#define bfd_mach_wasm32        1
 .  bfd_arch_pru,    {* PRU *}
 .#define bfd_mach_pru    0
 .  bfd_arch_last
@@ -654,6 +656,7 @@ extern const bfd_arch_info_type bfd_v850_arch;
 extern const bfd_arch_info_type bfd_v850_rh850_arch;
 extern const bfd_arch_info_type bfd_vax_arch;
 extern const bfd_arch_info_type bfd_visium_arch;
+extern const bfd_arch_info_type bfd_wasm32_arch;
 extern const bfd_arch_info_type bfd_w65_arch;
 extern const bfd_arch_info_type bfd_we32k_arch;
 extern const bfd_arch_info_type bfd_xstormy16_arch;
@@ -746,6 +749,7 @@ static const bfd_arch_info_type * const
bfd_archures_list[] =
     &bfd_vax_arch,
     &bfd_visium_arch,
     &bfd_w65_arch,
+    &bfd_wasm32_arch,
     &bfd_we32k_arch,
     &bfd_xstormy16_arch,
     &bfd_xtensa_arch,
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 59403af698..432caafd32 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -2372,6 +2372,8 @@ enum bfd_architecture
 #define bfd_mach_nios2r2       2
   bfd_arch_visium,     /* Visium */
 #define bfd_mach_visium        1
+  bfd_arch_wasm32,
+#define bfd_mach_wasm32        1
   bfd_arch_pru,        /* PRU */
 #define bfd_mach_pru   0
   bfd_arch_last
diff --git a/bfd/config.bfd b/bfd/config.bfd
index 52db9a47f1..1235c2cb86 100644
--- a/bfd/config.bfd
+++ b/bfd/config.bfd
@@ -197,6 +197,7 @@ tilegx*)     targ_archs=bfd_tilegx_arch ;;
 tilepro*)     targ_archs=bfd_tilepro_arch ;;
 v850*)         targ_archs="bfd_v850_arch bfd_v850_rh850_arch" ;;
 visium*)     targ_archs=bfd_visium_arch ;;
+wasm32)         targ_archs=bfd_wasm32_arch ;;
 x86_64*)     targ_archs=bfd_i386_arch ;;
 xtensa*)     targ_archs=bfd_xtensa_arch ;;
 xgate)         targ_archs=bfd_xgate_arch ;;
@@ -1793,6 +1794,11 @@ case "${targ}" in
     targ_defvec=visium_elf32_vec
     ;;

+  wasm32-*-*)
+    targ_defvec=wasm32_elf32_vec
+    targ_selvecs="wasm_vec"
+    ;;
+
   we32k-*-*)
     targ_defvec=we32k_coff_vec
     ;;
diff --git a/bfd/configure b/bfd/configure
index 83256d25df..7cae4ae3d8 100755
--- a/bfd/configure
+++ b/bfd/configure
@@ -14569,6 +14569,8 @@ do
     ft32_elf32_vec)         tb="$tb elf32-ft32.lo elf32.lo $elf" ;;
     visium_elf32_vec)         tb="$tb elf32-visium.lo elf32.lo $elf" ;;
     w65_coff_vec)         tb="$tb coff-w65.lo reloc16.lo $coffgen" ;;
+    wasm_vec)                    tb="$tb wasm-module.lo" ;;
+    wasm32_elf32_vec)            tb="$tb elf32-wasm32.lo elf32.lo $elf" ;;
     we32k_coff_vec)         tb="$tb coff-we32k.lo $coffgen" ;;
     x86_64_coff_vec)         tb="$tb coff-x86_64.lo $coff"; target_size=64 ;;
     x86_64_elf32_vec)         tb="$tb elf64-x86-64.lo elf-ifunc.lo
elf-nacl.lo elf64.lo elf32.lo $elf"; target_size=64 ;;
diff --git a/bfd/configure.ac b/bfd/configure.ac
index ee0c537ea2..feb1231c91 100644
--- a/bfd/configure.ac
+++ b/bfd/configure.ac
@@ -700,6 +700,8 @@ do
     ft32_elf32_vec)         tb="$tb elf32-ft32.lo elf32.lo $elf" ;;
     visium_elf32_vec)         tb="$tb elf32-visium.lo elf32.lo $elf" ;;
     w65_coff_vec)         tb="$tb coff-w65.lo reloc16.lo $coffgen" ;;
+    wasm_vec)                    tb="$tb wasm-module.lo" ;;
+    wasm32_elf32_vec)            tb="$tb elf32-wasm32.lo elf32.lo $elf" ;;
     we32k_coff_vec)         tb="$tb coff-we32k.lo $coffgen" ;;
     x86_64_coff_vec)         tb="$tb coff-x86_64.lo $coff"; target_size=64 ;;
     x86_64_elf32_vec)         tb="$tb elf64-x86-64.lo elf-ifunc.lo
elf-nacl.lo elf64.lo elf32.lo $elf"; target_size=64 ;;
diff --git a/bfd/cpu-wasm32.c b/bfd/cpu-wasm32.c
new file mode 100644
index 0000000000..929778d531
--- /dev/null
+++ b/bfd/cpu-wasm32.c
@@ -0,0 +1,36 @@
+/* BFD support for the WebAssembly target
+   Copyright (C) 1994-2017 Free Software Foundation, Inc.
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   This program 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 of the License, or
+   (at your option) any later version.
+
+   This program 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 this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "libbfd.h"
+#include "libiberty.h"
+
+#define N(number, print, default, next)  \
+{  32, 32, 8, bfd_arch_wasm32, number, "wasm32", "wasm32", 4,
default, bfd_default_compatible, \
+   bfd_default_scan, bfd_arch_default_fill, next }
+
+static const bfd_arch_info_type arch_info_struct[] =
+{
+  N (bfd_mach_wasm32,      "wasm32",   TRUE, NULL)
+};
+
+const bfd_arch_info_type bfd_wasm32_arch =
+  N (bfd_mach_wasm32, "wasm32", TRUE, & arch_info_struct[0]);
diff --git a/bfd/doc/webassembly.texi b/bfd/doc/webassembly.texi
new file mode 100644
index 0000000000..25aeb5d614
--- /dev/null
+++ b/bfd/doc/webassembly.texi
@@ -0,0 +1,29 @@
+@section WebAssembly backend
+The WebAssembly module file format, at present, is a very simple
+object file format with up to 11 numbered sections plus named
+``custom'' sections. At present, there is no standard for
+relocations or symbols, though a @code{"name"} subsection can assign
+names to function indices and local variables.
+
+As such, it offers no real advantages over ELF, and intermediate ELF
+files can be used to produce WebAssembly modules. The WebAssembly
+backend aims to enable the opposite: reading a WebAssembly module and
+producing an ELF file containing the same information, which can then
+be manipulated and inspected with standard tools.
+
+When writing WebAssembly modules, the WebAssembly backend attempts to
+determine based on the section name whether to use a numeric section
+id, a named section header, or to include the section verbatim,
+assuming it already contains any necessary header.
+
+Function names are supported as symbols; local names and WebAssembly
+relocation sections are currently unsupported.
+
+@menu
+* File layout::
+@end menu
+
+@node File layout, WebAssembly
+@subsection File layout
+For a description of the WebAssembly file format, see
+@url{https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md}.
diff --git a/bfd/elf32-wasm32.c b/bfd/elf32-wasm32.c
new file mode 100644
index 0000000000..cb56acab00
--- /dev/null
+++ b/bfd/elf32-wasm32.c
@@ -0,0 +1,52 @@
+/* 32-bit ELF for the WebAssembly target
+   Copyright (C) 1999-2017 Free Software Foundation, Inc.
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   This program 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 of the License, or
+   (at your option) any later version.
+
+   This program 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 this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "libbfd.h"
+#include "elf-bfd.h"
+#include "bfd_stdint.h"
+#include "elf/wasm32.h"
+
+#define ELF_ARCH        bfd_arch_wasm32
+#define ELF_TARGET_ID        0x4157 /* 'WA' */
+#define ELF_MACHINE_CODE    0x4157 /* 'WA' */
+/* FIXME we don't have paged executables, see
+ * https://github.com/pipcet/binutils-gdb/issues/4 */
+#define ELF_MAXPAGESIZE        4096
+
+#define TARGET_LITTLE_SYM       wasm32_elf32_vec
+#define TARGET_LITTLE_NAME    "elf32-wasm32"
+
+#define elf_backend_can_gc_sections          1
+#define elf_backend_rela_normal              1
+/* 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_DYNAMIC_INTERPRETER  "/sbin/elf-dynamic-interpreter.so"
+
+#define elf_backend_want_got_plt 1
+#define elf_backend_plt_readonly 1
+#define elf_backend_got_header_size 0
+
+#include "elf32-target.h"
diff --git a/bfd/po/SRC-POTFILES.in b/bfd/po/SRC-POTFILES.in
index 7ecdb0a11f..bf45ca8e1a 100644
--- a/bfd/po/SRC-POTFILES.in
+++ b/bfd/po/SRC-POTFILES.in
@@ -141,6 +141,7 @@ cpu-v850_rh850.c
 cpu-vax.c
 cpu-visium.c
 cpu-w65.c
+cpu-wasm32.c
 cpu-we32k.c
 cpu-xc16x.c
 cpu-xgate.c
diff --git a/bfd/targets.c b/bfd/targets.c
index 1a7c6b87d6..f9074b6ae5 100644
--- a/bfd/targets.c
+++ b/bfd/targets.c
@@ -893,6 +893,8 @@ extern const bfd_target vax_aout_nbsd_vec;
 extern const bfd_target vax_elf32_vec;
 extern const bfd_target visium_elf32_vec;
 extern const bfd_target w65_coff_vec;
+extern const bfd_target wasm_vec;
+extern const bfd_target wasm32_elf32_vec;
 extern const bfd_target we32k_coff_vec;
 extern const bfd_target x86_64_coff_vec;
 extern const bfd_target x86_64_elf32_vec;
diff --git a/bfd/wasm-module.c b/bfd/wasm-module.c
new file mode 100644
index 0000000000..f8d78b1d73
--- /dev/null
+++ b/bfd/wasm-module.c
@@ -0,0 +1,814 @@
+/* BFD back-end for WebAssembly modules.
+   Copyright (C) 1990-2017 Free Software Foundation, Inc.
+
+   Based on srec.c, mmo.c, and binary.c
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   This program 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 of the License, or
+   (at your option) any later version.
+
+   This program 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 this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+/* The WebAssembly module format is a simple object file format
+ * including up to 11 numbered sections, plus any number of named
+ * "custom" sections. It is described at
+ * https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md. */
+
+#include "sysdep.h"
+#include "alloca-conf.h"
+#include "bfd.h"
+#include "sysdep.h"
+#include <limits.h>
+#include "bfd_stdint.h"
+#include "libiberty.h"
+#include "libbfd.h"
+
+/* From elf-eh-frame.c: */
+/* If *ITER hasn't reached END yet, read the next byte into *RESULT and
+   move onto the next byte.  Return true on success.  */
+
+static inline bfd_boolean
+read_byte (bfd_byte **iter, bfd_byte *end, unsigned char *result)
+{
+  if (*iter >= end)
+    return FALSE;
+  *result = *((*iter)++);
+  return TRUE;
+}
+
+/* Move *ITER over LENGTH bytes, or up to END, whichever is closer.
+   Return true it was possible to move LENGTH bytes.  */
+
+static inline bfd_boolean
+skip_bytes (bfd_byte **iter, bfd_byte *end, bfd_size_type length)
+{
+  if ((bfd_size_type) (end - *iter) < length)
+    {
+      *iter = end;
+      return FALSE;
+    }
+  *iter += length;
+  return TRUE;
+}
+
+/* Move *ITER over an leb128, stopping at END.  Return true if the end
+   of the leb128 was found.  */
+
+static bfd_boolean
+skip_leb128 (bfd_byte **iter, bfd_byte *end)
+{
+  unsigned char byte;
+  do
+    if (!read_byte (iter, end, &byte))
+      return FALSE;
+  while (byte & 0x80);
+  return TRUE;
+}
+
+/* Like skip_leb128, but treat the leb128 as an unsigned value and
+   store it in *VALUE.  */
+
+static bfd_boolean
+read_uleb128 (bfd_byte **iter, bfd_byte *end, bfd_vma *value)
+{
+  bfd_byte *start, *p;
+
+  start = *iter;
+  if (!skip_leb128 (iter, end))
+    return FALSE;
+
+  p = *iter;
+  *value = *--p;
+  while (p > start)
+    *value = (*value << 7) | (*--p & 0x7f);
+
+  return TRUE;
+}
+
+static bfd_vma
+wasm_get_uleb128 (bfd* abfd, bfd_boolean* error)
+{
+  bfd_byte byte;
+  bfd_vma value = 0;
+  int shift = 0;
+
+  do
+    {
+      if (bfd_bread (&byte, 1, abfd) != 1)
+        goto error_return;
+
+      value += (byte & 0x7f) << shift;
+
+      shift += 7;
+    }
+  while (byte & 0x80);
+
+  return value;
+
+ error_return:
+  *error = TRUE;
+  return (bfd_vma)-1;
+}
+
+static bfd_boolean
+bfd_write_uleb128 (bfd *abfd, bfd_vma v)
+{
+  do
+    {
+      bfd_byte c = v & 0x7f;
+      v >>= 7;
+
+      if (v)
+        c |= 0x80;
+
+      if (bfd_bwrite (&c, 1, abfd) != 1)
+        return FALSE;
+    }
+  while (v);
+
+  return TRUE;
+}
+
+typedef struct
+{
+  asymbol *symbols;
+  bfd_size_type symcount;
+} tdata_type;
+
+static bfd_boolean
+wasm_get_magic (bfd *abfd, bfd_boolean *errorptr)
+{
+  bfd_byte magic[4];
+  if (bfd_bread (magic, (bfd_size_type) 4, abfd) != 4)
+    {
+      if (bfd_get_error () != bfd_error_file_truncated)
+        *errorptr = TRUE;
+      return FALSE;
+    }
+
+  if (magic[0] != 0 ||
+      magic[1] != 'a' ||
+      magic[2] != 's' ||
+      magic[3] != 'm')
+    {
+      *errorptr = TRUE;
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+static int
+wasm_get_byte (bfd *abfd, bfd_boolean *errorptr)
+{
+  bfd_byte byte;
+  if (bfd_bread (&byte, (bfd_size_type) 1, abfd) != 1)
+    {
+      if (bfd_get_error () != bfd_error_file_truncated)
+        *errorptr = TRUE;
+      return EOF;
+    }
+
+  return byte;
+}
+
+static bfd_boolean
+wasm_get_version (bfd *abfd, bfd_boolean *errorptr)
+{
+  bfd_byte vers[4];
+  if (bfd_bread (vers, (bfd_size_type) 4, abfd) != 4)
+    {
+      *errorptr = TRUE;
+      return FALSE;
+    }
+
+  /* Don't attempt to parse newer versions, which are likely to
+   * require code changes. */
+  if (vers[0] != 1 || vers[1] || vers[2] || vers[3])
+    return FALSE;
+
+  return TRUE;
+}
+
+#define WASM_NUMBERED_SECTIONS 11
+
+static const char *
+wasm_section_code_to_name (bfd_byte section_code)
+{
+  switch (section_code) {
+  case 1:
+    return ".wasm.type";
+  case 2:
+    return ".wasm.import";
+  case 3:
+    return ".wasm.function";
+  case 4:
+    return ".wasm.table";
+  case 5:
+    return ".wasm.memory";
+  case 6:
+    return ".wasm.global";
+  case 7:
+    return ".wasm.export";
+  case 8:
+    return ".wasm.start";
+  case 9:
+    return ".wasm.element";
+  case 10:
+    return ".wasm.code";
+  case 11:
+    return ".wasm.data";
+  }
+
+  return NULL;
+}
+
+static int
+wasm_section_name_to_code (const char *name)
+{
+  if (strcmp (name, ".wasm.type") == 0)
+    return 1;
+  if (strcmp (name, ".wasm.import") == 0)
+    return 2;
+  if (strcmp (name, ".wasm.function") == 0)
+    return 3;
+  if (strcmp (name, ".wasm.table") == 0)
+    return 4;
+  if (strcmp (name, ".wasm.memory") == 0)
+    return 5;
+  if (strcmp (name, ".wasm.global") == 0)
+    return 6;
+  if (strcmp (name, ".wasm.export") == 0)
+    return 7;
+  if (strcmp (name, ".wasm.start") == 0)
+    return 8;
+  if (strcmp (name, ".wasm.element") == 0)
+    return 9;
+  if (strcmp (name, ".wasm.code") == 0)
+    return 10;
+  if (strcmp (name, ".wasm.data") == 0)
+    return 11;
+
+  return -1;
+}
+
+static bfd_boolean
+bfd_wasm_read_header (bfd *abfd, bfd_boolean *error)
+{
+  if (!wasm_get_magic (abfd, error))
+    goto error_return;
+
+  if (!wasm_get_version (abfd, error))
+    goto error_return;
+
+  return TRUE;
+
+ error_return:
+  return FALSE;
+}
+
+static bfd_boolean
+wasm_scan_name_function_section (bfd *abfd, sec_ptr asect,
+                                 void *data ATTRIBUTE_UNUSED)
+{
+  if (!asect)
+    return FALSE;
+
+  if (strcmp (asect->name, ".wasm.name") != 0)
+    return FALSE;
+
+  bfd_byte *p = asect->contents;
+  bfd_byte *end = asect->contents + asect->size;
+
+  while (p && p < end)
+    {
+      if (*p++ == 1)
+        break;
+      bfd_vma payload_size;
+      if (!read_uleb128 (&p, end, &payload_size))
+        return FALSE;
+
+      p += payload_size;
+    }
+
+  if (!p || p >= end)
+    return FALSE;
+
+  bfd_vma payload_size;
+  if (!read_uleb128 (&p, end, &payload_size))
+    return FALSE;
+
+  if (p + payload_size > end)
+    return FALSE;
+
+  end = p + payload_size;
+
+  bfd_vma symcount = 0;
+  if (!read_uleb128 (&p, end, &symcount))
+    return FALSE;
+
+  tdata_type *tdata = abfd->tdata.any;
+  tdata->symcount = symcount;
+  symcount = 0;
+
+  bfd_size_type sym_allocated = 0;
+  asymbol *symbols = NULL;
+  sec_ptr space_function_index = bfd_make_section_with_flags (abfd,
".space.function_index", SEC_READONLY | SEC_CODE);
+  if (!space_function_index)
+    space_function_index = bfd_get_section_by_name (abfd,
".space.function_index");
+
+  for (bfd_vma i = 0; p < end && i < tdata->symcount; i++)
+    {
+      bfd_vma index;
+      bfd_vma len;
+      char *name;
+
+      if (!read_uleb128 (&p, end, &index) ||
+          !read_uleb128 (&p, end, &len))
+        return FALSE;
+
+      name = bfd_alloc (abfd, len + 1);
+
+      name[len] = 0;
+
+      memcpy (name, p, len);
+
+      p += len;
+
+      if (symcount == sym_allocated)
+        {
+          sym_allocated *= 2;
+          if (sym_allocated == 0)
+            sym_allocated = 512;
+
+          symbols = bfd_realloc (symbols, sym_allocated * sizeof (asymbol));
+        }
+
+      asymbol *sym = &symbols[symcount++];
+      sym->the_bfd = abfd;
+      sym->name = name;
+      sym->value = index;
+      sym->flags = BSF_GLOBAL | BSF_FUNCTION;
+      sym->section = space_function_index;
+      sym->udata.p = NULL;
+    }
+
+  tdata->symbols = symbols;
+  tdata->symcount = symcount;
+  abfd->symcount = symcount;
+
+  return TRUE;
+}
+
+static bfd_boolean
+wasm_scan (bfd *abfd)
+{
+  bfd_boolean error = FALSE;
+  bfd_vma vma = 0x80000000;
+  int section_code;
+
+  if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
+    goto error_return;
+
+  if (!bfd_wasm_read_header (abfd, &error))
+    goto error_return;
+
+  while ((section_code = wasm_get_byte (abfd, &error)) != EOF)
+    {
+      asection *bfdsec;
+      if (section_code)
+        {
+          const char *name = wasm_section_code_to_name (section_code);
+          char *secname;
+
+          if (!name)
+            goto error_return;
+
+          secname = strdup (name);
+
+          bfdsec = bfd_make_section_anyway_with_flags (abfd, secname,
SEC_HAS_CONTENTS);
+          if (bfdsec == NULL)
+            goto error_return;
+
+          bfdsec->vma = vma;
+          bfdsec->lma = vma;
+          bfdsec->size = wasm_get_uleb128 (abfd, &error);
+          bfdsec->filepos = bfd_tell (abfd);
+          bfdsec->alignment_power = 0;
+        }
+      else
+        {
+          bfd_vma payload_len = wasm_get_uleb128 (abfd, &error);
+          file_ptr section_start = bfd_tell (abfd);
+          bfd_vma namelen = wasm_get_uleb128 (abfd, &error);
+          if (namelen == (bfd_vma)-1)
+            goto error_return;
+          char *name = bfd_zalloc (abfd, namelen+1);
+          name[namelen] = 0;
+          if (bfd_bread (name, namelen, abfd) != namelen)
+            goto error_return;
+
+          char *secname;
+          asprintf (&secname, ".wasm.%s", name);
+
+          bfdsec = bfd_make_section_anyway_with_flags (abfd, secname,
SEC_HAS_CONTENTS);
+          if (bfdsec == NULL)
+            goto error_return;
+
+          bfdsec->vma = vma;
+          bfdsec->lma = vma;
+          bfdsec->size = payload_len - bfd_tell (abfd) + section_start;
+          bfdsec->filepos = bfd_tell (abfd);
+          bfdsec->alignment_power = 0;
+        }
+
+      bfdsec->contents = bfd_zalloc (abfd, bfdsec->size);
+      if (bfdsec->size && !bfdsec->contents)
+        goto error_return;
+
+      if (bfd_bread (bfdsec->contents, bfdsec->size, abfd) != bfdsec->size)
+        goto error_return;
+
+      vma += bfdsec->size;
+    }
+
+  /* Make sure we're at actual EOF. There's no indication in the
+   * WebAssembly format of how long the file is supposed to be. */
+  if (error)
+    goto error_return;
+
+  if (!wasm_scan_name_function_section (abfd, bfd_get_section_by_name
(abfd, ".wasm.name"), NULL))
+    return TRUE;
+
+  return TRUE;
+
+ error_return:
+  return FALSE;
+}
+
+static void
+wasm_register_section (bfd *abfd ATTRIBUTE_UNUSED,
+                       asection *asect, void *fsarg)
+{
+  sec_ptr *numbered_sections = fsarg;
+  int index = wasm_section_name_to_code (asect->name);
+
+  if (index == -1)
+    return;
+
+  numbered_sections[index] = asect;
+}
+
+struct compute_section_arg
+{
+  bfd_vma pos;
+  bfd_boolean failed;
+};
+
+static void
+wasm_compute_custom_section_file_position (bfd *abfd, sec_ptr asect,
+                                           void *fsarg)
+{
+  struct compute_section_arg *fs = fsarg;
+
+  if (fs->failed)
+    return;
+
+  int index = wasm_section_name_to_code (asect->name);
+
+  if (index != -1)
+    return;
+
+  if (CONST_STRNEQ (asect->name, ".wasm."))
+    {
+      const char *name = asect->name + strlen (".wasm.");
+      bfd_size_type payload_len = asect->size;
+      bfd_size_type name_len = strlen (name);
+      bfd_size_type nl = name_len;
+
+      payload_len += name_len;
+
+      do
+        {
+          payload_len++;
+          nl >>= 7;
+        }
+      while (nl);
+
+      bfd_seek (abfd, fs->pos, SEEK_SET);
+      if (!bfd_write_uleb128 (abfd, 0) ||
+          !bfd_write_uleb128 (abfd, payload_len) ||
+          !bfd_write_uleb128 (abfd, name_len) ||
+          bfd_bwrite (name, name_len, abfd) != name_len)
+        goto error_return;
+      fs->pos = asect->filepos = bfd_tell (abfd);
+    }
+  else
+    {
+      asect->filepos = fs->pos;
+    }
+
+
+  fs->pos += asect->size;
+
+  return;
+
+ error_return:
+  fs->failed = TRUE;
+  return;
+}
+
+static bfd_boolean
+wasm_compute_section_file_positions (bfd *abfd)
+{
+  bfd_byte magic[] = { 0x00, 'a', 's', 'm' };
+  bfd_byte vers[] = { 0x01, 0x00, 0x00, 0x00 };
+
+  bfd_seek (abfd, (bfd_vma)0, SEEK_SET);
+
+  if (bfd_bwrite (magic, 4, abfd) != 4 ||
+      bfd_bwrite (vers, 4, abfd) != 4)
+    return FALSE;
+
+  sec_ptr numbered_sections[WASM_NUMBERED_SECTIONS+1];
+
+  for (int i = 0; i <= WASM_NUMBERED_SECTIONS; i++)
+    numbered_sections[i] = 0;
+
+  bfd_map_over_sections (abfd, wasm_register_section, numbered_sections);
+
+  struct compute_section_arg fs;
+  fs.pos = 8;
+  for (int i = 0; i <= WASM_NUMBERED_SECTIONS; i++)
+    {
+      sec_ptr sec = numbered_sections[i];
+      if (!sec)
+        continue;
+      bfd_seek (abfd, fs.pos, SEEK_SET);
+      bfd_size_type size = sec->size;
+      if (!bfd_write_uleb128 (abfd, i) ||
+          !bfd_write_uleb128 (abfd, size))
+        return FALSE;
+      fs.pos = sec->filepos = bfd_tell (abfd);
+      fs.pos += size;
+    }
+
+  fs.failed = FALSE;
+
+  bfd_map_over_sections (abfd, wasm_compute_custom_section_file_position, &fs);
+
+  if (fs.failed)
+    return FALSE;
+
+  return TRUE;
+}
+
+
+static bfd_boolean
+wasm_set_section_contents (bfd *abfd,
+                           sec_ptr section,
+                           const void *location,
+                           file_ptr offset,
+                           bfd_size_type count)
+{
+  if (count == 0)
+    return TRUE;
+
+  if (!abfd->output_has_begun &&
+      !wasm_compute_section_file_positions (abfd))
+    return FALSE;
+
+  if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0
+      || bfd_bwrite (location, count, abfd) != count)
+    return FALSE;
+
+  return TRUE;
+}
+
+static bfd_boolean
+_bfd_wasm_write_object_contents (bfd* abfd)
+{
+  bfd_byte magic[] = { 0x00, 'a', 's', 'm' };
+  bfd_byte vers[] = { 0x01, 0x00, 0x00, 0x00 };
+
+  if (bfd_seek (abfd, 0, SEEK_SET) != 0)
+    return FALSE;
+
+  if (bfd_bwrite (magic, 4, abfd) != 4 ||
+      bfd_bwrite (vers, 4, abfd) != 4)
+    return FALSE;
+
+  return TRUE;
+}
+
+static bfd_boolean
+wasm_mkobject (bfd *abfd)
+{
+  tdata_type *tdata = (tdata_type *) bfd_alloc (abfd, sizeof (tdata_type));
+
+  if (!tdata)
+    return FALSE;
+
+  tdata->symbols = NULL;
+  tdata->symcount = 0;
+
+  abfd->tdata.any = tdata;
+
+  return TRUE;
+}
+
+static int
+wasm_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
+                     struct bfd_link_info *info ATTRIBUTE_UNUSED)
+{
+  return 8;
+}
+
+static long
+wasm_get_symtab_upper_bound (bfd *abfd)
+{
+  tdata_type *tdata = abfd->tdata.any;
+
+  return (tdata->symcount + 1) * (sizeof (asymbol));
+}
+
+static long
+wasm_canonicalize_symtab (bfd *abfd, asymbol **alocation)
+{
+  tdata_type *tdata = abfd->tdata.any;
+  size_t i;
+
+  for (i = 0; i < tdata->symcount; i++)
+    alocation[i] = &tdata->symbols[i];
+  alocation[i] = NULL;
+
+  return tdata->symcount;
+}
+
+static asymbol *
+wasm_make_empty_symbol (bfd *abfd)
+{
+  bfd_size_type amt = sizeof (asymbol);
+  asymbol *new_symbol = (asymbol *) bfd_zalloc (abfd, amt);
+
+  if (!new_symbol)
+    return NULL;
+  new_symbol->the_bfd = abfd;
+  return new_symbol;
+}
+
+static void
+wasm_print_symbol (bfd *abfd,
+                   void * filep,
+                   asymbol *symbol,
+                   bfd_print_symbol_type how)
+{
+  FILE *file = (FILE *) filep;
+
+  switch (how)
+    {
+    case bfd_print_symbol_name:
+      fprintf (file, "%s", symbol->name);
+      break;
+
+    default:
+      bfd_print_symbol_vandf (abfd, filep, symbol);
+      fprintf (file, " %-5s %s", symbol->section->name, symbol->name);
+    }
+}
+
+static void
+wasm_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED,
+                      asymbol *symbol,
+                      symbol_info *ret)
+{
+  bfd_symbol_info (symbol, ret);
+}
+
+static const bfd_target *
+wasm_object_p (bfd *abfd)
+{
+  bfd_byte b[8];
+
+  if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
+      || bfd_bread (b, (bfd_size_type) 8, abfd) != 8)
+    return NULL;
+
+  if (b[0] != 0 || b[1] != 'a' || b[2] != 's' || b[3] != 'm' ||
+      b[4] != 1 || b[5] != 0 || b[6] != 0 || b[7] != 0)
+    {
+      bfd_set_error (bfd_error_wrong_format);
+      return NULL;
+    }
+
+  if (! wasm_mkobject (abfd) || ! wasm_scan (abfd))
+    return NULL;
+
+  if (! bfd_default_set_arch_mach (abfd, bfd_arch_wasm32, 0))
+    return NULL;
+
+  if (abfd->symcount > 0)
+    abfd->flags |= HAS_SYMS;
+
+  return abfd->xvec;
+}
+
+/* BFD_JUMP_TABLE_WRITE */
+#define wasm_set_arch_mach                       _bfd_generic_set_arch_mach
+
+/* BFD_JUMP_TABLE_SYMBOLS */
+#define wasm_get_symbol_version_string
_bfd_nosymbols_get_symbol_version_string
+#define wasm_bfd_is_local_label_name       bfd_generic_is_local_label_name
+#define wasm_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *,
asymbol *)) bfd_false)
+#define wasm_get_lineno                   _bfd_nosymbols_get_lineno
+#define wasm_find_nearest_line            _bfd_nosymbols_find_nearest_line
+#define wasm_find_line                    _bfd_nosymbols_find_line
+#define wasm_find_inliner_info            _bfd_nosymbols_find_inliner_info
+#define wasm_bfd_make_debug_symbol        _bfd_nosymbols_bfd_make_debug_symbol
+#define wasm_read_minisymbols             _bfd_generic_read_minisymbols
+#define wasm_minisymbol_to_symbol         _bfd_generic_minisymbol_to_symbol
+
+/* BFD_JUMP_TABLE_LINK */
+#define wasm_bfd_get_relocated_section_contents
bfd_generic_get_relocated_section_contents
+#define wasm_bfd_relax_section            bfd_generic_relax_section
+#define wasm_bfd_gc_sections              bfd_generic_gc_sections
+#define wasm_bfd_lookup_section_flags     bfd_generic_lookup_section_flags
+#define wasm_bfd_merge_sections           bfd_generic_merge_sections
+#define wasm_bfd_is_group_section         bfd_generic_is_group_section
+#define wasm_bfd_discard_group            bfd_generic_discard_group
+#define wasm_bfd_link_hash_table_create  _bfd_generic_link_hash_table_create
+#define wasm_bfd_link_add_symbols        _bfd_generic_link_add_symbols
+#define wasm_bfd_link_just_syms          _bfd_generic_link_just_syms
+#define wasm_bfd_copy_link_hash_symbol_type
_bfd_generic_copy_link_hash_symbol_type
+#define wasm_bfd_final_link              _bfd_generic_final_link
+#define wasm_bfd_link_split_section      _bfd_generic_link_split_section
+#define wasm_section_already_linked      _bfd_generic_section_already_linked
+#define wasm_bfd_define_common_symbol     bfd_generic_define_common_symbol
+#define wasm_bfd_link_check_relocs       _bfd_generic_link_check_relocs
+
+const bfd_target wasm_vec =
+{
+  "wasm",               /* Name */
+  bfd_target_unknown_flavour,
+  BFD_ENDIAN_LITTLE,
+  BFD_ENDIAN_LITTLE,
+  (HAS_SYMS | WP_TEXT),             /* Object flags. */
+  (SEC_CODE | SEC_DATA | SEC_HAS_CONTENTS), /* Section flags */
+  0,                    /* Leading underscore */
+  ' ',                  /* AR_pad_char */
+  255,                  /* AR_max_namelen */
+  0,                /* match priority.  */
+  /* Routines to byte-swap various sized integers from the data sections */
+  bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+  bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+  bfd_getl16, bfd_getl_signed_16, bfd_putl16,
+
+  /* Routines to byte-swap various sized integers from the file headers */
+  bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+  bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+  bfd_getl16, bfd_getl_signed_16, bfd_putl16,
+
+  {
+    _bfd_dummy_target,
+    wasm_object_p,    /* bfd_check_format.  */
+    _bfd_dummy_target,
+    _bfd_dummy_target,
+  },
+  {
+    bfd_false,
+    wasm_mkobject,
+    _bfd_generic_mkarchive,
+    bfd_false,
+  },
+  {                /* bfd_write_contents.  */
+    bfd_false,
+    _bfd_wasm_write_object_contents,
+    _bfd_write_archive_contents,
+    bfd_false,
+  },
+
+  BFD_JUMP_TABLE_GENERIC (_bfd_generic),
+  BFD_JUMP_TABLE_COPY (_bfd_generic),
+  BFD_JUMP_TABLE_CORE (_bfd_nocore),
+  BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
+  BFD_JUMP_TABLE_SYMBOLS (wasm),
+  BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
+  BFD_JUMP_TABLE_WRITE (wasm),
+  BFD_JUMP_TABLE_LINK (wasm),
+  BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
+
+  NULL,
+
+  NULL,
+};
diff --git a/include/ChangeLog b/include/ChangeLog
index eacfeb9ac9..dc467fd384 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,7 @@
+2017-03-20  Pip Cet  <pipcet@gmail.com>
+
+    * elf/wasm32.h: New file to support WebAssembly architecture.
+
 2017-03-16  Nick Clifton  <nickc@redhat.com>

     * elf/common.h (GNU_BUILD_ATTRIBUTE_SHORT_ENUM): New GNU BUILD
diff --git a/include/elf/wasm32.h b/include/elf/wasm32.h
new file mode 100644
index 0000000000..4edd66fa8c
--- /dev/null
+++ b/include/elf/wasm32.h
@@ -0,0 +1,28 @@
+/* ELF support for BFD for the WebAssembly target
+   Copyright (C) 1998-2017 Free Software Foundation, Inc.
+
+   This program 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 of the License, or
+   (at your option) any later version.
+
+   This program 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 this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#ifndef _ELF_WASM32_H
+#define _ELF_WASM32_H
+
+#include "elf/reloc-macros.h"
+
+/* Relocation types.  */
+
+START_RELOC_NUMBERS (elf_wasm32_reloc_type)
+END_RELOC_NUMBERS (R_WASM32_max = 1)
+
+#endif /* _ELF_WASM32_H */

Attachment: binutils-wasm-001.diff
Description: Text document


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]