(root)/
binutils-2.41/
bfd/
wasm-module.c
       1  /* BFD back-end for WebAssembly modules.
       2     Copyright (C) 2017-2023 Free Software Foundation, Inc.
       3  
       4     Based on srec.c, mmo.c, and binary.c
       5  
       6     This file is part of BFD, the Binary File Descriptor library.
       7  
       8     This program is free software; you can redistribute it and/or modify
       9     it under the terms of the GNU General Public License as published by
      10     the Free Software Foundation; either version 3 of the License, or
      11     (at your option) any later version.
      12  
      13     This program is distributed in the hope that it will be useful,
      14     but WITHOUT ANY WARRANTY; without even the implied warranty of
      15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16     GNU General Public License for more details.
      17  
      18     You should have received a copy of the GNU General Public License
      19     along with this program; if not, write to the Free Software
      20     Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
      21     MA 02110-1301, USA.  */
      22  
      23  /* The WebAssembly module format is a simple object file format
      24     including up to 11 numbered sections, plus any number of named
      25     "custom" sections. It is described at:
      26     https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md. */
      27  
      28  #include "sysdep.h"
      29  #include "bfd.h"
      30  #include "libiberty.h"
      31  #include "libbfd.h"
      32  #include "wasm-module.h"
      33  
      34  #include <limits.h>
      35  #ifndef CHAR_BIT
      36  #define CHAR_BIT 8
      37  #endif
      38  
      39  typedef struct
      40  {
      41    asymbol *      symbols;
      42    bfd_size_type  symcount;
      43  } tdata_type;
      44  
      45  static const char * const wasm_numbered_sections[] =
      46  {
      47    NULL, /* Custom section, different layout.  */
      48    WASM_SECTION ( 1, "type"),
      49    WASM_SECTION ( 2, "import"),
      50    WASM_SECTION ( 3, "function"),
      51    WASM_SECTION ( 4, "table"),
      52    WASM_SECTION ( 5, "memory"),
      53    WASM_SECTION ( 6, "global"),
      54    WASM_SECTION ( 7, "export"),
      55    WASM_SECTION ( 8, "start"),
      56    WASM_SECTION ( 9, "element"),
      57    WASM_SECTION (10, "code"),
      58    WASM_SECTION (11, "data"),
      59  };
      60  
      61  #define WASM_NUMBERED_SECTIONS ARRAY_SIZE (wasm_numbered_sections)
      62  
      63  /* Resolve SECTION_CODE to a section name if there is one, NULL
      64     otherwise.  */
      65  
      66  static const char *
      67  wasm_section_code_to_name (bfd_byte section_code)
      68  {
      69    if (section_code < WASM_NUMBERED_SECTIONS)
      70      return wasm_numbered_sections[section_code];
      71  
      72    return NULL;
      73  }
      74  
      75  /* Translate section name NAME to a section code, or 0 if it's a
      76     custom name.  */
      77  
      78  static unsigned int
      79  wasm_section_name_to_code (const char *name)
      80  {
      81    unsigned i;
      82  
      83    for (i = 1; i < WASM_NUMBERED_SECTIONS; i++)
      84      if (strcmp (name, wasm_numbered_sections[i]) == 0)
      85        return i;
      86  
      87    return 0;
      88  }
      89  
      90  /* WebAssembly LEB128 integers are sufficiently like DWARF LEB128
      91     integers that we use _bfd_safe_read_leb128, but there are two
      92     points of difference:
      93  
      94     - WebAssembly requires a 32-bit value to be encoded in at most 5
      95       bytes, etc.
      96     - _bfd_safe_read_leb128 accepts incomplete LEB128 encodings at the
      97       end of the buffer, while these are invalid in WebAssembly.
      98  
      99     Those differences mean that we will accept some files that are
     100     invalid WebAssembly.  */
     101  
     102  /* Read an LEB128-encoded integer from ABFD's I/O stream, reading one
     103     byte at a time.  Set ERROR_RETURN if no complete integer could be
     104     read, LENGTH_RETURN to the number of bytes read (including bytes in
     105     incomplete numbers).  SIGN means interpret the number as SLEB128. */
     106  
     107  static bfd_vma
     108  wasm_read_leb128 (bfd *abfd,
     109  		  bool *error_return,
     110  		  unsigned int *length_return,
     111  		  bool sign)
     112  {
     113    bfd_vma result = 0;
     114    unsigned int num_read = 0;
     115    unsigned int shift = 0;
     116    unsigned char byte = 0;
     117    unsigned char lost, mask;
     118    int status = 1;
     119  
     120    while (bfd_bread (&byte, 1, abfd) == 1)
     121      {
     122        num_read++;
     123  
     124        if (shift < CHAR_BIT * sizeof (result))
     125  	{
     126  	  result |= ((bfd_vma) (byte & 0x7f)) << shift;
     127  	  /* These bits overflowed.  */
     128  	  lost = byte ^ (result >> shift);
     129  	  /* And this is the mask of possible overflow bits.  */
     130  	  mask = 0x7f ^ ((bfd_vma) 0x7f << shift >> shift);
     131  	  shift += 7;
     132  	}
     133        else
     134  	{
     135  	  lost = byte;
     136  	  mask = 0x7f;
     137  	}
     138        if ((lost & mask) != (sign && (bfd_signed_vma) result < 0 ? mask : 0))
     139  	status |= 2;
     140  
     141        if ((byte & 0x80) == 0)
     142  	{
     143  	  status &= ~1;
     144  	  if (sign && shift < CHAR_BIT * sizeof (result) && (byte & 0x40))
     145  	    result |= -((bfd_vma) 1 << shift);
     146  	  break;
     147  	}
     148      }
     149  
     150    if (length_return != NULL)
     151      *length_return = num_read;
     152    if (error_return != NULL)
     153      *error_return = status != 0;
     154  
     155    return result;
     156  }
     157  
     158  /* Encode an integer V as LEB128 and write it to ABFD, return TRUE on
     159     success.  */
     160  
     161  static bool
     162  wasm_write_uleb128 (bfd *abfd, bfd_vma v)
     163  {
     164    do
     165      {
     166        bfd_byte c = v & 0x7f;
     167        v >>= 7;
     168  
     169        if (v)
     170  	c |= 0x80;
     171  
     172        if (bfd_bwrite (&c, 1, abfd) != 1)
     173  	return false;
     174      }
     175    while (v);
     176  
     177    return true;
     178  }
     179  
     180  /* Read the LEB128 integer at P, saving it to X; at end of buffer,
     181     jump to error_return.  */
     182  #define READ_LEB128(x, p, end)						\
     183    do									\
     184      {									\
     185        if ((p) >= (end))							\
     186  	goto error_return;						\
     187        (x) = _bfd_safe_read_leb128 (abfd, &(p), false, (end));		\
     188      }									\
     189    while (0)
     190  
     191  /* Verify the magic number at the beginning of a WebAssembly module
     192     ABFD, setting ERRORPTR if there's a mismatch.  */
     193  
     194  static bool
     195  wasm_read_magic (bfd *abfd, bool *errorptr)
     196  {
     197    bfd_byte magic_const[SIZEOF_WASM_MAGIC] = WASM_MAGIC;
     198    bfd_byte magic[SIZEOF_WASM_MAGIC];
     199  
     200    if (bfd_bread (magic, sizeof (magic), abfd) == sizeof (magic)
     201        && memcmp (magic, magic_const, sizeof (magic)) == 0)
     202      return true;
     203  
     204    *errorptr = true;
     205    return false;
     206  }
     207  
     208  /* Read the version number from ABFD, returning TRUE if it's a supported
     209     version. Set ERRORPTR otherwise.  */
     210  
     211  static bool
     212  wasm_read_version (bfd *abfd, bool *errorptr)
     213  {
     214    bfd_byte vers_const[SIZEOF_WASM_VERSION] = WASM_VERSION;
     215    bfd_byte vers[SIZEOF_WASM_VERSION];
     216  
     217    if (bfd_bread (vers, sizeof (vers), abfd) == sizeof (vers)
     218        /* Don't attempt to parse newer versions, which are likely to
     219  	 require code changes.  */
     220        && memcmp (vers, vers_const, sizeof (vers)) == 0)
     221      return true;
     222  
     223    *errorptr = true;
     224    return false;
     225  }
     226  
     227  /* Read the WebAssembly header (magic number plus version number) from
     228     ABFD, setting ERRORPTR to TRUE if there is a mismatch.  */
     229  
     230  static bool
     231  wasm_read_header (bfd *abfd, bool *errorptr)
     232  {
     233    if (! wasm_read_magic (abfd, errorptr))
     234      return false;
     235  
     236    if (! wasm_read_version (abfd, errorptr))
     237      return false;
     238  
     239    return true;
     240  }
     241  
     242  /* Scan the "function" subsection of the "name" section ASECT in the
     243     wasm module ABFD. Create symbols. Return TRUE on success.  */
     244  
     245  static bool
     246  wasm_scan_name_function_section (bfd *abfd, sec_ptr asect)
     247  {
     248    bfd_byte *p;
     249    bfd_byte *end;
     250    bfd_vma payload_size;
     251    bfd_vma symcount = 0;
     252    tdata_type *tdata = abfd->tdata.any;
     253    asymbol *symbols = NULL;
     254    sec_ptr space_function_index;
     255    size_t amt;
     256  
     257    p = asect->contents;
     258    end = asect->contents + asect->size;
     259  
     260    if (!p)
     261      return false;
     262  
     263    while (p < end)
     264      {
     265        bfd_byte subsection_code = *p++;
     266        if (subsection_code == WASM_FUNCTION_SUBSECTION)
     267  	break;
     268  
     269        /* subsection_code is documented to be a varuint7, meaning that
     270  	 it has to be a single byte in the 0 - 127 range.  If it isn't,
     271  	 the spec must have changed underneath us, so give up.  */
     272        if (subsection_code & 0x80)
     273  	return false;
     274  
     275        READ_LEB128 (payload_size, p, end);
     276  
     277        if (payload_size > (size_t) (end - p))
     278  	return false;
     279  
     280        p += payload_size;
     281      }
     282  
     283    if (p >= end)
     284      return false;
     285  
     286    READ_LEB128 (payload_size, p, end);
     287  
     288    if (payload_size > (size_t) (end - p))
     289      return false;
     290  
     291    end = p + payload_size;
     292  
     293    READ_LEB128 (symcount, p, end);
     294  
     295    /* Sanity check: each symbol has at least two bytes.  */
     296    if (symcount > payload_size / 2)
     297      return false;
     298  
     299    tdata->symcount = symcount;
     300  
     301    space_function_index
     302      = bfd_make_section_with_flags (abfd, WASM_SECTION_FUNCTION_INDEX,
     303  				   SEC_READONLY | SEC_CODE);
     304  
     305    if (!space_function_index)
     306      space_function_index
     307        = bfd_get_section_by_name (abfd, WASM_SECTION_FUNCTION_INDEX);
     308  
     309    if (!space_function_index)
     310      return false;
     311  
     312    if (_bfd_mul_overflow (tdata->symcount, sizeof (asymbol), &amt))
     313      {
     314        bfd_set_error (bfd_error_file_too_big);
     315        return false;
     316      }
     317    symbols = bfd_alloc (abfd, amt);
     318    if (!symbols)
     319      return false;
     320  
     321    for (symcount = 0; p < end && symcount < tdata->symcount; symcount++)
     322      {
     323        bfd_vma idx;
     324        bfd_vma len;
     325        char *name;
     326        asymbol *sym;
     327  
     328        READ_LEB128 (idx, p, end);
     329        READ_LEB128 (len, p, end);
     330  
     331        if (len > (size_t) (end - p))
     332  	goto error_return;
     333  
     334        name = bfd_alloc (abfd, len + 1);
     335        if (!name)
     336  	goto error_return;
     337  
     338        memcpy (name, p, len);
     339        name[len] = 0;
     340        p += len;
     341  
     342        sym = &symbols[symcount];
     343        sym->the_bfd = abfd;
     344        sym->name = name;
     345        sym->value = idx;
     346        sym->flags = BSF_GLOBAL | BSF_FUNCTION;
     347        sym->section = space_function_index;
     348        sym->udata.p = NULL;
     349      }
     350  
     351    if (symcount < tdata->symcount)
     352      goto error_return;
     353  
     354    tdata->symbols = symbols;
     355    abfd->symcount = symcount;
     356  
     357    return true;
     358  
     359   error_return:
     360    if (symbols)
     361      bfd_release (abfd, symbols);
     362    tdata->symcount = 0;
     363    return false;
     364  }
     365  
     366  /* Read a byte from ABFD and return it, or EOF for EOF or error.
     367     Set ERRORPTR on non-EOF error.  */
     368  
     369  static int
     370  wasm_read_byte (bfd *abfd, bool *errorptr)
     371  {
     372    bfd_byte byte;
     373  
     374    if (bfd_bread (&byte, (bfd_size_type) 1, abfd) != 1)
     375      {
     376        if (bfd_get_error () != bfd_error_file_truncated)
     377  	*errorptr = true;
     378        return EOF;
     379      }
     380  
     381    return byte;
     382  }
     383  
     384  /* Scan the wasm module ABFD, creating sections and symbols.
     385     Return TRUE on success.  */
     386  
     387  static bool
     388  wasm_scan (bfd *abfd)
     389  {
     390    bool error = false;
     391    /* Fake VMAs for now. Choose 0x80000000 as base to avoid clashes
     392       with actual data addresses.  */
     393    bfd_vma vma = 0x80000000;
     394    int section_code;
     395    unsigned int bytes_read;
     396    asection *bfdsec;
     397  
     398    if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
     399      goto error_return;
     400  
     401    if (!wasm_read_header (abfd, &error))
     402      goto error_return;
     403  
     404    while ((section_code = wasm_read_byte (abfd, &error)) != EOF)
     405      {
     406        if (section_code != 0)
     407  	{
     408  	  const char *sname = wasm_section_code_to_name (section_code);
     409  
     410  	  if (!sname)
     411  	    goto error_return;
     412  
     413  	  bfdsec = bfd_make_section_anyway_with_flags (abfd, sname,
     414  						       SEC_HAS_CONTENTS);
     415  	  if (bfdsec == NULL)
     416  	    goto error_return;
     417  
     418  	  bfdsec->size = wasm_read_leb128 (abfd, &error, &bytes_read, false);
     419  	  if (error)
     420  	    goto error_return;
     421  	}
     422        else
     423  	{
     424  	  bfd_vma payload_len;
     425  	  bfd_vma namelen;
     426  	  char *name;
     427  	  char *prefix = WASM_SECTION_PREFIX;
     428  	  size_t prefixlen = strlen (prefix);
     429  	  ufile_ptr filesize;
     430  
     431  	  payload_len = wasm_read_leb128 (abfd, &error, &bytes_read, false);
     432  	  if (error)
     433  	    goto error_return;
     434  	  namelen = wasm_read_leb128 (abfd, &error, &bytes_read, false);
     435  	  if (error || bytes_read > payload_len
     436  	      || namelen > payload_len - bytes_read)
     437  	    goto error_return;
     438  	  payload_len -= namelen + bytes_read;
     439  	  filesize = bfd_get_file_size (abfd);
     440  	  if (filesize != 0 && namelen > filesize)
     441  	    {
     442  	      bfd_set_error (bfd_error_file_truncated);
     443  	      return false;
     444  	    }
     445  	  name = bfd_alloc (abfd, namelen + prefixlen + 1);
     446  	  if (!name)
     447  	    goto error_return;
     448  	  memcpy (name, prefix, prefixlen);
     449  	  if (bfd_bread (name + prefixlen, namelen, abfd) != namelen)
     450  	    goto error_return;
     451  	  name[prefixlen + namelen] = 0;
     452  
     453  	  bfdsec = bfd_make_section_anyway_with_flags (abfd, name,
     454  						       SEC_HAS_CONTENTS);
     455  	  if (bfdsec == NULL)
     456  	    goto error_return;
     457  
     458  	  bfdsec->size = payload_len;
     459  	}
     460  
     461        bfdsec->vma = vma;
     462        bfdsec->lma = vma;
     463        bfdsec->alignment_power = 0;
     464        bfdsec->filepos = bfd_tell (abfd);
     465        if (bfdsec->size != 0)
     466  	{
     467  	  bfdsec->contents = _bfd_alloc_and_read (abfd, bfdsec->size,
     468  						  bfdsec->size);
     469  	  if (!bfdsec->contents)
     470  	    goto error_return;
     471  	}
     472  
     473        vma += bfdsec->size;
     474      }
     475  
     476    /* Make sure we're at actual EOF.  There's no indication in the
     477       WebAssembly format of how long the file is supposed to be.  */
     478    if (error)
     479      goto error_return;
     480  
     481    return true;
     482  
     483   error_return:
     484    return false;
     485  }
     486  
     487  /* Put a numbered section ASECT of ABFD into the table of numbered
     488     sections pointed to by FSARG.  */
     489  
     490  static void
     491  wasm_register_section (bfd *abfd ATTRIBUTE_UNUSED,
     492  		       asection *asect,
     493  		       void *fsarg)
     494  {
     495    sec_ptr *numbered_sections = fsarg;
     496    int idx = wasm_section_name_to_code (asect->name);
     497  
     498    if (idx == 0)
     499      return;
     500  
     501    numbered_sections[idx] = asect;
     502  }
     503  
     504  struct compute_section_arg
     505  {
     506    bfd_vma pos;
     507    bool failed;
     508  };
     509  
     510  /* Compute the file position of ABFD's section ASECT.  FSARG is a
     511     pointer to the current file position.
     512  
     513     We allow section names of the form .wasm.id to encode the numbered
     514     section with ID id, if it exists; otherwise, a custom section with
     515     ID "id" is produced.  Arbitrary section names are for sections that
     516     are assumed already to contain a section header; those are appended
     517     to the WebAssembly module verbatim.  */
     518  
     519  static void
     520  wasm_compute_custom_section_file_position (bfd *abfd,
     521  					   sec_ptr asect,
     522  					   void *fsarg)
     523  {
     524    struct compute_section_arg *fs = fsarg;
     525    int idx;
     526  
     527    if (fs->failed)
     528      return;
     529  
     530    idx = wasm_section_name_to_code (asect->name);
     531  
     532    if (idx != 0)
     533      return;
     534  
     535    if (startswith (asect->name, WASM_SECTION_PREFIX))
     536      {
     537        const char *name = asect->name + strlen (WASM_SECTION_PREFIX);
     538        bfd_size_type payload_len = asect->size;
     539        bfd_size_type name_len = strlen (name);
     540        bfd_size_type nl = name_len;
     541  
     542        payload_len += name_len;
     543  
     544        do
     545  	{
     546  	  payload_len++;
     547  	  nl >>= 7;
     548  	}
     549        while (nl);
     550  
     551        bfd_seek (abfd, fs->pos, SEEK_SET);
     552        if (! wasm_write_uleb128 (abfd, 0)
     553  	  || ! wasm_write_uleb128 (abfd, payload_len)
     554  	  || ! wasm_write_uleb128 (abfd, name_len)
     555  	  || bfd_bwrite (name, name_len, abfd) != name_len)
     556  	goto error_return;
     557        fs->pos = asect->filepos = bfd_tell (abfd);
     558      }
     559    else
     560      {
     561        asect->filepos = fs->pos;
     562      }
     563  
     564  
     565    fs->pos += asect->size;
     566    return;
     567  
     568   error_return:
     569    fs->failed = true;
     570  }
     571  
     572  /* Compute the file positions for the sections of ABFD.  Currently,
     573     this writes all numbered sections first, in order, then all custom
     574     sections, in section order.
     575  
     576     The spec says that the numbered sections must appear in order of
     577     their ids, but custom sections can appear in any position and any
     578     order, and more than once. FIXME: support that.  */
     579  
     580  static bool
     581  wasm_compute_section_file_positions (bfd *abfd)
     582  {
     583    bfd_byte magic[SIZEOF_WASM_MAGIC] = WASM_MAGIC;
     584    bfd_byte vers[SIZEOF_WASM_VERSION] = WASM_VERSION;
     585    sec_ptr numbered_sections[WASM_NUMBERED_SECTIONS];
     586    struct compute_section_arg fs;
     587    unsigned int i;
     588  
     589    bfd_seek (abfd, (bfd_vma) 0, SEEK_SET);
     590  
     591    if (bfd_bwrite (magic, sizeof (magic), abfd) != (sizeof magic)
     592        || bfd_bwrite (vers, sizeof (vers), abfd) != sizeof (vers))
     593      return false;
     594  
     595    for (i = 0; i < WASM_NUMBERED_SECTIONS; i++)
     596      numbered_sections[i] = NULL;
     597  
     598    bfd_map_over_sections (abfd, wasm_register_section, numbered_sections);
     599  
     600    fs.pos = bfd_tell (abfd);
     601    for (i = 0; i < WASM_NUMBERED_SECTIONS; i++)
     602      {
     603        sec_ptr sec = numbered_sections[i];
     604        bfd_size_type size;
     605  
     606        if (! sec)
     607  	continue;
     608        size = sec->size;
     609        if (bfd_seek (abfd, fs.pos, SEEK_SET) != 0)
     610  	return false;
     611        if (! wasm_write_uleb128 (abfd, i)
     612  	  || ! wasm_write_uleb128 (abfd, size))
     613  	return false;
     614        fs.pos = sec->filepos = bfd_tell (abfd);
     615        fs.pos += size;
     616      }
     617  
     618    fs.failed = false;
     619  
     620    bfd_map_over_sections (abfd, wasm_compute_custom_section_file_position, &fs);
     621  
     622    if (fs.failed)
     623      return false;
     624  
     625    abfd->output_has_begun = true;
     626  
     627    return true;
     628  }
     629  
     630  static bool
     631  wasm_set_section_contents (bfd *abfd,
     632  			   sec_ptr section,
     633  			   const void *location,
     634  			   file_ptr offset,
     635  			   bfd_size_type count)
     636  {
     637    if (count == 0)
     638      return true;
     639  
     640    if (! abfd->output_has_begun
     641        && ! wasm_compute_section_file_positions (abfd))
     642      return false;
     643  
     644    if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0
     645        || bfd_bwrite (location, count, abfd) != count)
     646      return false;
     647  
     648    return true;
     649  }
     650  
     651  static bool
     652  wasm_write_object_contents (bfd* abfd)
     653  {
     654    bfd_byte magic[] = WASM_MAGIC;
     655    bfd_byte vers[] = WASM_VERSION;
     656  
     657    if (bfd_seek (abfd, 0, SEEK_SET) != 0)
     658      return false;
     659  
     660    if (bfd_bwrite (magic, sizeof (magic), abfd) != sizeof (magic)
     661        || bfd_bwrite (vers, sizeof (vers), abfd) != sizeof (vers))
     662      return false;
     663  
     664    return true;
     665  }
     666  
     667  static bool
     668  wasm_mkobject (bfd *abfd)
     669  {
     670    tdata_type *tdata = (tdata_type *) bfd_alloc (abfd, sizeof (tdata_type));
     671  
     672    if (! tdata)
     673      return false;
     674  
     675    tdata->symbols = NULL;
     676    tdata->symcount = 0;
     677  
     678    abfd->tdata.any = tdata;
     679  
     680    return true;
     681  }
     682  
     683  static long
     684  wasm_get_symtab_upper_bound (bfd *abfd)
     685  {
     686    tdata_type *tdata = abfd->tdata.any;
     687  
     688    return (tdata->symcount + 1) * (sizeof (asymbol *));
     689  }
     690  
     691  static long
     692  wasm_canonicalize_symtab (bfd *abfd, asymbol **alocation)
     693  {
     694    tdata_type *tdata = abfd->tdata.any;
     695    size_t i;
     696  
     697    for (i = 0; i < tdata->symcount; i++)
     698      alocation[i] = &tdata->symbols[i];
     699    alocation[i] = NULL;
     700  
     701    return tdata->symcount;
     702  }
     703  
     704  static asymbol *
     705  wasm_make_empty_symbol (bfd *abfd)
     706  {
     707    size_t amt = sizeof (asymbol);
     708    asymbol *new_symbol = (asymbol *) bfd_zalloc (abfd, amt);
     709  
     710    if (! new_symbol)
     711      return NULL;
     712    new_symbol->the_bfd = abfd;
     713    return new_symbol;
     714  }
     715  
     716  static void
     717  wasm_print_symbol (bfd *abfd,
     718  		   void * filep,
     719  		   asymbol *symbol,
     720  		   bfd_print_symbol_type how)
     721  {
     722    FILE *file = (FILE *) filep;
     723  
     724    switch (how)
     725      {
     726      case bfd_print_symbol_name:
     727        fprintf (file, "%s", symbol->name);
     728        break;
     729  
     730      default:
     731        bfd_print_symbol_vandf (abfd, filep, symbol);
     732        fprintf (file, " %-5s %s", symbol->section->name, symbol->name);
     733      }
     734  }
     735  
     736  static void
     737  wasm_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED,
     738  		      asymbol *symbol,
     739  		      symbol_info *ret)
     740  {
     741    bfd_symbol_info (symbol, ret);
     742  }
     743  
     744  /* Check whether ABFD is a WebAssembly module; if so, scan it.  */
     745  
     746  static bfd_cleanup
     747  wasm_object_p (bfd *abfd)
     748  {
     749    bool error;
     750    asection *s;
     751  
     752    if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
     753      return NULL;
     754  
     755    if (!wasm_read_header (abfd, &error))
     756      {
     757        bfd_set_error (bfd_error_wrong_format);
     758        return NULL;
     759      }
     760  
     761    if (!wasm_mkobject (abfd))
     762      return NULL;
     763  
     764    if (!wasm_scan (abfd)
     765        || !bfd_default_set_arch_mach (abfd, bfd_arch_wasm32, 0))
     766      {
     767        bfd_release (abfd, abfd->tdata.any);
     768        abfd->tdata.any = NULL;
     769        return NULL;
     770      }
     771  
     772    s = bfd_get_section_by_name (abfd, WASM_NAME_SECTION);
     773    if (s != NULL && wasm_scan_name_function_section (abfd, s))
     774      abfd->flags |= HAS_SYMS;
     775  
     776    return _bfd_no_cleanup;
     777  }
     778  
     779  /* BFD_JUMP_TABLE_WRITE */
     780  #define wasm_set_arch_mach		  _bfd_generic_set_arch_mach
     781  
     782  /* BFD_JUMP_TABLE_SYMBOLS */
     783  #define wasm_get_symbol_version_string	  _bfd_nosymbols_get_symbol_version_string
     784  #define wasm_bfd_is_local_label_name	   bfd_generic_is_local_label_name
     785  #define wasm_bfd_is_target_special_symbol _bfd_bool_bfd_asymbol_false
     786  #define wasm_get_lineno			  _bfd_nosymbols_get_lineno
     787  #define wasm_find_nearest_line		  _bfd_nosymbols_find_nearest_line
     788  #define wasm_find_nearest_line_with_alt	  _bfd_nosymbols_find_nearest_line_with_alt
     789  #define wasm_find_line			  _bfd_nosymbols_find_line
     790  #define wasm_find_inliner_info		  _bfd_nosymbols_find_inliner_info
     791  #define wasm_bfd_make_debug_symbol	  _bfd_nosymbols_bfd_make_debug_symbol
     792  #define wasm_read_minisymbols		  _bfd_generic_read_minisymbols
     793  #define wasm_minisymbol_to_symbol	  _bfd_generic_minisymbol_to_symbol
     794  
     795  const bfd_target wasm_vec =
     796  {
     797    "wasm",			/* Name.  */
     798    bfd_target_unknown_flavour,
     799    BFD_ENDIAN_LITTLE,
     800    BFD_ENDIAN_LITTLE,
     801    (HAS_SYMS | WP_TEXT),		/* Object flags.  */
     802    (SEC_CODE | SEC_DATA | SEC_HAS_CONTENTS), /* Section flags.  */
     803    0,				/* Leading underscore.  */
     804    ' ',				/* AR_pad_char.  */
     805    255,				/* AR_max_namelen.  */
     806    0,				/* Match priority.  */
     807    TARGET_KEEP_UNUSED_SECTION_SYMBOLS, /* keep unused section symbols.  */
     808    /* Routines to byte-swap various sized integers from the data sections.  */
     809    bfd_getl64, bfd_getl_signed_64, bfd_putl64,
     810    bfd_getl32, bfd_getl_signed_32, bfd_putl32,
     811    bfd_getl16, bfd_getl_signed_16, bfd_putl16,
     812  
     813    /* Routines to byte-swap various sized integers from the file headers.  */
     814    bfd_getl64, bfd_getl_signed_64, bfd_putl64,
     815    bfd_getl32, bfd_getl_signed_32, bfd_putl32,
     816    bfd_getl16, bfd_getl_signed_16, bfd_putl16,
     817  
     818    {
     819      _bfd_dummy_target,
     820      wasm_object_p,		/* bfd_check_format.  */
     821      _bfd_dummy_target,
     822      _bfd_dummy_target,
     823    },
     824    {
     825      _bfd_bool_bfd_false_error,
     826      wasm_mkobject,
     827      _bfd_generic_mkarchive,
     828      _bfd_bool_bfd_false_error,
     829    },
     830    {				/* bfd_write_contents.  */
     831      _bfd_bool_bfd_false_error,
     832      wasm_write_object_contents,
     833      _bfd_write_archive_contents,
     834      _bfd_bool_bfd_false_error,
     835    },
     836  
     837    BFD_JUMP_TABLE_GENERIC (_bfd_generic),
     838    BFD_JUMP_TABLE_COPY (_bfd_generic),
     839    BFD_JUMP_TABLE_CORE (_bfd_nocore),
     840    BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
     841    BFD_JUMP_TABLE_SYMBOLS (wasm),
     842    BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
     843    BFD_JUMP_TABLE_WRITE (wasm),
     844    BFD_JUMP_TABLE_LINK (_bfd_nolink),
     845    BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
     846  
     847    NULL,
     848  
     849    NULL,
     850  };