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