public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* Re: [PATCH] [WebAssembly] Disassembler support
@ 2017-04-06 19:39 Simon Marchi
  2017-04-07  0:00 ` Pip Cet
  0 siblings, 1 reply; 15+ messages in thread
From: Simon Marchi @ 2017-04-06 19:39 UTC (permalink / raw)
  To: pipcet; +Cc: binutils

Hi Pip,

With gcc 4.8.4 (default on Ubuntu 14.04, so not thaaat old), I get this:

/home/emaisin/src/binutils-gdb/opcodes/wasm32-dis.c: In function ‘print_insn_wasm32’:
/home/emaisin/src/binutils-gdb/opcodes/wasm32-dis.c:408:34: error: ‘DECIMAL_DIG’ undeclared (first use in this function)
           prin (stream, " %.*g", DECIMAL_DIG, fconstant);
                                  ^
/home/emaisin/src/binutils-gdb/opcodes/wasm32-dis.c:408:34: note: each undeclared identifier is reported only once for each function it appears in

According to [1], DECIMAL_DIG appeared in C99, and the default mode for gcc 4.8.4
is C89.  It compiles fine when I add -std=c99 to CFLAGS.  If people are ok with
requiring that version of the C language, it would be nice to add it to CFLAGS in
the Makefile.

Thanks,

Simon

[1] http://en.cppreference.com/w/c/types/limits

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] [WebAssembly] Disassembler support
  2017-04-06 19:39 [PATCH] [WebAssembly] Disassembler support Simon Marchi
@ 2017-04-07  0:00 ` Pip Cet
  2017-04-07  9:32   ` Nick Clifton
  0 siblings, 1 reply; 15+ messages in thread
From: Pip Cet @ 2017-04-07  0:00 UTC (permalink / raw)
  To: Simon Marchi; +Cc: binutils, nickc

[-- Attachment #1: Type: text/plain, Size: 2340 bytes --]

Hello Simon,
thanks for catching that!

It certainly wasn't my intention to introduce any new C language
requirements, and in this case it's also not quite the right thing to
do to begin with: we want to print IEEE 754 floats with the right
precision, no matter what our host floating-point format is.
Unfortunately, I can't find a way to do that, thus the DECIMAL_DIG
usage.

I'm attaching a patch to use a fixed value of 17, which is the right
thing to do for a 52-bit mantissa. It still won't do the right thing
on hosts whose double type is insufficient to represent IEEE 754
doubles.

Suggested change log entry:
opcodes/:
2017-04-06  Pip Cet  <pipcet@gmail.com>

    * wasm32-dis.c (print_insn_wasm32): Use a fixed value (valid for
    IEEE 754 doubles) instead of DECIMAL_DIG.

diff --git a/opcodes/wasm32-dis.c b/opcodes/wasm32-dis.c
index 80e4ffe81a..f150163a80 100644
--- a/opcodes/wasm32-dis.c
+++ b/opcodes/wasm32-dis.c
@@ -23,13 +23,22 @@
 #include "opintl.h"
 #include "safe-ctype.h"
 #include "floatformat.h"
-#include <float.h>
 #include "libiberty.h"
 #include "elf-bfd.h"
 #include "elf/internal.h"
 #include "elf/wasm32.h"
 #include <stdint.h>

+/* Number of decimal digits, n, such that any floating-point number in the
+   widest supported floating type with pmax radix b digits can be rounded
+   to a floating-point number with n decimal digits and back again without
+   change to the value,
+
+    pmax * log10(b)            if b is a power of 10
+    ceil(1 + pmax * log10(b))    otherwise
+*/
+#define DECIMAL_DIG_IEEE754 17
+
 /* Type names for blocks and signatures.  */
 #define BLOCK_TYPE_NONE              0x40
 #define BLOCK_TYPE_I32               0x7f
@@ -405,7 +414,7 @@ print_insn_wasm32 (bfd_vma pc, struct
disassemble_info *info)
           if (ret < 0)
             return -1;
           len += ret;
-          prin (stream, " %.*g", DECIMAL_DIG, fconstant);
+          prin (stream, " %.*g", DECIMAL_DIG_IEEE754, fconstant);
           break;

         case wasm_constant_f64:
@@ -413,7 +422,7 @@ print_insn_wasm32 (bfd_vma pc, struct
disassemble_info *info)
           if (ret < 0)
             return -1;
           len += ret;
-          prin (stream, " %.*g", DECIMAL_DIG, fconstant);
+          prin (stream, " %.*g", DECIMAL_DIG_IEEE754, fconstant);
           break;

         case wasm_call:

[-- Attachment #2: binutils-wasm-009.diff --]
[-- Type: text/plain, Size: 1540 bytes --]

diff --git a/opcodes/wasm32-dis.c b/opcodes/wasm32-dis.c
index 80e4ffe81a..f150163a80 100644
--- a/opcodes/wasm32-dis.c
+++ b/opcodes/wasm32-dis.c
@@ -23,13 +23,22 @@
 #include "opintl.h"
 #include "safe-ctype.h"
 #include "floatformat.h"
-#include <float.h>
 #include "libiberty.h"
 #include "elf-bfd.h"
 #include "elf/internal.h"
 #include "elf/wasm32.h"
 #include <stdint.h>
 
+/* Number of decimal digits, n, such that any floating-point number in the
+   widest supported floating type with pmax radix b digits can be rounded
+   to a floating-point number with n decimal digits and back again without
+   change to the value,
+
+	pmax * log10(b)			if b is a power of 10
+	ceil(1 + pmax * log10(b))	otherwise
+*/
+#define DECIMAL_DIG_IEEE754 17
+
 /* Type names for blocks and signatures.  */
 #define BLOCK_TYPE_NONE              0x40
 #define BLOCK_TYPE_I32               0x7f
@@ -405,7 +414,7 @@ print_insn_wasm32 (bfd_vma pc, struct disassemble_info *info)
           if (ret < 0)
             return -1;
           len += ret;
-          prin (stream, " %.*g", DECIMAL_DIG, fconstant);
+          prin (stream, " %.*g", DECIMAL_DIG_IEEE754, fconstant);
           break;
 
         case wasm_constant_f64:
@@ -413,7 +422,7 @@ print_insn_wasm32 (bfd_vma pc, struct disassemble_info *info)
           if (ret < 0)
             return -1;
           len += ret;
-          prin (stream, " %.*g", DECIMAL_DIG, fconstant);
+          prin (stream, " %.*g", DECIMAL_DIG_IEEE754, fconstant);
           break;
 
         case wasm_call:

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] [WebAssembly] Disassembler support
  2017-04-07  0:00 ` Pip Cet
@ 2017-04-07  9:32   ` Nick Clifton
  2017-04-07 18:22     ` Pip Cet
  0 siblings, 1 reply; 15+ messages in thread
From: Nick Clifton @ 2017-04-07  9:32 UTC (permalink / raw)
  To: Pip Cet, Simon Marchi; +Cc: binutils

Hi Pip,

> +/* Number of decimal digits, n, such that any floating-point number in the
> +   widest supported floating type with pmax radix b digits can be rounded
> +   to a floating-point number with n decimal digits and back again without
> +   change to the value,
> +
> +    pmax * log10(b)            if b is a power of 10
> +    ceil(1 + pmax * log10(b))    otherwise
> +*/
> +#define DECIMAL_DIG_IEEE754 17

Wouldn't it just be easier to provide a value for DECIMAL_DIG if it is not
currently defined ?  That way, if it is defined, you can be sure that you
are getting the correct value for the host system.

Cheers
  Nick

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] [WebAssembly] Disassembler support
  2017-04-07  9:32   ` Nick Clifton
@ 2017-04-07 18:22     ` Pip Cet
  2017-04-07 22:05       ` Alan Modra
  0 siblings, 1 reply; 15+ messages in thread
From: Pip Cet @ 2017-04-07 18:22 UTC (permalink / raw)
  To: Nick Clifton; +Cc: Simon Marchi, binutils

Hi Nick,
On Fri, Apr 7, 2017 at 9:32 AM, Nick Clifton <nickc@redhat.com> wrote:
>> +#define DECIMAL_DIG_IEEE754 17
>
> Wouldn't it just be easier to provide a value for DECIMAL_DIG if it is not
> currently defined ?  That way, if it is defined, you can be sure that you
> are getting the correct value for the host system.

I don't think that would be the right thing to do--we want to preserve
WebAssembly's f64s, not host doubles. If our host system provides long
doubles, DECIMAL_DIG might be larger than 17, even though 17 is enough
to represent each IEEE 754 double (i.e. each WebAssembly f64)
uniquely. So forcing it to 17 will do the right thing on hosts where
doubles are good enough to preserve IEEE 754 doubles.

Thanks,
Pip

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] [WebAssembly] Disassembler support
  2017-04-07 18:22     ` Pip Cet
@ 2017-04-07 22:05       ` Alan Modra
  2017-04-07 22:57         ` Pip Cet
  0 siblings, 1 reply; 15+ messages in thread
From: Alan Modra @ 2017-04-07 22:05 UTC (permalink / raw)
  To: Pip Cet; +Cc: Nick Clifton, Simon Marchi, binutils

Building --enable-targets=all is broken on Ubuntu 16.04 where gcc is:
gcc (Ubuntu 4.9.4-2ubuntu1~16.04) 4.9.4

.../opcodes/wasm32-dis.c: In function ‘print_insn_wasm32’:
.../wasm32-dis.c:408:34: error: ‘DECIMAL_DIG’ undeclared (first use in this function)
           prin (stream, " %.*g", DECIMAL_DIG, fconstant);
                                  ^
This boils down to the fact that you can't use a C99 feature unless
C99 is default for your compiler or you build with -std=c99.  I
wouldn't be against requiring C99 to build binutils, but that policy
decision hasn't been made yet..

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] [WebAssembly] Disassembler support
  2017-04-07 22:05       ` Alan Modra
@ 2017-04-07 22:57         ` Pip Cet
  2017-04-09 10:35           ` Alan Modra
  0 siblings, 1 reply; 15+ messages in thread
From: Pip Cet @ 2017-04-07 22:57 UTC (permalink / raw)
  To: Alan Modra; +Cc: Nick Clifton, Simon Marchi, binutils

Hi Alan,
you're right; it was my mistake to use DECIMAL_DIG in the first place.
I still believe the right fix is to avoid that constant entirely, and
use one specific to IEEE 754 doubles, which are what we want to print
anyway; but if you can think of a better fix, please let me know.

Thanks,
Pip

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] [WebAssembly] Disassembler support
  2017-04-07 22:57         ` Pip Cet
@ 2017-04-09 10:35           ` Alan Modra
  2017-04-09 13:20             ` Pip Cet
  0 siblings, 1 reply; 15+ messages in thread
