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