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