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