xref: /openbsd-src/gnu/usr.bin/binutils/bfd/cpu-arm.c (revision 007c2a4539b8b8aaa95c5e73e77620090abe113b)
12159047fSniklas /* BFD support for the ARM processor
2c074d1c9Sdrahn    Copyright 1994, 1997, 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
32159047fSniklas    Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
42159047fSniklas 
52159047fSniklas    This file is part of BFD, the Binary File Descriptor library.
62159047fSniklas 
72159047fSniklas    This program is free software; you can redistribute it and/or modify
82159047fSniklas    it under the terms of the GNU General Public License as published by
92159047fSniklas    the Free Software Foundation; either version 2 of the License, or
102159047fSniklas    (at your option) any later version.
112159047fSniklas 
122159047fSniklas    This program is distributed in the hope that it will be useful,
132159047fSniklas    but WITHOUT ANY WARRANTY; without even the implied warranty of
142159047fSniklas    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
152159047fSniklas    GNU General Public License for more details.
162159047fSniklas 
172159047fSniklas    You should have received a copy of the GNU General Public License
182159047fSniklas    along with this program; if not, write to the Free Software
192159047fSniklas    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
202159047fSniklas 
212159047fSniklas #include "bfd.h"
222159047fSniklas #include "sysdep.h"
232159047fSniklas #include "libbfd.h"
24c074d1c9Sdrahn #include "libiberty.h"
252159047fSniklas 
26f7cc78ecSespie static const bfd_arch_info_type * compatible
27f7cc78ecSespie   PARAMS ((const bfd_arch_info_type *, const bfd_arch_info_type *));
28c074d1c9Sdrahn static bfd_boolean scan
29c074d1c9Sdrahn   PARAMS ((const struct bfd_arch_info *, const char *));
30c074d1c9Sdrahn static bfd_boolean arm_check_note
31c074d1c9Sdrahn   PARAMS ((bfd *, char *, bfd_size_type, const char *, char **));
32f7cc78ecSespie 
33f7cc78ecSespie /* This routine is provided two arch_infos and works out which ARM
34f7cc78ecSespie    machine which would be compatible with both and returns a pointer
35c074d1c9Sdrahn    to its info structure.  */
36f7cc78ecSespie 
37f7cc78ecSespie static const bfd_arch_info_type *
compatible(a,b)38f7cc78ecSespie compatible (a,b)
39f7cc78ecSespie      const bfd_arch_info_type * a;
40f7cc78ecSespie      const bfd_arch_info_type * b;
412159047fSniklas {
42c074d1c9Sdrahn   /* If a & b are for different architecture we can do nothing.  */
43f7cc78ecSespie   if (a->arch != b->arch)
44f7cc78ecSespie       return NULL;
45f7cc78ecSespie 
46c074d1c9Sdrahn   /* If a & b are for the same machine then all is well.  */
47f7cc78ecSespie   if (a->mach == b->mach)
48f7cc78ecSespie     return a;
49f7cc78ecSespie 
50c074d1c9Sdrahn   /* Otherwise if either a or b is the 'default' machine
51c074d1c9Sdrahn      then it can be polymorphed into the other.  */
52f7cc78ecSespie   if (a->the_default)
53f7cc78ecSespie     return b;
54f7cc78ecSespie 
55f7cc78ecSespie   if (b->the_default)
56f7cc78ecSespie     return a;
57f7cc78ecSespie 
58c074d1c9Sdrahn   /* So far all newer ARM architecture cores are
59c074d1c9Sdrahn      supersets of previous cores.  */
60f7cc78ecSespie   if (a->mach < b->mach)
61f7cc78ecSespie     return b;
62f7cc78ecSespie   else if (a->mach > b->mach)
63f7cc78ecSespie     return a;
64f7cc78ecSespie 
65f7cc78ecSespie   /* Never reached!  */
66f7cc78ecSespie   return NULL;
67f7cc78ecSespie }
68f7cc78ecSespie 
69f7cc78ecSespie static struct
70f7cc78ecSespie {
71c074d1c9Sdrahn   unsigned int mach;
72f7cc78ecSespie   char *       name;
73f7cc78ecSespie }
74f7cc78ecSespie processors[] =
75f7cc78ecSespie {
76f7cc78ecSespie   { bfd_mach_arm_2,  "arm2"     },
77f7cc78ecSespie   { bfd_mach_arm_2a, "arm250"   },
78f7cc78ecSespie   { bfd_mach_arm_2a, "arm3"     },
79f7cc78ecSespie   { bfd_mach_arm_3,  "arm6"     },
80f7cc78ecSespie   { bfd_mach_arm_3,  "arm60"    },
81f7cc78ecSespie   { bfd_mach_arm_3,  "arm600"   },
82f7cc78ecSespie   { bfd_mach_arm_3,  "arm610"   },
83f7cc78ecSespie   { bfd_mach_arm_3,  "arm7"     },
84f7cc78ecSespie   { bfd_mach_arm_3,  "arm710"   },
85f7cc78ecSespie   { bfd_mach_arm_3,  "arm7500"  },
86f7cc78ecSespie   { bfd_mach_arm_3,  "arm7d"    },
87f7cc78ecSespie   { bfd_mach_arm_3,  "arm7di"   },
88f7cc78ecSespie   { bfd_mach_arm_3M, "arm7dm"   },
89f7cc78ecSespie   { bfd_mach_arm_3M, "arm7dmi"  },
90f7cc78ecSespie   { bfd_mach_arm_4T, "arm7tdmi" },
91f7cc78ecSespie   { bfd_mach_arm_4,  "arm8"     },
92f7cc78ecSespie   { bfd_mach_arm_4,  "arm810"   },
93f7cc78ecSespie   { bfd_mach_arm_4,  "arm9"     },
94f7cc78ecSespie   { bfd_mach_arm_4,  "arm920"   },
95f7cc78ecSespie   { bfd_mach_arm_4T, "arm920t"  },
96f7cc78ecSespie   { bfd_mach_arm_4T, "arm9tdmi" },
97f7cc78ecSespie   { bfd_mach_arm_4,  "sa1"      },
98f7cc78ecSespie   { bfd_mach_arm_4,  "strongarm"},
99f7cc78ecSespie   { bfd_mach_arm_4,  "strongarm110" },
100f7cc78ecSespie   { bfd_mach_arm_4,  "strongarm1100" },
101c074d1c9Sdrahn   { bfd_mach_arm_XScale, "xscale" },
102c074d1c9Sdrahn   { bfd_mach_arm_ep9312, "ep9312" },
103c074d1c9Sdrahn   { bfd_mach_arm_iWMMXt, "iwmmxt" }
1042159047fSniklas };
105f7cc78ecSespie 
106c074d1c9Sdrahn static bfd_boolean
scan(info,string)107f7cc78ecSespie scan (info, string)
108f7cc78ecSespie      const struct bfd_arch_info * info;
109f7cc78ecSespie      const char * string;
110f7cc78ecSespie {
111f7cc78ecSespie   int  i;
112f7cc78ecSespie 
113c074d1c9Sdrahn   /* First test for an exact match.  */
114f7cc78ecSespie   if (strcasecmp (string, info->printable_name) == 0)
115c074d1c9Sdrahn     return TRUE;
116f7cc78ecSespie 
117c074d1c9Sdrahn   /* Next check for a processor name instead of an Architecture name.  */
118f7cc78ecSespie   for (i = sizeof (processors) / sizeof (processors[0]); i--;)
119f7cc78ecSespie     {
120f7cc78ecSespie       if (strcasecmp (string, processors [i].name) == 0)
121f7cc78ecSespie 	break;
122f7cc78ecSespie     }
123f7cc78ecSespie 
124c074d1c9Sdrahn   if (i != -1 && info->mach == processors [i].mach)
125c074d1c9Sdrahn     return TRUE;
126f7cc78ecSespie 
127c074d1c9Sdrahn   /* Finally check for the default architecture.  */
128f7cc78ecSespie   if (strcasecmp (string, "arm") == 0)
129f7cc78ecSespie     return info->the_default;
130f7cc78ecSespie 
131c074d1c9Sdrahn   return FALSE;
132f7cc78ecSespie }
133f7cc78ecSespie 
134f7cc78ecSespie #define N(number, print, default, next)  \
135f7cc78ecSespie {  32, 32, 8, bfd_arch_arm, number, "arm", print, 4, default, compatible, scan, next }
136f7cc78ecSespie 
137f7cc78ecSespie static const bfd_arch_info_type arch_info_struct[] =
138f7cc78ecSespie {
139c074d1c9Sdrahn   N (bfd_mach_arm_2,      "armv2",   FALSE, & arch_info_struct[1]),
140c074d1c9Sdrahn   N (bfd_mach_arm_2a,     "armv2a",  FALSE, & arch_info_struct[2]),
141c074d1c9Sdrahn   N (bfd_mach_arm_3,      "armv3",   FALSE, & arch_info_struct[3]),
142c074d1c9Sdrahn   N (bfd_mach_arm_3M,     "armv3m",  FALSE, & arch_info_struct[4]),
143c074d1c9Sdrahn   N (bfd_mach_arm_4,      "armv4",   FALSE, & arch_info_struct[5]),
144c074d1c9Sdrahn   N (bfd_mach_arm_4T,     "armv4t",  FALSE, & arch_info_struct[6]),
145c074d1c9Sdrahn   N (bfd_mach_arm_5,      "armv5",   FALSE, & arch_info_struct[7]),
146c074d1c9Sdrahn   N (bfd_mach_arm_5T,     "armv5t",  FALSE, & arch_info_struct[8]),
147c074d1c9Sdrahn   N (bfd_mach_arm_5TE,    "armv5te", FALSE, & arch_info_struct[9]),
148c074d1c9Sdrahn   N (bfd_mach_arm_XScale, "xscale",  FALSE, & arch_info_struct[10]),
149c074d1c9Sdrahn   N (bfd_mach_arm_ep9312, "ep9312",  FALSE, & arch_info_struct[11]),
150c074d1c9Sdrahn   N (bfd_mach_arm_iWMMXt,"iwmmxt",  FALSE, NULL)
151f7cc78ecSespie };
152f7cc78ecSespie 
153f7cc78ecSespie const bfd_arch_info_type bfd_arm_arch =
154c074d1c9Sdrahn   N (0, "arm", TRUE, & arch_info_struct[0]);
155c074d1c9Sdrahn 
156c074d1c9Sdrahn /* Support functions used by both the COFF and ELF versions of the ARM port.  */
157c074d1c9Sdrahn 
158*007c2a45Smiod /* Handle the merging of the 'machine' settings of input file IBFD
159c074d1c9Sdrahn    and an output file OBFD.  These values actually represent the
160c074d1c9Sdrahn    different possible ARM architecture variants.
161c074d1c9Sdrahn    Returns TRUE if they were merged successfully or FALSE otherwise.  */
162c074d1c9Sdrahn 
163c074d1c9Sdrahn bfd_boolean
bfd_arm_merge_machines(ibfd,obfd)164c074d1c9Sdrahn bfd_arm_merge_machines (ibfd, obfd)
165c074d1c9Sdrahn      bfd * ibfd;
166c074d1c9Sdrahn      bfd * obfd;
167c074d1c9Sdrahn {
168c074d1c9Sdrahn   unsigned int in  = bfd_get_mach (ibfd);
169c074d1c9Sdrahn   unsigned int out = bfd_get_mach (obfd);
170c074d1c9Sdrahn 
171c074d1c9Sdrahn   /* If the output architecture is unknown, we now have a value to set.  */
172c074d1c9Sdrahn   if (out == bfd_mach_arm_unknown)
173c074d1c9Sdrahn     bfd_set_arch_mach (obfd, bfd_arch_arm, in);
174c074d1c9Sdrahn 
175*007c2a45Smiod   /* If the input architecture is unknown,
176c074d1c9Sdrahn      then so must be the output architecture.  */
177c074d1c9Sdrahn   else if (in == bfd_mach_arm_unknown)
178c074d1c9Sdrahn     /* FIXME: We ought to have some way to
179c074d1c9Sdrahn        override this on the command line.  */
180c074d1c9Sdrahn     bfd_set_arch_mach (obfd, bfd_arch_arm, bfd_mach_arm_unknown);
181c074d1c9Sdrahn 
182c074d1c9Sdrahn   /* If they are the same then nothing needs to be done.  */
183c074d1c9Sdrahn   else if (out == in)
184c074d1c9Sdrahn     ;
185c074d1c9Sdrahn 
186c074d1c9Sdrahn   /* Otherwise the general principle that a earlier architecture can be
187*007c2a45Smiod      linked with a later architecture to produce a binary that will execute
188c074d1c9Sdrahn      on the later architecture.
189c074d1c9Sdrahn 
190c074d1c9Sdrahn      We fail however if we attempt to link a Cirrus EP9312 binary with an
191c074d1c9Sdrahn      Intel XScale binary, since these architecture have co-processors which
192c074d1c9Sdrahn      will not both be present on the same physical hardware.  */
193c074d1c9Sdrahn   else if (in == bfd_mach_arm_ep9312
194c074d1c9Sdrahn 	   && (out == bfd_mach_arm_XScale || out == bfd_mach_arm_iWMMXt))
195c074d1c9Sdrahn     {
196c074d1c9Sdrahn       _bfd_error_handler (_("\
197c074d1c9Sdrahn ERROR: %s is compiled for the EP9312, whereas %s is compiled for XScale"),
198c074d1c9Sdrahn 			  bfd_archive_filename (ibfd),
199c074d1c9Sdrahn 			  bfd_get_filename (obfd));
200c074d1c9Sdrahn       bfd_set_error (bfd_error_wrong_format);
201c074d1c9Sdrahn       return FALSE;
202c074d1c9Sdrahn     }
203c074d1c9Sdrahn   else if (out == bfd_mach_arm_ep9312
204c074d1c9Sdrahn 	   && (in == bfd_mach_arm_XScale || in == bfd_mach_arm_iWMMXt))
205c074d1c9Sdrahn     {
206c074d1c9Sdrahn       _bfd_error_handler (_("\
207c074d1c9Sdrahn ERROR: %s is compiled for the EP9312, whereas %s is compiled for XScale"),
208c074d1c9Sdrahn 			  bfd_archive_filename (obfd),
209c074d1c9Sdrahn 			  bfd_get_filename (ibfd));
210c074d1c9Sdrahn       bfd_set_error (bfd_error_wrong_format);
211c074d1c9Sdrahn       return FALSE;
212c074d1c9Sdrahn     }
213c074d1c9Sdrahn   else if (in > out)
214c074d1c9Sdrahn     bfd_set_arch_mach (obfd, bfd_arch_arm, in);
215c074d1c9Sdrahn   /* else
216c074d1c9Sdrahn      Nothing to do.  */
217c074d1c9Sdrahn 
218c074d1c9Sdrahn   return TRUE;
219c074d1c9Sdrahn }
220c074d1c9Sdrahn 
221c074d1c9Sdrahn typedef struct
222c074d1c9Sdrahn {
223c074d1c9Sdrahn   unsigned char	namesz[4];	/* Size of entry's owner string.  */
224c074d1c9Sdrahn   unsigned char	descsz[4];	/* Size of the note descriptor.  */
225c074d1c9Sdrahn   unsigned char	type[4];	/* Interpretation of the descriptor.  */
226c074d1c9Sdrahn   char		name[1];	/* Start of the name+desc data.  */
227c074d1c9Sdrahn } arm_Note;
228c074d1c9Sdrahn 
229c074d1c9Sdrahn static bfd_boolean
arm_check_note(abfd,buffer,buffer_size,expected_name,description_return)230c074d1c9Sdrahn arm_check_note (abfd, buffer, buffer_size, expected_name, description_return)
231c074d1c9Sdrahn      bfd *           abfd;
232c074d1c9Sdrahn      char *          buffer;
233c074d1c9Sdrahn      bfd_size_type   buffer_size;
234c074d1c9Sdrahn      const char *    expected_name;
235c074d1c9Sdrahn      char **         description_return;
236c074d1c9Sdrahn {
237c074d1c9Sdrahn   unsigned long namesz;
238c074d1c9Sdrahn   unsigned long descsz;
239c074d1c9Sdrahn   unsigned long type;
240c074d1c9Sdrahn   char *        descr;
241c074d1c9Sdrahn 
242c074d1c9Sdrahn   if (buffer_size < offsetof (arm_Note, name))
243c074d1c9Sdrahn     return FALSE;
244c074d1c9Sdrahn 
245c074d1c9Sdrahn   /* We have to extract the values this way to allow for a
246c074d1c9Sdrahn      host whose endian-ness is different from the target.  */
247c074d1c9Sdrahn   namesz = bfd_get_32 (abfd, buffer);
248c074d1c9Sdrahn   descsz = bfd_get_32 (abfd, buffer + offsetof (arm_Note, descsz));
249c074d1c9Sdrahn   type   = bfd_get_32 (abfd, buffer + offsetof (arm_Note, type));
250c074d1c9Sdrahn   descr  = buffer + offsetof (arm_Note, name);
251c074d1c9Sdrahn 
252c074d1c9Sdrahn   /* Check for buffer overflow.  */
253c074d1c9Sdrahn   if (namesz + descsz + offsetof (arm_Note, name) > buffer_size)
254c074d1c9Sdrahn     return FALSE;
255c074d1c9Sdrahn 
256c074d1c9Sdrahn   if (expected_name == NULL)
257c074d1c9Sdrahn     {
258c074d1c9Sdrahn       if (namesz != 0)
259c074d1c9Sdrahn 	return FALSE;
260c074d1c9Sdrahn     }
261c074d1c9Sdrahn   else
262c074d1c9Sdrahn     {
263c074d1c9Sdrahn       if (namesz != ((strlen (expected_name) + 1 + 3) & ~3))
264c074d1c9Sdrahn 	return FALSE;
265c074d1c9Sdrahn 
266c074d1c9Sdrahn       if (strcmp (descr, expected_name) != 0)
267c074d1c9Sdrahn 	return FALSE;
268c074d1c9Sdrahn 
269c074d1c9Sdrahn       descr += (namesz + 3) & ~3;
270c074d1c9Sdrahn     }
271c074d1c9Sdrahn 
272c074d1c9Sdrahn   /* FIXME: We should probably check the type as well.  */
273c074d1c9Sdrahn 
274c074d1c9Sdrahn   if (description_return != NULL)
275c074d1c9Sdrahn     * description_return = descr;
276c074d1c9Sdrahn 
277c074d1c9Sdrahn   return TRUE;
278c074d1c9Sdrahn }
279c074d1c9Sdrahn 
280c074d1c9Sdrahn #define NOTE_ARCH_STRING 	"arch: "
281c074d1c9Sdrahn 
282c074d1c9Sdrahn bfd_boolean
bfd_arm_update_notes(abfd,note_section)283c074d1c9Sdrahn bfd_arm_update_notes (abfd, note_section)
284c074d1c9Sdrahn      bfd * abfd;
285c074d1c9Sdrahn      const char * note_section;
286c074d1c9Sdrahn {
287c074d1c9Sdrahn   asection *     arm_arch_section;
288c074d1c9Sdrahn   bfd_size_type  buffer_size;
289c074d1c9Sdrahn   char *         buffer;
290c074d1c9Sdrahn   char *         arch_string;
291c074d1c9Sdrahn   char *         expected;
292c074d1c9Sdrahn 
293c074d1c9Sdrahn   /* Look for a note section.  If one is present check the architecture
294c074d1c9Sdrahn      string encoded in it, and set it to the current architecture if it is
295c074d1c9Sdrahn      different.  */
296c074d1c9Sdrahn   arm_arch_section = bfd_get_section_by_name (abfd, note_section);
297c074d1c9Sdrahn 
298c074d1c9Sdrahn   if (arm_arch_section == NULL)
299c074d1c9Sdrahn     return TRUE;
300c074d1c9Sdrahn 
301c074d1c9Sdrahn   buffer_size = arm_arch_section->_raw_size;
302c074d1c9Sdrahn   if (buffer_size == 0)
303c074d1c9Sdrahn     return FALSE;
304c074d1c9Sdrahn 
305c074d1c9Sdrahn   buffer = bfd_malloc (buffer_size);
306c074d1c9Sdrahn   if (buffer == NULL)
307c074d1c9Sdrahn     return FALSE;
308c074d1c9Sdrahn 
309c074d1c9Sdrahn   if (! bfd_get_section_contents (abfd, arm_arch_section, buffer,
310c074d1c9Sdrahn 				  (file_ptr) 0, buffer_size))
311c074d1c9Sdrahn     goto FAIL;
312c074d1c9Sdrahn 
313c074d1c9Sdrahn   /* Parse the note.  */
314c074d1c9Sdrahn   if (! arm_check_note (abfd, buffer, buffer_size, NOTE_ARCH_STRING, & arch_string))
315c074d1c9Sdrahn     goto FAIL;
316c074d1c9Sdrahn 
317c074d1c9Sdrahn   /* Check the architecture in the note against the architecture of the bfd.  */
318c074d1c9Sdrahn   switch (bfd_get_mach (abfd))
319c074d1c9Sdrahn     {
320c074d1c9Sdrahn     default:
321c074d1c9Sdrahn     case bfd_mach_arm_unknown: expected = "unknown"; break;
322c074d1c9Sdrahn     case bfd_mach_arm_2:       expected = "armv2"; break;
323c074d1c9Sdrahn     case bfd_mach_arm_2a:      expected = "armv2a"; break;
324c074d1c9Sdrahn     case bfd_mach_arm_3:       expected = "armv3"; break;
325c074d1c9Sdrahn     case bfd_mach_arm_3M:      expected = "armv3M"; break;
326c074d1c9Sdrahn     case bfd_mach_arm_4:       expected = "armv4"; break;
327c074d1c9Sdrahn     case bfd_mach_arm_4T:      expected = "armv4t"; break;
328c074d1c9Sdrahn     case bfd_mach_arm_5:       expected = "armv5"; break;
329c074d1c9Sdrahn     case bfd_mach_arm_5T:      expected = "armv5t"; break;
330c074d1c9Sdrahn     case bfd_mach_arm_5TE:     expected = "armv5te"; break;
331c074d1c9Sdrahn     case bfd_mach_arm_XScale:  expected = "XScale"; break;
332c074d1c9Sdrahn     case bfd_mach_arm_ep9312:  expected = "ep9312"; break;
333c074d1c9Sdrahn     case bfd_mach_arm_iWMMXt:  expected = "iWMMXt"; break;
334c074d1c9Sdrahn     }
335c074d1c9Sdrahn 
336c074d1c9Sdrahn   if (strcmp (arch_string, expected) != 0)
337c074d1c9Sdrahn     {
338c074d1c9Sdrahn       strcpy (buffer + offsetof (arm_Note, name) + ((strlen (NOTE_ARCH_STRING) + 3) & ~3), expected);
339c074d1c9Sdrahn 
340c074d1c9Sdrahn       if (! bfd_set_section_contents (abfd, arm_arch_section, buffer,
341c074d1c9Sdrahn 				      (file_ptr) 0, buffer_size))
342c074d1c9Sdrahn 	{
343c074d1c9Sdrahn 	  (*_bfd_error_handler)
344c074d1c9Sdrahn 	    (_("warning: unable to update contents of %s section in %s"),
345c074d1c9Sdrahn 	     note_section, bfd_get_filename (abfd));
346c074d1c9Sdrahn 	  goto FAIL;
347c074d1c9Sdrahn 	}
348c074d1c9Sdrahn     }
349c074d1c9Sdrahn 
350c074d1c9Sdrahn   free (buffer);
351c074d1c9Sdrahn   return TRUE;
352c074d1c9Sdrahn 
353c074d1c9Sdrahn  FAIL:
354c074d1c9Sdrahn   free (buffer);
355c074d1c9Sdrahn   return FALSE;
356c074d1c9Sdrahn }
357c074d1c9Sdrahn 
358c074d1c9Sdrahn 
359c074d1c9Sdrahn static struct
360c074d1c9Sdrahn {
361c074d1c9Sdrahn   const char * string;
362c074d1c9Sdrahn   unsigned int mach;
363c074d1c9Sdrahn }
364c074d1c9Sdrahn architectures[] =
365c074d1c9Sdrahn {
366c074d1c9Sdrahn   { "armv2",   bfd_mach_arm_2 },
367c074d1c9Sdrahn   { "armv2a",  bfd_mach_arm_2a },
368c074d1c9Sdrahn   { "armv3",   bfd_mach_arm_3 },
369c074d1c9Sdrahn   { "armv3M",  bfd_mach_arm_3M },
370c074d1c9Sdrahn   { "armv4",   bfd_mach_arm_4 },
371c074d1c9Sdrahn   { "armv4t",  bfd_mach_arm_4T },
372c074d1c9Sdrahn   { "armv5",   bfd_mach_arm_5 },
373c074d1c9Sdrahn   { "armv5t",  bfd_mach_arm_5T },
374c074d1c9Sdrahn   { "armv5te", bfd_mach_arm_5TE },
375c074d1c9Sdrahn   { "XScale",  bfd_mach_arm_XScale },
376c074d1c9Sdrahn   { "ep9312",  bfd_mach_arm_ep9312 },
377c074d1c9Sdrahn   { "iWMMXt",  bfd_mach_arm_iWMMXt }
378c074d1c9Sdrahn };
379c074d1c9Sdrahn 
380c074d1c9Sdrahn /* Extract the machine number stored in a note section.  */
381c074d1c9Sdrahn unsigned int
bfd_arm_get_mach_from_notes(abfd,note_section)382c074d1c9Sdrahn bfd_arm_get_mach_from_notes (abfd, note_section)
383c074d1c9Sdrahn      bfd * abfd;
384c074d1c9Sdrahn      const char * note_section;
385c074d1c9Sdrahn {
386c074d1c9Sdrahn   asection *     arm_arch_section;
387c074d1c9Sdrahn   bfd_size_type  buffer_size;
388c074d1c9Sdrahn   char *         buffer;
389c074d1c9Sdrahn   char *         arch_string;
390c074d1c9Sdrahn   int            i;
391c074d1c9Sdrahn 
392c074d1c9Sdrahn   /* Look for a note section.  If one is present check the architecture
393c074d1c9Sdrahn      string encoded in it, and set it to the current architecture if it is
394c074d1c9Sdrahn      different.  */
395c074d1c9Sdrahn   arm_arch_section = bfd_get_section_by_name (abfd, note_section);
396c074d1c9Sdrahn 
397c074d1c9Sdrahn   if (arm_arch_section == NULL)
398c074d1c9Sdrahn     return bfd_mach_arm_unknown;
399c074d1c9Sdrahn 
400c074d1c9Sdrahn   buffer_size = arm_arch_section->_raw_size;
401c074d1c9Sdrahn   if (buffer_size == 0)
402c074d1c9Sdrahn     return bfd_mach_arm_unknown;
403c074d1c9Sdrahn 
404c074d1c9Sdrahn   buffer = bfd_malloc (buffer_size);
405c074d1c9Sdrahn   if (buffer == NULL)
406c074d1c9Sdrahn     return bfd_mach_arm_unknown;
407c074d1c9Sdrahn 
408c074d1c9Sdrahn   if (! bfd_get_section_contents (abfd, arm_arch_section, buffer,
409c074d1c9Sdrahn 				  (file_ptr) 0, buffer_size))
410c074d1c9Sdrahn     goto FAIL;
411c074d1c9Sdrahn 
412c074d1c9Sdrahn   /* Parse the note.  */
413c074d1c9Sdrahn   if (! arm_check_note (abfd, buffer, buffer_size, NOTE_ARCH_STRING, & arch_string))
414c074d1c9Sdrahn     goto FAIL;
415c074d1c9Sdrahn 
416c074d1c9Sdrahn   /* Interpret the architecture string.  */
417c074d1c9Sdrahn   for (i = ARRAY_SIZE (architectures); i--;)
418c074d1c9Sdrahn     if (strcmp (arch_string, architectures[i].string) == 0)
419c074d1c9Sdrahn       {
420c074d1c9Sdrahn 	free (buffer);
421c074d1c9Sdrahn 	return architectures[i].mach;
422c074d1c9Sdrahn       }
423c074d1c9Sdrahn 
424c074d1c9Sdrahn  FAIL:
425c074d1c9Sdrahn   free (buffer);
426c074d1c9Sdrahn   return bfd_mach_arm_unknown;
427c074d1c9Sdrahn }
428