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