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