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