1 1.1 christos /* BFD back-end for WebAssembly modules. 2 1.1.1.5 christos Copyright (C) 2017-2024 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.1.5 christos while (bfd_read (&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.1.5 christos if (bfd_write (&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.1.5 christos if (bfd_read (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.1.5 christos if (bfd_read (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.1.5 christos if (bfd_read (&byte, 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.1.5 christos if (bfd_seek (abfd, 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.5 christos if (bfd_read (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.1.5 christos if (bfd_seek (abfd, fs->pos, SEEK_SET) != 0 552 1.1.1.5 christos || ! 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.5 christos || bfd_write (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.1.5 christos if (bfd_seek (abfd, (bfd_vma) 0, SEEK_SET) != 0 590 1.1.1.5 christos || bfd_write (magic, sizeof (magic), abfd) != (sizeof magic) 591 1.1.1.5 christos || bfd_write (vers, sizeof (vers), abfd) != sizeof (vers)) 592 1.1.1.4 christos return false; 593 1.1 christos 594 1.1 christos for (i = 0; i < WASM_NUMBERED_SECTIONS; i++) 595 1.1 christos numbered_sections[i] = NULL; 596 1.1 christos 597 1.1 christos bfd_map_over_sections (abfd, wasm_register_section, numbered_sections); 598 1.1 christos 599 1.1 christos fs.pos = bfd_tell (abfd); 600 1.1 christos for (i = 0; i < WASM_NUMBERED_SECTIONS; i++) 601 1.1 christos { 602 1.1 christos sec_ptr sec = numbered_sections[i]; 603 1.1 christos bfd_size_type size; 604 1.1 christos 605 1.1 christos if (! sec) 606 1.1.1.2 christos continue; 607 1.1 christos size = sec->size; 608 1.1 christos if (bfd_seek (abfd, fs.pos, SEEK_SET) != 0) 609 1.1.1.4 christos return false; 610 1.1 christos if (! wasm_write_uleb128 (abfd, i) 611 1.1.1.2 christos || ! wasm_write_uleb128 (abfd, size)) 612 1.1.1.4 christos return false; 613 1.1 christos fs.pos = sec->filepos = bfd_tell (abfd); 614 1.1 christos fs.pos += size; 615 1.1 christos } 616 1.1 christos 617 1.1.1.4 christos fs.failed = false; 618 1.1 christos 619 1.1 christos bfd_map_over_sections (abfd, wasm_compute_custom_section_file_position, &fs); 620 1.1 christos 621 1.1 christos if (fs.failed) 622 1.1.1.4 christos return false; 623 1.1 christos 624 1.1.1.4 christos abfd->output_has_begun = true; 625 1.1 christos 626 1.1.1.4 christos return true; 627 1.1 christos } 628 1.1 christos 629 1.1.1.4 christos static bool 630 1.1 christos wasm_set_section_contents (bfd *abfd, 631 1.1.1.2 christos sec_ptr section, 632 1.1.1.2 christos const void *location, 633 1.1.1.2 christos file_ptr offset, 634 1.1.1.2 christos bfd_size_type count) 635 1.1 christos { 636 1.1 christos if (count == 0) 637 1.1.1.4 christos return true; 638 1.1 christos 639 1.1 christos if (! abfd->output_has_begun 640 1.1 christos && ! wasm_compute_section_file_positions (abfd)) 641 1.1.1.4 christos return false; 642 1.1 christos 643 1.1 christos if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0 644 1.1.1.5 christos || bfd_write (location, count, abfd) != count) 645 1.1.1.4 christos return false; 646 1.1 christos 647 1.1.1.4 christos return true; 648 1.1 christos } 649 1.1 christos 650 1.1.1.4 christos static bool 651 1.1 christos wasm_write_object_contents (bfd* abfd) 652 1.1 christos { 653 1.1 christos bfd_byte magic[] = WASM_MAGIC; 654 1.1 christos bfd_byte vers[] = WASM_VERSION; 655 1.1 christos 656 1.1 christos if (bfd_seek (abfd, 0, SEEK_SET) != 0) 657 1.1.1.4 christos return false; 658 1.1 christos 659 1.1.1.5 christos if (bfd_write (magic, sizeof (magic), abfd) != sizeof (magic) 660 1.1.1.5 christos || bfd_write (vers, sizeof (vers), abfd) != sizeof (vers)) 661 1.1.1.4 christos return false; 662 1.1 christos 663 1.1.1.4 christos return true; 664 1.1 christos } 665 1.1 christos 666 1.1.1.4 christos static bool 667 1.1 christos wasm_mkobject (bfd *abfd) 668 1.1 christos { 669 1.1 christos tdata_type *tdata = (tdata_type *) bfd_alloc (abfd, sizeof (tdata_type)); 670 1.1 christos 671 1.1 christos if (! tdata) 672 1.1.1.4 christos return false; 673 1.1 christos 674 1.1 christos tdata->symbols = NULL; 675 1.1 christos tdata->symcount = 0; 676 1.1 christos 677 1.1 christos abfd->tdata.any = tdata; 678 1.1 christos 679 1.1.1.4 christos return true; 680 1.1 christos } 681 1.1 christos 682 1.1 christos static long 683 1.1 christos wasm_get_symtab_upper_bound (bfd *abfd) 684 1.1 christos { 685 1.1 christos tdata_type *tdata = abfd->tdata.any; 686 1.1 christos 687 1.1 christos return (tdata->symcount + 1) * (sizeof (asymbol *)); 688 1.1 christos } 689 1.1 christos 690 1.1 christos static long 691 1.1 christos wasm_canonicalize_symtab (bfd *abfd, asymbol **alocation) 692 1.1 christos { 693 1.1 christos tdata_type *tdata = abfd->tdata.any; 694 1.1 christos size_t i; 695 1.1 christos 696 1.1 christos for (i = 0; i < tdata->symcount; i++) 697 1.1 christos alocation[i] = &tdata->symbols[i]; 698 1.1 christos alocation[i] = NULL; 699 1.1 christos 700 1.1 christos return tdata->symcount; 701 1.1 christos } 702 1.1 christos 703 1.1 christos static asymbol * 704 1.1 christos wasm_make_empty_symbol (bfd *abfd) 705 1.1 christos { 706 1.1.1.3 christos size_t amt = sizeof (asymbol); 707 1.1 christos asymbol *new_symbol = (asymbol *) bfd_zalloc (abfd, amt); 708 1.1 christos 709 1.1 christos if (! new_symbol) 710 1.1 christos return NULL; 711 1.1 christos new_symbol->the_bfd = abfd; 712 1.1 christos return new_symbol; 713 1.1 christos } 714 1.1 christos 715 1.1 christos static void 716 1.1 christos wasm_print_symbol (bfd *abfd, 717 1.1.1.2 christos void * filep, 718 1.1.1.2 christos asymbol *symbol, 719 1.1.1.2 christos bfd_print_symbol_type how) 720 1.1 christos { 721 1.1 christos FILE *file = (FILE *) filep; 722 1.1 christos 723 1.1 christos switch (how) 724 1.1 christos { 725 1.1 christos case bfd_print_symbol_name: 726 1.1 christos fprintf (file, "%s", symbol->name); 727 1.1 christos break; 728 1.1 christos 729 1.1 christos default: 730 1.1 christos bfd_print_symbol_vandf (abfd, filep, symbol); 731 1.1 christos fprintf (file, " %-5s %s", symbol->section->name, symbol->name); 732 1.1 christos } 733 1.1 christos } 734 1.1 christos 735 1.1 christos static void 736 1.1 christos wasm_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED, 737 1.1.1.2 christos asymbol *symbol, 738 1.1.1.2 christos symbol_info *ret) 739 1.1 christos { 740 1.1 christos bfd_symbol_info (symbol, ret); 741 1.1 christos } 742 1.1 christos 743 1.1 christos /* Check whether ABFD is a WebAssembly module; if so, scan it. */ 744 1.1 christos 745 1.1.1.3 christos static bfd_cleanup 746 1.1 christos wasm_object_p (bfd *abfd) 747 1.1 christos { 748 1.1.1.4 christos bool error; 749 1.1.1.3 christos asection *s; 750 1.1 christos 751 1.1.1.5 christos if (bfd_seek (abfd, 0, SEEK_SET) != 0) 752 1.1 christos return NULL; 753 1.1 christos 754 1.1.1.3 christos if (!wasm_read_header (abfd, &error)) 755 1.1 christos { 756 1.1 christos bfd_set_error (bfd_error_wrong_format); 757 1.1 christos return NULL; 758 1.1 christos } 759 1.1 christos 760 1.1.1.3 christos if (!wasm_mkobject (abfd)) 761 1.1 christos return NULL; 762 1.1 christos 763 1.1.1.3 christos if (!wasm_scan (abfd) 764 1.1.1.3 christos || !bfd_default_set_arch_mach (abfd, bfd_arch_wasm32, 0)) 765 1.1.1.3 christos { 766 1.1.1.3 christos bfd_release (abfd, abfd->tdata.any); 767 1.1.1.3 christos abfd->tdata.any = NULL; 768 1.1.1.3 christos return NULL; 769 1.1.1.3 christos } 770 1.1 christos 771 1.1.1.3 christos s = bfd_get_section_by_name (abfd, WASM_NAME_SECTION); 772 1.1.1.3 christos if (s != NULL && wasm_scan_name_function_section (abfd, s)) 773 1.1 christos abfd->flags |= HAS_SYMS; 774 1.1 christos 775 1.1.1.3 christos return _bfd_no_cleanup; 776 1.1 christos } 777 1.1 christos 778 1.1 christos /* BFD_JUMP_TABLE_WRITE */ 779 1.1.1.2 christos #define wasm_set_arch_mach _bfd_generic_set_arch_mach 780 1.1 christos 781 1.1 christos /* BFD_JUMP_TABLE_SYMBOLS */ 782 1.1.1.2 christos #define wasm_get_symbol_version_string _bfd_nosymbols_get_symbol_version_string 783 1.1.1.2 christos #define wasm_bfd_is_local_label_name bfd_generic_is_local_label_name 784 1.1.1.2 christos #define wasm_bfd_is_target_special_symbol _bfd_bool_bfd_asymbol_false 785 1.1.1.2 christos #define wasm_get_lineno _bfd_nosymbols_get_lineno 786 1.1.1.2 christos #define wasm_find_nearest_line _bfd_nosymbols_find_nearest_line 787 1.1.1.4 christos #define wasm_find_nearest_line_with_alt _bfd_nosymbols_find_nearest_line_with_alt 788 1.1.1.2 christos #define wasm_find_line _bfd_nosymbols_find_line 789 1.1.1.2 christos #define wasm_find_inliner_info _bfd_nosymbols_find_inliner_info 790 1.1.1.2 christos #define wasm_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol 791 1.1.1.2 christos #define wasm_read_minisymbols _bfd_generic_read_minisymbols 792 1.1.1.2 christos #define wasm_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol 793 1.1 christos 794 1.1 christos const bfd_target wasm_vec = 795 1.1 christos { 796 1.1.1.2 christos "wasm", /* Name. */ 797 1.1 christos bfd_target_unknown_flavour, 798 1.1 christos BFD_ENDIAN_LITTLE, 799 1.1 christos BFD_ENDIAN_LITTLE, 800 1.1 christos (HAS_SYMS | WP_TEXT), /* Object flags. */ 801 1.1 christos (SEC_CODE | SEC_DATA | SEC_HAS_CONTENTS), /* Section flags. */ 802 1.1.1.2 christos 0, /* Leading underscore. */ 803 1.1.1.2 christos ' ', /* AR_pad_char. */ 804 1.1.1.2 christos 255, /* AR_max_namelen. */ 805 1.1 christos 0, /* Match priority. */ 806 1.1.1.4 christos TARGET_KEEP_UNUSED_SECTION_SYMBOLS, /* keep unused section symbols. */ 807 1.1 christos /* Routines to byte-swap various sized integers from the data sections. */ 808 1.1 christos bfd_getl64, bfd_getl_signed_64, bfd_putl64, 809 1.1 christos bfd_getl32, bfd_getl_signed_32, bfd_putl32, 810 1.1 christos bfd_getl16, bfd_getl_signed_16, bfd_putl16, 811 1.1 christos 812 1.1 christos /* Routines to byte-swap various sized integers from the file headers. */ 813 1.1 christos bfd_getl64, bfd_getl_signed_64, bfd_putl64, 814 1.1 christos bfd_getl32, bfd_getl_signed_32, bfd_putl32, 815 1.1 christos bfd_getl16, bfd_getl_signed_16, bfd_putl16, 816 1.1 christos 817 1.1 christos { 818 1.1 christos _bfd_dummy_target, 819 1.1 christos wasm_object_p, /* bfd_check_format. */ 820 1.1 christos _bfd_dummy_target, 821 1.1 christos _bfd_dummy_target, 822 1.1 christos }, 823 1.1 christos { 824 1.1.1.2 christos _bfd_bool_bfd_false_error, 825 1.1 christos wasm_mkobject, 826 1.1 christos _bfd_generic_mkarchive, 827 1.1.1.2 christos _bfd_bool_bfd_false_error, 828 1.1 christos }, 829 1.1 christos { /* bfd_write_contents. */ 830 1.1.1.2 christos _bfd_bool_bfd_false_error, 831 1.1 christos wasm_write_object_contents, 832 1.1 christos _bfd_write_archive_contents, 833 1.1.1.2 christos _bfd_bool_bfd_false_error, 834 1.1 christos }, 835 1.1 christos 836 1.1 christos BFD_JUMP_TABLE_GENERIC (_bfd_generic), 837 1.1 christos BFD_JUMP_TABLE_COPY (_bfd_generic), 838 1.1 christos BFD_JUMP_TABLE_CORE (_bfd_nocore), 839 1.1 christos BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), 840 1.1 christos BFD_JUMP_TABLE_SYMBOLS (wasm), 841 1.1 christos BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), 842 1.1 christos BFD_JUMP_TABLE_WRITE (wasm), 843 1.1 christos BFD_JUMP_TABLE_LINK (_bfd_nolink), 844 1.1 christos BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), 845 1.1 christos 846 1.1 christos NULL, 847 1.1 christos 848 1.1 christos NULL, 849 1.1 christos }; 850