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