xref: /netbsd-src/external/gpl3/gdb.old/dist/bfd/cpu-arm.c (revision 7bdf38e5b7a28439665f2fdeff81e36913eef7dd)
1 /* BFD support for the ARM processor
2    Copyright (C) 1994-2022 Free Software Foundation, Inc.
3    Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
4 
5    This file is part of BFD, the Binary File Descriptor library.
6 
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20    MA 02110-1301, USA.  */
21 
22 #include "sysdep.h"
23 #include "bfd.h"
24 #include "libbfd.h"
25 #include "libiberty.h"
26 #include "cpu-arm.h"
27 
28 /* This routine is provided two arch_infos and works out which ARM
29    machine which would be compatible with both and returns a pointer
30    to its info structure.  */
31 
32 static const bfd_arch_info_type *
33 compatible (const bfd_arch_info_type *a, const bfd_arch_info_type *b)
34 {
35   /* If a & b are for different architecture we can do nothing.  */
36   if (a->arch != b->arch)
37       return NULL;
38 
39   /* If a & b are for the same machine then all is well.  */
40   if (a->mach == b->mach)
41     return a;
42 
43   /* Otherwise if either a or b is the 'default' machine
44      then it can be polymorphed into the other.  */
45   if (a->the_default)
46     return b;
47 
48   if (b->the_default)
49     return a;
50 
51   /* So far all newer ARM architecture cores are
52      supersets of previous cores.  */
53   if (a->mach < b->mach)
54     return b;
55   else if (a->mach > b->mach)
56     return a;
57 
58   /* Never reached!  */
59   return NULL;
60 }
61 
62 static struct
63 {
64   unsigned int mach;
65   char *       name;
66 }
67 processors[] =
68 {
69   { bfd_mach_arm_2,	  "arm2"	    },
70   { bfd_mach_arm_2a,	  "arm250"	    },
71   { bfd_mach_arm_2a,	  "arm3"	    },
72   { bfd_mach_arm_3,	  "arm6"	    },
73   { bfd_mach_arm_3,	  "arm60"	    },
74   { bfd_mach_arm_3,	  "arm600"	    },
75   { bfd_mach_arm_3,	  "arm610"	    },
76   { bfd_mach_arm_3,	  "arm620"	    },
77   { bfd_mach_arm_3,	  "arm7"	    },
78   { bfd_mach_arm_3,	  "arm70"	    },
79   { bfd_mach_arm_3,	  "arm700"	    },
80   { bfd_mach_arm_3,	  "arm700i"	    },
81   { bfd_mach_arm_3,	  "arm710"	    },
82   { bfd_mach_arm_3,	  "arm7100"	    },
83   { bfd_mach_arm_3,	  "arm710c"	    },
84   { bfd_mach_arm_4T,	  "arm710t"	    },
85   { bfd_mach_arm_3,	  "arm720"	    },
86   { bfd_mach_arm_4T,	  "arm720t"	    },
87   { bfd_mach_arm_4T,	  "arm740t"	    },
88   { bfd_mach_arm_3,	  "arm7500"	    },
89   { bfd_mach_arm_3,	  "arm7500fe"	    },
90   { bfd_mach_arm_3,	  "arm7d"	    },
91   { bfd_mach_arm_3,	  "arm7di"	    },
92   { bfd_mach_arm_3M,	  "arm7dm"	    },
93   { bfd_mach_arm_3M,	  "arm7dmi"	    },
94   { bfd_mach_arm_4T,	  "arm7t"	    },
95   { bfd_mach_arm_4T,	  "arm7tdmi"	    },
96   { bfd_mach_arm_4T,	  "arm7tdmi-s"	    },
97   { bfd_mach_arm_3M,	  "arm7m"	    },
98   { bfd_mach_arm_4,	  "arm8"	    },
99   { bfd_mach_arm_4,	  "arm810"	    },
100   { bfd_mach_arm_4,	  "arm9"	    },
101   { bfd_mach_arm_4T,	  "arm920"	    },
102   { bfd_mach_arm_4T,	  "arm920t"	    },
103   { bfd_mach_arm_4T,	  "arm922t"	    },
104   { bfd_mach_arm_5TEJ,	  "arm926ej"	    },
105   { bfd_mach_arm_5TEJ,	  "arm926ejs"	    },
106   { bfd_mach_arm_5TEJ,	  "arm926ej-s"	    },
107   { bfd_mach_arm_4T,	  "arm940t"	    },
108   { bfd_mach_arm_5TE,	  "arm946e"	    },
109   { bfd_mach_arm_5TE,	  "arm946e-r0"	    },
110   { bfd_mach_arm_5TE,	  "arm946e-s"	    },
111   { bfd_mach_arm_5TE,	  "arm966e"	    },
112   { bfd_mach_arm_5TE,	  "arm966e-r0"	    },
113   { bfd_mach_arm_5TE,	  "arm966e-s"	    },
114   { bfd_mach_arm_5TE,	  "arm968e-s"	    },
115   { bfd_mach_arm_5TE,	  "arm9e"	    },
116   { bfd_mach_arm_5TE,	  "arm9e-r0"	    },
117   { bfd_mach_arm_4T,	  "arm9tdmi"	    },
118   { bfd_mach_arm_5TE,	  "arm1020"	    },
119   { bfd_mach_arm_5T,	  "arm1020t"	    },
120   { bfd_mach_arm_5TE,	  "arm1020e"	    },
121   { bfd_mach_arm_5TE,	  "arm1022e"	    },
122   { bfd_mach_arm_5TEJ,	  "arm1026ejs"	    },
123   { bfd_mach_arm_5TEJ,	  "arm1026ej-s"	    },
124   { bfd_mach_arm_5TE,	  "arm10e"	    },
125   { bfd_mach_arm_5T,	  "arm10t"	    },
126   { bfd_mach_arm_5T,	  "arm10tdmi"	    },
127   { bfd_mach_arm_6,	  "arm1136j-s"	    },
128   { bfd_mach_arm_6,	  "arm1136js"	    },
129   { bfd_mach_arm_6,	  "arm1136jf-s"	    },
130   { bfd_mach_arm_6,	  "arm1136jfs"	    },
131   { bfd_mach_arm_6KZ,	  "arm1176jz-s"	    },
132   { bfd_mach_arm_6KZ,	  "arm1176jzf-s"    },
133   { bfd_mach_arm_6T2,	  "arm1156t2-s"	    },
134   { bfd_mach_arm_6T2,	  "arm1156t2f-s"    },
135   { bfd_mach_arm_7,	  "cortex-a5"	    },
136   { bfd_mach_arm_7,	  "cortex-a7"	    },
137   { bfd_mach_arm_7,	  "cortex-a8"	    },
138   { bfd_mach_arm_7,	  "cortex-a9"	    },
139   { bfd_mach_arm_7,	  "cortex-a12"	    },
140   { bfd_mach_arm_7,	  "cortex-a15"	    },
141   { bfd_mach_arm_7,	  "cortex-a17"	    },
142   { bfd_mach_arm_8,	  "cortex-a32"	    },
143   { bfd_mach_arm_8,	  "cortex-a35"	    },
144   { bfd_mach_arm_8,	  "cortex-a53"	    },
145   { bfd_mach_arm_8,	  "cortex-a55"	    },
146   { bfd_mach_arm_8,	  "cortex-a57"	    },
147   { bfd_mach_arm_8,	  "cortex-a72"	    },
148   { bfd_mach_arm_8,	  "cortex-a73"	    },
149   { bfd_mach_arm_8,	  "cortex-a75"	    },
150   { bfd_mach_arm_8,	  "cortex-a76"	    },
151   { bfd_mach_arm_8,	  "cortex-a76ae"    },
152   { bfd_mach_arm_8,	  "cortex-a77"	    },
153   { bfd_mach_arm_8,	  "cortex-a78"	    },
154   { bfd_mach_arm_8,	  "cortex-a78ae"    },
155   { bfd_mach_arm_8,	  "cortex-a78c"     },
156   { bfd_mach_arm_6SM,	  "cortex-m0"	    },
157   { bfd_mach_arm_6SM,	  "cortex-m0plus"   },
158   { bfd_mach_arm_6SM,	  "cortex-m1"	    },
159   { bfd_mach_arm_8M_BASE, "cortex-m23"	    },
160   { bfd_mach_arm_7,	  "cortex-m3"	    },
161   { bfd_mach_arm_8M_MAIN, "cortex-m33"	    },
162   { bfd_mach_arm_8M_MAIN, "cortex-m35p"	    },
163   { bfd_mach_arm_7EM,	  "cortex-m4"	    },
164   { bfd_mach_arm_7EM,	  "cortex-m7"	    },
165   { bfd_mach_arm_7,	  "cortex-r4"	    },
166   { bfd_mach_arm_7,	  "cortex-r4f"	    },
167   { bfd_mach_arm_7,	  "cortex-r5"	    },
168   { bfd_mach_arm_8R,	  "cortex-r52"	    },
169   { bfd_mach_arm_8R,	  "cortex-r52plus"	    },
170   { bfd_mach_arm_7,	  "cortex-r7"	    },
171   { bfd_mach_arm_7,	  "cortex-r8"	    },
172   { bfd_mach_arm_8,	  "cortex-x1"	    },
173   { bfd_mach_arm_8,	  "cortex-x1c"	    },
174   { bfd_mach_arm_4T,	  "ep9312"	    },
175   { bfd_mach_arm_8,	  "exynos-m1"	    },
176   { bfd_mach_arm_4,	  "fa526"	    },
177   { bfd_mach_arm_5TE,	  "fa606te"	    },
178   { bfd_mach_arm_5TE,	  "fa616te"	    },
179   { bfd_mach_arm_4,	  "fa626"	    },
180   { bfd_mach_arm_5TE,	  "fa626te"	    },
181   { bfd_mach_arm_5TE,	  "fa726te"	    },
182   { bfd_mach_arm_5TE,	  "fmp626"	    },
183   { bfd_mach_arm_XScale,  "i80200"	    },
184   { bfd_mach_arm_7,	  "marvell-pj4"	    },
185   { bfd_mach_arm_7,	  "marvell-whitney" },
186   { bfd_mach_arm_6K,	  "mpcore"	    },
187   { bfd_mach_arm_6K,	  "mpcorenovfp"	    },
188   { bfd_mach_arm_4,	  "sa1"		    },
189   { bfd_mach_arm_4,	  "strongarm"	    },
190   { bfd_mach_arm_4,	  "strongarm1"	    },
191   { bfd_mach_arm_4,	  "strongarm110"    },
192   { bfd_mach_arm_4,	  "strongarm1100"   },
193   { bfd_mach_arm_4,	  "strongarm1110"   },
194   { bfd_mach_arm_XScale,  "xscale"	    },
195   { bfd_mach_arm_8,	  "xgene1"	    },
196   { bfd_mach_arm_8,	  "xgene2"	    },
197   { bfd_mach_arm_9,	  "cortex-a710"	    },
198   { bfd_mach_arm_ep9312,  "ep9312"	    },
199   { bfd_mach_arm_iWMMXt,  "iwmmxt"	    },
200   { bfd_mach_arm_iWMMXt2, "iwmmxt2"	    },
201   { bfd_mach_arm_unknown, "arm_any"	    }
202 };
203 
204 static bool
205 scan (const struct bfd_arch_info *info, const char *string)
206 {
207   int  i;
208 
209   /* First test for an exact match.  */
210   if (strcasecmp (string, info->printable_name) == 0)
211     return true;
212 
213   /* If there is a prefix of "arm:" then skip it.  */
214   const char * colon;
215   if ((colon = strchr (string, ':')) != NULL)
216     {
217       if (strncasecmp (string, "arm", colon - string) != 0)
218 	return false;
219       string = colon + 1;
220     }
221 
222   /* Next check for a processor name instead of an Architecture name.  */
223   for (i = sizeof (processors) / sizeof (processors[0]); i--;)
224     {
225       if (strcasecmp (string, processors [i].name) == 0)
226 	break;
227     }
228 
229   if (i != -1 && info->mach == processors [i].mach)
230     return true;
231 
232   /* Finally check for the default architecture.  */
233   if (strcasecmp (string, "arm") == 0)
234     return info->the_default;
235 
236   return false;
237 }
238 
239 #define N(number, print, default, next)  \
240 {  32, 32, 8, bfd_arch_arm, number, "arm", print, 4, default, compatible, \
241     scan, bfd_arch_default_fill, next, 0 }
242 
243 static const bfd_arch_info_type arch_info_struct[] =
244 {
245   N (bfd_mach_arm_2,         "armv2",          false, & arch_info_struct[1]),
246   N (bfd_mach_arm_2a,        "armv2a",         false, & arch_info_struct[2]),
247   N (bfd_mach_arm_3,         "armv3",          false, & arch_info_struct[3]),
248   N (bfd_mach_arm_3M,        "armv3m",         false, & arch_info_struct[4]),
249   N (bfd_mach_arm_4,         "armv4",          false, & arch_info_struct[5]),
250   N (bfd_mach_arm_4T,        "armv4t",         false, & arch_info_struct[6]),
251   N (bfd_mach_arm_5,         "armv5",          false, & arch_info_struct[7]),
252   N (bfd_mach_arm_5T,        "armv5t",         false, & arch_info_struct[8]),
253   N (bfd_mach_arm_5TE,       "armv5te",        false, & arch_info_struct[9]),
254   N (bfd_mach_arm_XScale,    "xscale",         false, & arch_info_struct[10]),
255   N (bfd_mach_arm_ep9312,    "ep9312",         false, & arch_info_struct[11]),
256   N (bfd_mach_arm_iWMMXt,    "iwmmxt",         false, & arch_info_struct[12]),
257   N (bfd_mach_arm_iWMMXt2,   "iwmmxt2",        false, & arch_info_struct[13]),
258   N (bfd_mach_arm_5TEJ,      "armv5tej",       false, & arch_info_struct[14]),
259   N (bfd_mach_arm_6,         "armv6",          false, & arch_info_struct[15]),
260   N (bfd_mach_arm_6KZ,       "armv6kz",        false, & arch_info_struct[16]),
261   N (bfd_mach_arm_6T2,       "armv6t2",        false, & arch_info_struct[17]),
262   N (bfd_mach_arm_6K,        "armv6k",         false, & arch_info_struct[18]),
263   N (bfd_mach_arm_7,         "armv7",          false, & arch_info_struct[19]),
264   N (bfd_mach_arm_6M,        "armv6-m",        false, & arch_info_struct[20]),
265   N (bfd_mach_arm_6SM,       "armv6s-m",       false, & arch_info_struct[21]),
266   N (bfd_mach_arm_7EM,       "armv7e-m",       false, & arch_info_struct[22]),
267   N (bfd_mach_arm_8,         "armv8-a",        false, & arch_info_struct[23]),
268   N (bfd_mach_arm_8R,        "armv8-r",        false, & arch_info_struct[24]),
269   N (bfd_mach_arm_8M_BASE,   "armv8-m.base",   false, & arch_info_struct[25]),
270   N (bfd_mach_arm_8M_MAIN,   "armv8-m.main",   false, & arch_info_struct[26]),
271   N (bfd_mach_arm_8_1M_MAIN, "armv8.1-m.main", false, & arch_info_struct[27]),
272   N (bfd_mach_arm_9,         "armv9-a",        false, & arch_info_struct[28]),
273   N (bfd_mach_arm_unknown,   "arm_any",        false, NULL)
274 };
275 
276 const bfd_arch_info_type bfd_arm_arch =
277   N (0, "arm", true, & arch_info_struct[0]);
278 
279 /* Support functions used by both the COFF and ELF versions of the ARM port.  */
280 
281 /* Handle the merging of the 'machine' settings of input file IBFD
282    and an output file OBFD.  These values actually represent the
283    different possible ARM architecture variants.
284    Returns TRUE if they were merged successfully or FALSE otherwise.  */
285 
286 bool
287 bfd_arm_merge_machines (bfd *ibfd, bfd *obfd)
288 {
289   unsigned int in  = bfd_get_mach (ibfd);
290   unsigned int out = bfd_get_mach (obfd);
291 
292   /* If the output architecture is unknown, we now have a value to set.  */
293   if (out == bfd_mach_arm_unknown)
294     bfd_set_arch_mach (obfd, bfd_arch_arm, in);
295 
296   /* If the input architecture is unknown,
297      then so must be the output architecture.  */
298   else if (in == bfd_mach_arm_unknown)
299     /* FIXME: We ought to have some way to
300        override this on the command line.  */
301     bfd_set_arch_mach (obfd, bfd_arch_arm, bfd_mach_arm_unknown);
302 
303   /* If they are the same then nothing needs to be done.  */
304   else if (out == in)
305     ;
306 
307   /* Otherwise the general principle that a earlier architecture can be
308      linked with a later architecture to produce a binary that will execute
309      on the later architecture.
310 
311      We fail however if we attempt to link a Cirrus EP9312 binary with an
312      Intel XScale binary, since these architecture have co-processors which
313      will not both be present on the same physical hardware.  */
314   else if (in == bfd_mach_arm_ep9312
315 	   && (out == bfd_mach_arm_XScale
316 	       || out == bfd_mach_arm_iWMMXt
317 	       || out == bfd_mach_arm_iWMMXt2))
318     {
319       /* xgettext: c-format */
320       _bfd_error_handler (_("error: %pB is compiled for the EP9312, "
321 			    "whereas %pB is compiled for XScale"),
322 			  ibfd, obfd);
323       bfd_set_error (bfd_error_wrong_format);
324       return false;
325     }
326   else if (out == bfd_mach_arm_ep9312
327 	   && (in == bfd_mach_arm_XScale
328 	       || in == bfd_mach_arm_iWMMXt
329 	       || in == bfd_mach_arm_iWMMXt2))
330     {
331       /* xgettext: c-format */
332       _bfd_error_handler (_("error: %pB is compiled for the EP9312, "
333 			    "whereas %pB is compiled for XScale"),
334 			  obfd, ibfd);
335       bfd_set_error (bfd_error_wrong_format);
336       return false;
337     }
338   else if (in > out)
339     bfd_set_arch_mach (obfd, bfd_arch_arm, in);
340   /* else
341      Nothing to do.  */
342 
343   return true;
344 }
345 
346 typedef struct
347 {
348   unsigned char	namesz[4];	/* Size of entry's owner string.  */
349   unsigned char	descsz[4];	/* Size of the note descriptor.  */
350   unsigned char	type[4];	/* Interpretation of the descriptor.  */
351   char		name[1];	/* Start of the name+desc data.  */
352 } arm_Note;
353 
354 static bool
355 arm_check_note (bfd *abfd,
356 		bfd_byte *buffer,
357 		bfd_size_type buffer_size,
358 		const char *expected_name,
359 		char **description_return)
360 {
361   unsigned long namesz;
362   unsigned long descsz;
363   unsigned long type;
364   char *	descr;
365 
366   if (buffer_size < offsetof (arm_Note, name))
367     return false;
368 
369   /* We have to extract the values this way to allow for a
370      host whose endian-ness is different from the target.  */
371   namesz = bfd_get_32 (abfd, buffer);
372   descsz = bfd_get_32 (abfd, buffer + offsetof (arm_Note, descsz));
373   type   = bfd_get_32 (abfd, buffer + offsetof (arm_Note, type));
374   descr  = (char *) buffer + offsetof (arm_Note, name);
375 
376   /* Check for buffer overflow.  */
377   if (namesz + descsz + offsetof (arm_Note, name) > buffer_size)
378     return false;
379 
380   if (expected_name == NULL)
381     {
382       if (namesz != 0)
383 	return false;
384     }
385   else
386     {
387       if (namesz != ((strlen (expected_name) + 1 + 3) & ~3))
388 	return false;
389 
390       if (strcmp (descr, expected_name) != 0)
391 	return false;
392 
393       descr += (namesz + 3) & ~3;
394     }
395 
396   /* FIXME: We should probably check the type as well.  */
397   (void) type;
398 
399   if (description_return != NULL)
400     * description_return = descr;
401 
402   return true;
403 }
404 
405 #define NOTE_ARCH_STRING	"arch: "
406 
407 bool
408 bfd_arm_update_notes (bfd *abfd, const char *note_section)
409 {
410   asection *	 arm_arch_section;
411   bfd_size_type	 buffer_size;
412   bfd_byte *	 buffer;
413   char *	 arch_string;
414   char *	 expected;
415 
416   /* Look for a note section.  If one is present check the architecture
417      string encoded in it, and set it to the current architecture if it is
418      different.  */
419   arm_arch_section = bfd_get_section_by_name (abfd, note_section);
420 
421   if (arm_arch_section == NULL)
422     return true;
423 
424   buffer_size = arm_arch_section->size;
425   if (buffer_size == 0)
426     return false;
427 
428   if (!bfd_malloc_and_get_section (abfd, arm_arch_section, &buffer))
429     goto FAIL;
430 
431   /* Parse the note.  */
432   if (! arm_check_note (abfd, buffer, buffer_size, NOTE_ARCH_STRING, & arch_string))
433     goto FAIL;
434 
435   /* Check the architecture in the note against the architecture of the bfd.
436      Newer architectures versions should not be added here as build attribute
437      are a better mechanism to convey ISA used.  */
438   switch (bfd_get_mach (abfd))
439     {
440     default:
441     case bfd_mach_arm_unknown: expected = "unknown"; break;
442     case bfd_mach_arm_2:       expected = "armv2"; break;
443     case bfd_mach_arm_2a:      expected = "armv2a"; break;
444     case bfd_mach_arm_3:       expected = "armv3"; break;
445     case bfd_mach_arm_3M:      expected = "armv3M"; break;
446     case bfd_mach_arm_4:       expected = "armv4"; break;
447     case bfd_mach_arm_4T:      expected = "armv4t"; break;
448     case bfd_mach_arm_5:       expected = "armv5"; break;
449     case bfd_mach_arm_5T:      expected = "armv5t"; break;
450     case bfd_mach_arm_5TE:     expected = "armv5te"; break;
451     case bfd_mach_arm_XScale:  expected = "XScale"; break;
452     case bfd_mach_arm_ep9312:  expected = "ep9312"; break;
453     case bfd_mach_arm_iWMMXt:  expected = "iWMMXt"; break;
454     case bfd_mach_arm_iWMMXt2: expected = "iWMMXt2"; break;
455     }
456 
457   if (strcmp (arch_string, expected) != 0)
458     {
459       strcpy ((char *) buffer + (offsetof (arm_Note, name)
460 				 + ((strlen (NOTE_ARCH_STRING) + 3) & ~3)),
461 	      expected);
462 
463       if (! bfd_set_section_contents (abfd, arm_arch_section, buffer,
464 				      (file_ptr) 0, buffer_size))
465 	{
466 	  _bfd_error_handler
467 	    /* xgettext: c-format */
468 	    (_("warning: unable to update contents of %s section in %pB"),
469 	     note_section, abfd);
470 	  goto FAIL;
471 	}
472     }
473 
474   free (buffer);
475   return true;
476 
477  FAIL:
478   free (buffer);
479   return false;
480 }
481 
482 
483 static struct
484 {
485   const char * string;
486   unsigned int mach;
487 }
488 
489 /* Newer architectures versions should not be added here as build attribute are
490    a better mechanism to convey ISA used.  */
491 architectures[] =
492 {
493   { "armv2",   bfd_mach_arm_2 },
494   { "armv2a",  bfd_mach_arm_2a },
495   { "armv3",   bfd_mach_arm_3 },
496   { "armv3M",  bfd_mach_arm_3M },
497   { "armv4",   bfd_mach_arm_4 },
498   { "armv4t",  bfd_mach_arm_4T },
499   { "armv5",   bfd_mach_arm_5 },
500   { "armv5t",  bfd_mach_arm_5T },
501   { "armv5te", bfd_mach_arm_5TE },
502   { "XScale",  bfd_mach_arm_XScale },
503   { "ep9312",  bfd_mach_arm_ep9312 },
504   { "iWMMXt",  bfd_mach_arm_iWMMXt },
505   { "iWMMXt2", bfd_mach_arm_iWMMXt2 },
506   { "arm_any", bfd_mach_arm_unknown }
507 };
508 
509 /* Extract the machine number stored in a note section.  */
510 unsigned int
511 bfd_arm_get_mach_from_notes (bfd *abfd, const char *note_section)
512 {
513   asection *	 arm_arch_section;
514   bfd_size_type	 buffer_size;
515   bfd_byte *	 buffer;
516   char *	 arch_string;
517   int		 i;
518 
519   /* Look for a note section.  If one is present check the architecture
520      string encoded in it, and set it to the current architecture if it is
521      different.  */
522   arm_arch_section = bfd_get_section_by_name (abfd, note_section);
523 
524   if (arm_arch_section == NULL)
525     return bfd_mach_arm_unknown;
526 
527   buffer_size = arm_arch_section->size;
528   if (buffer_size == 0)
529     return bfd_mach_arm_unknown;
530 
531   if (!bfd_malloc_and_get_section (abfd, arm_arch_section, &buffer))
532     goto FAIL;
533 
534   /* Parse the note.  */
535   if (! arm_check_note (abfd, buffer, buffer_size, NOTE_ARCH_STRING, & arch_string))
536     goto FAIL;
537 
538   /* Interpret the architecture string.  */
539   for (i = ARRAY_SIZE (architectures); i--;)
540     if (strcmp (arch_string, architectures[i].string) == 0)
541       {
542 	free (buffer);
543 	return architectures[i].mach;
544       }
545 
546  FAIL:
547   free (buffer);
548   return bfd_mach_arm_unknown;
549 }
550 
551 bool
552 bfd_is_arm_special_symbol_name (const char * name, int type)
553 {
554   /* The ARM compiler outputs several obsolete forms.  Recognize them
555      in addition to the standard $a, $t and $d.  We are somewhat loose
556      in what we accept here, since the full set is not documented.  */
557   if (!name || name[0] != '$')
558     return false;
559   if (name[1] == 'a' || name[1] == 't' || name[1] == 'd')
560     type &= BFD_ARM_SPECIAL_SYM_TYPE_MAP;
561   else if (name[1] == 'm' || name[1] == 'f' || name[1] == 'p')
562     type &= BFD_ARM_SPECIAL_SYM_TYPE_TAG;
563   else if (name[1] >= 'a' && name[1] <= 'z')
564     type &= BFD_ARM_SPECIAL_SYM_TYPE_OTHER;
565   else
566     return false;
567 
568   return (type != 0 && (name[2] == 0 || name[2] == '.'));
569 }
570 
571