1198092Srdivacky/* ELF attributes support (based on ARM EABI attributes). 2198092Srdivacky Copyright 2005, 2006, 2007, 2009, 2010 3198092Srdivacky Free Software Foundation, Inc. 4198092Srdivacky 5198092Srdivacky This file is part of BFD, the Binary File Descriptor library. 6198092Srdivacky 7198092Srdivacky This program is free software; you can redistribute it and/or modify 8198092Srdivacky it under the terms of the GNU General Public License as published by 9198092Srdivacky the Free Software Foundation; either version 3 of the License, or 10198092Srdivacky (at your option) any later version. 11198092Srdivacky 12198092Srdivacky This program is distributed in the hope that it will be useful, 13212904Sdim but WITHOUT ANY WARRANTY; without even the implied warranty of 14212904Sdim MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15212904Sdim GNU General Public License for more details. 16198092Srdivacky 17207619Srdivacky You should have received a copy of the GNU General Public License 18212904Sdim along with this program; if not, write to the Free Software 19212904Sdim Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 20212904Sdim MA 02110-1301, USA. */ 21198092Srdivacky 22199482Srdivacky#include "sysdep.h" 23198893Srdivacky#include "bfd.h" 24198893Srdivacky#include "libiberty.h" 25218893Sdim#include "libbfd.h" 26198092Srdivacky#include "elf-bfd.h" 27198092Srdivacky 28207619Srdivacky/* Return the number of bytes needed by I in uleb128 format. */ 29212904Sdimstatic int 30198092Srdivackyuleb128_size (unsigned int i) 31198092Srdivacky{ 32198092Srdivacky int size; 33198092Srdivacky size = 1; 34198092Srdivacky while (i >= 0x80) 35212904Sdim { 36198092Srdivacky i >>= 7; 37198092Srdivacky size++; 38198092Srdivacky } 39198092Srdivacky return size; 40198092Srdivacky} 41198092Srdivacky 42198092Srdivacky/* Return TRUE if the attribute has the default value (0/""). */ 43198092Srdivackystatic bfd_boolean 44198092Srdivackyis_default_attr (obj_attribute *attr) 45198092Srdivacky{ 46198092Srdivacky if (ATTR_TYPE_HAS_INT_VAL (attr->type) && attr->i != 0) 47212904Sdim return FALSE; 48198092Srdivacky if (ATTR_TYPE_HAS_STR_VAL (attr->type) && attr->s && *attr->s) 49198092Srdivacky return FALSE; 50198092Srdivacky if (ATTR_TYPE_HAS_NO_DEFAULT (attr->type)) 51198092Srdivacky return FALSE; 52198092Srdivacky 53198092Srdivacky return TRUE; 54198092Srdivacky} 55198092Srdivacky 56198092Srdivacky/* Return the size of a single attribute. */ 57198092Srdivackystatic bfd_vma 58200583Srdivackyobj_attr_size (int tag, obj_attribute *attr) 59200583Srdivacky{ 60200583Srdivacky bfd_vma size; 61200583Srdivacky 62200583Srdivacky if (is_default_attr (attr)) 63200583Srdivacky return 0; 64200583Srdivacky 65200583Srdivacky size = uleb128_size (tag); 66200583Srdivacky if (ATTR_TYPE_HAS_INT_VAL (attr->type)) 67200583Srdivacky size += uleb128_size (attr->i); 68200583Srdivacky if (ATTR_TYPE_HAS_STR_VAL (attr->type)) 69200583Srdivacky size += strlen ((char *)attr->s) + 1; 70200583Srdivacky return size; 71200583Srdivacky} 72200583Srdivacky 73200583Srdivacky/* Return the vendor name for a given object attributes section. */ 74200583Srdivackystatic const char * 75200583Srdivackyvendor_obj_attr_name (bfd *abfd, int vendor) 76200583Srdivacky{ 77200583Srdivacky return (vendor == OBJ_ATTR_PROC 78200583Srdivacky ? get_elf_backend_data (abfd)->obj_attrs_vendor 79200583Srdivacky : "gnu"); 80200583Srdivacky} 81200583Srdivacky 82200583Srdivacky/* Return the size of the object attributes section for VENDOR 83200583Srdivacky (OBJ_ATTR_PROC or OBJ_ATTR_GNU), or 0 if there are no attributes 84200583Srdivacky for that vendor to record and the vendor is OBJ_ATTR_GNU. */ 85200583Srdivackystatic bfd_vma 86200583Srdivackyvendor_obj_attr_size (bfd *abfd, int vendor) 87200583Srdivacky{ 88200583Srdivacky bfd_vma size; 89200583Srdivacky obj_attribute *attr; 90200583Srdivacky obj_attribute_list *list; 91200583Srdivacky int i; 92200583Srdivacky const char *vendor_name = vendor_obj_attr_name (abfd, vendor); 93200583Srdivacky 94200583Srdivacky if (!vendor_name) 95200583Srdivacky return 0; 96200583Srdivacky 97200583Srdivacky attr = elf_known_obj_attributes (abfd)[vendor]; 98200583Srdivacky size = 0; 99200583Srdivacky for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) 100200583Srdivacky size += obj_attr_size (i, &attr[i]); 101200583Srdivacky 102200583Srdivacky for (list = elf_other_obj_attributes (abfd)[vendor]; 103200583Srdivacky list; 104200583Srdivacky list = list->next) 105200583Srdivacky size += obj_attr_size (list->tag, &list->attr); 106200583Srdivacky 107200583Srdivacky /* <size> <vendor_name> NUL 0x1 <size> */ 108200583Srdivacky return ((size || vendor == OBJ_ATTR_PROC) 109200583Srdivacky ? size + 10 + strlen (vendor_name) 110200583Srdivacky : 0); 111200583Srdivacky} 112198092Srdivacky 113198092Srdivacky/* Return the size of the object attributes section. */ 114198092Srdivackybfd_vma 115200583Srdivackybfd_elf_obj_attr_size (bfd *abfd) 116198092Srdivacky{ 117198092Srdivacky bfd_vma size; 118198092Srdivacky 119198092Srdivacky size = vendor_obj_attr_size (abfd, OBJ_ATTR_PROC); 120218893Sdim size += vendor_obj_attr_size (abfd, OBJ_ATTR_GNU); 121218893Sdim 122218893Sdim /* 'A' <sections for each vendor> */ 123198092Srdivacky return (size ? size + 1 : 0); 124198092Srdivacky} 125198092Srdivacky 126198092Srdivacky/* Write VAL in uleb128 format to P, returning a pointer to the 127202379Srdivacky following byte. */ 128202379Srdivackystatic bfd_byte * 129202379Srdivackywrite_uleb128 (bfd_byte *p, unsigned int val) 130202379Srdivacky{ 131202379Srdivacky bfd_byte c; 132210299Sed do 133210299Sed { 134210299Sed c = val & 0x7f; 135210299Sed val >>= 7; 136210299Sed if (val) 137210299Sed c |= 0x80; 138210299Sed *(p++) = c; 139198092Srdivacky } 140198092Srdivacky while (val); 141198092Srdivacky return p; 142198092Srdivacky} 143212904Sdim 144212904Sdim/* Write attribute ATTR to butter P, and return a pointer to the following 145212904Sdim byte. */ 146212904Sdimstatic bfd_byte * 147212904Sdimwrite_obj_attribute (bfd_byte *p, int tag, obj_attribute *attr) 148212904Sdim{ 149212904Sdim /* Suppress default entries. */ 150212904Sdim if (is_default_attr (attr)) 151212904Sdim return p; 152212904Sdim 153218893Sdim p = write_uleb128 (p, tag); 154218893Sdim if (ATTR_TYPE_HAS_INT_VAL (attr->type)) 155218893Sdim p = write_uleb128 (p, attr->i); 156218893Sdim if (ATTR_TYPE_HAS_STR_VAL (attr->type)) 157218893Sdim { 158218893Sdim int len; 159218893Sdim 160218893Sdim len = strlen (attr->s) + 1; 161210299Sed memcpy (p, attr->s, len); 162218893Sdim p += len; 163218893Sdim } 164198092Srdivacky 165218893Sdim return p; 166218893Sdim} 167218893Sdim 168218893Sdim/* Write the contents of the object attributes section (length SIZE) 169218893Sdim for VENDOR to CONTENTS. */ 170218893Sdimstatic void 171218893Sdimvendor_set_obj_attr_contents (bfd *abfd, bfd_byte *contents, bfd_vma size, 172218893Sdim int vendor) 173218893Sdim{ 174218893Sdim bfd_byte *p; 175218893Sdim obj_attribute *attr; 176218893Sdim obj_attribute_list *list; 177218893Sdim int i; 178218893Sdim const char *vendor_name = vendor_obj_attr_name (abfd, vendor); 179218893Sdim size_t vendor_length = strlen (vendor_name) + 1; 180218893Sdim 181218893Sdim p = contents; 182218893Sdim bfd_put_32 (abfd, size, p); 183218893Sdim p += 4; 184218893Sdim memcpy (p, vendor_name, vendor_length); 185218893Sdim p += vendor_length; 186218893Sdim *(p++) = Tag_File; 187218893Sdim bfd_put_32 (abfd, size - 4 - vendor_length, p); 188218893Sdim p += 4; 189218893Sdim 190218893Sdim attr = elf_known_obj_attributes (abfd)[vendor]; 191198092Srdivacky for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) 192208600Srdivacky { 193208600Srdivacky int tag = i; 194208600Srdivacky if (get_elf_backend_data (abfd)->obj_attrs_order) 195208600Srdivacky tag = get_elf_backend_data (abfd)->obj_attrs_order (i); 196212904Sdim p = write_obj_attribute (p, tag, &attr[tag]); 197208600Srdivacky } 198208600Srdivacky 199198092Srdivacky for (list = elf_other_obj_attributes (abfd)[vendor]; 200198092Srdivacky list; 201198092Srdivacky list = list->next) 202198092Srdivacky p = write_obj_attribute (p, list->tag, &list->attr); 203198092Srdivacky} 204198092Srdivacky 205198092Srdivacky/* Write the contents of the object attributes section to CONTENTS. */ 206198092Srdivackyvoid 207198092Srdivackybfd_elf_set_obj_attr_contents (bfd *abfd, bfd_byte *contents, bfd_vma size) 208210299Sed{ 209210299Sed bfd_byte *p; 210210299Sed int vendor; 211210299Sed bfd_vma my_size; 212210299Sed 213212904Sdim p = contents; 214212904Sdim *(p++) = 'A'; 215212904Sdim my_size = 1; 216212904Sdim for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++) 217212904Sdim { 218212904Sdim bfd_vma vendor_size = vendor_obj_attr_size (abfd, vendor); 219212904Sdim if (vendor_size) 220212904Sdim vendor_set_obj_attr_contents (abfd, p, vendor_size, vendor); 221212904Sdim p += vendor_size; 222212904Sdim my_size += vendor_size; 223212904Sdim } 224212904Sdim 225212904Sdim if (size != my_size) 226212904Sdim abort (); 227212904Sdim} 228212904Sdim 229212904Sdim/* Allocate/find an object attribute. */ 230212904Sdimstatic obj_attribute * 231212904Sdimelf_new_obj_attr (bfd *abfd, int vendor, int tag) 232212904Sdim{ 233218893Sdim obj_attribute *attr; 234218893Sdim obj_attribute_list *list; 235218893Sdim obj_attribute_list *p; 236218893Sdim obj_attribute_list **lastp; 237218893Sdim 238218893Sdim 239212904Sdim if (tag < NUM_KNOWN_OBJ_ATTRIBUTES) 240202379Srdivacky { 241202379Srdivacky /* Known tags are preallocated. */ 242202379Srdivacky attr = &elf_known_obj_attributes (abfd)[vendor][tag]; 243202379Srdivacky } 244202379Srdivacky else 245218893Sdim { 246218893Sdim /* Create a new tag. */ 247218893Sdim list = (obj_attribute_list *) 248218893Sdim bfd_alloc (abfd, sizeof (obj_attribute_list)); 249218893Sdim memset (list, 0, sizeof (obj_attribute_list)); 250218893Sdim list->tag = tag; 251218893Sdim /* Keep the tag list in order. */ 252202379Srdivacky lastp = &elf_other_obj_attributes (abfd)[vendor]; 253202379Srdivacky for (p = *lastp; p; p = p->next) 254202379Srdivacky { 255202379Srdivacky if (tag < p->tag) 256202379Srdivacky break; 257202379Srdivacky lastp = &p->next; 258202379Srdivacky } 259202379Srdivacky list->next = *lastp; 260202379Srdivacky *lastp = list; 261202379Srdivacky attr = &list->attr; 262202379Srdivacky } 263202379Srdivacky 264202379Srdivacky return attr; 265202379Srdivacky} 266202379Srdivacky 267202379Srdivacky/* Return the value of an integer object attribute. */ 268202379Srdivackyint 269202379Srdivackybfd_elf_get_obj_attr_int (bfd *abfd, int vendor, int tag) 270198092Srdivacky{ 271198092Srdivacky obj_attribute_list *p; 272198092Srdivacky 273198092Srdivacky if (tag < NUM_KNOWN_OBJ_ATTRIBUTES) 274202379Srdivacky { 275198092Srdivacky /* Known tags are preallocated. */ 276198092Srdivacky return elf_known_obj_attributes (abfd)[vendor][tag].i; 277198092Srdivacky } 278198092Srdivacky else 279202379Srdivacky { 280202379Srdivacky for (p = elf_other_obj_attributes (abfd)[vendor]; 281202379Srdivacky p; 282202379Srdivacky p = p->next) 283202379Srdivacky { 284202379Srdivacky if (tag == p->tag) 285202379Srdivacky return p->attr.i; 286202379Srdivacky if (tag < p->tag) 287202379Srdivacky break; 288202379Srdivacky } 289202379Srdivacky return 0; 290202379Srdivacky } 291202379Srdivacky} 292202379Srdivacky 293202379Srdivacky/* Add an integer object attribute. */ 294202379Srdivackyvoid 295202379Srdivackybfd_elf_add_obj_attr_int (bfd *abfd, int vendor, int tag, unsigned int i) 296198092Srdivacky{ 297198092Srdivacky obj_attribute *attr; 298198092Srdivacky 299198092Srdivacky attr = elf_new_obj_attr (abfd, vendor, tag); 300198092Srdivacky attr->type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag); 301198092Srdivacky attr->i = i; 302199482Srdivacky} 303199482Srdivacky 304199482Srdivacky/* Duplicate an object attribute string value. */ 305198092Srdivackychar * 306198092Srdivacky_bfd_elf_attr_strdup (bfd *abfd, const char * s) 307198092Srdivacky{ 308198092Srdivacky char * p; 309198092Srdivacky int len; 310198092Srdivacky 311198092Srdivacky len = strlen (s) + 1; 312210299Sed p = (char *) bfd_alloc (abfd, len); 313212904Sdim return (char *) memcpy (p, s, len); 314202379Srdivacky} 315198092Srdivacky 316198092Srdivacky/* Add a string object attribute. */ 317198092Srdivackyvoid 318198092Srdivackybfd_elf_add_obj_attr_string (bfd *abfd, int vendor, int tag, const char *s) 319198092Srdivacky{ 320198092Srdivacky obj_attribute *attr; 321198092Srdivacky 322198092Srdivacky attr = elf_new_obj_attr (abfd, vendor, tag); 323202379Srdivacky attr->type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag); 324210299Sed attr->s = _bfd_elf_attr_strdup (abfd, s); 325212904Sdim} 326218893Sdim 327198092Srdivacky/* Add a int+string object attribute. */ 328198092Srdivackyvoid 329198092Srdivackybfd_elf_add_obj_attr_int_string (bfd *abfd, int vendor, int tag, 330198092Srdivacky unsigned int i, const char *s) 331200583Srdivacky{ 332200583Srdivacky obj_attribute *attr; 333200583Srdivacky 334200583Srdivacky attr = elf_new_obj_attr (abfd, vendor, tag); 335200583Srdivacky attr->type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag); 336200583Srdivacky attr->i = i; 337200583Srdivacky attr->s = _bfd_elf_attr_strdup (abfd, s); 338200583Srdivacky} 339200583Srdivacky 340200583Srdivacky/* Copy the object attributes from IBFD to OBFD. */ 341200583Srdivackyvoid 342200583Srdivacky_bfd_elf_copy_obj_attributes (bfd *ibfd, bfd *obfd) 343200583Srdivacky{ 344200583Srdivacky obj_attribute *in_attr; 345200583Srdivacky obj_attribute *out_attr; 346200583Srdivacky obj_attribute_list *list; 347200583Srdivacky int i; 348200583Srdivacky int vendor; 349200583Srdivacky 350200583Srdivacky for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++) 351200583Srdivacky { 352200583Srdivacky in_attr 353200583Srdivacky = &elf_known_obj_attributes (ibfd)[vendor][LEAST_KNOWN_OBJ_ATTRIBUTE]; 354200583Srdivacky out_attr 355200583Srdivacky = &elf_known_obj_attributes (obfd)[vendor][LEAST_KNOWN_OBJ_ATTRIBUTE]; 356200583Srdivacky for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) 357200583Srdivacky { 358200583Srdivacky out_attr->type = in_attr->type; 359200583Srdivacky out_attr->i = in_attr->i; 360200583Srdivacky if (in_attr->s && *in_attr->s) 361200583Srdivacky out_attr->s = _bfd_elf_attr_strdup (obfd, in_attr->s); 362200583Srdivacky in_attr++; 363200583Srdivacky out_attr++; 364200583Srdivacky } 365200583Srdivacky 366200583Srdivacky for (list = elf_other_obj_attributes (ibfd)[vendor]; 367200583Srdivacky list; 368200583Srdivacky list = list->next) 369200583Srdivacky { 370200583Srdivacky in_attr = &list->attr; 371200583Srdivacky switch (in_attr->type & (ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL)) 372200583Srdivacky { 373218893Sdim case ATTR_TYPE_FLAG_INT_VAL: 374200583Srdivacky bfd_elf_add_obj_attr_int (obfd, vendor, list->tag, in_attr->i); 375200583Srdivacky break; 376200583Srdivacky case ATTR_TYPE_FLAG_STR_VAL: 377218893Sdim bfd_elf_add_obj_attr_string (obfd, vendor, list->tag, 378200583Srdivacky in_attr->s); 379200583Srdivacky break; 380200583Srdivacky case ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL: 381200583Srdivacky bfd_elf_add_obj_attr_int_string (obfd, vendor, list->tag, 382200583Srdivacky in_attr->i, in_attr->s); 383200583Srdivacky break; 384200583Srdivacky default: 385200583Srdivacky abort (); 386200583Srdivacky } 387200583Srdivacky } 388200583Srdivacky } 389200583Srdivacky} 390200583Srdivacky 391200583Srdivacky/* Determine whether a GNU object attribute tag takes an integer, a 392200583Srdivacky string or both. */ 393200583Srdivackystatic int 394200583Srdivackygnu_obj_attrs_arg_type (int tag) 395200583Srdivacky{ 396200583Srdivacky /* Except for Tag_compatibility, for GNU attributes we follow the 397200583Srdivacky same rule ARM ones > 32 follow: odd-numbered tags take strings 398200583Srdivacky and even-numbered tags take integers. In addition, tag & 2 is 399200583Srdivacky nonzero for architecture-independent tags and zero for 400200583Srdivacky architecture-dependent ones. */ 401200583Srdivacky if (tag == Tag_compatibility) 402200583Srdivacky return 3; 403200583Srdivacky else 404200583Srdivacky return (tag & 1) != 0 ? 2 : 1; 405200583Srdivacky} 406200583Srdivacky 407200583Srdivacky/* Determine what arguments an attribute tag takes. */ 408200583Srdivackyint 409200583Srdivacky_bfd_elf_obj_attrs_arg_type (bfd *abfd, int vendor, int tag) 410200583Srdivacky{ 411200583Srdivacky switch (vendor) 412200583Srdivacky { 413200583Srdivacky case OBJ_ATTR_PROC: 414200583Srdivacky return get_elf_backend_data (abfd)->obj_attrs_arg_type (tag); 415200583Srdivacky break; 416200583Srdivacky case OBJ_ATTR_GNU: 417200583Srdivacky return gnu_obj_attrs_arg_type (tag); 418200583Srdivacky break; 419200583Srdivacky default: 420198092Srdivacky abort (); 421198092Srdivacky } 422198092Srdivacky} 423198092Srdivacky 424198092Srdivacky/* Parse an object attributes section. */ 425198092Srdivackyvoid 426198092Srdivacky_bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr) 427198092Srdivacky{ 428198092Srdivacky bfd_byte *contents; 429198092Srdivacky bfd_byte *p; 430198092Srdivacky bfd_vma len; 431198092Srdivacky const char *std_section; 432198092Srdivacky 433198092Srdivacky contents = (bfd_byte *) bfd_malloc (hdr->sh_size); 434198092Srdivacky if (!contents) 435198092Srdivacky return; 436198092Srdivacky if (!bfd_get_section_contents (abfd, hdr->bfd_section, contents, 0, 437198092Srdivacky hdr->sh_size)) 438198092Srdivacky { 439198092Srdivacky free (contents); 440198092Srdivacky return; 441198092Srdivacky } 442198092Srdivacky p = contents; 443198092Srdivacky std_section = get_elf_backend_data (abfd)->obj_attrs_vendor; 444198092Srdivacky if (*(p++) == 'A') 445198092Srdivacky { 446198092Srdivacky len = hdr->sh_size - 1; 447198092Srdivacky while (len > 0) 448198092Srdivacky { 449198092Srdivacky int namelen; 450198092Srdivacky bfd_vma section_len; 451198092Srdivacky int vendor; 452198092Srdivacky 453198092Srdivacky section_len = bfd_get_32 (abfd, p); 454212904Sdim p += 4; 455212904Sdim if (section_len > len) 456212904Sdim section_len = len; 457212904Sdim len -= section_len; 458198092Srdivacky namelen = strlen ((char *)p) + 1; 459212904Sdim section_len -= namelen + 4; 460198092Srdivacky if (std_section && strcmp ((char *)p, std_section) == 0) 461198092Srdivacky vendor = OBJ_ATTR_PROC; 462198092Srdivacky else if (strcmp ((char *)p, "gnu") == 0) 463198092Srdivacky vendor = OBJ_ATTR_GNU; 464199482Srdivacky else 465198092Srdivacky { 466198092Srdivacky /* Other vendor section. Ignore it. */ 467198092Srdivacky p += namelen + section_len; 468202379Srdivacky continue; 469202379Srdivacky } 470202379Srdivacky 471198092Srdivacky p += namelen; 472202379Srdivacky while (section_len > 0) 473202379Srdivacky { 474202379Srdivacky int tag; 475198092Srdivacky unsigned int n; 476202379Srdivacky unsigned int val; 477202379Srdivacky bfd_vma subsection_len; 478198092Srdivacky bfd_byte *end; 479198092Srdivacky 480198092Srdivacky tag = read_unsigned_leb128 (abfd, p, &n); 481205219Srdivacky p += n; 482202379Srdivacky subsection_len = bfd_get_32 (abfd, p); 483202379Srdivacky p += 4; 484200583Srdivacky if (subsection_len > section_len) 485202379Srdivacky subsection_len = section_len; 486202379Srdivacky section_len -= subsection_len; 487202379Srdivacky subsection_len -= n + 4; 488198092Srdivacky end = p + subsection_len; 489200583Srdivacky switch (tag) 490202379Srdivacky { 491202379Srdivacky case Tag_File: 492202379Srdivacky while (p < end) 493202379Srdivacky { 494202379Srdivacky int type; 495198092Srdivacky 496198092Srdivacky tag = read_unsigned_leb128 (abfd, p, &n); 497202379Srdivacky p += n; 498198092Srdivacky type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag); 499198092Srdivacky switch (type & (ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL)) 500210299Sed { 501198398Srdivacky case ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL: 502198398Srdivacky val = read_unsigned_leb128 (abfd, p, &n); 503198092Srdivacky p += n; 504198398Srdivacky bfd_elf_add_obj_attr_int_string (abfd, vendor, tag, 505198092Srdivacky val, (char *)p); 506210299Sed p += strlen ((char *)p) + 1; 507210299Sed break; 508210299Sed case ATTR_TYPE_FLAG_STR_VAL: 509210299Sed bfd_elf_add_obj_attr_string (abfd, vendor, tag, 510202379Srdivacky (char *)p); 511198092Srdivacky p += strlen ((char *)p) + 1; 512198092Srdivacky break; 513218893Sdim case ATTR_TYPE_FLAG_INT_VAL: 514218893Sdim val = read_unsigned_leb128 (abfd, p, &n); 515218893Sdim p += n; 516218893Sdim bfd_elf_add_obj_attr_int (abfd, vendor, tag, val); 517218893Sdim break; 518218893Sdim default: 519218893Sdim abort (); 520202379Srdivacky } 521218893Sdim } 522212904Sdim break; 523212904Sdim case Tag_Section: 524212904Sdim case Tag_Symbol: 525218893Sdim /* Don't have anywhere convenient to attach these. 526218893Sdim Fall through for now. */ 527212904Sdim default: 528212904Sdim /* Ignore things we don't kow about. */ 529198092Srdivacky p += subsection_len; 530202379Srdivacky subsection_len = 0; 531202379Srdivacky break; 532202379Srdivacky } 533202379Srdivacky } 534202379Srdivacky } 535202379Srdivacky } 536202379Srdivacky free (contents); 537202379Srdivacky} 538202379Srdivacky 539202379Srdivacky/* Merge common object attributes from IBFD into OBFD. Raise an error 540202379Srdivacky if there are conflicting attributes. Any processor-specific 541202379Srdivacky attributes have already been merged. This must be called from the 542212904Sdim bfd_elfNN_bfd_merge_private_bfd_data hook for each individual 543202379Srdivacky target, along with any target-specific merging. Because there are 544202379Srdivacky no common attributes other than Tag_compatibility at present, and 545202379Srdivacky non-"gnu" Tag_compatibility is not expected in "gnu" sections, this 546202379Srdivacky is not presently called for targets without their own 547202379Srdivacky attributes. */ 548202379Srdivacky 549202379Srdivackybfd_boolean 550202379Srdivacky_bfd_elf_merge_object_attributes (bfd *ibfd, bfd *obfd) 551202379Srdivacky{ 552202379Srdivacky obj_attribute *in_attr; 553202379Srdivacky obj_attribute *out_attr; 554202379Srdivacky int vendor; 555212904Sdim 556202379Srdivacky /* The only common attribute is currently Tag_compatibility, 557202379Srdivacky accepted in both processor and "gnu" sections. */ 558202379Srdivacky for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++) 559202379Srdivacky { 560202379Srdivacky /* Handle Tag_compatibility. The tags are only compatible if the flags 561212904Sdim are identical and, if the flags are '1', the strings are identical. 562202379Srdivacky If the flags are non-zero, then we can only use the string "gnu". */ 563202379Srdivacky in_attr = &elf_known_obj_attributes (ibfd)[vendor][Tag_compatibility]; 564202379Srdivacky out_attr = &elf_known_obj_attributes (obfd)[vendor][Tag_compatibility]; 565202379Srdivacky 566202379Srdivacky if (in_attr->i > 0 && strcmp (in_attr->s, "gnu") != 0) 567202379Srdivacky { 568202379Srdivacky _bfd_error_handler 569202379Srdivacky (_("error: %B: Object has vendor-specific contents that " 570202379Srdivacky "must be processed by the '%s' toolchain"), 571202379Srdivacky ibfd, in_attr->s); 572202379Srdivacky return FALSE; 573202379Srdivacky } 574202379Srdivacky 575210299Sed if (in_attr->i != out_attr->i 576210299Sed || (in_attr->i != 0 && strcmp (in_attr->s, out_attr->s) != 0)) 577212904Sdim { 578210299Sed _bfd_error_handler (_("error: %B: Object tag '%d, %s' is " 579210299Sed "incompatible with tag '%d, %s'"), 580210299Sed ibfd, 581210299Sed in_attr->i, in_attr->s ? in_attr->s : "", 582210299Sed out_attr->i, out_attr->s ? out_attr->s : ""); 583210299Sed return FALSE; 584210299Sed } 585210299Sed } 586210299Sed 587210299Sed return TRUE; 588210299Sed} 589210299Sed 590210299Sed/* Merge an unknown processor-specific attribute TAG, within the range 591210299Sed of known attributes, from IBFD into OBFD; return TRUE if the link 592210299Sed is OK, FALSE if it must fail. */ 593210299Sed 594210299Sedbfd_boolean 595210299Sed_bfd_elf_merge_unknown_attribute_low (bfd *ibfd, bfd *obfd, int tag) 596210299Sed{ 597210299Sed obj_attribute *in_attr; 598210299Sed obj_attribute *out_attr; 599210299Sed bfd *err_bfd = NULL; 600210299Sed bfd_boolean result = TRUE; 601210299Sed 602210299Sed in_attr = elf_known_obj_attributes_proc (ibfd); 603210299Sed out_attr = elf_known_obj_attributes_proc (obfd); 604210299Sed 605210299Sed if (out_attr[tag].i != 0 || out_attr[tag].s != NULL) 606210299Sed err_bfd = obfd; 607210299Sed else if (in_attr[tag].i != 0 || in_attr[tag].s != NULL) 608210299Sed err_bfd = ibfd; 609210299Sed 610210299Sed if (err_bfd != NULL) 611210299Sed result 612210299Sed = get_elf_backend_data (err_bfd)->obj_attrs_handle_unknown (err_bfd, tag); 613210299Sed 614210299Sed /* Only pass on attributes that match in both inputs. */ 615210299Sed if (in_attr[tag].i != out_attr[tag].i 616210299Sed || (in_attr[tag].s == NULL) != (out_attr[tag].s == NULL) 617210299Sed || (in_attr[tag].s != NULL && out_attr[tag].s != NULL 618210299Sed && strcmp (in_attr[tag].s, out_attr[tag].s) != 0)) 619210299Sed { 620210299Sed out_attr[tag].i = 0; 621210299Sed out_attr[tag].s = NULL; 622210299Sed } 623210299Sed 624210299Sed return result; 625210299Sed} 626210299Sed 627210299Sed/* Merge the lists of unknown processor-specific attributes, outside 628210299Sed the known range, from IBFD into OBFD; return TRUE if the link is 629210299Sed OK, FALSE if it must fail. */ 630210299Sed 631210299Sedbfd_boolean 632210299Sed_bfd_elf_merge_unknown_attribute_list (bfd *ibfd, bfd *obfd) 633210299Sed{ 634210299Sed obj_attribute_list *in_list; 635210299Sed obj_attribute_list *out_list; 636210299Sed obj_attribute_list **out_listp; 637210299Sed bfd_boolean result = TRUE; 638210299Sed 639210299Sed in_list = elf_other_obj_attributes_proc (ibfd); 640210299Sed out_listp = &elf_other_obj_attributes_proc (obfd); 641210299Sed out_list = *out_listp; 642210299Sed 643210299Sed for (; in_list || out_list; ) 644210299Sed { 645210299Sed bfd *err_bfd = NULL; 646210299Sed int err_tag = 0; 647212904Sdim 648210299Sed /* The tags for each list are in numerical order. */ 649210299Sed /* If the tags are equal, then merge. */ 650210299Sed if (out_list && (!in_list || in_list->tag > out_list->tag)) 651210299Sed { 652210299Sed /* This attribute only exists in obfd. We can't merge, and we don't 653210299Sed know what the tag means, so delete it. */ 654210299Sed err_bfd = obfd; 655210299Sed err_tag = out_list->tag; 656210299Sed *out_listp = out_list->next; 657210299Sed out_list = *out_listp; 658210299Sed } 659210299Sed else if (in_list && (!out_list || in_list->tag < out_list->tag)) 660210299Sed { 661210299Sed /* This attribute only exists in ibfd. We can't merge, and we don't 662210299Sed know what the tag means, so ignore it. */ 663210299Sed err_bfd = ibfd; 664210299Sed err_tag = in_list->tag; 665210299Sed in_list = in_list->next; 666210299Sed } 667210299Sed else /* The tags are equal. */ 668210299Sed { 669210299Sed /* As present, all attributes in the list are unknown, and 670221345Sdim therefore can't be merged meaningfully. */ 671221345Sdim err_bfd = obfd; 672221345Sdim err_tag = out_list->tag; 673221345Sdim 674221345Sdim /* Only pass on attributes that match in both inputs. */ 675221345Sdim if (in_list->attr.i != out_list->attr.i 676221345Sdim || (in_list->attr.s == NULL) != (out_list->attr.s == NULL) 677221345Sdim || (in_list->attr.s && out_list->attr.s 678221345Sdim && strcmp (in_list->attr.s, out_list->attr.s) != 0)) 679221345Sdim { 680221345Sdim /* No match. Delete the attribute. */ 681221345Sdim *out_listp = out_list->next; 682221345Sdim out_list = *out_listp; 683221345Sdim } 684221345Sdim else 685221345Sdim { 686221345Sdim /* Matched. Keep the attribute and move to the next. */ 687221345Sdim out_list = out_list->next; 688221345Sdim in_list = in_list->next; 689221345Sdim } 690221345Sdim } 691221345Sdim 692221345Sdim if (err_bfd) 693221345Sdim result = result 694221345Sdim && get_elf_backend_data (err_bfd)->obj_attrs_handle_unknown (err_bfd, 695221345Sdim err_tag); 696221345Sdim } 697221345Sdim 698221345Sdim return result; 699221345Sdim} 700221345Sdim