From: Alan Modra @ 2017-04-09 10:35 UTC (permalink / raw)
  To: Pip Cet; +Cc: Nick Clifton, Simon Marchi, binutils

On Fri, Apr 07, 2017 at 10:56:57PM +0000, Pip Cet wrote:
> Hi Alan,
> you're right; it was my mistake to use DECIMAL_DIG in the first place.
> I still believe the right fix is to avoid that constant entirely, and
> use one specific to IEEE 754 doubles, which are what we want to print
> anyway; but if you can think of a better fix, please let me know.

I hadn't been following the thread, and have only just now seen
Simon's email.  Sorry to gang up on you.  :)

I think what I'd be inclined to do is print your WebAssembly floats
and doubles in %a format.  You can probably do that without converting
to host doubles.  If that idea doesn't fly, just use a constant
specific to your target floats and doubles, hoping the host is
reasonably compatible.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] [WebAssembly] Disassembler support
  2017-04-09 10:35           ` Alan Modra
@ 2017-04-09 13:20             ` Pip Cet
  2017-04-09 23:39               ` Alan Modra
  0 siblings, 1 reply; 15+ messages in thread
From: Pip Cet @ 2017-04-09 13:20 UTC (permalink / raw)
  To: Alan Modra; +Cc: Nick Clifton, Simon Marchi, binutils

Hi Alan,

On Sun, Apr 9, 2017 at 10:35 AM, Alan Modra <amodra@gmail.com> wrote:
> On Fri, Apr 07, 2017 at 10:56:57PM +0000, Pip Cet wrote:
>> Hi Alan,
>> you're right; it was my mistake to use DECIMAL_DIG in the first place.
>> I still believe the right fix is to avoid that constant entirely, and
>> use one specific to IEEE 754 doubles, which are what we want to print
>> anyway; but if you can think of a better fix, please let me know.
>
> I hadn't been following the thread, and have only just now seen
> Simon's email.  Sorry to gang up on you.  :)

No worries at all, at least from this side! I appreciate the suggestions.

> I think what I'd be inclined to do is print your WebAssembly floats
> and doubles in %a format.

Wouldn't that also be a C99 thing? I know I looked into using %a and
decided it wasn't a good idea, probably for that reason. (Possibly,
also, because I personally find it hard to read, but that's less of a
concern).

> You can probably do that without converting
> to host doubles.

Well, I certainly would have to convert 32-bit floats to doubles
before calling printf...

> If that idea doesn't fly, just use a constant
> specific to your target floats and doubles, hoping the host is
> reasonably compatible.

I think that's what my patch does, and I think it's the best thing to
do for now; should non-IEEE floats become significant again,
floatformat should probably provide its own printing functions.

Thanks for your comments,
Pip

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] [WebAssembly] Disassembler support
  2017-04-09 13:20             ` Pip Cet
@ 2017-04-09 23:39               ` Alan Modra
  2017-04-10  0:11                 ` Pip Cet
  0 siblings, 1 reply; 15+ messages in thread
From: Alan Modra @ 2017-04-09 23:39 UTC (permalink / raw)
  To: Pip Cet; +Cc: Nick Clifton, Simon Marchi, binutils

On Sun, Apr 09, 2017 at 01:20:16PM +0000, Pip Cet wrote:
> On Sun, Apr 9, 2017 at 10:35 AM, Alan Modra <amodra@gmail.com> wrote:
> > I think what I'd be inclined to do is print your WebAssembly floats
> > and doubles in %a format.
> 
> Wouldn't that also be a C99 thing? I know I looked into using %a and
> decided it wasn't a good idea, probably for that reason. (Possibly,
> also, because I personally find it hard to read, but that's less of a
> concern).
> 
> > You can probably do that without converting
> > to host doubles.
> 
> Well, I certainly would have to convert 32-bit floats to doubles
> before calling printf...

What I meant by %a format and not converting to host double is:
- read 4-byte or 8-byte value
- convert to host endian with bfd_get_32 or bfd_get_64
- extract sign, mantissa and exponent
- decode special cases, nan, inf
- print sign if negative, mantissa as hex, exponent as decimal to give
  [-]0xL.MMMMMMMMMMMMMp[+-]EEE (L being the leading implicit 1 or 0 if
  denormal, M mantissa, E exponent).
See glibc/stdio_common/printf_fphex.c

> > If that idea doesn't fly, just use a constant
> > specific to your target floats and doubles, hoping the host is
> > reasonably compatible.
> 
> I think that's what my patch does, and I think it's the best thing to
> do for now; should non-IEEE floats become significant again,
> floatformat should probably provide its own printing functions.

Yeah, I'm fine with your DECIMAL_DIG_IEEE754 patch, except to query
whether you really want a precision of 17 for wasm_constant_f32,
in which case forget the #define and use a hardcoded %.9g there and
%.17g for wasm_constant_f64.  Patch to do that preapproved.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] [WebAssembly] Disassembler support
  2017-04-09 23:39               ` Alan Modra
@ 2017-04-10  0:11                 ` Pip Cet
  2017-04-10  5:32                   ` Alan Modra
  0 siblings, 1 reply; 15+ messages in thread
From: Pip Cet @ 2017-04-10  0:11 UTC (permalink / raw)
  To: Alan Modra; +Cc: Nick Clifton, Simon Marchi, binutils

[-- Attachment #1: Type: text/plain, Size: 479 bytes --]

On Sun, Apr 9, 2017 at 11:39 PM, Alan Modra <amodra@gmail.com> wrote:
> Yeah, I'm fine with your DECIMAL_DIG_IEEE754 patch, except to query
> whether you really want a precision of 17 for wasm_constant_f32,
> in which case forget the #define and use a hardcoded %.9g there and
> %.17g for wasm_constant_f64.  Patch to do that preapproved.


Thank you. I've attached a patch to do that (I don't have
write-after-approval privileges, so I'd be grateful if someone could
apply it).

[-- Attachment #2: binutils-wasm-010.diff --]
[-- Type: text/plain, Size: 1369 bytes --]

diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog
index 73a0071a93..1e8763e307 100644
--- a/opcodes/ChangeLog
+++ b/opcodes/ChangeLog
@@ -1,3 +1,8 @@
+2017-04-09  Pip Cet  <pipcet@gmail.com>
+
+	* wasm32-dis.c (print_insn_wasm32): Avoid DECIMAL_DIG, specify
+	appropriate floating-point precision directly.
+
 2017-04-07  Alan Modra  <amodra@gmail.com>
 
 	* ppc-opc.c (powerpc_opcodes <mviwsplt, mvidsplt, lvexbx, lvepxl,
diff --git a/opcodes/wasm32-dis.c b/opcodes/wasm32-dis.c
index 80e4ffe81a..18295d08e1 100644
--- a/opcodes/wasm32-dis.c
+++ b/opcodes/wasm32-dis.c
@@ -23,7 +23,6 @@
 #include "opintl.h"
 #include "safe-ctype.h"
 #include "floatformat.h"
-#include <float.h>
 #include "libiberty.h"
 #include "elf-bfd.h"
 #include "elf/internal.h"
@@ -405,7 +404,7 @@ print_insn_wasm32 (bfd_vma pc, struct disassemble_info *info)
           if (ret < 0)
             return -1;
           len += ret;
-          prin (stream, " %.*g", DECIMAL_DIG, fconstant);
+          prin (stream, " %.9g", fconstant);
           break;
 
         case wasm_constant_f64:
@@ -413,7 +412,7 @@ print_insn_wasm32 (bfd_vma pc, struct disassemble_info *info)
           if (ret < 0)
             return -1;
           len += ret;
-          prin (stream, " %.*g", DECIMAL_DIG, fconstant);
+          prin (stream, " %.17g", fconstant);
           break;
 
         case wasm_call:

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] [WebAssembly] Disassembler support
  2017-04-10  0:11                 ` Pip Cet
@ 2017-04-10  5:32                   ` Alan Modra
  0 siblings, 0 replies; 15+ messages in thread
From: Alan Modra @ 2017-04-10  5:32 UTC (permalink / raw)
  To: Pip Cet; +Cc: Nick Clifton, Simon Marchi, binutils

On Mon, Apr 10, 2017 at 12:10:28AM +0000, Pip Cet wrote:
> Thank you. I've attached a patch to do that (I don't have
> write-after-approval privileges, so I'd be grateful if someone could
> apply it).

Applied.  Please ask for write privilege at overseers@sourceware.org
nominating me as a sponsor.

You might also like to add the following to your .git/config in the
[core] section.

        whitespace = indent-with-non-tab,space-before-tab,trailing-space

I'm not asking you post a patch fixing whitespace!  That can be done
once you have write privilege..

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] [WebAssembly] Disassembler support
  2017-04-07  0:29   ` Pip Cet
@ 2017-04-07  7:41     ` Nick Clifton
  0 siblings, 0 replies; 15+ messages in thread
From: Nick Clifton @ 2017-04-07  7:41 UTC (permalink / raw)
  To: Pip Cet; +Cc: binutils

Hi Pip,

> Do you have any preferences as to whether it is okay to send the
> linker changes as one large patch rather than several shorter ones?
> The latter would be a little effort for me, but would obviously be
> worth it if you think it's likely this code will go through multiple
> review cycles.

Nope, one large patch should be fine.

Cheers
  Nick


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] [WebAssembly] Disassembler support
  2017-04-06 16:22 ` Nick Clifton
@ 2017-04-07  0:29   ` Pip Cet
  2017-04-07  7:41     ` Nick Clifton
  0 siblings, 1 reply; 15+ messages in thread
From: Pip Cet @ 2017-04-07  0:29 UTC (permalink / raw)
  To: Nick Clifton; +Cc: binutils

Hi Nick,
Thank you, and thanks for fixing the problem! I'd indeed neglected to
provide an updated patch after Pedro's change to the disassembler API
yesterday.

Do you have any preferences as to whether it is okay to send the
linker changes as one large patch rather than several shorter ones?
The latter would be a little effort for me, but would obviously be
worth it if you think it's likely this code will go through multiple
review cycles.

Thanks again,
Pip

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] [WebAssembly] Disassembler support
  2017-03-31 23:18 Pip Cet
@ 2017-04-06 16:22 ` Nick Clifton
  2017-04-07  0:29   ` Pip Cet
  0 siblings, 1 reply; 15+ messages in thread
From: Nick Clifton @ 2017-04-06 16:22 UTC (permalink / raw)
  To: Pip Cet, binutils

Hi Pip,

