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