1 /* Object attributes parsing. 2 Copyright (C) 2025-2026 Free Software Foundation, Inc. 3 4 This file is part of GAS, the GNU Assembler. 5 6 GAS is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3, or (at your option) 9 any later version. 10 11 GAS is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GAS; see the file COPYING. If not, write to the Free 18 Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 19 02110-1301, USA. */ 20 21 #include "obj-elf-attr.h" 22 23 #ifdef TC_OBJ_ATTR 24 25 #include "obstack.h" 26 #include "safe-ctype.h" 27 28 /* A variant type to store information about known OAv2 identifiers. */ 29 typedef union { 30 uint8_t u8; 31 bool b; 32 } oav2_identifier_variant_value_t; 33 34 typedef enum { 35 OAv2_ASM_ID_VALUE_UNDEFINED = 0, 36 OAv2_ASM_ID_VALUE_U8, 37 OAv2_ASM_ID_VALUE_BOOL, 38 } oav2_identifier_variant_type_info_t; 39 40 typedef struct { 41 oav2_identifier_variant_value_t val; 42 oav2_identifier_variant_type_info_t vtype; 43 } oav2_identifier_variant_t; 44 45 typedef struct { 46 const char *const name; 47 const oav2_identifier_variant_t value; 48 } oav2_identifier_t; 49 50 typedef struct { 51 size_t len; 52 struct arg_variant_t *elts; 53 } arg_variant_list_t; 54 55 typedef union { 56 const char *string; 57 uint64_t u64; 58 int64_t i64; 59 arg_variant_list_t list; 60 } arg_variant_value_t; 61 62 typedef enum { 63 VALUE_UNDEFINED = 0, 64 VALUE_U64, 65 VALUE_I64, 66 VALUE_UNSIGNED_INTEGER = VALUE_U64, 67 VALUE_SIGNED_INTEGER = VALUE_I64, 68 VALUE_STRING, 69 VALUE_LIST, 70 VALUE_OPTIONAL_ABSENT, 71 } arg_variant_type_info_t; 72 73 /* A variant type to store the argument values of an assembly directive. */ 74 typedef struct arg_variant_t { 75 arg_variant_value_t val; 76 arg_variant_type_info_t vtype; 77 } arg_variant_t; 78 79 typedef arg_variant_t arg_t; 80 81 #define skip_whitespace(str) do { if (is_whitespace (*(str))) ++(str); } while (0) 82 83 static inline bool 84 skip_past_char (char **str, char c) 85 { 86 if (**str == c) 87 { 88 (*str)++; 89 return true; 90 } 91 return false; 92 } 93 #define skip_past_comma(str) skip_past_char (str, ',') 94 95 #if (TC_OBJ_ATTR_v1) 96 97 /* A list of attributes that have been explicitly set by the assembly code. 98 VENDOR is the vendor id, BASE is the tag shifted right by the number 99 of bits in MASK, and bit N of MASK is set if tag BASE+N has been set. */ 100 typedef struct recorded_attribute_info { 101 struct recorded_attribute_info *next; 102 obj_attr_vendor_t vendor; 103 unsigned int base; 104 unsigned long mask; 105 } recorded_attribute_info_t; 106 static recorded_attribute_info_t *recorded_attributes; 107 108 static void 109 oav1_attr_info_free (recorded_attribute_info_t *node) 110 { 111 while (node != NULL) 112 { 113 recorded_attribute_info_t *next = node->next; 114 free (node); 115 node = next; 116 } 117 } 118 119 void 120 oav1_attr_info_init (void) 121 { 122 /* Note: this "constructor" was added for symmetry with oav1_attr_info_exit. 123 recorded_attributes is a static variable which is automatically initialized 124 to NULL. There is no need to initialize it another time except for a 125 cosmetic reason and to possibly help fuzzing. */ 126 recorded_attributes = NULL; 127 } 128 129 void 130 oav1_attr_info_exit (void) 131 { 132 oav1_attr_info_free (recorded_attributes); 133 } 134 135 /* Record that we have seen an explicit specification of attribute TAG 136 for vendor VENDOR. */ 137 138 static void 139 oav1_attr_record_seen (obj_attr_vendor_t vendor, obj_attr_tag_t tag) 140 { 141 unsigned int base; 142 unsigned long mask; 143 recorded_attribute_info_t *rai; 144 145 base = tag / (8 * sizeof (rai->mask)); 146 mask = 1UL << (tag % (8 * sizeof (rai->mask))); 147 for (rai = recorded_attributes; rai; rai = rai->next) 148 if (rai->vendor == vendor && rai->base == base) 149 { 150 rai->mask |= mask; 151 return; 152 } 153 154 rai = XNEW (recorded_attribute_info_t); 155 rai->next = recorded_attributes; 156 rai->vendor = vendor; 157 rai->base = base; 158 rai->mask = mask; 159 recorded_attributes = rai; 160 } 161 162 /* Return true if we have seen an explicit specification of attribute TAG 163 for vendor VENDOR. */ 164 165 bool 166 oav1_attr_seen (obj_attr_vendor_t vendor, obj_attr_tag_t tag) 167 { 168 unsigned int base; 169 unsigned long mask; 170 recorded_attribute_info_t *rai; 171 172 base = tag / (8 * sizeof (rai->mask)); 173 mask = 1UL << (tag % (8 * sizeof (rai->mask))); 174 for (rai = recorded_attributes; rai; rai = rai->next) 175 if (rai->vendor == vendor && rai->base == base) 176 return (rai->mask & mask) != 0; 177 return false; 178 } 179 180 #endif /* TC_OBJ_ATTR_v1 */ 181 182 /* Expected argument tokens for object attribute directives. */ 183 typedef enum { 184 /* Base types. */ 185 IDENTIFIER = 0x1, 186 UNSIGNED_INTEGER = 0x2, 187 SIGNED_INTEGER = 0x4, 188 STRING = 0x8, 189 LIST = 0x10, 190 LT_MASK = 0xFF, 191 /* Higher types. */ 192 SUBSECTION_NAME = 0x100, 193 SUBSECTION_OPTION_1 = 0x200, 194 SUBSECTION_OPTION_2 = 0x400, 195 ATTRIBUTE_KEY = 0x800, 196 ATTRIBUTE_VALUE = 0x1000, 197 HT_MASK = 0xFF00, 198 } arg_token_t; 199 200 /* Free an arguments list of size N. */ 201 static void 202 args_list_free (arg_t *args, size_t n) 203 { 204 for (size_t i = 0; i < n; ++i) 205 if (args[i].vtype == VALUE_STRING) 206 free ((void *) args[i].val.string); 207 else if (args[i].vtype == VALUE_LIST) 208 args_list_free (args[i].val.list.elts, args[i].val.list.len); 209 free (args); 210 } 211 212 /* Extract a string literal from the input. */ 213 static bool 214 extract_string_literal (arg_t *arg_out) 215 { 216 int len; 217 char *obstack_buf = demand_copy_C_string (&len); 218 if (obstack_buf != NULL) 219 { 220 arg_out->val.string = xstrdup (obstack_buf); 221 obstack_free (¬es, obstack_buf); 222 arg_out->vtype = VALUE_STRING; 223 return true; 224 } 225 226 arg_out->val.string = NULL; 227 return false; 228 } 229 230 /* Extract an integer literal from the input. 231 Anything matched by O_constant is considered an integer literal (see the 232 usage of O_constant in expr.c to see all the matches. 233 Return true on success, false otherwise. If a signedness issue is detected, 234 'signedness_issue' is also set to true. */ 235 static bool 236 extract_integer_literal (arg_t *arg_out, 237 bool want_unsigned, 238 bool *signedness_issue) 239 { 240 const char *cursor_begin = input_line_pointer; 241 expressionS exp; 242 expression_and_evaluate (&exp); 243 if (exp.X_op != O_constant) 244 { 245 char backup_c = *input_line_pointer; 246 *input_line_pointer = '\0'; 247 as_bad (_("expression '%s' does not resolve to an integer"), 248 cursor_begin); 249 /* Restore the character pointed by the current cursor position, 250 otherwise '\0' misleads ignore_rest_of_line(). */ 251 *input_line_pointer = backup_c; 252 return false; 253 } 254 255 int64_t val = (int64_t) exp.X_add_number; 256 if (want_unsigned) 257 { 258 if (! exp.X_unsigned && val < 0) 259 { 260 as_bad (_("unexpected value '%" PRId64 "', expected `unsigned integer' instead"), 261 val); 262 *signedness_issue = true; 263 return false; 264 } 265 arg_out->val.u64 = val; 266 arg_out->vtype = VALUE_UNSIGNED_INTEGER; 267 } 268 else 269 { 270 arg_out->val.i64 = val; 271 arg_out->vtype = VALUE_SIGNED_INTEGER; 272 } 273 return true; 274 } 275 276 /* Extract an identifier based on the provided character matcher. */ 277 static bool 278 extract_identifier (bool (*char_predicate) (char), arg_t *arg_out) 279 { 280 const char *s = input_line_pointer; 281 unsigned int i = 0; 282 for (; char_predicate (*input_line_pointer); ++input_line_pointer) 283 i++; 284 if (i == 0) 285 { 286 as_bad (_("invalid character '%c' in identifier"), 287 *input_line_pointer); 288 return false; 289 } 290 291 arg_out->vtype = VALUE_STRING; 292 arg_out->val.string = xmemdup0 (s, i); 293 return true; 294 } 295 296 #if (TC_OBJ_ATTR_v2) 297 /* Resolve the identifier if it matches a known tag. */ 298 static bool 299 resolve_if_matching_known_tag (const char *identifier, 300 const obj_attr_tag_info_t *known_identifier, 301 arg_t *val_out) 302 { 303 if (strcmp (known_identifier->name, identifier) != 0) 304 return false; 305 306 val_out->val.u64 = known_identifier->value; 307 val_out->vtype = VALUE_UNSIGNED_INTEGER; 308 return true; 309 } 310 311 /* Resolve the identifier if it matches the known one. */ 312 static bool 313 resolve_if_matching (const char *identifier, 314 const oav2_identifier_t *known_identifier, 315 arg_t *val_out) 316 { 317 /* Lowercase the identifier before comparison. */ 318 char normalized_identifier[100]; 319 unsigned int i = 0; 320 for (; i < sizeof (normalized_identifier) && identifier[i] != '\0'; ++i) 321 normalized_identifier[i] = TOLOWER (identifier[i]); 322 if (i >= sizeof (normalized_identifier)) 323 /* Identifier is too long. */ 324 return false; 325 gas_assert (identifier[i] == '\0'); 326 normalized_identifier[i] = '\0'; 327 328 /* Comparison with normalized identifier. */ 329 if (strcmp (known_identifier->name, normalized_identifier) != 0) 330 return false; 331 332 /* We only need U8 and Bool for now. */ 333 switch (known_identifier->value.vtype) 334 { 335 case OAv2_ASM_ID_VALUE_U8: 336 val_out->val.u64 = known_identifier->value.val.b; 337 val_out->vtype = VALUE_UNSIGNED_INTEGER; 338 break; 339 case OAv2_ASM_ID_VALUE_BOOL: 340 val_out->val.u64 = known_identifier->value.val.u8; 341 val_out->vtype = VALUE_UNSIGNED_INTEGER; 342 break; 343 default: 344 abort (); 345 } 346 347 return true; 348 } 349 #endif /* TC_OBJ_ATTR_v2 */ 350 351 #if (TC_OBJ_ATTR_v1) 352 /* Look up attribute tags defined in the backend (object attribute v1). */ 353 static bool 354 obj_attr_v1_lookup_known_attr_tag_symbol 355 (const char *identifier ATTRIBUTE_UNUSED, 356 arg_token_t token_type, 357 arg_t *val_out) 358 { 359 gas_assert (token_type & UNSIGNED_INTEGER); 360 361 #ifndef CONVERT_SYMBOLIC_ATTRIBUTE 362 # define CONVERT_SYMBOLIC_ATTRIBUTE(a) -1 363 #endif 364 int tag = CONVERT_SYMBOLIC_ATTRIBUTE (identifier); 365 if (tag < 0) 366 return false; 367 val_out->val.u64 = tag; 368 val_out->vtype = VALUE_UNSIGNED_INTEGER; 369 return true; 370 } 371 #endif /* TC_OBJ_ATTR_v1 */ 372 373 #if (TC_OBJ_ATTR_v2) 374 /* Look up attribute tags defined in the backend (object attribute v2). */ 375 static bool 376 obj_attr_v2_lookup_known_attr_tag_symbol (const char *identifier, 377 arg_token_t token_type, 378 arg_t *val_out) 379 { 380 obj_attr_subsection_v2_t *subsec = elf_obj_attr_subsections (stdoutput).last; 381 /* This function is called when setting a value for an attribute, and it 382 requires an active subsection. Calling this function without setting 383 'subsec' is a logical error. Invalid user code, where the subsection 384 has not been selected must be handled by the caller. We require 'subsec' 385 to be non-NULL here. */ 386 gas_assert (subsec != NULL); 387 388 /* An attribute tag is an unsigned integer, so the expected token type should 389 always have the base type UNSIGNED_INTEGER. Otherwise, this function was 390 called incorrectly. */ 391 gas_assert (token_type & UNSIGNED_INTEGER); 392 393 bool resolved = false; 394 const struct elf_backend_data *be = get_elf_backend_data (stdoutput); 395 const known_subsection_v2_t *known_subsec 396 = bfd_obj_attr_v2_identify_subsection (be, subsec->name); 397 if (known_subsec != NULL) 398 { 399 for (size_t i = 0; i < known_subsec->len && ! resolved; ++i) 400 resolved 401 = resolve_if_matching_known_tag (identifier, 402 &known_subsec->known_attrs[i].tag, 403 val_out); 404 } 405 406 if (resolved) 407 /* An attribute tag is an unsigned integer, so the type of the found value 408 should be VALUE_UNSIGNED_INTEGER. Otherwise, check if you set correctly 409 the type of the value associated to the symbol. */ 410 gas_assert (val_out->vtype == VALUE_UNSIGNED_INTEGER); 411 412 return resolved; 413 } 414 #endif /* TC_OBJ_ATTR_v2 */ 415 416 /* Look up known symbols, and try to resolve the given identifier. */ 417 static bool 418 lookup_known_symbols (const char *identifier, 419 arg_token_t token_type, 420 arg_t *val_out) 421 { 422 if (identifier == NULL) 423 return false; 424 425 arg_token_t high_ttype = (token_type & HT_MASK); 426 427 #if (TC_OBJ_ATTR_v2) 428 static const oav2_identifier_t known_identifiers_subsection_optional[] = { 429 { "optional", { 430 .val.b = true, 431 .vtype = OAv2_ASM_ID_VALUE_BOOL 432 } 433 }, 434 { "required", { 435 .val.b = false, 436 .vtype = OAv2_ASM_ID_VALUE_BOOL 437 } 438 }, 439 }; 440 441 static const oav2_identifier_t known_identifiers_subsection_encoding[] = { 442 { "uleb128", { 443 .val.u8 = obj_attr_encoding_v2_to_u8 (OA_ENC_ULEB128), 444 .vtype = OAv2_ASM_ID_VALUE_U8 445 } 446 }, 447 { "ntbs", { 448 .val.u8 = obj_attr_encoding_v2_to_u8 (OA_ENC_NTBS), 449 .vtype = OAv2_ASM_ID_VALUE_U8 450 } 451 }, 452 }; 453 #endif /* TC_OBJ_ATTR_v2 */ 454 455 bool resolved = false; 456 457 #if (TC_OBJ_ATTR_v2) 458 if (high_ttype == SUBSECTION_OPTION_1 || high_ttype == SUBSECTION_OPTION_2) 459 { 460 const oav2_identifier_t *known_identifiers 461 = (high_ttype == SUBSECTION_OPTION_1 462 ? known_identifiers_subsection_optional 463 : known_identifiers_subsection_encoding); 464 const size_t N_identifiers 465 = (high_ttype == SUBSECTION_OPTION_1 466 ? ARRAY_SIZE (known_identifiers_subsection_optional) 467 : ARRAY_SIZE (known_identifiers_subsection_encoding)); 468 469 for (size_t i = 0; i < N_identifiers && ! resolved; ++i) 470 resolved = resolve_if_matching (identifier, 471 &known_identifiers[i], 472 val_out); 473 } 474 else 475 #endif /* TC_OBJ_ATTR_v2 */ 476 if (high_ttype == ATTRIBUTE_KEY) 477 { 478 obj_attr_version_t version = elf_obj_attr_version (stdoutput); 479 switch (version) 480 { 481 #if (TC_OBJ_ATTR_v1) 482 case OBJ_ATTR_V1: 483 resolved = obj_attr_v1_lookup_known_attr_tag_symbol 484 (identifier, token_type, val_out); 485 break; 486 #endif /* TC_OBJ_ATTR_v1 */ 487 #if (TC_OBJ_ATTR_v2) 488 case OBJ_ATTR_V2: 489 resolved = obj_attr_v2_lookup_known_attr_tag_symbol 490 (identifier, token_type, val_out); 491 break; 492 #endif /* TC_OBJ_ATTR_v2 */ 493 default: 494 abort (); 495 } 496 } 497 else 498 abort (); 499 500 return resolved; 501 } 502 503 /* Look up the symbol table of this compilation unit, and try to resolve the 504 given identifier. */ 505 static bool 506 lookup_symbol_table (const char *identifier, 507 const arg_token_t expected_ttype, 508 arg_t *val_out) 509 { 510 if (identifier == NULL) 511 return false; 512 513 /* Note: signed integer are unsupported for now. */ 514 gas_assert (expected_ttype & UNSIGNED_INTEGER); 515 516 symbolS *symbolP = symbol_find (identifier); 517 if (symbolP == NULL) 518 return false; 519 520 if (! S_IS_DEFINED (symbolP)) 521 return false; 522 523 valueT val = S_GET_VALUE (symbolP); 524 val_out->val.u64 = val; 525 val_out->vtype = VALUE_UNSIGNED_INTEGER; 526 527 return true; 528 } 529 530 /* Function similar to snprintf from the standard library, except that it 531 also updates the buffer pointer to point to the last written character, 532 and length to match the remaining space in the buffer. 533 Return the number of bytes printed. The function is assumed to always be 534 successful, and a failure with vnsprintf() will trigger an assert(). */ 535 static size_t 536 snprintf_append (char **sbuffer, size_t *length, 537 const char *format, ...) 538 { 539 va_list args; 540 va_start (args, format); 541 int rval = vsnprintf (*sbuffer, *length, format, args); 542 va_end (args); 543 544 gas_assert (rval >= 0); 545 size_t written = rval; 546 *length -= written; 547 *sbuffer += written; 548 return written; 549 } 550 551 /* Return the list of comma-separated strings matching the expected types 552 (i.e. the flags set in low_ttype). */ 553 static const char * 554 expectations_to_string (const arg_token_t low_ttype, 555 char *sbuffer, size_t length) 556 { 557 unsigned match_n = 0; 558 char *sbuffer_start = sbuffer; 559 size_t total = 0; 560 if (low_ttype & IDENTIFIER) 561 { 562 ++match_n; 563 total += snprintf_append (&sbuffer, &length, "`%s'", "identifier"); 564 } 565 566 #define EXP_APPEND_TYPE_STR(type_flag, type_str) \ 567 if (low_ttype & type_flag) \ 568 { \ 569 if (match_n >= 1) \ 570 total += snprintf_append (&sbuffer, &length, "%s", ", or "); \ 571 ++match_n; \ 572 total += snprintf_append (&sbuffer, &length, "`%s'", type_str); \ 573 } 574 575 EXP_APPEND_TYPE_STR (STRING, "string"); 576 EXP_APPEND_TYPE_STR (UNSIGNED_INTEGER, "unsigned integer"); 577 EXP_APPEND_TYPE_STR (SIGNED_INTEGER, "signed integer"); 578 #undef APPEND_TYPE_STR 579 580 gas_assert (total <= length); 581 return sbuffer_start; 582 } 583 584 /* In the context of object attributes, an identifier is defined with the 585 following lexical constraint: [a-zA-z_][a-zA-Z0-9_]*. An identifier can 586 be used to define the name of a subsection, its optionality, or its 587 encoding, as well as for an attribute's tag. */ 588 589 static bool 590 is_identifier_beginner (char c) 591 { 592 return ISALPHA (c) || c == '_'; 593 } 594 595 static bool 596 is_part_of_identifier (char c) 597 { 598 return ISALNUM (c) || c == '_'; 599 } 600 601 /* Parse an argument, and set its type accordingly depending on the input 602 value, and the constraints on the expected argument. */ 603 static bool 604 obj_attr_parse_arg (arg_token_t expected_ttype, 605 bool resolve_identifier, 606 bool optional, 607 arg_t *arg_out) 608 { 609 const arg_token_t low_ttype = (expected_ttype & LT_MASK); 610 611 if (optional && is_end_of_stmt (*input_line_pointer)) 612 { 613 arg_out->vtype = VALUE_OPTIONAL_ABSENT; 614 return true; 615 } 616 617 /* Check whether this looks like a string literal 618 Note: symbol look-up for string literals is not available. */ 619 if (*input_line_pointer == '"') 620 { 621 bool status = extract_string_literal (arg_out); 622 if (status && (low_ttype & STRING)) 623 return true; 624 625 if (status) 626 { 627 char sbuffer[100]; 628 as_bad (_("unexpected `string' \"%s\", expected %s instead"), 629 arg_out->val.string, 630 expectations_to_string (low_ttype, sbuffer, sizeof(sbuffer))); 631 free ((char *) arg_out->val.string); 632 arg_out->val.string = NULL; 633 arg_out->vtype = VALUE_UNDEFINED; 634 } 635 return false; 636 } 637 638 /* Check whether this looks like an identifier. */ 639 if (is_identifier_beginner (*input_line_pointer)) 640 { 641 bool status = extract_identifier (is_part_of_identifier, arg_out); 642 /* is_identifier_beginner() confirmed that it was the beginning of an 643 identifier, so we don't expect the extraction to fail. */ 644 gas_assert (status); 645 gas_assert (arg_out->vtype == VALUE_STRING); 646 647 if (! (low_ttype & IDENTIFIER)) 648 { 649 char sbuffer[100]; 650 as_bad (_("unexpected `identifier' \"%s\", expected %s instead"), 651 arg_out->val.string, 652 expectations_to_string (low_ttype, sbuffer, sizeof(sbuffer))); 653 free ((char *) arg_out->val.string); 654 arg_out->val.string = NULL; 655 arg_out->vtype = VALUE_UNDEFINED; 656 return false; 657 } 658 659 /* In some cases, we don't want to resolve the identifier because it is the 660 actual value. */ 661 if (! resolve_identifier) 662 return true; 663 664 /* Move the identifier out of arg_out. */ 665 const char *identifier = arg_out->val.string; 666 arg_out->val.string = NULL; 667 arg_out->vtype = VALUE_UNDEFINED; 668 bool resolved = true; 669 670 /* The identifier is a symbol, let's try to resolve it by: 671 1. using the provided list of known symbols. 672 a) backend-independent 673 b) backend-specific. */ 674 if (lookup_known_symbols (identifier, expected_ttype, arg_out)) 675 goto free_identifier; 676 677 /* 2. using the symbol table for this compilation unit. 678 Note: this is the last attempt before failure. */ 679 if (lookup_symbol_table (identifier, low_ttype, arg_out)) 680 goto free_identifier; 681 682 as_bad (_("unknown identifier '%s' in this context"), identifier); 683 resolved = false; 684 685 free_identifier: 686 free ((char *) identifier); 687 return resolved; 688 } 689 690 /* If it is neither a string nor an identifier, it must be an expression. */ 691 bool signedness_issue = false; 692 bool success = extract_integer_literal (arg_out, 693 (low_ttype & UNSIGNED_INTEGER), 694 &signedness_issue); 695 if (success && (low_ttype & (UNSIGNED_INTEGER | SIGNED_INTEGER))) 696 return true; 697 698 char sbuffer[100]; 699 if (success) 700 as_bad (_("unexpected integer '%"PRIu64"', expected %s instead"), 701 arg_out->val.u64, 702 expectations_to_string (low_ttype, sbuffer, sizeof(sbuffer))); 703 else if ((low_ttype & UNSIGNED_INTEGER) && signedness_issue) 704 { 705 /* Already handled by extract_integer_literal(), nothing to do. */ 706 } 707 else 708 as_bad (_("fell back to integer literal extraction from expression, " 709 "but expected %s instead"), 710 expectations_to_string (low_ttype, sbuffer, sizeof(sbuffer))); 711 712 arg_out->vtype = VALUE_UNDEFINED; 713 return false; 714 } 715 716 /* Trim white space before a parameter. 717 Error if it meets a parameter separator before a parameter. */ 718 static bool 719 trim_whitespace_before_param (void) 720 { 721 skip_whitespace (input_line_pointer); 722 if (*input_line_pointer == ',') 723 { 724 as_bad (_("syntax error, comma not expected here")); 725 return false; 726 } 727 return true; 728 } 729 730 /* Skip white space + parameter separator after a parameter. 731 Error if it does not meet a parameter separator after a parameter. */ 732 static bool 733 skip_whitespace_past_comma (void) 734 { 735 skip_whitespace (input_line_pointer); 736 if (! skip_past_comma (&input_line_pointer)) 737 { 738 as_bad (_("syntax error, comma missing here")); 739 return false; 740 } 741 return true; 742 } 743 744 /* Can parse a list of arguments with variable length. */ 745 static bool 746 obj_attr_parse_args (arg_token_t expected_ttype, 747 bool resolve_identifier, 748 arg_t *arg_out) 749 { 750 if ((expected_ttype & LIST) == 0) 751 return obj_attr_parse_arg (expected_ttype, resolve_identifier, false, 752 arg_out); 753 754 static const size_t LIST_MAX_SIZE = 2; 755 arg_t *arg_list = xcalloc (LIST_MAX_SIZE, sizeof (*arg_list)); 756 757 /* We don't want to support recursive lists. */ 758 expected_ttype &= ~LIST; 759 760 size_t n = 0; 761 do { 762 if (! trim_whitespace_before_param ()) 763 goto bad; 764 765 if (! obj_attr_parse_arg (expected_ttype, resolve_identifier, false, 766 &arg_list[n])) 767 goto bad; 768 769 ++n; 770 skip_whitespace (input_line_pointer); 771 if (is_end_of_stmt (*input_line_pointer)) 772 break; 773 774 if (! skip_whitespace_past_comma ()) 775 goto bad; 776 777 if (n >= LIST_MAX_SIZE) 778 { 779 as_bad ("too many arguments for a list (max: %zu)", LIST_MAX_SIZE); 780 goto bad; 781 } 782 } while (n < LIST_MAX_SIZE); 783 784 arg_out->vtype = VALUE_LIST; 785 arg_out->val.list.len = n; 786 arg_out->val.list.elts = arg_list; 787 return true; 788 789 bad: 790 args_list_free (arg_list, n); 791 return false; 792 } 793 794 #if (TC_OBJ_ATTR_v2) 795 static bool 796 is_valid_boolean (uint64_t value) 797 { 798 return value <= 1; 799 } 800 801 #define is_valid_comprehension is_valid_boolean 802 803 static bool 804 is_valid_encoding (uint64_t value) 805 { 806 value = obj_attr_encoding_v2_from_u8 (value); 807 return OA_ENC_UNSET < value && value <= OA_ENC_MAX; 808 } 809 810 #endif /* TC_OBJ_ATTR_v2 */ 811 812 #if (TC_OBJ_ATTR_v1) 813 /* Determine the expected argument type based on the tag ID. */ 814 static arg_token_t 815 obj_attr_v1_get_arg_type (bfd *abfd, 816 obj_attr_vendor_t vendor, 817 obj_attr_tag_t tag) 818 { 819 int attr_type = bfd_elf_obj_attrs_arg_type (abfd, vendor, tag); 820 arg_token_t arg_type; 821 if (attr_type == (ATTR_TYPE_FLAG_STR_VAL | ATTR_TYPE_FLAG_INT_VAL)) 822 arg_type = LIST | UNSIGNED_INTEGER | STRING; 823 else if (attr_type == ATTR_TYPE_FLAG_STR_VAL) 824 arg_type = STRING; 825 else 826 /* Covers the remaning cases: 827 - ATTR_TYPE_FLAG_INT_VAL. 828 - ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_NO_DEFAULT. */ 829 arg_type = UNSIGNED_INTEGER; 830 return arg_type; 831 } 832 #endif /* TC_OBJ_ATTR_v1 */ 833 834 #if (TC_OBJ_ATTR_v2) 835 /* Determine the expected argument type based on the subsection encoding. */ 836 static arg_token_t 837 obj_attr_v2_get_arg_type (obj_attr_encoding_v2_t subsec_encoding) 838 { 839 arg_token_t arg_type; 840 switch (subsec_encoding) 841 { 842 case OA_ENC_ULEB128: 843 arg_type = UNSIGNED_INTEGER; 844 break; 845 case OA_ENC_NTBS: 846 arg_type = STRING; 847 break; 848 case OA_ENC_UNSET: 849 default: 850 abort (); 851 } 852 return arg_type; 853 } 854 #endif /* TC_OBJ_ATTR_v2 */ 855 856 /* Parse the arguments of [vendor]_attribute directive. */ 857 static arg_t * 858 vendor_attribute_parse_args (obj_attr_vendor_t vendor ATTRIBUTE_UNUSED, 859 const obj_attr_subsection_v2_t *subsec ATTRIBUTE_UNUSED, 860 unsigned int nargs, ...) 861 { 862 va_list args; 863 va_start (args, nargs); 864 865 arg_t *args_out = xcalloc (nargs, sizeof (arg_t)); 866 867 for (unsigned int n = 0; n < nargs; ++n) 868 { 869 if (! trim_whitespace_before_param ()) 870 goto bad; 871 872 arg_t *arg_out = &args_out[n]; 873 874 arg_token_t expected_ttype = va_arg (args, arg_token_t); 875 arg_token_t high_ttype = (expected_ttype & HT_MASK); 876 /* Make sure that we called the right parse_args(). */ 877 gas_assert (high_ttype == ATTRIBUTE_KEY 878 || high_ttype == ATTRIBUTE_VALUE); 879 880 if (high_ttype == ATTRIBUTE_VALUE) 881 { 882 arg_token_t type_attr_value 883 #if (TC_OBJ_ATTR_v1 && TC_OBJ_ATTR_v2) 884 = (subsec != NULL) 885 ? obj_attr_v2_get_arg_type (subsec->encoding) 886 : obj_attr_v1_get_arg_type (stdoutput, vendor, 887 args_out[n - 1].val.u64); 888 #elif (TC_OBJ_ATTR_v1) 889 = obj_attr_v1_get_arg_type (stdoutput, vendor, 890 args_out[n - 1].val.u64); 891 #else /* TC_OBJ_ATTR_v2 */ 892 = obj_attr_v2_get_arg_type (subsec->encoding); 893 #endif 894 expected_ttype |= type_attr_value; 895 } 896 897 if (! obj_attr_parse_args (expected_ttype, true, arg_out)) 898 { 899 if (high_ttype == ATTRIBUTE_KEY) 900 { 901 as_bad (_("could not parse attribute tag")); 902 goto bad; 903 } 904 else 905 { 906 as_bad (_("could not parse attribute value")); 907 goto bad; 908 } 909 } 910 911 if (n + 1 < nargs && !skip_whitespace_past_comma ()) 912 goto bad; 913 } 914 915 demand_empty_rest_of_line (); 916 va_end (args); 917 return args_out; 918 919 bad: 920 ignore_rest_of_line (); 921 args_list_free (args_out, nargs); 922 va_end (args); 923 return NULL; 924 } 925 926 #if (TC_OBJ_ATTR_v1) 927 /* Record an attribute (object attribute v1 only). */ 928 static obj_attribute * 929 obj_attr_v1_record (bfd *abfd, 930 const obj_attr_vendor_t vendor, 931 const obj_attr_tag_t tag, 932 arg_t *parsed_arg) 933 { 934 obj_attribute *attr = bfd_elf_new_obj_attr (abfd, vendor, tag); 935 if (attr != NULL) 936 { 937 attr->type = bfd_elf_obj_attrs_arg_type (abfd, vendor, tag); 938 if (parsed_arg->vtype == VALUE_LIST) 939 { 940 arg_variant_list_t *plist = &parsed_arg->val.list; 941 gas_assert (plist->len == 2 942 && plist->elts[0].vtype == VALUE_UNSIGNED_INTEGER 943 && plist->elts[1].vtype == VALUE_STRING); 944 attr->i = plist->elts[0].val.u64; 945 attr->s = (char *) plist->elts[1].val.string; 946 plist->elts[1].val.string = NULL; 947 } 948 else if (parsed_arg->vtype == VALUE_STRING) 949 { 950 attr->s = (char *) parsed_arg->val.string; 951 parsed_arg->val.string = NULL; 952 } 953 else 954 { 955 attr->i = parsed_arg->val.u64; 956 } 957 } 958 return attr; 959 } 960 #endif /* TC_OBJ_ATTR_v1 */ 961 962 #if (TC_OBJ_ATTR_v2) 963 /* Parse the arguments of [vendor]_subsection directive (v2 only). */ 964 static arg_t * 965 vendor_subsection_parse_args (unsigned int nargs, ...) 966 { 967 va_list args; 968 va_start (args, nargs); 969 970 arg_t *args_out = xcalloc (nargs, sizeof (arg_t)); 971 972 for (unsigned int n = 0; n < nargs; ++n) 973 { 974 if (! trim_whitespace_before_param ()) 975 goto bad; 976 977 arg_t *arg_out = &args_out[n]; 978 979 arg_token_t expected_ttype = va_arg (args, arg_token_t); 980 arg_token_t high_ttype = (expected_ttype & HT_MASK); 981 /* Make sure that we called the right parse_args(). */ 982 gas_assert (high_ttype == SUBSECTION_NAME 983 || high_ttype == SUBSECTION_OPTION_1 984 || high_ttype == SUBSECTION_OPTION_2); 985 986 if (high_ttype == SUBSECTION_NAME) 987 { 988 if (! obj_attr_parse_arg (expected_ttype, false, false, arg_out)) 989 { 990 as_bad (_("expected <subsection_name>, <comprehension>, " 991 "<encoding>")); 992 goto bad; 993 } 994 } 995 else if (high_ttype == SUBSECTION_OPTION_1 996 || high_ttype == SUBSECTION_OPTION_2) 997 { 998 if (! obj_attr_parse_arg (expected_ttype, true, true, arg_out)) 999 goto bad; 1000 1001 if (arg_out->vtype == VALUE_OPTIONAL_ABSENT) 1002 continue; 1003 1004 if (high_ttype == SUBSECTION_OPTION_1 1005 && ! is_valid_comprehension (arg_out->val.u64)) 1006 { 1007 as_bad 1008 (_("invalid value '%" PRIu64 "', expected values for " 1009 "<comprehension> are 0 (=`required') or 1 (=`optional')"), 1010 arg_out->val.u64); 1011 goto bad; 1012 } 1013 else if (high_ttype == SUBSECTION_OPTION_2 1014 && ! is_valid_encoding (arg_out->val.u64)) 1015 { 1016 as_bad 1017 (_("invalid value '%" PRIu64 "', expected values for <encoding>" 1018 " are 0 (=`ULEB128') or 1 (=`NTBS')"), 1019 arg_out->val.u64); 1020 goto bad; 1021 } 1022 } 1023 else 1024 abort (); 1025 1026 if (n + 1 < nargs 1027 && ! is_end_of_stmt (*input_line_pointer) 1028 && ! skip_whitespace_past_comma ()) 1029 goto bad; 1030 } 1031 1032 va_end (args); 1033 demand_empty_rest_of_line (); 1034 return args_out; 1035 1036 bad: 1037 ignore_rest_of_line (); 1038 args_list_free (args_out, nargs); 1039 va_end (args); 1040 return NULL; 1041 } 1042 1043 /* Record an attribute (object attribute v2 only). */ 1044 static void 1045 obj_attr_v2_record (obj_attr_tag_t key, arg_t *arg_val) 1046 { 1047 /* An OAv2 cannot be recorded unless a subsection has been recorded. */ 1048 gas_assert (elf_obj_attr_subsections (stdoutput).last != NULL); 1049 1050 union obj_attr_value_v2 obj_attr_val; 1051 if (arg_val->vtype == VALUE_UNSIGNED_INTEGER) 1052 obj_attr_val.uint = arg_val->val.u64; 1053 else 1054 { 1055 /* Move the string. */ 1056 obj_attr_val.string = arg_val->val.string; 1057 arg_val->val.string = NULL; 1058 } 1059 1060 obj_attr_v2_t *obj_attr = bfd_elf_obj_attr_v2_init (key, obj_attr_val); 1061 gas_assert (obj_attr != NULL); 1062 1063 /* Go over the list of already recorded attributes and check for 1064 redefinitions (which are forbidden). */ 1065 bool skip_recording = false; 1066 obj_attr_v2_t *recorded_attr = bfd_obj_attr_v2_find_by_tag 1067 (elf_obj_attr_subsections (stdoutput).last, obj_attr->tag, false); 1068 if (recorded_attr != NULL) 1069 { 1070 if ((arg_val->vtype == VALUE_UNSIGNED_INTEGER 1071 && recorded_attr->val.uint != obj_attr->val.uint) 1072 || (arg_val->vtype == VALUE_STRING 1073 && strcmp (recorded_attr->val.string, obj_attr->val.string) != 0)) 1074 as_bad (_("attribute '%" PRIu64 "' cannot be redefined"), 1075 recorded_attr->tag); 1076 skip_recording = true; 1077 } 1078 1079 if (skip_recording) 1080 { 1081 if (arg_val->vtype == VALUE_STRING) 1082 free ((void *) obj_attr->val.string); 1083 free (obj_attr); 1084 return; 1085 } 1086 1087 bfd_obj_attr_subsection_v2_append 1088 (elf_obj_attr_subsections (stdoutput).last, obj_attr); 1089 } 1090 1091 /* Record a subsection (object attribute v2 only). 1092 Note: this function takes the ownership of 'name', so is responsible to free 1093 it if an issue occurs. */ 1094 static void 1095 obj_attr_v2_subsection_record (const char *name, 1096 arg_t *arg_comprehension, 1097 arg_t *arg_encoding) 1098 { 1099 obj_attr_subsection_v2_t *already_recorded_subsec 1100 = bfd_obj_attr_subsection_v2_find_by_name 1101 (elf_obj_attr_subsections (stdoutput).first, name, false); 1102 1103 bool comprehension_optional = arg_comprehension->val.u64; 1104 obj_attr_encoding_v2_t encoding 1105 = obj_attr_encoding_v2_from_u8 (arg_encoding->val.u64); 1106 1107 if (already_recorded_subsec != NULL) 1108 { 1109 bool error_redeclaration = false; 1110 1111 if (arg_comprehension->vtype == VALUE_OPTIONAL_ABSENT) 1112 gas_assert (arg_encoding->vtype == VALUE_OPTIONAL_ABSENT); 1113 else if (comprehension_optional != already_recorded_subsec->optional) 1114 error_redeclaration = true; 1115 1116 if (arg_encoding->vtype != VALUE_OPTIONAL_ABSENT 1117 && encoding != already_recorded_subsec->encoding) 1118 error_redeclaration = true; 1119 1120 /* Check for mismatching redefinition of the subsection, i.e. the names 1121 match but the properties are different. */ 1122 if (error_redeclaration) 1123 { 1124 const char *prev_comprehension = bfd_oav2_comprehension_to_string ( 1125 already_recorded_subsec->optional); 1126 const char *prev_encoding = bfd_oav2_encoding_to_string ( 1127 already_recorded_subsec->encoding); 1128 as_bad (_("incompatible redeclaration of subsection %s"), name); 1129 as_info (1, _("previous declaration had properties: %s=%s, %s=%s"), 1130 "comprehension", prev_comprehension, 1131 "encoding", prev_encoding); 1132 goto free_name; 1133 } 1134 1135 /* Move the existing subsection to the last position. */ 1136 bfd_obj_attr_subsection_v2_list_remove 1137 (&elf_obj_attr_subsections (stdoutput), already_recorded_subsec); 1138 bfd_obj_attr_subsection_v2_list_append 1139 (&elf_obj_attr_subsections (stdoutput), already_recorded_subsec); 1140 /* Note: 'name' was unused, and will be freed on exit. */ 1141 } 1142 else 1143 { 1144 if (arg_comprehension->vtype == VALUE_OPTIONAL_ABSENT 1145 || arg_encoding->vtype == VALUE_OPTIONAL_ABSENT) 1146 { 1147 as_bad (_("comprehension and encoding of a subsection cannot be " 1148 "omitted on the first declaration")); 1149 goto free_name; 1150 } 1151 1152 obj_attr_subsection_scope_v2_t scope 1153 = bfd_elf_obj_attr_subsection_v2_scope (stdoutput, name); 1154 1155 /* Note: ownership of 'name' is transfered to the callee when initializing 1156 the subsection. That is why we skip free() at the end. */ 1157 obj_attr_subsection_v2_t *new_subsection 1158 = bfd_elf_obj_attr_subsection_v2_init (name, scope, 1159 comprehension_optional, 1160 encoding); 1161 bfd_obj_attr_subsection_v2_list_append 1162 (&elf_obj_attr_subsections (stdoutput), new_subsection); 1163 return; 1164 } 1165 1166 free_name: 1167 free ((void *) name); 1168 } 1169 #endif /* TC_OBJ_ATTR_v2 */ 1170 1171 /* Parse an attribute directive (supports both v1 & v2). */ 1172 obj_attr_tag_t 1173 obj_attr_process_attribute (obj_attr_vendor_t vendor) 1174 { 1175 obj_attr_version_t version = elf_obj_attr_version (stdoutput); 1176 obj_attr_subsection_v2_t *subsec = NULL; 1177 1178 #if (TC_OBJ_ATTR_v2) 1179 if (version == OBJ_ATTR_V2) 1180 { 1181 subsec = elf_obj_attr_subsections (stdoutput).last; 1182 if (subsec == NULL) 1183 { 1184 as_bad (_("declaration of an attribute outside the scope of an " 1185 "attribute subsection")); 1186 ignore_rest_of_line (); 1187 return 0; 1188 } 1189 } 1190 #endif /* TC_OBJ_ATTR_v2 */ 1191 1192 const size_t N_ARGS = 2; 1193 arg_t *args = vendor_attribute_parse_args ( 1194 vendor, subsec, N_ARGS, 1195 ATTRIBUTE_KEY | IDENTIFIER | UNSIGNED_INTEGER, 1196 ATTRIBUTE_VALUE); 1197 1198 if (args == NULL) 1199 return 0; 1200 1201 obj_attr_tag_t tag = args[0].val.u64; 1202 switch (version) 1203 { 1204 #if (TC_OBJ_ATTR_v1) 1205 case OBJ_ATTR_V1: 1206 oav1_attr_record_seen (vendor, tag); 1207 obj_attr_v1_record (stdoutput, vendor, tag, &args[1]); 1208 break; 1209 #endif /* TC_OBJ_ATTR_v1 */ 1210 #if (TC_OBJ_ATTR_v2) 1211 case OBJ_ATTR_V2: 1212 obj_attr_v2_record (tag, &args[1]); 1213 break; 1214 #endif /* TC_OBJ_ATTR_v2 */ 1215 default: 1216 abort (); 1217 } 1218 1219 args_list_free (args, N_ARGS); 1220 1221 return tag; 1222 } 1223 1224 #if (TC_OBJ_ATTR_v2) 1225 /* Parse an object attribute v2's subsection directive. */ 1226 void 1227 obj_attr_process_subsection (void) 1228 { 1229 const size_t N_ARGS = 3; 1230 arg_t *args = vendor_subsection_parse_args ( 1231 N_ARGS, 1232 SUBSECTION_NAME | IDENTIFIER, 1233 SUBSECTION_OPTION_1 | IDENTIFIER | UNSIGNED_INTEGER, 1234 SUBSECTION_OPTION_2 | IDENTIFIER | UNSIGNED_INTEGER); 1235 1236 if (args == NULL) 1237 return; 1238 1239 /* Note: move the value to avoid double free. */ 1240 const char *name = args[0].val.string; 1241 args[0].val.string = NULL; 1242 1243 /* Note: ownership of 'name' is transferred to the callee. */ 1244 obj_attr_v2_subsection_record (name, &args[1], &args[2]); 1245 args_list_free (args, N_ARGS); 1246 } 1247 #endif /* TC_OBJ_ATTR_v2 */ 1248 1249 /* Parse a .gnu_attribute directive. */ 1250 1251 void 1252 obj_elf_gnu_attribute (int ignored ATTRIBUTE_UNUSED) 1253 { 1254 obj_attr_process_attribute (OBJ_ATTR_GNU); 1255 } 1256 1257 #if (TC_OBJ_ATTR_v2) 1258 /* Return True if the VERSION of object attributes supports subsections, False 1259 otherwise. */ 1260 1261 static inline bool 1262 attr_fmt_has_subsections (obj_attr_version_t version) 1263 { 1264 switch (version) 1265 { 1266 case OBJ_ATTR_V1: 1267 return false; 1268 case OBJ_ATTR_V2: 1269 return true; 1270 default: 1271 abort (); /* Unsupported format. */ 1272 } 1273 } 1274 1275 /* Parse a .gnu_subsection directive. */ 1276 1277 void 1278 obj_elf_gnu_subsection (int ignored ATTRIBUTE_UNUSED) 1279 { 1280 obj_attr_version_t version = elf_obj_attr_version (stdoutput); 1281 if (! attr_fmt_has_subsections (version)) 1282 { 1283 as_bad (_(".gnu_subsection is only available with object attributes v2")); 1284 ignore_rest_of_line (); 1285 return; 1286 } 1287 obj_attr_process_subsection (); 1288 } 1289 #endif /* TC_OBJ_ATTR_v2 */ 1290 1291 #endif /* TC_OBJ_ATTR */ 1292