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