> opcodes/:
> 2017-03-31  Pip Cet  <pipcet@gmail.com>
> 
>     * Makefile.am: Add wasm32-dis.c.
>     * configure.ac: Add wasm32-dis.c to wasm32 target.
>     * disassemble.c: Add wasm32 disassembler code.
>     * wasm32-dis.c: New file.
>     * Makefile.in: Regenerate.
>     * configure: Regenerate.
>     * po/POTFILES.in: Regenerate.
> 
> gas/:
> 2017-03-31  Pip Cet  <pipcet@gmail.com>
> 
>     * testsuite/gas/wasm32/allinsn.d: Adjust test for disassembler
>     changes.
>     * testsuite/gas/wasm32/disass.d: New test.
>     * testsuite/gas/wasm32/disass.s: New test.
>     * testsuite/gas/wasm32/disass-2.d: New test.
>     * testsuite/gas/wasm32/disass-2.s: New test.
>     * testsuite/gas/wasm32/reloc.d: Adjust test for changed reloc names.
>     * testsuite/gas/wasm32/reloc.s: Update test for changed assembler
>     syntax.
>     * testsuite/gas/wasm32/wasm32.exp: Run new tests.  Expect allinsn
>     test to succeed.
> 
> include/:
> 2017-03-31  Pip Cet  <pipcet@gmail.com>
> 
>     * dis-asm.h: Add prototypes for wasm32 disassembler.

Approved and applied.

Note - there was one problem:

