aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gas/ChangeLog15
-rw-r--r--gas/testsuite/gas/wasm32/allinsn.d64
-rw-r--r--gas/testsuite/gas/wasm32/disass-2.d9
-rw-r--r--gas/testsuite/gas/wasm32/disass-2.s3
-rw-r--r--gas/testsuite/gas/wasm32/disass.d9
-rw-r--r--gas/testsuite/gas/wasm32/disass.s3
-rw-r--r--gas/testsuite/gas/wasm32/reloc.d7
-rw-r--r--gas/testsuite/gas/wasm32/reloc.s2
-rw-r--r--gas/testsuite/gas/wasm32/wasm32.exp4
-rw-r--r--include/ChangeLog4
-rw-r--r--include/dis-asm.h3
-rw-r--r--opcodes/ChangeLog11
-rw-r--r--opcodes/Makefile.am1
-rw-r--r--opcodes/Makefile.in2
-rwxr-xr-xopcodes/configure2
-rw-r--r--opcodes/configure.ac2
-rw-r--r--opcodes/disassemble.c14
-rw-r--r--opcodes/po/POTFILES.in1
-rw-r--r--opcodes/po/opcodes.pot18
-rw-r--r--opcodes/wasm32-dis.c521
20 files changed, 654 insertions, 41 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index cc5f349..0a0d207 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,18 @@
+2017-04-06 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.
+
2017-04-04 H.J. Lu <hongjiu.lu@intel.com>
* NEWS: Mention support for ELF SHF_GNU_MBIND.
diff --git a/gas/testsuite/gas/wasm32/allinsn.d b/gas/testsuite/gas/wasm32/allinsn.d
index 06124be..c594c72 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 0000000..b6aa795
--- /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 0000000..bed9410
--- /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 0000000..2708137
--- /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 0000000..bed9410
--- /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 9317e6e..9dc54e7 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 8cdfd58..cd34591 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 e6d1819..49c14e4 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/ChangeLog b/include/ChangeLog
index 956e252..330a656 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,7 @@
+2017-04-06 Pip Cet <pipcet@gmail.com>
+
+ * dis-asm.h: Add prototypes for wasm32 disassembler.
+
2017-04-05 Pedro Alves <palves@redhat.com>
* dis-asm.h (disassemble_info) <disassembler_options>: Now a
diff --git a/include/dis-asm.h b/include/dis-asm.h
index 2ed3d7e..6f1801d 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/ChangeLog b/opcodes/ChangeLog
index 2889f53..424d7fc 100644
--- a/opcodes/ChangeLog
+++ b/opcodes/ChangeLog
@@ -1,3 +1,14 @@
+2017-04-06 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.
+ * po/opcodes.pot: Regenerate.
+
2017-04-05 Pedro Alves <palves@redhat.com>
* arc-dis.c (parse_option, parse_disassembler_options): Constify.
diff --git a/opcodes/Makefile.am b/opcodes/Makefile.am
index b43c679..1ac6bb1 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/Makefile.in b/opcodes/Makefile.in
index 84efa6c..8c2d71f 100644
--- a/opcodes/Makefile.in
+++ b/opcodes/Makefile.in
@@ -561,6 +561,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 \
@@ -969,6 +970,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/visium-dis.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/visium-opc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/w65-dis.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wasm32-dis.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xc16x-asm.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xc16x-desc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xc16x-dis.Plo@am__quote@
diff --git a/opcodes/configure b/opcodes/configure
index ea26b91..27d1472 100755
--- a/opcodes/configure
+++ b/opcodes/configure
@@ -12724,7 +12724,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/configure.ac b/opcodes/configure.ac
index ca98292..a9fbfd6 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 eef0658..dd7d3a3 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/po/POTFILES.in b/opcodes/po/POTFILES.in
index a1f48dc..cb1b513 100644
--- a/opcodes/po/POTFILES.in
+++ b/opcodes/po/POTFILES.in
@@ -217,6 +217,7 @@ visium-dis.c
visium-opc.c
w65-dis.c
w65-opc.h
+wasm32-dis.c
xc16x-asm.c
xc16x-desc.c
xc16x-desc.h
diff --git a/opcodes/po/opcodes.pot b/opcodes/po/opcodes.pot
index b62fc95..ff22de4 100644
--- a/opcodes/po/opcodes.pot
+++ b/opcodes/po/opcodes.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: bug-binutils@gnu.org\n"
-"POT-Creation-Date: 2017-03-29 17:08+0100\n"
+"POT-Creation-Date: 2017-04-06 16:22+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -1695,6 +1695,22 @@ msgstr ""
msgid "invalid register name"
msgstr ""
+#: wasm32-dis.c:89
+msgid "Disassemble \"register\" names"
+msgstr ""
+
+#: wasm32-dis.c:90
+msgid "Name well-known globals"
+msgstr ""
+
+#: wasm32-dis.c:489
+#, c-format
+msgid ""
+"The following WebAssembly-specific disassembler options are supported for "
+"use\n"
+"with the -M switch:\n"
+msgstr ""
+
#: xc16x-asm.c:65
msgid "Missing '#' prefix"
msgstr ""
diff --git a/opcodes/wasm32-dis.c b/opcodes/wasm32-dis.c
new file mode 100644
index 0000000..80e4ffe
--- /dev/null
+++ b/opcodes/wasm32-dis.c
@@ -0,0 +1,521 @@
+/* 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,
+ const 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));
+}