| /* BFD back-end for WebAssembly modules. | |
| Copyright (C) 2017-2023 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 "bfd.h" | |
| #include "libiberty.h" | |
| #include "libbfd.h" | |
| #include "wasm-module.h" | |
| #include <limits.h> | |
| #ifndef CHAR_BIT | |
| #define CHAR_BIT 8 | |
| #endif | |
| typedef struct | |
| { | |
| asymbol * symbols; | |
| bfd_size_type symcount; | |
| } tdata_type; | |
| static const char * const wasm_numbered_sections[] = | |
| { | |
| NULL, /* Custom section, different layout. */ | |
| WASM_SECTION ( 1, "type"), | |
| WASM_SECTION ( 2, "import"), | |
| WASM_SECTION ( 3, "function"), | |
| WASM_SECTION ( 4, "table"), | |
| WASM_SECTION ( 5, "memory"), | |
| WASM_SECTION ( 6, "global"), | |
| WASM_SECTION ( 7, "export"), | |
| WASM_SECTION ( 8, "start"), | |
| WASM_SECTION ( 9, "element"), | |
| WASM_SECTION (10, "code"), | |
| WASM_SECTION (11, "data"), | |
| }; | |
| #define WASM_NUMBERED_SECTIONS ARRAY_SIZE (wasm_numbered_sections) | |
| /* Resolve SECTION_CODE to a section name if there is one, NULL | |
| otherwise. */ | |
| static const char * | |
| wasm_section_code_to_name (bfd_byte section_code) | |
| { | |
| if (section_code < WASM_NUMBERED_SECTIONS) | |
| return wasm_numbered_sections[section_code]; | |
| return NULL; | |
| } | |
| /* Translate section name NAME to a section code, or 0 if it's a | |
| custom name. */ | |
| static unsigned int | |
| wasm_section_name_to_code (const char *name) | |
| { | |
| unsigned i; | |
| for (i = 1; i < WASM_NUMBERED_SECTIONS; i++) | |
| if (strcmp (name, wasm_numbered_sections[i]) == 0) | |
| return i; | |
| return 0; | |
| } | |
| /* WebAssembly LEB128 integers are sufficiently like DWARF LEB128 | |
| integers that we use _bfd_safe_read_leb128, but there are two | |
| points of difference: | |
| - WebAssembly requires a 32-bit value to be encoded in at most 5 | |
| bytes, etc. | |
| - _bfd_safe_read_leb128 accepts incomplete LEB128 encodings at the | |
| end of the buffer, while these are invalid in WebAssembly. | |
| Those differences mean that we will accept some files that are | |
| invalid WebAssembly. */ | |
| /* Read an LEB128-encoded integer from ABFD's I/O stream, reading one | |
| byte at a time. Set ERROR_RETURN if no complete integer could be | |
| read, LENGTH_RETURN to the number of bytes read (including bytes in | |
| incomplete numbers). SIGN means interpret the number as SLEB128. */ | |
| static bfd_vma | |
| wasm_read_leb128 (bfd *abfd, | |
| bool *error_return, | |
| unsigned int *length_return, | |
| bool sign) | |
| { | |
| bfd_vma result = 0; | |
| unsigned int num_read = 0; | |
| unsigned int shift = 0; | |
| unsigned char byte = 0; | |
| unsigned char lost, mask; | |
| int status = 1; | |
| while (bfd_bread (&byte, 1, abfd) == 1) | |
| { | |
| num_read++; | |
| if (shift < CHAR_BIT * sizeof (result)) | |
| { | |
| result |= ((bfd_vma) (byte & 0x7f)) << shift; | |
| /* These bits overflowed. */ | |
| lost = byte ^ (result >> shift); | |
| /* And this is the mask of possible overflow bits. */ | |
| mask = 0x7f ^ ((bfd_vma) 0x7f << shift >> shift); | |
| shift += 7; | |
| } | |
| else | |
| { | |
| lost = byte; | |
| mask = 0x7f; | |
| } | |
| if ((lost & mask) != (sign && (bfd_signed_vma) result < 0 ? mask : 0)) | |
| status |= 2; | |
| if ((byte & 0x80) == 0) | |
| { | |
| status &= ~1; | |
| if (sign && shift < CHAR_BIT * sizeof (result) && (byte & 0x40)) | |
| result |= -((bfd_vma) 1 << shift); | |
| break; | |
| } | |
| } | |
| if (length_return != NULL) | |
| *length_return = num_read; | |
| if (error_return != NULL) | |
| *error_return = status != 0; | |
| return result; | |
| } | |
| /* Encode an integer V as LEB128 and write it to ABFD, return TRUE on | |
| success. */ | |
| static bool | |
| wasm_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; | |
| } | |
| /* Read the LEB128 integer at P, saving it to X; at end of buffer, | |
| jump to error_return. */ | |
| #define READ_LEB128(x, p, end) \ | |
| do \ | |
| { \ | |
| if ((p) >= (end)) \ | |
| goto error_return; \ | |
| (x) = _bfd_safe_read_leb128 (abfd, &(p), false, (end)); \ | |
| } \ | |
| while (0) | |
| /* Verify the magic number at the beginning of a WebAssembly module | |
| ABFD, setting ERRORPTR if there's a mismatch. */ | |
| static bool | |
| wasm_read_magic (bfd *abfd, bool *errorptr) | |
| { | |
| bfd_byte magic_const[SIZEOF_WASM_MAGIC] = WASM_MAGIC; | |
| bfd_byte magic[SIZEOF_WASM_MAGIC]; | |
| if (bfd_bread (magic, sizeof (magic), abfd) == sizeof (magic) | |
| && memcmp (magic, magic_const, sizeof (magic)) == 0) | |
| return true; | |
| *errorptr = true; | |
| return false; | |
| } | |
| /* Read the version number from ABFD, returning TRUE if it's a supported | |
| version. Set ERRORPTR otherwise. */ | |
| static bool | |
| wasm_read_version (bfd *abfd, bool *errorptr) | |
| { | |
| bfd_byte vers_const[SIZEOF_WASM_VERSION] = WASM_VERSION; | |
| bfd_byte vers[SIZEOF_WASM_VERSION]; | |
| if (bfd_bread (vers, sizeof (vers), abfd) == sizeof (vers) | |
| /* Don't attempt to parse newer versions, which are likely to | |
| require code changes. */ | |
| && memcmp (vers, vers_const, sizeof (vers)) == 0) | |
| return true; | |
| *errorptr = true; | |
| return false; | |
| } | |
| /* Read the WebAssembly header (magic number plus version number) from | |
| ABFD, setting ERRORPTR to TRUE if there is a mismatch. */ | |
| static bool | |
| wasm_read_header (bfd *abfd, bool *errorptr) | |
| { | |
| if (! wasm_read_magic (abfd, errorptr)) | |
| return false; | |
| if (! wasm_read_version (abfd, errorptr)) | |
| return false; | |
| return true; | |
| } | |
| /* Scan the "function" subsection of the "name" section ASECT in the | |
| wasm module ABFD. Create symbols. Return TRUE on success. */ | |
| static bool | |
| wasm_scan_name_function_section (bfd *abfd, sec_ptr asect) | |
| { | |
| bfd_byte *p; | |
| bfd_byte *end; | |
| bfd_vma payload_size; | |
| bfd_vma symcount = 0; | |
| tdata_type *tdata = abfd->tdata.any; | |
| asymbol *symbols = NULL; | |
| sec_ptr space_function_index; | |
| size_t amt; | |
| p = asect->contents; | |
| end = asect->contents + asect->size; | |
| if (!p) | |
| return false; | |
| while (p < end) | |
| { | |
| bfd_byte subsection_code = *p++; | |
| if (subsection_code == WASM_FUNCTION_SUBSECTION) | |
| break; | |
| /* subsection_code is documented to be a varuint7, meaning that | |
| it has to be a single byte in the 0 - 127 range. If it isn't, | |
| the spec must have changed underneath us, so give up. */ | |
| if (subsection_code & 0x80) | |
| return false; | |
| READ_LEB128 (payload_size, p, end); | |
| if (payload_size > (size_t) (end - p)) | |
| return false; | |
| p += payload_size; | |
| } | |
| if (p >= end) | |
| return false; | |
| READ_LEB128 (payload_size, p, end); | |
| if (payload_size > (size_t) (end - p)) | |
| return false; | |
| end = p + payload_size; | |
| READ_LEB128 (symcount, p, end); | |
| /* Sanity check: each symbol has at least two bytes. */ | |
| if (symcount > payload_size / 2) | |
| return false; | |
| tdata->symcount = symcount; | |
| space_function_index | |
| = bfd_make_section_with_flags (abfd, WASM_SECTION_FUNCTION_INDEX, | |
| SEC_READONLY | SEC_CODE); | |
| if (!space_function_index) | |
| space_function_index | |
| = bfd_get_section_by_name (abfd, WASM_SECTION_FUNCTION_INDEX); | |
| if (!space_function_index) | |
| return false; | |
| if (_bfd_mul_overflow (tdata->symcount, sizeof (asymbol), &amt)) | |
| { | |
| bfd_set_error (bfd_error_file_too_big); | |
| return false; | |
| } | |
| symbols = bfd_alloc (abfd, amt); | |
| if (!symbols) | |
| return false; | |
| for (symcount = 0; p < end && symcount < tdata->symcount; symcount++) | |
| { | |
| bfd_vma idx; | |
| bfd_vma len; | |
| char *name; | |
| asymbol *sym; | |
| READ_LEB128 (idx, p, end); | |
| READ_LEB128 (len, p, end); | |
| if (len > (size_t) (end - p)) | |
| goto error_return; | |
| name = bfd_alloc (abfd, len + 1); | |
| if (!name) | |
| goto error_return; | |
| memcpy (name, p, len); | |
| name[len] = 0; | |
| p += len; | |
| sym = &symbols[symcount]; | |
| sym->the_bfd = abfd; | |
| sym->name = name; | |
| sym->value = idx; | |
| sym->flags = BSF_GLOBAL | BSF_FUNCTION; | |
| sym->section = space_function_index; | |
| sym->udata.p = NULL; | |
| } | |
| if (symcount < tdata->symcount) | |
| goto error_return; | |
| tdata->symbols = symbols; | |
| abfd->symcount = symcount; | |
| return true; | |
| error_return: | |
| if (symbols) | |
| bfd_release (abfd, symbols); | |
| tdata->symcount = 0; | |
| return false; | |
| } | |
| /* Read a byte from ABFD and return it, or EOF for EOF or error. | |
| Set ERRORPTR on non-EOF error. */ | |
| static int | |
| wasm_read_byte (bfd *abfd, bool *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; | |
| } | |
| /* Scan the wasm module ABFD, creating sections and symbols. | |
| Return TRUE on success. */ | |
| static bool | |
| wasm_scan (bfd *abfd) | |
| { | |
| bool error = false; | |
| /* Fake VMAs for now. Choose 0x80000000 as base to avoid clashes | |
| with actual data addresses. */ | |
| bfd_vma vma = 0x80000000; | |
| int section_code; | |
| unsigned int bytes_read; | |
| asection *bfdsec; | |
| if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) | |
| goto error_return; | |
| if (!wasm_read_header (abfd, &error)) | |
| goto error_return; | |
| while ((section_code = wasm_read_byte (abfd, &error)) != EOF) | |
| { | |
| if (section_code != 0) | |
| { | |
| const char *sname = wasm_section_code_to_name (section_code); | |
| if (!sname) | |
| goto error_return; | |
| bfdsec = bfd_make_section_anyway_with_flags (abfd, sname, | |
| SEC_HAS_CONTENTS); | |
| if (bfdsec == NULL) | |
| goto error_return; | |
| bfdsec->size = wasm_read_leb128 (abfd, &error, &bytes_read, false); | |
| if (error) | |
| goto error_return; | |
| } | |
| else | |
| { | |
| bfd_vma payload_len; | |
| bfd_vma namelen; | |
| char *name; | |
| char *prefix = WASM_SECTION_PREFIX; | |
| size_t prefixlen = strlen (prefix); | |
| ufile_ptr filesize; | |
| payload_len = wasm_read_leb128 (abfd, &error, &bytes_read, false); | |
| if (error) | |
| goto error_return; | |
| namelen = wasm_read_leb128 (abfd, &error, &bytes_read, false); | |
| if (error || bytes_read > payload_len | |
| || namelen > payload_len - bytes_read) | |
| goto error_return; | |
| payload_len -= namelen + bytes_read; | |
| filesize = bfd_get_file_size (abfd); | |
| if (filesize != 0 && namelen > filesize) | |
| { | |
| bfd_set_error (bfd_error_file_truncated); | |
| return false; | |
| } | |
| name = bfd_alloc (abfd, namelen + prefixlen + 1); | |
| if (!name) | |
| goto error_return; | |
| memcpy (name, prefix, prefixlen); | |
| if (bfd_bread (name + prefixlen, namelen, abfd) != namelen) | |
| goto error_return; | |
| name[prefixlen + namelen] = 0; | |
| bfdsec = bfd_make_section_anyway_with_flags (abfd, name, | |
| SEC_HAS_CONTENTS); | |
| if (bfdsec == NULL) | |
| goto error_return; | |
| bfdsec->size = payload_len; | |
| } | |
| bfdsec->vma = vma; | |
| bfdsec->lma = vma; | |
| bfdsec->alignment_power = 0; | |
| bfdsec->filepos = bfd_tell (abfd); | |
| if (bfdsec->size != 0) | |
| { | |
| bfdsec->contents = _bfd_alloc_and_read (abfd, bfdsec->size, | |
| bfdsec->size); | |
| if (!bfdsec->contents) | |
| 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; | |
| return true; | |
| error_return: | |
| return false; | |
| } | |
| /* Put a numbered section ASECT of ABFD into the table of numbered | |
| sections pointed to by FSARG. */ | |
| static void | |
| wasm_register_section (bfd *abfd ATTRIBUTE_UNUSED, | |
| asection *asect, | |
| void *fsarg) | |
| { | |
| sec_ptr *numbered_sections = fsarg; | |
| int idx = wasm_section_name_to_code (asect->name); | |
| if (idx == 0) | |
| return; | |
| numbered_sections[idx] = asect; | |
| } | |
| struct compute_section_arg | |
| { | |
| bfd_vma pos; | |
| bool failed; | |
| }; | |
| /* Compute the file position of ABFD's section ASECT. FSARG is a | |
| pointer to the current file position. | |
| We allow section names of the form .wasm.id to encode the numbered | |
| section with ID id, if it exists; otherwise, a custom section with | |
| ID "id" is produced. Arbitrary section names are for sections that | |
| are assumed already to contain a section header; those are appended | |
| to the WebAssembly module verbatim. */ | |
| static void | |
| wasm_compute_custom_section_file_position (bfd *abfd, | |
| sec_ptr asect, | |
| void *fsarg) | |
| { | |
| struct compute_section_arg *fs = fsarg; | |
| int idx; | |
| if (fs->failed) | |
| return; | |
| idx = wasm_section_name_to_code (asect->name); | |
| if (idx != 0) | |
| return; | |
| if (startswith (asect->name, WASM_SECTION_PREFIX)) | |
| { | |
| const char *name = asect->name + strlen (WASM_SECTION_PREFIX); | |
| 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 (! wasm_write_uleb128 (abfd, 0) | |
| || ! wasm_write_uleb128 (abfd, payload_len) | |
| || ! wasm_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; | |
| } | |
| /* Compute the file positions for the sections of ABFD. Currently, | |
| this writes all numbered sections first, in order, then all custom | |
| sections, in section order. | |
| The spec says that the numbered sections must appear in order of | |
| their ids, but custom sections can appear in any position and any | |
| order, and more than once. FIXME: support that. */ | |
| static bool | |
| wasm_compute_section_file_positions (bfd *abfd) | |
| { | |
| bfd_byte magic[SIZEOF_WASM_MAGIC] = WASM_MAGIC; | |
| bfd_byte vers[SIZEOF_WASM_VERSION] = WASM_VERSION; | |
| sec_ptr numbered_sections[WASM_NUMBERED_SECTIONS]; | |
| struct compute_section_arg fs; | |
| unsigned int i; | |
| bfd_seek (abfd, (bfd_vma) 0, SEEK_SET); | |
| if (bfd_bwrite (magic, sizeof (magic), abfd) != (sizeof magic) | |
| || bfd_bwrite (vers, sizeof (vers), abfd) != sizeof (vers)) | |
| return false; | |
| for (i = 0; i < WASM_NUMBERED_SECTIONS; i++) | |
| numbered_sections[i] = NULL; | |
| bfd_map_over_sections (abfd, wasm_register_section, numbered_sections); | |
| fs.pos = bfd_tell (abfd); | |
| for (i = 0; i < WASM_NUMBERED_SECTIONS; i++) | |
| { | |
| sec_ptr sec = numbered_sections[i]; | |
| bfd_size_type size; | |
| if (! sec) | |
| continue; | |
| size = sec->size; | |
| if (bfd_seek (abfd, fs.pos, SEEK_SET) != 0) | |
| return false; | |
| if (! wasm_write_uleb128 (abfd, i) | |
| || ! wasm_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; | |
| abfd->output_has_begun = true; | |
| return true; | |
| } | |
| static bool | |
| 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 bool | |
| wasm_write_object_contents (bfd* abfd) | |
| { | |
| bfd_byte magic[] = WASM_MAGIC; | |
| bfd_byte vers[] = WASM_VERSION; | |
| if (bfd_seek (abfd, 0, SEEK_SET) != 0) | |
| return false; | |
| if (bfd_bwrite (magic, sizeof (magic), abfd) != sizeof (magic) | |
| || bfd_bwrite (vers, sizeof (vers), abfd) != sizeof (vers)) | |
| return false; | |
| return true; | |
| } | |
| static bool | |
| 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 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) | |
| { | |
| size_t 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); | |
| } | |
| /* Check whether ABFD is a WebAssembly module; if so, scan it. */ | |
| static bfd_cleanup | |
| wasm_object_p (bfd *abfd) | |
| { | |
| bool error; | |
| asection *s; | |
| if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) | |
| return NULL; | |
| if (!wasm_read_header (abfd, &error)) | |
| { | |
| bfd_set_error (bfd_error_wrong_format); | |
| return NULL; | |
| } | |
| if (!wasm_mkobject (abfd)) | |
| return NULL; | |
| if (!wasm_scan (abfd) | |
| || !bfd_default_set_arch_mach (abfd, bfd_arch_wasm32, 0)) | |
| { | |
| bfd_release (abfd, abfd->tdata.any); | |
| abfd->tdata.any = NULL; | |
| return NULL; | |
| } | |
| s = bfd_get_section_by_name (abfd, WASM_NAME_SECTION); | |
| if (s != NULL && wasm_scan_name_function_section (abfd, s)) | |
| abfd->flags |= HAS_SYMS; | |
| return _bfd_no_cleanup; | |
| } | |
| /* 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_bool_bfd_asymbol_false | |
| #define wasm_get_lineno _bfd_nosymbols_get_lineno | |
| #define wasm_find_nearest_line _bfd_nosymbols_find_nearest_line | |
| #define wasm_find_nearest_line_with_alt _bfd_nosymbols_find_nearest_line_with_alt | |
| #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 | |
| 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. */ | |
| TARGET_KEEP_UNUSED_SECTION_SYMBOLS, /* keep unused section symbols. */ | |
| /* 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_bool_bfd_false_error, | |
| wasm_mkobject, | |
| _bfd_generic_mkarchive, | |
| _bfd_bool_bfd_false_error, | |
| }, | |
| { /* bfd_write_contents. */ | |
| _bfd_bool_bfd_false_error, | |
| wasm_write_object_contents, | |
| _bfd_write_archive_contents, | |
| _bfd_bool_bfd_false_error, | |
| }, | |
| 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 (_bfd_nolink), | |
| BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), | |
| NULL, | |
| NULL, | |
| }; |