1214571Sdim/* ELF attributes support (based on ARM EABI attributes). 2214571Sdim Copyright 2005, 2006, 2007 3214571Sdim Free Software Foundation, Inc. 4214571Sdim 5214571Sdim This file is part of BFD, the Binary File Descriptor library. 6214571Sdim 7214571Sdim This program is free software; you can redistribute it and/or modify 8214571Sdim it under the terms of the GNU General Public License as published by 9214571Sdim the Free Software Foundation; either version 2 of the License, or 10214571Sdim (at your option) any later version. 11214571Sdim 12214571Sdim This program is distributed in the hope that it will be useful, 13214571Sdim but WITHOUT ANY WARRANTY; without even the implied warranty of 14214571Sdim MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15214571Sdim GNU General Public License for more details. 16214571Sdim 17214571Sdim You should have received a copy of the GNU General Public License 18214571Sdim along with this program; if not, write to the Free Software 19214571Sdim Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 20214571Sdim 21214571Sdim#include "sysdep.h" 22214571Sdim#include "bfd.h" 23214571Sdim#include "libiberty.h" 24214571Sdim#include "libbfd.h" 25214571Sdim#include "elf-bfd.h" 26214571Sdim 27214571Sdim/* Return the number of bytes needed by I in uleb128 format. */ 28214571Sdimstatic int 29214571Sdimuleb128_size (unsigned int i) 30214571Sdim{ 31214571Sdim int size; 32214571Sdim size = 1; 33214571Sdim while (i >= 0x80) 34214571Sdim { 35214571Sdim i >>= 7; 36214571Sdim size++; 37214571Sdim } 38214571Sdim return size; 39214571Sdim} 40214571Sdim 41214571Sdim/* Return TRUE if the attribute has the default value (0/""). */ 42214571Sdimstatic bfd_boolean 43214571Sdimis_default_attr (obj_attribute *attr) 44214571Sdim{ 45214571Sdim if ((attr->type & 1) && attr->i != 0) 46214571Sdim return FALSE; 47214571Sdim if ((attr->type & 2) && attr->s && *attr->s) 48214571Sdim return FALSE; 49214571Sdim 50214571Sdim return TRUE; 51214571Sdim} 52214571Sdim 53214571Sdim/* Return the size of a single attribute. */ 54214571Sdimstatic bfd_vma 55214571Sdimobj_attr_size (int tag, obj_attribute *attr) 56214571Sdim{ 57214571Sdim bfd_vma size; 58214571Sdim 59214571Sdim if (is_default_attr (attr)) 60214571Sdim return 0; 61214571Sdim 62214571Sdim size = uleb128_size (tag); 63214571Sdim if (attr->type & 1) 64214571Sdim size += uleb128_size (attr->i); 65214571Sdim if (attr->type & 2) 66214571Sdim size += strlen ((char *)attr->s) + 1; 67214571Sdim return size; 68214571Sdim} 69214571Sdim 70214571Sdim/* Return the vendor name for a given object attributes section. */ 71214571Sdimstatic const char * 72214571Sdimvendor_obj_attr_name (bfd *abfd, int vendor) 73214571Sdim{ 74214571Sdim return (vendor == OBJ_ATTR_PROC 75214571Sdim ? get_elf_backend_data (abfd)->obj_attrs_vendor 76214571Sdim : "gnu"); 77214571Sdim} 78214571Sdim 79214571Sdim/* Return the size of the object attributes section for VENDOR 80214571Sdim (OBJ_ATTR_PROC or OBJ_ATTR_GNU), or 0 if there are no attributes 81214571Sdim for that vendor to record and the vendor is OBJ_ATTR_GNU. */ 82214571Sdimstatic bfd_vma 83214571Sdimvendor_obj_attr_size (bfd *abfd, int vendor) 84214571Sdim{ 85214571Sdim bfd_vma size; 86214571Sdim obj_attribute *attr; 87214571Sdim obj_attribute_list *list; 88214571Sdim int i; 89214571Sdim const char *vendor_name = vendor_obj_attr_name (abfd, vendor); 90214571Sdim 91214571Sdim if (!vendor_name) 92214571Sdim return 0; 93214571Sdim 94214571Sdim attr = elf_known_obj_attributes (abfd)[vendor]; 95214571Sdim size = 0; 96214571Sdim for (i = 4; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) 97214571Sdim size += obj_attr_size (i, &attr[i]); 98214571Sdim 99214571Sdim for (list = elf_other_obj_attributes (abfd)[vendor]; 100214571Sdim list; 101214571Sdim list = list->next) 102214571Sdim size += obj_attr_size (list->tag, &list->attr); 103214571Sdim 104214571Sdim /* <size> <vendor_name> NUL 0x1 <size> */ 105214571Sdim return ((size || vendor == OBJ_ATTR_PROC) 106214571Sdim ? size + 10 + strlen (vendor_name) 107214571Sdim : 0); 108214571Sdim} 109214571Sdim 110214571Sdim/* Return the size of the object attributes section. */ 111214571Sdimbfd_vma 112214571Sdimbfd_elf_obj_attr_size (bfd *abfd) 113214571Sdim{ 114214571Sdim bfd_vma size; 115214571Sdim 116214571Sdim size = vendor_obj_attr_size (abfd, OBJ_ATTR_PROC); 117214571Sdim size += vendor_obj_attr_size (abfd, OBJ_ATTR_GNU); 118214571Sdim 119214571Sdim /* 'A' <sections for each vendor> */ 120214571Sdim return (size ? size + 1 : 0); 121214571Sdim} 122214571Sdim 123214571Sdim/* Write VAL in uleb128 format to P, returning a pointer to the 124214571Sdim following byte. */ 125214571Sdimstatic bfd_byte * 126214571Sdimwrite_uleb128 (bfd_byte *p, unsigned int val) 127214571Sdim{ 128214571Sdim bfd_byte c; 129214571Sdim do 130214571Sdim { 131214571Sdim c = val & 0x7f; 132214571Sdim val >>= 7; 133214571Sdim if (val) 134214571Sdim c |= 0x80; 135214571Sdim *(p++) = c; 136214571Sdim } 137214571Sdim while (val); 138214571Sdim return p; 139214571Sdim} 140214571Sdim 141214571Sdim/* Write attribute ATTR to butter P, and return a pointer to the following 142214571Sdim byte. */ 143214571Sdimstatic bfd_byte * 144214571Sdimwrite_obj_attribute (bfd_byte *p, int tag, obj_attribute *attr) 145214571Sdim{ 146214571Sdim /* Suppress default entries. */ 147214571Sdim if (is_default_attr (attr)) 148214571Sdim return p; 149214571Sdim 150214571Sdim p = write_uleb128 (p, tag); 151214571Sdim if (attr->type & 1) 152214571Sdim p = write_uleb128 (p, attr->i); 153214571Sdim if (attr->type & 2) 154214571Sdim { 155214571Sdim int len; 156214571Sdim 157214571Sdim len = strlen (attr->s) + 1; 158214571Sdim memcpy (p, attr->s, len); 159214571Sdim p += len; 160214571Sdim } 161214571Sdim 162214571Sdim return p; 163214571Sdim} 164214571Sdim 165214571Sdim/* Write the contents of the object attributes section (length SIZE) 166214571Sdim for VENDOR to CONTENTS. */ 167214571Sdimstatic void 168214571Sdimvendor_set_obj_attr_contents (bfd *abfd, bfd_byte *contents, bfd_vma size, 169214571Sdim int vendor) 170214571Sdim{ 171214571Sdim bfd_byte *p; 172214571Sdim obj_attribute *attr; 173214571Sdim obj_attribute_list *list; 174214571Sdim int i; 175214571Sdim const char *vendor_name = vendor_obj_attr_name (abfd, vendor); 176214571Sdim size_t vendor_length = strlen (vendor_name) + 1; 177214571Sdim 178214571Sdim p = contents; 179214571Sdim bfd_put_32 (abfd, size, p); 180214571Sdim p += 4; 181214571Sdim memcpy (p, vendor_name, vendor_length); 182214571Sdim p += vendor_length; 183214571Sdim *(p++) = Tag_File; 184214571Sdim bfd_put_32 (abfd, size - 4 - vendor_length, p); 185214571Sdim p += 4; 186214571Sdim 187214571Sdim attr = elf_known_obj_attributes (abfd)[vendor]; 188214571Sdim for (i = 4; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) 189214571Sdim p = write_obj_attribute (p, i, &attr[i]); 190214571Sdim 191214571Sdim for (list = elf_other_obj_attributes (abfd)[vendor]; 192214571Sdim list; 193214571Sdim list = list->next) 194214571Sdim p = write_obj_attribute (p, list->tag, &list->attr); 195214571Sdim} 196214571Sdim 197214571Sdim/* Write the contents of the object attributes section to CONTENTS. */ 198214571Sdimvoid 199214571Sdimbfd_elf_set_obj_attr_contents (bfd *abfd, bfd_byte *contents, bfd_vma size) 200214571Sdim{ 201214571Sdim bfd_byte *p; 202214571Sdim int vendor; 203214571Sdim bfd_vma my_size; 204214571Sdim 205214571Sdim p = contents; 206214571Sdim *(p++) = 'A'; 207214571Sdim my_size = 1; 208214571Sdim for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++) 209214571Sdim { 210214571Sdim bfd_vma vendor_size = vendor_obj_attr_size (abfd, vendor); 211214571Sdim if (vendor_size) 212214571Sdim vendor_set_obj_attr_contents (abfd, p, vendor_size, vendor); 213214571Sdim p += vendor_size; 214214571Sdim my_size += vendor_size; 215214571Sdim } 216214571Sdim 217214571Sdim if (size != my_size) 218214571Sdim abort (); 219214571Sdim} 220214571Sdim 221214571Sdim/* Allocate/find an object attribute. */ 222214571Sdimstatic obj_attribute * 223214571Sdimelf_new_obj_attr (bfd *abfd, int vendor, int tag) 224214571Sdim{ 225214571Sdim obj_attribute *attr; 226214571Sdim obj_attribute_list *list; 227214571Sdim obj_attribute_list *p; 228214571Sdim obj_attribute_list **lastp; 229214571Sdim 230214571Sdim 231214571Sdim if (tag < NUM_KNOWN_OBJ_ATTRIBUTES) 232214571Sdim { 233214571Sdim /* Knwon tags are preallocated. */ 234214571Sdim attr = &elf_known_obj_attributes (abfd)[vendor][tag]; 235214571Sdim } 236214571Sdim else 237214571Sdim { 238214571Sdim /* Create a new tag. */ 239214571Sdim list = (obj_attribute_list *) 240214571Sdim bfd_alloc (abfd, sizeof (obj_attribute_list)); 241214571Sdim memset (list, 0, sizeof (obj_attribute_list)); 242214571Sdim list->tag = tag; 243214571Sdim /* Keep the tag list in order. */ 244214571Sdim lastp = &elf_other_obj_attributes (abfd)[vendor]; 245214571Sdim for (p = *lastp; p; p = p->next) 246214571Sdim { 247214571Sdim if (tag < p->tag) 248214571Sdim break; 249214571Sdim lastp = &p->next; 250214571Sdim } 251214571Sdim list->next = *lastp; 252214571Sdim *lastp = list; 253214571Sdim attr = &list->attr; 254214571Sdim } 255214571Sdim 256214571Sdim return attr; 257214571Sdim} 258214571Sdim 259214571Sdim/* Return the value of an integer object attribute. */ 260214571Sdimint 261214571Sdimbfd_elf_get_obj_attr_int (bfd *abfd, int vendor, int tag) 262214571Sdim{ 263214571Sdim obj_attribute_list *p; 264214571Sdim 265214571Sdim if (tag < NUM_KNOWN_OBJ_ATTRIBUTES) 266214571Sdim { 267214571Sdim /* Knwon tags are preallocated. */ 268214571Sdim return elf_known_obj_attributes (abfd)[vendor][tag].i; 269214571Sdim } 270214571Sdim else 271214571Sdim { 272214571Sdim for (p = elf_other_obj_attributes (abfd)[vendor]; 273214571Sdim p; 274214571Sdim p = p->next) 275214571Sdim { 276214571Sdim if (tag == p->tag) 277214571Sdim return p->attr.i; 278214571Sdim if (tag < p->tag) 279214571Sdim break; 280214571Sdim } 281214571Sdim return 0; 282214571Sdim } 283214571Sdim} 284214571Sdim 285214571Sdim/* Add an integer object attribute. */ 286214571Sdimvoid 287214571Sdimbfd_elf_add_obj_attr_int (bfd *abfd, int vendor, int tag, unsigned int i) 288214571Sdim{ 289214571Sdim obj_attribute *attr; 290214571Sdim 291214571Sdim attr = elf_new_obj_attr (abfd, vendor, tag); 292214571Sdim attr->type = 1; 293214571Sdim attr->i = i; 294214571Sdim} 295214571Sdim 296214571Sdim/* Duplicate an object attribute string value. */ 297214571Sdimchar * 298214571Sdim_bfd_elf_attr_strdup (bfd *abfd, const char * s) 299214571Sdim{ 300214571Sdim char * p; 301214571Sdim int len; 302214571Sdim 303214571Sdim len = strlen (s) + 1; 304214571Sdim p = (char *) bfd_alloc (abfd, len); 305214571Sdim return memcpy (p, s, len); 306214571Sdim} 307214571Sdim 308214571Sdim/* Add a string object attribute. */ 309214571Sdimvoid 310214571Sdimbfd_elf_add_obj_attr_string (bfd *abfd, int vendor, int tag, const char *s) 311214571Sdim{ 312214571Sdim obj_attribute *attr; 313214571Sdim 314214571Sdim attr = elf_new_obj_attr (abfd, vendor, tag); 315214571Sdim attr->type = 2; 316214571Sdim attr->s = _bfd_elf_attr_strdup (abfd, s); 317214571Sdim} 318214571Sdim 319214571Sdim/* Add a Tag_compatibility object attribute. */ 320214571Sdimvoid 321214571Sdimbfd_elf_add_obj_attr_compat (bfd *abfd, int vendor, unsigned int i, 322214571Sdim const char *s) 323214571Sdim{ 324214571Sdim obj_attribute_list *list; 325214571Sdim obj_attribute_list *p; 326214571Sdim obj_attribute_list **lastp; 327214571Sdim 328214571Sdim list = (obj_attribute_list *) 329214571Sdim bfd_alloc (abfd, sizeof (obj_attribute_list)); 330214571Sdim memset (list, 0, sizeof (obj_attribute_list)); 331214571Sdim list->tag = Tag_compatibility; 332214571Sdim list->attr.type = 3; 333214571Sdim list->attr.i = i; 334214571Sdim list->attr.s = _bfd_elf_attr_strdup (abfd, s); 335214571Sdim 336214571Sdim lastp = &elf_other_obj_attributes (abfd)[vendor]; 337214571Sdim for (p = *lastp; p; p = p->next) 338214571Sdim { 339214571Sdim int cmp; 340214571Sdim if (p->tag != Tag_compatibility) 341214571Sdim break; 342214571Sdim cmp = strcmp(s, p->attr.s); 343214571Sdim if (cmp < 0 || (cmp == 0 && i < p->attr.i)) 344214571Sdim break; 345214571Sdim lastp = &p->next; 346214571Sdim } 347214571Sdim list->next = *lastp; 348214571Sdim *lastp = list; 349214571Sdim} 350214571Sdim 351214571Sdim/* Copy the object attributes from IBFD to OBFD. */ 352214571Sdimvoid 353214571Sdim_bfd_elf_copy_obj_attributes (bfd *ibfd, bfd *obfd) 354214571Sdim{ 355214571Sdim obj_attribute *in_attr; 356214571Sdim obj_attribute *out_attr; 357214571Sdim obj_attribute_list *list; 358214571Sdim int i; 359214571Sdim int vendor; 360214571Sdim 361214571Sdim for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++) 362214571Sdim { 363214571Sdim in_attr = &elf_known_obj_attributes (ibfd)[vendor][4]; 364214571Sdim out_attr = &elf_known_obj_attributes (obfd)[vendor][4]; 365214571Sdim for (i = 4; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) 366214571Sdim { 367214571Sdim out_attr->type = in_attr->type; 368214571Sdim out_attr->i = in_attr->i; 369214571Sdim if (in_attr->s && *in_attr->s) 370214571Sdim out_attr->s = _bfd_elf_attr_strdup (obfd, in_attr->s); 371214571Sdim in_attr++; 372214571Sdim out_attr++; 373214571Sdim } 374214571Sdim 375214571Sdim for (list = elf_other_obj_attributes (ibfd)[vendor]; 376214571Sdim list; 377214571Sdim list = list->next) 378214571Sdim { 379214571Sdim in_attr = &list->attr; 380214571Sdim switch (in_attr->type) 381214571Sdim { 382214571Sdim case 1: 383214571Sdim bfd_elf_add_obj_attr_int (obfd, vendor, list->tag, in_attr->i); 384214571Sdim break; 385214571Sdim case 2: 386214571Sdim bfd_elf_add_obj_attr_string (obfd, vendor, list->tag, 387214571Sdim in_attr->s); 388214571Sdim break; 389214571Sdim case 3: 390214571Sdim bfd_elf_add_obj_attr_compat (obfd, vendor, in_attr->i, 391214571Sdim in_attr->s); 392214571Sdim break; 393214571Sdim default: 394214571Sdim abort (); 395214571Sdim } 396214571Sdim } 397214571Sdim } 398214571Sdim} 399214571Sdim 400214571Sdim/* Determine whether a GNU object attribute tag takes an integer, a 401214571Sdim string or both. */ 402214571Sdimstatic int 403214571Sdimgnu_obj_attrs_arg_type (int tag) 404214571Sdim{ 405214571Sdim /* Except for Tag_compatibility, for GNU attributes we follow the 406214571Sdim same rule ARM ones > 32 follow: odd-numbered tags take strings 407214571Sdim and even-numbered tags take integers. In addition, tag & 2 is 408214571Sdim nonzero for architecture-independent tags and zero for 409214571Sdim architecture-dependent ones. */ 410214571Sdim if (tag == Tag_compatibility) 411214571Sdim return 3; 412214571Sdim else 413214571Sdim return (tag & 1) != 0 ? 2 : 1; 414214571Sdim} 415214571Sdim 416214571Sdim/* Determine what arguments an attribute tag takes. */ 417214571Sdimint 418214571Sdim_bfd_elf_obj_attrs_arg_type (bfd *abfd, int vendor, int tag) 419214571Sdim{ 420214571Sdim switch (vendor) 421214571Sdim { 422214571Sdim case OBJ_ATTR_PROC: 423214571Sdim return get_elf_backend_data (abfd)->obj_attrs_arg_type (tag); 424214571Sdim break; 425214571Sdim case OBJ_ATTR_GNU: 426214571Sdim return gnu_obj_attrs_arg_type (tag); 427214571Sdim break; 428214571Sdim default: 429214571Sdim abort (); 430214571Sdim } 431214571Sdim} 432214571Sdim 433214571Sdim/* Parse an object attributes section. */ 434214571Sdimvoid 435214571Sdim_bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr) 436214571Sdim{ 437214571Sdim bfd_byte *contents; 438214571Sdim bfd_byte *p; 439214571Sdim bfd_vma len; 440214571Sdim const char *std_section; 441214571Sdim 442214571Sdim contents = bfd_malloc (hdr->sh_size); 443214571Sdim if (!contents) 444214571Sdim return; 445214571Sdim if (!bfd_get_section_contents (abfd, hdr->bfd_section, contents, 0, 446214571Sdim hdr->sh_size)) 447214571Sdim { 448214571Sdim free (contents); 449214571Sdim return; 450214571Sdim } 451214571Sdim p = contents; 452214571Sdim std_section = get_elf_backend_data (abfd)->obj_attrs_vendor; 453214571Sdim if (*(p++) == 'A') 454214571Sdim { 455214571Sdim len = hdr->sh_size - 1; 456214571Sdim while (len > 0) 457214571Sdim { 458214571Sdim int namelen; 459214571Sdim bfd_vma section_len; 460214571Sdim int vendor; 461214571Sdim 462214571Sdim section_len = bfd_get_32 (abfd, p); 463214571Sdim p += 4; 464214571Sdim if (section_len > len) 465214571Sdim section_len = len; 466214571Sdim len -= section_len; 467214571Sdim namelen = strlen ((char *)p) + 1; 468214571Sdim section_len -= namelen + 4; 469214571Sdim if (std_section && strcmp ((char *)p, std_section) == 0) 470214571Sdim vendor = OBJ_ATTR_PROC; 471214571Sdim else if (strcmp ((char *)p, "gnu") == 0) 472214571Sdim vendor = OBJ_ATTR_GNU; 473214571Sdim else 474214571Sdim { 475214571Sdim /* Other vendor section. Ignore it. */ 476214571Sdim p += namelen + section_len; 477214571Sdim continue; 478214571Sdim } 479214571Sdim 480214571Sdim p += namelen; 481214571Sdim while (section_len > 0) 482214571Sdim { 483214571Sdim int tag; 484214571Sdim unsigned int n; 485214571Sdim unsigned int val; 486214571Sdim bfd_vma subsection_len; 487214571Sdim bfd_byte *end; 488214571Sdim 489214571Sdim tag = read_unsigned_leb128 (abfd, p, &n); 490214571Sdim p += n; 491214571Sdim subsection_len = bfd_get_32 (abfd, p); 492214571Sdim p += 4; 493214571Sdim if (subsection_len > section_len) 494214571Sdim subsection_len = section_len; 495214571Sdim section_len -= subsection_len; 496214571Sdim subsection_len -= n + 4; 497214571Sdim end = p + subsection_len; 498214571Sdim switch (tag) 499214571Sdim { 500214571Sdim case Tag_File: 501214571Sdim while (p < end) 502214571Sdim { 503214571Sdim int type; 504214571Sdim 505214571Sdim tag = read_unsigned_leb128 (abfd, p, &n); 506214571Sdim p += n; 507214571Sdim type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag); 508214571Sdim switch (type) 509214571Sdim { 510214571Sdim case 3: 511214571Sdim val = read_unsigned_leb128 (abfd, p, &n); 512214571Sdim p += n; 513214571Sdim bfd_elf_add_obj_attr_compat (abfd, vendor, val, 514214571Sdim (char *)p); 515214571Sdim p += strlen ((char *)p) + 1; 516214571Sdim break; 517214571Sdim case 2: 518214571Sdim bfd_elf_add_obj_attr_string (abfd, vendor, tag, 519214571Sdim (char *)p); 520214571Sdim p += strlen ((char *)p) + 1; 521214571Sdim break; 522214571Sdim case 1: 523214571Sdim val = read_unsigned_leb128 (abfd, p, &n); 524214571Sdim p += n; 525214571Sdim bfd_elf_add_obj_attr_int (abfd, vendor, tag, val); 526214571Sdim break; 527214571Sdim default: 528214571Sdim abort (); 529214571Sdim } 530214571Sdim } 531214571Sdim break; 532214571Sdim case Tag_Section: 533214571Sdim case Tag_Symbol: 534214571Sdim /* Don't have anywhere convenient to attach these. 535214571Sdim Fall through for now. */ 536214571Sdim default: 537214571Sdim /* Ignore things we don't kow about. */ 538214571Sdim p += subsection_len; 539214571Sdim subsection_len = 0; 540214571Sdim break; 541214571Sdim } 542214571Sdim } 543214571Sdim } 544214571Sdim } 545214571Sdim free (contents); 546214571Sdim} 547214571Sdim 548214571Sdim/* Merge common object attributes from IBFD into OBFD. Raise an error 549214571Sdim if there are conflicting attributes. Any processor-specific 550214571Sdim attributes have already been merged. This must be called from the 551214571Sdim bfd_elfNN_bfd_merge_private_bfd_data hook for each individual 552214571Sdim target, along with any target-specific merging. Because there are 553214571Sdim no common attributes other than Tag_compatibility at present, and 554214571Sdim non-"gnu" Tag_compatibility is not expected in "gnu" sections, this 555214571Sdim is not presently called for targets without their own 556214571Sdim attributes. */ 557214571Sdim 558214571Sdimbfd_boolean 559214571Sdim_bfd_elf_merge_object_attributes (bfd *ibfd, bfd *obfd) 560214571Sdim{ 561214571Sdim obj_attribute *in_attr; 562214571Sdim obj_attribute *out_attr; 563214571Sdim obj_attribute_list *in_list; 564214571Sdim obj_attribute_list *out_list; 565214571Sdim int vendor; 566214571Sdim 567214571Sdim /* The only common attribute is currently Tag_compatibility, 568214571Sdim accepted in both processor and "gnu" sections. */ 569214571Sdim for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++) 570214571Sdim { 571214571Sdim in_list = elf_other_obj_attributes (ibfd)[vendor]; 572214571Sdim out_list = elf_other_obj_attributes (ibfd)[vendor]; 573214571Sdim while (in_list && in_list->tag == Tag_compatibility) 574214571Sdim { 575214571Sdim in_attr = &in_list->attr; 576214571Sdim if (in_attr->i == 0) 577214571Sdim continue; 578214571Sdim if (in_attr->i == 1 && strcmp (in_attr->s, "gnu") != 0) 579214571Sdim { 580214571Sdim _bfd_error_handler 581214571Sdim (_("ERROR: %B: Must be processed by '%s' toolchain"), 582214571Sdim ibfd, in_attr->s); 583214571Sdim return FALSE; 584214571Sdim } 585214571Sdim if (!out_list || out_list->tag != Tag_compatibility 586214571Sdim || strcmp (in_attr->s, out_list->attr.s) != 0) 587214571Sdim { 588214571Sdim /* Add this compatibility tag to the output. */ 589214571Sdim bfd_elf_add_proc_attr_compat (obfd, in_attr->i, in_attr->s); 590214571Sdim continue; 591214571Sdim } 592214571Sdim out_attr = &out_list->attr; 593214571Sdim /* Check all the input tags with the same identifier. */ 594214571Sdim for (;;) 595214571Sdim { 596214571Sdim if (out_list->tag != Tag_compatibility 597214571Sdim || in_attr->i != out_attr->i 598214571Sdim || strcmp (in_attr->s, out_attr->s) != 0) 599214571Sdim { 600214571Sdim _bfd_error_handler 601214571Sdim (_("ERROR: %B: Incompatible object tag '%s':%d"), 602214571Sdim ibfd, in_attr->s, in_attr->i); 603214571Sdim return FALSE; 604214571Sdim } 605214571Sdim in_list = in_list->next; 606214571Sdim if (in_list->tag != Tag_compatibility 607214571Sdim || strcmp (in_attr->s, in_list->attr.s) != 0) 608214571Sdim break; 609214571Sdim in_attr = &in_list->attr; 610214571Sdim out_list = out_list->next; 611214571Sdim if (out_list) 612214571Sdim out_attr = &out_list->attr; 613214571Sdim } 614214571Sdim 615214571Sdim /* Check the output doesn't have extra tags with this identifier. */ 616214571Sdim if (out_list && out_list->tag == Tag_compatibility 617214571Sdim && strcmp (in_attr->s, out_list->attr.s) == 0) 618214571Sdim { 619214571Sdim _bfd_error_handler 620214571Sdim (_("ERROR: %B: Incompatible object tag '%s':%d"), 621214571Sdim ibfd, in_attr->s, out_list->attr.i); 622214571Sdim return FALSE; 623214571Sdim } 624214571Sdim } 625214571Sdim } 626214571Sdim 627214571Sdim return TRUE; 628214571Sdim} 629