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