> +static void
> +parse_wasm32_disassembler_options (struct disassemble_info *info,
> +                                   char *opts)
> +{
 
The second parameter to this function is a const char * not a char *.
I fixed this as part of the check-in.

Cheers
  Nick

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH] [WebAssembly] Disassembler support
@ 2017-03-31 23:18 Pip Cet
  2017-04-06 16:22 ` Nick Clifton
  0 siblings, 1 reply; 15+ messages in thread
From: Pip Cet @ 2017-03-31 23:18 UTC (permalink / raw)
  To: binutils

[-- Attachment #1: Type: text/plain, Size: 29390 bytes --]

This patch adds support for disassembling WebAssembly opcodes.  It
includes some tests and un-xfails the all-instructions test.

Comments and improvements would be most welcome.

Thanks,
Pip

Suggested change log entries:
opcodes/:
2017-03-31  Pip Cet  <pipcet@gmail.com>

    * Makefile.am: Add wasm32-dis.c.
    * configure.ac: Add wasm32-dis.c to wasm32 target.
    * disassemble.c: Add wasm32 disassembler code.
    * wasm32-dis.c: New file.
    * Makefile.in: Regenerate.
    * configure: Regenerate.
    * po/POTFILES.in: Regenerate.

gas/:
2017-03-31  Pip Cet  <pipcet@gmail.com>

    * testsuite/gas/wasm32/allinsn.d: Adjust test for disassembler
    changes.
    * testsuite/gas/wasm32/disass.d: New test.
    * testsuite/gas/wasm32/disass.s: New test.
    * testsuite/gas/wasm32/disass-2.d: New test.
    * testsuite/gas/wasm32/disass-2.s: New test.
    * testsuite/gas/wasm32/reloc.d: Adjust test for changed reloc names.
    * testsuite/gas/wasm32/reloc.s: Update test for changed assembler
    syntax.
    * testsuite/gas/wasm32/wasm32.exp: Run new tests.  Expect allinsn
    test to succeed.

include/:
2017-03-31  Pip Cet  <pipcet@gmail.com>

    * dis-asm.h: Add prototypes for wasm32 disassembler.

----------
diff --git a/gas/testsuite/gas/wasm32/allinsn.d
b/gas/testsuite/gas/wasm32/allinsn.d
index 06124be4d6..c594c72501 100644
--- a/gas/testsuite/gas/wasm32/allinsn.d
+++ b/gas/testsuite/gas/wasm32/allinsn.d
@@ -11,7 +11,7 @@ Disassembly of section .text:
    0:    02 40               block\[\]
    2:    0c 00               br 0
    4:    0d 00               br_if 0
-   6:    0e 01 01 01         br_table 1 1
+   6:    0e 01 01 01         br_table 1 1 1
    a:    10 00               call 0x0
    c:    11 00 00            call_indirect 0 0
    f:    1a                  drop
@@ -22,12 +22,12 @@ Disassembly of section .text:
   14:    8d                  f32.ceil
   15:    43 d0 0f 49         f32.const 3.141590118408203125
   19:    40
-  1a:    b2                  f32.convert_s_i32
-  1b:    b4                  f32.convert_s_i64
-  1c:    b3                  f32.convert_u_i32
-  1d:    b5                  f32.convert_u_i64
+  1a:    b2                  f32.convert_s/i32
+  1b:    b4                  f32.convert_s/i64
+  1c:    b3                  f32.convert_u/i32
+  1d:    b5                  f32.convert_u/i64
   1e:    98                  f32.copysign
-  1f:    b6                  f32.demote_f64
+  1f:    b6                  f32.demote/f64
   20:    95                  f32.div
   21:    5b                  f32.eq
   22:    8e                  f32.floor
@@ -42,7 +42,7 @@ Disassembly of section .text:
   2d:    5c                  f32.ne
   2e:    90                  f32.nearest
   2f:    8c                  f32.neg
-  30:    be                  f32.reinterpret_i32
+  30:    be                  f32.reinterpret/i32
   31:    91                  f32.sqrt
   32:    38 00 00            f32.store a=0 0
   35:    93                  f32.sub
@@ -53,10 +53,10 @@ Disassembly of section .text:
   3a:    44 97 5f 4f         f64.const 3.14158999999999976088e\+200
   3e:    fd bc 6a 90
   42:    69
-  43:    b7                  f64.convert_s_i32
-  44:    b9                  f64.convert_s_i64
-  45:    b8                  f64.convert_u_i32
-  46:    ba                  f64.convert_u_i64
+  43:    b7                  f64.convert_s/i32
+  44:    b9                  f64.convert_s/i64
+  45:    b8                  f64.convert_u/i32
+  46:    ba                  f64.convert_u/i64
   47:    a6                  f64.copysign
   48:    a3                  f64.div
   49:    61                  f64.eq
@@ -72,14 +72,14 @@ Disassembly of section .text:
   55:    62                  f64.ne
   56:    9e                  f64.nearest
   57:    9a                  f64.neg
-  58:    bb                  f64.promote_f32
-  59:    bf                  f64.reinterpret_i64
+  58:    bb                  f64.promote/f32
+  59:    bf                  f64.reinterpret/i64
   5a:    9f                  f64.sqrt
   5b:    39 00 00            f64.store a=0 0
   5e:    a1                  f64.sub
   5f:    9d                  f64.trunc
-  60:    23 00               get_global 0 <\$got>
-  62:    20 00               get_local 0 <\$dpc>
+  60:    23 00               get_global 0
+  62:    20 00               get_local 0
   64:    6a                  i32.add
   65:    71                  i32.and
   66:    67                  i32.clz
@@ -107,7 +107,7 @@ Disassembly of section .text:
   8a:    47                  i32.ne
   8b:    72                  i32.or
   8c:    69                  i32.popcnt
-  8d:    bc                  i32.reinterpret_f32
+  8d:    bc                  i32.reinterpret/f32
   8e:    6f                  i32.rem_s
   8f:    70                  i32.rem_u
   90:    77                  i32.rotl
@@ -119,11 +119,11 @@ Disassembly of section .text:
   98:    3b 00 00            i32.store16 a=0 0
   9b:    3a 00 00            i32.store8 a=0 0
   9e:    6b                  i32.sub
-  9f:    a8                  i32.trunc_s_f32
-  a0:    aa                  i32.trunc_s_f64
-  a1:    a9                  i32.trunc_u_f32
-  a2:    ab                  i32.trunc_u_f64
-  a3:    a7                  i32.wrap_i64
+  9f:    a8                  i32.trunc_s/f32
+  a0:    aa                  i32.trunc_s/f64
+  a1:    a9                  i32.trunc_u/f32
+  a2:    ab                  i32.trunc_u/f64
+  a3:    a7                  i32.wrap/i64
   a4:    73                  i32.xor
   a5:    7c                  i64.add
   a6:    83                  i64.and
@@ -136,8 +136,8 @@ Disassembly of section .text:
   b4:    80                  i64.div_u
   b5:    51                  i64.eq
   b6:    50                  i64.eqz
-  b7:    ac                  i64.extend_s_i32
-  b8:    ad                  i64.extend_u_i32
+  b7:    ac                  i64.extend_s/i32
+  b8:    ad                  i64.extend_u/i32
   b9:    59                  i64.ge_s
   ba:    5a                  i64.ge_u
   bb:    55                  i64.gt_s
@@ -157,7 +157,7 @@ Disassembly of section .text:
   d7:    52                  i64.ne
   d8:    84                  i64.or
   d9:    7b                  i64.popcnt
-  da:    bd                  i64.reinterpret_f64
+  da:    bd                  i64.reinterpret/f64
   db:    81                  i64.rem_s
   dc:    82                  i64.rem_u
   dd:    89                  i64.rotl
@@ -170,20 +170,20 @@ Disassembly of section .text:
   e8:    3e 00 00            i64.store32 a=0 0
   eb:    3c 00 00            i64.store8 a=0 0
   ee:    7d                  i64.sub
-  ef:    ae                  i64.trunc_s_f32
-  f0:    b0                  i64.trunc_s_f64
-  f1:    af                  i64.trunc_u_f32
-  f2:    b1                  i64.trunc_u_f64
+  ef:    ae                  i64.trunc_s/f32
+  f0:    b0                  i64.trunc_s/f64
+  f1:    af                  i64.trunc_u/f32
+  f2:    b1                  i64.trunc_u/f64
   f3:    85                  i64.xor
   f4:    04 7f               if\[i\]
   f6:    03 7e               loop\[l\]
   f8:    01                  nop
   f9:    0f                  return
   fa:    1b                  select
-  fb:    24 00               set_global 0 <\$got>
-  fd:    21 00               set_local 0 <\$dpc>
+  fb:    24 00               set_global 0
+  fd:    21 00               set_local 0
   ff:    60                  f32.ge
- 100:    08                  .byte 08
+ 100:    08                  .byte 0x08

  101:    7f                  i64.div_s
  102:    7e                  i64.mul
@@ -194,5 +194,5 @@ Disassembly of section .text:
  107:    7e                  i64.mul
  108:    7f                  i64.div_s
  109:    00                  unreachable
- 10a:    22 00               tee_local 0 <\$dpc>
+ 10a:    22 00               tee_local 0
     ...
diff --git a/gas/testsuite/gas/wasm32/disass-2.d
b/gas/testsuite/gas/wasm32/disass-2.d
new file mode 100644
index 0000000000..b6aa7954de
--- /dev/null
+++ b/gas/testsuite/gas/wasm32/disass-2.d
@@ -0,0 +1,9 @@
+#as:
+#objdump: -d -Mglobals
+#name: disass-2.d
+^dump.o:     file format elf32-wasm32$
+
+^Disassembly of section .text:$
+^00000000 <.text>:$
+^   0:    20 00               get_local 0$
+^   2:    23 00               get_global 0 <\$got>$
diff --git a/gas/testsuite/gas/wasm32/disass-2.s
b/gas/testsuite/gas/wasm32/disass-2.s
new file mode 100644
index 0000000000..bed9410505
--- /dev/null
+++ b/gas/testsuite/gas/wasm32/disass-2.s
@@ -0,0 +1,3 @@
+        .text
+        get_local 0
+        get_global 0
diff --git a/gas/testsuite/gas/wasm32/disass.d
b/gas/testsuite/gas/wasm32/disass.d
new file mode 100644
index 0000000000..2708137916
--- /dev/null
+++ b/gas/testsuite/gas/wasm32/disass.d
@@ -0,0 +1,9 @@
+#as:
+#objdump: -d -Mregisters,globals
+#name: disass.d
+^dump.o:     file format elf32-wasm32$
+
+^Disassembly of section .text:$
+^00000000 <.text>:$
+^   0:    20 00               get_local 0 <\$dpc>$
+^   2:    23 00               get_global 0 <\$got>$
diff --git a/gas/testsuite/gas/wasm32/disass.s
b/gas/testsuite/gas/wasm32/disass.s
new file mode 100644
index 0000000000..bed9410505
--- /dev/null
+++ b/gas/testsuite/gas/wasm32/disass.s
@@ -0,0 +1,3 @@
+        .text
+        get_local 0
+        get_global 0
diff --git a/gas/testsuite/gas/wasm32/reloc.d b/gas/testsuite/gas/wasm32/reloc.d
index 9317e6e9a3..9dc54e7760 100644
--- a/gas/testsuite/gas/wasm32/reloc.d
+++ b/gas/testsuite/gas/wasm32/reloc.d
@@ -9,10 +9,11 @@ Disassembly of section .text:
 00000000 <.text>:
    0:    41 80 80 80         i32.const 0
    4:    80 00
-            1: R_ASMJS_LEB128_PLT    f
+            1: R_WASM32_PLT_SIG    __sigchar_FiiiiiiiE
+            1: R_WASM32_LEB128_PLT    f
    6:    41 80 80 80         i32.const 0
    a:    80 00
-            7: R_ASMJS_LEB128_GOT    x
+            7: R_WASM32_LEB128_GOT    x
    c:    41 80 80 80         i32.const 0
   10:    80 00
-            d: R_ASMJS_LEB128_GOT_CODE    f
+            d: R_WASM32_LEB128_GOT_CODE    f
diff --git a/gas/testsuite/gas/wasm32/reloc.s b/gas/testsuite/gas/wasm32/reloc.s
index 8cdfd58b96..cd34591b2c 100644
--- a/gas/testsuite/gas/wasm32/reloc.s
+++ b/gas/testsuite/gas/wasm32/reloc.s
@@ -1,3 +1,3 @@
-        i32.const f@plt
+        i32.const f@plt{__sigchar_FiiiiiiiE}
         i32.const x@got
         i32.const f@gotcode
diff --git a/gas/testsuite/gas/wasm32/wasm32.exp
b/gas/testsuite/gas/wasm32/wasm32.exp
index e6d1819677..49c14e45f9 100644
--- a/gas/testsuite/gas/wasm32/wasm32.exp
+++ b/gas/testsuite/gas/wasm32/wasm32.exp
@@ -21,8 +21,6 @@
 # wasm32 assembler testsuite.

 if [istarget wasm32-*-*] {
-    # no disassembler support yet
-    setup_xfail "wasm32-*-*"
     run_dump_test "allinsn"
     # no GOT/PLT relocs yet.
     setup_xfail "wasm32-*-*"
@@ -55,4 +53,6 @@ if [istarget wasm32-*-*] {
     # illegal-23 has become legal
     run_list_test "illegal-24"
     run_list_test "illegal-25"
+    run_dump_test "disass"
+    run_dump_test "disass-2"
 }
diff --git a/include/dis-asm.h b/include/dis-asm.h
index f0544509d0..a6b65431de 100644
--- a/include/dis-asm.h
+++ b/include/dis-asm.h
@@ -318,6 +318,7 @@ extern int print_insn_v850        (bfd_vma,
disassemble_info *);
 extern int print_insn_vax        (bfd_vma, disassemble_info *);
 extern int print_insn_visium        (bfd_vma, disassemble_info *);
 extern int print_insn_w65        (bfd_vma, disassemble_info *);
+extern int print_insn_wasm32        (bfd_vma, disassemble_info *);
 extern int print_insn_xc16x        (bfd_vma, disassemble_info *);
 extern int print_insn_xgate             (bfd_vma, disassemble_info *);
 extern int print_insn_xstormy16        (bfd_vma, disassemble_info *);
@@ -343,10 +344,12 @@ extern void print_riscv_disassembler_options (FILE *);
 extern void print_arm_disassembler_options (FILE *);
 extern void print_arc_disassembler_options (FILE *);
 extern void print_s390_disassembler_options (FILE *);
+extern void print_wasm32_disassembler_options (FILE *);
 extern bfd_boolean aarch64_symbol_is_valid (asymbol *, struct
disassemble_info *);
 extern bfd_boolean arm_symbol_is_valid (asymbol *, struct disassemble_info *);
 extern void disassemble_init_powerpc (struct disassemble_info *);
 extern void disassemble_init_s390 (struct disassemble_info *);
+extern void disassemble_init_wasm32 (struct disassemble_info *);
 extern const disasm_options_t *disassembler_options_powerpc (void);
 extern const disasm_options_t *disassembler_options_arm (void);
 extern const disasm_options_t *disassembler_options_s390 (void);
diff --git a/opcodes/Makefile.am b/opcodes/Makefile.am
index b43c679bff..1ac6bb1128 100644
--- a/opcodes/Makefile.am
+++ b/opcodes/Makefile.am
@@ -259,6 +259,7 @@ TARGET_LIBOPCODES_CFILES = \
     visium-dis.c \
     visium-opc.c \
     w65-dis.c \
+    wasm32-dis.c \
     xc16x-asm.c \
     xc16x-desc.c \
     xc16x-dis.c \
diff --git a/opcodes/configure.ac b/opcodes/configure.ac
index ca982924e6..a9fbfd61f1 100644
--- a/opcodes/configure.ac
+++ b/opcodes/configure.ac
@@ -348,7 +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_wasm32_arch)        ta="$ta wasm32-dis.lo" ;;
     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" ;;
diff --git a/opcodes/disassemble.c b/opcodes/disassemble.c
index eef06584f4..dd7d3a32b7 100644
--- a/opcodes/disassemble.c
+++ b/opcodes/disassemble.c
@@ -94,6 +94,7 @@
 #define ARCH_vax
 #define ARCH_visium
 #define ARCH_w65
+#define ARCH_wasm32
 #define ARCH_xstormy16
 #define ARCH_xc16x
 #define ARCH_xgate
@@ -474,6 +475,11 @@ disassembler (bfd *abfd)
       disassemble = print_insn_w65;
       break;
 #endif
+#ifdef ARCH_wasm32
+    case bfd_arch_wasm32:
+      disassemble = print_insn_wasm32;
+      break;
+#endif
 #ifdef ARCH_xgate
     case bfd_arch_xgate:
       disassemble = print_insn_xgate;
@@ -580,6 +586,9 @@ disassembler_usage (FILE *stream ATTRIBUTE_UNUSED)
 #ifdef ARCH_s390
   print_s390_disassembler_options (stream);
 #endif
+#ifdef ARCH_wasm32
+  print_wasm32_disassembler_options (stream);
+#endif

   return;
 }
@@ -650,6 +659,11 @@ disassemble_init_for_target (struct
disassemble_info * info)
       disassemble_init_powerpc (info);
       break;
 #endif
+#ifdef ARCH_wasm32
+    case bfd_arch_wasm32:
+      disassemble_init_wasm32 (info);
+      break;
+#endif
 #ifdef ARCH_s390
     case bfd_arch_s390:
       disassemble_init_s390 (info);
diff --git a/opcodes/wasm32-dis.c b/opcodes/wasm32-dis.c
new file mode 100644
index 0000000000..d3858880c0
--- /dev/null
+++ b/opcodes/wasm32-dis.c
@@ -0,0 +1,505 @@
+/* Opcode printing code for the WebAssembly target
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+   This file is part of libopcodes.
+
+   This library 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.
+
+   It 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 "dis-asm.h"
+#include "opintl.h"
+#include "safe-ctype.h"
+#include "floatformat.h"
+#include <float.h>
+#include "libiberty.h"
+#include "elf-bfd.h"
+#include "elf/internal.h"
+#include "elf/wasm32.h"
+#include <stdint.h>
+
+/* 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
+
+enum wasm_class
+  {
+    wasm_typed,
+    wasm_special,
+    wasm_break,
+    wasm_break_if,
+    wasm_break_table,
+    wasm_return,
+    wasm_call,
+    wasm_call_import,
+    wasm_call_indirect,
+    wasm_get_local,
+    wasm_set_local,
+    wasm_tee_local,
+    wasm_drop,
+    wasm_constant_i32,
+    wasm_constant_i64,
+    wasm_constant_f32,
+    wasm_constant_f64,
+    wasm_unary,
+    wasm_binary,
+    wasm_conv,
+    wasm_load,
+    wasm_store,
+    wasm_select,
+    wasm_relational,
+    wasm_eqz,
+    wasm_current_memory,
+    wasm_grow_memory,
+    wasm_signature
+  };
+
+struct wasm32_private_data
+{
+  bfd_boolean print_registers;
+  bfd_boolean print_well_known_globals;
+
+  /* Limit valid symbols to those with a given prefix.  */
+  const char *section_prefix;
+};
+
+typedef struct
+{
+  const char *name;
+  const char *description;
+} wasm32_options_t;
+
+static const wasm32_options_t options[] =
+{
+  { "registers", N_("Disassemble \"register\" names") },
+  { "globals",   N_("Name well-known globals") },
+};
+
+#define WASM_OPCODE(opcode, name, intype, outtype, clas, signedness)     \
+  { name, wasm_ ## clas, opcode },
+
+struct wasm32_opcode_s
+{
+  const char *name;
+  enum wasm_class clas;
+  unsigned char opcode;
+} wasm32_opcodes[] =
+{
+#include "opcode/wasm.h"
+  { NULL, 0, 0 }
+};
+
+/* Parse the disassembler options in OPTS and initialize INFO.  */
+
+static void
+parse_wasm32_disassembler_options (struct disassemble_info *info,
+                                   char *opts)
+{
+  struct wasm32_private_data *private = info->private_data;
+  while (opts != NULL)
+    {
+      if (CONST_STRNEQ (opts, "registers"))
+        private->print_registers = TRUE;
+      else if (CONST_STRNEQ (opts, "globals"))
+        private->print_well_known_globals = TRUE;
+
+      opts = strchr (opts, ',');
+      if (opts)
+        opts++;
+    }
+}
+
+/* Check whether SYM is valid.  Special-case absolute symbols, which
+   are unhelpful to print, and arguments to a "call" insn, which we
+   want to be in a section matching a given prefix.  */
+
+static bfd_boolean
+wasm32_symbol_is_valid (asymbol *sym,
+                        struct disassemble_info *info)
+{
+  struct wasm32_private_data *private_data = info->private_data;
+
+  if (sym == NULL)
+    return FALSE;
+
+  if (strcmp(sym->section->name, "*ABS*") == 0)
+    return FALSE;
+
+  if (private_data && private_data->section_prefix != NULL
+      && strncmp (sym->section->name, private_data->section_prefix,
+                  strlen (private_data->section_prefix)))
+    return FALSE;
+
+  return TRUE;
+}
+
+/* Initialize the disassembler structures for INFO.  */
+
+void
+disassemble_init_wasm32 (struct disassemble_info *info)
+{
+  if (info->private_data == NULL)
+    {
+      static struct wasm32_private_data private;
+
+      private.print_registers = FALSE;
+      private.print_well_known_globals = FALSE;
+      private.section_prefix = NULL;
+
+      info->private_data = &private;
+    }
+
+  if (info->disassembler_options)
+    {
+      parse_wasm32_disassembler_options (info, info->disassembler_options);
+
+      info->disassembler_options = NULL;
+    }
+
+  info->symbol_is_valid = wasm32_symbol_is_valid;
+}
+
+/* Read an LEB128-encoded integer from INFO at address PC, reading one
+   byte at a time.  Set ERROR_RETURN if no complete integer could be
+   read, LENGTH_RETURN to the number oof bytes read (including bytes
+   in incomplete numbers).  SIGN means interpret the number as
+   SLEB128.  Unfortunately, this is a duplicate of wasm-module.c's
+   wasm_read_leb128 ().  */
+
+static uint64_t
+wasm_read_leb128 (bfd_vma                   pc,
+                  struct disassemble_info * info,
+                  bfd_boolean *             error_return,
+                  unsigned int *            length_return,
+                  bfd_boolean               sign)
+{
+  uint64_t result = 0;
+  unsigned int num_read = 0;
+  unsigned int shift = 0;
+  unsigned char byte = 0;
+  bfd_boolean success = FALSE;
+
+  while (info->read_memory_func (pc + num_read, &byte, 1, info) == 0)
+    {
+      num_read++;
+
+      result |= ((bfd_vma) (byte & 0x7f)) << shift;
+
+      shift += 7;
+      if ((byte & 0x80) == 0)
+        {
+          success = TRUE;
+          break;
+        }
+    }
+
+  if (length_return != NULL)
+    *length_return = num_read;
+  if (error_return != NULL)
+    *error_return = ! success;
+
+  if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40))
+    result |= -((uint64_t) 1 << shift);
+
+  return result;
+}
+
+/* Read a 32-bit IEEE float from PC using INFO, convert it to a host
+   double, and store it at VALUE.  */
+
+static int
+read_f32 (double *value, bfd_vma pc, struct disassemble_info *info)
+{
+  bfd_byte buf[4];
+
+  if (info->read_memory_func (pc, buf, sizeof (buf), info))
+    return -1;
+
+  floatformat_to_double (&floatformat_ieee_single_little, buf,
+                         value);
+
+  return sizeof (buf);
+}
+
+/* Read a 64-bit IEEE float from PC using INFO, convert it to a host
+   double, and store it at VALUE.  */
+
+static int
+read_f64 (double *value, bfd_vma pc, struct disassemble_info *info)
+{
+  bfd_byte buf[8];
+
+  if (info->read_memory_func (pc, buf, sizeof (buf), info))
+    return -1;
+
+  floatformat_to_double (&floatformat_ieee_double_little, buf,
+                         value);
+
+  return sizeof (buf);
+}
+
+/* Main disassembly routine.  Disassemble insn at PC using INFO.  */
+
+int
+print_insn_wasm32 (bfd_vma pc, struct disassemble_info *info)
+{
+  unsigned char opcode;
+  struct wasm32_opcode_s *op;
+  bfd_byte buffer[16];
+  void *stream = info->stream;
+  fprintf_ftype prin = info->fprintf_func;
+  struct wasm32_private_data *private_data = info->private_data;
+  long long constant = 0;
+  double fconstant = 0.0;
+  long flags = 0;
+  long offset = 0;
+  long depth = 0;
+  long index = 0;
+  long target_count = 0;
+  long block_type = 0;
+  int len = 1;
+  int ret = 0;
+  unsigned int bytes_read = 0;
+  int i;
+  const char *locals[] = {
+    "$dpc", "$sp1", "$r0", "$r1", "$rpc", "$pc0",
+    "$rp", "$fp", "$sp",
+    "$r2", "$r3", "$r4", "$r5", "$r6", "$r7",
+    "$i0", "$i1", "$i2", "$i3", "$i4", "$i5", "$i6", "$i7",
+    "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
+  };
+  int nlocals = ARRAY_SIZE (locals);
+  const char *globals[] = {
+    "$got", "$plt", "$gpo"
+  };
+  int nglobals = ARRAY_SIZE (globals);
+  bfd_boolean error = FALSE;
+
+  if (info->read_memory_func (pc, buffer, 1, info))
+    return -1;
+
+  opcode = buffer[0];
+
+  for (op = wasm32_opcodes; op->name; op++)
+    if (op->opcode == opcode)
+      break;
+
+  if (!op->name)
+    {
+      prin (stream, "\t.byte 0x%02x\n", buffer[0]);
+      return 1;
+    }
+  else
+    {
+      len = 1;
+
+      prin (stream, "\t");
+      prin (stream, "%s", op->name);
+
+      if (op->clas == wasm_typed)
+        {
+          block_type = wasm_read_leb128
+            (pc + len, info, &error, &bytes_read, FALSE);
+          if (error)
+            return -1;
+          len += bytes_read;
+          switch (block_type)
+            {
+            case BLOCK_TYPE_NONE:
+              prin (stream, "[]");
+              break;
+            case BLOCK_TYPE_I32:
+              prin (stream, "[i]");
+              break;
+            case BLOCK_TYPE_I64:
+              prin (stream, "[l]");
+              break;
+            case BLOCK_TYPE_F32:
+              prin (stream, "[f]");
+              break;
+            case BLOCK_TYPE_F64:
+              prin (stream, "[d]");
+              break;
+            }
+        }
+
+      switch (op->clas)
+        {
+        case wasm_special:
+        case wasm_eqz:
+        case wasm_binary:
+        case wasm_unary:
+        case wasm_conv:
+        case wasm_relational:
+        case wasm_drop:
+        case wasm_signature:
+        case wasm_call_import:
+        case wasm_typed:
+        case wasm_select:
+          break;
+        case wasm_break_table:
+          target_count = wasm_read_leb128
+            (pc + len, info, &error, &bytes_read, FALSE);
+          if (error)
+            return -1;
+          len += bytes_read;
+          prin (stream, " %ld", target_count);
+          for (i = 0; i < target_count + 1; i++)
+            {
+              long target = 0;
+              target = wasm_read_leb128
+                (pc + len, info, &error, &bytes_read, FALSE);
+              if (error)
+                return -1;
+              len += bytes_read;
+              prin (stream, " %ld", target);
+            }
+          break;
+        case wasm_break:
+        case wasm_break_if:
+          depth = wasm_read_leb128
+            (pc + len, info, &error, &bytes_read, FALSE);
+          if (error)
+            return -1;
+          len += bytes_read;
+          prin (stream, " %ld", depth);
+          break;
+        case wasm_return:
+          break;
+        case wasm_constant_i32:
+        case wasm_constant_i64:
+          constant = wasm_read_leb128
+            (pc + len, info, &error, &bytes_read, TRUE);
+          if (error)
+            return -1;
+          len += bytes_read;
+          prin (stream, " %lld", constant);
+          break;
+        case wasm_constant_f32:
+          /* This appears to be the best we can do, even though we're
+             using host doubles for WebAssembly floats.  */
+          ret = read_f32 (&fconstant, pc + len, info);
+          if (ret < 0)
+            return -1;
+          len += ret;
+          prin (stream, " %.*g", DECIMAL_DIG, fconstant);
+          break;
+        case wasm_constant_f64:
+          ret = read_f64 (&fconstant, pc + len, info);
+          if (ret < 0)
+            return -1;
+          len += ret;
+          prin (stream, " %.*g", DECIMAL_DIG, fconstant);
+          break;
+        case wasm_call:
+          index = wasm_read_leb128
+            (pc + len, info, &error, &bytes_read, FALSE);
+          if (error)
+            return -1;
+          len += bytes_read;
+          prin (stream, " ");
+          private_data->section_prefix = ".space.function_index";
+          (*info->print_address_func) ((bfd_vma) index, info);
+          private_data->section_prefix = NULL;
+          break;
+        case wasm_call_indirect:
+          constant = wasm_read_leb128
+            (pc + len, info, &error, &bytes_read, FALSE);
+          if (error)
+            return -1;
+          len += bytes_read;
+          prin (stream, " %lld", constant);
+          constant = wasm_read_leb128
+            (pc + len, info, &error, &bytes_read, FALSE);
+          if (error)
+            return -1;
+          len += bytes_read;
+          prin (stream, " %lld", constant);
+          break;
+        case wasm_get_local:
+        case wasm_set_local:
+        case wasm_tee_local:
+          constant = wasm_read_leb128
+            (pc + len, info, &error, &bytes_read, FALSE);
+          if (error)
+            return -1;
+          len += bytes_read;
+          prin (stream, " %lld", constant);
+          if (strcmp (op->name + 4, "local") == 0)
+            {
+              if (private_data->print_registers
+                  && constant >= 0 && constant < nlocals)
+                prin (stream, " <%s>", locals[constant]);
+            }
+          else
+            {
+              if (private_data->print_well_known_globals
+                  && constant >= 0 && constant < nglobals)
+                prin (stream, " <%s>", globals[constant]);
+            }
+          break;
+        case wasm_grow_memory:
+        case wasm_current_memory:
+          constant = wasm_read_leb128
+            (pc + len, info, &error, &bytes_read, FALSE);
+          if (error)
+            return -1;
+          len += bytes_read;
+          prin (stream, " %lld", constant);
+          break;
+        case wasm_load:
+        case wasm_store:
+          flags = wasm_read_leb128
+            (pc + len, info, &error, &bytes_read, FALSE);
+          if (error)
+            return -1;
+          len += bytes_read;
+          offset = wasm_read_leb128
+            (pc + len, info, &error, &bytes_read, FALSE);
+          if (error)
+            return -1;
+          len += bytes_read;
+          prin (stream, " a=%ld %ld", flags, offset);
+        }
+    }
+  return len;
+}
+
+/* Print valid disassembler options to STREAM.  */
+
+void
+print_wasm32_disassembler_options (FILE *stream)
+{
+  unsigned int i, max_len = 0;
+  fprintf (stream, _("\
+The following WebAssembly-specific disassembler options are supported
for use\n\
+with the -M switch:\n"));
+
+  for (i = 0; i < ARRAY_SIZE (options); i++)
+    {
+      unsigned int len = strlen (options[i].name);
+      if (max_len < len)
+    max_len = len;
+    }
+
+  for (i = 0, max_len++; i < ARRAY_SIZE (options); i++)
+    fprintf (stream, "  %s%*c %s\n",
+         options[i].name,
+         (int)(max_len - strlen (options[i].name)), ' ',
+         _(options[i].description));
+}

[-- Attachment #2: binutils-wasm-008.diff --]
[-- Type: text/plain, Size: 26663 bytes --]

diff --git a/gas/testsuite/gas/wasm32/allinsn.d b/gas/testsuite/gas/wasm32/allinsn.d
index 06124be4d6..c594c72501 100644
--- a/gas/testsuite/gas/wasm32/allinsn.d
+++ b/gas/testsuite/gas/wasm32/allinsn.d
@@ -11,7 +11,7 @@ Disassembly of section .text:
    0:	02 40       		block\[\]
    2:	0c 00       		br 0
    4:	0d 00       		br_if 0
-   6:	0e 01 01 01 		br_table 1 1
+   6:	0e 01 01 01 		br_table 1 1 1
    a:	10 00       		call 0x0
    c:	11 00 00    		call_indirect 0 0
    f:	1a          		drop
@@ -22,12 +22,12 @@ Disassembly of section .text:
   14:	8d          		f32.ceil
   15:	43 d0 0f 49 		f32.const 3.141590118408203125
   19:	40 
-  1a:	b2          		f32.convert_s_i32
-  1b:	b4          		f32.convert_s_i64
-  1c:	b3          		f32.convert_u_i32
-  1d:	b5          		f32.convert_u_i64
+  1a:	b2          		f32.convert_s/i32
+  1b:	b4          		f32.convert_s/i64
+  1c:	b3          		f32.convert_u/i32
+  1d:	b5          		f32.convert_u/i64
   1e:	98          		f32.copysign
-  1f:	b6          		f32.demote_f64
+  1f:	b6          		f32.demote/f64
   20:	95          		f32.div
   21:	5b          		f32.eq
   22:	8e          		f32.floor
@@ -42,7 +42,7 @@ Disassembly of section .text:
   2d:	5c          		f32.ne
   2e:	90          		f32.nearest
   2f:	8c          		f32.neg
-  30:	be          		f32.reinterpret_i32
+  30:	be          		f32.reinterpret/i32
   31:	91          		f32.sqrt
   32:	38 00 00    		f32.store a=0 0
   35:	93          		f32.sub
@@ -53,10 +53,10 @@ Disassembly of section .text:
   3a:	44 97 5f 4f 		f64.const 3.14158999999999976088e\+200
   3e:	fd bc 6a 90 
   42:	69 
-  43:	b7          		f64.convert_s_i32
-  44:	b9          		f64.convert_s_i64
-  45:	b8          		f64.convert_u_i32
-  46:	ba          		f64.convert_u_i64
+  43:	b7          		f64.convert_s/i32
+  44:	b9          		f64.convert_s/i64
+  45:	b8          		f64.convert_u/i32
+  46:	ba          		f64.convert_u/i64
   47:	a6          		f64.copysign
   48:	a3          		f64.div
   49:	61          		f64.eq
@@ -72,14 +72,14 @@ Disassembly of section .text:
   55:	62          		f64.ne
   56:	9e          		f64.nearest
   57:	9a          		f64.neg
-  58:	bb          		f64.promote_f32
-  59:	bf          		f64.reinterpret_i64
+  58:	bb          		f64.promote/f32
+  59:	bf          		f64.reinterpret/i64
   5a:	9f          		f64.sqrt
   5b:	39 00 00    		f64.store a=0 0
   5e:	a1          		f64.sub
   5f:	9d          		f64.trunc
-  60:	23 00       		get_global 0 <\$got>
-  62:	20 00       		get_local 0 <\$dpc>
+  60:	23 00       		get_global 0
+  62:	20 00       		get_local 0
   64:	6a          		i32.add
   65:	71          		i32.and
   66:	67          		i32.clz
@@ -107,7 +107,7 @@ Disassembly of section .text:
   8a:	47          		i32.ne
   8b:	72          		i32.or
   8c:	69          		i32.popcnt
-  8d:	bc          		i32.reinterpret_f32
+  8d:	bc          		i32.reinterpret/f32
   8e:	6f          		i32.rem_s
   8f:	70          		i32.rem_u
   90:	77          		i32.rotl
@@ -119,11 +119,11 @@ Disassembly of section .text:
   98:	3b 00 00    		i32.store16 a=0 0
   9b:	3a 00 00    		i32.store8 a=0 0
   9e:	6b          		i32.sub
-  9f:	a8          		i32.trunc_s_f32
-  a0:	aa          		i32.trunc_s_f64
-  a1:	a9          		i32.trunc_u_f32
-  a2:	ab          		i32.trunc_u_f64
-  a3:	a7          		i32.wrap_i64
+  9f:	a8          		i32.trunc_s/f32
+  a0:	aa          		i32.trunc_s/f64
+  a1:	a9          		i32.trunc_u/f32
+  a2:	ab          		i32.trunc_u/f64
+  a3:	a7          		i32.wrap/i64
   a4:	73          		i32.xor
   a5:	7c          		i64.add
   a6:	83          		i64.and
@@ -136,8 +136,8 @@ Disassembly of section .text:
   b4:	80          		i64.div_u
   b5:	51          		i64.eq
   b6:	50          		i64.eqz
-  b7:	ac          		i64.extend_s_i32
-  b8:	ad          		i64.extend_u_i32
+  b7:	ac          		i64.extend_s/i32
+  b8:	ad          		i64.extend_u/i32
   b9:	59          		i64.ge_s
   ba:	5a          		i64.ge_u
   bb:	55          		i64.gt_s
@@ -157,7 +157,7 @@ Disassembly of section .text:
   d7:	52          		i64.ne
   d8:	84          		i64.or
   d9:	7b          		i64.popcnt
-  da:	bd          		i64.reinterpret_f64
+  da:	bd          		i64.reinterpret/f64
   db:	81          		i64.rem_s
   dc:	82          		i64.rem_u
   dd:	89          		i64.rotl
@@ -170,20 +170,20 @@ Disassembly of section .text:
   e8:	3e 00 00    		i64.store32 a=0 0
   eb:	3c 00 00    		i64.store8 a=0 0
   ee:	7d          		i64.sub
-  ef:	ae          		i64.trunc_s_f32
-  f0:	b0          		i64.trunc_s_f64
-  f1:	af          		i64.trunc_u_f32
-  f2:	b1          		i64.trunc_u_f64
+  ef:	ae          		i64.trunc_s/f32
+  f0:	b0          		i64.trunc_s/f64
+  f1:	af          		i64.trunc_u/f32
+  f2:	b1          		i64.trunc_u/f64
   f3:	85          		i64.xor
   f4:	04 7f       		if\[i\]
   f6:	03 7e       		loop\[l\]
   f8:	01          		nop
   f9:	0f          		return
   fa:	1b          		select
-  fb:	24 00       		set_global 0 <\$got>
-  fd:	21 00       		set_local 0 <\$dpc>
+  fb:	24 00       		set_global 0
+  fd:	21 00       		set_local 0
   ff:	60          		f32.ge
- 100:	08          		.byte 08
+ 100:	08          		.byte 0x08
 
  101:	7f          		i64.div_s
  102:	7e          		i64.mul
@@ -194,5 +194,5 @@ Disassembly of section .text:
  107:	7e          		i64.mul
  108:	7f          		i64.div_s
  109:	00          		unreachable
- 10a:	22 00       		tee_local 0 <\$dpc>
+ 10a:	22 00       		tee_local 0
 	...
diff --git a/gas/testsuite/gas/wasm32/disass-2.d b/gas/testsuite/gas/wasm32/disass-2.d
new file mode 100644
index 0000000000..b6aa7954de
--- /dev/null
+++ b/gas/testsuite/gas/wasm32/disass-2.d
@@ -0,0 +1,9 @@
+#as:
+#objdump: -d -Mglobals
+#name: disass-2.d
+^dump.o:     file format elf32-wasm32$
+
+^Disassembly of section .text:$
+^00000000 <.text>:$
+^   0:	20 00       		get_local 0$
+^   2:	23 00       		get_global 0 <\$got>$
diff --git a/gas/testsuite/gas/wasm32/disass-2.s b/gas/testsuite/gas/wasm32/disass-2.s
new file mode 100644
index 0000000000..bed9410505
--- /dev/null
+++ b/gas/testsuite/gas/wasm32/disass-2.s
@@ -0,0 +1,3 @@
+        .text
+        get_local 0
+        get_global 0
diff --git a/gas/testsuite/gas/wasm32/disass.d b/gas/testsuite/gas/wasm32/disass.d
new file mode 100644
index 0000000000..2708137916
--- /dev/null
+++ b/gas/testsuite/gas/wasm32/disass.d
@@ -0,0 +1,9 @@
+#as:
+#objdump: -d -Mregisters,globals
+#name: disass.d
+^dump.o:     file format elf32-wasm32$
+
+^Disassembly of section .text:$
+^00000000 <.text>:$
+^   0:	20 00       		get_local 0 <\$dpc>$
+^   2:	23 00       		get_global 0 <\$got>$
diff --git a/gas/testsuite/gas/wasm32/disass.s b/gas/testsuite/gas/wasm32/disass.s
new file mode 100644
index 0000000000..bed9410505
--- /dev/null
+++ b/gas/testsuite/gas/wasm32/disass.s
@@ -0,0 +1,3 @@
+        .text
+        get_local 0
+        get_global 0
diff --git a/gas/testsuite/gas/wasm32/reloc.d b/gas/testsuite/gas/wasm32/reloc.d
index 9317e6e9a3..9dc54e7760 100644
--- a/gas/testsuite/gas/wasm32/reloc.d
+++ b/gas/testsuite/gas/wasm32/reloc.d
@@ -9,10 +9,11 @@ Disassembly of section .text:
 00000000 <.text>:
    0:	41 80 80 80 		i32.const 0
    4:	80 00 
-			1: R_ASMJS_LEB128_PLT	f
+			1: R_WASM32_PLT_SIG	__sigchar_FiiiiiiiE
+			1: R_WASM32_LEB128_PLT	f
    6:	41 80 80 80 		i32.const 0
    a:	80 00 
-			7: R_ASMJS_LEB128_GOT	x
+			7: R_WASM32_LEB128_GOT	x
    c:	41 80 80 80 		i32.const 0
   10:	80 00 
-			d: R_ASMJS_LEB128_GOT_CODE	f
+			d: R_WASM32_LEB128_GOT_CODE	f
diff --git a/gas/testsuite/gas/wasm32/reloc.s b/gas/testsuite/gas/wasm32/reloc.s
index 8cdfd58b96..cd34591b2c 100644
--- a/gas/testsuite/gas/wasm32/reloc.s
+++ b/gas/testsuite/gas/wasm32/reloc.s
@@ -1,3 +1,3 @@
-        i32.const f@plt
+        i32.const f@plt{__sigchar_FiiiiiiiE}
         i32.const x@got
         i32.const f@gotcode
diff --git a/gas/testsuite/gas/wasm32/wasm32.exp b/gas/testsuite/gas/wasm32/wasm32.exp
index e6d1819677..49c14e45f9 100644
--- a/gas/testsuite/gas/wasm32/wasm32.exp
+++ b/gas/testsuite/gas/wasm32/wasm32.exp
@@ -21,8 +21,6 @@
 # wasm32 assembler testsuite.
 
 if [istarget wasm32-*-*] {
-    # no disassembler support yet
-    setup_xfail "wasm32-*-*"
     run_dump_test "allinsn"
     # no GOT/PLT relocs yet.
     setup_xfail "wasm32-*-*"
@@ -55,4 +53,6 @@ if [istarget wasm32-*-*] {
     # illegal-23 has become legal
     run_list_test "illegal-24"
     run_list_test "illegal-25"
+    run_dump_test "disass"
+    run_dump_test "disass-2"
 }
diff --git a/include/dis-asm.h b/include/dis-asm.h
index f0544509d0..a6b65431de 100644
--- a/include/dis-asm.h
+++ b/include/dis-asm.h
@@ -318,6 +318,7 @@ extern int print_insn_v850		(bfd_vma, disassemble_info *);
 extern int print_insn_vax		(bfd_vma, disassemble_info *);
 extern int print_insn_visium		(bfd_vma, disassemble_info *);
 extern int print_insn_w65		(bfd_vma, disassemble_info *);
+extern int print_insn_wasm32		(bfd_vma, disassemble_info *);
 extern int print_insn_xc16x		(bfd_vma, disassemble_info *);
 extern int print_insn_xgate             (bfd_vma, disassemble_info *);
 extern int print_insn_xstormy16		(bfd_vma, disassemble_info *);
@@ -343,10 +344,12 @@ extern void print_riscv_disassembler_options (FILE *);
 extern void print_arm_disassembler_options (FILE *);
 extern void print_arc_disassembler_options (FILE *);
 extern void print_s390_disassembler_options (FILE *);
+extern void print_wasm32_disassembler_options (FILE *);
 extern bfd_boolean aarch64_symbol_is_valid (asymbol *, struct disassemble_info *);
 extern bfd_boolean arm_symbol_is_valid (asymbol *, struct disassemble_info *);
 extern void disassemble_init_powerpc (struct disassemble_info *);
 extern void disassemble_init_s390 (struct disassemble_info *);
+extern void disassemble_init_wasm32 (struct disassemble_info *);
 extern const disasm_options_t *disassembler_options_powerpc (void);
 extern const disasm_options_t *disassembler_options_arm (void);
 extern const disasm_options_t *disassembler_options_s390 (void);
diff --git a/opcodes/Makefile.am b/opcodes/Makefile.am
index b43c679bff..1ac6bb1128 100644
--- a/opcodes/Makefile.am
+++ b/opcodes/Makefile.am
@@ -259,6 +259,7 @@ TARGET_LIBOPCODES_CFILES = \
 	visium-dis.c \
 	visium-opc.c \
 	w65-dis.c \
+	wasm32-dis.c \
 	xc16x-asm.c \
 	xc16x-desc.c \
 	xc16x-dis.c \
diff --git a/opcodes/configure.ac b/opcodes/configure.ac
index ca982924e6..a9fbfd61f1 100644
--- a/opcodes/configure.ac
+++ b/opcodes/configure.ac
@@ -348,7 +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_wasm32_arch)        ta="$ta wasm32-dis.lo" ;;
 	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" ;;
diff --git a/opcodes/disassemble.c b/opcodes/disassemble.c
index eef06584f4..dd7d3a32b7 100644
--- a/opcodes/disassemble.c
+++ b/opcodes/disassemble.c
@@ -94,6 +94,7 @@
 #define ARCH_vax
 #define ARCH_visium
 #define ARCH_w65
+#define ARCH_wasm32
 #define ARCH_xstormy16
 #define ARCH_xc16x
 #define ARCH_xgate
@@ -474,6 +475,11 @@ disassembler (bfd *abfd)
       disassemble = print_insn_w65;
       break;
 #endif
+#ifdef ARCH_wasm32
+    case bfd_arch_wasm32:
+      disassemble = print_insn_wasm32;
+      break;
+#endif
 #ifdef ARCH_xgate
     case bfd_arch_xgate:
       disassemble = print_insn_xgate;
@@ -580,6 +586,9 @@ disassembler_usage (FILE *stream ATTRIBUTE_UNUSED)
 #ifdef ARCH_s390
   print_s390_disassembler_options (stream);
 #endif
+#ifdef ARCH_wasm32
+  print_wasm32_disassembler_options (stream);
+#endif
 
   return;
 }
@@ -650,6 +659,11 @@ disassemble_init_for_target (struct disassemble_info * info)
       disassemble_init_powerpc (info);
       break;
 #endif
+#ifdef ARCH_wasm32
+    case bfd_arch_wasm32:
+      disassemble_init_wasm32 (info);
+      break;
+#endif
 #ifdef ARCH_s390
     case bfd_arch_s390:
       disassemble_init_s390 (info);
diff --git a/opcodes/wasm32-dis.c b/opcodes/wasm32-dis.c
new file mode 100644
index 0000000000..d3858880c0
--- /dev/null
+++ b/opcodes/wasm32-dis.c
@@ -0,0 +1,505 @@
+/* Opcode printing code for the WebAssembly target
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+   This file is part of libopcodes.
+
+   This library 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.
+
+   It 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 "dis-asm.h"
+#include "opintl.h"
+#include "safe-ctype.h"
+#include "floatformat.h"
+#include <float.h>
+#include "libiberty.h"
+#include "elf-bfd.h"
+#include "elf/internal.h"
+#include "elf/wasm32.h"
+#include <stdint.h>
+
+/* 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
+
+enum wasm_class
+  {
+    wasm_typed,
+    wasm_special,
+    wasm_break,
+    wasm_break_if,
+    wasm_break_table,
+    wasm_return,
+    wasm_call,
+    wasm_call_import,
+    wasm_call_indirect,
+    wasm_get_local,
+    wasm_set_local,
+    wasm_tee_local,
+    wasm_drop,
+    wasm_constant_i32,
+    wasm_constant_i64,
+    wasm_constant_f32,
+    wasm_constant_f64,
+    wasm_unary,
+    wasm_binary,
+    wasm_conv,
+    wasm_load,
+    wasm_store,
+    wasm_select,
+    wasm_relational,
+    wasm_eqz,
+    wasm_current_memory,
+    wasm_grow_memory,
+    wasm_signature
+  };
+
+struct wasm32_private_data
+{
+  bfd_boolean print_registers;
+  bfd_boolean print_well_known_globals;
+
+  /* Limit valid symbols to those with a given prefix.  */
+  const char *section_prefix;
+};
+
+typedef struct
+{
+  const char *name;
+  const char *description;
+} wasm32_options_t;
+
+static const wasm32_options_t options[] =
+{
+  { "registers", N_("Disassemble \"register\" names") },
+  { "globals",   N_("Name well-known globals") },
+};
+
+#define WASM_OPCODE(opcode, name, intype, outtype, clas, signedness)     \
+  { name, wasm_ ## clas, opcode },
+
+struct wasm32_opcode_s
+{
+  const char *name;
+  enum wasm_class clas;
+  unsigned char opcode;
+} wasm32_opcodes[] =
+{
+#include "opcode/wasm.h"
+  { NULL, 0, 0 }
+};
+
+/* Parse the disassembler options in OPTS and initialize INFO.  */
+
+static void
+parse_wasm32_disassembler_options (struct disassemble_info *info,
+                                   char *opts)
+{
+  struct wasm32_private_data *private = info->private_data;
+  while (opts != NULL)
+    {
+      if (CONST_STRNEQ (opts, "registers"))
+        private->print_registers = TRUE;
+      else if (CONST_STRNEQ (opts, "globals"))
+        private->print_well_known_globals = TRUE;
+
+      opts = strchr (opts, ',');
+      if (opts)
+        opts++;
+    }
+}
+
+/* Check whether SYM is valid.  Special-case absolute symbols, which
+   are unhelpful to print, and arguments to a "call" insn, which we
+   want to be in a section matching a given prefix.  */
+
+static bfd_boolean
+wasm32_symbol_is_valid (asymbol *sym,
+                        struct disassemble_info *info)
+{
+  struct wasm32_private_data *private_data = info->private_data;
+
+  if (sym == NULL)
+    return FALSE;
+
+  if (strcmp(sym->section->name, "*ABS*") == 0)
+    return FALSE;
+
+  if (private_data && private_data->section_prefix != NULL
+      && strncmp (sym->section->name, private_data->section_prefix,
+                  strlen (private_data->section_prefix)))
+    return FALSE;
+
+  return TRUE;
+}
+
+/* Initialize the disassembler structures for INFO.  */
+
+void
+disassemble_init_wasm32 (struct disassemble_info *info)
+{
+  if (info->private_data == NULL)
+    {
+      static struct wasm32_private_data private;
+
+      private.print_registers = FALSE;
+      private.print_well_known_globals = FALSE;
+      private.section_prefix = NULL;
+
+      info->private_data = &private;
+    }
+
+  if (info->disassembler_options)
+    {
+      parse_wasm32_disassembler_options (info, info->disassembler_options);
+
+      info->disassembler_options = NULL;
+    }
+
+  info->symbol_is_valid = wasm32_symbol_is_valid;
+}
+
+/* Read an LEB128-encoded integer from INFO at address PC, reading one
+   byte at a time.  Set ERROR_RETURN if no complete integer could be
+   read, LENGTH_RETURN to the number oof bytes read (including bytes
+   in incomplete numbers).  SIGN means interpret the number as
+   SLEB128.  Unfortunately, this is a duplicate of wasm-module.c's
+   wasm_read_leb128 ().  */
+
+static uint64_t
+wasm_read_leb128 (bfd_vma                   pc,
+                  struct disassemble_info * info,
+                  bfd_boolean *             error_return,
+                  unsigned int *            length_return,
+                  bfd_boolean               sign)
+{
+  uint64_t result = 0;
+  unsigned int num_read = 0;
+  unsigned int shift = 0;
+  unsigned char byte = 0;
+  bfd_boolean success = FALSE;
+
+  while (info->read_memory_func (pc + num_read, &byte, 1, info) == 0)
+    {
+      num_read++;
+
+      result |= ((bfd_vma) (byte & 0x7f)) << shift;
+
+      shift += 7;
+      if ((byte & 0x80) == 0)
+        {
+          success = TRUE;
+          break;
+        }
+    }
+
+  if (length_return != NULL)
+    *length_return = num_read;
+  if (error_return != NULL)
+    *error_return = ! success;
+
+  if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40))
+    result |= -((uint64_t) 1 << shift);
+
+  return result;
+}
+
+/* Read a 32-bit IEEE float from PC using INFO, convert it to a host
+   double, and store it at VALUE.  */
+
+static int
+read_f32 (double *value, bfd_vma pc, struct disassemble_info *info)
+{
+  bfd_byte buf[4];
+
+  if (info->read_memory_func (pc, buf, sizeof (buf), info))
+    return -1;
+
+  floatformat_to_double (&floatformat_ieee_single_little, buf,
+                         value);
+
+  return sizeof (buf);
+}
+
+/* Read a 64-bit IEEE float from PC using INFO, convert it to a host
+   double, and store it at VALUE.  */
+
+static int
+read_f64 (double *value, bfd_vma pc, struct disassemble_info *info)
+{
+  bfd_byte buf[8];
+
+  if (info->read_memory_func (pc, buf, sizeof (buf), info))
+    return -1;
+
+  floatformat_to_double (&floatformat_ieee_double_little, buf,
+                         value);
+
+  return sizeof (buf);
+}
+
+/* Main disassembly routine.  Disassemble insn at PC using INFO.  */
+
+int
+print_insn_wasm32 (bfd_vma pc, struct disassemble_info *info)
+{
+  unsigned char opcode;
+  struct wasm32_opcode_s *op;
+  bfd_byte buffer[16];
+  void *stream = info->stream;
+  fprintf_ftype prin = info->fprintf_func;
+  struct wasm32_private_data *private_data = info->private_data;
+  long long constant = 0;
+  double fconstant = 0.0;
+  long flags = 0;
+  long offset = 0;
+  long depth = 0;
+  long index = 0;
+  long target_count = 0;
+  long block_type = 0;
+  int len = 1;
+  int ret = 0;
+  unsigned int bytes_read = 0;
+  int i;
+  const char *locals[] = {
+    "$dpc", "$sp1", "$r0", "$r1", "$rpc", "$pc0",
+    "$rp", "$fp", "$sp",
+    "$r2", "$r3", "$r4", "$r5", "$r6", "$r7",
+    "$i0", "$i1", "$i2", "$i3", "$i4", "$i5", "$i6", "$i7",
+    "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
+  };
+  int nlocals = ARRAY_SIZE (locals);
+  const char *globals[] = {
+    "$got", "$plt", "$gpo"
+  };
+  int nglobals = ARRAY_SIZE (globals);
+  bfd_boolean error = FALSE;
+
+  if (info->read_memory_func (pc, buffer, 1, info))
+    return -1;
+
+  opcode = buffer[0];
+
+  for (op = wasm32_opcodes; op->name; op++)
+    if (op->opcode == opcode)
+      break;
+
+  if (!op->name)
+    {
+      prin (stream, "\t.byte 0x%02x\n", buffer[0]);
+      return 1;
+    }
+  else
+    {
+      len = 1;
+
+      prin (stream, "\t");
+      prin (stream, "%s", op->name);
+
+      if (op->clas == wasm_typed)
+        {
+          block_type = wasm_read_leb128
+            (pc + len, info, &error, &bytes_read, FALSE);
+          if (error)
+            return -1;
+          len += bytes_read;
+          switch (block_type)
+            {
+            case BLOCK_TYPE_NONE:
+              prin (stream, "[]");
+              break;
+            case BLOCK_TYPE_I32:
+              prin (stream, "[i]");
+              break;
+            case BLOCK_TYPE_I64:
+              prin (stream, "[l]");
+              break;
+            case BLOCK_TYPE_F32:
+              prin (stream, "[f]");
+              break;
+            case BLOCK_TYPE_F64:
+              prin (stream, "[d]");
+              break;
+            }
+        }
+
+      switch (op->clas)
+        {
+        case wasm_special:
+        case wasm_eqz:
+        case wasm_binary:
+        case wasm_unary:
+        case wasm_conv:
+        case wasm_relational:
+        case wasm_drop:
+        case wasm_signature:
+        case wasm_call_import:
+        case wasm_typed:
+        case wasm_select:
+          break;
+        case wasm_break_table:
+          target_count = wasm_read_leb128
+            (pc + len, info, &error, &bytes_read, FALSE);
+          if (error)
+            return -1;
+          len += bytes_read;
+          prin (stream, " %ld", target_count);
+          for (i = 0; i < target_count + 1; i++)
+            {
+              long target = 0;
+              target = wasm_read_leb128
+                (pc + len, info, &error, &bytes_read, FALSE);
+              if (error)
+                return -1;
+              len += bytes_read;
+              prin (stream, " %ld", target);
+            }
+          break;
+        case wasm_break:
+        case wasm_break_if:
+          depth = wasm_read_leb128
+            (pc + len, info, &error, &bytes_read, FALSE);
+          if (error)
+            return -1;
+          len += bytes_read;
+          prin (stream, " %ld", depth);
+          break;
+        case wasm_return:
+          break;
+        case wasm_constant_i32:
+        case wasm_constant_i64:
+          constant = wasm_read_leb128
+            (pc + len, info, &error, &bytes_read, TRUE);
+          if (error)
+            return -1;
+          len += bytes_read;
+          prin (stream, " %lld", constant);
+          break;
+        case wasm_constant_f32:
+          /* This appears to be the best we can do, even though we're
+             using host doubles for WebAssembly floats.  */
+          ret = read_f32 (&fconstant, pc + len, info);
+          if (ret < 0)
+            return -1;
+          len += ret;
+          prin (stream, " %.*g", DECIMAL_DIG, fconstant);
+          break;
+        case wasm_constant_f64:
+          ret = read_f64 (&fconstant, pc + len, info);
+          if (ret < 0)
+            return -1;
+          len += ret;
+          prin (stream, " %.*g", DECIMAL_DIG, fconstant);
+          break;
+        case wasm_call:
+          index = wasm_read_leb128
+            (pc + len, info, &error, &bytes_read, FALSE);
+          if (error)
+            return -1;
+          len += bytes_read;
+          prin (stream, " ");
+          private_data->section_prefix = ".space.function_index";
+          (*info->print_address_func) ((bfd_vma) index, info);
+          private_data->section_prefix = NULL;
+          break;
+        case wasm_call_indirect:
+          constant = wasm_read_leb128
+            (pc + len, info, &error, &bytes_read, FALSE);
+          if (error)
+            return -1;
+          len += bytes_read;
+          prin (stream, " %lld", constant);
+          constant = wasm_read_leb128
+            (pc + len, info, &error, &bytes_read, FALSE);
+          if (error)
+            return -1;
+          len += bytes_read;
+          prin (stream, " %lld", constant);
+          break;
+        case wasm_get_local:
+        case wasm_set_local:
+        case wasm_tee_local:
+          constant = wasm_read_leb128
+            (pc + len, info, &error, &bytes_read, FALSE);
+          if (error)
+            return -1;
+          len += bytes_read;
+          prin (stream, " %lld", constant);
+          if (strcmp (op->name + 4, "local") == 0)
+            {
+              if (private_data->print_registers
+                  && constant >= 0 && constant < nlocals)
+                prin (stream, " <%s>", locals[constant]);
+            }
+          else
+            {
+              if (private_data->print_well_known_globals
+                  && constant >= 0 && constant < nglobals)
+                prin (stream, " <%s>", globals[constant]);
+            }
+          break;
+        case wasm_grow_memory:
+        case wasm_current_memory:
+          constant = wasm_read_leb128
+            (pc + len, info, &error, &bytes_read, FALSE);
+          if (error)
+            return -1;
+          len += bytes_read;
+          prin (stream, " %lld", constant);
+          break;
+        case wasm_load:
+        case wasm_store:
+          flags = wasm_read_leb128
+            (pc + len, info, &error, &bytes_read, FALSE);
+          if (error)
+            return -1;
+          len += bytes_read;
+          offset = wasm_read_leb128
+            (pc + len, info, &error, &bytes_read, FALSE);
+          if (error)
+            return -1;
+          len += bytes_read;
+          prin (stream, " a=%ld %ld", flags, offset);
+        }
+    }
+  return len;
+}
+
+/* Print valid disassembler options to STREAM.  */
+
+void
+print_wasm32_disassembler_options (FILE *stream)
+{
+  unsigned int i, max_len = 0;
+  fprintf (stream, _("\
+The following WebAssembly-specific disassembler options are supported for use\n\
+with the -M switch:\n"));
+
+  for (i = 0; i < ARRAY_SIZE (options); i++)
+    {
+      unsigned int len = strlen (options[i].name);
+      if (max_len < len)
+	max_len = len;
+    }
+
+  for (i = 0, max_len++; i < ARRAY_SIZE (options); i++)
+    fprintf (stream, "  %s%*c %s\n",
+	     options[i].name,
+	     (int)(max_len - strlen (options[i].name)), ' ',
+	     _(options[i].description));
+}

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2017-04-10  5:32 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-04-06 19:39 [PATCH] [WebAssembly] Disassembler support Simon Marchi
2017-04-07  0:00 ` Pip Cet
2017-04-07  9:32   ` Nick Clifton
2017-04-07 18:22     ` Pip Cet
2017-04-07 22:05       ` Alan Modra
2017-04-07 22:57         ` Pip Cet
2017-04-09 10:35           ` Alan Modra
2017-04-09 13:20             ` Pip Cet
2017-04-09 23:39               ` Alan Modra
2017-04-10  0:11                 ` Pip Cet
2017-04-10  5:32                   ` Alan Modra
  -- strict thread matches above, loose matches on Subject: below --
2017-03-31 23:18 Pip Cet
2017-04-06 16:22 ` Nick Clifton
2017-04-07  0:29   ` Pip Cet
2017-04-07  7:41     ` Nick Clifton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).