160484Sobrien/* BFD support for the ARM processor
2218822Sdim   Copyright 1994, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2007
3218822Sdim   Free Software Foundation, Inc.
460484Sobrien   Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
560484Sobrien
6104834Sobrien   This file is part of BFD, the Binary File Descriptor library.
760484Sobrien
8104834Sobrien   This program is free software; you can redistribute it and/or modify
9104834Sobrien   it under the terms of the GNU General Public License as published by
10104834Sobrien   the Free Software Foundation; either version 2 of the License, or
11104834Sobrien   (at your option) any later version.
1260484Sobrien
13104834Sobrien   This program is distributed in the hope that it will be useful,
14104834Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
15104834Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16104834Sobrien   GNU General Public License for more details.
1760484Sobrien
18104834Sobrien   You should have received a copy of the GNU General Public License
19104834Sobrien   along with this program; if not, write to the Free Software
20218822Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
2160484Sobrien
22218822Sdim#include "sysdep.h"
2360484Sobrien#include "bfd.h"
2460484Sobrien#include "libbfd.h"
25130561Sobrien#include "libiberty.h"
2660484Sobrien
2760484Sobrien/* This routine is provided two arch_infos and works out which ARM
2860484Sobrien   machine which would be compatible with both and returns a pointer
29104834Sobrien   to its info structure.  */
3060484Sobrien
3160484Sobrienstatic const bfd_arch_info_type *
32218822Sdimcompatible (const bfd_arch_info_type *a, const bfd_arch_info_type *b)
3360484Sobrien{
34104834Sobrien  /* If a & b are for different architecture we can do nothing.  */
3560484Sobrien  if (a->arch != b->arch)
3660484Sobrien      return NULL;
3760484Sobrien
38104834Sobrien  /* If a & b are for the same machine then all is well.  */
3960484Sobrien  if (a->mach == b->mach)
4060484Sobrien    return a;
4160484Sobrien
42104834Sobrien  /* Otherwise if either a or b is the 'default' machine
43104834Sobrien     then it can be polymorphed into the other.  */
4460484Sobrien  if (a->the_default)
4560484Sobrien    return b;
4677298Sobrien
4760484Sobrien  if (b->the_default)
4860484Sobrien    return a;
4960484Sobrien
50104834Sobrien  /* So far all newer ARM architecture cores are
51104834Sobrien     supersets of previous cores.  */
5260484Sobrien  if (a->mach < b->mach)
5360484Sobrien    return b;
5460484Sobrien  else if (a->mach > b->mach)
5560484Sobrien    return a;
5660484Sobrien
57104834Sobrien  /* Never reached!  */
5860484Sobrien  return NULL;
5960484Sobrien}
6060484Sobrien
6160484Sobrienstatic struct
6260484Sobrien{
63104834Sobrien  unsigned int mach;
64104834Sobrien  char *       name;
6560484Sobrien}
6660484Sobrienprocessors[] =
6760484Sobrien{
6860484Sobrien  { bfd_mach_arm_2,  "arm2"     },
6960484Sobrien  { bfd_mach_arm_2a, "arm250"   },
7060484Sobrien  { bfd_mach_arm_2a, "arm3"     },
7160484Sobrien  { bfd_mach_arm_3,  "arm6"     },
7260484Sobrien  { bfd_mach_arm_3,  "arm60"    },
7360484Sobrien  { bfd_mach_arm_3,  "arm600"   },
7460484Sobrien  { bfd_mach_arm_3,  "arm610"   },
7560484Sobrien  { bfd_mach_arm_3,  "arm7"     },
7660484Sobrien  { bfd_mach_arm_3,  "arm710"   },
7760484Sobrien  { bfd_mach_arm_3,  "arm7500"  },
7860484Sobrien  { bfd_mach_arm_3,  "arm7d"    },
7960484Sobrien  { bfd_mach_arm_3,  "arm7di"   },
8060484Sobrien  { bfd_mach_arm_3M, "arm7dm"   },
8160484Sobrien  { bfd_mach_arm_3M, "arm7dmi"  },
8260484Sobrien  { bfd_mach_arm_4T, "arm7tdmi" },
8360484Sobrien  { bfd_mach_arm_4,  "arm8"     },
8460484Sobrien  { bfd_mach_arm_4,  "arm810"   },
8560484Sobrien  { bfd_mach_arm_4,  "arm9"     },
8660484Sobrien  { bfd_mach_arm_4,  "arm920"   },
8760484Sobrien  { bfd_mach_arm_4T, "arm920t"  },
8860484Sobrien  { bfd_mach_arm_4T, "arm9tdmi" },
8960484Sobrien  { bfd_mach_arm_4,  "sa1"      },
9060484Sobrien  { bfd_mach_arm_4,  "strongarm"},
9160484Sobrien  { bfd_mach_arm_4,  "strongarm110" },
9260484Sobrien  { bfd_mach_arm_4,  "strongarm1100" },
93130561Sobrien  { bfd_mach_arm_XScale, "xscale" },
94130561Sobrien  { bfd_mach_arm_ep9312, "ep9312" },
95218822Sdim  { bfd_mach_arm_iWMMXt, "iwmmxt" },
96218822Sdim  { bfd_mach_arm_iWMMXt2, "iwmmxt2" }
9760484Sobrien};
9860484Sobrien
99130561Sobrienstatic bfd_boolean
100218822Sdimscan (const struct bfd_arch_info *info, const char *string)
10160484Sobrien{
10260484Sobrien  int  i;
10360484Sobrien
104104834Sobrien  /* First test for an exact match.  */
10560484Sobrien  if (strcasecmp (string, info->printable_name) == 0)
106130561Sobrien    return TRUE;
10760484Sobrien
108104834Sobrien  /* Next check for a processor name instead of an Architecture name.  */
10960484Sobrien  for (i = sizeof (processors) / sizeof (processors[0]); i--;)
11060484Sobrien    {
111104834Sobrien      if (strcasecmp (string, processors [i].name) == 0)
11260484Sobrien	break;
11360484Sobrien    }
11460484Sobrien
115104834Sobrien  if (i != -1 && info->mach == processors [i].mach)
116130561Sobrien    return TRUE;
11760484Sobrien
118104834Sobrien  /* Finally check for the default architecture.  */
11960484Sobrien  if (strcasecmp (string, "arm") == 0)
12060484Sobrien    return info->the_default;
12177298Sobrien
122130561Sobrien  return FALSE;
12360484Sobrien}
12460484Sobrien
12560484Sobrien#define N(number, print, default, next)  \
12660484Sobrien{  32, 32, 8, bfd_arch_arm, number, "arm", print, 4, default, compatible, scan, next }
12760484Sobrien
12860484Sobrienstatic const bfd_arch_info_type arch_info_struct[] =
12977298Sobrien{
130130561Sobrien  N (bfd_mach_arm_2,      "armv2",   FALSE, & arch_info_struct[1]),
131130561Sobrien  N (bfd_mach_arm_2a,     "armv2a",  FALSE, & arch_info_struct[2]),
132130561Sobrien  N (bfd_mach_arm_3,      "armv3",   FALSE, & arch_info_struct[3]),
133130561Sobrien  N (bfd_mach_arm_3M,     "armv3m",  FALSE, & arch_info_struct[4]),
134130561Sobrien  N (bfd_mach_arm_4,      "armv4",   FALSE, & arch_info_struct[5]),
135130561Sobrien  N (bfd_mach_arm_4T,     "armv4t",  FALSE, & arch_info_struct[6]),
136130561Sobrien  N (bfd_mach_arm_5,      "armv5",   FALSE, & arch_info_struct[7]),
137130561Sobrien  N (bfd_mach_arm_5T,     "armv5t",  FALSE, & arch_info_struct[8]),
138130561Sobrien  N (bfd_mach_arm_5TE,    "armv5te", FALSE, & arch_info_struct[9]),
139130561Sobrien  N (bfd_mach_arm_XScale, "xscale",  FALSE, & arch_info_struct[10]),
140130561Sobrien  N (bfd_mach_arm_ep9312, "ep9312",  FALSE, & arch_info_struct[11]),
141218822Sdim  N (bfd_mach_arm_iWMMXt, "iwmmxt",  FALSE, & arch_info_struct[12]),
142218822Sdim  N (bfd_mach_arm_iWMMXt2, "iwmmxt2", FALSE, NULL)
14360484Sobrien};
14460484Sobrien
14560484Sobrienconst bfd_arch_info_type bfd_arm_arch =
146130561Sobrien  N (0, "arm", TRUE, & arch_info_struct[0]);
147130561Sobrien
148130561Sobrien/* Support functions used by both the COFF and ELF versions of the ARM port.  */
149130561Sobrien
150130561Sobrien/* Handle the merging of the 'machine' settings of input file IBFD
151130561Sobrien   and an output file OBFD.  These values actually represent the
152130561Sobrien   different possible ARM architecture variants.
153130561Sobrien   Returns TRUE if they were merged successfully or FALSE otherwise.  */
154130561Sobrien
155130561Sobrienbfd_boolean
156218822Sdimbfd_arm_merge_machines (bfd *ibfd, bfd *obfd)
157130561Sobrien{
158130561Sobrien  unsigned int in  = bfd_get_mach (ibfd);
159130561Sobrien  unsigned int out = bfd_get_mach (obfd);
160130561Sobrien
161130561Sobrien  /* If the output architecture is unknown, we now have a value to set.  */
162130561Sobrien  if (out == bfd_mach_arm_unknown)
163130561Sobrien    bfd_set_arch_mach (obfd, bfd_arch_arm, in);
164130561Sobrien
165130561Sobrien  /* If the input architecture is unknown,
166130561Sobrien     then so must be the output architecture.  */
167130561Sobrien  else if (in == bfd_mach_arm_unknown)
168130561Sobrien    /* FIXME: We ought to have some way to
169130561Sobrien       override this on the command line.  */
170130561Sobrien    bfd_set_arch_mach (obfd, bfd_arch_arm, bfd_mach_arm_unknown);
171130561Sobrien
172130561Sobrien  /* If they are the same then nothing needs to be done.  */
173130561Sobrien  else if (out == in)
174130561Sobrien    ;
175130561Sobrien
176130561Sobrien  /* Otherwise the general principle that a earlier architecture can be
177130561Sobrien     linked with a later architecture to produce a binary that will execute
178130561Sobrien     on the later architecture.
179130561Sobrien
180130561Sobrien     We fail however if we attempt to link a Cirrus EP9312 binary with an
181130561Sobrien     Intel XScale binary, since these architecture have co-processors which
182130561Sobrien     will not both be present on the same physical hardware.  */
183130561Sobrien  else if (in == bfd_mach_arm_ep9312
184218822Sdim	   && (out == bfd_mach_arm_XScale
185218822Sdim	       || out == bfd_mach_arm_iWMMXt
186218822Sdim	       || out == bfd_mach_arm_iWMMXt2))
187130561Sobrien    {
188130561Sobrien      _bfd_error_handler (_("\
189218822SdimERROR: %B is compiled for the EP9312, whereas %B is compiled for XScale"),
190218822Sdim			  ibfd, obfd);
191130561Sobrien      bfd_set_error (bfd_error_wrong_format);
192130561Sobrien      return FALSE;
193130561Sobrien    }
194130561Sobrien  else if (out == bfd_mach_arm_ep9312
195218822Sdim	   && (in == bfd_mach_arm_XScale
196218822Sdim	       || in == bfd_mach_arm_iWMMXt
197218822Sdim	       || in == bfd_mach_arm_iWMMXt2))
198130561Sobrien    {
199130561Sobrien      _bfd_error_handler (_("\
200218822SdimERROR: %B is compiled for the EP9312, whereas %B is compiled for XScale"),
201218822Sdim			  obfd, ibfd);
202130561Sobrien      bfd_set_error (bfd_error_wrong_format);
203130561Sobrien      return FALSE;
204130561Sobrien    }
205130561Sobrien  else if (in > out)
206130561Sobrien    bfd_set_arch_mach (obfd, bfd_arch_arm, in);
207130561Sobrien  /* else
208130561Sobrien     Nothing to do.  */
209130561Sobrien
210130561Sobrien  return TRUE;
211130561Sobrien}
212130561Sobrien
213130561Sobrientypedef struct
214130561Sobrien{
215130561Sobrien  unsigned char	namesz[4];	/* Size of entry's owner string.  */
216130561Sobrien  unsigned char	descsz[4];	/* Size of the note descriptor.  */
217130561Sobrien  unsigned char	type[4];	/* Interpretation of the descriptor.  */
218130561Sobrien  char		name[1];	/* Start of the name+desc data.  */
219130561Sobrien} arm_Note;
220130561Sobrien
221130561Sobrienstatic bfd_boolean
222218822Sdimarm_check_note (bfd *abfd,
223218822Sdim		bfd_byte *buffer,
224218822Sdim		bfd_size_type buffer_size,
225218822Sdim		const char *expected_name,
226218822Sdim		char **description_return)
227130561Sobrien{
228130561Sobrien  unsigned long namesz;
229130561Sobrien  unsigned long descsz;
230130561Sobrien  unsigned long type;
231130561Sobrien  char *        descr;
232130561Sobrien
233130561Sobrien  if (buffer_size < offsetof (arm_Note, name))
234130561Sobrien    return FALSE;
235130561Sobrien
236130561Sobrien  /* We have to extract the values this way to allow for a
237130561Sobrien     host whose endian-ness is different from the target.  */
238130561Sobrien  namesz = bfd_get_32 (abfd, buffer);
239130561Sobrien  descsz = bfd_get_32 (abfd, buffer + offsetof (arm_Note, descsz));
240130561Sobrien  type   = bfd_get_32 (abfd, buffer + offsetof (arm_Note, type));
241218822Sdim  descr  = (char *) buffer + offsetof (arm_Note, name);
242130561Sobrien
243130561Sobrien  /* Check for buffer overflow.  */
244130561Sobrien  if (namesz + descsz + offsetof (arm_Note, name) > buffer_size)
245130561Sobrien    return FALSE;
246130561Sobrien
247130561Sobrien  if (expected_name == NULL)
248130561Sobrien    {
249130561Sobrien      if (namesz != 0)
250130561Sobrien	return FALSE;
251130561Sobrien    }
252130561Sobrien  else
253130561Sobrien    {
254130561Sobrien      if (namesz != ((strlen (expected_name) + 1 + 3) & ~3))
255130561Sobrien	return FALSE;
256130561Sobrien
257130561Sobrien      if (strcmp (descr, expected_name) != 0)
258130561Sobrien	return FALSE;
259130561Sobrien
260130561Sobrien      descr += (namesz + 3) & ~3;
261130561Sobrien    }
262130561Sobrien
263130561Sobrien  /* FIXME: We should probably check the type as well.  */
264130561Sobrien
265130561Sobrien  if (description_return != NULL)
266130561Sobrien    * description_return = descr;
267130561Sobrien
268130561Sobrien  return TRUE;
269130561Sobrien}
270130561Sobrien
271130561Sobrien#define NOTE_ARCH_STRING 	"arch: "
272130561Sobrien
273130561Sobrienbfd_boolean
274218822Sdimbfd_arm_update_notes (bfd *abfd, const char *note_section)
275130561Sobrien{
276130561Sobrien  asection *     arm_arch_section;
277130561Sobrien  bfd_size_type  buffer_size;
278218822Sdim  bfd_byte *     buffer;
279130561Sobrien  char *         arch_string;
280130561Sobrien  char *         expected;
281130561Sobrien
282130561Sobrien  /* Look for a note section.  If one is present check the architecture
283130561Sobrien     string encoded in it, and set it to the current architecture if it is
284130561Sobrien     different.  */
285130561Sobrien  arm_arch_section = bfd_get_section_by_name (abfd, note_section);
286130561Sobrien
287130561Sobrien  if (arm_arch_section == NULL)
288130561Sobrien    return TRUE;
289130561Sobrien
290218822Sdim  buffer_size = arm_arch_section->size;
291130561Sobrien  if (buffer_size == 0)
292130561Sobrien    return FALSE;
293130561Sobrien
294218822Sdim  if (!bfd_malloc_and_get_section (abfd, arm_arch_section, &buffer))
295130561Sobrien    goto FAIL;
296130561Sobrien
297130561Sobrien  /* Parse the note.  */
298130561Sobrien  if (! arm_check_note (abfd, buffer, buffer_size, NOTE_ARCH_STRING, & arch_string))
299130561Sobrien    goto FAIL;
300130561Sobrien
301130561Sobrien  /* Check the architecture in the note against the architecture of the bfd.  */
302130561Sobrien  switch (bfd_get_mach (abfd))
303130561Sobrien    {
304130561Sobrien    default:
305130561Sobrien    case bfd_mach_arm_unknown: expected = "unknown"; break;
306130561Sobrien    case bfd_mach_arm_2:       expected = "armv2"; break;
307130561Sobrien    case bfd_mach_arm_2a:      expected = "armv2a"; break;
308130561Sobrien    case bfd_mach_arm_3:       expected = "armv3"; break;
309130561Sobrien    case bfd_mach_arm_3M:      expected = "armv3M"; break;
310130561Sobrien    case bfd_mach_arm_4:       expected = "armv4"; break;
311130561Sobrien    case bfd_mach_arm_4T:      expected = "armv4t"; break;
312130561Sobrien    case bfd_mach_arm_5:       expected = "armv5"; break;
313130561Sobrien    case bfd_mach_arm_5T:      expected = "armv5t"; break;
314130561Sobrien    case bfd_mach_arm_5TE:     expected = "armv5te"; break;
315130561Sobrien    case bfd_mach_arm_XScale:  expected = "XScale"; break;
316130561Sobrien    case bfd_mach_arm_ep9312:  expected = "ep9312"; break;
317130561Sobrien    case bfd_mach_arm_iWMMXt:  expected = "iWMMXt"; break;
318218822Sdim    case bfd_mach_arm_iWMMXt2: expected = "iWMMXt2"; break;
319130561Sobrien    }
320130561Sobrien
321130561Sobrien  if (strcmp (arch_string, expected) != 0)
322130561Sobrien    {
323218822Sdim      strcpy ((char *) buffer + (offsetof (arm_Note, name)
324218822Sdim				 + ((strlen (NOTE_ARCH_STRING) + 3) & ~3)),
325218822Sdim	      expected);
326130561Sobrien
327130561Sobrien      if (! bfd_set_section_contents (abfd, arm_arch_section, buffer,
328130561Sobrien				      (file_ptr) 0, buffer_size))
329130561Sobrien	{
330130561Sobrien	  (*_bfd_error_handler)
331130561Sobrien	    (_("warning: unable to update contents of %s section in %s"),
332130561Sobrien	     note_section, bfd_get_filename (abfd));
333130561Sobrien	  goto FAIL;
334130561Sobrien	}
335130561Sobrien    }
336130561Sobrien
337130561Sobrien  free (buffer);
338130561Sobrien  return TRUE;
339130561Sobrien
340130561Sobrien FAIL:
341218822Sdim  if (buffer != NULL)
342218822Sdim    free (buffer);
343130561Sobrien  return FALSE;
344130561Sobrien}
345130561Sobrien
346130561Sobrien
347130561Sobrienstatic struct
348130561Sobrien{
349130561Sobrien  const char * string;
350130561Sobrien  unsigned int mach;
351130561Sobrien}
352130561Sobrienarchitectures[] =
353130561Sobrien{
354130561Sobrien  { "armv2",   bfd_mach_arm_2 },
355130561Sobrien  { "armv2a",  bfd_mach_arm_2a },
356130561Sobrien  { "armv3",   bfd_mach_arm_3 },
357130561Sobrien  { "armv3M",  bfd_mach_arm_3M },
358130561Sobrien  { "armv4",   bfd_mach_arm_4 },
359130561Sobrien  { "armv4t",  bfd_mach_arm_4T },
360130561Sobrien  { "armv5",   bfd_mach_arm_5 },
361130561Sobrien  { "armv5t",  bfd_mach_arm_5T },
362130561Sobrien  { "armv5te", bfd_mach_arm_5TE },
363130561Sobrien  { "XScale",  bfd_mach_arm_XScale },
364130561Sobrien  { "ep9312",  bfd_mach_arm_ep9312 },
365218822Sdim  { "iWMMXt",  bfd_mach_arm_iWMMXt },
366218822Sdim  { "iWMMXt2", bfd_mach_arm_iWMMXt2 }
367130561Sobrien};
368130561Sobrien
369130561Sobrien/* Extract the machine number stored in a note section.  */
370130561Sobrienunsigned int
371218822Sdimbfd_arm_get_mach_from_notes (bfd *abfd, const char *note_section)
372130561Sobrien{
373130561Sobrien  asection *     arm_arch_section;
374130561Sobrien  bfd_size_type  buffer_size;
375218822Sdim  bfd_byte *     buffer;
376130561Sobrien  char *         arch_string;
377130561Sobrien  int            i;
378130561Sobrien
379130561Sobrien  /* Look for a note section.  If one is present check the architecture
380130561Sobrien     string encoded in it, and set it to the current architecture if it is
381130561Sobrien     different.  */
382130561Sobrien  arm_arch_section = bfd_get_section_by_name (abfd, note_section);
383130561Sobrien
384130561Sobrien  if (arm_arch_section == NULL)
385130561Sobrien    return bfd_mach_arm_unknown;
386130561Sobrien
387218822Sdim  buffer_size = arm_arch_section->size;
388130561Sobrien  if (buffer_size == 0)
389130561Sobrien    return bfd_mach_arm_unknown;
390130561Sobrien
391218822Sdim  if (!bfd_malloc_and_get_section (abfd, arm_arch_section, &buffer))
392130561Sobrien    goto FAIL;
393130561Sobrien
394130561Sobrien  /* Parse the note.  */
395130561Sobrien  if (! arm_check_note (abfd, buffer, buffer_size, NOTE_ARCH_STRING, & arch_string))
396130561Sobrien    goto FAIL;
397130561Sobrien
398130561Sobrien  /* Interpret the architecture string.  */
399130561Sobrien  for (i = ARRAY_SIZE (architectures); i--;)
400130561Sobrien    if (strcmp (arch_string, architectures[i].string) == 0)
401130561Sobrien      {
402130561Sobrien	free (buffer);
403130561Sobrien	return architectures[i].mach;
404130561Sobrien      }
405130561Sobrien
406130561Sobrien FAIL:
407218822Sdim  if (buffer != NULL)
408218822Sdim    free (buffer);
409130561Sobrien  return bfd_mach_arm_unknown;
410130561Sobrien}
411218822Sdim
412218822Sdimbfd_boolean
413218822Sdimbfd_is_arm_special_symbol_name (const char * name, int type)
414218822Sdim{
415218822Sdim  /* The ARM compiler outputs several obsolete forms.  Recognize them
416218822Sdim     in addition to the standard $a, $t and $d.  We are somewhat loose
417218822Sdim     in what we accept here, since the full set is not documented.  */
418218822Sdim  if (!name || name[0] != '$')
419218822Sdim    return FALSE;
420218822Sdim  if (name[1] == 'a' || name[1] == 't' || name[1] == 'd')
421218822Sdim    type &= BFD_ARM_SPECIAL_SYM_TYPE_MAP;
422218822Sdim  else if (name[1] == 'm' || name[1] == 'f' || name[1] == 'p')
423218822Sdim    type &= BFD_ARM_SPECIAL_SYM_TYPE_TAG;
424218822Sdim  else if (name[1] >= 'a' && name[1] <= 'z')
425218822Sdim    type &= BFD_ARM_SPECIAL_SYM_TYPE_OTHER;
426218822Sdim  else
427218822Sdim    return FALSE;
428218822Sdim
429218822Sdim  return (type != 0 && (name[2] == 0 || name[2] == '.'));
430218822Sdim}
431218822Sdim
432