1 /* BFD back-end for WebAssembly modules.
2    Copyright (C) 2017-2022 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 *
wasm_section_code_to_name(bfd_byte section_code)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
wasm_section_name_to_code(const char * name)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
wasm_read_leb128(bfd * abfd,bool * error_return,unsigned int * length_return,bool sign)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
wasm_write_uleb128(bfd * abfd,bfd_vma v)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
wasm_read_magic(bfd * abfd,bool * errorptr)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
wasm_read_version(bfd * abfd,bool * errorptr)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
wasm_read_header(bfd * abfd,bool * errorptr)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
wasm_scan_name_function_section(bfd * abfd,sec_ptr asect)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   return false;
363 }
364 
365 /* Read a byte from ABFD and return it, or EOF for EOF or error.
366    Set ERRORPTR on non-EOF error.  */
367 
368 static int
wasm_read_byte(bfd * abfd,bool * errorptr)369 wasm_read_byte (bfd *abfd, bool *errorptr)
370 {
371   bfd_byte byte;
372 
373   if (bfd_bread (&byte, (bfd_size_type) 1, abfd) != 1)
374     {
375       if (bfd_get_error () != bfd_error_file_truncated)
376 	*errorptr = true;
377       return EOF;
378     }
379 
380   return byte;
381 }
382 
383 /* Scan the wasm module ABFD, creating sections and symbols.
384    Return TRUE on success.  */
385 
386 static bool
wasm_scan(bfd * abfd)387 wasm_scan (bfd *abfd)
388 {
389   bool error = false;
390   /* Fake VMAs for now. Choose 0x80000000 as base to avoid clashes
391      with actual data addresses.  */
392   bfd_vma vma = 0x80000000;
393   int section_code;
394   unsigned int bytes_read;
395   asection *bfdsec;
396 
397   if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
398     goto error_return;
399 
400   if (!wasm_read_header (abfd, &error))
401     goto error_return;
402 
403   while ((section_code = wasm_read_byte (abfd, &error)) != EOF)
404     {
405       if (section_code != 0)
406 	{
407 	  const char *sname = wasm_section_code_to_name (section_code);
408 
409 	  if (!sname)
410 	    goto error_return;
411 
412 	  bfdsec = bfd_make_section_anyway_with_flags (abfd, sname,
413 						       SEC_HAS_CONTENTS);
414 	  if (bfdsec == NULL)
415 	    goto error_return;
416 
417 	  bfdsec->size = wasm_read_leb128 (abfd, &error, &bytes_read, false);
418 	  if (error)
419 	    goto error_return;
420 	}
421       else
422 	{
423 	  bfd_vma payload_len;
424 	  bfd_vma namelen;
425 	  char *name;
426 	  char *prefix = WASM_SECTION_PREFIX;
427 	  size_t prefixlen = strlen (prefix);
428 	  ufile_ptr filesize;
429 
430 	  payload_len = wasm_read_leb128 (abfd, &error, &bytes_read, false);
431 	  if (error)
432 	    goto error_return;
433 	  namelen = wasm_read_leb128 (abfd, &error, &bytes_read, false);
434 	  if (error || bytes_read > payload_len
435 	      || namelen > payload_len - bytes_read)
436 	    goto error_return;
437 	  payload_len -= namelen + bytes_read;
438 	  filesize = bfd_get_file_size (abfd);
439 	  if (filesize != 0 && namelen > filesize)
440 	    {
441 	      bfd_set_error (bfd_error_file_truncated);
442 	      return false;
443 	    }
444 	  name = bfd_alloc (abfd, namelen + prefixlen + 1);
445 	  if (!name)
446 	    goto error_return;
447 	  memcpy (name, prefix, prefixlen);
448 	  if (bfd_bread (name + prefixlen, namelen, abfd) != namelen)
449 	    goto error_return;
450 	  name[prefixlen + namelen] = 0;
451 
452 	  bfdsec = bfd_make_section_anyway_with_flags (abfd, name,
453 						       SEC_HAS_CONTENTS);
454 	  if (bfdsec == NULL)
455 	    goto error_return;
456 
457 	  bfdsec->size = payload_len;
458 	}
459 
460       bfdsec->vma = vma;
461       bfdsec->lma = vma;
462       bfdsec->alignment_power = 0;
463       bfdsec->filepos = bfd_tell (abfd);
464       if (bfdsec->size != 0)
465 	{
466 	  bfdsec->contents = _bfd_alloc_and_read (abfd, bfdsec->size,
467 						  bfdsec->size);
468 	  if (!bfdsec->contents)
469 	    goto error_return;
470 	}
471 
472       vma += bfdsec->size;
473     }
474 
475   /* Make sure we're at actual EOF.  There's no indication in the
476      WebAssembly format of how long the file is supposed to be.  */
477   if (error)
478     goto error_return;
479 
480   return true;
481 
482  error_return:
483   return false;
484 }
485 
486 /* Put a numbered section ASECT of ABFD into the table of numbered
487    sections pointed to by FSARG.  */
488 
489 static void
wasm_register_section(bfd * abfd ATTRIBUTE_UNUSED,asection * asect,void * fsarg)490 wasm_register_section (bfd *abfd ATTRIBUTE_UNUSED,
491 		       asection *asect,
492 		       void *fsarg)
493 {
494   sec_ptr *numbered_sections = fsarg;
495   int idx = wasm_section_name_to_code (asect->name);
496 
497   if (idx == 0)
498     return;
499 
500   numbered_sections[idx] = asect;
501 }
502 
503 struct compute_section_arg
504 {
505   bfd_vma pos;
506   bool failed;
507 };
508 
509 /* Compute the file position of ABFD's section ASECT.  FSARG is a
510    pointer to the current file position.
511 
512    We allow section names of the form .wasm.id to encode the numbered
513    section with ID id, if it exists; otherwise, a custom section with
514    ID "id" is produced.  Arbitrary section names are for sections that
515    are assumed already to contain a section header; those are appended
516    to the WebAssembly module verbatim.  */
517 
518 static void
wasm_compute_custom_section_file_position(bfd * abfd,sec_ptr asect,void * fsarg)519 wasm_compute_custom_section_file_position (bfd *abfd,
520 					   sec_ptr asect,
521 					   void *fsarg)
522 {
523   struct compute_section_arg *fs = fsarg;
524   int idx;
525 
526   if (fs->failed)
527     return;
528 
529   idx = wasm_section_name_to_code (asect->name);
530 
531   if (idx != 0)
532     return;
533 
534   if (startswith (asect->name, WASM_SECTION_PREFIX))
535     {
536       const char *name = asect->name + strlen (WASM_SECTION_PREFIX);
537       bfd_size_type payload_len = asect->size;
538       bfd_size_type name_len = strlen (name);
539       bfd_size_type nl = name_len;
540 
541       payload_len += name_len;
542 
543       do
544 	{
545 	  payload_len++;
546 	  nl >>= 7;
547 	}
548       while (nl);
549 
550       bfd_seek (abfd, fs->pos, SEEK_SET);
551       if (! wasm_write_uleb128 (abfd, 0)
552 	  || ! wasm_write_uleb128 (abfd, payload_len)
553 	  || ! wasm_write_uleb128 (abfd, name_len)
554 	  || bfd_bwrite (name, name_len, abfd) != name_len)
555 	goto error_return;
556       fs->pos = asect->filepos = bfd_tell (abfd);
557     }
558   else
559     {
560       asect->filepos = fs->pos;
561     }
562 
563 
564   fs->pos += asect->size;
565   return;
566 
567  error_return:
568   fs->failed = true;
569 }
570 
571 /* Compute the file positions for the sections of ABFD.  Currently,
572    this writes all numbered sections first, in order, then all custom
573    sections, in section order.
574 
575    The spec says that the numbered sections must appear in order of
576    their ids, but custom sections can appear in any position and any
577    order, and more than once. FIXME: support that.  */
578 
579 static bool
wasm_compute_section_file_positions(bfd * abfd)580 wasm_compute_section_file_positions (bfd *abfd)
581 {
582   bfd_byte magic[SIZEOF_WASM_MAGIC] = WASM_MAGIC;
583   bfd_byte vers[SIZEOF_WASM_VERSION] = WASM_VERSION;
584   sec_ptr numbered_sections[WASM_NUMBERED_SECTIONS];
585   struct compute_section_arg fs;
586   unsigned int i;
587 
588   bfd_seek (abfd, (bfd_vma) 0, SEEK_SET);
589 
590   if (bfd_bwrite (magic, sizeof (magic), abfd) != (sizeof magic)
591       || bfd_bwrite (vers, sizeof (vers), abfd) != sizeof (vers))
592     return false;
593 
594   for (i = 0; i < WASM_NUMBERED_SECTIONS; i++)
595     numbered_sections[i] = NULL;
596 
597   bfd_map_over_sections (abfd, wasm_register_section, numbered_sections);
598 
599   fs.pos = bfd_tell (abfd);
600   for (i = 0; i < WASM_NUMBERED_SECTIONS; i++)
601     {
602       sec_ptr sec = numbered_sections[i];
603       bfd_size_type size;
604 
605       if (! sec)
606 	continue;
607       size = sec->size;
608       if (bfd_seek (abfd, fs.pos, SEEK_SET) != 0)
609 	return false;
610       if (! wasm_write_uleb128 (abfd, i)
611 	  || ! wasm_write_uleb128 (abfd, size))
612 	return false;
613       fs.pos = sec->filepos = bfd_tell (abfd);
614       fs.pos += size;
615     }
616 
617   fs.failed = false;
618 
619   bfd_map_over_sections (abfd, wasm_compute_custom_section_file_position, &fs);
620 
621   if (fs.failed)
622     return false;
623 
624   abfd->output_has_begun = true;
625 
626   return true;
627 }
628 
629 static bool
wasm_set_section_contents(bfd * abfd,sec_ptr section,const void * location,file_ptr offset,bfd_size_type count)630 wasm_set_section_contents (bfd *abfd,
631 			   sec_ptr section,
632 			   const void *location,
633 			   file_ptr offset,
634 			   bfd_size_type count)
635 {
636   if (count == 0)
637     return true;
638 
639   if (! abfd->output_has_begun
640       && ! wasm_compute_section_file_positions (abfd))
641     return false;
642 
643   if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0
644       || bfd_bwrite (location, count, abfd) != count)
645     return false;
646 
647   return true;
648 }
649 
650 static bool
wasm_write_object_contents(bfd * abfd)651 wasm_write_object_contents (bfd* abfd)
652 {
653   bfd_byte magic[] = WASM_MAGIC;
654   bfd_byte vers[] = WASM_VERSION;
655 
656   if (bfd_seek (abfd, 0, SEEK_SET) != 0)
657     return false;
658 
659   if (bfd_bwrite (magic, sizeof (magic), abfd) != sizeof (magic)
660       || bfd_bwrite (vers, sizeof (vers), abfd) != sizeof (vers))
661     return false;
662 
663   return true;
664 }
665 
666 static bool
wasm_mkobject(bfd * abfd)667 wasm_mkobject (bfd *abfd)
668 {
669   tdata_type *tdata = (tdata_type *) bfd_alloc (abfd, sizeof (tdata_type));
670 
671   if (! tdata)
672     return false;
673 
674   tdata->symbols = NULL;
675   tdata->symcount = 0;
676 
677   abfd->tdata.any = tdata;
678 
679   return true;
680 }
681 
682 static long
wasm_get_symtab_upper_bound(bfd * abfd)683 wasm_get_symtab_upper_bound (bfd *abfd)
684 {
685   tdata_type *tdata = abfd->tdata.any;
686 
687   return (tdata->symcount + 1) * (sizeof (asymbol *));
688 }
689 
690 static long
wasm_canonicalize_symtab(bfd * abfd,asymbol ** alocation)691 wasm_canonicalize_symtab (bfd *abfd, asymbol **alocation)
692 {
693   tdata_type *tdata = abfd->tdata.any;
694   size_t i;
695 
696   for (i = 0; i < tdata->symcount; i++)
697     alocation[i] = &tdata->symbols[i];
698   alocation[i] = NULL;
699 
700   return tdata->symcount;
701 }
702 
703 static asymbol *
wasm_make_empty_symbol(bfd * abfd)704 wasm_make_empty_symbol (bfd *abfd)
705 {
706   size_t amt = sizeof (asymbol);
707   asymbol *new_symbol = (asymbol *) bfd_zalloc (abfd, amt);
708 
709   if (! new_symbol)
710     return NULL;
711   new_symbol->the_bfd = abfd;
712   return new_symbol;
713 }
714 
715 static void
wasm_print_symbol(bfd * abfd,void * filep,asymbol * symbol,bfd_print_symbol_type how)716 wasm_print_symbol (bfd *abfd,
717 		   void * filep,
718 		   asymbol *symbol,
719 		   bfd_print_symbol_type how)
720 {
721   FILE *file = (FILE *) filep;
722 
723   switch (how)
724     {
725     case bfd_print_symbol_name:
726       fprintf (file, "%s", symbol->name);
727       break;
728 
729     default:
730       bfd_print_symbol_vandf (abfd, filep, symbol);
731       fprintf (file, " %-5s %s", symbol->section->name, symbol->name);
732     }
733 }
734 
735 static void
wasm_get_symbol_info(bfd * abfd ATTRIBUTE_UNUSED,asymbol * symbol,symbol_info * ret)736 wasm_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED,
737 		      asymbol *symbol,
738 		      symbol_info *ret)
739 {
740   bfd_symbol_info (symbol, ret);
741 }
742 
743 /* Check whether ABFD is a WebAssembly module; if so, scan it.  */
744 
745 static bfd_cleanup
wasm_object_p(bfd * abfd)746 wasm_object_p (bfd *abfd)
747 {
748   bool error;
749   asection *s;
750 
751   if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
752     return NULL;
753 
754   if (!wasm_read_header (abfd, &error))
755     {
756       bfd_set_error (bfd_error_wrong_format);
757       return NULL;
758     }
759 
760   if (!wasm_mkobject (abfd))
761     return NULL;
762 
763   if (!wasm_scan (abfd)
764       || !bfd_default_set_arch_mach (abfd, bfd_arch_wasm32, 0))
765     {
766       bfd_release (abfd, abfd->tdata.any);
767       abfd->tdata.any = NULL;
768       return NULL;
769     }
770 
771   s = bfd_get_section_by_name (abfd, WASM_NAME_SECTION);
772   if (s != NULL && wasm_scan_name_function_section (abfd, s))
773     abfd->flags |= HAS_SYMS;
774 
775   return _bfd_no_cleanup;
776 }
777 
778 /* BFD_JUMP_TABLE_WRITE */
779 #define wasm_set_arch_mach		  _bfd_generic_set_arch_mach
780 
781 /* BFD_JUMP_TABLE_SYMBOLS */
782 #define wasm_get_symbol_version_string	  _bfd_nosymbols_get_symbol_version_string
783 #define wasm_bfd_is_local_label_name	   bfd_generic_is_local_label_name
784 #define wasm_bfd_is_target_special_symbol _bfd_bool_bfd_asymbol_false
785 #define wasm_get_lineno			  _bfd_nosymbols_get_lineno
786 #define wasm_find_nearest_line		  _bfd_nosymbols_find_nearest_line
787 #define wasm_find_line			  _bfd_nosymbols_find_line
788 #define wasm_find_inliner_info		  _bfd_nosymbols_find_inliner_info
789 #define wasm_bfd_make_debug_symbol	  _bfd_nosymbols_bfd_make_debug_symbol
790 #define wasm_read_minisymbols		  _bfd_generic_read_minisymbols
791 #define wasm_minisymbol_to_symbol	  _bfd_generic_minisymbol_to_symbol
792 
793 const bfd_target wasm_vec =
794 {
795   "wasm",			/* Name.  */
796   bfd_target_unknown_flavour,
797   BFD_ENDIAN_LITTLE,
798   BFD_ENDIAN_LITTLE,
799   (HAS_SYMS | WP_TEXT),		/* Object flags.  */
800   (SEC_CODE | SEC_DATA | SEC_HAS_CONTENTS), /* Section flags.  */
801   0,				/* Leading underscore.  */
802   ' ',				/* AR_pad_char.  */
803   255,				/* AR_max_namelen.  */
804   0,				/* Match priority.  */
805   TARGET_KEEP_UNUSED_SECTION_SYMBOLS, /* keep unused section symbols.  */
806   /* Routines to byte-swap various sized integers from the data sections.  */
807   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
808   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
809   bfd_getl16, bfd_getl_signed_16, bfd_putl16,
810 
811   /* Routines to byte-swap various sized integers from the file headers.  */
812   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
813   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
814   bfd_getl16, bfd_getl_signed_16, bfd_putl16,
815 
816   {
817     _bfd_dummy_target,
818     wasm_object_p,		/* bfd_check_format.  */
819     _bfd_dummy_target,
820     _bfd_dummy_target,
821   },
822   {
823     _bfd_bool_bfd_false_error,
824     wasm_mkobject,
825     _bfd_generic_mkarchive,
826     _bfd_bool_bfd_false_error,
827   },
828   {				/* bfd_write_contents.  */
829     _bfd_bool_bfd_false_error,
830     wasm_write_object_contents,
831     _bfd_write_archive_contents,
832     _bfd_bool_bfd_false_error,
833   },
834 
835   BFD_JUMP_TABLE_GENERIC (_bfd_generic),
836   BFD_JUMP_TABLE_COPY (_bfd_generic),
837   BFD_JUMP_TABLE_CORE (_bfd_nocore),
838   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
839   BFD_JUMP_TABLE_SYMBOLS (wasm),
840   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
841   BFD_JUMP_TABLE_WRITE (wasm),
842   BFD_JUMP_TABLE_LINK (_bfd_nolink),
843   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
844 
845   NULL,
846 
847   NULL,
848 };
849