* [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
* Re: [PATCH] [WebAssembly] Disassembler support
2017-03-31 23:18 [PATCH] [WebAssembly] Disassembler support 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
* 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-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-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-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-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 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-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-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 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 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 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-06 19:39 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-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
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-03-31 23:18 [PATCH] [WebAssembly] Disassembler support Pip Cet
2017-04-06 16:22 ` Nick Clifton
2017-04-07 0:29 ` Pip Cet
2017-04-07 7:41 ` Nick Clifton
2017-04-06 19:39 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
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).