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