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